This commit is contained in:
Patrick Niebeling
2025-03-12 11:11:19 +01:00
parent 4e4ae2b372
commit 7f683fcec1
16 changed files with 211 additions and 154 deletions

22
appinfo/application.php Normal file
View File

@ -0,0 +1,22 @@
<?php
namespace OCA\Deckflow\AppInfo;
use OCP\AppFramework\App;
use OCA\Deckflow\Controller\SettingsController;
class Application extends App {
public function __construct() {
parent::__construct('deckflow');
}
public function register() {
$this->getContainer()->registerService('SettingsController', function($c) {
return new SettingsController(
$c->query('OCP\IRequest'),
$c->query('OCP\IUserSession'),
$c->query('OCA\Deckflow\Service\WorkflowService')
);
});
}
}

View File

@ -1,9 +0,0 @@
<?php
// lib/cron.php
/** @var \OCP\IContainer $container */
$container = require __DIR__ . '/../lib/container.php';
$job = $container->query('OCA\Deckflow\Cron\MoveOverdueCardsJob');
// Führe den Cronjob aus
$job->execute();

View File

@ -1,14 +0,0 @@
<?xml version="1.0"?>
<ocl:information xmlns:ocl="http://www.nextcloud.org/ns">
<id>deckflow</id>
<name>Deckflow</name>
<summary>Automatisiere Deck-Karten mit Cronjobs und Workflows</summary>
<description>Diese App automatisiert die Bewegung von Karten basierend auf Workflows und Überprüfungen von überfälligen Karten.</description>
<version>0.1.0</version>
<namespace>deckflow</namespace>
<dependencies>
<nextcloud>21</nextcloud>
<app>workflow</app>
<app>deck</app>
</dependencies>
</ocl:information>

20
appinfo/routes.php Normal file
View File

@ -0,0 +1,20 @@
<?php
use OCP\AppFramework\Router;
use OCP\IContainer;
$container->registerService('SettingsController', function(IContainer $c) {
return new \OCA\Deckflow\Controller\SettingsController(
$c->query('OCP\IRequest'),
$c->query('OCP\IUserSession'),
$c->query('OCA\Deckflow\Service\WorkflowService')
);
});
// Hier wird die Route für den Webhook definiert
$container->registerService('WebhookController', function(IContainer $c) {
return new \OCA\Deckflow\Controller\WebhookController(
$c->query('OCP\IRequest'),
$c->query('OCA\Deckflow\Service\WorkflowService')
);
});

24
assets/js/addWorkflow.js Normal file
View File

@ -0,0 +1,24 @@
document.getElementById('addWorkflow').addEventListener('click', function() {
let workflowContainer = document.getElementById('workflows');
let newWorkflow = document.createElement('div');
newWorkflow.classList.add('workflow');
newWorkflow.innerHTML = `
<label for="deckId">Wählen Sie das Deck:</label>
<select name="deckId[]" id="deckId">
<!-- Liste der Decks des Users -->
</select>
<label for="sourceStack">Wählen Sie den Quellstapel:</label>
<select name="sourceStack[]" id="sourceStack">
<!-- Quellstapel -->
</select>
<label for="targetStack">Wählen Sie den Zielstapel:</label>
<select name="targetStack[]" id="targetStack">
<!-- Zielstapel -->
</select>
`;
workflowContainer.appendChild(newWorkflow);
});

15
composer.json Normal file
View File

@ -0,0 +1,15 @@
{
"name": "deckflow",
"description": "Automatisierung von Deck Workflows mit Flow",
"type": "nextcloud-app",
"require": {
"php": ">=7.2",
"nextcloud/server": "^23.0"
},
"autoload": {
"psr-4": {
"OCA\\Deckflow\\": "lib/"
}
}
}

View File

@ -0,0 +1,33 @@
<?php
namespace OCA\Deckflow\Controller;
use OCP\AppFramework\Controller;
use OCP\IRequest;
use OCP\IUserSession;
use OCA\Deckflow\Service\WorkflowService;
class SettingsController extends Controller {
private $workflowService;
public function __construct(IRequest $request, IUserSession $userSession, WorkflowService $workflowService) {
parent::__construct('deckflow', $request);
$this->workflowService = $workflowService;
}
public function showSettingsForm() {
$workflows = $this->workflowService->getWorkflows();
return $this->render('settings.php', [
'workflows' => $workflows
]);
}
public function saveWorkflows() {
$deckId = $_POST['deckId'];
$sourceStackId = $_POST['sourceStack'];
$targetStackId = $_POST['targetStack'];
$this->workflowService->saveWorkflows($deckId, $sourceStackId, $targetStackId);
}
}

View File

@ -0,0 +1,25 @@
<?php
namespace OCA\Deckflow\Controller;
use OCP\AppFramework\Controller;
use OCP\IRequest;
use OCA\Deckflow\Service\WorkflowService;
class WebhookController extends Controller {
private $workflowService;
public function __construct(IRequest $request, WorkflowService $workflowService) {
parent::__construct('deckflow', $request);
$this->workflowService = $workflowService;
}
public function moveCards() {
$deckId = $_POST['deckId'];
$sourceStackId = $_POST['sourceStackId'];
$targetStackId = $_POST['targetStackId'];
$this->workflowService->moveOverdueCards($deckId, $sourceStackId, $targetStackId);
}
}

11
cron.php Normal file
View File

@ -0,0 +1,11 @@
<?php
// Beispiel Cronjob zum Überprüfen der Workflows
require_once('path/to/autoload.php');
use OCA\Deckflow\Service\WorkflowService;
$workflowService = new WorkflowService($db, $userSession, $deckService);
$workflows = $workflowService->getWorkflows();
foreach ($workflows as $workflow) {
$workflowService->moveOverdueCards($workflow['deck_id'], $workflow['source_stack_id'], $workflow['target_stack_id']);
}

11
db/schema.xml Normal file
View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://nextcloud.org/ns/nextcloud">
<table name="deckflow_workflows">
<column name="id" type="integer" unsigned="true" notnull="true" primarykey="true" autoincrement="true" />
<column name="user_id" type="string" length="255" notnull="true" />
<column name="deck_id" type="integer" unsigned="true" notnull="true" />
<column name="source_stack_id" type="integer" unsigned="true" notnull="true" />
<column name="target_stack_id" type="integer" unsigned="true" notnull="true" />
<column name="created_at" type="timestamp" notnull="true" default="CURRENT_TIMESTAMP" />
</table>
</schema>

View File

@ -1,32 +0,0 @@
<?php
namespace OCA\Deckflow\AppInfo;
use OCP\AppFramework\App;
use OCA\Deckflow\Controller\SettingsController;
use OCA\Deckflow\Cron\MoveOverdueCardsJob;
use OCP\IContainer;
class Application extends App {
public function __construct(array $urlParams = []) {
parent::__construct('deckflow', $urlParams);
$container = $this->getContainer();
// Routen für das Backend
$container->registerService('SettingsController', function(IContainer $c) {
return new SettingsController(
$c->query('OCP\IRequest'),
$c->query('OCP\IUserSession'),
$c->query('OCA\Deckflow\Service\WorkflowService'),
$c->query('OCP\IDBConnection')
);
});
// CronJob registrieren
$container->registerService('MoveOverdueCardsJob', function(IContainer $c) {
return new MoveOverdueCardsJob(
$c->query('OCA\Deckflow\Service\WorkflowService')
);
});
}
}

View File

@ -1,21 +0,0 @@
<?php
namespace OCA\Deckflow\DB;
use OCP\DB\ISQLiteConnection;
class Migration {
/**
* Erstellt die Tabelle für Workflow-Konfigurationen
* @param ISQLiteConnection $connection
*/
public function createWorkflowConfigTable(ISQLiteConnection $connection) {
$connection->query("CREATE TABLE IF NOT EXISTS *PREFIX*deckflow_workflows (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id TEXT NOT NULL,
deck_id TEXT NOT NULL,
source_stack_id TEXT NOT NULL,
target_stack_id TEXT NOT NULL
)");
}
}

View File

@ -1,27 +0,0 @@
<?php
namespace OCA\Deckflow\Cron;
use OCP\BackgroundJob\TimedJob;
use OCA\Deckflow\Service\WorkflowService;
class MoveOverdueCardsJob extends TimedJob {
private $workflowService;
public function __construct(WorkflowService $workflowService) {
parent::__construct();
$this->workflowService = $workflowService;
}
/**
* Ausführen des Cronjobs
*/
protected function run($argument) {
try {
// Überfällige Karten verschieben
$this->workflowService->moveOverdueCards();
} catch (\Exception $e) {
\OCP\Util::writeLog('deckflow', 'Fehler beim Ausführen des Cronjobs: ' . $e->getMessage(), \OCP\Util::ERROR);
}
}
}

View File

@ -1,63 +1,54 @@
<?php <?php
namespace OCA\Deckflow\Service; namespace OCA\Deckflow\Service;
use OCP\IDBConnection;
use OCP\IUserSession; use OCP\IUserSession;
use OCA\Deck\Service\DeckService; use OCA\Deck\Service\DeckService;
use OCP\ILogger;
use OCA\Deckflow\DB\Migration;
class WorkflowService { class WorkflowService {
private $db;
private $userSession; private $userSession;
private $deckService; private $deckService;
private $logger;
private $db;
public function __construct(IUserSession $userSession, DeckService $deckService, ILogger $logger, \OCP\IDBConnection $db) { public function __construct(IDBConnection $db, IUserSession $userSession, DeckService $deckService) {
$this->db = $db;
$this->userSession = $userSession; $this->userSession = $userSession;
$this->deckService = $deckService; $this->deckService = $deckService;
$this->logger = $logger;
$this->db = $db;
} }
/** // Speichert die Workflows
* Holt alle Workflows des aktuellen Benutzers public function saveWorkflows($deckId, $sourceStackId, $targetStackId) {
* @return array $userId = $this->userSession->getUser()->getUID();
*/ $this->db->executeQuery("INSERT INTO *PREFIX*deckflow_workflows (user_id, deck_id, source_stack_id, target_stack_id)
private function getUserWorkflows() { VALUES (?, ?, ?, ?)", [
$user = $this->userSession->getUser(); $userId,
$userId = $user ? $user->getUID() : null; $deckId,
$sourceStackId,
$targetStackId
]);
}
// Hole alle Workflow-Konfigurationen des Benutzers aus der DB // Ruft alle Workflows für den aktuellen Benutzer ab
public function getWorkflows() {
$userId = $this->userSession->getUser()->getUID();
$result = $this->db->executeQuery("SELECT * FROM *PREFIX*deckflow_workflows WHERE user_id = ?", [$userId]); $result = $this->db->executeQuery("SELECT * FROM *PREFIX*deckflow_workflows WHERE user_id = ?", [$userId]);
return $result->fetchAll(); return $result->fetchAll();
} }
/** // Webhook zur Ausführung des Workflows, Karten zu verschieben
* Verschiebt überfällige Karten für alle Workflows public function moveOverdueCards($deckId, $sourceStackId, $targetStackId) {
*/ $deck = $this->deckService->getDeckById($deckId);
public function moveOverdueCards() { $sourceStack = $deck->getStackById($sourceStackId);
$user = $this->userSession->getUser(); $targetStack = $deck->getStackById($targetStackId);
if ($user === null) {
return;
}
$workflows = $this->getUserWorkflows();
foreach ($workflows as $workflow) {
// Hole das Deck und die Stacks aus der Konfiguration
$deck = $this->deckService->getDeckById($workflow['deck_id']);
$sourceStack = $deck->getStackById($workflow['source_stack_id']);
$targetStack = $deck->getStackById($workflow['target_stack_id']);
// Überprüfe alle Karten im Quellstapel auf Überfälligkeit
foreach ($sourceStack->getCards() as $card) { foreach ($sourceStack->getCards() as $card) {
if ($this->isCardOverdue($card)) { if ($this->isCardOverdue($card)) {
$this->moveCardToTargetStack($card, $targetStack); $this->moveCardToTargetStack($card, $targetStack);
} }
} }
} }
}
private function isCardOverdue($card) { private function isCardOverdue($card) {
$dueDate = $card->getDueDate(); $dueDate = $card->getDueDate();
@ -66,6 +57,5 @@ class WorkflowService {
private function moveCardToTargetStack($card, $targetStack) { private function moveCardToTargetStack($card, $targetStack) {
$this->deckService->moveCardToStack($card, $targetStack); $this->deckService->moveCardToStack($card, $targetStack);
$this->logger->info("Card moved to target stack.");
} }
} }

View File

@ -1,19 +1,28 @@
<h1>Deckflow Settings</h1> <h1>Deckflow Einstellungen</h1>
<form method="post" action="/settings/deckflow"> <form method="post" action="/settings/deckflow/save">
<label for="deckId">Wählen Sie das Deck:</label> <div id="workflows">
<select name="deckId" id="deckId"> <?php foreach ($workflows as $workflow): ?>
<!-- Liste der Decks des Users --> <div class="workflow">
<label for="deckId">Deck:</label>
<select name="deckId[]" id="deckId">
<!-- Hier Decks des Benutzers dynamisch laden -->
</select> </select>
<label for="sourceStack">Wählen Sie den Quellstapel:</label> <label for="sourceStack">Quellstapel:</label>
<select name="sourceStack" id="sourceStack"> <select name="sourceStack[]" id="sourceStack">
<!-- Quellstapel --> <!-- Quellstapel dynamisch laden -->
</select> </select>
<label for="targetStack">Wählen Sie den Zielstapel:</label> <label for="targetStack">Zielstapel:</label>
<select name="targetStack" id="targetStack"> <select name="targetStack[]" id="targetStack">
<!-- Zielstapel --> <!-- Zielstapel dynamisch laden -->
</select> </select>
</div>
<?php endforeach; ?>
</div>
<button type="button" id="addWorkflow">Weitere Kombination hinzufügen</button>
<button type="submit">Speichern</button> <button type="submit">Speichern</button>
</form> </form>
<script src="/apps/deckflow/assets/js/addWorkflow.js"></script>