(in-package #:cl-user) (defpackage #:nera-db (:nicknames #:nera) (:use #:cl #:app-constants #:hermetic #:ritherdon-archive.db #:utils #:user #:pages #:files #:site-settings #:archive) (:export #:init-db #:update-user #:get-user #:get-user-id #:delete-user #:create-user #:get-site-settings #:migrate-all #:get-all-users #:update-enable-sign-on-settings #:set-home-page #:update-enable-site-logo-setting #:update-site-name #:create-page #:update-page #:get-page #:delete-page #:get-all-pages #:nav-menu-slugs #:update-nav-menu #:system-data #:add-storage-file #:get-storage-file #:get-all-storage-files #:rename-storage-file #:delete-storage-file #:get-all-archive-entries #:create-archive-entry #:get-archive-entry #:delete-archive-entry #:update-archive-entry-property #:latest-archive-editted-entries #:latest-editted-pages #:latest-storage-editted-files)) (in-package #:nera-db) (defparameter *tables* '(user site-settings page storage-file archive-entry) "List of the DB tables that need to be checked for migrations and DB setup.") (defun init-db (request) "Creates the database and creates Admin. in `USER' table." (destructuring-bind (&key username display-name password allow-sign-up &allow-other-keys) (utils:request-params request) (with-connection (db) ;; Add to the list to add more tables. (mapcar #'mito:ensure-table-exists *tables*) (mito:create-dao 'user :username username :display-name display-name :password (hermetic::hash password) :administrator +true+) (mito:create-dao 'site-settings :enable-sign-up (utils:checkbox-to-bool allow-sign-up)) (mito:create-dao 'page :title "Home" :slug "home" :enable-nav-menu +true+ :can-delete +true+) (mito:create-dao 'page :title "About" :slug "about" :enable-nav-menu +true+ :can-delete +true+) (mito:create-dao 'page :title "Contact" :slug "contact" :enable-nav-menu +true+ :can-delete +true+) (mito:create-dao 'page :title "Pages" :slug "pages" :enable-nav-menu +true+ :can-delete +false+) (mito:create-dao 'page :title "Archive" :slug "archive" :enable-nav-menu +true+ :can-delete +false+) (mito:create-dao 'page :title "Sign-Up" :slug "sign-up" :enable-nav-menu +true+ :can-delete +false+) (mito:create-dao 'page :title "Log-In" :slug "login" :enable-nav-menu +true+ :can-delete +false+)))) (defun ensure-tables-exist () "Creates missing tables from the database." (with-connection (db) (mapcar #'mito:ensure-table-exists *tables*))) (defun migrate-all () "Migrate the tables after we changed the class definition." (with-connection (db) (ensure-tables-exist) (mapcar #'mito:migrate-table *tables*))) (defun create-user (username display-name password administrator) "Add a new `USER' to the database." (with-connection (db) (mito:create-dao 'user :username username :display-name display-name :administrator administrator :password (hermetic::hash password)))) (defun delete-user (username) "Deletes `USER' from the database." (with-connection (db) (mito:delete-by-values 'user:user :username username))) (defun update-user (username &key display-name new-password) "Updates `USER' in database." (with-connection (db) (let ((user-to-update (mito:find-dao 'user:user :username username))) (if (not (utils:string-is-nil-or-empty? display-name)) (setf (user::display-name-of user-to-update) display-name)) (if (not (utils:string-is-nil-or-empty? new-password)) (setf (user::password-of user-to-update) (hermetic::hash new-password))) (mito:save-dao user-to-update)))) (defun get-user-id (username) "Returns the Id. number of the specified `USERNAME' in the database." (with-connection (db) (mito:object-id (mito:find-dao 'user :username username)))) (defun get-user (username) "Returns a `USER' profile from the database." (with-connection (db) (mito:find-dao 'user :username username))) (defun get-all-users () "Returns a list of all `USER' entries in the database." (with-connection (db) (mito:select-dao 'user (sxql:order-by (:asc :display-name))))) (defun get-page (slug) "Returns a `PAGE' from the database." (with-connection (db) (mito:find-dao 'page :slug slug))) (defun get-all-pages () "Returns a list of all `PAGE' entries in the database." (with-connection (db) (mito:select-dao 'page (sxql:order-by (:asc :slug))))) (defun latest-editted-pages (amount &optional reverse) "Gets the latest `AMOUNT' of edited entries from the database. `REVERSE' is an optional parameter which puts the most recently editted article entry as the first item in the list.." (with-connection (db) (mito:select-dao 'pages:page (sxql:limit amount) (if reverse (sxql:order-by (:desc 'pages::updated-at)) (sxql:order-by 'pages::updated-at))))) (defun create-page (title slug nav-menu can-delete) "Add a new `PAGE' to the database." (with-connection (db) (mito:create-dao 'page :title title :slug slug :enable-nav-menu nav-menu :can-delete can-delete))) (defun update-page (id title slug &optional nav-menu can-delete) "Add a new `PAGE' to the database." (with-connection (db) (let ((page-to-update (mito:find-dao 'page :id id))) (if (not (utils:string-is-nil-or-empty? title)) (setf (pages::title-of page-to-update) title)) (if (not (utils:string-is-nil-or-empty? slug)) (setf (pages::slug-of page-to-update) slug)) (if (not (null nav-menu)) (setf (pages::enable-nav-menu-p page-to-update) nav-menu)) (if (not (null can-delete)) (setf (pages::can-delete-p page-to-update) can-delete)) (mito:save-dao page-to-update)))) (defun delete-page (&key id slug) "Delete `PAGE' from the database." (with-connection (db) (cond ((not slug) (mito:delete-dao (mito:find-dao 'page :id id))) ((not id) (mito:delete-dao (mito:find-dao 'page :slug slug))) (t nil)))) (defun get-site-settings () "Gets the settings for the website from the database." (with-connection (db) (mito:find-dao 'site-settings))) (defun update-enable-sign-on-settings (value) "Updates the 'Enable Sign Up' setting in the database with `VALUE'." (with-connection (db) (let ((settings-to-update (mito:find-dao 'site-settings))) (setf (site-settings::enable-sign-up-p settings-to-update) (utils:checkbox-to-bool value)) (mito:save-dao settings-to-update)))) (defun update-enable-site-logo-setting (value) "Updates the 'Enable Site Logo' setting in the database with `VALUE'." (with-connection (db) (let ((settings-to-update (mito:find-dao 'site-settings))) (setf (site-settings::enable-site-logo-p settings-to-update) (utils:checkbox-to-bool value)) (mito:save-dao settings-to-update)))) (defun set-home-page (value) "Sets the page (in /storage/pages) to be displayed on the sites home page." (with-connection (db) (let ((settings-to-update (mito:find-dao 'site-settings))) (setf (site-settings::home-page-of settings-to-update) value) (mito:save-dao settings-to-update)))) (defun update-site-name (name) "Updates the website's `SITE-NAME' the database." (with-connection (db) (let ((settings-to-update (mito:find-dao 'site-settings))) (setf (site-settings::site-name-of settings-to-update) name) (mito:save-dao settings-to-update)))) (defun update-nav-menu (selected-pages) "Updates the `ENABLE-NAV-MENU' property in `PAGE' database." (loop for page in selected-pages do (with-connection (db) (let ((page-to-update (mito:find-dao 'page :slug (car page)))) (setf (pages::enable-nav-menu-p page-to-update) (utils:checkbox-to-bool (cdr page))) (mito:save-dao page-to-update))))) (defun nav-menu-slugs () (with-connection (db) (mito:select-dao 'page (sxql:where (:= :enable-nav-menu +true+))))) (defun system-data () "Gets the website's settings and nav-menu from database." (list (get-site-settings) (nav-menu-slugs))) (defun add-storage-file (filename slug file-type) "Add a row to the 'storage_file' table in the database." (with-connection (db) (mito:create-dao 'storage-file :name filename :slug slug :file-type file-type))) (defun get-storage-file (&key filename slug) "Returns a `STORAGE-FILE' row from the database. `NIL' if nothing found." (with-connection (db) (if (null slug) (mito:find-dao 'files:storage-file :name filename) (mito:find-dao 'files:storage-file :slug slug)))) (defun latest-storage-editted-files (amount &optional reverse) "Gets the latest `AMOUNT' of edited entries from the database. `REVERSE' is an optional parameter which puts the most recently editted article entry as the first item in the list.." (with-connection (db) (mito:select-dao 'storage-file (sxql:limit amount) (if reverse (sxql:order-by (:desc 'storage::updated-at)) (sxql:order-by 'storage::updated-at))))) (defun get-all-storage-files () "Returns a list of all `STORAGE-FILES' entries in the database." (with-connection (db) (mito:select-dao 'storage-file (sxql:order-by (:asc :name))))) (defun rename-storage-file (old-file-name new-file-name) "Renames `STORAGE-FILE' in the database. The `NAME' is renamed from `OLD-FILE-NAME' to `NEW-FILE-NAME' and the slug is updated based on `NEW-FILE-NAME'." (with-connection (db) (let ((file-to-rename (mito:find-dao 'storage-file :name old-file-name))) (setf (files::name-of file-to-rename) new-file-name (files::slug-of file-to-rename) (utils:slugify new-file-name)) (mito:save-dao file-to-rename)))) (defun delete-storage-file (&key name slug) "Delete `STORAGE-FILE' from database." (with-connection (db) (if (null slug) (mito:delete-by-values 'files:storage-file :name name) (mito:delete-by-values 'files:storage-file :slug slug)))) (defun get-all-archive-entries () "Returns a list of all `ARCHIVE-ENTRY' entries in the database." (with-connection (db) (mito:select-dao 'archive:archive-entry (sxql:order-by (:asc :title))))) (defun create-archive-entry (title search-id slug thumbnail-slug thumbnail-file-type keywords) "Add a new `ARCHIVE-ENTRY' to the database." (with-connection (db) (mito:create-dao 'archive:archive-entry :title title :search-id search-id :slug slug :thumbnail-slug thumbnail-slug :thumbnail-file-type thumbnail-file-type :keywords keywords))) (defun get-archive-entry (&key id title slug) "Returns a `ARCHIVE-ENTRY' from the database." (with-connection (db) (cond ((and (not title) (not slug)) (mito:find-dao 'archive:archive-entry :id id)) ((and (not id) (not slug)) (mito:find-dao 'archive:archive-entry :title title)) ((and (not id) (not title)) (mito:find-dao 'archive:archive-entry :slug slug)) (t nil)))) (defun latest-archive-editted-entries (amount &optional reverse) "Gets the latest `AMOUNT' of edited entries from the database. `REVERSE' is an optional parameter which puts the most recently editted article entry as the first item in the list.." (with-connection (db) (mito:select-dao 'archive:archive-entry (sxql:limit amount) (if reverse (sxql:order-by (:desc 'archive::updated-at)) (sxql:order-by 'archive::updated-at))))) (defun update-archive-entry-property (&key slug property value) "Updates an `ARCHIVE-ENTRY' entry in database. An example of how to use this function is as follows (remove back-slashes): (nera:update-archive-entry-property :slug \"edit-archive-test.html\" :propery 'archive::keywords-of :value \"test,image\")" (with-connection (db) (let ((entry-to-update (mito:find-dao 'archive:archive-entry :slug slug))) (eval `(setf (,property ,entry-to-update) ,value)) (mito:save-dao entry-to-update)))) (defun delete-archive-entry (&key id slug) "Delete `ARCHIVE-ENTRY' from the database." (with-connection (db) (cond ((not slug) (mito:delete-dao (mito:find-dao 'archive:archive-entry :id id))) ((not id) (mito:delete-dao (mito:find-dao 'archive:archive-entry :slug slug))))))