Browse Source

Can upload

Dashie der otter 1 year ago
parent
commit
19aea0fdb0
Signed by: Dashie <dashie@sigpipe.me> GPG Key ID: C2D57B325840B755
11 changed files with 120 additions and 65 deletions
  1. 1
    0
      .gitignore
  2. 7
    1
      README.md
  3. 5
    3
      app.py
  4. 31
    52
      controllers/sound.py
  5. 4
    4
      controllers/users.py
  6. 10
    2
      forms.py
  7. 26
    0
      migrations/versions/02_6b5a95742bb4_.py
  8. 6
    1
      models.py
  9. 4
    2
      templates/layout.jinja2
  10. 26
    0
      templates/sound/upload.jinja2
  11. 0
    0
      uploads/.gitkeep

+ 1
- 0
.gitignore View File

@@ -4,4 +4,5 @@ TODO.org
4 4
 .idea
5 5
 *.db
6 6
 uploads/pictures/*
7
+uploads/sounds/*
7 8
 tmp/cty.xml

+ 7
- 1
README.md View File

@@ -33,6 +33,12 @@ Reel2Bits
33 33
   
34 34
 # Crons explained
35 35
   - none yet
36
-  
36
+
37
+# TODO
38
+  - Albums
39
+  - Tags
40
+  - Genre
41
+  - User picture
42
+
37 43
 # Licensing
38 44
  - MIT License

+ 5
- 3
app.py View File

@@ -9,11 +9,12 @@ from flask_bootstrap import Bootstrap
9 9
 from flask_mail import Mail
10 10
 from flask_migrate import Migrate
11 11
 from flask_security import Security
12
-from flask_uploads import configure_uploads, UploadSet, IMAGES
12
+from flask_uploads import configure_uploads, UploadSet, AUDIO
13 13
 
14 14
 from controllers.admin import bp_admin
15 15
 from controllers.main import bp_main
16 16
 from controllers.users import bp_users
17
+from controllers.sound import bp_sound
17 18
 from forms import ExtendedRegisterForm
18 19
 from models import db, user_datastore
19 20
 from utils import dt_utc_to_user_tz, InvalidUsage, show_date_no_offset, is_admin, gcfg
@@ -74,12 +75,13 @@ def create_app(cfg=None):
74 75
         response.status_code = error.status_code
75 76
         return response
76 77
 
77
-    pictures = UploadSet('pictures', IMAGES)
78
-    configure_uploads(app, pictures)
78
+    sounds = UploadSet('sounds', AUDIO)
79
+    configure_uploads(app, sounds)
79 80
 
80 81
     app.register_blueprint(bp_main)
81 82
     app.register_blueprint(bp_users)
82 83
     app.register_blueprint(bp_admin)
84
+    app.register_blueprint(bp_sound)
83 85
 
84 86
     # Used in development
85 87
     @app.route('/uploads/<path:stuff>', methods=['GET'])

+ 31
- 52
controllers/sound.py View File

@@ -2,60 +2,39 @@ import pytz
2 2
 from flask import Blueprint, render_template, request, redirect, url_for, flash
3 3
 from flask_security import login_required, current_user
4 4
 from sqlalchemy import func
5
+from werkzeug.utils import secure_filename
6
+from forms import SoundUploadForm
7
+from models import db, User, UserLogging, Sound
8
+from flask_uploads import UploadSet, AUDIO
5 9
 
6
-from forms import UserProfileForm
7
-from models import db, User, UserLogging
10
+bp_sound = Blueprint('bp_sound', __name__)
8 11
 
9
-bp_users = Blueprint('bp_users', __name__)
12
+sounds = UploadSet('sounds', AUDIO)
10 13
 
11 14
 
12
-@bp_users.route('/user/logs', methods=['GET'])
15
+@bp_sound.route('/sound/upload', methods=['GET', 'POST'])
13 16
 @login_required
14
-def logs():
15
-    level = request.args.get('level')
16
-    pcfg = {"title": "User Logs"}
17
-    if level:
18
-        _logs = UserLogging.query.filter(UserLogging.level == level.upper(),
19
-                                         UserLogging.user_id == current_user.id
20
-                                         ).order_by(UserLogging.timestamp.desc()).limit(100).all()
21
-    else:
22
-        _logs = UserLogging.query.filter(UserLogging.user_id == current_user.id
23
-                                         ).order_by(UserLogging.timestamp.desc()).limit(100).all()
24
-    return render_template('users/user_logs.jinja2', pcfg=pcfg, logs=_logs)
25
-
26
-
27
-@bp_users.route('/user', methods=['GET'])
28
-@login_required
29
-def profile():
30
-    pcfg = {"title": "My Profile"}
31
-
32
-    user = User.query.filter(User.id == current_user.id).first()
33
-    if not user:
34
-        flash("User not found", 'error')
35
-        return redirect(url_for("bp_main.home"))
36
-
37
-    return render_template('users/profile.jinja2', pcfg=pcfg, user=user)
38
-
39
-
40
-@bp_users.route('/user/edit', methods=['GET', 'POST'])
41
-@login_required
42
-def edit():
43
-    pcfg = {"title": "Edit my profile"}
44
-
45
-    user = User.query.filter(User.id == current_user.id).first()
46
-    if not user:
47
-        flash("User not found", 'error')
48
-        return redirect(url_for("bp_main.home"))
49
-
50
-    form = UserProfileForm(request.form, user)
51
-    form.timezone.choices = [[str(i), str(i)] for i in pytz.all_timezones]
52
-
53
-    if form.validate_on_submit():
54
-        user.lastname = form.lastname.data
55
-        user.firstname = form.firstname.data
56
-        user.timezone = form.timezone.data
57
-
58
-        db.session.commit()
59
-        return redirect(url_for('bp_users.profile'))
60
-
61
-    return render_template('users/edit.jinja2', pcfg=pcfg, form=form, user=user)
17
+def upload():
18
+    pcfg = {"title": "New upload"}
19
+
20
+    form = SoundUploadForm()
21
+
22
+    if request.method == 'POST' and 'sound' in request.files:
23
+        if form.validate_on_submit():
24
+            filename = sounds.save(request.files['sound'])
25
+            rec = Sound()
26
+            rec.filename=filename
27
+            rec.user_id=current_user.id
28
+            rec.title = form.title.data
29
+            rec.public = form.public.data
30
+
31
+            db.session.add(rec)
32
+            db.session.commit()
33
+            flash('Uploaded !', 'success')
34
+        else:
35
+            return render_template('sound/upload.jinja2', pcfg=pcfg, form=form, flash='Error with the file')
36
+        return redirect(url_for('bp_main.home', username=current_user.name))
37
+        # TODO redirect to song page
38
+
39
+    # GET
40
+    return render_template('sound/upload.jinja2', pcfg=pcfg, form=form)

+ 4
- 4
controllers/users.py View File

@@ -24,12 +24,12 @@ def logs():
24 24
     return render_template('users/user_logs.jinja2', pcfg=pcfg, logs=_logs)
25 25
 
26 26
 
27
-@bp_users.route('/user', methods=['GET'])
27
+@bp_users.route('/user/<string:name>', methods=['GET'])
28 28
 @login_required
29
-def profile():
30
-    pcfg = {"title": "My Profile"}
29
+def profile(name):
30
+    pcfg = {"title": "%s's profile" % name}
31 31
 
32
-    user = User.query.filter(User.id == current_user.id).first()
32
+    user = User.query.filter(User.name == name).first()
33 33
     if not user:
34 34
         flash("User not found", 'error')
35 35
         return redirect(url_for("bp_main.home"))

+ 10
- 2
forms.py View File

@@ -2,7 +2,7 @@ import datetime
2 2
 from libqth import is_valid_qth
3 3
 
4 4
 from flask_security import RegisterForm, current_user
5
-from flask_uploads import UploadSet, IMAGES
5
+from flask_uploads import UploadSet, AUDIO
6 6
 from flask_wtf import Form
7 7
 from flask_wtf.file import FileField, FileAllowed, FileRequired
8 8
 from wtforms import PasswordField, SubmitField, TextAreaField, SelectField, IntegerField, \
@@ -20,7 +20,7 @@ from utils import dt_utc_to_user_tz
20 20
 
21 21
 BaseModelForm = model_form_factory(Form)
22 22
 
23
-pictures = UploadSet('pictures', IMAGES)
23
+sounds = UploadSet('sounds', AUDIO)
24 24
 
25 25
 
26 26
 class PasswordFieldNotHidden(StringField):
@@ -69,3 +69,11 @@ class ConfigForm(Form):
69 69
     app_name = StringField('App Name', [DataRequired()])
70 70
 
71 71
     submit = SubmitField('Update config')
72
+
73
+
74
+class SoundUploadForm(Form):
75
+    title = StringField('Title')
76
+    sound = FileField('File', [FileRequired(), FileAllowed(AUDIO)])
77
+    public = BooleanField('Public', default=True)
78
+
79
+    submit = SubmitField('Upload')

+ 26
- 0
migrations/versions/02_6b5a95742bb4_.py View File

@@ -0,0 +1,26 @@
1
+"""Add Sound filename
2
+
3
+Revision ID: 6b5a95742bb4
4
+Revises: da3273ca0f0f
5
+Create Date: 2016-12-31 15:24:39.095388
6
+
7
+"""
8
+
9
+# revision identifiers, used by Alembic.
10
+revision = '6b5a95742bb4'
11
+down_revision = 'da3273ca0f0f'
12
+
13
+from alembic import op
14
+import sqlalchemy as sa
15
+
16
+
17
+def upgrade():
18
+    ### commands auto generated by Alembic - please adjust! ###
19
+    op.add_column('sound', sa.Column('filename', sa.String(length=255), nullable=True))
20
+    ### end Alembic commands ###
21
+
22
+
23
+def downgrade():
24
+    ### commands auto generated by Alembic - please adjust! ###
25
+    op.drop_column('sound', 'filename')
26
+    ### end Alembic commands ###

+ 6
- 1
models.py View File

@@ -127,10 +127,12 @@ class Sound(db.Model):
127 127
     description = db.Column(db.UnicodeText(), nullable=True)
128 128
     public = db.Column(db.Boolean(), default=True, nullable=False)
129 129
     slug = db.Column(db.String(255), unique=True, nullable=True)
130
+    filename = db.Column(db.String(255), unique=False, nullable=True)
130 131
 
131 132
     user_id = db.Column(db.Integer(), db.ForeignKey('user.id'), nullable=False)
132 133
     sound_infos = db.relationship('SoundInfo', backref='sound_info', lazy='dynamic', cascade="delete")
133 134
 
135
+
134 136
 @event.listens_for(User, 'after_update')
135 137
 @event.listens_for(User, 'after_insert')
136 138
 def make_slug(mapper, connection, target):
@@ -145,7 +147,10 @@ def make_slug(mapper, connection, target):
145 147
 @event.listens_for(Sound, 'after_insert')
146 148
 def make_slug(mapper, connection, target):
147 149
     if not target.slug or target.slug == "":
148
-        title = "{0} {1}".format(target.id, target.title)
150
+        if not target.title or target.title == "":
151
+            title = "{0} {1}".format(target.id, target.filename)
152
+        else:
153
+            title = "{0} {1}".format(target.id, target.title)
149 154
         slug = slugify(title)
150 155
         connection.execute(
151 156
             User.__table__.update().where(User.__table__.c.id == target.id).values(slug=slug)

+ 4
- 2
templates/layout.jinja2 View File

@@ -52,7 +52,9 @@
52 52
         </div>
53 53
         <div id="navbar" class="navbar-collapse collapse">
54 54
           <ul class="nav navbar-nav">
55
-
55
+            {% if current_user.is_authenticated %}
56
+                <li><a href="{{ url_for('bp_sound.upload') }}">Upload</a></li>
57
+            {% endif %}
56 58
           </ul>
57 59
           <ul class="nav navbar-nav navbar-right">
58 60
             {% if request.endpoint %}
@@ -62,7 +64,7 @@
62 64
                       <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Logged as {{ current_user.name }} <span class="caret"></span></a>
63 65
                       <ul class="dropdown-menu">
64 66
                           <li class="dropdown-header">User</li>
65
-                          <li><a href="{{ url_for('bp_users.profile') }}">Profile</a></li>
67
+                          <li><a href="{{ url_for('bp_users.profile', name=current_user.name) }}">Profile</a></li>
66 68
                           <li><a href="{{ url_for('bp_users.logs') }}">Logs</a></li>
67 69
                           {% if is_admin() %}
68 70
                               <li role="separator" class="divider"></li>

+ 26
- 0
templates/sound/upload.jinja2 View File

@@ -0,0 +1,26 @@
1
+{% extends "layout.jinja2" %}
2
+{% import "bootstrap/wtf.html" as wtf %}
3
+
4
+{% block content %}
5
+    <div class="row">
6
+        <div class="col-lg-6">
7
+            <h3>New upload</h3>
8
+        </div>
9
+    </div>
10
+<div class="row">
11
+    <div class="col-lg-6">
12
+        <form action="{{ url_for('bp_sound.upload') }}" method="POST" class="form-horizontal" enctype="multipart/form-data">
13
+            {{ form.hidden_tag() }}
14
+            {{ wtf.form_errors(form, hiddens=True) }}
15
+            {{ wtf.form_field(form.title, 'horizontal', placeholder="What's the title ?") }}
16
+            {{ wtf.form_field(form.sound, 'horizontal', accept='.wav, .mp3, .aac, .ogg, .oga, .flac') }}
17
+            {{ wtf.form_field(form.public, 'horizontal') }}
18
+            {{ wtf.form_field(form.submit, button_map={'submit': 'success'}) }}
19
+        </form>
20
+    </div>
21
+
22
+    <div class="col-lg-6">
23
+    </div>
24
+
25
+</div>
26
+{% endblock %}

+ 0
- 0
uploads/.gitkeep View File


Loading…
Cancel
Save