allow alternative hostnames
This commit is contained in:
parent
f2abc7a7c0
commit
d2d755d7f6
16 changed files with 73 additions and 196 deletions
|
@ -1,5 +1,5 @@
|
|||
# 🧩 NeoDB
|
||||
_mark the things you love._
|
||||
_mark the things you love_
|
||||
|
||||

|
||||

|
||||
|
|
|
@ -41,6 +41,8 @@ env = environ.FileAwareEnv(
|
|||
),
|
||||
# Links in site footer
|
||||
NEODB_SITE_LINKS=(dict, {}),
|
||||
# Alternative domains
|
||||
NEODB_ALTERNATIVE_DOMAINS=(list, []),
|
||||
# Default language
|
||||
NEODB_LANGUAGE=(str, "zh-hans"),
|
||||
# Invite only mode
|
||||
|
@ -200,12 +202,9 @@ ALLOW_EMAIL_ONLY_ACCOUNT = env.bool(
|
|||
# Allow user to login via any Mastodon/Pleroma sites
|
||||
MASTODON_ALLOW_ANY_SITE = len(MASTODON_ALLOWED_SITES) == 0
|
||||
|
||||
REDIRECT_URIS = env(
|
||||
"NEODB_LOGIN_MASTODON_REDIRECT_URI",
|
||||
default=SITE_INFO["site_url"] + "/account/login/oauth",
|
||||
)
|
||||
# for sites migrated from previous version, either wipe mastodon client ids or use:
|
||||
# REDIRECT_URIS = f'{SITE_INFO["site_url"]}/users/OAuth2_login/'
|
||||
ALTERNATIVE_DOMAINS = env("NEODB_ALTERNATIVE_DOMAINS", default=[]) # type: ignore
|
||||
|
||||
SITE_DOMAINS = [SITE_DOMAIN] + ALTERNATIVE_DOMAINS
|
||||
|
||||
ENABLE_LOCAL_ONLY = env("NEODB_ENABLE_LOCAL_ONLY")
|
||||
|
||||
|
|
|
@ -126,7 +126,7 @@ def search(request):
|
|||
|
||||
if keywords.find("://") > 0:
|
||||
host = keywords.split("://")[1].split("/")[0]
|
||||
if host == settings.SITE_INFO["site_domain"]:
|
||||
if host in settings.SITE_DOMAINS:
|
||||
return redirect(keywords)
|
||||
site = SiteManager.get_site_by_url(keywords)
|
||||
if site:
|
||||
|
|
|
@ -51,10 +51,7 @@ class FediverseInstance(AbstractSite):
|
|||
val = URLValidator()
|
||||
try:
|
||||
val(url)
|
||||
if (
|
||||
url.split("://", 1)[1].split("/", 1)[0].lower()
|
||||
== settings.SITE_INFO["site_domain"]
|
||||
):
|
||||
if url.split("://", 1)[1].split("/", 1)[0].lower() in settings.SITE_DOMAINS:
|
||||
# disallow local instance URLs
|
||||
return False
|
||||
return cls.get_json_from_url(url) is not None
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
<div class="item">
|
||||
<div class="cover">
|
||||
<a href="{{ item.url }}">
|
||||
<img src="{{ item.cover_image_url }}" alt="cover" />
|
||||
<img src="{{ item.cover_image_url|relative_uri }}" alt="cover" />
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
<meta property="og:title"
|
||||
content="{{ site_name }}{% trans item.category.label %} - {{ item.display_title }}">
|
||||
<meta property="og:type" content="{{ item.category }}">
|
||||
<meta property="og:url" content="{{ request.build_absolute_uri }}">
|
||||
<meta property="og:url" content="{{ item.absolute_url }}">
|
||||
{% if item.has_cover %}<meta property="og:image" content="{{ item.cover_image_url }}">{% endif %}
|
||||
<meta property="og:site_name" content="{{ site_name }}">
|
||||
<meta property="og:description" content="{{ item.brief }}">
|
||||
|
@ -48,7 +48,7 @@
|
|||
</span>
|
||||
</div>
|
||||
<div id="item-cover" class="left">
|
||||
<img src="{{ item.cover_image_url|default:item.cover.url }}"
|
||||
<img src="{{ item.cover_image_url|default:item.cover.url|relative_uri }}"
|
||||
alt="{{ item.title }}">
|
||||
</div>
|
||||
{% if request.user.is_authenticated and not mark.shelf_type %}
|
||||
|
|
|
@ -15,9 +15,9 @@
|
|||
content="0;url={{ item.parent_item.url }}?focus={{ item.uuid }}{% if request.GET.position %}&position={{ request.GET.position }}{% endif %}" />
|
||||
{% endif %}
|
||||
<meta property="og:image"
|
||||
content="{{ item.cover_url | default:item.program.cover_image_url }}">
|
||||
content="{{ item.cover_url|default:item.program.cover_image_url }}">
|
||||
<meta property="twitter:image"
|
||||
content="{{ item.cover_url | default:item.program.cover_image_url }}">
|
||||
content="{{ item.cover_url|default:item.program.cover_image_url }}">
|
||||
{% if item.media_url and item.parent_item %}
|
||||
<meta property="twitter:card" content="player">
|
||||
<meta property="twitter:player"
|
||||
|
|
|
@ -15,6 +15,9 @@
|
|||
rel="noopener"
|
||||
href="https://github.com/neodb-social">源代码</a>
|
||||
</div>
|
||||
<div class="hide_unless_alter_domain" style="padding-top: 1em;">
|
||||
这是{{ site_name }}的临时镜像,请尽可能使用<a href="{{ site_url }}{{ request.get_full_path }}">原始站点</a>。
|
||||
</div>
|
||||
</footer>
|
||||
<div class="player"></div>
|
||||
<script>
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
{% load thumb %}
|
||||
{% load collection %}
|
||||
{% load bleach_tags %}
|
||||
{% load duration %}
|
||||
<aside class="grid__aside sidebar">
|
||||
{% if request.user.unread_announcements %}
|
||||
<section class="announcement">
|
||||
|
@ -40,7 +41,7 @@
|
|||
<div class="avatar">
|
||||
<a href="{{ identity.url }}" onclick="window.location = this.href;">
|
||||
{% comment %} onclick to workaround webkit issue with <a /> in <summary /> {% endcomment %}
|
||||
<img src="{{ identity.avatar }}" alt="">
|
||||
<img src="{{ identity.avatar|relative_uri }}" alt="">
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
|
@ -127,7 +128,7 @@
|
|||
data-position="0"
|
||||
href="{{ item.url }}"
|
||||
title="{{ item.title }}">
|
||||
<img src="{{ item.cover_image_url | default:item.cover.url }}"
|
||||
<img src="{{ item.cover_image_url|default:item.cover.url|relative_uri }}"
|
||||
alt="{{ item.title }}"
|
||||
loading="lazy">
|
||||
<div class="card-title">
|
||||
|
|
|
@ -51,4 +51,9 @@
|
|||
<link rel="apple-touch-icon" href="{{ site_logo }}">
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta name="apple-mobile-web-app-title" content="{{ site_name }}">
|
||||
{% if request.META.HTTP_HOST == site_domain %}
|
||||
<style type="text/css">.hide_unless_alter_domain{display:none;}</style>
|
||||
{% else %}
|
||||
<meta name="robots" content="noindex">
|
||||
{% endif %}
|
||||
{{ site_head|safe }}
|
||||
|
|
|
@ -54,6 +54,12 @@ def rating_star(value):
|
|||
return mark_safe(html)
|
||||
|
||||
|
||||
@register.filter()
|
||||
@stringfilter
|
||||
def relative_uri(value: str) -> str:
|
||||
return str(value).replace(settings.SITE_INFO["site_url"], "")
|
||||
|
||||
|
||||
@register.filter
|
||||
def make_range(number):
|
||||
return range(1, number + 1)
|
||||
|
|
|
@ -26,6 +26,8 @@ x-shared:
|
|||
NEODB_USER_ICON:
|
||||
NEODB_SITE_LINKS:
|
||||
NEODB_SITE_DESCRIPTION:
|
||||
NEODB_ALTERNATIVE_DOMAINS:
|
||||
NEODB_LANGUAGE:
|
||||
NEODB_ADMIN_USERNAMES:
|
||||
NEODB_INVITE_ONLY:
|
||||
NEODB_LOGIN_ENABLE_EMAIL_ONLY:
|
||||
|
|
|
@ -8,7 +8,6 @@ most settings resides in `settings.py`, a few notable ones:
|
|||
|
||||
- `SECRET_KEY` must use your own, back it up well somewhere
|
||||
- `SITE_INFO` change by you need
|
||||
- `REDIRECT_URIS` this should be `SITE_INFO["site_url"] + "/account/login/oauth"` . It used to be multiple urls separated by `\n` , but now it must be only one url, bc not all Fediverse software support >1 urls very well. Also note changing this later may invalidate app token granted previously
|
||||
- `MASTODON_ALLOW_ANY_SITE` set to `True` so that user can login via any Mastodon API compatible sites (e.g. Mastodon/Pleroma)
|
||||
- `MASTODON_CLIENT_SCOPE` change it later may invalidate app token granted previously
|
||||
- `ADMIN_URL` admin page url, keep it private
|
||||
|
@ -20,3 +19,19 @@ Settings for Scrapers
|
|||
---------------------
|
||||
|
||||
TBA
|
||||
|
||||
|
||||
Other maintenance tasks
|
||||
-----------------------
|
||||
|
||||
Add alias to your shell for easier access
|
||||
|
||||
```
|
||||
alias neodb-manage='docker-compose --profile production run shell neodb-manage'
|
||||
```
|
||||
|
||||
Enable Developer Console
|
||||
|
||||
```
|
||||
neodb-manage createapplication --client-id NEODB_DEVELOPER_CONSOLE --skip-authorization --name 'NeoDB Developer Console' --redirect-uris 'https://example.org/lol' confidential authorization-code
|
||||
```
|
||||
|
|
154
doc/install.md
154
doc/install.md
|
@ -1,156 +1,6 @@
|
|||
NiceDB / NeoDB - Getting Start
|
||||
==============================
|
||||
This is a very basic guide with limited detail, contributions welcomed
|
||||
|
||||
## Table of Contents
|
||||
- [Run in Docker](#0-run-in-docker)
|
||||
- [1 Install](#1-manual-install)
|
||||
* [1.1 Database](#11-database)
|
||||
* [1.2 Configuration](#12-configuration)
|
||||
* [1.3 Packages and Build](#13-packages-and-build)
|
||||
- [2 Start services](#2-start-services)
|
||||
- [3 Migrate from an earlier version](#3-migrate-from-an-earlier-version)
|
||||
- [4 Add Cron Jobs (optional)](#4-add-cron-jobs-optional)
|
||||
- [5 Index and Search (optional)](#5-index-and-search-optional)
|
||||
- [6 Other maintenance tasks (optional)](#6-other-maintenance-tasks-optional)
|
||||
- [7 Frequently Asked Questions](#7-frequently-asked-questions)
|
||||
see [Docker Installation](install-docker.md)
|
||||
|
||||
|
||||
|
||||
0 Run in Docker
|
||||
---------------
|
||||
|
||||
Recommended, see [Docker Installation](install-docker.md)
|
||||
|
||||
*Manual installation are no longer recommended and the doc below may be outdated*
|
||||
|
||||
1 Manual Install
|
||||
----------------
|
||||
Install PostgreSQL, Redis and Python (3.10 or above) if not yet
|
||||
|
||||
### 1.1 Database
|
||||
Setup database
|
||||
```
|
||||
CREATE ROLE neodb with LOGIN ENCRYPTED PASSWORD 'abadface';
|
||||
CREATE DATABASE neodb ENCODING 'UTF8' LC_COLLATE='en_US.UTF-8' LC_CTYPE='en_US.UTF-8' TEMPLATE template0;
|
||||
GRANT ALL ON DATABASE neodb TO neodb;
|
||||
```
|
||||
|
||||
### 1.2 Configuration
|
||||
Create and edit your own configuration file (optional but very much recommended)
|
||||
```
|
||||
mkdir mysite && cp boofilsic/settings.py mysite/
|
||||
export DJANGO_SETTINGS_MODULE=mysite.settings
|
||||
```
|
||||
Alternatively you can have a configuration file import `boofilsic/settings.py` then override it:
|
||||
```
|
||||
from boofilsic.settings import *
|
||||
|
||||
SECRET_KEY = "my_key"
|
||||
```
|
||||
|
||||
The most important configurations to setup are:
|
||||
|
||||
- `MASTODON_ALLOW_ANY_SITE` set to `True` so that user can login via any Mastodon API compatible sites (e.g. Mastodon/Pleroma)
|
||||
- `REDIRECT_URIS` should be `SITE_INFO["site_url"] + "/account/login/oauth"`. If you want to run **on local**, `SITE_INFO["site_url"]` should be set to `"http://localhost/"`
|
||||
|
||||
More details on `settings.py` in [configuration.md](configuration.md)
|
||||
|
||||
### 1.3 Packages and Build
|
||||
Create and use `venv` as you normally would, then install packages
|
||||
```
|
||||
python3 -m pip install -r requirements.txt
|
||||
|
||||
```
|
||||
|
||||
Quick check
|
||||
```
|
||||
python3 manage.py check
|
||||
```
|
||||
|
||||
Initialize database
|
||||
```
|
||||
python3 manage.py migrate
|
||||
```
|
||||
|
||||
Build static assets (production only)
|
||||
```
|
||||
python3 manage.py compilescss
|
||||
python3 manage.py collectstatic
|
||||
```
|
||||
|
||||
|
||||
2 Start services
|
||||
--------------
|
||||
Make sure PostgreSQL and Redis are running
|
||||
|
||||
Start job queue server
|
||||
```
|
||||
export OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES # required and only for macOS, otherwise it may crash
|
||||
python3 manage.py rqworker --with-scheduler import export mastodon fetch crawl
|
||||
```
|
||||
|
||||
Run web server in dev mode
|
||||
```
|
||||
python3 manage.py runserver
|
||||
```
|
||||
|
||||
It should be ready to serve from here, to run web server for production, consider `gunicorn -w 8 boofilsic.wsgi` in systemd or sth similar
|
||||
|
||||
|
||||
3 Migrate from an earlier version
|
||||
-------------------------------
|
||||
Update database
|
||||
```
|
||||
python3 manage.py migrate
|
||||
```
|
||||
|
||||
Rebuild static assets
|
||||
```
|
||||
python3 manage.py compilescss
|
||||
python3 manage.py collectstatic
|
||||
```
|
||||
|
||||
4 Add Cron Jobs (optional)
|
||||
-------------
|
||||
add `python manage.py refresh_mastodon` to crontab to run hourly, it will refresh cached users' follow/mute/block from mastodon
|
||||
|
||||
5 Index and Search (optional)
|
||||
----------------
|
||||
Install TypeSense or Meilisearch, change `SEARCH_BACKEND` and coniguration for search server in `settings.py`
|
||||
|
||||
Build initial index, it may take a few minutes or hours
|
||||
```
|
||||
python3 manage.py index --init
|
||||
python3 manage.py index --reindex
|
||||
```
|
||||
|
||||
6 Other maintenance tasks (optional)
|
||||
-----------------------
|
||||
Requeue failed import jobs
|
||||
```
|
||||
rq requeue --all --queue import
|
||||
```
|
||||
|
||||
Run Tests
|
||||
```
|
||||
coverage run --source='.' manage.py test
|
||||
coverage report
|
||||
```
|
||||
|
||||
Enable Developer Console
|
||||
```
|
||||
python3 manage.py createapplication --client-id NEODB_DEVELOPER_CONSOLE --skip-authorization --name 'NeoDB Developer Console' --redirect-uris 'https://example.org/lol' confidential authorization-code
|
||||
```
|
||||
|
||||
7 Frequently Asked Questions
|
||||
------
|
||||
|
||||
### I got Error: “无效的登录回调地址”.
|
||||
|
||||
Check `REDIRECT_URIS` in `settings.py`, the final value should be `"http://localhost/account/login/oauth"` or sth similar. If you are specifying a port, add the port to the localhost address.
|
||||
|
||||
If any change was made to `REDIRECT_URIS`, existing apps registered in Mastodon are no longer valid, so delete the app record in the database:
|
||||
```
|
||||
delete from mastodon_mastodonapplication;
|
||||
```
|
||||
*Manual installation are no longer supported*
|
||||
|
|
|
@ -8,6 +8,7 @@ from urllib.parse import quote
|
|||
import django_rq
|
||||
import requests
|
||||
from django.conf import settings
|
||||
from django.urls import reverse
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from loguru import logger
|
||||
|
||||
|
@ -226,29 +227,22 @@ def post_toot(
|
|||
return response
|
||||
|
||||
|
||||
def create_app(domain_name):
|
||||
# naive protocal strip
|
||||
is_http = False
|
||||
if domain_name.startswith("https://"):
|
||||
domain_name = domain_name.replace("https://", "")
|
||||
elif domain_name.startswith("http://"):
|
||||
is_http = True
|
||||
domain_name = domain_name.replace("http://", "")
|
||||
if domain_name.endswith("/"):
|
||||
domain_name = domain_name[0:-1]
|
||||
def _get_redirect_uris(allow_multiple=True) -> str:
|
||||
u = settings.SITE_INFO["site_url"] + "/account/login/oauth"
|
||||
if not allow_multiple:
|
||||
return u
|
||||
u2s = [f"https://{d}/account/login/oauth" for d in settings.ALTERNATIVE_DOMAINS]
|
||||
return "\n".join([u] + u2s)
|
||||
|
||||
if not is_http:
|
||||
|
||||
def create_app(domain_name, allow_multiple_redir):
|
||||
url = "https://" + domain_name + API_CREATE_APP
|
||||
else:
|
||||
url = "http://" + domain_name + API_CREATE_APP
|
||||
|
||||
payload = {
|
||||
"client_name": settings.SITE_INFO["site_name"],
|
||||
"scopes": settings.MASTODON_CLIENT_SCOPE,
|
||||
"redirect_uris": settings.REDIRECT_URIS,
|
||||
"redirect_uris": _get_redirect_uris(allow_multiple_redir),
|
||||
"website": settings.SITE_INFO["site_url"],
|
||||
}
|
||||
|
||||
response = post(url, data=payload, headers={"User-Agent": USER_AGENT})
|
||||
return response
|
||||
|
||||
|
@ -368,12 +362,12 @@ def get_or_create_fediverse_application(login_domain):
|
|||
if not settings.MASTODON_ALLOW_ANY_SITE:
|
||||
logger.warning(f"Disallowed to create app for {domain}")
|
||||
raise Exception("不支持其它实例登录")
|
||||
if settings.SITE_DOMAIN.lower() == login_domain.lower():
|
||||
if login_domain.lower() in settings.SITE_DOMAINS:
|
||||
raise ValueError("必须使用其它实例登录")
|
||||
domain, api_domain, server_version = detect_server_info(login_domain)
|
||||
if (
|
||||
settings.SITE_DOMAIN.lower() == domain.lower()
|
||||
or settings.SITE_DOMAIN.lower() == api_domain.lower()
|
||||
domain.lower() in settings.SITE_DOMAINS
|
||||
or api_domain.lower() in settings.SITE_DOMAINS
|
||||
):
|
||||
raise ValueError("必须使用其它实例登录")
|
||||
if "neodb/" in server_version:
|
||||
|
@ -382,7 +376,8 @@ def get_or_create_fediverse_application(login_domain):
|
|||
app = MastodonApplication.objects.filter(domain_name__iexact=domain).first()
|
||||
if app:
|
||||
return app
|
||||
response = create_app(api_domain)
|
||||
allow_multiple_redir = True # TODO detect site supports multiple redirect uris
|
||||
response = create_app(api_domain, allow_multiple_redir)
|
||||
if response.status_code != 200:
|
||||
logger.error(
|
||||
f"Error creating app for {domain} on {api_domain}: {response.status_code}"
|
||||
|
@ -406,7 +401,7 @@ def get_or_create_fediverse_application(login_domain):
|
|||
|
||||
|
||||
def get_mastodon_login_url(app, login_domain, request):
|
||||
url = settings.REDIRECT_URIS
|
||||
url = request.build_absolute_uri(reverse("users:login_oauth"))
|
||||
version = app.server_version or ""
|
||||
scope = (
|
||||
settings.MASTODON_LEGACY_CLIENT_SCOPE
|
||||
|
@ -429,7 +424,7 @@ def get_mastodon_login_url(app, login_domain, request):
|
|||
def obtain_token(site, request, code):
|
||||
"""Returns token if success else None."""
|
||||
mast_app = MastodonApplication.objects.get(domain_name=site)
|
||||
redirect_uri = settings.REDIRECT_URIS
|
||||
redirect_uri = request.build_absolute_uri(reverse("users:login_oauth"))
|
||||
payload = {
|
||||
"client_id": mast_app.client_id,
|
||||
"client_secret": mast_app.client_secret,
|
||||
|
|
|
@ -147,14 +147,18 @@
|
|||
{% endif %}
|
||||
</small>
|
||||
{% endif %}
|
||||
<small id="fedi-tips">如不便或尚未<a href="https://joinmastodon.org/zh/servers" target="_blank">注册联邦宇宙</a>,也可以在上方选择「电子邮件验证」注册登录本站。</small>
|
||||
<small id="email-tips" style="display:none;">现有用户通过联邦宇宙登录后关联电子邮件地址,即可通过邮件登录本站;如不便使用联邦宇宙,也可在此输入邮件地址注册账号,未来再关联到联邦宇宙。</small>
|
||||
</form>
|
||||
{% endif %}
|
||||
<small class="hide_unless_alter_domain">
|
||||
<br>
|
||||
这是{{ site_name }}的临时镜像,请尽可能使用<a href="{{ site_url }}{{ request.get_full_path }}">原始站点</a>。
|
||||
</small>
|
||||
<div class="delayed">部分模块加载超时,请检查网络(翻墙)设置。</div>
|
||||
</div>
|
||||
</article>
|
||||
<footer>
|
||||
<small id="fedi-tips">如尚未<a href="https://joinmastodon.org/zh/servers" target="_blank">注册联邦宇宙</a>,也可点选「电子邮件验证」注册登录本站。</small>
|
||||
<small id="email-tips" style="display:none;">现有用户通过联邦宇宙登录后关联电子邮件地址,即可通过邮件登录本站;如不便使用联邦宇宙,也可在此输入邮件地址注册账号,未来再关联到联邦宇宙。</small>
|
||||
<br>
|
||||
<small>继续访问或注册视为同意本站<a href="{% url 'management:retrieve_slug' 'data-policy' %}">数据方针</a>及使用cookie提供必要功能</small>
|
||||
</footer>
|
||||
|
|
Loading…
Add table
Reference in a new issue