Api updated. done everything except for system message sending, user registration and any testing
This commit is contained in:
parent
807f0d0eab
commit
925229bbda
1
.gitignore
vendored
1
.gitignore
vendored
@ -16,3 +16,4 @@ iu9-ca-web-chat.db
|
||||
log/
|
||||
core
|
||||
|
||||
config/example.json
|
29
assets/HypertextPages/chat-members.nytl.html
Normal file
29
assets/HypertextPages/chat-members.nytl.html
Normal file
@ -0,0 +1,29 @@
|
||||
{% ELDEF main JSON pres JSON userinfo JSON openedchat JSON initial_chatUpdResp %}
|
||||
<!DOCTYPE html>
|
||||
<html lang="ru">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Веб-Чат Members</title>
|
||||
<link rel="stylesheet" href="/assets/css/chat.css">
|
||||
</head>
|
||||
<body>
|
||||
{% PUT chat.pass pres userinfo openedchat initial_chatUpdResp %}
|
||||
<!--TODO: ADD SOMETHING WRITE SOMETHING AAAAAA -->
|
||||
<div class="overlay" id="overlay">
|
||||
<div class="members-list" id="members-list">
|
||||
<div class="members-list-header">
|
||||
<span class="close" onclick="closeMembersList()">×</span>
|
||||
<h2 class="all-members">Все участники</h2>
|
||||
</div>
|
||||
<div class="members-list-body">
|
||||
<ul id="members-list-body">
|
||||
<!-- Список участников будет добавлен динамически -->
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="/assets/js/chat-members.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
{% ENDELDEF %}
|
@ -1,4 +1,13 @@
|
||||
{% ELDEF main JSON pres JSON userinfo %}
|
||||
{% ELDEF pass JSON pres JSON userinfo JSON openedchat JSON initial_chatUpdResp %}
|
||||
<script>
|
||||
let pres = {% PUT jsinsert pres %};
|
||||
let userinfo = {% PUT jsinsert userinfo %};
|
||||
let openedchat = {% PUT jsinsert openedchat %};
|
||||
let initial_chatUpdResp = {% PUT jsinsert initial_chatUpdResp %};
|
||||
</script>
|
||||
{% ENDELDEF %}
|
||||
|
||||
{% ELDEF main JSON pres JSON userinfo JSON openedchat JSON initial_chatUpdResp %}
|
||||
<!DOCTYPE html>
|
||||
<html lang="ru">
|
||||
<head>
|
||||
@ -8,6 +17,8 @@
|
||||
<link rel="stylesheet" href="/assets/css/chat.css">
|
||||
</head>
|
||||
<body>
|
||||
{% PUT chat.pass pres userinfo openedchat initial_chatUpdResp %}
|
||||
<!-- TODO AAAAA-->
|
||||
<div class="chat-container">
|
||||
<div class="chat-header">
|
||||
<span class="room-name">Веб чат</span>
|
||||
@ -21,19 +32,6 @@
|
||||
<button class="chat-send-button" onclick="sendMessage()">Отправить</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="overlay" id="overlay">
|
||||
<div class="members-list" id="members-list">
|
||||
<div class="members-list-header">
|
||||
<span class="close" onclick="closeMembersList()">×</span>
|
||||
<h2 class="all-members">Все участники</h2>
|
||||
</div>
|
||||
<div class="members-list-body">
|
||||
<ul id="members-list-body">
|
||||
<!-- Список участников будет добавлен динамически -->
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="/assets/js/chat.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
42
assets/HypertextPages/edit-profile.nytl.html
Normal file
42
assets/HypertextPages/edit-profile.nytl.html
Normal file
@ -0,0 +1,42 @@
|
||||
{% ELDEF main JSON pres JSON userprofile JSON errors %}
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<link rel="stylesheet" href="/assets/css/profile.css">
|
||||
<title>Профиль</title>
|
||||
</head>
|
||||
<body>
|
||||
<div class="main-container">
|
||||
{% FOR error IN errors %}
|
||||
<div>
|
||||
<p>{% WRITE error.text %}</p>
|
||||
</div>
|
||||
{% ENDFOR %}
|
||||
<div class="profile-header">
|
||||
<h1>Редактирование профиля</h1>
|
||||
</div>
|
||||
<form method="post" action="/user/{% WRITE userprofile.nickname %}">
|
||||
<div class="columns">
|
||||
<div class="column">
|
||||
<p>{% WRITE userprofile.name %} ( {% WRITE userprofile.nickname %} )</p>
|
||||
<label for="name"> Изменить имя </label>
|
||||
<input type="text" name="name" id="name">
|
||||
<br>
|
||||
<label for="password"> Изменить пароль </label>
|
||||
<input type="password" name="password" id="password">
|
||||
<br>
|
||||
</div>
|
||||
</div>
|
||||
<div class="additional-info">
|
||||
<p>О себе</p>
|
||||
<p>{% WRITE userprofile.bio %}</p><br>
|
||||
<label for="bio">Изменить</label>
|
||||
<textarea name="bio" id="bio"></textarea>
|
||||
</div>
|
||||
<button class="save" type="submit">Сохранить изменения</button>
|
||||
</form>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
{% ENDELDEF%}
|
10
assets/HypertextPages/err-404.html
Normal file
10
assets/HypertextPages/err-404.html
Normal file
@ -0,0 +1,10 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Not found</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Page not found</h1>
|
||||
</body>
|
||||
</html>
|
@ -1,4 +1,4 @@
|
||||
{% ELDEF main JSON pres JSON userinfo %}
|
||||
{% ELDEF main JSON pres JSON userinfo JSON initial_chatListUpdResp %}
|
||||
<!DOCTYPE html>
|
||||
<html lang="{% WRITE pres.lang %}">
|
||||
<head>
|
||||
@ -8,7 +8,11 @@
|
||||
<link rel="stylesheet" href="/assets/css/list-rooms.css">
|
||||
</head>
|
||||
<body>
|
||||
{% PUT pass-pres-userinfo pres userinfo %}
|
||||
<script>
|
||||
let pres = {% PUT jsinsert pres %};
|
||||
let userinfo = {% PUT jsinsert userinfo %};
|
||||
let initial_chatListUpdResp = {% PUT jsinsert initial_chatListUpdResp %};
|
||||
</script>
|
||||
<div class="container">
|
||||
<h1 style="color: white;">Выберите Чат-Комнату</h1>
|
||||
<ul class="room-list">
|
||||
|
@ -9,10 +9,9 @@
|
||||
</head>
|
||||
|
||||
<body>
|
||||
{% PUT pass-pres-userinfo pres userinfo %}
|
||||
{% FOR msg IN errors %}
|
||||
<div class="error-msg">
|
||||
{% WRITE msg %}
|
||||
{% WRITE msg.text %}
|
||||
</div>
|
||||
{% ENDFOR %}
|
||||
<div class="form-container">
|
||||
|
@ -1,6 +0,0 @@
|
||||
{% ELDEF main JSON pres JSON userinfo %}
|
||||
<script>
|
||||
let pres = {% PUT jsinsert pres %};
|
||||
let userinfo = {% PUT jsinsert userinfo %};
|
||||
</script>
|
||||
{% ENDELDEF %}
|
@ -1,39 +0,0 @@
|
||||
{% ELDEF main JSON pres JSON userinfo %}
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<link rel="stylesheet" href="/assets/css/profile.css">
|
||||
<title>Профиль</title>
|
||||
</head>
|
||||
<body>
|
||||
<div class="main-container">
|
||||
<div class="profile-header">
|
||||
<h1 style="color: white; text-align: center;">Профиль пользователя</h1>
|
||||
<a class="return" href="chat.nytl.html">Назад</a>
|
||||
</div>
|
||||
<form>
|
||||
<div class="columns">
|
||||
<div class="column">
|
||||
<img class="avatar" src="/assets/img/empty_avatar.png" id="avatar" height="200" width="200"><br>
|
||||
<input type="file" id="fileInput" style="display:none">
|
||||
<button class="add" type="button" onclick="document.getElementById('fileInput').click();">Изменить фото</button><br>
|
||||
</div>
|
||||
<div class="column">
|
||||
<input type="text" name="username" placeholder = "Имя пользователя" value="Some Name" id="username"><br>
|
||||
<input type="text" name="login" placeholder="Логин" value="some_login123" id="login" readonly><br>
|
||||
</div>
|
||||
</div>
|
||||
<h3 style="color:#007bb5;">О себе</h3>
|
||||
<div class="additional-info">
|
||||
<textarea name="bio" placeholder="Напишите о себе..." id="bio"></textarea>
|
||||
</div>
|
||||
<button class="save" type="submit">Сохранить изменения</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<script src="/assets/js/list-rooms.js"> </script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
{% ENDELDEF%}
|
@ -1,27 +0,0 @@
|
||||
{% ELDEF main JSON pres JSON userinfo %}
|
||||
<!DOCTYPE html>
|
||||
<html lang="ru">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Страница Регистрации</title>
|
||||
<link rel="stylesheet" href="/assets/css/registration.css">
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="form-container">
|
||||
<h1 class="hide-cursor no-select">Вход</h1>
|
||||
<form action="assets/html/list-rooms.html" method="post">
|
||||
<input type="text" name="username" placeholder="Имя пользователя" id="username"><br>
|
||||
<input type="text" name="login" placeholder="Логин" id="login"><br>
|
||||
<input type="password" name="password" placeholder="Пароль" id="password"><br>
|
||||
<button type="submit" class="hide-cursor no-select">Зарегистрироваться</button>
|
||||
<div id="error"></div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<script src="assets/js/registration.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
{% ENDELDEF %}
|
26
assets/HypertextPages/view-profile.nytl.html
Normal file
26
assets/HypertextPages/view-profile.nytl.html
Normal file
@ -0,0 +1,26 @@
|
||||
{% ELDEF main JSON pres JSON userprofile %}
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<link rel="stylesheet" href="/assets/css/profile.css">
|
||||
<title>Профиль</title>
|
||||
</head>
|
||||
<body>
|
||||
<div class="main-container">
|
||||
<div class="profile-header">
|
||||
<h1>Профиль пользователя</h1>
|
||||
</div>
|
||||
<div class="columns">
|
||||
<div class="column">
|
||||
<p>{% WRITE userprofile.name %} ( {% WRITE userprofile.nickname %} )</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="additional-info">
|
||||
<p>О себе</p>
|
||||
<p>{% WRITE userprofile.bio %}</p><br>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
{% ENDELDEF%}
|
Binary file not shown.
Before Width: | Height: | Size: 81 KiB |
BIN
assets/img/logo0.png
Normal file
BIN
assets/img/logo0.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.7 KiB |
0
assets/js/chat-members.js
Normal file
0
assets/js/chat-members.js
Normal file
@ -1,10 +0,0 @@
|
||||
document.getElementById('fileInput').addEventListener('change', function(event) {
|
||||
const file = event.target.files[0];
|
||||
if (file) {
|
||||
const reader = new FileReader();
|
||||
reader.onload = function(e) {
|
||||
document.getElementById('avatar').src = e.target.result;
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
});
|
@ -149,23 +149,8 @@ struct CAWebChat {
|
||||
"login_cookie.cpp",
|
||||
"backend_logic/server_data_interact.cpp",
|
||||
"backend_logic/client_server_interact.cpp",
|
||||
"backend_logic/when_list_rooms.cpp",
|
||||
"backend_logic/when_login.cpp",
|
||||
"backend_logic/when_chat.cpp",
|
||||
"backend_logic/when_user.cpp",
|
||||
"backend_logic/api_pollevents.cpp",
|
||||
"backend_logic/api_getchatlist.cpp",
|
||||
"backend_logic/api_getchatinfo.cpp",
|
||||
"backend_logic/api_getchatmemberlist.cpp",
|
||||
"backend_logic/api_getuserinfo.cpp",
|
||||
"backend_logic/api_getmessageinfo.cpp",
|
||||
"backend_logic/api_getmessageneighbours.cpp",
|
||||
"backend_logic/api_sendmessage.cpp",
|
||||
"backend_logic/api_deletemessage.cpp",
|
||||
"backend_logic/api_addmembertochat.cpp",
|
||||
"backend_logic/api_removememberfromchat.cpp",
|
||||
"backend_logic/api_createchat.cpp",
|
||||
"backend_logic/api_removechat.cpp",
|
||||
|
||||
"backend_logic/polling.cpp",
|
||||
};
|
||||
for (std::string& u: T.units)
|
||||
u = "web_chat/iu9_ca_web_chat_lib/" + u;
|
||||
|
0
config/default.json
Normal file
0
config/default.json
Normal file
@ -14,7 +14,9 @@
|
||||
"name-of-room": "Название комнаты",
|
||||
"create-room": "Создать комнату",
|
||||
|
||||
"incorrect-nickname-or-password": "Неправильный никнейм или пароль"
|
||||
"incorrect-nickname-or-password": "Неправильный никнейм или пароль",
|
||||
|
||||
"incorrect-profile-data": "Неправильно заполнены поля профиля"
|
||||
},
|
||||
"ask" : {
|
||||
"select-chat-room": "Выберете чат комнату"
|
||||
@ -29,7 +31,7 @@
|
||||
},
|
||||
"assets": "./assets",
|
||||
"database": {
|
||||
"type": "sqlite",
|
||||
"type": "sqlite3",
|
||||
"file": "./iu9-ca-web-chat.db"
|
||||
},
|
||||
"limits": {
|
||||
|
@ -258,8 +258,8 @@ namespace een9 {
|
||||
}
|
||||
errno = 0;
|
||||
ret = poll(pollfds.data(), Nip, params.mainloop_recheck_interval_us);
|
||||
if (ret != 0) {
|
||||
printf("poll() error :> %d\n", errno);
|
||||
if (ret != 0 && errno != 0) {
|
||||
printf("poll() error :> %s\n", een9::prettyprint_errno("").c_str());
|
||||
}
|
||||
ASSERT_on_iret(ret, "poll()");
|
||||
for (size_t i = 0; i < Nip; i++) {
|
||||
|
@ -18,7 +18,14 @@ int main(int argc, char** argv) {
|
||||
een9::readFile(config_file, config_text);
|
||||
const json::JSON config = json::parse_str_flawless(config_text);
|
||||
|
||||
std::string answer2 = templater.render("login", {&config["presentation"].g()});
|
||||
json::JSON userprofile;
|
||||
userprofile["uid"].asInteger() = json::Integer(0l);
|
||||
userprofile["name"].asString() = "radasdasdasdadsdasd";
|
||||
userprofile["nickname"].asString() = "root";
|
||||
userprofile["bio"].asString() = "Your mother";
|
||||
json::JSON errors;
|
||||
errors = json::JSON(json::array);
|
||||
std::string answer2 = templater.render("edit-profile", {&config["presentation"], &userprofile, &errors});
|
||||
printf("%s\n<a><f><t><e><r><><l><f>\n", answer2.c_str());
|
||||
|
||||
return 0;
|
||||
|
@ -178,7 +178,7 @@ namespace nytl {
|
||||
}
|
||||
ASSERT(nm == "EL", "Type of argument variable is either JSON or EL(...signature)")
|
||||
skip(ctx, '(');
|
||||
result = json::JSON(json::array);
|
||||
result.asArray();
|
||||
assert(result.isArray());
|
||||
}
|
||||
skipWhitespace(ctx);
|
||||
@ -220,16 +220,16 @@ namespace nytl {
|
||||
ASSERT(!first.empty(), "Expression should start with 'root' name of global package or local variable");
|
||||
ASSERT(first != "_", "_ ??? ARE YOU KIDDING???");
|
||||
if (local_var_names.count(first) == 1) {
|
||||
result["V"] = json::JSON(json::Integer((int64_t)local_var_names.at(first)));
|
||||
result["V"].asInteger() = json::Integer((int64_t)local_var_names.at(first));
|
||||
} else {
|
||||
result["V"] = json::JSON(first);
|
||||
result["V"].asString() = first;
|
||||
}
|
||||
result["C"] = json::JSON(json::array);
|
||||
result["C"].asArray();
|
||||
} else {
|
||||
skipWhitespace(ctx);
|
||||
skip(ctx, ']');
|
||||
}
|
||||
std::vector<json::JSON>& chain = result["C"].g().asArray();
|
||||
std::vector<json::JSON>& chain = result["C"].asArray();
|
||||
while (true) {
|
||||
if (peep(ctx) == '.') {
|
||||
skip(ctx, '.');
|
||||
|
@ -56,18 +56,18 @@ namespace nytl {
|
||||
descend(*(temp_ret.JSON_subval));
|
||||
} else {
|
||||
assert(expr.isDictionary());
|
||||
const json::JSON& val = expr["V"].g();
|
||||
const json::JSON& val = expr["V"];
|
||||
if (val.isInteger()) {
|
||||
size_t lv_ind = val.asInteger().get_int();
|
||||
assert(lv_ind < local_vars.size());
|
||||
result = local_vars[lv_ind];
|
||||
} else if (val.isString()) {
|
||||
std::string cur_el_name_str = expr["V"].g().asString();
|
||||
std::string cur_el_name_str = expr["V"].asString();
|
||||
result = LocalVarValue{false, cur_el_name_str, NULL};
|
||||
} else
|
||||
assert(false);
|
||||
}
|
||||
const std::vector<json::JSON>& chain = expr["C"].g().asArray();
|
||||
const std::vector<json::JSON>& chain = expr["C"].asArray();
|
||||
while (true) {
|
||||
if (chain_el >= chain.size())
|
||||
return NULL;
|
||||
@ -211,7 +211,8 @@ namespace nytl {
|
||||
uptr<RFrame> RFrame_OverParts::toMe(bool returned, const global_elem_set_t &elem_ns, Ditch &result,
|
||||
const std::function<std::string(std::string)> &escape) {
|
||||
if (!returned)
|
||||
ASSERT(elem_ns.count(name) == 1, "No such element");
|
||||
if (elem_ns.count(name) != 1)
|
||||
THROW("No such element");
|
||||
const Element& el = elem_ns.at(name);
|
||||
if (!returned) {
|
||||
/* Continue to do checks */
|
||||
|
@ -0,0 +1,30 @@
|
||||
#include "server_data_interact.h"
|
||||
#include <engine_engine_number_9/baza_throw.h>
|
||||
#include <engine_engine_number_9/baza.h>
|
||||
#include "../str_fields.h"
|
||||
|
||||
namespace iu9cawebchat {
|
||||
std::string admin_control_procedure(SqliteConnection& conn, const std::string& req, bool& termination) {
|
||||
if (req == "hello") {
|
||||
return ":0 omg! hiii!! Hewwou :3 !!!!\n";
|
||||
}
|
||||
if (req == "8") {
|
||||
termination = true;
|
||||
return "Bye\n";
|
||||
}
|
||||
std::string updaterootpw_pref = "updaterootpw";
|
||||
if (een9::beginsWith(req, "updaterootpw")) {
|
||||
size_t nid = updaterootpw_pref.size();
|
||||
if (nid >= req.size() || !isSPACE(req[nid]))
|
||||
return "Bad command syntax. Missing whitespace\n";
|
||||
std::string new_password = req.substr(nid + 1);
|
||||
if (!check_password(new_password))
|
||||
een9_THROW("Bad password");
|
||||
sqlite_nooutput(conn,
|
||||
"UPDATE `user` SET `password` = ?1 WHERE `id` = 0 ",
|
||||
{}, {{1, new_password}});
|
||||
return "Successul update\n";
|
||||
}
|
||||
return "Incorrect command\n";
|
||||
}
|
||||
}
|
@ -1,15 +1,48 @@
|
||||
#include "server_data_interact.h"
|
||||
#include <engine_engine_number_9/baza_throw.h>
|
||||
#include <assert.h>
|
||||
|
||||
namespace iu9cawebchat {
|
||||
void make_her_a_member_of_the_midnight_crew(SqliteConnection& conn, int64_t chatId, int64_t alienUserId, int64_t role) {
|
||||
assert(role != user_chat_role_deleted);
|
||||
int64_t chat_HistoryId_BEFORE_EV = get_current_history_id_of_chat(conn, chatId);
|
||||
int64_t alien_chatlist_HistoryId_BEFORE_EV = get_current_history_id_of_user_chatList(conn, alienUserId);
|
||||
sqlite_nooutput(conn,
|
||||
"INSERT INTO `user_chat_membership` (`userId`, `chatId`, `user_chatList_IncHistoryId`,"
|
||||
"`chat_IncHistoryId`, `role`) VALUES (?1, ?2, ?3, ?4, ?5)",
|
||||
{{1, alienUserId}, {2, chatId}, {3, alien_chatlist_HistoryId_BEFORE_EV + 1},
|
||||
{4, chat_HistoryId_BEFORE_EV + 1}, {5, role}}, {});
|
||||
|
||||
sqlite_nooutput(conn,
|
||||
"UPDATE `chat` SET `it_HistoryId` = ?1 WHERE `id` = ?2", {{1, chat_HistoryId_BEFORE_EV + 1},
|
||||
{2, chatId}}, {});
|
||||
|
||||
sqlite_nooutput(conn,
|
||||
"UPDATE `user` SET `chatList_HistoryId` = ?1 WHERE `id` = ?2",
|
||||
{{1, alien_chatlist_HistoryId_BEFORE_EV + 1}, {2, alienUserId}}, {});
|
||||
}
|
||||
|
||||
json::JSON internalapi_addMemberToChat(SqliteConnection& conn, int64_t uid, const json::JSON& Sent) {
|
||||
int64_t chatId = Sent["chatId"].g().asInteger().get_int();
|
||||
int64_t chatId = Sent["chatUpdReq"]["chatId"].asInteger().get_int();
|
||||
int64_t my_role_here = get_role_of_user_in_chat(conn, uid, chatId);
|
||||
if (my_role_here == user_chat_role_deleted)
|
||||
een9_THROW("Unauthorized user tries to access internalapi_getChatInfo");
|
||||
if (my_role_here != user_chat_role_admin)
|
||||
een9_THROW("Non-admin user tries to access internalapi_getChatInfo");
|
||||
|
||||
std::string alien_nickname = Sent["nickname"].asString();
|
||||
RowUser_Content alien;
|
||||
try {
|
||||
alien = lookup_user_content_by_nickname(conn, alien_nickname);
|
||||
} catch (std::exception& e) {
|
||||
return json::JSON(json::jdict{{"status", json::JSON(-1l)}});
|
||||
}
|
||||
|
||||
int64_t aliens_old_role = get_role_of_user_in_chat(conn, alien.id, chatId);
|
||||
if (aliens_old_role == user_chat_role_deleted) {
|
||||
make_her_a_member_of_the_midnight_crew(conn, chatId, alien.id, user_chat_role_regular);
|
||||
}
|
||||
|
||||
json::JSON Recv;
|
||||
Recv["status"] = json::JSON(0l);
|
||||
// todo: WRITE THIS MORBID THING
|
||||
poll_update_chat(conn, Sent, Recv);
|
||||
return Recv;
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,27 @@
|
||||
#include "server_data_interact.h"
|
||||
#include <engine_engine_number_9/baza_throw.h>
|
||||
#include "../str_fields.h"
|
||||
|
||||
namespace iu9cawebchat {
|
||||
json::JSON internalapi_createChat(SqliteConnection& conn, int64_t uid, const json::JSON& Sent) {
|
||||
std::string new_chat_name = Sent["content"]["name"].asString();
|
||||
std::string new_chat_nickname = Sent["content"]["nickname"].asString();
|
||||
if (!check_nickname(new_chat_nickname) || !check_name(new_chat_name))
|
||||
return json::JSON(json::jdict{{"status", json::JSON(-1l)}});
|
||||
if (is_nickname_taken(conn, new_chat_nickname))
|
||||
return json::JSON(json::jdict{{"status", json::JSON(-2l)}});
|
||||
reserve_nickname(conn, new_chat_nickname);
|
||||
|
||||
sqlite_nooutput(conn,
|
||||
"INSERT INTO `chat` (`nickname`, `name`, `it_HistoryId`, `lastMsgId`) VALUES (?1, ?2, 0, -1)");
|
||||
|
||||
int64_t CHAT_ID = sqlite_trsess_last_insert_rowid(conn);
|
||||
|
||||
make_her_a_member_of_the_midnight_crew(conn, CHAT_ID, uid, user_chat_role_admin);
|
||||
|
||||
// todo: send a message into chat
|
||||
json::JSON Recv;
|
||||
Recv["status"] = json::JSON(0l);
|
||||
// todo: WRITE THIS MORBID THING
|
||||
poll_update_chat_list(conn, uid, Sent, Recv);
|
||||
return Recv;
|
||||
}
|
||||
}
|
||||
|
@ -3,13 +3,30 @@
|
||||
|
||||
namespace iu9cawebchat {
|
||||
json::JSON internalapi_deleteMessage(SqliteConnection& conn, int64_t uid, const json::JSON& Sent) {
|
||||
int64_t chatId = Sent["chatId"].g().asInteger().get_int();
|
||||
int64_t chatId = Sent["chatUpdReq"].asInteger().get_int();
|
||||
int64_t my_role_here = get_role_of_user_in_chat(conn, uid, chatId);
|
||||
if (my_role_here == user_chat_role_deleted)
|
||||
een9_THROW("Unauthorized user tries to access internalapi_getChatInfo");
|
||||
if (my_role_here == user_chat_role_read_only)
|
||||
een9_THROW("read-only user can't send messages");
|
||||
|
||||
int64_t LocalHistoryId = Sent["chatUpdReq"]["LocalHistoryId"].asInteger().get_int();
|
||||
int64_t msgId = Sent["id"].asInteger().get_int();
|
||||
RowMessage_Content msgInQuestion = lookup_message_content(conn, chatId, msgId);
|
||||
if (!(!msgInQuestion.isSystem && (msgInQuestion.senderUserId == uid || my_role_here == user_chat_role_admin) ))
|
||||
een9_THROW("Can't delete: permission denied");
|
||||
|
||||
int64_t chat_HistoryId_BEFORE_EV = get_current_history_id_of_chat(conn, chatId);
|
||||
|
||||
sqlite_nooutput(conn,
|
||||
"UPDATE `message` SET `exists` = 0, `text` = NULL, `chat_IncHistoryId` = ?1 WHERE `id` = ?2",
|
||||
{{1, chat_HistoryId_BEFORE_EV + 1}, {2, msgId}});
|
||||
|
||||
sqlite_nooutput(conn, "UPDATE `chat` SET `it_HistoryId` = ?1 WHERE `id` = ?2",
|
||||
{{1, chat_HistoryId_BEFORE_EV + 1}, {2, chatId}}, {});
|
||||
|
||||
json::JSON Recv;
|
||||
Recv["status"] = json::JSON(0l);
|
||||
// todo: WRITE THIS MORBID THING
|
||||
poll_update_chat(conn, Sent, Recv);
|
||||
return Recv;
|
||||
}
|
||||
}
|
||||
|
@ -1,19 +0,0 @@
|
||||
#include "server_data_interact.h"
|
||||
#include <engine_engine_number_9/baza_throw.h>
|
||||
|
||||
namespace iu9cawebchat {
|
||||
json::JSON internalapi_getChatInfo(SqliteConnection& conn, int64_t uid, const json::JSON& Sent) {
|
||||
int64_t chatId = Sent["id"].g().asInteger().get_int();
|
||||
int64_t my_role_here = get_role_of_user_in_chat(conn, uid, chatId);
|
||||
if (my_role_here == user_chat_role_deleted)
|
||||
een9_THROW("Unauthorized user tries to access internalapi_getChatInfo");
|
||||
json::JSON Recv;
|
||||
Recv["status"] = json::JSON(0l);
|
||||
RowChat_Content content = lookup_chat_content(conn, chatId);
|
||||
Recv["name"] = json::JSON(content.name);
|
||||
Recv["nickname"] = json::JSON(content.nickname);
|
||||
Recv["lastMsgId"] = json::JSON(content.lastMsgId);
|
||||
Recv["roleHere"] = json::JSON(stringify_user_chat_role(my_role_here));
|
||||
return Recv;
|
||||
}
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
#include "server_data_interact.h"
|
||||
#include <engine_engine_number_9/baza_throw.h>
|
||||
|
||||
namespace iu9cawebchat {
|
||||
json::JSON internalapi_getChatList(SqliteConnection& conn, int64_t uid, const json::JSON& Sent) {
|
||||
json::JSON Recv;
|
||||
Recv["status"] = json::JSON(0l);
|
||||
Recv["chats"] = json::JSON(json::array);
|
||||
std::vector<json::JSON>& chats = Recv["chats"].g().asArray();
|
||||
SqliteStatement req(conn,
|
||||
"SELECT `chat`.`id`, `chat`.`nickname`, `chat`.`name`, `chat`.`lastMsgId`, "
|
||||
"`user_chat_membership`.`role` FROM `chat` "
|
||||
"RIGHT JOIN `user_chat_membership` ON `chat`.`id` = `user_chat_membership`.`chatId` "
|
||||
"WHERE `user_chat_membership`.`userId` = ?1 ", {{1, uid}}, {});
|
||||
while (true) {
|
||||
fsql_integer_or_null chat_id;
|
||||
fsql_text8_or_null chat_nickname, chat_name;
|
||||
fsql_integer_or_null chat_lastMsgId, role_here;
|
||||
int status = sqlite_stmt_step(req, {{0, &chat_id}, {3, &chat_lastMsgId}, {4, &role_here}},
|
||||
{{1, &chat_nickname}, {2, &chat_name}});
|
||||
if (status != SQLITE_ROW)
|
||||
break;
|
||||
chats.emplace_back();
|
||||
json::JSON& chat = chats.back();
|
||||
chat["id"] = json::JSON(chat_id.value);
|
||||
chat["content"]["nickname"] = json::JSON(chat_nickname.value);
|
||||
chat["content"]["name"] = json::JSON(chat_name.value);
|
||||
chat["content"]["lastMsgId"] = json::JSON(chat_lastMsgId.exist ? chat_lastMsgId.value : -1);
|
||||
chat["content"]["roleHere"] = json::JSON(stringify_user_chat_role(role_here.value));
|
||||
}
|
||||
return Recv;
|
||||
}
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
#include "server_data_interact.h"
|
||||
#include <engine_engine_number_9/baza_throw.h>
|
||||
|
||||
namespace iu9cawebchat {
|
||||
json::JSON internalapi_getChatMemberList(SqliteConnection& conn, int64_t uid, const json::JSON& Sent) {
|
||||
int64_t chatId = Sent["id"].g().asInteger().get_int();
|
||||
int64_t my_role_here = get_role_of_user_in_chat(conn, uid, chatId);
|
||||
if (my_role_here == user_chat_role_deleted)
|
||||
een9_THROW("Unauthorized user tries to access internalapi_getChatInfo");
|
||||
json::JSON Recv;
|
||||
Recv["status"] = json::JSON(0l);
|
||||
Recv["members"] = json::JSON(json::array);
|
||||
std::vector<json::JSON>& members = Recv["members"].g().asArray();
|
||||
SqliteStatement req(conn,
|
||||
"SELECT `user`.`id`, `user`.`nickname`, `user`.`name`, `user_chat_membership`.`role` FROM "
|
||||
"`user` RIGHT JOIN `user_chat_membership` ON `user`.`id` = `user_chat_membership`.`userId` "
|
||||
"WHERE `user_chat_membership`.`chatId` = ?1",
|
||||
{{1, chatId}}, {});
|
||||
while (true) {
|
||||
fsql_integer_or_null this_user_id;
|
||||
fsql_text8_or_null this_user_nickname, this_user_name;
|
||||
fsql_integer_or_null this_users_role;
|
||||
int status = sqlite_stmt_step(req, {{0, &this_user_id}, {3, &this_users_role}},
|
||||
{{1, &this_user_nickname}, {2, &this_user_name}});
|
||||
if (status != SQLITE_ROW)
|
||||
break;
|
||||
members.emplace_back();
|
||||
json::JSON& member = members.back();
|
||||
member["id"] = json::JSON(this_user_id.value);
|
||||
member["content"]["nickname"] = json::JSON(this_user_nickname.value);
|
||||
member["content"]["name"] = json::JSON(this_user_name.value);
|
||||
member["content"]["role"] = json::JSON(this_users_role.value);
|
||||
}
|
||||
return Recv;
|
||||
}
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
#include "server_data_interact.h"
|
||||
#include <engine_engine_number_9/baza_throw.h>
|
||||
|
||||
namespace iu9cawebchat {
|
||||
json::JSON internalapi_getMessageInfo(SqliteConnection& conn, int64_t uid, const json::JSON& Sent) {
|
||||
int64_t chatId = Sent["chatId"].g().asInteger().get_int();
|
||||
int64_t msgId = Sent["id"].g().asInteger().get_int();
|
||||
if (get_role_of_user_in_chat(conn, uid, chatId) == user_chat_role_deleted)
|
||||
een9_THROW("Authentication failure");
|
||||
json::JSON Recv;
|
||||
Recv["status"] = json::JSON(0l);
|
||||
RowMessage_Content content = lookup_message_content(conn, chatId, msgId);
|
||||
Recv["text"] = json::JSON(content.text);
|
||||
Recv["isSystem"] = json::JSON(content.isSystem);
|
||||
Recv["sender"] = json::JSON(content.senderUserId);
|
||||
// todo: sync that addition with api documentation
|
||||
Recv["previous"] = json::JSON(content.previous);
|
||||
return Recv;
|
||||
}
|
||||
}
|
@ -1,52 +0,0 @@
|
||||
#include "server_data_interact.h"
|
||||
#include <engine_engine_number_9/baza_throw.h>
|
||||
|
||||
namespace iu9cawebchat {
|
||||
/* This is literally the most dumb and useless query */
|
||||
json::JSON internalapi_getMessageNeighbours(SqliteConnection& conn, int64_t uid, const json::JSON& Sent) {
|
||||
int64_t chatId = Sent["chatId"].g().asInteger().get_int();
|
||||
if (get_role_of_user_in_chat(conn, uid, chatId) == user_chat_role_deleted)
|
||||
een9_THROW("Authentication failure");
|
||||
bool dir_forward = Sent["direction"].g().asString() == "forward";
|
||||
int64_t amount = Sent["amount"].g().asInteger().get_int();
|
||||
if (amount < 0)
|
||||
een9_THROW("Incorrect amount");
|
||||
json::JSON Recv;
|
||||
Recv["status"] = json::JSON(0l);
|
||||
Recv["messages"] = json::JSON(json::array);
|
||||
std::vector<json::JSON>& messages = Recv["messages"].g().asArray();
|
||||
if (dir_forward) {
|
||||
int64_t curMsg = Sent["id"].g().asInteger().get_int();
|
||||
if (curMsg < 0)
|
||||
een9_THROW("forward message lookup from the beginning of chat is not supported yet");
|
||||
while (true) {
|
||||
/* At this point, curMsg is non-negative */
|
||||
std::pair<int64_t, RowMessage_Content> nxt = lookup_message_content_rev_side(conn, chatId, curMsg);
|
||||
if (nxt.first < 0)
|
||||
break;
|
||||
messages.emplace_back();
|
||||
json::JSON& message = messages.back();
|
||||
message["id"] = json::JSON(nxt.first);
|
||||
message["previous"] = json::JSON(curMsg);
|
||||
message["content"]["text"] = json::JSON(nxt.second.text);
|
||||
message["content"]["isSystem"] = json::JSON(nxt.second.isSystem);
|
||||
message["content"]["sender"] = json::JSON(nxt.second.senderUserId);
|
||||
curMsg = nxt.first;
|
||||
}
|
||||
} else {
|
||||
int64_t curMsg = Sent["previousMsgId"].g().asInteger().get_int();
|
||||
while (curMsg >= 0) {
|
||||
RowMessage_Content curRow = lookup_message_content(conn, chatId, curMsg);
|
||||
messages.emplace_back();
|
||||
json::JSON& message = messages.back();
|
||||
message["id"] = json::JSON(curMsg);
|
||||
message["previous"] = json::JSON(curRow.previous);
|
||||
message["content"]["text"] = json::JSON(curRow.text);
|
||||
message["content"]["isSystem"] = json::JSON(curRow.isSystem);
|
||||
message["content"]["sender"] = json::JSON(curRow.senderUserId);
|
||||
curMsg = curRow.previous;
|
||||
}
|
||||
}
|
||||
return Recv;
|
||||
}
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
#include "server_data_interact.h"
|
||||
|
||||
namespace iu9cawebchat {
|
||||
json::JSON internalapi_getUserInfo(SqliteConnection& conn, int64_t uid, const json::JSON& Sent) {
|
||||
int64_t otherUserId = Sent["id"].g().asInteger().get_int();
|
||||
json::JSON Recv;
|
||||
Recv["status"] = json::JSON(0l);
|
||||
RowUser_Content content = lookup_user_content(conn, otherUserId);
|
||||
Recv["name"] = json::JSON(content.name);
|
||||
Recv["nickname"] = json::JSON(content.nickname);
|
||||
return Recv;
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
#include "server_data_interact.h"
|
||||
#include <engine_engine_number_9/baza_throw.h>
|
||||
|
||||
namespace iu9cawebchat {
|
||||
json::JSON internalapi_leaveChat(SqliteConnection& conn, int64_t uid, const json::JSON& Sent) {
|
||||
int64_t chatId = Sent["chatId"].asInteger().get_int();
|
||||
if (get_role_of_user_in_chat(conn, uid, chatId) == user_chat_role_deleted)
|
||||
een9_THROW("Not a member");
|
||||
kick_from_chat(conn, uid, chatId);
|
||||
json::JSON Recv;
|
||||
poll_update_chat_list(conn, uid, Sent, Recv);
|
||||
return Recv;
|
||||
}
|
||||
}
|
@ -1,151 +0,0 @@
|
||||
#include "server_data_interact.h"
|
||||
#include <engine_engine_number_9/baza_throw.h>
|
||||
|
||||
namespace iu9cawebchat {
|
||||
int64_t get_current_history_id_of_chat(SqliteConnection& conn, int64_t chatId) {
|
||||
SqliteStatement req(conn, "SELECT `it_HistoryId` FROM `chat` WHERE `id` = ?1", {{1, chatId}}, {});
|
||||
fsql_integer_or_null HistoryId;
|
||||
int status = sqlite_stmt_step(req, {{0, &HistoryId}}, {});
|
||||
een9_ASSERT_pl(status == SQLITE_ROW);
|
||||
return HistoryId.value;
|
||||
}
|
||||
|
||||
int64_t get_current_history_id_of_user_chatList(SqliteConnection& conn, int64_t userId) {
|
||||
SqliteStatement req(conn, "SELECT `chatList_HistoryId` FROM `user` WHERE `id` = ?1", {{1, userId}}, {});
|
||||
fsql_integer_or_null HistoryId;
|
||||
int status = sqlite_stmt_step(req, {{0, &HistoryId}}, {});
|
||||
een9_ASSERT_pl(status == SQLITE_ROW);
|
||||
return HistoryId.value;
|
||||
}
|
||||
|
||||
void internalapi_pollEvents_in_chat_collect_membership_events(SqliteConnection& conn,
|
||||
std::vector<json::JSON>& events, int64_t chatId, int64_t LocalHistoryId) {
|
||||
SqliteStatement membership_changes(conn,
|
||||
"SELECT `userId`, `role`, FROM `user_chat_membership` WHERE `chatId` = ?1 "
|
||||
"AND `chat_IncHistoryId` > ?2", {{1, chatId}, {2, LocalHistoryId}}, {});
|
||||
fsql_integer_or_null ev_userId;
|
||||
fsql_integer_or_null ev_user_role;
|
||||
while (true) {
|
||||
int status = sqlite_stmt_step(membership_changes,
|
||||
{{0, &ev_userId}, {1, &ev_user_role}}, {});
|
||||
if (status != SQLITE_ROW)
|
||||
break;
|
||||
events.emplace_back();
|
||||
json::JSON& event = events.back();
|
||||
event["member"] = json::JSON(ev_userId.value);
|
||||
if (ev_user_role.value == user_chat_role_deleted) {
|
||||
event["type"] = json::JSON("removedMember");
|
||||
} else {
|
||||
event["type"] = json::JSON("addedMember");
|
||||
RowUser_Content USER = lookup_user_content(conn, ev_userId.value);
|
||||
event["content"]["name"] = json::JSON(USER.name);
|
||||
event["content"]["nickname"] = json::JSON(USER.nickname);
|
||||
event["content"]["role"] = json::JSON(stringify_user_chat_role(ev_user_role.value));
|
||||
}
|
||||
events.push_back(event);
|
||||
}
|
||||
}
|
||||
|
||||
void internalapi_pollEvents_in_chat_collect_messages_events(SqliteConnection& conn,
|
||||
std::vector<json::JSON>& events, int64_t chatId, int64_t LocalHistoryId) {
|
||||
SqliteStatement messages_changes(conn,
|
||||
"SELECT `id`, `previous`, `senderUserId`, `exists`, `isSystem`, `text` FROM `messages` WHERE "
|
||||
"WHERE `chatId` = ?1 AND `chat_IncHistoryId` > ?2", {{1, chatId}, {2, LocalHistoryId}}, {});
|
||||
fsql_integer_or_null ev_msgId, ev_previousMsgId, msgSenderUserId, msgExists, msgIsSystem;
|
||||
fsql_text8_or_null msgText;
|
||||
while (true) {
|
||||
int status = sqlite_stmt_step(messages_changes,
|
||||
{{0, &ev_msgId}, {1, &ev_previousMsgId}, {2, &msgSenderUserId}, {3, &msgExists}, {4, &msgIsSystem}},
|
||||
{{5, &msgText}});
|
||||
if (status != SQLITE_ROW)
|
||||
break;
|
||||
events.emplace_back();
|
||||
json::JSON& event = events.back();
|
||||
event["type"] = json::JSON("newMessage");
|
||||
event["id"] = json::JSON(ev_msgId.value);
|
||||
event["previous"] = json::JSON(ev_previousMsgId.value);
|
||||
event["content"]["sender"] = json::JSON(msgSenderUserId.value);
|
||||
event["content"]["isSystem"] = json::JSON((bool)msgIsSystem.value);
|
||||
event["content"]["text"] = json::JSON(msgText.value);
|
||||
events.push_back(event);
|
||||
}
|
||||
}
|
||||
|
||||
void internalapi_pollEvents_in_user_chatList_collect_events(SqliteConnection& conn,
|
||||
std::vector<json::JSON>& events, int64_t userId, int64_t LocalHistoryId) {
|
||||
SqliteStatement membership_changes(conn,
|
||||
"SELECT `chatId`, `role` FROM `user_chat_membership` WHERE `userId` = ?1 "
|
||||
"AND `user_chatList_IncHistoryId` > ?2", {{1, userId}, {2, LocalHistoryId}});
|
||||
fsql_integer_or_null ev_chatId, usersRoleHere;
|
||||
while (true) {
|
||||
int status = sqlite_stmt_step(membership_changes, {{0, &ev_chatId}, {1, &usersRoleHere}}, {});
|
||||
if (status != SQLITE_ROW)
|
||||
break;
|
||||
events.emplace_back();
|
||||
json::JSON& event = events.back();
|
||||
event["id"] = json::JSON(ev_chatId.value);
|
||||
if (usersRoleHere.value == user_chat_role_deleted) {
|
||||
event["type"] = json::JSON("removedChat");
|
||||
} else {
|
||||
event["type"] = json::JSON("addedChat");
|
||||
RowChat_Content CHAT = lookup_chat_content(conn, ev_chatId.value);
|
||||
event["content"]["name"] = json::JSON(CHAT.name);
|
||||
event["content"]["nickname"] = json::JSON(CHAT.nickname);
|
||||
event["content"]["lastMsgId"] = json::JSON(CHAT.lastMsgId);
|
||||
event["content"]["roleHere"] = json::JSON(stringify_user_chat_role(usersRoleHere.value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int64_t event_polling_fill_chat_hist_entity_response(SqliteConnection& conn, json::JSON& hist_entity_response,
|
||||
int64_t uid, int64_t chatId, int64_t LocalHistoryId) {
|
||||
hist_entity_response["type"] = json::JSON("chat");
|
||||
if (get_role_of_user_in_chat(conn, uid, chatId) == user_chat_role_deleted)
|
||||
een9_THROW("internalapi/pollEvents: trying to access chat that user does not belong to");
|
||||
hist_entity_response["chatId"] = json::JSON(chatId);
|
||||
int64_t NewHistoryId = get_current_history_id_of_chat(conn, chatId);
|
||||
hist_entity_response["HistoryId"] = json::JSON(NewHistoryId);
|
||||
|
||||
hist_entity_response["events"] = json::JSON(json::array);
|
||||
std::vector<json::JSON>& events = hist_entity_response["events"].g().asArray();
|
||||
/* Two classes of 'real events' can happen to chat: membership table change, message table change */
|
||||
/* Here, I collect membership changes (related to this chat) */
|
||||
internalapi_pollEvents_in_chat_collect_membership_events(conn, events, chatId, LocalHistoryId);
|
||||
/* Here, I collect message changes (related to this chat) */
|
||||
internalapi_pollEvents_in_chat_collect_messages_events(conn, events, chatId, LocalHistoryId);
|
||||
return NewHistoryId;
|
||||
}
|
||||
|
||||
int64_t event_polling_fill_chatlist_hist_entity_response(SqliteConnection& conn, json::JSON& hist_entity_response,
|
||||
int64_t uid, int64_t LocalHistoryId) {
|
||||
hist_entity_response["type"] = json::JSON("chatlist");
|
||||
int64_t NewHistoryId = get_current_history_id_of_user_chatList(conn, uid);
|
||||
hist_entity_response["HistotyId"] = json::JSON(NewHistoryId);
|
||||
|
||||
hist_entity_response["events"] = json::JSON(json::array);
|
||||
std::vector<json::JSON>& events = hist_entity_response["events"].g().asArray();
|
||||
internalapi_pollEvents_in_user_chatList_collect_events(conn, events, uid, LocalHistoryId);
|
||||
return NewHistoryId;
|
||||
}
|
||||
|
||||
json::JSON internalapi_pollEvents(SqliteConnection& conn, int64_t uid, const json::JSON& Sent) {
|
||||
json::JSON Recv;
|
||||
Recv["status"] = json::JSON(0l);
|
||||
Recv["update"] = json::JSON(json::array);
|
||||
const std::vector<json::JSON>& req_scope = Sent["scope"].g().asArray();
|
||||
std::vector<json::JSON>& updated = Recv["update"].g().asArray();
|
||||
for (const json::JSON& hist_entity_request: req_scope) {
|
||||
updated.emplace_back();
|
||||
json::JSON& hist_entity_response = updated.back();
|
||||
const int64_t LocalHistoryId = hist_entity_request["LocalHistoryId"].g().asInteger().get_int();
|
||||
if (hist_entity_request["type"].g().asString() == "chat") {
|
||||
int64_t chatId = hist_entity_request["chatId"].g().asInteger().get_int();
|
||||
event_polling_fill_chat_hist_entity_response(conn, hist_entity_response, uid, chatId, LocalHistoryId);
|
||||
} else if (hist_entity_request["type"].g().asString() == "chatlist") {
|
||||
event_polling_fill_chatlist_hist_entity_response(conn, hist_entity_response, uid, LocalHistoryId);
|
||||
} else
|
||||
een9_THROW("Bad request");
|
||||
}
|
||||
return Recv;
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
#include "server_data_interact.h"
|
||||
#include <engine_engine_number_9/baza_throw.h>
|
||||
|
||||
namespace iu9cawebchat {
|
||||
json::JSON internalapi_removeChat(SqliteConnection& conn, int64_t uid, const json::JSON& Sent) {
|
||||
json::JSON Recv;
|
||||
Recv["status"] = json::JSON(0l);
|
||||
// todo: WRITE THIS MORBID THING
|
||||
return Recv;
|
||||
}
|
||||
}
|
@ -2,14 +2,36 @@
|
||||
#include <engine_engine_number_9/baza_throw.h>
|
||||
|
||||
namespace iu9cawebchat {
|
||||
void kick_from_chat(SqliteConnection& conn, int64_t alienUserId, int64_t chatId) {
|
||||
if (get_role_of_user_in_chat(conn, alienUserId, chatId) == user_chat_role_deleted)
|
||||
een9_THROW("Can't delete a deleted member");
|
||||
int64_t chat_HistoryId_BEFORE_EV = get_current_history_id_of_chat(conn, chatId);
|
||||
int64_t alien_chatlist_HistoryId_BEFORE_EV = get_current_history_id_of_user_chatList(conn, alienUserId);
|
||||
|
||||
sqlite_nooutput(conn,
|
||||
"UPDATE `user_chat_membership` SET `user_chatList_IncHistoryId` = ?3,"
|
||||
"`chat_IncHistoryId` = ?4, `role` = ?5 WHERE `userId` = ?1 AND `chatId` = ?2",
|
||||
{{1, alienUserId}, {2, chatId}, {3, alien_chatlist_HistoryId_BEFORE_EV + 1},
|
||||
{4, chat_HistoryId_BEFORE_EV + 1}, {5, user_chat_role_deleted}}, {});
|
||||
|
||||
sqlite_nooutput(conn,
|
||||
"UPDATE `chat` SET `it_HistoryId` = ?1 WHERE `id` = ?2", {{1, chat_HistoryId_BEFORE_EV + 1},
|
||||
{2, chatId}}, {});
|
||||
|
||||
sqlite_nooutput(conn,
|
||||
"UPDATE `user` SET `chatList_HistoryId` = ?1 WHERE `id` = ?2",
|
||||
{{1, alien_chatlist_HistoryId_BEFORE_EV + 1}, {2, alienUserId}}, {});
|
||||
}
|
||||
|
||||
json::JSON internalapi_removeMemberFromChat(SqliteConnection& conn, int64_t uid, const json::JSON& Sent) {
|
||||
int64_t chatId = Sent["chatId"].g().asInteger().get_int();
|
||||
int64_t chatId = Sent["chatUpdReq"]["chatId"].asInteger().get_int();
|
||||
int64_t my_role_here = get_role_of_user_in_chat(conn, uid, chatId);
|
||||
if (my_role_here == user_chat_role_deleted)
|
||||
een9_THROW("Unauthorized user tries to access internalapi_getChatInfo");
|
||||
if (my_role_here != user_chat_role_deleted)
|
||||
een9_THROW("Only admin can delete members of chat");
|
||||
int64_t badAlienId = Sent["chatUpdReq"]["userId"].asInteger().get_int();
|
||||
kick_from_chat(conn, badAlienId, chatId);
|
||||
json::JSON Recv;
|
||||
Recv["status"] = json::JSON(0l);
|
||||
// todo: WRITE THIS MORBID THING
|
||||
poll_update_chat(conn, Sent, Recv);
|
||||
return Recv;
|
||||
}
|
||||
}
|
||||
|
@ -3,46 +3,39 @@
|
||||
#include "../str_fields.h"
|
||||
|
||||
namespace iu9cawebchat {
|
||||
/* Throws excetion on failure
|
||||
* Chat's HistoryId will increment after this operation, incremented
|
||||
/* No authorization check is performed
|
||||
* Chat's HistoryId will increment after this operation
|
||||
* if adding system message, uid is ignored
|
||||
*/
|
||||
int64_t insert_new_message(SqliteConnection& conn, int64_t uid, int64_t chatId,
|
||||
void insert_new_message(SqliteConnection& conn, int64_t uid, int64_t chatId,
|
||||
const std::string& text, bool isSystem) {
|
||||
int64_t chat_HistoryId_BEFORE_MSG = get_current_history_id_of_chat(conn, chatId);
|
||||
if (chat_HistoryId_BEFORE_MSG > INT64_MAX - 100)
|
||||
een9_THROW("please no");
|
||||
int64_t chat_lastMsgId = get_lastMsgId_of_chat(conn, chatId);
|
||||
SqliteStatement req(conn,
|
||||
"INSERT INTO `message` (`chatId`, `previous`, `senderUserId`, `exists`, `isSystem`, `text`,"
|
||||
"`chat_IncHistoryId`) VALUES (?1, ?2, ?3, 1, ?4, ?5, ?6)",
|
||||
{{1, chatId}, {4, (int64_t)isSystem}, {6, chat_HistoryId_BEFORE_MSG + 1}}, {{5, text}});
|
||||
int64_t chat_cur_last_msg_id = get_lastMsgId_of_chat(conn, chatId);
|
||||
if (chat_cur_last_msg_id >= 0)
|
||||
sqlite_stmt_bind_int64(req, 2, chat_cur_last_msg_id);
|
||||
"INSERT INTO `message` (`chatId`, `id`, `senderUserId`, `exists`, `isSystem`, `chat_IncHistoryId`, "
|
||||
"`text`) VALUES (?1, ?2, ?3 1, ?4, ?5, ?6)",
|
||||
{{1, chatId}, {2, chat_lastMsgId + 1}, {4, (int64_t)isSystem}, {5, chat_HistoryId_BEFORE_MSG + 1}}, {{6, text}});
|
||||
if (!isSystem)
|
||||
sqlite_stmt_bind_int64(req, 3, uid);
|
||||
int64_t MSG_ID = sqlite_trsess_last_insert_rowid(conn);
|
||||
sqlite_nooutput(conn, "UPDATE `chat` SET `lastMsgId` = ?1, `it_HistoryId` = ?2 WHERE `id` = ?3",
|
||||
{{1, MSG_ID}, {2, chat_HistoryId_BEFORE_MSG + 1}, {3, chatId}}, {});
|
||||
return MSG_ID;
|
||||
{{1, chat_lastMsgId + 1}, {2, chat_HistoryId_BEFORE_MSG + 1}, {3, chatId}}, {});
|
||||
}
|
||||
|
||||
json::JSON internalapi_sendMessage(SqliteConnection& conn, int64_t uid, const json::JSON& Sent) {
|
||||
int64_t chatId = Sent["chatId"].g().asInteger().get_int();
|
||||
int64_t chatId = Sent["chatUpdReq"].asInteger().get_int();
|
||||
int64_t my_role_here = get_role_of_user_in_chat(conn, uid, chatId);
|
||||
if (my_role_here == user_chat_role_deleted)
|
||||
een9_THROW("Unauthorized user tries to access internalapi_getChatInfo");
|
||||
if (my_role_here == user_chat_role_read_only)
|
||||
een9_THROW("read-only user can't send messages");
|
||||
const int64_t LocalHistoryId = Sent["LocalHistoryId"].g().asInteger().get_int();
|
||||
std::string text = Sent["content"]["text"].g().asString();
|
||||
|
||||
std::string text = Sent["content"]["text"].asString();
|
||||
if (!is_orthodox_string(text) || text.empty())
|
||||
een9_THROW("Bad input text");
|
||||
int64_t MSG_ID = insert_new_message(conn, uid, chatId, text, false);
|
||||
insert_new_message(conn, uid, chatId, text, false);
|
||||
|
||||
json::JSON Recv;
|
||||
Recv["status"] = json::JSON(0l);
|
||||
json::JSON hist_ent_response = Recv["update"][0].g();
|
||||
event_polling_fill_chat_hist_entity_response(conn, hist_ent_response, uid, chatId, LocalHistoryId);
|
||||
poll_update_chat(conn, Sent, Recv);
|
||||
return Recv;
|
||||
}
|
||||
}
|
||||
|
@ -20,64 +20,45 @@ namespace iu9cawebchat {
|
||||
if (ret_logged_in_user >= 0) {
|
||||
ret_userinfo["uid"] = json::JSON(ret_logged_in_user);
|
||||
ret_userinfo["nickname"] = json::JSON(tried.nickname);
|
||||
ret_userinfo["name"] = json::JSON(find_user_name(conn, ret_logged_in_user));
|
||||
ret_userinfo["name"] = json::JSON(get_user_name(conn, ret_logged_in_user));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string R200_pres_uinfo(const std::string& el_name, WorkerGuestData& wgd,
|
||||
const json::JSON& config_presentation,
|
||||
const json::JSON& userinfo) {
|
||||
|
||||
std::string page = wgd.templater->render(el_name, {&config_presentation, &userinfo});
|
||||
std::string http_R200(const std::string &el_name, WorkerGuestData &wgd,
|
||||
const std::vector<const json::JSON *> &args) {
|
||||
std::string page = wgd.templater->render(el_name, args);
|
||||
return een9::form_http_server_response_200("text/html", page);
|
||||
}
|
||||
|
||||
std::string R200_pres_uinfo_msges(const std::string& el_name, WorkerGuestData& wgd,
|
||||
const json::JSON& config_presentation,
|
||||
const json::JSON& userinfo, const std::vector<HtmlMsgBox>& messages) {
|
||||
|
||||
json::JSON jmessages;
|
||||
// todo: optimize
|
||||
json::JSON jsonify_html_message_list(const std::vector<HtmlMsgBox>& messages) {
|
||||
json::JSON jmessages(json::array);
|
||||
for (size_t i = 0; i < messages.size(); i++) {
|
||||
jmessages[i]["class"] = json::JSON(messages[i].class_);
|
||||
jmessages[i]["text"] = json::JSON(messages[i].text);
|
||||
jmessages[i]["class"].asString() = messages[i].class_;
|
||||
jmessages[i]["text"].asString() = messages[i].text;
|
||||
}
|
||||
std::string page = wgd.templater->render(el_name, {&config_presentation, &userinfo, &jmessages});
|
||||
return een9::form_http_server_response_200("text/html", page);
|
||||
return jmessages;
|
||||
}
|
||||
|
||||
std::string page_E404(WorkerGuestData &wgd) {
|
||||
return een9::form_http_server_response_404("text/html",
|
||||
wgd.templater->render("err-404", {}));
|
||||
}
|
||||
|
||||
/* ========================= API =========================*/
|
||||
|
||||
std::string when_internalapi(WorkerGuestData& wgd, const een9::ClientRequest& req, int64_t uid,
|
||||
const std::function<json::JSON(SqliteConnection&, int64_t, const json::JSON&)>& F) {
|
||||
const std::function<json::JSON(SqliteConnection&, int64_t, const json::JSON&)>& F) {
|
||||
const json::JSON& Sent = json::parse_str_flawless(req.body);
|
||||
std::string result = json::generate_str(F(*wgd.db, uid, Sent), json::print_pretty);
|
||||
return een9::form_http_server_response_200("text/json", result);
|
||||
}
|
||||
|
||||
std::string when_internalapi_pollevents(WorkerGuestData& wgd, const een9::ClientRequest& req, int64_t uid) {
|
||||
return when_internalapi(wgd, req, uid, internalapi_pollEvents);
|
||||
std::string when_internalapi_chatpollevents(WorkerGuestData& wgd, const een9::ClientRequest& req, int64_t uid) {
|
||||
return when_internalapi(wgd, req, uid, internalapi_chatPollEvents);
|
||||
}
|
||||
|
||||
std::string when_internalapi_getchatlist(WorkerGuestData& wgd, const een9::ClientRequest& req, int64_t uid) {
|
||||
return when_internalapi(wgd, req, uid, internalapi_getChatList);
|
||||
}
|
||||
|
||||
std::string when_internalapi_getchatinfo(WorkerGuestData& wgd, const een9::ClientRequest& req, int64_t uid) {
|
||||
return when_internalapi(wgd, req, uid, internalapi_getChatInfo);
|
||||
}
|
||||
|
||||
std::string when_internalapi_getchatmemberlist(WorkerGuestData& wgd, const een9::ClientRequest& req, int64_t uid) {
|
||||
return when_internalapi(wgd, req, uid, internalapi_getChatMemberList);
|
||||
}
|
||||
|
||||
std::string when_internalapi_getuserinfo(WorkerGuestData& wgd, const een9::ClientRequest& req, int64_t uid) {
|
||||
return when_internalapi(wgd, req, uid, internalapi_getUserInfo);
|
||||
}
|
||||
|
||||
std::string when_internalapi_getmessageinfo(WorkerGuestData& wgd, const een9::ClientRequest& req, int64_t uid) {
|
||||
return when_internalapi(wgd, req, uid, internalapi_getMessageInfo);
|
||||
std::string when_internalapi_chatlistpollevents(WorkerGuestData &wgd, const een9::ClientRequest &req, int64_t uid) {
|
||||
return when_internalapi(wgd, req, uid, internalapi_chatListPollEvents);
|
||||
}
|
||||
|
||||
std::string when_internalapi_getmessageneighbours(WorkerGuestData &wgd, const een9::ClientRequest &req, int64_t uid) {
|
||||
@ -104,7 +85,7 @@ namespace iu9cawebchat {
|
||||
return when_internalapi(wgd, req, uid, internalapi_createChat);
|
||||
}
|
||||
|
||||
std::string when_internalapi_removechat(WorkerGuestData &wgd, const een9::ClientRequest &req, int64_t uid) {
|
||||
return when_internalapi(wgd, req, uid, internalapi_removeChat);
|
||||
std::string when_internalapi_leavechat(WorkerGuestData &wgd, const een9::ClientRequest &req, int64_t uid) {
|
||||
return when_internalapi(wgd, req, uid, internalapi_leaveChat);
|
||||
}
|
||||
}
|
||||
|
@ -27,18 +27,17 @@ namespace iu9cawebchat {
|
||||
int64_t& ret_logged_in_user
|
||||
);
|
||||
|
||||
std::string R200_pres_uinfo(const std::string& el_name, WorkerGuestData& wgd,
|
||||
const json::JSON& config_presentation,
|
||||
const json::JSON& userinfo);
|
||||
std::string http_R200(const std::string& el_name, WorkerGuestData& wgd,
|
||||
const std::vector<const json::JSON*>& args);
|
||||
|
||||
struct HtmlMsgBox {
|
||||
std::string class_;
|
||||
std::string text;
|
||||
};
|
||||
|
||||
std::string R200_pres_uinfo_msges(const std::string& el_name, WorkerGuestData& wgd,
|
||||
const json::JSON& config_presentation,
|
||||
const json::JSON& userinfo, const std::vector<HtmlMsgBox>& messages);
|
||||
json::JSON jsonify_html_message_list(const std::vector<HtmlMsgBox>& messages);
|
||||
|
||||
std::string page_E404(WorkerGuestData& wgd);
|
||||
|
||||
/* ========================== PAGES ================================== */
|
||||
|
||||
@ -52,22 +51,13 @@ namespace iu9cawebchat {
|
||||
const een9::ClientRequest& req, const json::JSON& userinfo);
|
||||
|
||||
std::string when_page_user(WorkerGuestData& wgd, const json::JSON& config_presentation,
|
||||
const een9::ClientRequest& req, const json::JSON& userinfo);
|
||||
const een9::ClientRequest& req, const std::vector<LoginCookie>& login_cookies, const json::JSON& userinfo);
|
||||
|
||||
|
||||
/* ======================== API ============================== */
|
||||
std::string when_internalapi_chatpollevents(WorkerGuestData& wgd, const een9::ClientRequest& req, int64_t uid);
|
||||
|
||||
std::string when_internalapi_pollevents(WorkerGuestData& wgd, const een9::ClientRequest& req, int64_t uid);
|
||||
|
||||
std::string when_internalapi_getchatlist(WorkerGuestData& wgd, const een9::ClientRequest& req, int64_t uid);
|
||||
|
||||
std::string when_internalapi_getchatinfo(WorkerGuestData& wgd, const een9::ClientRequest& req, int64_t uid);
|
||||
|
||||
std::string when_internalapi_getchatmemberlist(WorkerGuestData& wgd, const een9::ClientRequest& req, int64_t uid);
|
||||
|
||||
std::string when_internalapi_getuserinfo(WorkerGuestData& wgd, const een9::ClientRequest& req, int64_t uid);
|
||||
|
||||
std::string when_internalapi_getmessageinfo(WorkerGuestData& wgd, const een9::ClientRequest& req, int64_t uid);
|
||||
std::string when_internalapi_chatlistpollevents(WorkerGuestData& wgd, const een9::ClientRequest& req, int64_t uid);
|
||||
|
||||
std::string when_internalapi_getmessageneighbours(WorkerGuestData& wgd, const een9::ClientRequest& req, int64_t uid);
|
||||
|
||||
@ -81,7 +71,7 @@ namespace iu9cawebchat {
|
||||
|
||||
std::string when_internalapi_createchat(WorkerGuestData &wgd, const een9::ClientRequest &req, int64_t uid);
|
||||
|
||||
std::string when_internalapi_removechat(WorkerGuestData &wgd, const een9::ClientRequest &req, int64_t uid);
|
||||
std::string when_internalapi_leavechat(WorkerGuestData &wgd, const een9::ClientRequest &req, int64_t uid);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
196
src/web_chat/iu9_ca_web_chat_lib/backend_logic/polling.cpp
Normal file
196
src/web_chat/iu9_ca_web_chat_lib/backend_logic/polling.cpp
Normal file
@ -0,0 +1,196 @@
|
||||
#include "server_data_interact.h"
|
||||
#include <assert.h>
|
||||
#include <engine_engine_number_9/baza_throw.h>
|
||||
|
||||
namespace iu9cawebchat {
|
||||
json::JSON poll_update_chat_list_resp(SqliteConnection& conn, int64_t userId, int64_t LocalHistoryId) {
|
||||
json::JSON chatListUpdResp;
|
||||
SqliteStatement my_membership_changes(conn,
|
||||
"SELECT `chatId`, `role` FROM `user_chat_membership` WHERE `userId` = ?1 "
|
||||
"AND `user_chatList_IncHistoryId` > ?2", {{1, userId}, {2, LocalHistoryId}});
|
||||
json::jarr myChats = chatListUpdResp["myChats"].asArray();
|
||||
while (true) {
|
||||
fsql_integer_or_null ev_chatId, usersRoleHere;
|
||||
int status = sqlite_stmt_step(my_membership_changes, {{0, &ev_chatId}, {1, &usersRoleHere}}, {});
|
||||
if (status != SQLITE_ROW)
|
||||
break;
|
||||
myChats.emplace_back();
|
||||
json::JSON& myMembershipSt = myChats.back();
|
||||
myMembershipSt["chatId"].asInteger() = json::Integer(ev_chatId.value);
|
||||
myMembershipSt["myRoleHere"].asString() = stringify_user_chat_role(usersRoleHere.value);
|
||||
if (usersRoleHere.value != user_chat_role_deleted) {
|
||||
RowChat_Content CHAT = lookup_chat_content(conn, ev_chatId.value);
|
||||
myMembershipSt["chatName"].asString() = CHAT.name;
|
||||
myMembershipSt["chatNickname"].asString() = CHAT.nickname;
|
||||
}
|
||||
}
|
||||
int64_t HistoryId = get_current_history_id_of_user_chatList(conn, userId);
|
||||
chatListUpdResp["HistoryId"].asInteger() = json::Integer(HistoryId);
|
||||
return chatListUpdResp;
|
||||
}
|
||||
|
||||
void poll_update_chat_list(SqliteConnection& conn, int64_t userId, const json::JSON& Sent, json::JSON& Recv) {
|
||||
Recv["status"].asInteger() = json::Integer(0l);
|
||||
// todo: in libjsonincpp: get rid of Integer
|
||||
poll_update_chat_list_resp(conn, userId, Sent["chatListUpdReq"]["LocalHistoryId"].asInteger().get_int());
|
||||
}
|
||||
|
||||
json::JSON make_messageSt_obj(int64_t id, int64_t senderUserId, bool exists, bool isSystem, const std::string& text) {
|
||||
json::JSON messageSt;
|
||||
messageSt["id"].asInteger() = json::Integer(id);
|
||||
if (!isSystem)
|
||||
messageSt["senderUserId"].asInteger() = json::Integer(senderUserId);
|
||||
messageSt["exists"] = json::JSON(exists);
|
||||
messageSt["isSystem"] = json::JSON(isSystem);
|
||||
if (exists)
|
||||
messageSt["text"].asString() = text;
|
||||
return messageSt;
|
||||
}
|
||||
|
||||
json::jarr poll_update_chat_resp_messages(SqliteConnection& conn, int64_t chatId, int64_t LocalHistoryId,
|
||||
int64_t QSEG_A, int64_t QSEG_B) {
|
||||
|
||||
json::jarr messages;
|
||||
SqliteStatement messages_changes(conn,
|
||||
"SELECT `id`, `senderUserId`, `exists`, `isSystem`, `text` FROM `messages` "
|
||||
"WHERE `chatId` = ?1 AND ( `chat_IncHistoryId` > ?2 OR ( ?3 <= `id` AND `id` <= ?4 ) )",
|
||||
{{1, chatId}, {2, LocalHistoryId}, {3, QSEG_A}, {4, QSEG_B}}, {});
|
||||
while (true) {
|
||||
fsql_integer_or_null msgId, msgSenderUserId, msgExists, msgIsSystem;
|
||||
fsql_text8_or_null msgText;
|
||||
int status = sqlite_stmt_step(messages_changes,
|
||||
{{0, &msgId}, {1, &msgSenderUserId}, {2, &msgExists}, {3, &msgIsSystem}},
|
||||
{{4, &msgText}});
|
||||
if (status != SQLITE_ROW)
|
||||
break;
|
||||
messages.push_back(make_messageSt_obj(msgId.value, msgSenderUserId.value, msgExists.value,
|
||||
msgIsSystem.value, msgText.value));
|
||||
}
|
||||
return messages;
|
||||
}
|
||||
|
||||
json::jarr poll_update_chat_resp_members(SqliteConnection& conn, int64_t chatId, int64_t LocalHistoryId) {
|
||||
json::jarr members;
|
||||
|
||||
SqliteStatement membership_changes(conn,
|
||||
"SELECT `userId`, `role`, FROM `user_chat_membership` WHERE `chatId` = ?1 "
|
||||
"AND `chat_IncHistoryId` > ?2", {{1, chatId}, {2, LocalHistoryId}}, {});
|
||||
while (true) {
|
||||
fsql_integer_or_null alienUserId;
|
||||
fsql_integer_or_null alienRoleHere;
|
||||
int status = sqlite_stmt_step(membership_changes,
|
||||
{{0, &alienUserId}, {1, &alienRoleHere}}, {});
|
||||
if (status != SQLITE_ROW)
|
||||
break;
|
||||
members.emplace_back();
|
||||
json::JSON& memberSt = members.back();
|
||||
memberSt["userId"].asInteger() = json::Integer(alienUserId.value);
|
||||
memberSt["roleHere"].asString() = stringify_user_chat_role(alienRoleHere.value);
|
||||
if (alienRoleHere.value != user_chat_role_deleted) {
|
||||
RowUser_Content alien = lookup_user_content(conn, alienUserId.value);
|
||||
memberSt["name"].asString() = alien.name;
|
||||
memberSt["nickname"].asString() = alien.nickname;
|
||||
}
|
||||
}
|
||||
return members;
|
||||
}
|
||||
|
||||
json::JSON poll_update_chat_ONE_MSG_resp(SqliteConnection& conn, int64_t chatId, int64_t selectedMsg) {
|
||||
json::JSON chatUpdResp;
|
||||
|
||||
chatUpdResp["members"].asArray() = poll_update_chat_resp_members(conn, chatId, 0);
|
||||
|
||||
|
||||
json::jarr messages = chatUpdResp["messages"].asArray();
|
||||
if (selectedMsg >= 0) {
|
||||
RowMessage_Content msg = lookup_message_content(conn, chatId, selectedMsg);
|
||||
messages.push_back(make_messageSt_obj(msg.id, msg.senderUserId, msg.exists, msg.isSystem, msg.text));
|
||||
}
|
||||
|
||||
int64_t lastMsgId = get_lastMsgId_of_chat(conn, chatId);
|
||||
chatUpdResp["lastMsgId"].asInteger() = json::Integer(lastMsgId);
|
||||
|
||||
int64_t HistoryId = get_current_history_id_of_chat(conn, chatId);
|
||||
chatUpdResp["HistoryId"].asInteger() = json::Integer(HistoryId);
|
||||
return chatUpdResp;
|
||||
}
|
||||
|
||||
json::JSON poll_update_chat_important_segment_resp(SqliteConnection& conn, int64_t chatId, int64_t LocalHistoryId,
|
||||
int64_t QSEG_A, int64_t QSEG_B) {
|
||||
|
||||
json::JSON chatUpdResp;
|
||||
|
||||
chatUpdResp["members"].asArray() = poll_update_chat_resp_members(conn, chatId, LocalHistoryId);
|
||||
chatUpdResp["messages"].asArray() = poll_update_chat_resp_messages(conn, chatId, LocalHistoryId, QSEG_A, QSEG_B);
|
||||
|
||||
int64_t lastMsgId = get_lastMsgId_of_chat(conn, chatId);
|
||||
chatUpdResp["lastMsgId"].asInteger() = json::Integer(lastMsgId);
|
||||
|
||||
int64_t HistoryId = get_current_history_id_of_chat(conn, chatId);
|
||||
chatUpdResp["HistoryId"].asInteger() = json::Integer(HistoryId);
|
||||
return chatUpdResp;
|
||||
}
|
||||
|
||||
/* chat polling function MUST have one queer feature: it accepts a range of msgId, which are guaranteed to be
|
||||
* lookud up. */
|
||||
void poll_update_chat_important_segment(SqliteConnection& conn, const json::JSON& Sent, json::JSON& Recv,
|
||||
int64_t QSEG_A, int64_t QSEG_B) {
|
||||
|
||||
Recv["status"].asInteger() = json::Integer(0l);
|
||||
Recv["charUpdResp"] = poll_update_chat_important_segment_resp(conn,
|
||||
Sent["chatUpdReq"]["chatId"].asInteger().get_int(),
|
||||
Sent["chatUpdReq"]["LocalHistoryId"].asInteger().get_int(), QSEG_A, QSEG_B);
|
||||
}
|
||||
|
||||
void poll_update_chat(SqliteConnection& conn, const json::JSON& Sent, json::JSON& Recv) {
|
||||
poll_update_chat_important_segment(conn, Sent, Recv, -1, -2);
|
||||
}
|
||||
|
||||
json::JSON internalapi_chatPollEvents(SqliteConnection& conn, int64_t uid, const json::JSON& Sent) {
|
||||
int64_t chatId = Sent["chatUpdReq"]["chatId"].asInteger().get_int();
|
||||
if (get_role_of_user_in_chat(conn, uid, chatId) == user_chat_role_deleted)
|
||||
een9_THROW("chatPollEvents: trying to access chat that user does not belong to");
|
||||
json::JSON Recv;
|
||||
poll_update_chat(conn, Sent, Recv);
|
||||
return Recv;
|
||||
}
|
||||
|
||||
json::JSON internalapi_chatListPollEvents(SqliteConnection& conn, int64_t uid, const json::JSON& Sent) {
|
||||
json::JSON Recv;
|
||||
poll_update_chat_list(conn, uid, Sent, Recv);
|
||||
return Recv;
|
||||
}
|
||||
|
||||
|
||||
/* Reznya */
|
||||
json::JSON internalapi_getMessageNeighbours(SqliteConnection& conn, int64_t uid, const json::JSON& Sent) {
|
||||
int64_t chatId = Sent["chatId"].asInteger().get_int();
|
||||
if (get_role_of_user_in_chat(conn, uid, chatId) == user_chat_role_deleted)
|
||||
een9_THROW("Authentication failure");
|
||||
int64_t lastMsgId = get_lastMsgId_of_chat(conn, chatId);
|
||||
bool dir_forward = Sent["direction"].asString() == "forward";
|
||||
int64_t amount = Sent["amount"].asInteger().get_int();
|
||||
int64_t K = Sent["msgId"].asInteger().get_int();
|
||||
if (amount <= 0 || amount > 15)
|
||||
een9_THROW("Incorrect amount");
|
||||
json::JSON Recv;
|
||||
int64_t qBeg = -1;
|
||||
int64_t qEnd = -2;
|
||||
if (lastMsgId >= 0) {
|
||||
if (K < 0) {
|
||||
if (dir_forward)
|
||||
een9_THROW("Can't go from the top of chat");
|
||||
qBeg = std::max(0l, lastMsgId - amount + 1);
|
||||
qEnd = lastMsgId;
|
||||
} else if (dir_forward) {
|
||||
qBeg = K + 1;
|
||||
qEnd = K + amount;
|
||||
} else {
|
||||
qBeg = K - amount;
|
||||
qEnd = K - 1;
|
||||
}
|
||||
}
|
||||
poll_update_chat_important_segment(conn, Sent, Recv, qBeg, qEnd);
|
||||
return Recv;
|
||||
}
|
||||
}
|
@ -2,6 +2,7 @@
|
||||
|
||||
#include <engine_engine_number_9/baza_throw.h>
|
||||
#include <engine_engine_number_9/http_structures/cookies.h>
|
||||
#include "../str_fields.h"
|
||||
|
||||
namespace iu9cawebchat {
|
||||
const char* stringify_user_chat_role(int64_t role) {
|
||||
@ -27,7 +28,7 @@ namespace iu9cawebchat {
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::string find_user_name (SqliteConnection& conn, int64_t uid) {
|
||||
std::string get_user_name (SqliteConnection& conn, int64_t uid) {
|
||||
een9_ASSERT(uid >= 0, "Are you crazy?");
|
||||
SqliteStatement sql_req(conn,
|
||||
"SELECT `name` FROM `user` WHERE `id` = ?1",
|
||||
@ -50,7 +51,20 @@ namespace iu9cawebchat {
|
||||
fsql_text8_or_null name_col;
|
||||
int status = sqlite_stmt_step(sql_req, {}, {{0, &nickname_col}, {1, &name_col}});
|
||||
if (status == SQLITE_ROW) {
|
||||
return {std::move(nickname_col.value), std::move(name_col.value)};
|
||||
return {uid, std::move(nickname_col.value), std::move(name_col.value)};
|
||||
}
|
||||
een9_THROW("No such user");
|
||||
}
|
||||
|
||||
RowUser_Content lookup_user_content_by_nickname(SqliteConnection& conn, const std::string& nickname) {
|
||||
SqliteStatement sql_req(conn,
|
||||
"SELECT `id`, `name` FROM `user` WHERE `nickname` = ?1",
|
||||
{}, {{1, nickname}});
|
||||
fsql_integer_or_null id_col;
|
||||
fsql_text8_or_null name_col;
|
||||
int status = sqlite_stmt_step(sql_req, {{0, &id_col}}, {{1, &name_col}});
|
||||
if (status == SQLITE_ROW) {
|
||||
return {id_col.value, nickname, std::move(name_col.value)};
|
||||
}
|
||||
een9_THROW("No such user");
|
||||
}
|
||||
@ -65,7 +79,22 @@ namespace iu9cawebchat {
|
||||
fsql_integer_or_null last_msg_id_col;
|
||||
int status = sqlite_stmt_step(sql_req, {{2, &last_msg_id_col}}, {{0, &nickname_col}, {1, &name_col}});
|
||||
if (status == SQLITE_ROW) {
|
||||
return {std::move(nickname_col.value), std::move(name_col.value),
|
||||
return {chatId, std::move(nickname_col.value), std::move(name_col.value),
|
||||
last_msg_id_col.exist ? last_msg_id_col.value : -1};
|
||||
}
|
||||
een9_THROW("No such chat");
|
||||
}
|
||||
|
||||
RowChat_Content lookup_chat_content_by_nickname(SqliteConnection &conn, const std::string& nickname) {
|
||||
SqliteStatement sql_req(conn,
|
||||
"SELECT `id`, `name`, `lastMsgId` FROM `chat` WHERE `nickname` = ?1",
|
||||
{}, {{1, nickname}});
|
||||
fsql_integer_or_null id_col;
|
||||
fsql_text8_or_null name_col;
|
||||
fsql_integer_or_null last_msg_id_col;
|
||||
int status = sqlite_stmt_step(sql_req, {{0, &id_col}, {2, &last_msg_id_col}}, {{1, &name_col}});
|
||||
if (status == SQLITE_ROW) {
|
||||
return {id_col.value, nickname, std::move(name_col.value),
|
||||
last_msg_id_col.exist ? last_msg_id_col.value : -1};
|
||||
}
|
||||
een9_THROW("No such chat");
|
||||
@ -73,39 +102,21 @@ namespace iu9cawebchat {
|
||||
|
||||
RowMessage_Content lookup_message_content(SqliteConnection& conn, int64_t chatId, int64_t msgId) {
|
||||
SqliteStatement req(conn,
|
||||
"SELECT `previousId`, `senderUserId`, `exists`, `isSystem`, `text` FROM `message` WHERE "
|
||||
"SELECT `senderUserId`, `exists`, `isSystem`, `text` FROM `message` WHERE "
|
||||
"`chatId` = ?1 AND `id` = ?2", {{1, chatId}, {2, msgId}}, {});
|
||||
fsql_integer_or_null previousId, senderUserId, exists, isSystem;
|
||||
fsql_integer_or_null senderUserId, exists, isSystem;
|
||||
fsql_text8_or_null msg_text;
|
||||
int status = sqlite_stmt_step(req, {{0, &previousId}, {1, &senderUserId}, {2, &exists}, {3, &isSystem}},
|
||||
{{4, &msg_text}});
|
||||
int status = sqlite_stmt_step(req, {{0, &senderUserId}, {1, &exists}, {2, &isSystem}},
|
||||
{{3, &msg_text}});
|
||||
if (status == SQLITE_ROW) {
|
||||
if (!(bool)exists.value)
|
||||
een9_THROW("Message existed, but now it isn't");
|
||||
return {(bool)isSystem.value, msg_text.value, senderUserId.exist ? senderUserId.value : -1,
|
||||
previousId.exist ? previousId.value : -1};
|
||||
een9_THROW("Message existed, but now it does not");
|
||||
return {msgId, senderUserId.exist ? senderUserId.value : -1, (bool)exists.value,
|
||||
(bool)isSystem.value, msg_text.value};
|
||||
}
|
||||
een9_THROW("No such message");
|
||||
}
|
||||
|
||||
std::pair<int64_t, RowMessage_Content> lookup_message_content_rev_side(SqliteConnection& conn, int64_t chatId, int64_t prevMsgId) {
|
||||
een9_ASSERT(prevMsgId >= 0, "V durku dobro pozhalovat");
|
||||
SqliteStatement req(conn,
|
||||
"SELECT `id`, `senderUserId`, `exists`, `isSystem`, `text` FROM `message` WHERE "
|
||||
"`chatId` = ?1 AND `previous` = ?2", {{1, chatId}, {2, prevMsgId}}, {});
|
||||
fsql_integer_or_null id, senderUserId, exists, isSystem;
|
||||
fsql_text8_or_null msg_text;
|
||||
int status = sqlite_stmt_step(req, {{0, &id}, {1, &senderUserId}, {2, &exists}, {3, &isSystem}},
|
||||
{{4, &msg_text}});
|
||||
if (status == SQLITE_ROW) {
|
||||
een9_ASSERT_pl(exists.value == 1);
|
||||
return {id.value,
|
||||
{(bool)isSystem.value, msg_text.value, senderUserId.exist ? senderUserId.value : -1, prevMsgId}};
|
||||
}
|
||||
return {-1, {}};
|
||||
}
|
||||
|
||||
|
||||
int64_t get_role_of_user_in_chat(SqliteConnection& conn, int64_t userId, int64_t chatId) {
|
||||
SqliteStatement req(conn,
|
||||
"SELECT `role` FROM `user_chat_membership` WHERE `userId` = ?1 AND `chatId` = ?2",
|
||||
@ -132,4 +143,103 @@ namespace iu9cawebchat {
|
||||
|
||||
/* All the api calls processing is done in dedicated files.
|
||||
* All functions related to polling are defined in api_pollevents.cpp */
|
||||
|
||||
// todo: move everything to dedicated files
|
||||
int64_t get_current_history_id_of_chat(SqliteConnection& conn, int64_t chatId) {
|
||||
SqliteStatement req(conn, "SELECT `it_HistoryId` FROM `chat` WHERE `id` = ?1", {{1, chatId}}, {});
|
||||
fsql_integer_or_null HistoryId;
|
||||
int status = sqlite_stmt_step(req, {{0, &HistoryId}}, {});
|
||||
een9_ASSERT_pl(status == SQLITE_ROW);
|
||||
return HistoryId.value;
|
||||
}
|
||||
|
||||
int64_t get_current_history_id_of_user_chatList(SqliteConnection& conn, int64_t userId) {
|
||||
SqliteStatement req(conn, "SELECT `chatList_HistoryId` FROM `user` WHERE `id` = ?1", {{1, userId}}, {});
|
||||
fsql_integer_or_null HistoryId;
|
||||
int status = sqlite_stmt_step(req, {{0, &HistoryId}}, {});
|
||||
een9_ASSERT_pl(status == SQLITE_ROW);
|
||||
return HistoryId.value;
|
||||
}
|
||||
|
||||
|
||||
// todo: extract useful clues from deprecated code.
|
||||
// todo: deprecated code goes here:
|
||||
/* !!! DEPRECATED FUNCTION */
|
||||
json::JSON toremoveinternalapi_getChatList(SqliteConnection& conn, int64_t uid, const json::JSON& Sent) {
|
||||
json::JSON Recv;
|
||||
Recv["status"] = json::JSON(0l);
|
||||
Recv["chats"] = json::JSON(json::array);
|
||||
std::vector<json::JSON>& chats = Recv["chats"].asArray();
|
||||
SqliteStatement req(conn,
|
||||
"SELECT `chat`.`id`, `chat`.`nickname`, `chat`.`name`, `chat`.`lastMsgId`, "
|
||||
"`user_chat_membership`.`role` FROM `chat` "
|
||||
"RIGHT JOIN `user_chat_membership` ON `chat`.`id` = `user_chat_membership`.`chatId` "
|
||||
"WHERE `user_chat_membership`.`userId` = ?1 ", {{1, uid}}, {});
|
||||
while (true) {
|
||||
fsql_integer_or_null chat_id;
|
||||
fsql_text8_or_null chat_nickname, chat_name;
|
||||
fsql_integer_or_null chat_lastMsgId, role_here;
|
||||
int status = sqlite_stmt_step(req, {{0, &chat_id}, {3, &chat_lastMsgId}, {4, &role_here}},
|
||||
{{1, &chat_nickname}, {2, &chat_name}});
|
||||
if (status != SQLITE_ROW)
|
||||
break;
|
||||
chats.emplace_back();
|
||||
json::JSON& chat = chats.back();
|
||||
chat["id"] = json::JSON(chat_id.value);
|
||||
chat["content"]["nickname"] = json::JSON(chat_nickname.value);
|
||||
chat["content"]["name"] = json::JSON(chat_name.value);
|
||||
chat["content"]["lastMsgId"] = json::JSON(chat_lastMsgId.exist ? chat_lastMsgId.value : -1);
|
||||
chat["content"]["roleHere"] = json::JSON(stringify_user_chat_role(role_here.value));
|
||||
}
|
||||
return Recv;
|
||||
}
|
||||
|
||||
/* !!! DEPRECATED FUNCTION */
|
||||
json::JSON toremoveinternalapi_getChatMemberList(SqliteConnection& conn, int64_t uid, const json::JSON& Sent) {
|
||||
int64_t chatId = Sent["id"].asInteger().get_int();
|
||||
int64_t my_role_here = get_role_of_user_in_chat(conn, uid, chatId);
|
||||
if (my_role_here == user_chat_role_deleted)
|
||||
een9_THROW("Unauthorized user tries to access internalapi_getChatInfo");
|
||||
json::JSON Recv;
|
||||
Recv["status"] = json::JSON(0l);
|
||||
Recv["members"] = json::JSON(json::array);
|
||||
std::vector<json::JSON>& members = Recv["members"].asArray();
|
||||
SqliteStatement req(conn,
|
||||
"SELECT `user`.`id`, `user`.`nickname`, `user`.`name`, `user_chat_membership`.`role` FROM "
|
||||
"`user` RIGHT JOIN `user_chat_membership` ON `user`.`id` = `user_chat_membership`.`userId` "
|
||||
"WHERE `user_chat_membership`.`chatId` = ?1",
|
||||
{{1, chatId}}, {});
|
||||
while (true) {
|
||||
fsql_integer_or_null this_user_id;
|
||||
fsql_text8_or_null this_user_nickname, this_user_name;
|
||||
fsql_integer_or_null this_users_role;
|
||||
int status = sqlite_stmt_step(req, {{0, &this_user_id}, {3, &this_users_role}},
|
||||
{{1, &this_user_nickname}, {2, &this_user_name}});
|
||||
if (status != SQLITE_ROW)
|
||||
break;
|
||||
members.emplace_back();
|
||||
json::JSON& member = members.back();
|
||||
member["id"] = json::JSON(this_user_id.value);
|
||||
member["content"]["nickname"] = json::JSON(this_user_nickname.value);
|
||||
member["content"]["name"] = json::JSON(this_user_name.value);
|
||||
member["content"]["role"] = json::JSON(this_users_role.value);
|
||||
}
|
||||
return Recv;
|
||||
}
|
||||
|
||||
bool is_nickname_taken(SqliteConnection& conn, const std::string& nickname) {
|
||||
if (!check_nickname(nickname))
|
||||
return true;
|
||||
SqliteStatement req(conn, "SELECT EXISTS(SELECT 1 FROM `nickname` WHERE `it` = ?1)",
|
||||
{}, {{1, nickname}});
|
||||
fsql_integer_or_null r{true, 0};
|
||||
int status = sqlite_stmt_step(req, {{0, &r}}, {});
|
||||
return r.value;
|
||||
}
|
||||
|
||||
void reserve_nickname(SqliteConnection& conn, const std::string& nickname) {
|
||||
if (!check_nickname(nickname))
|
||||
een9_THROW("PRECAUTION! Trying to insert incorrect nickname into nickname table");
|
||||
sqlite_nooutput(conn, "INSERT INTO `nickname` (`it`) VALUES (?1)", {}, {{1, nickname}});
|
||||
}
|
||||
}
|
||||
|
@ -16,62 +16,70 @@ namespace iu9cawebchat {
|
||||
const char* stringify_user_chat_role(int64_t role);
|
||||
|
||||
int64_t find_user_by_credentials (SqliteConnection& conn, const std::string& nickname, const std::string& password);
|
||||
std::string find_user_name (SqliteConnection& conn, int64_t uid);
|
||||
std::string get_user_name (SqliteConnection& conn, int64_t uid);
|
||||
|
||||
struct RowUser_Content {
|
||||
int64_t id;
|
||||
std::string nickname;
|
||||
std::string name;
|
||||
};
|
||||
|
||||
struct RowChat_Content {
|
||||
int64_t id;
|
||||
std::string nickname;
|
||||
std::string name;
|
||||
int64_t lastMsgId; // Negative if it does not exist
|
||||
};
|
||||
|
||||
RowUser_Content lookup_user_content(SqliteConnection& conn, int64_t uid);
|
||||
RowUser_Content lookup_user_content_by_nickname(SqliteConnection& conn, const std::string& nickname);
|
||||
/* Does not make authorization check */
|
||||
RowChat_Content lookup_chat_content(SqliteConnection& conn, int64_t chatId);
|
||||
RowChat_Content lookup_chat_content_by_nickname(SqliteConnection &conn, const std::string& nickname);
|
||||
|
||||
struct RowMessage_Content {
|
||||
int64_t id;
|
||||
int64_t senderUserId;
|
||||
bool exists;
|
||||
bool isSystem;
|
||||
std::string text;
|
||||
int64_t senderUserId;
|
||||
int64_t previous = -1;
|
||||
};
|
||||
|
||||
RowMessage_Content lookup_message_content(SqliteConnection& conn, int64_t chatId, int64_t msgId);
|
||||
|
||||
/* If prevMsgId is id of the last message in chat, and there is no message ahead of it, .first = -1 */
|
||||
std::pair<int64_t, RowMessage_Content> lookup_message_content_rev_side(SqliteConnection& conn, int64_t chatId, int64_t prevMsgId);
|
||||
|
||||
/* Does not make authorization check */
|
||||
int64_t get_role_of_user_in_chat(SqliteConnection& conn, int64_t userId, int64_t chatId);
|
||||
/* Does not make authorization check */
|
||||
int64_t get_lastMsgId_of_chat(SqliteConnection& conn, int64_t chatId);
|
||||
|
||||
/* ============================= API ====================================*/
|
||||
int64_t get_current_history_id_of_chat(SqliteConnection& conn, int64_t chatId);
|
||||
int64_t get_current_history_id_of_user_chatList(SqliteConnection& conn, int64_t userId);
|
||||
/* Returns HistoryId of chat (latest) */
|
||||
int64_t event_polling_fill_chat_hist_entity_response(SqliteConnection& conn, json::JSON& hist_entity_response,
|
||||
int64_t uid, int64_t chatId, int64_t LocalHistoryId);
|
||||
/* Returns HistoryId of chat list (latest) */
|
||||
int64_t event_polling_fill_chatlist_hist_entity_response(SqliteConnection& conn, json::JSON& hist_entity_response,
|
||||
int64_t uid, int64_t LocalHistoryId);
|
||||
json::JSON internalapi_pollEvents(SqliteConnection& conn, int64_t uid, const json::JSON& Sent);
|
||||
json::JSON internalapi_getChatList(SqliteConnection& conn, int64_t uid, const json::JSON& Sent);
|
||||
json::JSON internalapi_getChatInfo(SqliteConnection& conn, int64_t uid, const json::JSON& Sent);
|
||||
json::JSON internalapi_getChatMemberList(SqliteConnection& conn, int64_t uid, const json::JSON& Sent);
|
||||
json::JSON internalapi_getUserInfo(SqliteConnection& conn, int64_t uid, const json::JSON& Sent);
|
||||
json::JSON internalapi_getMessageInfo(SqliteConnection& conn, int64_t uid, const json::JSON& Sent);
|
||||
|
||||
json::JSON poll_update_chat_list_resp(SqliteConnection& conn, int64_t userId, int64_t LocalHistoryId);
|
||||
void poll_update_chat_list(SqliteConnection& conn, int64_t userId, const json::JSON& Sent, json::JSON& Recv);
|
||||
|
||||
json::JSON poll_update_chat_ONE_MSG_resp(SqliteConnection& conn, int64_t chatId, int64_t selectedMsg);
|
||||
void poll_update_chat(SqliteConnection& conn, const json::JSON& Sent, json::JSON& Recv);
|
||||
|
||||
void make_her_a_member_of_the_midnight_crew(SqliteConnection& conn, int64_t chatId, int64_t alienUserId, int64_t role);
|
||||
void kick_from_chat(SqliteConnection& conn, int64_t alienUserId, int64_t chatId);
|
||||
|
||||
bool is_nickname_taken(SqliteConnection& conn, const std::string& nickname);
|
||||
void reserve_nickname(SqliteConnection& conn, const std::string& nickname);
|
||||
|
||||
/* ============================= API ==================================== */
|
||||
json::JSON internalapi_chatPollEvents(SqliteConnection& conn, int64_t uid, const json::JSON& Sent);
|
||||
json::JSON internalapi_chatListPollEvents(SqliteConnection& conn, int64_t uid, const json::JSON& Sent);
|
||||
json::JSON internalapi_getMessageNeighbours(SqliteConnection& conn, int64_t uid, const json::JSON& Sent);
|
||||
json::JSON internalapi_sendMessage(SqliteConnection& conn, int64_t uid, const json::JSON& Sent);
|
||||
json::JSON internalapi_deleteMessage(SqliteConnection& conn, int64_t uid, const json::JSON& Sent);
|
||||
json::JSON internalapi_addMemberToChat(SqliteConnection& conn, int64_t uid, const json::JSON& Sent);
|
||||
json::JSON internalapi_removeMemberFromChat(SqliteConnection& conn, int64_t uid, const json::JSON& Sent);
|
||||
json::JSON internalapi_createChat(SqliteConnection& conn, int64_t uid, const json::JSON& Sent);
|
||||
json::JSON internalapi_removeChat(SqliteConnection& conn, int64_t uid, const json::JSON& Sent);
|
||||
json::JSON internalapi_leaveChat(SqliteConnection& conn, int64_t uid, const json::JSON& Sent);
|
||||
|
||||
/**/
|
||||
std::string admin_control_procedure(SqliteConnection& conn, const std::string& req, bool& termination);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -1,8 +1,54 @@
|
||||
#include "client_server_interact.h"
|
||||
|
||||
#include <engine_engine_number_9/baza_throw.h>
|
||||
#include "../str_fields.h"
|
||||
|
||||
namespace iu9cawebchat {
|
||||
std::string when_page_chat(WorkerGuestData& wgd, const json::JSON& config_presentation,
|
||||
const een9::ClientRequest& req, const json::JSON& userinfo) {
|
||||
return R200_pres_uinfo("chat", config_presentation, wgd, userinfo);
|
||||
const een9::ClientRequest& req, const json::JSON& userinfo) {
|
||||
|
||||
std::vector<std::string> path_segs = {""};
|
||||
path_segs.reserve(4);
|
||||
for (char ch: req.uri_path) {
|
||||
if (ch == '/')
|
||||
path_segs.emplace_back();
|
||||
else
|
||||
path_segs.back() += ch;
|
||||
}
|
||||
// Parameter, passed from server to javascript
|
||||
std::string chat_nickname;
|
||||
int64_t selected_message_id = -1;
|
||||
if (path_segs.size() >= 2) {
|
||||
chat_nickname = std::move(path_segs[1]);
|
||||
}
|
||||
if (!check_nickname(chat_nickname))
|
||||
return page_E404(wgd);
|
||||
if (path_segs.size() == 2) {
|
||||
} else if (path_segs.size() == 4) {
|
||||
if (path_segs[2] != "m")
|
||||
return page_E404(wgd);
|
||||
selected_message_id = std::stoll(path_segs[3]);
|
||||
return page_E404(wgd);
|
||||
} else
|
||||
return page_E404(wgd);
|
||||
|
||||
bool chat_members = (path_segs[0] == "chat-members");
|
||||
|
||||
|
||||
// todo: do not throw id chat not found, catch exception and return 404
|
||||
json::JSON openedchat;
|
||||
RowChat_Content chatInfo = lookup_chat_content_by_nickname(*wgd.db, chat_nickname);
|
||||
if (get_role_of_user_in_chat(*wgd.db, userinfo["id"].asInteger().get_int(), chatInfo.id) == user_chat_role_deleted) {
|
||||
return page_E404(wgd);
|
||||
}
|
||||
|
||||
openedchat["name"] = json::JSON(chatInfo.name);
|
||||
openedchat["nickname"] = json::JSON(chatInfo.nickname);
|
||||
openedchat["id"] = json::JSON(chatInfo.id);
|
||||
openedchat["selectedMessageId"] = json::JSON(selected_message_id); // -1 means that nothing was selected
|
||||
json::JSON initial_chatUpdResp = poll_update_chat_ONE_MSG_resp(*wgd.db, chatInfo.id, selected_message_id);
|
||||
if (chat_members)
|
||||
return http_R200("chat", wgd, {&config_presentation, &userinfo, &openedchat, &initial_chatUpdResp});
|
||||
return http_R200("chat", wgd, {&config_presentation, &userinfo, &openedchat, &initial_chatUpdResp});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,8 @@ namespace iu9cawebchat {
|
||||
if (userinfo.isNull()) {
|
||||
return een9::form_http_server_response_303("/login");
|
||||
}
|
||||
return R200_pres_uinfo("list-rooms", config_presentation, wgd, userinfo);
|
||||
json::JSON initial_chatListUpdResp = poll_update_chat_list_resp(*wgd.db,
|
||||
userinfo["uid"].asInteger().get_int(), 0);
|
||||
return http_R200("list-rooms", wgd, {&config_presentation, &userinfo, &initial_chatListUpdResp});
|
||||
}
|
||||
}
|
||||
|
@ -25,15 +25,18 @@ namespace iu9cawebchat {
|
||||
} catch(const std::exception& e){}
|
||||
if (uid < 0) {
|
||||
printf("Redirecting back to /login because of incorrect credentials\n");
|
||||
// class will be successfully ignored
|
||||
return R200_pres_uinfo_msges("login", wgd, config_presentation, userinfo, {{"",
|
||||
config_presentation["phr"]["decl"]["incorrect-nickname-or-password"].g().asString()}});
|
||||
json::JSON msg_list = jsonify_html_message_list({{"",
|
||||
config_presentation["phr"]["decl"]["incorrect-nickname-or-password"].asString()}});
|
||||
return http_R200("login", wgd, {&config_presentation, &userinfo, &msg_list});
|
||||
}
|
||||
std::vector<std::pair<std::string, std::string>> response_hlines;
|
||||
LoginCookie new_login_cookie = create_login_cookie(nickname, password);
|
||||
add_set_cookie_headers_to_login(login_cookies, response_hlines, new_login_cookie);
|
||||
return een9::form_http_server_response_303_spec_head("/", response_hlines);
|
||||
}
|
||||
return R200_pres_uinfo_msges("login", wgd, config_presentation, userinfo, {});
|
||||
if (req.method != "GET")
|
||||
een9_THROW("Bad method");
|
||||
json::JSON empty_msg_list = json::JSON(json::array);
|
||||
return http_R200("login", wgd, {&config_presentation, &userinfo, &empty_msg_list});
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,111 @@
|
||||
#include "client_server_interact.h"
|
||||
#include <engine_engine_number_9/form_data_structure/urlencoded_query.h>
|
||||
#include <engine_engine_number_9/baza_throw.h>
|
||||
#include <string.h>
|
||||
#include "../str_fields.h"
|
||||
#include "../login_cookie.h"
|
||||
|
||||
namespace iu9cawebchat {
|
||||
std::string get_user_bio(SqliteConnection& conn, int64_t userId) {
|
||||
een9_ASSERT(userId >= 0, "Are you crazy?");
|
||||
SqliteStatement sql_req(conn, "SELECT `bio` FROM `user` WHERE `id` = ?1", {{1, userId}}, {});
|
||||
fsql_text8_or_null bio_col;
|
||||
int status = sqlite_stmt_step(sql_req, {}, {{0, &bio_col}});
|
||||
if (status == SQLITE_ROW)
|
||||
return bio_col.value;
|
||||
een9_THROW("No such user");
|
||||
}
|
||||
|
||||
static const char* pr_path = "/user/";
|
||||
|
||||
bool is_page_of_certain_user(const std::string& path) {
|
||||
if (!een9::beginsWith(path, pr_path))
|
||||
return false;
|
||||
std::string r = path.substr(strlen(pr_path));
|
||||
return check_nickname(r);
|
||||
}
|
||||
|
||||
std::string obtain_nickname_in_user_page_path(const std::string& path) {
|
||||
return path.substr(strlen(pr_path));
|
||||
}
|
||||
|
||||
json::JSON user_row_to_userprofile_obj(SqliteConnection& conn, const RowUser_Content& alien) {
|
||||
return json::JSON(json::jdict{
|
||||
{"name", json::JSON(alien.name)},
|
||||
{"nickname", json::JSON(alien.nickname)},
|
||||
{"bio", json::JSON(get_user_bio(conn, alien.id))}
|
||||
});
|
||||
}
|
||||
|
||||
std::string when_page_user(WorkerGuestData& wgd, const json::JSON& config_presentation,
|
||||
const een9::ClientRequest& req, const json::JSON& userinfo) {
|
||||
return R200_pres_uinfo("profile", config_presentation, wgd, userinfo);
|
||||
const een9::ClientRequest& req, const std::vector<LoginCookie>& login_cookies, const json::JSON& userinfo) {
|
||||
SqliteConnection& conn = *wgd.db;
|
||||
if (!is_page_of_certain_user(req.uri_path))
|
||||
return page_E404(wgd);
|
||||
std::string alien_nickname = obtain_nickname_in_user_page_path(req.uri_path);
|
||||
RowUser_Content alien;
|
||||
try {
|
||||
alien = lookup_user_content_by_nickname(conn, alien_nickname);
|
||||
} catch (const std::exception& e) {
|
||||
return page_E404(wgd);
|
||||
}
|
||||
// todo: in libjsonincpp: fix '999999 problem'
|
||||
int64_t myuid = userinfo["uid"].asInteger().get_int();
|
||||
bool can_edit = (alien.id == myuid);
|
||||
if (req.method == "POST") {
|
||||
std::vector<std::pair<std::string, std::string>> response_hlines;
|
||||
try {
|
||||
if (!can_edit)
|
||||
een9_THROW("Unauthorized access");
|
||||
std::vector<std::pair<std::string, std::string>> query = een9::split_html_query(req.body);
|
||||
// Profile update processing
|
||||
std::string bio;
|
||||
std::string name;
|
||||
std::string password;
|
||||
for (const std::pair<std::string, std::string>& p: query) {
|
||||
if (p.first == "bio")
|
||||
bio = p.second;
|
||||
else if (p.first == "name")
|
||||
name = p.second;
|
||||
else if (p.first == "password")
|
||||
password = p.second;
|
||||
}
|
||||
if (!bio.empty()) {
|
||||
if (!is_orthodox_string(bio) || bio.size() > 100000)
|
||||
een9_THROW("Incorrect `bio`");
|
||||
sqlite_nooutput(conn, "UPDATE `user` SET `bio` = ?1", {}, {{1, bio}});
|
||||
}
|
||||
if (!name.empty()) {
|
||||
if (!check_name(name))
|
||||
een9_THROW("Incorrect `name`");
|
||||
sqlite_nooutput(conn, "UPDATE `user` SET `name` = ?1", {}, {{1, name}});
|
||||
}
|
||||
if (!password.empty()) {
|
||||
if (!check_strong_password(password))
|
||||
een9_THROW("Incorrect `password`");
|
||||
sqlite_nooutput(conn, "UPDATE `user` SET `password` = ?1", {}, {{1, password}});
|
||||
if (alien.id == myuid) {
|
||||
LoginCookie new_login_cookie = create_login_cookie(userinfo["nickname"].asString(), password);
|
||||
add_set_cookie_headers_to_login(login_cookies, response_hlines, new_login_cookie);
|
||||
}
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
printf("Redirecting back to /user/... because of incorrect credentials\n");
|
||||
json::JSON msg_list = jsonify_html_message_list({{"",
|
||||
config_presentation["phr"]["decl"]["incorrect-profile-data"].asString()}});
|
||||
json::JSON alien_userprofile = user_row_to_userprofile_obj(conn, alien);
|
||||
return http_R200("edit-profile", wgd, {&config_presentation, &alien_userprofile, &msg_list});
|
||||
}
|
||||
return een9::form_http_server_response_303_spec_head("/user/" + alien_nickname, response_hlines);
|
||||
}
|
||||
if (req.method == "GET") {
|
||||
json::JSON alien_userprofile = user_row_to_userprofile_obj(conn, alien);
|
||||
if (can_edit) {
|
||||
json::JSON empty_msg_list = jsonify_html_message_list({});
|
||||
return http_R200("edit-profile", wgd, {&config_presentation, &alien_userprofile, &empty_msg_list});
|
||||
}
|
||||
return http_R200("view-profile", wgd, {&config_presentation, &alien_userprofile});
|
||||
}
|
||||
een9_THROW("Bad method");
|
||||
}
|
||||
}
|
||||
|
@ -2,15 +2,17 @@
|
||||
|
||||
namespace iu9cawebchat{
|
||||
int find_db_sqlite_file_path(const json::JSON& config, std::string& res_path) {
|
||||
const json::JSON& type = config["database"]["type"].g();
|
||||
if (!type.isString() && type.asString() == "sqlite3")
|
||||
try {
|
||||
const std::string& type = config["database"]["type"].asString();
|
||||
if (type != "sqlite3")
|
||||
return -1;
|
||||
const std::string& path = config["database"]["file"].asString();
|
||||
if (path.empty() || path[0] == ':')
|
||||
return -1;
|
||||
res_path = path;
|
||||
} catch (const json::misuse& e) {
|
||||
return -1;
|
||||
const json::JSON& path = config["database"]["file"].g();
|
||||
if (!path.isString())
|
||||
return -1;
|
||||
if (path.asString().empty() || path.asString()[0] == ':')
|
||||
return -1;
|
||||
res_path = path.asString();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -44,36 +44,38 @@ namespace iu9cawebchat {
|
||||
"`nickname` TEXT UNIQUE REFERENCES `nickname` NOT NULL,"
|
||||
"`name` TEXT NOT NULL,"
|
||||
"`chatList_HistoryId` INTEGER NOT NULL,"
|
||||
"`password` TEXT NOT NULL"
|
||||
"`password` TEXT NOT NULL,"
|
||||
"`bio` TEXT NOT NULL"
|
||||
")");
|
||||
sqlite_nooutput(conn, "CREATE TABLE `chat` ("
|
||||
"`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,"
|
||||
"`nickname` TEXT UNIQUE REFERENCES `nickname` NOT NULL,"
|
||||
"`name` TEXT NOT NULL,"
|
||||
"`it_HistoryId` INTEGER NOT NULL,"
|
||||
"`lastMsgId` INTEGER REFERENCES `message`"
|
||||
"`lastMsgId` INTEGER NOT NULL"
|
||||
")");
|
||||
sqlite_nooutput(conn, "CREATE TABLE `user_chat_membership` ("
|
||||
"`userId` INTEGER REFERENCES `user` NOT NULL,"
|
||||
"`chatId` INTEGER REFERENCES `chat` NOT NULL,"
|
||||
"`user_chatList_IncHistoryId` INTEGER NOT NULL,"
|
||||
"`chat_IncHistoryId` INTEGER NOT NULL,"
|
||||
"`role` INTEGER NOT NULL"
|
||||
"`role` INTEGER NOT NULL,"
|
||||
"UNIQUE (`userId`, `chatId`)"
|
||||
")");
|
||||
sqlite_nooutput(conn, "CREATE TABLE `message` ("
|
||||
"`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,"
|
||||
"`chatId` INTEGER REFERENCES `chat` NOT NULL,"
|
||||
"`previous` INTEGER REFERENCES `message`,"
|
||||
"`id` INTEGER NOT NULL,"
|
||||
"`senderUserId` INTEGER REFERENCES `user`,"
|
||||
"`exists` BOOLEAN NOT NULL,"
|
||||
"`isSystem` BOOLEAN NOT NULL,"
|
||||
"`text` TEXT NOT NULL,"
|
||||
"`chat_IncHistoryId` INTEGER NOT NULL"
|
||||
"`text` TEXT,"
|
||||
"`chat_IncHistoryId` INTEGER NOT NULL,"
|
||||
"PRIMARY KEY (`chatId`, `id`)"
|
||||
")");
|
||||
sqlite_nooutput(conn, "INSERT INTO `nickname` VALUES (?1)", {}, {{1, "root"}});
|
||||
sqlite_nooutput(conn, "INSERT INTO `user` (`id`, `nickname`, `name`, `chatList_HistoryId`, `password`) VALUES "
|
||||
"(0, ?1, ?2, 0, ?3)", {},
|
||||
{{1, "root"}, {2, "Rootov Root Rootovich"}, {3, root_pw}});
|
||||
sqlite_nooutput(conn, "INSERT INTO `user` (`id`, `nickname`, `name`, `chatList_HistoryId`, `password`, "
|
||||
"`bio` ) VALUES (0, ?1, ?2, 0, ?3, ?4)", {},
|
||||
{{1, "root"}, {2, "Rootov Root Rootovich"}, {3, root_pw}, {4, "One admin to rule them all"}});
|
||||
sqlite_nooutput(conn, "END");
|
||||
} catch (const std::exception& e) {
|
||||
sqlite_nooutput(conn, "ROLLBACK", {}, {});
|
||||
|
@ -23,8 +23,8 @@ namespace iu9cawebchat {
|
||||
uint64_t nsec = std::stoull(ft.substr(s_ + 1, ft.size() - s_ - 1));
|
||||
een9_ASSERT_pl(nsec < 1000000000);
|
||||
const json::JSON cnt = json::parse_str_flawless(base64_decode(login_cookie_encoded.second));
|
||||
std::string nickname = cnt[0].g().asString();
|
||||
std::string password = cnt[1].g().asString();
|
||||
std::string nickname = cnt[0].asString();
|
||||
std::string password = cnt[1].asString();
|
||||
return LoginCookie{{(time_t)sec, (time_t)nsec}, nickname, password};
|
||||
}
|
||||
|
||||
@ -37,8 +37,8 @@ namespace iu9cawebchat {
|
||||
|
||||
std::pair<std::string, std::string> encode_login_cookie(const LoginCookie& cookie) {
|
||||
json::JSON cnt;
|
||||
cnt[1].g() = cookie.password;
|
||||
cnt[0].g() = cookie.nickname;
|
||||
cnt[1].asString() = cookie.password;
|
||||
cnt[0].asString() = cookie.nickname;
|
||||
return {"login_" + std::to_string(cookie.login_time.tv_sec) + "_" + std::to_string(cookie.login_time.tv_nsec),
|
||||
base64_encode(json::generate_str(cnt, json::print_compact))};
|
||||
}
|
||||
|
@ -16,9 +16,25 @@ namespace iu9cawebchat {
|
||||
termination = true;
|
||||
}
|
||||
|
||||
struct ONE_SQLITE_TRANSACTION_GUARD {
|
||||
SqliteConnection& conn;
|
||||
bool rollback = false;
|
||||
|
||||
explicit ONE_SQLITE_TRANSACTION_GUARD(SqliteConnection& conn_) : conn(conn_) {
|
||||
sqlite_nooutput(conn, "BEGIN", {}, {});
|
||||
}
|
||||
|
||||
~ONE_SQLITE_TRANSACTION_GUARD() {
|
||||
if (rollback)
|
||||
sqlite_nooutput(conn, "ROLLBACK", {}, {});
|
||||
else
|
||||
sqlite_nooutput(conn, "END", {}, {});
|
||||
}
|
||||
};
|
||||
|
||||
void run_website(const json::JSON& config) {
|
||||
een9_ASSERT(config["assets"].g().isString(), "config[\"assets\"] is not string");
|
||||
std::string assets_dir = config["assets"].g().asString();
|
||||
een9_ASSERT(config["assets"].isString(), "config[\"assets\"] is not string");
|
||||
const std::string& assets_dir = config["assets"].asString();
|
||||
een9_ASSERT(een9::isDirectory(assets_dir), "\"" + assets_dir + "\" is not a directory");
|
||||
|
||||
een9::StaticAssetManagerSlaveModule samI;
|
||||
@ -30,8 +46,8 @@ namespace iu9cawebchat {
|
||||
} },
|
||||
});
|
||||
|
||||
const json::JSON& config_presentation = config["presentation"].g();
|
||||
int64_t slave_number = config["server"]["workers"].g().asInteger().get_int();
|
||||
const json::JSON& config_presentation = config["presentation"];
|
||||
int64_t slave_number = config["server"]["workers"].asInteger().get_int();
|
||||
een9_ASSERT(slave_number > 0 && slave_number <= 200, "E");
|
||||
|
||||
std::string sqlite_db_path;
|
||||
@ -52,13 +68,7 @@ namespace iu9cawebchat {
|
||||
een9_ASSERT_pl(0 <= worker_id && worker_id < worker_guest_data.size());
|
||||
WorkerGuestData& wgd = worker_guest_data[worker_id];
|
||||
een9::StaticAsset sa;
|
||||
sqlite_nooutput(*wgd.db, "BEGIN", {}, {});
|
||||
struct guard {SqliteConnection& conn; bool rollback = false; ~guard() {
|
||||
if (rollback)
|
||||
sqlite_nooutput(conn, "ROLLBACK", {}, {});
|
||||
else
|
||||
sqlite_nooutput(conn, "END", {}, {});
|
||||
}} guard_{*wgd.db};
|
||||
ONE_SQLITE_TRANSACTION_GUARD conn_guard(*wgd.db);
|
||||
try {
|
||||
std::vector<std::pair<std::string, std::string>> cookies;
|
||||
std::vector<LoginCookie> login_cookies;
|
||||
@ -72,53 +82,42 @@ namespace iu9cawebchat {
|
||||
if (req.uri_path == "/login") {
|
||||
return when_page_login(wgd, config_presentation, req, login_cookies, userinfo);
|
||||
}
|
||||
if (een9::beginsWith(req.uri_path, "/chat")) {
|
||||
// todo: split
|
||||
if (een9::beginsWith(req.uri_path, "/chat/") || een9::beginsWith(req.uri_path, "/chat-members/")) {
|
||||
return when_page_chat(wgd, config_presentation, req, userinfo);
|
||||
}
|
||||
if (req.uri_path == "/user") {
|
||||
return when_page_user(wgd, config_presentation, req, userinfo);
|
||||
if (een9::beginsWith(req.uri_path, "/user/")) {
|
||||
return when_page_user(wgd, config_presentation, req, login_cookies, userinfo);
|
||||
}
|
||||
if (req.uri_path == "/internalapi/pollEvents") {
|
||||
return when_internalapi_pollevents(wgd, req, logged_in_user);
|
||||
if (req.uri_path == "/api/chatPollEvents") {
|
||||
return when_internalapi_chatpollevents(wgd, req, logged_in_user);
|
||||
}
|
||||
if (req.uri_path == "/internalapi/getChatList") {
|
||||
return when_internalapi_getchatlist(wgd, req, logged_in_user);
|
||||
if (req.uri_path == "/api/chatListPollEvents") {
|
||||
return when_internalapi_chatlistpollevents(wgd, req, logged_in_user);
|
||||
}
|
||||
if (req.uri_path == "/internalapi/getChatInfo") {
|
||||
return when_internalapi_getchatinfo(wgd, req, logged_in_user);
|
||||
}
|
||||
if (req.uri_path == "/internalapi/getChatMemberList") {
|
||||
return when_internalapi_getchatmemberlist(wgd, req, logged_in_user);
|
||||
}
|
||||
if (req.uri_path == "/internalapi/getUserInfo") {
|
||||
return when_internalapi_getuserinfo(wgd, req, logged_in_user);
|
||||
}
|
||||
if (req.uri_path == "/internalapi/getMessageInfo") {
|
||||
return when_internalapi_getmessageinfo(wgd, req, logged_in_user);
|
||||
}
|
||||
if (req.uri_path == "/internalapi/getMessageNeighbours") {
|
||||
if (req.uri_path == "/api/getMessageNeighbours") {
|
||||
return when_internalapi_getmessageneighbours(wgd, req, logged_in_user);
|
||||
}
|
||||
if (req.uri_path == "/internalapi/sendMessage") {
|
||||
if (req.uri_path == "/api/sendMessage") {
|
||||
return when_internalapi_sendmessage(wgd, req, logged_in_user);
|
||||
}
|
||||
if (req.uri_path == "/internalapi/deleteMessage") {
|
||||
if (req.uri_path == "/api/deleteMessage") {
|
||||
return when_internalapi_deletemessage(wgd, req, logged_in_user);
|
||||
}
|
||||
if (req.uri_path == "/internalapi/addMemberToChat") {
|
||||
if (req.uri_path == "/api/addMemberToChat") {
|
||||
return when_internalapi_addmembertochat(wgd, req, logged_in_user);
|
||||
}
|
||||
if (req.uri_path == "/internalapi/removeMemberFromChat") {
|
||||
if (req.uri_path == "/api/removeMemberFromChat") {
|
||||
return when_internalapi_removememberfromchat(wgd, req, logged_in_user);
|
||||
}
|
||||
if (req.uri_path == "/internalapi/createChat") {
|
||||
if (req.uri_path == "/api/createChat") {
|
||||
return when_internalapi_createchat(wgd, req, logged_in_user);
|
||||
}
|
||||
if (req.uri_path == "/internalapi/removeChat") {
|
||||
return when_internalapi_removechat(wgd, req, logged_in_user);
|
||||
if (req.uri_path == "/api/leaveChat") {
|
||||
return when_internalapi_leavechat(wgd, req, logged_in_user);
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
guard_.rollback = true;
|
||||
conn_guard.rollback = true;
|
||||
throw;
|
||||
}
|
||||
/* Trying to interpret request as asset lookup */
|
||||
@ -133,29 +132,11 @@ namespace iu9cawebchat {
|
||||
(const een9::SlaveTask& task, const std::string& req, een9::worker_id_t worker_id) -> std::string {
|
||||
een9_ASSERT_pl(0 <= worker_id && worker_id < worker_guest_data.size());
|
||||
WorkerGuestData& wgd = worker_guest_data[worker_id];
|
||||
ONE_SQLITE_TRANSACTION_GUARD conn_guad(*wgd.db);
|
||||
try {
|
||||
if (req == "hello") {
|
||||
return ":0 omg! hiii!! Hewwou :3 !!!!\n";
|
||||
}
|
||||
if (req == "8") {
|
||||
termination = true;
|
||||
return "Bye\n";
|
||||
}
|
||||
std::string updaterootpw_pref = "updaterootpw";
|
||||
if (een9::beginsWith(req, "updaterootpw")) {
|
||||
size_t nid = updaterootpw_pref.size();
|
||||
if (nid >= req.size() || !isSPACE(req[nid]))
|
||||
return "Bad command syntax. Missing whitespace\n";
|
||||
std::string new_password = req.substr(nid + 1);
|
||||
if (!check_password(new_password))
|
||||
een9_THROW("Bad password");
|
||||
sqlite_nooutput(*wgd.db,
|
||||
"UPDATE `user` SET `password` = ?1 WHERE `id` = 0 ",
|
||||
{}, {{1, new_password}});
|
||||
return "Successul update\n";
|
||||
}
|
||||
return "Incorrect command\n";
|
||||
return admin_control_procedure(*wgd.db, req, termination);
|
||||
} catch (std::exception& e) {
|
||||
conn_guad.rollback = true;
|
||||
return std::string("Server error\n") + e.what();
|
||||
}
|
||||
};
|
||||
@ -171,8 +152,8 @@ namespace iu9cawebchat {
|
||||
een9_ASSERT(ret == 0, "Incorrect ear address: " + source[i].asString());
|
||||
}
|
||||
};
|
||||
translate_addr_list_conf(params.client_regular_listened, config["server"]["http-listen"].g().asArray());
|
||||
translate_addr_list_conf(params.admin_control_listened, config["server"]["admin-command-listen"].g().asArray());
|
||||
translate_addr_list_conf(params.client_regular_listened, config["server"]["http-listen"].asArray());
|
||||
translate_addr_list_conf(params.admin_control_listened, config["server"]["admin-command-listen"].asArray());
|
||||
|
||||
signal(SIGINT, sigterm_action);
|
||||
signal(SIGTERM, sigterm_action);
|
||||
|
@ -28,11 +28,15 @@ namespace iu9cawebchat {
|
||||
}
|
||||
|
||||
bool check_password(const std::string &pwd) {
|
||||
return is_orthodox_string(pwd) && pwd.size() >= 8;
|
||||
return is_orthodox_string(pwd) && pwd.size() <= 150;
|
||||
}
|
||||
|
||||
bool check_strong_password(const std::string& pwd) {
|
||||
return check_password(pwd) && pwd.size() >= 8;
|
||||
}
|
||||
|
||||
bool check_name(const std::string &name) {
|
||||
return is_orthodox_string(name);
|
||||
return is_orthodox_string(name) && name.size() <= 150;
|
||||
}
|
||||
|
||||
bool check_nickname(const std::string &nickname) {
|
||||
@ -42,7 +46,7 @@ namespace iu9cawebchat {
|
||||
if (!isUNCHAR(ch))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return nickname.size() <= 150;
|
||||
}
|
||||
|
||||
/* Yeah baby, it's base64 time!!! */
|
||||
|
@ -13,6 +13,7 @@ namespace iu9cawebchat {
|
||||
bool is_orthodox_string(const std::string& str);
|
||||
|
||||
bool check_password(const std::string& pwd);
|
||||
bool check_strong_password(const std::string& pwd);
|
||||
bool check_name(const std::string& name);
|
||||
bool check_nickname(const std::string& nickname);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user