kwipper 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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