Adding profiles and adminship
This commit is contained in:
parent
156d58e549
commit
32e7c37158
7 changed files with 133 additions and 16 deletions
|
|
@ -2,6 +2,13 @@
|
|||
|
||||
## 0.6-dev
|
||||
|
||||
* Added user adminship. Admins are users with very high privileges. Adminship can be assigned only at script level (not from the web).
|
||||
* Now one's messages won't show up in public timeline.
|
||||
* Added user profile info. Now you can specify your full name, biography, location, birth year, website, Facebook and Instagram. Of course this is totally optional.
|
||||
* Added reference to terms of service and privacy policy on signup page.
|
||||
* When visiting signup page as logged in, user should confirm he wants to create another account in order to do it.
|
||||
* Moved user stats inside profile info.
|
||||
|
||||
## 0.5.0
|
||||
|
||||
* Removed `type` and `info` fields from `Message` table and merged `privacy` field, previously into a separate table, into that table. In order to make the app work, when upgrading you should run the `migrate_0_4_to_0_5.py` script.
|
||||
|
|
|
|||
57
app.py
57
app.py
|
|
@ -93,6 +93,38 @@ class User(BaseModel):
|
|||
.where(
|
||||
(Notification.target == self) & (Notification.seen == 0)
|
||||
))
|
||||
# user adminship is stored into a separate table; new in 0.6
|
||||
@property
|
||||
def is_admin(self):
|
||||
return UserAdminship.select().where(UserAdminship.user == self).exists()
|
||||
# user profile info; new in 0.6
|
||||
@property
|
||||
def profile(self):
|
||||
# lazy initialization; I don't want (and don't know how)
|
||||
# to do schema changes.
|
||||
try:
|
||||
return UserProfile.get(UserProfile.user == self)
|
||||
except UserProfile.DoesNotExist:
|
||||
return UserProfile.create(user=self, full_name=self.username)
|
||||
|
||||
# User adminship.
|
||||
# A very high privilege where users can review posts.
|
||||
# For very few users only; new in 0.6
|
||||
class UserAdminship(BaseModel):
|
||||
user = ForeignKeyField(User, primary_key=True)
|
||||
|
||||
# User profile.
|
||||
# Additional info for identifying users.
|
||||
# New in 0.6
|
||||
class UserProfile(BaseModel):
|
||||
user = ForeignKeyField(User, primary_key=True)
|
||||
full_name = TextField()
|
||||
biography = TextField(default='')
|
||||
location = IntegerField(null=True)
|
||||
year = IntegerField(null=True)
|
||||
website = TextField(null=True)
|
||||
instagram = TextField(null=True)
|
||||
facebook = TextField(null=True)
|
||||
|
||||
# The message privacy values.
|
||||
MSGPRV_PUBLIC = 0 # everyone
|
||||
|
|
@ -118,11 +150,11 @@ class Message(BaseModel):
|
|||
privacy = self.privacy
|
||||
if user == cur_user:
|
||||
# short path
|
||||
return True
|
||||
# also: don't show user's messages in public timeline
|
||||
return not is_public_timeline
|
||||
elif privacy == MSGPRV_PUBLIC:
|
||||
return True
|
||||
elif privacy == MSGPRV_UNLISTED:
|
||||
# TODO user's posts may appear the same in public timeline,
|
||||
# even if unlisted
|
||||
return not is_public_timeline
|
||||
elif privacy == MSGPRV_FRIENDS:
|
||||
|
|
@ -172,7 +204,8 @@ class Notification(BaseModel):
|
|||
def create_tables():
|
||||
with database:
|
||||
database.create_tables([
|
||||
User, Message, Relationship, Upload, Notification])
|
||||
User, UserAdminship, UserProfile, Message, Relationship,
|
||||
Upload, Notification])
|
||||
if not os.path.isdir(UPLOAD_DIRECTORY):
|
||||
os.makedirs(UPLOAD_DIRECTORY)
|
||||
|
||||
|
|
@ -384,6 +417,11 @@ def register():
|
|||
username = request.form['username'].lower()
|
||||
if not is_username(username):
|
||||
flash('This username is invalid')
|
||||
return render_template('join.html')
|
||||
if username == getattr(get_current_user(), 'username', None) and not request.form.get('confirm_another'):
|
||||
flash('You are already logged in. Please confirm you want to '
|
||||
'create another account by checking the option.')
|
||||
return render_template('join.html')
|
||||
try:
|
||||
with database.atomic():
|
||||
# Attempt to create the user. If the username is taken, due to the
|
||||
|
|
@ -394,6 +432,10 @@ def register():
|
|||
email=request.form['email'],
|
||||
birthday=birthday,
|
||||
join_date=datetime.datetime.now())
|
||||
UserProfile.create(
|
||||
user=user,
|
||||
full_name=request.form.get('full_name') or username
|
||||
)
|
||||
|
||||
# mark the user as being 'authenticated' by setting the session vars
|
||||
login_user(user)
|
||||
|
|
@ -562,6 +604,15 @@ def edit(id):
|
|||
#def confirm_delete(id):
|
||||
# return render_template('confirm_delete.html')
|
||||
|
||||
@app.route('/edit_profile/', methods=['GET', 'POST'])
|
||||
def edit_profile():
|
||||
if request.method == 'POST':
|
||||
user = get_current_user()
|
||||
username = request.form['username']
|
||||
if username != user.username:
|
||||
User.update(username=username).where(User.id == user.id).execute()
|
||||
return render_template('edit_profile.html')
|
||||
|
||||
@app.route('/notifications/')
|
||||
@login_required
|
||||
def notifications():
|
||||
|
|
|
|||
|
|
@ -8,7 +8,12 @@ body{margin:0}
|
|||
.metanav{float:right}
|
||||
.header h1{margin:0;display:inline-block}
|
||||
.flash{background-color:#ff9;border:yellow 1px solid}
|
||||
.infobox{padding:12px;border:#ccc 1px solid}
|
||||
@media (min-width:640px) {
|
||||
.infobox{float:right;width:320px}
|
||||
}
|
||||
.weak{opacity:.5}
|
||||
.field_desc{display:block}
|
||||
.message-visual img{max-width:100%;max-height:8em}
|
||||
.message-options-showhide::before{content:'\2026'}
|
||||
.message-options{display:none}
|
||||
|
|
|
|||
13
templates/edit_profile.html
Normal file
13
templates/edit_profile.html
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block body %}
|
||||
<h2>Edit Profile</h2>
|
||||
|
||||
<form method="POST">
|
||||
<dl>
|
||||
<dt>Username:</dt>
|
||||
<dd><input type="text" class="username_input" name="username" required value="{{ current_user.username }}" autocomplete="off"></dd>
|
||||
<dd><input type="submit" value="Save"></dd>
|
||||
</dl>
|
||||
</form>
|
||||
{% endblock %}
|
||||
30
templates/includes/infobox_profile.html
Normal file
30
templates/includes/infobox_profile.html
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
{% set profile = user.profile %}
|
||||
<div class="infobox">
|
||||
<h3>{{ profile.full_name }}</h3>
|
||||
<p>{{ profile.biography|enrich }}</p>
|
||||
{% if profile.location %}
|
||||
<p><span class="weak">Location:</span> {{ profile.location }}</p>
|
||||
{% endif %}
|
||||
{% if profile.year %}
|
||||
<p><span class="weak">Year:</span> {{ profile.year }}</p>
|
||||
{% endif %}
|
||||
{% if profile.website %}
|
||||
<p><span class="weak">Website:</span> {{ profile.website|urlize }}</p>
|
||||
{% endif %}
|
||||
{% if profile.instagram %}
|
||||
<p><span class="weak">Instagram:</span> <a href="https://www.instagram.com/{{ profile.instagram }}">{{ profile.instagram }}</a></p>
|
||||
{% endif %}
|
||||
{% if profile.facebook %}
|
||||
<p><span class="weak">Facebook:</span> <a href="https://facebook.com/{{ profile.facebook }}">{{ profile.facebook }}</a></p>
|
||||
{% endif %}
|
||||
<p>
|
||||
<strong>{{ user.messages|count }}</strong> messages
|
||||
-
|
||||
<strong>{{ user.followers()|count }}</strong> followers
|
||||
-
|
||||
<strong>{{ user.following()|count }}</strong> following
|
||||
</p>
|
||||
{% if user == current_user %}
|
||||
<p><a href="/edit_profile/">Edit profile</a></p>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
|
@ -1,16 +1,34 @@
|
|||
{% extends "base.html" %}
|
||||
{% block body %}
|
||||
<h2>Join {{ site_name }}</h2>
|
||||
<form action="{{ url_for('register') }}" method="post">
|
||||
<form action="{{ url_for('register') }}" method="POST">
|
||||
<dl>
|
||||
<dt>Username:</dt>
|
||||
<dd><input type="text" class="username-input" name="username"></dd>
|
||||
<dd><input type="text" class="username-input" name="username" autocomplete="off"></dd>
|
||||
<dt>Full name:</dt>
|
||||
<dd>
|
||||
<small class="field_desc">If not given, defaults to your username.</small>
|
||||
<input type="text" name="full_name">
|
||||
</dd>
|
||||
<dt>Password:</dt>
|
||||
<dd><input type="password" name="password"></dd>
|
||||
<dt>Email:</dt>
|
||||
<dd><input type="text" name="email"></dd>
|
||||
<dt>Birthday:
|
||||
<dd><input type="text" name="birthday" placeholder="yyyy-mm-dd">
|
||||
<dt>Birthday:</dt>
|
||||
<dd>
|
||||
<small class="field_desc">Your birthday won't be shown to anyone.</small>
|
||||
<input type="text" name="birthday" placeholder="yyyy-mm-dd">
|
||||
</dd>
|
||||
{% if not current_user.is_anonymous %}
|
||||
<dd>
|
||||
<input type="checkbox" name="confirm_another" value="1">
|
||||
<label for="confirm_another">I want to create another account</label>
|
||||
</dd>
|
||||
{% endif %}
|
||||
<dd>
|
||||
<input type="checkbox" name="legal" value="1">
|
||||
<label for="legal">I've read the <a href="/terms/">Terms of Service</a> and <a href="/privacy/">Privacy Policy</a>.</label>
|
||||
</dd>
|
||||
<dd><input type="submit" value="Join">
|
||||
</dl>
|
||||
</form>
|
||||
|
|
|
|||
|
|
@ -1,13 +1,7 @@
|
|||
{% extends "base.html" %}
|
||||
{% block body %}
|
||||
{% include "includes/infobox_profile.html" %}
|
||||
<h2>Messages from {{ user.username }}</h2>
|
||||
<p>
|
||||
<strong>{{ user.messages|count }}</strong> messages
|
||||
-
|
||||
<strong>{{ user.followers()|count }}</strong> followers
|
||||
-
|
||||
<strong>{{ user.following()|count }}</strong> following
|
||||
</p>
|
||||
{% if not current_user.is_anonymous %}
|
||||
{% if user.username != current_user.username %}
|
||||
{% if current_user|is_following(user) %}
|
||||
|
|
@ -21,8 +15,7 @@
|
|||
{% endif %}
|
||||
<p><a href="/create/?preload=%2B{{ user.username }}">Mention this user in a message</a></p>
|
||||
{% else %}
|
||||
<!-- here should go the "edit profile" button -->
|
||||
<a href="/create/">Create a status</a>
|
||||
<a href="/create/">Create a message</a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
<ul>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue