Files
ulthon_information/app/api/controller/Articles.php
augushong 6f332467df feat(content-type): add content_type field, markdown auto-conversion, and API doc updates
- Add content_type column to ul_post via migration
- Install league/commonmark for markdown->HTML conversion
- Add Post model accessors/setters for content_type and content
- Update API Articles controller save/update with content_type support
- Update API docs with content_type parameter and markdown example

Closes content-type-support plan
2026-04-29 20:46:44 +08:00

264 lines
7.8 KiB
PHP

<?php
declare(strict_types=1);
namespace app\api\controller;
use app\BaseController;
use app\model\Post;
use app\model\PostCategory;
use app\model\PostTag;
use League\CommonMark\CommonMarkConverter;
use think\Request;
class Articles extends BaseController
{
protected $middleware = [\app\middleware\ApiKeyAuth::class];
/**
* 文章列表
*/
public function index(Request $request)
{
$page = $request->param('page', 1, 'intval');
$limit = $request->param('limit', 15, 'intval');
$type = $request->param('type', '');
$category_id = $request->param('category_id', 0, 'intval');
$keyword = $request->param('keyword', '');
$model_list = Post::with(['categorys.category', 'tags.tag'])
->order('id desc');
if (!empty($type)) {
$model_list = $model_list->where('type', $type);
}
if (!empty($category_id)) {
$model_list = $model_list->where('category_id', $category_id);
}
if (!empty($keyword)) {
$model_list = $model_list->where('title', 'like', "%{$keyword}%");
}
$list = $model_list->paginate([
'page' => $page,
'list_rows' => $limit,
]);
return json_message([
'list' => $list->items(),
'total' => $list->total(),
'page' => $page,
]);
}
/**
* 文章详情
*/
public function read(Request $request)
{
$id = $request->param('id', 0, 'intval');
if ($id <= 0) {
return json_message('参数错误');
}
$post = Post::with(['categorys.category', 'tags.tag'])->find($id);
if (empty($post)) {
return json_message('文章不存在');
}
return json_message(['post' => $post]);
}
/**
* 创建文章
*/
public function save(Request $request)
{
if ($request->can_write_own != 1) {
return json_message('无权操作', 403);
}
$post_data = $request->post();
if (empty($post_data['title'])) {
return json_message('标题必填');
}
$categorys = [];
$tags = [];
if (isset($post_data['categorys'])) {
$categorys = $post_data['categorys'];
unset($post_data['categorys']);
}
if (isset($post_data['tags'])) {
$tags = $post_data['tags'];
unset($post_data['tags']);
}
$post_data['uid'] = uniqid();
$post_data['source'] = 'api';
$post_data['create_time'] = time();
$post_data['update_time'] = time();
if (!isset($post_data['type'])) {
$post_data['type'] = '1';
}
if (!isset($post_data['status'])) {
$post_data['status'] = 0;
}
if (!isset($post_data['content_type'])) {
$post_data['content_type'] = 'html';
}
// content_type 白名单校验
$allowed_content_types = ['html', 'markdown'];
if (!in_array($post_data['content_type'], $allowed_content_types)) {
return json_message('无效的content_type', 500);
}
// Markdown→HTML 自动转换
if ($post_data['content_type'] === 'markdown' && !empty($post_data['content'])) {
$converter = new CommonMarkConverter(['html_input' => 'strip', 'allow_unsafe_links' => false]);
$post_data['content_html'] = $converter->convert($post_data['content']);
}
$model_post = Post::create($post_data);
foreach ($categorys as $category) {
PostCategory::create([
'post_id' => $model_post->id,
'category_id' => $category,
]);
}
foreach ($tags as $tag) {
PostTag::create([
'post_id' => $model_post->id,
'tag_id' => $tag,
]);
}
return json_message(['id' => $model_post->id, 'uid' => $model_post->uid], 0, '创建成功');
}
/**
* 编辑文章
*/
public function update(Request $request)
{
$id = $request->param('id', 0, 'intval');
if ($id <= 0) {
return json_message('参数错误');
}
$model_post = Post::find($id);
if (empty($model_post)) {
return json_message('文章不存在');
}
$source = $model_post->getData('source');
if ($source === 'api') {
if ($request->can_write_own != 1) {
return json_message('无权操作', 403);
}
} else {
if ($request->can_write_other != 1) {
return json_message('无权操作', 403);
}
}
$post_data = $request->post();
unset($post_data['id']);
// categorys diff update
if (isset($post_data['categorys'])) {
$categorys = $post_data['categorys'];
unset($post_data['categorys']);
$old_category_list = PostCategory::where('post_id', $id)->select();
$old_category_ids = array_column($old_category_list->toArray(), 'category_id');
// old has, new doesn't -> delete
foreach ($old_category_list as $model_category) {
if (!in_array($model_category->category_id, $categorys)) {
$model_category->delete();
}
}
// new has, old doesn't -> create
foreach ($categorys as $category) {
if (!in_array($category, $old_category_ids)) {
PostCategory::create([
'post_id' => $id,
'category_id' => $category,
]);
}
}
}
// tags diff update
if (isset($post_data['tags'])) {
$tags = $post_data['tags'];
unset($post_data['tags']);
$old_tag_list = PostTag::where('post_id', $id)->select();
$old_tag_ids = array_column($old_tag_list->toArray(), 'tag_id');
foreach ($old_tag_list as $model_tag) {
if (!in_array($model_tag->tag_id, $tags)) {
$model_tag->delete();
}
}
foreach ($tags as $tag) {
if (!in_array($tag, $old_tag_ids)) {
PostTag::create([
'post_id' => $id,
'tag_id' => $tag,
]);
}
}
}
// Markdown→HTML 自动转换
if (isset($post_data['content_type']) && $post_data['content_type'] === 'markdown' && !empty($post_data['content'])) {
$converter = new CommonMarkConverter(['html_input' => 'strip', 'allow_unsafe_links' => false]);
$post_data['content_html'] = $converter->convert($post_data['content']);
}
$model_post->save($post_data);
return json_message([], 0, '更新成功');
}
/**
* 删除文章
*/
public function delete(Request $request)
{
$id = $request->param('id', 0, 'intval');
if ($id <= 0) {
return json_message('参数错误');
}
$model_post = Post::find($id);
if (empty($model_post)) {
return json_message('文章不存在');
}
$source = $model_post->getData('source');
if ($source === 'api') {
if ($request->can_delete < 1) {
return json_message('无权删除', 403);
}
} else {
if ($request->can_delete != 2) {
return json_message('无权删除', 403);
}
}
$model_post->delete();
PostCategory::where('post_id', $id)->delete();
PostTag::where('post_id', $id)->delete();
return json_message([], 0, '删除成功');
}
}