Added new API endpoints

This commit is contained in:
Yusur 2019-11-08 16:51:32 +01:00
parent a70b4f2eae
commit 7fb5c47e4d
4 changed files with 101 additions and 8 deletions

View file

@ -4,6 +4,9 @@
* Schema changes: moved `full_name` field from table `userprofile` to table `user` for search improvement reasons.
* Adding `messages_count`, `followers_count` and `following_count` to `profile_info` API endpoint (what I've done to 0.7.1 too).
* Adding media URLs to messages in API.
* Added `relationships_follow`, `relationships_unfollow`, `username_availability` and `edit_profile` endpoints to API.
* Added `url` utility to model `Upload`.
## 0.7.1-dev

View file

@ -1,13 +1,20 @@
from flask import Blueprint, jsonify, request
import sys, datetime, re
from functools import wraps
from .models import User, Message, Relationship, \
from peewee import IntegrityError
from .models import User, Message, Relationship, database, \
MSGPRV_PUBLIC, MSGPRV_UNLISTED, MSGPRV_FRIENDS, MSGPRV_ONLYME
from .utils import check_access_token, Visibility
from .utils import check_access_token, Visibility, push_notification, unpush_notification
bp = Blueprint('api', __name__, url_prefix='/api/V1')
def get_message_info(message):
try:
media = message.uploads[0].url()
except IndexError:
media = None
if media:
print(media)
return {
'id': message.id,
'user': {
@ -16,7 +23,8 @@ def get_message_info(message):
},
'text': message.text,
'privacy': message.privacy,
'pub_date': message.pub_date.timestamp()
'pub_date': message.pub_date.timestamp(),
'media': media
}
def validate_access(func):
@ -163,6 +171,34 @@ def profile_feed(self, userid):
timeline_media.append(get_message_info(message))
return {'timeline_media': timeline_media}
@bp.route('/relationships/<int:userid>/follow', methods=['POST'])
@validate_access
def relationships_follow(self, userid):
user = User[userid]
try:
with database.atomic():
Relationship.create(
from_user=self,
to_user=user,
created_date=datetime.datetime.now())
except IntegrityError:
pass
push_notification('follow', user, user=self.id)
return get_relationship_info(self, user)
@bp.route('/relationships/<int:userid>/unfollow', methods=['POST'])
@validate_access
def relationships_unfollow(self, userid):
user = User[userid]
(Relationship
.delete()
.where(
(Relationship.from_user == self) &
(Relationship.to_user == user))
.execute())
unpush_notification('follow', user, user=self.id)
return get_relationship_info(self, user)
@bp.route('/profile_search', methods=['POST'])
@validate_access
def profile_search(self):
@ -181,3 +217,53 @@ def profile_search(self):
"users": results
}
@bp.route('/username_availability/<username>')
@validate_access
def username_availability(self, username):
current = self.username
is_valid = is_username(username)
if is_valid:
try:
user = User.get(User.username == username)
is_available = current == user.username
except User.DoesNotExist:
is_available = True
else:
is_available = False
return {
'is_valid': is_valid,
'is_available': is_available
}
@bp.route('/edit_profile', methods=['POST'])
@validate_access
def edit_profile(user):
data = request.get_json(True)
username = data['username']
if not username:
# prevent username to be set to empty
username = user.username
if username != user.username:
try:
User.update(username=username).where(User.id == user.id).execute()
except IntegrityError:
raise ValueError('that username is already taken')
full_name = data['full_name'] or username
if full_name != user.full_name:
User.update(full_name=full_name).where(User.id == user.id).execute()
website = data['website'].strip().replace(' ', '%20')
if website and not validate_website(website):
raise ValueError('You should enter a valid URL.')
#location = int(request.form.get('location'))
#if location == 0:
# location = None
UserProfile.update(
biography=data['biography'],
#year=data['year'] if data.get('has_year') else None,
#location=location,
website=website,
instagram=data['instagram'],
facebook=data['facebook'],
telegram=data['telegram']
).where(UserProfile.user == user).execute()
return {}

View file

@ -11,6 +11,7 @@ The tables are:
* notification - a in-site notification to a user; new in 0.3
'''
from flask import request
from peewee import *
import os
# here should go `from .utils import get_current_user`, but it will cause
@ -188,6 +189,8 @@ class Upload(BaseModel):
# helper to retrieve contents
def filename(self):
return str(self.id) + '.' + self.type
def url(self):
return request.host_url + 'uploads/' + self.filename()
class Notification(BaseModel):
type = TextField()

View file

@ -60,13 +60,13 @@ def register():
# unique constraint, the database will raise an IntegrityError.
user = User.create(
username=username,
full_name=request.form.get('full_name') or username,
password=pwdhash(request.form['password']),
email=request.form['email'],
birthday=birthday,
join_date=datetime.datetime.now())
UserProfile.create(
user=user,
full_name=request.form.get('full_name') or username
user=user
)
# mark the user as being 'authenticated' by setting the session vars
@ -260,7 +260,6 @@ def confirm_delete(id):
def profile_checkpoint():
return UserProfile(
user=get_current_user(),
full_name=request.form['full_name'],
biography=request.form['biography'],
location=int(request.form['location']),
year=int(request.form['year'] if request.form.get('has_year') else '0'),
@ -285,6 +284,9 @@ def edit_profile():
except IntegrityError:
flash('That username is already taken')
return render_template('edit_profile.html', profile=profile_checkpoint())
full_name = request.form['full_name'] or username
if full_name != user.full_name:
User.update(full_name=full_name).where(User.id == user.id).execute()
website = request.form['website'].strip().replace(' ', '%20')
if website and not validate_website(website):
flash('You should enter a valid URL.')
@ -293,7 +295,6 @@ def edit_profile():
if location == 0:
location = None
UserProfile.update(
full_name=request.form['full_name'] or username,
biography=request.form['biography'],
year=request.form['year'] if request.form.get('has_year') else None,
location=location,