Added new API endpoints
This commit is contained in:
parent
a70b4f2eae
commit
7fb5c47e4d
4 changed files with 101 additions and 8 deletions
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
94
app/api.py
94
app/api.py
|
|
@ -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):
|
||||||
|
|
@ -180,4 +216,54 @@ def profile_search(self):
|
||||||
return {
|
return {
|
||||||
"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 {}
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue