feat: enhance error handling and permissions in Admin and Report services
This commit is contained in:
@@ -364,7 +364,8 @@ Json::Value AdminService::updateUserRoles(const auth::UserContext &user,
|
||||
return failure("user_not_found");
|
||||
}
|
||||
|
||||
db->execSqlSync("DELETE FROM user_roles WHERE user_id = ?", targetUserId);
|
||||
std::vector<long long> roleIds;
|
||||
roleIds.reserve(body["roles"].size());
|
||||
for (const auto &role : body["roles"])
|
||||
{
|
||||
if (!role.isString())
|
||||
@@ -378,10 +379,15 @@ Json::Value AdminService::updateUserRoles(const auth::UserContext &user,
|
||||
{
|
||||
return failure("role_not_found");
|
||||
}
|
||||
db->execSqlSync(
|
||||
"INSERT INTO user_roles (user_id, role_id) VALUES (?, ?)",
|
||||
targetUserId,
|
||||
roleRows[0]["id"].as<long long>());
|
||||
roleIds.push_back(roleRows[0]["id"].as<long long>());
|
||||
}
|
||||
|
||||
db->execSqlSync("DELETE FROM user_roles WHERE user_id = ?", targetUserId);
|
||||
for (const auto roleId : roleIds)
|
||||
{
|
||||
db->execSqlSync("INSERT INTO user_roles (user_id, role_id) VALUES (?, ?)",
|
||||
targetUserId,
|
||||
roleId);
|
||||
}
|
||||
return success();
|
||||
}
|
||||
|
||||
@@ -123,6 +123,11 @@ bool canInteractWithReport(const auth::UserContext &user, long long reportId)
|
||||
return ownsReport(user, reportId) || canModifyReport(user, reportId);
|
||||
}
|
||||
|
||||
bool canCreateCitizenReport(const auth::UserContext &user)
|
||||
{
|
||||
return !auth::canManageReports(user);
|
||||
}
|
||||
|
||||
int boundedPage(const std::optional<std::string> &value)
|
||||
{
|
||||
if (!value)
|
||||
@@ -257,6 +262,11 @@ void notifyReportOwner(long long reportId,
|
||||
Json::Value ReportService::createReport(const auth::UserContext &user,
|
||||
const Json::Value &body)
|
||||
{
|
||||
if (!canCreateCitizenReport(user))
|
||||
{
|
||||
return failure("forbidden");
|
||||
}
|
||||
|
||||
const auto missing =
|
||||
validation::missingStrings(body, {"address", "description"});
|
||||
if (!missing.empty() || !validation::hasNumber(body, "category_id") ||
|
||||
@@ -318,8 +328,13 @@ Json::Value ReportService::createReport(const auth::UserContext &user,
|
||||
|
||||
if (body["media"].isArray())
|
||||
{
|
||||
size_t mediaCount = 0;
|
||||
for (const auto &item : body["media"])
|
||||
{
|
||||
if (mediaCount >= 5)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (item.isString() && !item.asString().empty())
|
||||
{
|
||||
db->execSqlSync(
|
||||
@@ -327,6 +342,7 @@ Json::Value ReportService::createReport(const auth::UserContext &user,
|
||||
"VALUES (?, ?, 'IMAGE')",
|
||||
reportId,
|
||||
item.asString());
|
||||
++mediaCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -713,6 +729,13 @@ Json::Value ReportService::assignTeam(const auth::UserContext &user,
|
||||
{
|
||||
return failure("invalid_status_transition");
|
||||
}
|
||||
const auto team = db->execSqlSync(
|
||||
"SELECT id FROM teams WHERE id = ? AND active = TRUE",
|
||||
body["team_id"].asInt64());
|
||||
if (team.empty())
|
||||
{
|
||||
return failure("team_not_found");
|
||||
}
|
||||
|
||||
db->execSqlSync(
|
||||
"INSERT INTO assignments (report_id, team_id, assigned_by_user_id) "
|
||||
@@ -786,11 +809,25 @@ Json::Value ReportService::flagReport(const auth::UserContext &user,
|
||||
long long reportId,
|
||||
const Json::Value &body)
|
||||
{
|
||||
if (!canAccessReport(user, reportId) ||
|
||||
!validation::hasString(body, "reason"))
|
||||
if (!validation::hasString(body, "reason"))
|
||||
{
|
||||
return failure("invalid_flag");
|
||||
}
|
||||
|
||||
const auto owner = reportOwner(reportId);
|
||||
if (!owner)
|
||||
{
|
||||
return failure("report_not_found");
|
||||
}
|
||||
if (*owner == user.id)
|
||||
{
|
||||
return failure("cannot_flag_own_report");
|
||||
}
|
||||
if (!canAccessReport(user, reportId))
|
||||
{
|
||||
return failure("forbidden");
|
||||
}
|
||||
|
||||
auto db = drogon::app().getDbClient();
|
||||
db->execSqlSync(
|
||||
"INSERT INTO moderation_flags "
|
||||
@@ -812,20 +849,27 @@ Json::Value ReportService::flagMessage(const auth::UserContext &user,
|
||||
long long messageId,
|
||||
const Json::Value &body)
|
||||
{
|
||||
if (!canInteractWithReport(user, reportId) ||
|
||||
!validation::hasString(body, "reason"))
|
||||
if (!validation::hasString(body, "reason"))
|
||||
{
|
||||
return failure("invalid_flag");
|
||||
}
|
||||
if (!canInteractWithReport(user, reportId))
|
||||
{
|
||||
return failure("forbidden");
|
||||
}
|
||||
auto db = drogon::app().getDbClient();
|
||||
const auto message = db->execSqlSync(
|
||||
"SELECT id FROM messages WHERE id = ? AND report_id = ?",
|
||||
"SELECT id, user_id FROM messages WHERE id = ? AND report_id = ?",
|
||||
messageId,
|
||||
reportId);
|
||||
if (message.empty())
|
||||
{
|
||||
return failure("message_not_found");
|
||||
}
|
||||
if (message[0]["user_id"].as<long long>() == user.id)
|
||||
{
|
||||
return failure("cannot_flag_own_message");
|
||||
}
|
||||
db->execSqlSync(
|
||||
"INSERT INTO moderation_flags "
|
||||
"(content_type, report_id, message_id, reason, details, created_by_user_id) "
|
||||
|
||||
Reference in New Issue
Block a user