first commit
This commit is contained in:
commit
20f7c7234f
21 changed files with 614 additions and 0 deletions
17
.gitignore
vendored
Normal file
17
.gitignore
vendored
Normal file
|
@ -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
|
0
README.md
Normal file
0
README.md
Normal file
0
ubottu/factoids/__init__.py
Normal file
0
ubottu/factoids/__init__.py
Normal file
26
ubottu/factoids/admin.py
Normal file
26
ubottu/factoids/admin.py
Normal file
|
@ -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)
|
6
ubottu/factoids/apps.py
Normal file
6
ubottu/factoids/apps.py
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class FactoidsConfig(AppConfig):
|
||||||
|
default_auto_field = 'django.db.models.BigAutoField'
|
||||||
|
name = 'factoids'
|
9
ubottu/factoids/forms.py
Normal file
9
ubottu/factoids/forms.py
Normal file
|
@ -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}),
|
||||||
|
}
|
34
ubottu/factoids/models.py
Normal file
34
ubottu/factoids/models.py
Normal file
|
@ -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)
|
12
ubottu/factoids/serializers.py
Normal file
12
ubottu/factoids/serializers.py
Normal file
|
@ -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
|
107
ubottu/factoids/static/factoids/css/styles.css
Normal file
107
ubottu/factoids/static/factoids/css/styles.css
Normal file
|
@ -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 */
|
||||||
|
}
|
BIN
ubottu/factoids/static/factoids/images/favicon.ico
Normal file
BIN
ubottu/factoids/static/factoids/images/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
50
ubottu/factoids/templates/factoids/base.html
Normal file
50
ubottu/factoids/templates/factoids/base.html
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
{% load static %}
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
|
||||||
|
<link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-icons/1.7.2/font/bootstrap-icons.min.css" rel="stylesheet">
|
||||||
|
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Open+Sans:wght@400;600&display=swap" rel="stylesheet">
|
||||||
|
<link rel="stylesheet" type="text/css" href="{% static 'factoids/css/styles.css' %}">
|
||||||
|
<link rel="icon" href="{% static 'factoids/images/favicon.ico' %}" type="image/x-icon">
|
||||||
|
<title>{% block title %}Factoids{% endblock %}</title>
|
||||||
|
<script>
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
const themeToggleButton = document.getElementById('theme-toggle');
|
||||||
|
const currentTheme = localStorage.getItem('theme') || 'light';
|
||||||
|
|
||||||
|
if (currentTheme === 'dark') {
|
||||||
|
document.body.classList.add('dark-theme');
|
||||||
|
themeToggleButton.classList.add('active');
|
||||||
|
}
|
||||||
|
|
||||||
|
themeToggleButton.addEventListener('click', function() {
|
||||||
|
document.body.classList.toggle('dark-theme');
|
||||||
|
themeToggleButton.classList.toggle('active');
|
||||||
|
localStorage.setItem('theme', document.body.classList.contains('dark-theme') ? 'dark' : 'light');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header>
|
||||||
|
<h1>Factoids</h1>
|
||||||
|
<!-- Navigation, etc. -->
|
||||||
|
</header>
|
||||||
|
<div class="theme-toggle-container">
|
||||||
|
<button id="theme-toggle" class="btn toggle-switch">
|
||||||
|
<span class="switch"></span>
|
||||||
|
</button>
|
||||||
|
<span class="toggle-description">Dark Mode</span>
|
||||||
|
</div>
|
||||||
|
<main>
|
||||||
|
{% block content %}
|
||||||
|
{% endblock content %}
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
<!-- Footer content -->
|
||||||
|
</footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
48
ubottu/factoids/templates/factoids/list_facts.html
Normal file
48
ubottu/factoids/templates/factoids/list_facts.html
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
{% extends "factoids/base.html" %}
|
||||||
|
{% block content %}
|
||||||
|
<script>
|
||||||
|
$(document).ready(function() {
|
||||||
|
$('.expandable').click(function() {
|
||||||
|
$(this).toggleClass('expanded');
|
||||||
|
if ($(this).hasClass('expanded')) {
|
||||||
|
$(this).css({'max-height': 'none', 'white-space': 'normal'});
|
||||||
|
} else {
|
||||||
|
$(this).css({'max-height': '20px', 'white-space': 'nowrap'});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<div class="container mt-3">
|
||||||
|
<h2>Facts List</h2>
|
||||||
|
<div class="table-responsive"> <!-- Make table responsive -->
|
||||||
|
<table class="table table-striped table-hover"> <!-- Add Bootstrap classes for styling -->
|
||||||
|
<thead class="thead-dark"> <!-- Use a darker theme for the table header -->
|
||||||
|
<tr>
|
||||||
|
<th><a href="?sort=name">Name</a></th>
|
||||||
|
<th>Value</th>
|
||||||
|
<th>Type</th>
|
||||||
|
<th>Author</th>
|
||||||
|
<th><a href="?sort=popularity">Popularity</a></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for fact in facts %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ fact.name }}</td>
|
||||||
|
<td class="expandable">{{ fact.value }}</td>
|
||||||
|
<td>{{ fact.get_ftype_display }}</td>
|
||||||
|
<td>{% if fact.author %}{{ fact.author.username }}{% else %}N/A{% endif %}</td>
|
||||||
|
<td>{{ fact.popularity }}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div class="alert alert-info d-flex align-items-center" role="alert">
|
||||||
|
<i class="bi bi-info-circle-fill me-2"></i>
|
||||||
|
<div>
|
||||||
|
You can get <a href="/factoids/api/facts/">all</a> or <a href="/factoids/api/facts/">single</a> facts via the API.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
3
ubottu/factoids/tests.py
Normal file
3
ubottu/factoids/tests.py
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
# Create your tests here.
|
11
ubottu/factoids/urls.py
Normal file
11
ubottu/factoids/urls.py
Normal file
|
@ -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/<str:city_name>/', views.city_time, name='citytime'),
|
||||||
|
path('api/facts/', FactList.as_view(), name='fact-list'), # For listing all facts
|
||||||
|
path('api/facts/<int:id>/', FactList.as_view(), name='fact-detail-by-id'), # For fetching by id
|
||||||
|
path('api/facts/<slug:name>/', FactList.as_view(), name='fact-detail-by-name'), # For fetching by name
|
||||||
|
]
|
93
ubottu/factoids/views.py
Normal file
93
ubottu/factoids/views.py
Normal file
|
@ -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)
|
22
ubottu/manage.py
Executable file
22
ubottu/manage.py
Executable file
|
@ -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()
|
0
ubottu/ubottu/__init__.py
Normal file
0
ubottu/ubottu/__init__.py
Normal file
16
ubottu/ubottu/asgi.py
Normal file
16
ubottu/ubottu/asgi.py
Normal file
|
@ -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()
|
135
ubottu/ubottu/settings.py
Normal file
135
ubottu/ubottu/settings.py
Normal file
|
@ -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'
|
9
ubottu/ubottu/urls.py
Normal file
9
ubottu/ubottu/urls.py
Normal file
|
@ -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'
|
||||||
|
]
|
16
ubottu/ubottu/wsgi.py
Normal file
16
ubottu/ubottu/wsgi.py
Normal file
|
@ -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()
|
Loading…
Reference in a new issue