mirror of
				https://gitlab.ub.uni-bielefeld.de/sfb1288inf/nopaque.git
				synced 2025-11-03 20:02:47 +00:00 
			
		
		
		
	user settings page
This commit is contained in:
		@@ -77,6 +77,9 @@ def create_app(config: Config = Config) -> Flask:
 | 
			
		||||
 | 
			
		||||
    from .main import bp as main_blueprint
 | 
			
		||||
    app.register_blueprint(main_blueprint, url_prefix='/')
 | 
			
		||||
    
 | 
			
		||||
    from .profile import bp as profile_blueprint
 | 
			
		||||
    app.register_blueprint(profile_blueprint, url_prefix='/profile')
 | 
			
		||||
 | 
			
		||||
    from .services import bp as services_blueprint
 | 
			
		||||
    app.register_blueprint(services_blueprint, url_prefix='/services')
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										5
									
								
								app/profile/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								app/profile/__init__.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
			
		||||
from flask import Blueprint
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
bp = Blueprint('profile', __name__)
 | 
			
		||||
from . import routes  # noqa
 | 
			
		||||
							
								
								
									
										24
									
								
								app/profile/routes.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								app/profile/routes.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,24 @@
 | 
			
		||||
from flask import render_template, url_for
 | 
			
		||||
from flask_login import current_user, login_required
 | 
			
		||||
from app import db
 | 
			
		||||
from app.models import User
 | 
			
		||||
from . import bp
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@bp.route('')
 | 
			
		||||
@login_required
 | 
			
		||||
def profile():
 | 
			
		||||
  user_image = 'static/images/user_avatar.png'
 | 
			
		||||
  user_name = current_user.username
 | 
			
		||||
  last_seen = current_user.last_seen
 | 
			
		||||
  member_since = current_user.member_since
 | 
			
		||||
  email = current_user.email
 | 
			
		||||
  role = current_user.role
 | 
			
		||||
  return render_template('profile/profile_page.html.j2', 
 | 
			
		||||
  user_image=user_image, 
 | 
			
		||||
  user_name=user_name, 
 | 
			
		||||
  last_seen=last_seen, 
 | 
			
		||||
  member_since=member_since, 
 | 
			
		||||
  email=email, 
 | 
			
		||||
  role=role)
 | 
			
		||||
 | 
			
		||||
@@ -1,10 +1,12 @@
 | 
			
		||||
from flask_wtf import FlaskForm
 | 
			
		||||
from wtforms import (
 | 
			
		||||
    BooleanField,
 | 
			
		||||
    FileField,
 | 
			
		||||
    PasswordField,
 | 
			
		||||
    SelectField,
 | 
			
		||||
    StringField,
 | 
			
		||||
    SubmitField,
 | 
			
		||||
    TextAreaField,
 | 
			
		||||
    ValidationError
 | 
			
		||||
)
 | 
			
		||||
from wtforms.validators import (
 | 
			
		||||
@@ -47,6 +49,9 @@ class ChangePasswordForm(FlaskForm):
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class EditGeneralSettingsForm(FlaskForm):
 | 
			
		||||
    user_avatar = FileField(
 | 
			
		||||
        'Image File'
 | 
			
		||||
    )
 | 
			
		||||
    email = StringField(
 | 
			
		||||
        'E-Mail',
 | 
			
		||||
        validators=[InputRequired(), Length(max=254), Email()]
 | 
			
		||||
@@ -65,8 +70,41 @@ class EditGeneralSettingsForm(FlaskForm):
 | 
			
		||||
            )
 | 
			
		||||
        ]
 | 
			
		||||
    )
 | 
			
		||||
    full_name = StringField(
 | 
			
		||||
        'Full name',
 | 
			
		||||
        validators=[Length(max=128)]
 | 
			
		||||
    )
 | 
			
		||||
    bio = TextAreaField(
 | 
			
		||||
        'About me', 
 | 
			
		||||
        validators=[
 | 
			
		||||
            Length(max=254)
 | 
			
		||||
        ]
 | 
			
		||||
    )
 | 
			
		||||
    website = StringField(
 | 
			
		||||
        'Website',
 | 
			
		||||
        validators=[
 | 
			
		||||
            Length(max=254)
 | 
			
		||||
        ]
 | 
			
		||||
    )
 | 
			
		||||
    organization = StringField(
 | 
			
		||||
        'Organization',
 | 
			
		||||
        validators=[
 | 
			
		||||
            Length(max=128)
 | 
			
		||||
        ]
 | 
			
		||||
    )
 | 
			
		||||
    location = StringField(
 | 
			
		||||
        'Location',
 | 
			
		||||
        validators=[
 | 
			
		||||
            Length(max=128)
 | 
			
		||||
        ]
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    submit = SubmitField()
 | 
			
		||||
 | 
			
		||||
    def validate_image_file(self, field):
 | 
			
		||||
        if not field.data.filename.lower().endswith('.jpg' or '.png' or '.jpeg'):
 | 
			
		||||
            raise ValidationError('only .jpg, .png and .jpeg!')
 | 
			
		||||
 | 
			
		||||
    def __init__(self, user, *args, **kwargs):
 | 
			
		||||
        super().__init__(*args, **kwargs)
 | 
			
		||||
        self.user = user
 | 
			
		||||
@@ -96,3 +134,9 @@ class EditNotificationSettingsForm(FlaskForm):
 | 
			
		||||
            (x.name, x.name.capitalize())
 | 
			
		||||
            for x in UserSettingJobStatusMailNotificationLevel
 | 
			
		||||
        ]
 | 
			
		||||
 | 
			
		||||
class EditPrivacySettingsForm(FlaskForm):
 | 
			
		||||
    public_profile = BooleanField(
 | 
			
		||||
        'Public profile'
 | 
			
		||||
    )
 | 
			
		||||
    submit = SubmitField()
 | 
			
		||||
 
 | 
			
		||||
@@ -6,7 +6,8 @@ from . import bp
 | 
			
		||||
from .forms import (
 | 
			
		||||
    ChangePasswordForm,
 | 
			
		||||
    EditGeneralSettingsForm,
 | 
			
		||||
    EditNotificationSettingsForm
 | 
			
		||||
    EditNotificationSettingsForm,
 | 
			
		||||
    EditPrivacySettingsForm
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -26,7 +27,10 @@ def settings():
 | 
			
		||||
        data=current_user.to_json_serializeable(),
 | 
			
		||||
        prefix='edit-notification-settings-form'
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    edit_privacy_settings_form = EditPrivacySettingsForm(
 | 
			
		||||
        data=current_user.to_json_serializeable(),
 | 
			
		||||
        prefix='edit-privacy-settings-form'
 | 
			
		||||
    )
 | 
			
		||||
    if change_password_form.submit.data and change_password_form.validate():
 | 
			
		||||
        current_user.password = change_password_form.new_password.data
 | 
			
		||||
        db.session.commit()
 | 
			
		||||
@@ -49,10 +53,13 @@ def settings():
 | 
			
		||||
        db.session.commit()
 | 
			
		||||
        flash('Your changes have been saved')
 | 
			
		||||
        return redirect(url_for('.settings'))
 | 
			
		||||
    user_image = 'static/images/user_avatar.png'
 | 
			
		||||
    return render_template(
 | 
			
		||||
        'settings/settings.html.j2',
 | 
			
		||||
        change_password_form=change_password_form,
 | 
			
		||||
        edit_general_settings_form=edit_general_settings_form,
 | 
			
		||||
        edit_notification_settings_form=edit_notification_settings_form,
 | 
			
		||||
        title='Settings'
 | 
			
		||||
        edit_privacy_settings_form=edit_privacy_settings_form,
 | 
			
		||||
        user_image=user_image,
 | 
			
		||||
        title='Profile & Settings'
 | 
			
		||||
    )
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								app/static/images/user_avatar.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								app/static/images/user_avatar.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 2.0 KiB  | 
							
								
								
									
										42
									
								
								app/templates/profile/profile_page.html.j2
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								app/templates/profile/profile_page.html.j2
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,42 @@
 | 
			
		||||
{% extends "base.html.j2" %}
 | 
			
		||||
{% import "materialize/wtf.html.j2" as wtf %}
 | 
			
		||||
 | 
			
		||||
{% block page_content %}
 | 
			
		||||
    <div class="container">
 | 
			
		||||
        <div class="row">
 | 
			
		||||
          <div class="col s12">
 | 
			
		||||
            <div class="card">
 | 
			
		||||
              <div class="card-content">
 | 
			
		||||
                <div class="row">
 | 
			
		||||
                  <div class="col s1"></div>
 | 
			
		||||
                  <div class="col s3">
 | 
			
		||||
                    <img src="{{ user_image }}" alt="user-image" class="circle responsive-img">
 | 
			
		||||
                  </div>
 | 
			
		||||
                  <div class="col s1"></div>
 | 
			
		||||
                  <div class="col s7">
 | 
			
		||||
                    <h3>{{ user_name }}</h3>
 | 
			
		||||
                    <div class="chip">Last seen: {{ last_seen }}</div>
 | 
			
		||||
                    <p><span class="material-icons" style="margin-right:20px; margin-top:20px;">location_on</span><i>Bielefeld</i></p>
 | 
			
		||||
                    <p></p>
 | 
			
		||||
                    <br>
 | 
			
		||||
                    <p>Inga Kirschnick</p>
 | 
			
		||||
                    <p>Bio</p>
 | 
			
		||||
                  </div>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="row">
 | 
			
		||||
                  <div class="col s1"></div>
 | 
			
		||||
                  <div class="col s6">
 | 
			
		||||
                    <p>{{ email }}</p>
 | 
			
		||||
                    <p>Webseite</p>
 | 
			
		||||
                    <p>Organization</p>
 | 
			
		||||
                    <p>Member since: {{ member_since }}</p>
 | 
			
		||||
                    <p>Role: {{ role }}</p>
 | 
			
		||||
                  </div>
 | 
			
		||||
                </div>
 | 
			
		||||
              </div>
 | 
			
		||||
            </div>
 | 
			
		||||
            </div>
 | 
			
		||||
          </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
{% endblock page_content %}
 | 
			
		||||
@@ -14,63 +14,99 @@
 | 
			
		||||
        {{ edit_general_settings_form.hidden_tag() }}
 | 
			
		||||
        <div class="card">
 | 
			
		||||
          <div class="card-content">
 | 
			
		||||
            <span class="card-title">General settings</span>
 | 
			
		||||
            {{ wtf.render_field(edit_general_settings_form.username, material_icon='person') }}
 | 
			
		||||
            {{ wtf.render_field(edit_general_settings_form.email, material_icon='email') }}
 | 
			
		||||
            <span class="card-title" style="margin-bottom: 40px;">Your profile</span>
 | 
			
		||||
            <div class="row">
 | 
			
		||||
              <div class="col s1"></div>
 | 
			
		||||
              <div class="col s3">
 | 
			
		||||
                <img src="{{ user_image }}" alt="user-image" class="circle responsive-img">
 | 
			
		||||
                {{wtf.render_field(edit_general_settings_form.user_avatar, accept='image/*', class='file-path validate')}}
 | 
			
		||||
              </div>
 | 
			
		||||
              <div class="col s1"></div>
 | 
			
		||||
              <div class="col s7">
 | 
			
		||||
                {{ wtf.render_field(edit_general_settings_form.username, material_icon='person') }}
 | 
			
		||||
                {{ wtf.render_field(edit_general_settings_form.email, material_icon='email') }}
 | 
			
		||||
                {{ wtf.render_field(edit_general_settings_form.full_name, material_icon='badge') }}
 | 
			
		||||
                {{ wtf.render_field(edit_general_settings_form.bio, material_icon='description') }}
 | 
			
		||||
              </div>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="row">
 | 
			
		||||
              <div class="col s6">
 | 
			
		||||
                {{ wtf.render_field(edit_general_settings_form.website, material_icon='laptop') }}
 | 
			
		||||
                {{ wtf.render_field(edit_general_settings_form.organization, material_icon='business') }}
 | 
			
		||||
                {{ wtf.render_field(edit_general_settings_form.location, material_icon='location_on') }}
 | 
			
		||||
              </div>
 | 
			
		||||
            </div>
 | 
			
		||||
          </div>
 | 
			
		||||
          <div class="card-action">
 | 
			
		||||
            <div class="right-align">
 | 
			
		||||
              {{ wtf.render_field(edit_general_settings_form.submit, material_icon='send') }}
 | 
			
		||||
            </div>
 | 
			
		||||
          </div>
 | 
			
		||||
        </form>
 | 
			
		||||
      </div>
 | 
			
		||||
    </form>
 | 
			
		||||
        </div>
 | 
			
		||||
      </form>
 | 
			
		||||
 | 
			
		||||
    <form method="POST">
 | 
			
		||||
      {{ edit_notification_settings_form.hidden_tag() }}
 | 
			
		||||
      <div class="card">
 | 
			
		||||
        <div class="card-content">
 | 
			
		||||
          <span class="card-title">Notification settings</span>
 | 
			
		||||
          {{ wtf.render_field(edit_notification_settings_form.job_status_mail_notification_level, material_icon='notifications') }}
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="card-action">
 | 
			
		||||
          <div class="right-align">
 | 
			
		||||
            {{ wtf.render_field(edit_notification_settings_form.submit, material_icon='send') }}
 | 
			
		||||
          <span class="card-title" style="margin-bottom: 40px;">Settings</span>
 | 
			
		||||
          <form method="POST">
 | 
			
		||||
            {{ edit_notification_settings_form.hidden_tag() }}
 | 
			
		||||
            <div class="card">
 | 
			
		||||
              <div class="card-content">
 | 
			
		||||
                <span class="card-title">Notification settings</span>
 | 
			
		||||
                {{ wtf.render_field(edit_notification_settings_form.job_status_mail_notification_level, material_icon='notifications') }}
 | 
			
		||||
              </div>
 | 
			
		||||
              <div class="card-action">
 | 
			
		||||
                <div class="right-align">
 | 
			
		||||
                  {{ wtf.render_field(edit_notification_settings_form.submit, material_icon='send') }}
 | 
			
		||||
                </div>
 | 
			
		||||
              </div>
 | 
			
		||||
            </div>
 | 
			
		||||
          </form>
 | 
			
		||||
          
 | 
			
		||||
          <div class="card">
 | 
			
		||||
            <div class="card-content">
 | 
			
		||||
              <span class="card-title">Privacy settings</span>
 | 
			
		||||
              {{ wtf.render_field(edit_privacy_settings_form.public_profile) }}
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="card-action">
 | 
			
		||||
              <div class="right-align">
 | 
			
		||||
                {{ wtf.render_field(edit_notification_settings_form.submit, material_icon='send') }}
 | 
			
		||||
              </div>
 | 
			
		||||
            </div>
 | 
			
		||||
          </div>
 | 
			
		||||
 | 
			
		||||
          <form method="POST">
 | 
			
		||||
            {{ change_password_form.hidden_tag() }}
 | 
			
		||||
            <div class="card">
 | 
			
		||||
              <div class="card-content">
 | 
			
		||||
                <span class="card-title">Change Password</span>
 | 
			
		||||
                {{ wtf.render_field(change_password_form.password, material_icon='vpn_key') }}
 | 
			
		||||
                {{ wtf.render_field(change_password_form.new_password, material_icon='vpn_key') }}
 | 
			
		||||
                {{ wtf.render_field(change_password_form.new_password_2, material_icon='vpn_key') }}
 | 
			
		||||
              </div>
 | 
			
		||||
              <div class="card-action">
 | 
			
		||||
                <div class="right-align">
 | 
			
		||||
                  {{ wtf.render_field(change_password_form.submit, material_icon='send') }}
 | 
			
		||||
                </div>
 | 
			
		||||
              </div>
 | 
			
		||||
            </div>
 | 
			
		||||
          </form>
 | 
			
		||||
 | 
			
		||||
          <div class="card">
 | 
			
		||||
            <div class="card-content">
 | 
			
		||||
              <span class="card-title">Delete account</span>
 | 
			
		||||
              <p>Deleting an account has the following effects:</p>
 | 
			
		||||
              <ul>
 | 
			
		||||
                <li>All data associated with your corpora and jobs will be permanently deleted.</li>
 | 
			
		||||
                <li>All settings will be permanently deleted.</li>
 | 
			
		||||
              </ul>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="card-action right-align">
 | 
			
		||||
              <a class="btn red waves-effect waves-light" id="delete-user"><i class="material-icons left">delete</i>Delete</a>
 | 
			
		||||
            </div>
 | 
			
		||||
          </div>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </form>
 | 
			
		||||
 | 
			
		||||
    <form method="POST">
 | 
			
		||||
      {{ change_password_form.hidden_tag() }}
 | 
			
		||||
      <div class="card">
 | 
			
		||||
        <div class="card-content">
 | 
			
		||||
          <span class="card-title">Change Password</span>
 | 
			
		||||
          {{ wtf.render_field(change_password_form.password, material_icon='vpn_key') }}
 | 
			
		||||
          {{ wtf.render_field(change_password_form.new_password, material_icon='vpn_key') }}
 | 
			
		||||
          {{ wtf.render_field(change_password_form.new_password_2, material_icon='vpn_key') }}
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="card-action">
 | 
			
		||||
          <div class="right-align">
 | 
			
		||||
            {{ wtf.render_field(change_password_form.submit, material_icon='send') }}
 | 
			
		||||
          </div>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </form>
 | 
			
		||||
 | 
			
		||||
    <div class="card">
 | 
			
		||||
      <div class="card-content">
 | 
			
		||||
        <span class="card-title">Delete account</span>
 | 
			
		||||
        <p>Deleting an account has the following effects:</p>
 | 
			
		||||
        <ul>
 | 
			
		||||
          <li>All data associated with your corpora and jobs will be permanently deleted.</li>
 | 
			
		||||
          <li>All settings will be permanently deleted.</li>
 | 
			
		||||
        </ul>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="card-action right-align">
 | 
			
		||||
        <a class="btn red waves-effect waves-light" id="delete-user"><i class="material-icons left">delete</i>Delete</a>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</div>
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user