let admin change site logo through UI #197

This commit is contained in:
rimu 2024-06-14 18:03:47 +08:00
parent be0544a372
commit 4b3844bbae
6 changed files with 112 additions and 14 deletions

View file

@ -2183,6 +2183,7 @@ def parse_redis_socket_string(connection_string: str):
def lemmy_site_data():
site = g.site
logo = site.logo if site.logo else '/static/images/logo2.png'
data = {
"site_view": {
"site": {
@ -2191,7 +2192,7 @@ def lemmy_site_data():
"sidebar": site.sidebar,
"published": site.created_at.isoformat(),
"updated": site.updated.isoformat(),
"icon": f"https://{current_app.config['SERVER_NAME']}/static/images/logo2.png",
"icon": f"https://{current_app.config['SERVER_NAME']}{logo}",
"banner": "",
"description": site.description,
"actor_id": f"https://{current_app.config['SERVER_NAME']}/",

View file

@ -1,11 +1,14 @@
import os
from datetime import datetime, timedelta
from io import BytesIO
from time import sleep
from flask import request, flash, json, url_for, current_app, redirect, g
from flask import request, flash, json, url_for, current_app, redirect, g, abort
from flask_login import login_required, current_user
from flask_babel import _
from slugify import slugify
from sqlalchemy import text, desc, or_
from PIL import Image
from app import db, celery, cache
from app.activitypub.routes import process_inbox_request, process_delete_request
@ -21,7 +24,7 @@ from app.models import AllowedInstances, BannedInstances, ActivityPubLog, utcnow
User, Instance, File, Report, Topic, UserRegistration, Role, Post, PostReply, Language
from app.utils import render_template, permission_required, set_setting, get_setting, gibberish, markdown_to_html, \
moderating_communities, joined_communities, finalize_user_setup, theme_list, blocked_phrases, blocked_referrers, \
topic_tree, languages_for_form, menu_topics
topic_tree, languages_for_form, menu_topics, ensure_directory_exists
from app.admin import bp
@ -53,6 +56,58 @@ def admin_site():
site.contact_email = form.contact_email.data
if site.id is None:
db.session.add(site)
# Save site icon
uploaded_icon = request.files['icon']
if uploaded_icon and uploaded_icon.filename != '':
allowed_extensions = ['.gif', '.jpg', '.jpeg', '.png', '.webp']
file_ext = os.path.splitext(uploaded_icon.filename)[1]
if file_ext.lower() not in allowed_extensions:
abort(400)
directory = 'app/static/media'
ensure_directory_exists(directory)
# Remove existing logo files
if os.path.isfile(f'app{site.logo}'):
os.unlink(f'app{site.logo}')
if os.path.isfile(f'app{site.logo_152}'):
os.unlink(f'app{site.logo_152}')
if os.path.isfile(f'app{site.logo_32}'):
os.unlink(f'app{site.logo_32}')
if os.path.isfile(f'app{site.logo_16}'):
os.unlink(f'app{site.logo_16}')
# Save logo file
base_filename = f'logo_{gibberish(5)}'
uploaded_icon.save(f'{directory}/{base_filename}{file_ext}')
img = Image.open(f'{directory}/{base_filename}{file_ext}')
if img.width > 100:
img.thumbnail((100, 100))
img.save(f'{directory}/{base_filename}_100{file_ext}')
site.logo = f'/static/media/{base_filename}_100{file_ext}'
delete_original = True
else:
site.logo = f'/static/media/{base_filename}{file_ext}'
delete_original = False
# Save multiple copies of the logo - different sizes
img = Image.open(f'{directory}/{base_filename}{file_ext}')
img.thumbnail((152, 152))
img.save(f'{directory}/{base_filename}_152{file_ext}')
site.logo_152 = f'/static/media/{base_filename}_152{file_ext}'
img = Image.open(f'{directory}/{base_filename}{file_ext}')
img.thumbnail((32, 32))
img.save(f'{directory}/{base_filename}_32{file_ext}')
site.logo_32 = f'/static/media/{base_filename}_32{file_ext}'
img = Image.open(f'{directory}/{base_filename}{file_ext}')
img.thumbnail((16, 16))
img.save(f'{directory}/{base_filename}_16{file_ext}')
site.logo_16 = f'/static/media/{base_filename}_16{file_ext}'
if delete_original:
os.unlink(f'app/static/media/{base_filename}{file_ext}')
db.session.commit()
set_setting('announcement', form.announcement.data)
flash('Settings saved.')

View file

@ -1479,6 +1479,10 @@ class Site(db.Model):
default_theme = db.Column(db.String(20), default='')
contact_email = db.Column(db.String(255), default='')
about = db.Column(db.Text, default='')
logo = db.Column(db.String(40), default='')
logo_152 = db.Column(db.String(40), default='')
logo_32 = db.Column(db.String(40), default='')
logo_16 = db.Column(db.String(40), default='')
@staticmethod
def admins() -> List[User]:

View file

@ -17,17 +17,17 @@
{{ render_field(form.name) }}
{{ render_field(form.description) }}
{{ render_field(form.sidebar) }}
<p class="small field_hint">HTML is allowed in this field.</p>
<p class="small field_hint">{{ _('HTML is allowed in this field.') }}</p>
{{ render_field(form.announcement) }}
<p class="small field_hint">HTML is allowed in this field.</p>
<p class="small field_hint">{{ _('HTML is allowed in this field.') }}</p>
{{ render_field(form.icon) }}
<p class="small field_hint">{{ _('Provide a square image, minimum 50 pixels wide but ideally 152+ pixels.') }}
<h2>{{ _('About this instance') }}</h2>
<p>{{ _('Provide a more extensive description of the instance, set a contact address and provide legal information. This information appears on the <a href="/about">about</a> page.') }}</p>
{{ render_field(form.about) }}
<p class="small field_hint">HTML is allowed in this field.</p>
<p class="small field_hint">{{ _('HTML is allowed in this field.') }}</p>
{{ render_field(form.legal_information) }}
<p class="small field_hint">HTML is allowed in this field.</p>
<p class="small field_hint">{{ _('HTML is allowed in this field.') }}</p>
{{ render_field(form.contact_email) }}
{{ render_field(form.submit) }}
</form>

View file

@ -53,12 +53,12 @@
{% endif -%}
{% endblock -%}
<title>{% if title %}{{ title }}{% else %}{{ _('PieFed') }}{% endif %}</title>
<link rel="apple-touch-icon" sizes="152x152" href="/static/images/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="/static/images/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/static/images/favicon-16x16.png">
<link rel="apple-touch-icon" sizes="152x152" href="{{ g.site.logo_152 if g.site.logo_152 else '/static/images/apple-touch-icon.png' }}">
<link rel="icon" type="image/png" sizes="32x32" href="{{ g.site.logo_32 if g.site.logo_32 else '/static/images/favicon-32x32.png' }}">
<link rel="icon" type="image/png" sizes="16x16" href="{{ g.site.logo_16 if g.site.logo_16 else '/static/images/favicon-16x16.png' }}">
<link rel="manifest" href="/static/manifest.json">
<link rel="shortcut icon" type="image/png" href="/static/images/favicon-32x32.png">
<link href='/static/images/favicon.ico' rel='icon' type='image/x-icon'>
<link rel="shortcut icon" type="image/png" href="{{ g.site.logo_32 if g.site.logo_32 else '/static/images/favicon-32x32.png' }}">
<link href="{{ g.site.logo_16 if g.site.logo_16 else '/static/images/favicon.ico' }}" rel='icon' type='image/x-icon'>
<meta name="msapplication-TileColor" content="#da532c">
<meta name="msapplication-config" content="/static/browserconfig.xml">
<meta name="theme-color" content="#ffffff">
@ -111,7 +111,7 @@
{% block navbar -%}
<div class="navbar navbar-expand-lg sticky-md-top">
<div class="{{ 'container-lg' if post_layout != 'masonry_wide' else 'container-fluid' }}" role="banner">
<a class="navbar-brand" href="/">{% if not low_bandwidth %}<img src="/static/images/logo2.png" alt="Logo" width="50" height="50" />{% endif %}{{ g.site.name }}</a>
<a class="navbar-brand" href="/">{% if not low_bandwidth %}<img src="{{ g.site.logo if g.site.logo else '/static/images/logo2.png' }}" alt="Logo" width="50" height="50" />{% endif %}{{ g.site.name }}</a>
{% if current_user.is_authenticated -%}
<a class="nav-link d-lg-none" href="/notifications" aria-label="{{ _('Notifications') }}">
{% if current_user.unread_notifications -%}

View file

@ -0,0 +1,38 @@
"""site logo
Revision ID: 1c51c3df2770
Revises: 5e84668d279e
Create Date: 2024-06-14 17:50:12.371773
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '1c51c3df2770'
down_revision = '5e84668d279e'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('site', schema=None) as batch_op:
batch_op.add_column(sa.Column('logo', sa.String(length=40), nullable=True))
batch_op.add_column(sa.Column('logo_152', sa.String(length=40), nullable=True))
batch_op.add_column(sa.Column('logo_32', sa.String(length=40), nullable=True))
batch_op.add_column(sa.Column('logo_16', sa.String(length=40), nullable=True))
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('site', schema=None) as batch_op:
batch_op.drop_column('logo_16')
batch_op.drop_column('logo_32')
batch_op.drop_column('logo_152')
batch_op.drop_column('logo')
# ### end Alembic commands ###