Finished the merge, Disabling comments, Community bans.

This commit is contained in:
some weird guy
2023-08-12 14:55:51 -07:00
parent 46844a7cfb
commit 74ef0db34c
67 changed files with 870 additions and 759 deletions
+16
View File
@@ -0,0 +1,16 @@
Stuff that is done:
- Disable comments button
- merge with closedverse-video-support (mostly)
- Prevent users from posting in communities created by blocked users.
Stuff that is in progress
- Removing shitty code.
- Finding and killing bugs!
Stuff that I want
- Image and video file boxes in one.
- Pinning posts????
Not needed at all if I'm being honest.
- Ways for mods to view who invited who.
- Hide email password reset form if no SMTP server is set up.
- Fix icon and banner uploads. Make that shit work with image_upload
+1 -10
View File
@@ -33,7 +33,6 @@ If you have an announcement community, each post will appear there.
Can you rewrite this? Can you rewrite this?
# YOU NEED # YOU NEED
- Cloudflare
- A server (obviously) - A server (obviously)
- Terminal access (also, obviously) - Terminal access (also, obviously)
- Python 3 - Python 3
@@ -55,7 +54,7 @@ You need Pip
4. 4.
Get everything else you need. Get everything else you need.
`pip3 install Django==3.2.2 urllib3 lxml passlib bcrypt pillow django-markdown-deux django-markdown2 whitenoise` `pip3 install Django==3.2.2 urllib3 lxml passlib bcrypt pillow django-markdown-deux django-markdown2 whitenoise django-xff`
5. 5.
Clone the clone! Clone the clone!
@@ -99,9 +98,6 @@ A: You forgot to migrate and make the database.
Q: "Why is the page white, with no color or style at all?" Q: "Why is the page white, with no color or style at all?"
A: You need to collect the static files as mentioned prior. A: You need to collect the static files as mentioned prior.
Q: "KeyError: HTTP_CF_CONNECTING_IP"
A: Cloudflare is needed for this shit to work properly.
You may have to do some additional troubleshooting, and that's the joy of web-hosting. You may have to do some additional troubleshooting, and that's the joy of web-hosting.
Fixing problems yourself is a great way to learn how this shit works. Fixing problems yourself is a great way to learn how this shit works.
@@ -148,8 +144,3 @@ Make sure it works too!
``` ```
sudo systemctl status django sudo systemctl status django
``` ```
18.
The final stretch!
Set up your server with Cloudflare. You need a domain name, and you need patience, as this can take some time to take effect.
If you do this final step right, Cedar should be working fine, and it should have HTTPS working too!
+144 -77
View File
@@ -1,43 +1,46 @@
""" """
Django settings for closedverse project. Django settings for closedverse project.
Generated by 'django-admin startproject' using Django 1.10.7. Generated by 'django-admin startproject' using Django 2.2.13.
For more information on this file, see For more information on this file, see
https://docs.djangoproject.com/en/1.10/topics/settings/ https://docs.djangoproject.com/en/2.2/topics/settings/
For the full list of settings and their values, see For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.10/ref/settings/ https://docs.djangoproject.com/en/2.2/ref/settings/
""" """
# Django Settings
import os import os
# Build paths inside the project like this: os.path.join(BASE_DIR, ...) # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = False
PROD = False
# Quick-start development settings - unsuitable for production # Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.10/howto/deployment/checklist/ # See https://docs.djangoproject.com/en/2.2/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret! (If you want a website that can generate key https://miniwebtool.com/django-secret-key-generator/ goto here.) # SECURITY WARNING: keep the secret key used in production secret! (If you want a website that can generate key https://miniwebtool.com/django-secret-key-generator/ goto here.)
SECRET_KEY = '' SECRET_KEY = ''
# Change the ALLOWED_HOSTS to your liking. # SECURITY WARNING: don't run with debug turned on in production!
DEBUG = False
# This is just a default value for testing
# Do not include 127.0.0.1 or localhost
# in production for security reasons.
ALLOWED_HOSTS = [ ALLOWED_HOSTS = [
'domain.com' '127.0.0.1',
] ]
DEFAULT_AUTO_FIELD = 'django.db.models.AutoField' DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'
STATIC_URL = '/s/'
MEDIA_URL = '/i/'
CLOSEDVERSE_PROD = True
IMAGE_DELETE_SETTING = 2
# Application definition # Application definition
INSTALLED_APPS = [ INSTALLED_APPS = [
'admin_interface',
'colorfield',
'django.contrib.admin', 'django.contrib.admin',
'django.contrib.auth', 'django.contrib.auth',
'django.contrib.contenttypes', 'django.contrib.contenttypes',
@@ -46,22 +49,26 @@ INSTALLED_APPS = [
'django.contrib.staticfiles', 'django.contrib.staticfiles',
'markdown_deux', 'markdown_deux',
'closedverse_main', 'closedverse_main',
'ban',
'maintenance',
] ]
X_FRAME_OPTIONS='SAMEORIGIN' X_FRAME_OPTIONS='SAMEORIGIN'
MIDDLEWARE = [ MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware', 'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware',
# use this middleware if you need x-forwarded-for support
#'xff.middleware.XForwardedForMiddleware',
'django.middleware.common.CommonMiddleware', 'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware', 'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware', 'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware',
#'ban.middleware.BanManagement',
'closedverse_main.middleware.ClosedMiddleware', 'closedverse_main.middleware.ClosedMiddleware',
'whitenoise.middleware.WhiteNoiseMiddleware' #'maintenance.middleware.MaintenanceManagement',
] ]
if not DEBUG:
MIDDLEWARE += ['whitenoise.middleware.WhiteNoiseMiddleware']
ROOT_URLCONF = 'closedverse.urls' ROOT_URLCONF = 'closedverse.urls'
@@ -76,6 +83,7 @@ TEMPLATES = [
'django.template.context_processors.request', 'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth', 'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages', 'django.contrib.messages.context_processors.messages',
'closedverse_main.context_processors.brand_name_universal',
], ],
}, },
}, },
@@ -85,17 +93,41 @@ WSGI_APPLICATION = 'closedverse.wsgi.application'
# Database # Database
# https://docs.djangoproject.com/en/1.10/ref/settings/#databases # https://docs.djangoproject.com/en/2.2/ref/settings/#databases
DATABASES = { DATABASES = {
'default': { 'default': {
'ENGINE': 'django.db.backends.sqlite3', 'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR + '/sql.sqlite3', 'NAME': os.path.join(BASE_DIR, 'sql.sqlite3'),
} }
} }
"""
# log errors.
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'file': {
'level': 'ERROR',
'class': 'logging.FileHandler',
'filename': 'logs/errors.log',
},
},
'loggers': {
'django': {
'handlers': ['file'],
'level': 'ERROR',
'propagate': True,
},
},
}
"""
# Password validation # Password validation
# https://docs.djangoproject.com/en/1.10/ref/settings/#auth-password-validators # https://docs.djangoproject.com/en/2.2/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [ AUTH_PASSWORD_VALIDATORS = [
{ {
@@ -114,67 +146,95 @@ AUTH_PASSWORD_VALIDATORS = [
# Internationalization # Internationalization
# https://docs.djangoproject.com/en/1.10/topics/i18n/ # https://docs.djangoproject.com/en/2.2/topics/i18n/
TIME_ZONE = 'PST8PDT'
LANGUAGE_CODE = 'en-us' LANGUAGE_CODE = 'en-us'
USE_I18N = True # replace with your own timezone
TIME_ZONE = 'PST8PDT'
USE_L10N = True # Disable internationalization because Closedverse doesn't use it
USE_I18N = False
USE_L10N = False
USE_TZ = True USE_TZ = True
# You can use Mailtrap to get the email system working. Mailtrap is free and will work well for what you'll be doing with this.
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'send.smtp.mailtrap.io'
EMAIL_HOST_USER = 'api'
EMAIL_HOST_PASSWORD = ''
EMAIL_PORT = ''
EMAIL_USE_TLS = True
DEFAULT_FROM_EMAIL = 'noreply@domain'
YOUR_DOMAIN = 'yoursite.com'
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/2.2/howto/static-files/
#STATIC_URL = '/static/'
if not DEBUG:
# without this, this will not serve static for admin (and other apps potentially)
WHITENOISE_USE_FINDERS = True
STATICFILES_STORAGE = 'whitenoise.storage.CompressedStaticFilesStorage'
STATIC_ROOT = os.path.join(BASE_DIR, 'static/')
else:
# Define static files in the base directory
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'static/'),
]
# Closedverse models and routes for Django
AUTH_USER_MODEL = 'closedverse_main.User' AUTH_USER_MODEL = 'closedverse_main.User'
CSRF_FAILURE_VIEW = 'closedverse_main.views.csrf_fail' CSRF_FAILURE_VIEW = 'closedverse_main.views.csrf_fail'
LOGIN_URL = '/login/' LOGIN_URL = '/login/'
LOGIN_REDIRECT_URL = '/login/' LOGIN_REDIRECT_URL = '/login/'
# Static files (CSS, JavaScript, Images) # User-uploaded media paths for Closedverse
# https://docs.djangoproject.com/en/1.10/howto/static-files/ #MEDIA_URL = '/media/'
STATICFILES_DIRS = [ # Must end with a trailing slash
os.path.join(BASE_DIR, 'static/')
]
STATIC_URL = '/s/'
STATIC_ROOT = os.path.join(BASE_DIR, 's/')
STATICFILES_STORAGE = 'whitenoise.storage.CompressedStaticFilesStorage'
# Media root
# This MUST end with a trailing slash and there must be an 'rm' folder in it
MEDIA_ROOT = os.path.join(BASE_DIR, 'media/') MEDIA_ROOT = os.path.join(BASE_DIR, 'media/')
# URL that handles the media served from MEDIA_ROOT. Make sure to use a
# trailing slash.
# Examples: "http://media.lawrence.com/media/", "http://example.com/media/"
MEDIA_URL = '/i/'
# Cedar Three settings # Settings for markdown_deux, a module
# reCAPTCHA v2 keys, None for no reCAPTCHA # that Closedverse uses in user messages
recaptcha_pub = '' MARKDOWN_DEUX_STYLES = {
recaptcha_priv = '' 'default': {
'extras': {
'code-friendly': None,
},
'safe_mode': 'escape',
},
}
# NNID forbidden list. None for no passing. # Initialize version and Git URL
nnid_forbiddens = BASE_DIR + '/forbidden.json' CLOSEDVERSE_GIT_VERSION = 'unknown'
CLOSEDVERSE_GIT_URL = ''
CLOSEDVERSE_GIT_HAS_CHANGES = False
# Memo title and message on communities list # Only set git version/URL if .git folder exists
# I got rid of this setting because it was annoying i guess, edit the HTML to change it. -seedur if os.path.isdir(os.path.join(BASE_DIR, '.git')):
# Get version from Git. This is shown in the layout
git_process = os.popen('git rev-parse HEAD', 'r')
CLOSEDVERSE_GIT_VERSION = git_process.read()[:-1]
# Client key to use for iphub.email, because we're using that # if this command returns a non-zero exit code, then
# None for no IP checking (recommended since this is so slow) # there have been some changes so let's indicate that
if os.system('git diff-index --quiet HEAD --'):
CLOSEDVERSE_GIT_HAS_CHANGES = True
git_process = os.popen('git remote get-url origin', 'r')
CLOSEDVERSE_GIT_URL = git_process.read()[:-1]
try:
git_url_without_ext = CLOSEDVERSE_GIT_URL.split('.git')[0]
except IndexError:
pass
else:
CLOSEDVERSE_GIT_URL = git_url_without_ext + '/commit/' + CLOSEDVERSE_GIT_VERSION
# Google reCAPTCHA (v2) settings
# This feature won't work if these fields are not populated.
RECAPTCHA_PUBLIC_KEY = None
RECAPTCHA_PRIVATE_KEY = None
# Key for IPHub service for Closedverse, which detects proxies.
IPHUB_KEY = "" IPHUB_KEY = ""
# If this is set to True, then users will receive an error
# If IP can be checked, then use this to disallow any proxies # upon trying to sign up for the site behind a proxy.
disallow_proxy = False # Uses IPHub service and requires an API key defined above.
DISALLOW_PROXY = False
# Setting this to True forces every user to log in/ # Setting this to True forces every user to log in/
# sign up for the site to view any content. # sign up for the site to view any content.
@@ -191,15 +251,10 @@ LOGIN_EXEMPT_URLS = {
r'^help/login$', r'^help/login$',
} }
# MD # Action to perform on images belonging to posts/
MARKDOWN_DEUX_STYLES = { # comments when they are deleted
"default": { # 0: keep, 1: move to 'rm' folder, 2: delete
"extras": { IMAGE_DELETE_SETTING = 2
"code-friendly": None,
},
"safe_mode": "escape",
},
}
# allow sign ups. # allow sign ups.
allow_signups = True allow_signups = True
@@ -226,20 +281,32 @@ max_banner_size = 1
minimum_password_length = 7 minimum_password_length = 7
# The hard limit for uploading, Will cause an error if this is exceeded. This is set to 15MB by default (15728640) # The hard limit for uploading, Will cause an error if this is exceeded. This is set to 15MB by default (15728640)
DATA_UPLOAD_MAX_MEMORY_SIZE = 15728640 DATA_UPLOAD_MAX_MEMORY_SIZE = 52428800
# Set the default theme here! Set this to None to use the normal Closedverse theme. # Set the default theme here! Set this to None to use the normal Closedverse theme.
# TODO, make this work for users who aren't logged in. # TODO, make this work for users who aren't logged in.
# Example: site_wide_theme_hex = "#ff4159"
# The site wide global theme cannot be deactivated by your users.
site_wide_theme_hex = 'ff4159' site_wide_theme_hex = 'ff4159'
# The location to redirect to if a user's status is set to 2 (Redirect) (rickroll)
inactive_redirect = "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
# Option to delete image if it's local # Option to delete image if it's local
# 0 - keep, 1 - move to 'rm' folder, 2 - DELETE # 0 - keep, 1 - move to 'rm' folder, 2 - DELETE
IMAGE_DELETE_SETTING = 0 image_delete_opt = 0
# age (minimal 13 due to C.O.P.P.A) # age (minimal 13 due to C.O.P.P.A)
age_allowed = "13" age_allowed = "13"
# brand name currently being implemented throughout templates
brand_name = "Cedar"
# This option enables some production-specific pages
# and routines, such as HTTPS scheme redirection and
# proxy detection via IPHub.
CLOSEDVERSE_PROD = True
XFF_TRUSTED_PROXY_DEPTH = 1
XFF_STRICT = True
XFF_NO_SPOOFING = True
XFF_ALWAYS_PROXY = True
XFF_HEADER_REQUIRED = True
# uncomment this if you want miis to be retrieved on the server
#mii_endpoint = '/origin?a='
+25 -16
View File
@@ -1,30 +1,39 @@
"""closedverse URL Configuration """closedverse URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see: The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/1.10/topics/http/urls/ https://docs.djangoproject.com/en/2.2/topics/http/urls/
Examples: Examples:
Function views Function views
1. Add an import: from my_app import views 1. Add an import: from my_app import views
2. Add a URL to urlpatterns: url(r'^$', views.home, name='home') 2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views Class-based views
1. Add an import: from other_app.views import Home 1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home') 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf Including another URLconf
1. Import the include() function: from django.conf.urls import url, include 1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls')) 2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
""" """
from django.conf.urls import url, include
from django.contrib import admin from django.contrib import admin
from .settings import INSTALLED_APPS, MEDIA_ROOT, MEDIA_URL from django.urls import include, path, re_path
from django.conf.urls.static import static from django.views.static import serve
#from closedverse_main import urls
from closedverse.settings import STATIC_URL
# determine static root for admin app
#admin_root = admin.__file__.replace('__init__.py', 'static/admin')
# Set internal server error handler
handler500 = 'closedverse_main.views.server_err' handler500 = 'closedverse_main.views.server_err'
urlpatterns = [ urlpatterns = [
url(r'^admin/', admin.site.urls), path('admin/', admin.site.urls),
url(r'^', include('closedverse_main.urls')) # edit - the below snippet and admin_root variable are only for if you don't want to use whitenoise
# translation: i made all of this before realizing whitenoise could serve it lmao
# serve static for admin, in production? since admin is the only app now
# accomodations might be needed for other apps (e.g silk?)
# also the slice is meant to normalize e.g static_url being '/s/' to just 's/', etc. (is this necessary? prob not)
#re_path(r'^'+STATIC_URL[1:]+'admin/(?P<path>.*)$', serve, {'document_root': admin_root}),
# URLs for Closedverse
path('', include('closedverse_main.urls'))
] ]
if 'silk' in INSTALLED_APPS:
urlpatterns += [url(r'^silk/', include('silk.urls', namespace='silk'))]
urlpatterns += static(MEDIA_URL, document_root=MEDIA_ROOT)
+2 -2
View File
@@ -4,13 +4,13 @@ WSGI config for closedverse project.
It exposes the WSGI callable as a module-level variable named ``application``. It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see For more information on this file, see
https://docs.djangoproject.com/en/1.10/howto/deployment/wsgi/ https://docs.djangoproject.com/en/2.2/howto/deployment/wsgi/
""" """
import os import os
from django.core.wsgi import get_wsgi_application from django.core.wsgi import get_wsgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "closedverse.settings") os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'closedverse.settings')
application = get_wsgi_application() application = get_wsgi_application()
+12 -2
View File
@@ -33,6 +33,12 @@ def Hide_content(modeladmin, request, queryset):
@admin.action(description='Show selected items') @admin.action(description='Show selected items')
def Show_content(modeladmin, request, queryset): def Show_content(modeladmin, request, queryset):
queryset.update(is_rm = False) queryset.update(is_rm = False)
@admin.action(description='Disable comments')
def Disable_comments(modeladmin, request, queryset):
queryset.update(lock_comments = 2)
@admin.action(description='Enable comments')
def Enable_comments(modeladmin, request, queryset):
queryset.update(lock_comments = 0)
@admin.action(description='Feature selected communities') @admin.action(description='Feature selected communities')
def Feature_community(modeladmin, request, queryset): def Feature_community(modeladmin, request, queryset):
queryset.update(is_feature = True) queryset.update(is_feature = True)
@@ -48,12 +54,16 @@ def unforce_login(modeladmin, request, queryset):
@admin.action(description='Disable user') @admin.action(description='Disable user')
def Disable_user(modeladmin, request, queryset): def Disable_user(modeladmin, request, queryset):
queryset.update(active = False) queryset.update(active = False)
@admin.action(description='Enable user')
def Enable_user(modeladmin, request, queryset):
queryset.update(active = True)
class UserAdmin(admin.ModelAdmin): class UserAdmin(admin.ModelAdmin):
search_fields = ('id', 'unique_id', 'username', 'nickname', 'email', ) search_fields = ('id', 'unique_id', 'username', 'nickname', 'email', )
list_display = ('id', 'username', 'nickname', 'warned', 'level', 'staff', 'active', ) list_display = ('id', 'username', 'nickname', 'warned', 'level', 'staff', 'active', )
exclude = ('addr', 'signup_addr', 'password', ) exclude = ('addr', 'signup_addr', 'password', )
actions = [Disable_user] actions = [Disable_user, Enable_user]
#exclude = ('staff', ) #exclude = ('staff', )
# Not yet # Not yet
#form = UserForm #form = UserForm
@@ -73,7 +83,7 @@ class PostAdmin(admin.ModelAdmin):
raw_id_fields = ('creator', 'poll', ) raw_id_fields = ('creator', 'poll', )
search_fields = ('id', 'unique_id', 'body', 'creator__username', ) search_fields = ('id', 'unique_id', 'body', 'creator__username', )
list_display = ('id', 'creator', 'body', 'is_rm', ) list_display = ('id', 'creator', 'body', 'is_rm', )
actions = [Hide_content, Show_content] actions = [Hide_content, Show_content, Disable_comments, Enable_comments]
def get_queryset(self, request): def get_queryset(self, request):
return models.Post.real.get_queryset() return models.Post.real.get_queryset()
-2
View File
@@ -1,5 +1,3 @@
from __future__ import unicode_literals
from django.apps import AppConfig from django.apps import AppConfig
+12
View File
@@ -0,0 +1,12 @@
try:
from closedverse.settings import brand_name
except ImportError:
# use default app name by default as brand name
from closedverse_main import apps
brand_name = apps.ClosedverseMainConfig.verbose_name
# the name of the function is merely what's imported into settings.py
def brand_name_universal(request):
# this returns what's actually newly available to the template
# so the name of the key actually dictates what you put in the tmpl
return {"brand_name": brand_name}
+8
View File
@@ -31,12 +31,17 @@ class ClosedMiddleware(object):
return redirect('https://{0}{1}'.format(request.get_host(), request.get_full_path())) return redirect('https://{0}{1}'.format(request.get_host(), request.get_full_path()))
""" """
if request.user.is_authenticated: if request.user.is_authenticated:
"""
if not request.user.is_active(): if not request.user.is_active():
if request.user.warned_reason: if request.user.warned_reason:
ban_msg = request.user.warned_reason ban_msg = request.user.warned_reason
else: else:
ban_msg = 'You are banned.' ban_msg = 'You are banned.'
return HttpResponseForbidden(ban_msg) return HttpResponseForbidden(ban_msg)
"""
# can just forbid post requests for the time being (but leav our funny logout message :3)
if not request.user.is_active() and request.method != 'GET' and request.get_full_path() != '/logout/':
return HttpResponseForbidden()
# If there isn't a request.session # If there isn't a request.session
if not request.session.get('passwd'): if not request.session.get('passwd'):
request.session['passwd'] = request.user.password request.session['passwd'] = request.user.password
@@ -44,5 +49,8 @@ class ClosedMiddleware(object):
if request.session['passwd'] != request.user.password: if request.session['passwd'] != request.user.password:
logout(request) logout(request)
response = self.get_response(request) response = self.get_response(request)
if request.user.is_authenticated:
# for reverse proxy
response['X-Username'] = request.user.username
return response return response
+88 -39
View File
@@ -10,6 +10,7 @@ from django.core.exceptions import ValidationError
from datetime import timedelta, datetime, date, time from datetime import timedelta, datetime, date, time
from passlib.hash import bcrypt_sha256 from passlib.hash import bcrypt_sha256
from closedverse import settings from closedverse import settings
from closedverse_main.context_processors import brand_name
from . import util from . import util
from random import getrandbits from random import getrandbits
import uuid, json, base64 import uuid, json, base64
@@ -98,6 +99,8 @@ class UserManager(BaseUserManager):
return (user, 2) return (user, 2)
else: else:
if not passwd: if not passwd:
#if user.can_manage():
# return None
return (user, False) return (user, False)
return (user, True) return (user, True)
@@ -117,7 +120,6 @@ class ColorField(models.CharField):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
kwargs['max_length'] = 18 kwargs['max_length'] = 18
super(ColorField, self).__init__(*args, **kwargs) super(ColorField, self).__init__(*args, **kwargs)
#mii_domain = 'https://mii-secure.cdn.nintendo.net' #mii_domain = 'https://mii-secure.cdn.nintendo.net'
# as of writing, mii-secure is unstable, nintendo please do not f*ck me for this # as of writing, mii-secure is unstable, nintendo please do not f*ck me for this
mii_domain = 'https://s3.us-east-1.amazonaws.com/mii-images.account.nintendo.net/' mii_domain = 'https://s3.us-east-1.amazonaws.com/mii-images.account.nintendo.net/'
@@ -137,7 +139,7 @@ class User(models.Model):
# LEVEL: 0-1 is default, everything else is just levels # LEVEL: 0-1 is default, everything else is just levels
level = models.SmallIntegerField(default=0) level = models.SmallIntegerField(default=0)
# ROLE: This doesn't have anything # ROLE: This doesn't have anything
role = models.SmallIntegerField(default=0, choices=((0, 'normal'), (1, 'Bot'), (2, 'Administrator'), (3, 'Moderator'), (4, 'NO'), (5, 'Donator'), (6, 'Tester'), (7, 'Cools'), (8, 'Developer'), (9, 'SMF9-Django'), (10, 'Staff'), (11, 'GAY DOGWATER' ), ( 12, 'DUMB SNAIL' ), (13, 'Russian ADRIAN'), (14, 'Contest'), (15, 'Gamecon'), (16, 'Cedar'), )) role = models.SmallIntegerField(default=0, choices=((0, 'normal'), (1, 'bot'), (2, 'administrator'), (3, 'moderator'), (4, 'openverse'), (5, 'donator'), (6, 'cool'), (7, 'urapp'), (8, 'owner'), (9, 'badgedes'), (10, 'jack'), (11, 'verified'),))
addr = models.CharField(max_length=64, null=True, blank=True) addr = models.CharField(max_length=64, null=True, blank=True)
signup_addr = models.CharField(max_length=64, null=True, blank=True) signup_addr = models.CharField(max_length=64, null=True, blank=True)
user_agent = models.TextField(null=True, blank=True) user_agent = models.TextField(null=True, blank=True)
@@ -150,7 +152,6 @@ class User(models.Model):
color = ColorField(default='', null=True, blank=True) color = ColorField(default='', null=True, blank=True)
staff = models.BooleanField(default=False) staff = models.BooleanField(default=False)
#active = models.SmallIntegerField(default=1, choices=((0, 'Redirect'), (1, 'Good'), (2, 'Disabled')))
active = models.BooleanField(default=True) active = models.BooleanField(default=True)
can_invite = models.BooleanField(default=True) can_invite = models.BooleanField(default=True)
warned = models.BooleanField(default=False) warned = models.BooleanField(default=False)
@@ -238,40 +239,30 @@ class User(models.Model):
def get_class(self): def get_class(self):
first = { first = {
1: 'tester', 1: 'cool',
2: 'administrator', 2: 'administrator',
3: 'moderator', 3: 'moderator',
4: 'openverse', 4: 'openverse',
5: 'donator', 5: 'donator',
6: 'tester', 6: 'cool',
7: 'urapp', 7: 'urapp',
8: 'developer', 8: 'developer',
9: 'pipinstalldjango', 9: 'badgedes',
10: 'staff', 10: 'jack',
11: 'kanna', 11: 'verifiedd',
12: 'verified',
13: 'artcon',
14: 'contest',
15: 'gamecom',
16: 'mp',
}.get(self.role, '') }.get(self.role, '')
second = { second = {
1: "Bot", 1: "Bot",
2: "Administrator", 2: "Administrator",
3: "Moderator", 3: "Moderator",
4: "No", 4: "O-PHP-enverse Man",
5: "Donator", 5: "Donator",
6: "Tester", 6: "Cool Person",
7: "Cool Dude", 7: "cave story is okay",
8: "Wii U still best console.", 8: "owner guy",
9: "Rixy Installed Django!", 9: "Badge Designer",
10: "Staff", 10: "stupid man",
11: "GAY DOGWATER ETC", 11: "Verified",
12: "THE STUPIDEST ROLE IN THE WORLD",
13: "A D R I A N",
14: "Contest Winner",
15: "Game Contest Winner",
16: "Cedar Inc.",
}.get(self.role, '') }.get(self.role, '')
if first: if first:
first = 'official ' + first first = 'official ' + first
@@ -555,15 +546,14 @@ class User(models.Model):
def password_reset_email(self, request): def password_reset_email(self, request):
htmlmsg = render_to_string('closedverse_main/help/email.html', { htmlmsg = render_to_string('closedverse_main/help/email.html', {
'menulogo': request.build_absolute_uri(settings.STATIC_URL + 'img/menu-logo.png'), 'menulogo': request.build_absolute_uri(settings.STATIC_URL + 'img/menu-logo.png'),
'contact': 'something', 'contact': request.build_absolute_uri(reverse('main:help-contact')),
'link': request.build_absolute_uri(reverse('main:forgot-passwd')) + "?token=" + base64.urlsafe_b64encode(bytes(self.password, 'utf-8')).decode(), 'link': request.build_absolute_uri(reverse('main:forgot-passwd')) + "?token=" + base64.urlsafe_b64encode(bytes(self.password, 'utf-8')).decode(),
}) })
subj = 'Closedverse password reset for "{0}"'.format(self.username) subj = '{1} password reset for "{0}"'.format(self.username, brand_name)
return send_mail( return send_mail(
subject='Reset password', subject=subj,
html_message=htmlmsg, html_message=htmlmsg,
message=htmlmsg, from_email="{1} <{0}>".format(settings.DEFAULT_FROM_EMAIL, brand_name),
from_email="noreply@" + settings.YOUR_DOMAIN,
recipient_list=[self.email], recipient_list=[self.email],
fail_silently=False) fail_silently=False)
def find_related(self): def find_related(self):
@@ -711,7 +701,19 @@ class Community(models.Model):
#print(str(post) + ' to ' + str(self.creator) + ':' + str(post.user_is_blocked)) #print(str(post) + ' to ' + str(self.creator) + ':' + str(post.user_is_blocked))
post.recent_comment = post.recent_comment() post.recent_comment = post.recent_comment()
return posts return posts
def Community_block(self, request):
# This goes both ways.
if request.user.is_authenticated and not request.user.can_manage():
if UserBlock.find_block(self.creator, request.user):
return True
return False
def post_perm(self, request): def post_perm(self, request):
if not request.user.active:
return False
if self.Community_block(request):
return False
if request.user.level >= self.rank_needed_to_post: if request.user.level >= self.rank_needed_to_post:
return True return True
elif request.user.staff == True: elif request.user.staff == True:
@@ -766,7 +768,7 @@ class Community(models.Model):
URLValidator()(value=request.POST['url']) URLValidator()(value=request.POST['url'])
except ValidationError: except ValidationError:
return 5 return 5
if not request.user.has_freedom() and (request.POST.get('url') or request.FILES.get('screen')): if not request.user.has_freedom() and (request.POST.get('url') or request.FILES.get('screen') or request.FILES.get('video')):
return 6 return 6
if not request.user.is_active(): if not request.user.is_active():
return 6 return 6
@@ -774,14 +776,19 @@ class Community(models.Model):
return 1 return 1
upload = None upload = None
drawing = None drawing = None
video = None
body = request.POST.get('body') body = request.POST.get('body')
for c in body: for c in body:
if unicodedata.combining(c): if unicodedata.combining(c):
return 11 return 12
if request.FILES.get('screen'): if request.FILES.get('screen'):
upload = util.image_upload(request.FILES['screen'], True) upload = util.image_upload(request.FILES['screen'], True)
if upload == 1: if upload == 1:
return 2 return 2
if request.FILES.get('video'):
video = util.video_upload(request.FILES['video'])
if video == 1:
return 11
if request.POST.get('_post_type') == 'painting': if request.POST.get('_post_type') == 'painting':
if not request.POST.get('painting'): if not request.POST.get('painting'):
return 2 return 2
@@ -796,7 +803,7 @@ class Community(models.Model):
return 9 return 9
if body.isspace() and not drawing: if body.isspace() and not drawing:
return 10 return 10
new_post = self.post_set.create(body=body, creator=request.user, community=self, feeling=int(request.POST.get('feeling_id', 0)), spoils=bool(request.POST.get('is_spoiler')), screenshot=upload, drawing=drawing, url=request.POST.get('url')) new_post = self.post_set.create(body=body, creator=request.user, community=self, feeling=int(request.POST.get('feeling_id', 0)), spoils=bool(request.POST.get('is_spoiler')), screenshot=upload, drawing=drawing, url=request.POST.get('url'), video=video)
new_post.is_mine = True new_post.is_mine = True
return new_post return new_post
@@ -826,9 +833,11 @@ class Post(models.Model):
body = models.TextField(null=True) body = models.TextField(null=True)
drawing = models.CharField(max_length=200, null=True, blank=True) drawing = models.CharField(max_length=200, null=True, blank=True)
screenshot = models.CharField(max_length=1200, null=True, blank=True, default='') screenshot = models.CharField(max_length=1200, null=True, blank=True, default='')
video = models.CharField(max_length=256, null=True, blank=True, default='')
url = models.URLField(max_length=1200, null=True, blank=True, default='') url = models.URLField(max_length=1200, null=True, blank=True, default='')
spoils = models.BooleanField(default=False) spoils = models.BooleanField(default=False)
disable_yeah = models.BooleanField(default=False) disable_yeah = models.BooleanField(default=False)
lock_comments = models.SmallIntegerField(default=0, choices=((0, 'Not locked'), (1, 'Locked by user'), (2, 'Locked by mod')))
created = models.DateTimeField(auto_now_add=True) created = models.DateTimeField(auto_now_add=True)
edited = models.DateTimeField(auto_now=True) edited = models.DateTimeField(auto_now=True)
befores = models.TextField(null=True, blank=True) befores = models.TextField(null=True, blank=True)
@@ -892,10 +901,12 @@ class Post(models.Model):
else: else:
return False return False
def can_yeah(self, request): def can_yeah(self, request):
if not request.user.is_authenticated or not request.user.is_active(): if not request.user.is_authenticated:
return False
if not request.user.is_active():
return False
if self.community.Community_block(request):
return False return False
# why did cedar-django do this? god knows
#return True
if self.is_mine(request.user) or UserBlock.find_block(self.creator, request.user): if self.is_mine(request.user) or UserBlock.find_block(self.creator, request.user):
return False return False
return True return True
@@ -923,12 +934,44 @@ class Post(models.Model):
def get_yeahs(self, request): def get_yeahs(self, request):
return Yeah.objects.filter(type=0, post=self).order_by('-created')[0:30] return Yeah.objects.filter(type=0, post=self).order_by('-created')[0:30]
def can_comment(self, request): def can_comment(self, request):
# TODO: Make this so that if a post's comments exceeds 100, make the user able to close the comments section
if self.number_comments() > 500: if self.number_comments() > 500:
return False return False
if not request.user.active:
return False
# yeah this is fucking nuts. It's basically a ban from an entire community.
if self.community.Community_block(request):
return False
if self.lock_comments != 0:
return False
if UserBlock.find_block(self.creator, request.user): if UserBlock.find_block(self.creator, request.user):
return False return False
return True return True
def can_lock_comments(self, request):
if self.lock_comments != 0:
return False
# If you are a mod, you can bypass the timer
# The timer is a personal choice of mine, I don't want users to pussy out of a fight too early or whatever.
# Always annoys me when someone has a dumb ass take only for them to turn off the comments immediately.
if self.created < timezone.now() - timedelta(hours=24) or request.user.can_manage():
if self.creator == request.user:
return True
if not self.creator.has_authority(request.user) and request.user.can_manage():
return True
return False
def lock_the_comments_up(self, request):
if request and self.can_lock_comments(request):
if self.is_mine(request.user):
self.lock_comments = 1
else:
self.lock_comments = 2
AuditLog.objects.create(type=3, post=self, user=self.creator, by=request.user)
self.save()
return True
else:
return False
def get_comments(self, request=None, limit=0, offset=0): def get_comments(self, request=None, limit=0, offset=0):
if request.user.is_authenticated: if request.user.is_authenticated:
blocked_me = request.user.block_target.filter().values('source') blocked_me = request.user.block_target.filter().values('source')
@@ -967,7 +1010,7 @@ class Post(models.Model):
return 6 return 6
for c in request.POST['body']: for c in request.POST['body']:
if unicodedata.combining(c): if unicodedata.combining(c):
return 11 return 12
if not request.user.is_active(): if not request.user.is_active():
return 6 return 6
if len(request.POST['body']) > 2200 or (len(request.POST['body']) < 1 and not request.POST.get('_post_type') == 'painting'): if len(request.POST['body']) > 2200 or (len(request.POST['body']) < 1 and not request.POST.get('_post_type') == 'painting'):
@@ -1709,7 +1752,7 @@ class UserBlock(models.Model):
class AuditLog(models.Model): class AuditLog(models.Model):
id = models.AutoField(primary_key=True) id = models.AutoField(primary_key=True)
created = models.DateTimeField(auto_now_add=True) created = models.DateTimeField(auto_now_add=True)
type = models.SmallIntegerField(choices=((0, "Post delete"), (1, "Comment delete"), (2, "User edit"), (3, "Generate passwd reset"), (4, "User delete"), (5, "Image delete"), (6, "Purge 1"), (7, "Purge 2"), (8, "Purge 3"), (9, "Purge 4"), (10, "Purge 5"), (11, "Un-purge 1"), (12, 'Changed server settings'), )) type = models.SmallIntegerField(choices=((0, "Post delete"), (1, "Comment delete"), (2, "User edit"), (3, "Disable comments"), (4, "User delete"), (5, "Image delete"), (6, "Purge 1"), (7, "Purge 2"), (8, "Purge 3"), (9, "Purge 4"), (10, "Purge 5"), (11, "Un-purge 1"), (12, 'Changed server settings'), ))
post = models.ForeignKey(Post, related_name='audit_post', null=True, on_delete=models.CASCADE) post = models.ForeignKey(Post, related_name='audit_post', null=True, on_delete=models.CASCADE)
comment = models.ForeignKey(Comment, related_name='audit_comment', null=True, on_delete=models.CASCADE) comment = models.ForeignKey(Comment, related_name='audit_comment', null=True, on_delete=models.CASCADE)
user = models.ForeignKey(User, related_name='audit_user', null=True, on_delete=models.CASCADE) user = models.ForeignKey(User, related_name='audit_user', null=True, on_delete=models.CASCADE)
@@ -1762,6 +1805,9 @@ class Ads(models.Model):
adsavailable = False adsavailable = False
return adsavailable return adsavailable
class Meta:
verbose_name_plural = "ads"
def __str__(self): def __str__(self):
return "Ad with id " + str(self.id) + ", created at " + str(self.created) + ", with url " + str(self.url) + ", and imageurl " + str(self.imageurl) return "Ad with id " + str(self.id) + ", created at " + str(self.created) + ", with url " + str(self.url) + ", and imageurl " + str(self.imageurl)
@@ -1787,6 +1833,9 @@ class ProfileHistory(models.Model):
def __str__(self): def __str__(self):
return str(self.user) + ' changed profile details' return str(self.user) + ' changed profile details'
class Meta:
verbose_name_plural = "profile histories"
# blah blah blah # blah blah blah
# this method will be executed when... # this method will be executed when...
def rm_post_image(sender, instance, **kwargs): def rm_post_image(sender, instance, **kwargs):
@@ -28,7 +28,7 @@
<div id="js-main"> <div id="js-main">
<div class="activity-feed content-loading-window"> <div class="activity-feed content-loading-window">
<div> <div>
{% discordapp_spinner %} {% loading_spinner %}
<p class="tleft"><span>Loading activity feed...</span></p> <p class="tleft"><span>Loading activity feed...</span></p>
</div> </div>
</div> </div>
@@ -1,5 +1,5 @@
{% extends "closedverse_main/layout.html" %} {% extends "closedverse_main/layout.html" %}
{% load closedverse_tags %}{% load closedverse_community %}{% block main-body %} {% load closedverse_tags %}{% load closedverse_community %}{% load closedverse_user %}{% block main-body %}
<div class="community-main"> <div class="community-main">
<div id="community-eyecatch"></div> <div id="community-eyecatch"></div>
</div> </div>
@@ -7,8 +7,13 @@
<form action="{% url "main:community-search" %}" class="search"> <form action="{% url "main:community-search" %}" class="search">
<input maxlength="32" name="query" placeholder="Search all communities" type="text"><input title="Search" type="submit" value="q"> <input maxlength="32" name="query" placeholder="Search all communities" type="text"><input title="Search" type="submit" value="q">
</form> </form>
<!--<div class="close-announce-container">
<div class="close-announce-link">
<a class="title" id="close-text-ann" href="/posts/1186"><b>Closedverse is still in indefinite maintenance.</b></a>
</div>
</div>-->
{% if user.is_warned %} {% if user.is_warned and user.is_active %}
<div class="notice" style="background-color: #ffc783;border: 1px solid #ffb358;"> <div class="notice" style="background-color: #ffc783;border: 1px solid #ffb358;">
<p><b>WARNING</b>: You have been issued a warning by an administrator. <p><b>WARNING</b>: You have been issued a warning by an administrator.
<div> <div>
@@ -18,23 +23,35 @@
</div> </div>
</div> </div>
{% endif %} {% endif %}
{% if not user.is_active and user.is_authenticated %}
<div class="notice" style="background-color: #ff9797;border: 1px solid #ff5252;">
<p><b>Oops</b>: You've been smacked by an admin. Better luck next time.
<div>
{% if user.get_warned_reason %}
<p>Reason: "{{ user.get_warned_reason }}"</p>
{% endif %}
</div>
</div>
{% endif %}
{% if announcements and request.user.is_authenticated %} {% if announcements and request.user.is_authenticated %}
<div class="Announcements"> <div class="tleft">
{% for announcements in announcements %} <div class="post-list-outline">
<div class='Announcement-content'> <h2 class="label">Latest Announcements</h2>
{% user_icon_container announcements.creator announcements.feeling %} <div class="post-body">
<a class='user-name' href={% url "main:user-view" announcements.creator.username %} {% if announcements.creator.color %}style=color:{{ announcements.creator.color }}{% endif %}>{{ announcements.creator }}</a><a class='timestamp"'> - {{ announcements.created }}</a> <div class="list multi-timeline-post-list">
<p>{{ announcements.body|linebreaksbr|urlize }}</p> {% for announcement in announcements %}
{% if announcements.screenshot %}<image class='Announcement-image' src={{ announcements.screenshot }}></image>{% endif %} {% profile_post announcement True %}
</div>
{% endfor %} {% endfor %}
</div>
</div>
</div>
</div> </div>
{% endif %} {% endif %}
{% if WelcomeMSG and not request.user.is_authenticated %} {% if WelcomeMSG and not request.user.is_authenticated %}
<div class="post-list-outline index-memo"> <div class="post-list-outline index-memo">
<h2 class="label">Welcome to Cedar!</h2> <h2 class="label">Welcome to {{ brand_name }}!</h2>
{% for WelcomeMSG in WelcomeMSG %} {% for WelcomeMSG in WelcomeMSG %}
<h2>{{ WelcomeMSG.Title }}</h2> <h2>{{ WelcomeMSG.Title }}</h2>
<p>{{ WelcomeMSG.message|linebreaksbr|urlize }}</p> <p>{{ WelcomeMSG.message|linebreaksbr|urlize }}</p>
@@ -51,7 +68,7 @@
</div> </div>
{% endif %} {% endif %}
</div> </div>
<div class="community-main"> <div class="community-main" id="communities">
{% if favorites %} {% if favorites %}
<h3 class="community-title symbol community-favorite-title">Favorite communities</h3> <h3 class="community-title symbol community-favorite-title">Favorite communities</h3>
<div class="card" id="community-favorite"> <div class="card" id="community-favorite">
@@ -74,12 +91,12 @@
{% if feature %} {% if feature %}
{% community_page_element feature "Featured Communities" True %} {% community_page_element feature "Featured Communities" True %}
{% endif %} {% endif %}
{% if general %}{% community_page_element general "General Communities" %}{% endif %} {% community_page_element general "General Communities" False "general" %}
{% if game %}{% community_page_element game "Game Communities" %}{% endif %} {% community_page_element game "Game Communities" False "game" %}
{% if special %}{% community_page_element special "Special Communities" %}{% endif %} {% community_page_element special "Special Communities" False "special" %}
{% if user_communities %}{% community_page_element user_communities "Popular User-Created Communities" %}{% endif %} {% community_page_element user_communities "Popular User-Created Communities" False "usr" %}
{% if my_communities %}{% community_page_element my_communities "My Communities" %}{% endif %} {% if user_communities %}<a href="{% url "main:community-viewall" "usr" %}" class="big-button">Show more</a>{% endif %}
<a href="{% url "main:community-viewall" "gen" %}" class="big-button">Show more</a> {% community_page_element my_communities "My Communities" %}
</div> </div>
<div id="community-guide-footer"> <div id="community-guide-footer">
<div id="guide-menu"> <div id="guide-menu">
@@ -1,18 +1,8 @@
{% extends "closedverse_main/layout.html" %}{% block main-body %}{% load closedverse_community %} {% extends "closedverse_main/layout.html" %}{% block main-body %}{% load closedverse_community %}
{% community_sidebar community request %} {% community_sidebar community request %}
<div class="main-column"> <div class="main-column">
{% if user.is_warned %}
<div class="notice" style="background-color: #ffc783;border: 1px solid #ffb358;">
<p><b>WARNING</b>: You have been issued a warning by an administrator.
<div>
{% if user.get_warned_reason %}
<p>Reason: "{{ user.get_warned_reason }}"</p>
{% endif %}
</div>
</div>
{% endif %}
<div class="post-list-outline"> <div class="post-list-outline">
<h2 class="label">{{ community.name }}:</h2> <h2 class="label">{{ community.name }}</h2>
{% if request.user.is_authenticated and community.post_perm %} {% if request.user.is_authenticated and community.post_perm %}
{% post_form request.user community %} {% post_form request.user community %}
{% endif %} {% endif %}
@@ -1,5 +1,4 @@
{% load closedverse_community %} {% load closedverse_community %}
{% if user.is_active %}
<form id="reply-form" class="for-identified-user" method="post" action="{% url "main:post-comments" post.id %}"> <form id="reply-form" class="for-identified-user" method="post" action="{% url "main:post-comments" post.id %}">
{% csrf_token %} {% csrf_token %}
{% if not user.limit_remaining is False %} {% if not user.limit_remaining is False %}
@@ -31,6 +30,8 @@
</div> </div>
{% if user.has_freedom %} {% if user.has_freedom %}
{% file_button %} {% file_button %}
<!-- hack to temporarily hide video input, for now... -->
<style>div.file-button-container{display:none;}</style>
{% endif %} {% endif %}
<div class="post-form-footer-options"> <div class="post-form-footer-options">
@@ -47,8 +48,3 @@
<input type="submit" class="black-button reply-button disabled" value="Send" data-community-id="{{ post.community.unique_id }}" data-url-id="{{ post.id }}" data-post-content-type="text" data-post-with-screenshot="nodata" disabled=""> <input type="submit" class="black-button reply-button disabled" value="Send" data-community-id="{{ post.community.unique_id }}" data-url-id="{{ post.id }}" data-post-content-type="text" data-post-with-screenshot="nodata" disabled="">
</div> </div>
</form> </form>
{% endif %}
{% if not user.is_active %}
<p class="center">Your account has been disabled.</p>
{% endif %}
@@ -1,5 +1,6 @@
{% load closedverse_tags %}{% if title %}<h3 class="community-title">{{ title }}</h3> {% load closedverse_tags %}{% if communities %}
{% endif %}{% if communities %} {% if title %}<h3 class="community-title">{{ title }}</h3>
{% endif %}
<ul class="list community-list{% if title %} community-card-list {% if feature %}test-community-list-item{% else %}device-new-community-list{% endif %}{% endif %}"> <ul class="list community-list{% if title %} community-card-list {% if feature %}test-community-list-item{% else %}device-new-community-list{% endif %}{% endif %}">
{% for community in communities %} {% for community in communities %}
<li class="trigger" data-href="{% url "main:community-view" community.id %}"{% if not title %} class="test-community-list-item"{% endif %}> <li class="trigger" data-href="{% url "main:community-view" community.id %}"{% if not title %} class="test-community-list-item"{% endif %}>
@@ -21,12 +22,15 @@
</li> </li>
{% endfor %} {% endfor %}
</ul> </ul>
{% if url_name and communities.count >= 12 %}
<a href="{% url "main:community-viewall" url_name %}" class="big-button">Show more</a>
{% endif %}
{% else %} {% else %}
{% if title %}<div class="post-list-outline">{% endif %} <!--{% if title %}<div class="post-list-outline">{% endif %}-->
{% if title %} {% if title %}
{% nocontent "No communities of this type have been created yet." %} <!--{% nocontent "No communities of this type have been created yet." %}-->
{% else %} {% else %}
{% nocontent "You haven't favorited any communities yet. Use the favorite button in a community to add it here." %} {% nocontent "You haven't favorited any communities yet. Use the favorite button in a community to add it here." %}
{% endif %} {% endif %}
{% if title %}</div>{% endif %} <!--{% if title %}</div>{% endif %}-->
{% endif %} {% endif %}
@@ -44,7 +44,8 @@
{% endif %} {% endif %}
{% endif %} {% endif %}
{% if post.screenshot %}<a class="screenshot-container still-image" href="{% if post.is_reply %}{% url "main:comment-view" post.id %}{% else %}{% url "main:post-view" post.id %}{% endif %}"><img src="{{ post.screenshot }}"></a>{% endif %} {% if post.screenshot %}<a class="screenshot-container still-image" href="{% if post.is_reply %}{% url "main:comment-view" post.id %}{% else %}{% url "main:post-view" post.id %}{% endif %}"><img src="{{ post.screenshot }}"></a>{% endif %}
{% if post.spoils and post.creator.is_active %} {% if post.video %}<div class="screenshot-container still-image"><video class="vidya" controls src="{{ post.video }}" style="max-width:100%;max-height: 450px;"></video></div>{% endif %}
{% if post.spoils and not post.is_mine and post.creator.is_active %}
<div class="hidden-content"><p>This post contains spoilers.</p> <div class="hidden-content"><p>This post contains spoilers.</p>
<button type="button" class="hidden-content-button">View Post</button> <button type="button" class="hidden-content-button">View Post</button>
</div> </div>
@@ -1,4 +1,9 @@
<div id="sidebar"> <div id="sidebar">
{% if Community_block %}
<div class="notice" style="background-color: #ff9797;border: 1px solid #ff5252;">
<p><b>Oops</b>: You're either blocked by, or blocking {{ community.creator }}, who owns this community. You cannot Yeah, Reply, or Post here.
</div>
{% endif %}
<section class="sidebar-container" id="sidebar-community"> <section class="sidebar-container" id="sidebar-community">
{% if community.banner %} {% if community.banner %}
<span id="sidebar-cover"> <span id="sidebar-cover">
@@ -22,8 +27,6 @@
<span class="news-community-badge">Announcement Community</span> <span class="news-community-badge">Announcement Community</span>
{% elif community.tags == 'changelog' %} {% elif community.tags == 'changelog' %}
<span class="news-community-badge">Changelog Community</span> <span class="news-community-badge">Changelog Community</span>
{% elif community.tags == 'general' %}
<span class="news-community-badge">General</span>
{% endif %} {% endif %}
<h1 class="community-name"> <h1 class="community-name">
<a href="{% url "main:community-view" community.id %}">{{ community.name }} <a href="{% url "main:community-view" community.id %}">{{ community.name }}
@@ -1 +0,0 @@
<p>I'm loading it !</p>
@@ -7,10 +7,16 @@
<label class="file-button-container"> <label class="file-button-container">
<span class="input-label">Image <span id="image-dimensions">PNG and JPEG are allowed.</span></span> <span class="input-label">Image <span id="image-dimensions">PNG and JPEG are allowed.</span></span>
<span class="button file-upload-button">Upload</span> <span class="button file-upload-button">Upload</span>
<input accept="image/gif, image/png, image/jpeg, image/jpg, image/svg+xml, image/bmp" type="file" style="display: none;" id="upload-file"> <input accept="image/gif, image/png, image/jpeg, image/jpg, image/svg+xml, image/bmp" type="file" style="display: none;" id="upload-file" name="screen">
<input type="hidden" id="upload-input" name="screen">
<div id="upload-preview-container" class="screenshot-container still-image" style="display: none;"> <div id="upload-preview-container" class="screenshot-container still-image" style="display: none;">
<img id="upload-preview"> <img id="upload-preview">
<!-- not functional currently
<video id="video-upload-preview"></video>
-->
</div> </div>
</label> </label>
<div class="file-button-container">
<span class="input-label">Video <span>MP4s and WEBMs are allowed. (50MB size limit)</span></span>
<input type="file" class="file-button" name="video" accept="video/mp4, video/webm">
</div>
@@ -0,0 +1 @@
<span class="open-spin"></span>
@@ -1,5 +1,4 @@
{% load closedverse_community %} {% load closedverse_community %}
{% if user.is_active %}
<form id="post-form" method="post" action="{% url "main:messages-view" friend.username %}" class="folded"> <form id="post-form" method="post" action="{% url "main:messages-view" friend.username %}" class="folded">
{% csrf_token %} {% csrf_token %}
{% feeling_selector %} {% feeling_selector %}
@@ -29,14 +28,7 @@
</div> </div>
<div class="form-buttons"> <div class="form-buttons">
<input type="submit" class="black-button post-button disabled" value="Send" data-post-content-type="text" disabled=""> <input type="submit" class="black-button post-button disabled" value="Send" data-post-content-type="text" disabled="">
</div> </div>
</form> </form>
{% endif %}
{% if not user.is_active %}
<p class="center">Your account has been disabled.</p>
{% endif %}
@@ -1,5 +1,4 @@
{% load closedverse_community %} {% load closedverse_community %}
{% if user.is_active %}
<form id="post-form" method="post" action="{% url "main:post-create" community.id %}" class="folded for-identified-user" data-post-subtype="default" name="test-post-default-form"> <form id="post-form" method="post" action="{% url "main:post-create" community.id %}" class="folded for-identified-user" data-post-subtype="default" name="test-post-default-form">
{% csrf_token %} {% csrf_token %}
<input type="hidden" name="community" value="{{ community.unique_id }}"> <input type="hidden" name="community" value="{{ community.unique_id }}">
@@ -63,8 +62,3 @@
<input type="submit" class="black-button post-button disabled" value="Send" data-community-id="{{ community.unique_id }}" data-post-content-type="text" data-post-with-screenshot="nodata" disabled=""> <input type="submit" class="black-button post-button disabled" value="Send" data-community-id="{{ community.unique_id }}" data-post-content-type="text" data-post-with-screenshot="nodata" disabled="">
</div> </div>
</form> </form>
{% endif %}
{% if not user.is_active %}
<p class="center">Your account has been disabled.</p>
{% endif %}
@@ -1,8 +1,8 @@
{% load closedverse_tags %}<div id="{{ post.unique_id }}" {% if post.spoils and not post.is_mine or not post.creator.is_active %}data-href-hidden{% else %}data-href{% endif %}="{% url "main:post-view" post.id %}" class="post trigger{% if post.screenshot %} with-image{% endif %}{% if post.spoils and not post.is_mine or not post.creator.is_active %} hidden test-hidden{% endif %}" tabindex="0"> {% load closedverse_tags %}<div {% if post.spoils and not post.is_mine or not post.creator.is_active %}data-href-hidden{% else %}data-href{% endif %}="{% url "main:post-view" post.id %}" class="post trigger{% if post.screenshot and not for_announcements %} with-image{% endif %}{% if post.spoils and not post.is_mine or not post.creator.is_active %} hidden test-hidden{% endif %}" tabindex="0">
<p class="community-container"><a {% if post.community.clickable %}href="{% url "main:community-view" post.community_id %}"{% endif %}><img src="{{ post.community.icon }}" class="community-icon">{{ post.community.name }}</a></p> <p class="community-container"><a {% if post.community.clickable %}href="{% url "main:community-view" post.community_id %}"{% endif %}><img src="{{ post.community.icon }}" class="community-icon">{{ post.community.name }}</a></p>
<div class="body"> <div {% if not for_announcements %}class="body"{% endif %}>
<div class="post-content"> <div class="post-content">
{% user_icon_container post.creator post.feeling %} {% user_icon_container post.creator post.feeling %}
@@ -26,7 +26,10 @@
<div class="screenshot-container video"><video src="{{ post.url }}" width="50" height="48"></video></div> <div class="screenshot-container video"><video src="{{ post.url }}" width="50" height="48"></video></div>
{% endif %} {% endif %}
{% if post.screenshot %} {% if post.screenshot %}
<a href="{% url "main:post-view" post.id %}" class="screenshot-container still-image"><img src="{{ post.screenshot }}"></a> <a href="{% url "main:post-view" post.id %}" class="{% if not for_announcements %}screenshot-container {% endif %}still-image"><img src="{{ post.screenshot }}"></a>
{% endif %}
{% if post.video %}
<div class="screenshot-container video"><video src="{{ post.video }}" width="50" height="48"></video></div>
{% endif %} {% endif %}
{% if post.drawing %} {% if post.drawing %}
<p class="post-content-memo"><img src="{{ post.drawing }}" class="post-memo"></p> <p class="post-content-memo"><img src="{{ post.drawing }}" class="post-memo"></p>
@@ -50,6 +53,7 @@
<button type="button" class="hidden-content-button">View Anyway</button> <button type="button" class="hidden-content-button">View Anyway</button>
</p></div> </p></div>
{% endif %} {% endif %}
{% if not for_announcements %}
<div class="post-meta"> <div class="post-meta">
<button type="button"{% if not post.can_yeah %} disabled{% endif %} class="symbol submit yeah-button <button type="button"{% if not post.can_yeah %} disabled{% endif %} class="symbol submit yeah-button
{% if post.has_yeah %}empathy-added{% endif %} {% if post.has_yeah %}empathy-added{% endif %}
@@ -60,6 +64,7 @@
<div class="empathy symbol"><span class="symbol-label">Yeahs</span><span class="empathy-count">{{ post.number_yeahs }}</span></div> <div class="empathy symbol"><span class="symbol-label">Yeahs</span><span class="empathy-count">{{ post.number_yeahs }}</span></div>
<div class="reply symbol"><span class="symbol-label">Comments</span><span class="reply-count">{{ post.number_comments }}</span></div> <div class="reply symbol"><span class="symbol-label">Comments</span><span class="reply-count">{{ post.number_comments }}</span></div>
</div> </div>
{% endif %}
</div> </div>
</div> </div>
@@ -21,11 +21,16 @@
<li>My notifications: <span> {{ notifications }} <li>My notifications: <span> {{ notifications }}
</ul> </ul>
<h3>Restrictions:</h3> <h3>Restrictions:</h3>
{% if request.user.active %}
<ul> <ul>
<li>Sending images and creating new accounts: <span> {% if user.has_freedom %}Good standing{% else %}Restricted{% endif %} <li>Sending images and creating new accounts: <span> {% if user.has_freedom %}Good standing{% else %}Restricted{% endif %}
<li>Post limit: <span> {% if request.user.profile.limit_post == 0 %}Good standing{% else %}{{ user.profile.limit_post }}{% endif %} <li>Post limit: <span> {% if request.user.profile.limit_post == 0 %}Good standing{% else %}{{ user.profile.limit_post }}{% endif %}
<li>Editing your profile: <span> {% if not user.profile.cannot_edit %}Good standing{% else %}Restricted{% endif %} <li>Editing your profile: <span> {% if not user.profile.cannot_edit %}Good standing{% else %}Restricted{% endif %}
<li>Creating invites: <span> {% if user.can_invite %}Good standing{% else %}Restricted{% endif %}
</ul> </ul>
{% else %}
<p class='center'>You've been fucking banned lmao</p>
{% endif %}
<h3>Collected data:</h3> <h3>Collected data:</h3>
<div class="user-data"> <div class="user-data">
<p class="label">Account login history:</p> <p class="label">Account login history:</p>
@@ -4,14 +4,14 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
{% endif %} {% endif %}
<title>{% if title %}{{ title }} - Cedar{% else %}Cedar{% endif %}</title> <title>{% if title %}{{ title }} - {{ brand_name }} {% else %}{{ brand_name }}{% endif %}</title>
{% if not request.META.HTTP_X_PJAX %} {% if not request.META.HTTP_X_PJAX %}
<meta http-equiv="content-style-type" content="text/css"> <meta http-equiv="content-style-type" content="text/css">
<meta http-equiv="content-script-type" content="text/javascript"> <meta http-equiv="content-script-type" content="text/javascript">
<meta name="format-detection" content="telephone=no"> <meta name="format-detection" content="telephone=no">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<meta name="apple-mobile-web-app-title" content="Cedar"> <meta name="apple-mobile-web-app-title" content="{{ brand_name }}">
<meta name="description" content="It's Closedverse but Cedar!"> <meta name="description" content="{{ brand_name }} is a social network: designed by PF2M, programmed by Arian Kordi. With Miiverse DNA, style and familiar assets such as Miiverse's interface and Miis, you're sure to have fun here!">
<meta property="og:locale" content="en_US"> <meta property="og:locale" content="en_US">
{% if ogdata %} {% if ogdata %}
<meta property="og:title" content="{{ ogdata.title }}"> <meta property="og:title" content="{{ ogdata.title }}">
@@ -19,7 +19,7 @@
<meta property="og:url" content="{{ request.build_absolute_uri }}"> <meta property="og:url" content="{{ request.build_absolute_uri }}">
<meta property="og:image" content="{{ ogdata.image }}"> <meta property="og:image" content="{{ ogdata.image }}">
<meta property="og:description" content="{{ ogdata.description|truncatechars:150 }}"> <meta property="og:description" content="{{ ogdata.description|truncatechars:150 }}">
<meta property="og:site_name" content="Cedar"> <meta property="og:site_name" content="{{ brand_name }}">
<meta property="article:published_time" content="{{ ogdata.date }}"> <meta property="article:published_time" content="{{ ogdata.date }}">
{% endif %} {% endif %}
<link rel="shortcut icon" type="image/png" href="{% static "img/favicon.png" %}"> <link rel="shortcut icon" type="image/png" href="{% static "img/favicon.png" %}">
@@ -62,6 +62,7 @@
document.documentElement.style.setProperty("--theme-slightly-dark", slightlyDarkColor); document.documentElement.style.setProperty("--theme-slightly-dark", slightlyDarkColor);
document.documentElement.style.setProperty("--theme-darker", darkerColor); document.documentElement.style.setProperty("--theme-darker", darkerColor);
document.documentElement.style.setProperty("--theme-light", lightColor); document.documentElement.style.setProperty("--theme-light", lightColor);
{% if not request.user.bg_url %}document.documentElement.style.setProperty("--background", "url('img/indigo-pattern.png')");{% endif %}
} }
// hex -> rgb // hex -> rgb
@@ -80,18 +81,19 @@
} }
function toDefault() { function toDefault() {
document.documentElement.style.setProperty("--theme", "initial"); document.documentElement.style.setProperty("--theme", "");
document.documentElement.style.setProperty("--theme-dark", "initial"); document.documentElement.style.setProperty("--theme-dark", "initial");
document.documentElement.style.setProperty("--theme-slightly-dark", "initial"); document.documentElement.style.setProperty("--theme-slightly-dark", "initial");
document.documentElement.style.setProperty("--theme-darker", "initial"); document.documentElement.style.setProperty("--theme-darker", "initial");
document.documentElement.style.setProperty("--theme-light", "initial"); document.documentElement.style.setProperty("--theme-light", "initial");
document.documentElement.style.setProperty("--background", "");
} }
changeThemeColor(); changeThemeColor();
</script>{% endif %} </script>{% endif %}
<style> <style>
:root { :root {
{% if request.user.bg_url %}--background: url({{ request.user.bg_url }});{% elif not theme %}--background: url({% static 'img/Background.png' %}){% endif %} {% if request.user.bg_url %}--background: url({{ request.user.bg_url }});{% endif %}
} }
</style> </style>
</head> </head>
@@ -102,12 +104,12 @@
<div id="wrapper"{% if not request.user.is_authenticated %} class="guest"{% endif %}> <div id="wrapper"{% if not request.user.is_authenticated %} class="guest"{% endif %}>
<div id="sub-body"> <div id="sub-body">
<menu id="global-menu"> <menu id="global-menu">
<li id="global-menu-logo"><h1><a href="/"><img src="{% static "img/menu-logo.svg" %}" alt="Cedar"></a></h1></li> <li id="global-menu-logo"><h1><a href="/"><img src="{% static "img/menu-logo.svg" %}" alt="{{ brand_name }}"></a></h1></li>
{% if request.user.unique_id %} {% if request.user.unique_id %}
{% invite_only request as inv %} {% invite_only request as inv %}
<li id="global-menu-list"> <li id="global-menu-list">
<ul> <ul>
<li id="global-menu-mymenu"><a href="{% url "main:user-view" request.user.username %}"><span class="icon-container {% user_class request.user %}"><img src="{% avatar request.user %}" alt="My Profile"></span><span>My Profile</span></a></li> <li id="global-menu-mymenu"><a href="{% url "main:user-view" request.user.username %}"><span class="icon-container {% user_class request.user %}"><img src="{% avatar request.user %}" alt="User Page"></span><span>User Page</span></a></li>
<li id="global-menu-feed"><a href="{% url "main:activity" %}" class="symbol"><span>Activity Feed</span></a></li> <li id="global-menu-feed"><a href="{% url "main:activity" %}" class="symbol"><span>Activity Feed</span></a></li>
<li id="global-menu-community"><a href="/" class="symbol"><span>Communities</span></a></li> <li id="global-menu-community"><a href="/" class="symbol"><span>Communities</span></a></li>
<li id="global-menu-message"><a href="{% url "main:messages" %}" class="symbol"><span>Messages</span></a></li> <li id="global-menu-message"><a href="{% url "main:messages" %}" class="symbol"><span>Messages</span></a></li>
@@ -117,9 +119,10 @@
<li><a href="{% url "main:profile-settings" %}" class="symbol my-menu-profile-setting"><span>Profile settings</span></a></li> <li><a href="{% url "main:profile-settings" %}" class="symbol my-menu-profile-setting"><span>Profile settings</span></a></li>
<li><a href="#" class="symbol my-menu-account-setting"><span>Account preferences</span></a></li> <li><a href="#" class="symbol my-menu-account-setting"><span>Account preferences</span></a></li>
{% if inv %}<li><a href="{% url "main:invites" %}" class="symbol my-menu-guide"><span>Invites</span></a></li>{% endif %} {% if inv %}<li><a href="{% url "main:invites" %}" class="symbol my-menu-guide"><span>Invites</span></a></li>{% endif %}
<li><a href="{% url "main:special-community-tag" "announcements" %}" class="symbol my-menu-openman"><span>Cedar Announcements</span></a></li> <li><a href="{% url "main:special-community-tag" "announcements" %}" class="symbol my-menu-openman"><span>{{ brand_name }} Announcements</span></a></li>
<li><a href="{% url "main:special-community-tag" "changelog" %}" class="symbol my-menu-openman"><span>{{ brand_name }} Changelog</span></a></li>
<li><a href="{% url "main:help-faq" %}" class="symbol my-menu-guide"><span>Frequently Asked Questions (FAQ)</span></a></li> <li><a href="{% url "main:help-faq" %}" class="symbol my-menu-guide"><span>Frequently Asked Questions (FAQ)</span></a></li>
<li><a href="{% url "main:help-rules" %}" class="symbol my-menu-guide"><span>Cedar Rules</span></a></li> <li><a href="{% url "main:help-rules" %}" class="symbol my-menu-guide"><span>{{ brand_name }} Rules</span></a></li>
<li><a href="#" class="symbol my-menu-white-power"><span>Feedback/bug report</span></a></li> <li><a href="#" class="symbol my-menu-white-power"><span>Feedback/bug report</span></a></li>
<li><a href="{% url "main:server-stat" %}" class="symbol my-menu-openman"><span>Server Statistics</span></a></li> <li><a href="{% url "main:server-stat" %}" class="symbol my-menu-openman"><span>Server Statistics</span></a></li>
<li> <li>
@@ -5,7 +5,7 @@
<form method="post"> <form method="post">
<img src="{% static "img/menu-logo.svg" %}"> <img src="{% static "img/menu-logo.svg" %}">
<h1 class="lh">Sign In</h1> <h1 class="lh">Sign In</h1>
<h2 class="lh">Please sign in to access Cedar.</h2> <h2 class="lh">Please sign in to access {{ brand_name }}.</h2>
<div class="login-box"> <div class="login-box">
<h3 class="label"><input type="text" class="auth-input" name="username" maxlength="32" placeholder="Username"></h3> <h3 class="label"><input type="text" class="auth-input" name="username" maxlength="32" placeholder="Username"></h3>
<h3 class="label"><input type="password" class="auth-input" name="password" maxlength="32" placeholder="Password"></h3> <h3 class="label"><input type="password" class="auth-input" name="password" maxlength="32" placeholder="Password"></h3>
@@ -10,7 +10,6 @@
</h1> </h1>
</header> </header>
{% if post.is_mine or post.can_rm %} {% if post.is_mine or post.can_rm %}
{% if user.is_active %}
<div class="edit-buttons-content"> <div class="edit-buttons-content">
<button type="button" class="symbol button edit-button rm-post-button" data-action="{% url "main:post-rm" post.id %}"><span class="symbol-label">Delete</span></button> <button type="button" class="symbol button edit-button rm-post-button" data-action="{% url "main:post-rm" post.id %}"><span class="symbol-label">Delete</span></button>
{% if post.is_mine and not post.has_edit %} {% if post.is_mine and not post.has_edit %}
@@ -19,8 +18,10 @@
{% if post.is_mine and post.screenshot %} {% if post.is_mine and post.screenshot %}
<button type="button" class="symbol button edit-button profile-post-button{% if post.is_favorite %} done {% endif %}" data-action="{% if post.is_favorite %}{% url "main:post-unset-profile" post.id %}{% else %}{% url "main:post-set-profile" post.id %}{% endif %}"><span class="symbol-label">Set as profile post</span></button> <button type="button" class="symbol button edit-button profile-post-button{% if post.is_favorite %} done {% endif %}" data-action="{% if post.is_favorite %}{% url "main:post-unset-profile" post.id %}{% else %}{% url "main:post-set-profile" post.id %}{% endif %}"><span class="symbol-label">Set as profile post</span></button>
{% endif %} {% endif %}
</div> {% if post.can_lock_comments %}
<button type="button" class="symbol button edit-button lock-comments-button" data-action="{% url "main:lock-the-comments" post.id %}"><span class="symbol-label">Lock comments</span></button>
{% endif %} {% endif %}
</div>
{% endif %} {% endif %}
<div class="user-content"> <div class="user-content">
@@ -83,10 +84,12 @@
{% elif post.screenshot %}<div class="screenshot-container still-image"><img src="{{ post.screenshot }}"></div>{% endif %} {% elif post.screenshot %}<div class="screenshot-container still-image"><img src="{{ post.screenshot }}"></div>{% endif %}
{% if post.yt_vid %} {% if post.yt_vid %}
<div class="screenshot-container video"><iframe class="youtube-player" type="text/html" width="490" height="276" src="https://www.youtube.com/embed/{{ post.yt_vid }}?rel=0&modestbranding=1&iv_load_policy=3" frameborder="0"></iframe></div> <div class="screenshot-container video"><iframe class="youtube-player" type="text/html" style="max-width:100%;max-height: 450px;" src="https://www.youtube.com/embed/{{ post.yt_vid }}?rel=0&modestbranding=1&iv_load_policy=3" frameborder="0"></iframe></div>
{% elif post.video %}
<div class="screenshot-container video"><video class="vidya" controls src="{{ post.video }}" style="max-width:100%;max-height: 450px;"></video></div>
{% elif post.discord_vid %} {% elif post.discord_vid %}
<div class="DiscordCDN-container video"> <div class="DiscordCDN-container video">
<video class="discord-player" src="{{ post.url }}" style='max-width:100%;' controls></video> <video class="discord-player" src="{{ post.url }}" style="max-width:100%;max-height: 450px;" controls></video>
</div> </div>
<a>Discord embedded video</a> <a>Discord embedded video</a>
{% elif post.url %} {% elif post.url %}
@@ -126,13 +129,19 @@
<h2 class="reply-label">Add a Comment</h2> <h2 class="reply-label">Add a Comment</h2>
{% if not request.user.is_authenticated %} {% if not request.user.is_authenticated %}
<div class="guest-message"> <div class="guest-message">
<p>You must sign in to post a comment.<br><br>Sign in using a Cedar account to make posts and comments, as well as give Yeahs and follow users.</p> <p>You must sign in to post a comment.<br><br>Sign in using a {{ brand_name }} account to make posts and comments, as well as give Yeahs and follow users.</p>
<a href="{% url "main:signup" %}" class="arrow-button"><span>Create an account</span></a> <a href="{% url "main:signup" %}" class="arrow-button"><span>Create an account</span></a>
<a href="{% url "main:help-faq" %}" class="arrow-button"><span>FAQ/Frequently Asked Questions</span></a> <a href="{% url "main:help-faq" %}" class="arrow-button"><span>FAQ/Frequently Asked Questions</span></a>
</div> </div>
{% elif not post.can_comment %} {% elif not post.can_comment %}
<div class="cannot-reply"><div> <div class="cannot-reply"><div>
{% if post.lock_comments == 1 %}
<p>{{ post.creator.nickname }} has locked the comments.</p>
{% elif post.lock_comments == 2 %}
<p>The comments have been locked up tight.</p>
{% else %}
<p>You cannot comment on this post.</p> <p>You cannot comment on this post.</p>
{% endif %}
</div></div> </div></div>
{% else %} {% else %}
{% comment_form post request.user %} {% comment_form post request.user %}
@@ -22,7 +22,8 @@
<li class="setting-profile-comment"> <li class="setting-profile-comment">
<p class="settings-label">Profile comment</p> <p class="settings-label">Profile comment</p>
<textarea class="textarea" name="profile_comment" maxlength="2200" placeholder="Write about yourself here.">{{ profile.comment }}</textarea> <textarea class="textarea" name="profile_comment" maxlength="2200" placeholder="Write about yourself here.">{{ profile.comment }}</textarea>
<p class="note">Anything you write here will appear on your profile. Remember to keep it brief. Please don't write anything that'll violate <a href="{% url "main:help-rules" %}">Cedar's rules</a>.</p>
<p class="note">Anything you write here will appear on your profile. Remember to keep it brief. Please don't write anything that'll violate <a href="{% url "main:help-rules" %}">{{ brand_name }}'s rules</a>.</p>
</li> </li>
<!-- <!--
<li> <li>
@@ -5,11 +5,11 @@
<form method="post" onload=""> <form method="post" onload="">
<img src="{% static "img/menu-logo.svg" %}"> <img src="{% static "img/menu-logo.svg" %}">
<p class="lh">Sign Up</p> <p class="lh">Sign Up</p>
<p>Create a Cedar account on this instance to access this instance.</p><br> <p>Create a {{ brand_name }} account to make posts and comments to various communities, give Yeahs to other users' content, and interact with other members of the {{ brand_name }} community.</p><br>
<p>Please follow <a href="{% url "main:help-rules" %}">our rules</a>. If you don't, be careful with your behavior.<br><br>You <strong>must</strong> be {{ age }} years of age or older to join, no exceptions.<br>If you are suspected to be younger than {{ age }} years old, we will ban you until you're {{ age }}.</p> <p>Please follow <a href="{% url "main:help-rules" %}">our rules</a>. If you don't, be careful with your behavior.<br><br>You <strong>must</strong> be {{ age }} years of age or older to join, no exceptions.<br>If you are suspected to be younger than {{ age }} years old, we will ban you until you're {{ age }}.</p>
{% if invite_only %}<h3 class="label"><label><span class="red">*</span> Invite code: <input type="text" class="auth-input" name="invite_code" maxlength="64" minlength="4" placeholder="Invite code"></label></h3>{% endif %} {% if invite_only %}<h3 class="label"><label><span class="red">*</span> Invite code: <input type="text" class="auth-input" name="invite_code" maxlength="64" minlength="4" placeholder="Invite code"></label></h3>{% endif %}
<h3 class="label"><label><span class="red">*$</span> User ID: <input type="text" class="auth-input" name="username" maxlength="32" minlength="4" placeholder="ID"></label></h3> <h3 class="label"><label><span class="red">*$</span> Username: <input type="text" class="auth-input" name="username" maxlength="32" minlength="4" placeholder="Username"></label></h3>
<h3 class="label"><label>Nickname: <input type="text" class="auth-input" name="nickname" maxlength="32" placeholder="Nick/Mii name?"></label></h3> <h3 class="label"><label><span class="red">*</span>Nickname: <input type="text" class="auth-input" name="nickname" maxlength="32" placeholder="Nick/Mii name?"></label></h3>
<h3 class="label nnid"><label>Nintendo Network ID: <input type="text" class="auth-input" name="origin_id" maxlength="16" minlength="6" placeholder="NNID" data-mii-domain="{{ mii_domain }}" data-action="{{ mii_endpoint }}"> <h3 class="label nnid"><label>Nintendo Network ID: <input type="text" class="auth-input" name="origin_id" maxlength="16" minlength="6" placeholder="NNID" data-mii-domain="{{ mii_domain }}" data-action="{{ mii_endpoint }}">
<img class="none"> <img class="none">
</label></h3> </label></h3>
@@ -1,4 +1,4 @@
{% extends "closedverse_main/layout.html" %} {% extends "closedverse_main/layout.html" %}
{% load closedverse_tags %}{% block main-body %} {% load closedverse_tags %}{% block main-body %}
{% nocontent "Sign Ups are disabled for now. Please contact the administrator using the contact page." %} {% nocontent "Sign ups are disabled for now. Please contact the administrator using the contact page." %}
{% endblock %} {% endblock %}
@@ -6,6 +6,7 @@ def community_sidebar(community, request):
return { return {
'community': community, 'community': community,
'can_edit': community.can_edit_community(request), 'can_edit': community.can_edit_community(request),
'Community_block': community.Community_block(request),
'request': request, 'request': request,
} }
@register.inclusion_tag('closedverse_main/elements/community_post.html') @register.inclusion_tag('closedverse_main/elements/community_post.html')
@@ -64,9 +65,10 @@ def file_button():
} }
@register.inclusion_tag('closedverse_main/elements/community_page_elem.html') @register.inclusion_tag('closedverse_main/elements/community_page_elem.html')
def community_page_element(communities, text='General Communities', feature=False): def community_page_element(communities, text='General Communities', feature=False, url_name=''):
return { return {
'communities': communities, 'communities': communities,
'title': text, 'title': text,
'feature': feature, 'feature': feature,
'url_name': url_name,
} }
@@ -97,8 +97,8 @@ def print_names(names):
'nameallmn': len(names) - 4, 'nameallmn': len(names) - 4,
'names': names, 'names': names,
} }
@register.inclusion_tag('closedverse_main/elements/discordapp-spinner.html') @register.inclusion_tag('closedverse_main/elements/loading-spinner.html')
def discordapp_spinner(): def loading_spinner():
return { return {
} }
@@ -69,9 +69,10 @@ def u_post_list(posts, next_offset=None, type=2, nf_text='', time=None):
'type': type, 'type': type,
} }
@register.inclusion_tag('closedverse_main/elements/profile-post.html') @register.inclusion_tag('closedverse_main/elements/profile-post.html')
def profile_post(post): def profile_post(post, for_announcements=False):
return { return {
'post': post, 'post': post,
'for_announcements': for_announcements,
} }
@register.inclusion_tag('closedverse_main/elements/profile-user-list.html') @register.inclusion_tag('closedverse_main/elements/profile-user-list.html')
def profile_user_list(users, next_offset=None, request=None): def profile_user_list(users, next_offset=None, request=None):
+3 -1
View File
@@ -61,7 +61,7 @@ urlpatterns = [
url(r'posts/'+ post +'/yeah$', views.post_add_yeah, name='post-add-yeah'), url(r'posts/'+ post +'/yeah$', views.post_add_yeah, name='post-add-yeah'),
url(r'posts/'+ post +'/yeahu$', views.post_delete_yeah, name='post-delete-yeah'), url(r'posts/'+ post +'/yeahu$', views.post_delete_yeah, name='post-delete-yeah'),
url(r'posts/'+ post +'/comments$', views.post_comments, name='post-comments'), url(r'posts/'+ post +'/comments$', views.post_comments, name='post-comments'),
url(r'posts/'+ post +'/comments$', views.post_comments, name='post-comments'), url(r'posts/'+ post +'/lock-comments$', views.lock_the_comments, name='lock-the-comments'),
url(r'posts/'+ post +'/change$', views.post_change, name='post-change'), url(r'posts/'+ post +'/change$', views.post_change, name='post-change'),
url(r'posts/'+ post +'/profile$', views.post_setprofile, name='post-set-profile'), url(r'posts/'+ post +'/profile$', views.post_setprofile, name='post-set-profile'),
url(r'posts/'+ post +'/profile_rm', views.post_unsetprofile, name='post-unset-profile'), url(r'posts/'+ post +'/profile_rm', views.post_unsetprofile, name='post-unset-profile'),
@@ -115,4 +115,6 @@ urlpatterns = [
#url(r'openverse.png', views.openverse_logo, name='openverse-logo'), #url(r'openverse.png', views.openverse_logo, name='openverse-logo'),
] ]
# + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
# serve static and media i think???? mighTTT???????
urlpatterns += [re_path(r'^i/(?P<path>.*)$', serve, {'document_root': MEDIA_ROOT, }), ] urlpatterns += [re_path(r'^i/(?P<path>.*)$', serve, {'document_root': MEDIA_ROOT, }), ]
+61 -18
View File
@@ -1,6 +1,6 @@
# Todo: move all requests to using requests instead of urllib3
import urllib.request, urllib.error import urllib.request, urllib.error
import requests # requests is only used for get_mii which is not being used currently
#import requests
from lxml import etree from lxml import etree
from random import choice from random import choice
import json import json
@@ -38,35 +38,41 @@ def HumanTime(date, full=False):
unit_name += 's' unit_name += 's'
return f'{number_of_units} {unit_name} ago' return f'{number_of_units} {unit_name} ago'
# the current source as of now uses AJAX to get mii data
def get_mii(id): def get_mii(id):
# Using AccountWS # Using AccountWS
dmca = { dmca = {
'X-Nintendo-Client-ID': 'a2efa818a34fa16b8afbc8a74eba3eda', 'X-Nintendo-Client-ID': 'a2efa818a34fa16b8afbc8a74eba3eda',
'X-Nintendo-Client-Secret': 'c91cdb5658bd4954ade78533a339cf9a', 'X-Nintendo-Client-Secret': 'c91cdb5658bd4954ade78533a339cf9a',
} }
# TODO: Make this, the gravatar request, and reCAPTCHA request escape (or plainly use) URL params
nnid = requests.get('https://accountws.nintendo.net/v1/api/admin/mapped_ids?input_type=user_id&output_type=pid&input=' + id, headers=dmca) # Perform the first request to get pid
nnid_dec = etree.fromstring(nnid.content) url_pid = 'https://accountws.nintendo.net/v1/api/admin/mapped_ids?input_type=user_id&output_type=pid&input=' + id
del(nnid) request_pid = urllib.request.Request(url_pid, headers=dmca)
with urllib.request.urlopen(request_pid) as nnid_response:
nnid_content = nnid_response.read()
nnid_dec = etree.fromstring(nnid_content)
pid = nnid_dec[0][1].text pid = nnid_dec[0][1].text
if not pid: if not pid:
return False return False
del(nnid_dec)
mii = requests.get('https://accountws.nintendo.net/v1/api/miis?pids=' + pid, headers=dmca) # Perform the second request to get mii information
url_mii = 'https://accountws.nintendo.net/v1/api/miis?pids=' + pid
request_mii = urllib.request.Request(url_mii, headers=dmca)
with urllib.request.urlopen(request_mii) as mii_response:
mii_content = mii_response.read()
try: try:
mii_dec = etree.fromstring(mii.content) mii_dec = etree.fromstring(mii_content)
# Can't be fucked to put individual exceptions to catch here
except: except:
return False return False
del(mii)
try: try:
miihash = mii_dec[0][2][0][0].text.split('.net/')[1].split('_')[0] miihash = mii_dec[0][2][0][0].text.split('.net/')[1].split('_')[0]
except IndexError: except IndexError:
miihash = None miihash = None
screenname = mii_dec[0][3].text screenname = mii_dec[0][3].text
nnid = mii_dec[0][6].text nnid = mii_dec[0][6].text
del(mii_dec)
# Also todo: Return the NNID based on what accountws returns, not the user's input!!!
return [miihash, screenname, nnid] return [miihash, screenname, nnid]
def recaptcha_verify(request, key): def recaptcha_verify(request, key):
@@ -78,6 +84,26 @@ def recaptcha_verify(request, key):
return False return False
return True return True
def video_upload(video):
hash = sha1()
for chunk in video.chunks():
hash.update(chunk)
imhash = hash.hexdigest()
# only either webm or mp4
extension = video.name[-4:]
if extension == '.mp4':
fname = imhash + '.mp4'
elif extension == 'webm':
fname = imhash + '.webm'
else:
return 1
# simply only write image if the hashed path doesn't already exist
if not os.path.exists(settings.MEDIA_ROOT + fname):
with open(settings.MEDIA_ROOT + fname, "wb+") as destination:
for chunk in video.chunks():
destination.write(chunk)
return settings.MEDIA_URL + fname
ImageFile.LOAD_TRUNCATED_IMAGES = True ImageFile.LOAD_TRUNCATED_IMAGES = True
def image_upload(img, stream=False, drawing=False, avatar=False): def image_upload(img, stream=False, drawing=False, avatar=False):
if stream: if stream:
@@ -212,11 +238,28 @@ def getipintel(addr):
else: else:
return 0 return 0
""" """
# not ideal, switch this to use a real cache when caching for everything else is implemented (never?)
iphub_cache = dict()
# Now using iphub # Now using iphub
def iphub(addr): def iphub(addr, want_asn=False):
# hack to exclude my private network at the time (security flaw?)
if settings.IPHUB_KEY and not '192.168' in addr: if settings.IPHUB_KEY and not '192.168' in addr:
get = requests.get('http://v2.api.iphub.info/ip/' + addr, headers={'X-Key': settings.IPHUB_KEY}) if addr in iphub_cache:
if get.json()['block'] == 1: get_r = iphub_cache[addr]
return True #print('getting ip ' + addr + ' from cache 😌')
else: else:
return False #print('GETTING IP ' + addr + ' FROM IPHUB😤😤😤😤😤😤')
req = urllib.request.Request('http://v2.api.iphub.info/ip/' + addr, headers={'X-Key': settings.IPHUB_KEY})
response = urllib.request.urlopen(req)
data = response.read().decode()
get_r = json.loads(data)
iphub_cache[addr] = get_r
if want_asn:
return get_r.get('asn', '0')
if get_r.get('block', 0) == 1:
return True
# should just return falsey when returning nothing anyway?
#else:
# return False
+109 -107
View File
@@ -3,16 +3,15 @@ from django.template import loader
from django.shortcuts import render, redirect, get_object_or_404 from django.shortcuts import render, redirect, get_object_or_404
from django.http import Http404 from django.http import Http404
from django.views.decorators.csrf import csrf_exempt from django.views.decorators.csrf import csrf_exempt
from django.db.models import Q, QuerySet, Max, F, Count, Case, When, Exists, OuterRef
from django.contrib.auth import login, logout from django.contrib.auth import login, logout
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from django.views.decorators.http import require_http_methods from django.views.decorators.http import require_http_methods
from django.core.validators import EmailValidator from django.core.validators import EmailValidator
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.db.models import Q, Count, Exists, OuterRef from django.db.models import Q, Count, Exists, OuterRef
from django.db.models.functions import Now
from .models import * from .models import *
from .util import * from .util import *
from .serializers import CommunitySerializer
from closedverse import settings from closedverse import settings
import re import re
from django.urls import reverse from django.urls import reverse
@@ -22,14 +21,19 @@ from json import dumps, loads
import sys, traceback import sys, traceback
import base64 import base64
import subprocess import subprocess
from datetime import datetime from datetime import datetime, timedelta
from django.utils import timezone from django.utils import timezone
import django.utils.dateformat import django.utils.dateformat
from binascii import hexlify from binascii import hexlify
from os import urandom from os import urandom
#from silk.profiling.profiler import silk_profile
# client-side mii fetch GET endpoint (like pf2m.com/hash if it supported cors) # client-side mii fetch GET endpoint (like pf2m.com/hash if it supported cors)
mii_endpoint = 'https://nnidlt.murilo.eu.org/api.php?output=hash_only&env=production&user_id=' mii_endpoint = 'https://nnidlt.murilo.eu.org/api.php?output=hash_only&env=production&user_id='
#mii_endpoint = '/origin?a='
if hasattr(settings, 'mii_endpoint'):
mii_endpoint = settings.mii_endpoint
def json_response(msg='', code=0, httperr=400): def json_response(msg='', code=0, httperr=400):
thing = { thing = {
@@ -46,9 +50,10 @@ def json_response(msg='', code=0, httperr=400):
'code': httperr, 'code': httperr,
} }
return JsonResponse(thing, safe=False, status=httperr) return JsonResponse(thing, safe=False, status=httperr)
def community_list(request): def community_list(request):
"""Lists communities / main page.""" """Lists communities / main page."""
popularity = Community.popularity #popularity = Community.popularity
obj = Community.objects obj = Community.objects
if request.user.is_authenticated: if request.user.is_authenticated:
classes = ['guest-top'] classes = ['guest-top']
@@ -64,7 +69,8 @@ def community_list(request):
ad = "no ads" ad = "no ads"
WelcomeMSG = welcomemsg.objects.filter(show=True).order_by('-order', '-id') WelcomeMSG = welcomemsg.objects.filter(show=True).order_by('-order', '-id')
announcements = Post.objects.filter(community__tags='announcements').order_by('-id')[:6] # announcements within the past week-ish
announcements = Post.objects.filter(community__tags='announcements', created__gte=Now()-timedelta(days=5)).order_by('-created')[:6]
if request.user.is_authenticated: if request.user.is_authenticated:
my_communities = obj.filter(creator=request.user).order_by('-created')[0:12] my_communities = obj.filter(creator=request.user).order_by('-created')[0:12]
else: else:
@@ -206,7 +212,7 @@ def login_page(request):
else: else:
# Todo: I might want to do some things relating to making models take care of object stuff like this instead of the view, it's totally messed up now. # Todo: I might want to do some things relating to making models take care of object stuff like this instead of the view, it's totally messed up now.
successful = False if user[1] is False or not user[0].is_active() else True successful = False if user[1] is False or not user[0].is_active() else True
LoginAttempt.objects.create(user=user[0], success=successful, user_agent=request.META.get('HTTP_USER_AGENT'), addr=request.META.get('HTTP_CF_CONNECTING_IP')) LoginAttempt.objects.create(user=user[0], success=successful, user_agent=request.META.get('HTTP_USER_AGENT'), addr=request.META.get('REMOTE_ADDR'))
if user[1] == False: if user[1] == False:
return HttpResponse("Invalid password.", status=401) return HttpResponse("Invalid password.", status=401)
elif user[1] == 2: elif user[1] == 2:
@@ -243,8 +249,8 @@ def signup_page(request):
if request.user.is_authenticated: if request.user.is_authenticated:
return redirect('/') return redirect('/')
if request.method == 'POST': if request.method == 'POST':
if settings.recaptcha_pub: if settings.RECAPTCHA_PUBLIC_KEY:
if not recaptcha_verify(request, settings.recaptcha_priv): if not recaptcha_verify(request, settings.RECAPTCHA_PRIVATE_KEY):
return HttpResponse("The reCAPTCHA validation has failed.", status=402) return HttpResponse("The reCAPTCHA validation has failed.", status=402)
if not (request.POST.get('username') and request.POST.get('password') and request.POST.get('password_again')): if not (request.POST.get('username') and request.POST.get('password') and request.POST.get('password_again')):
return HttpResponseBadRequest("You didn't fill in all of the required fields.") return HttpResponseBadRequest("You didn't fill in all of the required fields.")
@@ -263,15 +269,42 @@ def signup_page(request):
return HttpResponseBadRequest("The provided invite code has been used or is void. Please ask for another code.") return HttpResponseBadRequest("The provided invite code has been used or is void. Please ask for another code.")
invited = True invited = True
if not re.compile(r'^[A-Za-z0-9-._]{1,32}$').match(request.POST['username']) or not re.compile(r'[A-Za-z0-9]').match(request.POST['username']): if not re.compile(r'^[A-Za-z0-9-._]{1,32}$').match(request.POST['username']) or not re.compile(r'[A-Za-z0-9]').match(request.POST['username']):
return HttpResponseBadRequest("Your username either contains invalid characters or is too long (only letters + numbers, dashes, dots and underscores are allowed") return HttpResponseBadRequest("Your username either contains invalid characters or is too long (only letters + numbers, dashes, dots and underscores are allowed")
for keyword in ['admin', 'admln', 'adrnin', 'admn', ]:
if keyword in request.POST['username'].lower(): # forbidden keywords
return HttpResponseForbidden("You aren't funny. Please use a funny name.") groups = [
for keyword in ['nigger', 'nigga', 'faggot', 'kile', ]: [
if keyword in request.POST['username'].lower(): 'admin', 'admln', 'adrnin', 'admn', 'closedverse',
return HttpResponseForbidden("Nigga test failed, invalid pass.") 'arian', 'kordi', 'windowscj', 'gab', 'term',
'penis', 'nazi', 'hitler', 'hitlre', 'ihtler', 'heil', 'kkk'
'nigg', 'niger', 'fag',
'smf9', 'dakux', 'dacucks', 'adrian'
],
['adam', 'nintendotom'],
['funny'],
['doeggs', 'do_eggs', 'do-eggs', 'do.eggs'],
]
messages = [
"That username isn't funny. Please pick a funny username.",
"Adam, no.",
"I'm laughing so hard right now!! No seriously. Pick a better username.",
"the world may never know",
]
for id in range(len(groups)):
for keyword in groups[id]:
if keyword in request.POST['username'].lower() or keyword in request.POST['nickname'].lower():
# perhaps warn admins at a later time
return HttpResponseForbidden(messages[id])
# this is such a miniscule amount of NNIDs that either an admin or a person could
# claim all of them, in which case they could not be reused
#for keyword in ['windowscj', 'gabalt']:
# if keyword in request.POST['origin_id'].lower():
# return HttpResponseForbidden("You're very funny. Unfortunately your funniness blah blah blah fuck off.")
# end of forbidden keywords
conflicting_user = User.objects.filter(Q(username__iexact=request.POST['username']) | Q(username__iexact=request.POST['username'].replace(' ', ''))) conflicting_user = User.objects.filter(Q(username__iexact=request.POST['username']) | Q(username__iexact=request.POST['username'].replace(' ', '')))
if conflicting_user: if conflicting_user:
return HttpResponseBadRequest("A user with that username already exists.") return HttpResponseBadRequest("A user with that username already exists.")
@@ -280,11 +313,11 @@ def signup_page(request):
# do the length check # do the length check
if len(request.POST['password']) < settings.minimum_password_length: if len(request.POST['password']) < settings.minimum_password_length:
return HttpResponseBadRequest('The password must be at least ' + str(settings.minimum_password_length) + ' characters long.') return HttpResponseBadRequest('The password must be at least ' + str(settings.minimum_password_length) + ' characters long.')
if not (request.POST['nickname'] or request.POST['origin_id']): if not request.POST['nickname']:
return HttpResponseBadRequest("You didn't fill in an NNID, so you need a nickname.") return HttpResponseBadRequest("You need a nickname. What else are we gonna call you????? Ghosty?")
if request.POST['nickname'] and len(request.POST['nickname']) > 32: if request.POST['nickname'] and len(request.POST['nickname']) > 32:
return HttpResponseBadRequest("Your nickname is either too long or too short (1-32 characters)") return HttpResponseBadRequest("Your nickname is either too long or too short (1-32 characters)")
if request.POST['origin_id'] and (len(request.POST['origin_id']) > 16 or len(request.POST['origin_id']) < 6): if request.POST.get('origin_id') and (len(request.POST['origin_id']) > 16 or len(request.POST['origin_id']) < 6):
return HttpResponseBadRequest("The NNID provided is either too short or too long.") return HttpResponseBadRequest("The NNID provided is either too short or too long.")
if request.POST.get('email'): if request.POST.get('email'):
if User.email_in_use(request.POST['email']): if User.email_in_use(request.POST['email']):
@@ -293,46 +326,50 @@ def signup_page(request):
EmailValidator()(value=request.POST['email']) EmailValidator()(value=request.POST['email'])
except ValidationError: except ValidationError:
return HttpResponseBadRequest("Your e-mail address is invalid. Input an e-mail address, or input nothing.") return HttpResponseBadRequest("Your e-mail address is invalid. Input an e-mail address, or input nothing.")
check_others = Profile.objects.filter(user__addr=request.META['HTTP_CF_CONNECTING_IP'], let_freedom=False).exists() check_others = Profile.objects.filter(user__addr=request.META['REMOTE_ADDR'], let_freedom=False).exists()
if check_others: if check_others:
return HttpResponseBadRequest("Unfortunately, you cannot make any accounts at this time. This restriction was set for a reason, please contact the administration. Please don't bypass this, as if you do, you are just being ignorant. If you have not made any accounts, contact the administration and this restriction will be removed for you.") return HttpResponseBadRequest("Unfortunately, you cannot make any accounts at this time. This restriction was set for a reason, please contact the administration. Please don't bypass this, as if you do, you are just being ignorant. If you have not made any accounts, contact the administration and this restriction will be removed for you.")
check_othersban = User.objects.filter(addr=request.META['HTTP_CF_CONNECTING_IP'], active=False).exists() check_othersban = User.objects.filter(addr=request.META['REMOTE_ADDR'], active=False).exists()
if check_othersban: if check_othersban:
return HttpResponseBadRequest("You cannot sign up while banned.") return HttpResponseBadRequest("You cannot sign up while banned.")
check_signupban = User.objects.filter(signup_addr=request.META['HTTP_CF_CONNECTING_IP'], active=False).exists() check_signupban = User.objects.filter(signup_addr=request.META['REMOTE_ADDR'], active=False).exists()
if check_signupban: if check_signupban:
return HttpResponseBadRequest("Get on your hands and knees") return HttpResponseBadRequest("Get on your hands and knees")
if iphub(request.META['HTTP_CF_CONNECTING_IP']): if iphub(request.META['REMOTE_ADDR']):
if settings.disallow_proxy: if settings.DISALLOW_PROXY:
return HttpResponseBadRequest("You cannot sign up with a proxy.") return HttpResponseBadRequest("please do not use a vpn ok thanks")
if request.POST['origin_id']: if request.POST.get('origin_id'):
if not request.POST.get('mh'):
return HttpResponseBadRequest("sorry didn't get the mii image attribute. you might need to wait or just refresh, sorry")
if User.nnid_in_use(request.POST['origin_id']): if User.nnid_in_use(request.POST['origin_id']):
return HttpResponseBadRequest("That Nintendo Network ID is already in use, that would cause confusion.") return HttpResponseBadRequest("That Nintendo Network ID is already in use, that would cause confusion.")
mii = get_mii(request.POST['origin_id']) #mii = get_mii(request.POST['origin_id'])
if not mii: #if not mii:
return HttpResponseBadRequest("The NNID provided doesn't exist.") # return HttpResponseBadRequest("The NNID provided doesn't exist.")
nick = mii[1] #nick = mii[1]
nick = request.POST['nickname']
mii = [request.POST.get('mh'), 'if you see this then something is wrong', request.POST['origin_id']]
gravatar = False gravatar = False
else: else:
nick = request.POST['nickname'] nick = request.POST['nickname']
mii = None mii = None
gravatar = True gravatar = True
make = User.objects.closed_create_user(username=request.POST['username'], password=request.POST['password'], email=request.POST.get('email'), addr=request.META['HTTP_CF_CONNECTING_IP'], user_agent=request.META['HTTP_USER_AGENT'], signup_addr=request.META['HTTP_CF_CONNECTING_IP'], nick=nick, nn=mii, gravatar=gravatar) make = User.objects.closed_create_user(username=request.POST['username'], password=request.POST['password'], email=request.POST.get('email'), addr=request.META['REMOTE_ADDR'], user_agent=request.META['HTTP_USER_AGENT'], signup_addr=request.META['REMOTE_ADDR'], nick=nick, nn=mii, gravatar=gravatar)
if invited == True: if invited == True:
invite.used = True invite.used = True
invite.used_by = make invite.used_by = make
invite.save() invite.save()
LoginAttempt.objects.create(user=make, success=True, user_agent=request.META.get('HTTP_USER_AGENT'), addr=request.META.get('HTTP_CF_CONNECTING_IP')) LoginAttempt.objects.create(user=make, success=True, user_agent=request.META.get('HTTP_USER_AGENT'), addr=request.META.get('REMOTE_ADDR'))
login(request, make) login(request, make)
request.session['passwd'] = make.password request.session['passwd'] = make.password
return HttpResponse("/") return HttpResponse("/")
else: else:
if not settings.recaptcha_pub: if not settings.RECAPTCHA_PUBLIC_KEY:
settings.recaptcha_pub = None settings.RECAPTCHA_PUBLIC_KEY = None
return render(request, 'closedverse_main/signup_page.html', { return render(request, 'closedverse_main/signup_page.html', {
'title': 'Sign up', 'title': 'Sign up',
'recaptcha': settings.recaptcha_pub, 'recaptcha': settings.RECAPTCHA_PUBLIC_KEY,
'invite_only': settings.invite_only, 'invite_only': settings.invite_only,
'age': settings.age_allowed, 'age': settings.age_allowed,
'mii_domain': mii_domain, 'mii_domain': mii_domain,
@@ -374,10 +411,15 @@ def forgot_passwd(request):
def logout_page(request): def logout_page(request):
"""Password email page / post endpoint.""" """Password email page / post endpoint."""
if not request.user.is_active():
r = HttpResponseForbidden("You can't log out while you're inactive. According to me and God, you'll just have to sit here and suffer for now. Go contemplate your actions. You will be redirected to Wario Land 4 momentarily.", content_type='text/plain')
r['Refresh'] = '7; url=https://gba.js.org/player#warioland4'
return r
logout(request) logout(request)
if request.GET.get('next'): if request.GET.get('next'):
return redirect(request.GET['next']) return redirect(request.GET['next'])
return redirect('/') return redirect('/')
def user_view(request, username): def user_view(request, username):
"""The user view page, has recent posts/yeahs.""" """The user view page, has recent posts/yeahs."""
user = get_object_or_404(User, username__iexact=username) user = get_object_or_404(User, username__iexact=username)
@@ -423,11 +465,15 @@ def user_view(request, username):
if len(request.POST.get('bg_url')) > 300: if len(request.POST.get('bg_url')) > 300:
return json_response('Background URL is too long (length '+str(len(request.POST.get('bg_url')))+', max 300)') return json_response('Background URL is too long (length '+str(len(request.POST.get('bg_url')))+', max 300)')
if len(request.POST.get('whatareyou')) > 300: if len(request.POST.get('whatareyou')) > 300:
return json_response('Big brother it\'s too big, I can\'t take it! (length '+str(len(request.POST.get('whatareyou')))+', max 300)') return json_response('"What Are You" is too long (length '+str(len(request.POST.get('whatareyou')))+', max 300)')
if len(request.POST.get('external')) > 255: if len(request.POST.get('external')) > 255:
return json_response('Big brother it\'s too big, I can\'t take it! (length '+str(len(request.POST.get('external')))+', max 300)') return json_response('Discord Tag is too long (length '+str(len(request.POST.get('external')))+', max 300)')
if len(request.POST.get('email')) > 500: if len(request.POST.get('email')) > 500:
return json_response('Big brother it\'s too big, I can\'t take it! (length '+str(len(request.POST.get('email')))+', max 500)') return json_response('Email is too long (length '+str(len(request.POST.get('email')))+', max 500)')
# Kinda unneeded but gdsjkgdfsg
if request.POST.get('website') == 'Web URL' or request.POST.get('country') == 'Region' or request.POST.get('external') == 'Discord Tag':
return json_response("I'm laughing right now.")
if len(request.POST.get('avatar')) > 255: if len(request.POST.get('avatar')) > 255:
return json_response('Avatar is too long (length '+str(len(request.POST.get('avatar')))+', max 255)') return json_response('Avatar is too long (length '+str(len(request.POST.get('avatar')))+', max 255)')
if request.POST.get('email') and not request.POST.get('email') == 'None': if request.POST.get('email') and not request.POST.get('email') == 'None':
@@ -615,11 +661,11 @@ def user_posts(request, username):
next_offset = offset + 50 next_offset = offset + 50
if request.META.get('HTTP_X_AUTOPAGERIZE'): if request.META.get('HTTP_X_AUTOPAGERIZE'):
return (debug(request, username) if 'HTTP_DIS' in request.META else render(request, 'closedverse_main/elements/u-post-list.html', { return render(request, 'closedverse_main/elements/u-post-list.html', {
'posts': posts, 'posts': posts,
'next': next_offset, 'next': next_offset,
'time': offset_time.isoformat(), 'time': offset_time.isoformat(),
})) })
else: else:
return render(request, 'closedverse_main/user_posts.html', { return render(request, 'closedverse_main/user_posts.html', {
'user': user, 'user': user,
@@ -1079,7 +1125,7 @@ def community_create_action(request):
def post_create(request, community): def post_create(request, community):
if request.method == 'POST': if request.method == 'POST':
# Wake # Wake
request.user.wake(request.META['HTTP_CF_CONNECTING_IP']) request.user.wake(request.META['REMOTE_ADDR'])
# Required # Required
if not (request.POST.get('community')): if not (request.POST.get('community')):
return HttpResponseBadRequest() return HttpResponseBadRequest()
@@ -1106,7 +1152,8 @@ def post_create(request, community):
7: "Please don't spam.", 7: "Please don't spam.",
9: "You're very funny. Unfortunately your funniness blah blah blah fuck off.", 9: "You're very funny. Unfortunately your funniness blah blah blah fuck off.",
10: "No mr white, you can't make a post entirely consistant of spaces", 10: "No mr white, you can't make a post entirely consistant of spaces",
11: "Please don't post Zalgo text.", 11: "The video you've uploaded is invalid.",
12: "Please don't post Zalgo text.",
}.get(new_post)) }.get(new_post))
# Render correctly whether we're posting to Activity Feed # Render correctly whether we're posting to Activity Feed
if community.is_activity(): if community.is_activity():
@@ -1134,6 +1181,7 @@ def post_view(request, post):
post.can_rm = post.can_rm(request) post.can_rm = post.can_rm(request)
post.is_favorite = post.is_favorite(request.user) post.is_favorite = post.is_favorite(request.user)
post.can_comment = post.can_comment(request) post.can_comment = post.can_comment(request)
post.can_lock_comments = post.can_lock_comments(request)
if post.is_mine: if post.is_mine:
title = 'Your post' title = 'Your post'
else: else:
@@ -1183,6 +1231,12 @@ def post_change(request, post):
return HttpResponse() return HttpResponse()
@require_http_methods(['POST']) @require_http_methods(['POST'])
@login_required @login_required
def lock_the_comments(request, post):
the_post = get_object_or_404(Post, id=post)
the_post.lock_the_comments_up(request)
return HttpResponse()
@require_http_methods(['POST'])
@login_required
def post_setprofile(request, post): def post_setprofile(request, post):
the_post = get_object_or_404(Post, id=post) the_post = get_object_or_404(Post, id=post)
the_post.favorite(request.user) the_post.favorite(request.user)
@@ -1215,11 +1269,9 @@ def comment_rm(request, comment):
@login_required @login_required
def post_comments(request, post): def post_comments(request, post):
post = get_object_or_404(Post, id=post) post = get_object_or_404(Post, id=post)
if not request.is_ajax():
raise Http404()
if request.method == 'POST': if request.method == 'POST':
# Wake # Wake
request.user.wake(request.META['HTTP_CF_CONNECTING_IP']) request.user.wake(request.META['REMOTE_ADDR'])
# Method of Post # Method of Post
new_post = post.create_comment(request) new_post = post.create_comment(request)
if not new_post: if not new_post:
@@ -1234,7 +1286,7 @@ def post_comments(request, post):
2: "The image you've uploaded is invalid.", 2: "The image you've uploaded is invalid.",
3: "You're making comments too fast, wait a few seconds and try again.", 3: "You're making comments too fast, wait a few seconds and try again.",
6: "Not allowed.", 6: "Not allowed.",
11: "Please don't post Zalgo text.", 12: "Please don't post Zalgo text.",
}.get(new_post)) }.get(new_post))
# Give the notification! # Give the notification!
if post.is_mine(request.user): if post.is_mine(request.user):
@@ -1327,17 +1379,15 @@ def user_follow(request, username):
if user.follow(request.user): if user.follow(request.user):
# Give the notification! # Give the notification!
Notification.give_notification(request.user, 4, user) Notification.give_notification(request.user, 4, user)
followct = request.user.num_following() followct = user.num_followers()
return JsonResponse({'following_count': followct}) return JsonResponse({'following_count': followct})
@require_http_methods(['POST']) @require_http_methods(['POST'])
@login_required @login_required
def user_unfollow(request, username): def user_unfollow(request, username):
user = get_object_or_404(User, username=username) user = get_object_or_404(User, username=username)
user.unfollow(request.user) user.unfollow(request.user)
return HttpResponse() followct = user.num_followers()
followct = request.user.num_following()
return JsonResponse({'following_count': followct}) return JsonResponse({'following_count': followct})
@require_http_methods(['POST']) @require_http_methods(['POST'])
@login_required @login_required
def user_friendrequest_create(request, username): def user_friendrequest_create(request, username):
@@ -1397,7 +1447,7 @@ def check_notifications(request):
all_count = request.user.get_frs_notif() + n_count all_count = request.user.get_frs_notif() + n_count
msg_count = request.user.msg_count() msg_count = request.user.msg_count()
# Let's update the user's online status # Let's update the user's online status
request.user.wake(request.META['HTTP_CF_CONNECTING_IP']) request.user.wake(request.META['REMOTE_ADDR'])
# Let's just now return the JSON only for Accept: HTML # Let's just now return the JSON only for Accept: HTML
if 'html' in request.META.get('HTTP_ACCEPT'): if 'html' in request.META.get('HTTP_ACCEPT'):
return JsonResponse({'success': True, 'n': all_count, 'msg': msg_count}) return JsonResponse({'success': True, 'n': all_count, 'msg': msg_count})
@@ -1414,14 +1464,6 @@ def check_notifications(request):
return HttpResponse(binary_notifications, content_type='application/octet-stream') return HttpResponse(binary_notifications, content_type='application/octet-stream')
@require_http_methods(['POST']) @require_http_methods(['POST'])
@login_required @login_required
def notification_setread(request):
if request.GET.get('fr'):
update = request.user.read_fr()
else:
update = request.user.notification_read()
return HttpResponse()
@require_http_methods(['POST'])
@login_required
def notification_delete(request, notification): def notification_delete(request, notification):
if not request.method == 'POST': if not request.method == 'POST':
raise Http404() raise Http404()
@@ -1559,7 +1601,7 @@ def messages_view(request, username):
conversation = friendship.conversation() conversation = friendship.conversation()
if request.method == 'POST': if request.method == 'POST':
# Wake # Wake
request.user.wake(request.META['HTTP_CF_CONNECTING_IP']) request.user.wake(request.META['REMOTE_ADDR'])
new_post = conversation.make_message(request) new_post = conversation.make_message(request)
if not new_post: if not new_post:
return HttpResponseBadRequest() return HttpResponseBadRequest()
@@ -1637,46 +1679,6 @@ def prefs(request):
arr = [profile.let_yeahnotifs, lights, request.user.hide_online] arr = [profile.let_yeahnotifs, lights, request.user.hide_online]
return JsonResponse(arr, safe=False) return JsonResponse(arr, safe=False)
@login_required
def post_list(request):
if not request.user.is_staff():
return JsonResponse({"err": "Not authorized"})
if not request.GET.get('s') or not request.GET.get('e'):
return JsonResponse({"err": "Start time required with 's' query param and end required with 'e' param (epoch)"})
if not request.GET.get('l'):
return JsonResponse({"err": "Limit required via 'l' query param"})
else:
limit = int(request.GET['l'])
if not request.GET.get('o'):
return JsonResponse({"err": "Offset required via 'o' query param"})
else:
offset = int(request.GET['o'])
if limit > 250:
return JsonResponse({"err": "Limit cannot be higher than 250"})
dateone = datetime.fromtimestamp(int(request.GET['s']))
datetwo = datetime.fromtimestamp(int(request.GET['e']))
iable = Post.objects.filter(created__range=(dateone, datetwo)).order_by('-created')[offset:offset + limit]
resparr = []
for post in iable:
resparr.append({
'id': post.id,
'created': django.utils.dateformat.format(post.created, 'U'),
'user': post.creator.username,
'community': post.community_id,
'feeling': post.feeling,
'spoiler': post.spoils,
'content': (post.body or None),
'drawing': (post.drawing or None),
'screenshot': (post.screenshot or None),
'url': (post.url or None),
})
#return HttpResponse(msgpack.packb(resparr), content_type='application/x-msgpack')
return JsonResponse(resparr, safe=False)
def user_tools(request, username): def user_tools(request, username):
if not request.user.is_authenticated: if not request.user.is_authenticated:
raise Http404() raise Http404()
@@ -1840,15 +1842,15 @@ def create_invite(request):
else: else:
raise Http404() raise Http404()
@require_http_methods(['POST']) #@require_http_methods(['POST'])
# Disabling login requirement since it's in signup now. Regret? # Disabling login requirement since it's in signup now. Regret?
#@login_required #@login_required
def origin_id(request): def origin_id(request):
if not request.headers.get('x-requested-with') == 'XMLHttpRequest': if not request.headers.get('x-requested-with') == 'XMLHttpRequest':
return HttpResponse("<a href='https://github.com/ariankordi/closedverse/blob/master/closedverse_main/util.py#L44-L86'>Please do not use this as an API!</a>") return HttpResponse("<a href='https://github.com/ariankordi/closedverse/blob/master/closedverse_main/util.py#L44-L86'>Please do not use this as an API!</a>")
if not request.POST.get('a'): if not request.GET.get('a'):
return HttpResponseBadRequest() return HttpResponseBadRequest()
mii = get_mii(request.POST['a']) mii = get_mii(request.GET['a'])
if not mii: if not mii:
return HttpResponseBadRequest("The NNID provided doesn't exist.") return HttpResponseBadRequest("The NNID provided doesn't exist.")
return HttpResponse(mii[0]) return HttpResponse(mii[0])
@@ -1954,17 +1956,17 @@ def whatads(request):
return render(request, 'closedverse_main/help/whatads.html', {'title': 'What are user-generated ads?'}) return render(request, 'closedverse_main/help/whatads.html', {'title': 'What are user-generated ads?'})
@login_required @login_required
def help_rules(request): def help_rules(request):
return render(request, 'closedverse_main/help/rules.html', {'title': 'Cedar Three Rules', 'age': settings.age_allowed}) return render(request, 'closedverse_main/help/rules.html', {'title': 'Rules', 'age': settings.age_allowed})
def help_faq(request): def help_faq(request):
return render(request, 'closedverse_main/help/faq.html', {'title': 'FAQ'}) return render(request, 'closedverse_main/help/faq.html', {'title': 'FAQ'})
def help_legal(request): def help_legal(request):
if not settings.PROD: if not settings.CLOSEDVERSE_PROD:
return HttpResponseForbidden() return HttpResponseForbidden()
return render(request, 'closedverse_main/help/legal.html', {}) return render(request, 'closedverse_main/help/legal.html', {'title': "Legal Information"})
def help_contact(request): def help_contact(request):
return render(request, 'closedverse_main/help/contact.html', {'title': "Contact Info"}) return render(request, 'closedverse_main/help/contact.html', {'title': "Contact info"})
def help_why(request): def help_why(request):
return render(request, 'closedverse_main/help/why.html', {'title': "Why even join Cedar Three?"}) return render(request, 'closedverse_main/help/why.html', {'title': "Why even join this site?"})
def help_login(request): def help_login(request):
return render(request, 'closedverse_main/help/login-help.html', {'title': "Login help"}) return render(request, 'closedverse_main/help/login-help.html', {'title': "Login help"})
+2 -2
View File
@@ -476,10 +476,10 @@ border-top: 1px solid #222;
border: 1px solid rgba(221, 221, 221, 0); border: 1px solid rgba(221, 221, 221, 0);
} }
#wrapper, #image-header-content { #wrapper, #image-header-content {
background: var(--theme, #2f2f58) var(--background, url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAEpElEQVR4nO2dW3LiQBAEE8kmOPae2w7j/ZjFa0CAHi1N16jqABMZlf2pKB1Op9MfgnI8Hun7Puq5q5zPZz4+Pvj+/g55z6yFs4t6zIWWqLBeOEMOwIWWqLD+5lx8AC60RIX1lnPRAbjQEhXWIc7ZB+BCS1RYH3HOOgAXWqLC+oxz8gG40BIV1leckw7AhZaosI7hHH0ALrREhXUs56gDcKElKqxTOF8egAstUWGdyvn0AFxoiQrrHM6HB+BCS1RY53IOHoALLVFhXcJ5dwAutESFdSnn1QG40BIV1gjOnwNwoSUqrFGcHbjQS1RYIzk7F1qiwhrN2e29UNBhXYPzLeSlm3x9ffH5+Zm+UNi3/L7v4z4KvcTydeTDwk/CbmP5WvIh8AAsX08+BB2A5WvKh4ADOJ/Plh+cLTkXHYBKoaDDujXn7ANQKRR0WGtwzjoAlUJBh7UW5+QDUCkUdFhrck46AJVCQYe1NufoA6gNOiUqrBk4Rx1ABtCxUWHNwvnyALKAjokKaybOpweQCfRVVFizcT48gGygz6LCmpFz8AAygj6KCmtWzrsDyAo6FBXWzJxXB5AZ9DYqrNk5fw4gO+jvqLAqcHagAXqJCqsKZ6cCCjqlqnACdCqgKqWqcEL5kqtTAFUpVYUTinxPxQZGhRP+y4eAbwItX4cTruWDp2IXR4UT7uWDp2IXRYUThuWDp2JnR4UTHssHT8XOigonPJcPnoqdHBVOeC0fPBU7KSqcME4+eCp2dFQ4Ybx88FTsqKhwwjT54KnYl1HhhOnywVOxT6PCCfPkg6diH0aFE+bLB0/FDkaFE5bJB0/F3kWFE5bLB0/FXkWFE2Lkg6dif6LCCXHywVOxgA4nxMo/HA6eilXhhHj5x+MxfikUdEpV4YSV5Hdd/AGolKrCCevJh+CpWJVSVThhXfkQeAAqpapwwvryIegAVEpV4YRt5EPQVKxCqSqcsJ182MlUrAonbCsfdjAVq8IJ28uHxqdiVTihjnxoeCpWhRPqyYdGp2JVOKGufGhwKlaFE+rLh8amYlU4IYd8aGgqVoUT8siHRqZiVTghl3xoYCpWhRPyyQfxqVgVTsgpH4SnYlU4Ia98EJ2KVeGE3PJBcCpWhRPyywexqVgVTtCQD/Cm8t9fy1/l+106y4+NknyJqVjLX09++qlYy19XPiSeirX89eVD0qlYy99GPiScirX87eRDsqlYy99WPiSairX87eVDkqlYy68jHxJMxVp+PflQeSrW8uvKh4pTsZZfXz5Umoq1/BzyocJUrOXnkQ8bT8Vafi75sOFUrOXnkw8bTcVafk75sMFUrOXnlQ8rT8Vafm75sOJUrOXnl7/aVKzla8h/f3/f71IoWH7f97yFvPgvlq8hf5WpWMvXkw87WwoFyw+firV8Xfmwk6VQsPzwqVjL15cPjS+FguWHT8VafjvyodGlULD88KlYy29PPjS2FAr1C52SDKzNLIVCjkLHJgtrE0uhkKfQMcnEKr8UCrkKfZVsrNJLoZCv0GfJyCq7FAo5C32UrKySS6GQt9ChZGaVWwqF3IXeJjur1FIo5C/0dxRYO8vfr3yAv3rECG2I4F0DAAAAAElFTkSuQmCC')) !important; background: var(--theme, #eeeeee) var(--background, url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHgAAAB4CAIAAAC2BqGFAAAABmJLR0QAFgAWACbcRYNiAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4QkQChoXcqytowAAATpJREFUeNrt3MEJwzAQRFFn8MlVuIT0X5jPqSEgLVr5/QLC7DskYII/9/095vQ8z9Gt67omfXIOlQQaNGiBBg0aAWjQAg0atECDFmjQoAUatECDBi3QoLUIdMd/z0ydHco140O55oRQrjkklGvOOct05v1Rc57mQJy8WblyWN6sXDkvL1cuGxnKNVNDuWawZx1FgQYNWqBBg0YAGrRAgwYt0KAFGjRogQYt0KBBCzRogQYNWqBBCzRo0AINWqBBgxZo0AINGrRAgxZo0KAFGrSWgG73Grypg9N3eq+p6X5Al5HZ44z152WnY1Yedg58B1nZez7LGoiTNWdtpjz+q2Mb6+GHZP2JGyjP+jFsbT1pfHrNbap8eNZRFmjQoAUaNGgEoEELNGjQAg1aoEGDFmjQAg0atECD1p/9AKkzTyh2EOP+AAAAAElFTkSuQmCC')) !important;
} }
#empathy-content:before { #empathy-content:before {
background: url(/s/img/rks.png) no-repeat 0 0 !important; background: url(img/rks.png) no-repeat 0 0 !important;
} }
.community-switcher .community-switcher-tab { .community-switcher .community-switcher-tab {
background-color: var(--theme-dark, #202030); background-color: var(--theme-dark, #202030);
+110 -82
View File
@@ -1,15 +1,15 @@
@charset 'UTF-8'; @charset 'UTF-8';
@font-face { @font-face {
font-family: 'MiiverseSymbols'; font-family: 'MiiverseSymbols';
src: url('/s/img/font/Symbols.eot'); src: url('img/font/Symbols.eot');
src: url('/s/img/font/Symbols-IEFix.eot') format('embedded-opentype'), url('/s/img/font/Symbols.woff') format('woff'), url('/s/img/font/Symbols.ttf') format('truetype'); src: url('img/font/Symbols-IEFix.eot') format('embedded-opentype'), url('img/font/Symbols.woff') format('woff'), url('img/font/Symbols.ttf') format('truetype');
font-weight: normal; font-weight: normal;
font-style: normal; font-style: normal;
} }
@font-face { @font-face {
font-family: 'MiiverseSymbols'; font-family: 'MiiverseSymbols';
src: url('/s/img/font/Symbols.eot'); src: url('img/font/Symbols.eot');
src: url('/s/img/font/Symbols-IEFix.eot') format('embedded-opentype'), url('/s/img/font/Symbols.woff') format('woff'), url('/s/img/font/Symbols.ttf') format('truetype'); src: url('img/font/Symbols-IEFix.eot') format('embedded-opentype'), url('img/font/Symbols.woff') format('woff'), url('img/font/Symbols.ttf') format('truetype');
font-weight: normal; font-weight: normal;
font-style: normal; font-style: normal;
} }
@@ -81,19 +81,6 @@ button {
font-size: 20px; font-size: 20px;
width: 175px; width: 175px;
} }
.Announcement-content {
border: 1px solid #00000045;
border-radius: 6px;
padding: 6px;
padding-bottom: 6px;
margin-bottom: 12px;
text-align: left;
padding-bottom: 22px;
background: white;
}
.Announcement-content .Announcement-image {
padding-top: 6px;
}
.none { .none {
display: none !important; display: none !important;
} }
@@ -220,8 +207,7 @@ body {
min-width: 320px; min-width: 320px;
margin: auto 0; margin: auto 0;
text-align: left; text-align: left;
background-color: #f4f4f4; background: var(--theme, #eee) var(--background, url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHgAAAB4CAIAAAC2BqGFAAADF0lEQVR4nO2dwW7bMBAFuRLz/5+bgyWyhwUE13ELtN43EIE3pyQHZj1YUoRMPcX393fT8Hg8zvOcc4rGryUi9n3/+voSjb+Jxm2tbdsWEbrxa4mIbVPa0A1tnrFoCIuGsGgIi4awaAiLhrBoCIuGsGgIi4awaAiLhrBoCIuGsGgIi4awaAiLhrBoCKHoOecqX4E3fbUS0RGxluUkaxZ9c6/q6DnnGEM0uIgxhq456kVnO+fRmYWaOqvNshVNXS96znkcx0JnlC5S9HEcisorRWcjnOd5nmfhsDBX/bV93UtGyZrGGFnl20XjqvsO58Su8l7qzF+zqfd9z0NiJQ1eIzovI1cv/KwsK87zbTcRnTVHxMtF+8V1RJQU3B+Px4eH+66i2zvFWeW2bYVFl/B89Wu/V54/jzHGGCXNMcbo53l+uA/70zRsraXZfd9rp2EJ1ySLiLcTMS1nG30oes7ZdZuw/Ay99+zl+yhOsp7s1og4jqP9Ycn++ff/QHuvI3u53amRX8jCrjp1qETnitF7v8+i/BeeZ57oX6judaToG64Yb8nth/Ryrerom2zj/gnp0xXCpWOVdk6yqZdcOhQjq1lv6TAvWDSERUNYNIRFQ1g0hEVDWDSERUNYNIRFQ1g0hEVDWDSERUNYNIRFQ1g0hEVDWDSERUNYNIRFQ1g0hEVDWDSERUNYNIRFQ1g0hEVDWDSERUNYNIRFQ1g0hEVDWDSERUNYNIRFQ1g0hEVDSESvFS34jK5yYWSmLudTgTpPVSVamvMpQpqnKlw6dDmf5QB5qsKlQ5fzWQ6Qp6rddYhyPgvB8lT755krfM5nCWSe6pyzXwo+GQXO+SyBzFMdY/SSd7uTOZ8lwHmq+77XpO2SOZ8l8HmqNaLhnE8dujzVyl0HlvMpRZSnKnmZgjrnU4Q0T1XyMgV1zqcCdZ6qMDJTl/MpQrojUt3rWKudE2meqrDp1nKtrnax2b0uFg1h0RAWDWHREBYNYdEQFg1h0RAWDWHREBYNYdEQFg1h0RAWDWHREBYNYdEQFg0hFL3W0xXS5ypaa78A+zg9ngAQ62UAAAAASUVORK5CYII='));
background-image: var(--background, url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAYAAABWdVznAAAArUlEQVQoFYWQuwrCQBBFd42FlaYQRMRCO3vBNpA/8HNtBbt04gcItnaKoLKegRnYTRYzcLjzuLNh4kMILooh+SeqO6kYJOawhzE0cIBsDLRboRPwsIUFZMMWTM1UWNJWMx4ZPHV4Rq9to9U+OlpeHcHDhjmNF3LzHc01yBdPEOwvkXdiQ6fW7gp9QWM3aD+RWVI5N5X638KF+VuXvqjUru+GEs8SbnCH3gXxJPEDtBsiPW8IwCQAAAAASUVORK5CYII='));
background-attachment: fixed; background-attachment: fixed;
} }
#sub-body { #sub-body {
@@ -853,7 +839,7 @@ left: 10% !important;
content: "Z"; content: "Z";
} }
#global-menu #global-my-menu .my-menu-white-power:before { #global-menu #global-my-menu .my-menu-white-power:before {
content: url(/s/img/font/wp.svg); content: url(img/font/wp.svg);
width: 20px; width: 20px;
} }
#global-menu #global-my-menu .my-menu-account-setting:before { #global-menu #global-my-menu .my-menu-account-setting:before {
@@ -870,7 +856,7 @@ left: 10% !important;
#global-menu #global-my-menu form input:hover, #global-menu #global-my-menu form input:hover,
#global-menu #global-my-menu form input:active { #global-menu #global-my-menu form input:active {
text-indent: 27px; text-indent: 27px;
} }
} }
h2.label { h2.label {
border-bottom: 3px solid var(--theme, #5ac800); border-bottom: 3px solid var(--theme, #5ac800);
@@ -1116,7 +1102,7 @@ h2.label-topic .with-filter-right {
padding: 10px 10px 8px; padding: 10px 10px 8px;
font-size: 14px; font-size: 14px;
font-weight: bold; font-weight: bold;
background: url("/s/img/button-bg.gif") repeat-x 0 bottom #ffffff; background: url("img/button-bg.gif") repeat-x 0 bottom #ffffff;
background-color: #ffffff; background-color: #ffffff;
background: -webkit-gradient(linear, left top, left bottom, from(#ffffff), to(#e6e6e6), color-stop(0.5, #ffffff)); background: -webkit-gradient(linear, left top, left bottom, from(#ffffff), to(#e6e6e6), color-stop(0.5, #ffffff));
background: -webkit-linear-gradient(top, #ffffff 0%, #ffffff 50%, #e6e6e6 100%); background: -webkit-linear-gradient(top, #ffffff 0%, #ffffff 50%, #e6e6e6 100%);
@@ -1206,7 +1192,7 @@ h2.label-topic .with-filter-right {
.tab2 a.selected, .tab2 a.selected,
.tab3 a.selected { .tab3 a.selected {
color: #FFF; color: #FFF;
background: url("/s/img/color-button-bg.gif") repeat-x 0 bottom #257811; background: url("img/color-button-bg.gif") repeat-x 0 bottom var(--theme, #2e81e5);
background-color: #81e52e; background-color: #81e52e;
background: -webkit-gradient(linear, left top, left bottom, from(var(--theme, #257811)), to(var(--theme-slightly-dark, #1e610e))); background: -webkit-gradient(linear, left top, left bottom, from(var(--theme, #257811)), to(var(--theme-slightly-dark, #1e610e)));
background: -webkit-linear-gradient(top, #257811 #1e610e); background: -webkit-linear-gradient(top, #257811 #1e610e);
@@ -1301,28 +1287,34 @@ span.owner-label {
height: 22px; height: 22px;
} }
.icon-container.administrator:after { .icon-container.administrator:after {
content: url("/s/img/administrator.png"); content: url("img/administrator.png");
} }
.icon-container.developer:after { .icon-container.developer:after {
content: url("/s/img/developer.png"); content: url("img/developer.png");
}
.icon-container.badgedes:after {
content: url("img/badgedes.png");
} }
.icon-container.openverse:after { .icon-container.openverse:after {
content: url("/s/img/open-dev.png"); content: url("img/open-dev.png");
} }
.icon-container.urapp:after { .icon-container.urapp:after {
content: url("/s/img/open-zsdev.png"); content: url("img/open-zsdev.png");
} }
.icon-container.moderator:after { .icon-container.moderator:after {
content: url("/s/img/moderator.png"); content: url("img/moderator.png");
} }
.icon-container.donator:after { .icon-container.donator:after {
content: url("/s/img/donator.png"); content: url("img/donator.png");
} }
.icon-container.tester:after { .icon-container.cool:after {
content: url("/s/img/tester.png"); content: url("img/cool.png");
} }
.icon-container.verified:after { .icon-container.jack:after {
content: url("/s/img/verified.png"); content: url("img/jack.png");
}
.icon-container.verifiedd:after {
content: url("img/verified.png");
} }
.multi-timeline-post-list .post .icon-container.offline:before, .multi-timeline-post-list .post .icon-container.offline:before,
@@ -1390,6 +1382,9 @@ span.owner-label {
.post-permalink-feeling-icon.developer { .post-permalink-feeling-icon.developer {
position: relative; position: relative;
} }
.post-permalink-feeling-icon.badgedes {
position: relative;
}
.post-permalink-feeling-icon.openverse { .post-permalink-feeling-icon.openverse {
position: relative; position: relative;
} }
@@ -1402,14 +1397,17 @@ span.owner-label {
.post-permalink-feeling-icon.donator { .post-permalink-feeling-icon.donator {
position: relative; position: relative;
} }
.post-permalink-feeling-icon.tester { .post-permalink-feeling-icon.cool {
position: relative; position: relative;
} }
.post-permalink-feeling-icon.staff { .post-permalink-feeling-icon.jack {
position: relative;
}
.post-permalink-feeling-icon.verifiedd {
position: relative; position: relative;
} }
.post-permalink-feeling-icon.administrator:after { .post-permalink-feeling-icon.administrator:after {
content: url("/s/img/administrator.png"); content: url("img/administrator.png");
position: absolute; position: absolute;
display: block; display: block;
top: 0; top: 0;
@@ -1418,7 +1416,16 @@ span.owner-label {
height: 22px; height: 22px;
} }
.post-permalink-feeling-icon.developer:after { .post-permalink-feeling-icon.developer:after {
content: url("/s/img/developer.png"); content: url("img/developer.png");
position: absolute;
display: block;
top: 0;
left: 0;
width: 22px;
height: 22px;
}
.post-permalink-feeling-icon.badgedes:after {
content: url("img/badgedes.png");
position: absolute; position: absolute;
display: block; display: block;
top: 0; top: 0;
@@ -1427,7 +1434,7 @@ span.owner-label {
height: 22px; height: 22px;
} }
.post-permalink-feeling-icon.openverse:after { .post-permalink-feeling-icon.openverse:after {
content: url("/s/img/open-dev.png"); content: url("img/open-dev.png");
position: absolute; position: absolute;
display: block; display: block;
top: 0; top: 0;
@@ -1436,7 +1443,7 @@ span.owner-label {
height: 22px; height: 22px;
} }
.post-permalink-feeling-icon.moderator:after { .post-permalink-feeling-icon.moderator:after {
content: url("/s/img/moderator.png"); content: url("img/moderator.png");
position: absolute; position: absolute;
display: block; display: block;
top: 0; top: 0;
@@ -1445,7 +1452,7 @@ span.owner-label {
height: 22px; height: 22px;
} }
.post-permalink-feeling-icon.donator:after { .post-permalink-feeling-icon.donator:after {
content: url("/s/img/donator.png"); content: url("img/donator.png");
position: absolute; position: absolute;
display: block; display: block;
top: 0; top: 0;
@@ -1453,8 +1460,8 @@ span.owner-label {
width: 22px; width: 22px;
height: 22px; height: 22px;
} }
.post-permalink-feeling-icon.verified:after { .post-permalink-feeling-icon.verifiedd:after {
content: url("/s/img/verified.png"); content: url("img/verified.png");
position: absolute; position: absolute;
display: block; display: block;
top: 0; top: 0;
@@ -1462,8 +1469,8 @@ span.owner-label {
width: 22px; width: 22px;
height: 22px; height: 22px;
} }
.post-permalink-feeling-icon.tester:after { .post-permalink-feeling-icon.cool:after {
content: url("/s/img/tester.png"); content: url("img/cool.png");
position: absolute; position: absolute;
display: block; display: block;
top: 0; top: 0;
@@ -1471,8 +1478,8 @@ span.owner-label {
width: 22px; width: 22px;
height: 22px; height: 22px;
} }
.post-permalink-feeling-icon.Staff:after { .post-permalink-feeling-icon.jack:after {
content: url("/s/img/splus.png"); content: url("img/jack.png");
position: absolute; position: absolute;
display: block; display: block;
top: 0; top: 0;
@@ -1525,6 +1532,9 @@ span.owner-label {
.button.edit-post-button:before { .button.edit-post-button:before {
content: "J" !important; content: "J" !important;
} }
.button.lock-comments-button:before {
content: "p" !important;
}
.button.rm-post-button:before { .button.rm-post-button:before {
content: "d" !important; content: "d" !important;
} }
@@ -1598,7 +1608,7 @@ span.owner-label {
clear: both; clear: both;
display: block; display: block;
padding: 11px 20px 9px 15px; padding: 11px 20px 9px 15px;
background: url('/s/img/icon-arrow-right.png') no-repeat 97.5% center; background: url('img/icon-arrow-right.png') no-repeat 97.5% center;
color: #323232; color: #323232;
-webkit-background-size: 9px 15px; -webkit-background-size: 9px 15px;
-moz-background-size: 9px 15px; -moz-background-size: 9px 15px;
@@ -1709,7 +1719,7 @@ font-size: 18px;
font-size: 14px; font-size: 14px;
font-weight: bold; font-weight: bold;
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.5); text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.5);
background: url("/s/img/black-button-bg.gif") repeat-x 0 bottom #646464; background: url("img/black-button-bg.gif") repeat-x 0 bottom #646464;
background-color: #646464; background-color: #646464;
background: -webkit-gradient(linear, left top, left bottom, from(#646464), to(#323232), color-stop(0.96, #434343)); background: -webkit-gradient(linear, left top, left bottom, from(#646464), to(#323232), color-stop(0.96, #434343));
background: -webkit-linear-gradient(top, #646464 0%, #434343 96%, #323232 100%); background: -webkit-linear-gradient(top, #646464 0%, #434343 96%, #323232 100%);
@@ -1767,7 +1777,7 @@ font-size: 18px;
font-size: 14px; font-size: 14px;
font-weight: bold; font-weight: bold;
text-shadow: 0 1px 0 #fff; text-shadow: 0 1px 0 #fff;
background: url("/s/img/gray-button-bg.gif") repeat-x 0 bottom #ffffff; background: url("img/gray-button-bg.gif") repeat-x 0 bottom #ffffff;
background-color: #ffffff; background-color: #ffffff;
background: -webkit-gradient(linear, left top, left bottom, from(#ffffff), to(#bbbbbb), color-stop(0.96, #dddddd)); background: -webkit-gradient(linear, left top, left bottom, from(#ffffff), to(#bbbbbb), color-stop(0.96, #dddddd));
background: -webkit-linear-gradient(top, #ffffff 0%, #dddddd 96%, #bbbbbb 100%); background: -webkit-linear-gradient(top, #ffffff 0%, #dddddd 96%, #bbbbbb 100%);
@@ -2947,7 +2957,7 @@ input.file-button {
margin: 0; margin: 0;
padding: 0; padding: 0;
border: 0; border: 0;
background: url('/s/img/mask-bg-white.png'); background: url('img/mask-bg-white.png');
background: rgba(240, 240, 240, 0.6); background: rgba(240, 240, 240, 0.6);
z-index: 31; z-index: 31;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0); -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
@@ -3149,7 +3159,7 @@ border-top: 1px solid var(--theme, #94ff3d);
clear: both; clear: both;
display: block; display: block;
padding: 11px 20px 9px 15px; padding: 11px 20px 9px 15px;
background: url('/s/img/icon-arrow-right.png') no-repeat 97.5% center; background: url('img/icon-arrow-right.png') no-repeat 97.5% center;
color: #323232; color: #323232;
-webkit-background-size: 9px 15px; -webkit-background-size: 9px 15px;
-moz-background-size: 9px 15px; -moz-background-size: 9px 15px;
@@ -3247,7 +3257,7 @@ border-top: 1px solid var(--theme, #94ff3d);
.sidebar-setting a { .sidebar-setting a {
clear: both; clear: both;
padding: 11px 20px 9px 15px; padding: 11px 20px 9px 15px;
background: url('/s/img/icon-arrow-right.png') no-repeat 97.5% center; background: url('img/icon-arrow-right.png') no-repeat 97.5% center;
color: #323232; color: #323232;
-webkit-background-size: 9px 15px; -webkit-background-size: 9px 15px;
-moz-background-size: 9px 15px; -moz-background-size: 9px 15px;
@@ -3478,7 +3488,7 @@ border-top: 1px solid var(--theme, #94ff3d);
} }
#sidebar-profile-status li a.selected { #sidebar-profile-status li a.selected {
font-weight: bold; font-weight: bold;
background-image: url('/s/img/bg-select.png'); background-image: url('img/bg-select.png');
background-size: 6px auto; background-size: 6px auto;
} }
#sidebar-profile-status .number { #sidebar-profile-status .number {
@@ -3667,13 +3677,13 @@ border-top: 1px solid var(--theme, #94ff3d);
background-size: 26px auto; background-size: 26px auto;
} }
.user-data .game-skill span.beginner:before { .user-data .game-skill span.beginner:before {
background-image: url('/s/img/skill-beginner.png'); background-image: url('img/skill-beginner.png');
} }
.user-data .game-skill span.intermediate:before { .user-data .game-skill span.intermediate:before {
background-image: url('/s/img/skill-intermediate.png'); background-image: url('img/skill-intermediate.png');
} }
.user-data .game-skill span.expert:before { .user-data .game-skill span.expert:before {
background-image: url('/s/img/skill-expert.png'); background-image: url('img/skill-expert.png');
} }
.user-data .game .note > div { .user-data .game .note > div {
display: inline-block; display: inline-block;
@@ -4408,7 +4418,7 @@ div#activity-feed-tutorial.no-content p.tleft {
clear: both; clear: both;
display: block; display: block;
padding: 11px 20px 9px 15px; padding: 11px 20px 9px 15px;
background: url('/s/img/icon-arrow-right.png') no-repeat 97.5% center; background: url('img/icon-arrow-right.png') no-repeat 97.5% center;
color: #323232; color: #323232;
-webkit-background-size: 9px 15px; -webkit-background-size: 9px 15px;
-moz-background-size: 9px 15px; -moz-background-size: 9px 15px;
@@ -4588,7 +4598,7 @@ div#activity-feed-tutorial.no-content p.tleft {
text-align: left; text-align: left;
} }
#identified-user-banner a:before { #identified-user-banner a:before {
background: url(/s/img/identified-user-banner.png); background: url(img/identified-user-banner.png);
background-size: 100px 50px; background-size: 100px 50px;
content: ''; content: '';
height: 50px; height: 50px;
@@ -4903,7 +4913,7 @@ div#activity-feed-tutorial.no-content p.tleft {
font-weight: bold; font-weight: bold;
color: #323232; color: #323232;
} }
.news-list .nick-namea:hover { .news-list .nick-name a:hover {
text-decoration: underline; text-decoration: underline;
} }
.news-list a.link { .news-list a.link {
@@ -5914,7 +5924,7 @@ h2.label-topic_post .label-topic_post-msgid {
display: inline-block; display: inline-block;
width: 22px; width: 22px;
height: 10px; height: 10px;
background: url('/s/img/tutorial-window-balloon.png'); background: url('img/tutorial-window-balloon.png');
background-size: 22px 10px; background-size: 22px 10px;
position: absolute; position: absolute;
top: -10px; top: -10px;
@@ -6132,7 +6142,7 @@ h2.label-topic_post .label-topic_post-msgid {
height: 7px; height: 7px;
top: -6px; top: -6px;
left: 22px; left: 22px;
background: url('/s/img/balloon-part-empathy.png') no-repeat 0 0; background: url('img/balloon-part-empathy.png') no-repeat 0 0;
-webkit-background-size: 10px 7px; -webkit-background-size: 10px 7px;
-moz-background-size: 10px 7px; -moz-background-size: 10px 7px;
-ms-background-size: 10px 7px; -ms-background-size: 10px 7px;
@@ -6300,7 +6310,7 @@ h2.label-topic_post .label-topic_post-msgid {
text-align: center; text-align: center;
} }
.post-permalink-button { .post-permalink-button {
background: #ffffff url('/s/img/icon-arrow-left.png') no-repeat 15px center; background: #ffffff url('img/icon-arrow-left.png') no-repeat 15px center;
color: #323232; color: #323232;
display: table; display: table;
width: 100%; width: 100%;
@@ -6547,7 +6557,7 @@ h2.label-topic_post .label-topic_post-msgid {
#diary-container #diary-user-content { #diary-container #diary-user-content {
padding: 5px 10px 10px; padding: 5px 10px 10px;
text-align: center; text-align: center;
background-image: url('/s/img/bg-gray-dot.png'); background-image: url('img/bg-gray-dot.png');
background-size: 14px auto; background-size: 14px auto;
border-bottom: 1px solid #dddddd; border-bottom: 1px solid #dddddd;
border-top: 4px solid #04c9db; border-top: 4px solid #04c9db;
@@ -6609,7 +6619,7 @@ h2.label-topic_post .label-topic_post-msgid {
background-position: center bottom; background-position: center bottom;
background-repeat: repeat-x; background-repeat: repeat-x;
background-size: 14px auto; background-size: 14px auto;
background-image: url('/s/img/bg-gray.png'); background-image: url('img/bg-gray.png');
min-height: 140px; min-height: 140px;
width: 100%; width: 100%;
position: relative; position: relative;
@@ -7573,49 +7583,63 @@ margin: 10px 0px 15px !important;
#empathy-content .icon-container.donator:after, #empathy-content .icon-container.donator:after,
#reply-content .icon-container.donator:after, #reply-content .icon-container.donator:after,
.news-list .icon-container.donator:after { .news-list .icon-container.donator:after {
content: url(/s/img/donator.png); content: url(img/donator.png);
width: 17px; width: 17px;
height: 17px; height: 17px;
} }
#empathy-content .icon-container.verified:after, #empathy-content .icon-container.verifiedd:after,
#reply-content .icon-container.verified:after, #reply-content .icon-container.verifiedd:after,
.news-list .icon-container.verified:after { .news-list .icon-container.verifiedd:after {
content: url(/s/img/verified.png); content: url(img/.png);
width: 17px; width: 17px;
height: 17px; height: 17px;
} }
#empathy-content .icon-container.tester:after, #empathy-content .icon-container.cool:after,
#reply-content .icon-container.tester:after, #reply-content .icon-container.cool:after,
.news-list .icon-container.tester:after { .news-list .icon-container.cool:after {
content: url(/s/img/tester.png); content: url(img/cool.png);
width: 17px;
height: 17px;
}
#empathy-content .icon-container.jack:after,
#reply-content .icon-container.jack:after,
.news-list .icon-container.jack:after {
content: url(img/jack.png);
width: 17px; width: 17px;
height: 17px; height: 17px;
} }
#empathy-content .icon-container.moderator:after, #empathy-content .icon-container.moderator:after,
#reply-content .icon-container.moderator:after, #reply-content .icon-container.moderator:after,
.news-list .icon-container.moderator:after { .news-list .icon-container.moderator:after {
content: url(/s/img/moderator.png); content: url(img/moderator.png);
width: 17px; width: 17px;
height: 17px; height: 17px;
} }
#empathy-content .icon-container.administrator:after, #empathy-content .icon-container.administrator:after,
#reply-content .icon-container.administrator:after, #reply-content .icon-container.administrator:after,
.news-list .icon-container.administrator:after { .news-list .icon-container.administrator:after {
content: url("/s/img/administrator.png"); content: url("img/administrator.png");
width: 17px; width: 17px;
height: 17px; height: 17px;
} }
#empathy-content .icon-container.developer:after, #empathy-content .icon-container.developer:after,
#reply-content .icon-container.developer:after, #reply-content .icon-container.developer:after,
.news-list .icon-container.developer:after { .news-list .icon-container.developer:after {
content: url("/s/img/developer.png"); content: url("img/developer.png");
width: 17px;
height: 17px;
}
#empathy-content .icon-container.badgedes:after,
#reply-content .icon-container.badgedes:after,
.news-list .icon-container.badgedes:after {
content: url("img/badgedes.png");
width: 17px; width: 17px;
height: 17px; height: 17px;
} }
#empathy-content .icon-container.openverse:after, #empathy-content .icon-container.openverse:after,
#reply-content .icon-container.openverse:after, #reply-content .icon-container.openverse:after,
.news-list .icon-container.openverse:after { .news-list .icon-container.openverse:after {
content: url("/s/img/open-dev.png"); content: url("img/open-dev.png");
width: 17px; width: 17px;
height: 17px; height: 17px;
} }
@@ -8427,7 +8451,7 @@ margin: 10px 0px 15px !important;
font-size: 14px; font-size: 14px;
} }
.post-permalink-button { .post-permalink-button {
background: #ffffff url('/s/img/icon-arrow-left.png') no-repeat 10px center; background: #ffffff url('img/icon-arrow-left.png') no-repeat 10px center;
min-height: 56px; min-height: 56px;
} }
.post-permalink-button > span { .post-permalink-button > span {
@@ -8699,7 +8723,7 @@ margin: 10px 0px 15px !important;
.textarea-with-menu .textarea-menu-memo:before, .textarea-with-menu .textarea-menu-memo:before,
.textarea-with-menu .textarea-menu-poll:before { .textarea-with-menu .textarea-menu-poll:before {
content: ""; content: "";
background: url(/s/img/form-icons.png); background: url(img/form-icons.png);
position: absolute; position: absolute;
top: 3px; top: 3px;
left: 50%; left: 50%;
@@ -8708,7 +8732,7 @@ margin: 10px 0px 15px !important;
.textarea-with-menu.active-text .textarea-menu-text, .textarea-with-menu.active-text .textarea-menu-text,
.textarea-with-menu.active-memo .textarea-menu-memo, .textarea-with-menu.active-memo .textarea-menu-memo,
.textarea-with-menu.active-poll .textarea-menu-poll { .textarea-with-menu.active-poll .textarea-menu-poll {
background: -webkit-gradient(linear, left top, left bottom, from(var(--theme, #257811)), to(var(--theme-slightly-dark, #1e610e))) 0 0; background: -webkit-gradient(linear, left top, left bottom, from(var(--theme, #2e81e5)), to(var(--theme-slightly-dark, #005ac8))) 0 0;
} }
.textarea-with-menu .textarea-menu-text.disabled, .textarea-with-menu .textarea-menu-text.disabled,
.textarea-with-menu .textarea-menu-memo.disabled, .textarea-with-menu .textarea-menu-memo.disabled,
@@ -8836,6 +8860,9 @@ font-size: 20px;
margin-top: 20px; margin-top: 20px;
margin-bottom: 20px; margin-bottom: 20px;
} }
.login-page a:hover {
text-decoration: underline;
}
.login-page .g-recaptcha { .login-page .g-recaptcha {
margin: 10px auto 15px; margin: 10px auto 15px;
display: block; display: block;
@@ -8942,7 +8969,7 @@ display: block !important;
top: 0px; top: 0px;
left: 0px; left: 0px;
z-index: 2000; z-index: 2000;
background: transparent url("/s/img/load.png") 0 0 no-repeat; background: transparent url("img/load.png") 0 0 no-repeat;
animation: woomy 0.36s steps(17) infinite; animation: woomy 0.36s steps(17) infinite;
} }
@keyframes woomy { @keyframes woomy {
@@ -9451,7 +9478,7 @@ See http://bgrins.github.io/spectrum/themes/ for instructions.
.open-spin { .open-spin {
width: 40px; width: 40px;
margin: -2px 0 -2px 0; margin: -2px 0 -2px 0;
content: url(/s/img/favicon.png); content: url(img/favicon.png);
animation: spin 1.6s linear infinite; animation: spin 1.6s linear infinite;
} }
@keyframes spin { 100% { -webkit-transform: rotate(360deg); transform:rotate(360deg); } } @keyframes spin { 100% { -webkit-transform: rotate(360deg); transform:rotate(360deg); } }
@@ -9500,6 +9527,7 @@ See http://bgrins.github.io/spectrum/themes/ for instructions.
background-color: #fffce4; background-color: #fffce4;
} }
.close-announce-link:before { .close-announce-link:before {
font-family: "MiiverseSymbols";
font-size: 14px; font-size: 14px;
content: 'A'; content: 'A';
color: #FF9100; color: #FF9100;
+133 -16
View File
@@ -835,14 +835,15 @@ var Olv = Olv || {};
}, },
submit: function(b, c) { submit: function(b, c) {
b.trigger("olv:form:submit", [c || a()]); b.trigger("olv:form:submit", [c || a()]);
if(a('input[type=file]').length) { var d = new FormData(b[0]);
/*if(a('input[type=file]').length) {
var d = new FormData(b[0]) var d = new FormData(b[0])
d.append('screen', $('input[type=file]')[0].files[0]) d.append('screen', $('input[type=file]')[0].files[0])
sucky = true sucky = true
} else { } else {
var d = b.serializeArray() var d = b.serializeArray()
sucky = false sucky = false
} }*/
var e = c && c.is("input, button") && c.prop("name"); var e = c && c.is("input, button") && c.prop("name");
e && d.push({ e && d.push({
name: e, name: e,
@@ -853,10 +854,10 @@ var Olv = Olv || {};
url: b.attr("action"), url: b.attr("action"),
data: d data: d
}; };
if(sucky) { //if(sucky) {
f.processData = false; f.processData = false;
f.contentType = false; f.contentType = false;
} //}
return this.send(f, c) return this.send(f, c)
}, },
get: function(a, b, c) { get: function(a, b, c) {
@@ -947,7 +948,7 @@ var Olv = Olv || {};
b.router.connect("", b.Form.setupForPage), b.router.connect("", b.Form.setupForPage),
b.Guest = { b.Guest = {
isGuest: function() { isGuest: function() {
return a("main-body").hasClass("guest") return a("#main-body").hasClass("guest")
} }
}, },
b.DecreasingTimer = function(a, b, c) { b.DecreasingTimer = function(a, b, c) {
@@ -1855,7 +1856,8 @@ var Olv = Olv || {};
}), }),
e() e()
}*/ }*/
function h() { // original function source is lost media
/*function h() {
/*var e = a(d.target).siblings().filter("input") /*var e = a(d.target).siblings().filter("input")
, f = d.target.files[0]; , f = d.target.files[0];
if (!f) if (!f)
@@ -1869,7 +1871,7 @@ var Olv = Olv || {};
} }
,*/ ,*/
/*b.Form.toggleDisabled(j, !0), /*b.Form.toggleDisabled(j, !0),
g.readAsDataURL(f)*/ g.readAsDataURL(f)
var e = $("#upload-file"), var e = $("#upload-file"),
h = $("#upload-input"), h = $("#upload-input"),
f = $("#upload-preview"), f = $("#upload-preview"),
@@ -1879,7 +1881,7 @@ var Olv = Olv || {};
var n = function(a) { var n = function(a) {
/*window.anus = a /*window.anus = a
console.log(a) console.log(a)
*/switch (!0) { switch (!0) {
case void 0 !== a.target.files: case void 0 !== a.target.files:
var c = a.target.files; var c = a.target.files;
break; break;
@@ -1901,6 +1903,7 @@ var Olv = Olv || {};
h.val(""); h.val("");
f.attr("src", ""); f.attr("src", "");
m.text("..."); m.text("...");
window.ass = e
var e = new FileReader, var e = new FileReader,
n = function() { n = function() {
f.attr("src", e.result); f.attr("src", e.result);
@@ -1913,6 +1916,7 @@ var Olv = Olv || {};
}; };
a.addEventListener("load", c); a.addEventListener("load", c);
l.show(); l.show();
console.log('...now!')
h.val(e.result.split(";base64,")[1]); h.val(e.result.split(";base64,")[1]);
e.removeEventListener("load", n) e.removeEventListener("load", n)
}; };
@@ -1933,6 +1937,100 @@ var Olv = Olv || {};
h.val("") h.val("")
Olv.fuUUckFiles = null; Olv.fuUUckFiles = null;
}) })
}*/
function h() {
var uploadFile = $("#upload-file"),
uploadInput = $("#upload-input"),
uploadPreview = $("#upload-preview"),
uploadPreviewContainer = $("#upload-preview-container"),
imageDimensions = $("#image-dimensions");
b.EntryForm.tempPollutionButImageFormAllowedText = imageDimensions.text();
var handleFileChange = function(event) {
//var fileList;
console.log('handleFileChange: files is being assigned...');
switch(true) {
case event.target.files !== undefined:
uploadFile[0].files = event.target.files;
break;
case event.originalEvent.dataTransfer !== undefined:
uploadFile[0].files = event.originalEvent.dataTransfer.files;
break;
case event.originalEvent.clipboardData !== undefined:
uploadFile[0].files = event.originalEvent.clipboardData.files;
break;
default:
return;
}
if (!(null === uploadFile[0].files || uploadFile[0].files.length < 1 || void 0 === uploadFile[0].files[0] || uploadFile[0].files[0].type.indexOf("image") < 0)) {
event.preventDefault();
Olv.Form.toggleDisabled($("input.black-button"), false);
uploadPreview.hide();
uploadPreviewContainer.hide();
uploadInput.val("");
uploadPreview.attr("src", "");
imageDimensions.text("...");
/*window.ass = uploadFile[0].files;window.uploadFile = uploadFile
console.log('here is your fileList, and uploadFile')
*/
var blobURL = URL.createObjectURL(uploadFile[0].files[0]);
console.log(uploadFile[0].files[0])
uploadPreview.attr("src", blobURL);
uploadPreview.show();
var handleImageLoad = function() {
imageDimensions.text(uploadPreview[0].width + " x " + uploadPreview[0].height);
uploadPreview[0].removeEventListener("load", handleImageLoad);
};
uploadPreview[0].addEventListener("load", handleImageLoad);
uploadPreviewContainer.show();
/*var fileReader = new FileReader();
var handleReaderLoad = function() {
uploadPreview.attr("src", fileReader.result);
uploadPreview.show();
var image = new Image();
image.src = fileReader.result;
var handleImageLoad = function() {
imageDimensions.text(image.width + " x " + image.height);
image.removeEventListener("load", handleImageLoad);
};
image.addEventListener("load", handleImageLoad);
uploadPreviewContainer.show();
console.log('...now!')
uploadInput.val(fileReader.result.split(";base64,")[1]);
fileReader.removeEventListener("load", handleReaderLoad);
};
fileReader.addEventListener("load", handleReaderLoad);
fileReader.readAsDataURL(fileList[0]);
*/
}
};
uploadFile.change(handleFileChange);
c.on("dragover dragenter", function(event) {
event.preventDefault();
});
c.on("drop paste", handleFileChange);
c.on("olv:entryform:post:done", function() {
imageDimensions.text(b.EntryForm.tempPollutionButImageFormAllowedText);
uploadPreview.hide();
uploadPreviewContainer.hide();
uploadPreview.attr("src", "");
uploadInput.val("");
});
} }
function i(a) { function i(a) {
k.siblings().filter("input[type=hidden]").val(""), k.siblings().filter("input[type=hidden]").val(""),
@@ -2263,7 +2361,9 @@ var Olv = Olv || {};
b.Global.setupMyMenu() b.Global.setupMyMenu()
}), }),
b.init.done(function(a) { b.init.done(function(a) {
if (a("#global-menu-news").length) { // don't check notifications if there's no news icon
// why didn't this always use isGuest but now it does
if (a("#global-menu-news").length && !Olv.Guest.isGuest()) {
a("#global-menu-news > a").on("click", function(b) { a("#global-menu-news > a").on("click", function(b) {
a(b.currentTarget).find(".badge").hide() a(b.currentTarget).find(".badge").hide()
}); });
@@ -2840,6 +2940,15 @@ $('.post-poll .poll-votes').on('click', function() {
}) })
}) })
} }
lock_comments_button = $('.lock-comments-button')
if(lock_comments_button.length) {
lock_comments_button.on('click',function(){
b.showConfirm("Lock comments", "Really lock up the comments? This cannot be undone.")
$('.ok-button').on('click',function(){
b.Form.post(lock_comments_button.attr('data-action')).done
})
})
}
fav_btn = $('.profile-post-button') fav_btn = $('.profile-post-button')
if(fav_btn.length) { if(fav_btn.length) {
if(fav_btn.hasClass('done')) { if(fav_btn.hasClass('done')) {
@@ -3355,9 +3464,6 @@ mode_post = 0;
$('input[name=color]').val(color); $('input[name=color]').val(color);
} }
}); });
$('div.form-buttons > input').click(function(a) {
$('.color-thing').spectrum('destroy');
});
}); });
$('.color-thing2').click(function(a) { $('.color-thing2').click(function(a) {
a.preventDefault(); a.preventDefault();
@@ -3365,14 +3471,16 @@ mode_post = 0;
color: $('input[name=theme]'), color: $('input[name=theme]'),
preferredFormat: "hex", preferredFormat: "hex",
showInput: true, showInput: true,
//clickoutFiresChange: false,
flat: true, flat: true,
change: function(color) { change: function(color) {
if(!$('.color-thing2').is(':visible')) {
$('.current-theme').attr('style', 'color:' + color); $('.current-theme').attr('style', 'color:' + color);
$('input[name=theme]').val(color); $('input[name=theme]').val(color);
window.mainColor = color.toString().substring(1);
changeThemeColor();
}
} }
});
$('div.form-buttons > input').click(function(a) {
$('.color-thing2').spectrum('destroy');
}); });
}); });
// } // }
@@ -3383,9 +3491,18 @@ mode_post = 0;
, e = d.closest("form"); , e = d.closest("form");
b.Form.isDisabled(d) || c.isDefaultPrevented() || (c.preventDefault(), b.Form.isDisabled(d) || c.isDefaultPrevented() || (c.preventDefault(),
b.Form.submit(e, d).done(function() { b.Form.submit(e, d).done(function() {
b.Net.reload() $('.color-thing').spectrum();
$('.color-thing2').spectrum();
b.Net.reload();
var updateAvatar = function() { var updateAvatar = function() {
a('#global-menu-mymenu .icon-container img').attr('src', a('#sidebar-profile-body .icon').attr('src')); a('#global-menu-mymenu .icon-container img').attr('src', a('#sidebar-profile-body .icon').attr('src'));
var them = a('[name=theme]').val();
if(them === 'None') {
toDefault();
} else {
window.mainColor = them.substring(1);
changeThemeColor();
}
a(document).off("pjax:complete", updateAvatar); a(document).off("pjax:complete", updateAvatar);
} }
a(document).on("pjax:complete", updateAvatar); a(document).on("pjax:complete", updateAvatar);
-141
View File
@@ -1,141 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
version="1.1"
id="svg1"
width="130"
height="130"
viewBox="0 0 130 130"
sodipodi:docname="backgroundclear.svg"
inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
xml:space="preserve"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"><defs
id="defs1"><inkscape:path-effect
effect="fillet_chamfer"
id="path-effect5"
is_visible="true"
lpeversion="1"
nodesatellites_param="C,0,0,1,0,8,0,1 @ C,0,0,1,0,8,0,1 @ C,0,0,1,0,8,0,1 @ C,0,0,1,0,8,0,1"
radius="8"
unit="px"
method="auto"
mode="F"
chamfer_steps="1"
flexible="false"
use_knot_distance="true"
apply_no_radius="true"
apply_with_radius="true"
only_selected="false"
hide_knots="false" /><inkscape:path-effect
effect="fillet_chamfer"
id="path-effect4"
is_visible="true"
lpeversion="1"
nodesatellites_param="C,0,0,1,0,8,0,1 @ C,0,0,1,0,8,0,1 @ C,0,0,1,0,8,0,1 @ C,0,0,1,0,8,0,1"
radius="8"
unit="px"
method="auto"
mode="F"
chamfer_steps="1"
flexible="false"
use_knot_distance="true"
apply_no_radius="true"
apply_with_radius="true"
only_selected="false"
hide_knots="false" /><inkscape:path-effect
effect="fillet_chamfer"
id="path-effect3"
is_visible="true"
lpeversion="1"
nodesatellites_param="F,0,0,1,0,11,0,1 @ F,0,0,1,0,11,0,1 @ F,0,0,1,0,11,0,1 @ F,0,0,1,0,11,0,1"
radius="11"
unit="px"
method="auto"
mode="F"
chamfer_steps="1"
flexible="false"
use_knot_distance="true"
apply_no_radius="true"
apply_with_radius="true"
only_selected="false"
hide_knots="false" /></defs><sodipodi:namedview
id="namedview1"
pagecolor="#505050"
bordercolor="#ffffff"
borderopacity="1"
inkscape:showpageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="1"
inkscape:deskcolor="#505050"
inkscape:zoom="5.08125"
inkscape:cx="63.468635"
inkscape:cy="55.694957"
inkscape:window-width="1920"
inkscape:window-height="1011"
inkscape:window-x="0"
inkscape:window-y="32"
inkscape:window-maximized="1"
inkscape:current-layer="g1"
showgrid="false"
showguides="false" /><g
inkscape:groupmode="layer"
inkscape:label="Image"
id="g1"><rect
style="opacity:1;fill:#000000;fill-opacity:0.40000001;stroke-width:0.8125"
id="rect2"
width="130"
height="130"
x="0"
y="0" /><path
style="fill:#000000;fill-opacity:0.11323686"
id="rect1"
width="65"
height="65"
x="0"
y="0"
sodipodi:type="rect"
inkscape:path-effect="#path-effect4"
d="m 8,0 h 49 l 8,8 v 49 l -8,8 H 8 L 0,57 V 8 Z" /><path
style="fill:#000000;fill-opacity:0.11323686"
id="rect1-3"
width="65"
height="65"
x="65"
y="65"
inkscape:path-effect="#path-effect5"
sodipodi:type="rect"
d="m 73,65 h 49 l 8,8 v 49 l -8,8 H 73 l -8,-8 V 73 Z" /><image
width="128"
height="128"
preserveAspectRatio="none"
xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAEpElEQVR4nO2dW3LiQBAEE8kmOPae
2w7j/ZjFa0CAHi1N16jqABMZlf2pKB1Op9MfgnI8Hun7Puq5q5zPZz4+Pvj+/g55z6yFs4t6zIWW
qLBeOEMOwIWWqLD+5lx8AC60RIX1lnPRAbjQEhXWIc7ZB+BCS1RYH3HOOgAXWqLC+oxz8gG40BIV
1leckw7AhZaosI7hHH0ALrREhXUs56gDcKElKqxTOF8egAstUWGdyvn0AFxoiQrrHM6HB+BCS1RY
53IOHoALLVFhXcJ5dwAutESFdSnn1QG40BIV1gjOnwNwoSUqrFGcHbjQS1RYIzk7F1qiwhrN2e29
UNBhXYPzLeSlm3x9ffH5+Zm+UNi3/L7v4z4KvcTydeTDwk/CbmP5WvIh8AAsX08+BB2A5WvKh4AD
OJ/Plh+cLTkXHYBKoaDDujXn7ANQKRR0WGtwzjoAlUJBh7UW5+QDUCkUdFhrck46AJVCQYe1Nufo
A6gNOiUqrBk4Rx1ABtCxUWHNwvnyALKAjokKaybOpweQCfRVVFizcT48gGygz6LCmpFz8AAygj6K
CmtWzrsDyAo6FBXWzJxXB5AZ9DYqrNk5fw4gO+jvqLAqcHagAXqJCqsKZ6cCCjqlqnACdCqgKqWq
cEL5kqtTAFUpVYUTinxPxQZGhRP+y4eAbwItX4cTruWDp2IXR4UT7uWDp2IXRYUThuWDp2JnR4UT
HssHT8XOigonPJcPnoqdHBVOeC0fPBU7KSqcME4+eCp2dFQ4Ybx88FTsqKhwwjT54KnYl1HhhOny
wVOxT6PCCfPkg6diH0aFE+bLB0/FDkaFE5bJB0/F3kWFE5bLB0/FXkWFE2Lkg6dif6LCCXHywVOx
gA4nxMo/HA6eilXhhHj5x+MxfikUdEpV4YSV5Hdd/AGolKrCCevJh+CpWJVSVThhXfkQeAAqpapw
wvryIegAVEpV4YRt5EPQVKxCqSqcsJ182MlUrAonbCsfdjAVq8IJ28uHxqdiVTihjnxoeCpWhRPq
yYdGp2JVOKGufGhwKlaFE+rLh8amYlU4IYd8aGgqVoUT8siHRqZiVTghl3xoYCpWhRPyyQfxqVgV
TsgpH4SnYlU4Ia98EJ2KVeGE3PJBcCpWhRPyywexqVgVTtCQD/Cm8t9fy1/l+106y4+NknyJqVjL
X09++qlYy19XPiSeirX89eVD0qlYy99GPiScirX87eRDsqlYy99WPiSairX87eVDkqlYy68jHxJM
xVp+PflQeSrW8uvKh4pTsZZfXz5Umoq1/BzyocJUrOXnkQ8bT8Vafi75sOFUrOXnkw8bTcVafk75
sMFUrOXnlQ8rT8Vafm75sOJUrOXnl7/aVKzla8h/f3/f71IoWH7f97yFvPgvlq8hf5WpWMvXkw87
WwoFyw+firV8Xfmwk6VQsPzwqVjL15cPjS+FguWHT8VafjvyodGlULD88KlYy29PPjS2FAr1C52S
DKzNLIVCjkLHJgtrE0uhkKfQMcnEKr8UCrkKfZVsrNJLoZCv0GfJyCq7FAo5C32UrKySS6GQt9Ch
ZGaVWwqF3IXeJjur1FIo5C/0dxRYO8vfr3yAv3rECG2I4F0DAAAAAElFTkSuQmCC
"
id="image3405"
x="-149.11778"
y="16" /></g></svg>

Before

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 429 B

-129
View File
@@ -1,129 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
version="1.1"
id="svg1"
width="160"
height="160"
viewBox="0 0 160 160"
sodipodi:docname="background.svg"
inkscape:version="1.3 (0e150ed6c4, 2023-07-21)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs1">
<inkscape:path-effect
effect="fillet_chamfer"
id="path-effect5"
is_visible="true"
lpeversion="1"
nodesatellites_param="C,0,0,1,0,8,0,1 @ C,0,0,1,0,8,0,1 @ C,0,0,1,0,8,0,1 @ C,0,0,1,0,8,0,1"
radius="8"
unit="px"
method="auto"
mode="F"
chamfer_steps="1"
flexible="false"
use_knot_distance="true"
apply_no_radius="true"
apply_with_radius="true"
only_selected="false"
hide_knots="false" />
<inkscape:path-effect
effect="fillet_chamfer"
id="path-effect4"
is_visible="true"
lpeversion="1"
nodesatellites_param="C,0,0,1,0,8,0,1 @ C,0,0,1,0,8,0,1 @ C,0,0,1,0,8,0,1 @ C,0,0,1,0,8,0,1"
radius="8"
unit="px"
method="auto"
mode="F"
chamfer_steps="1"
flexible="false"
use_knot_distance="true"
apply_no_radius="true"
apply_with_radius="true"
only_selected="false"
hide_knots="false" />
<inkscape:path-effect
effect="fillet_chamfer"
id="path-effect3"
is_visible="true"
lpeversion="1"
nodesatellites_param="F,0,0,1,0,11,0,1 @ F,0,0,1,0,11,0,1 @ F,0,0,1,0,11,0,1 @ F,0,0,1,0,11,0,1"
radius="11"
unit="px"
method="auto"
mode="F"
chamfer_steps="1"
flexible="false"
use_knot_distance="true"
apply_no_radius="true"
apply_with_radius="true"
only_selected="false"
hide_knots="false" />
</defs>
<sodipodi:namedview
id="namedview1"
pagecolor="#505050"
bordercolor="#ffffff"
borderopacity="1"
inkscape:showpageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="1"
inkscape:deskcolor="#505050"
inkscape:zoom="2.540625"
inkscape:cx="-35.621156"
inkscape:cy="65.535055"
inkscape:window-width="1920"
inkscape:window-height="1011"
inkscape:window-x="0"
inkscape:window-y="32"
inkscape:window-maximized="1"
inkscape:current-layer="g1" />
<g
inkscape:groupmode="layer"
inkscape:label="Image"
id="g1">
<image
width="160"
height="160"
preserveAspectRatio="none"
xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHgAAAB4CAIAAAC2BqGFAAAABmJLR0QAFgAWACbcRYNiAAAACXBI&#10;WXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4QkQChoXcqytowAAATpJREFUeNrt3MEJwzAQRFFn8MlV&#10;uIT0X5jPqSEgLVr5/QLC7DskYII/9/095vQ8z9Gt67omfXIOlQQaNGiBBg0aAWjQAg0atECDFmjQ&#10;oAUatECDBi3QoLUIdMd/z0ydHco140O55oRQrjkklGvOOct05v1Rc57mQJy8WblyWN6sXDkvL1cu&#10;GxnKNVNDuWawZx1FgQYNWqBBg0YAGrRAgwYt0KAFGjRogQYt0KBBCzRogQYNWqBBCzRo0AINWqBB&#10;gxZo0AINGrRAgxZo0KAFGrSWgG73Grypg9N3eq+p6X5Al5HZ44z152WnY1Yedg58B1nZez7LGoiT&#10;NWdtpjz+q2Mb6+GHZP2JGyjP+jFsbT1pfHrNbap8eNZRFmjQoAUaNGgEoEELNGjQAg1aoEGDFmjQ&#10;Ag0atECD1p/9AKkzTyh2EOP+AAAAAElFTkSuQmCC&#10;"
id="image1"
x="-167.89395"
y="0" />
<rect
style="fill:#161626;fill-opacity:1"
id="rect2"
width="160"
height="160"
x="0"
y="0" />
<path
style="fill:#202030;fill-opacity:1"
id="rect1"
width="80"
height="80"
x="0"
y="0"
sodipodi:type="rect"
inkscape:path-effect="#path-effect4"
d="m 8,0 h 64 l 8,8 v 64 l -8,8 H 8 L 0,72 V 8 Z" />
<path
style="fill:#202030;fill-opacity:1"
id="rect1-3"
width="80"
height="80"
x="80"
y="80"
inkscape:path-effect="#path-effect5"
sodipodi:type="rect"
d="m 88,80 h 64 l 8,8 v 64 l -8,8 H 88 l -8,-8 V 88 Z" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 523 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 359 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 669 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 339 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 381 B

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 538 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 409 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 367 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 519 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 524 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 527 B

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 389 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 319 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 387 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 631 B