Initial commit

This commit is contained in:
snt 2025-06-23 16:12:14 +00:00
commit 2ce34b0dc8
4 changed files with 189 additions and 0 deletions

2
.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
node_modules/
package-lock.json

13
README.md Normal file
View file

@ -0,0 +1,13 @@
# Cleaner plugin for Gancio
This is a plugin for gancio that cleans past eventsd, this is a beta release.
## Configuration
Once the plugin is installed, navigate to your instance plugins tab of the admin interface. Enable the plugin and add the required data.
## Try it
1. Restart your gancio instance and look at the logs for any message saying that this plugin has been loaded.

161
index.js Normal file
View file

@ -0,0 +1,161 @@
/**
* Clean past events from gancio
*/
const path = require('path')
const fs = require('fs/promises')
const config = require('../../config')
const notifier = require('../../../gancio_source/server/notifier')
const { Op } = require('sequelize')
const { Event, Resource, Tag, Place, Notification, APUser, EventNotification, Message, User } = require('../../../gancio_source/server/api/models/models')
const plugin = {
configuration: {
name: 'Cleaner',
author: 'snt',
url: 'https://git.criptomart.net/snt/gancio',
description: 'Cleans events from a specified time before now, this is a beta release of this plugin.',
settings: {
refresh_time: {
type: 'NUMBER',
hint: 'Search for past events each n hours',
required: true,
description: '1 hour?'
},
deadline_time: {
type: 'NUMBER',
hint: 'Clean all events non recurrent with end time n hours ago.',
required: true,
description: '720 hours? events ended after this number of hours ago will be deleted.'
},
events_number: {
type: 'NUMBER',
hint: 'Limit the number of events to be deleted each call.',
required: true,
description: '4? Do not set too much, it can overload notifications.'
},
}
},
gancio: null, // { helpers, log, settings }
log: null,
settings: null,
db: null,
interval: null,
ETag: null,
load(gancio, settings) {
plugin.gancio = gancio // contains all gancio settings, including all plugins settings
plugin.log = gancio.log // just the logger
plugin.db = gancio.db
plugin.settings = settings // this plugin settings
plugin.apiBaseUrl = gancio.settings.baseurl + '/api'
// TODO: could use the TaskManager?
plugin.interval = setInterval(this._tick, settings.refresh_time*1000*60*60)
plugin.log.debug("[Cleaner Plugin] loaded with params: refresh: %s -- deadline: %s -- number: %s", settings.refresh_time, settings.deadline_time, settings.events_number)
// this._tick()
},
unload () {
plugin.log.debug('[Cleaner Plugin] Clear interval an unload plugin')
clearInterval(plugin.interval)
},
onTest () {
plugin._tick()
},
async _tick () {
// Avoid running multiple ticks at the same time which could cause race conditions on the database
if (plugin._isTickRunning) {
plugin.log.warn('[Cleaner Plugin] _tick already in progress, skipping')
return
}
plugin.log.debug('[Cleaner Plugin] _tick started, locking it')
plugin._isTickRunning = true
try {
if (!plugin.settings?.refresh_time) {
plugin.log.debug('[Cleaner Plugin] refresh time not set, default to 1 hour')
plugin.settings.refresh_time = 1
plugin.interval = setInterval(this._tick, settings.refresh_time*1000*60*60)
}
if (!plugin.settings?.deadline_time) {
plugin.log.debug('[Cleaner Plugin] deadline time not set, default to 4 weeks')
plugin.settings.deadline_time = 720
}
if (!plugin.settings?.events_number) {
plugin.log.debug('[Cleaner Plugin] events cleared not set, default to 1')
plugin.settings.events_number = 1
}
try {
plugin.log.debug(`[Cleaner Plugin] Begin searching`)
const now = Math.floor(Date.now())
const cut_datetime = now - plugin.settings?.deadline_time*60*60*1000
const date_obj = new Date(cut_datetime)
plugin.log.debug("now %s -- deadline %s", now, cut_datetime)
plugin.log.info("[Cleaner Plugin] Removing old events before " + date_obj)
events = await plugin.db.models.event.findAll({
where: {
recurrent: null,
start_datetime: { [Op.lt]: cut_datetime/1000 },
[Op.or]: [ {end_datetime: { [Op.lt]: cut_datetime/1000 } }, { end_datetime: null } ]
},
order: [['end_datetime', 'ASC']],
include: [{ model: Event, as:'child' }],
limit: plugin.settings.events_number,
})
plugin.log.warn("[Cleaner Plugin] Found %s past events and related resources.", events.length)
if (!events.length) { return }
for (e of events) {
end_date = new Date(e.end_datetime * 1000)
start_date = new Date(e.start_datetime * 1000)
plugin.log.info("[Cleaner Plugin] Cleaning: " + e.title + " - Rec: " + e.recurrent + " - From: " + start_date + " - To: " + end_date + " - place: " + e.placeId)
plugin.log.debug("[Cleaner Plugin] %s", JSON.stringify(e, null, "\t"))
if (e.media && e.media.length && !e.recurrent && !e.parentId) {
try {
const old_path = path.join(config.upload_path, e.media[0].url)
const old_thumb_path = path.join(config.upload_path, 'thumb', e.media[0].url)
await fs.unlink(old_thumb_path)
await fs.unlink(old_path)
plugin.log.debug("[Cleaner Plugin] removing file: " + old_path)
} catch (excep) {
plugin.log.error("[Cleaner Plugin] error removing file %s", excep.toString())
}
}
try {
// notify local events before destroying notifications
if (!e.ap_id) {
await notifier.notifyEvent("Delete", e.id)
}
// remove related resources
await Resource.destroy({ where: { eventId: e.id }})
// remove notifications
await EventNotification.destroy({ where: { eventId: e.id }})
// remove event
await e.destroy()
} catch (excep) {
console.error(excep)
plugin.log.error("[Cleaner Plugin] error destroying %s", excep.toString() )
}
};
} catch (e) {
plugin.log.error(`[Cleaner Plugin] Error: ${String(e)}`)
}
} catch (e) {
plugin.log.error(`[Cleaner Plugin] Uncaught error in _tick: ${String(e)}`)
} finally {
plugin.log.debug('[Cleaner Plugin] _tick finished, unlocking it')
plugin._isTickRunning = false
}
}
}
module.exports = plugin

13
package.json Normal file
View file

@ -0,0 +1,13 @@
{
"name": "gancio-plugin-cleaner",
"version": "0.1.0",
"description": "Cleaner plugin for Gancio",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"license": "AGPL-3.0-or-later",
"dependencies": {
"sequelize": "^6.37.7"
}
}