diff options
33 files changed, 471 insertions, 195 deletions
| diff --git a/Gemfile.lock b/Gemfile.lock index 6b672bc..e2e85e9 100644 --- a/Gemfile.lock +++ b/Gemfile.lock | |||
| @@ -1,111 +1,118 @@ | |||
| 1 | GEM | 1 | GEM |
| 2 | remote: https://rubygems.org/ | 2 | remote: https://rubygems.org/ |
| 3 | specs: | 3 | specs: |
| 4 | actioncable (7.1.1) | 4 | actioncable (7.1.5.1) |
| 5 | actionpack (= 7.1.1) | 5 | actionpack (= 7.1.5.1) |
| 6 | activesupport (= 7.1.1) | 6 | activesupport (= 7.1.5.1) |
| 7 | nio4r (~> 2.0) | 7 | nio4r (~> 2.0) |
| 8 | websocket-driver (>= 0.6.1) | 8 | websocket-driver (>= 0.6.1) |
| 9 | zeitwerk (~> 2.6) | 9 | zeitwerk (~> 2.6) |
| 10 | actionmailbox (7.1.1) | 10 | actionmailbox (7.1.5.1) |
| 11 | actionpack (= 7.1.1) | 11 | actionpack (= 7.1.5.1) |
| 12 | activejob (= 7.1.1) | 12 | activejob (= 7.1.5.1) |
| 13 | activerecord (= 7.1.1) | 13 | activerecord (= 7.1.5.1) |
| 14 | activestorage (= 7.1.1) | 14 | activestorage (= 7.1.5.1) |
| 15 | activesupport (= 7.1.1) | 15 | activesupport (= 7.1.5.1) |
| 16 | mail (>= 2.7.1) | 16 | mail (>= 2.7.1) |
| 17 | net-imap | 17 | net-imap |
| 18 | net-pop | 18 | net-pop |
| 19 | net-smtp | 19 | net-smtp |
| 20 | actionmailer (7.1.1) | 20 | actionmailer (7.1.5.1) |
| 21 | actionpack (= 7.1.1) | 21 | actionpack (= 7.1.5.1) |
| 22 | actionview (= 7.1.1) | 22 | actionview (= 7.1.5.1) |
| 23 | activejob (= 7.1.1) | 23 | activejob (= 7.1.5.1) |
| 24 | activesupport (= 7.1.1) | 24 | activesupport (= 7.1.5.1) |
| 25 | mail (~> 2.5, >= 2.5.4) | 25 | mail (~> 2.5, >= 2.5.4) |
| 26 | net-imap | 26 | net-imap |
| 27 | net-pop | 27 | net-pop |
| 28 | net-smtp | 28 | net-smtp |
| 29 | rails-dom-testing (~> 2.2) | 29 | rails-dom-testing (~> 2.2) |
| 30 | actionpack (7.1.1) | 30 | actionpack (7.1.5.1) |
| 31 | actionview (= 7.1.1) | 31 | actionview (= 7.1.5.1) |
| 32 | activesupport (= 7.1.1) | 32 | activesupport (= 7.1.5.1) |
| 33 | nokogiri (>= 1.8.5) | 33 | nokogiri (>= 1.8.5) |
| 34 | racc | ||
| 34 | rack (>= 2.2.4) | 35 | rack (>= 2.2.4) |
| 35 | rack-session (>= 1.0.1) | 36 | rack-session (>= 1.0.1) |
| 36 | rack-test (>= 0.6.3) | 37 | rack-test (>= 0.6.3) |
| 37 | rails-dom-testing (~> 2.2) | 38 | rails-dom-testing (~> 2.2) |
| 38 | rails-html-sanitizer (~> 1.6) | 39 | rails-html-sanitizer (~> 1.6) |
| 39 | actiontext (7.1.1) | 40 | actiontext (7.1.5.1) |
| 40 | actionpack (= 7.1.1) | 41 | actionpack (= 7.1.5.1) |
| 41 | activerecord (= 7.1.1) | 42 | activerecord (= 7.1.5.1) |
| 42 | activestorage (= 7.1.1) | 43 | activestorage (= 7.1.5.1) |
| 43 | activesupport (= 7.1.1) | 44 | activesupport (= 7.1.5.1) |
| 44 | globalid (>= 0.6.0) | 45 | globalid (>= 0.6.0) |
| 45 | nokogiri (>= 1.8.5) | 46 | nokogiri (>= 1.8.5) |
| 46 | actionview (7.1.1) | 47 | actionview (7.1.5.1) |
| 47 | activesupport (= 7.1.1) | 48 | activesupport (= 7.1.5.1) |
| 48 | builder (~> 3.1) | 49 | builder (~> 3.1) |
| 49 | erubi (~> 1.11) | 50 | erubi (~> 1.11) |
| 50 | rails-dom-testing (~> 2.2) | 51 | rails-dom-testing (~> 2.2) |
| 51 | rails-html-sanitizer (~> 1.6) | 52 | rails-html-sanitizer (~> 1.6) |
| 52 | active_storage_validations (1.1.1) | 53 | active_storage_validations (2.0.3) |
| 53 | activejob (>= 5.2.0) | 54 | activejob (>= 6.1.4) |
| 54 | activemodel (>= 5.2.0) | 55 | activemodel (>= 6.1.4) |
| 55 | activestorage (>= 5.2.0) | 56 | activestorage (>= 6.1.4) |
| 56 | activesupport (>= 5.2.0) | 57 | activesupport (>= 6.1.4) |
| 57 | activejob (7.1.1) | 58 | marcel (>= 1.0.3) |
| 58 | activesupport (= 7.1.1) | 59 | activejob (7.1.5.1) |
| 60 | activesupport (= 7.1.5.1) | ||
| 59 | globalid (>= 0.3.6) | 61 | globalid (>= 0.3.6) |
| 60 | activemodel (7.1.1) | 62 | activemodel (7.1.5.1) |
| 61 | activesupport (= 7.1.1) | 63 | activesupport (= 7.1.5.1) |
| 62 | activerecord (7.1.1) | 64 | activerecord (7.1.5.1) |
| 63 | activemodel (= 7.1.1) | 65 | activemodel (= 7.1.5.1) |
| 64 | activesupport (= 7.1.1) | 66 | activesupport (= 7.1.5.1) |
| 65 | timeout (>= 0.4.0) | 67 | timeout (>= 0.4.0) |
| 66 | activestorage (7.1.1) | 68 | activestorage (7.1.5.1) |
| 67 | actionpack (= 7.1.1) | 69 | actionpack (= 7.1.5.1) |
| 68 | activejob (= 7.1.1) | 70 | activejob (= 7.1.5.1) |
| 69 | activerecord (= 7.1.1) | 71 | activerecord (= 7.1.5.1) |
| 70 | activesupport (= 7.1.1) | 72 | activesupport (= 7.1.5.1) |
| 71 | marcel (~> 1.0) | 73 | marcel (~> 1.0) |
| 72 | activesupport (7.1.1) | 74 | activesupport (7.1.5.1) |
| 73 | base64 | 75 | base64 |
| 76 | benchmark (>= 0.3) | ||
| 74 | bigdecimal | 77 | bigdecimal |
| 75 | concurrent-ruby (~> 1.0, >= 1.0.2) | 78 | concurrent-ruby (~> 1.0, >= 1.0.2) |
| 76 | connection_pool (>= 2.2.5) | 79 | connection_pool (>= 2.2.5) |
| 77 | drb | 80 | drb |
| 78 | i18n (>= 1.6, < 2) | 81 | i18n (>= 1.6, < 2) |
| 82 | logger (>= 1.4.2) | ||
| 79 | minitest (>= 5.1) | 83 | minitest (>= 5.1) |
| 80 | mutex_m | 84 | mutex_m |
| 85 | securerandom (>= 0.3) | ||
| 81 | tzinfo (~> 2.0) | 86 | tzinfo (~> 2.0) |
| 82 | acts-as-taggable-on (10.0.0) | 87 | acts-as-taggable-on (12.0.0) |
| 83 | activerecord (>= 6.1, < 7.2) | 88 | activerecord (>= 7.1, < 8.1) |
| 84 | addressable (2.8.5) | 89 | zeitwerk (>= 2.4, < 3.0) |
| 85 | public_suffix (>= 2.0.2, < 6.0) | 90 | addressable (2.8.7) |
| 86 | airbrussh (1.5.0) | 91 | public_suffix (>= 2.0.2, < 7.0) |
| 92 | airbrussh (1.5.3) | ||
| 87 | sshkit (>= 1.6.1, != 1.7.0) | 93 | sshkit (>= 1.6.1, != 1.7.0) |
| 88 | akismet (3.0.0) | 94 | akismet (3.0.0) |
| 89 | audited (5.4.0) | 95 | audited (5.8.0) |
| 90 | activerecord (>= 5.0, < 7.2) | 96 | activerecord (>= 5.2, < 8.2) |
| 91 | request_store (~> 1.2) | 97 | activesupport (>= 5.2, < 8.2) |
| 92 | base64 (0.2.0) | 98 | base64 (0.2.0) |
| 93 | bcrypt (3.1.19) | 99 | bcrypt (3.1.20) |
| 94 | bcrypt_pbkdf (1.1.1) | 100 | bcrypt_pbkdf (1.1.1) |
| 95 | bigdecimal (3.1.4) | 101 | benchmark (0.4.0) |
| 102 | bigdecimal (3.1.9) | ||
| 96 | bindex (0.8.1) | 103 | bindex (0.8.1) |
| 97 | builder (3.2.4) | 104 | builder (3.3.0) |
| 98 | byebug (11.1.3) | 105 | byebug (12.0.0) |
| 99 | capistrano (3.18.0) | 106 | capistrano (3.19.2) |
| 100 | airbrussh (>= 1.0.0) | 107 | airbrussh (>= 1.0.0) |
| 101 | i18n | 108 | i18n |
| 102 | rake (>= 10.0.0) | 109 | rake (>= 10.0.0) |
| 103 | sshkit (>= 1.9.0) | 110 | sshkit (>= 1.9.0) |
| 104 | capistrano-bundler (2.1.0) | 111 | capistrano-bundler (2.1.1) |
| 105 | capistrano (~> 3.1) | 112 | capistrano (~> 3.1) |
| 106 | capistrano-passenger (0.2.1) | 113 | capistrano-passenger (0.2.1) |
| 107 | capistrano (~> 3.0) | 114 | capistrano (~> 3.0) |
| 108 | capistrano-rails (1.6.3) | 115 | capistrano-rails (1.7.0) |
| 109 | capistrano (~> 3.1) | 116 | capistrano (~> 3.1) |
| 110 | capistrano-bundler (>= 1.1, < 3) | 117 | capistrano-bundler (>= 1.1, < 3) |
| 111 | capistrano-rvm (0.1.2) | 118 | capistrano-rvm (0.1.2) |
| @@ -127,35 +134,35 @@ GEM | |||
| 127 | coffee-script-source | 134 | coffee-script-source |
| 128 | execjs | 135 | execjs |
| 129 | coffee-script-source (1.12.2) | 136 | coffee-script-source (1.12.2) |
| 130 | concurrent-ruby (1.2.2) | 137 | concurrent-ruby (1.3.5) |
| 131 | connection_pool (2.4.1) | 138 | connection_pool (2.5.3) |
| 132 | crass (1.0.6) | 139 | crass (1.0.6) |
| 133 | date (3.3.4) | 140 | date (3.4.1) |
| 134 | devise (4.9.3) | 141 | devise (4.9.4) |
| 135 | bcrypt (~> 3.0) | 142 | bcrypt (~> 3.0) |
| 136 | orm_adapter (~> 0.1) | 143 | orm_adapter (~> 0.1) |
| 137 | railties (>= 4.1.0) | 144 | railties (>= 4.1.0) |
| 138 | responders | 145 | responders |
| 139 | warden (~> 1.2.3) | 146 | warden (~> 1.2.3) |
| 140 | domain_name (0.6.20240107) | 147 | domain_name (0.6.20240107) |
| 141 | drb (2.2.0) | 148 | drb (2.2.1) |
| 142 | ruby2_keywords | 149 | ed25519 (1.4.0) |
| 143 | ed25519 (1.3.0) | 150 | enumerize (2.8.1) |
| 144 | enumerize (2.7.0) | ||
| 145 | activesupport (>= 3.2) | 151 | activesupport (>= 3.2) |
| 146 | erubi (1.12.0) | 152 | erubi (1.13.1) |
| 147 | execjs (2.9.1) | 153 | execjs (2.10.0) |
| 148 | ffi (1.16.3) | 154 | ffi (1.17.2) |
| 149 | ffi-compiler (1.3.2) | 155 | ffi-compiler (1.3.2) |
| 150 | ffi (>= 1.15.5) | 156 | ffi (>= 1.15.5) |
| 151 | rake | 157 | rake |
| 152 | globalid (1.2.1) | 158 | globalid (1.2.1) |
| 153 | activesupport (>= 6.1) | 159 | activesupport (>= 6.1) |
| 154 | haml (6.2.3) | 160 | haml (6.3.0) |
| 155 | temple (>= 0.8.2) | 161 | temple (>= 0.8.2) |
| 156 | thor | 162 | thor |
| 157 | tilt | 163 | tilt |
| 158 | highline (2.1.0) | 164 | highline (3.1.2) |
| 165 | reline | ||
| 159 | http (5.2.0) | 166 | http (5.2.0) |
| 160 | addressable (~> 2.8) | 167 | addressable (~> 2.8) |
| 161 | base64 (~> 0.1) | 168 | base64 (~> 0.1) |
| @@ -165,40 +172,43 @@ GEM | |||
| 165 | http-cookie (1.0.8) | 172 | http-cookie (1.0.8) |
| 166 | domain_name (~> 0.5) | 173 | domain_name (~> 0.5) |
| 167 | http-form_data (2.3.0) | 174 | http-form_data (2.3.0) |
| 168 | i18n (1.14.1) | 175 | i18n (1.14.7) |
| 169 | concurrent-ruby (~> 1.0) | 176 | concurrent-ruby (~> 1.0) |
| 170 | image_processing (1.12.2) | 177 | image_processing (1.14.0) |
| 171 | mini_magick (>= 4.9.5, < 5) | 178 | mini_magick (>= 4.9.5, < 6) |
| 172 | ruby-vips (>= 2.0.17, < 3) | 179 | ruby-vips (>= 2.0.17, < 3) |
| 173 | indieweb-endpoints (8.0.0) | 180 | indieweb-endpoints (9.1.0) |
| 174 | http (~> 5.0) | 181 | http (~> 5.2) |
| 175 | link-header-parser (~> 5.0) | 182 | link-header-parser (~> 6.1) |
| 176 | nokogiri (>= 1.13) | 183 | nokogiri (>= 1.13) |
| 177 | io-console (0.6.0) | 184 | io-console (0.8.0) |
| 178 | irb (1.8.3) | 185 | irb (1.15.2) |
| 179 | rdoc | 186 | pp (>= 0.6.0) |
| 180 | reline (>= 0.3.8) | 187 | rdoc (>= 4.0.0) |
| 181 | jbuilder (2.11.5) | 188 | reline (>= 0.4.2) |
| 189 | jbuilder (2.13.0) | ||
| 182 | actionview (>= 5.0.0) | 190 | actionview (>= 5.0.0) |
| 183 | activesupport (>= 5.0.0) | 191 | activesupport (>= 5.0.0) |
| 184 | jquery-rails (4.6.0) | 192 | jquery-rails (4.6.0) |
| 185 | rails-dom-testing (>= 1, < 3) | 193 | rails-dom-testing (>= 1, < 3) |
| 186 | railties (>= 4.2.0) | 194 | railties (>= 4.2.0) |
| 187 | thor (>= 0.14, < 2.0) | 195 | thor (>= 0.14, < 2.0) |
| 188 | jquery-ui-rails (6.0.1) | 196 | jquery-ui-rails (8.0.0) |
| 189 | railties (>= 3.2.16) | 197 | railties (>= 3.2.16) |
| 190 | js-routes (2.2.7) | 198 | js-routes (2.3.5) |
| 191 | railties (>= 4) | 199 | railties (>= 5) |
| 192 | json (2.9.0) | 200 | sorbet-runtime |
| 193 | libv8-node (18.16.0.0) | 201 | json (2.12.0) |
| 194 | link-header-parser (5.1.1) | 202 | libv8-node (23.6.1.0) |
| 203 | link-header-parser (6.1.1) | ||
| 195 | listen (3.0.8) | 204 | listen (3.0.8) |
| 196 | rb-fsevent (~> 0.9, >= 0.9.4) | 205 | rb-fsevent (~> 0.9, >= 0.9.4) |
| 197 | rb-inotify (~> 0.9, >= 0.9.7) | 206 | rb-inotify (~> 0.9, >= 0.9.7) |
| 198 | llhttp-ffi (0.5.0) | 207 | llhttp-ffi (0.5.1) |
| 199 | ffi-compiler (~> 1.0) | 208 | ffi-compiler (~> 1.0) |
| 200 | rake (~> 13.0) | 209 | rake (~> 13.0) |
| 201 | loofah (2.21.4) | 210 | logger (1.7.0) |
| 211 | loofah (2.24.1) | ||
| 202 | crass (~> 1.0.2) | 212 | crass (~> 1.0.2) |
| 203 | nokogiri (>= 1.12.0) | 213 | nokogiri (>= 1.12.0) |
| 204 | mail (2.8.1) | 214 | mail (2.8.1) |
| @@ -206,120 +216,128 @@ GEM | |||
| 206 | net-imap | 216 | net-imap |
| 207 | net-pop | 217 | net-pop |
| 208 | net-smtp | 218 | net-smtp |
| 209 | marcel (1.0.2) | 219 | marcel (1.0.4) |
| 210 | meta-tags (2.19.0) | 220 | meta-tags (2.22.1) |
| 211 | actionpack (>= 3.2.0, < 7.2) | 221 | actionpack (>= 6.0.0, < 8.1) |
| 212 | microformats (4.5.0) | 222 | microformats (4.5.0) |
| 213 | json | 223 | json |
| 214 | nokogiri | 224 | nokogiri |
| 215 | mime-types (3.5.1) | 225 | mime-types (3.7.0) |
| 216 | mime-types-data (~> 3.2015) | 226 | logger |
| 217 | mime-types-data (3.2023.1003) | 227 | mime-types-data (~> 3.2025, >= 3.2025.0507) |
| 228 | mime-types-data (3.2025.0507) | ||
| 218 | mimemagic (0.3.10) | 229 | mimemagic (0.3.10) |
| 219 | nokogiri (~> 1) | 230 | nokogiri (~> 1) |
| 220 | rake | 231 | rake |
| 221 | mini_magick (4.12.0) | 232 | mini_magick (5.2.0) |
| 233 | benchmark | ||
| 234 | logger | ||
| 222 | mini_mime (1.1.5) | 235 | mini_mime (1.1.5) |
| 223 | mini_portile2 (2.8.5) | 236 | mini_portile2 (2.8.9) |
| 224 | mini_racer (0.8.0) | 237 | mini_racer (0.18.1) |
| 225 | libv8-node (~> 18.16.0.0) | 238 | libv8-node (~> 23.6.1.0) |
| 226 | minitest (5.20.0) | 239 | minitest (5.25.5) |
| 227 | mutex_m (0.2.0) | 240 | mutex_m (0.3.0) |
| 228 | mysql2 (0.5.5) | 241 | mysql2 (0.5.6) |
| 229 | net-imap (0.4.4) | 242 | net-imap (0.5.8) |
| 230 | date | 243 | date |
| 231 | net-protocol | 244 | net-protocol |
| 232 | net-pop (0.1.2) | 245 | net-pop (0.1.2) |
| 233 | net-protocol | 246 | net-protocol |
| 234 | net-protocol (0.2.2) | 247 | net-protocol (0.2.2) |
| 235 | timeout | 248 | timeout |
| 236 | net-scp (4.0.0) | 249 | net-scp (4.1.0) |
| 237 | net-ssh (>= 2.6.5, < 8.0.0) | 250 | net-ssh (>= 2.6.5, < 8.0.0) |
| 238 | net-smtp (0.4.0) | 251 | net-sftp (4.0.0) |
| 252 | net-ssh (>= 5.0.0, < 8.0.0) | ||
| 253 | net-smtp (0.5.1) | ||
| 239 | net-protocol | 254 | net-protocol |
| 240 | net-ssh (7.2.0) | 255 | net-ssh (7.3.0) |
| 241 | nio4r (2.5.9) | 256 | nio4r (2.7.4) |
| 242 | nokogiri (1.15.4) | 257 | nokogiri (1.18.8) |
| 243 | mini_portile2 (~> 2.8.2) | 258 | mini_portile2 (~> 2.8.2) |
| 244 | racc (~> 1.4) | 259 | racc (~> 1.4) |
| 245 | normalize-rails (8.0.1) | 260 | normalize-rails (8.0.1) |
| 246 | orm_adapter (0.5.0) | 261 | orm_adapter (0.5.0) |
| 262 | ostruct (0.6.1) | ||
| 247 | paperclip (6.1.0) | 263 | paperclip (6.1.0) |
| 248 | activemodel (>= 4.2.0) | 264 | activemodel (>= 4.2.0) |
| 249 | activesupport (>= 4.2.0) | 265 | activesupport (>= 4.2.0) |
| 250 | mime-types | 266 | mime-types |
| 251 | mimemagic (~> 0.3.0) | 267 | mimemagic (~> 0.3.0) |
| 252 | terrapin (~> 0.6.0) | 268 | terrapin (~> 0.6.0) |
| 253 | psych (5.1.1.1) | 269 | pp (0.6.2) |
| 270 | prettyprint | ||
| 271 | prettyprint (0.2.0) | ||
| 272 | psych (5.2.6) | ||
| 273 | date | ||
| 254 | stringio | 274 | stringio |
| 255 | public_suffix (5.0.3) | 275 | public_suffix (6.0.2) |
| 256 | racc (1.7.3) | 276 | racc (1.8.1) |
| 257 | rack (2.2.8) | 277 | rack (2.2.14) |
| 258 | rack-session (1.0.1) | 278 | rack-session (1.0.2) |
| 259 | rack (< 3) | 279 | rack (< 3) |
| 260 | rack-test (2.1.0) | 280 | rack-test (2.2.0) |
| 261 | rack (>= 1.3) | 281 | rack (>= 1.3) |
| 262 | rackup (1.0.0) | 282 | rackup (1.0.1) |
| 263 | rack (< 3) | 283 | rack (< 3) |
| 264 | webrick | 284 | webrick |
| 265 | rails (7.1.1) | 285 | rails (7.1.5.1) |
| 266 | actioncable (= 7.1.1) | 286 | actioncable (= 7.1.5.1) |
| 267 | actionmailbox (= 7.1.1) | 287 | actionmailbox (= 7.1.5.1) |
| 268 | actionmailer (= 7.1.1) | 288 | actionmailer (= 7.1.5.1) |
| 269 | actionpack (= 7.1.1) | 289 | actionpack (= 7.1.5.1) |
| 270 | actiontext (= 7.1.1) | 290 | actiontext (= 7.1.5.1) |
| 271 | actionview (= 7.1.1) | 291 | actionview (= 7.1.5.1) |
| 272 | activejob (= 7.1.1) | 292 | activejob (= 7.1.5.1) |
| 273 | activemodel (= 7.1.1) | 293 | activemodel (= 7.1.5.1) |
| 274 | activerecord (= 7.1.1) | 294 | activerecord (= 7.1.5.1) |
| 275 | activestorage (= 7.1.1) | 295 | activestorage (= 7.1.5.1) |
| 276 | activesupport (= 7.1.1) | 296 | activesupport (= 7.1.5.1) |
| 277 | bundler (>= 1.15.0) | 297 | bundler (>= 1.15.0) |
| 278 | railties (= 7.1.1) | 298 | railties (= 7.1.5.1) |
| 279 | rails-dom-testing (2.2.0) | 299 | rails-dom-testing (2.2.0) |
| 280 | activesupport (>= 5.0.0) | 300 | activesupport (>= 5.0.0) |
| 281 | minitest | 301 | minitest |
| 282 | nokogiri (>= 1.6) | 302 | nokogiri (>= 1.6) |
| 283 | rails-html-sanitizer (1.6.0) | 303 | rails-html-sanitizer (1.6.2) |
| 284 | loofah (~> 2.21) | 304 | loofah (~> 2.21) |
| 285 | nokogiri (~> 1.14) | 305 | nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0) |
| 286 | rails_autolink (1.1.8) | 306 | rails_autolink (1.1.8) |
| 287 | actionview (> 3.1) | 307 | actionview (> 3.1) |
| 288 | activesupport (> 3.1) | 308 | activesupport (> 3.1) |
| 289 | railties (> 3.1) | 309 | railties (> 3.1) |
| 290 | railties (7.1.1) | 310 | railties (7.1.5.1) |
| 291 | actionpack (= 7.1.1) | 311 | actionpack (= 7.1.5.1) |
| 292 | activesupport (= 7.1.1) | 312 | activesupport (= 7.1.5.1) |
| 293 | irb | 313 | irb |
| 294 | rackup (>= 1.0.0) | 314 | rackup (>= 1.0.0) |
| 295 | rake (>= 12.2) | 315 | rake (>= 12.2) |
| 296 | thor (~> 1.0, >= 1.2.2) | 316 | thor (~> 1.0, >= 1.2.2) |
| 297 | zeitwerk (~> 2.6) | 317 | zeitwerk (~> 2.6) |
| 298 | rake (13.1.0) | 318 | rake (13.2.1) |
| 299 | ransack (4.3.0) | 319 | ransack (4.3.0) |
| 300 | activerecord (>= 6.1.5) | 320 | activerecord (>= 6.1.5) |
| 301 | activesupport (>= 6.1.5) | 321 | activesupport (>= 6.1.5) |
| 302 | i18n | 322 | i18n |
| 303 | rb-fsevent (0.11.2) | 323 | rb-fsevent (0.11.2) |
| 304 | rb-inotify (0.10.1) | 324 | rb-inotify (0.11.1) |
| 305 | ffi (~> 1.0) | 325 | ffi (~> 1.0) |
| 306 | rdoc (6.6.0) | 326 | rdoc (6.13.1) |
| 307 | psych (>= 4.0.0) | 327 | psych (>= 4.0.0) |
| 308 | recaptcha (5.19.0) | 328 | recaptcha (5.19.0) |
| 309 | redcarpet (3.6.0) | 329 | redcarpet (3.6.1) |
| 310 | reline (0.3.9) | 330 | reline (0.6.1) |
| 311 | io-console (~> 0.5) | 331 | io-console (~> 0.5) |
| 312 | request_store (1.5.1) | ||
| 313 | rack (>= 1.4) | ||
| 314 | responders (3.1.1) | 332 | responders (3.1.1) |
| 315 | actionpack (>= 5.2) | 333 | actionpack (>= 5.2) |
| 316 | railties (>= 5.2) | 334 | railties (>= 5.2) |
| 317 | rexml (3.2.6) | 335 | rexml (3.4.1) |
| 318 | rouge (4.2.0) | 336 | rouge (4.5.2) |
| 319 | ruby-vips (2.2.0) | 337 | ruby-vips (2.2.3) |
| 320 | ffi (~> 1.12) | 338 | ffi (~> 1.12) |
| 321 | ruby2_keywords (0.0.5) | 339 | logger |
| 322 | rubyzip (2.3.2) | 340 | rubyzip (2.4.1) |
| 323 | sassc (2.4.0) | 341 | sassc (2.4.0) |
| 324 | ffi (~> 1.9) | 342 | ffi (~> 1.9) |
| 325 | sassc-rails (2.1.2) | 343 | sassc-rails (2.1.2) |
| @@ -328,10 +346,14 @@ GEM | |||
| 328 | sprockets (> 3.0) | 346 | sprockets (> 3.0) |
| 329 | sprockets-rails | 347 | sprockets-rails |
| 330 | tilt | 348 | tilt |
| 331 | selenium-webdriver (4.14.0) | 349 | securerandom (0.4.1) |
| 350 | selenium-webdriver (4.32.0) | ||
| 351 | base64 (~> 0.2) | ||
| 352 | logger (~> 1.4) | ||
| 332 | rexml (~> 3.2, >= 3.2.5) | 353 | rexml (~> 3.2, >= 3.2.5) |
| 333 | rubyzip (>= 1.2.2, < 3.0) | 354 | rubyzip (>= 1.2.2, < 3.0) |
| 334 | websocket (~> 1.0) | 355 | websocket (~> 1.0) |
| 356 | sorbet-runtime (0.5.12087) | ||
| 335 | spring (2.1.1) | 357 | spring (2.1.1) |
| 336 | spring-watcher-listen (2.0.1) | 358 | spring-watcher-listen (2.0.1) |
| 337 | listen (>= 2.7, < 4.0) | 359 | listen (>= 2.7, < 4.0) |
| @@ -339,24 +361,28 @@ GEM | |||
| 339 | sprockets (3.7.2) | 361 | sprockets (3.7.2) |
| 340 | concurrent-ruby (~> 1.0) | 362 | concurrent-ruby (~> 1.0) |
| 341 | rack (> 1, < 3) | 363 | rack (> 1, < 3) |
| 342 | sprockets-rails (3.4.2) | 364 | sprockets-rails (3.5.2) |
| 343 | actionpack (>= 5.2) | 365 | actionpack (>= 6.1) |
| 344 | activesupport (>= 5.2) | 366 | activesupport (>= 6.1) |
| 345 | sprockets (>= 3.0.0) | 367 | sprockets (>= 3.0.0) |
| 346 | sqlite3 (1.6.7) | 368 | sqlite3 (2.6.0) |
| 347 | mini_portile2 (~> 2.8.0) | 369 | mini_portile2 (~> 2.8.0) |
| 348 | sshkit (1.21.5) | 370 | sshkit (1.24.0) |
| 371 | base64 | ||
| 372 | logger | ||
| 349 | net-scp (>= 1.1.2) | 373 | net-scp (>= 1.1.2) |
| 374 | net-sftp (>= 2.1.2) | ||
| 350 | net-ssh (>= 2.8.0) | 375 | net-ssh (>= 2.8.0) |
| 351 | stringio (3.0.8) | 376 | ostruct |
| 377 | stringio (3.1.7) | ||
| 352 | temple (0.10.3) | 378 | temple (0.10.3) |
| 353 | terrapin (0.6.0) | 379 | terrapin (0.6.0) |
| 354 | climate_control (>= 0.0.3, < 1.0) | 380 | climate_control (>= 0.0.3, < 1.0) |
| 355 | terser (1.1.19) | 381 | terser (1.1.20) |
| 356 | execjs (>= 0.3.0, < 3) | 382 | execjs (>= 0.3.0, < 3) |
| 357 | thor (1.3.0) | 383 | thor (1.3.2) |
| 358 | tilt (2.3.0) | 384 | tilt (2.6.0) |
| 359 | timeout (0.4.1) | 385 | timeout (0.4.3) |
| 360 | turbolinks (5.2.1) | 386 | turbolinks (5.2.1) |
| 361 | turbolinks-source (~> 5.2) | 387 | turbolinks-source (~> 5.2) |
| 362 | turbolinks-source (5.2.0) | 388 | turbolinks-source (5.2.0) |
| @@ -369,21 +395,22 @@ GEM | |||
| 369 | activemodel (>= 6.0.0) | 395 | activemodel (>= 6.0.0) |
| 370 | bindex (>= 0.4.0) | 396 | bindex (>= 0.4.0) |
| 371 | railties (>= 6.0.0) | 397 | railties (>= 6.0.0) |
| 372 | webmention (7.0.0) | 398 | webmention (8.0.0) |
| 373 | http (~> 5.0) | 399 | http (~> 5.2) |
| 374 | indieweb-endpoints (~> 8.0) | 400 | indieweb-endpoints (~> 9.0) |
| 375 | nokogiri (>= 1.13) | 401 | nokogiri (>= 1.16) |
| 376 | webrick (1.8.1) | 402 | webrick (1.9.1) |
| 377 | websocket (1.2.10) | 403 | websocket (1.2.11) |
| 378 | websocket-driver (0.7.6) | 404 | websocket-driver (0.7.7) |
| 405 | base64 | ||
| 379 | websocket-extensions (>= 0.1.0) | 406 | websocket-extensions (>= 0.1.0) |
| 380 | websocket-extensions (0.1.5) | 407 | websocket-extensions (0.1.5) |
| 381 | whenever (1.0.0) | 408 | whenever (1.0.0) |
| 382 | chronic (>= 0.6.3) | 409 | chronic (>= 0.6.3) |
| 383 | will_paginate (4.0.0) | 410 | will_paginate (4.0.1) |
| 384 | xpath (3.2.0) | 411 | xpath (3.2.0) |
| 385 | nokogiri (~> 1.8) | 412 | nokogiri (~> 1.8) |
| 386 | zeitwerk (2.6.12) | 413 | zeitwerk (2.7.2) |
| 387 | 414 | ||
| 388 | PLATFORMS | 415 | PLATFORMS |
| 389 | ruby | 416 | ruby |
| diff --git a/app/assets/stylesheets/main/entries.scss b/app/assets/stylesheets/main/entries.scss index 4afd15d..d67ae67 100644 --- a/app/assets/stylesheets/main/entries.scss +++ b/app/assets/stylesheets/main/entries.scss | |||
| @@ -153,7 +153,6 @@ | |||
| 153 | 153 | ||
| 154 | .update-posted { | 154 | .update-posted { |
| 155 | display: block; | 155 | display: block; |
| 156 | font-style: italic; | ||
| 157 | background-color: #EAADEA; | 156 | background-color: #EAADEA; |
| 158 | font-size: 16px; | 157 | font-size: 16px; |
| 159 | margin: .5em -20px; | 158 | margin: .5em -20px; |
| @@ -161,6 +160,16 @@ | |||
| 161 | border-width: 1px 0 1px 0; | 160 | border-width: 1px 0 1px 0; |
| 162 | border-style: solid; | 161 | border-style: solid; |
| 163 | border-color: #DB70DB; | 162 | border-color: #DB70DB; |
| 163 | |||
| 164 | time { | ||
| 165 | font-style: italic; | ||
| 166 | } | ||
| 167 | |||
| 168 | .update-edit-link { | ||
| 169 | float: right; | ||
| 170 | color: blue; | ||
| 171 | font-weight: normal; | ||
| 172 | } | ||
| 164 | } | 173 | } |
| 165 | } | 174 | } |
| 166 | } | 175 | } |
| @@ -463,3 +472,46 @@ | |||
| 463 | .next-post { | 472 | .next-post { |
| 464 | float: right; | 473 | float: right; |
| 465 | } | 474 | } |
| 475 | |||
| 476 | #streams-index { | ||
| 477 | width: 100%; | ||
| 478 | border-collapse: collapse; | ||
| 479 | |||
| 480 | #streams-index-header-row { | ||
| 481 | th { | ||
| 482 | background-color: #bdbdbd; | ||
| 483 | padding-left: 0.5em; | ||
| 484 | border-top: 1px solid #848484; | ||
| 485 | border-bottom: 1px solid #848484; | ||
| 486 | } | ||
| 487 | } | ||
| 488 | |||
| 489 | th { | ||
| 490 | padding-bottom: 0.5em; | ||
| 491 | padding-top: 0.5em; | ||
| 492 | text-align: left; | ||
| 493 | } | ||
| 494 | |||
| 495 | td { | ||
| 496 | padding-top: 1em; | ||
| 497 | padding-left: 0.5em; | ||
| 498 | |||
| 499 | time { | ||
| 500 | font-size: .75em; | ||
| 501 | } | ||
| 502 | |||
| 503 | .stream-link { | ||
| 504 | font-weight: bold; | ||
| 505 | text-decoration: none; | ||
| 506 | |||
| 507 | &, &:visited { | ||
| 508 | color: #ee2c2c; | ||
| 509 | } | ||
| 510 | |||
| 511 | &:hover { | ||
| 512 | text-decoration: underline; | ||
| 513 | color: #9ea1ad; | ||
| 514 | } | ||
| 515 | } | ||
| 516 | } | ||
| 517 | } | ||
| diff --git a/app/assets/stylesheets/main/layout.scss b/app/assets/stylesheets/main/layout.scss index ef31ada..d5fe7a7 100644 --- a/app/assets/stylesheets/main/layout.scss +++ b/app/assets/stylesheets/main/layout.scss | |||
| @@ -228,3 +228,14 @@ h2.centered { | |||
| 228 | text-decoration: none; | 228 | text-decoration: none; |
| 229 | } | 229 | } |
| 230 | } | 230 | } |
| 231 | |||
| 232 | #scrobble-box { | ||
| 233 | img { | ||
| 234 | margin: 0 auto; | ||
| 235 | display: block; | ||
| 236 | } | ||
| 237 | |||
| 238 | p { | ||
| 239 | text-align: center; | ||
| 240 | } | ||
| 241 | } | ||
| diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 0174cae..ad46fb9 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb | |||
| @@ -1,9 +1,19 @@ | |||
| 1 | class ApplicationController < ActionController::Base | 1 | class ApplicationController < ActionController::Base |
| 2 | protect_from_forgery with: :exception | 2 | protect_from_forgery with: :exception |
| 3 | before_action :choose_random_song | ||
| 3 | 4 | ||
| 4 | private | 5 | private |
| 5 | 6 | ||
| 6 | def after_sign_out_path_for(resource) | 7 | def after_sign_out_path_for(resource) |
| 7 | new_session_path(resource) | 8 | new_session_path(resource) |
| 8 | end | 9 | end |
| 10 | |||
| 11 | def choose_random_song | ||
| 12 | ids = Scrobble.ids | ||
| 13 | if ids.empty? | ||
| 14 | @random_song = nil | ||
| 15 | else | ||
| 16 | @random_song = Scrobble.find(ids.sample) | ||
| 17 | end | ||
| 18 | end | ||
| 9 | end | 19 | end |
| diff --git a/app/controllers/blogs_controller.rb b/app/controllers/blogs_controller.rb index 4f6d9ce..6e80754 100644 --- a/app/controllers/blogs_controller.rb +++ b/app/controllers/blogs_controller.rb | |||
| @@ -1,12 +1,7 @@ | |||
| 1 | require 'redcarpet/render_strip' | ||
| 2 | 1 | ||
| 3 | class StrippedSummary < Redcarpet::Render::StripDown | ||
| 4 | def block_html(raw_html) | ||
| 5 | nil | ||
| 6 | end | ||
| 7 | end | ||
| 8 | 2 | ||
| 9 | class BlogsController < ApplicationController | 3 | class BlogsController < ApplicationController |
| 4 | include ApplicationHelper | ||
| 10 | 5 | ||
| 11 | def summary | 6 | def summary |
| 12 | @blogs = Blog.where(published: true).order(published_at: :desc).paginate(page: params[:page], per_page: 10) | 7 | @blogs = Blog.where(published: true).order(published_at: :desc).paginate(page: params[:page], per_page: 10) |
| @@ -33,12 +28,12 @@ class BlogsController < ApplicationController | |||
| 33 | @prev = @blog.prev | 28 | @prev = @blog.prev |
| 34 | @next = @blog.next | 29 | @next = @blog.next |
| 35 | 30 | ||
| 36 | body = Redcarpet::Markdown.new(StrippedSummary).render(@blog.body) | 31 | body = stripped_markdown(@blog.body) |
| 37 | 32 | ||
| 38 | set_meta_tags(og: { | 33 | set_meta_tags(og: { |
| 39 | title: @blog.title, | 34 | title: @blog.title, |
| 40 | type: "article", | 35 | type: "article", |
| 41 | description: (body.length <= 300 ? body : body[0..299]), | 36 | description: body[0, 299], |
| 42 | url: blog_url(@blog, host: "www.fourisland.com"), | 37 | url: blog_url(@blog, host: "www.fourisland.com"), |
| 43 | article: { | 38 | article: { |
| 44 | published_time: @blog.published_at.iso8601, | 39 | published_time: @blog.published_at.iso8601, |
| diff --git a/app/controllers/streams_controller.rb b/app/controllers/streams_controller.rb index 664f533..ec4cee8 100644 --- a/app/controllers/streams_controller.rb +++ b/app/controllers/streams_controller.rb | |||
| @@ -1,7 +1,26 @@ | |||
| 1 | class StreamsController < ApplicationController | 1 | class StreamsController < ApplicationController |
| 2 | include ApplicationHelper | ||
| 3 | |||
| 4 | def index | ||
| 5 | @streams = Stream.order(latest_post_at: :desc).paginate(page: params[:page], per_page: 10) | ||
| 6 | end | ||
| 2 | 7 | ||
| 3 | def show | 8 | def show |
| 4 | @stream = Stream.find_by_slug(params[:slug]) | 9 | @stream = Stream.find_by_slug(params[:slug]) |
| 10 | @updates = @stream.updates.paginate(page: params[:page], per_page: 10) | ||
| 11 | |||
| 12 | body = stripped_markdown(@stream.body) | ||
| 13 | |||
| 14 | set_meta_tags(og: { | ||
| 15 | title: @stream.title, | ||
| 16 | type: "article", | ||
| 17 | description: body[0, 299], | ||
| 18 | url: stream_url(@stream, host: "www.fourisland.com"), | ||
| 19 | article: { | ||
| 20 | published_time: @stream.created_at.iso8601, | ||
| 21 | modified_time: @stream.latest_post_at.iso8601 | ||
| 22 | } | ||
| 23 | }) | ||
| 5 | end | 24 | end |
| 6 | 25 | ||
| 7 | end | 26 | end |
| diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 97a897f..a51f1a1 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb | |||
| @@ -1,6 +1,7 @@ | |||
| 1 | require 'redcarpet' | 1 | require 'redcarpet' |
| 2 | require 'rouge' | 2 | require 'rouge' |
| 3 | require 'rouge/plugins/redcarpet' | 3 | require 'rouge/plugins/redcarpet' |
| 4 | require 'redcarpet/render_strip' | ||
| 4 | 5 | ||
| 5 | module ApplicationHelper | 6 | module ApplicationHelper |
| 6 | 7 | ||
| @@ -45,4 +46,14 @@ module ApplicationHelper | |||
| 45 | ] | 46 | ] |
| 46 | end | 47 | end |
| 47 | 48 | ||
| 49 | class StrippedSummary < Redcarpet::Render::StripDown | ||
| 50 | def block_html(raw_html) | ||
| 51 | nil | ||
| 52 | end | ||
| 53 | end | ||
| 54 | |||
| 55 | def stripped_markdown(text) | ||
| 56 | Redcarpet::Markdown.new(StrippedSummary).render(text) | ||
| 57 | end | ||
| 58 | |||
| 48 | end | 59 | end |
| diff --git a/app/models/scrobble.rb b/app/models/scrobble.rb new file mode 100644 index 0000000..f527612 --- /dev/null +++ b/app/models/scrobble.rb | |||
| @@ -0,0 +1,2 @@ | |||
| 1 | class Scrobble < ApplicationRecord | ||
| 2 | end | ||
| diff --git a/app/models/stream.rb b/app/models/stream.rb index 0773143..6a738e2 100644 --- a/app/models/stream.rb +++ b/app/models/stream.rb | |||
| @@ -8,11 +8,22 @@ class Stream < ApplicationRecord | |||
| 8 | validates :title, presence: true | 8 | validates :title, presence: true |
| 9 | validates :slug, presence: true, format: /\A[-a-z0-9]+\z/ | 9 | validates :slug, presence: true, format: /\A[-a-z0-9]+\z/ |
| 10 | 10 | ||
| 11 | before_create :set_post_timestamp | ||
| 12 | |||
| 11 | def path | 13 | def path |
| 12 | "/thinks/#{slug}" | 14 | "/thinks/#{slug}" |
| 13 | end | 15 | end |
| 14 | 16 | ||
| 17 | def to_param | ||
| 18 | slug | ||
| 19 | end | ||
| 20 | |||
| 15 | def taggable | 21 | def taggable |
| 16 | self | 22 | self |
| 17 | end | 23 | end |
| 24 | |||
| 25 | private | ||
| 26 | def set_post_timestamp | ||
| 27 | self.latest_post_at = self.created_at | ||
| 28 | end | ||
| 18 | end | 29 | end |
| diff --git a/app/models/update.rb b/app/models/update.rb index 01907d8..a98a5d4 100644 --- a/app/models/update.rb +++ b/app/models/update.rb | |||
| @@ -5,6 +5,8 @@ class Update < ApplicationRecord | |||
| 5 | 5 | ||
| 6 | validates :stream, :body, presence: true | 6 | validates :stream, :body, presence: true |
| 7 | 7 | ||
| 8 | after_create :set_latest_timestamp | ||
| 9 | |||
| 8 | def path | 10 | def path |
| 9 | "/thinks/#{stream.slug}\#update-#{id}" | 11 | "/thinks/#{stream.slug}\#update-#{id}" |
| 10 | end | 12 | end |
| @@ -12,4 +14,10 @@ class Update < ApplicationRecord | |||
| 12 | def taggable | 14 | def taggable |
| 13 | stream | 15 | stream |
| 14 | end | 16 | end |
| 17 | |||
| 18 | private | ||
| 19 | def set_latest_timestamp | ||
| 20 | self.stream.latest_post_at = self.created_at | ||
| 21 | self.stream.save! | ||
| 22 | end | ||
| 15 | end | 23 | end |
| diff --git a/app/views/admin/streams/edit.html.haml b/app/views/admin/streams/edit.html.haml index 8d910fe..8c250e2 100644 --- a/app/views/admin/streams/edit.html.haml +++ b/app/views/admin/streams/edit.html.haml | |||
| @@ -1,3 +1,3 @@ | |||
| 1 | - title "Editing #{@stream.title}" | 1 | - title "Editing #{@stream.title}" |
| 2 | = form_for @stream, url: admin_stream_url(@stream), html: { id: "entry-form" } do |f| | 2 | = form_for @stream, url: admin_stream_url(@stream.id), html: { id: "entry-form" } do |f| |
| 3 | = render partial: "form", locals: { f: f } | 3 | = render partial: "form", locals: { f: f } |
| diff --git a/app/views/admin/streams/index.html.haml b/app/views/admin/streams/index.html.haml index 6903fd1..a2a25d7 100644 --- a/app/views/admin/streams/index.html.haml +++ b/app/views/admin/streams/index.html.haml | |||
| @@ -10,5 +10,5 @@ | |||
| 10 | %td= stream.created_at.strftime("%B %d, %Y, %l:%M%P") | 10 | %td= stream.created_at.strftime("%B %d, %Y, %l:%M%P") |
| 11 | %td | 11 | %td |
| 12 | %ul.admin-actions | 12 | %ul.admin-actions |
| 13 | %li= link_to "Edit", edit_admin_stream_url(stream) | 13 | %li= link_to "Edit", edit_admin_stream_url(stream.id) |
| 14 | %li= link_to "Add Update", new_admin_stream_update_url(stream) | 14 | %li= link_to "Add Update", new_admin_stream_update_url(stream.id) |
| diff --git a/app/views/admin/updates/edit.html.haml b/app/views/admin/updates/edit.html.haml index 75a9957..3cab0b6 100644 --- a/app/views/admin/updates/edit.html.haml +++ b/app/views/admin/updates/edit.html.haml | |||
| @@ -1,3 +1,3 @@ | |||
| 1 | - title "Editing stream update" | 1 | - title "Editing stream update" |
| 2 | = form_for @update, url: admin_stream_update_url(@stream, @update), html: { id: "entry-form" } do |f| | 2 | = form_for @update, url: admin_stream_update_url(@stream.id, @update), html: { id: "entry-form" } do |f| |
| 3 | = render partial: "form", locals: { f: f } | 3 | = render partial: "form", locals: { f: f } |
| diff --git a/app/views/blogs/_blog.html.haml b/app/views/blogs/_blog.html.haml index 878b1a2..34b343f 100644 --- a/app/views/blogs/_blog.html.haml +++ b/app/views/blogs/_blog.html.haml | |||
| @@ -24,5 +24,5 @@ | |||
| 24 | %time.dt-published{ datetime: blog.visible_date.strftime("%Y-%m-%dT%H:%M:%SZ%z") }= blog.visible_date.strftime("%B #{blog.visible_date.day.ordinalize}, %Y at %-I:%M:%S%P") | 24 | %time.dt-published{ datetime: blog.visible_date.strftime("%Y-%m-%dT%H:%M:%SZ%z") }= blog.visible_date.strftime("%B #{blog.visible_date.day.ordinalize}, %Y at %-I:%M:%S%P") |
| 25 | .post-vote{ id: "blog-vote-section-#{blog.id}" } | 25 | .post-vote{ id: "blog-vote-section-#{blog.id}" } |
| 26 | %span.vote-link{ id: "blog-upvote-link-#{blog.id}" }= link_to_unless (not blog.published or blog.already_upvoted?(request.remote_ip)), "👍", upvote_blog_path(blog), remote: true, rel: "nofollow", class: "blog-upvote-link", method: :post | 26 | %span.vote-link{ id: "blog-upvote-link-#{blog.id}" }= link_to_unless (not blog.published or blog.already_upvoted?(request.remote_ip)), "👍", upvote_blog_path(blog), remote: true, rel: "nofollow", class: "blog-upvote-link", method: :post |
| 27 | %span.post-rating{ id: "blog-rating-#{blog.id}" }= blog.upvotes - blog.downvotes | 27 | %span.post-rating{ id: "blog-rating-#{blog.id}" }= blog.upvotes |
| 28 | %span.vote-link{ id: "blog-downvote-link-#{blog.id}" }= link_to_unless (not blog.published or blog.already_downvoted?(request.remote_ip)), "👎", downvote_blog_path(blog), remote: true, rel: "nofollow", class: "blog-downvote-link", method: :post | 28 | %span.vote-link{ id: "blog-downvote-link-#{blog.id}" }= link_to_unless (not blog.published or blog.already_downvoted?(request.remote_ip)), "👎", downvote_blog_path(blog), remote: true, rel: "nofollow", class: "blog-downvote-link", method: :post |
| diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml index 1d0bea3..6bc7041 100644 --- a/app/views/layouts/application.html.haml +++ b/app/views/layouts/application.html.haml | |||
| @@ -73,6 +73,16 @@ | |||
| 73 | %li | 73 | %li |
| 74 | = image_tag "feed.png" | 74 | = image_tag "feed.png" |
| 75 | = link_to "Atom feed", blogs_url(format: :atom) | 75 | = link_to "Atom feed", blogs_url(format: :atom) |
| 76 | - unless @random_song.nil? | ||
| 77 | .sidebar-module#scrobble-box | ||
| 78 | .bubble.rounded | ||
| 79 | %h2 Listening to | ||
| 80 | = image_tag @random_song.image, width: "174px" | ||
| 81 | %p | ||
| 82 | %strong= @random_song.title | ||
| 83 | by | ||
| 84 | = @random_song.artist | ||
| 85 | %p= @random_song.album | ||
| 76 | .sidebar-module | 86 | .sidebar-module |
| 77 | .bubble.rounded | 87 | .bubble.rounded |
| 78 | %h2 Meta | 88 | %h2 Meta |
| diff --git a/app/views/layouts/quotes.html.haml b/app/views/layouts/quotes.html.haml index 4a7681e..040fdfe 100644 --- a/app/views/layouts/quotes.html.haml +++ b/app/views/layouts/quotes.html.haml | |||
| @@ -21,11 +21,12 @@ | |||
| 21 | %li= link_to_unless_current "Home", quotes_url | 21 | %li= link_to_unless_current "Home", quotes_url |
| 22 | %li= link_to_unless_current "Latest", latest_quotes_url | 22 | %li= link_to_unless_current "Latest", latest_quotes_url |
| 23 | %li= link_to_unless_current "Top", top_quotes_url | 23 | %li= link_to_unless_current "Top", top_quotes_url |
| 24 | %li= link_to "Random", random_quotes_url | 24 | %li{"data-turbolinks" => "false"}= link_to "Random", random_quotes_url |
| 25 | - if user_signed_in? | 25 | - if user_signed_in? |
| 26 | %li= link_to_unless_current "Submit", new_quote_url | 26 | %li= link_to_unless_current "Submit", new_quote_url |
| 27 | %li= link_to_unless_current "Tags", tags_quotes_url | 27 | %li= link_to_unless_current "Tags", tags_quotes_url |
| 28 | %li= link_to_unless_current "Stats", stats_quotes_url | 28 | %li= link_to_unless_current "Search", search_form_quotes_url |
| 29 | %li{"data-turbolinks" => "false"}= link_to_unless_current "Stats", stats_quotes_url | ||
| 29 | %li= link_to_unless_current "Feed", latest_quotes_url(:atom) | 30 | %li= link_to_unless_current "Feed", latest_quotes_url(:atom) |
| 30 | - if user_signed_in? | 31 | - if user_signed_in? |
| 31 | %li= link_to_unless_current "Admin", admin_url | 32 | %li= link_to_unless_current "Admin", admin_url |
| diff --git a/app/views/streams/_stream.html.haml b/app/views/streams/_stream.html.haml index 84a6478..97d4813 100644 --- a/app/views/streams/_stream.html.haml +++ b/app/views/streams/_stream.html.haml | |||
| @@ -1,6 +1,8 @@ | |||
| 1 | %article#stream-post | 1 | %article#stream-post |
| 2 | %h2#stream-title= stream.title | 2 | %h2#stream-title= stream.title |
| 3 | - unless stream.body.blank? | 3 | - unless stream.body.blank? |
| 4 | %header#stream-intro.entry-content= stream.body.html_safe | 4 | %header#stream-intro.entry-content= markdown(stream.body) |
| 5 | - unless stream.updates.empty? | 5 | = will_paginate @updates |
| 6 | = render stream.updates | 6 | - unless @updates.empty? |
| 7 | = render @updates | ||
| 8 | = will_paginate @updates | ||
| diff --git a/app/views/streams/index.html.haml b/app/views/streams/index.html.haml new file mode 100644 index 0000000..bf5073f --- /dev/null +++ b/app/views/streams/index.html.haml | |||
| @@ -0,0 +1,19 @@ | |||
| 1 | %table#streams-index | ||
| 2 | %tr#streams-index-header-row | ||
| 3 | %th Stream Topic | ||
| 4 | %th Updates | ||
| 5 | %th Last Post | ||
| 6 | - @streams.each do |stream| | ||
| 7 | %tr | ||
| 8 | %td | ||
| 9 | = link_to stream.title, stream, class: "stream-link" | ||
| 10 | %br | ||
| 11 | %time= stream.created_at.strftime("%B #{stream.created_at.day.ordinalize}, %Y at %-I:%M:%S%P") | ||
| 12 | %td= stream.updates.size | ||
| 13 | %td | ||
| 14 | - unless stream.updates.empty? | ||
| 15 | - latest_post = stream.updates.order(created_at: :desc).first | ||
| 16 | = link_to (stripped_markdown(latest_post.body)[0, 30] + "..."), stream | ||
| 17 | %br | ||
| 18 | %time= latest_post.created_at.strftime("%B #{latest_post.created_at.day.ordinalize}, %Y at %-I:%M:%S%P") | ||
| 19 | = will_paginate @streams | ||
| diff --git a/app/views/streams/show.html.haml b/app/views/streams/show.html.haml index 8365556..8d58f62 100644 --- a/app/views/streams/show.html.haml +++ b/app/views/streams/show.html.haml | |||
| @@ -1,3 +1,3 @@ | |||
| 1 | - title @stream.title | 1 | - title @stream.title |
| 2 | .breadcrumb= link_to "← Back to home page", root_path | 2 | .breadcrumb= link_to "← Back to streams", streams_path |
| 3 | = render @stream | 3 | = render @stream |
| diff --git a/app/views/updates/_update.html.haml b/app/views/updates/_update.html.haml index 57f4158..ceb7d8f 100644 --- a/app/views/updates/_update.html.haml +++ b/app/views/updates/_update.html.haml | |||
| @@ -1,3 +1,6 @@ | |||
| 1 | %section.stream-update.entry-content{ id: "update-#{update.id}" } | 1 | %section.stream-update.entry-content{ id: "update-#{update.id}" } |
| 2 | %time.update-posted= update.created_at.strftime("%B #{update.created_at.day.ordinalize}, %Y at %-I:%M:%S%P") | 2 | %header.update-posted |
| 3 | = update.body.html_safe | 3 | %time= update.created_at.strftime("%B #{update.created_at.day.ordinalize}, %Y at %-I:%M:%S%P") |
| 4 | - if user_signed_in? and !update.new_record? | ||
| 5 | = link_to "Edit", edit_admin_stream_update_path(update.stream.id, update), :class => "update-edit-link" | ||
| 6 | = markdown(update.body) | ||
| diff --git a/config/credentials.yml.enc b/config/credentials.yml.enc index cd9cac5..e08912f 100644 --- a/config/credentials.yml.enc +++ b/config/credentials.yml.enc | |||
| @@ -1 +1 @@ | |||
| TMbFARKxiuopoIWE/n0a8KMCh28dFjTGFpfXoXHUQmDlVhA40doz/aLWCYDE00djC70eM4BwXZmaDFC7tly1miU0OymvYijYKNb5Kv9bu2rihSprleyjnBrCF4qykWpDh8XfzXGfiDegSuZzw5RUGKkEU+EGJNIPTnPKAm2MSSnPStVFt1gGxGuYRd0pXCgFUW/USVYnbJEPv6DOxqh3HmKmneP29fcx1V+N/RccyzHsjL2S5lej5s8Q4oAy+SZ4+xLK9Pdh6nA3dZ82fNTLffqmnFxEovuW5n6Cjt0Ka2MZRvYg6sBNDvUVvQSw4u1BRXx7JOHcIWiKdykF/uHdrSwmIPepwd+zs/HCxrthdMSry+yrLwJpZ67JiMA/VKIMYzgLy8yk2JEblBXq3FGo44TWwumIkfTn4H/6UZNb4jGJ4dH+LAFiE7il2X3BbvBb4EkYB3xbu+zqvnohOzuVKkJtjILV6RBrEFzbCijwi3PBOoX8O9fwW8B0BduSp4AhFa+dyenOkD2HjtyEMttJAPuuw3neQKhkv/4SaPaugcD4vKONSwU3F/7nB7yMVQqofVLIc2a1tJaTjWIlNIwVssZS2HS5OZFTpv1XJpCyMcLO/EAe9poqiPieE8WwpdXntRs9O/QQqPWyt2ZdHD8RMKerZjbU1wV58h4rJmmAKUkTCuo=--Jo9AwrM/hr9nWWoS--iHpkNsZwBWB0lySmzkcLdA== \ No newline at end of file | MTHDW1ZOa9otC2lb9iG3bKlhzM8WgEoJddmcsv22b7TEv+ZxlnjBvql1MGJjfo+tNl9dT4gqUOH41Q2WfRhwIokibD6cLMKl8z3VPLHdARR3HW4OzEJoLYXYB5ycLtSFmL3jq/TkMBkctRvPo7jeGGBwtEHvh1tBx6cGr/fEvzWMKYMUPiugaMN3OPExZ5VaD1sCHTMm7erwP06+8KTABwGfF6quthHctj/39RusmAWaObVsUwm70nqij+/qekJEZS3xYEuCDZlKqQvwC7Z+qJlmO8vj8CYNFq80bD9MiuEL0kiTVp22ZyMj2TY6YXy2jabkVx5c7FVytx/+kbaNdGtLYqvvuqDXodcai18OWUhR3r+tzPqcinggWmzZeJ0O54dE7Srpe3wGFH3xmgXHRa1jczmCDwlGRTqmjX7E6CBiP7u5NAKLeALvADWGocJwUi0r8r6E3/a8rpsaL97JCjL1GNCDlRSAapqHafzszDWN31yG5mLc9OUoE2RJjU7bgohrhoAPyHpetRxO7fBpZ0quNAh1awiTXVTcNUlDT+UPkQi1mvQo47G3CM9OG8hlgKtfkMMKsl9D92k/g7zIyJzLsPKqYnxHj+qcnU0939xJ0x4MnUPam1oq7OF2FtBgU/OCDxMuM//qSI2Q4+RRKRHs/NLdADxRgO3WJZ+oe2r9YBfTYTlbdOEKmCxSrQMzpB/1jq0jSTRYynn/GO0Z1Pjx0wVzH8vjVosXfh6/PaKslMdHbOM=--A5y7uJSVaL0539+f--FP9Oigql2/EdcYszZ6hj/A== \ No newline at end of file | ||
| diff --git a/config/credentials/production.yml.enc b/config/credentials/production.yml.enc index af415a7..6359cc9 100644 --- a/config/credentials/production.yml.enc +++ b/config/credentials/production.yml.enc | |||
| @@ -1 +1 @@ | |||
| V//BL1LV+HIfxWVXgfAHG5TrUakYlbjN5V3gkDi9StysvSQ0rM3Opo2/Vt0KbU4FHhjiHoGAOZRPdf08j5k3zS3i4YroBfR3HwOj7snvq2mdBleL9D1UqkBLldjdaco1MnSLSfS2yJe8F3VhtVxesz/Sh4LXoZWemsWGJLu0GfRxPDwswTvdWBgyASnKUOlFyQNypgRTWGMqCe99Z5pw8co8JqZho29Dk6Tp7UJzoim8j5YU+tfgBZ4GF81c0eT8SvBJhHHbcTm/DPUMGxvUJAT9adjQnjPq0tferHziTGl54/ROQCXqrJHKLUOH5JRqh2lAkY3EK3SvTezuYSoV0MwsOxntxC54bQYznN5Dz6/I31UbWpydPGY8P+/Sjdh4QInD51VcDeuJ/QaDSeqJFxHUWDJ0Da55rwsZFr6jmpgbqcmunXLl2B+VDH7sSQOn71IEyNikq5l/9m2dYEdXZpWFsujkyVXzg4O5WFkLtmqoe4wudN7kk8nEZffd6xPtKNpl51Ml1BpSoNMNwGAf72Xxq5/5Z9QFK7mtyPhBVYqalR0kEZPbxmeZGmedcE/fgQXlZYNw4tzBy2/24hJokMLRoX5prmOGMf+6f62wEbBozyaDU2eAMC0HCwg/rb22hDPvzs1XKu2TTEGK7iT3BvdsUHIVnHdUd//hLEeNHeI43FLxPKgyaG7Ovnn8DmNrvUuapaFHjykVsQ2GOLQ9a7GGrwObqr0w33HG/UAwhzEE8s9KwF6qMdqPCCPuYOsbj5xgTyv5X5s0oIgCinvkfAIyFV7WXwLbbE9yxc6UumXbLLTSQE2s8mZ2yL+gdE+iYkSOhz8Z3bj9agOQD5zHMu/NxzTdpNwH6rsLLXq5EfToIWNXEl9kTU8=--x7Ic40D296IOMLm6--VBDaN0LLlyO8zeyfWW+UBA== \ No newline at end of file | uzTsEcFmu5QyOod1jjNQT8pqdQ9Tq8+OuH5qOulURR+Ew3+DBAN9/kYZ0b5OBcxnNGlN3suMC6fpgev4fYoaucCufXgNVAhhl1Lch9SJ2jo/1jCIS1U6mTPmwbF1aWM/P7jJhw8535RdlzohVStrIO0Rn3ygshVFFPODSccqyIhDbiiK5j0bvErzt5fDN091SIB0pdtxzy/XBwwfcQ6EaTg170Pv1mmIyCSWD1AGyzGlRhFVYhyv3sEabsC1dfYXjyZYrpbhvfZbi46TzeNA4kPLIVfVNiW0QoJtT90UqpOLcnQKwf23WIxPemzsT9iQj0/pEci+umHG6MkH2zE1eBOlj2VdopBqVEwQEgDvqt6zQMKAbLPU1E3VM94gCxeTidwIMoFGhSXl6nlGwI9ozBXvKyFNgMiz9UKtjEXcQOG3cIBxxMEQ+sjGEu3vAMvD7OymSGSC81JCbcdOqHWH/iIh2K3IcGyibJ4ScVsUBMn7lnsMEPrQQEJ/Df0X2mplJc0i8n19H1S7SrLKSaO7FDENPC0d1dN5nnOt5nDGU2/qkiGJ+LepX/Gb3cxc0fpcnC359rB5WCTKsxBOzjqW5IapCRSa0ztZz+xeXUBN4sDRUzPun2yCqaCxe+ptzTxzT+Ej9oMKSJJncc/zUuwRmd6KbnyQ3/ISeNNIC0BLWaohaj3lP/tRkLkcBNqu/MA4pxUxs1Lwu/8gW9d4GrrxCxOSsQnDk5VzF80LCk4oq+BVrjPYY0vWzVxtj+56slIoUIBIUWRjFTbBuyr3gejPjis5NwiFMyi8emH+a9aa3Ge44YnrDSAA+JVzqHSAF8erIuiqgaTAFwprSmED8pIIV2A0/WWrPcuI5xaAv4e2bQWfzM3SujvY--rs7RvQb911E+dh50--fCsEmvYD6LcaB6ReBcHGrA== \ No newline at end of file | ||
| diff --git a/config/deploy.rb b/config/deploy.rb index f28894f..de297e3 100644 --- a/config/deploy.rb +++ b/config/deploy.rb | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | # config valid only for current version of Capistrano | 1 | # config valid only for current version of Capistrano |
| 2 | lock "3.18.0" | 2 | lock "3.19.2" |
| 3 | 3 | ||
| 4 | set :application, "thoughts" | 4 | set :application, "thoughts" |
| 5 | set :repo_url, "/srv/git/thoughts" | 5 | set :repo_url, "/srv/git/thoughts" |
| diff --git a/config/mail.yml b/config/mail.yml index e2d15c3..6c0435d 100644 --- a/config/mail.yml +++ b/config/mail.yml | |||
| @@ -1,8 +1,8 @@ | |||
| 1 | production: | 1 | production: |
| 2 | smtp_settings: | 2 | smtp_settings: |
| 3 | address: "smtp.sendgrid.com" | 3 | address: "mail.smtp2go.com" |
| 4 | port: 587 | 4 | port: 2525 |
| 5 | user_name: "apikey" | 5 | user_name: "fourisland.com" |
| 6 | password: <%= Rails.application.credentials.sendgrid_api_key %> | 6 | password: <%= Rails.application.credentials.smtp2go_password %> |
| 7 | authentication: "plain" | 7 | authentication: "plain" |
| 8 | openssl_verify_mode: "none" | 8 | openssl_verify_mode: "none" |
| diff --git a/config/routes.rb b/config/routes.rb index 9e62ebb..ad66501 100644 --- a/config/routes.rb +++ b/config/routes.rb | |||
| @@ -56,6 +56,7 @@ Rails.application.routes.draw do | |||
| 56 | end | 56 | end |
| 57 | end | 57 | end |
| 58 | 58 | ||
| 59 | get 'thinks', to: 'streams#index', as: :streams | ||
| 59 | get 'thinks/:slug', to: 'streams#show', as: :stream | 60 | get 'thinks/:slug', to: 'streams#show', as: :stream |
| 60 | 61 | ||
| 61 | get 'plays', to: 'games#index' | 62 | get 'plays', to: 'games#index' |
| diff --git a/config/schedule.rb b/config/schedule.rb index e53ebf4..268dfcb 100644 --- a/config/schedule.rb +++ b/config/schedule.rb | |||
| @@ -21,3 +21,7 @@ | |||
| 21 | every 1.day, at: "6:00am" do | 21 | every 1.day, at: "6:00am" do |
| 22 | rake "thoughts:email_upvote_report" | 22 | rake "thoughts:email_upvote_report" |
| 23 | end | 23 | end |
| 24 | |||
| 25 | every 6.hours do | ||
| 26 | rake "thoughts:refresh_scrobbles" | ||
| 27 | end | ||
| diff --git a/db/migrate/20250512181245_add_latest_post_at_to_stream.rb b/db/migrate/20250512181245_add_latest_post_at_to_stream.rb new file mode 100644 index 0000000..9d753e3 --- /dev/null +++ b/db/migrate/20250512181245_add_latest_post_at_to_stream.rb | |||
| @@ -0,0 +1,21 @@ | |||
| 1 | class AddLatestPostAtToStream < ActiveRecord::Migration[7.1] | ||
| 2 | def up | ||
| 3 | add_column :streams, :latest_post_at, :datetime | ||
| 4 | |||
| 5 | Stream.all.each do |stream| | ||
| 6 | if stream.updates.empty? | ||
| 7 | stream.latest_post_at = stream.created_at | ||
| 8 | else | ||
| 9 | stream.latest_post_at = stream.updates.order(created_at: :desc).first.created_at | ||
| 10 | end | ||
| 11 | |||
| 12 | stream.save! | ||
| 13 | end | ||
| 14 | |||
| 15 | change_column_null :streams, :latest_post_at, false | ||
| 16 | end | ||
| 17 | |||
| 18 | def down | ||
| 19 | remove_column :streams, :latest_post_at, :datetime | ||
| 20 | end | ||
| 21 | end | ||
| diff --git a/db/migrate/20251122012500_create_scrobbles.rb b/db/migrate/20251122012500_create_scrobbles.rb new file mode 100644 index 0000000..9f00435 --- /dev/null +++ b/db/migrate/20251122012500_create_scrobbles.rb | |||
| @@ -0,0 +1,12 @@ | |||
| 1 | class CreateScrobbles < ActiveRecord::Migration[7.1] | ||
| 2 | def change | ||
| 3 | create_table :scrobbles do |t| | ||
| 4 | t.string :title | ||
| 5 | t.string :artist | ||
| 6 | t.string :album | ||
| 7 | t.string :image | ||
| 8 | |||
| 9 | t.timestamps | ||
| 10 | end | ||
| 11 | end | ||
| 12 | end | ||
| diff --git a/db/schema.rb b/db/schema.rb index 795a986..74e1976 100644 --- a/db/schema.rb +++ b/db/schema.rb | |||
| @@ -10,7 +10,7 @@ | |||
| 10 | # | 10 | # |
| 11 | # It's strongly recommended that you check this file into your version control system. | 11 | # It's strongly recommended that you check this file into your version control system. |
| 12 | 12 | ||
| 13 | ActiveRecord::Schema[7.1].define(version: 2025_01_12_025207) do | 13 | ActiveRecord::Schema[7.1].define(version: 2025_11_22_012500) do |
| 14 | create_table "active_storage_attachments", force: :cascade do |t| | 14 | create_table "active_storage_attachments", force: :cascade do |t| |
| 15 | t.string "name", null: false | 15 | t.string "name", null: false |
| 16 | t.string "record_type", null: false | 16 | t.string "record_type", null: false |
| @@ -352,12 +352,22 @@ ActiveRecord::Schema[7.1].define(version: 2025_01_12_025207) do | |||
| 352 | t.index ["recordable_type", "recordable_id"], name: "index_records_on_recordable_type_and_recordable_id" | 352 | t.index ["recordable_type", "recordable_id"], name: "index_records_on_recordable_type_and_recordable_id" |
| 353 | end | 353 | end |
| 354 | 354 | ||
| 355 | create_table "scrobbles", force: :cascade do |t| | ||
| 356 | t.string "title" | ||
| 357 | t.string "artist" | ||
| 358 | t.string "album" | ||
| 359 | t.string "image" | ||
| 360 | t.datetime "created_at", null: false | ||
| 361 | t.datetime "updated_at", null: false | ||
| 362 | end | ||
| 363 | |||
| 355 | create_table "streams", force: :cascade do |t| | 364 | create_table "streams", force: :cascade do |t| |
| 356 | t.string "title" | 365 | t.string "title" |
| 357 | t.text "body" | 366 | t.text "body" |
| 358 | t.string "slug" | 367 | t.string "slug" |
| 359 | t.datetime "created_at", precision: nil, null: false | 368 | t.datetime "created_at", precision: nil, null: false |
| 360 | t.datetime "updated_at", precision: nil, null: false | 369 | t.datetime "updated_at", precision: nil, null: false |
| 370 | t.datetime "latest_post_at", null: false | ||
| 361 | end | 371 | end |
| 362 | 372 | ||
| 363 | create_table "taggings", force: :cascade do |t| | 373 | create_table "taggings", force: :cascade do |t| |
| diff --git a/lib/tasks/tasks.rake b/lib/tasks/tasks.rake index fee22f4..91e196f 100644 --- a/lib/tasks/tasks.rake +++ b/lib/tasks/tasks.rake | |||
| @@ -1,3 +1,5 @@ | |||
| 1 | require 'net/http' | ||
| 2 | |||
| 1 | namespace :thoughts do | 3 | namespace :thoughts do |
| 2 | desc "Email a review of the last day's upvotes" | 4 | desc "Email a review of the last day's upvotes" |
| 3 | task :email_upvote_report => :environment do | 5 | task :email_upvote_report => :environment do |
| @@ -7,4 +9,23 @@ namespace :thoughts do | |||
| 7 | VoteMailer.with(votes: votes).daily_report_email.deliver | 9 | VoteMailer.with(votes: votes).daily_report_email.deliver |
| 8 | end | 10 | end |
| 9 | end | 11 | end |
| 12 | |||
| 13 | desc "Refresh the recently listened tracks" | ||
| 14 | task :refresh_scrobbles => :environment do | ||
| 15 | Scrobble.destroy_all | ||
| 16 | |||
| 17 | api_key = Rails.application.credentials.lastfm_api_key | ||
| 18 | url = URI.parse("http://ws.audioscrobbler.com/2.0/?method=user.getrecenttracks&user=fefferburbia&api_key=#{api_key}&format=json") | ||
| 19 | req = Net::HTTP::Get.new(url.to_s) | ||
| 20 | res = Net::HTTP.start(url.host, url.port) {|http| | ||
| 21 | http.request(req) | ||
| 22 | } | ||
| 23 | output = JSON.parse(res.body) | ||
| 24 | |||
| 25 | items = output["recenttracks"]["track"].map {|p| [p["name"], p["artist"]["#text"], p["album"]["#text"], p["image"][2]["#text"]]}.sort.uniq | ||
| 26 | |||
| 27 | items.each do |item| | ||
| 28 | Scrobble.create!(title: item[0], artist: item[1], album: item[2], image: item[3]) | ||
| 29 | end | ||
| 30 | end | ||
| 10 | end | 31 | end |
| diff --git a/public/robots.txt b/public/robots.txt index 37b576a..d7e6b45 100644 --- a/public/robots.txt +++ b/public/robots.txt | |||
| @@ -1 +1,7 @@ | |||
| 1 | # See http://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file | 1 | # See http://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file |
| 2 | User-agent: PetalBot | ||
| 3 | Disallow: / | ||
| 4 | |||
| 5 | User-agent: AI2Bot | ||
| 6 | Disallow: / | ||
| 7 | |||
| diff --git a/test/fixtures/scrobbles.yml b/test/fixtures/scrobbles.yml new file mode 100644 index 0000000..9ca535d --- /dev/null +++ b/test/fixtures/scrobbles.yml | |||
| @@ -0,0 +1,13 @@ | |||
| 1 | # Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html | ||
| 2 | |||
| 3 | one: | ||
| 4 | title: MyString | ||
| 5 | artist: MyString | ||
| 6 | album: MyString | ||
| 7 | image: MyString | ||
| 8 | |||
| 9 | two: | ||
| 10 | title: MyString | ||
| 11 | artist: MyString | ||
| 12 | album: MyString | ||
| 13 | image: MyString | ||
| diff --git a/test/models/scrobble_test.rb b/test/models/scrobble_test.rb new file mode 100644 index 0000000..48541da --- /dev/null +++ b/test/models/scrobble_test.rb | |||
| @@ -0,0 +1,7 @@ | |||
| 1 | require "test_helper" | ||
| 2 | |||
| 3 | class ScrobbleTest < ActiveSupport::TestCase | ||
| 4 | # test "the truth" do | ||
| 5 | # assert true | ||
| 6 | # end | ||
| 7 | end | ||
