diff --git a/migrations/20260208165810_edit_level_id.down.sql b/migrations/20260208165810_edit_level_id.down.sql new file mode 100644 index 00000000..9262baf2 --- /dev/null +++ b/migrations/20260208165810_edit_level_id.down.sql @@ -0,0 +1,47 @@ +ALTER TABLE demon_modifications DROP COLUMN level_id; + +CREATE OR REPLACE FUNCTION audit_demon_modification() RETURNS trigger AS $demon_modification_trigger$ +DECLARE + name_change CITEXT; + position_change SMALLINT; + requirement_change SMALLINT; + video_change VARCHAR(200); + thumbnail_change TEXT; + verifier_change INT; + publisher_change INT; +BEGIN + IF (OLD.name <> NEW.name) THEN + name_change = OLD.name; + END IF; + + IF (OLD.position <> NEW.position) THEN + position_change = OLD.position; + END IF; + + IF (OLD.requirement <> NEW.requirement) THEN + requirement_change = OLD.requirement; + END IF; + + IF (OLD.video <> NEW.video) THEN + video_change = OLD.video; + END IF; + + IF (OLD.thumbnail <> NEW.thumbnail) THEN + thumbnail_change = OLD.thumbnail; + END IF; + + IF (OLD.verifier <> NEW.verifier) THEN + verifier_change = OLD.verifier; + END IF; + + IF (OLD.publisher <> NEW.publisher) THEN + publisher_change = OLD.publisher; + END IF; + + INSERT INTO demon_modifications (userid, name, position, requirement, video, verifier, publisher, thumbnail, id) + (SELECT id, name_change, position_change, requirement_change, video_change, verifier_change, publisher_change, thumbnail_change, NEW.id + FROM active_user LIMIT 1); + + RETURN NEW; +END; +$demon_modification_trigger$ LANGUAGE plpgsql; \ No newline at end of file diff --git a/migrations/20260208165810_edit_level_id.up.sql b/migrations/20260208165810_edit_level_id.up.sql new file mode 100644 index 00000000..c482fa8d --- /dev/null +++ b/migrations/20260208165810_edit_level_id.up.sql @@ -0,0 +1,52 @@ +ALTER TABLE demon_modifications ADD COLUMN level_id BIGINT NULL DEFAULT NULL; + +CREATE OR REPLACE FUNCTION audit_demon_modification() RETURNS trigger AS $demon_modification_trigger$ +DECLARE + name_change CITEXT; + position_change SMALLINT; + requirement_change SMALLINT; + video_change VARCHAR(200); + thumbnail_change TEXT; + verifier_change INT; + publisher_change INT; + level_id_change BIGINT; +BEGIN + IF (OLD.name <> NEW.name) THEN + name_change = OLD.name; + END IF; + + IF (OLD.position <> NEW.position) THEN + position_change = OLD.position; + END IF; + + IF (OLD.requirement <> NEW.requirement) THEN + requirement_change = OLD.requirement; + END IF; + + IF (OLD.video <> NEW.video) THEN + video_change = OLD.video; + END IF; + + IF (OLD.thumbnail <> NEW.thumbnail) THEN + thumbnail_change = OLD.thumbnail; + END IF; + + IF (OLD.verifier <> NEW.verifier) THEN + verifier_change = OLD.verifier; + END IF; + + IF (OLD.publisher <> NEW.publisher) THEN + publisher_change = OLD.publisher; + END IF; + + IF (OLD.level_id <> NEW.level_id) THEN + level_id_change = OLD.level_id; + END IF; + + INSERT INTO demon_modifications (userid, name, position, requirement, video, verifier, publisher, thumbnail, level_id, id) + (SELECT id, name_change, position_change, requirement_change, video_change, verifier_change, publisher_change, thumbnail_change, level_id_change, NEW.id + FROM active_user LIMIT 1); + + RETURN NEW; +END; +$demon_modification_trigger$ LANGUAGE plpgsql; \ No newline at end of file diff --git a/pointercrate-demonlist-pages/src/account/demons.rs b/pointercrate-demonlist-pages/src/account/demons.rs index dc928a45..92b8fb3c 100644 --- a/pointercrate-demonlist-pages/src/account/demons.rs +++ b/pointercrate-demonlist-pages/src/account/demons.rs @@ -112,6 +112,15 @@ impl AccountPageTab for DemonsTab { span #demon-verifier {} } } + div.stats-container.flex.space { + span{ + b { + i.fa.fa-pencil-alt.clickable #demon-levelid-pen aria-hidden = "true" {} " " (tr("demon-viewer.levelid-field")) + } + br; + span #demon-levelid {} + } + } div.stats-container.flex.space { span{ i.fa.fa-plus.clickable #demon-add-creator-pen aria-hidden = "true" {} b { @@ -138,6 +147,7 @@ impl AccountPageTab for DemonsTab { (change_thumbnail_dialog()) (change_verifier_dialog()) (change_publisher_dialog()) + (change_levelid_dialog()) (add_creator_dialog()) } } @@ -317,6 +327,31 @@ fn change_publisher_dialog() -> Markup { ) } +fn change_levelid_dialog() -> Markup { + html! { + div.overlay.closable { + div.dialog #demon-levelid-dialog { + span.plus.cross.hover {} + h2.underlined.pad { + (tr("demon-levelid-dialog")) + } + p style = "max-width: 400px"{ + (tr("demon-levelid-dialog.info")) + } + form.flex.col novalidate = "" { + p.info-red.output {} + p.info-green.output {} + span.form-input #demon-levelid-edit { + input name = "level_id" type = "number" min = "1"; + p.error {} + } + input.button.blue.hover type = "submit" style = "margin: 15px auto 0px;" value = (tr("demon-levelid-dialog.submit")); + } + } + } + } +} + fn add_creator_dialog() -> Markup { player_selection_dialog( "demon-add-creator-dialog", diff --git a/pointercrate-demonlist-pages/static/ftl/en-us/demon.ftl b/pointercrate-demonlist-pages/static/ftl/en-us/demon.ftl index 250a403c..63ac511a 100644 --- a/pointercrate-demonlist-pages/static/ftl/en-us/demon.ftl +++ b/pointercrate-demonlist-pages/static/ftl/en-us/demon.ftl @@ -122,6 +122,7 @@ demon-viewer = Demon # .publisher-field = { demon-publisher }: .verifier-field = { demon-verifier }: .creators-field = { demon-creators }: + .levelid-field = { demon-id }: demon-add-panel = Add Demon .button = Add a demon! @@ -181,6 +182,10 @@ demon-verifier-dialog = Change demon verifier .info = Type the new verifier of the demon into the text field below. If the player already exists, it will appear as a suggestion below the text field. Then click the button below. .submit = Edit +demon-levelid-dialog = Change level ID + .info = Leave empty to remove the level ID. + .submit = Edit + demon-creator-dialog = Add creator .info = Type the creator to add to this demon into the text field below. If the player already exists, it will appear as a suggestion below the text field. Then click the button below. .submit = Add Creator diff --git a/pointercrate-demonlist-pages/static/ftl/ru-ru/demon.ftl b/pointercrate-demonlist-pages/static/ftl/ru-ru/demon.ftl index 00db9e56..284d620f 100644 --- a/pointercrate-demonlist-pages/static/ftl/ru-ru/demon.ftl +++ b/pointercrate-demonlist-pages/static/ftl/ru-ru/demon.ftl @@ -124,6 +124,7 @@ demon-viewer = Демон # .publisher-field = { demon-publisher }: .verifier-field = { demon-verifier }: .creators-field = { demon-creators }: + .levelid-field = { demon-id }: demon-add-panel = Добавление демона .button = Добавить демон! @@ -183,6 +184,10 @@ demon-verifier-dialog = Изменение верифера демона .info = Здесь проходит введение нового верифера демона через поле ниже. Если такой игрок уже существует, его имя появится в качестве предложения ниже поля ввода. После этого нажмите на кнопку ниже. .submit = Изменить +demon-levelid-dialog = Изменение ID уровня + .info = Оставьте пустой для удаления ID уровня. + .submit = Изменить + demon-creator-dialog = Добавление креатора .info = Здесь проходит добавление нового креатора для этого демона через поле ниже. Если такой игрок уже существует, его имя появится в качестве предложения ниже поля ввода. После этого нажмите на кнопку ниже. .submit = Добавить креатора diff --git a/pointercrate-demonlist-pages/static/js/account/demon.js b/pointercrate-demonlist-pages/static/js/account/demon.js index e9ad3918..e2f06b29 100644 --- a/pointercrate-demonlist-pages/static/js/account/demon.js +++ b/pointercrate-demonlist-pages/static/js/account/demon.js @@ -21,7 +21,7 @@ import { setupEditorDialog, FormDialog, } from "/static/core/js/modules/form.js"; -import { loadResource, tr } from "/static/core/js/modules/localization.js"; +import { tr } from "/static/core/js/modules/localization.js"; export let demonManager; @@ -50,6 +50,8 @@ export class DemonManager extends FilteredPaginator { this._verifier = document.getElementById("demon-verifier"); this._publisher = document.getElementById("demon-publisher"); + this._level_id = document.getElementById("demon-levelid"); + this._creators = document.getElementById("demon-creators"); let videoForm = setupFormDialogEditor( @@ -150,6 +152,12 @@ export class DemonManager extends FilteredPaginator { new PaginatorEditorBackend(this, true), this.output ); + setupFormDialogEditor( + new PaginatorEditorBackend(this, true), + "demon-levelid-dialog", + "demon-levelid-pen", + this.output + ); } onReceive(response) { @@ -194,6 +202,13 @@ export class DemonManager extends FilteredPaginator { " (" + this.currentObject.verifier.id + ")"; + + if (this.currentObject.level_id) { + this._level_id.innerText = this.currentObject.level_id; + this._level_id.style.display = "initial"; + } else { + this._level_id.style.display = "none"; + } while (this._creators.lastChild) { this._creators.removeChild(this._creators.lastChild); diff --git a/pointercrate-demonlist/src/demon/patch.rs b/pointercrate-demonlist/src/demon/patch.rs index c6cc16fc..b4482835 100644 --- a/pointercrate-demonlist/src/demon/patch.rs +++ b/pointercrate-demonlist/src/demon/patch.rs @@ -30,6 +30,9 @@ pub struct PatchDemon { #[serde(default, deserialize_with = "non_nullable")] pub publisher: Option, + + #[serde(default, deserialize_with = "nullable")] + pub level_id: Option>, } impl FullDemon { @@ -89,6 +92,10 @@ impl Demon { self.set_requirement(requirement, connection).await?; } + if let Some(level_id) = patch.level_id { + self.set_level_id(level_id, connection).await?; + } + Ok(self) } @@ -169,6 +176,21 @@ impl Demon { Ok(()) } + + pub async fn set_level_id(&mut self, level_id: Option, connection: &mut PgConnection) -> Result<()> { + let validated_level_id = match level_id { + Some(id) => Some(Demon::validate_level_id(id)?), + None => None, + }; + + sqlx::query!("UPDATE demons SET level_id = $1 WHERE id = $2", level_id, self.base.id) + .execute(connection) + .await?; + + self.level_id = validated_level_id; + + Ok(()) + } } impl MinimalDemon {