Merge pull request 'testing' (#14) from testing into main
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 14m51s

Reviewed-on: #14
This commit was merged in pull request #14.
This commit is contained in:
2026-06-25 21:24:06 +00:00
31 changed files with 511 additions and 124 deletions
+1
View File
@@ -226,3 +226,4 @@ __marimo__/
Webcal-python/*
.idea/*
django_code/db.sqlite3
+2
View File
@@ -8,11 +8,13 @@ python django_code/manage.py makemigrations
python django_code/manage.py makemigrations redirect
python django_code/manage.py makemigrations cloudmanager
python django_code/manage.py makemigrations simpsons
python django_code/manage.py makemigrations job
python django_code/manage.py migrate
python django_code/manage.py migrate --database=cloudmanager_db
python django_code/manage.py migrate --database=simpsons_db
python django_code/manage.py migrate --database=redirect_db
python django_code/manage.py migrate --database=job_db
```
### Database debug
+105
View File
@@ -0,0 +1,105 @@
import requests
import hashlib
from apps.bitwarden.utils import bitwardenUtils
class betaserieUtils():
url = "https://api.betaseries.com/members/auth"
username_UID="7bc7ebd2-9c95-487f-9ba2-b47301591ef0"
password_UID="262c3246-203b-44e0-854b-b47301599730"
token_UID="2cf4be0f-f26f-473f-b8f1-b473016139e4"
#Adding __ to make the variable private and can't be access outside the class,
# only by the class itself ot the subclass
__access_token = "0.7720f24b-4328-41ef-b70b-b419018270a3.nhBoRMSkfrlxqJVZ9W0W1g3lNFrmfI:35muVQz2mO3coR46bIZgcQ=="
__organization_id = "a6361589-badd-4bde-9cb4-af8901161c0d"
bw = bitwardenUtils(__access_token,__organization_id)
__betaserie_username = bw.read_value_secret(username_UID)
__betaserie_md5_password = bw.read_value_secret(password_UID)
__betaserie_apikey = bw.read_value_secret(token_UID)
payload = {
'login': __betaserie_username, # username or email
'password': __betaserie_md5_password # MD5 hashed password
}
headers = {
'X-BetaSeries-Key': __betaserie_apikey,
}
response = requests.post(url, headers=headers, data=payload)
#now set with the correct value
__betaserie_token = response.json()['token']
#set the __betaserie_token to the doct headers now
headers.update({'X-BetaSeries-Token': __betaserie_token})
def status_code(self):
print("Status code:", self.response.status_code)
print("Response:", self.response.json())
def identify_serie(self,serie_name,verbose=False):
#
# Usage
# show_id = beta.identify_serie("The simpsons")
# show_id = beta.identify_serie("The simpsons",verbose=True)
#
url = "https://api.betaseries.com/shows/search?title="+serie_name
response = requests.request("GET", url, headers=self.headers, data=self.payload)
if verbose:
print("Url request: "+str(url))
print(response.text)
show_id = response.json()['shows'][0]['id']
return show_id
def identify_episode(self,show_id,episode_number,verbose=False):
#
# Usage
# episode_id = beta.identify_episode(show_id,"S01E01",True)
#
url = "https://api.betaseries.com/episodes/search?show_id="+str(show_id)+"&number="+str(episode_number)
response = requests.request("GET", url, headers=self.headers, data=self.payload)
episode_id = response.json()['episode']['id']
if verbose:
print("Url request: "+str(url))
print(response.text)
return episode_id
def mark_episodes_watched(self,episode_id,verbose=False):
#
# Usage
# response = beta.mark_episodes_watched(episode_id,True)
#
url = "https://api.betaseries.com/episodes/watched?id="+str(episode_id)+"&bulk=false"
response = requests.request("POST", url, headers=self.headers, data=self.payload)
if verbose:
print("Url request: "+str(url))
print(response.text)
return response.status_code
def unmark_episodes_watched(self,episode_id,verbose=False):
#
# Usage
# response = beta.unmark_episodes_watched(episode_id,True)
#
url = "https://api.betaseries.com/episodes/watched?id="+str(episode_id)
response = requests.request("DELETE", url, headers=self.headers, data=self.payload)
if verbose:
print("Url request: "+str(url))
print(response.text)
return response.status_code
+87
View File
@@ -0,0 +1,87 @@
import logging
import os
from datetime import datetime, timezone
from bitwarden_sdk import BitwardenClient, DeviceType, client_settings_from_dict
class bitwardenUtils():
#documentation
#https://github.com/external-secrets/bitwarden-sdk-server
state_path = "/tmp/state_file.txt"
client = BitwardenClient(
client_settings_from_dict(
{
"apiUrl": os.getenv("API_URL", "https://bitwarden.tryton.geeraert.eu/api"),
"deviceType": DeviceType.SDK,
"identityUrl": os.getenv("IDENTITY_URL", "https://bitwarden.tryton.geeraert.eu/identity"),
"userAgent": "Python",
}
)
)
def verbose(self):
logging.basicConfig(level=logging.DEBUG)
def __init__(self, __access_token, __organization_id):
self.__access_token = __access_token
self.__organization_id = __organization_id
self.client.auth().login_access_token(self.__access_token, self.state_path)
def create_project(self,project_name):
project = self.client.projects().create(self.__organization_id, project_name)
return project.data.id
def generate_strong_password(self):
# Note: using the generator does not require authentication with a server
return self.client.generators().generate() # using default params
def create_secret(self,project_id,secret_name,secret_value,description="description"):
secret = self.client.secrets().create(
self.__organization_id,
secret_name,
secret_value,
description,
[project_id],
)
return secret.data.id
def read_value_secret(self,secret_id):
return self.client.secrets().get_by_ids([secret_id]).data.data[0].value
def read_value_secrets(self,list_secret_id):
if not(isinstance(list_secret_id, list)):
print("this is not a list")
return 1
list_secret_value = []
for secret_value in self.client.secrets().get_by_ids(list_secret_id).data.data:
list_secret_value.append(secret_value.value)
return list_secret_value
def delete_secrets(self,list_secret_id):
if not(isinstance(list_secret_id, list)):
print("this is not a list")
return 1
try:
self.client.secrets().delete(list_secret_id)
status=0
except:
print("Cannot delete the secrets")
status=1
return status
def delete_projects(self,list_project_id):
if not(isinstance(list_project_id, list)):
print("this is not a list")
return 1
try:
self.client.projects().delete(list_project_id)
status=0
except:
print("Cannot delete the project")
status=1
return status
@@ -1,4 +1,4 @@
# Generated by Django 4.2.30 on 2026-06-17 13:00
# Generated by Django 4.2.29 on 2026-06-22 20:21
from django.db import migrations, models
import django.db.models.deletion
@@ -12,6 +12,16 @@ class Migration(migrations.Migration):
]
operations = [
migrations.CreateModel(
name='Namespace_Data',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('namespace', models.CharField(max_length=100)),
],
options={
'db_table': 'namespace',
},
),
migrations.CreateModel(
name='Schedule_Day_Data',
fields=[
@@ -64,7 +74,7 @@ class Migration(migrations.Migration):
},
),
migrations.CreateModel(
name='Machine_Data',
name='Deployment_Data',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=100)),
@@ -1,23 +0,0 @@
# Generated by Django 4.2.30 on 2026-06-19 14:47
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('cloudmanager', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='Namespace_Data',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('namespace', models.CharField(max_length=100)),
],
options={
'db_table': 'namespace',
},
),
]
@@ -1,17 +0,0 @@
# Generated by Django 4.2.30 on 2026-06-19 14:49
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('cloudmanager', '0002_namespace_data'),
]
operations = [
migrations.RenameModel(
old_name='Machine_Data',
new_name='Deployment_Data',
),
]
+40
View File
@@ -0,0 +1,40 @@
from django.contrib import admin
from import_export.admin import ImportExportModelAdmin
from import_export import resources
from import_export.fields import Field
from .models import JobData
from django.utils.text import Truncator
# Register your models here.
class JobResource(resources.ModelResource):
# Map 'csv_column_name' from the file to 'model_variable_name' in your DB
job_position = Field(attribute='job_position',column_name='Job Position')
company = Field(attribute='company',column_name='Company')
URL = Field(attribute='URL',column_name='URL')
status = Field(attribute='status',column_name='Status')
date_saved = Field(attribute='date_saved',column_name='Date Saved')
date_applied = Field(attribute='date_applied',column_name='Date Applied')
type = Field(attribute='type',column_name='Type')
resume = Field(attribute='resume',column_name='Resume')
#cover_letter = Field(attribute='cover_letter',column_name='Cover Letter')
location = Field(attribute='location',column_name='Location')
job_description = Field(attribute='job_description',column_name='Job Description')
salary = Field(attribute='salary',column_name='Salary')
contact = Field(attribute='contact',column_name='Contact')
source = Field(attribute='source',column_name='Source')
class Meta:
model = JobData
@admin.register(JobData)
class JobAdmin(ImportExportModelAdmin):
list_display = ('job_position','company','URL','status','date_saved','date_applied','type','resume','location','short_description','salary','contact','source')
#fields = ['job_position','company','URL','status','date_saved','date_applied','type','resume','cover_letter','location','job_description','salary ','contact','source']
resource_classes = [JobResource]
def short_description(self, obj):
return Truncator(obj.job_description).words(10, truncate=' ...')
+6
View File
@@ -0,0 +1,6 @@
from django.apps import AppConfig
class JobDashboardConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'apps.job_dashboard'
label = 'job'
File diff suppressed because one or more lines are too long
@@ -0,0 +1,36 @@
# Generated by Django 4.2.29 on 2026-06-22 20:21
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='JobData',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('job_position', models.CharField(max_length=100, null=True)),
('company', models.CharField(max_length=100, null=True)),
('URL', models.URLField(max_length=1000, null=True)),
('status', models.CharField(choices=[('Rejected', 'Rejected'), ('Applied', 'Applied'), ('Negotiating', 'Negotiating'), ('Bookmarked', 'Bookmarked'), ('Accepted', 'Accepted')], max_length=100, null=True)),
('date_saved', models.CharField(max_length=100, null=True)),
('date_applied', models.CharField(max_length=100, null=True)),
('type', models.CharField(max_length=100, null=True)),
('resume', models.URLField(null=True)),
('location', models.CharField(max_length=100, null=True)),
('job_description', models.CharField(null=True)),
('salary', models.CharField(null=True)),
('contact', models.CharField(max_length=100, null=True)),
('source', models.CharField(max_length=100, null=True)),
],
options={
'db_table': 'job',
},
),
]
+29
View File
@@ -0,0 +1,29 @@
from django.db import models
status_CHOICES = (
('Rejected','Rejected'),
('Applied','Applied'),
('Negotiating','Negotiating'),
('Bookmarked','Bookmarked'),
('Accepted','Accepted')
)
class JobData(models.Model):
job_position = models.CharField(max_length=100, null=True)
company = models.CharField(max_length=100, null=True)
URL = models.URLField(max_length=1000,null=True)
status = models.CharField(max_length=100,choices=status_CHOICES, null=True)
date_saved = models.CharField(max_length=100, null=True)
date_applied = models.CharField(max_length=100, null=True)
type = models.CharField(max_length=100, null=True)
resume = models.URLField(max_length=200, null=True)
#cover_letter = models.URLField(max_length=200, null=True)
location = models.CharField(max_length=100, null=True)
job_description = models.CharField(null=True)
salary = models.CharField(null=True)
contact = models.CharField(max_length=100, null=True)
source = models.CharField(max_length=100, null=True)
class Meta:
db_table = 'job'
+3
View File
@@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.
+23
View File
@@ -0,0 +1,23 @@
"""
URL configuration for django_code project.
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/4.2/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path
urlpatterns = [
path('', admin.site.urls),
]
+3
View File
@@ -0,0 +1,3 @@
from django.shortcuts import render
# Create your views here.
+21 -5
View File
@@ -1,6 +1,8 @@
from django.contrib import admin,messages
from django.utils.translation import ngettext
from prompt_toolkit.shortcuts import print_container
from .models import SimpsonsData,simpsons_data_object
from .utils import mark_episode_watched,unwatch_all_episodes
from import_export import resources
from import_export.admin import ImportExportModelAdmin
# Register your models here.
@@ -10,6 +12,13 @@ DB = 'simpsons_db'
@admin.action(description="Mark episode as seen")
def make_seen(modeladmin, request, queryset):
updated = queryset.update(seen="True")
for query in queryset.values():
print(query)
season_number = query.get('season')
episode_number = query.get('episode')
mark_episode_watched(season_number,episode_number,"watched")
modeladmin.message_user(
request,
ngettext(
@@ -24,6 +33,12 @@ def make_seen(modeladmin, request, queryset):
@admin.action(description="Mark episode as not seen")
def make_unseen(modeladmin, request, queryset):
updated = queryset.update(seen="False")
for query in queryset.values():
print(query)
season_number = query.get('season')
episode_number = query.get('episode')
mark_episode_watched(season_number,episode_number,"unwatched")
modeladmin.message_user(
request,
ngettext(
@@ -35,16 +50,17 @@ def make_unseen(modeladmin, request, queryset):
messages.SUCCESS,
)
@admin.action(description="create_entry")
def create_entry(modeladmin, request, queryset):
simpsons_data_object.create(season=2, episode=3, url="google.com", seen=True)
@admin.action(description="mark all of them as unseen on betaserie")
def unseen_betaserie(modeladmin, request, queryset):
unwatch_all_episodes()
@admin.register(SimpsonsData)
class EpisodeAdmin(ImportExportModelAdmin):
list_display = ('season', 'episode', 'url', 'seen')
list_display = [field.name for field in SimpsonsData._meta.fields if field.name != 'id']
list_filter = ['seen']
fields = ['season', 'episode', 'url', 'seen']
actions = [make_seen,make_unseen,create_entry]
actions = [make_seen,make_unseen,unseen_betaserie]
def get_queryset(self, request):
return super().get_queryset(request).using(DB)
@@ -1,4 +1,4 @@
# Generated by Django 4.2.30 on 2026-06-16 08:46
# Generated by Django 4.2.29 on 2026-06-22 20:21
from django.db import migrations, models
@@ -1,41 +0,0 @@
# Generated by Django 4.2.29 on 2026-06-21 18:21
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('simpsons', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='Author',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=100)),
],
),
migrations.CreateModel(
name='Category',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=100)),
],
),
migrations.CreateModel(
name='Book',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=100, verbose_name='Book name')),
('author_email', models.EmailField(blank=True, max_length=75, verbose_name='Author email')),
('imported', models.BooleanField(default=False)),
('published', models.DateField(blank=True, null=True, verbose_name='Published')),
('price', models.DecimalField(blank=True, decimal_places=2, max_digits=10, null=True)),
('author', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='simpsons.author')),
('categories', models.ManyToManyField(blank=True, to='simpsons.category')),
],
),
]
@@ -1,30 +0,0 @@
# Generated by Django 4.2.29 on 2026-06-21 20:11
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('simpsons', '0002_author_category_book'),
]
operations = [
migrations.RemoveField(
model_name='book',
name='author',
),
migrations.RemoveField(
model_name='book',
name='categories',
),
migrations.DeleteModel(
name='Author',
),
migrations.DeleteModel(
name='Book',
),
migrations.DeleteModel(
name='Category',
),
]
+37
View File
@@ -0,0 +1,37 @@
from apps.betaserie.utils import betaserieUtils
from django.db.models import Count
from celery.worker.state import active_requests
from requests.compat import str
from .models import simpsons_data_object
betaserie = betaserieUtils()
simpsons_id = 12
def mark_episode_watched(season,episode,action):
print("season_number: "+str(season))
print("episode_number: "+str(episode))
episode_number = "S"+str(season)+"E"+str(episode)
episode_id = betaserie.identify_episode(simpsons_id,episode_number)
if action == "watched":
betaserie.mark_episodes_watched(episode_id)
elif action == "unwatched":
betaserie.unmark_episodes_watched(episode_id)
else:
print("Parameter action not in range")
def unwatch_all_episodes():
maximum_number_of_seasons = simpsons_data_object.aggregate(unique_season=Count('season', distinct=True))['unique_season']
print("maximum_number_of_seasons: "+str(maximum_number_of_seasons))
for season in range(1,maximum_number_of_seasons+1):
maximum_number_of_episodes = simpsons_data_object.filter(season=season).count()
print("maximum_number_of_episodes for "+str(season)+": "+str(maximum_number_of_episodes))
for episode in range(1,maximum_number_of_episodes+1):
print("S"+str(season)+"E"+str(episode))
mark_episode_watched(season,episode,"unwatched")
+6 -1
View File
@@ -1,7 +1,8 @@
from django.http import HttpResponse
from django.db.models import Count
from django.shortcuts import redirect
from apps.random_simpsons.models import SimpsonsData,simpsons_data_object
from .models import SimpsonsData,simpsons_data_object
from .utils import mark_episode_watched
import random
@@ -36,6 +37,9 @@ def episode_generator(request):
# It will still update an already seem episode but it works and I'm lazy
simpsons_data_object.filter(season=random_seasons, episode=random_episode).values('seen').update(seen=True)
#Mark episode as seen on betaseries
mark_episode_watched(random_seasons,random_episode,"watched")
return redirect(str(random_url))
@@ -60,3 +64,4 @@ def download_mo(request,file):
file_name = file[5:]
response['Content-Disposition'] = 'inline; filename=' + file_name
return response
@@ -1,3 +1,9 @@
from django.contrib import admin
from .models import redirectData
from import_export.admin import ImportExportModelAdmin
# Register your models here.
@admin.register(redirectData)
class redirectAdmin(ImportExportModelAdmin):
list_display = [field.name for field in redirectData._meta.fields if field.name != 'id']
@@ -1,4 +1,4 @@
# Generated by Django 4.2.29 on 2026-06-21 20:05
# Generated by Django 4.2.29 on 2026-06-22 20:21
from django.db import migrations, models
@@ -16,6 +16,7 @@ class Migration(migrations.Migration):
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('url', models.CharField(max_length=1000)),
('addedDate', models.DateField(blank=True, null=True, verbose_name='Published')),
('seenDate', models.DateField(blank=True, null=True, verbose_name='Published')),
],
options={
+3
View File
@@ -4,4 +4,7 @@ from django_hosts import patterns, host
host_patterns = patterns('',
host(r"django-testing", settings.ROOT_URLCONF, name="django-testing"),
host(r"redirect", 'apps.website_redirection.urls', name="redirect"),
host(r"redirect-testing", 'apps.website_redirection.urls', name="redirect-testing"),
host(r"job", 'apps.job_dashboard.urls', name="job_dashboard"),
host(r"job-testing", 'apps.job_dashboard.urls', name="job_dashboard-testing"),
)
+9 -3
View File
@@ -10,6 +10,8 @@ class ProjectDatabaseRouter:
"""Attempts to read simpsons and cloudmanager models go to their specific dbs."""
if model._meta.app_label == 'simpsons':
return 'simpsons_db'
if model._meta.app_label == 'job':
return 'job_db'
if model._meta.app_label == 'redirect':
return 'redirect_db'
if model._meta.app_label == 'cloudmanager':
@@ -20,6 +22,8 @@ class ProjectDatabaseRouter:
"""Attempts to write simpsons and cloudmanager models go to their specific dbs."""
if model._meta.app_label == 'simpsons':
return 'simpsons_db'
if model._meta.app_label == 'job':
return 'job_db'
if model._meta.app_label == 'cloudmanager':
return 'cloudmanager_db'
if model._meta.app_label == 'redirect':
@@ -30,8 +34,8 @@ class ProjectDatabaseRouter:
"""Allow relations if both models are in the same database."""
# Prevents accidental foreign key relationships across different physical DBs
if (
obj1._meta.app_label in ['simpsons', 'cloudmanager','redirect'] or
obj2._meta.app_label in ['simpsons', 'cloudmanager','redirect']
obj1._meta.app_label in ['simpsons', 'cloudmanager','redirect','job'] or
obj2._meta.app_label in ['simpsons', 'cloudmanager','redirect','job']
):
return obj1._meta.app_label == obj2._meta.app_label
return None
@@ -40,12 +44,14 @@ class ProjectDatabaseRouter:
"""Ensure the app's models only show up in the designated database."""
if app_label == 'simpsons':
return db == 'simpsons_db'
if app_label == 'job':
return db == 'job_db'
if app_label == 'cloudmanager':
return db == 'cloudmanager_db'
if app_label == 'redirect':
return 'redirect_db'
# Ensure default Django apps (auth, sessions, etc.) don't migrate into simpsons/cloudmanager
if db in ['simpsons_db', 'cloudmanager_db','redirect_db']:
if db in ['simpsons_db', 'cloudmanager_db','redirect_db','job_db']:
return False
return None
+9
View File
@@ -46,6 +46,7 @@ INSTALLED_APPS = [
'apps.cloudmanager.apps.CloudmanagerConfig',
'apps.random_simpsons.apps.RandomSimpsonsConfig',
'apps.website_redirection.apps.redirectConfig',
'apps.job_dashboard.apps.JobDashboardConfig',
'import_export',
]
@@ -124,6 +125,14 @@ DATABASES = {
'HOST': os.environ.get('DB_HOST'),
'PORT': os.environ.get('DB_PORT'),
},
'job_db': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'job',
'USER': os.environ.get('DB_USERNAME'),
'PASSWORD': os.environ.get('DB_PASSWORD'),
'HOST': os.environ.get('DB_HOST'),
'PORT': os.environ.get('DB_PORT'),
},
}
DATABASE_ROUTERS = ['core.routers.ProjectDatabaseRouter']
#DATABASE_ROUTERS = []
+1
View File
@@ -15,3 +15,4 @@ lxml
requests
django-hosts
django-import-export
bitwarden_sdk