forked from mirrors/bookwyrm
Merge branch 'main' into production
This commit is contained in:
commit
5446a5b238
22 changed files with 354 additions and 29 deletions
|
@ -4,11 +4,12 @@ import sys
|
|||
|
||||
from .base_activity import ActivityEncoder, Image, PublicKey, Signature
|
||||
from .note import Note, GeneratedNote, Article, Comment, Review, Quotation
|
||||
from .note import Tombstone
|
||||
from .interaction import Boost, Like
|
||||
from .ordered_collection import OrderedCollection, OrderedCollectionPage
|
||||
from .person import Person
|
||||
from .book import Edition, Work, Author
|
||||
from .verbs import Create, Undo, Update
|
||||
from .verbs import Create, Delete, Undo, Update
|
||||
from .verbs import Follow, Accept, Reject
|
||||
from .verbs import Add, Remove
|
||||
|
||||
|
|
|
@ -4,6 +4,14 @@ from typing import Dict, List
|
|||
|
||||
from .base_activity import ActivityObject, Image
|
||||
|
||||
@dataclass(init=False)
|
||||
class Tombstone(ActivityObject):
|
||||
url: str
|
||||
published: str
|
||||
deleted: str
|
||||
type: str = 'Tombstone'
|
||||
|
||||
|
||||
@dataclass(init=False)
|
||||
class Note(ActivityObject):
|
||||
''' Note activity '''
|
||||
|
|
|
@ -21,6 +21,15 @@ class Create(Verb):
|
|||
type: str = 'Create'
|
||||
|
||||
|
||||
@dataclass(init=False)
|
||||
class Delete(Verb):
|
||||
''' Create activity '''
|
||||
to: List
|
||||
cc: List
|
||||
signature: Signature
|
||||
type: str = 'Delete'
|
||||
|
||||
|
||||
@dataclass(init=False)
|
||||
class Update(Verb):
|
||||
''' Update activity '''
|
||||
|
|
|
@ -57,6 +57,7 @@ def shared_inbox(request):
|
|||
'Accept': handle_follow_accept,
|
||||
'Reject': handle_follow_reject,
|
||||
'Create': handle_create,
|
||||
'Delete': handle_delete_status,
|
||||
'Like': handle_favorite,
|
||||
'Announce': handle_boost,
|
||||
'Add': {
|
||||
|
@ -134,7 +135,9 @@ def handle_follow(activity):
|
|||
except django.db.utils.IntegrityError as err:
|
||||
if err.__cause__.diag.constraint_name != 'userfollowrequest_unique':
|
||||
raise
|
||||
relationship = models.UserFollowRequest.objects.get(remote_id=activity['id'])
|
||||
relationship = models.UserFollowRequest.objects.get(
|
||||
remote_id=activity['id']
|
||||
)
|
||||
# send the accept normally for a duplicate request
|
||||
|
||||
if not to_follow.manually_approves_followers:
|
||||
|
@ -143,7 +146,7 @@ def handle_follow(activity):
|
|||
'FOLLOW',
|
||||
related_user=actor
|
||||
)
|
||||
outgoing.handle_accept(actor, to_follow, relationship)
|
||||
outgoing.handle_accept(relationship)
|
||||
else:
|
||||
# Accept will be triggered manually
|
||||
status_builder.create_notification(
|
||||
|
@ -194,7 +197,7 @@ def handle_follow_reject(activity):
|
|||
user_object=rejecter
|
||||
)
|
||||
request.delete()
|
||||
#raises models.UserFollowRequest.DoesNotExist:
|
||||
#raises models.UserFollowRequest.DoesNotExist
|
||||
|
||||
|
||||
@app.task
|
||||
|
@ -235,6 +238,20 @@ def handle_create(activity):
|
|||
)
|
||||
|
||||
|
||||
@app.task
|
||||
def handle_delete_status(activity):
|
||||
''' remove a status '''
|
||||
status_id = activity['object']['id']
|
||||
try:
|
||||
status = models.Status.objects.select_subclasses().get(
|
||||
remote_id=status_id
|
||||
)
|
||||
except models.Status.DoesNotExist:
|
||||
return
|
||||
status_builder.delete_status(status)
|
||||
|
||||
|
||||
|
||||
@app.task
|
||||
def handle_favorite(activity):
|
||||
''' approval of your good good post '''
|
||||
|
|
24
bookwyrm/migrations/0053_auto_20201006_2020.py
Normal file
24
bookwyrm/migrations/0053_auto_20201006_2020.py
Normal file
|
@ -0,0 +1,24 @@
|
|||
# Generated by Django 3.0.7 on 2020-10-06 20:20
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.utils.timezone
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('bookwyrm', '0052_auto_20201005_2145'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='status',
|
||||
name='deleted',
|
||||
field=models.BooleanField(default=False),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='status',
|
||||
name='deleted_date',
|
||||
field=models.DateTimeField(default=django.utils.timezone.now),
|
||||
),
|
||||
]
|
18
bookwyrm/migrations/0054_auto_20201016_2359.py
Normal file
18
bookwyrm/migrations/0054_auto_20201016_2359.py
Normal file
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 3.0.7 on 2020-10-16 23:59
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('bookwyrm', '0053_auto_20201006_2020'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='status',
|
||||
name='deleted_date',
|
||||
field=models.DateTimeField(),
|
||||
),
|
||||
]
|
|
@ -22,6 +22,8 @@ class Status(OrderedCollectionPageMixin, BookWyrmModel):
|
|||
sensitive = models.BooleanField(default=False)
|
||||
# the created date can't be this, because of receiving federated posts
|
||||
published_date = models.DateTimeField(default=timezone.now)
|
||||
deleted = models.BooleanField(default=False)
|
||||
deleted_date = models.DateTimeField()
|
||||
favorites = models.ManyToManyField(
|
||||
'User',
|
||||
symmetrical=False,
|
||||
|
@ -104,6 +106,18 @@ class Status(OrderedCollectionPageMixin, BookWyrmModel):
|
|||
**kwargs
|
||||
)
|
||||
|
||||
def to_activity(self, **kwargs):
|
||||
''' return tombstone if the status is deleted '''
|
||||
if self.deleted:
|
||||
return activitypub.Tombstone(
|
||||
id=self.remote_id,
|
||||
url=self.remote_id,
|
||||
deleted=http_date(self.deleted_date.timestamp()),
|
||||
published=http_date(self.deleted_date.timestamp()),
|
||||
).serialize()
|
||||
return ActivitypubMixin.to_activity(self, **kwargs)
|
||||
|
||||
|
||||
class GeneratedStatus(Status):
|
||||
''' these are app-generated messages about user activity '''
|
||||
@property
|
||||
|
@ -112,7 +126,7 @@ class GeneratedStatus(Status):
|
|||
message = self.content
|
||||
books = ', '.join(
|
||||
'<a href="%s">"%s"</a>' % (self.book.local_id, self.book.title) \
|
||||
for book in self.mention_books
|
||||
for book in self.mention_books.all()
|
||||
)
|
||||
return '%s %s' % (message, books)
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ from bookwyrm.status import create_review, create_status
|
|||
from bookwyrm.status import create_quotation, create_comment
|
||||
from bookwyrm.status import create_tag, create_notification, create_rating
|
||||
from bookwyrm.status import create_generated_note
|
||||
from bookwyrm.status import delete_status
|
||||
from bookwyrm.remote_user import get_or_create_remote_user
|
||||
|
||||
|
||||
|
@ -80,8 +81,10 @@ def handle_unfollow(user, to_unfollow):
|
|||
to_unfollow.followers.remove(user)
|
||||
|
||||
|
||||
def handle_accept(user, to_follow, follow_request):
|
||||
def handle_accept(follow_request):
|
||||
''' send an acceptance message to a follow request '''
|
||||
user = follow_request.user_subject
|
||||
to_follow = follow_request.user_object
|
||||
with transaction.atomic():
|
||||
relationship = models.UserFollows.from_request(follow_request)
|
||||
follow_request.delete()
|
||||
|
@ -91,10 +94,12 @@ def handle_accept(user, to_follow, follow_request):
|
|||
broadcast(to_follow, activity, privacy='direct', direct_recipients=[user])
|
||||
|
||||
|
||||
def handle_reject(user, to_follow, relationship):
|
||||
def handle_reject(follow_request):
|
||||
''' a local user who managed follows rejects a follow request '''
|
||||
activity = relationship.to_reject_activity(user)
|
||||
relationship.delete()
|
||||
user = follow_request.user_subject
|
||||
to_follow = follow_request.user_object
|
||||
activity = follow_request.to_reject_activity()
|
||||
follow_request.delete()
|
||||
broadcast(to_follow, activity, privacy='direct', direct_recipients=[user])
|
||||
|
||||
|
||||
|
@ -107,11 +112,16 @@ def handle_shelve(user, book, shelf):
|
|||
broadcast(user, shelve.to_add_activity(user))
|
||||
|
||||
# tell the world about this cool thing that happened
|
||||
message = {
|
||||
'to-read': 'wants to read',
|
||||
'reading': 'started reading',
|
||||
'read': 'finished reading'
|
||||
}[shelf.identifier]
|
||||
try:
|
||||
message = {
|
||||
'to-read': 'wants to read',
|
||||
'reading': 'started reading',
|
||||
'read': 'finished reading'
|
||||
}[shelf.identifier]
|
||||
except KeyError:
|
||||
# it's a non-standard shelf, don't worry about it
|
||||
return
|
||||
|
||||
status = create_generated_note(user, message, mention_books=[book])
|
||||
status.save()
|
||||
|
||||
|
@ -193,6 +203,12 @@ def handle_import_books(user, items):
|
|||
return None
|
||||
|
||||
|
||||
def handle_delete_status(user, status):
|
||||
''' delete a status and broadcast deletion to other servers '''
|
||||
delete_status(status)
|
||||
broadcast(user, status.to_activity())
|
||||
|
||||
|
||||
def handle_rate(user, book, rating):
|
||||
''' a review that's just a rating '''
|
||||
builder = create_rating
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
''' Handle user activity '''
|
||||
from datetime import datetime
|
||||
from django.db import IntegrityError
|
||||
|
||||
from bookwyrm import models
|
||||
|
@ -6,6 +7,12 @@ from bookwyrm.books_manager import get_or_create_book
|
|||
from bookwyrm.sanitize_html import InputHtmlParser
|
||||
|
||||
|
||||
def delete_status(status):
|
||||
''' replace the status with a tombstone '''
|
||||
status.deleted = True
|
||||
status.deleted_date = datetime.now()
|
||||
status.save()
|
||||
|
||||
def create_rating(user, book, rating):
|
||||
''' a review that's just a rating '''
|
||||
if not rating or rating < 1 or rating > 5:
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
{% load humanize %}
|
||||
{% load fr_display %}
|
||||
|
||||
{% if not status.deleted %}
|
||||
<div class="card">
|
||||
<header class="card-header">
|
||||
{% include 'snippets/status_header.html' with status=status %}
|
||||
|
@ -25,7 +26,29 @@
|
|||
<span class="icon icon-public">
|
||||
<span class="is-sr-only">Public post</span>
|
||||
</span>
|
||||
{% if status.user == request.user %}
|
||||
<form name="delete-{{status.id}}" action="/delete-status" method="post">
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name="status" value="{{ status.id }}">
|
||||
<button type="submit">
|
||||
<span class="icon icon-cancel">
|
||||
<span class="is-sr-only">Delete post</span>
|
||||
</span>
|
||||
</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
<a href="{{ status.remote_id }}">{{ status.published_date | naturaltime }}</a>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="card">
|
||||
<header class="card-header">
|
||||
<p>
|
||||
{% include 'snippets/avatar.html' with user=status.user %}
|
||||
{% include 'snippets/username.html' with user=status.user %}
|
||||
deleted this status
|
||||
</p>
|
||||
</header>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
|
|
@ -42,7 +42,8 @@ def get_replies(status):
|
|||
''' get all direct replies to a status '''
|
||||
#TODO: this limit could cause problems
|
||||
return models.Status.objects.filter(
|
||||
reply_parent=status
|
||||
reply_parent=status,
|
||||
deleted=False,
|
||||
).select_subclasses().all()[:10]
|
||||
|
||||
|
||||
|
|
1
bookwyrm/tests/incoming/__init__.py
Normal file
1
bookwyrm/tests/incoming/__init__.py
Normal file
|
@ -0,0 +1 @@
|
|||
from . import *
|
|
@ -6,7 +6,6 @@ from bookwyrm import models, incoming
|
|||
|
||||
|
||||
class Favorite(TestCase):
|
||||
''' not too much going on in the books model but here we are '''
|
||||
def setUp(self):
|
||||
self.remote_user = models.User.objects.create_user(
|
||||
'rat', 'rat@rat.com', 'ratword',
|
||||
|
@ -25,7 +24,7 @@ class Favorite(TestCase):
|
|||
)
|
||||
|
||||
datafile = pathlib.Path(__file__).parent.joinpath(
|
||||
'data/ap_user.json'
|
||||
'../data/ap_user.json'
|
||||
)
|
||||
self.user_data = json.loads(datafile.read_bytes())
|
||||
|
|
@ -1,11 +1,9 @@
|
|||
import json
|
||||
from django.test import TestCase
|
||||
|
||||
from bookwyrm import models, incoming
|
||||
|
||||
|
||||
class Follow(TestCase):
|
||||
''' not too much going on in the books model but here we are '''
|
||||
class IncomingFollow(TestCase):
|
||||
def setUp(self):
|
||||
self.remote_user = models.User.objects.create_user(
|
||||
'rat', 'rat@rat.com', 'ratword',
|
|
@ -1,11 +1,9 @@
|
|||
import json
|
||||
from django.test import TestCase
|
||||
|
||||
from bookwyrm import models, incoming
|
||||
|
||||
|
||||
class IncomingFollowAccept(TestCase):
|
||||
''' not too much going on in the books model but here we are '''
|
||||
def setUp(self):
|
||||
self.remote_user = models.User.objects.create_user(
|
||||
'rat', 'rat@rat.com', 'ratword',
|
1
bookwyrm/tests/outgoing/__init__.py
Normal file
1
bookwyrm/tests/outgoing/__init__.py
Normal file
|
@ -0,0 +1 @@
|
|||
from . import *
|
72
bookwyrm/tests/outgoing/test_follow.py
Normal file
72
bookwyrm/tests/outgoing/test_follow.py
Normal file
|
@ -0,0 +1,72 @@
|
|||
from django.test import TestCase
|
||||
|
||||
from bookwyrm import models, outgoing
|
||||
|
||||
|
||||
class Following(TestCase):
|
||||
def setUp(self):
|
||||
self.remote_user = models.User.objects.create_user(
|
||||
'rat', 'rat@rat.com', 'ratword',
|
||||
local=False,
|
||||
remote_id='https://example.com/users/rat',
|
||||
inbox='https://example.com/users/rat/inbox',
|
||||
outbox='https://example.com/users/rat/outbox',
|
||||
)
|
||||
self.local_user = models.User.objects.create_user(
|
||||
'mouse', 'mouse@mouse.com', 'mouseword',
|
||||
local=True,
|
||||
remote_id='http://local.com/users/mouse',
|
||||
)
|
||||
|
||||
|
||||
def test_handle_follow(self):
|
||||
self.assertEqual(models.UserFollowRequest.objects.count(), 0)
|
||||
|
||||
outgoing.handle_follow(self.local_user, self.remote_user)
|
||||
rel = models.UserFollowRequest.objects.get()
|
||||
|
||||
self.assertEqual(rel.user_subject, self.local_user)
|
||||
self.assertEqual(rel.user_object, self.remote_user)
|
||||
self.assertEqual(rel.status, 'follow_request')
|
||||
|
||||
|
||||
def test_handle_unfollow(self):
|
||||
self.remote_user.followers.add(self.local_user)
|
||||
self.assertEqual(self.remote_user.followers.count(), 1)
|
||||
outgoing.handle_unfollow(self.local_user, self.remote_user)
|
||||
|
||||
self.assertEqual(self.remote_user.followers.count(), 0)
|
||||
|
||||
|
||||
def test_handle_accept(self):
|
||||
rel = models.UserFollowRequest.objects.create(
|
||||
user_subject=self.local_user,
|
||||
user_object=self.remote_user
|
||||
)
|
||||
rel_id = rel.id
|
||||
|
||||
outgoing.handle_accept(rel)
|
||||
# request should be deleted
|
||||
self.assertEqual(
|
||||
models.UserFollowRequest.objects.filter(id=rel_id).count(), 0
|
||||
)
|
||||
# follow relationship should exist
|
||||
self.assertEqual(self.remote_user.followers.first(), self.local_user)
|
||||
|
||||
|
||||
def test_handle_reject(self):
|
||||
rel = models.UserFollowRequest.objects.create(
|
||||
user_subject=self.local_user,
|
||||
user_object=self.remote_user
|
||||
)
|
||||
rel_id = rel.id
|
||||
|
||||
outgoing.handle_reject(rel)
|
||||
# request should be deleted
|
||||
self.assertEqual(
|
||||
models.UserFollowRequest.objects.filter(id=rel_id).count(), 0
|
||||
)
|
||||
# follow relationship should not exist
|
||||
self.assertEqual(
|
||||
models.UserFollows.objects.filter(id=rel_id).count(), 0
|
||||
)
|
97
bookwyrm/tests/outgoing/test_shelving.py
Normal file
97
bookwyrm/tests/outgoing/test_shelving.py
Normal file
|
@ -0,0 +1,97 @@
|
|||
from django.test import TestCase
|
||||
|
||||
from bookwyrm import models, outgoing
|
||||
|
||||
|
||||
class Shelving(TestCase):
|
||||
def setUp(self):
|
||||
self.user = models.User.objects.create_user(
|
||||
'mouse', 'mouse@mouse.com', 'mouseword',
|
||||
local=True,
|
||||
remote_id='http://local.com/users/mouse',
|
||||
)
|
||||
self.book = models.Edition.objects.create(
|
||||
title='Example Edition',
|
||||
remote_id='https://example.com/book/1',
|
||||
)
|
||||
self.shelf = models.Shelf.objects.create(
|
||||
name='Test Shelf',
|
||||
identifier='test-shelf',
|
||||
user=self.user
|
||||
)
|
||||
|
||||
|
||||
def test_handle_shelve(self):
|
||||
outgoing.handle_shelve(self.user, self.book, self.shelf)
|
||||
# make sure the book is on the shelf
|
||||
self.assertEqual(self.shelf.books.get(), self.book)
|
||||
|
||||
|
||||
def test_handle_shelve_to_read(self):
|
||||
shelf = models.Shelf.objects.get(identifier='to-read')
|
||||
|
||||
outgoing.handle_shelve(self.user, self.book, shelf)
|
||||
# make sure the book is on the shelf
|
||||
self.assertEqual(shelf.books.get(), self.book)
|
||||
|
||||
# it should have posted a status about this
|
||||
status = models.GeneratedStatus.objects.get()
|
||||
self.assertEqual(status.content, 'wants to read')
|
||||
self.assertEqual(status.user, self.user)
|
||||
self.assertEqual(status.mention_books.count(), 1)
|
||||
self.assertEqual(status.mention_books.first(), self.book)
|
||||
|
||||
# and it should not create a read-through
|
||||
self.assertEqual(models.ReadThrough.objects.count(), 0)
|
||||
|
||||
|
||||
def test_handle_shelve_reading(self):
|
||||
shelf = models.Shelf.objects.get(identifier='reading')
|
||||
|
||||
outgoing.handle_shelve(self.user, self.book, shelf)
|
||||
# make sure the book is on the shelf
|
||||
self.assertEqual(shelf.books.get(), self.book)
|
||||
|
||||
# it should have posted a status about this
|
||||
status = models.GeneratedStatus.objects.order_by('-published_date').first()
|
||||
self.assertEqual(status.content, 'started reading')
|
||||
self.assertEqual(status.user, self.user)
|
||||
self.assertEqual(status.mention_books.count(), 1)
|
||||
self.assertEqual(status.mention_books.first(), self.book)
|
||||
|
||||
# and it should create a read-through
|
||||
readthrough = models.ReadThrough.objects.get()
|
||||
self.assertEqual(readthrough.user, self.user)
|
||||
self.assertEqual(readthrough.book.id, self.book.id)
|
||||
self.assertIsNotNone(readthrough.start_date)
|
||||
self.assertIsNone(readthrough.finish_date)
|
||||
|
||||
|
||||
def test_handle_shelve_read(self):
|
||||
shelf = models.Shelf.objects.get(identifier='read')
|
||||
|
||||
outgoing.handle_shelve(self.user, self.book, shelf)
|
||||
# make sure the book is on the shelf
|
||||
self.assertEqual(shelf.books.get(), self.book)
|
||||
|
||||
# it should have posted a status about this
|
||||
status = models.GeneratedStatus.objects.order_by('-published_date').first()
|
||||
self.assertEqual(status.content, 'finished reading')
|
||||
self.assertEqual(status.user, self.user)
|
||||
self.assertEqual(status.mention_books.count(), 1)
|
||||
self.assertEqual(status.mention_books.first(), self.book)
|
||||
|
||||
# and it should update the existing read-through
|
||||
readthrough = models.ReadThrough.objects.get()
|
||||
self.assertEqual(readthrough.user, self.user)
|
||||
self.assertEqual(readthrough.book.id, self.book.id)
|
||||
self.assertIsNotNone(readthrough.start_date)
|
||||
self.assertIsNotNone(readthrough.finish_date)
|
||||
|
||||
|
||||
def test_handle_unshelve(self):
|
||||
self.shelf.books.add(self.book)
|
||||
self.shelf.save()
|
||||
self.assertEqual(self.shelf.books.count(), 1)
|
||||
outgoing.handle_unshelve(self.user, self.book, self.shelf)
|
||||
self.assertEqual(self.shelf.books.count(), 0)
|
|
@ -1,8 +1,6 @@
|
|||
from django.test import TestCase
|
||||
import json
|
||||
import pathlib
|
||||
|
||||
from bookwyrm import activitypub, models
|
||||
from bookwyrm import models
|
||||
from bookwyrm import status as status_builder
|
||||
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ localname_regex = r'(?P<username>[\w\-_]+)'
|
|||
user_path = r'^user/%s' % username_regex
|
||||
local_user_path = r'^user/%s' % localname_regex
|
||||
|
||||
status_types = ['status', 'review', 'comment', 'quotation', 'boost']
|
||||
status_types = ['status', 'review', 'comment', 'quotation', 'boost', 'generatedstatus']
|
||||
status_path = r'%s/(%s)/(?P<status_id>\d+)' % \
|
||||
(local_user_path, '|'.join(status_types))
|
||||
|
||||
|
@ -107,6 +107,8 @@ urlpatterns = [
|
|||
re_path(r'^unfavorite/(?P<status_id>\d+)/?$', actions.unfavorite),
|
||||
re_path(r'^boost/(?P<status_id>\d+)/?$', actions.boost),
|
||||
|
||||
re_path(r'^delete-status/?$', actions.delete_status),
|
||||
|
||||
re_path(r'^shelve/?$', actions.shelve),
|
||||
|
||||
re_path(r'^follow/?$', actions.follow),
|
||||
|
|
|
@ -418,6 +418,27 @@ def boost(request, status_id):
|
|||
outgoing.handle_boost(request.user, status)
|
||||
return redirect(request.headers.get('Referer', '/'))
|
||||
|
||||
|
||||
@login_required
|
||||
def delete_status(request):
|
||||
''' delete and tombstone a status '''
|
||||
status_id = request.POST.get('status')
|
||||
if not status_id:
|
||||
return HttpResponseBadRequest()
|
||||
try:
|
||||
status = models.Status.objects.get(id=status_id)
|
||||
except models.Status.DoesNotExist:
|
||||
return HttpResponseBadRequest()
|
||||
|
||||
# don't let people delete other people's statuses
|
||||
if status.user != request.user:
|
||||
return HttpResponseBadRequest()
|
||||
|
||||
# perform deletion
|
||||
outgoing.handle_delete_status(request.user, status)
|
||||
return redirect(request.headers.get('Referer', '/'))
|
||||
|
||||
|
||||
@login_required
|
||||
def follow(request):
|
||||
''' follow another user, here or abroad '''
|
||||
|
@ -473,7 +494,7 @@ def accept_follow_request(request):
|
|||
# Request already dealt with.
|
||||
pass
|
||||
else:
|
||||
outgoing.handle_accept(requester, request.user, follow_request)
|
||||
outgoing.handle_accept(follow_request)
|
||||
|
||||
return redirect('/user/%s' % request.user.localname)
|
||||
|
||||
|
@ -495,7 +516,7 @@ def delete_follow_request(request):
|
|||
except models.UserFollowRequest.DoesNotExist:
|
||||
return HttpResponseBadRequest()
|
||||
|
||||
outgoing.handle_reject(requester, request.user, follow_request)
|
||||
outgoing.handle_reject(follow_request)
|
||||
return redirect('/user/%s' % request.user.localname)
|
||||
|
||||
|
||||
|
|
|
@ -118,7 +118,7 @@ def get_activity_feed(user, filter_level, model=models.Status):
|
|||
|
||||
activities = model
|
||||
if hasattr(model, 'objects'):
|
||||
activities = model.objects
|
||||
activities = model.objects.filter(deleted=False)
|
||||
|
||||
activities = activities.order_by(
|
||||
'-created_date'
|
||||
|
|
Loading…
Reference in a new issue