kwipper 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.DS_Store +0 -0
- data/.gitignore +16 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +33 -0
- data/Rakefile +2 -0
- data/app/controllers/comments_controller.rb +32 -0
- data/app/controllers/post_favorites_controller.rb +17 -0
- data/app/controllers/posts_controller.rb +41 -0
- data/app/controllers/sessions_controller.rb +32 -0
- data/app/controllers/users_controller.rb +70 -0
- data/app/models/comment.rb +20 -0
- data/app/models/post.rb +31 -0
- data/app/models/post_favorite.rb +6 -0
- data/app/models/session.rb +12 -0
- data/app/models/user.rb +21 -0
- data/app/views/edit_user.erb +26 -0
- data/app/views/fave_button.erb +8 -0
- data/app/views/home.erb +126 -0
- data/app/views/layout.erb +110 -0
- data/app/views/login_user.erb +24 -0
- data/app/views/new_comment.erb +18 -0
- data/app/views/new_post.erb +11 -0
- data/app/views/new_user.erb +26 -0
- data/app/views/not_found.erb +11 -0
- data/app/views/pagination.erb +29 -0
- data/app/views/posts.erb +7 -0
- data/app/views/posts_list.erb +44 -0
- data/app/views/reply_button.erb +4 -0
- data/app/views/server_error.erb +17 -0
- data/app/views/show_post.erb +37 -0
- data/app/views/show_user.erb +11 -0
- data/app/views/users.erb +38 -0
- data/db/.DS_Store +0 -0
- data/kwipper.gemspec +27 -0
- data/lib/kwipper.rb +46 -0
- data/lib/kwipper/application.rb +87 -0
- data/lib/kwipper/controller.rb +36 -0
- data/lib/kwipper/controller_helpers.rb +22 -0
- data/lib/kwipper/errors.rb +5 -0
- data/lib/kwipper/http_parser.rb +51 -0
- data/lib/kwipper/http_server.rb +61 -0
- data/lib/kwipper/inflect.rb +19 -0
- data/lib/kwipper/model.rb +174 -0
- data/lib/kwipper/paginator.rb +71 -0
- data/lib/kwipper/renders_views.rb +18 -0
- data/lib/kwipper/request.rb +35 -0
- data/lib/kwipper/request_headers.rb +36 -0
- data/lib/kwipper/response.rb +85 -0
- data/lib/kwipper/version.rb +3 -0
- data/public/css/bootstrap-lumen.min.css +7 -0
- data/public/css/styles.css +48 -0
- data/public/fonts/glyphicons-halflings-regular.eot +0 -0
- data/public/fonts/glyphicons-halflings-regular.svg +229 -0
- data/public/fonts/glyphicons-halflings-regular.ttf +0 -0
- data/public/fonts/glyphicons-halflings-regular.woff +0 -0
- data/public/js/bootstrap.min.js +7 -0
- metadata +173 -0
@@ -0,0 +1,110 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html lang="en">
|
3
|
+
<head>
|
4
|
+
<meta charset="utf-8">
|
5
|
+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
7
|
+
|
8
|
+
<title>Kwipper</title>
|
9
|
+
|
10
|
+
<link rel="stylesheet" href="/css/bootstrap-lumen.min.css">
|
11
|
+
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css">
|
12
|
+
<link rel="stylesheet" href="/css/styles.css">
|
13
|
+
|
14
|
+
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
|
15
|
+
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
|
16
|
+
<!--[if lt IE 9]>
|
17
|
+
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
|
18
|
+
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
|
19
|
+
<![endif]-->
|
20
|
+
</head>
|
21
|
+
<body role="document">
|
22
|
+
|
23
|
+
<nav class="navbar navbar-default">
|
24
|
+
<div class="container">
|
25
|
+
<div class="navbar-header">
|
26
|
+
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
|
27
|
+
<span class="sr-only">Toggle navigation</span>
|
28
|
+
<span class="icon-bar"></span>
|
29
|
+
<span class="icon-bar"></span>
|
30
|
+
<span class="icon-bar"></span>
|
31
|
+
</button>
|
32
|
+
<a class="navbar-brand" href="/">Kwipper</a>
|
33
|
+
</div>
|
34
|
+
|
35
|
+
<div id="navbar" class="collapse navbar-collapse">
|
36
|
+
<ul class="nav navbar-nav">
|
37
|
+
<li class="<%= 'active' if action == :posts %>">
|
38
|
+
<a href="/kwips">Kwips</a>
|
39
|
+
</li>
|
40
|
+
<% if current_user %>
|
41
|
+
<li class="<%= 'active' if action == :users %>">
|
42
|
+
<a href="/users">Users</a>
|
43
|
+
</li>
|
44
|
+
<% end %>
|
45
|
+
</ul>
|
46
|
+
|
47
|
+
<ul class="nav navbar-nav navbar-right">
|
48
|
+
<% if current_user %>
|
49
|
+
<li class="dropdown">
|
50
|
+
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">
|
51
|
+
<%= current_user.username %> <span class="caret"></span>
|
52
|
+
</a>
|
53
|
+
<ul class="dropdown-menu" role="menu">
|
54
|
+
<li>
|
55
|
+
<a href="/users/edit?id=<%= current_user.id %>">Profile</a>
|
56
|
+
</li>
|
57
|
+
<li>
|
58
|
+
<a href="/logout">
|
59
|
+
<span class="fa fa-sign-out"> </span>
|
60
|
+
Logout
|
61
|
+
</a>
|
62
|
+
</li>
|
63
|
+
</ul>
|
64
|
+
</li>
|
65
|
+
<% else %>
|
66
|
+
<li>
|
67
|
+
<a href="/login">
|
68
|
+
<span class="fa fa-sign-in"> </span>
|
69
|
+
Login
|
70
|
+
</a>
|
71
|
+
</li>
|
72
|
+
<% end %>
|
73
|
+
</ul>
|
74
|
+
|
75
|
+
<% if current_user %>
|
76
|
+
<ul class="nav navbar-right navbar-nav nav-pills">
|
77
|
+
<li role="presentation">
|
78
|
+
<a href="/kwips/new">
|
79
|
+
<span class="fa fa-plus"> </span>
|
80
|
+
New Kwip
|
81
|
+
</a>
|
82
|
+
</li>
|
83
|
+
</ul>
|
84
|
+
<% end %>
|
85
|
+
</div>
|
86
|
+
</div>
|
87
|
+
</nav>
|
88
|
+
|
89
|
+
<div class="container">
|
90
|
+
<div class="row">
|
91
|
+
<div class="col-sm-2"></div>
|
92
|
+
|
93
|
+
<div class="col-sm-8">
|
94
|
+
<%= @view %>
|
95
|
+
</div>
|
96
|
+
|
97
|
+
<div class="col-sm-2"></div>
|
98
|
+
</div>
|
99
|
+
</div>
|
100
|
+
|
101
|
+
<footer class="footer">
|
102
|
+
<div class="container">
|
103
|
+
<p class="text-muted">© 2015 Diego Salazar</p>
|
104
|
+
</div>
|
105
|
+
</footer>
|
106
|
+
|
107
|
+
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
|
108
|
+
<script src="/js/bootstrap.min.js"></script>
|
109
|
+
</body>
|
110
|
+
</html>
|
@@ -0,0 +1,24 @@
|
|
1
|
+
<h1>
|
2
|
+
<span class="fa fa-sign-in"></span>
|
3
|
+
Login
|
4
|
+
</h1>
|
5
|
+
|
6
|
+
<div class="row">
|
7
|
+
<div class="col-sm-12">
|
8
|
+
<form action="/sessions/create" method="post">
|
9
|
+
<div class="form-group">
|
10
|
+
<label>Username</label>
|
11
|
+
<input type="text" name="username" class="form-control">
|
12
|
+
</div>
|
13
|
+
|
14
|
+
<div class="form-group">
|
15
|
+
<label>Password</label>
|
16
|
+
<input type="text" name="password" class="form-control">
|
17
|
+
</div>
|
18
|
+
|
19
|
+
<div class="form-group">
|
20
|
+
<input type="submit" value="Login" class="btn btn-primary">
|
21
|
+
</div>
|
22
|
+
</form>
|
23
|
+
</div>
|
24
|
+
</div>
|
@@ -0,0 +1,18 @@
|
|
1
|
+
<h1><%= @post.username %></h1>
|
2
|
+
<p>@ <%= @post.created_at %></p>
|
3
|
+
|
4
|
+
<div class="well">
|
5
|
+
<%= @post.content %>
|
6
|
+
</div>
|
7
|
+
|
8
|
+
<h2>New Comment</h2>
|
9
|
+
|
10
|
+
<form action="/kwips/comments/create?id=<%= @post.id %>" method="post">
|
11
|
+
<div class="form-group">
|
12
|
+
<textarea name="content" class="form-control" rows="5"></textarea>
|
13
|
+
</div>
|
14
|
+
|
15
|
+
<div class="form-group">
|
16
|
+
<input type="submit" value="Submit" class="btn btn-xs btn-success">
|
17
|
+
</div>
|
18
|
+
</form>
|
@@ -0,0 +1,11 @@
|
|
1
|
+
<h1>New Kwip</h1>
|
2
|
+
|
3
|
+
<form action="/kwips/create" method="post">
|
4
|
+
<div class="form-group">
|
5
|
+
<textarea name="content" class="form-control" rows="5"></textarea>
|
6
|
+
</div>
|
7
|
+
|
8
|
+
<div class="form-group">
|
9
|
+
<input type="submit" value="Create" class="btn btn-primary">
|
10
|
+
</div>
|
11
|
+
</form>
|
@@ -0,0 +1,26 @@
|
|
1
|
+
<h1>New User</h1>
|
2
|
+
|
3
|
+
<div class="row">
|
4
|
+
<div class="col-sm-12">
|
5
|
+
<form action="/users/create" method="post">
|
6
|
+
<div class="form-group">
|
7
|
+
<label>Username</label>
|
8
|
+
<input type="text" name="username" class="form-control">
|
9
|
+
</div>
|
10
|
+
|
11
|
+
<div class="form-group">
|
12
|
+
<label>Email</label>
|
13
|
+
<input type="text" name="email" class="form-control">
|
14
|
+
</div>
|
15
|
+
|
16
|
+
<div class="form-group">
|
17
|
+
<label>Password</label>
|
18
|
+
<input type="text" name="hashed_password" class="form-control">
|
19
|
+
</div>
|
20
|
+
|
21
|
+
<div class="form-group">
|
22
|
+
<input type="submit" value="Create" class="btn btn-primary">
|
23
|
+
</div>
|
24
|
+
</form>
|
25
|
+
</div>
|
26
|
+
</div>
|
@@ -0,0 +1,29 @@
|
|
1
|
+
<nav>
|
2
|
+
<ul class="pagination pull-left">
|
3
|
+
<li class="<%= 'disabled' if @paginator.on_first_page? %>">
|
4
|
+
<a href="<%= @paginator.prev_page_path %>" aria-label="Previous">
|
5
|
+
<span aria-hidden="true">«</span>
|
6
|
+
</a>
|
7
|
+
</li>
|
8
|
+
|
9
|
+
<% @paginator.pages.each do |page| %>
|
10
|
+
<li class="<%= 'active' if page.current? %>">
|
11
|
+
<a href="<%= page.path %>">
|
12
|
+
<%= page.num %>
|
13
|
+
</a>
|
14
|
+
</li>
|
15
|
+
<% end %>
|
16
|
+
|
17
|
+
<li class="<%= 'disabled' if @paginator.on_last_page? %>">
|
18
|
+
<a href="<%= @paginator.next_page_path %>" aria-label="Next">
|
19
|
+
<span aria-hidden="true">»</span>
|
20
|
+
</a>
|
21
|
+
</li>
|
22
|
+
</ul>
|
23
|
+
|
24
|
+
<p class="pagination-stats pull-left">
|
25
|
+
Showing <%= @paginator.from %>
|
26
|
+
to <%= @paginator.to %>
|
27
|
+
of <%= @paginator.count %>
|
28
|
+
</p>
|
29
|
+
</nav>
|
data/app/views/posts.erb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
<ul class="list-unstyled">
|
2
|
+
<% @posts.each do |post| %>
|
3
|
+
<li>
|
4
|
+
<p>
|
5
|
+
<a href="/users/show?id=<%= post.user_id %>">
|
6
|
+
<strong><%= post.username %></strong>
|
7
|
+
</a>
|
8
|
+
@ <%= post.created_at %>
|
9
|
+
</p>
|
10
|
+
|
11
|
+
<div class="well">
|
12
|
+
<%= post.content %>
|
13
|
+
</div>
|
14
|
+
|
15
|
+
<div class="row">
|
16
|
+
<div class="col-sm-12">
|
17
|
+
<div class="btn-group pull-left">
|
18
|
+
<span class="badge">
|
19
|
+
<%= Inflect.plural post.faves_count, 'Fave' %>
|
20
|
+
</span>
|
21
|
+
</div>
|
22
|
+
|
23
|
+
<div class="btn-group pull-right">
|
24
|
+
<%= render :fave_button, post: post if current_user %>
|
25
|
+
|
26
|
+
<a href="/kwips/show?id=<%= post.id %>" class="btn btn-xs btn-info">
|
27
|
+
<span class="fa fa-comments-o"> </span>
|
28
|
+
Comments
|
29
|
+
<span class="badge">
|
30
|
+
<%= post.comments_count %>
|
31
|
+
</span>
|
32
|
+
</a>
|
33
|
+
|
34
|
+
<%= render :reply_button, post: post if current_user %>
|
35
|
+
</div>
|
36
|
+
</div>
|
37
|
+
</div>
|
38
|
+
|
39
|
+
<hr>
|
40
|
+
</li>
|
41
|
+
<% end %>
|
42
|
+
|
43
|
+
<%= render :pagination if @posts.any? %>
|
44
|
+
</ul>
|
@@ -0,0 +1,17 @@
|
|
1
|
+
<h1><%= response.info %></h1>
|
2
|
+
|
3
|
+
<p>
|
4
|
+
<code>
|
5
|
+
<%= @error.class %> <%= CGI.escapeHTML @error.message %>
|
6
|
+
</code>
|
7
|
+
</p>
|
8
|
+
|
9
|
+
<pre>
|
10
|
+
<%= @error.backtrace.map { |line| CGI.escapeHTML line }.join "\n" %>
|
11
|
+
</pre>
|
12
|
+
|
13
|
+
<p>Params:</p>
|
14
|
+
|
15
|
+
<pre>
|
16
|
+
<%= params.pretty_inspect %>
|
17
|
+
</pre>
|
@@ -0,0 +1,37 @@
|
|
1
|
+
<h1><%= @post.username %></h1>
|
2
|
+
<p>
|
3
|
+
<span class="fa fa-clock-o"> </span>
|
4
|
+
<%= @post.created_at %>
|
5
|
+
</p>
|
6
|
+
|
7
|
+
<div class="well">
|
8
|
+
<%= @post.content %>
|
9
|
+
</div>
|
10
|
+
|
11
|
+
<div class="btn-group pull-right">
|
12
|
+
<% if current_user %>
|
13
|
+
<%= render :fave_button, post: @post %>
|
14
|
+
<%= render :reply_button, post: @post %>
|
15
|
+
<% end %>
|
16
|
+
</div>
|
17
|
+
|
18
|
+
<% if @comments.empty? %>
|
19
|
+
<h2>No Comments</h2>
|
20
|
+
<% else %>
|
21
|
+
<h2>Comments</h2>
|
22
|
+
|
23
|
+
<ul class="list-unstyled">
|
24
|
+
<% @comments.each do |comment| %>
|
25
|
+
<li>
|
26
|
+
<p>
|
27
|
+
<span class="fa fa-comments"> </span>
|
28
|
+
<%= comment.username %> @ <%= comment.created_at %>
|
29
|
+
</p>
|
30
|
+
|
31
|
+
<div class="well well-xs">
|
32
|
+
<%= comment.content %>
|
33
|
+
</div>
|
34
|
+
</li>
|
35
|
+
<% end %>
|
36
|
+
</ul>
|
37
|
+
<% end %>
|
data/app/views/users.erb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
<h1>Users</h1>
|
2
|
+
|
3
|
+
<table class="table table-striped table-hover">
|
4
|
+
<thead>
|
5
|
+
<tr>
|
6
|
+
<th>ID</th>
|
7
|
+
<th>Username</th>
|
8
|
+
<th>Email</th>
|
9
|
+
<th>
|
10
|
+
<a href="/users/new" class="btn btn-xs btn-primary pull-right">
|
11
|
+
<span class="fa fa-user-plus"> </span>
|
12
|
+
New User
|
13
|
+
</a>
|
14
|
+
</th>
|
15
|
+
</tr>
|
16
|
+
</thead>
|
17
|
+
|
18
|
+
<tbody>
|
19
|
+
<% @users.each do |user| %>
|
20
|
+
<tr>
|
21
|
+
<td><%= user.id %></td>
|
22
|
+
<td><%= user.username %></td>
|
23
|
+
<td><%= user.email %></td>
|
24
|
+
<td>
|
25
|
+
<div class="text-right">
|
26
|
+
<a href="/users/edit?id=<%= user.id %>" class="btn btn-xs btn-primary">
|
27
|
+
Edit
|
28
|
+
</a>
|
29
|
+
<form action="/users/destroy" method="post" class="pull-right">
|
30
|
+
<input type="hidden" name="id" value="<%= user.id %>">
|
31
|
+
<input type="submit" value="Destroy" class="btn btn-xs btn-danger">
|
32
|
+
</form>
|
33
|
+
</div>
|
34
|
+
</td>
|
35
|
+
</tr>
|
36
|
+
<% end %>
|
37
|
+
</tbody>
|
38
|
+
</table>
|
data/db/.DS_Store
ADDED
Binary file
|
data/kwipper.gemspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'kwipper/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "kwipper"
|
8
|
+
spec.version = Kwipper::VERSION
|
9
|
+
spec.authors = ["Diego Salazar"]
|
10
|
+
spec.email = ["diego@greyrobot.com"]
|
11
|
+
spec.summary = %q{Kwipper is the reference example app for the Kwipper Programming Challenge}
|
12
|
+
spec.description = %q{Kwipper is the reference example app for the Kwipper Programming Challenge to build an app and server from scratch.}
|
13
|
+
spec.homepage = ""
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_dependency 'sqlite3'
|
22
|
+
spec.add_dependency 'colorize'
|
23
|
+
|
24
|
+
spec.add_development_dependency "bundler", "~> 1.7"
|
25
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
26
|
+
spec.add_development_dependency "pry"
|
27
|
+
end
|
data/lib/kwipper.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
$START_TIME = Time.now.to_f
|
2
|
+
require "socket"
|
3
|
+
require "securerandom"
|
4
|
+
require "sqlite3"
|
5
|
+
require "erb"
|
6
|
+
require "uri"
|
7
|
+
require "logger"
|
8
|
+
require "mime-types"
|
9
|
+
require "rack/utils"
|
10
|
+
require "colorize"
|
11
|
+
require "pry"
|
12
|
+
|
13
|
+
module Kwipper
|
14
|
+
ROOT = Dir.pwd
|
15
|
+
|
16
|
+
def self.log_startup_time
|
17
|
+
log.debug "Started in #{sprintf '%.2f', Time.now.to_f - $START_TIME}s"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def log
|
22
|
+
@logger ||= Logger.new(STDOUT).tap do |logger|
|
23
|
+
logger.datetime_format = '%Y-%m-%d %H:%M:%S '
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
require "kwipper/version"
|
28
|
+
require "kwipper/errors"
|
29
|
+
# Server
|
30
|
+
require "kwipper/http_parser"
|
31
|
+
require "kwipper/http_server"
|
32
|
+
require "kwipper/request"
|
33
|
+
require "kwipper/request_headers"
|
34
|
+
require "kwipper/response"
|
35
|
+
# Helpers
|
36
|
+
require "kwipper/inflect"
|
37
|
+
require "kwipper/renders_views"
|
38
|
+
require "kwipper/controller_helpers"
|
39
|
+
# Micro framework
|
40
|
+
require "kwipper/application"
|
41
|
+
require "kwipper/controller"
|
42
|
+
require "kwipper/model"
|
43
|
+
# Extensions
|
44
|
+
require "kwipper/paginator"
|
45
|
+
|
46
|
+
Kwipper::HttpServer.run if __FILE__ == $0
|