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.
Files changed (59) hide show
  1. checksums.yaml +7 -0
  2. data/.DS_Store +0 -0
  3. data/.gitignore +16 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE.txt +22 -0
  6. data/README.md +33 -0
  7. data/Rakefile +2 -0
  8. data/app/controllers/comments_controller.rb +32 -0
  9. data/app/controllers/post_favorites_controller.rb +17 -0
  10. data/app/controllers/posts_controller.rb +41 -0
  11. data/app/controllers/sessions_controller.rb +32 -0
  12. data/app/controllers/users_controller.rb +70 -0
  13. data/app/models/comment.rb +20 -0
  14. data/app/models/post.rb +31 -0
  15. data/app/models/post_favorite.rb +6 -0
  16. data/app/models/session.rb +12 -0
  17. data/app/models/user.rb +21 -0
  18. data/app/views/edit_user.erb +26 -0
  19. data/app/views/fave_button.erb +8 -0
  20. data/app/views/home.erb +126 -0
  21. data/app/views/layout.erb +110 -0
  22. data/app/views/login_user.erb +24 -0
  23. data/app/views/new_comment.erb +18 -0
  24. data/app/views/new_post.erb +11 -0
  25. data/app/views/new_user.erb +26 -0
  26. data/app/views/not_found.erb +11 -0
  27. data/app/views/pagination.erb +29 -0
  28. data/app/views/posts.erb +7 -0
  29. data/app/views/posts_list.erb +44 -0
  30. data/app/views/reply_button.erb +4 -0
  31. data/app/views/server_error.erb +17 -0
  32. data/app/views/show_post.erb +37 -0
  33. data/app/views/show_user.erb +11 -0
  34. data/app/views/users.erb +38 -0
  35. data/db/.DS_Store +0 -0
  36. data/kwipper.gemspec +27 -0
  37. data/lib/kwipper.rb +46 -0
  38. data/lib/kwipper/application.rb +87 -0
  39. data/lib/kwipper/controller.rb +36 -0
  40. data/lib/kwipper/controller_helpers.rb +22 -0
  41. data/lib/kwipper/errors.rb +5 -0
  42. data/lib/kwipper/http_parser.rb +51 -0
  43. data/lib/kwipper/http_server.rb +61 -0
  44. data/lib/kwipper/inflect.rb +19 -0
  45. data/lib/kwipper/model.rb +174 -0
  46. data/lib/kwipper/paginator.rb +71 -0
  47. data/lib/kwipper/renders_views.rb +18 -0
  48. data/lib/kwipper/request.rb +35 -0
  49. data/lib/kwipper/request_headers.rb +36 -0
  50. data/lib/kwipper/response.rb +85 -0
  51. data/lib/kwipper/version.rb +3 -0
  52. data/public/css/bootstrap-lumen.min.css +7 -0
  53. data/public/css/styles.css +48 -0
  54. data/public/fonts/glyphicons-halflings-regular.eot +0 -0
  55. data/public/fonts/glyphicons-halflings-regular.svg +229 -0
  56. data/public/fonts/glyphicons-halflings-regular.ttf +0 -0
  57. data/public/fonts/glyphicons-halflings-regular.woff +0 -0
  58. data/public/js/bootstrap.min.js +7 -0
  59. 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">&nbsp;</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">&nbsp;</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">&nbsp;</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">&copy; 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,11 @@
1
+ <h1><%= response.status_code %> Not Found</h1>
2
+
3
+ <p>
4
+ <code><%= request.info %></code> not found.
5
+ </p>
6
+
7
+ <p>Params:</p>
8
+
9
+ <pre>
10
+ <%= params.pretty_inspect %>
11
+ </pre>
@@ -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">&laquo;</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">&raquo;</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>
@@ -0,0 +1,7 @@
1
+ <% if @posts.empty? %>
2
+ <h1>No Kwips!</h1>
3
+ <% else %>
4
+ <h1>Kwips</h1>
5
+
6
+ <%= render :posts_list %>
7
+ <% end %>
@@ -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">&nbsp;</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,4 @@
1
+ <a href="/kwips/comments/new?id=<%= @post.id %>" class="btn btn-xs btn-success">
2
+ <span class="fa fa-reply">&nbsp;</span>
3
+ Reply
4
+ </a>
@@ -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">&nbsp;</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">&nbsp;</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 %>
@@ -0,0 +1,11 @@
1
+ <h1><%= @user.username %></h1>
2
+ <p>
3
+ <span class="fa fa-envelope">&nbsp;</span>
4
+ <%= @user.email %>
5
+ </p>
6
+
7
+ <hr>
8
+
9
+ <h2>Kwips</h2>
10
+
11
+ <%= render :posts_list %>
@@ -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">&nbsp;</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>
Binary file
@@ -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
@@ -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