Adding explore endpoint and fixing bugs
This commit is contained in:
parent
d40a8b9b6b
commit
29cf1532f7
6 changed files with 73 additions and 33 deletions
10
CHANGELOG.md
10
CHANGELOG.md
|
|
@ -1,5 +1,13 @@
|
|||
# Changelog
|
||||
|
||||
## 0.9-dev
|
||||
|
||||
* Added `create_account` endpoint to API. This endpoint does not require an access token.
|
||||
* Added `has_more` field to feed endpoints (`feed`, `explore` and `profile_feed`).
|
||||
* Added `/favicon.ico`.
|
||||
* Added `explore` endpoint.
|
||||
* Fixed some bugs when creating mentions and using offsets in feeds.
|
||||
|
||||
## 0.8.0
|
||||
|
||||
* Added the admin dashboard, accessible from `/admin/` via basic auth. Only users with admin right can access it. Added endpoints `admin.reports` and `admin.reports_detail`.
|
||||
|
|
@ -12,7 +20,7 @@
|
|||
* Added `relationships_follow`, `relationships_unfollow`, `username_availability`, `edit_profile`, `request_edit` and `confirm_edit` endpoints to API.
|
||||
* Added `url` utility to model `Upload`.
|
||||
* Changed default `robots.txt`, adding report and admin-related lines.
|
||||
* Released official [Android client](https://github.com/sakuragasaki46/coriplusapp/releases/tag/v0.8.0)
|
||||
* Released official [Android client](https://github.com/sakuragasaki46/coriplusapp/releases/tag/v0.8.0).
|
||||
|
||||
## 0.7.1-dev
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ import datetime, time, re, os, sys, string, json, html
|
|||
from functools import wraps
|
||||
from flask_login import LoginManager
|
||||
|
||||
__version__ = '0.8.0'
|
||||
__version__ = '0.9-dev'
|
||||
|
||||
# we want to support Python 3 only.
|
||||
# Python 2 has too many caveats.
|
||||
|
|
@ -69,6 +69,10 @@ def _inject_user(userid):
|
|||
@app.errorhandler(404)
|
||||
def error_404(body):
|
||||
return render_template('404.html'), 404
|
||||
|
||||
@app.route('/favicon.ico')
|
||||
def favicon_ico():
|
||||
return send_from_directory(os.getcwd(), 'favicon.ico')
|
||||
|
||||
@app.route('/robots.txt')
|
||||
def robots_txt():
|
||||
|
|
|
|||
71
app/api.py
71
app/api.py
|
|
@ -1,11 +1,11 @@
|
|||
from flask import Blueprint, jsonify, request
|
||||
import sys, os, datetime, re
|
||||
import sys, os, datetime, re, uuid
|
||||
from functools import wraps
|
||||
from peewee import IntegrityError
|
||||
from .models import User, UserProfile, Message, Upload, Relationship, database, \
|
||||
MSGPRV_PUBLIC, MSGPRV_UNLISTED, MSGPRV_FRIENDS, MSGPRV_ONLYME, UPLOAD_DIRECTORY
|
||||
from .utils import check_access_token, Visibility, push_notification, unpush_notification, \
|
||||
create_mentions, is_username
|
||||
create_mentions, is_username, generate_access_token, pwdhash
|
||||
|
||||
bp = Blueprint('api', __name__, url_prefix='/api/V1')
|
||||
|
||||
|
|
@ -64,17 +64,33 @@ def feed(self):
|
|||
if date is None:
|
||||
date = datetime.datetime.now()
|
||||
else:
|
||||
date = datetime.datetime.fromtimestamp(date)
|
||||
date = datetime.datetime.fromtimestamp(float(date))
|
||||
query = Visibility(Message
|
||||
.select()
|
||||
.where(((Message.user << self.following())
|
||||
| (Message.user == self))
|
||||
& (Message.pub_date < date))
|
||||
.order_by(Message.pub_date.desc())
|
||||
.limit(20))
|
||||
for message in query:
|
||||
.order_by(Message.pub_date.desc()))
|
||||
for message in query.paginate(1):
|
||||
timeline_media.append(get_message_info(message))
|
||||
return {'timeline_media': timeline_media}
|
||||
return {'timeline_media': timeline_media, 'has_more': query.count() > len(timeline_media)}
|
||||
|
||||
@bp.route('/explore')
|
||||
@validate_access
|
||||
def explore(self):
|
||||
timeline_media = []
|
||||
date = request.args.get('offset')
|
||||
if date is None:
|
||||
date = datetime.datetime.now()
|
||||
else:
|
||||
date = datetime.datetime.fromtimestamp(float(date))
|
||||
query = Visibility(Message
|
||||
.select()
|
||||
.where(Message.pub_date < date)
|
||||
.order_by(Message.pub_date.desc()), True)
|
||||
for message in query.paginate(1):
|
||||
timeline_media.append(get_message_info(message))
|
||||
return {'timeline_media': timeline_media, 'has_more': query.count() > len(timeline_media)}
|
||||
|
||||
@bp.route('/create', methods=['POST'])
|
||||
@validate_access
|
||||
|
|
@ -88,7 +104,7 @@ def create(self):
|
|||
pub_date=datetime.datetime.now(),
|
||||
privacy=privacy)
|
||||
# This API does not support files. Use create2 instead.
|
||||
create_mentions(self, text)
|
||||
create_mentions(self, text, privacy)
|
||||
return {}
|
||||
|
||||
@bp.route('/create2', methods=['POST'])
|
||||
|
|
@ -110,7 +126,7 @@ def create2(self):
|
|||
message=message
|
||||
)
|
||||
file.save(os.path.join(UPLOAD_DIRECTORY, str(upload.id) + '.' + ext))
|
||||
create_mentions(self, text)
|
||||
create_mentions(self, text, privacy)
|
||||
return {}
|
||||
|
||||
def get_relationship_info(self, other):
|
||||
|
|
@ -169,16 +185,15 @@ def profile_feed(self, userid):
|
|||
if date is None:
|
||||
date = datetime.datetime.now()
|
||||
else:
|
||||
date = datetime.datetime.fromtimestamp(date)
|
||||
date = datetime.datetime.fromtimestamp(float(date))
|
||||
query = Visibility(Message
|
||||
.select()
|
||||
.where((Message.user == user)
|
||||
& (Message.pub_date < date))
|
||||
.order_by(Message.pub_date.desc())
|
||||
.limit(20))
|
||||
for message in query:
|
||||
.order_by(Message.pub_date.desc()))
|
||||
for message in query.paginate(1):
|
||||
timeline_media.append(get_message_info(message))
|
||||
return {'timeline_media': timeline_media}
|
||||
return {'timeline_media': timeline_media, 'has_more': query.count() > len(timeline_media)}
|
||||
|
||||
@bp.route('/relationships/<int:userid>/follow', methods=['POST'])
|
||||
@validate_access
|
||||
|
|
@ -305,3 +320,31 @@ def save_edit(self, id):
|
|||
data = request.get_json(True)
|
||||
Message.update(text=data['text'], privacy=data['privacy']).where(Message.id == id).execute()
|
||||
return {}
|
||||
|
||||
# no validate access for this endpoint!
|
||||
@bp.route('/create_account', methods=['POST'])
|
||||
def create_account():
|
||||
try:
|
||||
data = request.get_json(True)
|
||||
try:
|
||||
birthday = datetime.datetime.fromisoformat(data['birthday'])
|
||||
except ValueError:
|
||||
raise ValueError('invalid date format')
|
||||
username = data['username'].lower()
|
||||
if not is_username(username):
|
||||
raise ValueError('invalid username')
|
||||
with database.atomic():
|
||||
user = User.create(
|
||||
username=username,
|
||||
full_name=data.get('full_name') or username,
|
||||
password=pwdhash(data['password']),
|
||||
email=data['email'],
|
||||
birthday=birthday,
|
||||
join_date=datetime.datetime.now())
|
||||
UserProfile.create(
|
||||
user=user
|
||||
)
|
||||
|
||||
return jsonify({'access_token': generate_access_token(user), 'status': 'ok'})
|
||||
except Exception as e:
|
||||
return jsonify({'message': str(e), 'status': 'fail'})
|
||||
|
|
|
|||
|
|
@ -198,7 +198,7 @@ def check_access_token(token):
|
|||
if h.hexdigest()[:32] == hh:
|
||||
return user
|
||||
|
||||
def create_mentions(cur_user, text):
|
||||
def create_mentions(cur_user, text, privacy):
|
||||
# create mentions
|
||||
mention_usernames = set()
|
||||
for mo in re.finditer(r'\+([A-Za-z0-9_]+(?:\.[A-Za-z0-9_]+)*)', text):
|
||||
|
|
|
|||
|
|
@ -188,22 +188,7 @@ def create():
|
|||
message=message
|
||||
)
|
||||
file.save(UPLOAD_DIRECTORY + str(upload.id) + '.' + ext)
|
||||
# create mentions
|
||||
mention_usernames = set()
|
||||
for mo in re.finditer(r'\+([A-Za-z0-9_]+(?:\.[A-Za-z0-9_]+)*)', text):
|
||||
mention_usernames.add(mo.group(1))
|
||||
# to avoid self mention
|
||||
mention_usernames.difference_update({user.username})
|
||||
for u in mention_usernames:
|
||||
try:
|
||||
mention_user = User.get(User.username == u)
|
||||
if privacy in (MSGPRV_PUBLIC, MSGPRV_UNLISTED) or \
|
||||
(privacy == MSGPRV_FRIENDS and
|
||||
mention_user.is_following(user) and
|
||||
user.is_following(mention_user)):
|
||||
push_notification('mention', mention_user, user=user.id)
|
||||
except User.DoesNotExist:
|
||||
pass
|
||||
create_mentions(user, text, privacy)
|
||||
flash('Your message has been posted successfully')
|
||||
return redirect(url_for('website.user_detail', username=user.username))
|
||||
return render_template('create.html')
|
||||
|
|
|
|||
BIN
favicon.ico
Normal file
BIN
favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
Loading…
Add table
Add a link
Reference in a new issue