Mention and notify users when creating a status

This commit is contained in:
Mouse Reeve 2020-11-01 10:13:51 -08:00
parent 4684a83e6f
commit 0cf1838276
6 changed files with 83 additions and 12 deletions

View file

@ -3,8 +3,9 @@ import inspect
import sys
from .base_activity import ActivityEncoder, Image, PublicKey, Signature
from .base_activity import Link, Mention
from .note import Note, GeneratedNote, Article, Comment, Review, Quotation
from .note import Tombstone, Link
from .note import Tombstone
from .interaction import Boost, Like
from .ordered_collection import OrderedCollection, OrderedCollectionPage
from .person import Person

View file

@ -21,6 +21,19 @@ class Image:
type: str = 'Image'
@dataclass
class Link():
''' for tagging a book in a status '''
href: str
name: str
type: str = 'Link'
@dataclass
class Mention(Link):
''' a subtype of Link for mentioning an actor '''
type: str = 'Mention'
@dataclass
class PublicKey:
''' public key block '''

View file

@ -2,7 +2,7 @@
from dataclasses import dataclass, field
from typing import Dict, List
from .base_activity import ActivityObject, Image
from .base_activity import ActivityObject, Image, Link
@dataclass(init=False)
class Tombstone(ActivityObject):
@ -20,6 +20,7 @@ class Note(ActivityObject):
inReplyTo: str
published: str
attributedTo: str
tag: List[Link]
to: List[str]
cc: List[str]
content: str
@ -36,17 +37,9 @@ class Article(Note):
type: str = 'Article'
@dataclass
class Link():
''' for tagging a book in a status '''
href: str
name: str
type: str = 'Link'
@dataclass(init=False)
class GeneratedNote(Note):
''' just a re-typed note '''
tag: List[Link]
type: str = 'GeneratedNote'

View file

@ -0,0 +1,26 @@
# Generated by Django 3.0.7 on 2020-11-01 17:58
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('bookwyrm', '0062_auto_20201031_1936'),
]
operations = [
migrations.RemoveConstraint(
model_name='notification',
name='notification_type_valid',
),
migrations.AlterField(
model_name='notification',
name='notification_type',
field=models.CharField(choices=[('FAVORITE', 'Favorite'), ('REPLY', 'Reply'), ('MENTION', 'Mention'), ('TAG', 'Tag'), ('FOLLOW', 'Follow'), ('FOLLOW_REQUEST', 'Follow Request'), ('BOOST', 'Boost'), ('IMPORT', 'Import')], max_length=255),
),
migrations.AddConstraint(
model_name='notification',
constraint=models.CheckConstraint(check=models.Q(notification_type__in=['FAVORITE', 'REPLY', 'MENTION', 'TAG', 'FOLLOW', 'FOLLOW_REQUEST', 'BOOST', 'IMPORT']), name='notification_type_valid'),
),
]

View file

@ -59,6 +59,7 @@ class Status(OrderedCollectionPageMixin, BookWyrmModel):
@property
def ap_tag(self):
''' references to books and/or users '''
tags = []
for book in self.mention_books.all():
tags.append(activitypub.Link(
@ -66,6 +67,11 @@ class Status(OrderedCollectionPageMixin, BookWyrmModel):
name=book.title,
type='Book'
))
for user in self.mention_users.all():
tags.append(activitypub.Mention(
href=user.remote_id,
name=user.username,
))
return tags
shared_mappings = [
@ -270,7 +276,7 @@ class ReadThrough(BookWyrmModel):
NotificationType = models.TextChoices(
'NotificationType',
'FAVORITE REPLY TAG FOLLOW FOLLOW_REQUEST BOOST IMPORT')
'FAVORITE REPLY MENTION TAG FOLLOW FOLLOW_REQUEST BOOST IMPORT')
class Notification(BookWyrmModel):
''' you've been tagged, liked, followed, etc '''

View file

@ -1,5 +1,6 @@
''' handles all the activity coming out of the server '''
from datetime import datetime
import re
from django.db import IntegrityError, transaction
from django.http import HttpResponseNotFound, JsonResponse
@ -13,6 +14,7 @@ from bookwyrm.status import create_tag, create_notification
from bookwyrm.status import create_generated_note
from bookwyrm.status import delete_status
from bookwyrm.remote_user import get_or_create_remote_user
from bookwyrm.settings import DOMAIN
@csrf_exempt
@ -211,7 +213,37 @@ def handle_status(user, form):
''' generic handler for statuses '''
status = form.save()
# notify reply parent or (TODO) tagged users
# inspect the text for user tags
text = status.content
matches = re.finditer(
r'\W@[a-zA-Z_\-\.0-9]+(@[a-z-A-Z0-9_\-]+.[a-z]+)?',
text
)
for match in matches:
username = match.group().strip().split('@')[1:]
if len(username) == 1:
# this looks like a local user (@user), fill in the domain
username.append(DOMAIN)
username = '@'.join(username)
try:
mention_user = models.User.objects.get(username=username)
except models.User.DoesNotExist:
# we can ignore users we don't know about
continue
# add them to status mentions fk
status.mention_users.add(mention_user)
# create notification if the mentioned user is local
if mention_user.local:
create_notification(
mention_user,
'MENTION',
related_user=user,
related_status=status
)
status.save()
# notify reply parent or tagged users
if status.reply_parent and status.reply_parent.user.local:
create_notification(
status.reply_parent.user,