blog-markdown #31
21
README.md
21
README.md
|
@ -1,4 +1,4 @@
|
||||||
# gawa
|
# Gawa
|
||||||
|
|
||||||
Gawa is my personal website. I've personally written it using the Django framework.
|
Gawa is my personal website. I've personally written it using the Django framework.
|
||||||
|
|
||||||
|
@ -7,21 +7,28 @@ Gawa is my personal website. I've personally written it using the Django framewo
|
||||||
These are the Credentials for logging into the admin panel:
|
These are the Credentials for logging into the admin panel:
|
||||||
| Username | Password |
|
| Username | Password |
|
||||||
|----------|----------|
|
|----------|----------|
|
||||||
| root | root |
|
| `root` | `root` |
|
||||||
|
|
||||||
### Blog
|
### Blog
|
||||||
|
|
||||||
| Username | Password |
|
| Username | Password |
|
||||||
|--------------------|--------------|
|
|--------------------------------------------------|----------------|
|
||||||
| contact@cscherr.de | hrCcDa0jBspG |
|
| [`contact@cscherr.de`](mailto:contact@cscherr.de) | `hrCcDa0jBspG` |
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
Bootstrap: MIT Licensed
|
Bootstrap: MIT Licensed
|
||||||
Django: BSD 3-Clause "New" or "Revised" License
|
Django: BSD 3-Clause "New" or "Revised" License
|
||||||
|
|
||||||
__Gawa: MIT Licensed, see LICENSE__
|
__Gawa: MIT Licensed, see LICENSE__
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
|
||||||
|
| Description | Package (fedora) |
|
||||||
|
|----------------|------------------|
|
||||||
|
| Database stuff | `libpq-devel` |
|
||||||
|
| Database stuff | `mariadb` |
|
||||||
|
|
||||||
## Security
|
## Security
|
||||||
|
|
||||||
- [ ] Do something about the files in the blog dir
|
- [ ] Do something about the files in the blog dir
|
||||||
|
|
|
@ -9,15 +9,18 @@ services:
|
||||||
# MYSQL_PASSWORD: changethisforprod
|
# MYSQL_PASSWORD: changethisforprod
|
||||||
MYSQL_ROOT_PASSWORD: root
|
MYSQL_ROOT_PASSWORD: root
|
||||||
volumes:
|
volumes:
|
||||||
- db_data:/var/lib/mysql
|
# - db_data:/var/lib/mysql
|
||||||
- ./docker/db/scripts:/docker-entrypoint-initdb.d/
|
- ./docker/db/scripts:/docker-entrypoint-initdb.d/
|
||||||
|
|
||||||
main:
|
main:
|
||||||
build: ./docker/main
|
build: ./docker/main
|
||||||
command: bash -c "
|
command: bash -c "echo 'setting django up'
|
||||||
python manage.py migrate
|
|
||||||
&& python manage.py collectstatic --noinput
|
&& python manage.py collectstatic --noinput
|
||||||
&& python manage.py runserver 0.0.0.0:8000
|
&& sleep 3
|
||||||
|
&& python manage.py migrate
|
||||||
|
&& DJANGO_SUPERUSER_PASSWORD='root' python manage.py createsuperuser\
|
||||||
|
--username root --noinput --email software@cscherr.de || true
|
||||||
|
&& python manage.py runserver 0.0.0.0:80
|
||||||
"
|
"
|
||||||
volumes:
|
volumes:
|
||||||
- ./gawa:/app
|
- ./gawa:/app
|
||||||
|
@ -43,21 +46,6 @@ services:
|
||||||
- ./gawa/static:/srv/static
|
- ./gawa/static:/srv/static
|
||||||
- ./gawa/media:/srv/media
|
- ./gawa/media:/srv/media
|
||||||
|
|
||||||
|
|
||||||
blog:
|
|
||||||
image: ghost
|
|
||||||
environment:
|
|
||||||
database__client: mysql
|
|
||||||
database__connection__host: db
|
|
||||||
database__connection__user: blog
|
|
||||||
database__connection__password: blogpass
|
|
||||||
database__connection__database: blog
|
|
||||||
url: http://localhost:8081
|
|
||||||
NODE_ENV: development
|
|
||||||
depends_on:
|
|
||||||
- db
|
|
||||||
|
|
||||||
|
|
||||||
db-admin:
|
db-admin:
|
||||||
image: phpmyadmin
|
image: phpmyadmin
|
||||||
ports:
|
ports:
|
||||||
|
@ -71,4 +59,4 @@ services:
|
||||||
volumes:
|
volumes:
|
||||||
caddy_data:
|
caddy_data:
|
||||||
caddy_config:
|
caddy_config:
|
||||||
db_data:
|
# db_data:
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -22,863 +22,3 @@ SET time_zone = "+00:00";
|
||||||
--
|
--
|
||||||
CREATE DATABASE IF NOT EXISTS `gawa` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
|
CREATE DATABASE IF NOT EXISTS `gawa` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
|
||||||
USE `gawa`;
|
USE `gawa`;
|
||||||
|
|
||||||
-- --------------------------------------------------------
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Tabellenstruktur für Tabelle `auth_group`
|
|
||||||
--
|
|
||||||
|
|
||||||
CREATE TABLE `auth_group` (
|
|
||||||
`id` int(11) NOT NULL,
|
|
||||||
`name` varchar(150) NOT NULL
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
|
||||||
|
|
||||||
-- --------------------------------------------------------
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Tabellenstruktur für Tabelle `auth_group_permissions`
|
|
||||||
--
|
|
||||||
|
|
||||||
CREATE TABLE `auth_group_permissions` (
|
|
||||||
`id` bigint(20) NOT NULL,
|
|
||||||
`group_id` int(11) NOT NULL,
|
|
||||||
`permission_id` int(11) NOT NULL
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
|
||||||
|
|
||||||
-- --------------------------------------------------------
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Tabellenstruktur für Tabelle `auth_permission`
|
|
||||||
--
|
|
||||||
|
|
||||||
CREATE TABLE `auth_permission` (
|
|
||||||
`id` int(11) NOT NULL,
|
|
||||||
`name` varchar(255) NOT NULL,
|
|
||||||
`content_type_id` int(11) NOT NULL,
|
|
||||||
`codename` varchar(100) NOT NULL
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Daten für Tabelle `auth_permission`
|
|
||||||
--
|
|
||||||
|
|
||||||
INSERT INTO `auth_permission` (`id`, `name`, `content_type_id`, `codename`) VALUES
|
|
||||||
(1, 'Can add keyword', 1, 'add_keyword'),
|
|
||||||
(2, 'Can change keyword', 1, 'change_keyword'),
|
|
||||||
(3, 'Can delete keyword', 1, 'delete_keyword'),
|
|
||||||
(4, 'Can view keyword', 1, 'view_keyword'),
|
|
||||||
(5, 'Can add searchable', 2, 'add_searchable'),
|
|
||||||
(6, 'Can change searchable', 2, 'change_searchable'),
|
|
||||||
(7, 'Can delete searchable', 2, 'delete_searchable'),
|
|
||||||
(8, 'Can view searchable', 2, 'view_searchable'),
|
|
||||||
(9, 'Can add static site', 3, 'add_staticsite'),
|
|
||||||
(10, 'Can change static site', 3, 'change_staticsite'),
|
|
||||||
(11, 'Can delete static site', 3, 'delete_staticsite'),
|
|
||||||
(12, 'Can view static site', 3, 'view_staticsite'),
|
|
||||||
(13, 'Can add category', 4, 'add_category'),
|
|
||||||
(14, 'Can change category', 4, 'change_category'),
|
|
||||||
(15, 'Can delete category', 4, 'delete_category'),
|
|
||||||
(16, 'Can view category', 4, 'view_category'),
|
|
||||||
(17, 'Can add blog post', 5, 'add_blogpost'),
|
|
||||||
(18, 'Can change blog post', 5, 'change_blogpost'),
|
|
||||||
(19, 'Can delete blog post', 5, 'delete_blogpost'),
|
|
||||||
(20, 'Can view blog post', 5, 'view_blogpost'),
|
|
||||||
(21, 'Can add log entry', 6, 'add_logentry'),
|
|
||||||
(22, 'Can change log entry', 6, 'change_logentry'),
|
|
||||||
(23, 'Can delete log entry', 6, 'delete_logentry'),
|
|
||||||
(24, 'Can view log entry', 6, 'view_logentry'),
|
|
||||||
(25, 'Can add permission', 7, 'add_permission'),
|
|
||||||
(26, 'Can change permission', 7, 'change_permission'),
|
|
||||||
(27, 'Can delete permission', 7, 'delete_permission'),
|
|
||||||
(28, 'Can view permission', 7, 'view_permission'),
|
|
||||||
(29, 'Can add group', 8, 'add_group'),
|
|
||||||
(30, 'Can change group', 8, 'change_group'),
|
|
||||||
(31, 'Can delete group', 8, 'delete_group'),
|
|
||||||
(32, 'Can view group', 8, 'view_group'),
|
|
||||||
(33, 'Can add user', 9, 'add_user'),
|
|
||||||
(34, 'Can change user', 9, 'change_user'),
|
|
||||||
(35, 'Can delete user', 9, 'delete_user'),
|
|
||||||
(36, 'Can view user', 9, 'view_user'),
|
|
||||||
(37, 'Can add content type', 10, 'add_contenttype'),
|
|
||||||
(38, 'Can change content type', 10, 'change_contenttype'),
|
|
||||||
(39, 'Can delete content type', 10, 'delete_contenttype'),
|
|
||||||
(40, 'Can view content type', 10, 'view_contenttype'),
|
|
||||||
(41, 'Can add session', 11, 'add_session'),
|
|
||||||
(42, 'Can change session', 11, 'change_session'),
|
|
||||||
(43, 'Can delete session', 11, 'delete_session'),
|
|
||||||
(44, 'Can view session', 11, 'view_session'),
|
|
||||||
(45, 'Can add Link', 12, 'add_link'),
|
|
||||||
(46, 'Can change Link', 12, 'change_link'),
|
|
||||||
(47, 'Can delete Link', 12, 'delete_link'),
|
|
||||||
(48, 'Can view Link', 12, 'view_link');
|
|
||||||
|
|
||||||
-- --------------------------------------------------------
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Tabellenstruktur für Tabelle `auth_user`
|
|
||||||
--
|
|
||||||
|
|
||||||
CREATE TABLE `auth_user` (
|
|
||||||
`id` int(11) NOT NULL,
|
|
||||||
`password` varchar(128) NOT NULL,
|
|
||||||
`last_login` datetime(6) DEFAULT NULL,
|
|
||||||
`is_superuser` tinyint(1) NOT NULL,
|
|
||||||
`username` varchar(150) NOT NULL,
|
|
||||||
`first_name` varchar(150) NOT NULL,
|
|
||||||
`last_name` varchar(150) NOT NULL,
|
|
||||||
`email` varchar(254) NOT NULL,
|
|
||||||
`is_staff` tinyint(1) NOT NULL,
|
|
||||||
`is_active` tinyint(1) NOT NULL,
|
|
||||||
`date_joined` datetime(6) NOT NULL
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Daten für Tabelle `auth_user`
|
|
||||||
--
|
|
||||||
|
|
||||||
INSERT INTO `auth_user` (`id`, `password`, `last_login`, `is_superuser`, `username`, `first_name`, `last_name`, `email`, `is_staff`, `is_active`, `date_joined`) VALUES
|
|
||||||
(1, 'pbkdf2_sha256$260000$cOxciSMkcV8kSVG1gUjOi7$LmOAxpppL7oBM2F+rFy0cdOZfReqdHqq1T6vw8PfODQ=', '2023-09-26 20:47:23.142649', 1, 'root', '', '', '', 1, 1, '2023-06-03 11:59:57.779755');
|
|
||||||
|
|
||||||
-- --------------------------------------------------------
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Tabellenstruktur für Tabelle `auth_user_groups`
|
|
||||||
--
|
|
||||||
|
|
||||||
CREATE TABLE `auth_user_groups` (
|
|
||||||
`id` bigint(20) NOT NULL,
|
|
||||||
`user_id` int(11) NOT NULL,
|
|
||||||
`group_id` int(11) NOT NULL
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
|
||||||
|
|
||||||
-- --------------------------------------------------------
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Tabellenstruktur für Tabelle `auth_user_user_permissions`
|
|
||||||
--
|
|
||||||
|
|
||||||
CREATE TABLE `auth_user_user_permissions` (
|
|
||||||
`id` bigint(20) NOT NULL,
|
|
||||||
`user_id` int(11) NOT NULL,
|
|
||||||
`permission_id` int(11) NOT NULL
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
|
||||||
|
|
||||||
-- --------------------------------------------------------
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Tabellenstruktur für Tabelle `blog_blogpost`
|
|
||||||
--
|
|
||||||
|
|
||||||
CREATE TABLE `blog_blogpost` (
|
|
||||||
`searchable_ptr_id` bigint(20) NOT NULL,
|
|
||||||
`thumbnail` varchar(100) NOT NULL,
|
|
||||||
`category_id` bigint(20) DEFAULT NULL,
|
|
||||||
`slug` varchar(50) NOT NULL,
|
|
||||||
`featured` tinyint(1) NOT NULL,
|
|
||||||
`markdown` tinyint(1) NOT NULL,
|
|
||||||
`body_de` longtext NOT NULL,
|
|
||||||
`body_en` longtext NOT NULL
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Daten für Tabelle `blog_blogpost`
|
|
||||||
--
|
|
||||||
|
|
||||||
INSERT INTO `blog_blogpost` (`searchable_ptr_id`, `thumbnail`, `category_id`, `slug`, `featured`, `markdown`, `body_de`, `body_en`) VALUES
|
|
||||||
(3, 'img/thumbnails/echter_ottifant.png', 1, 'test', 1, 0, 'Bis jetzt keine deutsche Übersetzung.', '<pre>\r\n81.271 Aufrufe 29.03.2023\r\nStellaris First Contact challenge video. No FTL Challenge. We will not research or use any FTL methods, from hyperdrive to jump drive. Can we survive and become a galactic superpower? Or will the forces of darkness seek to usurp us!\r\n\r\nThey called me a madman.\r\nThey said it couldn\'t be done.\r\nNow I present to you,\r\n\r\nStellaris With No FTL Travel.\r\n\r\nLets Dive In!\r\n\r\nSellaris Stories Playlist: • Stellaris Playthr... \r\n\r\nStellaris Version 3.7\r\n\r\nIf you enjoyed this video please leave a like & SUBSCRIBE!\r\n\r\nHumble Bundle Affiliate link: https://www.humblebundle.com/?partner...\r\n\r\nPatreon: https://www.patreon.com/MontuPlays\r\nChannel Membership: / @montuplays \r\nTwitter: https://twitter.com/MontuPlays\r\nTwitch: https://www.twitch.tv/montuplays\r\nInstagram: https://www.instagram.com/montuplays/\r\nTiktok: https://www.tiktok.com/@montuplays\r\n\r\nAnd please comment with any feedback, any ideas or if you disagree!\r\n</pre>'),
|
|
||||||
(4, 'img/thumbnails/thuglifemathemann.png', 1, 'hidden', 0, 0, 'Bis jetzt keine deutsche Übersetzung.', 'No english translation yet.'),
|
|
||||||
(5, 'img/thumbnails/wayland_logo.jpg', 2, 'wayland', 1, 0, 'Bis jetzt keine deutsche Übersetzung.', 'No english translation yet.'),
|
|
||||||
(6, 'img/thumbnails/Center_of_the_Milky_Way_Galaxy_IV__Composite.jpg', 1, 'badly-formatted', 1, 0, 'Bis jetzt keine deutsche Übersetzung.', 'No english translation yet.');
|
|
||||||
|
|
||||||
-- --------------------------------------------------------
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Tabellenstruktur für Tabelle `blog_category`
|
|
||||||
--
|
|
||||||
|
|
||||||
CREATE TABLE `blog_category` (
|
|
||||||
`id` bigint(20) NOT NULL,
|
|
||||||
`name` varchar(50) NOT NULL,
|
|
||||||
`slug` varchar(50) NOT NULL
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Daten für Tabelle `blog_category`
|
|
||||||
--
|
|
||||||
|
|
||||||
INSERT INTO `blog_category` (`id`, `name`, `slug`) VALUES
|
|
||||||
(1, 'test', 'test'),
|
|
||||||
(2, 'Linux', 'Linux');
|
|
||||||
|
|
||||||
-- --------------------------------------------------------
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Tabellenstruktur für Tabelle `django_admin_log`
|
|
||||||
--
|
|
||||||
|
|
||||||
CREATE TABLE `django_admin_log` (
|
|
||||||
`id` int(11) NOT NULL,
|
|
||||||
`action_time` datetime(6) NOT NULL,
|
|
||||||
`object_id` longtext DEFAULT NULL,
|
|
||||||
`object_repr` varchar(200) NOT NULL,
|
|
||||||
`action_flag` smallint(5) UNSIGNED NOT NULL CHECK (`action_flag` >= 0),
|
|
||||||
`change_message` longtext NOT NULL,
|
|
||||||
`content_type_id` int(11) DEFAULT NULL,
|
|
||||||
`user_id` int(11) NOT NULL
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Daten für Tabelle `django_admin_log`
|
|
||||||
--
|
|
||||||
|
|
||||||
INSERT INTO `django_admin_log` (`id`, `action_time`, `object_id`, `object_repr`, `action_flag`, `change_message`, `content_type_id`, `user_id`) VALUES
|
|
||||||
(1, '2023-06-03 12:04:18.697869', '1', 'Keyword object (1)', 1, '[{\"added\": {}}]', 1, 1),
|
|
||||||
(2, '2023-06-03 12:04:25.298763', '1', 'StaticSite object (1)', 1, '[{\"added\": {}}]', 3, 1),
|
|
||||||
(3, '2023-06-03 12:39:47.580686', '2', 'Keyword object (2)', 1, '[{\"added\": {}}]', 1, 1),
|
|
||||||
(4, '2023-06-03 12:39:54.676532', '2', 'StaticSite object (2)', 1, '[{\"added\": {}}]', 3, 1),
|
|
||||||
(5, '2023-06-03 18:49:19.838998', '3', 'Keyword object (3)', 1, '[{\"added\": {}}]', 1, 1),
|
|
||||||
(6, '2023-06-03 18:49:38.820915', '1', 'Category object (1)', 1, '[{\"added\": {}}]', 4, 1),
|
|
||||||
(7, '2023-06-03 18:50:06.156603', '3', 'BlogPost object (3)', 1, '[{\"added\": {}}]', 5, 1),
|
|
||||||
(8, '2023-06-03 22:24:55.684062', '3', 'BlogPost object (3)', 2, '[{\"changed\": {\"fields\": [\"Body\", \"Thumbnail\"]}}]', 5, 1),
|
|
||||||
(9, '2023-06-03 22:25:23.238473', '3', 'BlogPost object (3)', 2, '[{\"changed\": {\"fields\": [\"Body\"]}}]', 5, 1),
|
|
||||||
(10, '2023-06-03 22:32:15.868151', '3', 'BlogPost object (3)', 2, '[{\"changed\": {\"fields\": [\"Thumbnail\"]}}]', 5, 1),
|
|
||||||
(11, '2023-06-03 22:32:19.806919', '3', 'BlogPost object (3)', 2, '[{\"changed\": {\"fields\": [\"Thumbnail\"]}}]', 5, 1),
|
|
||||||
(12, '2023-06-03 22:34:12.390100', '3', 'BlogPost object (3)', 2, '[{\"changed\": {\"fields\": [\"Thumbnail\"]}}]', 5, 1),
|
|
||||||
(13, '2023-06-03 22:34:18.657049', '3', 'BlogPost object (3)', 2, '[{\"changed\": {\"fields\": [\"Thumbnail\"]}}]', 5, 1),
|
|
||||||
(14, '2023-06-03 22:35:20.148384', '3', 'BlogPost object (3)', 2, '[{\"changed\": {\"fields\": [\"Thumbnail\"]}}]', 5, 1),
|
|
||||||
(15, '2023-06-03 22:35:31.942529', '3', 'BlogPost object (3)', 2, '[{\"changed\": {\"fields\": [\"Thumbnail\"]}}]', 5, 1),
|
|
||||||
(16, '2023-06-03 22:37:55.565581', '3', 'BlogPost object (3)', 2, '[{\"changed\": {\"fields\": [\"Thumbnail\"]}}]', 5, 1),
|
|
||||||
(17, '2023-06-03 22:38:00.515394', '3', 'BlogPost object (3)', 2, '[{\"changed\": {\"fields\": [\"Thumbnail\"]}}]', 5, 1),
|
|
||||||
(18, '2023-06-03 22:42:32.527820', '3', 'BlogPost object (3)', 2, '[{\"changed\": {\"fields\": [\"Thumbnail\"]}}]', 5, 1),
|
|
||||||
(19, '2023-06-03 22:42:38.983331', '3', 'BlogPost object (3)', 2, '[{\"changed\": {\"fields\": [\"Thumbnail\"]}}]', 5, 1),
|
|
||||||
(20, '2023-06-03 22:43:03.221503', '3', 'BlogPost object (3)', 2, '[{\"changed\": {\"fields\": [\"Thumbnail\"]}}]', 5, 1),
|
|
||||||
(21, '2023-06-03 22:43:09.756742', '3', 'BlogPost object (3)', 2, '[{\"changed\": {\"fields\": [\"Thumbnail\"]}}]', 5, 1),
|
|
||||||
(22, '2023-06-03 22:43:32.898889', '3', 'BlogPost object (3)', 2, '[{\"changed\": {\"fields\": [\"Thumbnail\"]}}]', 5, 1),
|
|
||||||
(23, '2023-06-03 22:43:58.455830', '3', 'BlogPost object (3)', 2, '[{\"changed\": {\"fields\": [\"Thumbnail\"]}}]', 5, 1),
|
|
||||||
(24, '2023-06-03 22:44:49.711409', '3', 'BlogPost object (3)', 2, '[{\"changed\": {\"fields\": [\"Thumbnail\"]}}]', 5, 1),
|
|
||||||
(25, '2023-06-03 22:44:53.900045', '3', 'BlogPost object (3)', 2, '[{\"changed\": {\"fields\": [\"Thumbnail\"]}}]', 5, 1),
|
|
||||||
(26, '2023-06-03 22:46:22.495718', '3', 'BlogPost object (3)', 2, '[{\"changed\": {\"fields\": [\"Thumbnail\"]}}]', 5, 1),
|
|
||||||
(27, '2023-06-03 22:46:48.813958', '3', 'BlogPost object (3)', 2, '[{\"changed\": {\"fields\": [\"Thumbnail\"]}}]', 5, 1),
|
|
||||||
(28, '2023-06-03 23:10:31.960472', '3', 'BlogPost object (3)', 2, '[{\"changed\": {\"fields\": [\"Featured\"]}}]', 5, 1),
|
|
||||||
(29, '2023-06-03 23:11:49.738524', '3', 'BlogPost object (3)', 2, '[]', 5, 1),
|
|
||||||
(30, '2023-06-03 23:12:32.389296', '4', 'BlogPost object (4)', 1, '[{\"added\": {}}]', 5, 1),
|
|
||||||
(31, '2023-06-03 23:12:40.179260', '4', 'BlogPost object (4)', 2, '[{\"changed\": {\"fields\": [\"Public\", \"Featured\"]}}]', 5, 1),
|
|
||||||
(32, '2023-06-04 18:05:05.011703', '4', '{<BlogPost>\"hidden test\"}', 2, '[{\"changed\": {\"fields\": [\"Thumbnail\"]}}]', 5, 1),
|
|
||||||
(33, '2023-06-04 18:30:33.544753', '4', '{<Keyword>\"some keyword\"}', 1, '[{\"added\": {}}]', 1, 1),
|
|
||||||
(34, '2023-06-04 18:30:36.040424', '4', '{<BlogPost>\"hidden test\"}', 2, '[{\"changed\": {\"fields\": [\"Keywords\"]}}]', 5, 1),
|
|
||||||
(35, '2023-06-04 18:43:00.039374', '5', '{<Keyword>\"Linux\"}', 1, '[{\"added\": {}}]', 1, 1),
|
|
||||||
(36, '2023-06-04 18:43:06.821221', '6', '{<Keyword>\"Wayland\"}', 1, '[{\"added\": {}}]', 1, 1),
|
|
||||||
(37, '2023-06-04 18:43:30.492957', '2', '{<Category>\"Linux\"}', 1, '[{\"added\": {}}]', 4, 1),
|
|
||||||
(38, '2023-06-04 18:43:53.420012', '5', '{<BlogPost>\"wayland\"}', 1, '[{\"added\": {}}]', 5, 1),
|
|
||||||
(39, '2023-06-04 18:44:38.145122', '5', '{<BlogPost>\"wayland\"}', 2, '[{\"changed\": {\"fields\": [\"Thumbnail\"]}}]', 5, 1),
|
|
||||||
(40, '2023-06-04 18:48:08.975475', '5', '{<BlogPost>\"wayland\"}', 2, '[{\"changed\": {\"fields\": [\"Thumbnail\"]}}]', 5, 1),
|
|
||||||
(41, '2023-06-04 20:59:48.580334', '3', '{<BlogPost>\"test\"}', 2, '[{\"changed\": {\"fields\": [\"Keywords\"]}}]', 5, 1),
|
|
||||||
(42, '2023-06-04 21:12:48.508525', '6', '{<BlogPost>\"keywords\"}', 1, '[{\"added\": {}}]', 5, 1),
|
|
||||||
(43, '2023-06-04 21:13:03.091539', '6', '{<BlogPost>\"keywords\"}', 2, '[{\"changed\": {\"fields\": [\"Thumbnail\"]}}]', 5, 1),
|
|
||||||
(44, '2023-06-04 21:13:30.855689', '6', '{<BlogPost>\"keywords\"}', 2, '[{\"changed\": {\"fields\": [\"Thumbnail\"]}}]', 5, 1),
|
|
||||||
(45, '2023-06-05 16:17:00.484477', '7', '{<Keyword>\"selfhosting\"}', 1, '[{\"added\": {}}]', 1, 1),
|
|
||||||
(46, '2023-06-05 16:19:31.228250', 'https://european-alternatives.eu/', '{<Link>\"european alternative\"}', 1, '[{\"added\": {}}]', 12, 1),
|
|
||||||
(47, '2023-06-05 16:19:42.921776', 'https://european-alternatives.eu/', '{<Link>\"european alternatives\"}', 2, '[{\"changed\": {\"fields\": [\"Title en\"]}}]', 12, 1),
|
|
||||||
(48, '2023-06-05 16:40:04.807992', '8', '{<Keyword>\"tool\"}', 1, '[{\"added\": {}}]', 1, 1),
|
|
||||||
(49, '2023-06-05 16:40:51.112180', 'https://grep.app/', '{<Link>\"grep.app\"}', 1, '[{\"added\": {}}]', 12, 1),
|
|
||||||
(50, '2023-06-05 16:46:27.851078', 'https://cscherr.de', '{<Link>\"title EN\"}', 1, '[{\"added\": {}}]', 12, 1),
|
|
||||||
(51, '2023-06-05 16:46:30.662372', 'https://cscherr.de', '{<Link>\"title EN\"}', 2, '[]', 12, 1),
|
|
||||||
(52, '2023-06-05 16:46:32.422354', 'https://cscherr.de', '{<Link>\"title EN\"}', 2, '[]', 12, 1),
|
|
||||||
(53, '2023-06-05 16:46:59.815579', 'https://cscherr.de', '{<Link>\"title EN\"}', 2, '[]', 12, 1),
|
|
||||||
(54, '2023-06-05 16:47:14.035243', 'https://cschderr.de', '{<Link>\"title EN\"}', 1, '[{\"added\": {}}]', 12, 1),
|
|
||||||
(55, '2023-06-05 16:47:19.004185', 'https://dscschderr.de', '{<Link>\"title EN\"}', 1, '[{\"added\": {}}]', 12, 1),
|
|
||||||
(56, '2023-06-05 16:47:23.499798', 'https://cssdachderr.de', '{<Link>\"title EN\"}', 1, '[{\"added\": {}}]', 12, 1),
|
|
||||||
(57, '2023-06-05 17:13:16.967522', 'https://cscherr.de', '{<Link>\"title EN\"}', 2, '[{\"changed\": {\"fields\": [\"Keywords\"]}}]', 12, 1),
|
|
||||||
(58, '2023-06-05 17:14:44.255231', 'https://dscschderr.de', '{<Link>\"title EN\"}', 3, '', 12, 1),
|
|
||||||
(59, '2023-06-05 17:14:44.256420', 'https://cssdachderr.de', '{<Link>\"title EN\"}', 3, '', 12, 1),
|
|
||||||
(60, '2023-06-05 17:14:44.257328', 'https://cscherr.de', '{<Link>\"title EN\"}', 3, '', 12, 1),
|
|
||||||
(61, '2023-06-05 17:14:44.258159', 'https://cschderr.de', '{<Link>\"title EN\"}', 3, '', 12, 1),
|
|
||||||
(62, '2023-06-05 17:57:00.163052', 'https://cscherr.de', '{<Link>\"title EN\"}', 1, '[{\"added\": {}}]', 12, 1),
|
|
||||||
(63, '2023-06-05 20:58:00.230539', 'https://teslskdhglkjsahglkjdhflahgdlkjshgalskdhglkjsahglkjdsah.de', '{<Link>\"unavailable test\"}', 1, '[{\"added\": {}}]', 12, 1),
|
|
||||||
(64, '2023-06-05 21:17:01.550940', '4', '{<BlogPost>\"hidden test\"}', 2, '[{\"changed\": {\"fields\": [\"Featured\"]}}]', 5, 1),
|
|
||||||
(65, '2023-06-16 20:37:32.073731', '3', '{<BlogPost>\"test en\"}', 2, '[{\"changed\": {\"fields\": [\"Title de\", \"Title en\", \"Subtitle de\", \"Subtitle en\", \"Desc de\", \"Desc en\", \"Body en\"]}}]', 5, 1),
|
|
||||||
(66, '2023-06-16 22:05:16.217084', '3', '{<BlogPost>\"test en\"}', 2, '[{\"changed\": {\"fields\": [\"Body en\"]}}]', 5, 1),
|
|
||||||
(67, '2023-06-16 22:06:07.120314', '3', '{<BlogPost>\"test en\"}', 2, '[{\"changed\": {\"fields\": [\"Body en\"]}}]', 5, 1),
|
|
||||||
(68, '2023-06-16 22:09:16.732254', '3', '{<BlogPost>\"test en\"}', 2, '[{\"changed\": {\"fields\": [\"Body en\"]}}]', 5, 1),
|
|
||||||
(69, '2023-06-16 22:09:57.723744', '3', '{<BlogPost>\"test en\"}', 2, '[{\"changed\": {\"fields\": [\"Desc de\"]}}]', 5, 1),
|
|
||||||
(70, '2023-06-16 22:11:24.685523', '3', '{<BlogPost>\"test en\"}', 2, '[{\"changed\": {\"fields\": [\"Desc en\"]}}]', 5, 1),
|
|
||||||
(71, '2023-06-16 22:35:07.849677', '3', '{<BlogPost>\"test en\"}', 2, '[{\"changed\": {\"fields\": [\"Desc de\"]}}]', 5, 1),
|
|
||||||
(72, '2023-06-16 22:36:52.536498', '3', '{<BlogPost>\"test en\"}', 2, '[{\"changed\": {\"fields\": [\"Body en\"]}}]', 5, 1),
|
|
||||||
(73, '2023-06-16 22:37:59.812320', '3', '{<BlogPost>\"test en\"}', 2, '[{\"changed\": {\"fields\": [\"Body en\"]}}]', 5, 1),
|
|
||||||
(74, '2023-07-15 12:44:37.681112', '9', '{<Keyword>\"social media\"}', 1, '[{\"added\": {}}]', 1, 1),
|
|
||||||
(75, '2023-07-15 12:44:47.420748', '10', '{<Keyword>\"mastodon\"}', 1, '[{\"added\": {}}]', 1, 1),
|
|
||||||
(76, '2023-07-15 12:46:17.179222', 'https://infosec.exchange/@plexsheep/', '{<Link>\"Mastodon\"}', 1, '[{\"added\": {}}]', 12, 1),
|
|
||||||
(77, '2023-07-15 12:47:41.308504', 'https://cscherr.de', '{<Link>\"title EN\"}', 3, '', 12, 1),
|
|
||||||
(78, '2023-09-27 18:43:24.048812', '11', '{<Keyword>\"Hacking\"}', 1, '[{\"added\": {}}]', 1, 1),
|
|
||||||
(79, '2023-09-27 18:43:32.913389', 'https://cscg.de/', '{<Link>\"Cyber Security Challenge Germany\"}', 1, '[{\"added\": {}}]', 12, 1);
|
|
||||||
|
|
||||||
-- --------------------------------------------------------
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Tabellenstruktur für Tabelle `django_content_type`
|
|
||||||
--
|
|
||||||
|
|
||||||
CREATE TABLE `django_content_type` (
|
|
||||||
`id` int(11) NOT NULL,
|
|
||||||
`app_label` varchar(100) NOT NULL,
|
|
||||||
`model` varchar(100) NOT NULL
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Daten für Tabelle `django_content_type`
|
|
||||||
--
|
|
||||||
|
|
||||||
INSERT INTO `django_content_type` (`id`, `app_label`, `model`) VALUES
|
|
||||||
(6, 'admin', 'logentry'),
|
|
||||||
(8, 'auth', 'group'),
|
|
||||||
(7, 'auth', 'permission'),
|
|
||||||
(9, 'auth', 'user'),
|
|
||||||
(5, 'blog', 'blogpost'),
|
|
||||||
(4, 'blog', 'category'),
|
|
||||||
(10, 'contenttypes', 'contenttype'),
|
|
||||||
(11, 'sessions', 'session'),
|
|
||||||
(1, 'start', 'keyword'),
|
|
||||||
(12, 'start', 'link'),
|
|
||||||
(2, 'start', 'searchable'),
|
|
||||||
(3, 'start', 'staticsite');
|
|
||||||
|
|
||||||
-- --------------------------------------------------------
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Tabellenstruktur für Tabelle `django_migrations`
|
|
||||||
--
|
|
||||||
|
|
||||||
CREATE TABLE `django_migrations` (
|
|
||||||
`id` bigint(20) NOT NULL,
|
|
||||||
`app` varchar(255) NOT NULL,
|
|
||||||
`name` varchar(255) NOT NULL,
|
|
||||||
`applied` datetime(6) NOT NULL
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Daten für Tabelle `django_migrations`
|
|
||||||
--
|
|
||||||
|
|
||||||
INSERT INTO `django_migrations` (`id`, `app`, `name`, `applied`) VALUES
|
|
||||||
(1, 'contenttypes', '0001_initial', '2023-06-03 11:56:39.134383'),
|
|
||||||
(2, 'auth', '0001_initial', '2023-06-03 11:56:39.493397'),
|
|
||||||
(3, 'admin', '0001_initial', '2023-06-03 11:56:39.576389'),
|
|
||||||
(4, 'admin', '0002_logentry_remove_auto_add', '2023-06-03 11:56:39.587912'),
|
|
||||||
(5, 'admin', '0003_logentry_add_action_flag_choices', '2023-06-03 11:56:39.599213'),
|
|
||||||
(6, 'contenttypes', '0002_remove_content_type_name', '2023-06-03 11:56:39.670533'),
|
|
||||||
(7, 'auth', '0002_alter_permission_name_max_length', '2023-06-03 11:56:39.707524'),
|
|
||||||
(8, 'auth', '0003_alter_user_email_max_length', '2023-06-03 11:56:39.731843'),
|
|
||||||
(9, 'auth', '0004_alter_user_username_opts', '2023-06-03 11:56:39.745982'),
|
|
||||||
(10, 'auth', '0005_alter_user_last_login_null', '2023-06-03 11:56:39.782422'),
|
|
||||||
(11, 'auth', '0006_require_contenttypes_0002', '2023-06-03 11:56:39.785282'),
|
|
||||||
(12, 'auth', '0007_alter_validators_add_error_messages', '2023-06-03 11:56:39.797106'),
|
|
||||||
(13, 'auth', '0008_alter_user_username_max_length', '2023-06-03 11:56:39.827272'),
|
|
||||||
(14, 'auth', '0009_alter_user_last_name_max_length', '2023-06-03 11:56:39.851866'),
|
|
||||||
(15, 'auth', '0010_alter_group_name_max_length', '2023-06-03 11:56:39.879276'),
|
|
||||||
(16, 'auth', '0011_update_proxy_permissions', '2023-06-03 11:56:39.894042'),
|
|
||||||
(17, 'auth', '0012_alter_user_first_name_max_length', '2023-06-03 11:56:39.922412'),
|
|
||||||
(18, 'sessions', '0001_initial', '2023-06-03 11:56:39.960733'),
|
|
||||||
(19, 'start', '0001_initial', '2023-06-03 12:03:45.768696'),
|
|
||||||
(20, 'start', '0002_keyword_searchable_staticsite', '2023-06-03 12:03:45.941730'),
|
|
||||||
(21, 'blog', '0001_initial', '2023-06-03 12:03:45.945010'),
|
|
||||||
(22, 'blog', '0002_blogpost_category', '2023-06-03 12:03:46.053269'),
|
|
||||||
(23, 'blog', '0003_blogpost_public', '2023-06-03 18:52:48.544852'),
|
|
||||||
(24, 'blog', '0004_blogpost_slug', '2023-06-03 19:06:14.602364'),
|
|
||||||
(25, 'blog', '0005_auto_20230604_0050', '2023-06-03 22:50:53.031820'),
|
|
||||||
(26, 'blog', '0006_blogpost_markdown', '2023-06-03 22:55:58.592031'),
|
|
||||||
(27, 'blog', '0007_remove_blogpost_public', '2023-06-03 23:13:24.592228'),
|
|
||||||
(28, 'start', '0003_searchable_public', '2023-06-03 23:13:24.624613'),
|
|
||||||
(29, 'blog', '0008_auto_20230604_0156', '2023-06-03 23:56:46.268858'),
|
|
||||||
(30, 'start', '0004_auto_20230604_2312', '2023-06-04 21:12:38.055586'),
|
|
||||||
(31, 'start', '0005_link', '2023-06-05 16:15:09.586322'),
|
|
||||||
(32, 'start', '0006_alter_searchable_title_en', '2023-06-05 16:18:36.026234'),
|
|
||||||
(33, 'start', '0007_link_favicon', '2023-06-05 17:48:34.359895'),
|
|
||||||
(34, 'start', '0008_link_status', '2023-06-05 20:55:49.654569'),
|
|
||||||
(35, 'start', '0009_alter_link_favicon', '2023-06-05 23:01:06.878071'),
|
|
||||||
(36, 'blog', '0009_auto_20230616_2236', '2023-06-16 20:36:25.811914'),
|
|
||||||
(37, 'start', '0010_link_personal', '2023-07-15 12:20:30.979727'),
|
|
||||||
(38, 'start', '0011_auto_20230715_1441', '2023-07-15 12:41:41.290671');
|
|
||||||
|
|
||||||
-- --------------------------------------------------------
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Tabellenstruktur für Tabelle `django_session`
|
|
||||||
--
|
|
||||||
|
|
||||||
CREATE TABLE `django_session` (
|
|
||||||
`session_key` varchar(40) NOT NULL,
|
|
||||||
`session_data` longtext NOT NULL,
|
|
||||||
`expire_date` datetime(6) NOT NULL
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Daten für Tabelle `django_session`
|
|
||||||
--
|
|
||||||
|
|
||||||
INSERT INTO `django_session` (`session_key`, `session_data`, `expire_date`) VALUES
|
|
||||||
('0upcgnoxwloj2oe517p5gs49u5lp5zzq', 'eyJfbGFuZ3VhZ2UiOiJlbiJ9:1qAGqc:py_DCOFJ-FumxDRyHNdQX5fRdemoczmVG1R6SSAoQXA', '2023-06-30 21:19:10.696506'),
|
|
||||||
('1gv9x0aqsv9wnwjrdfn2jb2lmb6e7m1q', 'eyJfbGFuZ3VhZ2UiOiJlbiJ9:1q6I0M:8ck2jJRPvLCTVo8eO3Uf55V1qSCCmhbIVhoTqD-r-Io', '2023-06-19 21:44:46.153044'),
|
|
||||||
('2vj0n37v54tosuve9rzd869cxcto8mz2', 'eyJfbGFuZ3VhZ2UiOiJkZSJ9:1q5sLF:8r4rYdTtQYok9kkyr3UhO9m92jAPZC405pDYwP09-qA', '2023-06-18 18:20:37.522039'),
|
|
||||||
('3xiqj0zj3hqhng68kgetjvl3h3ef6rga', 'eyJfbGFuZ3VhZ2UiOiJkZSJ9:1q6Dwi:pSwhudkZDOHfIFHna_Qhk4zH3yb3hNDC_HIwKt70DIE', '2023-06-19 17:24:44.189905'),
|
|
||||||
('64c4rub7ajgnj111shwcpvpvhfangkw6', 'eyJfbGFuZ3VhZ2UiOiJkZSJ9:1q6IWp:gB20zXAKoPRbLklQlEzPAB2etNe510dvcw3HjZ2YqhE', '2023-06-19 22:18:19.400916'),
|
|
||||||
('7ig4cdxegsgr67am0qahc168ne7vnl6n', 'eyJfbGFuZ3VhZ2UiOiJkZSJ9:1q5aKH:la2kbcUB5332lRGgq-fmRfExgAqu21jCINyFziVMiPw', '2023-06-17 23:06:25.760931'),
|
|
||||||
('7zziio2fl6g4y2zlmbod3iqz8axi0c0w', '.eJxVjDsOgzAQBe_iOrLwD-yU6TmDtbteAwkyEuAqyt0DEg3tvJn3FXGGMlQYWDwFF_EQEeo-xrrxGqd0QHVnCPThcg7pfZSLpKXs64TyVOS1brJfEs-vy70djLCNR20Qk2tyY3UO1gT0wWhEm5kaF6gNGdkZRc560IrYAOkWsLPOd4iEIH5_vbE96w:1qAdo6:_7Ggp630uFVTXvIfzqnMcFQPZifnfd32YNw2xrRX4e4', '2023-07-01 21:50:06.829517'),
|
|
||||||
('82mt5l930fx2l18pvq62xve1dyjuczg4', 'eyJfbGFuZ3VhZ2UiOiJkZSJ9:1q6ImI:L5uK3sW-CLiZwmK82SRpB46kruvoVv7shUM9VtzOvaw', '2023-06-19 22:34:18.417914'),
|
|
||||||
('90cu9ksglbxjuav0ycu34entpl3u4qze', 'eyJfbGFuZ3VhZ2UiOiJkZSJ9:1q6DPn:FCYUrqa7sxjHrLAxvrd4xcXst3Bld3roZXiMIm6_F7g', '2023-06-19 16:50:43.835428'),
|
|
||||||
('9vrglur3tcfw30khosdk0whixdw5868f', 'eyJfbGFuZ3VhZ2UiOiJkZSJ9:1q6DJf:JMQ65g3ch9bxIJXCyHfBkmz8xqpCFDLqCCEB-Fjk1j8', '2023-06-19 16:44:23.542502'),
|
|
||||||
('a4lile9twdhc1yhb4jm2v5arw3njpmej', 'eyJfbGFuZ3VhZ2UiOiJkZSJ9:1q6bpg:OnpuTHTxOIhBWx00CQPrpYZhMxGIhsNypGHc_4oxT_Q', '2023-06-20 18:55:04.321078'),
|
|
||||||
('aj8r2xou6zmiev2qu09skea7uxl7mk4s', 'eyJfbGFuZ3VhZ2UiOiJlbiJ9:1qlEwK:PJsxynHSnR99RgKTXCdS04bczAM31zWnfKa_JbPQZJQ', '2023-10-10 20:45:52.004706'),
|
|
||||||
('b19ur3eet73u66lfhf7iowvb8e6ki2td', 'eyJfbGFuZ3VhZ2UiOiJkZSJ9:1q6IJN:ZIdTfsHuPhlUBDAW9wvz2hoEtMH4NYqgkomYVIieAhY', '2023-06-19 22:04:25.445445'),
|
|
||||||
('b1xgysjxf4yjco704xam548jixstkxk4', 'eyJfbGFuZ3VhZ2UiOiJkZSJ9:1q6IWp:gB20zXAKoPRbLklQlEzPAB2etNe510dvcw3HjZ2YqhE', '2023-06-19 22:18:19.426849'),
|
|
||||||
('evj2deqvxhbyxb49e9h6l9na2qbaqf95', 'eyJfbGFuZ3VhZ2UiOiJkZSJ9:1q5QmI:1rGcG2CjkEKezGaLrT8fLFdInLOqIDp2ctZb5w2h9eY', '2023-06-17 12:54:42.590440'),
|
|
||||||
('gx6813mra4mjk14s8731rtb9yrqepdq6', 'eyJfbGFuZ3VhZ2UiOiJkZSJ9:1q6IJN:ZIdTfsHuPhlUBDAW9wvz2hoEtMH4NYqgkomYVIieAhY', '2023-06-19 22:04:25.426613'),
|
|
||||||
('hseisfnzpao3n9vgsrm5xup83mnh5m8x', 'eyJfbGFuZ3VhZ2UiOiJkZSJ9:1q6Ddw:jbkCHqvAo-dZVnT_cPPyzr3ifoYQ8RWqavgGkZOLxM4', '2023-06-19 17:05:20.044989'),
|
|
||||||
('i99yua650ef8vl8b5fj5ap6adkwga4mf', 'eyJfbGFuZ3VhZ2UiOiJlbiJ9:1qlEKO:T9QlV6VyTrt6qAIWcDbc_DQAlr_CjRHFQupnY92Oqnc', '2023-10-10 20:06:40.283402'),
|
|
||||||
('iax6u7cdt7ccouzt9ewkgyzz1my8jl16', 'eyJfbGFuZ3VhZ2UiOiJkZSJ9:1q6FnU:aw4jJP-LzV0_VQMDgNJdIAkd4HinLKxDb6fP3ls6p5I', '2023-06-19 19:23:20.996410'),
|
|
||||||
('ir5lngwwf38u4ro0dreraqdv7sy8fl4j', 'eyJfbGFuZ3VhZ2UiOiJkZSJ9:1qkrLe:q--VIRxGKEfZEr1h28GRACqTPEwcSGOklzwjb2-BBco', '2023-10-09 19:34:26.798740'),
|
|
||||||
('jav4im7bxc31yig1weoojczl725hjetd', '.eJxVjDsOgzAQBe_iOrLwD-yU6TmDtbteAwkyEuAqyt0DEg3tvJn3FXGGMlQYWDwFF_EQEeo-xrrxGqd0QHVnCPThcg7pfZSLpKXs64TyVOS1brJfEs-vy70djLCNR20Qk2tyY3UO1gT0wWhEm5kaF6gNGdkZRc560IrYAOkWsLPOd4iEIH5_vbE96w:1qKfJc:bpPnwVuuqPB9oVGr8Revg7vj3eAIo1niHfWEmf8O0o0', '2023-07-29 13:28:04.767178'),
|
|
||||||
('jf3upknvj24cbyz5ucf2hvqes4o6brzf', 'eyJfbGFuZ3VhZ2UiOiJlbiJ9:1qAFve:_RL7IYW9MkLOwRPU7s-iljlJETcf2JNT8-s0CiQBgbI', '2023-06-30 20:20:18.080997'),
|
|
||||||
('nowaza4auf15ea5ceduizupmuoai5wed', '.eJxVjDsOgzAQBe_iOrLwD-yU6TmDtbteAwkyEuAqyt0DEg3tvJn3FXGGMlQYWDwFF_EQEeo-xrrxGqd0QHVnCPThcg7pfZSLpKXs64TyVOS1brJfEs-vy70djLCNR20Qk2tyY3UO1gT0wWhEm5kaF6gNGdkZRc560IrYAOkWsLPOd4iEIH5_vbE96w:1qlZTU:uwTe0XhXUDx5AoyAuiMe8bsgud4-dczCsuKKhjQxjno', '2023-10-11 18:41:28.391526'),
|
|
||||||
('nxbpuu69n360c4rtr30gatez80zceypc', 'eyJfbGFuZ3VhZ2UiOiJlbiJ9:1q5uwg:26g54m5XFWYTIyQ_XXmbuFM0dXKFK5PjIpnffTPooec', '2023-06-18 21:07:26.651759'),
|
|
||||||
('oksqlmqq4d95qbthf77cekpstsoras0x', 'eyJfbGFuZ3VhZ2UiOiJkZSJ9:1qAHVI:zMwTYu2mF4TuMp3z6xyGegM5Z4dV2QOS4KErwB_42IY', '2023-06-30 22:01:12.013664'),
|
|
||||||
('ou12hhptv10i3dicpx9eg73qhr2c2spw', 'eyJfbGFuZ3VhZ2UiOiJkZSJ9:1qAFve:D4NUcsnUU5BQLest9ZT3q98QlX1Vidt_wW73IIUcD0c', '2023-06-30 20:20:18.023866'),
|
|
||||||
('oxfk3q8saufspyg0hiinj9re5by7exfa', 'eyJfbGFuZ3VhZ2UiOiJlbiJ9:1qKdzi:6328QizeSnm7IrCb8D9WhpBYgBql6UhxN2DT65FLV8I', '2023-07-29 12:03:26.437263'),
|
|
||||||
('puu3uusjwghp6krjt33eh1hkd8zmpzp5', 'eyJfbGFuZ3VhZ2UiOiJkZSJ9:1q6bpg:OnpuTHTxOIhBWx00CQPrpYZhMxGIhsNypGHc_4oxT_Q', '2023-06-20 18:55:04.318858'),
|
|
||||||
('qizi095sgnejjvs8rwhp7pqdfekmallu', 'eyJfbGFuZ3VhZ2UiOiJlbiJ9:1q5WGm:eC3Esvpesob9k12yWTUQU-w3r1_FbxdRLENuAFm9ZXk', '2023-06-17 18:46:32.666643'),
|
|
||||||
('qkmrqp3xxmungtb5xbrwe2yjwe7lqt4g', 'eyJfbGFuZ3VhZ2UiOiJkZSJ9:1q6D0o:MBtnPS-eBpBPozK1IVNCJRQ7FAd7kNKqq2aK4M8oq80', '2023-06-19 16:24:54.958490'),
|
|
||||||
('qwkkyzzeqjg9172kyfek1hd9nzqtru3q', 'eyJfbGFuZ3VhZ2UiOiJkZSJ9:1q6IWp:gB20zXAKoPRbLklQlEzPAB2etNe510dvcw3HjZ2YqhE', '2023-06-19 22:18:19.401336'),
|
|
||||||
('qysgaziztbpgvtl3kyttosi93s1zwtvf', 'eyJfbGFuZ3VhZ2UiOiJkZSJ9:1q5QV9:1Uw36kLgFSXm1VjcuuiIGpkmQuRN_KK0Ma3Zl4DXT6o', '2023-06-17 12:36:59.495979'),
|
|
||||||
('rkty698r11z7zm85k2geknm0rcjwyfqv', 'eyJfbGFuZ3VhZ2UiOiJkZSJ9:1q6IWp:gB20zXAKoPRbLklQlEzPAB2etNe510dvcw3HjZ2YqhE', '2023-06-19 22:18:19.414335'),
|
|
||||||
('rtammfv9ja1mbvbgw7sdw4veiyp03xxm', 'eyJfbGFuZ3VhZ2UiOiJkZSJ9:1q6IJN:ZIdTfsHuPhlUBDAW9wvz2hoEtMH4NYqgkomYVIieAhY', '2023-06-19 22:04:25.435536'),
|
|
||||||
('swp0hlg8yx4hxwu7u9d7si0o9m8it1pn', 'eyJfbGFuZ3VhZ2UiOiJlbiJ9:1q5uoj:aBQfKM4_0_2dMJJKcfn6UXCiUpxS-b_UgIJiN0nRaqo', '2023-06-18 20:59:13.449268'),
|
|
||||||
('t2kwan6ekp81crswrsi9hii4b61imuue', 'eyJfbGFuZ3VhZ2UiOiJkZSJ9:1q6DnA:j-cI0mcCObdleGdnyjXwXCzYLi4AmXpo610VPxQBmM4', '2023-06-19 17:14:52.657342'),
|
|
||||||
('tvscp47jrsn5z4fzay4sozctp4o9tpr7', 'eyJfbGFuZ3VhZ2UiOiJkZSJ9:1q6Ftl:fbR1czINKX_3OFLpBEjlPSoOqVf4B5Yx5U13i83cz2Y', '2023-06-19 19:29:49.516429'),
|
|
||||||
('ty2uxmb0kropbz7ag4yk848t4hen54j7', 'eyJfbGFuZ3VhZ2UiOiJkZSJ9:1q6J1L:beudjtx8mUL9cLZg3z3PKqP5hW8lp_inxnyW3f3HEDk', '2023-06-19 22:49:51.870050'),
|
|
||||||
('whu9nbomfw3i5gs8fttvjxacu247tuft', 'eyJfbGFuZ3VhZ2UiOiJkZSJ9:1q6Drn:Eb7ima9uOKmHWTfkubqTkzHczghiDOglJCki3bib51I', '2023-06-19 17:19:39.665491'),
|
|
||||||
('z35tevuzugpk08wbgtlcvktitb5cuuvj', 'eyJfbGFuZ3VhZ2UiOiJkZSJ9:1qkrLg:t7mBZwP_Vzcn3gtTR-jeZ3P779bwZI_4o502I-Erxks', '2023-10-09 19:34:28.894312'),
|
|
||||||
('zj7tnj6l3xwq4n2vy4eg1gsvmc7rgagx', 'eyJfbGFuZ3VhZ2UiOiJkZSJ9:1q6Czj:IPERPMMtjCuW4sOHOEc7FY58NgjY0u8Lh10NMcinf_Y', '2023-06-19 16:23:47.958648');
|
|
||||||
|
|
||||||
-- --------------------------------------------------------
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Tabellenstruktur für Tabelle `start_keyword`
|
|
||||||
--
|
|
||||||
|
|
||||||
CREATE TABLE `start_keyword` (
|
|
||||||
`id` bigint(20) NOT NULL,
|
|
||||||
`text_de` varchar(40) NOT NULL,
|
|
||||||
`text_en` varchar(40) NOT NULL
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Daten für Tabelle `start_keyword`
|
|
||||||
--
|
|
||||||
|
|
||||||
INSERT INTO `start_keyword` (`id`, `text_de`, `text_en`) VALUES
|
|
||||||
(1, 'Statisch', 'static'),
|
|
||||||
(2, 'Blog', 'blog'),
|
|
||||||
(3, 'test', 'test'),
|
|
||||||
(4, 'ein keyword', 'some keyword'),
|
|
||||||
(5, 'Linux', 'Linux'),
|
|
||||||
(6, 'Wayland', 'Wayland'),
|
|
||||||
(7, 'Selfhosting', 'selfhosting'),
|
|
||||||
(8, 'Tool', 'tool'),
|
|
||||||
(9, 'Social Media', 'social media'),
|
|
||||||
(10, 'Mastodon', 'mastodon'),
|
|
||||||
(11, 'Hacking', 'Hacking');
|
|
||||||
|
|
||||||
-- --------------------------------------------------------
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Tabellenstruktur für Tabelle `start_link`
|
|
||||||
--
|
|
||||||
|
|
||||||
CREATE TABLE `start_link` (
|
|
||||||
`searchable_ptr_id` bigint(20) NOT NULL,
|
|
||||||
`url` varchar(200) NOT NULL,
|
|
||||||
`favicon` varchar(100) DEFAULT NULL,
|
|
||||||
`status` tinyint(1) NOT NULL,
|
|
||||||
`personal` tinyint(1) NOT NULL
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Daten für Tabelle `start_link`
|
|
||||||
--
|
|
||||||
|
|
||||||
INSERT INTO `start_link` (`searchable_ptr_id`, `url`, `favicon`, `status`, `personal`) VALUES
|
|
||||||
(19, 'https://cscg.de/', 'img/links/favicons/favicon-12398.png', 1, 0),
|
|
||||||
(10, 'https://european-alternatives.eu/', 'img/links/favicons/favicon-36105.png', 1, 0),
|
|
||||||
(11, 'https://grep.app/', 'img/links/favicons/favicon-43495.png', 1, 0),
|
|
||||||
(18, 'https://infosec.exchange/@plexsheep/', 'img/links/favicons/favicon-46734.png', 1, 1),
|
|
||||||
(17, 'https://teslskdhglkjsahglkjdhflahgdlkjshgalskdhglkjsahglkjdsah.de', '', 0, 0);
|
|
||||||
|
|
||||||
-- --------------------------------------------------------
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Tabellenstruktur für Tabelle `start_searchable`
|
|
||||||
--
|
|
||||||
|
|
||||||
CREATE TABLE `start_searchable` (
|
|
||||||
`id` bigint(20) NOT NULL,
|
|
||||||
`title_de` varchar(50) NOT NULL,
|
|
||||||
`title_en` varchar(50) NOT NULL,
|
|
||||||
`subtitle_de` varchar(50) NOT NULL,
|
|
||||||
`subtitle_en` varchar(50) NOT NULL,
|
|
||||||
`desc_de` longtext NOT NULL,
|
|
||||||
`desc_en` longtext NOT NULL,
|
|
||||||
`date` date DEFAULT NULL,
|
|
||||||
`suburl` varchar(200) DEFAULT NULL,
|
|
||||||
`public` tinyint(1) NOT NULL
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Daten für Tabelle `start_searchable`
|
|
||||||
--
|
|
||||||
|
|
||||||
INSERT INTO `start_searchable` (`id`, `title_de`, `title_en`, `subtitle_de`, `subtitle_en`, `desc_de`, `desc_en`, `date`, `suburl`, `public`) VALUES
|
|
||||||
(1, 'Startseite', 'startpage', '', '', 'Die Startseite von cscherr.de', 'The startpage of cscherr.de', NULL, '/', 1),
|
|
||||||
(2, 'Blog', 'blog', '', '', 'Die Startseite des Blogs', 'The startpage of the blob', NULL, '/blog', 1),
|
|
||||||
(3, 'Test de', 'test en', 'test blogpost de', 'test blogpost en', 'selbst gebaut oder template? Moritz — gestern um 23:16 Uhr Selbst natürlich Christoph — gestern um 23:16 Uhr wenn du ein framework suchst empfehle ich django, gibt aber genug auswahl Moritz — gestern um 23:16 Uhr Brauche aber erstmal die Zeit, wollte', 'ENENENEN<div class=\"d-md-flex flex-md-row-reverse align-items-center justify-content-between\"> <div class=\"mb-3 mb-md-0 d-flex text-nowrap\"><a class=\"btn btn-sm btn-bd-light rounded-2\" href=\"https://github.com/twbs/bootstrap/blob/v5.3.0/sit', '2023-06-03', '/blog/test/test', 1),
|
|
||||||
(4, 'hidden test', 'hidden test', '', '', 'Beschreibung DE', 'Description EN', NULL, '/blog/test/hidden', 1),
|
|
||||||
(5, 'Wayland', 'wayland', 'Linux Display Server', 'linux display server', 'Wayland ist ein Linux Display Server der endlich X11 verdrängen soll.', 'Wayland is a linux display server that will finally make X11 legacy software.', '2023-06-04', '/blog/Linux/wayland', 1),
|
|
||||||
(6, 'schlüsslis', 'keywords', 'viele von denen', 'too many', 'Beschreibung DE', 'Description EN', '2023-06-04', '/blog/test/badly-formatted', 1),
|
|
||||||
(10, 'Europäische Alternativen', 'european alternatives', '', '', 'Hilft bei der Suche nach europäischen Alternativen für digitale Dienstleistungen und Produkte, wie Cloud-Dienste und SaaS-Produkte.', 'Helps you find European alternatives for digital service and products, like cloud services and SaaS products.', '2023-06-05', '/links#european alternatives', 1),
|
|
||||||
(11, 'grep.app', 'grep.app', '', '', 'Suche über eine halbe Million Git-Repos', 'Search across a half million git repos', '2023-06-05', '/links#grep.app', 1),
|
|
||||||
(17, 'unavailable test', 'unavailable test', '', '', 'Beschreibung DE', 'Description EN', NULL, '/links#unavailable test', 1),
|
|
||||||
(18, 'Mastodon', 'Mastodon', 'Dezentralisiertes social Media', 'decentralized social media', 'Mastodon ist ein Microblogging Dienst im Fediverse. Ähnlich wie Twitter, aber besser.', 'Mastodon is a microblogging service on the fediverse, think twitter but better and more free.', '2023-07-15', '/links#Mastodon', 1),
|
|
||||||
(19, 'Cyber Security Challenge Deutschland', 'Cyber Security Challenge Germany', 'Nationaler IT-Sicherheitswettbewerb', 'National IT-Security Competition', 'Wettbewerb für Jugendliche (bis zu 25 Jahren) im Bereich IT-Sicherheit', 'Competition for youth (up to 25 years old) in Cybersecurity', '2023-09-27', '/links#Cyber Security Challenge Germany', 1);
|
|
||||||
|
|
||||||
-- --------------------------------------------------------
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Tabellenstruktur für Tabelle `start_searchable_keywords`
|
|
||||||
--
|
|
||||||
|
|
||||||
CREATE TABLE `start_searchable_keywords` (
|
|
||||||
`id` bigint(20) NOT NULL,
|
|
||||||
`searchable_id` bigint(20) NOT NULL,
|
|
||||||
`keyword_id` bigint(20) NOT NULL
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Daten für Tabelle `start_searchable_keywords`
|
|
||||||
--
|
|
||||||
|
|
||||||
INSERT INTO `start_searchable_keywords` (`id`, `searchable_id`, `keyword_id`) VALUES
|
|
||||||
(1, 1, 1),
|
|
||||||
(2, 2, 2),
|
|
||||||
(9, 3, 1),
|
|
||||||
(10, 3, 2),
|
|
||||||
(3, 3, 3),
|
|
||||||
(4, 4, 3),
|
|
||||||
(5, 4, 4),
|
|
||||||
(6, 5, 3),
|
|
||||||
(7, 5, 5),
|
|
||||||
(8, 5, 6),
|
|
||||||
(11, 6, 1),
|
|
||||||
(12, 6, 2),
|
|
||||||
(13, 6, 3),
|
|
||||||
(14, 6, 4),
|
|
||||||
(15, 6, 5),
|
|
||||||
(16, 6, 6),
|
|
||||||
(20, 10, 7),
|
|
||||||
(21, 11, 8),
|
|
||||||
(34, 17, 3),
|
|
||||||
(35, 18, 9),
|
|
||||||
(36, 18, 10),
|
|
||||||
(37, 19, 11);
|
|
||||||
|
|
||||||
-- --------------------------------------------------------
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Tabellenstruktur für Tabelle `start_staticsite`
|
|
||||||
--
|
|
||||||
|
|
||||||
CREATE TABLE `start_staticsite` (
|
|
||||||
`searchable_ptr_id` bigint(20) NOT NULL
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Daten für Tabelle `start_staticsite`
|
|
||||||
--
|
|
||||||
|
|
||||||
INSERT INTO `start_staticsite` (`searchable_ptr_id`) VALUES
|
|
||||||
(1),
|
|
||||||
(2);
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Indizes der exportierten Tabellen
|
|
||||||
--
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Indizes für die Tabelle `auth_group`
|
|
||||||
--
|
|
||||||
ALTER TABLE `auth_group`
|
|
||||||
ADD PRIMARY KEY (`id`),
|
|
||||||
ADD UNIQUE KEY `name` (`name`);
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Indizes für die Tabelle `auth_group_permissions`
|
|
||||||
--
|
|
||||||
ALTER TABLE `auth_group_permissions`
|
|
||||||
ADD PRIMARY KEY (`id`),
|
|
||||||
ADD UNIQUE KEY `auth_group_permissions_group_id_permission_id_0cd325b0_uniq` (`group_id`,`permission_id`),
|
|
||||||
ADD KEY `auth_group_permissio_permission_id_84c5c92e_fk_auth_perm` (`permission_id`);
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Indizes für die Tabelle `auth_permission`
|
|
||||||
--
|
|
||||||
ALTER TABLE `auth_permission`
|
|
||||||
ADD PRIMARY KEY (`id`),
|
|
||||||
ADD UNIQUE KEY `auth_permission_content_type_id_codename_01ab375a_uniq` (`content_type_id`,`codename`);
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Indizes für die Tabelle `auth_user`
|
|
||||||
--
|
|
||||||
ALTER TABLE `auth_user`
|
|
||||||
ADD PRIMARY KEY (`id`),
|
|
||||||
ADD UNIQUE KEY `username` (`username`);
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Indizes für die Tabelle `auth_user_groups`
|
|
||||||
--
|
|
||||||
ALTER TABLE `auth_user_groups`
|
|
||||||
ADD PRIMARY KEY (`id`),
|
|
||||||
ADD UNIQUE KEY `auth_user_groups_user_id_group_id_94350c0c_uniq` (`user_id`,`group_id`),
|
|
||||||
ADD KEY `auth_user_groups_group_id_97559544_fk_auth_group_id` (`group_id`);
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Indizes für die Tabelle `auth_user_user_permissions`
|
|
||||||
--
|
|
||||||
ALTER TABLE `auth_user_user_permissions`
|
|
||||||
ADD PRIMARY KEY (`id`),
|
|
||||||
ADD UNIQUE KEY `auth_user_user_permissions_user_id_permission_id_14a6b632_uniq` (`user_id`,`permission_id`),
|
|
||||||
ADD KEY `auth_user_user_permi_permission_id_1fbb5f2c_fk_auth_perm` (`permission_id`);
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Indizes für die Tabelle `blog_blogpost`
|
|
||||||
--
|
|
||||||
ALTER TABLE `blog_blogpost`
|
|
||||||
ADD PRIMARY KEY (`searchable_ptr_id`),
|
|
||||||
ADD KEY `blog_blogpost_category_id_0e9835dd_fk_blog_category_id` (`category_id`),
|
|
||||||
ADD KEY `blog_blogpost_slug_9e84ade1` (`slug`);
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Indizes für die Tabelle `blog_category`
|
|
||||||
--
|
|
||||||
ALTER TABLE `blog_category`
|
|
||||||
ADD PRIMARY KEY (`id`),
|
|
||||||
ADD KEY `blog_category_slug_92643dc5` (`slug`);
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Indizes für die Tabelle `django_admin_log`
|
|
||||||
--
|
|
||||||
ALTER TABLE `django_admin_log`
|
|
||||||
ADD PRIMARY KEY (`id`),
|
|
||||||
ADD KEY `django_admin_log_content_type_id_c4bce8eb_fk_django_co` (`content_type_id`),
|
|
||||||
ADD KEY `django_admin_log_user_id_c564eba6_fk_auth_user_id` (`user_id`);
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Indizes für die Tabelle `django_content_type`
|
|
||||||
--
|
|
||||||
ALTER TABLE `django_content_type`
|
|
||||||
ADD PRIMARY KEY (`id`),
|
|
||||||
ADD UNIQUE KEY `django_content_type_app_label_model_76bd3d3b_uniq` (`app_label`,`model`);
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Indizes für die Tabelle `django_migrations`
|
|
||||||
--
|
|
||||||
ALTER TABLE `django_migrations`
|
|
||||||
ADD PRIMARY KEY (`id`);
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Indizes für die Tabelle `django_session`
|
|
||||||
--
|
|
||||||
ALTER TABLE `django_session`
|
|
||||||
ADD PRIMARY KEY (`session_key`),
|
|
||||||
ADD KEY `django_session_expire_date_a5c62663` (`expire_date`);
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Indizes für die Tabelle `start_keyword`
|
|
||||||
--
|
|
||||||
ALTER TABLE `start_keyword`
|
|
||||||
ADD PRIMARY KEY (`id`);
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Indizes für die Tabelle `start_link`
|
|
||||||
--
|
|
||||||
ALTER TABLE `start_link`
|
|
||||||
ADD PRIMARY KEY (`url`),
|
|
||||||
ADD UNIQUE KEY `searchable_ptr_id` (`searchable_ptr_id`);
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Indizes für die Tabelle `start_searchable`
|
|
||||||
--
|
|
||||||
ALTER TABLE `start_searchable`
|
|
||||||
ADD PRIMARY KEY (`id`);
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Indizes für die Tabelle `start_searchable_keywords`
|
|
||||||
--
|
|
||||||
ALTER TABLE `start_searchable_keywords`
|
|
||||||
ADD PRIMARY KEY (`id`),
|
|
||||||
ADD UNIQUE KEY `start_searchable_keywords_searchable_id_keyword_id_2feb5e58_uniq` (`searchable_id`,`keyword_id`),
|
|
||||||
ADD KEY `start_searchable_key_keyword_id_230512a8_fk_start_key` (`keyword_id`);
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Indizes für die Tabelle `start_staticsite`
|
|
||||||
--
|
|
||||||
ALTER TABLE `start_staticsite`
|
|
||||||
ADD PRIMARY KEY (`searchable_ptr_id`);
|
|
||||||
|
|
||||||
--
|
|
||||||
-- AUTO_INCREMENT für exportierte Tabellen
|
|
||||||
--
|
|
||||||
|
|
||||||
--
|
|
||||||
-- AUTO_INCREMENT für Tabelle `auth_group`
|
|
||||||
--
|
|
||||||
ALTER TABLE `auth_group`
|
|
||||||
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;
|
|
||||||
|
|
||||||
--
|
|
||||||
-- AUTO_INCREMENT für Tabelle `auth_group_permissions`
|
|
||||||
--
|
|
||||||
ALTER TABLE `auth_group_permissions`
|
|
||||||
MODIFY `id` bigint(20) NOT NULL AUTO_INCREMENT;
|
|
||||||
|
|
||||||
--
|
|
||||||
-- AUTO_INCREMENT für Tabelle `auth_permission`
|
|
||||||
--
|
|
||||||
ALTER TABLE `auth_permission`
|
|
||||||
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=49;
|
|
||||||
|
|
||||||
--
|
|
||||||
-- AUTO_INCREMENT für Tabelle `auth_user`
|
|
||||||
--
|
|
||||||
ALTER TABLE `auth_user`
|
|
||||||
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=2;
|
|
||||||
|
|
||||||
--
|
|
||||||
-- AUTO_INCREMENT für Tabelle `auth_user_groups`
|
|
||||||
--
|
|
||||||
ALTER TABLE `auth_user_groups`
|
|
||||||
MODIFY `id` bigint(20) NOT NULL AUTO_INCREMENT;
|
|
||||||
|
|
||||||
--
|
|
||||||
-- AUTO_INCREMENT für Tabelle `auth_user_user_permissions`
|
|
||||||
--
|
|
||||||
ALTER TABLE `auth_user_user_permissions`
|
|
||||||
MODIFY `id` bigint(20) NOT NULL AUTO_INCREMENT;
|
|
||||||
|
|
||||||
--
|
|
||||||
-- AUTO_INCREMENT für Tabelle `blog_category`
|
|
||||||
--
|
|
||||||
ALTER TABLE `blog_category`
|
|
||||||
MODIFY `id` bigint(20) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=3;
|
|
||||||
|
|
||||||
--
|
|
||||||
-- AUTO_INCREMENT für Tabelle `django_admin_log`
|
|
||||||
--
|
|
||||||
ALTER TABLE `django_admin_log`
|
|
||||||
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=80;
|
|
||||||
|
|
||||||
--
|
|
||||||
-- AUTO_INCREMENT für Tabelle `django_content_type`
|
|
||||||
--
|
|
||||||
ALTER TABLE `django_content_type`
|
|
||||||
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=13;
|
|
||||||
|
|
||||||
--
|
|
||||||
-- AUTO_INCREMENT für Tabelle `django_migrations`
|
|
||||||
--
|
|
||||||
ALTER TABLE `django_migrations`
|
|
||||||
MODIFY `id` bigint(20) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=39;
|
|
||||||
|
|
||||||
--
|
|
||||||
-- AUTO_INCREMENT für Tabelle `start_keyword`
|
|
||||||
--
|
|
||||||
ALTER TABLE `start_keyword`
|
|
||||||
MODIFY `id` bigint(20) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=12;
|
|
||||||
|
|
||||||
--
|
|
||||||
-- AUTO_INCREMENT für Tabelle `start_searchable`
|
|
||||||
--
|
|
||||||
ALTER TABLE `start_searchable`
|
|
||||||
MODIFY `id` bigint(20) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=20;
|
|
||||||
|
|
||||||
--
|
|
||||||
-- AUTO_INCREMENT für Tabelle `start_searchable_keywords`
|
|
||||||
--
|
|
||||||
ALTER TABLE `start_searchable_keywords`
|
|
||||||
MODIFY `id` bigint(20) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=38;
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Constraints der exportierten Tabellen
|
|
||||||
--
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Constraints der Tabelle `auth_group_permissions`
|
|
||||||
--
|
|
||||||
ALTER TABLE `auth_group_permissions`
|
|
||||||
ADD CONSTRAINT `auth_group_permissio_permission_id_84c5c92e_fk_auth_perm` FOREIGN KEY (`permission_id`) REFERENCES `auth_permission` (`id`),
|
|
||||||
ADD CONSTRAINT `auth_group_permissions_group_id_b120cbf9_fk_auth_group_id` FOREIGN KEY (`group_id`) REFERENCES `auth_group` (`id`);
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Constraints der Tabelle `auth_permission`
|
|
||||||
--
|
|
||||||
ALTER TABLE `auth_permission`
|
|
||||||
ADD CONSTRAINT `auth_permission_content_type_id_2f476e4b_fk_django_co` FOREIGN KEY (`content_type_id`) REFERENCES `django_content_type` (`id`);
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Constraints der Tabelle `auth_user_groups`
|
|
||||||
--
|
|
||||||
ALTER TABLE `auth_user_groups`
|
|
||||||
ADD CONSTRAINT `auth_user_groups_group_id_97559544_fk_auth_group_id` FOREIGN KEY (`group_id`) REFERENCES `auth_group` (`id`),
|
|
||||||
ADD CONSTRAINT `auth_user_groups_user_id_6a12ed8b_fk_auth_user_id` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`);
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Constraints der Tabelle `auth_user_user_permissions`
|
|
||||||
--
|
|
||||||
ALTER TABLE `auth_user_user_permissions`
|
|
||||||
ADD CONSTRAINT `auth_user_user_permi_permission_id_1fbb5f2c_fk_auth_perm` FOREIGN KEY (`permission_id`) REFERENCES `auth_permission` (`id`),
|
|
||||||
ADD CONSTRAINT `auth_user_user_permissions_user_id_a95ead1b_fk_auth_user_id` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`);
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Constraints der Tabelle `blog_blogpost`
|
|
||||||
--
|
|
||||||
ALTER TABLE `blog_blogpost`
|
|
||||||
ADD CONSTRAINT `blog_blogpost_category_id_0e9835dd_fk_blog_category_id` FOREIGN KEY (`category_id`) REFERENCES `blog_category` (`id`),
|
|
||||||
ADD CONSTRAINT `blog_blogpost_searchable_ptr_id_2b1446e8_fk_start_searchable_id` FOREIGN KEY (`searchable_ptr_id`) REFERENCES `start_searchable` (`id`);
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Constraints der Tabelle `django_admin_log`
|
|
||||||
--
|
|
||||||
ALTER TABLE `django_admin_log`
|
|
||||||
ADD CONSTRAINT `django_admin_log_content_type_id_c4bce8eb_fk_django_co` FOREIGN KEY (`content_type_id`) REFERENCES `django_content_type` (`id`),
|
|
||||||
ADD CONSTRAINT `django_admin_log_user_id_c564eba6_fk_auth_user_id` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`);
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Constraints der Tabelle `start_link`
|
|
||||||
--
|
|
||||||
ALTER TABLE `start_link`
|
|
||||||
ADD CONSTRAINT `start_link_searchable_ptr_id_be644807_fk_start_searchable_id` FOREIGN KEY (`searchable_ptr_id`) REFERENCES `start_searchable` (`id`);
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Constraints der Tabelle `start_searchable_keywords`
|
|
||||||
--
|
|
||||||
ALTER TABLE `start_searchable_keywords`
|
|
||||||
ADD CONSTRAINT `start_searchable_key_keyword_id_230512a8_fk_start_key` FOREIGN KEY (`keyword_id`) REFERENCES `start_keyword` (`id`),
|
|
||||||
ADD CONSTRAINT `start_searchable_key_searchable_id_a2d58376_fk_start_sea` FOREIGN KEY (`searchable_id`) REFERENCES `start_searchable` (`id`);
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Constraints der Tabelle `start_staticsite`
|
|
||||||
--
|
|
||||||
ALTER TABLE `start_staticsite`
|
|
||||||
ADD CONSTRAINT `start_staticsite_searchable_ptr_id_aae84485_fk_start_sea` FOREIGN KEY (`searchable_ptr_id`) REFERENCES `start_searchable` (`id`);
|
|
||||||
COMMIT;
|
|
||||||
|
|
||||||
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
|
|
||||||
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
|
|
||||||
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
|
|
||||||
|
|
|
@ -8,3 +8,5 @@ RUN apt update && apt install -y gettext && rm -rf /var/lib/apt/lists/*
|
||||||
COPY requirements.txt /app/
|
COPY requirements.txt /app/
|
||||||
RUN pip install -r requirements.txt
|
RUN pip install -r requirements.txt
|
||||||
COPY . /app/
|
COPY . /app/
|
||||||
|
RUN mkdir -p /app/static
|
||||||
|
RUN pygmentize -S nord -f html -a .codehilite > /app/static/codehighlight.css
|
||||||
|
|
|
@ -6,4 +6,6 @@ django-libsass>=0.7
|
||||||
pillow>=9.0.0
|
pillow>=9.0.0
|
||||||
colorlog>=6.7.0
|
colorlog>=6.7.0
|
||||||
favicon>=0.7.0
|
favicon>=0.7.0
|
||||||
libpt>=0.1.5
|
markdown>=3.4.4
|
||||||
|
Pygments>=2.16.1
|
||||||
|
toml>=0.10
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
|
from django.urls import path
|
||||||
from django.utils.translation import gettext as _
|
from django.utils.translation import gettext as _
|
||||||
|
from django.http.response import HttpResponseRedirect
|
||||||
from .models import *
|
from .models import *
|
||||||
|
|
||||||
@admin.register(Category)
|
@admin.register(Category)
|
||||||
|
@ -15,6 +17,7 @@ def regenerate(modeladmin, request, queryset):
|
||||||
for obj in queryset:
|
for obj in queryset:
|
||||||
obj.regenerate()
|
obj.regenerate()
|
||||||
|
|
||||||
|
|
||||||
@admin.register(BlogPost)
|
@admin.register(BlogPost)
|
||||||
class BlogPostAdmin(admin.ModelAdmin):
|
class BlogPostAdmin(admin.ModelAdmin):
|
||||||
"""
|
"""
|
||||||
|
@ -24,3 +27,16 @@ class BlogPostAdmin(admin.ModelAdmin):
|
||||||
date_hierarchy = "date"
|
date_hierarchy = "date"
|
||||||
ordering = ['title_de', 'title_en']
|
ordering = ['title_de', 'title_en']
|
||||||
actions = [regenerate]
|
actions = [regenerate]
|
||||||
|
|
||||||
|
change_list_template = "admin/blogpost.html"
|
||||||
|
|
||||||
|
def get_urls(self):
|
||||||
|
urls = super().get_urls()
|
||||||
|
my_urls = [
|
||||||
|
path('sync/', self.sync_with_fs),
|
||||||
|
]
|
||||||
|
return my_urls + urls
|
||||||
|
|
||||||
|
def sync_with_fs(self, request):
|
||||||
|
BlogPost.sync_with_fs()
|
||||||
|
return HttpResponseRedirect("../")
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
date = "2023-10-02 09:59:00.127936"
|
||||||
|
update = "2023-10-02 10:59:00.127936"
|
||||||
|
keywords = ["bash"]
|
||||||
|
category = "Guide"
|
||||||
|
featured = true
|
||||||
|
public = true
|
||||||
|
thumbnail = "img/thumbnails/bash.png"
|
||||||
|
|
||||||
|
[lang.en]
|
||||||
|
title = "bash arrays"
|
||||||
|
subtitle = "how to work with bash arrays"
|
||||||
|
desc = """
|
||||||
|
bash scripting can be kind of weird.
|
||||||
|
This guide explains how they work without any fuzz.
|
||||||
|
"""
|
|
@ -0,0 +1,91 @@
|
||||||
|
**NOTE**
|
||||||
|
|
||||||
|
This is a stolen article from [opensource.com](https://opensource.com/article/18/5/you-dont-know-bash-intro-bash-arrays)
|
||||||
|
about bash scripting. It's a good article and I've decided to use it to test my
|
||||||
|
markdown rendering.
|
||||||
|
|
||||||
|
# GERMAN VERY YES YES
|
||||||
|
# Bash scripting
|
||||||
|
|
||||||
|
[TOC]
|
||||||
|
|
||||||
|
|
||||||
|
## Wait, but why?
|
||||||
|
|
||||||
|
Writing about Bash is challenging because it's remarkably easy for an article
|
||||||
|
to devolve into a manual that focuses on syntax oddities. Rest assured,
|
||||||
|
however, the intent of this article is to avoid having you RTFM.
|
||||||
|
|
||||||
|
## A real (actually useful) example
|
||||||
|
|
||||||
|
To that end, let's consider a real-world scenario and how Bash can help:
|
||||||
|
You are leading a new effort at your company to evaluate and optimize the
|
||||||
|
runtime of your internal data pipeline. As a first step, you want to do a
|
||||||
|
parameter sweep to evaluate how well the pipeline makes use of threads. For
|
||||||
|
the sake of simplicity, we'll treat the pipeline as a compiled C++ black box
|
||||||
|
where the only parameter we can tweak is the number of threads reserved for
|
||||||
|
data processing: `./pipeline --threads 4.`
|
||||||
|
|
||||||
|
## The basics
|
||||||
|
|
||||||
|
The first thing we'll do is define an array containing the values of the
|
||||||
|
`--threads` parameter that we want to test:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
allThreads=(1 2 4 8 16 32 64 128)
|
||||||
|
```
|
||||||
|
|
||||||
|
In this example, all the elements are numbers, but it need not be the
|
||||||
|
case—arrays in Bash can contain both numbers and strings, e.g., `myArray=(1
|
||||||
|
2 "three" 4 "five")` is a valid expression. And just as with any other Bash
|
||||||
|
variable, make sure to leave no spaces around the equal sign. Otherwise,
|
||||||
|
Bash will treat the variable name as a program to execute, and the `=` as its
|
||||||
|
first parameter!
|
||||||
|
|
||||||
|
Now that we've initialized the array, let's retrieve a few of its
|
||||||
|
elements. You'll notice that simply doing `echo $allThreads` will output only
|
||||||
|
the first element.
|
||||||
|
|
||||||
|
To understand why that is, let's take a step back and revisit how we usually
|
||||||
|
output variables in Bash. Consider the following scenario:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
type="article" echo "Found 42 $type"
|
||||||
|
```
|
||||||
|
|
||||||
|
Say the variable $type is given to us as a singular noun and we want to add
|
||||||
|
an `s` at the end of our sentence. We can't simply add an s to `$type` since
|
||||||
|
that would turn it into a different variable, `$types`. And although we could
|
||||||
|
utilize code contortions such as `echo "Found 42 "$type"s"`, the best way
|
||||||
|
to solve this problem is to use curly braces: `echo "Found 42 ${type}s"`,
|
||||||
|
which allows us to tell Bash where the name of a variable starts and ends
|
||||||
|
(interestingly, this is the same syntax used in JavaScript/ES6 to inject
|
||||||
|
variables and expressions in template literals).
|
||||||
|
|
||||||
|
So as it turns out, although Bash variables don't generally require curly
|
||||||
|
brackets, they are required for arrays. In turn, this allows us to specify
|
||||||
|
the index to access, e.g., `echo ${allThreads[1]}` returns the second element
|
||||||
|
of the array. Not including brackets, e.g.,`echo $allThreads[1]`, leads Bash
|
||||||
|
to treat `[1]` as a string and output it as such.
|
||||||
|
|
||||||
|
Yes, Bash arrays have odd syntax, but at least they are zero-indexed, unlike
|
||||||
|
some other languages (I'm looking at you, R).[^1]
|
||||||
|
|
||||||
|
## Looping through arrays
|
||||||
|
|
||||||
|
Although in the examples above we used integer indices in our arrays, let's
|
||||||
|
consider two occasions when that won't be the case: First, if we wanted the
|
||||||
|
$i-th element of the array, where $i is a variable containing the index of
|
||||||
|
interest, we can retrieve that element using: echo ${allThreads[$i]}. Second,
|
||||||
|
to output all the elements of an array, we replace the numeric index with
|
||||||
|
the @ symbol (you can think of @ as standing for all):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
type="article"
|
||||||
|
echo "Found 42 $type"
|
||||||
|
```
|
||||||
|
|
||||||
|
*[RTFM]: Read the Fucking Manual
|
||||||
|
*[HTML]: Hyper Text Markup Language
|
||||||
|
|
||||||
|
[^1]: Example Footnote
|
|
@ -0,0 +1,90 @@
|
||||||
|
**NOTE**
|
||||||
|
|
||||||
|
This is a stolen article from [opensource.com](https://opensource.com/article/18/5/you-dont-know-bash-intro-bash-arrays)
|
||||||
|
about bash scripting. It's a good article and I've decided to use it to test my
|
||||||
|
markdown rendering.
|
||||||
|
|
||||||
|
# Bash scripting
|
||||||
|
|
||||||
|
[TOC]
|
||||||
|
|
||||||
|
|
||||||
|
## Wait, but why?
|
||||||
|
|
||||||
|
Writing about Bash is challenging because it's remarkably easy for an article
|
||||||
|
to devolve into a manual that focuses on syntax oddities. Rest assured,
|
||||||
|
however, the intent of this article is to avoid having you RTFM.
|
||||||
|
|
||||||
|
## A real (actually useful) example
|
||||||
|
|
||||||
|
To that end, let's consider a real-world scenario and how Bash can help:
|
||||||
|
You are leading a new effort at your company to evaluate and optimize the
|
||||||
|
runtime of your internal data pipeline. As a first step, you want to do a
|
||||||
|
parameter sweep to evaluate how well the pipeline makes use of threads. For
|
||||||
|
the sake of simplicity, we'll treat the pipeline as a compiled C++ black box
|
||||||
|
where the only parameter we can tweak is the number of threads reserved for
|
||||||
|
data processing: `./pipeline --threads 4.`
|
||||||
|
|
||||||
|
## The basics
|
||||||
|
|
||||||
|
The first thing we'll do is define an array containing the values of the
|
||||||
|
`--threads` parameter that we want to test:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
allThreads=(1 2 4 8 16 32 64 128)
|
||||||
|
```
|
||||||
|
|
||||||
|
In this example, all the elements are numbers, but it need not be the
|
||||||
|
case—arrays in Bash can contain both numbers and strings, e.g., `myArray=(1
|
||||||
|
2 "three" 4 "five")` is a valid expression. And just as with any other Bash
|
||||||
|
variable, make sure to leave no spaces around the equal sign. Otherwise,
|
||||||
|
Bash will treat the variable name as a program to execute, and the `=` as its
|
||||||
|
first parameter!
|
||||||
|
|
||||||
|
Now that we've initialized the array, let's retrieve a few of its
|
||||||
|
elements. You'll notice that simply doing `echo $allThreads` will output only
|
||||||
|
the first element.
|
||||||
|
|
||||||
|
To understand why that is, let's take a step back and revisit how we usually
|
||||||
|
output variables in Bash. Consider the following scenario:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
type="article" echo "Found 42 $type"
|
||||||
|
```
|
||||||
|
|
||||||
|
Say the variable $type is given to us as a singular noun and we want to add
|
||||||
|
an `s` at the end of our sentence. We can't simply add an s to `$type` since
|
||||||
|
that would turn it into a different variable, `$types`. And although we could
|
||||||
|
utilize code contortions such as `echo "Found 42 "$type"s"`, the best way
|
||||||
|
to solve this problem is to use curly braces: `echo "Found 42 ${type}s"`,
|
||||||
|
which allows us to tell Bash where the name of a variable starts and ends
|
||||||
|
(interestingly, this is the same syntax used in JavaScript/ES6 to inject
|
||||||
|
variables and expressions in template literals).
|
||||||
|
|
||||||
|
So as it turns out, although Bash variables don't generally require curly
|
||||||
|
brackets, they are required for arrays. In turn, this allows us to specify
|
||||||
|
the index to access, e.g., `echo ${allThreads[1]}` returns the second element
|
||||||
|
of the array. Not including brackets, e.g.,`echo $allThreads[1]`, leads Bash
|
||||||
|
to treat `[1]` as a string and output it as such.
|
||||||
|
|
||||||
|
Yes, Bash arrays have odd syntax, but at least they are zero-indexed, unlike
|
||||||
|
some other languages (I'm looking at you, R).[^1]
|
||||||
|
|
||||||
|
## Looping through arrays
|
||||||
|
|
||||||
|
Although in the examples above we used integer indices in our arrays, let's
|
||||||
|
consider two occasions when that won't be the case: First, if we wanted the
|
||||||
|
$i-th element of the array, where $i is a variable containing the index of
|
||||||
|
interest, we can retrieve that element using: echo ${allThreads[$i]}. Second,
|
||||||
|
to output all the elements of an array, we replace the numeric index with
|
||||||
|
the @ symbol (you can think of @ as standing for all):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
type="article"
|
||||||
|
echo "Found 42 $type"
|
||||||
|
```
|
||||||
|
|
||||||
|
*[RTFM]: Read the Fucking Manual
|
||||||
|
*[HTML]: Hyper Text Markup Language
|
||||||
|
|
||||||
|
[^1]: Example Footnote
|
|
@ -1,12 +1,47 @@
|
||||||
# Generated by Django 3.2.19 on 2023-06-03 12:03
|
# Generated by Django 3.2.21 on 2023-10-02 08:14
|
||||||
|
|
||||||
from django.db import migrations
|
import blog.models
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
('start', '0001_initial'),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Category',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('name', models.CharField(max_length=50)),
|
||||||
|
('slug', models.SlugField(unique=True)),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Category',
|
||||||
|
'verbose_name_plural': 'Categories',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='BlogPost',
|
||||||
|
fields=[
|
||||||
|
('searchable_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='start.searchable')),
|
||||||
|
('body_en', models.TextField(blank=True, default='Dieser Artikel ist nicht auf deutsch verfügbar.')),
|
||||||
|
('body_de', models.TextField(blank=True, default='This aritcle is not available in english.')),
|
||||||
|
('thumbnail', models.ImageField(blank=True, default='img/thumbnails/default.jpg', upload_to='img/thumbnails')),
|
||||||
|
('featured', models.BooleanField(default=False)),
|
||||||
|
('langs', models.CharField(default="{'en': False, 'de': False}", max_length=64)),
|
||||||
|
('slug', models.SlugField()),
|
||||||
|
('category', models.ForeignKey(default=blog.models.Category.get_or_create_uncategorized, on_delete=django.db.models.deletion.SET_DEFAULT, to='blog.category')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'blog post',
|
||||||
|
'verbose_name_plural': 'blog posts',
|
||||||
|
},
|
||||||
|
bases=('start.searchable',),
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,35 +0,0 @@
|
||||||
# Generated by Django 3.2.19 on 2023-06-03 12:03
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
import django.db.models.deletion
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
initial = True
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('start', '0002_keyword_searchable_staticsite'),
|
|
||||||
('blog', '0001_initial'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='Category',
|
|
||||||
fields=[
|
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('name', models.CharField(max_length=50)),
|
|
||||||
('slug', models.SlugField()),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='BlogPost',
|
|
||||||
fields=[
|
|
||||||
('searchable_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='start.searchable')),
|
|
||||||
('body', models.TextField()),
|
|
||||||
('thumbnail', models.ImageField(blank=True, upload_to='')),
|
|
||||||
('category', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='blog.category')),
|
|
||||||
],
|
|
||||||
bases=('start.searchable',),
|
|
||||||
),
|
|
||||||
]
|
|
|
@ -1,18 +0,0 @@
|
||||||
# Generated by Django 3.2.19 on 2023-06-03 18:52
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('blog', '0002_blogpost_category'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='blogpost',
|
|
||||||
name='public',
|
|
||||||
field=models.BooleanField(default=True),
|
|
||||||
),
|
|
||||||
]
|
|
|
@ -1,19 +0,0 @@
|
||||||
# Generated by Django 3.2.19 on 2023-06-03 19:06
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('blog', '0003_blogpost_public'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='blogpost',
|
|
||||||
name='slug',
|
|
||||||
field=models.SlugField(default='test'),
|
|
||||||
preserve_default=False,
|
|
||||||
),
|
|
||||||
]
|
|
|
@ -1,23 +0,0 @@
|
||||||
# Generated by Django 3.2.19 on 2023-06-03 22:50
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('blog', '0004_blogpost_slug'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='blogpost',
|
|
||||||
name='featured',
|
|
||||||
field=models.BooleanField(default=False),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='blogpost',
|
|
||||||
name='thumbnail',
|
|
||||||
field=models.ImageField(blank=True, upload_to='img/thumbnails'),
|
|
||||||
),
|
|
||||||
]
|
|
|
@ -1,18 +0,0 @@
|
||||||
# Generated by Django 3.2.19 on 2023-06-03 22:55
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('blog', '0005_auto_20230604_0050'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='blogpost',
|
|
||||||
name='markdown',
|
|
||||||
field=models.BooleanField(default=False),
|
|
||||||
),
|
|
||||||
]
|
|
|
@ -1,17 +0,0 @@
|
||||||
# Generated by Django 3.2.19 on 2023-06-03 23:13
|
|
||||||
|
|
||||||
from django.db import migrations
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('blog', '0006_blogpost_markdown'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.RemoveField(
|
|
||||||
model_name='blogpost',
|
|
||||||
name='public',
|
|
||||||
),
|
|
||||||
]
|
|
|
@ -1,21 +0,0 @@
|
||||||
# Generated by Django 3.2.19 on 2023-06-03 23:56
|
|
||||||
|
|
||||||
from django.db import migrations
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('blog', '0007_remove_blogpost_public'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterModelOptions(
|
|
||||||
name='blogpost',
|
|
||||||
options={'verbose_name': 'blog post', 'verbose_name_plural': 'blog posts'},
|
|
||||||
),
|
|
||||||
migrations.AlterModelOptions(
|
|
||||||
name='category',
|
|
||||||
options={'verbose_name': 'Category', 'verbose_name_plural': 'Categories'},
|
|
||||||
),
|
|
||||||
]
|
|
|
@ -1,27 +0,0 @@
|
||||||
# Generated by Django 3.2.19 on 2023-06-16 20:36
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('blog', '0008_auto_20230604_0156'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.RemoveField(
|
|
||||||
model_name='blogpost',
|
|
||||||
name='body',
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='blogpost',
|
|
||||||
name='body_de',
|
|
||||||
field=models.TextField(default='Bis jetzt keine deutsche Übersetzung.'),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='blogpost',
|
|
||||||
name='body_en',
|
|
||||||
field=models.TextField(default='No english translation yet.'),
|
|
||||||
),
|
|
||||||
]
|
|
|
@ -1,10 +1,34 @@
|
||||||
|
import toml
|
||||||
|
import ast
|
||||||
|
import re
|
||||||
|
import os
|
||||||
|
import pathlib
|
||||||
|
import markdown
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.translation import gettext as _
|
from django.utils.translation import gettext as _
|
||||||
from start.models import Searchable
|
from start.models import Keyword, Searchable
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
EXTENSIONS = [
|
||||||
|
"extra",
|
||||||
|
"admonition",
|
||||||
|
"codehilite",
|
||||||
|
"meta",
|
||||||
|
"toc"
|
||||||
|
]
|
||||||
|
EXTENSION_CONFIGS = {
|
||||||
|
'codehilite': {
|
||||||
|
'linenums': True,
|
||||||
|
'pygments_style': 'monokai'
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
MD = markdown.Markdown(extensions=EXTENSIONS,
|
||||||
|
extension_configs=EXTENSION_CONFIGS)
|
||||||
|
|
||||||
|
|
||||||
class Category(models.Model):
|
class Category(models.Model):
|
||||||
"""
|
"""
|
||||||
A category of blog posts
|
A category of blog posts
|
||||||
|
@ -12,8 +36,8 @@ class Category(models.Model):
|
||||||
Name not translated because it would make i18n in urls and Searchables specifically a pain.
|
Name not translated because it would make i18n in urls and Searchables specifically a pain.
|
||||||
Maybe some day it would be cool if these were Searchable
|
Maybe some day it would be cool if these were Searchable
|
||||||
"""
|
"""
|
||||||
name= models.CharField(max_length=50)
|
name = models.CharField(max_length=50)
|
||||||
slug = models.SlugField()
|
slug = models.SlugField(unique=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _("Category")
|
verbose_name = _("Category")
|
||||||
|
@ -22,18 +46,46 @@ class Category(models.Model):
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f"{{<{self.__class__.__name__}>\"{self.name}\"}}"
|
return f"{{<{self.__class__.__name__}>\"{self.name}\"}}"
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_or_create_uncategorized():
|
||||||
|
try:
|
||||||
|
return Category.objects.get(slug="uncategorized")
|
||||||
|
except Category.DoesNotExist:
|
||||||
|
return Category.objects.create(
|
||||||
|
slug="uncategorized", name="uncategorized")
|
||||||
|
|
||||||
|
|
||||||
class BlogPost(Searchable):
|
class BlogPost(Searchable):
|
||||||
"""
|
"""
|
||||||
Should contain a blogpost
|
Should contain a blogpost
|
||||||
"""
|
"""
|
||||||
body_en = models.TextField(default="No english translation yet.")
|
DATA_DIR = "/app/blog/data/articles"
|
||||||
body_de = models.TextField(default="Bis jetzt keine deutsche Übersetzung.")
|
DEFAULT_LANGS = {'en': False, 'de': False}
|
||||||
category = models.ForeignKey(Category, on_delete=models.SET_NULL, null=True)
|
META_TOP_KEYS = [
|
||||||
thumbnail = models.ImageField(blank=True, upload_to="img/thumbnails")
|
"date",
|
||||||
featured = models.BooleanField(default=False)
|
"update",
|
||||||
markdown = models.BooleanField(default=False)
|
"keywords",
|
||||||
slug = models.SlugField()
|
"category",
|
||||||
|
"featured",
|
||||||
|
"public",
|
||||||
|
"lang"]
|
||||||
|
META_LANG_KEYS = ["title", "subtitle", "desc"]
|
||||||
|
|
||||||
|
body_en = models.TextField(blank=True,
|
||||||
|
default="""Dieser Artikel ist nicht auf deutsch verfügbar.""")
|
||||||
|
body_de = models.TextField(blank=True,
|
||||||
|
default="""This aritcle is not available in english.""")
|
||||||
|
category = models.ForeignKey(
|
||||||
|
Category, on_delete=models.SET_DEFAULT, null=False,
|
||||||
|
default=Category.get_or_create_uncategorized)
|
||||||
|
thumbnail = models.ImageField(
|
||||||
|
blank=True,
|
||||||
|
upload_to="img/thumbnails",
|
||||||
|
default="img/thumbnails/default.jpg")
|
||||||
|
featured = models.BooleanField(default=False)
|
||||||
|
langs = models.CharField(
|
||||||
|
default=DEFAULT_LANGS.__repr__(), max_length=64)
|
||||||
|
slug = models.SlugField()
|
||||||
|
|
||||||
def regenerate(self):
|
def regenerate(self):
|
||||||
"""
|
"""
|
||||||
|
@ -42,9 +94,207 @@ class BlogPost(Searchable):
|
||||||
Implements the abstract method of Searchable
|
Implements the abstract method of Searchable
|
||||||
"""
|
"""
|
||||||
logger.info(f"regenerating {self.__class__.__name__} object: {self}")
|
logger.info(f"regenerating {self.__class__.__name__} object: {self}")
|
||||||
|
# url stuff
|
||||||
self.suburl = f"/blog/{self.category.name}/{self.slug}"
|
self.suburl = f"/blog/{self.category.name}/{self.slug}"
|
||||||
|
|
||||||
|
# load from markdown
|
||||||
|
# self.sync_file()
|
||||||
|
|
||||||
|
# redundand vvvv
|
||||||
self.save()
|
self.save()
|
||||||
|
|
||||||
|
def sync_file(self):
|
||||||
|
"""
|
||||||
|
generate an article fromm it's original markdown file
|
||||||
|
"""
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
logger.info(f"syncing article to markdown for: {self}")
|
||||||
|
# read metadata
|
||||||
|
try:
|
||||||
|
fmeta = open(f"{self.DATA_DIR}/{self.slug}.toml", "r")
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"could not find meta file for '{self}'")
|
||||||
|
return
|
||||||
|
data = toml.load(fmeta)
|
||||||
|
langs = self.get_langs()
|
||||||
|
for key in self.META_TOP_KEYS:
|
||||||
|
if key not in data:
|
||||||
|
logger.error(f"Key '{key}' missing in meta file for '{self}'")
|
||||||
|
raise ValueError(
|
||||||
|
f"Key '{key}' missing in meta file for '{self}'")
|
||||||
|
for lang in self.DEFAULT_LANGS.keys():
|
||||||
|
if lang not in data['lang']:
|
||||||
|
langs[lang] = False
|
||||||
|
else:
|
||||||
|
langs[lang] = True
|
||||||
|
self.set_langs(langs)
|
||||||
|
for lang in data['lang']:
|
||||||
|
for key in self.META_LANG_KEYS:
|
||||||
|
if key not in data['lang'][lang]:
|
||||||
|
logger.warning(
|
||||||
|
f"Key '{key}' ('{lang}') missing in meta file for '{self}'")
|
||||||
|
langs[lang] = False
|
||||||
|
else:
|
||||||
|
langs[lang] = True
|
||||||
|
if not langs[lang]:
|
||||||
|
# no translation for this language
|
||||||
|
continue
|
||||||
|
with open(f"{self.DATA_DIR}/{lang}-{self.slug}.md") as f_en:
|
||||||
|
MD.reset()
|
||||||
|
body: str = f_en.read()
|
||||||
|
match lang:
|
||||||
|
case "en":
|
||||||
|
self.title_en = data['lang'][lang]["title"]
|
||||||
|
self.subtitle_en = data['lang'][lang]["subtitle"]
|
||||||
|
self.desc_en = data['lang'][lang]["desc"]
|
||||||
|
self.body_en = MD.convert(body)
|
||||||
|
case "de":
|
||||||
|
self.title_de = data['lang'][lang]["title"]
|
||||||
|
self.subtitle_de = data['lang'][lang]["subtitle"]
|
||||||
|
self.desc_de = data['lang'][lang]["desc"]
|
||||||
|
self.body_de = MD.convert(body)
|
||||||
|
case _:
|
||||||
|
logger.error(
|
||||||
|
f"unknown language '{lang}' in meta file for '{self}'")
|
||||||
|
self.date = data["date"]
|
||||||
|
self.update = data["update"]
|
||||||
|
self.featured = data["featured"]
|
||||||
|
self.public = data["public"]
|
||||||
|
# NOTE: thumbnail is optional
|
||||||
|
if "thumbnail" in data:
|
||||||
|
self.thumbnail = data["thumbnail"]
|
||||||
|
# NOTE: category is optional
|
||||||
|
if "category" in data:
|
||||||
|
try:
|
||||||
|
category: Category = Category.objects.get(
|
||||||
|
slug=data['category'])
|
||||||
|
except Category.DoesNotExist:
|
||||||
|
category = Category.objects.create(
|
||||||
|
name=data['category'], slug=data['category'])
|
||||||
|
self.category = category
|
||||||
|
self.save()
|
||||||
|
for keyword in data["keywords"]:
|
||||||
|
try:
|
||||||
|
self.keywords.add(Keyword.objects.get(slug=keyword))
|
||||||
|
except Keyword.DoesNotExist:
|
||||||
|
self.keywords.create(
|
||||||
|
slug=keyword, text_en=keyword, text_de=keyword)
|
||||||
|
self.save()
|
||||||
|
|
||||||
|
def get_langs(self) -> dict[str, bool]:
|
||||||
|
"""
|
||||||
|
get available languages
|
||||||
|
"""
|
||||||
|
# SECURITY:
|
||||||
|
# If someone could inject the langs field, literal_eval will evaluate to
|
||||||
|
# any literal Python value. This should not be a concern.
|
||||||
|
# If we would use a regular eval here, an attacker who controls one of
|
||||||
|
# the `langs` of a BlogPost could run arbitrary Python code.
|
||||||
|
try:
|
||||||
|
# literal_eval is safe because it only parses literals, not any kind
|
||||||
|
# of python expression. If the given str is not a valid literal,
|
||||||
|
# ValueError will be raised
|
||||||
|
langs = ast.literal_eval(str(self.langs))
|
||||||
|
return langs
|
||||||
|
except ValueError as e:
|
||||||
|
logger.error(
|
||||||
|
f"could not safely evaluate 'langs' for '{self}': {e}")
|
||||||
|
raise e
|
||||||
|
|
||||||
|
def set_langs(self, langs: dict[str, bool]):
|
||||||
|
"""
|
||||||
|
set available languages
|
||||||
|
"""
|
||||||
|
self.langs = langs.__repr__()
|
||||||
|
|
||||||
|
@ classmethod
|
||||||
|
def sync_with_fs(cls):
|
||||||
|
"""
|
||||||
|
Sync all Blog Posts with the filesystem.
|
||||||
|
|
||||||
|
Caution: Will delete all Blog Posts
|
||||||
|
"""
|
||||||
|
# logger.name = logger.name + ".sync_with_fs"
|
||||||
|
|
||||||
|
# delete all existing objects
|
||||||
|
BlogPost.objects.all().delete()
|
||||||
|
|
||||||
|
# check if the DATA_DIR is OK
|
||||||
|
data_dir = pathlib.Path(cls.DATA_DIR)
|
||||||
|
if not data_dir.exists():
|
||||||
|
logger.error(f"'{cls.DATA_DIR} does not exist'")
|
||||||
|
if not data_dir.is_dir():
|
||||||
|
logger.error(f"'{cls.DATA_DIR} is not a directory'")
|
||||||
|
|
||||||
|
files = [f for f in os.listdir(data_dir) if (
|
||||||
|
data_dir.joinpath(f)).is_file()]
|
||||||
|
logger.debug(f"discovered files: {files}")
|
||||||
|
|
||||||
|
# finding lang and title
|
||||||
|
regex = r"^(en|de)-(.*)\.md"
|
||||||
|
# TODO: only find toml files
|
||||||
|
|
||||||
|
# filepath, language codes, slug
|
||||||
|
files = [[f, cls.DEFAULT_LANGS, ""] for f in files]
|
||||||
|
for file in files:
|
||||||
|
# parse file name
|
||||||
|
try:
|
||||||
|
matches = re.match(regex, file[0])
|
||||||
|
if matches is None:
|
||||||
|
logger.warning(
|
||||||
|
f"Data file '{file[0]}' does not fit to the filename\
|
||||||
|
regex")
|
||||||
|
files.remove(file)
|
||||||
|
else:
|
||||||
|
current_lang = matches.group(1)
|
||||||
|
file[1][current_lang] = True
|
||||||
|
file[2] = matches.group(2)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(e)
|
||||||
|
files.remove(file)
|
||||||
|
|
||||||
|
# PERF:
|
||||||
|
# Optimize for single loop, should be doable and better design
|
||||||
|
|
||||||
|
# collapse diffrent versions
|
||||||
|
for file in files:
|
||||||
|
try:
|
||||||
|
if [_f[2] for _f in files].count(file[2]) >= 2:
|
||||||
|
logger.debug(f"multiple versions of '{file[2]}'")
|
||||||
|
versions = [_f for _f in files if _f[2] == file[2]]
|
||||||
|
lang: dict[str, bool] = file[1]
|
||||||
|
for version in versions:
|
||||||
|
for key in version[1]:
|
||||||
|
lang[key] |= version[1][key]
|
||||||
|
else:
|
||||||
|
# only a single version of this file
|
||||||
|
continue
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(
|
||||||
|
f"Could not combine BlogPosts for '{file[0]}': {e}")
|
||||||
|
|
||||||
|
# TODO: not needed when relying on toml files
|
||||||
|
try:
|
||||||
|
# deduplicate
|
||||||
|
_files = []
|
||||||
|
for f in [[_f[1], _f[2]]
|
||||||
|
for _f in files]: # dont care about fname
|
||||||
|
if f not in _files:
|
||||||
|
_files.append(f)
|
||||||
|
files = _files
|
||||||
|
logger.debug(f"to save: {files}")
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Could not dedup BlogPosts: {e}")
|
||||||
|
|
||||||
|
for file in files:
|
||||||
|
try:
|
||||||
|
obj = BlogPost(langs=file[0], slug=file[1])
|
||||||
|
obj.sync_file()
|
||||||
|
obj.regenerate()
|
||||||
|
obj.save()
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Could not create BlogPost for '{file[1]}': {e}")
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _("blog post")
|
verbose_name = _("blog post")
|
||||||
verbose_name_plural = _("blog posts")
|
verbose_name_plural = _("blog posts")
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
{% extends 'admin/change_list.html' %} {% block object-tools %}
|
||||||
|
<form action="sync" method="POST">
|
||||||
|
{% csrf_token %}
|
||||||
|
<button type="submit" class="button" style="padding: 4px">Sync with FS</button>
|
||||||
|
</form>
|
||||||
|
{{ block.super }} {% endblock %}
|
|
@ -1,69 +1,96 @@
|
||||||
{% extends 'base.html' %}
|
{% extends 'base.html' %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
{% load helper_tags %}
|
||||||
{% get_current_language as LANGUAGE_CODE %}
|
{% get_current_language as LANGUAGE_CODE %}
|
||||||
{% block languagecode %}{{ LANGUAGE_CODE }}{% endblock languagecode %}
|
{% block languagecode %}
|
||||||
{% block title %}{% translate "cscherr.de" %} - {% translate "Blog" %}{% endblock title %}
|
{{ LANGUAGE_CODE }}
|
||||||
|
{% endblock languagecode %}
|
||||||
|
{% block title %}
|
||||||
|
{% translate "cscherr.de" %} - {% translate "Blog" %}
|
||||||
|
{% endblock title %}
|
||||||
{% block nav %}
|
{% block nav %}
|
||||||
{% include 'nav.html' %}
|
{% include 'nav.html' %}
|
||||||
{% endblock nav %}
|
{% endblock nav %}
|
||||||
{% block headscripts %}
|
{% block headscripts %}
|
||||||
<script type="text/javascript" id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@3.0.0/es5/tex-mml-chtml.js"></script>
|
<script type="text/javascript"
|
||||||
|
id="MathJax-script"
|
||||||
|
async
|
||||||
|
src="https://cdn.jsdelivr.net/npm/mathjax@3.0.0/es5/tex-mml-chtml.js"></script>
|
||||||
{% endblock headscripts %}
|
{% endblock headscripts %}
|
||||||
{% block main %}
|
{% block main %}
|
||||||
<div class="container-xl">
|
<div class="container-xl">
|
||||||
<article>
|
<article>
|
||||||
<div class="jumbotron my-5">
|
<div class="jumbotron my-5">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
|
<picture>
|
||||||
|
<img src="{{ post.thumbnail.url }}" alt="thumbnail" class="img-fluid">
|
||||||
|
</picture>
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
<div class="row py-5">
|
||||||
|
{% if LANGUAGE_CODE == "de" %}
|
||||||
|
<h1 class="">
|
||||||
|
{{ post.title_de }}
|
||||||
|
<br>
|
||||||
|
<small class="fs-4">{{ post.subtitle_de }}</small>
|
||||||
|
</h1>
|
||||||
|
<br>
|
||||||
|
{% elif LANGUAGE_CODE == "en" %}
|
||||||
|
<h1 class="">
|
||||||
|
{{ post.title_en }}
|
||||||
|
<br>
|
||||||
|
<small class="fs-4">{{ post.subtitle_en }}</small>
|
||||||
|
</h1>
|
||||||
|
<br>
|
||||||
|
{% else %}
|
||||||
|
<h1 class="">
|
||||||
|
{{ post.title_en }}
|
||||||
|
<br>
|
||||||
|
<small class="fs-4">{{ post.subtitle_en }}</small>
|
||||||
|
</h1>
|
||||||
|
<br>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
<div class="row py-5">
|
||||||
|
{% if LANGUAGE_CODE == "de" %}
|
||||||
|
<p class="lead">{{ post.desc_de }}</p>
|
||||||
|
{% elif LANGUAGE_CODE == "en" %}
|
||||||
|
<p class="lead">{{ post.desc_en }}</p>
|
||||||
|
{% else %}
|
||||||
|
<p class="lead">{{ post.desc_en }}</p>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
<div class="row py-5">
|
||||||
|
<p>
|
||||||
|
<b>{{ post.category.name }}<b>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<hr>
|
||||||
|
<div class="my-5">
|
||||||
{% if LANGUAGE_CODE == "de" %}
|
{% if LANGUAGE_CODE == "de" %}
|
||||||
<h1 class="">{{ post.title_de }}<br>
|
{{ post.body_de | safe }}
|
||||||
<small class="fs-4">{{ post.subtitle_de }}</small></h1><br>
|
|
||||||
{% elif LANGUAGE_CODE == "en" %}
|
{% elif LANGUAGE_CODE == "en" %}
|
||||||
<h1 class="">{{ post.title_en }}<br>
|
{{ post.body_en | safe }}
|
||||||
<small class="fs-4">{{ post.subtitle_en }}</small></h1><br>
|
|
||||||
{% else %}
|
{% else %}
|
||||||
<h1 class="">{{ post.title_en }}<br>
|
{{ post.body_en | safe }}
|
||||||
<small class="fs-4">{{ post.subtitle_en }}</small></h1><br>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<hr>
|
||||||
<div class="row align-items-center text-center">
|
<div class="row text-center">
|
||||||
<div class="col">
|
|
||||||
<picture>
|
|
||||||
<img src="{{ post.thumbnail.url }}" alt="thumbnail" class="img-fluid">
|
|
||||||
</picture>
|
|
||||||
</div>
|
|
||||||
<div class="col px-3">
|
|
||||||
<div class="col">
|
<div class="col">
|
||||||
{% if LANGUAGE_CODE == "de" %}
|
{% format_time post.date as date %}
|
||||||
<p class="lead">{{ post.desc_de }}</p>
|
<p>{% trans "published" %}: {{ date }}</p>
|
||||||
{% elif LANGUAGE_CODE == "en" %}
|
|
||||||
<p class="lead">{{ post.desc_en }}</p>
|
|
||||||
{% else %}
|
|
||||||
<p class="lead">{{ post.desc_en }}</p>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<p>{{ post.date }}</p>
|
{% format_time post.update as update %}
|
||||||
</div>
|
<p>{% trans "updated" %}: {{ update }}</p>
|
||||||
<div class="col">
|
|
||||||
<p>{{ post.category.name }}</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</article>
|
||||||
</div>
|
</div>
|
||||||
<hr>
|
{% include 'blog/featured.html' %}
|
||||||
<div class="my-5">
|
{% endblock main %}
|
||||||
{% if LANGUAGE_CODE == "de" %}
|
|
||||||
{{ post.body_de | safe }}
|
|
||||||
{% elif LANGUAGE_CODE == "en" %}
|
|
||||||
{{ post.body_en | safe }}
|
|
||||||
{% else %}
|
|
||||||
{{ post.body_en | safe }}
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
<hr>
|
|
||||||
</article>
|
|
||||||
</div>
|
|
||||||
{% include 'blog/featured.html' %}
|
|
||||||
{% endblock main %}
|
|
||||||
|
|
|
@ -1,40 +1,59 @@
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
{% load helper_tags %}
|
||||||
{% get_current_language as LANGUAGE_CODE %}
|
{% get_current_language as LANGUAGE_CODE %}
|
||||||
<div class="container-lg mt-5">
|
<div class="container-lg mt-5">
|
||||||
<h4 class="">{% trans "Featured" %}</h4>
|
<h4 class="">{% trans "Featured" %}</h4>
|
||||||
<div class="row row-cols-1 row-cols-md-5 my-4">
|
<div class="row row-cols-1 row-cols-md-5 my-4">
|
||||||
{% for post in featured_posts %}
|
{% for post in featured_posts %}
|
||||||
<div class="card col m-2 p-0">
|
<div class="card col m-2 p-0">
|
||||||
<a class="text-reset link-offset-2 link-underline link-underline-opacity-0" href=" {% url 'blog:post' post.category.slug post.slug %}">
|
<a class="text-reset link-offset-2 link-underline link-underline-opacity-0"
|
||||||
<img src="{{ post.thumbnail.url }}" class="card-img-top img-fluid" style="max-height: 150px;" alt="thumbnail">
|
href=" {% url 'blog:post' post.category.slug post.slug %}">
|
||||||
<div class="card-body" style="height: 100px;">
|
<img src="{{ post.thumbnail.url }}"
|
||||||
{% if LANGUAGE_CODE == "de" %}
|
class="card-img-top img-fluid mx-auto d-block"
|
||||||
<h5 class="card-title">{{ post.title_de }}<small class="text-body-secondary">{{ post.subtitle }}</small></h5>
|
style="max-height: 150px; width: auto; padding-top: 8px;"
|
||||||
<p class="card-text">{{ post.desc_de }}</p>
|
alt="thumbnail" />
|
||||||
{% elif LANGUAGE_CODE == "en" %}
|
<div class="card-body" style="height: 100px">
|
||||||
<h5 class="card-title">{{ post.title_en }}<small class="text-body-secondary">{{ post.subtitle }}</small></h5>
|
|
||||||
<p class="card-text">{{ post.desc_en }}</p>
|
|
||||||
{% else %}
|
|
||||||
<h5 class="card-title">{{ post.title_en }}<small class="text-body-secondary">{{ post.subtitle }}</small></h5>
|
|
||||||
<p class="card-text">{{ post.desc_en }}</p>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
<div class="container pt-5">
|
|
||||||
<ul class="list-group list-group-flush">
|
|
||||||
<li class="list-group-item">{% translate "category" %}: <b>{{ post.category.name }}</b></li>
|
|
||||||
{% for keyword in post.keywords.all %}
|
|
||||||
{% if LANGUAGE_CODE == "de" %}
|
{% if LANGUAGE_CODE == "de" %}
|
||||||
<li class="list-group-item">{{ keyword.text_de }}</li>
|
<h5 class="card-title">
|
||||||
|
{{ post.title_de }}<small class="text-body-secondary">{{ post.subtitle }}</small>
|
||||||
|
</h5>
|
||||||
|
<p class="card-text">{{ post.desc_de }}</p>
|
||||||
{% elif LANGUAGE_CODE == "en" %}
|
{% elif LANGUAGE_CODE == "en" %}
|
||||||
<li class="list-group-item">{{ keyword.text_en }}</li>
|
<h5 class="card-title">
|
||||||
|
{{ post.title_en }}<small class="text-body-secondary">{{ post.subtitle }}</small>
|
||||||
|
</h5>
|
||||||
|
<p class="card-text">{{ post.desc_en }}</p>
|
||||||
{% else %}
|
{% else %}
|
||||||
<li class="list-group-item">{{ keyword.text_en }}</li>
|
<h5 class="card-title">
|
||||||
|
{{ post.title_en }}<small class="text-body-secondary">{{ post.subtitle }}</small>
|
||||||
|
</h5>
|
||||||
|
<p class="card-text">{{ post.desc_en }}</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
</div>
|
||||||
</ul>
|
<div class="container pt-5">
|
||||||
</div>
|
<ul class="list-group list-group-flush">
|
||||||
</a>
|
<li class="list-group-item">
|
||||||
</div>
|
{% translate "category" %}: <b>{{ post.category.name }}</b>
|
||||||
|
</li>
|
||||||
|
{% for keyword in post.keywords.all %}
|
||||||
|
{% if LANGUAGE_CODE == "de" %}
|
||||||
|
<li class="list-group-item">{{ keyword.text_de }}</li>
|
||||||
|
{% elif LANGUAGE_CODE == "en" %}
|
||||||
|
<li class="list-group-item">{{ keyword.text_en }}</li>
|
||||||
|
{% else %}
|
||||||
|
<li class="list-group-item">{{ keyword.text_en }}</li>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="container p-1 text-center" style="border-top: solid">
|
||||||
|
<li class="list-group-item">
|
||||||
|
{% format_time post.date "%F" as date %}
|
||||||
|
{% trans "published" %}: {{ date }}
|
||||||
|
</li>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -11,6 +11,8 @@ https://docs.djangoproject.com/en/3.2/ref/settings/
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# for getting envvars
|
# for getting envvars
|
||||||
|
import logging
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
import os
|
import os
|
||||||
|
|
||||||
# default django
|
# default django
|
||||||
|
@ -35,7 +37,7 @@ ALLOWED_HOSTS = ["*"]
|
||||||
|
|
||||||
# Allow inclusion of stuff from these origins
|
# Allow inclusion of stuff from these origins
|
||||||
CORS_ALLOWED_ORIGINS = [
|
CORS_ALLOWED_ORIGINS = [
|
||||||
"https://static.cscherr.de",
|
"https://static.cscherr.de",
|
||||||
]
|
]
|
||||||
|
|
||||||
# Application definition
|
# Application definition
|
||||||
|
@ -100,7 +102,6 @@ DATABASES = {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Password validation
|
# Password validation
|
||||||
# https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators
|
# https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators
|
||||||
|
|
||||||
|
@ -123,7 +124,6 @@ AUTH_PASSWORD_VALIDATORS = [
|
||||||
# Internationalization
|
# Internationalization
|
||||||
# https://docs.djangoproject.com/en/3.2/topics/i18n/
|
# https://docs.djangoproject.com/en/3.2/topics/i18n/
|
||||||
|
|
||||||
from django.utils.translation import gettext_lazy as _
|
|
||||||
|
|
||||||
LANGUAGES = [
|
LANGUAGES = [
|
||||||
("de", _("German")),
|
("de", _("German")),
|
||||||
|
@ -155,10 +155,10 @@ STATIC_URL = '/static/'
|
||||||
COMPRESS_ENABLED = True
|
COMPRESS_ENABLED = True
|
||||||
|
|
||||||
STATICFILES_FINDERS = [
|
STATICFILES_FINDERS = [
|
||||||
'django.contrib.staticfiles.finders.FileSystemFinder',
|
'django.contrib.staticfiles.finders.FileSystemFinder',
|
||||||
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
|
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
|
||||||
'compressor.finders.CompressorFinder',
|
'compressor.finders.CompressorFinder',
|
||||||
]
|
]
|
||||||
|
|
||||||
COMPRESS_PRECOMPILERS = (
|
COMPRESS_PRECOMPILERS = (
|
||||||
('text/x-scss', 'django_libsass.SassCompiler'),
|
('text/x-scss', 'django_libsass.SassCompiler'),
|
||||||
|
@ -173,7 +173,6 @@ DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
||||||
|
|
||||||
# Logging configs
|
# Logging configs
|
||||||
|
|
||||||
import logging
|
|
||||||
|
|
||||||
myServerFormatter = ServerFormatter
|
myServerFormatter = ServerFormatter
|
||||||
myServerFormatter.default_time_format = "%Y-%M-%d %H:%M:%S"
|
myServerFormatter.default_time_format = "%Y-%M-%d %H:%M:%S"
|
||||||
|
@ -294,7 +293,7 @@ LOGGING = {
|
||||||
# Media stuff
|
# Media stuff
|
||||||
# this is where user uploaded files will go.
|
# this is where user uploaded files will go.
|
||||||
# TODO change this for prod
|
# TODO change this for prod
|
||||||
#MEDIA_ROOT = "/home/plex/Documents/code/python/gawa/media"
|
# MEDIA_ROOT = "/home/plex/Documents/code/python/gawa/media"
|
||||||
MEDIA_ROOT = "/app/media"
|
MEDIA_ROOT = "/app/media"
|
||||||
MEDIA_URL = "/media/"
|
MEDIA_URL = "/media/"
|
||||||
FILE_UPLOAD_TEMP_DIR = "/tmp/gawa/upload"
|
# FILE_UPLOAD_TEMP_DIR = "/tmp/gawa/upload"
|
||||||
|
|
|
@ -14,14 +14,14 @@ Including another URLconf
|
||||||
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
|
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
|
||||||
"""
|
"""
|
||||||
from django.conf.urls.i18n import i18n_patterns
|
from django.conf.urls.i18n import i18n_patterns
|
||||||
from django.conf.urls import url
|
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
|
from django.urls import include, re_path
|
||||||
from django.urls import include, path
|
from django.urls import include, path
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.conf.urls.static import static
|
from django.conf.urls.static import static
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
url(r'^i18n/', include('django.conf.urls.i18n')),
|
re_path(r'^i18n/', include('django.conf.urls.i18n')),
|
||||||
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
||||||
|
|
||||||
urlpatterns += i18n_patterns(
|
urlpatterns += i18n_patterns(
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 62 KiB |
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
Binary file not shown.
After Width: | Height: | Size: 21 KiB |
Binary file not shown.
Before Width: | Height: | Size: 26 KiB |
|
@ -10,6 +10,7 @@ def regenerate(modeladmin, request, queryset):
|
||||||
for obj in queryset:
|
for obj in queryset:
|
||||||
obj.regenerate()
|
obj.regenerate()
|
||||||
|
|
||||||
|
|
||||||
@admin.register(Keyword)
|
@admin.register(Keyword)
|
||||||
class KeywordAdmin(admin.ModelAdmin):
|
class KeywordAdmin(admin.ModelAdmin):
|
||||||
"""
|
"""
|
||||||
|
@ -17,21 +18,25 @@ class KeywordAdmin(admin.ModelAdmin):
|
||||||
"""
|
"""
|
||||||
list_display = ["text_en", "text_de"]
|
list_display = ["text_en", "text_de"]
|
||||||
|
|
||||||
|
|
||||||
@admin.register(StaticSite)
|
@admin.register(StaticSite)
|
||||||
class StaticSiteAdmin(admin.ModelAdmin):
|
class StaticSiteAdmin(admin.ModelAdmin):
|
||||||
"""
|
"""
|
||||||
Admin Interface for StaticSite
|
Admin Interface for StaticSite
|
||||||
"""
|
"""
|
||||||
list_display = ["title_en", "subtitle_en", "title_de", "subtitle_de", "suburl"]
|
list_display = ["title_en", "subtitle_en",
|
||||||
|
"title_de", "subtitle_de", "suburl"]
|
||||||
ordering = ['title_de', 'title_en']
|
ordering = ['title_de', 'title_en']
|
||||||
actions = [regenerate]
|
actions = [regenerate]
|
||||||
|
|
||||||
|
|
||||||
@admin.register(Searchable)
|
@admin.register(Searchable)
|
||||||
class SearchableAdmin(admin.ModelAdmin):
|
class SearchableAdmin(admin.ModelAdmin):
|
||||||
"""
|
"""
|
||||||
Abstract Admin Interface for all Searchables
|
Abstract Admin Interface for all Searchables
|
||||||
"""
|
"""
|
||||||
list_display = ["title_en", "subtitle_en", "title_de", "subtitle_de", "suburl"]
|
list_display = ["title_en", "subtitle_en",
|
||||||
|
"title_de", "subtitle_de", "suburl"]
|
||||||
ordering = ['title_de', 'title_en']
|
ordering = ['title_de', 'title_en']
|
||||||
actions = [regenerate]
|
actions = [regenerate]
|
||||||
|
|
||||||
|
@ -41,6 +46,7 @@ class LinkAdmin(admin.ModelAdmin):
|
||||||
"""
|
"""
|
||||||
Admin Interface for Links
|
Admin Interface for Links
|
||||||
"""
|
"""
|
||||||
list_display = ["title_en", "title_de", "url", "suburl", "favicon", "status", "personal"]
|
list_display = ["title_en", "title_de", "url",
|
||||||
|
"suburl", "favicon", "status", "personal"]
|
||||||
ordering = ['status', 'title_de', 'title_en']
|
ordering = ['status', 'title_de', 'title_en']
|
||||||
actions = [regenerate]
|
actions = [regenerate]
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
from django.apps import AppConfig
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
class StartConfig(AppConfig):
|
class StartConfig(AppConfig):
|
||||||
default_auto_field = 'django.db.models.BigAutoField'
|
default_auto_field = 'django.db.models.BigAutoField'
|
||||||
name = 'start'
|
name = 'start'
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.utils.translation import gettext as _
|
from django.utils.translation import gettext as _
|
||||||
|
|
||||||
|
|
||||||
class MainSearchForm(forms.Form):
|
class MainSearchForm(forms.Form):
|
||||||
search = forms.CharField(
|
search = forms.CharField(
|
||||||
max_length=100,
|
max_length=100,
|
||||||
label=''
|
label=''
|
||||||
)
|
)
|
||||||
search.widget = forms.TextInput(
|
search.widget = forms.TextInput(
|
||||||
attrs={
|
attrs={
|
||||||
|
|
|
@ -15,7 +15,8 @@ class LangBasedOnUrlMiddleware(MiddlewareMixin):
|
||||||
def process_request(request):
|
def process_request(request):
|
||||||
|
|
||||||
if hasattr(request, 'session'):
|
if hasattr(request, 'session'):
|
||||||
active_session_lang = request.session.get(translation.LANGUAGE_SESSION_KEY)
|
active_session_lang = request.session.get(
|
||||||
|
translation.LANGUAGE_SESSION_KEY)
|
||||||
|
|
||||||
if active_session_lang == request.LANGUAGE_CODE:
|
if active_session_lang == request.LANGUAGE_CODE:
|
||||||
return
|
return
|
||||||
|
|
|
@ -1,12 +1,75 @@
|
||||||
# Generated by Django 3.2.19 on 2023-06-03 12:03
|
# Generated by Django 3.2.21 on 2023-10-02 08:14
|
||||||
|
|
||||||
from django.db import migrations
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Keyword',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('slug', models.SlugField(unique=True)),
|
||||||
|
('text_de', models.CharField(max_length=40)),
|
||||||
|
('text_en', models.CharField(max_length=40)),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Keyword',
|
||||||
|
'verbose_name_plural': 'keywords',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Searchable',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('title_de', models.CharField(default='Nicht übersetzt', max_length=50)),
|
||||||
|
('title_en', models.CharField(default='Not translated', max_length=50)),
|
||||||
|
('subtitle_de', models.CharField(blank=True, max_length=50)),
|
||||||
|
('subtitle_en', models.CharField(blank=True, max_length=50)),
|
||||||
|
('desc_de', models.TextField(blank=True, default='Keine Beschreibung', max_length=250)),
|
||||||
|
('desc_en', models.TextField(blank=True, default='no description', max_length=250)),
|
||||||
|
('date', models.DateTimeField(blank=True, null=True)),
|
||||||
|
('update', models.DateTimeField(blank=True, null=True)),
|
||||||
|
('suburl', models.CharField(blank=True, max_length=200, null=True)),
|
||||||
|
('public', models.BooleanField(default=False)),
|
||||||
|
('keywords', models.ManyToManyField(blank=True, to='start.Keyword')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Searchable',
|
||||||
|
'verbose_name_plural': 'Searchables',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Link',
|
||||||
|
fields=[
|
||||||
|
('searchable_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, to='start.searchable')),
|
||||||
|
('url', models.URLField(primary_key=True, serialize=False, unique=True)),
|
||||||
|
('favicon', models.ImageField(blank=True, null=True, upload_to='img/links/favicons')),
|
||||||
|
('status', models.BooleanField(default=False)),
|
||||||
|
('personal', models.BooleanField(default=False)),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Link',
|
||||||
|
'verbose_name_plural': 'Links',
|
||||||
|
},
|
||||||
|
bases=('start.searchable',),
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='StaticSite',
|
||||||
|
fields=[
|
||||||
|
('searchable_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='start.searchable')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'static site',
|
||||||
|
'verbose_name_plural': 'static sites',
|
||||||
|
},
|
||||||
|
bases=('start.searchable',),
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,46 +0,0 @@
|
||||||
# Generated by Django 3.2.19 on 2023-06-03 12:03
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
import django.db.models.deletion
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
initial = True
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('start', '0001_initial'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='Keyword',
|
|
||||||
fields=[
|
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('text_de', models.CharField(max_length=40)),
|
|
||||||
('text_en', models.CharField(max_length=40)),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='Searchable',
|
|
||||||
fields=[
|
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('title_de', models.CharField(default='Titel DE', max_length=50)),
|
|
||||||
('title_en', models.CharField(default='title en', max_length=50)),
|
|
||||||
('subtitle_de', models.CharField(blank=True, max_length=50)),
|
|
||||||
('subtitle_en', models.CharField(blank=True, max_length=50)),
|
|
||||||
('desc_de', models.CharField(default='Beschreibung DE', max_length=250, unique=True)),
|
|
||||||
('desc_en', models.CharField(default='Description EN', max_length=250, unique=True)),
|
|
||||||
('date', models.DateField(blank=True, null=True)),
|
|
||||||
('suburl', models.CharField(blank=True, max_length=200, null=True)),
|
|
||||||
('keywords', models.ManyToManyField(to='start.Keyword')),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='StaticSite',
|
|
||||||
fields=[
|
|
||||||
('searchable_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='start.searchable')),
|
|
||||||
],
|
|
||||||
bases=('start.searchable',),
|
|
||||||
),
|
|
||||||
]
|
|
|
@ -1,18 +0,0 @@
|
||||||
# Generated by Django 3.2.19 on 2023-06-03 23:13
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('start', '0002_keyword_searchable_staticsite'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='searchable',
|
|
||||||
name='public',
|
|
||||||
field=models.BooleanField(default=True),
|
|
||||||
),
|
|
||||||
]
|
|
|
@ -1,35 +0,0 @@
|
||||||
# Generated by Django 3.2.19 on 2023-06-04 21:12
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('start', '0003_searchable_public'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterModelOptions(
|
|
||||||
name='keyword',
|
|
||||||
options={'verbose_name': 'Keyword', 'verbose_name_plural': 'keywords'},
|
|
||||||
),
|
|
||||||
migrations.AlterModelOptions(
|
|
||||||
name='searchable',
|
|
||||||
options={'verbose_name': 'Searchable', 'verbose_name_plural': 'Searchables'},
|
|
||||||
),
|
|
||||||
migrations.AlterModelOptions(
|
|
||||||
name='staticsite',
|
|
||||||
options={'verbose_name': 'static site', 'verbose_name_plural': 'static sites'},
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='searchable',
|
|
||||||
name='desc_de',
|
|
||||||
field=models.CharField(default='Beschreibung DE', max_length=250),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='searchable',
|
|
||||||
name='desc_en',
|
|
||||||
field=models.CharField(default='Description EN', max_length=250),
|
|
||||||
),
|
|
||||||
]
|
|
|
@ -1,26 +0,0 @@
|
||||||
# Generated by Django 3.2.19 on 2023-06-05 16:15
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
import django.db.models.deletion
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('start', '0004_auto_20230604_2312'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='Link',
|
|
||||||
fields=[
|
|
||||||
('searchable_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, to='start.searchable')),
|
|
||||||
('url', models.URLField(primary_key=True, serialize=False, unique=True)),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'verbose_name': 'Link',
|
|
||||||
'verbose_name_plural': 'Links',
|
|
||||||
},
|
|
||||||
bases=('start.searchable',),
|
|
||||||
),
|
|
||||||
]
|
|
|
@ -1,18 +0,0 @@
|
||||||
# Generated by Django 3.2.19 on 2023-06-05 16:18
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('start', '0005_link'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='searchable',
|
|
||||||
name='title_en',
|
|
||||||
field=models.CharField(default='title EN', max_length=50),
|
|
||||||
),
|
|
||||||
]
|
|
|
@ -1,18 +0,0 @@
|
||||||
# Generated by Django 3.2.19 on 2023-06-05 17:48
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('start', '0006_alter_searchable_title_en'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='link',
|
|
||||||
name='favicon',
|
|
||||||
field=models.ImageField(blank=True, upload_to='img/links/favicons'),
|
|
||||||
),
|
|
||||||
]
|
|
|
@ -1,18 +0,0 @@
|
||||||
# Generated by Django 3.2.19 on 2023-06-05 20:55
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('start', '0007_link_favicon'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='link',
|
|
||||||
name='status',
|
|
||||||
field=models.BooleanField(default=False),
|
|
||||||
),
|
|
||||||
]
|
|
|
@ -1,18 +0,0 @@
|
||||||
# Generated by Django 3.2.19 on 2023-06-05 23:01
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('start', '0008_link_status'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='link',
|
|
||||||
name='favicon',
|
|
||||||
field=models.ImageField(blank=True, null=True, upload_to='img/links/favicons'),
|
|
||||||
),
|
|
||||||
]
|
|
|
@ -1,18 +0,0 @@
|
||||||
# Generated by Django 3.2.19 on 2023-07-15 12:29
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('start', '0009_alter_link_favicon'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='link',
|
|
||||||
name='personal',
|
|
||||||
field=models.BooleanField(default=False),
|
|
||||||
),
|
|
||||||
]
|
|
|
@ -1,23 +0,0 @@
|
||||||
# Generated by Django 3.2.19 on 2023-07-15 12:41
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('start', '0010_link_personal'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='searchable',
|
|
||||||
name='desc_de',
|
|
||||||
field=models.TextField(default='Beschreibung DE', max_length=250),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='searchable',
|
|
||||||
name='desc_en',
|
|
||||||
field=models.TextField(default='Description EN', max_length=250),
|
|
||||||
),
|
|
||||||
]
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
import random
|
||||||
|
import favicon
|
||||||
|
import requests
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.db.models.options import override
|
from django.db.models.options import override
|
||||||
from django.utils.translation import gettext as _
|
from django.utils.translation import gettext as _
|
||||||
|
@ -8,24 +11,23 @@ from django.conf import settings
|
||||||
import logging
|
import logging
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
import requests
|
|
||||||
import favicon
|
|
||||||
import random
|
|
||||||
|
|
||||||
class Keyword(models.Model):
|
class Keyword(models.Model):
|
||||||
"""
|
"""
|
||||||
this is the model that should contain searchable keywords
|
this is the model that should contain searchable keywords
|
||||||
"""
|
"""
|
||||||
|
slug = models.SlugField(unique=True)
|
||||||
text_de = models.CharField(max_length=40)
|
text_de = models.CharField(max_length=40)
|
||||||
text_en = models.CharField(max_length=40)
|
text_en = models.CharField(max_length=40)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f"{{<{self.__class__.__name__}>\"{self.text_en}\"}}"
|
return f"{{<{self.__class__.__name__}>\"{self.slug}\"}}"
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _("Keyword")
|
verbose_name = _("Keyword")
|
||||||
verbose_name_plural = _("keywords")
|
verbose_name_plural = _("keywords")
|
||||||
|
|
||||||
|
|
||||||
class Searchable(models.Model):
|
class Searchable(models.Model):
|
||||||
"""
|
"""
|
||||||
Abstract class for any model that should be searchable.
|
Abstract class for any model that should be searchable.
|
||||||
|
@ -33,17 +35,19 @@ class Searchable(models.Model):
|
||||||
|
|
||||||
This class is not a real abstract class, I need to query it in the main search, so thats impossible
|
This class is not a real abstract class, I need to query it in the main search, so thats impossible
|
||||||
"""
|
"""
|
||||||
title_de = models.CharField(max_length=50, default="Titel DE")
|
title_de = models.CharField(max_length=50, default="Nicht übersetzt")
|
||||||
title_en = models.CharField(max_length=50, default="title EN")
|
title_en = models.CharField(max_length=50, default="Not translated")
|
||||||
subtitle_de = models.CharField(max_length=50, blank=True)
|
subtitle_de = models.CharField(max_length=50, blank=True)
|
||||||
subtitle_en = models.CharField(max_length=50, blank=True)
|
subtitle_en = models.CharField(max_length=50, blank=True)
|
||||||
desc_de = models.TextField(max_length=250, unique=False, default="Beschreibung DE")
|
desc_de = models.TextField(
|
||||||
desc_en = models.TextField(max_length=250, unique=False, default="Description EN")
|
blank=True, max_length=250, unique=False, default="Keine Beschreibung")
|
||||||
# may be empty/blank for some entries
|
desc_en = models.TextField(
|
||||||
date = models.DateField(blank=True, null=True)
|
blank=True, max_length=250, unique=False, default="no description")
|
||||||
keywords = models.ManyToManyField(Keyword)
|
date = models.DateTimeField(blank=True, null=True)
|
||||||
|
update = models.DateTimeField(blank=True, null=True)
|
||||||
|
keywords = models.ManyToManyField(Keyword, blank=True)
|
||||||
suburl = models.CharField(max_length=200, blank=True, null=True)
|
suburl = models.CharField(max_length=200, blank=True, null=True)
|
||||||
public = models.BooleanField(default=True)
|
public = models.BooleanField(default=False)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def regenerate_all_entries(cls):
|
def regenerate_all_entries(cls):
|
||||||
|
@ -55,18 +59,20 @@ class Searchable(models.Model):
|
||||||
obj.regenerate()
|
obj.regenerate()
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f"{{<{self.__class__.__name__}>\"{self.title_en}\"}}"
|
return f"{{<{self.__class__.__name__}>\"{self.slug}\"}}"
|
||||||
|
|
||||||
def regenerate(self):
|
def regenerate(self):
|
||||||
"""
|
"""
|
||||||
regenerate a object
|
regenerate a object
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError(f"{self.__class__.__name__} does not implement regenerate")
|
raise NotImplementedError(
|
||||||
|
f"{self.__class__.__name__} does not implement regenerate")
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _("Searchable")
|
verbose_name = _("Searchable")
|
||||||
verbose_name_plural = _("Searchables")
|
verbose_name_plural = _("Searchables")
|
||||||
|
|
||||||
|
|
||||||
class StaticSite(Searchable):
|
class StaticSite(Searchable):
|
||||||
"""
|
"""
|
||||||
This model represents any static site, such as start:index,
|
This model represents any static site, such as start:index,
|
||||||
|
@ -75,20 +81,21 @@ class StaticSite(Searchable):
|
||||||
Every searchable view should inherit from start.views.SearchableView.
|
Every searchable view should inherit from start.views.SearchableView.
|
||||||
# TODO automate scanning for SearchableView classes
|
# TODO automate scanning for SearchableView classes
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def regenerate(self):
|
def regenerate(self):
|
||||||
"""
|
"""
|
||||||
regenerate a object
|
regenerate a object
|
||||||
"""
|
"""
|
||||||
logger.info(f"regenerating {self.__class__.__name__} object: {self}")
|
logger.info(f"regenerating {self.__class__.__name__} object: {self}")
|
||||||
logger.warning(f"{self.__class__.__name__} cannot regenerate.")
|
logger.warning(f"{self.__class__.__name__} cannot regenerate.")
|
||||||
#self.save()
|
# self.save()
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _("static site")
|
verbose_name = _("static site")
|
||||||
verbose_name_plural = _("static sites")
|
verbose_name_plural = _("static sites")
|
||||||
|
|
||||||
|
|
||||||
class Link(Searchable):
|
class Link(Searchable):
|
||||||
"""
|
"""
|
||||||
contains all my interesting links
|
contains all my interesting links
|
||||||
|
@ -121,11 +128,13 @@ class Link(Searchable):
|
||||||
icons = favicon.get(self.url, timeout=2)
|
icons = favicon.get(self.url, timeout=2)
|
||||||
except (ConnectionError) as ce:
|
except (ConnectionError) as ce:
|
||||||
# just keep whatever was stored if we cant get a new favicon
|
# just keep whatever was stored if we cant get a new favicon
|
||||||
logger.warn(f"unable to download favicon for {self}: {ce.with_traceback(None)}")
|
logger.warn(
|
||||||
|
f"unable to download favicon for {self}: {ce.with_traceback(None)}")
|
||||||
self.status = False
|
self.status = False
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(f"Unexpected Exception while downloading {self}: {e.with_traceback(None)}")
|
logger.warn(
|
||||||
|
f"Unexpected Exception while downloading {self}: {e.with_traceback(None)}")
|
||||||
self.status = False
|
self.status = False
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
@ -144,9 +153,10 @@ class Link(Searchable):
|
||||||
except FileNotFoundError as fe:
|
except FileNotFoundError as fe:
|
||||||
logger.error(f"cant write favicon to file for {self}: {fe}")
|
logger.error(f"cant write favicon to file for {self}: {fe}")
|
||||||
self.favicon = None
|
self.favicon = None
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(f"Unexpected Exception while downloading {self}: {e.with_traceback(None)}")
|
logger.warn(
|
||||||
|
f"Unexpected Exception while downloading {self}: {e.with_traceback(None)}")
|
||||||
self.favicon = None
|
self.favicon = None
|
||||||
|
|
||||||
self.save()
|
self.save()
|
||||||
|
|
|
@ -11,13 +11,9 @@
|
||||||
{% compress css %}
|
{% compress css %}
|
||||||
<link type="text/x-scss" href="/static/bs5/scss/bootstrap.scss" rel="stylesheet" media="screen">
|
<link type="text/x-scss" href="/static/bs5/scss/bootstrap.scss" rel="stylesheet" media="screen">
|
||||||
<link rel="stylesheet" href="/static/bsi1/font/bootstrap-icons.min.css">
|
<link rel="stylesheet" href="/static/bsi1/font/bootstrap-icons.min.css">
|
||||||
|
<link rel="stylesheet" href="/static/codehighlight.css">
|
||||||
|
<link rel="stylesheet" href="/static/custom.css">
|
||||||
{% endcompress %}
|
{% endcompress %}
|
||||||
<script>
|
|
||||||
const setTheme = theme => {
|
|
||||||
document.documentElement.setAttribute('data-bs-theme', theme)
|
|
||||||
}
|
|
||||||
setTheme(localStorage.getItem('theme'));
|
|
||||||
</script>
|
|
||||||
{% block headscripts %}
|
{% block headscripts %}
|
||||||
{% endblock headscripts %}
|
{% endblock headscripts %}
|
||||||
</head>
|
</head>
|
||||||
|
@ -106,6 +102,7 @@
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
{% compress js %}
|
{% compress js %}
|
||||||
|
<script src="/static/custom.js"></script>
|
||||||
<script src="/static/bs5/dist/js/bootstrap.bundle.min.js"></script>
|
<script src="/static/bs5/dist/js/bootstrap.bundle.min.js"></script>
|
||||||
{% endcompress %}
|
{% endcompress %}
|
||||||
</body>
|
</body>
|
||||||
|
|
|
@ -1,23 +0,0 @@
|
||||||
<button type="button" class="btn btn-dark" id="toggleThemeButton">
|
|
||||||
<i id="toggleThemeIcon" class="bi bi-sun"></i>
|
|
||||||
</button>
|
|
||||||
<script>
|
|
||||||
'use strict'
|
|
||||||
let i = document.getElementById("toggleThemeIcon").className = "bi bi-sun";
|
|
||||||
const storedTheme = localStorage.getItem('theme');
|
|
||||||
if (storedTheme == null) {
|
|
||||||
localStorage.setItem("theme", "light");
|
|
||||||
document.getElementById("toggleThemeIcon").className = "bi bi-sun-fill";
|
|
||||||
setTheme("light");
|
|
||||||
}
|
|
||||||
else if (storedTheme == "dark") {
|
|
||||||
localStorage.setItem("theme", "dark");
|
|
||||||
document.getElementById("toggleThemeIcon").className = "bi bi-sun";
|
|
||||||
setTheme("dark");
|
|
||||||
}
|
|
||||||
else if (storedTheme == "light") {
|
|
||||||
localStorage.setItem("theme", "light");
|
|
||||||
document.getElementById("toggleThemeIcon").className = "bi bi-sun-fill";
|
|
||||||
setTheme("light");
|
|
||||||
}
|
|
||||||
</script>
|
|
|
@ -51,7 +51,7 @@
|
||||||
</a>
|
</a>
|
||||||
<ul class="dropdown-menu">
|
<ul class="dropdown-menu">
|
||||||
{% for lang_code, lang_name in languages %}
|
{% for lang_code, lang_name in languages %}
|
||||||
<li><a class="dropdown-item"
|
<li><a class="dropdown-item"
|
||||||
href="{% change_lang lang_code %}">
|
href="{% change_lang lang_code %}">
|
||||||
{{ lang_name }}</a></li>
|
{{ lang_name }}</a></li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
@ -60,31 +60,12 @@
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
{% include 'dark_light_switch.html' %}
|
<button type="button" class="btn btn-dark" id="toggleThemeButton">
|
||||||
|
<i id="toggleThemeIcon" class="bi bi-sun"></i>
|
||||||
|
</button>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
{% include 'main_search_form.html' %}
|
{% include 'main_search_form.html' %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script>
|
|
||||||
'use strict'
|
|
||||||
document.getElementById("toggleThemeButton").onclick = function () {
|
|
||||||
const storedTheme = localStorage.getItem('theme');
|
|
||||||
if (storedTheme == null) {
|
|
||||||
localStorage.setItem("theme", "dark");
|
|
||||||
document.getElementById("toggleThemeIcon").className = "bi bi-sun";
|
|
||||||
setTheme("dark");
|
|
||||||
}
|
|
||||||
else if (storedTheme == "dark") {
|
|
||||||
localStorage.setItem("theme", "light");
|
|
||||||
document.getElementById("toggleThemeIcon").className = "bi bi-sun-fill";
|
|
||||||
setTheme("light");
|
|
||||||
}
|
|
||||||
else if (storedTheme == "light") {
|
|
||||||
localStorage.setItem("theme", "dark");
|
|
||||||
document.getElementById("toggleThemeIcon").className = "bi bi-sun";
|
|
||||||
setTheme("dark");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
</nav>
|
</nav>
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
from django.template import Library
|
from django.template import Library
|
||||||
from django.urls import resolve, reverse
|
from django.urls import resolve, reverse
|
||||||
from django.utils.translation import activate, get_language
|
from django.utils.translation import activate, get_language
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
@ -9,6 +10,9 @@ logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
register = Library()
|
register = Library()
|
||||||
|
|
||||||
|
@register.simple_tag
|
||||||
|
def format_time(timestamp: datetime, format: str = "%F %H:%M:%S %Z") -> str:
|
||||||
|
return timestamp.strftime(format)
|
||||||
|
|
||||||
@register.simple_tag(takes_context=True)
|
@register.simple_tag(takes_context=True)
|
||||||
def change_lang(context, lang="de", *args, **kwargs):
|
def change_lang(context, lang="de", *args, **kwargs):
|
||||||
|
@ -19,18 +23,21 @@ def change_lang(context, lang="de", *args, **kwargs):
|
||||||
shamelessly stolen from stackoverflow:
|
shamelessly stolen from stackoverflow:
|
||||||
https://stackoverflow.com/a/41147772
|
https://stackoverflow.com/a/41147772
|
||||||
"""
|
"""
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
path = context['request'].get_raw_uri()
|
|
||||||
url = path
|
|
||||||
try:
|
try:
|
||||||
cur_lang: str = get_language()
|
path = context['request'].get_raw_uri()
|
||||||
url = re.sub(f"/{cur_lang}/", f"/{lang}/", url)
|
url = path
|
||||||
|
try:
|
||||||
|
cur_lang: str = get_language()
|
||||||
|
url = re.sub(f"/{cur_lang}/", f"/{lang}/", url)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"exception while building language switcher form: {e}")
|
||||||
|
logger.debug(f"this is the context: {context}")
|
||||||
|
|
||||||
|
finally:
|
||||||
|
activate(lang)
|
||||||
|
return "%s" % url
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"exception while building language switcher form: {e}")
|
logger.error(f"passing error chain: {e}")
|
||||||
logger.debug(f"this is the context: {context}")
|
|
||||||
|
|
||||||
finally:
|
|
||||||
activate(lang)
|
|
||||||
return "%s" % url
|
|
||||||
|
|
||||||
|
|
|
@ -9,5 +9,6 @@ urlpatterns = [
|
||||||
path("legal/", views.LegalInfo.as_view(), name="legal"),
|
path("legal/", views.LegalInfo.as_view(), name="legal"),
|
||||||
path("links/", views.Links.as_view(), name="links"),
|
path("links/", views.Links.as_view(), name="links"),
|
||||||
path("professional/", views.LegalInfo.as_view(), name="professional"),
|
path("professional/", views.LegalInfo.as_view(), name="professional"),
|
||||||
path('language/activate/<language_code>/', views.ActivateLanguage.as_view(), name='activate_language'),
|
path('language/activate/<language_code>/',
|
||||||
|
views.ActivateLanguage.as_view(), name='activate_language'),
|
||||||
]
|
]
|
||||||
|
|
|
@ -18,6 +18,7 @@ from abc import ABC
|
||||||
import logging
|
import logging
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class SearchableView(View, ABC):
|
class SearchableView(View, ABC):
|
||||||
"""
|
"""
|
||||||
This abstract view implements some traits of views that should show up
|
This abstract view implements some traits of views that should show up
|
||||||
|
@ -40,6 +41,7 @@ class Index(TemplateView, SearchableView):
|
||||||
|
|
||||||
template_name: str = "start/index.html"
|
template_name: str = "start/index.html"
|
||||||
|
|
||||||
|
|
||||||
class Professional(TemplateView, SearchableView):
|
class Professional(TemplateView, SearchableView):
|
||||||
"""
|
"""
|
||||||
Professional informations that might interest a professional employer
|
Professional informations that might interest a professional employer
|
||||||
|
@ -47,6 +49,7 @@ class Professional(TemplateView, SearchableView):
|
||||||
# TODO
|
# TODO
|
||||||
template_name: str = "start/legalinfo.html"
|
template_name: str = "start/legalinfo.html"
|
||||||
|
|
||||||
|
|
||||||
class LegalInfo(TemplateView, SearchableView):
|
class LegalInfo(TemplateView, SearchableView):
|
||||||
"""
|
"""
|
||||||
Legal info that the german authorities want.
|
Legal info that the german authorities want.
|
||||||
|
@ -54,20 +57,22 @@ class LegalInfo(TemplateView, SearchableView):
|
||||||
# TODO
|
# TODO
|
||||||
template_name: str = "start/legalinfo.html"
|
template_name: str = "start/legalinfo.html"
|
||||||
|
|
||||||
|
|
||||||
class ActivateLanguage(View):
|
class ActivateLanguage(View):
|
||||||
"""
|
"""
|
||||||
Set the language to whatever
|
Set the language to whatever
|
||||||
"""
|
"""
|
||||||
language_code = ''
|
language_code = ''
|
||||||
redirect_to = ''
|
redirect_to = ''
|
||||||
|
|
||||||
def get(self, request, *args, **kwargs):
|
def get(self, request, *args, **kwargs):
|
||||||
self.redirect_to = request.META.get('HTTP_REFERER')
|
self.redirect_to = request.META.get('HTTP_REFERER')
|
||||||
self.language_code = kwargs.get('language_code')
|
self.language_code = kwargs.get('language_code')
|
||||||
translation.activate(self.language_code)
|
translation.activate(self.language_code)
|
||||||
request.session[translation.LANGUAGE_SESSION_KEY] = self.language_code
|
request.session[translation.LANGUAGE_SESSION_KEY] = self.language_code
|
||||||
return redirect(self.redirect_to)
|
return redirect(self.redirect_to)
|
||||||
|
|
||||||
|
|
||||||
class MainSearch(ListView):
|
class MainSearch(ListView):
|
||||||
"""
|
"""
|
||||||
Search for anything.
|
Search for anything.
|
||||||
|
@ -94,6 +99,7 @@ class MainSearch(ListView):
|
||||||
return render(request, "errors/bad_request.html")
|
return render(request, "errors/bad_request.html")
|
||||||
return super().get(request, *args, **kwargs)
|
return super().get(request, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class Links(ListView):
|
class Links(ListView):
|
||||||
"""
|
"""
|
||||||
This View contains links to various interesting sites.
|
This View contains links to various interesting sites.
|
||||||
|
@ -115,6 +121,6 @@ class Links(ListView):
|
||||||
return object_list
|
return object_list
|
||||||
|
|
||||||
def get_context_data(self, *, object_list=None, **kwargs):
|
def get_context_data(self, *, object_list=None, **kwargs):
|
||||||
context = super().get_context_data(object_list=object_list, **kwargs)
|
context = super().get_context_data(object_list=object_list, **kwargs)
|
||||||
context['personal_links'] = self.get_queryset_personal_links()
|
context['personal_links'] = self.get_queryset_personal_links()
|
||||||
return context
|
return context
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
#!/bin/bash
|
||||||
|
docker compose exec main python /app/manage.py makemigrations
|
||||||
|
docker compose exec main python /app/manage.py migrate
|
|
@ -0,0 +1,10 @@
|
||||||
|
Django>=3.0,<4.0
|
||||||
|
psycopg2>=2.8
|
||||||
|
mysqlclient>=1.4.3
|
||||||
|
django_compressor>=2.2
|
||||||
|
django-libsass>=0.7
|
||||||
|
pillow>=9.0.0
|
||||||
|
colorlog>=6.7.0
|
||||||
|
favicon>=0.7.0
|
||||||
|
markdown>=3.4.4
|
||||||
|
Pygments>=2.16.1
|
Loading…
Reference in New Issue