NewsBlur/apps/api/views.py

511 lines
19 KiB
Python
Raw Normal View History

2011-01-21 22:00:36 -05:00
import os
import base64
2020-06-17 00:36:01 -04:00
import urllib.parse
2012-08-25 19:58:03 -07:00
import datetime
import lxml.html
2016-06-28 16:16:36 -07:00
from django import forms
2011-01-21 22:00:36 -05:00
from django.conf import settings
from django.http import HttpResponse
from django.shortcuts import render
from django.contrib.auth import login as login_user
from django.contrib.auth import logout as logout_user
from apps.reader.forms import SignupForm, LoginForm
from apps.profile.models import Profile
from apps.social.models import MSocialProfile, MSharedStory, MSocialSubscription
from apps.rss_feeds.models import Feed, MStarredStoryCounts, MStarredStory
from apps.rss_feeds.text_importer import TextImporter
from apps.reader.models import UserSubscription, UserSubscriptionFolders, RUserStory
from utils import json_functions as json
from utils import log as logging
from utils.feed_functions import relative_timesince
from utils.view_functions import required_params
2018-03-19 14:27:30 -07:00
from utils.user_functions import get_user, ajax_login_required
2012-12-10 13:33:37 -08:00
@json.json_view
def login(request):
code = -1
errors = None
user_agent = request.environ.get('HTTP_USER_AGENT', '')
2015-07-21 10:38:22 -07:00
ip = request.META.get('HTTP_X_FORWARDED_FOR', None) or request.META['REMOTE_ADDR']
if not user_agent or user_agent.lower() in ['nativehost']:
errors = dict(user_agent="You must set a user agent to login.")
logging.user(request, "~FG~BB~SK~FRBlocked ~FGAPI Login~SN~FW: %s / %s" % (user_agent, ip))
elif request.method == "POST":
form = LoginForm(data=request.POST)
if form.errors:
errors = form.errors
if form.is_valid():
login_user(request, form.get_user(), backend='django.contrib.auth.backends.ModelBackend')
2015-07-21 10:38:22 -07:00
logging.user(request, "~FG~BB~SKAPI Login~SN~FW: %s / %s" % (user_agent, ip))
code = 1
else:
errors = dict(method="Invalid method. Use POST. You used %s" % request.method)
return dict(code=code, errors=errors)
@json.json_view
def signup(request):
code = -1
errors = None
2015-07-21 10:38:22 -07:00
ip = request.META.get('HTTP_X_FORWARDED_FOR', None) or request.META['REMOTE_ADDR']
if request.method == "POST":
form = SignupForm(data=request.POST)
if form.errors:
errors = form.errors
if form.is_valid():
2016-06-28 16:16:36 -07:00
try:
new_user = form.save()
login_user(request, new_user, backend='django.contrib.auth.backends.ModelBackend')
2016-06-28 16:16:36 -07:00
logging.user(request, "~FG~SB~BBAPI NEW SIGNUP: ~FW%s / %s" % (new_user.email, ip))
code = 1
2020-06-17 00:36:01 -04:00
except forms.ValidationError as e:
2016-06-28 16:16:36 -07:00
errors = [e.args[0]]
else:
errors = dict(method="Invalid method. Use POST. You used %s" % request.method)
return dict(code=code, errors=errors)
@json.json_view
def logout(request):
code = 1
logging.user(request, "~FG~BBAPI Logout~FW")
logout_user(request)
return dict(code=code)
def add_site_load_script(request, token):
code = 0
usf = None
2020-07-01 16:59:21 -04:00
profile = None
user_profile = None
starred_counts = {}
def image_base64(image_name, path='icons/circular/'):
image_file = open(os.path.join(settings.MEDIA_ROOT, 'img/%s%s' % (path, image_name)), 'rb')
return base64.b64encode(image_file.read()).decode('utf-8')
accept_image = image_base64('newuser_icn_setup.png')
error_image = image_base64('newuser_icn_sharewith_active.png')
new_folder_image = image_base64('g_icn_arrow_right.png')
add_image = image_base64('g_icn_expand_hover.png')
try:
profiles = Profile.objects.filter(secret_token=token)
if profiles:
profile = profiles[0]
usf = UserSubscriptionFolders.objects.get(
user=profile.user
)
user_profile = MSocialProfile.get_user(user_id=profile.user.pk)
starred_counts = MStarredStoryCounts.user_counts(profile.user.pk)
else:
code = -1
except Profile.DoesNotExist:
code = -1
except UserSubscriptionFolders.DoesNotExist:
code = -1
return render(request, 'api/share_bookmarklet.js', {
'code': code,
'token': token,
'folders': (usf and usf.folders) or [],
2012-08-11 17:18:35 -07:00
'user': profile and profile.user or {},
'user_profile': user_profile and json.encode(user_profile.canonical()) or {},
'starred_counts': json.encode(starred_counts),
'accept_image': accept_image,
'error_image': error_image,
'add_image': add_image,
'new_folder_image': new_folder_image,
},
content_type='application/javascript')
def add_site(request, token):
code = 0
url = request.GET['url']
folder = request.GET['folder']
new_folder = request.GET.get('new_folder')
2022-02-16 21:16:24 -08:00
callback = request.GET.get('callback', '')
if not url:
code = -1
else:
try:
profile = Profile.objects.get(secret_token=token)
if new_folder:
usf, _ = UserSubscriptionFolders.objects.get_or_create(user=profile.user)
usf.add_folder(folder, new_folder)
folder = new_folder
code, message, us = UserSubscription.add_subscription(
user=profile.user,
feed_address=url,
folder=folder,
bookmarklet=True
)
except Profile.DoesNotExist:
code = -1
if code > 0:
message = 'OK'
logging.user(profile.user, "~FRAdding URL from site: ~SB%s (in %s)" % (url, folder),
request=request)
return HttpResponse(callback + '(' + json.encode({
'code': code,
'message': message,
'usersub': us and us.feed_id,
}) + ')', content_type='text/plain')
2018-03-19 14:27:30 -07:00
@ajax_login_required
def add_site_authed(request):
code = 0
url = request.GET['url']
folder = request.GET['folder']
new_folder = request.GET.get('new_folder')
callback = request.GET['callback']
user = get_user(request)
2012-08-17 23:29:17 -07:00
2018-03-19 14:27:30 -07:00
if not url:
code = -1
else:
if new_folder:
usf, _ = UserSubscriptionFolders.objects.get_or_create(user=user)
usf.add_folder(folder, new_folder)
folder = new_folder
code, message, us = UserSubscription.add_subscription(
user=user,
feed_address=url,
folder=folder,
bookmarklet=True
)
if code > 0:
message = 'OK'
logging.user(user, "~FRAdding authed URL from site: ~SB%s (in %s)" % (url, folder),
request=request)
return HttpResponse(callback + '(' + json.encode({
'code': code,
'message': message,
'usersub': us and us.feed_id,
}) + ')', content_type='text/plain')
2018-03-19 14:27:30 -07:00
2012-08-17 23:29:17 -07:00
def check_share_on_site(request, token):
code = 0
story_url = request.GET['story_url']
rss_url = request.GET.get('rss_url')
2012-08-17 23:29:17 -07:00
callback = request.GET['callback']
other_stories = None
same_stories = None
usersub = None
2012-08-17 23:29:17 -07:00
message = None
user = None
2012-08-17 23:29:17 -07:00
if not story_url:
code = -1
else:
try:
user_profile = Profile.objects.get(secret_token=token)
user = user_profile.user
2012-08-17 23:29:17 -07:00
except Profile.DoesNotExist:
code = -1
2016-02-24 12:11:41 -08:00
logging.user(request.user, "~FBFinding feed (check_share_on_site): %s" % rss_url)
feed = Feed.get_feed_from_url(rss_url, create=False, fetch=False)
2022-02-16 21:16:24 -08:00
if not feed:
rss_url = urllib.parse.urljoin(story_url, rss_url)
logging.user(request.user, "~FBFinding feed (check_share_on_site): %s" % rss_url)
feed = Feed.get_feed_from_url(rss_url, create=False, fetch=False)
if not feed:
2016-02-24 12:11:41 -08:00
logging.user(request.user, "~FBFinding feed (check_share_on_site): %s" % story_url)
feed = Feed.get_feed_from_url(story_url, create=False, fetch=False)
if not feed:
2020-06-17 00:36:01 -04:00
parsed_url = urllib.parse.urlparse(story_url)
base_url = "%s://%s%s" % (parsed_url.scheme, parsed_url.hostname, parsed_url.path)
2016-02-24 12:11:41 -08:00
logging.user(request.user, "~FBFinding feed (check_share_on_site): %s" % base_url)
feed = Feed.get_feed_from_url(base_url, create=False, fetch=False)
if not feed:
2016-02-24 12:11:41 -08:00
logging.user(request.user, "~FBFinding feed (check_share_on_site): %s" % (base_url + '/'))
feed = Feed.get_feed_from_url(base_url+'/', create=False, fetch=False)
if feed and user:
try:
usersub = UserSubscription.objects.filter(user=user, feed=feed)
except UserSubscription.DoesNotExist:
usersub = None
feed_id = feed and feed.pk
your_story, same_stories, other_stories = MSharedStory.get_shared_stories_from_site(feed_id,
user_id=user_profile.user.pk, story_url=story_url)
previous_stories = MSharedStory.objects.filter(user_id=user_profile.user.pk).order_by('-shared_date').limit(3)
previous_stories = [{
"user_id": story.user_id,
"story_title": story.story_title,
"comments": story.comments,
"shared_date": story.shared_date,
"relative_date": relative_timesince(story.shared_date),
"blurblog_permalink": story.blurblog_permalink(),
} for story in previous_stories]
user_ids = set([user_profile.user.pk])
for story in same_stories:
user_ids.add(story['user_id'])
for story in other_stories:
user_ids.add(story['user_id'])
users = {}
profiles = MSocialProfile.profiles(user_ids)
for profile in profiles:
users[profile.user_id] = {
"username": profile.username,
"photo_url": profile.photo_url,
}
logging.user(user_profile.user, "~BM~FCChecking share from site: ~SB%s" % (story_url),
request=request)
response = HttpResponse(callback + '(' + json.encode({
'code' : code,
'message' : message,
'feed' : feed,
'subscribed' : bool(usersub),
'your_story' : your_story,
'same_stories' : same_stories,
'other_stories' : other_stories,
'previous_stories' : previous_stories,
'users' : users,
}) + ')', content_type='text/plain')
response['Access-Control-Allow-Origin'] = '*'
response['Access-Control-Allow-Methods'] = 'GET'
return response
2012-08-17 23:29:17 -07:00
@required_params('story_url', 'comments', 'title')
def share_story(request, token=None):
code = 0
story_url = request.POST['story_url']
comments = request.POST['comments']
title = request.POST['title']
content = request.POST.get('content', None)
rss_url = request.POST.get('rss_url', None)
feed_id = request.POST.get('feed_id', None) or 0
feed = None
message = None
profile = None
2012-08-17 23:29:17 -07:00
if request.user.is_authenticated:
profile = request.user.profile
2012-08-17 23:29:17 -07:00
else:
try:
profile = Profile.objects.get(secret_token=token)
except Profile.DoesNotExist:
code = -1
if token:
message = "Not authenticated, couldn't find user by token."
else:
message = "Not authenticated, no token supplied and not authenticated."
if not profile:
return HttpResponse(json.encode({
'code': code,
'message': message,
'story': None,
}), content_type='text/plain')
if feed_id:
feed = Feed.get_by_id(feed_id)
else:
if rss_url:
2016-02-24 12:11:41 -08:00
logging.user(request.user, "~FBFinding feed (share_story): %s" % rss_url)
feed = Feed.get_feed_from_url(rss_url, create=True, fetch=True)
if not feed:
2016-02-24 12:11:41 -08:00
logging.user(request.user, "~FBFinding feed (share_story): %s" % story_url)
feed = Feed.get_feed_from_url(story_url, create=True, fetch=True)
if feed:
feed_id = feed.pk
if content:
content = lxml.html.fromstring(content)
content.make_links_absolute(story_url)
content = lxml.html.tostring(content)
else:
importer = TextImporter(story=None, story_url=story_url, request=request, debug=settings.DEBUG)
document = importer.fetch(skip_save=True, return_document=True)
content = document['content']
if not title:
title = document['title']
shared_story = MSharedStory.objects.filter(user_id=profile.user.pk,
story_feed_id=feed_id,
story_guid=story_url).limit(1).first()
if not shared_story:
story_db = {
"story_guid": story_url,
"story_permalink": story_url,
"story_title": title,
"story_feed_id": feed_id,
"story_content": content,
2012-08-25 19:58:03 -07:00
"story_date": datetime.datetime.now(),
2012-08-17 23:29:17 -07:00
"user_id": profile.user.pk,
"comments": comments,
"has_comments": bool(comments),
}
shared_story = MSharedStory.objects.create(**story_db)
socialsubs = MSocialSubscription.objects.filter(subscription_user_id=profile.user.pk)
for socialsub in socialsubs:
socialsub.needs_unread_recalc = True
socialsub.save()
logging.user(profile.user, "~BM~FYSharing story from site: ~SB%s: %s" % (story_url, comments))
message = "Sharing story from site: %s: %s" % (story_url, comments)
else:
shared_story.story_content = content
shared_story.story_title = title
shared_story.comments = comments
shared_story.story_permalink = story_url
shared_story.story_guid = story_url
shared_story.has_comments = bool(comments)
shared_story.story_feed_id = feed_id
shared_story.save()
logging.user(profile.user, "~BM~FY~SBUpdating~SN shared story from site: ~SB%s: %s" % (story_url, comments))
message = "Updating shared story from site: %s: %s" % (story_url, comments)
try:
socialsub = MSocialSubscription.objects.get(user_id=profile.user.pk,
subscription_user_id=profile.user.pk)
except MSocialSubscription.DoesNotExist:
socialsub = None
if socialsub:
socialsub.mark_story_ids_as_read([shared_story.story_hash],
shared_story.story_feed_id,
request=request)
else:
RUserStory.mark_read(profile.user.pk, shared_story.story_feed_id, shared_story.story_hash)
2012-09-24 13:45:37 -07:00
shared_story.publish_update_to_subscribers()
2012-08-17 23:29:17 -07:00
response = HttpResponse(json.encode({
2012-08-17 23:29:17 -07:00
'code': code,
'message': message,
'story': shared_story,
}), content_type='text/plain')
response['Access-Control-Allow-Origin'] = '*'
response['Access-Control-Allow-Methods'] = 'POST'
2012-12-10 13:33:37 -08:00
return response
2019-08-27 20:28:11 -07:00
@required_params('story_url', 'title')
def save_story(request, token=None):
code = 0
story_url = request.POST['story_url']
user_tags = request.POST.getlist('user_tags') or request.POST.getlist('user_tags[]') or []
2019-08-27 20:28:11 -07:00
add_user_tag = request.POST.get('add_user_tag', None)
title = request.POST['title']
content = request.POST.get('content', None)
rss_url = request.POST.get('rss_url', None)
user_notes = request.POST.get('user_notes', None)
2019-08-27 20:28:11 -07:00
feed_id = request.POST.get('feed_id', None) or 0
feed = None
message = None
profile = None
2021-08-26 22:21:55 -07:00
if request.user.is_authenticated:
2019-08-27 20:28:11 -07:00
profile = request.user.profile
else:
try:
profile = Profile.objects.get(secret_token=token)
except Profile.DoesNotExist:
code = -1
if token:
message = "Not authenticated, couldn't find user by token."
else:
message = "Not authenticated, no token supplied and not authenticated."
if not profile:
return HttpResponse(json.encode({
'code': code,
'message': message,
'story': None,
}), content_type='text/plain')
2019-08-27 20:28:11 -07:00
if feed_id:
feed = Feed.get_by_id(feed_id)
else:
if rss_url:
logging.user(request.user, "~FBFinding feed (save_story): %s" % rss_url)
feed = Feed.get_feed_from_url(rss_url, create=True, fetch=True)
if not feed:
logging.user(request.user, "~FBFinding feed (save_story): %s" % story_url)
feed = Feed.get_feed_from_url(story_url, create=True, fetch=True)
if feed:
feed_id = feed.pk
if content:
content = lxml.html.fromstring(content)
content.make_links_absolute(story_url)
content = lxml.html.tostring(content)
else:
importer = TextImporter(story=None, story_url=story_url, request=request, debug=settings.DEBUG)
document = importer.fetch(skip_save=True, return_document=True)
content = document['content']
if not title:
title = document['title']
if add_user_tag:
user_tags = user_tags + [tag for tag in add_user_tag.split(',')]
2019-08-27 20:28:11 -07:00
starred_story = MStarredStory.objects.filter(user_id=profile.user.pk,
story_feed_id=feed_id,
story_guid=story_url).limit(1).first()
if not starred_story:
story_db = {
"story_guid": story_url,
"story_permalink": story_url,
"story_title": title,
"story_feed_id": feed_id,
"story_content": content,
"story_date": datetime.datetime.now(),
"starred_date": datetime.datetime.now(),
2019-08-27 20:28:11 -07:00
"user_id": profile.user.pk,
"user_tags": user_tags,
"user_notes": user_notes,
2019-08-27 20:28:11 -07:00
}
starred_story = MStarredStory.objects.create(**story_db)
logging.user(profile.user, "~BM~FCStarring story from site: ~SB%s: %s" % (story_url, user_tags))
message = "Saving story from site: %s: %s" % (story_url, user_tags)
2019-08-27 20:28:11 -07:00
else:
starred_story.story_content = content
starred_story.story_title = title
starred_story.user_tags = user_tags
starred_story.story_permalink = story_url
starred_story.story_guid = story_url
starred_story.story_feed_id = feed_id
starred_story.user_notes = user_notes
starred_story.save()
logging.user(profile.user, "~BM~FC~SBUpdating~SN starred story from site: ~SB%s: %s" % (story_url, user_tags))
message = "Updating saved story from site: %s: %s" % (story_url, user_tags)
2019-08-27 20:28:11 -07:00
MStarredStoryCounts.schedule_count_tags_for_user(request.user.pk)
2019-08-27 20:28:11 -07:00
response = HttpResponse(json.encode({
'code': code,
'message': message,
'story': starred_story,
}), content_type='text/plain')
2019-08-27 20:28:11 -07:00
response['Access-Control-Allow-Origin'] = '*'
response['Access-Control-Allow-Methods'] = 'POST'
return response
2021-01-04 13:33:07 -05:00
def ip_addresses(request):
import digitalocean
2021-07-26 16:44:27 -04:00
doapi = digitalocean.Manager(token=settings.DO_TOKEN_API_IPADDRESSES)
2021-01-04 13:33:07 -05:00
droplets = doapi.get_all_droplets()
addresses = '\n'.join([d.ip_address for d in droplets])
return HttpResponse(addresses, content_type='text/plain')