quick hack allow alternative settings and login via any Mastodon site

This commit is contained in:
Your Name 2021-09-10 20:24:22 -04:00
parent 921f8a29cf
commit 18df8ee3d7
19 changed files with 95 additions and 61 deletions

View file

@ -210,6 +210,9 @@ GAME_MEDIA_PATH_ROOT = 'game/'
DEFAULT_GAME_IMAGE = os.path.join(GAME_MEDIA_PATH_ROOT, 'default.svg')
SYNC_FILE_PATH_ROOT = 'sync/'
# Allow user to login via any Mastodon/Pleroma sites
MASTODON_ALLOW_ANY_SITE = False
# Timeout of requests to Mastodon, in seconds
MASTODON_TIMEOUT = 30

View file

@ -6,12 +6,12 @@ from django.core.serializers.json import DjangoJSONEncoder
from django.shortcuts import reverse
from common.models import Entity, Mark, Review, Tag
from common.utils import GenerateDateUUIDMediaFilePath
from boofilsic.settings import BOOK_MEDIA_PATH_ROOT, DEFAULT_BOOK_IMAGE
from django.utils import timezone
from django.conf import settings
def book_cover_path(instance, filename):
return GenerateDateUUIDMediaFilePath(instance, filename, BOOK_MEDIA_PATH_ROOT)
return GenerateDateUUIDMediaFilePath(instance, filename, settings.BOOK_MEDIA_PATH_ROOT)
class Book(Entity):
@ -43,7 +43,7 @@ class Book(Entity):
pages = models.PositiveIntegerField(_("pages"), null=True, blank=True)
isbn = models.CharField(_("ISBN"), blank=True, null=False, max_length=20, db_index=True, default='')
# to store previously scrapped data
cover = models.ImageField(_("cover picture"), upload_to=book_cover_path, default=DEFAULT_BOOK_IMAGE, blank=True)
cover = models.ImageField(_("cover picture"), upload_to=book_cover_path, default=settings.DEFAULT_BOOK_IMAGE, blank=True)
contents = models.TextField(blank=True, default="")
class Meta:

View file

@ -17,7 +17,7 @@ from common.models import SourceSiteEnum
from .models import *
from .forms import *
from .forms import BookMarkStatusTranslator
from boofilsic.settings import MASTODON_TAGS
from django.conf import settings
logger = logging.getLogger(__name__)
@ -314,7 +314,7 @@ def create_update_mark(request):
f"{book.title}" + \
rating_to_emoji(form.cleaned_data['rating'])
# tags = MASTODON_TAGS % {'category': '书', 'type': '标记'}
# tags = settings.MASTODON_TAGS % {'category': '书', 'type': '标记'}
tags = ''
content = words + '\n' + url + '\n' + \
form.cleaned_data['text'] + '\n' + tags
@ -405,7 +405,7 @@ def create_review(request, book_id):
url = "https://" + request.get_host() + reverse("books:retrieve_review",
args=[form.instance.id])
words = "发布了关于" + f"{form.instance.book.title}" + "的评论"
# tags = MASTODON_TAGS % {'category': '书', 'type': '评论'}
# tags = settings.MASTODON_TAGS % {'category': '书', 'type': '评论'}
tags = ''
content = words + '\n' + url + \
'\n' + form.cleaned_data['title'] + '\n' + tags
@ -457,7 +457,7 @@ def update_review(request, id):
url = "https://" + request.get_host() + reverse("books:retrieve_review",
args=[form.instance.id])
words = "发布了关于" + f"{form.instance.book.title}" + "的评论"
# tags = MASTODON_TAGS % {'category': '书', 'type': '评论'}
# tags = settings.MASTODON_TAGS % {'category': '书', 'type': '评论'}
tags = ''
content = words + '\n' + url + \
'\n' + form.cleaned_data['title'] + '\n' + tags

View file

@ -8,8 +8,8 @@ from django.db.models import Q
from markdownx.models import MarkdownxField
from users.models import User
from mastodon.api import get_relationships, get_cross_site_id
from boofilsic.settings import CLIENT_NAME
from django.utils import timezone
from django.conf import settings
RE_HTML_TAG = re.compile(r"<[^>]*>")
@ -18,7 +18,7 @@ RE_HTML_TAG = re.compile(r"<[^>]*>")
# abstract base classes
###################################
class SourceSiteEnum(models.TextChoices):
IN_SITE = "in-site", CLIENT_NAME
IN_SITE = "in-site", settings.CLIENT_NAME
DOUBAN = "douban", _("豆瓣")
SPOTIFY = "spotify", _("Spotify")
IMDB = "imdb", _("IMDb")

View file

@ -9,8 +9,6 @@ import time
from lxml import html
from mimetypes import guess_extension
from threading import Thread
from boofilsic.settings import LUMINATI_USERNAME, LUMINATI_PASSWORD, DEBUG, IMDB_API_KEY, SCRAPERAPI_KEY
from boofilsic.settings import SPOTIFY_CREDENTIAL
from django.utils import timezone
from django.utils.translation import ugettext_lazy as _
from django.core.exceptions import ObjectDoesNotExist, ValidationError
@ -24,6 +22,7 @@ from music.models import Album, Song
from music.forms import AlbumForm, SongForm
from games.models import Game
from games.forms import GameForm
from django.conf import settings
RE_NUMBERS = re.compile(r"\d+\d*")
@ -152,12 +151,12 @@ class AbstractScraper:
session_id = random.random()
proxy_url = ('http://%s-country-cn-session-%s:%s@zproxy.lum-superproxy.io:%d' %
(LUMINATI_USERNAME, session_id, LUMINATI_PASSWORD, PORT))
(settings.LUMINATI_USERNAME, session_id, settings.LUMINATI_PASSWORD, PORT))
proxies = {
'http': proxy_url,
'https': proxy_url,
}
# if DEBUG:
# if settings.DEBUG:
# proxies = None
r = requests.get(url, proxies=proxies,
headers=headers, timeout=TIMEOUT)
@ -175,12 +174,12 @@ class AbstractScraper:
raw_img = None
session_id = random.random()
proxy_url = ('http://%s-country-cn-session-%s:%s@zproxy.lum-superproxy.io:%d' %
(LUMINATI_USERNAME, session_id, LUMINATI_PASSWORD, PORT))
(settings.LUMINATI_USERNAME, session_id, settings.LUMINATI_PASSWORD, PORT))
proxies = {
'http': proxy_url,
'https': proxy_url,
}
# if DEBUG:
# if settings.DEBUG:
# proxies = None
if url:
img_response = requests.get(
@ -225,7 +224,7 @@ class DoubanScrapperMixin:
def download_page(cls, url, headers):
url = cls.get_effective_url(url)
scraper_api_endpoint = f'http://api.scraperapi.com?api_key={SCRAPERAPI_KEY}&url={url}'
scraper_api_endpoint = f'http://api.scraperapi.com?api_key={settings.SCRAPERAPI_KEY}&url={url}'
r = requests.get(scraper_api_endpoint, timeout=TIMEOUT)
@ -926,7 +925,7 @@ def invoke_spotify_token():
"grant_type": "client_credentials"
},
headers={
"Authorization": f"Basic {SPOTIFY_CREDENTIAL}"
"Authorization": f"Basic {settings.SPOTIFY_CREDENTIAL}"
}
)
data = r.json()
@ -940,7 +939,7 @@ def invoke_spotify_token():
"grant_type": "client_credentials"
},
headers={
"Authorization": f"Basic {SPOTIFY_CREDENTIAL}"
"Authorization": f"Basic {settings.SPOTIFY_CREDENTIAL}"
}
)
data = r.json()
@ -1049,7 +1048,7 @@ class ImdbMovieScraper(AbstractScraper):
@classmethod
def get_api_url(cls, url):
return f"https://imdb-api.com/zh/API/Title/{IMDB_API_KEY}/{cls.regex.findall(url)[0]}/FullActor,"
return f"https://imdb-api.com/zh/API/Title/{settings.IMDB_API_KEY}/{cls.regex.findall(url)[0]}/FullActor,"
class DoubanGameScraper(DoubanScrapperMixin, AbstractScraper):

View file

@ -6,12 +6,12 @@ from django.core.serializers.json import DjangoJSONEncoder
from django.shortcuts import reverse
from common.models import Entity, Mark, Review, Tag
from common.utils import ChoicesDictGenerator, GenerateDateUUIDMediaFilePath
from boofilsic.settings import GAME_MEDIA_PATH_ROOT, DEFAULT_GAME_IMAGE
from django.utils import timezone
from django.conf import settings
def game_cover_path(instance, filename):
return GenerateDateUUIDMediaFilePath(instance, filename, GAME_MEDIA_PATH_ROOT)
return GenerateDateUUIDMediaFilePath(instance, filename, settings.GAME_MEDIA_PATH_ROOT)
class Game(Entity):
@ -68,7 +68,7 @@ class Game(Entity):
verbose_name=_("平台")
)
cover = models.ImageField(_("封面"), upload_to=game_cover_path, default=DEFAULT_GAME_IMAGE, blank=True)
cover = models.ImageField(_("封面"), upload_to=game_cover_path, default=settings.DEFAULT_GAME_IMAGE, blank=True)

View file

@ -16,7 +16,7 @@ from common.views import PAGE_LINK_NUMBER, jump_or_scrape
from common.models import SourceSiteEnum
from .models import *
from .forms import *
from boofilsic.settings import MASTODON_TAGS
from django.conf import settings
logger = logging.getLogger(__name__)
@ -316,7 +316,7 @@ def create_update_mark(request):
f"{game.title}" + \
rating_to_emoji(form.cleaned_data['rating'])
# tags = MASTODON_TAGS % {'category': '书', 'type': '标记'}
# tags = settings.MASTODON_TAGS % {'category': '书', 'type': '标记'}
tags = ''
content = words + '\n' + url + '\n' + \
form.cleaned_data['text'] + '\n' + tags
@ -408,7 +408,7 @@ def create_review(request, game_id):
url = "https://" + request.get_host() + reverse("games:retrieve_review",
args=[form.instance.id])
words = "发布了关于" + f"{form.instance.game.title}" + "的评论"
# tags = MASTODON_TAGS % {'category': '书', 'type': '评论'}
# tags = settings.MASTODON_TAGS % {'category': '书', 'type': '评论'}
tags = ''
content = words + '\n' + url + \
'\n' + form.cleaned_data['title'] + '\n' + tags
@ -460,7 +460,7 @@ def update_review(request, id):
url = "https://" + request.get_host() + reverse("games:retrieve_review",
args=[form.instance.id])
words = "发布了关于" + f"{form.instance.game.title}" + "的评论"
# tags = MASTODON_TAGS % {'category': '书', 'type': '评论'}
# tags = settings.MASTODON_TAGS % {'category': '书', 'type': '评论'}
tags = ''
content = words + '\n' + url + \
'\n' + form.cleaned_data['title'] + '\n' + tags

View file

@ -3,9 +3,8 @@ import string
import random
import functools
from django.core.exceptions import ObjectDoesNotExist
from boofilsic.settings import MASTODON_TIMEOUT
from boofilsic.settings import CLIENT_NAME, APP_WEBSITE, REDIRECT_URIS
from .models import CrossSiteUserInfo
from django.conf import settings
# See https://docs.joinmastodon.org/methods/accounts/
@ -47,8 +46,8 @@ API_CREATE_APP = '/api/v1/apps'
API_SEARCH = '/api/v2/search'
get = functools.partial(requests.get, timeout=MASTODON_TIMEOUT)
post = functools.partial(requests.post, timeout=MASTODON_TIMEOUT)
get = functools.partial(requests.get, timeout=settings.MASTODON_TIMEOUT)
post = functools.partial(requests.post, timeout=settings.MASTODON_TIMEOUT)
# low level api below
@ -96,14 +95,13 @@ def create_app(domain_name):
url = 'http://' + domain_name + API_CREATE_APP
payload = {
'client_name': CLIENT_NAME,
'client_name': settings.CLIENT_NAME,
'scopes': 'read write follow',
'redirect_uris': REDIRECT_URIS,
'website': APP_WEBSITE
'redirect_uris': settings.REDIRECT_URIS,
'website': settings.APP_WEBSITE
}
from boofilsic.settings import DEBUG
if DEBUG:
if settings.DEBUG:
payload['redirect_uris'] = 'http://localhost/users/OAuth2_login/\nurn:ietf:wg:oauth:2.0:oob'
payload['client_name'] = 'test_do_not_authorise'

View file

@ -2,6 +2,7 @@ from django.contrib.auth.backends import ModelBackend, UserModel
from django.shortcuts import reverse
from .api import *
from .models import MastodonApplication
from django.conf import settings
def obtain_token(site, request, code):
@ -15,8 +16,7 @@ def obtain_token(site, request, code):
'code': code,
'scope': 'read write'
}
from boofilsic.settings import DEBUG
if DEBUG:
if settings.DEBUG:
payload['redirect_uri']= f"http://{request.get_host()}{reverse('users:OAuth2_login')}",
if mast_app.is_proxy:
url = 'https://' + mast_app.proxy_to + API_OBTAIN_TOKEN

View file

@ -1,4 +1,4 @@
from boofilsic.settings import STAR_EMPTY, STAR_HALF, STAR_SOLID
from django.conf import settings
def rating_to_emoji(score):
@ -8,7 +8,7 @@ def rating_to_emoji(score):
solid_stars = score // 2
half_star = int(bool(score % 2))
empty_stars = 5 - solid_stars if not half_star else 5 - solid_stars - 1
emoji_code = STAR_SOLID * solid_stars + STAR_HALF * half_star + STAR_EMPTY * empty_stars
emoji_code = settings.STAR_SOLID * solid_stars + settings.STAR_HALF * half_star + settings.STAR_EMPTY * empty_stars
emoji_code = emoji_code.replace("::", ": :")
emoji_code = ' ' + emoji_code + ' '
return emoji_code

View file

@ -6,12 +6,12 @@ from django.core.serializers.json import DjangoJSONEncoder
from django.shortcuts import reverse
from common.models import Entity, Mark, Review, Tag
from common.utils import ChoicesDictGenerator, GenerateDateUUIDMediaFilePath
from boofilsic.settings import MOVIE_MEDIA_PATH_ROOT, DEFAULT_MOVIE_IMAGE
from django.utils import timezone
from django.conf import settings
def movie_cover_path(instance, filename):
return GenerateDateUUIDMediaFilePath(instance, filename, MOVIE_MEDIA_PATH_ROOT)
return GenerateDateUUIDMediaFilePath(instance, filename, settings.MOVIE_MEDIA_PATH_ROOT)
class MovieGenreEnum(models.TextChoices):
@ -140,7 +140,7 @@ class Movie(Entity):
year = models.PositiveIntegerField(null=True, blank=True)
duration = models.CharField(blank=True, default='', max_length=200)
cover = models.ImageField(_("poster"), upload_to=movie_cover_path, default=DEFAULT_MOVIE_IMAGE, blank=True)
cover = models.ImageField(_("poster"), upload_to=movie_cover_path, default=settings.DEFAULT_MOVIE_IMAGE, blank=True)
############################################
# exclusive fields to series

View file

@ -16,7 +16,7 @@ from common.views import PAGE_LINK_NUMBER, jump_or_scrape
from common.models import SourceSiteEnum
from .models import *
from .forms import *
from boofilsic.settings import MASTODON_TAGS
from django.conf import settings
logger = logging.getLogger(__name__)
@ -315,7 +315,7 @@ def create_update_mark(request):
f"{movie.title}" + \
rating_to_emoji(form.cleaned_data['rating'])
# tags = MASTODON_TAGS % {'category': '书', 'type': '标记'}
# tags = settings.MASTODON_TAGS % {'category': '书', 'type': '标记'}
tags = ''
content = words + '\n' + url + '\n' + \
form.cleaned_data['text'] + '\n' + tags
@ -407,7 +407,7 @@ def create_review(request, movie_id):
url = "https://" + request.get_host() + reverse("movies:retrieve_review",
args=[form.instance.id])
words = "发布了关于" + f"{form.instance.movie.title}" + "的评论"
# tags = MASTODON_TAGS % {'category': '书', 'type': '评论'}
# tags = settings.MASTODON_TAGS % {'category': '书', 'type': '评论'}
tags = ''
content = words + '\n' + url + \
'\n' + form.cleaned_data['title'] + '\n' + tags
@ -459,7 +459,7 @@ def update_review(request, id):
url = "https://" + request.get_host() + reverse("movies:retrieve_review",
args=[form.instance.id])
words = "发布了关于" + f"{form.instance.movie.title}" + "的评论"
# tags = MASTODON_TAGS % {'category': '书', 'type': '评论'}
# tags = settings.MASTODON_TAGS % {'category': '书', 'type': '评论'}
tags = ''
content = words + '\n' + url + \
'\n' + form.cleaned_data['title'] + '\n' + tags

View file

@ -6,16 +6,16 @@ from django.core.serializers.json import DjangoJSONEncoder
from django.shortcuts import reverse
from common.models import Entity, Mark, Review, Tag
from common.utils import ChoicesDictGenerator, GenerateDateUUIDMediaFilePath
from boofilsic.settings import SONG_MEDIA_PATH_ROOT, DEFAULT_SONG_IMAGE, ALBUM_MEDIA_PATH_ROOT, DEFAULT_ALBUM_IMAGE
from django.utils import timezone
from django.conf import settings
def song_cover_path(instance, filename):
return GenerateDateUUIDMediaFilePath(instance, filename, SONG_MEDIA_PATH_ROOT)
return GenerateDateUUIDMediaFilePath(instance, filename, settings.SONG_MEDIA_PATH_ROOT)
def album_cover_path(instance, filename):
return GenerateDateUUIDMediaFilePath(instance, filename, ALBUM_MEDIA_PATH_ROOT)
return GenerateDateUUIDMediaFilePath(instance, filename, settings.ALBUM_MEDIA_PATH_ROOT)
class Album(Entity):
@ -23,7 +23,7 @@ class Album(Entity):
release_date = models.DateField(
_('发行日期'), auto_now=False, auto_now_add=False, null=True, blank=True)
cover = models.ImageField(
_("封面"), upload_to=album_cover_path, default=DEFAULT_ALBUM_IMAGE, blank=True)
_("封面"), upload_to=album_cover_path, default=settings.DEFAULT_ALBUM_IMAGE, blank=True)
duration = models.PositiveIntegerField(_("时长"), null=True, blank=True)
artist = postgres.ArrayField(
models.CharField(_("artist"), blank=True,
@ -70,7 +70,7 @@ class Song(Entity):
# duration in ms
duration = models.PositiveIntegerField(_("时长"), null=True, blank=True)
cover = models.ImageField(
_("封面"), upload_to=song_cover_path, default=DEFAULT_SONG_IMAGE, blank=True)
_("封面"), upload_to=song_cover_path, default=settings.DEFAULT_SONG_IMAGE, blank=True)
artist = postgres.ArrayField(
models.CharField(blank=True,
default='', max_length=100),

View file

@ -1,4 +1,3 @@
# from boofilsic.settings import MASTODON_TAGS
from .forms import *
from .models import *
from common.models import SourceSiteEnum
@ -20,7 +19,6 @@ import logging
from django.shortcuts import render
logger = logging.getLogger(__name__)
mastodon_logger = logging.getLogger("django.mastodon")

View file

@ -2,12 +2,12 @@ from django.db import models
from django.utils.translation import ugettext_lazy as _
import django.contrib.postgres.fields as postgres
from users.models import User
from boofilsic.settings import SYNC_FILE_PATH_ROOT
from common.utils import GenerateDateUUIDMediaFilePath
from django.conf import settings
def sync_file_path(instance, filename):
return GenerateDateUUIDMediaFilePath(instance, filename, SYNC_FILE_PATH_ROOT)
return GenerateDateUUIDMediaFilePath(instance, filename, settings.SYNC_FILE_PATH_ROOT)
class SyncTask(models.Model):

View file

@ -3,14 +3,14 @@ import django.contrib.postgres.fields as postgres
from django.db import models
from django.contrib.auth.models import AbstractUser
from django.utils import timezone
from boofilsic.settings import REPORT_MEDIA_PATH_ROOT, DEFAULT_PASSWORD
from django.core.serializers.json import DjangoJSONEncoder
from django.utils.translation import ugettext_lazy as _
from common.utils import GenerateDateUUIDMediaFilePath
from django.conf import settings
def report_image_path(instance, filename):
return GenerateDateUUIDMediaFilePath(instance, filename, REPORT_MEDIA_PATH_ROOT)
return GenerateDateUUIDMediaFilePath(instance, filename, settings.REPORT_MEDIA_PATH_ROOT)
class User(AbstractUser):
@ -28,8 +28,8 @@ class User(AbstractUser):
]
def save(self, *args, **kwargs):
""" Automatically populate password field with DEFAULT_PASSWORD before saving."""
self.set_password(DEFAULT_PASSWORD)
""" Automatically populate password field with settings.DEFAULT_PASSWORD before saving."""
self.set_password(settings.DEFAULT_PASSWORD)
return super().save(*args, **kwargs)
def __str__(self):

View file

@ -35,6 +35,11 @@
{% if user.is_authenticated %}
<a href="{% url 'common:home' %}" class="button">{% trans '前往我的主页' %}</a>
{% elif allow_any_site %}
<form action="/users/connect" onsubmit="Cookies.set('mastodon_domain', $('#domain').val());">
<input type="url" name="domain" id="domain" placeholder="mastodon.social" />
<input type='submit' value="{% trans '授权登录' %}" />
</form>
{% else %}
<select name="sites" id="sitesSelect" placeholder="test">
{% for site in sites %}
@ -47,7 +52,7 @@
</div>
</div>
{% if not user.is_authenticated %}
{% if not user.is_authenticated and not allow_any_site %}
<script>

View file

@ -5,6 +5,7 @@ app_name = 'users'
urlpatterns = [
path('login/', login, name='login'),
path('register/', register, name='register'),
path('connect/', connect, name='connect'),
path('logout/', logout, name='logout'),
path('delete/', delete, name='delete'),
path('layout/', set_layout, name='set_layout'),

View file

@ -25,7 +25,7 @@ from movies.forms import MovieMarkStatusTranslator
from music.forms import MusicMarkStatusTranslator
from games.forms import GameMarkStatusTranslator
from mastodon.models import MastodonApplication
from django.conf import settings
# Views
########################################
@ -89,11 +89,41 @@ def login(request):
{
'sites': sites,
'selected_site': selected_site,
'allow_any_site': settings.MASTODON_ALLOW_ANY_SITE,
}
)
else:
return HttpResponseBadRequest()
def connect(request):
domain = request.GET.get('domain').strip().lower()
app = MastodonApplication.objects.filter(domain_name=domain).first()
if app is None:
try:
response = create_app(domain)
except (requests.exceptions.Timeout, ConnectionError):
error_msg = _("长毛象请求超时。")
except Exception as e:
error_msg = str(e)
else:
# fill the form with returned data
data = response.json()
if response.status_code != 200:
error_msg = str(data)
else:
app = MastodonApplication.objects.create(domain_name=domain, app_id=data['id'], client_id=data['client_id'],
client_secret=data['client_secret'], vapid_key=data['vapid_key'])
if app is None:
return render(request,
'common/error.html',
{
'msg': error_msg,
'secondary_msg': "",
}
)
else:
login_url = "https://" + domain + "/oauth/authorize?client_id=" + app.client_id + "&scope=read+write&redirect_uri=http://" + request.get_host() + reverse('users:OAuth2_login') + "&response_type=code"
return redirect(login_url)
@mastodon_request_included
@login_required