solutus 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9ecaee3a0a58a45099f3c7c431fabb0f15c4b347a27120d45abeaa5640a59172
4
- data.tar.gz: fc5f357956eb4497b85b2aa54db9c70ff78fecbe08f9e84158008033d8617767
3
+ metadata.gz: 7de81fd93b57d53407c0e146559143c7ac95237bb21199afd0d3aeea017c5b94
4
+ data.tar.gz: 3dce67dce9f05d447159a53517311f1892efa92a719db866322fd055a6442920
5
5
  SHA512:
6
- metadata.gz: 1f1e2c125d11296e8f8eff2589b74c8fa2f76082690c6589ea6e0995454400f31897cedacba57228840093a2cc751d2b13f2e1510c873501949af3c7f1a62ca2
7
- data.tar.gz: 8715a7a6ee14eda0331261ef4a3c4745d721681ee6492a05b6cfe3cdb98119635b6caef17be9e41f27ac25f71cf6290e7f87d5e5444c414025dbf434e29832fb
6
+ metadata.gz: 4d9c10aa6739895a94e3949d123579393e3c38c4ef6f699f68479f2af6006dcde21a424b23d01c50e45a8e980568fa240e1df185fe786c354dd39efe71a3f340
7
+ data.tar.gz: 2664ed3b5e4c2c9edfe072cf2a9200173697d93154bc62ad5c47c6289df4d1d21641af1884178a526814c72ed3f9d3966d5f6a6983ae4ba6571d9d0977d74f0a
data/lib/solutus.rb CHANGED
@@ -5,6 +5,11 @@ require 'mustache'
5
5
  require 'redcarpet'
6
6
  require 'json'
7
7
  require 'nokogiri'
8
+ require 'digest'
9
+
10
+ #TODO: Add support for tags
11
+ #TODO: Make stress tests
12
+ #TODO: Fix bug : day being off with time in file
8
13
 
9
14
  class Solutus
10
15
  ARCHIVE = "archive"
@@ -18,8 +23,10 @@ class Solutus
18
23
  SITE_PAGES_PATH = File.join("pages", "site-pages")
19
24
  POSTS_PATH = File.join("pages", "posts")
20
25
  BLOG_DATE_FORMAT = "%b %e, %Y"
26
+ BLOG_DATE_DATA = "%Y-%m-%e %I:%M:%S"
21
27
  SETTINGS_FILE = "settings.yml"
22
28
  CACHE = ".solutus-cache"
29
+ PASSWORD_FILE = "password.txt"
23
30
  DAY_ENDINGS = ["th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th", "th", "th", "th", "th", "th", "th", "th", "th", "th", "th", "th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th", "th", "st"]
24
31
 
25
32
  @@blog_urls = Hash.new
@@ -39,35 +46,70 @@ class Solutus
39
46
  YAML.load(yml_text)
40
47
  rescue
41
48
  puts "Not a Solutus Project (yet) --- settings.yml not found"
49
+ false
42
50
  end
43
51
  end
44
52
 
45
53
  class Solutus_Server < Sinatra::Base
54
+ enable :sessions
55
+
46
56
  set :public_folder, SITE_PATH
57
+ set :environment, :production
47
58
 
48
59
  configure do
49
60
  glob = Solutus.load_settings
50
61
  set :global_settings, glob
51
62
  end
52
63
 
64
+ class ServerStache < Mustache
65
+ end
66
+
53
67
  get "/" do
54
68
  send_file File.join(settings.public_folder, 'index.html')
55
69
  end
56
70
 
71
+ post "/login" do
72
+ if !params["password"]
73
+ return 'no password'
74
+ end
75
+ given_password_hash = Digest::MD5.hexdigest params["password"]
76
+ password = File.read(PASSWORD_FILE)
77
+ puts given_password_hash.to_s
78
+ puts "password on file:" + password.to_s
79
+ if given_password_hash.to_s == password.to_s
80
+ session[:verified] = true
81
+ redirect "/edit"
82
+ else
83
+ render_login("Wrong password")
84
+ end
85
+ end
86
+
57
87
  get "/reset" do
88
+ if !session[:verified]
89
+ return render_login("You were logged out.")
90
+ end
58
91
  Solutus.command("build")
59
92
  redirect "/"
60
93
  end
61
94
 
62
95
  get "/edit" do
96
+ if !session[:verified]
97
+ return render_login()
98
+ end
63
99
  render_index
64
100
  end
65
101
 
66
102
  get "/editpage" do
103
+ if !session[:verified]
104
+ return render_login("You were logged out.")
105
+ end
67
106
  render_edit_page(params["page-path"])
68
107
  end
69
108
 
70
109
  post "/savepage" do
110
+ if !session[:verified]
111
+ return render_login("You were logged out.")
112
+ end
71
113
  path = params["path"]
72
114
 
73
115
  f = File.open(path, "r")
@@ -90,16 +132,29 @@ class Solutus
90
132
  end
91
133
 
92
134
  post "/newpost" do
93
- path = Solutus.command("new", "post", params["post-title"])
94
- Solutus.build
135
+ if !session[:verified]
136
+ return render_login("You were logged out.")
137
+ end
138
+ title = params["post-title"].gsub(/[^a-zA-Z0-9\-]/,"").strip
139
+ if title.empty?
140
+ return "Error"
141
+ end
142
+ path = Solutus.command("new", "post", title)
143
+ Solutus.command("build")
95
144
  render_edit_post(path)
96
145
  end
97
146
 
98
147
  get "/editpost" do
148
+ if !session[:verified]
149
+ return render_login("You were logged out.")
150
+ end
99
151
  render_edit_post(*params["post-path"].split(","))
100
152
  end
101
153
 
102
154
  post "/savepost" do
155
+ if !session[:verified]
156
+ return render_login("You were logged out.")
157
+ end
103
158
  path = params["path"]
104
159
  f = File.open(path, "r")
105
160
  yml_text = ""
@@ -109,6 +164,7 @@ class Solutus
109
164
  f.close
110
165
  data = YAML.load(yml_text)
111
166
  data["title"] = params["title"]
167
+ data["subtitle"] = params["subtitle"]
112
168
  new_contents = YAML.dump(data)
113
169
  new_contents += "---\n"
114
170
  new_contents += params["markdown"]
@@ -137,7 +193,7 @@ class Solutus
137
193
  else
138
194
  send_404
139
195
  end
140
- end
196
+ end
141
197
 
142
198
  def send_404
143
199
  send_file File.join(path_to_resources, "404.html")
@@ -147,9 +203,6 @@ class Solutus
147
203
  File.join(File.dirname(File.expand_path(__FILE__)), '../resources')
148
204
  end
149
205
 
150
- class ServerStache < Mustache
151
- end
152
-
153
206
  def render_edit_page(path)
154
207
  f = File.open(File.join(path_to_resources, "editPage.html"), "r")
155
208
  template = ""
@@ -170,6 +223,11 @@ class Solutus
170
223
 
171
224
  result[:title] = data["title"]
172
225
  result[:path] = path
226
+ link = path.split("/")[-1].split(".")[0]
227
+ if ["error", "index"].include?(link)
228
+ link = link + ".html"
229
+ end
230
+ result[:link] = link
173
231
  settings.global_settings.each do |key, val|
174
232
  result[key.to_sym] = val
175
233
  end
@@ -200,10 +258,19 @@ class Solutus
200
258
  data = YAML.load(file_contents)
201
259
 
202
260
  result[:title] = data["title"]
261
+ result[:date] = data["date"].strftime(BLOG_DATE_FORMAT)
203
262
  result[:markdown] = file_contents.split("---")[-1]
204
263
  result[:link] = url
205
264
  result[:canview] = url != "/"
206
265
  result[:path] = path
266
+ result[:subtitle] = data["subtitle"]
267
+ result.render
268
+ end
269
+
270
+ def render_login(message="")
271
+ ServerStache.template = File.read(File.join(path_to_resources, "login.html"))
272
+ result = ServerStache.new
273
+ result[:message] = message
207
274
  result.render
208
275
  end
209
276
 
@@ -286,7 +353,9 @@ class Solutus
286
353
  deploy
287
354
  else
288
355
  if args.length >= 2
289
- if args[0] == "create"
356
+ if args[0] == "password"
357
+ create_password(args[1])
358
+ elsif args[0] == "create"
290
359
  new_project(args[1])
291
360
  else
292
361
  if args.length >= 3
@@ -328,6 +397,9 @@ class Solutus
328
397
  def self.build
329
398
  puts "Solutus is building the static site"
330
399
  settings_data = load_settings
400
+ if settings_data == false
401
+ return
402
+ end
331
403
 
332
404
  if File.directory?(BUILD_PATH)
333
405
  FileUtils.remove_dir(BUILD_PATH)
@@ -367,6 +439,7 @@ class Solutus
367
439
  yaml_data[entry] = contents
368
440
  data = YAML.load(contents)
369
441
  date = data["date"]
442
+ subtitle = data.fetch("subtitle", "")
370
443
  relative_dir = File.join(date.year.to_s, date.month.to_s, date.day.to_s, entry.split(".")[0])
371
444
  year = date.year.to_s
372
445
  if !@@blog_urls.key?(year)
@@ -376,7 +449,8 @@ class Solutus
376
449
  "title" => data["title"],
377
450
  "url" => File.join(ARCHIVE, relative_dir),
378
451
  "file_path" => path,
379
- "date" => date
452
+ "date" => date,
453
+ "subtitle" => subtitle
380
454
  })
381
455
  end
382
456
 
@@ -385,7 +459,16 @@ class Solutus
385
459
  get_recents(recents_count).reverse.each do |post|
386
460
  url = post["url"]
387
461
  title = post["title"]
388
- recents += "<div class=\"solutus-recent-posts\"><a href=\"/#{url}\">#{title}</a></div>"
462
+ date = prettify_date(post["date"])
463
+ subtitle = post["subtitle"]
464
+
465
+ block = <<HERE
466
+ <div class="solutus-recents-block">
467
+ <a class="solutus-blog-thumbnail" href="/#{url}">#{title}</a> - #{date}
468
+ <div class="solutus-blog-subtitle"><i>#{subtitle}</i></div>
469
+ </div>
470
+ HERE
471
+ recents += block
389
472
  end
390
473
 
391
474
  yaml_data.each do |entry, contents|
@@ -457,12 +540,13 @@ class Solutus
457
540
  sorted.each do |hash|
458
541
  url = hash["url"]
459
542
  title = hash["title"]
460
- pretty_date = hash["date"].strftime("%b %e") +
461
- DAY_ENDINGS[hash["date"].strftime("%e").to_i]
462
- content += "<div class=\"solutus-blog-block\">"
463
- content += "<div class=\"solutus-blog-title\"><a href=\"/#{url}\">#{title}</a></div>"
464
- content += "<div>#{pretty_date}</div>"
465
- content += "</div>"
543
+ pretty_date = prettify_date(hash["date"])
544
+ content += "<div class=\"solutus-blog-block\">\n"
545
+ content += " <div class=\"solutus-blog-title\">\n"
546
+ content += " <a href=\"/#{url}\">#{title}</a>\n"
547
+ content += " </div>\n"
548
+ content += " <div>#{pretty_date}</div>\n"
549
+ content += "</div>\n"
466
550
  end
467
551
  end
468
552
  path = File.join(SITE_PATH, ARCHIVE, "index.html")
@@ -507,8 +591,17 @@ class Solutus
507
591
  end
508
592
 
509
593
  def self.new_page(title)
510
- file_title = title.gsub(/\s+/, "")
511
- path = File.join(SITE_PAGES_PATH, file_title + ".yml")
594
+ title = title.gsub(/\s+/, "").gsub(/[^a-zA-Z0-9\-]/, "").strip
595
+ if title.empty?
596
+ puts "Bad name"
597
+ return
598
+ end
599
+ if ["edit"].include?(title)
600
+ puts "Can't use #{title} as a page name."
601
+ return
602
+ end
603
+
604
+ path = File.join(SITE_PAGES_PATH, title + ".yml")
512
605
  if File.file?(path)
513
606
  puts "Page with that name already exists."
514
607
  return
@@ -531,7 +624,7 @@ HERE
531
624
 
532
625
  def self.new_post(title)
533
626
  i = 1
534
- new_title = title.gsub(/\s+/, "")
627
+ new_title = title.gsub(/\s+/, "").gsub(/[^a-zA-Z0-9\-]/, "").strip
535
628
  if title.empty?
536
629
  puts "Empty title"
537
630
  return ""
@@ -545,11 +638,12 @@ HERE
545
638
  break
546
639
  end
547
640
  end
548
- date = Time.now.strftime("%Y-%m-%e %I:%M:%S")
641
+ date = Time.now.strftime(BLOG_DATE_DATA)
549
642
  text = <<HERE
550
643
  ---
551
644
  title: #{title}
552
645
  date: #{date}
646
+ subtitle: Another new blog post
553
647
  ---
554
648
  *This is a temporary blog post page!*
555
649
  HERE
@@ -574,6 +668,10 @@ HERE
574
668
  end
575
669
  end
576
670
 
671
+ def self.prettify_date(date)
672
+ date.strftime("%b %e") + DAY_ENDINGS[date.strftime("%e").to_i]
673
+ end
674
+
577
675
  def self.get_recents(count)
578
676
  res = Array.new
579
677
  @@blog_urls.each do |yr, arr|
@@ -601,7 +699,23 @@ HERE
601
699
  result
602
700
  end
603
701
 
702
+ def self.create_password(password)
703
+ content = Digest::MD5.hexdigest password
704
+ if File.file?(PASSWORD_FILE)
705
+ FileUtils.rm(PASSWORD_FILE)
706
+ end
707
+ f = File.new(PASSWORD_FILE, "w")
708
+ f.write(content)
709
+ f.close
710
+ puts "Wrote password to password.txt"
711
+ end
712
+
604
713
  def self.new_project(name)
714
+ name = name.gsub(/[^a-zA-Z0-9\-]/, "").strip
715
+ if name == ""
716
+ puts "Invalid name"
717
+ return
718
+ end
605
719
  if File.directory?(name)
606
720
  puts "Invalid name, already a folder with that name"
607
721
  print "Overwrite? [Y/n]"
@@ -664,6 +778,8 @@ HERE
664
778
  {{{date}}}
665
779
  {{/blog}}
666
780
  {{{content}}}
781
+ <h3>Recent Posts</h3>
782
+ {{{recents}}}
667
783
  <small style="display: block; text-align: center;">&copy; {{year}} {{author}}</small>
668
784
  {{{watermark}}}
669
785
  </div>
@@ -672,9 +788,11 @@ HERE
672
788
  </html>
673
789
  HERE
674
790
 
791
+ datetime = Time.now.strftime(BLOG_DATE_DATA)
675
792
  test_file = <<HERE
676
793
  title: Example Blog Post
677
- date: 2018-05-10 03:43:20
794
+ date: #{datetime}
795
+ subtitle: an example post...
678
796
  ---
679
797
  *This is an example blog post page!*
680
798
  HERE
@@ -692,6 +810,7 @@ HERE
692
810
 
693
811
  files = {
694
812
  File.join(name, "settings.yml") => settings_file,
813
+ File.join(name, ".gitignore") => PASSWORD_FILE + "\n",
695
814
  File.join(name, "static", "css", "styles.css") => styles_file,
696
815
  File.join(name, "templates", "default.html") => default_file,
697
816
  File.join(name, "pages", "posts", "test.md") => test_file,
@@ -16,6 +16,14 @@
16
16
  h1, h2, h3 {
17
17
  line-height:1.2
18
18
  }
19
+
20
+ input[type=text] {
21
+ width: 500px;
22
+ }
23
+ a {
24
+ text-decoration: none;
25
+ color: #4286f4;
26
+ }
19
27
  </style>
20
28
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/simplemde/latest/simplemde.min.css">
21
29
  <script src="https://cdn.jsdelivr.net/simplemde/latest/simplemde.min.js"></script>
@@ -23,29 +31,51 @@
23
31
  </head>
24
32
 
25
33
  <body>
26
- <h1>Editing <span style="border: 1px solid gray" id="title-input" contenteditable>{{title}}</span></h1>
27
- ({{path}})
28
- <p><a href="/edit">Back to Edit</a></p>
29
- {{#canview}}
30
- <p><a href="{{link}}">View on Site</a></p>
31
- {{/canview}}
32
- <p><button id="solutus-save-button" type="submit">Save</button></p>
33
- <textarea id="solutus-mde">{{{markdown}}}</textarea>
34
+ <h1>Editing <span style="border: 1px dotted gray" id="title-input" contenteditable>{{title}}</span></h1>
35
+ <code>{{path}}</code> ({{date}})
36
+ <p>
37
+ [<a href="/edit">Back to Edit</a>]
38
+ {{#canview}}
39
+ [<a href="{{link}}">View on Site</a>]
40
+ {{/canview}}
41
+ </p>
42
+ <hr>
43
+ <p>
44
+ <button id="solutus-save-button" type="submit">Save</button>
45
+ <b><span id="solutus-status">Saved.</span></b>
46
+ </p>
47
+
48
+ <p>Subtitle: <input type="text" value="{{subtitle}}" placeholder="Subtitle text" id="solutus-subtitle-input"/></p>
34
49
 
50
+ <textarea id="solutus-mde">{{{markdown}}}</textarea>
51
+ <p style="text-align: center;">
52
+ <small>Powered by <a href="https://github.com/jeromew21/solutus">Solutus</a></small>
53
+ </p>
35
54
  <script>
36
55
  var simplemde = new SimpleMDE({ element: document.getElementById("solutus-mde") });
37
56
 
57
+ function updateStatus(status) {
58
+ $("#solutus-status").html(status);
59
+ }
60
+
38
61
  function save() {
62
+ updateStatus("Saving...")
39
63
  $.post("/savepost", {
40
64
  "path": "{{path}}",
41
65
  "title": $("#title-input").html(),
42
- "markdown": simplemde.value()
66
+ "markdown": simplemde.value(),
67
+ "subtitle": $("#solutus-subtitle-input").val()
43
68
  }, function(response) {
44
69
  console.log(response);
70
+ updateStatus("Saved.");
45
71
  });
46
72
  }
47
73
 
48
74
  $("#solutus-save-button").click(save);
75
+
76
+ $(document).keydown(function() {
77
+ updateStatus("Unsaved changes.")
78
+ })
49
79
  </script>
50
80
  </body>
51
81
  </html>
@@ -4,36 +4,53 @@
4
4
 
5
5
  <style type="text/css">
6
6
  #solutus-editmenu {
7
- width: 100%;
8
- margin: 0;
9
- padding: 15px;
7
+ font-family: "Segoe UI", sans-serif;
8
+ display: table-row;
10
9
  background-color: #eeeeee;
11
- font-family: sans-serif;
10
+ }
11
+
12
+ .solutus-edit-block {
13
+ display: table-cell;
14
+ padding: 8px 12px 8px 12px;
12
15
  }
13
16
  </style>
14
17
  {{{stylesheets}}}
15
18
  </head>
16
19
 
17
20
  <body>
18
- <div id="solutus-editmenu">
19
- <a href="/edit">Back to Edit</a> &nbsp;&nbsp;&nbsp;&nbsp;
20
- Editing <b>{{title}}</b> @ <code>{{path}}</code> &nbsp;&nbsp;&nbsp;&nbsp;
21
- <button id="solutus-save-button">Save</button>
21
+ <div style="display: table;">
22
+ <div id="solutus-editmenu">
23
+ <div class="solutus-edit-block"><a href="/edit">Back to Edit</a></div>
24
+ <div class="solutus-edit-block">Editing <a href="{{link}}"><b>{{title}}</b></a> @ <code>{{path}}</code></div>
25
+ <div class="solutus-edit-block"><button type="button" class="btn btn-primary" id="solutus-save-button">Save</button></div>
26
+ <div class="solutus-edit-block"><b><span id="solutus-status"></span></b></div>
27
+ </div>
22
28
  </div>
23
29
  {{{everything}}}
24
30
  {{{scripts}}}
25
31
  <script src="https://cdn.jsdelivr.net/npm/jquery@3.2.1/dist/jquery.min.js"></script>
26
32
  <script>
33
+ function updateStatus(status) {
34
+ $("#solutus-status").html(status);
35
+ }
36
+
27
37
  function save() {
38
+ updateStatus("Saving...")
28
39
  $.post("/savepage", {
29
40
  "path": "{{path}}",
30
41
  "content": $("#solutus-content").html()
31
42
  }, function(response) {
32
43
  console.log(response);
44
+ updateStatus("Saved.");
33
45
  });
34
46
  }
35
47
 
36
48
  $("#solutus-save-button").click(save);
49
+ $("#solutus-content").keydown(function() {
50
+ updateStatus("Unsaved changes.")
51
+ })
52
+
53
+ updateStatus("Saved.");
37
54
  </script>
38
55
  </body>
39
56
  </html>
data/resources/index.html CHANGED
@@ -16,12 +16,17 @@
16
16
  h1, h2, h3 {
17
17
  line-height:1.2
18
18
  }
19
+
20
+ a {
21
+ text-decoration: none;
22
+ color: #4286f4;
23
+ }
19
24
  </style>
20
25
  </head>
21
26
 
22
27
  <body>
23
28
  <h1>Editing {{name}}</h1>
24
- <p><a href="/">View Site</a></p>
29
+ <p>[<a href="/">View Site</a>]</p>
25
30
  <p>
26
31
  <form method="get" action="/editpage">
27
32
  <fieldset>
@@ -49,5 +54,8 @@
49
54
  </fieldset>
50
55
  </form>
51
56
  </p>
57
+ <p style="text-align: center;">
58
+ <small>Powered by <a href="https://github.com/jeromew21/solutus">Solutus</a></small>
59
+ </p>
52
60
  </body>
53
61
  </html>
@@ -0,0 +1,29 @@
1
+ <!DOCTYPE html>
2
+ <head>
3
+ <title>Log in to edit</title>
4
+ <style type="text/css">
5
+ body {
6
+ margin:40px auto;
7
+ background-color: #eeeeee;
8
+ max-width:650px;
9
+ line-height:1.6;
10
+ font-size:18px;
11
+ color:#444;
12
+ padding:0 10px;
13
+ font-family: "Segoe UI", sans-serif;
14
+ }
15
+
16
+ h1, h2, h3 {
17
+ line-height:1.2
18
+ }
19
+ </style>
20
+ </head>
21
+
22
+ <body>
23
+ <h1>Login</h1>
24
+ {{message}}
25
+ <form method="post" action="/login">
26
+ <p>Password: <input type="password" name="password" />
27
+ </form>
28
+ </body>
29
+ </html>
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: solutus
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jerome Wei
@@ -79,6 +79,7 @@ files:
79
79
  - resources/editBlog.html
80
80
  - resources/editPage.html
81
81
  - resources/index.html
82
+ - resources/login.html
82
83
  homepage: https://github.com/jeromew21/solutus
83
84
  licenses:
84
85
  - MIT