Mention and notify users when creating a status
This commit is contained in:
parent
4684a83e6f
commit
0cf1838276
|
@ -3,8 +3,9 @@ import inspect
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from .base_activity import ActivityEncoder, Image, PublicKey, Signature
|
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 Note, GeneratedNote, Article, Comment, Review, Quotation
|
||||||
from .note import Tombstone, Link
|
from .note import Tombstone
|
||||||
from .interaction import Boost, Like
|
from .interaction import Boost, Like
|
||||||
from .ordered_collection import OrderedCollection, OrderedCollectionPage
|
from .ordered_collection import OrderedCollection, OrderedCollectionPage
|
||||||
from .person import Person
|
from .person import Person
|
||||||
|
|
|
@ -21,6 +21,19 @@ class Image:
|
||||||
type: str = '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
|
@dataclass
|
||||||
class PublicKey:
|
class PublicKey:
|
||||||
''' public key block '''
|
''' public key block '''
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
from typing import Dict, List
|
from typing import Dict, List
|
||||||
|
|
||||||
from .base_activity import ActivityObject, Image
|
from .base_activity import ActivityObject, Image, Link
|
||||||
|
|
||||||
@dataclass(init=False)
|
@dataclass(init=False)
|
||||||
class Tombstone(ActivityObject):
|
class Tombstone(ActivityObject):
|
||||||
|
@ -20,6 +20,7 @@ class Note(ActivityObject):
|
||||||
inReplyTo: str
|
inReplyTo: str
|
||||||
published: str
|
published: str
|
||||||
attributedTo: str
|
attributedTo: str
|
||||||
|
tag: List[Link]
|
||||||
to: List[str]
|
to: List[str]
|
||||||
cc: List[str]
|
cc: List[str]
|
||||||
content: str
|
content: str
|
||||||
|
@ -36,17 +37,9 @@ class Article(Note):
|
||||||
type: str = 'Article'
|
type: str = 'Article'
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class Link():
|
|
||||||
''' for tagging a book in a status '''
|
|
||||||
href: str
|
|
||||||
name: str
|
|
||||||
type: str = 'Link'
|
|
||||||
|
|
||||||
@dataclass(init=False)
|
@dataclass(init=False)
|
||||||
class GeneratedNote(Note):
|
class GeneratedNote(Note):
|
||||||
''' just a re-typed note '''
|
''' just a re-typed note '''
|
||||||
tag: List[Link]
|
|
||||||
type: str = 'GeneratedNote'
|
type: str = 'GeneratedNote'
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -59,6 +59,7 @@ class Status(OrderedCollectionPageMixin, BookWyrmModel):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def ap_tag(self):
|
def ap_tag(self):
|
||||||
|
''' references to books and/or users '''
|
||||||
tags = []
|
tags = []
|
||||||
for book in self.mention_books.all():
|
for book in self.mention_books.all():
|
||||||
tags.append(activitypub.Link(
|
tags.append(activitypub.Link(
|
||||||
|
@ -66,6 +67,11 @@ class Status(OrderedCollectionPageMixin, BookWyrmModel):
|
||||||
name=book.title,
|
name=book.title,
|
||||||
type='Book'
|
type='Book'
|
||||||
))
|
))
|
||||||
|
for user in self.mention_users.all():
|
||||||
|
tags.append(activitypub.Mention(
|
||||||
|
href=user.remote_id,
|
||||||
|
name=user.username,
|
||||||
|
))
|
||||||
return tags
|
return tags
|
||||||
|
|
||||||
shared_mappings = [
|
shared_mappings = [
|
||||||
|
@ -270,7 +276,7 @@ class ReadThrough(BookWyrmModel):
|
||||||
|
|
||||||
NotificationType = models.TextChoices(
|
NotificationType = models.TextChoices(
|
||||||
'NotificationType',
|
'NotificationType',
|
||||||
'FAVORITE REPLY TAG FOLLOW FOLLOW_REQUEST BOOST IMPORT')
|
'FAVORITE REPLY MENTION TAG FOLLOW FOLLOW_REQUEST BOOST IMPORT')
|
||||||
|
|
||||||
class Notification(BookWyrmModel):
|
class Notification(BookWyrmModel):
|
||||||
''' you've been tagged, liked, followed, etc '''
|
''' you've been tagged, liked, followed, etc '''
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
''' handles all the activity coming out of the server '''
|
''' handles all the activity coming out of the server '''
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
import re
|
||||||
|
|
||||||
from django.db import IntegrityError, transaction
|
from django.db import IntegrityError, transaction
|
||||||
from django.http import HttpResponseNotFound, JsonResponse
|
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 create_generated_note
|
||||||
from bookwyrm.status import delete_status
|
from bookwyrm.status import delete_status
|
||||||
from bookwyrm.remote_user import get_or_create_remote_user
|
from bookwyrm.remote_user import get_or_create_remote_user
|
||||||
|
from bookwyrm.settings import DOMAIN
|
||||||
|
|
||||||
|
|
||||||
@csrf_exempt
|
@csrf_exempt
|
||||||
|
@ -211,7 +213,37 @@ def handle_status(user, form):
|
||||||
''' generic handler for statuses '''
|
''' generic handler for statuses '''
|
||||||
status = form.save()
|
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:
|
if status.reply_parent and status.reply_parent.user.local:
|
||||||
create_notification(
|
create_notification(
|
||||||
status.reply_parent.user,
|
status.reply_parent.user,
|
||||||
|
|
Loading…
Reference in New Issue