2020-05-05 23:50:48 +08:00
|
|
|
import uuid
|
2021-02-17 15:08:16 +01:00
|
|
|
import django.contrib.postgres.fields as postgres
|
2020-05-01 22:46:15 +08:00
|
|
|
from django.db import models
|
|
|
|
from django.contrib.auth.models import AbstractUser
|
2020-05-05 23:50:48 +08:00
|
|
|
from django.utils import timezone
|
2021-02-17 15:08:16 +01:00
|
|
|
from django.core.serializers.json import DjangoJSONEncoder
|
2021-12-24 11:56:04 -08:00
|
|
|
from django.utils.translation import gettext_lazy as _
|
2021-08-01 12:36:03 +02:00
|
|
|
from common.utils import GenerateDateUUIDMediaFilePath
|
2021-09-10 20:24:22 -04:00
|
|
|
from django.conf import settings
|
2021-12-14 16:06:27 -05:00
|
|
|
from mastodon.api import *
|
2023-01-01 23:50:57 -05:00
|
|
|
from django.urls import reverse
|
2020-05-01 22:46:15 +08:00
|
|
|
|
|
|
|
|
|
|
|
def report_image_path(instance, filename):
|
2023-01-01 23:50:57 -05:00
|
|
|
return GenerateDateUUIDMediaFilePath(
|
|
|
|
instance, filename, settings.REPORT_MEDIA_PATH_ROOT
|
|
|
|
)
|
2020-05-01 22:46:15 +08:00
|
|
|
|
|
|
|
|
|
|
|
class User(AbstractUser):
|
2021-09-13 23:13:28 -04:00
|
|
|
if settings.MASTODON_ALLOW_ANY_SITE:
|
|
|
|
username = models.CharField(
|
2023-01-01 23:50:57 -05:00
|
|
|
_("username"),
|
2021-09-13 23:13:28 -04:00
|
|
|
max_length=150,
|
|
|
|
unique=False,
|
2023-01-01 23:50:57 -05:00
|
|
|
help_text=_(
|
|
|
|
"Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only."
|
|
|
|
),
|
2021-09-13 23:13:28 -04:00
|
|
|
)
|
2022-05-30 17:54:35 -04:00
|
|
|
following = models.JSONField(default=list)
|
2021-09-11 19:53:36 -04:00
|
|
|
mastodon_id = models.CharField(max_length=100, blank=False)
|
2020-10-22 21:45:05 +02:00
|
|
|
# mastodon domain name, eg donotban.com
|
|
|
|
mastodon_site = models.CharField(max_length=100, blank=False)
|
2023-01-01 23:50:57 -05:00
|
|
|
mastodon_token = models.CharField(max_length=2048, default="")
|
|
|
|
mastodon_refresh_token = models.CharField(max_length=2048, default="")
|
2021-12-14 16:06:27 -05:00
|
|
|
mastodon_locked = models.BooleanField(default=False)
|
|
|
|
mastodon_followers = models.JSONField(default=list)
|
|
|
|
mastodon_following = models.JSONField(default=list)
|
|
|
|
mastodon_mutes = models.JSONField(default=list)
|
|
|
|
mastodon_blocks = models.JSONField(default=list)
|
2021-12-15 00:16:48 -05:00
|
|
|
mastodon_domain_blocks = models.JSONField(default=list)
|
2021-12-14 16:06:27 -05:00
|
|
|
mastodon_account = models.JSONField(default=dict)
|
|
|
|
mastodon_last_refresh = models.DateTimeField(default=timezone.now)
|
2022-05-13 00:11:59 -04:00
|
|
|
# store the latest read announcement id,
|
2020-12-09 13:47:00 +01:00
|
|
|
# every time user read the announcement update this field
|
|
|
|
read_announcement_index = models.PositiveIntegerField(default=0)
|
2020-10-22 21:45:05 +02:00
|
|
|
|
|
|
|
class Meta:
|
|
|
|
constraints = [
|
|
|
|
models.UniqueConstraint(
|
2023-01-01 23:50:57 -05:00
|
|
|
fields=["username", "mastodon_site"], name="unique_user_identity"
|
|
|
|
)
|
2020-10-22 21:45:05 +02:00
|
|
|
]
|
2020-05-01 22:46:15 +08:00
|
|
|
|
2021-12-15 00:16:48 -05:00
|
|
|
# def save(self, *args, **kwargs):
|
|
|
|
# """ Automatically populate password field with settings.DEFAULT_PASSWORD before saving."""
|
|
|
|
# self.set_password(settings.DEFAULT_PASSWORD)
|
|
|
|
# return super().save(*args, **kwargs)
|
2020-05-01 22:46:15 +08:00
|
|
|
|
2021-12-15 00:16:48 -05:00
|
|
|
@property
|
|
|
|
def mastodon_username(self):
|
2023-01-01 23:50:57 -05:00
|
|
|
return self.username + "@" + self.mastodon_site
|
2020-10-30 13:18:31 +01:00
|
|
|
|
2022-05-30 19:43:29 -04:00
|
|
|
@property
|
|
|
|
def display_name(self):
|
2023-01-01 23:50:57 -05:00
|
|
|
return (
|
|
|
|
self.mastodon_account["display_name"]
|
|
|
|
if self.mastodon_account
|
|
|
|
and "display_name" in self.mastodon_account
|
|
|
|
and self.mastodon_account["display_name"]
|
|
|
|
else self.mastodon_username
|
|
|
|
)
|
2022-05-30 19:43:29 -04:00
|
|
|
|
2022-11-08 02:32:35 +00:00
|
|
|
@property
|
|
|
|
def url(self):
|
2023-01-01 23:50:57 -05:00
|
|
|
return reverse("journal:user_profile", args=[self.mastodon_username])
|
2022-11-08 02:32:35 +00:00
|
|
|
|
2021-12-15 00:16:48 -05:00
|
|
|
def __str__(self):
|
|
|
|
return self.mastodon_username
|
|
|
|
|
2022-06-05 22:07:41 -04:00
|
|
|
def get_preference(self):
|
2022-08-09 15:50:18 +00:00
|
|
|
pref = Preference.objects.filter(user=self).first() # self.preference
|
2022-06-05 22:07:41 -04:00
|
|
|
if not pref:
|
|
|
|
pref = Preference.objects.create(user=self)
|
|
|
|
return pref
|
|
|
|
|
2021-12-14 16:06:27 -05:00
|
|
|
def refresh_mastodon_data(self):
|
2023-01-01 23:50:57 -05:00
|
|
|
"""Try refresh account data from mastodon server, return true if refreshed successfully, note it will not save to db"""
|
2021-12-14 16:06:27 -05:00
|
|
|
self.mastodon_last_refresh = timezone.now()
|
|
|
|
code, mastodon_account = verify_account(self.mastodon_site, self.mastodon_token)
|
2022-04-01 20:03:37 -04:00
|
|
|
if code == 401 and self.mastodon_refresh_token:
|
2023-01-01 23:50:57 -05:00
|
|
|
self.mastodon_token = refresh_access_token(
|
|
|
|
self.mastodon_site, self.mastodon_refresh_token
|
|
|
|
)
|
2022-04-01 20:03:37 -04:00
|
|
|
if self.mastodon_token:
|
2023-01-01 23:50:57 -05:00
|
|
|
code, mastodon_account = verify_account(
|
|
|
|
self.mastodon_site, self.mastodon_token
|
|
|
|
)
|
2021-12-14 16:06:27 -05:00
|
|
|
updated = False
|
|
|
|
if mastodon_account:
|
|
|
|
self.mastodon_account = mastodon_account
|
2023-01-01 23:50:57 -05:00
|
|
|
self.mastodon_locked = mastodon_account["locked"]
|
|
|
|
if self.username != mastodon_account["username"]:
|
2022-04-01 22:13:01 -04:00
|
|
|
print(f"username changed from {self} to {mastodon_account['username']}")
|
2023-01-01 23:50:57 -05:00
|
|
|
self.username = mastodon_account["username"]
|
2021-12-14 16:06:27 -05:00
|
|
|
# self.mastodon_token = token
|
|
|
|
# user.mastodon_id = mastodon_account['id']
|
2023-01-01 23:50:57 -05:00
|
|
|
self.mastodon_followers = get_related_acct_list(
|
|
|
|
self.mastodon_site,
|
|
|
|
self.mastodon_token,
|
|
|
|
f"/api/v1/accounts/{self.mastodon_id}/followers",
|
|
|
|
)
|
|
|
|
self.mastodon_following = get_related_acct_list(
|
|
|
|
self.mastodon_site,
|
|
|
|
self.mastodon_token,
|
|
|
|
f"/api/v1/accounts/{self.mastodon_id}/following",
|
|
|
|
)
|
|
|
|
self.mastodon_mutes = get_related_acct_list(
|
|
|
|
self.mastodon_site, self.mastodon_token, "/api/v1/mutes"
|
|
|
|
)
|
|
|
|
self.mastodon_blocks = get_related_acct_list(
|
|
|
|
self.mastodon_site, self.mastodon_token, "/api/v1/blocks"
|
|
|
|
)
|
|
|
|
self.mastodon_domain_blocks = get_related_acct_list(
|
|
|
|
self.mastodon_site, self.mastodon_token, "/api/v1/domain_blocks"
|
|
|
|
)
|
2022-05-30 17:54:35 -04:00
|
|
|
self.following = self.get_following_ids()
|
2021-12-14 16:06:27 -05:00
|
|
|
updated = True
|
|
|
|
elif code == 401:
|
2023-01-01 23:50:57 -05:00
|
|
|
print(f"401 {self}")
|
|
|
|
self.mastodon_token = ""
|
2021-12-14 16:06:27 -05:00
|
|
|
return updated
|
|
|
|
|
2022-05-30 17:54:35 -04:00
|
|
|
def get_following_ids(self):
|
|
|
|
fl = []
|
|
|
|
for m in self.mastodon_following:
|
|
|
|
target = User.get(m)
|
2023-01-01 23:50:57 -05:00
|
|
|
if target and (
|
|
|
|
(not target.mastodon_locked)
|
|
|
|
or self.mastodon_username in target.mastodon_followers
|
|
|
|
):
|
|
|
|
fl.append(target.pk)
|
2022-05-30 17:54:35 -04:00
|
|
|
return fl
|
|
|
|
|
2021-12-15 00:16:48 -05:00
|
|
|
def is_blocking(self, target):
|
2023-01-01 23:50:57 -05:00
|
|
|
return (
|
|
|
|
(
|
|
|
|
target.mastodon_username in self.mastodon_blocks
|
|
|
|
or target.mastodon_site in self.mastodon_domain_blocks
|
|
|
|
)
|
|
|
|
if target.is_authenticated
|
|
|
|
else self.preference.no_anonymous_view
|
|
|
|
)
|
2021-12-15 00:16:48 -05:00
|
|
|
|
|
|
|
def is_blocked_by(self, target):
|
2023-01-01 23:50:57 -05:00
|
|
|
return target.is_authenticated and target.is_blocking(self)
|
2021-12-15 00:16:48 -05:00
|
|
|
|
|
|
|
def is_muting(self, target):
|
|
|
|
return target.mastodon_username in self.mastodon_mutes
|
|
|
|
|
|
|
|
def is_following(self, target):
|
2023-01-01 23:50:57 -05:00
|
|
|
return (
|
|
|
|
self.mastodon_username in target.mastodon_followers
|
|
|
|
if target.mastodon_locked
|
|
|
|
else self.mastodon_username in target.mastodon_followers
|
|
|
|
or target.mastodon_username in self.mastodon_following
|
|
|
|
)
|
2021-12-15 00:16:48 -05:00
|
|
|
|
|
|
|
def is_followed_by(self, target):
|
|
|
|
return target.is_following(self)
|
|
|
|
|
2022-04-06 00:59:30 -04:00
|
|
|
def get_mark_for_item(self, item):
|
2023-01-01 23:50:57 -05:00
|
|
|
params = {item.__class__.__name__.lower() + "_id": item.id, "owner": self}
|
2022-04-06 00:59:30 -04:00
|
|
|
mark = item.mark_class.objects.filter(**params).first()
|
|
|
|
return mark
|
|
|
|
|
2022-05-13 00:11:59 -04:00
|
|
|
def get_max_visibility(self, viewer):
|
|
|
|
if not viewer.is_authenticated:
|
|
|
|
return 0
|
|
|
|
elif viewer == self:
|
|
|
|
return 2
|
|
|
|
elif viewer.is_blocked_by(self):
|
|
|
|
return -1
|
|
|
|
elif viewer.is_following(self):
|
|
|
|
return 1
|
|
|
|
else:
|
|
|
|
return 0
|
|
|
|
|
|
|
|
@classmethod
|
2023-01-01 23:50:57 -05:00
|
|
|
def get(cls, id):
|
2022-05-13 00:11:59 -04:00
|
|
|
if isinstance(id, str):
|
|
|
|
try:
|
2023-01-01 23:50:57 -05:00
|
|
|
username = id.split("@")[0]
|
|
|
|
site = id.split("@")[1]
|
|
|
|
except IndexError:
|
2022-05-13 00:11:59 -04:00
|
|
|
return None
|
2023-01-01 23:50:57 -05:00
|
|
|
query_kwargs = {"username": username, "mastodon_site": site}
|
2022-05-13 00:11:59 -04:00
|
|
|
elif isinstance(id, int):
|
2023-01-01 23:50:57 -05:00
|
|
|
query_kwargs = {"pk": id}
|
2022-05-13 00:11:59 -04:00
|
|
|
else:
|
|
|
|
return None
|
|
|
|
return User.objects.filter(**query_kwargs).first()
|
|
|
|
|
2020-05-01 22:46:15 +08:00
|
|
|
|
2021-02-17 15:08:16 +01:00
|
|
|
class Preference(models.Model):
|
|
|
|
user = models.OneToOneField(User, models.CASCADE, primary_key=True)
|
2023-01-01 23:50:57 -05:00
|
|
|
profile_layout = models.JSONField(
|
2021-02-17 15:08:16 +01:00
|
|
|
blank=True,
|
|
|
|
default=list,
|
|
|
|
)
|
2023-01-01 23:50:57 -05:00
|
|
|
export_status = models.JSONField(
|
|
|
|
blank=True, null=True, encoder=DjangoJSONEncoder, default=dict
|
|
|
|
)
|
|
|
|
import_status = models.JSONField(
|
|
|
|
blank=True, null=True, encoder=DjangoJSONEncoder, default=dict
|
|
|
|
)
|
2023-02-12 08:49:10 -05:00
|
|
|
default_no_share = models.BooleanField(default=False)
|
2022-05-30 17:54:35 -04:00
|
|
|
default_visibility = models.PositiveSmallIntegerField(default=0)
|
2022-05-30 22:48:11 -04:00
|
|
|
classic_homepage = models.BooleanField(null=False, default=False)
|
2021-12-11 09:43:31 -05:00
|
|
|
mastodon_publish_public = models.BooleanField(null=False, default=False)
|
2023-01-01 23:50:57 -05:00
|
|
|
mastodon_append_tag = models.CharField(max_length=2048, default="")
|
2022-11-17 15:19:05 +00:00
|
|
|
show_last_edit = models.PositiveSmallIntegerField(default=0)
|
2023-01-01 23:50:57 -05:00
|
|
|
no_anonymous_view = models.PositiveSmallIntegerField(default=0)
|
2021-02-17 15:08:16 +01:00
|
|
|
|
2021-02-17 17:36:22 +01:00
|
|
|
def __str__(self):
|
|
|
|
return str(self.user)
|
|
|
|
|
2021-02-17 15:08:16 +01:00
|
|
|
|
2020-05-01 22:46:15 +08:00
|
|
|
class Report(models.Model):
|
2023-01-01 23:50:57 -05:00
|
|
|
submit_user = models.ForeignKey(
|
|
|
|
User, on_delete=models.SET_NULL, related_name="sumbitted_reports", null=True
|
|
|
|
)
|
|
|
|
reported_user = models.ForeignKey(
|
|
|
|
User, on_delete=models.SET_NULL, related_name="accused_reports", null=True
|
|
|
|
)
|
|
|
|
image = models.ImageField(
|
|
|
|
upload_to=report_image_path,
|
|
|
|
height_field=None,
|
|
|
|
width_field=None,
|
|
|
|
blank=True,
|
|
|
|
default="",
|
|
|
|
)
|
2020-05-01 22:46:15 +08:00
|
|
|
is_read = models.BooleanField(default=False)
|
|
|
|
submitted_time = models.DateTimeField(auto_now_add=True)
|
2020-05-05 23:50:48 +08:00
|
|
|
message = models.CharField(max_length=1000)
|