OneBot: Leantime 改造版源码(BOM/Univer 表格/AI 接管/品牌替换等)
This commit is contained in:
63
app/Domain/Wiki/Hxcontrollers/ArticleActivity.php
Normal file
63
app/Domain/Wiki/Hxcontrollers/ArticleActivity.php
Normal file
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Leantime\Domain\Wiki\Hxcontrollers;
|
||||
|
||||
use Leantime\Core\Auth\Permissions\RequiresPermission;
|
||||
use Leantime\Core\Controller\HtmxController;
|
||||
use Leantime\Domain\Wiki\Permissions\WikiPermissions;
|
||||
use Leantime\Domain\Wiki\Services\Wiki;
|
||||
|
||||
/**
|
||||
* HTMX Controller for wiki article activity feed
|
||||
*/
|
||||
class ArticleActivity extends HtmxController
|
||||
{
|
||||
protected static string $view = 'wiki::partials.activityFeed';
|
||||
|
||||
private Wiki $wikiService;
|
||||
|
||||
public function init(Wiki $wikiService): void
|
||||
{
|
||||
$this->wikiService = $wikiService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the activity feed for an article. The service's getArticleActivity() is the precise
|
||||
* per-article-project IDOR fence; this VIEW gate stops non-viewers at dispatch.
|
||||
*/
|
||||
#[RequiresPermission(WikiPermissions::VIEW, entityScoped: true)]
|
||||
public function get(): void
|
||||
{
|
||||
$articleId = (int) $this->incomingRequest->query->get('articleId', 0);
|
||||
|
||||
if ($articleId <= 0) {
|
||||
$this->tpl->assign('activity', []);
|
||||
$this->tpl->assign('articleId', 0);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the article for created/modified fallback
|
||||
$article = $this->wikiService->getArticle($articleId);
|
||||
|
||||
$activity = $this->wikiService->getArticleActivity($articleId, 20);
|
||||
|
||||
// Always append the article's created date as the final entry
|
||||
if ($article && ! empty($article->created)) {
|
||||
$activity[] = [
|
||||
'type' => 'baseline',
|
||||
'action' => 'article.create',
|
||||
'date' => $article->created,
|
||||
'firstname' => $article->firstname ?? '',
|
||||
'lastname' => $article->lastname ?? '',
|
||||
'profileId' => $article->profileId ?? '',
|
||||
'values' => [],
|
||||
];
|
||||
}
|
||||
|
||||
$this->tpl->assign('activity', $activity);
|
||||
$this->tpl->assign('articleId', $articleId);
|
||||
}
|
||||
}
|
||||
123
app/Domain/Wiki/Hxcontrollers/ArticleContent.php
Normal file
123
app/Domain/Wiki/Hxcontrollers/ArticleContent.php
Normal file
@@ -0,0 +1,123 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Leantime\Domain\Wiki\Hxcontrollers;
|
||||
|
||||
use Leantime\Core\Auth\Permissions\RequiresPermission;
|
||||
use Leantime\Core\Controller\HtmxController;
|
||||
use Leantime\Domain\Wiki\Models\Article;
|
||||
use Leantime\Domain\Wiki\Permissions\WikiPermissions;
|
||||
use Leantime\Domain\Wiki\Services\Wiki;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
/**
|
||||
* HTMX Controller for inline wiki article content editing
|
||||
*/
|
||||
class ArticleContent extends HtmxController
|
||||
{
|
||||
protected static string $view = 'wiki::partials.articleContent';
|
||||
|
||||
private Wiki $wikiService;
|
||||
|
||||
public function init(Wiki $wikiService): void
|
||||
{
|
||||
$this->wikiService = $wikiService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save article content via HTMX (called on auto-save or blur).
|
||||
*
|
||||
* Gate defers (entityScoped) to the service's updateArticle(), which authorizes EDIT against
|
||||
* the article's real project.
|
||||
*/
|
||||
#[RequiresPermission(WikiPermissions::EDIT, entityScoped: true)]
|
||||
public function save(): Response
|
||||
{
|
||||
$articleId = (int) $this->incomingRequest->query->get('articleId', 0);
|
||||
$content = $this->incomingRequest->request->get('description');
|
||||
$title = $this->incomingRequest->request->get('title');
|
||||
$status = $this->incomingRequest->request->get('status');
|
||||
$icon = $this->incomingRequest->request->get('icon');
|
||||
$tags = $this->incomingRequest->request->get('tags');
|
||||
$milestoneId = $this->incomingRequest->request->get('milestoneId');
|
||||
$parent = $this->incomingRequest->request->get('parent');
|
||||
|
||||
if (! $articleId) {
|
||||
return new Response('Article ID required', 400);
|
||||
}
|
||||
|
||||
// Get the existing article
|
||||
$existingArticle = $this->wikiService->getArticle($articleId);
|
||||
|
||||
if (! $existingArticle) {
|
||||
return new Response('Article not found', 404);
|
||||
}
|
||||
|
||||
// Create article model with updated fields
|
||||
$article = new Article;
|
||||
$article->id = $articleId;
|
||||
$article->title = $title !== null ? $title : $existingArticle->title;
|
||||
$article->description = $content !== null ? $content : $existingArticle->description;
|
||||
$article->canvasId = $existingArticle->canvasId;
|
||||
$article->tags = $tags !== null ? $tags : $existingArticle->tags;
|
||||
$article->data = $icon !== null ? $icon : $existingArticle->data;
|
||||
$article->status = $status !== null ? $status : $existingArticle->status;
|
||||
$article->milestoneId = $milestoneId !== null ? (int) ($milestoneId !== '' ? $milestoneId : 0) : $existingArticle->milestoneId;
|
||||
$article->parent = $parent !== null ? $parent : $existingArticle->parent;
|
||||
$article->sortindex = $existingArticle->sortindex;
|
||||
|
||||
if ($this->wikiService->updateArticle($article, $existingArticle)) {
|
||||
|
||||
return new Response(json_encode([
|
||||
'success' => true,
|
||||
'message' => 'Saved',
|
||||
'timestamp' => dtHelper()->userNow()->formatDateTimeForDb(),
|
||||
'title' => $article->title,
|
||||
'status' => $article->status,
|
||||
], JSON_THROW_ON_ERROR), 200, ['Content-Type' => 'application/json']);
|
||||
}
|
||||
|
||||
return new Response(json_encode([
|
||||
'success' => false,
|
||||
'message' => 'Failed to save',
|
||||
], JSON_THROW_ON_ERROR), 500, ['Content-Type' => 'application/json']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new article and redirect to it.
|
||||
*
|
||||
* Gate defers (entityScoped) to the service's createArticle(), which authorizes CREATE against
|
||||
* the target wiki's project.
|
||||
*/
|
||||
#[RequiresPermission(WikiPermissions::CREATE, entityScoped: true)]
|
||||
public function create(): Response
|
||||
{
|
||||
$currentWiki = session('currentWiki');
|
||||
if (! $currentWiki) {
|
||||
return new Response('No wiki selected', 400);
|
||||
}
|
||||
|
||||
// Create new article with defaults
|
||||
$article = new Article;
|
||||
$article->title = 'Untitled';
|
||||
$article->author = session('userdata.id');
|
||||
$article->canvasId = $currentWiki;
|
||||
$article->data = 'far fa-file-alt';
|
||||
$article->tags = '';
|
||||
$article->status = 'draft';
|
||||
$article->parent = 0;
|
||||
$article->description = '';
|
||||
|
||||
$id = $this->wikiService->createArticle($article);
|
||||
|
||||
if ($id) {
|
||||
$response = new Response('', 200);
|
||||
$response->headers->set('HX-Redirect', BASE_URL.'/wiki/show/'.$id);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
return new Response('Failed to create article', 500);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user