Browse Source

User now have an actor; Returns Actor json via Accept: header

Dashie der otter 4 months ago
parent
commit
3c1fa9ed60

+ 1
- 0
.gitignore View File

@@ -11,3 +11,4 @@
11 11
 /reel2bits.egg-info
12 12
 /.eggs
13 13
 /configtest.py
14
+/errors_app.log

+ 28
- 0
activitypub/utils.py View File

@@ -0,0 +1,28 @@
1
+from flask import current_app
2
+
3
+
4
+def ap_url(klass, username):
5
+    if klass == "url":
6
+        return f"https://{current_app.config['AP_DOMAIN']}/user/{username}"
7
+    elif klass == "shared_inbox":
8
+        return f"https://{current_app.config['AP_DOMAIN']}/inbox"
9
+    elif klass == "inbox":
10
+        return f"https://{current_app.config['AP_DOMAIN']}" \
11
+               f"/user/{username}/inbox"
12
+    elif klass == "outbox":
13
+        return f"https://{current_app.config['AP_DOMAIN']}" \
14
+               f"/user/{username}/outbox"
15
+    else:
16
+        return None
17
+
18
+
19
+def full_url(path):
20
+    if path.startswith("http://") or path.startswith("https://"):
21
+        return path
22
+    root = current_app.config['AP_DOMAIN']
23
+    if path.startswith('/'):
24
+        return root + path[1:]
25
+    elif path.startswith('/'):
26
+        return root + "/" + path
27
+    else:
28
+        return root + path

+ 11
- 1
app.py View File

@@ -24,7 +24,7 @@ from controllers.api.v1.well_known import bp_wellknown
24 24
 from controllers.api.v1.nodeinfo import bp_nodeinfo
25 25
 
26 26
 from forms import ExtendedRegisterForm
27
-from models import db, Config, user_datastore, Role
27
+from models import db, Config, user_datastore, Role, create_actor
28 28
 from utils import InvalidUsage, is_admin, duration_elapsed_human, \
29 29
     duration_song_human, add_user_log
30 30
 
@@ -111,6 +111,16 @@ def create_app(config_filename="config.py"):
111 111
         add_user_log(user.id, user.id, "user", "info",
112 112
                      "Password reset instructions sent.")
113 113
 
114
+    @FlaskSecuritySignals.user_registered.connect_via(app)
115
+    def create_actor_for_registered_user(app, user, confirm_token):
116
+        if not user:
117
+            return
118
+        actor = create_actor(user)
119
+        actor.user = user
120
+        actor.user_id = user.id
121
+        db.session.add(actor)
122
+        db.session.commit()
123
+
114 124
     git_version = ""
115 125
     gitpath = os.path.join(os.getcwd(), ".git")
116 126
     if os.path.isdir(gitpath):

+ 40
- 1
controllers/users.py View File

@@ -1,12 +1,13 @@
1 1
 import pytz
2 2
 from flask import Blueprint, render_template, request, \
3
-    redirect, url_for, flash, Response, json
3
+    redirect, url_for, flash, Response, json, jsonify
4 4
 from flask_babelex import gettext
5 5
 from flask_security import login_required, current_user
6 6
 
7 7
 from forms import UserProfileForm
8 8
 from models import db, User, UserLogging, Sound, Album
9 9
 from utils import add_user_log
10
+from flask_accept import accept
10 11
 
11 12
 bp_users = Blueprint('bp_users', __name__)
12 13
 
@@ -44,6 +45,7 @@ def logs_delete(log_id):
44 45
 
45 46
 
46 47
 @bp_users.route('/user/<string:name>', methods=['GET'])
48
+@accept('text/html')
47 49
 def profile(name):
48 50
     pcfg = {"title": gettext(u"%(value)s' profile", value=name)}
49 51
 
@@ -64,6 +66,43 @@ def profile(name):
64 66
                            user=user, sounds=sounds)
65 67
 
66 68
 
69
+@bp_users.route('/user/<string:name>', methods=['GET'])
70
+@profile.support('application/json')
71
+def actor_json(name):
72
+    user = User.query.filter(User.name == name).first()
73
+    if not user:
74
+        return Response("", status=404)
75
+    actors = user.actor
76
+    if len(actors) <= 0:
77
+        return Response("", status=500)
78
+    actor = actors[0]
79
+
80
+    resp = {
81
+        "@context": [
82
+            "https://www.w3.org/ns/activitystreams",
83
+            "https://w3id.org/security/v1"
84
+        ],
85
+        "id": actor.url,
86
+        "type": actor.type.code,
87
+        "preferredUsername": actor.preferred_username,
88
+        "inbox": actor.inbox_url,
89
+        "outbox": actor.outbox_url,
90
+        "manuallyApprovesFollowers": actor.manually_approves_followers,
91
+        "publicKey": {
92
+            "id": actor.private_key_id(),
93
+            "owner": actor.url,
94
+            "publicKeyPem": actor.public_key
95
+        },
96
+        "endpoints": {
97
+            "sharedInbox": actor.shared_inbox_url
98
+        }
99
+    }
100
+
101
+    response = jsonify(resp)
102
+    response.mimetype = "application/activity+json; charset=utf-8"
103
+    return response
104
+
105
+
67 106
 @bp_users.route('/user/<string:name>/sets', methods=['GET'])
68 107
 def profile_albums(name):
69 108
     pcfg = {"title": gettext(u"%(value)s' profile", value=name)}

+ 167
- 116
messages.pot View File

@@ -1,147 +1,183 @@
1 1
 # Translations template for PROJECT.
2
-# Copyright (C) 2017 ORGANIZATION
2
+# Copyright (C) 2018 ORGANIZATION
3 3
 # This file is distributed under the same license as the PROJECT project.
4
-# FIRST AUTHOR <EMAIL@ADDRESS>, 2017.
4
+# FIRST AUTHOR <EMAIL@ADDRESS>, 2018.
5 5
 #
6 6
 #, fuzzy
7 7
 msgid ""
8 8
 msgstr ""
9 9
 "Project-Id-Version: PROJECT VERSION\n"
10 10
 "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
11
-"POT-Creation-Date: 2017-01-02 07:47+0100\n"
11
+"POT-Creation-Date: 2018-08-04 21:43+0200\n"
12 12
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
13 13
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14 14
 "Language-Team: LANGUAGE <LL@li.org>\n"
15 15
 "MIME-Version: 1.0\n"
16 16
 "Content-Type: text/plain; charset=utf-8\n"
17 17
 "Content-Transfer-Encoding: 8bit\n"
18
-"Generated-By: Babel 2.3.4\n"
18
+"Generated-By: Babel 2.6.0\n"
19 19
 
20
-#: forms.py:42
21
-msgid "Username required"
20
+#: app.py:143 controllers/admin.py:53
21
+msgid "Config not found"
22
+msgstr ""
23
+
24
+#: app.py:181 app.py:188 app.py:195 app.py:203
25
+msgid "Whoops, something failed."
26
+msgstr ""
27
+
28
+#: app.py:182
29
+msgid "Page not found"
30
+msgstr ""
31
+
32
+#: app.py:189
33
+msgid "Access forbidden"
34
+msgstr ""
35
+
36
+#: app.py:196
37
+msgid "Gone"
38
+msgstr ""
39
+
40
+#: app.py:205
41
+msgid "Something is broken"
22 42
 msgstr ""
23 43
 
24 44
 #: forms.py:46
45
+msgid "Username required"
46
+msgstr ""
47
+
48
+#: forms.py:51
25 49
 msgid "Username already taken"
26 50
 msgstr ""
27 51
 
28
-#: forms.py:53
52
+#: forms.py:58
29 53
 msgid "Password"
30 54
 msgstr ""
31 55
 
32
-#: forms.py:54
56
+#: forms.py:59
33 57
 msgid "Name"
34 58
 msgstr ""
35 59
 
36
-#: forms.py:55
60
+#: forms.py:60
37 61
 msgid "Email"
38 62
 msgstr ""
39 63
 
40
-#: forms.py:56
64
+#: forms.py:61
41 65
 msgid "Firstname"
42 66
 msgstr ""
43 67
 
44
-#: forms.py:57
68
+#: forms.py:62
45 69
 msgid "Lastname"
46 70
 msgstr ""
47 71
 
48
-#: forms.py:58
72
+#: forms.py:63
49 73
 msgid "Timezone"
50 74
 msgstr ""
51 75
 
52
-#: forms.py:59
76
+#: forms.py:65
53 77
 msgid "Locale"
54 78
 msgstr ""
55 79
 
56
-#: forms.py:60
80
+#: forms.py:67
57 81
 msgid "Update profile"
58 82
 msgstr ""
59 83
 
60
-#: forms.py:64
61
-msgid "App Name"
84
+#: forms.py:72
85
+msgid "Instance Name"
62 86
 msgstr ""
63 87
 
64
-#: forms.py:66
88
+#: forms.py:73
89
+msgid "Instance description"
90
+msgstr ""
91
+
92
+#: forms.py:75
65 93
 msgid "Update config"
66 94
 msgstr ""
67 95
 
68
-#: forms.py:74 forms.py:90 forms.py:106
96
+#: forms.py:87 forms.py:109 forms.py:130
69 97
 msgid "Title"
70 98
 msgstr ""
71 99
 
72
-#: forms.py:75
100
+#: forms.py:88
73 101
 msgid "File"
74 102
 msgstr ""
75 103
 
76
-#: forms.py:76 forms.py:91 forms.py:108
104
+#: forms.py:90 forms.py:110 forms.py:133
77 105
 msgid "Private"
78 106
 msgstr ""
79 107
 
80
-#: forms.py:79 forms.py:95
108
+#: forms.py:93 forms.py:114
81 109
 msgid "Album"
82 110
 msgstr ""
83 111
 
84
-#: forms.py:84 forms.py:100
112
+#: forms.py:94 forms.py:115
113
+msgid "No album"
114
+msgstr ""
115
+
116
+#: forms.py:98 forms.py:119 templates/sound/show.jinja2:114
117
+msgid "Licence"
118
+msgstr ""
119
+
120
+#: forms.py:103 forms.py:124
85 121
 msgid "Cannot put private sound in public album"
86 122
 msgstr ""
87 123
 
88
-#: forms.py:86 templates/layout.jinja2:56
124
+#: forms.py:105 templates/layout.jinja2:63
89 125
 msgid "Upload"
90 126
 msgstr ""
91 127
 
92
-#: forms.py:92 forms.py:107
128
+#: forms.py:111 forms.py:132
93 129
 msgid "Description"
94 130
 msgstr ""
95 131
 
96
-#: forms.py:102
132
+#: forms.py:126
97 133
 msgid "Edit sound"
98 134
 msgstr ""
99 135
 
100
-#: forms.py:110
136
+#: forms.py:135
101 137
 msgid "Save"
102 138
 msgstr ""
103 139
 
104
-#: controllers/admin.py:17
140
+#: controllers/admin.py:19
105 141
 msgid "Application Logs"
106 142
 msgstr ""
107 143
 
108
-#: controllers/admin.py:44
144
+#: controllers/admin.py:49
109 145
 msgid "Application Config"
110 146
 msgstr ""
111 147
 
112
-#: controllers/admin.py:48
113
-msgid "Config not found"
114
-msgstr ""
115
-
116
-#: controllers/admin.py:57
148
+#: controllers/admin.py:63
117 149
 msgid "Configuration updated"
118 150
 msgstr ""
119 151
 
120
-#: controllers/albums.py:14 templates/album/new.jinja2:7
121
-#: templates/layout.jinja2:57
152
+#: controllers/albums.py:17 templates/album/new.jinja2:7
153
+#: templates/layout.jinja2:64
122 154
 msgid "New album"
123 155
 msgstr ""
124 156
 
125
-#: controllers/albums.py:27
157
+#: controllers/albums.py:35
126 158
 msgid "Created !"
127 159
 msgstr ""
128 160
 
129
-#: controllers/albums.py:37 controllers/sound.py:19 controllers/sound.py:53
130
-#: controllers/users.py:46 controllers/users.py:63 controllers/users.py:81
161
+#: controllers/albums.py:48 controllers/sound.py:21 controllers/users.py:52
162
+#: controllers/users.py:73 controllers/users.py:93
131 163
 msgid "User not found"
132 164
 msgstr ""
133 165
 
134
-#: controllers/albums.py:41 controllers/albums.py:47 controllers/albums.py:50
135
-#: controllers/albums.py:63 controllers/albums.py:94
166
+#: controllers/albums.py:53 controllers/albums.py:59 controllers/albums.py:62
167
+#: controllers/albums.py:80
136 168
 msgid "Album not found"
137 169
 msgstr ""
138 170
 
139
-#: controllers/albums.py:66 controllers/sound.py:126
171
+#: controllers/albums.py:84 controllers/sound.py:161 controllers/sound.py:203
172
+msgid "Forbidden"
173
+msgstr ""
174
+
175
+#: controllers/albums.py:87 controllers/sound.py:164
140 176
 #, python-format
141 177
 msgid "Edit %(value)s"
142 178
 msgstr ""
143 179
 
144
-#: controllers/albums.py:85
180
+#: controllers/albums.py:112
145 181
 msgid "Public album cannot have private sounds"
146 182
 msgstr ""
147 183
 
@@ -149,112 +185,128 @@ msgstr ""
149 185
 msgid "Home"
150 186
 msgstr ""
151 187
 
152
-#: controllers/sound.py:23 controllers/sound.py:29 controllers/sound.py:32
153
-#: controllers/sound.py:57 controllers/sound.py:63 controllers/sound.py:66
154
-#: controllers/sound.py:123 controllers/sound.py:148
188
+#: controllers/sound.py:33 controllers/sound.py:39 controllers/sound.py:42
189
+#: controllers/sound.py:157 controllers/sound.py:199
155 190
 msgid "Sound not found"
156 191
 msgstr ""
157 192
 
158
-#: controllers/sound.py:44
159
-msgid "No HTML5 player supported actually"
160
-msgstr ""
161
-
162
-#: controllers/sound.py:82 templates/sound/upload.jinja2:7
193
+#: controllers/sound.py:92 templates/sound/upload.jinja2:7
163 194
 msgid "New upload"
164 195
 msgstr ""
165 196
 
166
-#: controllers/sound.py:109
197
+#: controllers/sound.py:139
167 198
 msgid "Uploaded !"
168 199
 msgstr ""
169 200
 
170
-#: controllers/users.py:16
201
+#: controllers/users.py:18
171 202
 msgid "User Logs"
172 203
 msgstr ""
173 204
 
174
-#: controllers/users.py:42 controllers/users.py:59
175
-#: templates/users/profile.jinja2:5 templates/users/profile_albums.jinja2:5
205
+#: controllers/users.py:48 controllers/users.py:69
206
+#: templates/users/profile.jinja2:13 templates/users/profile_albums.jinja2:13
176 207
 #, python-format
177 208
 msgid "%(value)s' profile"
178 209
 msgstr ""
179 210
 
180
-#: controllers/users.py:77
211
+#: controllers/users.py:89
181 212
 msgid "Edit my profile"
182 213
 msgstr ""
183 214
 
184
-#: templates/layout.jinja2:46
215
+#: controllers/users.py:111
216
+msgid "Profile updated"
217
+msgstr ""
218
+
219
+#: templates/about.jinja2:19
220
+#, python-format
221
+msgid "reel2bits is developped by %(dashie)s and is available under MIT license."
222
+msgstr ""
223
+
224
+#: templates/about.jinja2:21
225
+#, python-format
226
+msgid "Source code is here: %(link)s"
227
+msgstr ""
228
+
229
+#: templates/about.jinja2:22
230
+#, python-format
231
+msgid "Issue tracker is here: %(link)s"
232
+msgstr ""
233
+
234
+#: templates/error_page.jinja2:7
235
+#, python-format
236
+msgid "Maybe you can go back to the %(link)s."
237
+msgstr ""
238
+
239
+#: templates/error_page.jinja2:7
240
+msgid "index"
241
+msgstr ""
242
+
243
+#: templates/layout.jinja2:53
185 244
 msgid "Toggle navigation"
186 245
 msgstr ""
187 246
 
188
-#: templates/layout.jinja2:58
247
+#: templates/layout.jinja2:65
189 248
 msgid "My Profile"
190 249
 msgstr ""
191 250
 
192
-#: templates/layout.jinja2:63
251
+#: templates/layout.jinja2:70
193 252
 msgid "About"
194 253
 msgstr ""
195 254
 
196
-#: templates/layout.jinja2:66
255
+#: templates/layout.jinja2:73 templates/layout.jinja2:111
197 256
 #, python-format
198 257
 msgid "Logged as %(username)s"
199 258
 msgstr ""
200 259
 
201
-#: templates/admin/logs.jinja2:24 templates/layout.jinja2:68
260
+#: templates/admin/logs.jinja2:24 templates/layout.jinja2:75
202 261
 msgid "User"
203 262
 msgstr ""
204 263
 
205
-#: templates/layout.jinja2:69
264
+#: templates/layout.jinja2:76
206 265
 msgid "Profile"
207 266
 msgstr ""
208 267
 
209
-#: templates/layout.jinja2:70
268
+#: templates/layout.jinja2:77
210 269
 msgid "Logs"
211 270
 msgstr ""
212 271
 
213
-#: templates/layout.jinja2:73
272
+#: templates/layout.jinja2:80
214 273
 msgid "Admin"
215 274
 msgstr ""
216 275
 
217
-#: templates/layout.jinja2:74
276
+#: templates/layout.jinja2:81
218 277
 msgid "App config"
219 278
 msgstr ""
220 279
 
221
-#: templates/layout.jinja2:75
280
+#: templates/layout.jinja2:82
222 281
 msgid "App logs"
223 282
 msgstr ""
224 283
 
225
-#: templates/layout.jinja2:78
284
+#: templates/layout.jinja2:85
226 285
 msgid "Change password"
227 286
 msgstr ""
228 287
 
229
-#: templates/layout.jinja2:79
288
+#: templates/layout.jinja2:86
230 289
 msgid "Logout"
231 290
 msgstr ""
232 291
 
233
-#: templates/layout.jinja2:84
292
+#: templates/layout.jinja2:91
234 293
 msgid "Register"
235 294
 msgstr ""
236 295
 
237
-#: templates/layout.jinja2:86
296
+#: templates/layout.jinja2:93
238 297
 msgid "Login"
239 298
 msgstr ""
240 299
 
241
-#: templates/layout.jinja2:112
300
+#: templates/layout.jinja2:111
242 301
 #, python-format
243
-msgid ""
244
-"Use template for %(link1)s by %(link2)s and use %(link3)s, reel2bits "
245
-"%(link4)s"
246
-msgstr ""
247
-
248
-#: templates/layout.jinja2:116
249
-msgid "source code"
302
+msgid "version: %(version)s"
250 303
 msgstr ""
251 304
 
252
-#: templates/layout.jinja2:118
253
-#, python-format
254
-msgid "Running version %(version)s"
305
+#: templates/layout.jinja2:114
306
+msgid "Sources"
255 307
 msgstr ""
256 308
 
257
-#: templates/layout.jinja2:120
309
+#: templates/layout.jinja2:116
258 310
 msgid "Back to top"
259 311
 msgstr ""
260 312
 
@@ -306,24 +358,23 @@ msgstr ""
306 358
 msgid "Actions"
307 359
 msgstr ""
308 360
 
309
-#: templates/admin/logs.jinja2:40 templates/album/show.jinja2:80
310
-#: templates/album/show.jinja2:116 templates/sound/show.jinja2:78
311
-#: templates/users/user_logs.jinja2:43
361
+#: templates/admin/logs.jinja2:40 templates/album/show.jinja2:92
362
+#: templates/album/show.jinja2:130 templates/sound/show.jinja2:89
363
+#: templates/users/user_logs.jinja2:47
312 364
 msgid "yes really"
313 365
 msgstr ""
314 366
 
315
-#: templates/admin/logs.jinja2:40 templates/album/show.jinja2:80
316
-#: templates/album/show.jinja2:116 templates/sound/show.jinja2:78
317
-#: templates/users/user_logs.jinja2:43
367
+#: templates/admin/logs.jinja2:40 templates/album/show.jinja2:92
368
+#: templates/album/show.jinja2:130 templates/sound/show.jinja2:89
369
+#: templates/users/user_logs.jinja2:47
318 370
 msgid "delete"
319 371
 msgstr ""
320 372
 
321
-#: templates/admin/logs.jinja2:64 templates/users/user_logs.jinja2:67
373
+#: templates/admin/logs.jinja2:64 templates/users/user_logs.jinja2:71
322 374
 msgid "Log deletion"
323 375
 msgstr ""
324 376
 
325
-#: templates/admin/logs.jinja2:64 templates/album/show.jinja2:153
326
-#: templates/users/user_logs.jinja2:67
377
+#: templates/admin/logs.jinja2:64 templates/users/user_logs.jinja2:71
327 378
 msgid "An error occured"
328 379
 msgstr ""
329 380
 
@@ -340,29 +391,25 @@ msgstr ""
340 391
 msgid "Add a nice description ?"
341 392
 msgstr ""
342 393
 
343
-#: templates/album/edit.jinja2:19 templates/sound/edit.jinja2:23
394
+#: templates/album/edit.jinja2:19 templates/sound/edit.jinja2:24
344 395
 #: templates/users/edit.jinja2:27
345 396
 msgid "Cancel edit"
346 397
 msgstr ""
347 398
 
348
-#: templates/album/show.jinja2:19 templates/sound/show.jinja2:23
349
-#: templates/users/profile.jinja2:40 templates/users/profile_albums.jinja2:29
399
+#: templates/album/show.jinja2:31 templates/sound/show.jinja2:39
400
+#: templates/users/profile.jinja2:48 templates/users/profile_albums.jinja2:37
350 401
 #, python-format
351 402
 msgid "%(value)s ago"
352 403
 msgstr ""
353 404
 
354
-#: templates/album/show.jinja2:112 templates/sound/show.jinja2:74
405
+#: templates/album/show.jinja2:126 templates/sound/show.jinja2:85
355 406
 msgid "edit"
356 407
 msgstr ""
357 408
 
358
-#: templates/album/show.jinja2:122
409
+#: templates/album/show.jinja2:136
359 410
 msgid "This album is empty."
360 411
 msgstr ""
361 412
 
362
-#: templates/album/show.jinja2:153
363
-msgid "Switch sound"
364
-msgstr ""
365
-
366 413
 #: templates/security/change_password.html:9
367 414
 msgid "Set a new password"
368 415
 msgstr ""
@@ -383,43 +430,47 @@ msgstr ""
383 430
 msgid "Edit upload"
384 431
 msgstr ""
385 432
 
386
-#: templates/sound/edit.jinja2:19 templates/sound/upload.jinja2:19
433
+#: templates/sound/edit.jinja2:18 templates/sound/upload.jinja2:18
387 434
 msgid "If you want to add to a new album you need to create it separately."
388 435
 msgstr ""
389 436
 
390
-#: templates/sound/show.jinja2:12 templates/users/profile.jinja2:57
437
+#: templates/sound/show.jinja2:24 templates/users/profile.jinja2:65
391 438
 msgid "Please wait, song metadatas are processing..."
392 439
 msgstr ""
393 440
 
394
-#: templates/sound/show.jinja2:84 templates/users/profile.jinja2:49
441
+#: templates/sound/show.jinja2:28
442
+msgid "Please wait, transcoding is on her way..."
443
+msgstr ""
444
+
445
+#: templates/sound/show.jinja2:110 templates/users/profile.jinja2:57
395 446
 msgid "In album:"
396 447
 msgstr ""
397 448
 
398
-#: templates/sound/show.jinja2:89
449
+#: templates/sound/show.jinja2:130
399 450
 msgid "Type"
400 451
 msgstr ""
401 452
 
402
-#: templates/sound/show.jinja2:90
453
+#: templates/sound/show.jinja2:131
403 454
 msgid "Codec"
404 455
 msgstr ""
405 456
 
406
-#: templates/sound/show.jinja2:91
457
+#: templates/sound/show.jinja2:132
407 458
 msgid "Format"
408 459
 msgstr ""
409 460
 
410
-#: templates/sound/show.jinja2:92
461
+#: templates/sound/show.jinja2:133
411 462
 msgid "Channels"
412 463
 msgstr ""
413 464
 
414
-#: templates/sound/show.jinja2:93
465
+#: templates/sound/show.jinja2:134
415 466
 msgid "Rate"
416 467
 msgstr ""
417 468
 
418
-#: templates/sound/show.jinja2:96 templates/sound/show.jinja2:99
469
+#: templates/sound/show.jinja2:137 templates/sound/show.jinja2:140
419 470
 msgid "Bitrate"
420 471
 msgstr ""
421 472
 
422
-#: templates/sound/show.jinja2:103
473
+#: templates/sound/show.jinja2:144
423 474
 msgid "Bitrate mode"
424 475
 msgstr ""
425 476
 
@@ -428,28 +479,28 @@ msgstr ""
428 479
 msgid "Edit profile - %(username)s"
429 480
 msgstr ""
430 481
 
431
-#: templates/users/profile.jinja2:10 templates/users/profile_albums.jinja2:10
482
+#: templates/users/profile.jinja2:18 templates/users/profile_albums.jinja2:18
432 483
 msgid "all sounds"
433 484
 msgstr ""
434 485
 
435
-#: templates/users/profile.jinja2:11 templates/users/profile_albums.jinja2:11
486
+#: templates/users/profile.jinja2:19 templates/users/profile_albums.jinja2:19
436 487
 msgid "all albums"
437 488
 msgstr ""
438 489
 
439
-#: templates/users/profile.jinja2:15 templates/users/profile_albums.jinja2:15
490
+#: templates/users/profile.jinja2:23 templates/users/profile_albums.jinja2:23
440 491
 msgid "Edit profile"
441 492
 msgstr ""
442 493
 
443
-#: templates/users/profile.jinja2:66
494
+#: templates/users/profile.jinja2:74
444 495
 msgid "This user haven't uploaded any sound :( !"
445 496
 msgstr ""
446 497
 
447
-#: templates/users/profile_albums.jinja2:30
498
+#: templates/users/profile_albums.jinja2:38
448 499
 #, python-format
449 500
 msgid "%(nb)s tracks"
450 501
 msgstr ""
451 502
 
452
-#: templates/users/profile_albums.jinja2:40
503
+#: templates/users/profile_albums.jinja2:48
453 504
 msgid "This user haven't created any album !"
454 505
 msgstr ""
455 506
 
@@ -459,6 +510,6 @@ msgid "%(username)s's logs (latest 100)"
459 510
 msgstr ""
460 511
 
461 512
 #: templates/users/user_logs.jinja2:24
462
-msgid "Sound"
513
+msgid "Item ID"
463 514
 msgstr ""
464 515
 

+ 67
- 0
migrations/versions/25_32f48de123f3_.py View File

@@ -0,0 +1,67 @@
1
+"""Add actor federation
2
+
3
+Revision ID: 32f48de123f3
4
+Revises: be5369fae219
5
+Create Date: 2018-08-05 10:42:47.048304
6
+
7
+"""
8
+
9
+# revision identifiers, used by Alembic.
10
+revision = '32f48de123f3'
11
+down_revision = 'be5369fae219'
12
+
13
+from alembic import op  # noqa: E402
14
+import sqlalchemy as sa  # noqa: E402
15
+import sqlalchemy_utils  # noqa: E402
16
+from models import ACTOR_TYPE_CHOICES  # noqa: E402
17
+
18
+
19
+def upgrade():
20
+    op.create_table('actor',
21
+                    sa.Column('id', sa.Integer(), nullable=False),
22
+                    sa.Column('url', sqlalchemy_utils.types.url.URLType(),
23
+                              nullable=True),
24
+                    sa.Column('outbox_url',
25
+                              sqlalchemy_utils.types.url.URLType(),
26
+                              nullable=True),
27
+                    sa.Column('inbox_url',
28
+                              sqlalchemy_utils.types.url.URLType(),
29
+                              nullable=True),
30
+                    sa.Column('following_url',
31
+                              sqlalchemy_utils.types.url.URLType(),
32
+                              nullable=True),
33
+                    sa.Column('followers_url',
34
+                              sqlalchemy_utils.types.url.URLType(),
35
+                              nullable=True),
36
+                    sa.Column('shared_inbox_url',
37
+                              sqlalchemy_utils.types.url.URLType(),
38
+                              nullable=True),
39
+                    sa.Column('type', sqlalchemy_utils.types.choice.ChoiceType(
40
+                        choices=ACTOR_TYPE_CHOICES),
41
+                              server_default='Person', nullable=True),
42
+                    sa.Column('name', sa.String(length=200), nullable=True),
43
+                    sa.Column('domain', sa.String(length=1000),
44
+                              nullable=False),
45
+                    sa.Column('summary', sa.String(length=500), nullable=True),
46
+                    sa.Column('preferred_username', sa.String(length=200),
47
+                              nullable=True),
48
+                    sa.Column('public_key', sa.String(length=5000),
49
+                              nullable=True),
50
+                    sa.Column('private_key', sa.String(length=5000),
51
+                              nullable=True),
52
+                    sa.Column('creation_date', sa.DateTime(), nullable=True),
53
+                    sa.Column('last_fetch_date', sa.DateTime(), nullable=True),
54
+                    sa.Column('manually_approves_followers', sa.Boolean(),
55
+                              nullable=True),
56
+                    sa.Column('user_id', sa.Integer(), nullable=True),
57
+                    sa.ForeignKeyConstraint(['user_id'], ['user.id'], ),
58
+                    sa.PrimaryKeyConstraint('id'),
59
+                    sa.UniqueConstraint('domain', 'preferred_username',
60
+                                        name='_domain_pref_username_uc')
61
+                    )
62
+    op.create_index(op.f('ix_actor_url'), 'actor', ['url'], unique=True)
63
+
64
+
65
+def downgrade():
66
+    op.drop_index(op.f('ix_actor_url'), table_name='actor')
67
+    op.drop_table('actor')

+ 26
- 0
migrations/versions/26_d3c41a9e2688_.py View File

@@ -0,0 +1,26 @@
1
+"""Generate Actor for every User
2
+
3
+Revision ID: d3c41a9e2688
4
+Revises: 32f48de123f3
5
+Create Date: 2018-08-05 10:47:58.540699
6
+
7
+"""
8
+
9
+# revision identifiers, used by Alembic.
10
+revision = 'd3c41a9e2688'
11
+down_revision = '32f48de123f3'
12
+
13
+from models import db, User, create_actor  # noqa: E402
14
+
15
+
16
+def upgrade():
17
+    for user in User.query.all():
18
+        a = create_actor(user)
19
+        a.user = user
20
+        a.user_id = user.id
21
+        db.session.add(a)
22
+    db.session.commit()
23
+
24
+
25
+def downgrade():
26
+    pass

+ 111
- 11
models.py View File

@@ -1,23 +1,42 @@
1 1
 import datetime
2 2
 import os
3 3
 
4
+from flask import current_app
4 5
 from flask_security import SQLAlchemyUserDatastore, UserMixin, RoleMixin
5 6
 from flask_sqlalchemy import SQLAlchemy
6 7
 from slugify import slugify
8
+from sqlalchemy import UniqueConstraint
7 9
 from sqlalchemy import event
10
+from sqlalchemy.ext.hybrid import Comparator
11
+from sqlalchemy.ext.hybrid import hybrid_property
8 12
 from sqlalchemy.sql import func
9 13
 from sqlalchemy_searchable import make_searchable
10
-from sqlalchemy.ext.hybrid import Comparator, hybrid_property
14
+from sqlalchemy_utils.types.choice import ChoiceType
15
+from sqlalchemy_utils.types.url import URLType
16
+from little_boxes.key import Key as LittleBoxesKey
17
+from activitypub.utils import ap_url
11 18
 
12 19
 db = SQLAlchemy()
13 20
 make_searchable(db.metadata)
14 21
 
15 22
 
23
+# #### Base ####
24
+
16 25
 class CaseInsensitiveComparator(Comparator):
17 26
     def __eq__(self, other):
18 27
         return func.lower(self.__clause_element__()) == func.lower(other)
19 28
 
20 29
 
30
+class Config(db.Model):
31
+    __tablename__ = "config"
32
+
33
+    id = db.Column(db.Integer, primary_key=True)
34
+    app_name = db.Column(db.String(255), default=None)
35
+    app_description = db.Column(db.Text)
36
+
37
+
38
+# #### User ####
39
+
21 40
 roles_users = db.Table('roles_users',
22 41
                        db.Column('user_id',
23 42
                                  db.Integer(),
@@ -110,13 +129,7 @@ class Apitoken(db.Model):
110 129
 user_datastore = SQLAlchemyUserDatastore(db, User, Role)
111 130
 
112 131
 
113
-class Config(db.Model):
114
-    __tablename__ = "config"
115
-
116
-    id = db.Column(db.Integer, primary_key=True)
117
-    app_name = db.Column(db.String(255), default=None)
118
-    app_description = db.Column(db.Text)
119
-
132
+# #### Logging ####
120 133
 
121 134
 class Logging(db.Model):
122 135
     __tablename__ = "logging"
@@ -151,6 +164,8 @@ class UserLogging(db.Model):
151 164
     __mapper_args__ = {"order_by": timestamp.desc()}
152 165
 
153 166
 
167
+# #### Tracks ####
168
+
154 169
 class SoundInfo(db.Model):
155 170
     __tablename__ = "sound_info"
156 171
 
@@ -185,10 +200,10 @@ class Sound(db.Model):
185 200
     id = db.Column(db.Integer, primary_key=True)
186 201
     title = db.Column(db.String(255), nullable=True)
187 202
     uploaded = db.Column(db.DateTime(timezone=False),
188
-                         default=datetime.datetime.utcnow)
203
+                         default=func.now())
189 204
     updated = db.Column(db.DateTime(timezone=False),
190
-                        default=datetime.datetime.utcnow,
191
-                        onupdate=datetime.datetime.utcnow)
205
+                        default=func.now(),
206
+                        onupdate=func.now())
192 207
     # TODO genre
193 208
     # TODO tags
194 209
     # TODO picture ?
@@ -347,3 +362,88 @@ def make_album_slug(mapper, connection, target):
347 362
         Album.__table__.update().where(
348 363
             Album.__table__.c.id == target.id).values(slug=slug)
349 364
         )
365
+
366
+
367
+# #### Federation ####
368
+
369
+ACTOR_TYPE_CHOICES = [
370
+    ("Person", "Person"),
371
+    ("Application", "Application"),
372
+    ("Group", "Group"),
373
+    ("Organization", "Organization"),
374
+    ("Service", "Service"),
375
+]
376
+
377
+
378
+class Actor(db.Model):
379
+    __tablename__ = "actor"
380
+    ap_type = "Actor"
381
+
382
+    id = db.Column(db.Integer, primary_key=True)
383
+
384
+    url = db.Column(URLType(), unique=True, index=True)
385
+    outbox_url = db.Column(URLType())
386
+    inbox_url = db.Column(URLType())
387
+    following_url = db.Column(URLType(), nullable=True)
388
+    followers_url = db.Column(URLType(), nullable=True)
389
+    shared_inbox_url = db.Column(URLType(), nullable=True)
390
+    type = db.Column(ChoiceType(ACTOR_TYPE_CHOICES), server_default="Person")
391
+    name = db.Column(db.String(200), nullable=True)
392
+    domain = db.Column(db.String(1000), nullable=False)
393
+    summary = db.Column(db.String(500), nullable=True)
394
+    preferred_username = db.Column(db.String(200), nullable=True)
395
+    public_key = db.Column(db.String(5000), nullable=True)
396
+    private_key = db.Column(db.String(5000), nullable=True)
397
+    creation_date = db.Column(db.DateTime(timezone=False),
398
+                              default=func.now())
399
+    last_fetch_date = db.Column(db.DateTime(timezone=False),
400
+                                default=func.now())
401
+    manually_approves_followers = db.Column(db.Boolean, nullable=True,
402
+                                            server_default=None)
403
+    followers = None  # relation FIXME
404
+
405
+    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=True)
406
+    user = db.relationship("User", backref=db.backref('actor'))
407
+
408
+    __table_args__ = (
409
+        UniqueConstraint('domain', 'preferred_username',
410
+                         name='_domain_pref_username_uc'),
411
+    )
412
+
413
+    def webfinger_subject(self):
414
+        return f"{self.preferred_username}@{self.domain}"
415
+
416
+    def private_key_id(self):
417
+        return f"{self.url}#main-key"
418
+
419
+    def mention_username(self):
420
+        return f"@{self.preferred_username}@{self.domain}"
421
+
422
+    def is_local(self):
423
+        return self.domain == current_app.config['AP_DOMAIN']
424
+
425
+
426
+def create_actor(user):
427
+    """
428
+    :param user: an User object
429
+    :return: an Actor object
430
+    """
431
+    actor = Actor()
432
+
433
+    # Init a new Keypair for this user
434
+    key = LittleBoxesKey(owner=user.name)
435
+    key.new()
436
+
437
+    actor.preferred_username = user.name
438
+    actor.domain = current_app.config['AP_DOMAIN']
439
+    actor.type = "Person"
440
+    actor.name = user.name
441
+    actor.manually_approves_followers = False
442
+    actor.url = ap_url("url", user.name)
443
+    actor.shared_inbox_url = ap_url("shared_inbox", user.name)
444
+    actor.inbox_url = ap_url("inbox", user.name)
445
+    actor.outbox_url = ap_url("outbox", user.name)
446
+    actor.private_key = key.privkey_pem
447
+    actor.public_key = key.pubkey_pem
448
+
449
+    return actor

+ 1
- 0
shelltools.py View File

@@ -0,0 +1 @@
1
+from models import *  # noqa: F403, F401

+ 201
- 127
translations/fr/LC_MESSAGES/messages.po View File

@@ -7,143 +7,178 @@ msgid ""
7 7
 msgstr ""
8 8
 "Project-Id-Version: PROJECT VERSION\n"
9 9
 "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
10
-"POT-Creation-Date: 2017-01-02 07:47+0100\n"
10
+"POT-Creation-Date: 2018-08-04 21:43+0200\n"
11 11
 "PO-Revision-Date: 2017-01-02 08:23+0100\n"
12 12
 "Last-Translator: \n"
13 13
 "Language: fr\n"
14 14
 "Language-Team: fr <LL@li.org>\n"
15
-"Plural-Forms: nplurals=2; plural=(n > 1);\n"
15
+"Plural-Forms: nplurals=2; plural=(n > 1)\n"
16 16
 "MIME-Version: 1.0\n"
17 17
 "Content-Type: text/plain; charset=utf-8\n"
18 18
 "Content-Transfer-Encoding: 8bit\n"
19
-"Generated-By: Babel 2.3.4\n"
20
-"X-Generator: Poedit 1.8.9\n"
19
+"Generated-By: Babel 2.6.0\n"
21 20
 
22
-#: forms.py:42
21
+#: app.py:143 controllers/admin.py:53
22
+msgid "Config not found"
23
+msgstr "Configuration non trouvée"
24
+
25
+#: app.py:181 app.py:188 app.py:195 app.py:203
26
+msgid "Whoops, something failed."
27
+msgstr ""
28
+
29
+#: app.py:182
30
+msgid "Page not found"
31
+msgstr ""
32
+
33
+#: app.py:189
34
+msgid "Access forbidden"
35
+msgstr ""
36
+
37
+#: app.py:196
38
+msgid "Gone"
39
+msgstr ""
40
+
41
+#: app.py:205
42
+msgid "Something is broken"
43
+msgstr ""
44
+
45
+#: forms.py:46
23 46
 msgid "Username required"
24 47
 msgstr "Nom d'utilisateur requis"
25 48
 
26
-#: forms.py:46
49
+#: forms.py:51
27 50
 msgid "Username already taken"
28 51
 msgstr "Nom d'utilisateur déjà pris"
29 52
 
30
-#: forms.py:53
53
+#: forms.py:58
31 54
 msgid "Password"
32 55
 msgstr "Mot de passe"
33 56
 
34
-#: forms.py:54
57
+#: forms.py:59
35 58
 msgid "Name"
36 59
 msgstr "Nom"
37 60
 
38
-#: forms.py:55
61
+#: forms.py:60
39 62
 msgid "Email"
40 63
 msgstr "Email"
41 64
 
42
-#: forms.py:56
65
+#: forms.py:61
43 66
 msgid "Firstname"
44 67
 msgstr "Prénom"
45 68
 
46
-#: forms.py:57
69
+#: forms.py:62
47 70
 msgid "Lastname"
48 71
 msgstr "Nom"
49 72
 
50
-#: forms.py:58
73
+#: forms.py:63
51 74
 msgid "Timezone"
52 75
 msgstr "Fuseau horaire"
53 76
 
54
-#: forms.py:59
77
+#: forms.py:65
55 78
 msgid "Locale"
56 79
 msgstr "Langue"
57 80
 
58
-#: forms.py:60
81
+#: forms.py:67
59 82
 msgid "Update profile"
60 83
 msgstr "Mettre a jour le profil"
61 84
 
62
-#: forms.py:64
63
-msgid "App Name"
64
-msgstr "Nom de l'application"
85
+#: forms.py:72
86
+msgid "Instance Name"
87
+msgstr ""
65 88
 
66
-#: forms.py:66
89
+#: forms.py:73
90
+msgid "Instance description"
91
+msgstr ""
92
+
93
+#: forms.py:75
67 94
 msgid "Update config"
68 95
 msgstr "Mettre à jour la configuration"
69 96
 
70
-#: forms.py:74 forms.py:90 forms.py:106
97
+#: forms.py:87 forms.py:109 forms.py:130
71 98
 msgid "Title"
72 99
 msgstr "Titre"
73 100
 
74
-#: forms.py:75
101
+#: forms.py:88
75 102
 msgid "File"
76 103
 msgstr "Fichier"
77 104
 
78
-#: forms.py:76 forms.py:91 forms.py:108
105
+#: forms.py:90 forms.py:110 forms.py:133
79 106
 msgid "Private"
80 107
 msgstr "Privé"
81 108
 
82
-#: forms.py:79 forms.py:95
109
+#: forms.py:93 forms.py:114
83 110
 msgid "Album"
84 111
 msgstr "Album"
85 112
 
86
-#: forms.py:84 forms.py:100
113
+#: forms.py:94 forms.py:115
114
+msgid "No album"
115
+msgstr ""
116
+
117
+#: forms.py:98 forms.py:119 templates/sound/show.jinja2:114
118
+msgid "Licence"
119
+msgstr ""
120
+
121
+#: forms.py:103 forms.py:124
87 122
 msgid "Cannot put private sound in public album"
88 123
 msgstr "Impossible de mettre un son privé dans un album public"
89 124
 
90
-#: forms.py:86 templates/layout.jinja2:56
125
+#: forms.py:105 templates/layout.jinja2:63
91 126
 msgid "Upload"
92 127
 msgstr "Uploader"
93 128
 
94
-#: forms.py:92 forms.py:107
129
+#: forms.py:111 forms.py:132
95 130
 msgid "Description"
96 131
 msgstr "Description"
97 132
 
98
-#: forms.py:102
133
+#: forms.py:126
99 134
 msgid "Edit sound"
100 135
 msgstr "Éditer le son"
101 136
 
102
-#: forms.py:110
137
+#: forms.py:135
103 138
 msgid "Save"
104 139
 msgstr "Sauver"
105 140
 
106
-#: controllers/admin.py:17
141
+#: controllers/admin.py:19
107 142
 msgid "Application Logs"
108 143
 msgstr "Logs applicatifs"
109 144
 
110
-#: controllers/admin.py:44
145
+#: controllers/admin.py:49
111 146
 msgid "Application Config"
112 147
 msgstr "Configuration Applicative"
113 148
 
114
-#: controllers/admin.py:48
115
-msgid "Config not found"
116
-msgstr "Configuration non trouvée"
117
-
118
-#: controllers/admin.py:57
149
+#: controllers/admin.py:63
119 150
 msgid "Configuration updated"
120 151
 msgstr "Configuration mise-à-jour"
121 152
 
122
-#: controllers/albums.py:14 templates/album/new.jinja2:7
123
-#: templates/layout.jinja2:57
153
+#: controllers/albums.py:17 templates/album/new.jinja2:7
154
+#: templates/layout.jinja2:64
124 155
 msgid "New album"
125 156
 msgstr "Nouvel album"
126 157
 
127
-#: controllers/albums.py:27
158
+#: controllers/albums.py:35
128 159
 msgid "Created !"
129 160
 msgstr "Crée !"
130 161
 
131
-#: controllers/albums.py:37 controllers/sound.py:19 controllers/sound.py:53
132
-#: controllers/users.py:46 controllers/users.py:63 controllers/users.py:81
162
+#: controllers/albums.py:48 controllers/sound.py:21 controllers/users.py:52
163
+#: controllers/users.py:73 controllers/users.py:93
133 164
 msgid "User not found"
134 165
 msgstr "Utilisateur non trouvé"
135 166
 
136
-#: controllers/albums.py:41 controllers/albums.py:47 controllers/albums.py:50
137
-#: controllers/albums.py:63 controllers/albums.py:94
167
+#: controllers/albums.py:53 controllers/albums.py:59 controllers/albums.py:62
168
+#: controllers/albums.py:80
138 169
 msgid "Album not found"
139 170
 msgstr "Album non trouvé"
140 171
 
141
-#: controllers/albums.py:66 controllers/sound.py:126
172
+#: controllers/albums.py:84 controllers/sound.py:161 controllers/sound.py:203
173
+msgid "Forbidden"
174
+msgstr ""
175
+
176
+#: controllers/albums.py:87 controllers/sound.py:164
142 177
 #, python-format
143 178
 msgid "Edit %(value)s"
144 179
 msgstr "Éditer %(value)s"
145 180
 
146
-#: controllers/albums.py:85
181
+#: controllers/albums.py:112
147 182
 msgid "Public album cannot have private sounds"
148 183
 msgstr "Un album public ne peut avoir de son privé"
149 184
 
@@ -151,114 +186,128 @@ msgstr "Un album public ne peut avoir de son privé"
151 186
 msgid "Home"
152 187
 msgstr "Accueil"
153 188
 
154
-#: controllers/sound.py:23 controllers/sound.py:29 controllers/sound.py:32
155
-#: controllers/sound.py:57 controllers/sound.py:63 controllers/sound.py:66
156
-#: controllers/sound.py:123 controllers/sound.py:148
189
+#: controllers/sound.py:33 controllers/sound.py:39 controllers/sound.py:42
190
+#: controllers/sound.py:157 controllers/sound.py:199
157 191
 msgid "Sound not found"
158 192
 msgstr "Son non trouvé"
159 193
 
160
-#: controllers/sound.py:44
161
-msgid "No HTML5 player supported actually"
162
-msgstr "Aucun lecteur HTML5 actuellement supporté"
163
-
164
-#: controllers/sound.py:82 templates/sound/upload.jinja2:7
194
+#: controllers/sound.py:92 templates/sound/upload.jinja2:7
165 195
 msgid "New upload"
166 196
 msgstr "Nouvel upload"
167 197
 
168
-#: controllers/sound.py:109
198
+#: controllers/sound.py:139
169 199
 msgid "Uploaded !"
170 200
 msgstr "Envoyé !"
171 201
 
172
-#: controllers/users.py:16
202
+#: controllers/users.py:18
173 203
 msgid "User Logs"
174 204
 msgstr "Logs utilisateur"
175 205
 
176
-#: controllers/users.py:42 controllers/users.py:59
177
-#: templates/users/profile.jinja2:5 templates/users/profile_albums.jinja2:5
206
+#: controllers/users.py:48 controllers/users.py:69
207
+#: templates/users/profile.jinja2:13 templates/users/profile_albums.jinja2:13
178 208
 #, python-format
179 209
 msgid "%(value)s' profile"
180 210
 msgstr "Profil de %(value)s"
181 211
 
182
-#: controllers/users.py:77
212
+#: controllers/users.py:89
183 213
 msgid "Edit my profile"
184 214
 msgstr "Éditer mon profile"
185 215
 
186
-#: templates/layout.jinja2:46
216
+#: controllers/users.py:111
217
+msgid "Profile updated"
218
+msgstr ""
219
+
220
+#: templates/about.jinja2:19
221
+#, python-format
222
+msgid "reel2bits is developped by %(dashie)s and is available under MIT license."
223
+msgstr ""
224
+
225
+#: templates/about.jinja2:21
226
+#, python-format
227
+msgid "Source code is here: %(link)s"
228
+msgstr ""
229
+
230
+#: templates/about.jinja2:22
231
+#, python-format
232
+msgid "Issue tracker is here: %(link)s"
233
+msgstr ""
234
+
235
+#: templates/error_page.jinja2:7
236
+#, python-format
237
+msgid "Maybe you can go back to the %(link)s."
238
+msgstr ""
239
+
240
+#: templates/error_page.jinja2:7
241
+msgid "index"
242
+msgstr ""
243
+
244
+#: templates/layout.jinja2:53
187 245
 msgid "Toggle navigation"
188 246
 msgstr "Inverser la navigation"
189 247
 
190
-#: templates/layout.jinja2:58
248
+#: templates/layout.jinja2:65
191 249
 msgid "My Profile"
192 250
 msgstr "Mon profil"
193 251
 
194
-#: templates/layout.jinja2:63
252
+#: templates/layout.jinja2:70
195 253
 msgid "About"
196 254
 msgstr "À propos"
197 255
 
198
-#: templates/layout.jinja2:66
256
+#: templates/layout.jinja2:73 templates/layout.jinja2:111
199 257
 #, python-format
200 258
 msgid "Logged as %(username)s"
201 259
 msgstr "Connecté sous %(username)s"
202 260
 
203
-#: templates/admin/logs.jinja2:24 templates/layout.jinja2:68
261
+#: templates/admin/logs.jinja2:24 templates/layout.jinja2:75
204 262
 msgid "User"
205 263
 msgstr "Utilisateur"
206 264
 
207
-#: templates/layout.jinja2:69
265
+#: templates/layout.jinja2:76
208 266
 msgid "Profile"
209 267
 msgstr "Profile"
210 268
 
211
-#: templates/layout.jinja2:70
269
+#: templates/layout.jinja2:77
212 270
 msgid "Logs"
213 271
 msgstr "Logs"
214 272
 
215
-#: templates/layout.jinja2:73
273
+#: templates/layout.jinja2:80
216 274
 msgid "Admin"
217 275
 msgstr "Administrateur"
218 276
 
219
-#: templates/layout.jinja2:74
277
+#: templates/layout.jinja2:81
220 278
 msgid "App config"
221 279
 msgstr "Configuration applicative"
222 280
 
223
-#: templates/layout.jinja2:75
281
+#: templates/layout.jinja2:82
224 282
 msgid "App logs"
225 283
 msgstr "Logs applicatifs"
226 284
 
227
-#: templates/layout.jinja2:78
285
+#: templates/layout.jinja2:85
228 286
 msgid "Change password"
229 287
 msgstr "Changer mot de passe"
230 288
 
231
-#: templates/layout.jinja2:79
289
+#: templates/layout.jinja2:86
232 290
 msgid "Logout"
233 291
 msgstr "Se déconnecter"
234 292
 
235
-#: templates/layout.jinja2:84
293
+#: templates/layout.jinja2:91
236 294
 msgid "Register"
237 295
 msgstr "S'enregistrer"
238 296
 
239
-#: templates/layout.jinja2:86
297
+#: templates/layout.jinja2:93
240 298
 msgid "Login"
241 299
 msgstr "Se connecter"
242 300
 
243
-#: templates/layout.jinja2:112
301
+#: templates/layout.jinja2:111
244 302
 #, python-format
245
-msgid ""
246
-"Use template for %(link1)s by %(link2)s and use %(link3)s, reel2bits "
247
-"%(link4)s"
303
+msgid "version: %(version)s"
248 304
 msgstr ""
249
-"Utilise une template pour %(link1)s par %(link2)s et utilise %(link3)s, "
250
-"reel2bits %(link4)s"
251
-
252
-#: templates/layout.jinja2:116
253
-msgid "source code"
254
-msgstr "code source"
255 305
 
256
-#: templates/layout.jinja2:118
257
-#, python-format
258
-msgid "Running version %(version)s"
259
-msgstr "Version en cours %(version)s"
306
+#: templates/layout.jinja2:114
307
+msgid "Sources"
308
+msgstr ""
260 309
 
261
-#: templates/layout.jinja2:120
310
+#: templates/layout.jinja2:116
262 311
 msgid "Back to top"
263 312
 msgstr "Retour en haut"
264 313
 
@@ -310,24 +359,23 @@ msgstr "Message"
310 359
 msgid "Actions"
311 360
 msgstr "Actions"
312 361
 
313
-#: templates/admin/logs.jinja2:40 templates/album/show.jinja2:80
314
-#: templates/album/show.jinja2:116 templates/sound/show.jinja2:78
315
-#: templates/users/user_logs.jinja2:43
362
+#: templates/admin/logs.jinja2:40 templates/album/show.jinja2:92
363
+#: templates/album/show.jinja2:130 templates/sound/show.jinja2:89
364
+#: templates/users/user_logs.jinja2:47
316 365
 msgid "yes really"
317 366
 msgstr "oui vraiment"
318 367
 
319
-#: templates/admin/logs.jinja2:40 templates/album/show.jinja2:80
320
-#: templates/album/show.jinja2:116 templates/sound/show.jinja2:78
321
-#: templates/users/user_logs.jinja2:43
368
+#: templates/admin/logs.jinja2:40 templates/album/show.jinja2:92
369
+#: templates/album/show.jinja2:130 templates/sound/show.jinja2:89
370
+#: templates/users/user_logs.jinja2:47
322 371
 msgid "delete"
323 372
 msgstr "supprimer"
324 373
 
325
-#: templates/admin/logs.jinja2:64 templates/users/user_logs.jinja2:67
374
+#: templates/admin/logs.jinja2:64 templates/users/user_logs.jinja2:71
326 375
 msgid "Log deletion"
327 376
 msgstr "Suppression de logs"
328 377
 
329
-#: templates/admin/logs.jinja2:64 templates/album/show.jinja2:153
330
-#: templates/users/user_logs.jinja2:67
378
+#: templates/admin/logs.jinja2:64 templates/users/user_logs.jinja2:71
331 379
 msgid "An error occured"
332 380
 msgstr "Une erreur est survenue"
333 381
 
@@ -344,29 +392,25 @@ msgstr "Quel est le titre ?"
344 392
 msgid "Add a nice description ?"
345 393
 msgstr "Une description sympathique ?"
346 394
 
347
-#: templates/album/edit.jinja2:19 templates/sound/edit.jinja2:23
395
+#: templates/album/edit.jinja2:19 templates/sound/edit.jinja2:24
348 396
 #: templates/users/edit.jinja2:27
349 397
 msgid "Cancel edit"
350 398
 msgstr "Annuler l'édition"
351 399
 
352
-#: templates/album/show.jinja2:19 templates/sound/show.jinja2:23
353
-#: templates/users/profile.jinja2:40 templates/users/profile_albums.jinja2:29
400
+#: templates/album/show.jinja2:31 templates/sound/show.jinja2:39
401
+#: templates/users/profile.jinja2:48 templates/users/profile_albums.jinja2:37
354 402
 #, python-format
355 403
 msgid "%(value)s ago"
356 404
 msgstr "il-y-à %(value)s"
357 405
 
358
-#: templates/album/show.jinja2:112 templates/sound/show.jinja2:74
406
+#: templates/album/show.jinja2:126 templates/sound/show.jinja2:85
359 407
 msgid "edit"
360 408
 msgstr "éditer"
361 409
 
362
-#: templates/album/show.jinja2:122
410
+#: templates/album/show.jinja2:136
363 411
 msgid "This album is empty."
364 412
 msgstr "Cet album est vide."
365 413
 
366
-#: templates/album/show.jinja2:153
367
-msgid "Switch sound"
368
-msgstr "Changer le son"
369
-
370 414
 #: templates/security/change_password.html:9
371 415
 msgid "Set a new password"
372 416
 msgstr "Changer le mot de passe"
@@ -387,44 +431,47 @@ msgstr "Enregistrer un utilisateur"
387 431
 msgid "Edit upload"
388 432
 msgstr "Éditer l'upload"
389 433
 
390
-#: templates/sound/edit.jinja2:19 templates/sound/upload.jinja2:19
434
+#: templates/sound/edit.jinja2:18 templates/sound/upload.jinja2:18
391 435
 msgid "If you want to add to a new album you need to create it separately."
392
-msgstr ""
393
-"Si vous voulez ajouter à un nouvel album, vous devez le créer séparément."
436
+msgstr "Si vous voulez ajouter à un nouvel album, vous devez le créer séparément."
394 437
 
395
-#: templates/sound/show.jinja2:12 templates/users/profile.jinja2:57
438
+#: templates/sound/show.jinja2:24 templates/users/profile.jinja2:65
396 439
 msgid "Please wait, song metadatas are processing..."
397 440
 msgstr "Veuillez attendre, les métadonnés sont en cours de traitement..."
398 441
 
399
-#: templates/sound/show.jinja2:84 templates/users/profile.jinja2:49
442
+#: templates/sound/show.jinja2:28
443
+msgid "Please wait, transcoding is on her way..."
444
+msgstr ""
445
+
446
+#: templates/sound/show.jinja2:110 templates/users/profile.jinja2:57
400 447
 msgid "In album:"
401 448
 msgstr "Dans l'album:"
402 449
 
403
-#: templates/sound/show.jinja2:89
450
+#: templates/sound/show.jinja2:130
404 451
 msgid "Type"
405 452
 msgstr "Type"
406 453
 
407
-#: templates/sound/show.jinja2:90
454
+#: templates/sound/show.jinja2:131
408 455
 msgid "Codec"
409 456
 msgstr "Encodeur"
410 457
 
411
-#: templates/sound/show.jinja2:91
458
+#: templates/sound/show.jinja2:132
412 459
 msgid "Format"
413 460
 msgstr "Format"
414 461
 
415
-#: templates/sound/show.jinja2:92
462
+#: templates/sound/show.jinja2:133
416 463
 msgid "Channels"
417 464
 msgstr "Cannaux"
418 465
 
419
-#: templates/sound/show.jinja2:93
466
+#: templates/sound/show.jinja2:134
420 467
 msgid "Rate"
421 468
 msgstr "Rate"
422 469
 
423
-#: templates/sound/show.jinja2:96 templates/sound/show.jinja2:99
470
+#: templates/sound/show.jinja2:137 templates/sound/show.jinja2:140
424 471
 msgid "Bitrate"
425 472
 msgstr "Bitrate"
426 473
 
427
-#: templates/sound/show.jinja2:103
474
+#: templates/sound/show.jinja2:144
428 475
 msgid "Bitrate mode"
429 476
 msgstr "Bitrate mode"
430 477
 
@@ -433,28 +480,28 @@ msgstr "Bitrate mode"
433 480
 msgid "Edit profile - %(username)s"
434 481
 msgstr "Éditer le profil - %(username)s"
435 482
 
436
-#: templates/users/profile.jinja2:10 templates/users/profile_albums.jinja2:10
483
+#: templates/users/profile.jinja2:18 templates/users/profile_albums.jinja2:18
437 484
 msgid "all sounds"
438 485
 msgstr "tous les sons"
439 486
 
440
-#: templates/users/profile.jinja2:11 templates/users/profile_albums.jinja2:11
487
+#: templates/users/profile.jinja2:19 templates/users/profile_albums.jinja2:19
441 488
 msgid "all albums"
442 489
 msgstr "tous les albums"
443 490
 
444
-#: templates/users/profile.jinja2:15 templates/users/profile_albums.jinja2:15
491
+#: templates/users/profile.jinja2:23 templates/users/profile_albums.jinja2:23
445 492
 msgid "Edit profile"
446 493
 msgstr "Éditer le profil"
447 494
 
448
-#: templates/users/profile.jinja2:66
495
+#: templates/users/profile.jinja2:74
449 496
 msgid "This user haven't uploaded any sound :( !"
450 497
 msgstr "Cet utilisateur n'a rien uploadé :( !"
451 498
 
452
-#: templates/users/profile_albums.jinja2:30
499
+#: templates/users/profile_albums.jinja2:38
453 500
 #, python-format
454 501
 msgid "%(nb)s tracks"
455 502
 msgstr "%(nb)s pistes"
456 503
 
457
-#: templates/users/profile_albums.jinja2:40
504
+#: templates/users/profile_albums.jinja2:48
458 505
 msgid "This user haven't created any album !"
459 506
 msgstr "Cet utilisateur n'a crée aucuns album !"
460 507
 
@@ -464,15 +511,15 @@ msgid "%(username)s's logs (latest 100)"
464 511
 msgstr "Logs de %(username)s (100 derniers)"
465 512
 
466 513
 #: templates/users/user_logs.jinja2:24
467
-msgid "Sound"
468
-msgstr "Son"
514
+msgid "Item ID"
515
+msgstr ""
469 516
 
470 517
 #~ msgid ""
471
-#~ "reel2bits is developped by %(dashie)s and is available under MIT "
472
-#~ "license."
518
+#~ "reel2bits is developped by %(dashie)s "
519
+#~ "and is available under MIT license."
473 520
 #~ msgstr ""
474
-#~ "reel2bits est développé par %(dashie)s et est disponible sous licence "
475
-#~ "MIT."
521
+#~ "reel2bits est développé par %(dashie)s "
522
+#~ "et est disponible sous licence MIT."
476 523
 
477 524
 #~ msgid "Source code is here: %(link)s"
478 525
 #~ msgstr "Code source disponible: %(link)s"
@@ -485,3 +532,30 @@ msgstr "Son"
485 532
 
486 533
 #~ msgid "index"
487 534
 #~ msgstr "accueil"
535
+
536
+#~ msgid "App Name"
537
+#~ msgstr "Nom de l'application"
538
+
539
+#~ msgid "No HTML5 player supported actually"
540
+#~ msgstr "Aucun lecteur HTML5 actuellement supporté"
541
+
542
+#~ msgid ""
543
+#~ "Use template for %(link1)s by %(link2)s"
544
+#~ " and use %(link3)s, reel2bits %(link4)s"
545
+#~ msgstr ""
546
+#~ "Utilise une template pour %(link1)s par"
547
+#~ " %(link2)s et utilise %(link3)s, reel2bits"
548
+#~ " %(link4)s"
549
+
550
+#~ msgid "source code"
551
+#~ msgstr "code source"
552
+
553
+#~ msgid "Running version %(version)s"
554
+#~ msgstr "Version en cours %(version)s"
555
+
556
+#~ msgid "Switch sound"
557
+#~ msgstr "Changer le son"
558
+
559
+#~ msgid "Sound"
560
+#~ msgstr "Son"
561
+

Loading…
Cancel
Save