diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 8b415cc..5cc115f 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -42,9 +42,16 @@ jobs:
submodules: recursive
fetch-depth: 0
- - name: Install system dependencies
+ - name: Switch apt mirror
run: |
+ # GitHub 托管 runner 默认走 Azure 镜像,下载系统库容易卡住,切换到官方源
+ if [ -f /etc/apt/apt-mirrors.txt ]; then
+ sudo sed -i 's/azure\.archive\.ubuntu\.com/archive.ubuntu.com/g' /etc/apt/apt-mirrors.txt
+ fi
sudo apt-get update
+
+ - name: Install system dependencies
+ run: |
sudo apt-get install -y \
build-essential \
ninja-build \
diff --git a/dbproxy/xml/category.xml b/dbproxy/xml/category.xml
index accfb59..1d50c25 100644
--- a/dbproxy/xml/category.xml
+++ b/dbproxy/xml/category.xml
@@ -11,9 +11,10 @@
+
-
+
\ No newline at end of file
diff --git a/src/blog_module.cc b/src/blog_module.cc
index 921ae1d..8d80758 100644
--- a/src/blog_module.cc
+++ b/src/blog_module.cc
@@ -431,10 +431,14 @@ void BlogModule::registerServlets()
dp->addServlet("/api/v1/admin/database/exports/:id/delete", XX(ExportDeleteServlet));
dp->addServlet("/api/v1/admin/database/exports/:id/download", XX(ExportDownloadServlet));
dp->addServlet("/api/v1/admin/database/cleanup", XX(CleanupServlet));
- // 文章分类相关
- dp->addServlet("/api/v1/category/admin/create", XX(CategoryCreateServlet));
- dp->addServlet("/api/v1/category/admin/delete", XX(CategoryDeleteServlet));
- dp->addServlet("/api/v1/category/admin/query", XX(CategoryQueryServlet));
+ // 文章分类相关(个人分类,登录后使用)
+ dp->addServlet("/api/v1/category/create", XX(CategoryCreateServlet));
+ dp->addServlet("/api/v1/category/delete", XX(CategoryDeleteServlet));
+ dp->addServlet("/api/v1/category/query", XX(CategoryQueryServlet));
+ // 管理端分类管理(可跨用户操作)
+ dp->addServlet("/api/v1/category/admin/create", XX(CategoryAdminCreateServlet));
+ dp->addServlet("/api/v1/category/admin/delete", XX(CategoryAdminDeleteServlet));
+ dp->addServlet("/api/v1/category/admin/query", XX(CategoryAdminQueryServlet));
// 错误码下发(公开接口)
dp->addServlet("/api/v1/error-codes", XX(ErrorCodesServlet));
// 站点公开配置
diff --git a/src/index.cc b/src/index.cc
index 2ee908f..ddb39bf 100644
--- a/src/index.cc
+++ b/src/index.cc
@@ -42,6 +42,9 @@ static chen::ConfigVar::ptr g_jieba_dict_path =
static chen::ConfigVar::ptr g_index_path = chen::Config::Lookup("search.index_path", std::string(""), "search index file path");
+/// 索引文件格式版本。数据结构/内容口径变化时递增,旧文件会被丢弃并全量重建
+static const uint32_t kIndexFileVersion = 2;
+
Index::Index()
: m_createTime(0)
, m_endTime(0)
@@ -358,7 +361,7 @@ bool Index::save(const std::string& path)
}
chen::ByteArray::ptr ba(new chen::ByteArray);
ba->writeUint32(0x42494458); // magic 'BIDX'
- ba->writeUint32(1); // version
+ ba->writeUint32(kIndexFileVersion);
ba->writeInt64(m_docs.size());
for (auto id : m_docs) {
ba->writeInt64(id);
@@ -419,7 +422,10 @@ bool Index::load(const std::string& path)
return false;
}
uint32_t version = ba->readUint32();
- (void)version;
+ if (version != kIndexFileVersion) {
+ WARN(logger) << "index file version mismatch, file=" << version << " expect=" << kIndexFileVersion << ", rebuild from scratch";
+ return false;
+ }
initJieba();
diff --git a/src/manager/category_manager.cc b/src/manager/category_manager.cc
index d96780f..db2c75b 100644
--- a/src/manager/category_manager.cc
+++ b/src/manager/category_manager.cc
@@ -11,7 +11,7 @@ namespace blog {
static chen::Logger::ptr logger = LOG_ROOT();
static const int kCacheTTL = 300;
-static const char* kCachePrefix = "cache:obj:cat:";
+static const char* kCachePrefix = "cache:obj:cat2:";
static std::string categoryCacheKey(int64_t id)
{
@@ -22,6 +22,7 @@ static data::CategoryInfo::ptr parseCategoryCache(const Json::Value& v)
{
auto info = std::make_shared();
info->setId(cacheJsonInt64(v, "id"));
+ info->setUserId(cacheJsonInt64(v, "user_id"));
info->setName(cacheJsonString(v, "name"));
info->setColor(cacheJsonString(v, "color"));
info->setDescription(cacheJsonString(v, "description"));
@@ -104,21 +105,44 @@ void CategoryManager::listAll(std::vector& infos,
}
}
-blog::data::CategoryInfo::ptr CategoryManager::getByName(const std::string& name)
+bool CategoryManager::listByUserId(std::vector& infos, int64_t user_id, bool isValid)
{
- int64_t cachedId = getCachedIdMapping("cat:name:" + name);
+ auto db = GetDB();
+ if (!db) {
+ ERROR(logger) << "Get DB connection fail";
+ return false;
+ }
+ auto qb = data::CategoryInfoDao::newQuery();
+ qb->where("user_id", "=", user_id);
+ qb->whereIf(isValid, "is_deleted", "=", (int64_t)0);
+ qb->orderBy("id", "ASC");
+ if (data::CategoryInfoDao::QueryByBuilder(infos, qb, db)) {
+ ERROR(logger) << "QueryByBuilder failed";
+ return false;
+ }
+ return true;
+}
+
+blog::data::CategoryInfo::ptr CategoryManager::getByUserIdName(int64_t user_id, const std::string& name)
+{
+ std::string cache_key = "cat:uid_name:" + std::to_string(user_id) + ":" + name;
+ int64_t cachedId = getCachedIdMapping(cache_key);
if (cachedId > 0) {
- return get(cachedId);
+ auto cached = get(cachedId);
+ // 改名后旧映射可能仍在缓存中,校验归属和名称,避免命中脏数据
+ if (cached && cached->getUserId() == user_id && cached->getName() == name) {
+ return cached;
+ }
}
auto db = GetDB();
if (!db) {
ERROR(logger) << "Get DB connection fail";
return nullptr;
}
- auto info = data::CategoryInfoDao::QueryByName(name, db);
+ auto info = data::CategoryInfoDao::QueryByUserIdName(user_id, name, db);
if (info) {
setCategoryCache(info);
- cacheIdMapping("cat:name:" + name, info->getId());
+ cacheIdMapping(cache_key, info->getId());
}
return info;
}
diff --git a/src/manager/category_manager.h b/src/manager/category_manager.h
index 837ddd0..b36a103 100644
--- a/src/manager/category_manager.h
+++ b/src/manager/category_manager.h
@@ -11,11 +11,13 @@ class CategoryManager {
public:
void listAll(std::vector& infos, bool isValid = false);
+ bool listByUserId(std::vector& infos, int64_t user_id, bool isValid = false);
+
void add(blog::data::CategoryInfo::ptr info);
blog::data::CategoryInfo::ptr get(int64_t id);
- blog::data::CategoryInfo::ptr getByName(const std::string& name);
+ blog::data::CategoryInfo::ptr getByUserIdName(int64_t user_id, const std::string& name);
private:
static data::CategoryInfo::ptr parseRow(chen::ISQLData::ptr rt);
diff --git a/src/permission.h b/src/permission.h
index be6f358..ef2e325 100644
--- a/src/permission.h
+++ b/src/permission.h
@@ -8,6 +8,7 @@
#pragma once
+#include "error_codes.h"
#include "manager/organization_manager.h"
#include "manager/user_manager.h"
@@ -182,5 +183,38 @@ inline bool CanBypassReview(int32_t system_role)
return system_role == UserManager::Role::ADMIN || system_role == UserManager::Role::CHECKER;
}
+// ============================================================================
+// 管理端路由权限
+// ============================================================================
+
+/// 是否系统管理员
+inline bool IsAdmin(int32_t system_role)
+{
+ return system_role == UserManager::Role::ADMIN;
+}
+
+/**
+ * @brief 校验管理端路由访问权限
+ * @param uid 当前登录用户 id
+ * @param user 当前登录用户信息
+ * @return 0 表示通过,否则返回需要下发的错误码
+ */
+inline int32_t CheckAdminRoute(int64_t uid, const data::UserInfo::ptr& user)
+{
+ if (!uid) {
+ return errcode::NOT_LOGIN;
+ }
+ if (!user) {
+ return errcode::USER_NOT_FOUND;
+ }
+ if (user->getState() != UserManager::Status::ACTIVE || user->getIsDeleted()) {
+ return errcode::ACCOUNT_INVALID;
+ }
+ if (!IsAdmin(user->getRole())) {
+ return errcode::ACCESS_DENIED;
+ }
+ return 0;
+}
+
} // namespace permission
} // namespace blog
diff --git a/src/servlets/article/article_create_servlet.cc b/src/servlets/article/article_create_servlet.cc
index 2a1616b..693e6a6 100644
--- a/src/servlets/article/article_create_servlet.cc
+++ b/src/servlets/article/article_create_servlet.cc
@@ -79,7 +79,8 @@ int32_t ArticleCreateServlet::handle(
for (auto& s : cat_ids) {
int64_t cid = chen::TypeUtil::Atoi(s);
auto cinfo = CategoryMgr::GetInstance()->get(cid);
- if (!cinfo) {
+ if (!cinfo || cinfo->getUserId() != uid) {
+ WARN(logger) << "skip category not owned by user, user_id=" << uid << " category_id=" << cid;
continue;
}
data::ArticleCategoryRelInfo::ptr rel(new data::ArticleCategoryRelInfo);
diff --git a/src/servlets/article/article_update_category_servlet.cc b/src/servlets/article/article_update_category_servlet.cc
index 7752b87..8076ae7 100644
--- a/src/servlets/article/article_update_category_servlet.cc
+++ b/src/servlets/article/article_update_category_servlet.cc
@@ -2,6 +2,7 @@
#include
+#include "../../index.h"
#include "../../manager/article_category_rel_manager.h"
#include "../../manager/article_manager.h"
#include "../../manager/category_manager.h"
@@ -73,7 +74,8 @@ int32_t ArticleUpdateCategoryServlet::handle(
for (auto& i : tmps) {
int64_t cid = chen::TypeUtil::Atoi(i);
auto cinfo = CategoryMgr::GetInstance()->get(cid);
- if (!cinfo) {
+ if (!cinfo || cinfo->getUserId() != uid) {
+ WARN(logger) << "skip category not owned by user, user_id=" << uid << " category_id=" << cid;
continue;
}
auto acinfo = ArticleCategoryRelMgr::GetInstance()->getByArticleIdCategoryId(id, cid);
@@ -104,7 +106,8 @@ int32_t ArticleUpdateCategoryServlet::handle(
for (auto& i : tmps) {
int64_t cid = chen::TypeUtil::Atoi(i);
auto cinfo = CategoryMgr::GetInstance()->get(cid);
- if (!cinfo) {
+ if (!cinfo || cinfo->getUserId() != uid) {
+ WARN(logger) << "skip category not owned by user, user_id=" << uid << " category_id=" << cid;
continue;
}
auto acinfo = ArticleCategoryRelMgr::GetInstance()->getByArticleIdCategoryId(id, cid);
@@ -132,6 +135,9 @@ int32_t ArticleUpdateCategoryServlet::handle(
break;
}
+ // 分类关联已变化,同步刷新搜索索引中的 CAT_ID,避免按分类筛选结果滞后
+ IndexMgr::GetInstance()->updateArticle(ainfo);
+
if (!update_add_infos.empty()) {
auto& v = result->jsondata["add_category_ids"];
for (auto& i : update_add_infos) {
diff --git a/src/servlets/article/article_update_servlet.cc b/src/servlets/article/article_update_servlet.cc
index e601b99..20db653 100644
--- a/src/servlets/article/article_update_servlet.cc
+++ b/src/servlets/article/article_update_servlet.cc
@@ -158,12 +158,17 @@ int32_t ArticleUpdateServlet::syncCategoryRels(chen::http::HttpRequest::ptr requ
std::vector old_rels;
ArticleCategoryRelMgr::GetInstance()->listByArticleId(old_rels, id, true);
+ int64_t uid = getUserId(request);
+ if (!uid) {
+ return 0;
+ }
+
std::set new_cat_ids;
auto cat_id_strs = chen::StringUtil::Split(category, ',');
for (auto& s : cat_id_strs) {
int64_t cid = chen::TypeUtil::Atoi(s);
auto cinfo = CategoryMgr::GetInstance()->get(cid);
- if (cinfo) {
+ if (cinfo && cinfo->getUserId() == uid) {
new_cat_ids.insert(cid);
}
}
diff --git a/src/servlets/category/category_create_servlet.cc b/src/servlets/category/category_create_servlet.cc
index eec41c4..08324de 100644
--- a/src/servlets/category/category_create_servlet.cc
+++ b/src/servlets/category/category_create_servlet.cc
@@ -1,6 +1,8 @@
#include "category_create_servlet.h"
#include "../../manager/category_manager.h"
+#include "../../manager/user_manager.h"
+#include "../../permission.h"
#include "../../util.h"
#include
@@ -11,10 +13,35 @@ namespace servlet {
static chen::Logger::ptr logger = LOG_ROOT();
CategoryCreateServlet::CategoryCreateServlet()
- : BlogAdminServlet("CategoryCreateServlet")
+ : BlogLoginedServlet("CategoryCreateServlet")
{
}
+bool CategoryCreateServlet::handlePre(
+ chen::http::HttpRequest::ptr request,
+ chen::http::HttpResponse::ptr response,
+ chen::http::HttpSession::ptr session,
+ Result::ptr result)
+{
+ if (!BlogLoginedServlet::handlePre(request, response, session, result)) {
+ return false;
+ }
+ if (!isAdminRoute()) {
+ return true;
+ }
+ int64_t uid = getUserId(request);
+ data::UserInfo::ptr user;
+ if (uid) {
+ user = UserMgr::GetInstance()->get(uid);
+ }
+ int32_t rt = permission::CheckAdminRoute(uid, user);
+ if (rt) {
+ result->setErrno(rt);
+ return false;
+ }
+ return true;
+}
+
int32_t CategoryCreateServlet::handle(
chen::http::HttpRequest::ptr request,
chen::http::HttpResponse::ptr response,
@@ -30,40 +57,74 @@ int32_t CategoryCreateServlet::handle(
int64_t parent_id = request->getParamAs("parent_id");
int32_t status = request->getParamAs("status", 1);
int64_t cid = request->getParamAs("id", 0);
+ int64_t req_uid = request->getParamAs("user_id", 0);
int64_t uid = getUserId(request);
if (!uid) {
result->setErrno(errcode::NOT_LOGIN);
break;
}
-
- data::CategoryInfo::ptr parent_info;
- if (parent_id) {
- parent_info = CategoryMgr::GetInstance()->get(parent_id);
- if (!parent_info) {
- result->setErrno(errcode::PARAM_INVALID, "invalid parent_id");
- break;
- }
- }
+ bool admin_route = isAdminRoute();
data::CategoryInfo::ptr info;
+ int64_t owner_id = uid;
if (cid) {
info = CategoryMgr::GetInstance()->get(cid);
if (!info) {
result->setErrno(errcode::PARAM_INVALID, "invalid cid");
break;
}
- info->setName(name);
+ if (!admin_route && info->getUserId() != uid) {
+ result->setErrno(errcode::ACCESS_DENIED);
+ break;
+ }
+ owner_id = info->getUserId();
} else {
- info = CategoryMgr::GetInstance()->getByName(name);
+ if (req_uid && req_uid != uid) {
+ if (!admin_route) {
+ result->setErrno(errcode::ACCESS_DENIED);
+ break;
+ }
+ owner_id = req_uid;
+ }
+ auto owner = UserMgr::GetInstance()->get(owner_id);
+ if (!owner) {
+ result->setErrno(errcode::USER_NOT_FOUND);
+ break;
+ }
+ }
+
+ if (parent_id) {
+ auto parent_info = CategoryMgr::GetInstance()->get(parent_id);
+ if (!parent_info || parent_info->getUserId() != owner_id) {
+ result->setErrno(errcode::PARAM_INVALID, "invalid parent_id");
+ break;
+ }
+ if (parent_id == cid) {
+ result->setErrno(errcode::PARAM_INVALID, "invalid parent_id");
+ break;
+ }
+ }
+
+ if (!info) {
+ info = CategoryMgr::GetInstance()->getByUserIdName(owner_id, name);
if (!info) {
info.reset(new data::CategoryInfo);
+ info->setUserId(owner_id);
info->setName(name);
info->setCreateTime(time(0));
} else if (info->getIsDeleted()) {
info->setIsDeleted(0);
}
+ } else if (info->getName() != name) {
+ auto same = CategoryMgr::GetInstance()->getByUserIdName(owner_id, name);
+ if (same && same->getId() != info->getId()) {
+ result->setErrno(errcode::PARAM_INVALID, "category name exists");
+ break;
+ }
+ info->setName(name);
}
+
info->setColor(color);
info->setParentId(parent_id);
info->setIsDeleted(0);
@@ -88,6 +149,7 @@ int32_t CategoryCreateServlet::handle(
CategoryMgr::GetInstance()->add(info);
result->set("id", info->getId());
+ result->set("user_id", info->getUserId());
result->set("name", info->getName());
result->set("color", info->getColor());
result->set("parent_id", parent_id);
diff --git a/src/servlets/category/category_create_servlet.h b/src/servlets/category/category_create_servlet.h
index 68ef3a7..6078b3c 100644
--- a/src/servlets/category/category_create_servlet.h
+++ b/src/servlets/category/category_create_servlet.h
@@ -5,17 +5,36 @@
namespace blog {
namespace servlet {
-class CategoryCreateServlet : public BlogAdminServlet {
+class CategoryCreateServlet : public BlogLoginedServlet {
public:
typedef std::shared_ptr ptr;
CategoryCreateServlet();
protected:
+ bool handlePre(
+ chen::http::HttpRequest::ptr request,
+ chen::http::HttpResponse::ptr response,
+ chen::http::HttpSession::ptr session,
+ Result::ptr result) override;
+
int32_t handle(
chen::http::HttpRequest::ptr request,
chen::http::HttpResponse::ptr response,
chen::http::HttpSession::ptr session,
Result::ptr result) override;
+
+ virtual bool isAdminRoute() const { return false; }
+};
+
+/**
+ * @brief 管理端分类创建/编辑(可为任意用户操作)
+ */
+class CategoryAdminCreateServlet : public CategoryCreateServlet {
+public:
+ typedef std::shared_ptr ptr;
+
+protected:
+ bool isAdminRoute() const override { return true; }
};
} // namespace servlet
diff --git a/src/servlets/category/category_delete_servlet.cc b/src/servlets/category/category_delete_servlet.cc
index 80c40f7..af3f1ba 100644
--- a/src/servlets/category/category_delete_servlet.cc
+++ b/src/servlets/category/category_delete_servlet.cc
@@ -3,6 +3,8 @@
#include
#include "../../manager/category_manager.h"
+#include "../../manager/user_manager.h"
+#include "../../permission.h"
#include "../../util.h"
#include "blog/data/category_info.h"
@@ -14,14 +16,42 @@ namespace servlet {
static chen::Logger::ptr logger = LOG_ROOT();
CategoryDeleteServlet::CategoryDeleteServlet()
- : BlogAdminServlet("CategoryDeleteServlet")
+ : BlogLoginedServlet("CategoryDeleteServlet")
{
}
-void get_delete_values(std::map> parent_map, int64_t id, std::set& infos)
+bool CategoryDeleteServlet::handlePre(
+ chen::http::HttpRequest::ptr request,
+ chen::http::HttpResponse::ptr response,
+ chen::http::HttpSession::ptr session,
+ Result::ptr result)
{
- auto it = parent_map[0].find(id);
- if (it == parent_map[0].end()) {
+ if (!BlogLoginedServlet::handlePre(request, response, session, result)) {
+ return false;
+ }
+ if (!isAdminRoute()) {
+ return true;
+ }
+ int64_t uid = getUserId(request);
+ data::UserInfo::ptr user;
+ if (uid) {
+ user = UserMgr::GetInstance()->get(uid);
+ }
+ int32_t rt = permission::CheckAdminRoute(uid, user);
+ if (rt) {
+ result->setErrno(rt);
+ return false;
+ }
+ return true;
+}
+
+void get_delete_values(
+ const std::map>& parent_map,
+ int64_t id,
+ std::set& infos)
+{
+ auto it = parent_map.at(0).find(id);
+ if (it == parent_map.at(0).end()) {
return;
}
if (!infos.insert(it->second).second) {
@@ -49,14 +79,31 @@ int32_t CategoryDeleteServlet::handle(
for (auto& i : tmp) {
cat_ids.insert(chen::TypeUtil::Atoi(i));
}
+ int64_t req_uid = request->getParamAs("user_id", 0);
int64_t uid = getUserId(request);
if (!uid) {
result->setErrno(errcode::NOT_LOGIN);
break;
}
+ bool admin_route = isAdminRoute();
+
std::vector infos;
- CategoryMgr::GetInstance()->listAll(infos);
+ if (admin_route) {
+ if (req_uid) {
+ if (!CategoryMgr::GetInstance()->listByUserId(infos, req_uid)) {
+ result->setErrno(errcode::DB_OPERATION_FAILED);
+ break;
+ }
+ } else {
+ CategoryMgr::GetInstance()->listAll(infos);
+ }
+ } else {
+ if (!CategoryMgr::GetInstance()->listByUserId(infos, uid)) {
+ result->setErrno(errcode::DB_OPERATION_FAILED);
+ break;
+ }
+ }
if (infos.empty()) {
result->setErrno(errcode::PARAM_MISSING, "no categories");
break;
@@ -108,6 +155,7 @@ int32_t CategoryDeleteServlet::handle(
for (auto& i : del_cats) {
Json::Value item;
item["id"] = i->getId();
+ item["user_id"] = i->getUserId();
item["name"] = i->getName();
item["color"] = i->getColor();
item["parent_id"] = i->getParentId();
diff --git a/src/servlets/category/category_delete_servlet.h b/src/servlets/category/category_delete_servlet.h
index 4ce3aae..c3f8542 100644
--- a/src/servlets/category/category_delete_servlet.h
+++ b/src/servlets/category/category_delete_servlet.h
@@ -5,17 +5,36 @@
namespace blog {
namespace servlet {
-class CategoryDeleteServlet : public BlogAdminServlet {
+class CategoryDeleteServlet : public BlogLoginedServlet {
public:
typedef std::shared_ptr ptr;
CategoryDeleteServlet();
protected:
+ bool handlePre(
+ chen::http::HttpRequest::ptr request,
+ chen::http::HttpResponse::ptr response,
+ chen::http::HttpSession::ptr session,
+ Result::ptr result) override;
+
int32_t handle(
chen::http::HttpRequest::ptr request,
chen::http::HttpResponse::ptr response,
chen::http::HttpSession::ptr session,
Result::ptr result) override;
+
+ virtual bool isAdminRoute() const { return false; }
+};
+
+/**
+ * @brief 管理端分类删除(可删除任意用户的分类)
+ */
+class CategoryAdminDeleteServlet : public CategoryDeleteServlet {
+public:
+ typedef std::shared_ptr ptr;
+
+protected:
+ bool isAdminRoute() const override { return true; }
};
} // namespace servlet
diff --git a/src/servlets/category/category_query_servlet.cc b/src/servlets/category/category_query_servlet.cc
index d7b4d22..8a3420c 100644
--- a/src/servlets/category/category_query_servlet.cc
+++ b/src/servlets/category/category_query_servlet.cc
@@ -3,6 +3,8 @@
#include "../../manager/article_category_rel_manager.h"
#include "../../manager/article_manager.h"
#include "../../manager/category_manager.h"
+#include "../../manager/user_manager.h"
+#include "../../permission.h"
#include
@@ -12,10 +14,35 @@ namespace servlet {
static chen::Logger::ptr logger = LOG_ROOT();
CategoryQueryServlet::CategoryQueryServlet()
- : BlogAdminServlet("CategoryQueryServlet")
+ : BlogLoginedServlet("CategoryQueryServlet")
{
}
+bool CategoryQueryServlet::handlePre(
+ chen::http::HttpRequest::ptr request,
+ chen::http::HttpResponse::ptr response,
+ chen::http::HttpSession::ptr session,
+ Result::ptr result)
+{
+ if (!BlogLoginedServlet::handlePre(request, response, session, result)) {
+ return false;
+ }
+ if (!isAdminRoute()) {
+ return true;
+ }
+ int64_t uid = getUserId(request);
+ data::UserInfo::ptr user;
+ if (uid) {
+ user = UserMgr::GetInstance()->get(uid);
+ }
+ int32_t rt = permission::CheckAdminRoute(uid, user);
+ if (rt) {
+ result->setErrno(rt);
+ return false;
+ }
+ return true;
+}
+
int32_t CategoryQueryServlet::handle(
chen::http::HttpRequest::ptr request,
chen::http::HttpResponse::ptr response,
@@ -28,15 +55,29 @@ int32_t CategoryQueryServlet::handle(
result->setErrno(errcode::NOT_LOGIN);
break;
}
+ int64_t req_uid = request->getParamAs("user_id", 0);
std::vector infos;
- CategoryMgr::GetInstance()->listAll(infos, true);
+ if (req_uid) {
+ if (!CategoryMgr::GetInstance()->listByUserId(infos, req_uid, true)) {
+ result->setErrno(errcode::DB_OPERATION_FAILED);
+ break;
+ }
+ } else if (isAdminRoute()) {
+ CategoryMgr::GetInstance()->listAll(infos, true);
+ } else if (!CategoryMgr::GetInstance()->listByUserId(infos, uid, true)) {
+ result->setErrno(errcode::DB_OPERATION_FAILED);
+ break;
+ }
result->set("total", infos.size());
auto& list = result->jsondata["list"];
for (const auto& cat : infos) {
Json::Value item;
item["id"] = cat->getId();
+ item["user_id"] = cat->getUserId();
+ auto owner = UserMgr::GetInstance()->get(cat->getUserId());
+ item["author"] = owner ? owner->getName() : "";
item["name"] = cat->getName();
item["url"] = cat->getUrl();
item["icon"] = cat->getIcon();
diff --git a/src/servlets/category/category_query_servlet.h b/src/servlets/category/category_query_servlet.h
index e8c4797..4e77a46 100644
--- a/src/servlets/category/category_query_servlet.h
+++ b/src/servlets/category/category_query_servlet.h
@@ -5,17 +5,36 @@
namespace blog {
namespace servlet {
-class CategoryQueryServlet : public BlogAdminServlet {
+class CategoryQueryServlet : public BlogLoginedServlet {
public:
typedef std::shared_ptr ptr;
CategoryQueryServlet();
protected:
+ bool handlePre(
+ chen::http::HttpRequest::ptr request,
+ chen::http::HttpResponse::ptr response,
+ chen::http::HttpSession::ptr session,
+ Result::ptr result) override;
+
int32_t handle(
chen::http::HttpRequest::ptr request,
chen::http::HttpResponse::ptr response,
chen::http::HttpSession::ptr session,
Result::ptr result) override;
+
+ virtual bool isAdminRoute() const { return false; }
+};
+
+/**
+ * @brief 管理端分类查询(默认返回全部用户分类)
+ */
+class CategoryAdminQueryServlet : public CategoryQueryServlet {
+public:
+ typedef std::shared_ptr ptr;
+
+protected:
+ bool isAdminRoute() const override { return true; }
};
} // namespace servlet