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. * 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 `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 ## 0.7.1-dev

View file

@ -1,13 +1,20 @@
from flask import Blueprint, jsonify, request from flask import Blueprint, jsonify, request
import sys, datetime, re import sys, datetime, re
from functools import wraps 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 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') bp = Blueprint('api', __name__, url_prefix='/api/V1')
def get_message_info(message): def get_message_info(message):
try:
media = message.uploads[0].url()
except IndexError:
media = None
if media:
print(media)
return { return {
'id': message.id, 'id': message.id,
'user': { 'user': {
@ -16,7 +23,8 @@ def get_message_info(message):
}, },
'text': message.text, 'text': message.text,
'privacy': message.privacy, 'privacy': message.privacy,
'pub_date': message.pub_date.timestamp() 'pub_date': message.pub_date.timestamp(),
'media': media
} }
def validate_access(func): def validate_access(func):
@ -163,6 +171,34 @@ def profile_feed(self, userid):
timeline_media.append(get_message_info(message)) timeline_media.append(get_message_info(message))
return {'timeline_media': timeline_media} 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']) @bp.route('/profile_search', methods=['POST'])
@validate_access @validate_access
def profile_search(self): def profile_search(self):
@ -181,3 +217,53 @@ def profile_search(self):
"users": results "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 * notification - a in-site notification to a user; new in 0.3
''' '''
from flask import request
from peewee import * from peewee import *
import os import os
# here should go `from .utils import get_current_user`, but it will cause # here should go `from .utils import get_current_user`, but it will cause
@ -188,6 +189,8 @@ class Upload(BaseModel):
# helper to retrieve contents # helper to retrieve contents
def filename(self): def filename(self):
return str(self.id) + '.' + self.type return str(self.id) + '.' + self.type
def url(self):
return request.host_url + 'uploads/' + self.filename()
class Notification(BaseModel): class Notification(BaseModel):
type = TextField() type = TextField()

View file

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