diff --git a/nerochan/forms.py b/nerochan/forms.py index 9a5788d..c8a885a 100644 --- a/nerochan/forms.py +++ b/nerochan/forms.py @@ -1,5 +1,7 @@ +from urllib.parse import urlparse + from flask_wtf import FlaskForm -from wtforms import StringField, BooleanField +from wtforms import StringField, BooleanField, TextAreaField, EmailField from wtforms.validators import DataRequired, ValidationError from flask_wtf.file import FileField, FileRequired, FileAllowed from monero.address import address @@ -25,7 +27,6 @@ def is_valid_user(form, field): u = User.select().where(User.handle == field.data).first() if not u: raise ValidationError('User does not exist') - return True except ValueError: raise ValidationError('Error looking up user') @@ -53,3 +54,26 @@ class CreateArtwork(FlaskForm): description = StringField('Description:', validators=[], render_kw={'placeholder': 'Description', 'class': 'u-full-width', 'type': 'text'}) nsfw = BooleanField('NSFW:') content = FileField('Upload:', validators=[FileRequired(), FileAllowed(config.ALLOWED_UPLOADS)]) + +class EditProfile(UserRegistration): + website = StringField('Website URL:', render_kw={'placeholder': 'https:// .....', 'class': 'u-full-width', 'type': 'text'}) + twitter_handle = StringField('Twitter Handle:', render_kw={'placeholder': '@lza_menace', 'class': 'u-full-width', 'type': 'text'}) + bio = TextAreaField('Bio:', render_kw={'placeholder': 'So there I was...', 'class': 'u-full-width', 'type': 'text'}) + email = EmailField('Email:', render_kw={'placeholder': 'foo@bar.com', 'class': 'u-full-width', 'type': 'text', 'style': 'color: black;'}) + + def validate_website(form, field): + if not field.data: + return + if len(field.data) > 50: + raise ValidationError('URL too long') + u = urlparse(field.data) + if not u.scheme or not u.scheme.startswith('http'): + raise ValidationError('Invalid URL (requires scheme + domain)') + + def validate_twitter_handle(form, field): + if not field.data: + return + if len(field.data) > 30: + raise ValidationError('Twitter handle too long') + if field.data.startswith('http'): + raise ValidationError('Invalid Twitter handle') diff --git a/nerochan/models.py b/nerochan/models.py index bb4b1e8..b3a0ebc 100644 --- a/nerochan/models.py +++ b/nerochan/models.py @@ -21,7 +21,7 @@ def gen_challenge(): class User(pw.Model): """ - User model is for base user management and reporting. + User model is for user management, reporting, and metadata. """ id = pw.AutoField() register_date = pw.DateTimeField(default=datetime.utcnow) @@ -33,6 +33,10 @@ class User(pw.Model): is_mod = pw.BooleanField(default=False) is_verified = pw.BooleanField(default=False) is_banned = pw.BooleanField(default=False) + website = pw.CharField(unique=True, default='') + twitter_handle = pw.CharField(unique=True, default='') + bio = pw.TextField(default='') + email = pw.CharField(unique=True, default='') @property def is_authenticated(self): @@ -62,26 +66,6 @@ class User(pw.Model): database = db -class Profile(pw.Model): - """ - Profile model is for users to provide metadata about - themselves; artists for their fans or even just the general public. - Links to social media, contact info, portfolio sites, etc - should go in here. - """ - id = pw.AutoField() - user = pw.ForeignKeyField(User) - create_date = pw.DateTimeField(default=datetime.utcnow) - website = pw.CharField(unique=True, null=True) - twitter_handle = pw.CharField(unique=True, null=True) - bio = pw.CharField(null=True) - email = pw.CharField(unique=True, null=True) - verified = pw.CharField(default=False) - - class Meta: - database = db - - class Artwork(pw.Model): """ Artwork model is any uploaded content from a user. diff --git a/nerochan/routes/user.py b/nerochan/routes/user.py index d72341d..6f5467c 100644 --- a/nerochan/routes/user.py +++ b/nerochan/routes/user.py @@ -1,8 +1,9 @@ from math import ceil from flask import Blueprint, render_template, redirect, url_for, flash, request -from flask_login import login_required +from flask_login import login_required, current_user +from nerochan.forms import EditProfile from nerochan.models import User, Artwork, Transaction @@ -43,9 +44,50 @@ def show(handle: str): total_pages=total_pages ) -@bp.route('/profile') +@bp.route('/profile', methods=['GET', 'POST']) @login_required def edit(): + form = EditProfile() + if form.validate_on_submit(): + updated = False + if current_user.handle != form.handle.data: + if not User.select().where(User.handle == form.handle.data).first(): + current_user.handle = form.handle.data + updated = True + else: + flash('That handle is in use.', 'is-error') + if current_user.wallet_address != form.wallet_address.data: + if not User.select().where(User.wallet_address == form.wallet_address.data).first(): + current_user.wallet_address = form.wallet_address.data + updated = True + else: + flash('That wallet address is in use.', 'is-error') + if current_user.email != form.email.data: + if not User.select().where(User.email == form.email.data).first(): + current_user.email = form.email.data + updated = True + else: + flash('That email address is in use.', 'is-error') + if current_user.website != form.website.data: + if not User.select().where(User.website == form.website.data).first(): + current_user.website = form.website.data + updated = True + else: + flash('That website is in use.', 'is-error') + if current_user.twitter_handle != form.twitter_handle.data: + if not User.select().where(User.twitter_handle == form.twitter_handle.data).first(): + current_user.twitter_handle = form.twitter_handle.data + updated = True + else: + flash('That Twitter handle is in use.', 'is-error') + if current_user.bio != form.bio.data: + current_user.bio = form.bio.data + updated = True + if updated: + current_user.save() + flash('Updated your profile.', 'is-success') + return redirect(url_for('user.edit')) return render_template( - 'user/edit.html' + 'user/edit.html', + form=form ) \ No newline at end of file diff --git a/nerochan/static/css/main.css b/nerochan/static/css/main.css index f1d99bd..40d2c6c 100644 --- a/nerochan/static/css/main.css +++ b/nerochan/static/css/main.css @@ -85,7 +85,7 @@ hr { margin-top: 0; } -input[type="text"] { +input[type="text"], textarea { color: black; } diff --git a/nerochan/templates/includes/navbar.html b/nerochan/templates/includes/navbar.html index 9f8813f..262b38c 100644 --- a/nerochan/templates/includes/navbar.html +++ b/nerochan/templates/includes/navbar.html @@ -5,6 +5,7 @@ {%- if current_user.is_authenticated %} + {%- if current_user.is_admin %} {% endif %} diff --git a/nerochan/templates/user/edit.html b/nerochan/templates/user/edit.html index 0da9f1e..864773e 100644 --- a/nerochan/templates/user/edit.html +++ b/nerochan/templates/user/edit.html @@ -2,7 +2,34 @@ {% block content %} -

{{ current_user.handle }}

-

Edit your profile

+
+
+

profile

+

+ Update your artist info/socials for your patrons to find you. + View Profile +

+
+ {% for f in form %} + {% if f.name == 'csrf_token' %} + {{ f }} + {% elif f.name == 'bio' %} + {{ f.label }} + + {% else %} + {{ f.label }} + {{ f(value=current_user[f.name]) }} + {% endif %} + {% endfor %} + +
    + {%- for field, errors in form.errors.items() %} +
  • {{ form[field].label }}: {{ ', '.join(errors) }}
  • + {%- endfor %} +
+ +
+
+
{% endblock %}