From a009bbe1f941f9adfd178182ae255f804b574e2d Mon Sep 17 00:00:00 2001
From: Inga Kirschnick <inga.kirschnick@uni-bielefeld.de>
Date: Wed, 30 Nov 2022 14:36:42 +0100
Subject: [PATCH] Profile page

---
 app/admin/routes.py                        |  16 +--
 app/models.py                              |   5 +
 app/profile/forms.py                       |  87 +++++++++++++++
 app/profile/routes.py                      |  55 ++++++++--
 app/settings/forms.py                      |  12 +--
 app/settings/routes.py                     |  19 +---
 app/templates/_sidenav.html.j2             |  12 ++-
 app/templates/profile/edit_profile.html.j2 |  43 ++++++++
 app/templates/profile/profile_page.html.j2 |  61 +++++++++--
 app/templates/settings/settings.html.j2    | 119 +++++++--------------
 migrations/versions/4820fa2e3ee2_.py       |  44 ++++++++
 11 files changed, 342 insertions(+), 131 deletions(-)
 create mode 100644 app/profile/forms.py
 create mode 100644 app/templates/profile/edit_profile.html.j2
 create mode 100644 migrations/versions/4820fa2e3ee2_.py

diff --git a/app/admin/routes.py b/app/admin/routes.py
index c4480e18..90d9034d 100644
--- a/app/admin/routes.py
+++ b/app/admin/routes.py
@@ -5,7 +5,7 @@ from app import db, hashids
 from app.decorators import admin_required
 from app.models import Role, User, UserSettingJobStatusMailNotificationLevel
 from app.settings.forms import (
-    EditGeneralSettingsForm,
+    EditProfileSettingsForm,
     EditNotificationSettingsForm
 )
 from . import bp
@@ -51,10 +51,10 @@ def edit_user(user_id):
         data={'confirmed': user.confirmed, 'role': user.role.hashid},
         prefix='admin-edit-user-form'
     )
-    edit_general_settings_form = EditGeneralSettingsForm(
+    edit_profile_settings_form = EditProfileSettingsForm(
         user,
         data=user.to_json_serializeable(),
-        prefix='edit-general-settings-form'
+        prefix='edit-profile-settings-form'
     )
     edit_notification_settings_form = EditNotificationSettingsForm(
         data=user.to_json_serializeable(),
@@ -68,10 +68,10 @@ def edit_user(user_id):
         db.session.commit()
         flash('Your changes have been saved')
         return redirect(url_for('.edit_user', user_id=user.id))
-    if (edit_general_settings_form.submit.data
-            and edit_general_settings_form.validate()):
-        user.email = edit_general_settings_form.email.data
-        user.username = edit_general_settings_form.username.data
+    if (edit_profile_settings_form.submit.data
+            and edit_profile_settings_form.validate()):
+        user.email = edit_profile_settings_form.email.data
+        user.username = edit_profile_settings_form.username.data
         db.session.commit()
         flash('Your changes have been saved')
         return redirect(url_for('.edit_user', user_id=user.id))
@@ -87,7 +87,7 @@ def edit_user(user_id):
     return render_template(
         'admin/edit_user.html.j2',
         admin_edit_user_form=admin_edit_user_form,
-        edit_general_settings_form=edit_general_settings_form,
+        edit_profile_settings_form=edit_profile_settings_form,
         edit_notification_settings_form=edit_notification_settings_form,
         title='Edit user',
         user=user
diff --git a/app/models.py b/app/models.py
index c607dc5f..62d0d99b 100644
--- a/app/models.py
+++ b/app/models.py
@@ -262,6 +262,11 @@ class User(HashidMixin, UserMixin, db.Model):
         default=UserSettingJobStatusMailNotificationLevel.END
     )
     last_seen = db.Column(db.DateTime())
+    full_name = db.Column(db.String(64))
+    about_me = db.Column(db.String(256))
+    location = db.Column(db.String(64))
+    website = db.Column(db.String(128))
+    organization = db.Column(db.String(128))
     # Backrefs: role: Role
     # Relationships
     tesseract_ocr_pipeline_models = db.relationship(
diff --git a/app/profile/forms.py b/app/profile/forms.py
new file mode 100644
index 00000000..bcb9daf9
--- /dev/null
+++ b/app/profile/forms.py
@@ -0,0 +1,87 @@
+from flask_wtf import FlaskForm
+from wtforms import (
+    FileField,
+    StringField,
+    SubmitField,
+    TextAreaField,
+    ValidationError
+)
+from wtforms.validators import (
+    InputRequired,
+    Email,
+    Length,
+    Regexp
+)
+from app.models import User
+from app.auth import USERNAME_REGEX
+
+class EditProfileSettingsForm(FlaskForm):
+    user_avatar = FileField(
+        'Image File'
+    )
+    email = StringField(
+        'E-Mail',
+        validators=[InputRequired(), Length(max=254), Email()]
+    )
+    username = StringField(
+        'Username',
+        validators=[
+            InputRequired(),
+            Length(max=64),
+            Regexp(
+                USERNAME_REGEX,
+                message=(
+                    'Usernames must have only letters, numbers, dots or '
+                    'underscores'
+                )
+            )
+        ]
+    )
+    full_name = StringField(
+        'Full name',
+        validators=[Length(max=128)]
+    )
+    about_me = 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 __init__(self, user, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+        self.user = user
+
+    def validate_email(self, field):
+        if (field.data != self.user.email
+                and User.query.filter_by(email=field.data).first()):
+            raise ValidationError('Email already registered')
+
+    def validate_username(self, field):
+        if (field.data != self.user.username
+                and User.query.filter_by(username=field.data).first()):
+            raise ValidationError('Username already in use')
+   
+    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!')
diff --git a/app/profile/routes.py b/app/profile/routes.py
index 5487d417..8001ddb4 100644
--- a/app/profile/routes.py
+++ b/app/profile/routes.py
@@ -1,24 +1,61 @@
-from flask import render_template, url_for
+from flask import flash, redirect, render_template, url_for
 from flask_login import current_user, login_required
 from app import db
 from app.models import User
 from . import bp
-
+from .forms import (
+  EditProfileSettingsForm
+)
 
 @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
+  last_seen = f'{current_user.last_seen.strftime("%Y-%m-%d %H:%M")}'
+  location = 'Bielefeld'
+  about_me = '''Lorem ipsum dolor sit amet, consetetur sadipscing elitr, 
+                sed diam nonumy eirmod tempor invidunt ut labore et dolore 
+                magna aliquyam erat, sed diam voluptua. At vero eos et accusam 
+                et justo duo dolores et ea rebum. Stet clita kasd gubergren, 
+                no sea takimat'''
+  full_name = 'Inga Kirschnick'
   email = current_user.email
-  role = current_user.role
+  website = 'https://nopaque.uni-bielefeld.de'
+  organization = 'Universität Bielefeld'
+  member_since = f'{current_user.member_since.strftime("%Y-%m-%d")}'
   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)
+  last_seen=last_seen,
+  location=location,
+  about_me=about_me,
+  full_name=full_name,
+  email=email,
+  website=website,
+  organization=organization,
+  member_since=member_since)
 
+@bp.route('/edit')
+@login_required
+def edit_profile():
+  edit_profile_settings_form = EditProfileSettingsForm(
+        current_user,
+        data=current_user.to_json_serializeable(),
+        prefix='edit-profile-settings-form'
+  )
+  if (edit_profile_settings_form.submit.data
+            and edit_profile_settings_form.validate()):
+        current_user.email = edit_profile_settings_form.email.data
+        current_user.username = edit_profile_settings_form.username.data
+        current_user.about_me = edit_profile_settings_form.about_me.data
+        current_user.location = edit_profile_settings_form.location.data
+        current_user.organization = edit_profile_settings_form.organization.data
+        current_user.website = edit_profile_settings_form.website.data
+        current_user.full_name = edit_profile_settings_form.full_name.data
+        db.session.commit()
+        flash('Your changes have been saved')
+        return redirect(url_for('.profile.edit_profile'))
+  return render_template('profile/edit_profile.html.j2',
+  edit_profile_settings_form=edit_profile_settings_form,
+  title='Edit Profile')
diff --git a/app/settings/forms.py b/app/settings/forms.py
index 1403b501..25bb5f1f 100644
--- a/app/settings/forms.py
+++ b/app/settings/forms.py
@@ -48,7 +48,7 @@ class ChangePasswordForm(FlaskForm):
             raise ValidationError('Invalid password')
 
 
-class EditGeneralSettingsForm(FlaskForm):
+class EditProfileSettingsForm(FlaskForm):
     user_avatar = FileField(
         'Image File'
     )
@@ -74,7 +74,7 @@ class EditGeneralSettingsForm(FlaskForm):
         'Full name',
         validators=[Length(max=128)]
     )
-    bio = TextAreaField(
+    about_me = TextAreaField(
         'About me', 
         validators=[
             Length(max=254)
@@ -101,10 +101,6 @@ class EditGeneralSettingsForm(FlaskForm):
 
     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
@@ -118,6 +114,10 @@ class EditGeneralSettingsForm(FlaskForm):
         if (field.data != self.user.username
                 and User.query.filter_by(username=field.data).first()):
             raise ValidationError('Username already in use')
+   
+    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!')
 
 
 class EditNotificationSettingsForm(FlaskForm):
diff --git a/app/settings/routes.py b/app/settings/routes.py
index 42400136..d7e36218 100644
--- a/app/settings/routes.py
+++ b/app/settings/routes.py
@@ -5,7 +5,6 @@ from app.models import UserSettingJobStatusMailNotificationLevel
 from . import bp
 from .forms import (
     ChangePasswordForm,
-    EditGeneralSettingsForm,
     EditNotificationSettingsForm,
     EditPrivacySettingsForm
 )
@@ -18,11 +17,6 @@ def settings():
         current_user,
         prefix='change-password-form'
     )
-    edit_general_settings_form = EditGeneralSettingsForm(
-        current_user,
-        data=current_user.to_json_serializeable(),
-        prefix='edit-general-settings-form'
-    )
     edit_notification_settings_form = EditNotificationSettingsForm(
         data=current_user.to_json_serializeable(),
         prefix='edit-notification-settings-form'
@@ -36,13 +30,7 @@ def settings():
         db.session.commit()
         flash('Your changes have been saved')
         return redirect(url_for('.index'))
-    if (edit_general_settings_form.submit.data
-            and edit_general_settings_form.validate()):
-        current_user.email = edit_general_settings_form.email.data
-        current_user.username = edit_general_settings_form.username.data
-        db.session.commit()
-        flash('Your changes have been saved')
-        return redirect(url_for('.settings'))
+    
     if (edit_notification_settings_form.submit.data
             and edit_notification_settings_form.validate()):
         current_user.setting_job_status_mail_notification_level = (
@@ -53,13 +41,10 @@ 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,
         edit_privacy_settings_form=edit_privacy_settings_form,
-        user_image=user_image,
-        title='Profile & Settings'
+        title='Settings'
     )
diff --git a/app/templates/_sidenav.html.j2 b/app/templates/_sidenav.html.j2
index b0ea6de8..f87f701e 100644
--- a/app/templates/_sidenav.html.j2
+++ b/app/templates/_sidenav.html.j2
@@ -2,8 +2,16 @@
   <li>
     <div class="user-view">
       <div class="background primary-color"></div>
-      <span class="white-text name">{{ current_user.username }}</span>
-      <span class="white-text email">{{ current_user.email }}</span>
+      <div class="row">
+        <div class="col s2">
+          <a href="{{ url_for('profile.profile') }}">
+          <i class="material-icons" style="color:white; font-size:3em; margin-top: 25px; margin-left:-15px;">account_circle</i></div>
+          </a>
+        <div class="col s10">
+          <span class="white-text name">{{ current_user.username }}</span>
+          <span class="white-text email">{{ current_user.email }}</span>
+        </div>
+      </div>
     </div>
   </li>
   <li><a href="{{ url_for('main.index') }}">nopaque</a></li>
diff --git a/app/templates/profile/edit_profile.html.j2 b/app/templates/profile/edit_profile.html.j2
new file mode 100644
index 00000000..3a5ce381
--- /dev/null
+++ b/app/templates/profile/edit_profile.html.j2
@@ -0,0 +1,43 @@
+{% extends "base.html.j2" %}
+{% import "materialize/wtf.html.j2" as wtf %}
+
+{% block page_content %}
+<div class="container">
+  <div class="row">
+    <div class="col s12">
+        <h1 id="title">{{ title }}</h1>
+      </div>
+    <div class="col s12">
+      <form method="POST">
+        {{ edit_profile_settings_form.hidden_tag() }}
+        <div class="card">
+          <div class="card-content">
+            <div class="row">
+              <div class="col s1"></div>
+              <div class="col s3">
+                <img src="{{ url_for('static', filename='images/user_avatar.png') }}" alt="user-image" class="circle responsive-img">
+                {{wtf.render_field(edit_profile_settings_form.user_avatar, accept='image/*', class='file-path validate')}}
+              </div>
+              <div class="col s1"></div>
+              <div class="col s7">
+                {{ wtf.render_field(edit_profile_settings_form.username, material_icon='person') }}
+                {{ wtf.render_field(edit_profile_settings_form.email, material_icon='email') }}
+                {{ wtf.render_field(edit_profile_settings_form.full_name, material_icon='badge') }}
+                {{ wtf.render_field(edit_profile_settings_form.about_me, material_icon='description') }}
+                {{ wtf.render_field(edit_profile_settings_form.website, material_icon='laptop') }}
+                {{ wtf.render_field(edit_profile_settings_form.organization, material_icon='business') }}
+                {{ wtf.render_field(edit_profile_settings_form.location, material_icon='location_on') }}
+              </div>
+            </div>
+          </div>
+          <div class="card-action">
+            <div class="right-align">
+              {{ wtf.render_field(edit_profile_settings_form.submit, material_icon='send') }}
+            </div>
+          </div>
+        </div>
+      </form>
+    </div>
+  </div>
+</div>
+{% endblock page_content %}
diff --git a/app/templates/profile/profile_page.html.j2 b/app/templates/profile/profile_page.html.j2
index cf724303..fd4648aa 100644
--- a/app/templates/profile/profile_page.html.j2
+++ b/app/templates/profile/profile_page.html.j2
@@ -10,33 +10,76 @@
                 <div class="row">
                   <div class="col s1"></div>
                   <div class="col s3">
+                    {% if about_me %}
+                    <img src="{{ user_image }}" alt="user-image" class="circle responsive-img" style="margin-top:50px;">
+                    {% else %}
                     <img src="{{ user_image }}" alt="user-image" class="circle responsive-img">
+                    {% endif %}
                   </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>
+                    {% if location %}
+                    <p><span class="material-icons" style="margin-right:20px; margin-top:20px;">location_on</span><i>{{ location }}</i></p>
+                    {% endif %}
                     <p></p>
                     <br>
-                    <p>Inga Kirschnick</p>
-                    <p>Bio</p>
+                    {% if about_me%}
+                    <div class="card">
+                      <div class="card-content">
+                        <span class="card-title">About me</span>
+                        <p>{{ about_me }}</p>
+                      </div>
+                    </div>
+                    {% endif %}
                   </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>
+                    <table>
+                      {% if full_name %}
+                      <tr>
+                        <td><span class="material-icons">person</span></td>
+                        <td>{{ full_name }} </td>
+                      </tr>
+                      {% endif %}
+                      {% if email %}
+                      <tr>
+                        <td><span class="material-icons">email</span></td>
+                        <td>{{ email }}</td>
+                      </tr>
+                      {% endif %}
+                      {% if website %}
+                      <tr>
+                        <td><span class="material-icons">laptop</span></td>
+                        <td><a href="{{ website }}">{{ website }}</a></td>
+                      </tr>
+                      {% endif %}
+                      {% if organization %}
+                      <tr>
+                        <td><span class="material-icons">business</span></td>
+                        <td>{{ organization }}</td>
+                      </tr>
+                      {% endif %}
+                    </table>
+                    <br>
+                    <p><i>Member since: {{ member_since }}</i></p>
+                    <p></p>
+                    <br>
+                    <a class="waves-effect waves-light btn-small" href="{{ url_for('settings.settings') }}">Edit profile</a>
                   </div>
                 </div>
               </div>
             </div>
-            </div>
           </div>
         </div>
+        <div class="row">
+          <div class="col s6">
+          
+          </div>
+
+        </div>
     </div>
 {% endblock page_content %}
diff --git a/app/templates/settings/settings.html.j2 b/app/templates/settings/settings.html.j2
index a61e77ad..b33ab0a1 100644
--- a/app/templates/settings/settings.html.j2
+++ b/app/templates/settings/settings.html.j2
@@ -8,104 +8,63 @@
     <div class="col s12">
       <h1 id="title">{{ title }}</h1>
     </div>
-
     <div class="col s12">
       <form method="POST">
-        {{ edit_general_settings_form.hidden_tag() }}
+        {{ edit_notification_settings_form.hidden_tag() }}
         <div class="card">
           <div class="card-content">
-            <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>
+            <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_general_settings_form.submit, material_icon='send') }}
+              {{ 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" 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>
+          <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>
+      <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>
diff --git a/migrations/versions/4820fa2e3ee2_.py b/migrations/versions/4820fa2e3ee2_.py
new file mode 100644
index 00000000..4f821f66
--- /dev/null
+++ b/migrations/versions/4820fa2e3ee2_.py
@@ -0,0 +1,44 @@
+"""Add profile pages columns to users table
+
+Revision ID: 4820fa2e3ee2
+Revises: 31b9c0259e6b
+Create Date: 2022-11-30 10:03:49.080576
+
+"""
+from alembic import op
+import sqlalchemy as sa
+
+revision = '4820fa2e3ee2'
+down_revision = '31b9c0259e6b'
+branch_labels = None
+depends_on = None
+
+def upgrade():
+
+    op.add_column(
+        'users',
+        sa.Column('full_name', sa.String(length=64), nullable=True)
+    )
+    op.add_column(
+        'users',
+        sa.Column('about_me', sa.String(length=256), nullable=True)
+    )
+    op.add_column(
+        'users',
+        sa.Column('location', sa.String(length=64), nullable=True)
+    )
+    op.add_column(
+        'users',
+        sa.Column('website', sa.String(length=128), nullable=True)
+    )
+    op.add_column(
+        'users',
+        sa.Column('organization', sa.String(length=128), nullable=True)
+    )
+
+def downgrade():
+    op.drop_column('users', 'organization')
+    op.drop_column('users', 'website')
+    op.drop_column('users', 'location')
+    op.drop_column('users', 'about_me')
+    op.drop_column('users', 'full_name')
-- 
GitLab