Rewrote backend in c++
This commit is contained in:
		
							
								
								
									
										88
									
								
								backend/src/controllers/admin.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								backend/src/controllers/admin.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,88 @@
 | 
			
		||||
#pragma clang diagnostic push
 | 
			
		||||
#pragma ide diagnostic ignored "performance-unnecessary-value-param"
 | 
			
		||||
#pragma ide diagnostic ignored "readability-convert-member-functions-to-static"
 | 
			
		||||
 | 
			
		||||
#include "controllers.h"
 | 
			
		||||
#include "dto/dto.h"
 | 
			
		||||
 | 
			
		||||
namespace api {
 | 
			
		||||
    void admin::users(req_type, cbk_type cbk) {
 | 
			
		||||
        db::MapperUser user_mapper(drogon::app().getDbClient());
 | 
			
		||||
        std::vector<dto::Responses::GetUsersEntry> entries;
 | 
			
		||||
        auto users = user_mapper.findAll();
 | 
			
		||||
        for (const db::User& user : users)
 | 
			
		||||
            entries.emplace_back(
 | 
			
		||||
                    user.getValueOfId(),
 | 
			
		||||
                    user.getValueOfGitlab() != 0,
 | 
			
		||||
                    db::User_getEnumTfaType(user) != db::tfaTypes::NONE,
 | 
			
		||||
                    user.getValueOfName(),
 | 
			
		||||
                    db::User_getEnumRole(user)
 | 
			
		||||
            );
 | 
			
		||||
        cbk(dto::Responses::get_admin_users_res(entries));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void admin::set_role(req_type req, cbk_type cbk) {
 | 
			
		||||
        Json::Value& json = *req->jsonObject();
 | 
			
		||||
        try {
 | 
			
		||||
            uint64_t user_id = dto::json_get<uint64_t>(json, "user").value();
 | 
			
		||||
            db::UserRole role = (db::UserRole)dto::json_get<int>(json, "role").value();
 | 
			
		||||
 | 
			
		||||
            db::MapperUser user_mapper(drogon::app().getDbClient());
 | 
			
		||||
            auto user = user_mapper.findByPrimaryKey(user_id);
 | 
			
		||||
            user.setRole(role);
 | 
			
		||||
            user_mapper.update(user);
 | 
			
		||||
 | 
			
		||||
            cbk(dto::Responses::get_success_res());
 | 
			
		||||
        } catch (const std::exception&) {
 | 
			
		||||
            cbk(dto::Responses::get_badreq_res("Validation error"));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void admin::logout(req_type req, cbk_type cbk) {
 | 
			
		||||
        Json::Value& json = *req->jsonObject();
 | 
			
		||||
        try {
 | 
			
		||||
            uint64_t user_id = dto::json_get<uint64_t>(json, "user").value();
 | 
			
		||||
 | 
			
		||||
            db::MapperUser user_mapper(drogon::app().getDbClient());
 | 
			
		||||
            auto user = user_mapper.findByPrimaryKey(user_id);
 | 
			
		||||
            auth::revoke_all(user);
 | 
			
		||||
 | 
			
		||||
            cbk(dto::Responses::get_success_res());
 | 
			
		||||
        } catch (const std::exception&) {
 | 
			
		||||
            cbk(dto::Responses::get_badreq_res("Validation error"));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void admin::delete_user(req_type req, cbk_type cbk) {
 | 
			
		||||
        Json::Value& json = *req->jsonObject();
 | 
			
		||||
        try {
 | 
			
		||||
            uint64_t user_id = dto::json_get<uint64_t>(json, "user").value();
 | 
			
		||||
 | 
			
		||||
            db::MapperUser user_mapper(drogon::app().getDbClient());
 | 
			
		||||
            auto user = user_mapper.findByPrimaryKey(user_id);
 | 
			
		||||
            auth::revoke_all(user);
 | 
			
		||||
             fs::delete_node(fs::get_node(user.getValueOfRootId()).value(), true);
 | 
			
		||||
             user_mapper.deleteOne(user);
 | 
			
		||||
            cbk(dto::Responses::get_success_res());
 | 
			
		||||
        } catch (const std::exception&) {
 | 
			
		||||
            cbk(dto::Responses::get_badreq_res("Validation error"));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void admin::disable_2fa(req_type req, cbk_type cbk) {
 | 
			
		||||
        Json::Value& json = *req->jsonObject();
 | 
			
		||||
        try {
 | 
			
		||||
            uint64_t user_id = dto::json_get<uint64_t>(json, "user").value();
 | 
			
		||||
 | 
			
		||||
            db::MapperUser user_mapper(drogon::app().getDbClient());
 | 
			
		||||
            auto user = user_mapper.findByPrimaryKey(user_id);
 | 
			
		||||
            user.setTfaType(db::tfaTypes::NONE);
 | 
			
		||||
            user_mapper.update(user);
 | 
			
		||||
 | 
			
		||||
            cbk(dto::Responses::get_success_res());
 | 
			
		||||
        } catch (const std::exception&) {
 | 
			
		||||
            cbk(dto::Responses::get_badreq_res("Validation error"));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
#pragma clang diagnostic pop
 | 
			
		||||
							
								
								
									
										103
									
								
								backend/src/controllers/auth/auth_2fa.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								backend/src/controllers/auth/auth_2fa.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,103 @@
 | 
			
		||||
#pragma clang diagnostic push
 | 
			
		||||
#pragma ide diagnostic ignored "readability-make-member-function-const"
 | 
			
		||||
#pragma ide diagnostic ignored "readability-convert-member-functions-to-static"
 | 
			
		||||
 | 
			
		||||
#include <botan/base32.h>
 | 
			
		||||
#include <botan/base64.h>
 | 
			
		||||
#include <qrcodegen.hpp>
 | 
			
		||||
#include <png++/png.hpp>
 | 
			
		||||
 | 
			
		||||
#include "controllers/controllers.h"
 | 
			
		||||
#include "db/db.h"
 | 
			
		||||
#include "dto/dto.h"
 | 
			
		||||
 | 
			
		||||
std::string create_totp_qrcode(const db::User& user, const std::string& b32_secret) {
 | 
			
		||||
    const int qrcode_pixel_size = 4;
 | 
			
		||||
 | 
			
		||||
    std::stringstream code_ss;
 | 
			
		||||
    code_ss << "otpauth://totp/MFileserver:"
 | 
			
		||||
            << user.getValueOfName()
 | 
			
		||||
            << "?secret="
 | 
			
		||||
            << b32_secret
 | 
			
		||||
            << "&issuer=MFileserver";
 | 
			
		||||
    auto code = qrcodegen::QrCode::encodeText(code_ss.str().c_str(), qrcodegen::QrCode::Ecc::MEDIUM);
 | 
			
		||||
    const int mod_count = code.getSize();
 | 
			
		||||
    png::image<png::gray_pixel> image(mod_count*qrcode_pixel_size, mod_count*qrcode_pixel_size);
 | 
			
		||||
    for (int x = 0; x < mod_count; x++) for (int y = 0; y < mod_count; y++) {
 | 
			
		||||
        const bool mod = code.getModule(x, y);
 | 
			
		||||
        const int x_img_start = x * qrcode_pixel_size, y_img_start = y * qrcode_pixel_size;
 | 
			
		||||
        for (int x_img = x_img_start; x_img < x_img_start + qrcode_pixel_size; x_img++) for (int y_img = y_img_start; y_img < y_img_start + qrcode_pixel_size; y_img++)
 | 
			
		||||
            image[x_img][y_img] = mod ? 0 : 0xff;
 | 
			
		||||
    }
 | 
			
		||||
    std::stringstream image_ss;
 | 
			
		||||
    image.write_stream(image_ss);
 | 
			
		||||
 | 
			
		||||
    std::string image_str = image_ss.str();
 | 
			
		||||
    std::vector<uint8_t> secret(image_str.data(), image_str.data()+image_str.size());
 | 
			
		||||
 | 
			
		||||
    return "data:image/png;base64," + Botan::base64_encode(secret);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace api {
 | 
			
		||||
    void auth::tfa_setup(req_type req, cbk_type cbk) {
 | 
			
		||||
        db::User user = dto::get_user(req);
 | 
			
		||||
        Json::Value &json = *req->jsonObject();
 | 
			
		||||
        try {
 | 
			
		||||
            bool mail = dto::json_get<bool>(json, "mail").value();
 | 
			
		||||
 | 
			
		||||
            auto secret_uchar = rng->random_vec(32);
 | 
			
		||||
            std::vector<char> secret(secret_uchar.data(), secret_uchar.data()+32);
 | 
			
		||||
            user.setTfaSecret(secret);
 | 
			
		||||
 | 
			
		||||
            db::MapperUser user_mapper(drogon::app().getDbClient());
 | 
			
		||||
            user_mapper.update(user);
 | 
			
		||||
 | 
			
		||||
            if (mail) {
 | 
			
		||||
                send_mail(user);
 | 
			
		||||
                cbk(dto::Responses::get_success_res());
 | 
			
		||||
            } else {
 | 
			
		||||
                std::string b32_secret = Botan::base32_encode(secret_uchar);
 | 
			
		||||
                b32_secret.erase(std::remove(b32_secret.begin(), b32_secret.end(), '='), b32_secret.end());
 | 
			
		||||
                std::string code = create_totp_qrcode(user, b32_secret);
 | 
			
		||||
                cbk(dto::Responses::get_tfa_setup_res(b32_secret, code));
 | 
			
		||||
            }
 | 
			
		||||
        } catch (const std::exception&) {
 | 
			
		||||
            cbk(dto::Responses::get_badreq_res("Validation error"));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void auth::tfa_complete(req_type req, cbk_type cbk) {
 | 
			
		||||
        db::User user = dto::get_user(req);
 | 
			
		||||
        Json::Value &json = *req->jsonObject();
 | 
			
		||||
        try {
 | 
			
		||||
            bool mail = dto::json_get<bool>(json, "mail").value();
 | 
			
		||||
            uint32_t code = std::stoi(dto::json_get<std::string>(json, "code").value());
 | 
			
		||||
 | 
			
		||||
            user.setTfaType(mail ? db::tfaTypes::EMAIL : db::tfaTypes::TOTP);
 | 
			
		||||
 | 
			
		||||
            if (!verify2fa(user, code))
 | 
			
		||||
                return cbk(dto::Responses::get_unauth_res("Incorrect 2fa"));
 | 
			
		||||
 | 
			
		||||
            db::MapperUser user_mapper(drogon::app().getDbClient());
 | 
			
		||||
            user_mapper.update(user);
 | 
			
		||||
 | 
			
		||||
            revoke_all(user);
 | 
			
		||||
            cbk(dto::Responses::get_success_res());
 | 
			
		||||
        } catch (const std::exception&) {
 | 
			
		||||
            cbk(dto::Responses::get_badreq_res("Validation error"));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void auth::tfa_disable(req_type req, cbk_type cbk) {
 | 
			
		||||
        db::User user = dto::get_user(req);
 | 
			
		||||
 | 
			
		||||
        db::MapperUser user_mapper(drogon::app().getDbClient());
 | 
			
		||||
        user.setTfaType(db::tfaTypes::NONE);
 | 
			
		||||
        user_mapper.update(user);
 | 
			
		||||
 | 
			
		||||
        revoke_all(user);
 | 
			
		||||
        cbk(dto::Responses::get_success_res());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#pragma clang diagnostic pop
 | 
			
		||||
							
								
								
									
										135
									
								
								backend/src/controllers/auth/auth_basic.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										135
									
								
								backend/src/controllers/auth/auth_basic.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,135 @@
 | 
			
		||||
#pragma clang diagnostic push
 | 
			
		||||
#pragma ide diagnostic ignored "readability-make-member-function-const"
 | 
			
		||||
#pragma ide diagnostic ignored "readability-convert-member-functions-to-static"
 | 
			
		||||
 | 
			
		||||
#include <botan/argon2.h>
 | 
			
		||||
#include <botan/totp.h>
 | 
			
		||||
#include <jwt-cpp/traits/kazuho-picojson/traits.h>
 | 
			
		||||
#include <jwt-cpp/jwt.h>
 | 
			
		||||
 | 
			
		||||
#include "controllers/controllers.h"
 | 
			
		||||
#include "db/db.h"
 | 
			
		||||
#include "dto/dto.h"
 | 
			
		||||
 | 
			
		||||
namespace api {
 | 
			
		||||
    void auth::login(req_type req, cbk_type cbk) {
 | 
			
		||||
        Json::Value &json = *req->jsonObject();
 | 
			
		||||
        try {
 | 
			
		||||
            std::string username = dto::json_get<std::string>(json, "username").value();
 | 
			
		||||
            std::string password = dto::json_get<std::string>(json, "password").value();
 | 
			
		||||
            std::optional<std::string> otp = dto::json_get<std::string>(json, "otp");
 | 
			
		||||
 | 
			
		||||
            auto db = drogon::app().getDbClient();
 | 
			
		||||
 | 
			
		||||
            db::MapperUser user_mapper(db);
 | 
			
		||||
            auto db_users = user_mapper.findBy(
 | 
			
		||||
                    db::Criteria(db::User::Cols::_name, db::CompareOps::EQ, username) &&
 | 
			
		||||
                    db::Criteria(db::User::Cols::_gitlab, db::CompareOps::EQ, 0)
 | 
			
		||||
            );
 | 
			
		||||
            if (db_users.empty()) {
 | 
			
		||||
                cbk(dto::Responses::get_unauth_res("Invalid username or password"));
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            db::User &db_user = db_users.at(0);
 | 
			
		||||
            if (!Botan::argon2_check_pwhash(password.c_str(), password.size(), db_user.getValueOfPassword())) {
 | 
			
		||||
                cbk(dto::Responses::get_unauth_res("Invalid username or password"));
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            if (db::User_getEnumRole(db_user) == db::UserRole::DISABLED) {
 | 
			
		||||
                cbk(dto::Responses::get_unauth_res("Account is disabled"));
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            const auto tfa = db::User_getEnumTfaType(db_user);
 | 
			
		||||
            if (tfa != db::tfaTypes::NONE) {
 | 
			
		||||
                if (!otp.has_value()) {
 | 
			
		||||
                    if (tfa == db::tfaTypes::EMAIL) send_mail(db_user);
 | 
			
		||||
                    return cbk(dto::Responses::get_success_res());
 | 
			
		||||
                }
 | 
			
		||||
                if (!verify2fa(db_user, std::stoi(otp.value())))
 | 
			
		||||
                    return cbk(dto::Responses::get_unauth_res("Incorrect 2fa"));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            cbk(dto::Responses::get_login_res(get_token(db_user)));
 | 
			
		||||
        } catch (const std::exception&) {
 | 
			
		||||
            cbk(dto::Responses::get_badreq_res("Validation error"));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void auth::signup(req_type req, cbk_type cbk) {
 | 
			
		||||
        Json::Value &json = *req->jsonObject();
 | 
			
		||||
        try {
 | 
			
		||||
            std::string username = dto::json_get<std::string>(json, "username").value();
 | 
			
		||||
            std::string password = dto::json_get<std::string>(json, "password").value();
 | 
			
		||||
 | 
			
		||||
            db::MapperUser user_mapper(drogon::app().getDbClient());
 | 
			
		||||
 | 
			
		||||
            auto existing_users = user_mapper.count(
 | 
			
		||||
                    db::Criteria(db::User::Cols::_name, db::CompareOps::EQ, username) &&
 | 
			
		||||
                    db::Criteria(db::User::Cols::_gitlab, db::CompareOps::EQ, 0)
 | 
			
		||||
            );
 | 
			
		||||
            if (existing_users != 0) {
 | 
			
		||||
                cbk(dto::Responses::get_badreq_res("Username is already taken"));
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            //std::string hash = Botan::argon2_generate_pwhash(password.c_str(), password.size(), *rng, 1, 256*1024, 2);
 | 
			
		||||
            std::string hash = Botan::argon2_generate_pwhash(password.c_str(), password.size(), *rng, 1, 16*1024, 1);
 | 
			
		||||
 | 
			
		||||
            db::User new_user;
 | 
			
		||||
            new_user.setName(username);
 | 
			
		||||
            new_user.setPassword(hash);
 | 
			
		||||
            new_user.setGitlab(0);
 | 
			
		||||
            new_user.setRole(db::UserRole::DISABLED);
 | 
			
		||||
            new_user.setRootId(0);
 | 
			
		||||
            new_user.setTfaType(db::tfaTypes::NONE);
 | 
			
		||||
 | 
			
		||||
            user_mapper.insert(new_user);
 | 
			
		||||
            generate_root(new_user);
 | 
			
		||||
            cbk(dto::Responses::get_success_res());
 | 
			
		||||
        } catch (const std::exception& e) {
 | 
			
		||||
            cbk(dto::Responses::get_badreq_res("Validation error"));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void auth::refresh(req_type req, cbk_type cbk) {
 | 
			
		||||
        db::User user = dto::get_user(req);
 | 
			
		||||
        db::Token token = dto::get_token(req);
 | 
			
		||||
 | 
			
		||||
        db::MapperToken token_mapper(drogon::app().getDbClient());
 | 
			
		||||
        token_mapper.deleteOne(token);
 | 
			
		||||
        cbk(dto::Responses::get_login_res( get_token(user)));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void auth::logout_all(req_type req, cbk_type cbk) {
 | 
			
		||||
        db::User user = dto::get_user(req);
 | 
			
		||||
        revoke_all(user);
 | 
			
		||||
        cbk(dto::Responses::get_success_res());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void auth::change_password(req_type req, cbk_type cbk) {
 | 
			
		||||
        db::User user = dto::get_user(req);
 | 
			
		||||
        Json::Value &json = *req->jsonObject();
 | 
			
		||||
        try {
 | 
			
		||||
            std::string old_pw = dto::json_get<std::string>(json, "oldPassword").value();
 | 
			
		||||
            std::string new_pw = dto::json_get<std::string>(json, "newPassword").value();
 | 
			
		||||
 | 
			
		||||
            auto db = drogon::app().getDbClient();
 | 
			
		||||
            db::MapperUser user_mapper(db);
 | 
			
		||||
 | 
			
		||||
            if (!Botan::argon2_check_pwhash(old_pw.c_str(), old_pw.size(), user.getValueOfPassword()))
 | 
			
		||||
                return cbk(dto::Responses::get_unauth_res("Old password is wrong"));
 | 
			
		||||
 | 
			
		||||
            std::string hash = Botan::argon2_generate_pwhash(new_pw.c_str(), new_pw.size(), *rng, 1, 256*1024, 2);
 | 
			
		||||
 | 
			
		||||
            user.setPassword(hash);
 | 
			
		||||
            user_mapper.update(user);
 | 
			
		||||
            revoke_all(user);
 | 
			
		||||
            cbk(dto::Responses::get_success_res());
 | 
			
		||||
        } catch (const std::exception&) {
 | 
			
		||||
            cbk(dto::Responses::get_badreq_res("Validation error"));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#pragma clang diagnostic pop
 | 
			
		||||
							
								
								
									
										110
									
								
								backend/src/controllers/auth/auth_common.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								backend/src/controllers/auth/auth_common.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,110 @@
 | 
			
		||||
#pragma clang diagnostic push
 | 
			
		||||
#pragma ide diagnostic ignored "readability-make-member-function-const"
 | 
			
		||||
#pragma ide diagnostic ignored "readability-convert-member-functions-to-static"
 | 
			
		||||
 | 
			
		||||
#include <chrono>
 | 
			
		||||
#include <iomanip>
 | 
			
		||||
 | 
			
		||||
#include <botan/argon2.h>
 | 
			
		||||
#include <botan/uuid.h>
 | 
			
		||||
#include <botan/totp.h>
 | 
			
		||||
 | 
			
		||||
#if defined(BOTAN_HAS_SYSTEM_RNG)
 | 
			
		||||
#include <botan/system_rng.h>
 | 
			
		||||
#else
 | 
			
		||||
#include <botan/auto_rng.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include <jwt-cpp/traits/kazuho-picojson/traits.h>
 | 
			
		||||
#include <jwt-cpp/jwt.h>
 | 
			
		||||
#include <curl/curl.h>
 | 
			
		||||
 | 
			
		||||
#include "controllers/controllers.h"
 | 
			
		||||
#include "db/db.h"
 | 
			
		||||
#include "dto/dto.h"
 | 
			
		||||
 | 
			
		||||
size_t payload_source(char* ptr, size_t size, size_t nmemb, void* userp) {
 | 
			
		||||
    auto* ss = (std::stringstream*)userp;
 | 
			
		||||
    return ss->readsome(ptr, (long)(size*nmemb));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace api {
 | 
			
		||||
#if defined(BOTAN_HAS_SYSTEM_RNG)
 | 
			
		||||
    std::unique_ptr<Botan::RNG> auth::rng = std::make_unique<Botan::System_RNG>();
 | 
			
		||||
#else
 | 
			
		||||
    std::unique_ptr<Botan::RNG> auth::rng = std::make_unique<Botan::AutoSeeded_RNG>();
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    bool auth::verify2fa(const db::User& user, uint32_t totp) {
 | 
			
		||||
        size_t allowed_skew = db::User_getEnumTfaType(user) == db::tfaTypes::TOTP ? 0 : 10;
 | 
			
		||||
        const auto& totp_secret = (const std::vector<uint8_t>&) user.getValueOfTfaSecret();
 | 
			
		||||
        return Botan::TOTP(Botan::OctetString(totp_secret)).verify_totp(totp, std::chrono::system_clock::now(), allowed_skew);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void auth::send_mail(const db::User& user) {
 | 
			
		||||
        std::stringstream ss;
 | 
			
		||||
        std::time_t t = std::time(nullptr);
 | 
			
		||||
        const auto& totp_secret = (const std::vector<uint8_t>&) user.getValueOfTfaSecret();
 | 
			
		||||
        char totp[16];
 | 
			
		||||
        std::snprintf(totp, 16, "%06d", Botan::TOTP(Botan::OctetString(totp_secret)).generate_totp(t));
 | 
			
		||||
        ss.imbue(std::locale("en_US.utf8"));
 | 
			
		||||
        ss << "Date: " << std::put_time(std::localtime(&t), "%a, %d %b %Y %T %z") << "\r\n";
 | 
			
		||||
        ss << "To: " << user.getValueOfName() << "\r\n";
 | 
			
		||||
        ss << "From: fileserver@mattv.de\r\n";
 | 
			
		||||
        ss << "Message-ID: " << Botan::UUID(*rng).to_string() << "@mattv.de>\r\n";
 | 
			
		||||
        ss << "Subject: Fileserver - EMail 2fa code\r\n";
 | 
			
		||||
        ss << "Your code is: " << totp << "\r\n";
 | 
			
		||||
        ss << "It is valid for 5 Minutes\r\n";
 | 
			
		||||
 | 
			
		||||
        CURL* curl = curl_easy_init();
 | 
			
		||||
        curl_easy_setopt(curl, CURLOPT_USERNAME, "no-reply@mattv.de");
 | 
			
		||||
        curl_easy_setopt(curl, CURLOPT_PASSWORD, "noreplyLONGPASS123");
 | 
			
		||||
        curl_easy_setopt(curl, CURLOPT_URL, "smtp://mail.mattv.de:587");
 | 
			
		||||
        curl_easy_setopt(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_ALL);
 | 
			
		||||
        auto recp = curl_slist_append(nullptr, user.getValueOfName().c_str());
 | 
			
		||||
        curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, recp);
 | 
			
		||||
        curl_easy_setopt(curl, CURLOPT_READFUNCTION, &payload_source);
 | 
			
		||||
        curl_easy_setopt(curl, CURLOPT_READDATA, &ss);
 | 
			
		||||
        curl_easy_setopt(curl, CURLOPT_UPLOAD, 1);
 | 
			
		||||
        curl_easy_perform(curl);
 | 
			
		||||
        curl_slist_free_all(recp);
 | 
			
		||||
        curl_easy_cleanup(curl);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    std::string auth::get_token(const db::User& user) {
 | 
			
		||||
        auto db = drogon::app().getDbClient();
 | 
			
		||||
 | 
			
		||||
        db::MapperToken token_mapper(db);
 | 
			
		||||
        const auto iat = std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch());
 | 
			
		||||
        const auto exp = iat + std::chrono::hours{24};
 | 
			
		||||
 | 
			
		||||
        db::Token new_token;
 | 
			
		||||
        new_token.setOwnerId(user.getValueOfId());
 | 
			
		||||
        new_token.setExp(exp.count());
 | 
			
		||||
 | 
			
		||||
        token_mapper.insert(new_token);
 | 
			
		||||
 | 
			
		||||
        return jwt::create<jwt::traits::kazuho_picojson>()
 | 
			
		||||
                .set_type("JWT")
 | 
			
		||||
                .set_payload_claim("sub", picojson::value((int64_t)user.getValueOfId()))
 | 
			
		||||
                .set_payload_claim("jti", picojson::value((int64_t)new_token.getValueOfId()))
 | 
			
		||||
                .set_issued_at(std::chrono::system_clock::from_time_t(iat.count()))
 | 
			
		||||
                .set_expires_at(std::chrono::system_clock::from_time_t(exp.count()))
 | 
			
		||||
                .sign(jwt::algorithm::hs256{jwt_secret});
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void auth::generate_root(db::User& user) {
 | 
			
		||||
        db::MapperUser user_mapper(drogon::app().getDbClient());
 | 
			
		||||
 | 
			
		||||
        auto node = fs::create_node("", user, false, std::nullopt, true);
 | 
			
		||||
        user.setRootId(std::get<db::INode>(node).getValueOfId());
 | 
			
		||||
        user_mapper.update(user);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void auth::revoke_all(const db::User& user) {
 | 
			
		||||
        db::MapperToken token_mapper(drogon::app().getDbClient());
 | 
			
		||||
         token_mapper.deleteBy(db::Criteria(db::Token::Cols::_owner_id, db::CompareOps::EQ, user.getValueOfId()));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#pragma clang diagnostic pop
 | 
			
		||||
							
								
								
									
										118
									
								
								backend/src/controllers/auth/auth_gitlab.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										118
									
								
								backend/src/controllers/auth/auth_gitlab.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,118 @@
 | 
			
		||||
#pragma clang diagnostic push
 | 
			
		||||
#pragma ide diagnostic ignored "performance-unnecessary-value-param"
 | 
			
		||||
#pragma ide diagnostic ignored "readability-make-member-function-const"
 | 
			
		||||
#pragma ide diagnostic ignored "readability-convert-member-functions-to-static"
 | 
			
		||||
 | 
			
		||||
#include <utility>
 | 
			
		||||
 | 
			
		||||
#include "controllers/controllers.h"
 | 
			
		||||
#include "dto/dto.h"
 | 
			
		||||
 | 
			
		||||
const std::string GITLAB_ID = "98bcbad78cb1f880d1d1de62291d70a791251a7bea077bfe7df111ef3c115760";
 | 
			
		||||
const std::string GITLAB_SECRET = "7ee01d2b204aff3a05f9d028f004d169b6d381ec873e195f314b3935fa150959";
 | 
			
		||||
const std::string GITLAB_URL = "https://gitlab.mattv.de";
 | 
			
		||||
const std::string GITLAB_API_URL = "https://ssh.gitlab.mattv.de";
 | 
			
		||||
 | 
			
		||||
std::string get_redirect_uri(req_type req) {
 | 
			
		||||
    auto host_header = req->headers().find("host");
 | 
			
		||||
    std::stringstream ss;
 | 
			
		||||
    ss << (req->isOnSecureConnection() ? "https" : "http")
 | 
			
		||||
       << "://"
 | 
			
		||||
       << (host_header != req->headers().end() ? host_header->second : "127.0.0.1:1234")
 | 
			
		||||
       << "/api/auth/gitlab_callback";
 | 
			
		||||
    return drogon::utils::urlEncode(ss.str());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const drogon::HttpClientPtr& get_gitlab_client() {
 | 
			
		||||
    static drogon::HttpClientPtr client = drogon::HttpClient::newHttpClient(GITLAB_API_URL, drogon::app().getLoop(), false, false);
 | 
			
		||||
    return client;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
namespace api {
 | 
			
		||||
    std::optional<auth::gitlab_tokens> auth::get_gitlab_tokens(req_type req, const std::string& code_or_token, bool token) {
 | 
			
		||||
        std::stringstream ss;
 | 
			
		||||
        ss << "/oauth/token"
 | 
			
		||||
           << "?redirect_uri=" << get_redirect_uri(req)
 | 
			
		||||
           << "&client_id=" << GITLAB_ID
 | 
			
		||||
           << "&client_secret=" << GITLAB_SECRET
 | 
			
		||||
           << (token ? "&refresh_token=" : "&code=") << code_or_token
 | 
			
		||||
           << "&grant_type=" << (token ? "refresh_token" : "authorization_code");
 | 
			
		||||
        auto gitlab_req = drogon::HttpRequest::newHttpRequest();
 | 
			
		||||
        gitlab_req->setPathEncode(false);
 | 
			
		||||
        gitlab_req->setPath(ss.str());
 | 
			
		||||
        gitlab_req->setMethod(drogon::HttpMethod::Post);
 | 
			
		||||
        auto res_tuple = get_gitlab_client()->sendRequest(gitlab_req);
 | 
			
		||||
        auto res = res_tuple.second;
 | 
			
		||||
        if ((res->statusCode() != drogon::HttpStatusCode::k200OK) && (res->statusCode() != drogon::HttpStatusCode::k201Created))
 | 
			
		||||
            return std::nullopt;
 | 
			
		||||
        auto json = *res->jsonObject();
 | 
			
		||||
        return std::make_optional<gitlab_tokens>(
 | 
			
		||||
                json["access_token"].as<std::string>(),
 | 
			
		||||
                json["refresh_token"].as<std::string>()
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    std::optional<auth::gitlab_user> auth::get_gitlab_user(const std::string& at) {
 | 
			
		||||
        auto gitlab_req = drogon::HttpRequest::newHttpRequest();
 | 
			
		||||
        gitlab_req->setPath("/api/v4/user");
 | 
			
		||||
        gitlab_req->addHeader("Authorization", "Bearer " + at);
 | 
			
		||||
        gitlab_req->setMethod(drogon::HttpMethod::Get);
 | 
			
		||||
        auto res_tuple = get_gitlab_client()->sendRequest(gitlab_req);
 | 
			
		||||
        auto res = res_tuple.second;
 | 
			
		||||
        if (res->statusCode() != drogon::HttpStatusCode::k200OK)
 | 
			
		||||
            return std::nullopt;
 | 
			
		||||
        auto json = *res->jsonObject();
 | 
			
		||||
        return std::make_optional<gitlab_user>(
 | 
			
		||||
                json["username"].as<std::string>(),
 | 
			
		||||
                json.get("is_admin", false).as<bool>()
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void auth::gitlab(req_type req, cbk_type cbk) {
 | 
			
		||||
        std::stringstream ss;
 | 
			
		||||
        ss << GITLAB_URL << "/oauth/authorize"
 | 
			
		||||
           << "?redirect_uri=" << get_redirect_uri(req)
 | 
			
		||||
           << "&client_id=" << GITLAB_ID
 | 
			
		||||
           << "&scope=read_user&response_type=code";
 | 
			
		||||
        cbk(drogon::HttpResponse::newRedirectionResponse(ss.str()));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void auth::gitlab_callback(req_type req, cbk_type cbk, std::string code) {
 | 
			
		||||
        auto tokens =  get_gitlab_tokens(req, code, false);
 | 
			
		||||
        if (!tokens.has_value())
 | 
			
		||||
            return cbk(dto::Responses::get_unauth_res("Invalid code"));
 | 
			
		||||
        auto info =  get_gitlab_user(tokens->at);
 | 
			
		||||
        if (!info.has_value())
 | 
			
		||||
            return cbk(dto::Responses::get_unauth_res("Invalid code"));
 | 
			
		||||
 | 
			
		||||
        db::MapperUser user_mapper(drogon::app().getDbClient());
 | 
			
		||||
        auto db_users =  user_mapper.findBy(
 | 
			
		||||
                db::Criteria(db::User::Cols::_name, db::CompareOps::EQ, info->name) &&
 | 
			
		||||
                db::Criteria(db::User::Cols::_gitlab, db::CompareOps::EQ, 1)
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        if (db_users.empty()) {
 | 
			
		||||
            db::User new_user;
 | 
			
		||||
            new_user.setName(info->name);
 | 
			
		||||
            new_user.setPassword("");
 | 
			
		||||
            new_user.setGitlab(1);
 | 
			
		||||
            new_user.setRole(info->is_admin ? db::UserRole::ADMIN : db::UserRole::DISABLED);
 | 
			
		||||
            new_user.setRootId(0);
 | 
			
		||||
            new_user.setTfaType(db::tfaTypes::NONE);
 | 
			
		||||
 | 
			
		||||
            user_mapper.insert(new_user);
 | 
			
		||||
            generate_root(new_user);
 | 
			
		||||
            db_users.push_back(new_user);
 | 
			
		||||
        }
 | 
			
		||||
        db::User& db_user = db_users.at(0);
 | 
			
		||||
        db_user.setGitlabAt(tokens->at);
 | 
			
		||||
        db_user.setGitlabRt(tokens->rt);
 | 
			
		||||
        user_mapper.update(db_user);
 | 
			
		||||
 | 
			
		||||
        const std::string& token = get_token(db_user);
 | 
			
		||||
        cbk(drogon::HttpResponse::newRedirectionResponse("/set_token?token="+token));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#pragma clang diagnostic pop
 | 
			
		||||
							
								
								
									
										119
									
								
								backend/src/controllers/controllers.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								backend/src/controllers/controllers.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,119 @@
 | 
			
		||||
#ifndef BACKEND_CONTROLLERS_H
 | 
			
		||||
#define BACKEND_CONTROLLERS_H
 | 
			
		||||
#include <drogon/drogon.h>
 | 
			
		||||
#include <drogon/utils/coroutine.h>
 | 
			
		||||
#include <botan/rng.h>
 | 
			
		||||
#include <coroutine>
 | 
			
		||||
#include <variant>
 | 
			
		||||
 | 
			
		||||
#include "db/db.h"
 | 
			
		||||
 | 
			
		||||
using req_type = const drogon::HttpRequestPtr&;
 | 
			
		||||
using cbk_type = std::function<void(const drogon::HttpResponsePtr &)>&&;
 | 
			
		||||
 | 
			
		||||
namespace api {
 | 
			
		||||
class admin : public drogon::HttpController<admin> {
 | 
			
		||||
public:
 | 
			
		||||
    METHOD_LIST_BEGIN
 | 
			
		||||
        METHOD_ADD(admin::users, "/users", drogon::Get, "Login", "Admin");
 | 
			
		||||
        METHOD_ADD(admin::set_role, "/set_role", drogon::Post, "Login", "Admin");
 | 
			
		||||
        METHOD_ADD(admin::logout, "/logout", drogon::Post, "Login", "Admin");
 | 
			
		||||
        METHOD_ADD(admin::delete_user, "/delete", drogon::Post, "Login", "Admin");
 | 
			
		||||
        METHOD_ADD(admin::disable_2fa, "/disable_2fa", drogon::Post, "Login", "Admin");
 | 
			
		||||
    METHOD_LIST_END
 | 
			
		||||
 | 
			
		||||
    void users(req_type, cbk_type);
 | 
			
		||||
    void set_role(req_type, cbk_type);
 | 
			
		||||
    void logout(req_type, cbk_type);
 | 
			
		||||
    void delete_user(req_type, cbk_type);
 | 
			
		||||
    void disable_2fa(req_type, cbk_type);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class auth : public drogon::HttpController<auth> {
 | 
			
		||||
public:
 | 
			
		||||
    METHOD_LIST_BEGIN
 | 
			
		||||
        METHOD_ADD(auth::gitlab, "/gitlab", drogon::Get);
 | 
			
		||||
        METHOD_ADD(auth::gitlab_callback, "/gitlab_callback?code={}", drogon::Get);
 | 
			
		||||
        METHOD_ADD(auth::signup, "/signup", drogon::Post);
 | 
			
		||||
        METHOD_ADD(auth::login, "/login", drogon::Post);
 | 
			
		||||
        METHOD_ADD(auth::refresh, "/refresh", drogon::Post, "Login");
 | 
			
		||||
        METHOD_ADD(auth::tfa_setup, "/2fa/setup", drogon::Post, "Login");
 | 
			
		||||
        METHOD_ADD(auth::tfa_complete, "/2fa/complete", drogon::Post, "Login");
 | 
			
		||||
        METHOD_ADD(auth::tfa_disable, "/2fa/disable", drogon::Post, "Login");
 | 
			
		||||
        METHOD_ADD(auth::change_password, "/change_password", drogon::Post, "Login");
 | 
			
		||||
        METHOD_ADD(auth::logout_all, "/logout_all", drogon::Post, "Login");
 | 
			
		||||
    METHOD_LIST_END
 | 
			
		||||
 | 
			
		||||
    struct gitlab_tokens {
 | 
			
		||||
        gitlab_tokens(std::string at, std::string rt) : at(std::move(at)), rt(std::move(rt)) {}
 | 
			
		||||
        std::string at, rt;
 | 
			
		||||
    };
 | 
			
		||||
    struct gitlab_user {
 | 
			
		||||
        gitlab_user(std::string name, bool isAdmin) : name(std::move(name)), is_admin(isAdmin) {}
 | 
			
		||||
        std::string name;
 | 
			
		||||
        bool is_admin;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    static std::unique_ptr<Botan::RNG> rng;
 | 
			
		||||
 | 
			
		||||
    static std::optional<gitlab_tokens> get_gitlab_tokens(req_type, const std::string&, bool token);
 | 
			
		||||
    static std::optional<gitlab_user> get_gitlab_user(const std::string&);
 | 
			
		||||
    static bool verify2fa(const db::User&, uint32_t totp);
 | 
			
		||||
    static void send_mail(const db::User&);
 | 
			
		||||
    static std::string get_token(const db::User&);
 | 
			
		||||
    static void generate_root(db::User&);
 | 
			
		||||
    static void revoke_all(const db::User&);
 | 
			
		||||
 | 
			
		||||
    void gitlab(req_type, cbk_type);
 | 
			
		||||
    void gitlab_callback(req_type, cbk_type, std::string code);
 | 
			
		||||
    void signup(req_type, cbk_type);
 | 
			
		||||
    void login(req_type, cbk_type);
 | 
			
		||||
    void refresh(req_type, cbk_type);
 | 
			
		||||
    void tfa_setup(req_type, cbk_type);
 | 
			
		||||
    void tfa_complete(req_type, cbk_type);
 | 
			
		||||
    void tfa_disable(req_type, cbk_type);
 | 
			
		||||
    void change_password(req_type, cbk_type);
 | 
			
		||||
    void logout_all(req_type, cbk_type);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class fs : public drogon::HttpController<fs> {
 | 
			
		||||
public:
 | 
			
		||||
    METHOD_LIST_BEGIN
 | 
			
		||||
        METHOD_ADD(fs::root, "/root", drogon::Get, "Login");
 | 
			
		||||
        METHOD_ADD(fs::node, "/node/{}", drogon::Get, "Login");
 | 
			
		||||
        METHOD_ADD(fs::path, "/path/{}", drogon::Get, "Login");
 | 
			
		||||
        METHOD_ADD(fs::create_node_req<false>, "/createFolder", drogon::Post, "Login");
 | 
			
		||||
        METHOD_ADD(fs::create_node_req<true>, "/createFile", drogon::Post, "Login");
 | 
			
		||||
        METHOD_ADD(fs::delete_node_req, "/delete/{}", drogon::Post, "Login");
 | 
			
		||||
        METHOD_ADD(fs::upload, "/upload/{}", drogon::Post, "Login");
 | 
			
		||||
        METHOD_ADD(fs::download, "/download", drogon::Post, "Login");
 | 
			
		||||
    METHOD_LIST_END
 | 
			
		||||
 | 
			
		||||
    static std::optional<db::INode> get_node(uint64_t node);
 | 
			
		||||
    static std::optional<db::INode> get_node_and_validate(const db::User& user, uint64_t node);
 | 
			
		||||
    static std::vector<db::INode> get_children(const db::INode& parent);
 | 
			
		||||
    static std::variant<db::INode, std::string> create_node(std::string name, const db::User& owner, bool file, const std::optional<uint64_t> &parent, bool force = false);
 | 
			
		||||
    static void delete_node(db::INode node, bool allow_root = false);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    void root(req_type, cbk_type);
 | 
			
		||||
    void node(req_type, cbk_type, uint64_t node);
 | 
			
		||||
    void path(req_type, cbk_type, uint64_t node);
 | 
			
		||||
    template<bool file> void create_node_req(req_type req, cbk_type cbk);
 | 
			
		||||
    void delete_node_req(req_type, cbk_type, uint64_t node);
 | 
			
		||||
    void upload(req_type, cbk_type, uint64_t node);
 | 
			
		||||
    void download(req_type, cbk_type);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class user : public drogon::HttpController<user> {
 | 
			
		||||
public:
 | 
			
		||||
    METHOD_LIST_BEGIN
 | 
			
		||||
        METHOD_ADD(user::info, "/info", drogon::Get, "Login");
 | 
			
		||||
        METHOD_ADD(user::delete_user, "/delete", drogon::Post, "Login");
 | 
			
		||||
    METHOD_LIST_END
 | 
			
		||||
 | 
			
		||||
    void info(req_type, cbk_type);
 | 
			
		||||
    void delete_user(req_type, cbk_type);
 | 
			
		||||
};
 | 
			
		||||
}
 | 
			
		||||
#endif //BACKEND_CONTROLLERS_H
 | 
			
		||||
							
								
								
									
										211
									
								
								backend/src/controllers/fs.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										211
									
								
								backend/src/controllers/fs.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,211 @@
 | 
			
		||||
#pragma clang diagnostic push
 | 
			
		||||
#pragma ide diagnostic ignored "performance-unnecessary-value-param"
 | 
			
		||||
#pragma ide diagnostic ignored "readability-convert-member-functions-to-static"
 | 
			
		||||
 | 
			
		||||
#include <filesystem>
 | 
			
		||||
#include "controllers.h"
 | 
			
		||||
#include "dto/dto.h"
 | 
			
		||||
 | 
			
		||||
char windows_invalid_chars[] = "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F<>:\"/\\|";
 | 
			
		||||
 | 
			
		||||
std::string generate_path(db::INode node) {
 | 
			
		||||
    db::MapperInode inode_mapper(drogon::app().getDbClient());
 | 
			
		||||
    std::stack<db::INode> path;
 | 
			
		||||
    path.push(node);
 | 
			
		||||
    while (node.getParentId() != nullptr) {
 | 
			
		||||
        node = inode_mapper.findByPrimaryKey(node.getValueOfParentId());
 | 
			
		||||
        path.push(node);
 | 
			
		||||
    }
 | 
			
		||||
    std::stringstream ss;
 | 
			
		||||
    while (!path.empty()) {
 | 
			
		||||
        const db::INode& seg = path.top();
 | 
			
		||||
        ss << seg.getValueOfName();
 | 
			
		||||
        if (seg.getValueOfIsFile() == 0) ss << '/';
 | 
			
		||||
        path.pop();
 | 
			
		||||
    }
 | 
			
		||||
    return ss.str();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace api {
 | 
			
		||||
    std::optional<db::INode> fs::get_node(uint64_t node) {
 | 
			
		||||
        db::MapperInode inode_mapper(drogon::app().getDbClient());
 | 
			
		||||
        try {
 | 
			
		||||
            return inode_mapper.findByPrimaryKey(node);
 | 
			
		||||
        } catch (const std::exception&) {
 | 
			
		||||
            return std::nullopt;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    std::optional<db::INode> fs::get_node_and_validate(const db::User &user, uint64_t node) {
 | 
			
		||||
        auto inode = get_node(node);
 | 
			
		||||
        if (!inode.has_value()) return std::nullopt;
 | 
			
		||||
        if (inode->getValueOfOwnerId() != user.getValueOfId()) return std::nullopt;
 | 
			
		||||
        return inode;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    std::vector<db::INode> fs::get_children(const db::INode& parent) {
 | 
			
		||||
        db::MapperInode inode_mapper(drogon::app().getDbClient());
 | 
			
		||||
        return inode_mapper.findBy(db::Criteria(db::INode::Cols::_parent_id, db::CompareOps::EQ, parent.getValueOfId()));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    std::variant<db::INode, std::string> fs::create_node(std::string name, const db::User& owner, bool file, const std::optional<uint64_t> &parent, bool force) {
 | 
			
		||||
        // Stolen from https://github.com/boostorg/filesystem/blob/develop/src/portability.cpp
 | 
			
		||||
        if (!force)
 | 
			
		||||
            if (name.empty() || name[0] == ' ' || name.find_first_of(windows_invalid_chars, 0, sizeof(windows_invalid_chars)) != std::string::npos || *(name.end() - 1) == ' ' || *(name.end() - 1) == '.' || name == "." || name == "..")
 | 
			
		||||
                return {"Invalid name"};
 | 
			
		||||
 | 
			
		||||
        db::INode node;
 | 
			
		||||
        node.setIsFile(file ? 1 : 0);
 | 
			
		||||
        node.setName(name);
 | 
			
		||||
        node.setOwnerId(owner.getValueOfId());
 | 
			
		||||
        if (parent.has_value()) {
 | 
			
		||||
            auto parent_node =  get_node_and_validate(owner, *parent);
 | 
			
		||||
            if (!parent_node.has_value())
 | 
			
		||||
                return {"Invalid parent"};
 | 
			
		||||
            if (parent_node->getValueOfIsFile() != 0)
 | 
			
		||||
                return {"Can't use file as parent"};
 | 
			
		||||
            auto children = get_children(*parent_node);
 | 
			
		||||
            for (const auto& child : children)
 | 
			
		||||
                if (child.getValueOfName() == name)
 | 
			
		||||
                    return {"File/Folder already exists"};
 | 
			
		||||
            node.setParentId(*parent);
 | 
			
		||||
        }
 | 
			
		||||
        db::MapperInode inode_mapper(drogon::app().getDbClient());
 | 
			
		||||
        inode_mapper.insert(node);
 | 
			
		||||
        return {node};
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void fs::delete_node(db::INode node, bool allow_root) {
 | 
			
		||||
        if (node.getValueOfParentId() == 0 && (!allow_root)) return;
 | 
			
		||||
        if (node.getValueOfIsFile() == 0) {
 | 
			
		||||
            auto children =  get_children(node);
 | 
			
		||||
            for (const auto& child : children) delete_node(child, false);
 | 
			
		||||
        } else {
 | 
			
		||||
            std::filesystem::path p("./files");
 | 
			
		||||
            p /= std::to_string(node.getValueOfId());
 | 
			
		||||
            std::filesystem::remove(p);
 | 
			
		||||
        }
 | 
			
		||||
        db::MapperInode inode_mapper(drogon::app().getDbClient());
 | 
			
		||||
        inode_mapper.deleteOne(node);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void fs::root(req_type req, cbk_type cbk) {
 | 
			
		||||
        db::User user = dto::get_user(req);
 | 
			
		||||
        cbk(dto::Responses::get_root_res(user.getValueOfRootId()));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void fs::node(req_type req, cbk_type cbk, uint64_t node) {
 | 
			
		||||
        db::User user = dto::get_user(req);
 | 
			
		||||
        auto inode =  get_node_and_validate(user, node);
 | 
			
		||||
        if (!inode.has_value())
 | 
			
		||||
            cbk(dto::Responses::get_badreq_res("Unknown node"));
 | 
			
		||||
        else if (inode->getValueOfIsFile() == 0) {
 | 
			
		||||
            std::vector<uint64_t> children;
 | 
			
		||||
            for (const db::INode& child : get_children(*inode)) children.push_back(child.getValueOfId());
 | 
			
		||||
            cbk(dto::Responses::get_node_folder_res(
 | 
			
		||||
                    inode->getValueOfId(),
 | 
			
		||||
                    inode->getValueOfName(),
 | 
			
		||||
                    inode->getParentId(),
 | 
			
		||||
                    children
 | 
			
		||||
            ));
 | 
			
		||||
        } else
 | 
			
		||||
            cbk(dto::Responses::get_node_file_res(
 | 
			
		||||
                    inode->getValueOfId(),
 | 
			
		||||
                    inode->getValueOfName(),
 | 
			
		||||
                    inode->getParentId(),
 | 
			
		||||
                    inode->getValueOfSize()
 | 
			
		||||
            ));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void fs::path(req_type req, cbk_type cbk, uint64_t node) {
 | 
			
		||||
        db::User user = dto::get_user(req);
 | 
			
		||||
        auto inode = get_node_and_validate(user, node);
 | 
			
		||||
        if (!inode.has_value())
 | 
			
		||||
            cbk(dto::Responses::get_badreq_res("Unknown node"));
 | 
			
		||||
        else
 | 
			
		||||
            cbk(dto::Responses::get_path_res( generate_path(*inode)));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template<bool file>
 | 
			
		||||
    void fs::create_node_req(req_type req, cbk_type cbk) {
 | 
			
		||||
        db::User user = dto::get_user(req);
 | 
			
		||||
        Json::Value& json = *req->jsonObject();
 | 
			
		||||
        try {
 | 
			
		||||
            uint64_t parent = dto::json_get<uint64_t>(json, "parent").value();
 | 
			
		||||
            std::string name = dto::json_get<std::string>(json, "name").value();
 | 
			
		||||
 | 
			
		||||
            auto new_node = create_node(name, user, file, std::make_optional(parent));
 | 
			
		||||
            if (std::holds_alternative<std::string>(new_node))
 | 
			
		||||
                cbk(dto::Responses::get_badreq_res(std::get<std::string>(new_node)));
 | 
			
		||||
            else
 | 
			
		||||
                cbk(dto::Responses::get_new_node_res(std::get<db::INode>(new_node).getValueOfId()));
 | 
			
		||||
        } catch (const std::exception&) {
 | 
			
		||||
            cbk(dto::Responses::get_badreq_res("Validation error"));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void fs::delete_node_req(req_type req, cbk_type cbk, uint64_t node) {
 | 
			
		||||
        db::User user = dto::get_user(req);
 | 
			
		||||
        auto inode = get_node_and_validate(user, node);
 | 
			
		||||
        if (!inode.has_value())
 | 
			
		||||
            cbk(dto::Responses::get_badreq_res("Unknown node"));
 | 
			
		||||
        else if (inode->getValueOfParentId() == 0)
 | 
			
		||||
            cbk(dto::Responses::get_badreq_res("Can't delete root"));
 | 
			
		||||
        else {
 | 
			
		||||
             delete_node(*inode);
 | 
			
		||||
            cbk(dto::Responses::get_success_res());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void fs::upload(req_type req, cbk_type cbk, uint64_t node) {
 | 
			
		||||
        db::User user = dto::get_user(req);
 | 
			
		||||
 | 
			
		||||
        auto inode = get_node_and_validate(user, node);
 | 
			
		||||
        if (!inode.has_value())
 | 
			
		||||
            return cbk(dto::Responses::get_badreq_res("Unknown node"));
 | 
			
		||||
        if (inode->getValueOfIsFile() == 0)
 | 
			
		||||
            return cbk(dto::Responses::get_badreq_res("Can't upload to a directory"));
 | 
			
		||||
 | 
			
		||||
        drogon::MultiPartParser mpp;
 | 
			
		||||
        if (mpp.parse(req) != 0)
 | 
			
		||||
            return cbk(dto::Responses::get_badreq_res("Failed to parse files"));
 | 
			
		||||
        if (mpp.getFiles().size() != 1)
 | 
			
		||||
            return cbk(dto::Responses::get_badreq_res("Exactly 1 file needed"));
 | 
			
		||||
 | 
			
		||||
        const drogon::HttpFile& file = mpp.getFiles().at(0);
 | 
			
		||||
 | 
			
		||||
        std::filesystem::path p("./files");
 | 
			
		||||
        p /= std::to_string(inode->getValueOfId());
 | 
			
		||||
 | 
			
		||||
        file.saveAs(p.string());
 | 
			
		||||
 | 
			
		||||
        inode->setSize(file.fileLength());
 | 
			
		||||
        db::MapperInode inode_mapper(drogon::app().getDbClient());
 | 
			
		||||
        inode_mapper.update(*inode);
 | 
			
		||||
        cbk(dto::Responses::get_success_res());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void fs::download(req_type req, cbk_type cbk) {
 | 
			
		||||
        db::User user = dto::get_user(req);
 | 
			
		||||
 | 
			
		||||
        auto node_id = req->getOptionalParameter<uint64_t>("id");
 | 
			
		||||
        if (!node_id.has_value()) {
 | 
			
		||||
            cbk(dto::Responses::get_badreq_res("Invalid node"));
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        auto inode =  get_node_and_validate(user, *node_id);
 | 
			
		||||
        if (!inode.has_value()) {
 | 
			
		||||
            cbk(dto::Responses::get_badreq_res("Invalid node"));
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        std::filesystem::path p("./files");
 | 
			
		||||
        p /= std::to_string(inode->getValueOfId());
 | 
			
		||||
 | 
			
		||||
        cbk(drogon::HttpResponse::newFileResponse(
 | 
			
		||||
            p.string(),
 | 
			
		||||
            inode->getValueOfName()
 | 
			
		||||
        ));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
#pragma clang diagnostic pop
 | 
			
		||||
							
								
								
									
										29
									
								
								backend/src/controllers/user.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								backend/src/controllers/user.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,29 @@
 | 
			
		||||
#pragma clang diagnostic push
 | 
			
		||||
#pragma ide diagnostic ignored "performance-unnecessary-value-param"
 | 
			
		||||
#pragma ide diagnostic ignored "readability-convert-member-functions-to-static"
 | 
			
		||||
 | 
			
		||||
#include "controllers.h"
 | 
			
		||||
#include "dto/dto.h"
 | 
			
		||||
 | 
			
		||||
namespace api {
 | 
			
		||||
    void user::info(req_type req, cbk_type cbk) {
 | 
			
		||||
        db::User user = dto::get_user(req);
 | 
			
		||||
        cbk(dto::Responses::get_user_info_res(
 | 
			
		||||
                user.getValueOfName(),
 | 
			
		||||
                user.getValueOfGitlab() != 0,
 | 
			
		||||
                db::User_getEnumTfaType(user) != db::tfaTypes::NONE)
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void user::delete_user(req_type req, cbk_type cbk) {
 | 
			
		||||
        db::MapperUser user_mapper(drogon::app().getDbClient());
 | 
			
		||||
 | 
			
		||||
        db::User user = dto::get_user(req);
 | 
			
		||||
        auth::revoke_all(user);
 | 
			
		||||
        fs::delete_node((fs::get_node(user.getValueOfRootId())).value(), true);
 | 
			
		||||
        user_mapper.deleteOne(user);
 | 
			
		||||
 | 
			
		||||
        cbk(dto::Responses::get_success_res());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
#pragma clang diagnostic pop
 | 
			
		||||
							
								
								
									
										11
									
								
								backend/src/db/db.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								backend/src/db/db.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
			
		||||
#include "db.h"
 | 
			
		||||
 | 
			
		||||
namespace db {
 | 
			
		||||
    UserRole User_getEnumRole(const User& user) noexcept {
 | 
			
		||||
        return (UserRole)user.getValueOfRole();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    tfaTypes User_getEnumTfaType(const User& user) noexcept {
 | 
			
		||||
        return (tfaTypes)user.getValueOfTfaType();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										43
									
								
								backend/src/db/db.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								backend/src/db/db.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,43 @@
 | 
			
		||||
#ifndef BACKEND_DB_H
 | 
			
		||||
#define BACKEND_DB_H
 | 
			
		||||
 | 
			
		||||
#include <utility>
 | 
			
		||||
 | 
			
		||||
#include <drogon/utils/coroutine.h>
 | 
			
		||||
#include <drogon/drogon.h>
 | 
			
		||||
 | 
			
		||||
#include "model/Inode.h"
 | 
			
		||||
#include "model/Tokens.h"
 | 
			
		||||
#include "model/User.h"
 | 
			
		||||
 | 
			
		||||
const std::string jwt_secret = "CUM";
 | 
			
		||||
 | 
			
		||||
namespace db {
 | 
			
		||||
    enum UserRole : int {
 | 
			
		||||
        ADMIN = 2,
 | 
			
		||||
        USER = 1,
 | 
			
		||||
        DISABLED = 0
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    enum tfaTypes : int {
 | 
			
		||||
        NONE = 0,
 | 
			
		||||
        EMAIL = 1,
 | 
			
		||||
        TOTP = 2
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    using INode = drogon_model::sqlite3::Inode;
 | 
			
		||||
    using Token = drogon_model::sqlite3::Tokens;
 | 
			
		||||
    using User = drogon_model::sqlite3::User;
 | 
			
		||||
 | 
			
		||||
    using MapperInode = drogon::orm::Mapper<INode>;
 | 
			
		||||
    using MapperToken = drogon::orm::Mapper<Token>;
 | 
			
		||||
    using MapperUser = drogon::orm::Mapper<User>;
 | 
			
		||||
 | 
			
		||||
    using Criteria = drogon::orm::Criteria;
 | 
			
		||||
    using CompareOps = drogon::orm::CompareOperator;
 | 
			
		||||
 | 
			
		||||
    UserRole User_getEnumRole(const User&) noexcept;
 | 
			
		||||
    tfaTypes User_getEnumTfaType(const User&) noexcept;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif //BACKEND_DB_H
 | 
			
		||||
							
								
								
									
										1095
									
								
								backend/src/db/model/Inode.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1095
									
								
								backend/src/db/model/Inode.cc
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										275
									
								
								backend/src/db/model/Inode.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										275
									
								
								backend/src/db/model/Inode.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,275 @@
 | 
			
		||||
/**
 | 
			
		||||
 *
 | 
			
		||||
 *  Inode.h
 | 
			
		||||
 *  DO NOT EDIT. This file is generated by drogon_ctl
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
#include <drogon/orm/Result.h>
 | 
			
		||||
#include <drogon/orm/Row.h>
 | 
			
		||||
#include <drogon/orm/Field.h>
 | 
			
		||||
#include <drogon/orm/SqlBinder.h>
 | 
			
		||||
#include <drogon/orm/Mapper.h>
 | 
			
		||||
#ifdef __cpp_impl_coroutine
 | 
			
		||||
#include <drogon/orm/CoroMapper.h>
 | 
			
		||||
#endif
 | 
			
		||||
#include <trantor/utils/Date.h>
 | 
			
		||||
#include <trantor/utils/Logger.h>
 | 
			
		||||
#include <json/json.h>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include <tuple>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <iostream>
 | 
			
		||||
 | 
			
		||||
namespace drogon
 | 
			
		||||
{
 | 
			
		||||
namespace orm
 | 
			
		||||
{
 | 
			
		||||
class DbClient;
 | 
			
		||||
using DbClientPtr = std::shared_ptr<DbClient>;
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
namespace drogon_model
 | 
			
		||||
{
 | 
			
		||||
namespace sqlite3
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
class Inode
 | 
			
		||||
{
 | 
			
		||||
  public:
 | 
			
		||||
    struct Cols
 | 
			
		||||
    {
 | 
			
		||||
        static const std::string _id;
 | 
			
		||||
        static const std::string _is_file;
 | 
			
		||||
        static const std::string _name;
 | 
			
		||||
        static const std::string _parent_id;
 | 
			
		||||
        static const std::string _owner_id;
 | 
			
		||||
        static const std::string _size;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    const static int primaryKeyNumber;
 | 
			
		||||
    const static std::string tableName;
 | 
			
		||||
    const static bool hasPrimaryKey;
 | 
			
		||||
    const static std::string primaryKeyName;
 | 
			
		||||
    using PrimaryKeyType = uint64_t;
 | 
			
		||||
    const PrimaryKeyType &getPrimaryKey() const;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @brief constructor
 | 
			
		||||
     * @param r One row of records in the SQL query result.
 | 
			
		||||
     * @param indexOffset Set the offset to -1 to access all columns by column names,
 | 
			
		||||
     * otherwise access all columns by offsets.
 | 
			
		||||
     * @note If the SQL is not a style of 'select * from table_name ...' (select all
 | 
			
		||||
     * columns by an asterisk), please set the offset to -1.
 | 
			
		||||
     */
 | 
			
		||||
    explicit Inode(const drogon::orm::Row &r, const ssize_t indexOffset = 0) noexcept;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @brief constructor
 | 
			
		||||
     * @param pJson The json object to construct a new instance.
 | 
			
		||||
     */
 | 
			
		||||
    explicit Inode(const Json::Value &pJson) noexcept(false);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @brief constructor
 | 
			
		||||
     * @param pJson The json object to construct a new instance.
 | 
			
		||||
     * @param pMasqueradingVector The aliases of table columns.
 | 
			
		||||
     */
 | 
			
		||||
    Inode(const Json::Value &pJson, const std::vector<std::string> &pMasqueradingVector) noexcept(false);
 | 
			
		||||
 | 
			
		||||
    Inode() = default;
 | 
			
		||||
 | 
			
		||||
    void updateByJson(const Json::Value &pJson) noexcept(false);
 | 
			
		||||
    void updateByMasqueradedJson(const Json::Value &pJson,
 | 
			
		||||
                                 const std::vector<std::string> &pMasqueradingVector) noexcept(false);
 | 
			
		||||
    static bool validateJsonForCreation(const Json::Value &pJson, std::string &err);
 | 
			
		||||
    static bool validateMasqueradedJsonForCreation(const Json::Value &,
 | 
			
		||||
                                                const std::vector<std::string> &pMasqueradingVector,
 | 
			
		||||
                                                    std::string &err);
 | 
			
		||||
    static bool validateJsonForUpdate(const Json::Value &pJson, std::string &err);
 | 
			
		||||
    static bool validateMasqueradedJsonForUpdate(const Json::Value &,
 | 
			
		||||
                                          const std::vector<std::string> &pMasqueradingVector,
 | 
			
		||||
                                          std::string &err);
 | 
			
		||||
    static bool validJsonOfField(size_t index,
 | 
			
		||||
                          const std::string &fieldName,
 | 
			
		||||
                          const Json::Value &pJson,
 | 
			
		||||
                          std::string &err,
 | 
			
		||||
                          bool isForCreation);
 | 
			
		||||
 | 
			
		||||
    /**  For column id  */
 | 
			
		||||
    ///Get the value of the column id, returns the default value if the column is null
 | 
			
		||||
    const uint64_t &getValueOfId() const noexcept;
 | 
			
		||||
    ///Return a shared_ptr object pointing to the column const value, or an empty shared_ptr object if the column is null
 | 
			
		||||
    const std::shared_ptr<uint64_t> &getId() const noexcept;
 | 
			
		||||
    ///Set the value of the column id
 | 
			
		||||
    void setId(const uint64_t &pId) noexcept;
 | 
			
		||||
 | 
			
		||||
    /**  For column is_file  */
 | 
			
		||||
    ///Get the value of the column is_file, returns the default value if the column is null
 | 
			
		||||
    const uint64_t &getValueOfIsFile() const noexcept;
 | 
			
		||||
    ///Return a shared_ptr object pointing to the column const value, or an empty shared_ptr object if the column is null
 | 
			
		||||
    const std::shared_ptr<uint64_t> &getIsFile() const noexcept;
 | 
			
		||||
    ///Set the value of the column is_file
 | 
			
		||||
    void setIsFile(const uint64_t &pIsFile) noexcept;
 | 
			
		||||
 | 
			
		||||
    /**  For column name  */
 | 
			
		||||
    ///Get the value of the column name, returns the default value if the column is null
 | 
			
		||||
    const std::string &getValueOfName() const noexcept;
 | 
			
		||||
    ///Return a shared_ptr object pointing to the column const value, or an empty shared_ptr object if the column is null
 | 
			
		||||
    const std::shared_ptr<std::string> &getName() const noexcept;
 | 
			
		||||
    ///Set the value of the column name
 | 
			
		||||
    void setName(const std::string &pName) noexcept;
 | 
			
		||||
    void setName(std::string &&pName) noexcept;
 | 
			
		||||
    void setNameToNull() noexcept;
 | 
			
		||||
 | 
			
		||||
    /**  For column parent_id  */
 | 
			
		||||
    ///Get the value of the column parent_id, returns the default value if the column is null
 | 
			
		||||
    const uint64_t &getValueOfParentId() const noexcept;
 | 
			
		||||
    ///Return a shared_ptr object pointing to the column const value, or an empty shared_ptr object if the column is null
 | 
			
		||||
    const std::shared_ptr<uint64_t> &getParentId() const noexcept;
 | 
			
		||||
    ///Set the value of the column parent_id
 | 
			
		||||
    void setParentId(const uint64_t &pParentId) noexcept;
 | 
			
		||||
    void setParentIdToNull() noexcept;
 | 
			
		||||
 | 
			
		||||
    /**  For column owner_id  */
 | 
			
		||||
    ///Get the value of the column owner_id, returns the default value if the column is null
 | 
			
		||||
    const uint64_t &getValueOfOwnerId() const noexcept;
 | 
			
		||||
    ///Return a shared_ptr object pointing to the column const value, or an empty shared_ptr object if the column is null
 | 
			
		||||
    const std::shared_ptr<uint64_t> &getOwnerId() const noexcept;
 | 
			
		||||
    ///Set the value of the column owner_id
 | 
			
		||||
    void setOwnerId(const uint64_t &pOwnerId) noexcept;
 | 
			
		||||
 | 
			
		||||
    /**  For column size  */
 | 
			
		||||
    ///Get the value of the column size, returns the default value if the column is null
 | 
			
		||||
    const uint64_t &getValueOfSize() const noexcept;
 | 
			
		||||
    ///Return a shared_ptr object pointing to the column const value, or an empty shared_ptr object if the column is null
 | 
			
		||||
    const std::shared_ptr<uint64_t> &getSize() const noexcept;
 | 
			
		||||
    ///Set the value of the column size
 | 
			
		||||
    void setSize(const uint64_t &pSize) noexcept;
 | 
			
		||||
    void setSizeToNull() noexcept;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    static size_t getColumnNumber() noexcept {  return 6;  }
 | 
			
		||||
    static const std::string &getColumnName(size_t index) noexcept(false);
 | 
			
		||||
 | 
			
		||||
    Json::Value toJson() const;
 | 
			
		||||
    Json::Value toMasqueradedJson(const std::vector<std::string> &pMasqueradingVector) const;
 | 
			
		||||
    /// Relationship interfaces
 | 
			
		||||
  private:
 | 
			
		||||
    friend drogon::orm::Mapper<Inode>;
 | 
			
		||||
#ifdef __cpp_impl_coroutine
 | 
			
		||||
    friend drogon::orm::CoroMapper<Inode>;
 | 
			
		||||
#endif
 | 
			
		||||
    static const std::vector<std::string> &insertColumns() noexcept;
 | 
			
		||||
    void outputArgs(drogon::orm::internal::SqlBinder &binder) const;
 | 
			
		||||
    const std::vector<std::string> updateColumns() const;
 | 
			
		||||
    void updateArgs(drogon::orm::internal::SqlBinder &binder) const;
 | 
			
		||||
    ///For mysql or sqlite3
 | 
			
		||||
    void updateId(const uint64_t id);
 | 
			
		||||
    std::shared_ptr<uint64_t> id_;
 | 
			
		||||
    std::shared_ptr<uint64_t> isFile_;
 | 
			
		||||
    std::shared_ptr<std::string> name_;
 | 
			
		||||
    std::shared_ptr<uint64_t> parentId_;
 | 
			
		||||
    std::shared_ptr<uint64_t> ownerId_;
 | 
			
		||||
    std::shared_ptr<uint64_t> size_;
 | 
			
		||||
    struct MetaData
 | 
			
		||||
    {
 | 
			
		||||
        const std::string colName_;
 | 
			
		||||
        const std::string colType_;
 | 
			
		||||
        const std::string colDatabaseType_;
 | 
			
		||||
        const ssize_t colLength_;
 | 
			
		||||
        const bool isAutoVal_;
 | 
			
		||||
        const bool isPrimaryKey_;
 | 
			
		||||
        const bool notNull_;
 | 
			
		||||
    };
 | 
			
		||||
    static const std::vector<MetaData> metaData_;
 | 
			
		||||
    bool dirtyFlag_[6]={ false };
 | 
			
		||||
  public:
 | 
			
		||||
    static const std::string &sqlForFindingByPrimaryKey()
 | 
			
		||||
    {
 | 
			
		||||
        static const std::string sql="select * from " + tableName + " where id = ?";
 | 
			
		||||
        return sql;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static const std::string &sqlForDeletingByPrimaryKey()
 | 
			
		||||
    {
 | 
			
		||||
        static const std::string sql="delete from " + tableName + " where id = ?";
 | 
			
		||||
        return sql;
 | 
			
		||||
    }
 | 
			
		||||
    std::string sqlForInserting(bool &needSelection) const
 | 
			
		||||
    {
 | 
			
		||||
        std::string sql="insert into " + tableName + " (";
 | 
			
		||||
        size_t parametersCount = 0;
 | 
			
		||||
        needSelection = false;
 | 
			
		||||
        if(dirtyFlag_[1])
 | 
			
		||||
        {
 | 
			
		||||
            sql += "is_file,";
 | 
			
		||||
            ++parametersCount;
 | 
			
		||||
        }
 | 
			
		||||
        if(dirtyFlag_[2])
 | 
			
		||||
        {
 | 
			
		||||
            sql += "name,";
 | 
			
		||||
            ++parametersCount;
 | 
			
		||||
        }
 | 
			
		||||
        if(dirtyFlag_[3])
 | 
			
		||||
        {
 | 
			
		||||
            sql += "parent_id,";
 | 
			
		||||
            ++parametersCount;
 | 
			
		||||
        }
 | 
			
		||||
        if(dirtyFlag_[4])
 | 
			
		||||
        {
 | 
			
		||||
            sql += "owner_id,";
 | 
			
		||||
            ++parametersCount;
 | 
			
		||||
        }
 | 
			
		||||
        if(dirtyFlag_[5])
 | 
			
		||||
        {
 | 
			
		||||
            sql += "size,";
 | 
			
		||||
            ++parametersCount;
 | 
			
		||||
        }
 | 
			
		||||
        if(parametersCount > 0)
 | 
			
		||||
        {
 | 
			
		||||
            sql[sql.length()-1]=')';
 | 
			
		||||
            sql += " values (";
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
            sql += ") values (";
 | 
			
		||||
 | 
			
		||||
        if(dirtyFlag_[1])
 | 
			
		||||
        {
 | 
			
		||||
            sql.append("?,");
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
        if(dirtyFlag_[2])
 | 
			
		||||
        {
 | 
			
		||||
            sql.append("?,");
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
        if(dirtyFlag_[3])
 | 
			
		||||
        {
 | 
			
		||||
            sql.append("?,");
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
        if(dirtyFlag_[4])
 | 
			
		||||
        {
 | 
			
		||||
            sql.append("?,");
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
        if(dirtyFlag_[5])
 | 
			
		||||
        {
 | 
			
		||||
            sql.append("?,");
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
        if(parametersCount > 0)
 | 
			
		||||
        {
 | 
			
		||||
            sql.resize(sql.length() - 1);
 | 
			
		||||
        }
 | 
			
		||||
        sql.append(1, ')');
 | 
			
		||||
        LOG_TRACE << sql;
 | 
			
		||||
        return sql;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
} // namespace sqlite3
 | 
			
		||||
} // namespace drogon_model
 | 
			
		||||
							
								
								
									
										631
									
								
								backend/src/db/model/Tokens.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										631
									
								
								backend/src/db/model/Tokens.cc
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,631 @@
 | 
			
		||||
/**
 | 
			
		||||
 *
 | 
			
		||||
 *  Tokens.cc
 | 
			
		||||
 *  DO NOT EDIT. This file is generated by drogon_ctl
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "Tokens.h"
 | 
			
		||||
#include <drogon/utils/Utilities.h>
 | 
			
		||||
#include <string>
 | 
			
		||||
 | 
			
		||||
using namespace drogon;
 | 
			
		||||
using namespace drogon::orm;
 | 
			
		||||
using namespace drogon_model::sqlite3;
 | 
			
		||||
 | 
			
		||||
const std::string Tokens::Cols::_id = "id";
 | 
			
		||||
const std::string Tokens::Cols::_owner_id = "owner_id";
 | 
			
		||||
const std::string Tokens::Cols::_exp = "exp";
 | 
			
		||||
const std::string Tokens::primaryKeyName = "id";
 | 
			
		||||
const bool Tokens::hasPrimaryKey = true;
 | 
			
		||||
const std::string Tokens::tableName = "tokens";
 | 
			
		||||
 | 
			
		||||
const std::vector<typename Tokens::MetaData> Tokens::metaData_={
 | 
			
		||||
{"id","uint64_t","integer",8,1,1,1},
 | 
			
		||||
{"owner_id","uint64_t","integer",8,0,0,1},
 | 
			
		||||
{"exp","uint64_t","integer",8,0,0,1}
 | 
			
		||||
};
 | 
			
		||||
const std::string &Tokens::getColumnName(size_t index) noexcept(false)
 | 
			
		||||
{
 | 
			
		||||
    assert(index < metaData_.size());
 | 
			
		||||
    return metaData_[index].colName_;
 | 
			
		||||
}
 | 
			
		||||
Tokens::Tokens(const Row &r, const ssize_t indexOffset) noexcept
 | 
			
		||||
{
 | 
			
		||||
    if(indexOffset < 0)
 | 
			
		||||
    {
 | 
			
		||||
        if(!r["id"].isNull())
 | 
			
		||||
        {
 | 
			
		||||
            id_=std::make_shared<uint64_t>(r["id"].as<uint64_t>());
 | 
			
		||||
        }
 | 
			
		||||
        if(!r["owner_id"].isNull())
 | 
			
		||||
        {
 | 
			
		||||
            ownerId_=std::make_shared<uint64_t>(r["owner_id"].as<uint64_t>());
 | 
			
		||||
        }
 | 
			
		||||
        if(!r["exp"].isNull())
 | 
			
		||||
        {
 | 
			
		||||
            exp_=std::make_shared<uint64_t>(r["exp"].as<uint64_t>());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        size_t offset = (size_t)indexOffset;
 | 
			
		||||
        if(offset + 3 > r.size())
 | 
			
		||||
        {
 | 
			
		||||
            LOG_FATAL << "Invalid SQL result for this model";
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        size_t index;
 | 
			
		||||
        index = offset + 0;
 | 
			
		||||
        if(!r[index].isNull())
 | 
			
		||||
        {
 | 
			
		||||
            id_=std::make_shared<uint64_t>(r[index].as<uint64_t>());
 | 
			
		||||
        }
 | 
			
		||||
        index = offset + 1;
 | 
			
		||||
        if(!r[index].isNull())
 | 
			
		||||
        {
 | 
			
		||||
            ownerId_=std::make_shared<uint64_t>(r[index].as<uint64_t>());
 | 
			
		||||
        }
 | 
			
		||||
        index = offset + 2;
 | 
			
		||||
        if(!r[index].isNull())
 | 
			
		||||
        {
 | 
			
		||||
            exp_=std::make_shared<uint64_t>(r[index].as<uint64_t>());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Tokens::Tokens(const Json::Value &pJson, const std::vector<std::string> &pMasqueradingVector) noexcept(false)
 | 
			
		||||
{
 | 
			
		||||
    if(pMasqueradingVector.size() != 3)
 | 
			
		||||
    {
 | 
			
		||||
        LOG_ERROR << "Bad masquerading vector";
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    if(!pMasqueradingVector[0].empty() && pJson.isMember(pMasqueradingVector[0]))
 | 
			
		||||
    {
 | 
			
		||||
        dirtyFlag_[0] = true;
 | 
			
		||||
        if(!pJson[pMasqueradingVector[0]].isNull())
 | 
			
		||||
        {
 | 
			
		||||
            id_=std::make_shared<uint64_t>((uint64_t)pJson[pMasqueradingVector[0]].asUInt64());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if(!pMasqueradingVector[1].empty() && pJson.isMember(pMasqueradingVector[1]))
 | 
			
		||||
    {
 | 
			
		||||
        dirtyFlag_[1] = true;
 | 
			
		||||
        if(!pJson[pMasqueradingVector[1]].isNull())
 | 
			
		||||
        {
 | 
			
		||||
            ownerId_=std::make_shared<uint64_t>((uint64_t)pJson[pMasqueradingVector[1]].asUInt64());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if(!pMasqueradingVector[2].empty() && pJson.isMember(pMasqueradingVector[2]))
 | 
			
		||||
    {
 | 
			
		||||
        dirtyFlag_[2] = true;
 | 
			
		||||
        if(!pJson[pMasqueradingVector[2]].isNull())
 | 
			
		||||
        {
 | 
			
		||||
            exp_=std::make_shared<uint64_t>((uint64_t)pJson[pMasqueradingVector[2]].asUInt64());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Tokens::Tokens(const Json::Value &pJson) noexcept(false)
 | 
			
		||||
{
 | 
			
		||||
    if(pJson.isMember("id"))
 | 
			
		||||
    {
 | 
			
		||||
        dirtyFlag_[0]=true;
 | 
			
		||||
        if(!pJson["id"].isNull())
 | 
			
		||||
        {
 | 
			
		||||
            id_=std::make_shared<uint64_t>((uint64_t)pJson["id"].asUInt64());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if(pJson.isMember("owner_id"))
 | 
			
		||||
    {
 | 
			
		||||
        dirtyFlag_[1]=true;
 | 
			
		||||
        if(!pJson["owner_id"].isNull())
 | 
			
		||||
        {
 | 
			
		||||
            ownerId_=std::make_shared<uint64_t>((uint64_t)pJson["owner_id"].asUInt64());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if(pJson.isMember("exp"))
 | 
			
		||||
    {
 | 
			
		||||
        dirtyFlag_[2]=true;
 | 
			
		||||
        if(!pJson["exp"].isNull())
 | 
			
		||||
        {
 | 
			
		||||
            exp_=std::make_shared<uint64_t>((uint64_t)pJson["exp"].asUInt64());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Tokens::updateByMasqueradedJson(const Json::Value &pJson,
 | 
			
		||||
                                            const std::vector<std::string> &pMasqueradingVector) noexcept(false)
 | 
			
		||||
{
 | 
			
		||||
    if(pMasqueradingVector.size() != 3)
 | 
			
		||||
    {
 | 
			
		||||
        LOG_ERROR << "Bad masquerading vector";
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    if(!pMasqueradingVector[0].empty() && pJson.isMember(pMasqueradingVector[0]))
 | 
			
		||||
    {
 | 
			
		||||
        if(!pJson[pMasqueradingVector[0]].isNull())
 | 
			
		||||
        {
 | 
			
		||||
            id_=std::make_shared<uint64_t>((uint64_t)pJson[pMasqueradingVector[0]].asUInt64());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if(!pMasqueradingVector[1].empty() && pJson.isMember(pMasqueradingVector[1]))
 | 
			
		||||
    {
 | 
			
		||||
        dirtyFlag_[1] = true;
 | 
			
		||||
        if(!pJson[pMasqueradingVector[1]].isNull())
 | 
			
		||||
        {
 | 
			
		||||
            ownerId_=std::make_shared<uint64_t>((uint64_t)pJson[pMasqueradingVector[1]].asUInt64());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if(!pMasqueradingVector[2].empty() && pJson.isMember(pMasqueradingVector[2]))
 | 
			
		||||
    {
 | 
			
		||||
        dirtyFlag_[2] = true;
 | 
			
		||||
        if(!pJson[pMasqueradingVector[2]].isNull())
 | 
			
		||||
        {
 | 
			
		||||
            exp_=std::make_shared<uint64_t>((uint64_t)pJson[pMasqueradingVector[2]].asUInt64());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Tokens::updateByJson(const Json::Value &pJson) noexcept(false)
 | 
			
		||||
{
 | 
			
		||||
    if(pJson.isMember("id"))
 | 
			
		||||
    {
 | 
			
		||||
        if(!pJson["id"].isNull())
 | 
			
		||||
        {
 | 
			
		||||
            id_=std::make_shared<uint64_t>((uint64_t)pJson["id"].asUInt64());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if(pJson.isMember("owner_id"))
 | 
			
		||||
    {
 | 
			
		||||
        dirtyFlag_[1] = true;
 | 
			
		||||
        if(!pJson["owner_id"].isNull())
 | 
			
		||||
        {
 | 
			
		||||
            ownerId_=std::make_shared<uint64_t>((uint64_t)pJson["owner_id"].asUInt64());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if(pJson.isMember("exp"))
 | 
			
		||||
    {
 | 
			
		||||
        dirtyFlag_[2] = true;
 | 
			
		||||
        if(!pJson["exp"].isNull())
 | 
			
		||||
        {
 | 
			
		||||
            exp_=std::make_shared<uint64_t>((uint64_t)pJson["exp"].asUInt64());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const uint64_t &Tokens::getValueOfId() const noexcept
 | 
			
		||||
{
 | 
			
		||||
    const static uint64_t defaultValue = uint64_t();
 | 
			
		||||
    if(id_)
 | 
			
		||||
        return *id_;
 | 
			
		||||
    return defaultValue;
 | 
			
		||||
}
 | 
			
		||||
const std::shared_ptr<uint64_t> &Tokens::getId() const noexcept
 | 
			
		||||
{
 | 
			
		||||
    return id_;
 | 
			
		||||
}
 | 
			
		||||
void Tokens::setId(const uint64_t &pId) noexcept
 | 
			
		||||
{
 | 
			
		||||
    id_ = std::make_shared<uint64_t>(pId);
 | 
			
		||||
    dirtyFlag_[0] = true;
 | 
			
		||||
}
 | 
			
		||||
const typename Tokens::PrimaryKeyType & Tokens::getPrimaryKey() const
 | 
			
		||||
{
 | 
			
		||||
    assert(id_);
 | 
			
		||||
    return *id_;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const uint64_t &Tokens::getValueOfOwnerId() const noexcept
 | 
			
		||||
{
 | 
			
		||||
    const static uint64_t defaultValue = uint64_t();
 | 
			
		||||
    if(ownerId_)
 | 
			
		||||
        return *ownerId_;
 | 
			
		||||
    return defaultValue;
 | 
			
		||||
}
 | 
			
		||||
const std::shared_ptr<uint64_t> &Tokens::getOwnerId() const noexcept
 | 
			
		||||
{
 | 
			
		||||
    return ownerId_;
 | 
			
		||||
}
 | 
			
		||||
void Tokens::setOwnerId(const uint64_t &pOwnerId) noexcept
 | 
			
		||||
{
 | 
			
		||||
    ownerId_ = std::make_shared<uint64_t>(pOwnerId);
 | 
			
		||||
    dirtyFlag_[1] = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const uint64_t &Tokens::getValueOfExp() const noexcept
 | 
			
		||||
{
 | 
			
		||||
    const static uint64_t defaultValue = uint64_t();
 | 
			
		||||
    if(exp_)
 | 
			
		||||
        return *exp_;
 | 
			
		||||
    return defaultValue;
 | 
			
		||||
}
 | 
			
		||||
const std::shared_ptr<uint64_t> &Tokens::getExp() const noexcept
 | 
			
		||||
{
 | 
			
		||||
    return exp_;
 | 
			
		||||
}
 | 
			
		||||
void Tokens::setExp(const uint64_t &pExp) noexcept
 | 
			
		||||
{
 | 
			
		||||
    exp_ = std::make_shared<uint64_t>(pExp);
 | 
			
		||||
    dirtyFlag_[2] = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Tokens::updateId(const uint64_t id)
 | 
			
		||||
{
 | 
			
		||||
    id_ = std::make_shared<uint64_t>(id);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const std::vector<std::string> &Tokens::insertColumns() noexcept
 | 
			
		||||
{
 | 
			
		||||
    static const std::vector<std::string> inCols={
 | 
			
		||||
        "owner_id",
 | 
			
		||||
        "exp"
 | 
			
		||||
    };
 | 
			
		||||
    return inCols;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Tokens::outputArgs(drogon::orm::internal::SqlBinder &binder) const
 | 
			
		||||
{
 | 
			
		||||
    if(dirtyFlag_[1])
 | 
			
		||||
    {
 | 
			
		||||
        if(getOwnerId())
 | 
			
		||||
        {
 | 
			
		||||
            binder << getValueOfOwnerId();
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            binder << nullptr;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if(dirtyFlag_[2])
 | 
			
		||||
    {
 | 
			
		||||
        if(getExp())
 | 
			
		||||
        {
 | 
			
		||||
            binder << getValueOfExp();
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            binder << nullptr;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const std::vector<std::string> Tokens::updateColumns() const
 | 
			
		||||
{
 | 
			
		||||
    std::vector<std::string> ret;
 | 
			
		||||
    if(dirtyFlag_[1])
 | 
			
		||||
    {
 | 
			
		||||
        ret.push_back(getColumnName(1));
 | 
			
		||||
    }
 | 
			
		||||
    if(dirtyFlag_[2])
 | 
			
		||||
    {
 | 
			
		||||
        ret.push_back(getColumnName(2));
 | 
			
		||||
    }
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Tokens::updateArgs(drogon::orm::internal::SqlBinder &binder) const
 | 
			
		||||
{
 | 
			
		||||
    if(dirtyFlag_[1])
 | 
			
		||||
    {
 | 
			
		||||
        if(getOwnerId())
 | 
			
		||||
        {
 | 
			
		||||
            binder << getValueOfOwnerId();
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            binder << nullptr;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if(dirtyFlag_[2])
 | 
			
		||||
    {
 | 
			
		||||
        if(getExp())
 | 
			
		||||
        {
 | 
			
		||||
            binder << getValueOfExp();
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            binder << nullptr;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
Json::Value Tokens::toJson() const
 | 
			
		||||
{
 | 
			
		||||
    Json::Value ret;
 | 
			
		||||
    if(getId())
 | 
			
		||||
    {
 | 
			
		||||
        ret["id"]=(Json::UInt64)getValueOfId();
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        ret["id"]=Json::Value();
 | 
			
		||||
    }
 | 
			
		||||
    if(getOwnerId())
 | 
			
		||||
    {
 | 
			
		||||
        ret["owner_id"]=(Json::UInt64)getValueOfOwnerId();
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        ret["owner_id"]=Json::Value();
 | 
			
		||||
    }
 | 
			
		||||
    if(getExp())
 | 
			
		||||
    {
 | 
			
		||||
        ret["exp"]=(Json::UInt64)getValueOfExp();
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        ret["exp"]=Json::Value();
 | 
			
		||||
    }
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Json::Value Tokens::toMasqueradedJson(
 | 
			
		||||
    const std::vector<std::string> &pMasqueradingVector) const
 | 
			
		||||
{
 | 
			
		||||
    Json::Value ret;
 | 
			
		||||
    if(pMasqueradingVector.size() == 3)
 | 
			
		||||
    {
 | 
			
		||||
        if(!pMasqueradingVector[0].empty())
 | 
			
		||||
        {
 | 
			
		||||
            if(getId())
 | 
			
		||||
            {
 | 
			
		||||
                ret[pMasqueradingVector[0]]=(Json::UInt64)getValueOfId();
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                ret[pMasqueradingVector[0]]=Json::Value();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if(!pMasqueradingVector[1].empty())
 | 
			
		||||
        {
 | 
			
		||||
            if(getOwnerId())
 | 
			
		||||
            {
 | 
			
		||||
                ret[pMasqueradingVector[1]]=(Json::UInt64)getValueOfOwnerId();
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                ret[pMasqueradingVector[1]]=Json::Value();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if(!pMasqueradingVector[2].empty())
 | 
			
		||||
        {
 | 
			
		||||
            if(getExp())
 | 
			
		||||
            {
 | 
			
		||||
                ret[pMasqueradingVector[2]]=(Json::UInt64)getValueOfExp();
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                ret[pMasqueradingVector[2]]=Json::Value();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
    LOG_ERROR << "Masquerade failed";
 | 
			
		||||
    if(getId())
 | 
			
		||||
    {
 | 
			
		||||
        ret["id"]=(Json::UInt64)getValueOfId();
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        ret["id"]=Json::Value();
 | 
			
		||||
    }
 | 
			
		||||
    if(getOwnerId())
 | 
			
		||||
    {
 | 
			
		||||
        ret["owner_id"]=(Json::UInt64)getValueOfOwnerId();
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        ret["owner_id"]=Json::Value();
 | 
			
		||||
    }
 | 
			
		||||
    if(getExp())
 | 
			
		||||
    {
 | 
			
		||||
        ret["exp"]=(Json::UInt64)getValueOfExp();
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        ret["exp"]=Json::Value();
 | 
			
		||||
    }
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Tokens::validateJsonForCreation(const Json::Value &pJson, std::string &err)
 | 
			
		||||
{
 | 
			
		||||
    if(pJson.isMember("id"))
 | 
			
		||||
    {
 | 
			
		||||
        if(!validJsonOfField(0, "id", pJson["id"], err, true))
 | 
			
		||||
            return false;
 | 
			
		||||
    }
 | 
			
		||||
    if(pJson.isMember("owner_id"))
 | 
			
		||||
    {
 | 
			
		||||
        if(!validJsonOfField(1, "owner_id", pJson["owner_id"], err, true))
 | 
			
		||||
            return false;
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        err="The owner_id column cannot be null";
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    if(pJson.isMember("exp"))
 | 
			
		||||
    {
 | 
			
		||||
        if(!validJsonOfField(2, "exp", pJson["exp"], err, true))
 | 
			
		||||
            return false;
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        err="The exp column cannot be null";
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
bool Tokens::validateMasqueradedJsonForCreation(const Json::Value &pJson,
 | 
			
		||||
                                                const std::vector<std::string> &pMasqueradingVector,
 | 
			
		||||
                                                std::string &err)
 | 
			
		||||
{
 | 
			
		||||
    if(pMasqueradingVector.size() != 3)
 | 
			
		||||
    {
 | 
			
		||||
        err = "Bad masquerading vector";
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    try {
 | 
			
		||||
      if(!pMasqueradingVector[0].empty())
 | 
			
		||||
      {
 | 
			
		||||
          if(pJson.isMember(pMasqueradingVector[0]))
 | 
			
		||||
          {
 | 
			
		||||
              if(!validJsonOfField(0, pMasqueradingVector[0], pJson[pMasqueradingVector[0]], err, true))
 | 
			
		||||
                  return false;
 | 
			
		||||
          }
 | 
			
		||||
      }
 | 
			
		||||
      if(!pMasqueradingVector[1].empty())
 | 
			
		||||
      {
 | 
			
		||||
          if(pJson.isMember(pMasqueradingVector[1]))
 | 
			
		||||
          {
 | 
			
		||||
              if(!validJsonOfField(1, pMasqueradingVector[1], pJson[pMasqueradingVector[1]], err, true))
 | 
			
		||||
                  return false;
 | 
			
		||||
          }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            err="The " + pMasqueradingVector[1] + " column cannot be null";
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      if(!pMasqueradingVector[2].empty())
 | 
			
		||||
      {
 | 
			
		||||
          if(pJson.isMember(pMasqueradingVector[2]))
 | 
			
		||||
          {
 | 
			
		||||
              if(!validJsonOfField(2, pMasqueradingVector[2], pJson[pMasqueradingVector[2]], err, true))
 | 
			
		||||
                  return false;
 | 
			
		||||
          }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            err="The " + pMasqueradingVector[2] + " column cannot be null";
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    catch(const Json::LogicError &e)
 | 
			
		||||
    {
 | 
			
		||||
      err = e.what();
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
bool Tokens::validateJsonForUpdate(const Json::Value &pJson, std::string &err)
 | 
			
		||||
{
 | 
			
		||||
    if(pJson.isMember("id"))
 | 
			
		||||
    {
 | 
			
		||||
        if(!validJsonOfField(0, "id", pJson["id"], err, false))
 | 
			
		||||
            return false;
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        err = "The value of primary key must be set in the json object for update";
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    if(pJson.isMember("owner_id"))
 | 
			
		||||
    {
 | 
			
		||||
        if(!validJsonOfField(1, "owner_id", pJson["owner_id"], err, false))
 | 
			
		||||
            return false;
 | 
			
		||||
    }
 | 
			
		||||
    if(pJson.isMember("exp"))
 | 
			
		||||
    {
 | 
			
		||||
        if(!validJsonOfField(2, "exp", pJson["exp"], err, false))
 | 
			
		||||
            return false;
 | 
			
		||||
    }
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
bool Tokens::validateMasqueradedJsonForUpdate(const Json::Value &pJson,
 | 
			
		||||
                                              const std::vector<std::string> &pMasqueradingVector,
 | 
			
		||||
                                              std::string &err)
 | 
			
		||||
{
 | 
			
		||||
    if(pMasqueradingVector.size() != 3)
 | 
			
		||||
    {
 | 
			
		||||
        err = "Bad masquerading vector";
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    try {
 | 
			
		||||
      if(!pMasqueradingVector[0].empty() && pJson.isMember(pMasqueradingVector[0]))
 | 
			
		||||
      {
 | 
			
		||||
          if(!validJsonOfField(0, pMasqueradingVector[0], pJson[pMasqueradingVector[0]], err, false))
 | 
			
		||||
              return false;
 | 
			
		||||
      }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        err = "The value of primary key must be set in the json object for update";
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
      if(!pMasqueradingVector[1].empty() && pJson.isMember(pMasqueradingVector[1]))
 | 
			
		||||
      {
 | 
			
		||||
          if(!validJsonOfField(1, pMasqueradingVector[1], pJson[pMasqueradingVector[1]], err, false))
 | 
			
		||||
              return false;
 | 
			
		||||
      }
 | 
			
		||||
      if(!pMasqueradingVector[2].empty() && pJson.isMember(pMasqueradingVector[2]))
 | 
			
		||||
      {
 | 
			
		||||
          if(!validJsonOfField(2, pMasqueradingVector[2], pJson[pMasqueradingVector[2]], err, false))
 | 
			
		||||
              return false;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    catch(const Json::LogicError &e)
 | 
			
		||||
    {
 | 
			
		||||
      err = e.what();
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
bool Tokens::validJsonOfField(size_t index,
 | 
			
		||||
                              const std::string &fieldName,
 | 
			
		||||
                              const Json::Value &pJson,
 | 
			
		||||
                              std::string &err,
 | 
			
		||||
                              bool isForCreation)
 | 
			
		||||
{
 | 
			
		||||
    switch(index)
 | 
			
		||||
    {
 | 
			
		||||
        case 0:
 | 
			
		||||
            if(pJson.isNull())
 | 
			
		||||
            {
 | 
			
		||||
                err="The " + fieldName + " column cannot be null";
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
            if(isForCreation)
 | 
			
		||||
            {
 | 
			
		||||
                err="The automatic primary key cannot be set";
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
            if(!pJson.isUInt64())
 | 
			
		||||
            {
 | 
			
		||||
                err="Type error in the "+fieldName+" field";
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
            break;
 | 
			
		||||
        case 1:
 | 
			
		||||
            if(pJson.isNull())
 | 
			
		||||
            {
 | 
			
		||||
                err="The " + fieldName + " column cannot be null";
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
            if(!pJson.isUInt64())
 | 
			
		||||
            {
 | 
			
		||||
                err="Type error in the "+fieldName+" field";
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
            break;
 | 
			
		||||
        case 2:
 | 
			
		||||
            if(pJson.isNull())
 | 
			
		||||
            {
 | 
			
		||||
                err="The " + fieldName + " column cannot be null";
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
            if(!pJson.isUInt64())
 | 
			
		||||
            {
 | 
			
		||||
                err="Type error in the "+fieldName+" field";
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
            break;
 | 
			
		||||
        default:
 | 
			
		||||
            err="Internal error in the server";
 | 
			
		||||
            return false;
 | 
			
		||||
            break;
 | 
			
		||||
    }
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										211
									
								
								backend/src/db/model/Tokens.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										211
									
								
								backend/src/db/model/Tokens.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,211 @@
 | 
			
		||||
/**
 | 
			
		||||
 *
 | 
			
		||||
 *  Tokens.h
 | 
			
		||||
 *  DO NOT EDIT. This file is generated by drogon_ctl
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
#include <drogon/orm/Result.h>
 | 
			
		||||
#include <drogon/orm/Row.h>
 | 
			
		||||
#include <drogon/orm/Field.h>
 | 
			
		||||
#include <drogon/orm/SqlBinder.h>
 | 
			
		||||
#include <drogon/orm/Mapper.h>
 | 
			
		||||
#ifdef __cpp_impl_coroutine
 | 
			
		||||
#include <drogon/orm/CoroMapper.h>
 | 
			
		||||
#endif
 | 
			
		||||
#include <trantor/utils/Date.h>
 | 
			
		||||
#include <trantor/utils/Logger.h>
 | 
			
		||||
#include <json/json.h>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include <tuple>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <iostream>
 | 
			
		||||
 | 
			
		||||
namespace drogon
 | 
			
		||||
{
 | 
			
		||||
namespace orm
 | 
			
		||||
{
 | 
			
		||||
class DbClient;
 | 
			
		||||
using DbClientPtr = std::shared_ptr<DbClient>;
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
namespace drogon_model
 | 
			
		||||
{
 | 
			
		||||
namespace sqlite3
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
class Tokens
 | 
			
		||||
{
 | 
			
		||||
  public:
 | 
			
		||||
    struct Cols
 | 
			
		||||
    {
 | 
			
		||||
        static const std::string _id;
 | 
			
		||||
        static const std::string _owner_id;
 | 
			
		||||
        static const std::string _exp;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    const static int primaryKeyNumber;
 | 
			
		||||
    const static std::string tableName;
 | 
			
		||||
    const static bool hasPrimaryKey;
 | 
			
		||||
    const static std::string primaryKeyName;
 | 
			
		||||
    using PrimaryKeyType = uint64_t;
 | 
			
		||||
    const PrimaryKeyType &getPrimaryKey() const;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @brief constructor
 | 
			
		||||
     * @param r One row of records in the SQL query result.
 | 
			
		||||
     * @param indexOffset Set the offset to -1 to access all columns by column names,
 | 
			
		||||
     * otherwise access all columns by offsets.
 | 
			
		||||
     * @note If the SQL is not a style of 'select * from table_name ...' (select all
 | 
			
		||||
     * columns by an asterisk), please set the offset to -1.
 | 
			
		||||
     */
 | 
			
		||||
    explicit Tokens(const drogon::orm::Row &r, const ssize_t indexOffset = 0) noexcept;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @brief constructor
 | 
			
		||||
     * @param pJson The json object to construct a new instance.
 | 
			
		||||
     */
 | 
			
		||||
    explicit Tokens(const Json::Value &pJson) noexcept(false);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @brief constructor
 | 
			
		||||
     * @param pJson The json object to construct a new instance.
 | 
			
		||||
     * @param pMasqueradingVector The aliases of table columns.
 | 
			
		||||
     */
 | 
			
		||||
    Tokens(const Json::Value &pJson, const std::vector<std::string> &pMasqueradingVector) noexcept(false);
 | 
			
		||||
 | 
			
		||||
    Tokens() = default;
 | 
			
		||||
 | 
			
		||||
    void updateByJson(const Json::Value &pJson) noexcept(false);
 | 
			
		||||
    void updateByMasqueradedJson(const Json::Value &pJson,
 | 
			
		||||
                                 const std::vector<std::string> &pMasqueradingVector) noexcept(false);
 | 
			
		||||
    static bool validateJsonForCreation(const Json::Value &pJson, std::string &err);
 | 
			
		||||
    static bool validateMasqueradedJsonForCreation(const Json::Value &,
 | 
			
		||||
                                                const std::vector<std::string> &pMasqueradingVector,
 | 
			
		||||
                                                    std::string &err);
 | 
			
		||||
    static bool validateJsonForUpdate(const Json::Value &pJson, std::string &err);
 | 
			
		||||
    static bool validateMasqueradedJsonForUpdate(const Json::Value &,
 | 
			
		||||
                                          const std::vector<std::string> &pMasqueradingVector,
 | 
			
		||||
                                          std::string &err);
 | 
			
		||||
    static bool validJsonOfField(size_t index,
 | 
			
		||||
                          const std::string &fieldName,
 | 
			
		||||
                          const Json::Value &pJson,
 | 
			
		||||
                          std::string &err,
 | 
			
		||||
                          bool isForCreation);
 | 
			
		||||
 | 
			
		||||
    /**  For column id  */
 | 
			
		||||
    ///Get the value of the column id, returns the default value if the column is null
 | 
			
		||||
    const uint64_t &getValueOfId() const noexcept;
 | 
			
		||||
    ///Return a shared_ptr object pointing to the column const value, or an empty shared_ptr object if the column is null
 | 
			
		||||
    const std::shared_ptr<uint64_t> &getId() const noexcept;
 | 
			
		||||
    ///Set the value of the column id
 | 
			
		||||
    void setId(const uint64_t &pId) noexcept;
 | 
			
		||||
 | 
			
		||||
    /**  For column owner_id  */
 | 
			
		||||
    ///Get the value of the column owner_id, returns the default value if the column is null
 | 
			
		||||
    const uint64_t &getValueOfOwnerId() const noexcept;
 | 
			
		||||
    ///Return a shared_ptr object pointing to the column const value, or an empty shared_ptr object if the column is null
 | 
			
		||||
    const std::shared_ptr<uint64_t> &getOwnerId() const noexcept;
 | 
			
		||||
    ///Set the value of the column owner_id
 | 
			
		||||
    void setOwnerId(const uint64_t &pOwnerId) noexcept;
 | 
			
		||||
 | 
			
		||||
    /**  For column exp  */
 | 
			
		||||
    ///Get the value of the column exp, returns the default value if the column is null
 | 
			
		||||
    const uint64_t &getValueOfExp() const noexcept;
 | 
			
		||||
    ///Return a shared_ptr object pointing to the column const value, or an empty shared_ptr object if the column is null
 | 
			
		||||
    const std::shared_ptr<uint64_t> &getExp() const noexcept;
 | 
			
		||||
    ///Set the value of the column exp
 | 
			
		||||
    void setExp(const uint64_t &pExp) noexcept;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    static size_t getColumnNumber() noexcept {  return 3;  }
 | 
			
		||||
    static const std::string &getColumnName(size_t index) noexcept(false);
 | 
			
		||||
 | 
			
		||||
    Json::Value toJson() const;
 | 
			
		||||
    Json::Value toMasqueradedJson(const std::vector<std::string> &pMasqueradingVector) const;
 | 
			
		||||
    /// Relationship interfaces
 | 
			
		||||
  private:
 | 
			
		||||
    friend drogon::orm::Mapper<Tokens>;
 | 
			
		||||
#ifdef __cpp_impl_coroutine
 | 
			
		||||
    friend drogon::orm::CoroMapper<Tokens>;
 | 
			
		||||
#endif
 | 
			
		||||
    static const std::vector<std::string> &insertColumns() noexcept;
 | 
			
		||||
    void outputArgs(drogon::orm::internal::SqlBinder &binder) const;
 | 
			
		||||
    const std::vector<std::string> updateColumns() const;
 | 
			
		||||
    void updateArgs(drogon::orm::internal::SqlBinder &binder) const;
 | 
			
		||||
    ///For mysql or sqlite3
 | 
			
		||||
    void updateId(const uint64_t id);
 | 
			
		||||
    std::shared_ptr<uint64_t> id_;
 | 
			
		||||
    std::shared_ptr<uint64_t> ownerId_;
 | 
			
		||||
    std::shared_ptr<uint64_t> exp_;
 | 
			
		||||
    struct MetaData
 | 
			
		||||
    {
 | 
			
		||||
        const std::string colName_;
 | 
			
		||||
        const std::string colType_;
 | 
			
		||||
        const std::string colDatabaseType_;
 | 
			
		||||
        const ssize_t colLength_;
 | 
			
		||||
        const bool isAutoVal_;
 | 
			
		||||
        const bool isPrimaryKey_;
 | 
			
		||||
        const bool notNull_;
 | 
			
		||||
    };
 | 
			
		||||
    static const std::vector<MetaData> metaData_;
 | 
			
		||||
    bool dirtyFlag_[3]={ false };
 | 
			
		||||
  public:
 | 
			
		||||
    static const std::string &sqlForFindingByPrimaryKey()
 | 
			
		||||
    {
 | 
			
		||||
        static const std::string sql="select * from " + tableName + " where id = ?";
 | 
			
		||||
        return sql;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static const std::string &sqlForDeletingByPrimaryKey()
 | 
			
		||||
    {
 | 
			
		||||
        static const std::string sql="delete from " + tableName + " where id = ?";
 | 
			
		||||
        return sql;
 | 
			
		||||
    }
 | 
			
		||||
    std::string sqlForInserting(bool &needSelection) const
 | 
			
		||||
    {
 | 
			
		||||
        std::string sql="insert into " + tableName + " (";
 | 
			
		||||
        size_t parametersCount = 0;
 | 
			
		||||
        needSelection = false;
 | 
			
		||||
        if(dirtyFlag_[1])
 | 
			
		||||
        {
 | 
			
		||||
            sql += "owner_id,";
 | 
			
		||||
            ++parametersCount;
 | 
			
		||||
        }
 | 
			
		||||
        if(dirtyFlag_[2])
 | 
			
		||||
        {
 | 
			
		||||
            sql += "exp,";
 | 
			
		||||
            ++parametersCount;
 | 
			
		||||
        }
 | 
			
		||||
        if(parametersCount > 0)
 | 
			
		||||
        {
 | 
			
		||||
            sql[sql.length()-1]=')';
 | 
			
		||||
            sql += " values (";
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
            sql += ") values (";
 | 
			
		||||
 | 
			
		||||
        if(dirtyFlag_[1])
 | 
			
		||||
        {
 | 
			
		||||
            sql.append("?,");
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
        if(dirtyFlag_[2])
 | 
			
		||||
        {
 | 
			
		||||
            sql.append("?,");
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
        if(parametersCount > 0)
 | 
			
		||||
        {
 | 
			
		||||
            sql.resize(sql.length() - 1);
 | 
			
		||||
        }
 | 
			
		||||
        sql.append(1, ')');
 | 
			
		||||
        LOG_TRACE << sql;
 | 
			
		||||
        return sql;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
} // namespace sqlite3
 | 
			
		||||
} // namespace drogon_model
 | 
			
		||||
							
								
								
									
										1762
									
								
								backend/src/db/model/User.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1762
									
								
								backend/src/db/model/User.cc
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										361
									
								
								backend/src/db/model/User.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										361
									
								
								backend/src/db/model/User.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,361 @@
 | 
			
		||||
/**
 | 
			
		||||
 *
 | 
			
		||||
 *  User.h
 | 
			
		||||
 *  DO NOT EDIT. This file is generated by drogon_ctl
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
#include <drogon/orm/Result.h>
 | 
			
		||||
#include <drogon/orm/Row.h>
 | 
			
		||||
#include <drogon/orm/Field.h>
 | 
			
		||||
#include <drogon/orm/SqlBinder.h>
 | 
			
		||||
#include <drogon/orm/Mapper.h>
 | 
			
		||||
#ifdef __cpp_impl_coroutine
 | 
			
		||||
#include <drogon/orm/CoroMapper.h>
 | 
			
		||||
#endif
 | 
			
		||||
#include <trantor/utils/Date.h>
 | 
			
		||||
#include <trantor/utils/Logger.h>
 | 
			
		||||
#include <json/json.h>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include <tuple>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <iostream>
 | 
			
		||||
 | 
			
		||||
namespace drogon
 | 
			
		||||
{
 | 
			
		||||
namespace orm
 | 
			
		||||
{
 | 
			
		||||
class DbClient;
 | 
			
		||||
using DbClientPtr = std::shared_ptr<DbClient>;
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
namespace drogon_model
 | 
			
		||||
{
 | 
			
		||||
namespace sqlite3
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
class User
 | 
			
		||||
{
 | 
			
		||||
  public:
 | 
			
		||||
    struct Cols
 | 
			
		||||
    {
 | 
			
		||||
        static const std::string _id;
 | 
			
		||||
        static const std::string _gitlab;
 | 
			
		||||
        static const std::string _name;
 | 
			
		||||
        static const std::string _password;
 | 
			
		||||
        static const std::string _role;
 | 
			
		||||
        static const std::string _root_id;
 | 
			
		||||
        static const std::string _tfa_type;
 | 
			
		||||
        static const std::string _tfa_secret;
 | 
			
		||||
        static const std::string _gitlab_at;
 | 
			
		||||
        static const std::string _gitlab_rt;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    const static int primaryKeyNumber;
 | 
			
		||||
    const static std::string tableName;
 | 
			
		||||
    const static bool hasPrimaryKey;
 | 
			
		||||
    const static std::string primaryKeyName;
 | 
			
		||||
    using PrimaryKeyType = uint64_t;
 | 
			
		||||
    const PrimaryKeyType &getPrimaryKey() const;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @brief constructor
 | 
			
		||||
     * @param r One row of records in the SQL query result.
 | 
			
		||||
     * @param indexOffset Set the offset to -1 to access all columns by column names,
 | 
			
		||||
     * otherwise access all columns by offsets.
 | 
			
		||||
     * @note If the SQL is not a style of 'select * from table_name ...' (select all
 | 
			
		||||
     * columns by an asterisk), please set the offset to -1.
 | 
			
		||||
     */
 | 
			
		||||
    explicit User(const drogon::orm::Row &r, const ssize_t indexOffset = 0) noexcept;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @brief constructor
 | 
			
		||||
     * @param pJson The json object to construct a new instance.
 | 
			
		||||
     */
 | 
			
		||||
    explicit User(const Json::Value &pJson) noexcept(false);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @brief constructor
 | 
			
		||||
     * @param pJson The json object to construct a new instance.
 | 
			
		||||
     * @param pMasqueradingVector The aliases of table columns.
 | 
			
		||||
     */
 | 
			
		||||
    User(const Json::Value &pJson, const std::vector<std::string> &pMasqueradingVector) noexcept(false);
 | 
			
		||||
 | 
			
		||||
    User() = default;
 | 
			
		||||
 | 
			
		||||
    void updateByJson(const Json::Value &pJson) noexcept(false);
 | 
			
		||||
    void updateByMasqueradedJson(const Json::Value &pJson,
 | 
			
		||||
                                 const std::vector<std::string> &pMasqueradingVector) noexcept(false);
 | 
			
		||||
    static bool validateJsonForCreation(const Json::Value &pJson, std::string &err);
 | 
			
		||||
    static bool validateMasqueradedJsonForCreation(const Json::Value &,
 | 
			
		||||
                                                const std::vector<std::string> &pMasqueradingVector,
 | 
			
		||||
                                                    std::string &err);
 | 
			
		||||
    static bool validateJsonForUpdate(const Json::Value &pJson, std::string &err);
 | 
			
		||||
    static bool validateMasqueradedJsonForUpdate(const Json::Value &,
 | 
			
		||||
                                          const std::vector<std::string> &pMasqueradingVector,
 | 
			
		||||
                                          std::string &err);
 | 
			
		||||
    static bool validJsonOfField(size_t index,
 | 
			
		||||
                          const std::string &fieldName,
 | 
			
		||||
                          const Json::Value &pJson,
 | 
			
		||||
                          std::string &err,
 | 
			
		||||
                          bool isForCreation);
 | 
			
		||||
 | 
			
		||||
    /**  For column id  */
 | 
			
		||||
    ///Get the value of the column id, returns the default value if the column is null
 | 
			
		||||
    const uint64_t &getValueOfId() const noexcept;
 | 
			
		||||
    ///Return a shared_ptr object pointing to the column const value, or an empty shared_ptr object if the column is null
 | 
			
		||||
    const std::shared_ptr<uint64_t> &getId() const noexcept;
 | 
			
		||||
    ///Set the value of the column id
 | 
			
		||||
    void setId(const uint64_t &pId) noexcept;
 | 
			
		||||
 | 
			
		||||
    /**  For column gitlab  */
 | 
			
		||||
    ///Get the value of the column gitlab, returns the default value if the column is null
 | 
			
		||||
    const uint64_t &getValueOfGitlab() const noexcept;
 | 
			
		||||
    ///Return a shared_ptr object pointing to the column const value, or an empty shared_ptr object if the column is null
 | 
			
		||||
    const std::shared_ptr<uint64_t> &getGitlab() const noexcept;
 | 
			
		||||
    ///Set the value of the column gitlab
 | 
			
		||||
    void setGitlab(const uint64_t &pGitlab) noexcept;
 | 
			
		||||
 | 
			
		||||
    /**  For column name  */
 | 
			
		||||
    ///Get the value of the column name, returns the default value if the column is null
 | 
			
		||||
    const std::string &getValueOfName() const noexcept;
 | 
			
		||||
    ///Return a shared_ptr object pointing to the column const value, or an empty shared_ptr object if the column is null
 | 
			
		||||
    const std::shared_ptr<std::string> &getName() const noexcept;
 | 
			
		||||
    ///Set the value of the column name
 | 
			
		||||
    void setName(const std::string &pName) noexcept;
 | 
			
		||||
    void setName(std::string &&pName) noexcept;
 | 
			
		||||
 | 
			
		||||
    /**  For column password  */
 | 
			
		||||
    ///Get the value of the column password, returns the default value if the column is null
 | 
			
		||||
    const std::string &getValueOfPassword() const noexcept;
 | 
			
		||||
    ///Return a shared_ptr object pointing to the column const value, or an empty shared_ptr object if the column is null
 | 
			
		||||
    const std::shared_ptr<std::string> &getPassword() const noexcept;
 | 
			
		||||
    ///Set the value of the column password
 | 
			
		||||
    void setPassword(const std::string &pPassword) noexcept;
 | 
			
		||||
    void setPassword(std::string &&pPassword) noexcept;
 | 
			
		||||
 | 
			
		||||
    /**  For column role  */
 | 
			
		||||
    ///Get the value of the column role, returns the default value if the column is null
 | 
			
		||||
    const uint64_t &getValueOfRole() const noexcept;
 | 
			
		||||
    ///Return a shared_ptr object pointing to the column const value, or an empty shared_ptr object if the column is null
 | 
			
		||||
    const std::shared_ptr<uint64_t> &getRole() const noexcept;
 | 
			
		||||
    ///Set the value of the column role
 | 
			
		||||
    void setRole(const uint64_t &pRole) noexcept;
 | 
			
		||||
 | 
			
		||||
    /**  For column root_id  */
 | 
			
		||||
    ///Get the value of the column root_id, returns the default value if the column is null
 | 
			
		||||
    const uint64_t &getValueOfRootId() const noexcept;
 | 
			
		||||
    ///Return a shared_ptr object pointing to the column const value, or an empty shared_ptr object if the column is null
 | 
			
		||||
    const std::shared_ptr<uint64_t> &getRootId() const noexcept;
 | 
			
		||||
    ///Set the value of the column root_id
 | 
			
		||||
    void setRootId(const uint64_t &pRootId) noexcept;
 | 
			
		||||
 | 
			
		||||
    /**  For column tfa_type  */
 | 
			
		||||
    ///Get the value of the column tfa_type, returns the default value if the column is null
 | 
			
		||||
    const uint64_t &getValueOfTfaType() const noexcept;
 | 
			
		||||
    ///Return a shared_ptr object pointing to the column const value, or an empty shared_ptr object if the column is null
 | 
			
		||||
    const std::shared_ptr<uint64_t> &getTfaType() const noexcept;
 | 
			
		||||
    ///Set the value of the column tfa_type
 | 
			
		||||
    void setTfaType(const uint64_t &pTfaType) noexcept;
 | 
			
		||||
 | 
			
		||||
    /**  For column tfa_secret  */
 | 
			
		||||
    ///Get the value of the column tfa_secret, returns the default value if the column is null
 | 
			
		||||
    const std::vector<char> &getValueOfTfaSecret() const noexcept;
 | 
			
		||||
    ///Return the column value by std::string with binary data
 | 
			
		||||
    std::string getValueOfTfaSecretAsString() const noexcept;
 | 
			
		||||
    ///Return a shared_ptr object pointing to the column const value, or an empty shared_ptr object if the column is null
 | 
			
		||||
    const std::shared_ptr<std::vector<char>> &getTfaSecret() const noexcept;
 | 
			
		||||
    ///Set the value of the column tfa_secret
 | 
			
		||||
    void setTfaSecret(const std::vector<char> &pTfaSecret) noexcept;
 | 
			
		||||
    void setTfaSecret(const std::string &pTfaSecret) noexcept;
 | 
			
		||||
    void setTfaSecretToNull() noexcept;
 | 
			
		||||
 | 
			
		||||
    /**  For column gitlab_at  */
 | 
			
		||||
    ///Get the value of the column gitlab_at, returns the default value if the column is null
 | 
			
		||||
    const std::string &getValueOfGitlabAt() const noexcept;
 | 
			
		||||
    ///Return a shared_ptr object pointing to the column const value, or an empty shared_ptr object if the column is null
 | 
			
		||||
    const std::shared_ptr<std::string> &getGitlabAt() const noexcept;
 | 
			
		||||
    ///Set the value of the column gitlab_at
 | 
			
		||||
    void setGitlabAt(const std::string &pGitlabAt) noexcept;
 | 
			
		||||
    void setGitlabAt(std::string &&pGitlabAt) noexcept;
 | 
			
		||||
    void setGitlabAtToNull() noexcept;
 | 
			
		||||
 | 
			
		||||
    /**  For column gitlab_rt  */
 | 
			
		||||
    ///Get the value of the column gitlab_rt, returns the default value if the column is null
 | 
			
		||||
    const std::string &getValueOfGitlabRt() const noexcept;
 | 
			
		||||
    ///Return a shared_ptr object pointing to the column const value, or an empty shared_ptr object if the column is null
 | 
			
		||||
    const std::shared_ptr<std::string> &getGitlabRt() const noexcept;
 | 
			
		||||
    ///Set the value of the column gitlab_rt
 | 
			
		||||
    void setGitlabRt(const std::string &pGitlabRt) noexcept;
 | 
			
		||||
    void setGitlabRt(std::string &&pGitlabRt) noexcept;
 | 
			
		||||
    void setGitlabRtToNull() noexcept;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    static size_t getColumnNumber() noexcept {  return 10;  }
 | 
			
		||||
    static const std::string &getColumnName(size_t index) noexcept(false);
 | 
			
		||||
 | 
			
		||||
    Json::Value toJson() const;
 | 
			
		||||
    Json::Value toMasqueradedJson(const std::vector<std::string> &pMasqueradingVector) const;
 | 
			
		||||
    /// Relationship interfaces
 | 
			
		||||
  private:
 | 
			
		||||
    friend drogon::orm::Mapper<User>;
 | 
			
		||||
#ifdef __cpp_impl_coroutine
 | 
			
		||||
    friend drogon::orm::CoroMapper<User>;
 | 
			
		||||
#endif
 | 
			
		||||
    static const std::vector<std::string> &insertColumns() noexcept;
 | 
			
		||||
    void outputArgs(drogon::orm::internal::SqlBinder &binder) const;
 | 
			
		||||
    const std::vector<std::string> updateColumns() const;
 | 
			
		||||
    void updateArgs(drogon::orm::internal::SqlBinder &binder) const;
 | 
			
		||||
    ///For mysql or sqlite3
 | 
			
		||||
    void updateId(const uint64_t id);
 | 
			
		||||
    std::shared_ptr<uint64_t> id_;
 | 
			
		||||
    std::shared_ptr<uint64_t> gitlab_;
 | 
			
		||||
    std::shared_ptr<std::string> name_;
 | 
			
		||||
    std::shared_ptr<std::string> password_;
 | 
			
		||||
    std::shared_ptr<uint64_t> role_;
 | 
			
		||||
    std::shared_ptr<uint64_t> rootId_;
 | 
			
		||||
    std::shared_ptr<uint64_t> tfaType_;
 | 
			
		||||
    std::shared_ptr<std::vector<char>> tfaSecret_;
 | 
			
		||||
    std::shared_ptr<std::string> gitlabAt_;
 | 
			
		||||
    std::shared_ptr<std::string> gitlabRt_;
 | 
			
		||||
    struct MetaData
 | 
			
		||||
    {
 | 
			
		||||
        const std::string colName_;
 | 
			
		||||
        const std::string colType_;
 | 
			
		||||
        const std::string colDatabaseType_;
 | 
			
		||||
        const ssize_t colLength_;
 | 
			
		||||
        const bool isAutoVal_;
 | 
			
		||||
        const bool isPrimaryKey_;
 | 
			
		||||
        const bool notNull_;
 | 
			
		||||
    };
 | 
			
		||||
    static const std::vector<MetaData> metaData_;
 | 
			
		||||
    bool dirtyFlag_[10]={ false };
 | 
			
		||||
  public:
 | 
			
		||||
    static const std::string &sqlForFindingByPrimaryKey()
 | 
			
		||||
    {
 | 
			
		||||
        static const std::string sql="select * from " + tableName + " where id = ?";
 | 
			
		||||
        return sql;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static const std::string &sqlForDeletingByPrimaryKey()
 | 
			
		||||
    {
 | 
			
		||||
        static const std::string sql="delete from " + tableName + " where id = ?";
 | 
			
		||||
        return sql;
 | 
			
		||||
    }
 | 
			
		||||
    std::string sqlForInserting(bool &needSelection) const
 | 
			
		||||
    {
 | 
			
		||||
        std::string sql="insert into " + tableName + " (";
 | 
			
		||||
        size_t parametersCount = 0;
 | 
			
		||||
        needSelection = false;
 | 
			
		||||
        if(dirtyFlag_[1])
 | 
			
		||||
        {
 | 
			
		||||
            sql += "gitlab,";
 | 
			
		||||
            ++parametersCount;
 | 
			
		||||
        }
 | 
			
		||||
        if(dirtyFlag_[2])
 | 
			
		||||
        {
 | 
			
		||||
            sql += "name,";
 | 
			
		||||
            ++parametersCount;
 | 
			
		||||
        }
 | 
			
		||||
        if(dirtyFlag_[3])
 | 
			
		||||
        {
 | 
			
		||||
            sql += "password,";
 | 
			
		||||
            ++parametersCount;
 | 
			
		||||
        }
 | 
			
		||||
        if(dirtyFlag_[4])
 | 
			
		||||
        {
 | 
			
		||||
            sql += "role,";
 | 
			
		||||
            ++parametersCount;
 | 
			
		||||
        }
 | 
			
		||||
        if(dirtyFlag_[5])
 | 
			
		||||
        {
 | 
			
		||||
            sql += "root_id,";
 | 
			
		||||
            ++parametersCount;
 | 
			
		||||
        }
 | 
			
		||||
        if(dirtyFlag_[6])
 | 
			
		||||
        {
 | 
			
		||||
            sql += "tfa_type,";
 | 
			
		||||
            ++parametersCount;
 | 
			
		||||
        }
 | 
			
		||||
        if(dirtyFlag_[7])
 | 
			
		||||
        {
 | 
			
		||||
            sql += "tfa_secret,";
 | 
			
		||||
            ++parametersCount;
 | 
			
		||||
        }
 | 
			
		||||
        if(dirtyFlag_[8])
 | 
			
		||||
        {
 | 
			
		||||
            sql += "gitlab_at,";
 | 
			
		||||
            ++parametersCount;
 | 
			
		||||
        }
 | 
			
		||||
        if(dirtyFlag_[9])
 | 
			
		||||
        {
 | 
			
		||||
            sql += "gitlab_rt,";
 | 
			
		||||
            ++parametersCount;
 | 
			
		||||
        }
 | 
			
		||||
        if(parametersCount > 0)
 | 
			
		||||
        {
 | 
			
		||||
            sql[sql.length()-1]=')';
 | 
			
		||||
            sql += " values (";
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
            sql += ") values (";
 | 
			
		||||
 | 
			
		||||
        if(dirtyFlag_[1])
 | 
			
		||||
        {
 | 
			
		||||
            sql.append("?,");
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
        if(dirtyFlag_[2])
 | 
			
		||||
        {
 | 
			
		||||
            sql.append("?,");
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
        if(dirtyFlag_[3])
 | 
			
		||||
        {
 | 
			
		||||
            sql.append("?,");
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
        if(dirtyFlag_[4])
 | 
			
		||||
        {
 | 
			
		||||
            sql.append("?,");
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
        if(dirtyFlag_[5])
 | 
			
		||||
        {
 | 
			
		||||
            sql.append("?,");
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
        if(dirtyFlag_[6])
 | 
			
		||||
        {
 | 
			
		||||
            sql.append("?,");
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
        if(dirtyFlag_[7])
 | 
			
		||||
        {
 | 
			
		||||
            sql.append("?,");
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
        if(dirtyFlag_[8])
 | 
			
		||||
        {
 | 
			
		||||
            sql.append("?,");
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
        if(dirtyFlag_[9])
 | 
			
		||||
        {
 | 
			
		||||
            sql.append("?,");
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
        if(parametersCount > 0)
 | 
			
		||||
        {
 | 
			
		||||
            sql.resize(sql.length() - 1);
 | 
			
		||||
        }
 | 
			
		||||
        sql.append(1, ')');
 | 
			
		||||
        LOG_TRACE << sql;
 | 
			
		||||
        return sql;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
} // namespace sqlite3
 | 
			
		||||
} // namespace drogon_model
 | 
			
		||||
							
								
								
									
										5
									
								
								backend/src/db/model/model.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								backend/src/db/model/model.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
			
		||||
{
 | 
			
		||||
  "rdbms":"sqlite3",
 | 
			
		||||
  "filename":"run/sqlite.db",
 | 
			
		||||
  "tables":[]
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										56
									
								
								backend/src/dto/dto.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								backend/src/dto/dto.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,56 @@
 | 
			
		||||
#ifndef BACKEND_DTO_H
 | 
			
		||||
#define BACKEND_DTO_H
 | 
			
		||||
 | 
			
		||||
#include <drogon/HttpResponse.h>
 | 
			
		||||
#include "db/db.h"
 | 
			
		||||
 | 
			
		||||
namespace dto {
 | 
			
		||||
    template<typename T>
 | 
			
		||||
    std::optional<T> json_get(const Json::Value& j, const std::string& key) {
 | 
			
		||||
        return j.isMember(key)
 | 
			
		||||
            ? std::make_optional(j[key].as<T>())
 | 
			
		||||
            : std::nullopt;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    inline db::User get_user(const drogon::HttpRequestPtr& req) {
 | 
			
		||||
        return req->attributes()->get<db::User>("user");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    inline db::Token get_token(const drogon::HttpRequestPtr& req) {
 | 
			
		||||
        return req->attributes()->get<db::Token>("token");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    namespace Responses {
 | 
			
		||||
        struct GetUsersEntry {
 | 
			
		||||
            GetUsersEntry(int id, bool gitlab, bool tfa, std::string name, db::UserRole role)
 | 
			
		||||
                : id(id), gitlab(gitlab), tfa(tfa), name(std::move(name)), role(role) {}
 | 
			
		||||
            int id;
 | 
			
		||||
            bool gitlab, tfa;
 | 
			
		||||
            std::string name;
 | 
			
		||||
            db::UserRole role;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        drogon::HttpResponsePtr get_error_res(drogon::HttpStatusCode, const std::string &msg);
 | 
			
		||||
        drogon::HttpResponsePtr get_success_res();
 | 
			
		||||
        drogon::HttpResponsePtr get_success_res(Json::Value &);
 | 
			
		||||
 | 
			
		||||
        inline drogon::HttpResponsePtr get_badreq_res(const std::string &msg) { return get_error_res(drogon::HttpStatusCode::k400BadRequest, msg); }
 | 
			
		||||
        inline drogon::HttpResponsePtr get_unauth_res(const std::string &msg) { return get_error_res(drogon::HttpStatusCode::k401Unauthorized, msg); }
 | 
			
		||||
        inline drogon::HttpResponsePtr get_forbdn_res(const std::string &msg) { return get_error_res(drogon::HttpStatusCode::k403Forbidden, msg); }
 | 
			
		||||
 | 
			
		||||
        drogon::HttpResponsePtr get_login_res(const std::string &jwt);
 | 
			
		||||
        drogon::HttpResponsePtr get_tfa_setup_res(const std::string& secret, const std::string& qrcode);
 | 
			
		||||
 | 
			
		||||
        drogon::HttpResponsePtr get_user_info_res(const std::string& name, bool gitlab, bool tfa);
 | 
			
		||||
 | 
			
		||||
        drogon::HttpResponsePtr get_admin_users_res(const std::vector<GetUsersEntry>& users);
 | 
			
		||||
 | 
			
		||||
        drogon::HttpResponsePtr get_root_res(uint64_t root);
 | 
			
		||||
        drogon::HttpResponsePtr get_node_folder_res(uint64_t id, const std::string& name, const std::shared_ptr<uint64_t>& parent, const std::vector<uint64_t>& children);
 | 
			
		||||
        drogon::HttpResponsePtr get_node_file_res(uint64_t id, const std::string& name, const std::shared_ptr<uint64_t>& parent, uint64_t size);
 | 
			
		||||
        drogon::HttpResponsePtr get_path_res(const std::string& path);
 | 
			
		||||
        drogon::HttpResponsePtr get_new_node_res(uint64_t id);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif //BACKEND_DTO_H
 | 
			
		||||
							
								
								
									
										98
									
								
								backend/src/dto/responses.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								backend/src/dto/responses.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,98 @@
 | 
			
		||||
#include "dto.h"
 | 
			
		||||
 | 
			
		||||
namespace dto::Responses {
 | 
			
		||||
    drogon::HttpResponsePtr get_error_res(drogon::HttpStatusCode code, const std::string& msg) {
 | 
			
		||||
        Json::Value json;
 | 
			
		||||
        json["statusCode"] = static_cast<int>(code);
 | 
			
		||||
        json["message"] = msg;
 | 
			
		||||
        auto res = drogon::HttpResponse::newHttpJsonResponse(json);
 | 
			
		||||
        res->setStatusCode(code);
 | 
			
		||||
        return res;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    drogon::HttpResponsePtr get_success_res() {
 | 
			
		||||
        Json::Value json;
 | 
			
		||||
        return get_success_res(json);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    drogon::HttpResponsePtr get_success_res(Json::Value& json) {
 | 
			
		||||
        json["statusCode"] = 200;
 | 
			
		||||
        auto res = drogon::HttpResponse::newHttpJsonResponse(json);
 | 
			
		||||
        res->setStatusCode(drogon::HttpStatusCode::k200OK);
 | 
			
		||||
        return res;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    drogon::HttpResponsePtr get_login_res(const std::string &jwt) {
 | 
			
		||||
        Json::Value json;
 | 
			
		||||
        json["jwt"] = jwt;
 | 
			
		||||
        return get_success_res(json);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    drogon::HttpResponsePtr get_tfa_setup_res(const std::string& secret, const std::string& qrcode) {
 | 
			
		||||
        Json::Value json;
 | 
			
		||||
        json["secret"] = secret;
 | 
			
		||||
        json["qrCode"] = qrcode;
 | 
			
		||||
        return get_success_res(json);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    drogon::HttpResponsePtr get_user_info_res(const std::string &name, bool gitlab, bool tfa) {
 | 
			
		||||
        Json::Value json;
 | 
			
		||||
        json["name"] = name;
 | 
			
		||||
        json["gitlab"] = gitlab;
 | 
			
		||||
        json["tfaEnabled"] = tfa;
 | 
			
		||||
        return get_success_res(json);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    drogon::HttpResponsePtr get_admin_users_res(const std::vector<GetUsersEntry>& users) {
 | 
			
		||||
        Json::Value json;
 | 
			
		||||
        for (const GetUsersEntry& user : users) {
 | 
			
		||||
            Json::Value entry;
 | 
			
		||||
            entry["id"] = user.id;
 | 
			
		||||
            entry["gitlab"] = user.gitlab;
 | 
			
		||||
            entry["name"] = user.name;
 | 
			
		||||
            entry["role"] = user.role;
 | 
			
		||||
            entry["tfaEnabled"] = user.tfa;
 | 
			
		||||
            json["users"].append(entry);
 | 
			
		||||
        }
 | 
			
		||||
        return get_success_res(json);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    drogon::HttpResponsePtr get_root_res(uint64_t root) {
 | 
			
		||||
        Json::Value json;
 | 
			
		||||
        json["rootId"] = root;
 | 
			
		||||
        return get_success_res(json);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    drogon::HttpResponsePtr get_node_folder_res(uint64_t id, const std::string &name, const std::shared_ptr<uint64_t> &parent, const std::vector<uint64_t> &children) {
 | 
			
		||||
        Json::Value json;
 | 
			
		||||
        json["id"] = id;
 | 
			
		||||
        json["name"] = name;
 | 
			
		||||
        json["isFile"] = false;
 | 
			
		||||
        json["parent"] = (parent != nullptr) ? *parent : Json::Value::nullSingleton();
 | 
			
		||||
        for (uint64_t child : children)
 | 
			
		||||
            json["children"].append(child);
 | 
			
		||||
        return get_success_res(json);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    drogon::HttpResponsePtr get_node_file_res(uint64_t id, const std::string &name, const std::shared_ptr<uint64_t> &parent, uint64_t size) {
 | 
			
		||||
        Json::Value json;
 | 
			
		||||
        json["id"] = id;
 | 
			
		||||
        json["name"] = name;
 | 
			
		||||
        json["isFile"] = true;
 | 
			
		||||
        json["parent"] = (parent != nullptr) ? *parent : Json::Value::nullSingleton();
 | 
			
		||||
        json["size"] = size;
 | 
			
		||||
        return get_success_res(json);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    drogon::HttpResponsePtr get_path_res(const std::string& path) {
 | 
			
		||||
        Json::Value json;
 | 
			
		||||
        json["path"] = path;
 | 
			
		||||
        return get_success_res(json);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    drogon::HttpResponsePtr get_new_node_res(uint64_t id) {
 | 
			
		||||
        Json::Value json;
 | 
			
		||||
        json["id"] = id;
 | 
			
		||||
        return get_success_res(json);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										82
									
								
								backend/src/filters/filters.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								backend/src/filters/filters.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,82 @@
 | 
			
		||||
#include "filters.h"
 | 
			
		||||
 | 
			
		||||
#include <drogon/utils/coroutine.h>
 | 
			
		||||
#include <jwt-cpp/traits/kazuho-picojson/traits.h>
 | 
			
		||||
#include <jwt-cpp/jwt.h>
 | 
			
		||||
#include "db/db.h"
 | 
			
		||||
#include "dto/dto.h"
 | 
			
		||||
#include "controllers/controllers.h"
 | 
			
		||||
 | 
			
		||||
void cleanup_tokens(db::MapperToken& mapper) {
 | 
			
		||||
    const uint64_t now = std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch()).count();
 | 
			
		||||
    mapper.deleteBy(
 | 
			
		||||
            db::Criteria(db::Token::Cols::_exp, db::CompareOps::LE, now)
 | 
			
		||||
    );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Login::doFilter(const drogon::HttpRequestPtr& req, drogon::FilterCallback&& cb, drogon::FilterChainCallback&& ccb) {
 | 
			
		||||
    std::string token_str;
 | 
			
		||||
    if (req->path() == "/api/fs/download") {
 | 
			
		||||
        token_str = req->getParameter("jwtToken");
 | 
			
		||||
    } else {
 | 
			
		||||
        std::string auth_header = req->getHeader("Authorization");
 | 
			
		||||
        if (auth_header.empty() || (!auth_header.starts_with("Bearer ")))
 | 
			
		||||
            return cb(dto::Responses::get_unauth_res("Unauthorized"));
 | 
			
		||||
        token_str = auth_header.substr(7);
 | 
			
		||||
    }
 | 
			
		||||
    try {
 | 
			
		||||
        auto token = jwt::decode<jwt::traits::kazuho_picojson>(token_str);
 | 
			
		||||
        jwt::verify<jwt::traits::kazuho_picojson>()
 | 
			
		||||
                .allow_algorithm(jwt::algorithm::hs256{jwt_secret})
 | 
			
		||||
                .verify(token);
 | 
			
		||||
        uint64_t token_id = token.get_payload_claim("jti").as_int();
 | 
			
		||||
        uint64_t user_id = token.get_payload_claim("sub").as_int();
 | 
			
		||||
 | 
			
		||||
        auto db = drogon::app().getDbClient();
 | 
			
		||||
 | 
			
		||||
        db::MapperUser user_mapper(db);
 | 
			
		||||
        db::MapperToken token_mapper(db);
 | 
			
		||||
 | 
			
		||||
        cleanup_tokens(token_mapper);
 | 
			
		||||
 | 
			
		||||
        db::Token db_token = token_mapper.findByPrimaryKey(token_id);
 | 
			
		||||
        db::User db_user = user_mapper.findByPrimaryKey(db_token.getValueOfOwnerId());
 | 
			
		||||
 | 
			
		||||
        if (db_user.getValueOfId() != user_id) throw std::exception();
 | 
			
		||||
        if (db::User_getEnumRole(db_user) == db::UserRole::DISABLED) throw std::exception();
 | 
			
		||||
 | 
			
		||||
        if (db_user.getValueOfGitlab() != 0) {
 | 
			
		||||
            auto info = api::auth::get_gitlab_user(db_user.getValueOfGitlabAt());
 | 
			
		||||
            if (!info.has_value()) {
 | 
			
		||||
                auto tokens = api::auth::get_gitlab_tokens(req, db_user.getValueOfGitlabRt(), true);
 | 
			
		||||
                info = api::auth::get_gitlab_user(tokens->at);
 | 
			
		||||
                if (!tokens.has_value() || !info.has_value()) {
 | 
			
		||||
                    api::auth::revoke_all(db_user);
 | 
			
		||||
                    throw std::exception();
 | 
			
		||||
                }
 | 
			
		||||
                db_user.setGitlabAt(tokens->at);
 | 
			
		||||
                db_user.setGitlabRt(tokens->rt);
 | 
			
		||||
                user_mapper.update(db_user);
 | 
			
		||||
            }
 | 
			
		||||
            if (info->name != db_user.getValueOfName()) {
 | 
			
		||||
                api::auth::revoke_all(db_user);
 | 
			
		||||
                throw std::exception();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        req->attributes()->insert("token", db_token);
 | 
			
		||||
        req->attributes()->insert("user", db_user);
 | 
			
		||||
        ccb();
 | 
			
		||||
    } catch (const std::exception&) {
 | 
			
		||||
        cb(dto::Responses::get_unauth_res("Unauthorized"));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Admin::doFilter(const drogon::HttpRequestPtr& req, drogon::FilterCallback&& cb, drogon::FilterChainCallback&& ccb) {
 | 
			
		||||
    db::User user = dto::get_user(req);
 | 
			
		||||
 | 
			
		||||
    if (db::User_getEnumRole(user) != db::UserRole::ADMIN)
 | 
			
		||||
        cb(dto::Responses::get_forbdn_res("Forbidden"));
 | 
			
		||||
    else
 | 
			
		||||
        ccb();
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										14
									
								
								backend/src/filters/filters.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								backend/src/filters/filters.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
			
		||||
#ifndef BACKEND_FILTERS_H
 | 
			
		||||
#define BACKEND_FILTERS_H
 | 
			
		||||
 | 
			
		||||
#include <drogon/HttpFilter.h>
 | 
			
		||||
 | 
			
		||||
struct Login : public drogon::HttpFilter<Login> {
 | 
			
		||||
    void doFilter(const drogon::HttpRequestPtr&, drogon::FilterCallback&&, drogon::FilterChainCallback&&) override;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct Admin : public drogon::HttpFilter<Admin> {
 | 
			
		||||
    void doFilter(const drogon::HttpRequestPtr&, drogon::FilterCallback&&, drogon::FilterChainCallback&&) override;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif //BACKEND_FILTERS_H
 | 
			
		||||
							
								
								
									
										112
									
								
								backend/src/main.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								backend/src/main.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,112 @@
 | 
			
		||||
#include <filesystem>
 | 
			
		||||
 | 
			
		||||
#include <drogon/drogon.h>
 | 
			
		||||
#include <curl/curl.h>
 | 
			
		||||
 | 
			
		||||
#include "dto/dto.h"
 | 
			
		||||
 | 
			
		||||
void cleanup() {
 | 
			
		||||
    std::cout << "Stopping..." << std::endl;
 | 
			
		||||
    drogon::app().quit();
 | 
			
		||||
    std::cout << "Cleanup up uploads...";
 | 
			
		||||
    std::filesystem::remove_all("uploads");
 | 
			
		||||
    std::cout << " [Done]" << std::endl;
 | 
			
		||||
    std::cout << "Goodbye!" << std::endl;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int main() {
 | 
			
		||||
    std::cout << "Setting up..." << std::endl;
 | 
			
		||||
    std::cout << "Initializing curl..." << std::flush;
 | 
			
		||||
    curl_global_init(CURL_GLOBAL_ALL);
 | 
			
		||||
    std::cout << " [Done]" << std::endl;
 | 
			
		||||
    if (!std::filesystem::exists("files")) {
 | 
			
		||||
        std::cout << "Creating files..." << std::flush;
 | 
			
		||||
        std::filesystem::create_directory("files");
 | 
			
		||||
        std::cout << " [Done]" << std::endl;
 | 
			
		||||
    }
 | 
			
		||||
    if (!std::filesystem::exists("logs")) {
 | 
			
		||||
        std::cout << "Creating logs..." << std::flush;
 | 
			
		||||
        std::filesystem::create_directory("logs");
 | 
			
		||||
        std::cout << " [Done]" << std::endl;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    auto* loop = drogon::app().getLoop();
 | 
			
		||||
    loop->queueInLoop([]{
 | 
			
		||||
        std::cout << "Starting..." << std::endl;
 | 
			
		||||
        std::cout << "Creating db tables..." << std::flush;
 | 
			
		||||
        auto db = drogon::app().getDbClient();
 | 
			
		||||
        db->execSqlSync("CREATE TABLE IF NOT EXISTS 'tokens' (\n"
 | 
			
		||||
                        "  'id' INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,\n"
 | 
			
		||||
                        "  'owner_id' INTEGER NOT NULL,\n"
 | 
			
		||||
                        "  'exp' INTEGER NOT NULL\n"
 | 
			
		||||
                        ")");
 | 
			
		||||
        db->execSqlSync("CREATE TABLE IF NOT EXISTS 'user' (\n"
 | 
			
		||||
                        "  'id' INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,\n"
 | 
			
		||||
                        "  'gitlab' INTEGER NOT NULL,\n"
 | 
			
		||||
                        "  'name' TEXT NOT NULL,\n"
 | 
			
		||||
                        "  'password' TEXT NOT NULL,\n"
 | 
			
		||||
                        "  'role' INTEGER NOT NULL,\n"
 | 
			
		||||
                        "  'root_id' INTEGER NOT NULL,\n"
 | 
			
		||||
                        "  'tfa_type' INTEGER NOT NULL,\n"
 | 
			
		||||
                        "  'tfa_secret' BLOB,\n"
 | 
			
		||||
                        "  'gitlab_at' TEXT,\n"
 | 
			
		||||
                        "  'gitlab_rt' TEXT\n"
 | 
			
		||||
                        ")");
 | 
			
		||||
        db->execSqlSync("CREATE TABLE IF NOT EXISTS 'inode' (\n"
 | 
			
		||||
                        "  'id' INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,\n"
 | 
			
		||||
                        "  'is_file' INTEGER NOT NULL,\n"
 | 
			
		||||
                        "  'name' TEXT,\n"
 | 
			
		||||
                        "  'parent_id' INTEGER,\n"
 | 
			
		||||
                        "  'owner_id' INTEGER NOT NULL,\n"
 | 
			
		||||
                        "  'size' INTEGER\n"
 | 
			
		||||
                        ")");
 | 
			
		||||
        std::cout << " [Done]" << std::endl;
 | 
			
		||||
        std::cout << "Started!" << std::endl;
 | 
			
		||||
        std::cout << "Registered paths: " << std::endl;
 | 
			
		||||
        auto handlers = drogon::app().getHandlersInfo();
 | 
			
		||||
        for (const auto& handler : handlers) {
 | 
			
		||||
            std::cout << "  ";
 | 
			
		||||
            if (std::get<1>(handler) == drogon::HttpMethod::Post) std::cout << "POST ";
 | 
			
		||||
            else std::cout << "GET  ";
 | 
			
		||||
            std::string func = std::get<2>(handler).substr(16);
 | 
			
		||||
            func.resize(30, ' ');
 | 
			
		||||
            std::cout << '[' << func << "] ";
 | 
			
		||||
            std::cout << std::get<0>(handler) << std::endl;
 | 
			
		||||
        }
 | 
			
		||||
        std::cout << "Listening on:" << std::endl;
 | 
			
		||||
        auto listeners = drogon::app().getListeners();
 | 
			
		||||
        for (const auto& listener : listeners) {
 | 
			
		||||
            std::cout << "  " << listener.toIpPort() << std::endl;
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    Json::Value access_logger;
 | 
			
		||||
    access_logger["name"] = "drogon::plugin::AccessLogger";
 | 
			
		||||
 | 
			
		||||
    Json::Value config;
 | 
			
		||||
    config["plugins"].append(access_logger);
 | 
			
		||||
 | 
			
		||||
    drogon::app()
 | 
			
		||||
            .setClientMaxBodySize(1024L * 1024L * 1024L * 1024L) // 1 TB
 | 
			
		||||
 | 
			
		||||
            .loadConfigJson(config)
 | 
			
		||||
 | 
			
		||||
            .createDbClient("sqlite3", "", 0, "", "", "", 1, "sqlite.db")
 | 
			
		||||
 | 
			
		||||
            .setCustom404Page(drogon::HttpResponse::newFileResponse("./static/index.html"), false)
 | 
			
		||||
            .setDocumentRoot("./static")
 | 
			
		||||
            .setBrStatic(true)
 | 
			
		||||
            .setStaticFilesCacheTime(0)
 | 
			
		||||
 | 
			
		||||
            .setLogPath("./logs")
 | 
			
		||||
            .setLogLevel(trantor::Logger::LogLevel::kDebug)
 | 
			
		||||
 | 
			
		||||
            .setIntSignalHandler(cleanup)
 | 
			
		||||
            .setTermSignalHandler(cleanup)
 | 
			
		||||
 | 
			
		||||
            .addListener("0.0.0.0", 1234)
 | 
			
		||||
            .setThreadNum(2);
 | 
			
		||||
    std::cout << "Setup done!" << std::endl;
 | 
			
		||||
 | 
			
		||||
    drogon::app().run();
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user