|
@@ -6,10 +6,10 @@
|
|
|
namespace svapi {
|
|
namespace svapi {
|
|
|
namespace {
|
|
namespace {
|
|
|
// Authorize + verify the collection exists; returns the qualified collection name.
|
|
// Authorize + verify the collection exists; returns the qualified collection name.
|
|
|
-std::string scoped(ServerDeps* d, const httplib::Request& req, int projIdx, int collIdx) {
|
|
|
|
|
|
|
+std::string scoped(ServerDeps* d, const httplib::Request& req, int projIdx, int collIdx, KeyOp op) {
|
|
|
ApiKey k = requireKey(*d, req);
|
|
ApiKey k = requireKey(*d, req);
|
|
|
std::string project = req.matches[projIdx], name = req.matches[collIdx];
|
|
std::string project = req.matches[projIdx], name = req.matches[collIdx];
|
|
|
- requireProjectAccess(k, project);
|
|
|
|
|
|
|
+ requireCapability(*d, k, req, project, name, op);
|
|
|
if (!d->registry.get(project, name)) throw ApiError(ErrCode::NotFound, "not_found", "no such collection");
|
|
if (!d->registry.get(project, name)) throw ApiError(ErrCode::NotFound, "not_found", "no such collection");
|
|
|
return qualify(project, name);
|
|
return qualify(project, name);
|
|
|
}
|
|
}
|
|
@@ -18,7 +18,7 @@ void registerDocumentRoutes(ApiServer& s) {
|
|
|
auto& svr = s.raw(); ServerDeps* d = &s.deps();
|
|
auto& svr = s.raw(); ServerDeps* d = &s.deps();
|
|
|
|
|
|
|
|
svr.Post(R"(/api/v1/projects/([^/]+)/collections/([^/]+)/documents)", [d](const httplib::Request& req, httplib::Response& res) {
|
|
svr.Post(R"(/api/v1/projects/([^/]+)/collections/([^/]+)/documents)", [d](const httplib::Request& req, httplib::Response& res) {
|
|
|
- std::string c = scoped(d, req, 1, 2);
|
|
|
|
|
|
|
+ std::string c = scoped(d, req, 1, 2, KeyOp::Insert);
|
|
|
auto body = bodyJson(req);
|
|
auto body = bodyJson(req);
|
|
|
std::string id = body.value("id", "");
|
|
std::string id = body.value("id", "");
|
|
|
nlohmann::json data = body.contains("data") ? body["data"] : body;
|
|
nlohmann::json data = body.contains("data") ? body["data"] : body;
|
|
@@ -29,14 +29,14 @@ void registerDocumentRoutes(ApiServer& s) {
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
svr.Get(R"(/api/v1/projects/([^/]+)/collections/([^/]+)/documents/([^/]+))", [d](const httplib::Request& req, httplib::Response& res) {
|
|
svr.Get(R"(/api/v1/projects/([^/]+)/collections/([^/]+)/documents/([^/]+))", [d](const httplib::Request& req, httplib::Response& res) {
|
|
|
- std::string c = scoped(d, req, 1, 2);
|
|
|
|
|
|
|
+ std::string c = scoped(d, req, 1, 2, KeyOp::Read);
|
|
|
auto doc = d->db.client().get(c, req.matches[3]);
|
|
auto doc = d->db.client().get(c, req.matches[3]);
|
|
|
if (!doc) throw ApiError(ErrCode::NotFound, "not_found", "no such document");
|
|
if (!doc) throw ApiError(ErrCode::NotFound, "not_found", "no such document");
|
|
|
sendJson(res, 200, *doc);
|
|
sendJson(res, 200, *doc);
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
svr.Get(R"(/api/v1/projects/([^/]+)/collections/([^/]+)/documents)", [d](const httplib::Request& req, httplib::Response& res) {
|
|
svr.Get(R"(/api/v1/projects/([^/]+)/collections/([^/]+)/documents)", [d](const httplib::Request& req, httplib::Response& res) {
|
|
|
- std::string c = scoped(d, req, 1, 2);
|
|
|
|
|
|
|
+ std::string c = scoped(d, req, 1, 2, KeyOp::List);
|
|
|
smartbotic::database::Client::QueryOptions opts;
|
|
smartbotic::database::Client::QueryOptions opts;
|
|
|
auto range = req.params.equal_range("filter");
|
|
auto range = req.params.equal_range("filter");
|
|
|
for (auto it = range.first; it != range.second; ++it) opts.filters.push_back(parseFilter(it->second));
|
|
for (auto it = range.first; it != range.second; ++it) opts.filters.push_back(parseFilter(it->second));
|
|
@@ -53,7 +53,7 @@ void registerDocumentRoutes(ApiServer& s) {
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
svr.Patch(R"(/api/v1/projects/([^/]+)/collections/([^/]+)/documents/([^/]+))", [d](const httplib::Request& req, httplib::Response& res) {
|
|
svr.Patch(R"(/api/v1/projects/([^/]+)/collections/([^/]+)/documents/([^/]+))", [d](const httplib::Request& req, httplib::Response& res) {
|
|
|
- std::string c = scoped(d, req, 1, 2); std::string id = req.matches[3];
|
|
|
|
|
|
|
+ std::string c = scoped(d, req, 1, 2, KeyOp::Update); std::string id = req.matches[3];
|
|
|
if (!d->db.client().exists(c, id)) throw ApiError(ErrCode::NotFound, "not_found", "no such document");
|
|
if (!d->db.client().exists(c, id)) throw ApiError(ErrCode::NotFound, "not_found", "no such document");
|
|
|
uint64_t v = d->db.client().patch(c, id, bodyJson(req));
|
|
uint64_t v = d->db.client().patch(c, id, bodyJson(req));
|
|
|
if (v == 0) throw ApiError(ErrCode::Unavailable, "db_error", "patch failed");
|
|
if (v == 0) throw ApiError(ErrCode::Unavailable, "db_error", "patch failed");
|
|
@@ -61,14 +61,14 @@ void registerDocumentRoutes(ApiServer& s) {
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
svr.Put(R"(/api/v1/projects/([^/]+)/collections/([^/]+)/documents/([^/]+))", [d](const httplib::Request& req, httplib::Response& res) {
|
|
svr.Put(R"(/api/v1/projects/([^/]+)/collections/([^/]+)/documents/([^/]+))", [d](const httplib::Request& req, httplib::Response& res) {
|
|
|
- std::string c = scoped(d, req, 1, 2); std::string id = req.matches[3];
|
|
|
|
|
|
|
+ std::string c = scoped(d, req, 1, 2, KeyOp::Update); std::string id = req.matches[3];
|
|
|
if (!d->db.client().exists(c, id)) throw ApiError(ErrCode::NotFound, "not_found", "no such document");
|
|
if (!d->db.client().exists(c, id)) throw ApiError(ErrCode::NotFound, "not_found", "no such document");
|
|
|
if (!d->db.client().update(c, id, bodyJson(req))) throw ApiError(ErrCode::Unavailable, "db_error", "update failed");
|
|
if (!d->db.client().update(c, id, bodyJson(req))) throw ApiError(ErrCode::Unavailable, "db_error", "update failed");
|
|
|
sendJson(res, 200, {{"id", id}});
|
|
sendJson(res, 200, {{"id", id}});
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
svr.Delete(R"(/api/v1/projects/([^/]+)/collections/([^/]+)/documents/([^/]+))", [d](const httplib::Request& req, httplib::Response& res) {
|
|
svr.Delete(R"(/api/v1/projects/([^/]+)/collections/([^/]+)/documents/([^/]+))", [d](const httplib::Request& req, httplib::Response& res) {
|
|
|
- std::string c = scoped(d, req, 1, 2); std::string id = req.matches[3];
|
|
|
|
|
|
|
+ std::string c = scoped(d, req, 1, 2, KeyOp::Delete); std::string id = req.matches[3];
|
|
|
if (!d->db.client().remove(c, id)) throw ApiError(ErrCode::NotFound, "not_found", "no such document");
|
|
if (!d->db.client().remove(c, id)) throw ApiError(ErrCode::NotFound, "not_found", "no such document");
|
|
|
sendJson(res, 200, {{"deleted", id}});
|
|
sendJson(res, 200, {{"deleted", id}});
|
|
|
});
|
|
});
|