Browse Source

import static files and implement /l/life

I'm too lazy to rewrite the frontend in Rust for now. Maybe some other time.
Peter Cai 1 year ago
parent
commit
38fea9524f
Signed by: Peter Cai <[email protected]> GPG Key ID: 71F5FB4E4F3FD54F
5 changed files with 259 additions and 4 deletions
  1. 16
    0
      backend/src/life.rs
  2. 7
    4
      backend/src/main.rs
  3. BIN
      static/786px-Moha90.svg.png
  4. 232
    0
      static/index.html
  5. 4
    0
      static/robots.txt

+ 16
- 0
backend/src/life.rs View File

@@ -5,6 +5,22 @@ use futures::Future;
5 5
 
6 6
 pub fn setup_routes(app: App<AngryAppState>) -> App<AngryAppState> {
7 7
     app.resource("/p/life", |r| r.method(http::Method::POST).f(life_add))
8
+        .resource("/l/life", |r| r.method(http::Method::GET).f(life_show))
9
+}
10
+
11
+fn life_show(req: &HttpRequest<AngryAppState>) -> impl Responder {
12
+    let state = req.state().clone();
13
+    let db = state.get_db();
14
+    state.spawn_pool(db.get_async_u64("life_secs"))
15
+        .and_then(move |a| {
16
+            Ok(HttpResponse::Ok().body(format!("{}", a)))
17
+        })
18
+        .map_err(|e| {
19
+            // TODO: Properly return the error
20
+            println!("{:?}", e);
21
+            ErrorInternalServerError(e)
22
+        })
23
+        .responder()
8 24
 }
9 25
 
10 26
 fn life_add(req: &HttpRequest<AngryAppState>) -> impl Responder {

+ 7
- 4
backend/src/main.rs View File

@@ -18,7 +18,7 @@ mod life;
18 18
 mod url;
19 19
 mod paste;
20 20
 
21
-use actix_web::{http, server, App, Path, Responder};
21
+use actix_web::{fs, http, server, App, Path, Result};
22 22
 use sled::{ConfigBuilder, Tree};
23 23
 
24 24
 fn main() {
@@ -28,17 +28,20 @@ fn main() {
28 28
     let state = app::AngryAppState::new(db, db_sync_addr);
29 29
     server::new(move || {
30 30
         let mut app = App::with_state(state.clone())
31
-            .route("/test_index.html", http::Method::GET, test_index);
31
+            .route("/", http::Method::GET, index);
32 32
         app = life::setup_routes(app);
33 33
         app = url::setup_routes(app);
34 34
         app = paste::setup_routes(app);
35
+        // The static interface
36
+        app = app.handler("/",
37
+            fs::StaticFiles::new("./static").unwrap());
35 38
         app
36 39
     }).bind("127.0.0.1:60324").unwrap().start();
37 40
     actix_sys.run();
38 41
 }
39 42
 
40
-fn test_index(_info: Path<()>) -> impl Responder {
41
-    "I'm angry!"
43
+fn index(_info: Path<()>) -> Result<fs::NamedFile> {
44
+    Ok(fs::NamedFile::open("./static/index.html")?)
42 45
 }
43 46
 
44 47
 fn open_db(db_path: &str) -> Tree {

BIN
static/786px-Moha90.svg.png View File


+ 232
- 0
static/index.html View File

@@ -0,0 +1,232 @@
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
+    <title>Angry.Im</title>
8
+
9
+    <!-- Bootstrap -->
10
+    <link href="https://cdn.css.net/files/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" rel="stylesheet">
11
+    <!-- Hightlight.js -->
12
+    <link href="https://cdn.css.net/files/highlight.js/9.9.0/styles/rainbow.min.css" rel="stylesheet">
13
+    <!-- Animate.css -->
14
+    <link href="https://cdn.css.net/files/animatecss/3.5.2/animate.min.css" rel="stylesheet">
15
+    <style>
16
+      div.glass {
17
+        text-align: center;
18
+      }
19
+      div.life {
20
+        background-color: #333;
21
+        border-color: #333;
22
+        background-image: url('/786px-Moha90.svg.png');
23
+        text-align: center;
24
+      }
25
+      pre {
26
+        border-radius: 5px;
27
+      }
28
+
29
+      @media (max-width: 768px) {
30
+        div.glass > img {
31
+          max-width: 100%;
32
+          height: auto;
33
+        }
34
+      }
35
+    </style>
36
+
37
+  </head>
38
+  <body>
39
+    <div class="container">
40
+      <div class="glass"><img src="/786px-Moha90.svg.png"></img></div>
41
+      <div class="card card-inverse life">
42
+        <div class="card-block">
43
+          <h1 id="seconds" class="card-title">0</h3>
44
+          <a id="plus1" href="#" class="btn btn-danger">+1s</a>
45
+          <h3>or</h3>
46
+          <pre><code class="bash">
47
+$ curl -X POST 'https://angry.im/p/life'
48
+          </code></pre>
49
+        </div>
50
+      </div>
51
+      <br/>
52
+      <div class="card card-outline-info text-center">
53
+        <div class="card-block">
54
+            <h3>I'm angry with...</h3>
55
+            <textarea class="form-control" id="codeArea" rows="3" placeholder="Some code snippet to be pasted..."></textarea><br/>
56
+            <a id="paste" href="#" class="btn btn-info">Paste</a>
57
+            <h3>or</h3>
58
+            <pre><code class="bash">
59
+$ cat hong-kong-journalist.py | curl -X POST --data-binary [email protected] 'https://angry.im/p/text'
60
+            </code></pre>
61
+            <p>* Tip: Add <code>?lang=programming_language</code> to the short URL to get highlighting in specific <code>programming_language</code> for your pasted code.</p>
62
+        </div>
63
+      </div>
64
+      <br/>
65
+      <div class="card card-outline-success text-center">
66
+        <div class="card-block">
67
+          <h3>I'm angry with...</h3>
68
+          <input type="url" class="form-control" id="url" placeholder="Some web URL to be shortened..."></input><br/>
69
+          <a id="shorten" href="#" class="btn btn-success">Shorten</a>
70
+          <h3>or</h3>
71
+          <pre><code class="bash">
72
+$ curl -X POST -d 'u=https://example.com' 'https://angry.im/p/url'
73
+          </code></pre>
74
+          <p>* Tip: <code>magnet:?xt=</code> and <code>ed2k://</code> links are also supported.</p>
75
+        </div>
76
+      </div>
77
+      <br/>
78
+      <div class="card card-outline-warning text-center">
79
+        <div class="card-block">
80
+          <h3>I'm angry with...</h3>
81
+          <h4>Social Networks: Twitter / Facebook / Google+ / Weibo etc.</h4><br/>
82
+          <a href="https://sn.angry.im" target="_blank" class="btn btn-outline-warning">Join our Mastodon instance now!</a>
83
+        </div>
84
+      </div>
85
+      <br/>
86
+      <p class="text-center" style="color: #AAA">Copyright &copy; 2017 Angry.Im. No rights reserved.</p>
87
+    </div>
88
+    <br/>
89
+
90
+
91
+<div class="modal fade" id="pasteDialog" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
92
+  <div class="modal-dialog" role="document">
93
+    <div class="modal-content">
94
+      <div class="modal-header">
95
+        <h5 class="modal-title" id="exampleModalLabel">Pastebin</h5>
96
+        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
97
+          <span aria-hidden="true">&times;</span>
98
+        </button>
99
+      </div>
100
+      <div class="modal-body">
101
+        <a id="pasteResult" target="_blank"></a>
102
+      </div>
103
+      <div class="modal-footer">
104
+        <button type="button" class="btn btn-primary" data-dismiss="modal">OK</button>
105
+      </div>
106
+    </div>
107
+  </div>
108
+</div>
109
+
110
+    <!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
111
+    <script src="https://cdn.css.net/files/jquery/1.12.4/jquery.min.js"></script>
112
+    <!-- Include all compiled plugins (below), or include individual files as needed -->
113
+    <script src="https://cdn.css.net/files/bootstrap/4.0.0-alpha.6/js/bootstrap.min.js"></script>
114
+    <!-- Hightlight.js -->
115
+    <script src="https://cdn.css.net/files/highlight.js/9.9.0/highlight.min.js"></script>
116
+    <!--<script src="https://cdn.css.net/files/highlight.js/9.9.0/languages/bash.min.js"></script>-->
117
+    <script>
118
+        $.fn.extend({
119
+            animateCss: function (animationName) {
120
+                var animationEnd = 'webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend';
121
+                this.addClass('animated ' + animationName).one(animationEnd, function() {
122
+                    $(this).removeClass('animated ' + animationName);
123
+                });
124
+            }
125
+        });
126
+        hljs.initHighlightingOnLoad();
127
+        $(document).ready(function() {
128
+            setInterval(updateSeconds, 3000)
129
+            updateSeconds()
130
+            $('#plus1').on('click', function (ev) {
131
+                ev.preventDefault()
132
+                $.post("/p/life", function (data) {
133
+                    $('.glass').animateCss('pulse')
134
+                    $('#seconds').animateCss('tada')
135
+                    $('#seconds').text(formatTime(parseInt(data)))
136
+                })
137
+            })
138
+            $('#paste').on('click', function (ev) {
139
+                ev.preventDefault()
140
+                var code = $('#codeArea').val().trim()
141
+                if (code == "") {
142
+                    return
143
+                }
144
+                $('#paste').addClass('disabled')
145
+                $.ajax('/p/text', {
146
+                    method: 'POST',
147
+                    contentType: "text/plain",
148
+                    data: code,
149
+                    success: function (data) {
150
+                        $('#paste').removeClass('disabled')
151
+                        if (data != null && typeof(data) == "string" && data.trim() != "") {
152
+                            $('#codeArea').val('')
153
+                            $('#pasteResult').attr('href', data)
154
+                            $('#pasteResult').text(data)
155
+                            $('#pasteDialog').modal('show')
156
+                        }
157
+                    },
158
+                    error: function () {
159
+                        $('#paste').removeClass('disabled')
160
+                    }
161
+                })
162
+            })
163
+            $('#shorten').on('click', function (ev) {
164
+                ev.preventDefault()
165
+                var url = $('#url').val().trim()
166
+                if (url == "" || url.startsWith("https://" + location.hostname) || url.startsWith("http://" + location.hostname)
167
+                    || (!url.startsWith('http://') && !url.startsWith('https://') && (!url.startsWith('magnet:?xt=') && (!url.startsWith('ed2k://|'))))) {
168
+                    return
169
+                }
170
+                $('#shorten').addClass('disabled')
171
+                $.ajax('/p/url', {
172
+                    method: 'POST',
173
+                    contentType: "application/x-www-form-urlencoded",
174
+                    data: {
175
+                        u: url
176
+                    },
177
+                    success: function (data) {
178
+                        $('#shorten').removeClass('disabled')
179
+                        $('#url').val(data)
180
+                    },
181
+                    error: function() {
182
+                        $('#shorten').removeClass('disabled')
183
+                    }
184
+                })
185
+            })
186
+        })
187
+
188
+        function updateSeconds() {
189
+            // Update the seconds
190
+            $.get("/l/life", function (data) {
191
+                $('#seconds').text(formatTime(parseInt(data)))
192
+            })
193
+        }
194
+
195
+        function formatTime(t) {
196
+            if (t == 0) return "0s"
197
+            ret = ""
198
+            if (t > 60 * 60 * 24 * 30 * 12) {
199
+                ret += Math.floor(t / (60 * 60 * 24 * 30 * 12)) + "y "
200
+                t = t % (60 * 60 * 24 * 30 * 12)
201
+            }
202
+            
203
+            if (t > 60 * 60 * 24 * 30) {
204
+                ret += Math.floor(t / (60 * 60 * 24 * 30)) + "mo "
205
+                t = t % (60 * 60 * 24 * 30)
206
+            }
207
+
208
+            if (t > 60 * 60 * 24) {
209
+                ret += Math.floor(t / (60 * 60 * 24)) + "d "
210
+                t = t % (60 * 60 * 24)
211
+            }
212
+
213
+            if (t > 60 * 60) {
214
+                ret += Math.floor(t / (60 * 60)) + "h "
215
+                t = t % (60 * 60)
216
+            }
217
+
218
+            if (t > 60) {
219
+                ret += Math.floor(t / (60)) + "m "
220
+                t = t % (60)
221
+            }
222
+
223
+            if (t > 0) {
224
+                ret += Math.floor(t) + "s"
225
+                t = 0
226
+            }
227
+
228
+            return ret.trim()
229
+        }
230
+    </script>
231
+  </body>
232
+</html>

+ 4
- 0
static/robots.txt View File

@@ -0,0 +1,4 @@
1
+User-agent: *
2
+Disallow: /t/
3
+Disallow: /u/
4
+Disallow: /p/

Loading…
Cancel
Save