From 20f7c7234f756f182a9509f062a6442c6c60d192 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20B=C3=BCchner?= Date: Mon, 25 Mar 2024 10:42:15 +0100 Subject: [PATCH] first commit --- .gitignore | 17 +++ README.md | 0 ubottu/factoids/__init__.py | 0 ubottu/factoids/admin.py | 26 ++++ ubottu/factoids/apps.py | 6 + ubottu/factoids/forms.py | 9 ++ ubottu/factoids/models.py | 34 +++++ ubottu/factoids/serializers.py | 12 ++ .../factoids/static/factoids/css/styles.css | 107 ++++++++++++++ .../static/factoids/images/favicon.ico | Bin 0 -> 15406 bytes ubottu/factoids/templates/factoids/base.html | 50 +++++++ .../templates/factoids/list_facts.html | 48 +++++++ ubottu/factoids/tests.py | 3 + ubottu/factoids/urls.py | 11 ++ ubottu/factoids/views.py | 93 ++++++++++++ ubottu/manage.py | 22 +++ ubottu/ubottu/__init__.py | 0 ubottu/ubottu/asgi.py | 16 +++ ubottu/ubottu/settings.py | 135 ++++++++++++++++++ ubottu/ubottu/urls.py | 9 ++ ubottu/ubottu/wsgi.py | 16 +++ 21 files changed, 614 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 ubottu/factoids/__init__.py create mode 100644 ubottu/factoids/admin.py create mode 100644 ubottu/factoids/apps.py create mode 100644 ubottu/factoids/forms.py create mode 100644 ubottu/factoids/models.py create mode 100644 ubottu/factoids/serializers.py create mode 100644 ubottu/factoids/static/factoids/css/styles.css create mode 100644 ubottu/factoids/static/factoids/images/favicon.ico create mode 100644 ubottu/factoids/templates/factoids/base.html create mode 100644 ubottu/factoids/templates/factoids/list_facts.html create mode 100644 ubottu/factoids/tests.py create mode 100644 ubottu/factoids/urls.py create mode 100644 ubottu/factoids/views.py create mode 100755 ubottu/manage.py create mode 100644 ubottu/ubottu/__init__.py create mode 100644 ubottu/ubottu/asgi.py create mode 100644 ubottu/ubottu/settings.py create mode 100644 ubottu/ubottu/urls.py create mode 100644 ubottu/ubottu/wsgi.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9db5ed9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,17 @@ +__pycache__/ +*.py[cod] +venv +olm +src +.local +.cmake +.cache +.ubottu +.bashrc +.python_history +.bash_history +.mbp +*.db +*.log +plugins/* +ubottu/maubot.db diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/ubottu/factoids/__init__.py b/ubottu/factoids/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ubottu/factoids/admin.py b/ubottu/factoids/admin.py new file mode 100644 index 0000000..6a051b0 --- /dev/null +++ b/ubottu/factoids/admin.py @@ -0,0 +1,26 @@ +from django.contrib import admin +from django.forms import ModelForm, Textarea +from .models import Fact +from .forms import FactForm + +class FactAdmin(admin.ModelAdmin): + list_display = ('name', 'value', 'ftype', 'create_date', 'change_date', 'author', 'popularity') + list_filter = ('ftype', 'create_date', 'author') # Fields to add filters for + search_fields = ('name', 'value') + form = FactForm + def get_form(self, request, obj=None, **kwargs): + # Check if an instance is being added (obj is None) to exclude 'author_id' field + if obj is None: # This means a new instance is being created + self.exclude = ('author',) + else: # Editing an existing instance + self.exclude = [] + form = super(FactAdmin, self).get_form(request, obj, **kwargs) + return form + + def save_model(self, request, obj, form, change): + if not obj.pk: # Indicates a new instance + # Automatically set 'author_id' to current user for new instances + obj.author_id = request.user.id + super().save_model(request, obj, form, change) + +admin.site.register(Fact, FactAdmin) diff --git a/ubottu/factoids/apps.py b/ubottu/factoids/apps.py new file mode 100644 index 0000000..0fcd820 --- /dev/null +++ b/ubottu/factoids/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class FactoidsConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'factoids' diff --git a/ubottu/factoids/forms.py b/ubottu/factoids/forms.py new file mode 100644 index 0000000..c2f97b8 --- /dev/null +++ b/ubottu/factoids/forms.py @@ -0,0 +1,9 @@ +from django.forms import ModelForm, Textarea +from .models import Fact +class FactForm(ModelForm): + class Meta: + model = Fact + fields = '__all__' + widgets = { + 'value': Textarea(attrs={'cols': 60, 'rows': 10}), + } \ No newline at end of file diff --git a/ubottu/factoids/models.py b/ubottu/factoids/models.py new file mode 100644 index 0000000..de87304 --- /dev/null +++ b/ubottu/factoids/models.py @@ -0,0 +1,34 @@ +from django.db import models +from django.utils import timezone +from django.contrib.auth.models import User + +# Define Author model +class Author(models.Model): + name = models.CharField(max_length=64) + +def get_sentinel_author(): + # This assumes 'Author' model is already defined as shown above + return Author.objects.get_or_create(name='deleted')[0] +class Fact(models.Model): + name = models.CharField(max_length=32) + value = models.TextField() + FTYPE_CHOICES = ( + ("REPLY", "Reply"), + ("ALIAS", "Alias") + ) + ftype = models.CharField( + max_length=32, + choices=FTYPE_CHOICES, + default="REPLY" + ) + + id = models.BigAutoField(primary_key=True) + author = models.ForeignKey(User, on_delete=models.SET_NULL, null=True) + create_date = models.DateTimeField("date published", default=timezone.now) + change_date = models.DateTimeField("date changed", default=timezone.now) + popularity = models.IntegerField(default=0) + def __str__(self): + return self.name + + def was_published_recently(self): + return self.create_date >= timezone.now() - datetime.timedelta(days=7) diff --git a/ubottu/factoids/serializers.py b/ubottu/factoids/serializers.py new file mode 100644 index 0000000..37dece8 --- /dev/null +++ b/ubottu/factoids/serializers.py @@ -0,0 +1,12 @@ +from rest_framework import serializers +from .models import Fact + +class FactSerializer(serializers.ModelSerializer): + author_name = serializers.SerializerMethodField() + class Meta: + model = Fact + fields = ['id', 'name', 'value', 'ftype', 'author_name', 'create_date', 'change_date', 'popularity'] + + def get_author_name(self, obj): + # Assuming the author field can be null + return obj.author.username if obj.author else None \ No newline at end of file diff --git a/ubottu/factoids/static/factoids/css/styles.css b/ubottu/factoids/static/factoids/css/styles.css new file mode 100644 index 0000000..984ff9d --- /dev/null +++ b/ubottu/factoids/static/factoids/css/styles.css @@ -0,0 +1,107 @@ +/* static/css/styles.css */ + +body { + font-family: 'Open Sans', sans-serif; + font-size: 10pt; +} + +.dark-theme { + background-color: #343a40; + color: #ffffff; + } + +.dark-theme .table { + color: #ffffff; + background-color: #454d55; +} + +.dark-theme .table thead th { + color: #ffffff; + background-color: #343a40; +} + +.dark-theme .table tbody tr:nth-of-type(odd) { + background-color: #454d55; +} + +/* Hover effect for light theme (or the default theme) */ +.table tbody tr:hover { + background-color: #e9ecef; /* Light grey for hover in light theme */ + color: #212529; /* Optional: Darker text color if needed */ +} + +/* Hover effect for dark theme */ +.dark-theme .table tbody tr:hover { + background-color: #5a6268; /* Darker grey for hover in dark theme */ + color: #f8f9fa; /* Lighter text color for dark theme */ +} + +/* Light theme link hover color */ +.table tbody tr:hover a { + color: #007bff; /* Bootstrap's default link color */ +} + +/* Dark theme link hover color */ +.dark-theme .table tbody tr:hover a { + color: #80bdff; /* A lighter shade for dark mode */ +} + +.expandable { + max-height: 12px; /* Adjust based on your line height */ + max-width: 420px; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + cursor: pointer; +} + +.toggle-switch { + position: relative; + display: inline-block; + width: 40px; /* Reduced from 60px */ + height: 22px; /* Reduced from 34px */ + background-color: #ccc; + border-radius: 22px; /* Match height for full roundness */ + transition: background-color .3s; +} + +.toggle-switch .switch { + position: absolute; + top: 1px; /* Adjusted for smaller size */ + left: 1px; /* Adjusted for smaller size */ + width: 20px; /* Reduced from 30px */ + height: 20px; /* Reduced from 30px */ + background-color: white; + border-radius: 50%; + transition: transform .3s; +} + +.toggle-switch.active { + background-color: #4CAF50; +} + +.toggle-switch.active .switch { + transform: translateX(18px); /* Adjusted to fit the smaller toggle size */ +} + +.theme-toggle-container { + display: flex; + align-items: center; /* Aligns the button and text vertically */ + gap: 10px; /* Adds some space between the button and the text */ + font-family: 'Open Sans', sans-serif; /* This should match the font you've chosen */ +} + +.toggle-description { + font-size: 16px; /* Adjust as needed */ + color: #333; /* Adjust based on your light theme color */ + font-weight: 600; /* Makes the font slightly bolder */ +} + +/* Additional styles for dark theme */ +.dark-theme .toggle-description { + color: #fff; /* Adjust based on your dark theme color */ +} + +.bi-info-circle-fill { + font-size: 2rem; /* Adjust the size as needed */ +} \ No newline at end of file diff --git a/ubottu/factoids/static/factoids/images/favicon.ico b/ubottu/factoids/static/factoids/images/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..ca23307bae5353905d7a381511ffee69cc0039b1 GIT binary patch literal 15406 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 literal 0 HcmV?d00001 diff --git a/ubottu/factoids/templates/factoids/base.html b/ubottu/factoids/templates/factoids/base.html new file mode 100644 index 0000000..e748e82 --- /dev/null +++ b/ubottu/factoids/templates/factoids/base.html @@ -0,0 +1,50 @@ +{% load static %} + + + + + + + + + + {% block title %}Factoids{% endblock %} + + + +
+

Factoids

+ +
+
+ + Dark Mode +
+
+ {% block content %} + {% endblock content %} +
+ +
+ +
+ + diff --git a/ubottu/factoids/templates/factoids/list_facts.html b/ubottu/factoids/templates/factoids/list_facts.html new file mode 100644 index 0000000..9201e7f --- /dev/null +++ b/ubottu/factoids/templates/factoids/list_facts.html @@ -0,0 +1,48 @@ +{% extends "factoids/base.html" %} +{% block content %} + +
+

Facts List

+
+ + + + + + + + + + + + {% for fact in facts %} + + + + + + + + {% endfor %} + +
NameValueTypeAuthorPopularity
{{ fact.name }}{{ fact.get_ftype_display }}{% if fact.author %}{{ fact.author.username }}{% else %}N/A{% endif %}{{ fact.popularity }}
+
+ +
+{% endblock %} diff --git a/ubottu/factoids/tests.py b/ubottu/factoids/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/ubottu/factoids/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/ubottu/factoids/urls.py b/ubottu/factoids/urls.py new file mode 100644 index 0000000..54373c4 --- /dev/null +++ b/ubottu/factoids/urls.py @@ -0,0 +1,11 @@ +from django.urls import path +from .views import FactList +from . import views + +urlpatterns = [ + path('', views.list_facts, name='facts-list'), + path('api/citytime//', views.city_time, name='citytime'), + path('api/facts/', FactList.as_view(), name='fact-list'), # For listing all facts + path('api/facts//', FactList.as_view(), name='fact-detail-by-id'), # For fetching by id + path('api/facts//', FactList.as_view(), name='fact-detail-by-name'), # For fetching by name +] diff --git a/ubottu/factoids/views.py b/ubottu/factoids/views.py new file mode 100644 index 0000000..fecb491 --- /dev/null +++ b/ubottu/factoids/views.py @@ -0,0 +1,93 @@ +from django.http import HttpResponse, Http404 +from rest_framework.views import APIView +from rest_framework.decorators import api_view +from rest_framework.response import Response +from .models import Fact +from .serializers import FactSerializer +from django.shortcuts import render +from geopy.geocoders import Nominatim +from timezonefinder import TimezoneFinder +from datetime import datetime +from rest_framework import status +import pytz +import json + +def index(request): + return HttpResponse("Hello, world. You're at the factoids index.") + +@api_view(['GET']) +def city_time(request, city_name): + try: + geolocator = Nominatim(user_agent="Ubottu", timeout=10) + location = geolocator.geocode(city_name, exactly_one=True, language='en') + if location is None: + # If the location wasn't found, return an appropriate response + return Response({'error': 'Location not found'}, status=status.HTTP_404_NOT_FOUND) + + tf = TimezoneFinder() + timezone_str = tf.timezone_at(lat=location.latitude, lng=location.longitude) # Get the timezone name + + if timezone_str is None: + # If the timezone wasn't found, return an appropriate response + return Response({'error': 'Timezone not found for the given location'}, status=status.HTTP_404_NOT_FOUND) + + timezone = pytz.timezone(timezone_str) + datetime_obj = datetime.now(timezone) + local_time = datetime_obj.strftime('%A, %d %B %Y, %H:%M') + city_name = str(location).split(',')[0] + data = {'location': str(location), 'city': city_name, 'local_time': local_time} + return Response(data) + except Exception as e: + # Log the exception if needed + print(f"Error processing request for city {city_name}: {str(e)}") + # Return a JSON response indicating an error occurred + # Returning False directly is not recommended for API responses + return Response({'error': 'An error occurred processing your request'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) + + +def list_facts(request): + #facts = Fact.objects.all() + sort_by = request.GET.get('sort', 'name') # Default sort by 'name' + allowed_sorts = ['name', 'ftype', 'popularity'] + if sort_by not in allowed_sorts: + sort_by = 'name' # Fallback to a safe default + if sort_by == 'popularity': + facts = Fact.objects.order_by('-popularity', 'name') + else: + facts = Fact.objects.order_by(sort_by) + return render(request, 'factoids/list_facts.html', {'facts': facts}) + +class FactList(APIView): + """ + List all Fact items or retrieve a single Fact item by name or id. + """ + def get(self, request, *args, **kwargs): + # Check if an 'id' parameter is provided in the URL. + fact_id = kwargs.get('id') + # Check if a 'name' parameter is provided in the URL. + name = kwargs.get('name') + + if fact_id: + # Fetching the Fact item by id. + try: + fact = Fact.objects.get(id=fact_id) + except Fact.DoesNotExist: + raise Http404("Fact not found") + elif name: + # Fetching the Fact item by name. + try: + fact = Fact.objects.get(name=name) + fact.popularity += 1 # Increment popularity + fact.save(update_fields=['popularity']) # Save the change + except Fact.DoesNotExist: + raise Http404("Fact not found") + else: + # If neither 'id' nor 'name' is provided, you might want to list all facts + # or handle the situation differently (e.g., return an error response). + facts = Fact.objects.all() + serializer = FactSerializer(facts, many=True) + return Response(serializer.data) + + # Serializing the retrieved Fact item. + serializer = FactSerializer(fact) + return Response(serializer.data) \ No newline at end of file diff --git a/ubottu/manage.py b/ubottu/manage.py new file mode 100755 index 0000000..9e06365 --- /dev/null +++ b/ubottu/manage.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +"""Django's command-line utility for administrative tasks.""" +import os +import sys + + +def main(): + """Run administrative tasks.""" + os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'ubottu.settings') + try: + from django.core.management import execute_from_command_line + except ImportError as exc: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from exc + execute_from_command_line(sys.argv) + + +if __name__ == '__main__': + main() diff --git a/ubottu/ubottu/__init__.py b/ubottu/ubottu/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ubottu/ubottu/asgi.py b/ubottu/ubottu/asgi.py new file mode 100644 index 0000000..f5d1cde --- /dev/null +++ b/ubottu/ubottu/asgi.py @@ -0,0 +1,16 @@ +""" +ASGI config for ubottu project. + +It exposes the ASGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/5.0/howto/deployment/asgi/ +""" + +import os + +from django.core.asgi import get_asgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'ubottu.settings') + +application = get_asgi_application() diff --git a/ubottu/ubottu/settings.py b/ubottu/ubottu/settings.py new file mode 100644 index 0000000..0e4e45b --- /dev/null +++ b/ubottu/ubottu/settings.py @@ -0,0 +1,135 @@ +""" +Django settings for ubottu project. + +Generated by 'django-admin startproject' using Django 5.0.3. + +For more information on this file, see +https://docs.djangoproject.com/en/5.0/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/5.0/ref/settings/ +""" + +from pathlib import Path + +# Build paths inside the project like this: BASE_DIR / 'subdir'. +BASE_DIR = Path(__file__).resolve().parent.parent + + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/5.0/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = 'aekeijahsheik8AhghaiDie5awuen3ahvaeHeeyirahsaic4einaePeiyoophahd' + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +ALLOWED_HOSTS = ['*'] + +REST_FRAMEWORK = { + 'DEFAULT_RENDERER_CLASSES': [ + 'rest_framework.renderers.JSONRenderer', + ], +} + +# Application definition + +INSTALLED_APPS = [ + 'rest_framework', + 'factoids.apps.FactoidsConfig', + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', +] + +MIDDLEWARE = [ + 'django.middleware.security.SecurityMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', +] + +ROOT_URLCONF = 'ubottu.urls' + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [BASE_DIR / 'templates'], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + ], + }, + }, +] + +WSGI_APPLICATION = 'ubottu.wsgi.application' + + +# Database +# https://docs.djangoproject.com/en/5.0/ref/settings/#databases + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.mysql', + 'HOST': '127.0.0.1', + 'USER': 'ubottu', + 'PASSWORD': 'iyoiyiG7Kahy', + 'NAME': 'ubottu' + } +} + + +# Password validation +# https://docs.djangoproject.com/en/5.0/ref/settings/#auth-password-validators + +AUTH_PASSWORD_VALIDATORS = [ + { + 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + }, +] + + +# Internationalization +# https://docs.djangoproject.com/en/5.0/topics/i18n/ + +LANGUAGE_CODE = 'en-us' + +TIME_ZONE = 'UTC' + +USE_I18N = True + +USE_TZ = True + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/5.0/howto/static-files/ + +STATIC_URL = 'static/' +#STATIC_ROOT = "/home/maubot/ubottu-web/static/" +STATICFILES_DIRS = [BASE_DIR / 'static'] + +# Default primary key field type +# https://docs.djangoproject.com/en/5.0/ref/settings/#default-auto-field + +DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' diff --git a/ubottu/ubottu/urls.py b/ubottu/ubottu/urls.py new file mode 100644 index 0000000..61a2b75 --- /dev/null +++ b/ubottu/ubottu/urls.py @@ -0,0 +1,9 @@ +from django.contrib import admin +from django.urls import include, path +from django.shortcuts import redirect + +urlpatterns = [ + path("factoids/", include("factoids.urls")), + path("admin/", admin.site.urls), + path('', lambda request: redirect('factoids/', permanent=False)), # Redirect from root to 'factoids' +] \ No newline at end of file diff --git a/ubottu/ubottu/wsgi.py b/ubottu/ubottu/wsgi.py new file mode 100644 index 0000000..f1d8832 --- /dev/null +++ b/ubottu/ubottu/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for ubottu project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/5.0/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'ubottu.settings') + +application = get_wsgi_application()