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/
|
log/
|
||||||
core
|
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>
|
<!DOCTYPE html>
|
||||||
<html lang="ru">
|
<html lang="ru">
|
||||||
<head>
|
<head>
|
||||||
@ -8,6 +17,8 @@
|
|||||||
<link rel="stylesheet" href="/assets/css/chat.css">
|
<link rel="stylesheet" href="/assets/css/chat.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
{% PUT chat.pass pres userinfo openedchat initial_chatUpdResp %}
|
||||||
|
<!-- TODO AAAAA-->
|
||||||
<div class="chat-container">
|
<div class="chat-container">
|
||||||
<div class="chat-header">
|
<div class="chat-header">
|
||||||
<span class="room-name">Веб чат</span>
|
<span class="room-name">Веб чат</span>
|
||||||
@ -21,19 +32,6 @@
|
|||||||
<button class="chat-send-button" onclick="sendMessage()">Отправить</button>
|
<button class="chat-send-button" onclick="sendMessage()">Отправить</button>
|
||||||
</div>
|
</div>
|
||||||
</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>
|
<script src="/assets/js/chat.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</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>
|
<!DOCTYPE html>
|
||||||
<html lang="{% WRITE pres.lang %}">
|
<html lang="{% WRITE pres.lang %}">
|
||||||
<head>
|
<head>
|
||||||
@ -8,7 +8,11 @@
|
|||||||
<link rel="stylesheet" href="/assets/css/list-rooms.css">
|
<link rel="stylesheet" href="/assets/css/list-rooms.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<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">
|
<div class="container">
|
||||||
<h1 style="color: white;">Выберите Чат-Комнату</h1>
|
<h1 style="color: white;">Выберите Чат-Комнату</h1>
|
||||||
<ul class="room-list">
|
<ul class="room-list">
|
||||||
|
@ -9,10 +9,9 @@
|
|||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
{% PUT pass-pres-userinfo pres userinfo %}
|
|
||||||
{% FOR msg IN errors %}
|
{% FOR msg IN errors %}
|
||||||
<div class="error-msg">
|
<div class="error-msg">
|
||||||
{% WRITE msg %}
|
{% WRITE msg.text %}
|
||||||
</div>
|
</div>
|
||||||
{% ENDFOR %}
|
{% ENDFOR %}
|
||||||
<div class="form-container">
|
<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",
|
"login_cookie.cpp",
|
||||||
"backend_logic/server_data_interact.cpp",
|
"backend_logic/server_data_interact.cpp",
|
||||||
"backend_logic/client_server_interact.cpp",
|
"backend_logic/client_server_interact.cpp",
|
||||||
"backend_logic/when_list_rooms.cpp",
|
|
||||||
"backend_logic/when_login.cpp",
|
"backend_logic/polling.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",
|
|
||||||
};
|
};
|
||||||
for (std::string& u: T.units)
|
for (std::string& u: T.units)
|
||||||
u = "web_chat/iu9_ca_web_chat_lib/" + u;
|
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": "Название комнаты",
|
"name-of-room": "Название комнаты",
|
||||||
"create-room": "Создать комнату",
|
"create-room": "Создать комнату",
|
||||||
|
|
||||||
"incorrect-nickname-or-password": "Неправильный никнейм или пароль"
|
"incorrect-nickname-or-password": "Неправильный никнейм или пароль",
|
||||||
|
|
||||||
|
"incorrect-profile-data": "Неправильно заполнены поля профиля"
|
||||||
},
|
},
|
||||||
"ask" : {
|
"ask" : {
|
||||||
"select-chat-room": "Выберете чат комнату"
|
"select-chat-room": "Выберете чат комнату"
|
||||||
@ -29,7 +31,7 @@
|
|||||||
},
|
},
|
||||||
"assets": "./assets",
|
"assets": "./assets",
|
||||||
"database": {
|
"database": {
|
||||||
"type": "sqlite",
|
"type": "sqlite3",
|
||||||
"file": "./iu9-ca-web-chat.db"
|
"file": "./iu9-ca-web-chat.db"
|
||||||
},
|
},
|
||||||
"limits": {
|
"limits": {
|
||||||
|
@ -258,8 +258,8 @@ namespace een9 {
|
|||||||
}
|
}
|
||||||
errno = 0;
|
errno = 0;
|
||||||
ret = poll(pollfds.data(), Nip, params.mainloop_recheck_interval_us);
|
ret = poll(pollfds.data(), Nip, params.mainloop_recheck_interval_us);
|
||||||
if (ret != 0) {
|
if (ret != 0 && errno != 0) {
|
||||||
printf("poll() error :> %d\n", errno);
|
printf("poll() error :> %s\n", een9::prettyprint_errno("").c_str());
|
||||||
}
|
}
|
||||||
ASSERT_on_iret(ret, "poll()");
|
ASSERT_on_iret(ret, "poll()");
|
||||||
for (size_t i = 0; i < Nip; i++) {
|
for (size_t i = 0; i < Nip; i++) {
|
||||||
|
@ -18,7 +18,14 @@ int main(int argc, char** argv) {
|
|||||||
een9::readFile(config_file, config_text);
|
een9::readFile(config_file, config_text);
|
||||||
const json::JSON config = json::parse_str_flawless(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());
|
printf("%s\n<a><f><t><e><r><><l><f>\n", answer2.c_str());
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -178,7 +178,7 @@ namespace nytl {
|
|||||||
}
|
}
|
||||||
ASSERT(nm == "EL", "Type of argument variable is either JSON or EL(...signature)")
|
ASSERT(nm == "EL", "Type of argument variable is either JSON or EL(...signature)")
|
||||||
skip(ctx, '(');
|
skip(ctx, '(');
|
||||||
result = json::JSON(json::array);
|
result.asArray();
|
||||||
assert(result.isArray());
|
assert(result.isArray());
|
||||||
}
|
}
|
||||||
skipWhitespace(ctx);
|
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.empty(), "Expression should start with 'root' name of global package or local variable");
|
||||||
ASSERT(first != "_", "_ ??? ARE YOU KIDDING???");
|
ASSERT(first != "_", "_ ??? ARE YOU KIDDING???");
|
||||||
if (local_var_names.count(first) == 1) {
|
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 {
|
} else {
|
||||||
result["V"] = json::JSON(first);
|
result["V"].asString() = first;
|
||||||
}
|
}
|
||||||
result["C"] = json::JSON(json::array);
|
result["C"].asArray();
|
||||||
} else {
|
} else {
|
||||||
skipWhitespace(ctx);
|
skipWhitespace(ctx);
|
||||||
skip(ctx, ']');
|
skip(ctx, ']');
|
||||||
}
|
}
|
||||||
std::vector<json::JSON>& chain = result["C"].g().asArray();
|
std::vector<json::JSON>& chain = result["C"].asArray();
|
||||||
while (true) {
|
while (true) {
|
||||||
if (peep(ctx) == '.') {
|
if (peep(ctx) == '.') {
|
||||||
skip(ctx, '.');
|
skip(ctx, '.');
|
||||||
|
@ -56,18 +56,18 @@ namespace nytl {
|
|||||||
descend(*(temp_ret.JSON_subval));
|
descend(*(temp_ret.JSON_subval));
|
||||||
} else {
|
} else {
|
||||||
assert(expr.isDictionary());
|
assert(expr.isDictionary());
|
||||||
const json::JSON& val = expr["V"].g();
|
const json::JSON& val = expr["V"];
|
||||||
if (val.isInteger()) {
|
if (val.isInteger()) {
|
||||||
size_t lv_ind = val.asInteger().get_int();
|
size_t lv_ind = val.asInteger().get_int();
|
||||||
assert(lv_ind < local_vars.size());
|
assert(lv_ind < local_vars.size());
|
||||||
result = local_vars[lv_ind];
|
result = local_vars[lv_ind];
|
||||||
} else if (val.isString()) {
|
} 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};
|
result = LocalVarValue{false, cur_el_name_str, NULL};
|
||||||
} else
|
} else
|
||||||
assert(false);
|
assert(false);
|
||||||
}
|
}
|
||||||
const std::vector<json::JSON>& chain = expr["C"].g().asArray();
|
const std::vector<json::JSON>& chain = expr["C"].asArray();
|
||||||
while (true) {
|
while (true) {
|
||||||
if (chain_el >= chain.size())
|
if (chain_el >= chain.size())
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -211,7 +211,8 @@ namespace nytl {
|
|||||||
uptr<RFrame> RFrame_OverParts::toMe(bool returned, const global_elem_set_t &elem_ns, Ditch &result,
|
uptr<RFrame> RFrame_OverParts::toMe(bool returned, const global_elem_set_t &elem_ns, Ditch &result,
|
||||||
const std::function<std::string(std::string)> &escape) {
|
const std::function<std::string(std::string)> &escape) {
|
||||||
if (!returned)
|
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);
|
const Element& el = elem_ns.at(name);
|
||||||
if (!returned) {
|
if (!returned) {
|
||||||
/* Continue to do checks */
|
/* 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 "server_data_interact.h"
|
||||||
#include <engine_engine_number_9/baza_throw.h>
|
#include <engine_engine_number_9/baza_throw.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
namespace iu9cawebchat {
|
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) {
|
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);
|
int64_t my_role_here = get_role_of_user_in_chat(conn, uid, chatId);
|
||||||
if (my_role_here == user_chat_role_deleted)
|
if (my_role_here != user_chat_role_admin)
|
||||||
een9_THROW("Unauthorized user tries to access internalapi_getChatInfo");
|
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;
|
json::JSON Recv;
|
||||||
Recv["status"] = json::JSON(0l);
|
poll_update_chat(conn, Sent, Recv);
|
||||||
// todo: WRITE THIS MORBID THING
|
|
||||||
return Recv;
|
return Recv;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,27 @@
|
|||||||
#include "server_data_interact.h"
|
#include "server_data_interact.h"
|
||||||
#include <engine_engine_number_9/baza_throw.h>
|
#include <engine_engine_number_9/baza_throw.h>
|
||||||
|
#include "../str_fields.h"
|
||||||
|
|
||||||
namespace iu9cawebchat {
|
namespace iu9cawebchat {
|
||||||
json::JSON internalapi_createChat(SqliteConnection& conn, int64_t uid, const json::JSON& Sent) {
|
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;
|
json::JSON Recv;
|
||||||
Recv["status"] = json::JSON(0l);
|
poll_update_chat_list(conn, uid, Sent, Recv);
|
||||||
// todo: WRITE THIS MORBID THING
|
|
||||||
return Recv;
|
return Recv;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,13 +3,30 @@
|
|||||||
|
|
||||||
namespace iu9cawebchat {
|
namespace iu9cawebchat {
|
||||||
json::JSON internalapi_deleteMessage(SqliteConnection& conn, int64_t uid, const json::JSON& Sent) {
|
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);
|
int64_t my_role_here = get_role_of_user_in_chat(conn, uid, chatId);
|
||||||
if (my_role_here == user_chat_role_deleted)
|
if (my_role_here == user_chat_role_deleted)
|
||||||
een9_THROW("Unauthorized user tries to access internalapi_getChatInfo");
|
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;
|
json::JSON Recv;
|
||||||
Recv["status"] = json::JSON(0l);
|
poll_update_chat(conn, Sent, Recv);
|
||||||
// todo: WRITE THIS MORBID THING
|
|
||||||
return 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>
|
#include <engine_engine_number_9/baza_throw.h>
|
||||||
|
|
||||||
namespace iu9cawebchat {
|
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) {
|
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);
|
int64_t my_role_here = get_role_of_user_in_chat(conn, uid, chatId);
|
||||||
if (my_role_here == user_chat_role_deleted)
|
if (my_role_here != user_chat_role_deleted)
|
||||||
een9_THROW("Unauthorized user tries to access internalapi_getChatInfo");
|
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;
|
json::JSON Recv;
|
||||||
Recv["status"] = json::JSON(0l);
|
poll_update_chat(conn, Sent, Recv);
|
||||||
// todo: WRITE THIS MORBID THING
|
|
||||||
return Recv;
|
return Recv;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,46 +3,39 @@
|
|||||||
#include "../str_fields.h"
|
#include "../str_fields.h"
|
||||||
|
|
||||||
namespace iu9cawebchat {
|
namespace iu9cawebchat {
|
||||||
/* Throws excetion on failure
|
/* No authorization check is performed
|
||||||
* Chat's HistoryId will increment after this operation, incremented
|
* Chat's HistoryId will increment after this operation
|
||||||
* if adding system message, uid is ignored
|
* 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) {
|
const std::string& text, bool isSystem) {
|
||||||
int64_t chat_HistoryId_BEFORE_MSG = get_current_history_id_of_chat(conn, chatId);
|
int64_t chat_HistoryId_BEFORE_MSG = get_current_history_id_of_chat(conn, chatId);
|
||||||
if (chat_HistoryId_BEFORE_MSG > INT64_MAX - 100)
|
int64_t chat_lastMsgId = get_lastMsgId_of_chat(conn, chatId);
|
||||||
een9_THROW("please no");
|
|
||||||
SqliteStatement req(conn,
|
SqliteStatement req(conn,
|
||||||
"INSERT INTO `message` (`chatId`, `previous`, `senderUserId`, `exists`, `isSystem`, `text`,"
|
"INSERT INTO `message` (`chatId`, `id`, `senderUserId`, `exists`, `isSystem`, `chat_IncHistoryId`, "
|
||||||
"`chat_IncHistoryId`) VALUES (?1, ?2, ?3, 1, ?4, ?5, ?6)",
|
"`text`) VALUES (?1, ?2, ?3 1, ?4, ?5, ?6)",
|
||||||
{{1, chatId}, {4, (int64_t)isSystem}, {6, chat_HistoryId_BEFORE_MSG + 1}}, {{5, text}});
|
{{1, chatId}, {2, chat_lastMsgId + 1}, {4, (int64_t)isSystem}, {5, chat_HistoryId_BEFORE_MSG + 1}}, {{6, 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);
|
|
||||||
if (!isSystem)
|
if (!isSystem)
|
||||||
sqlite_stmt_bind_int64(req, 3, uid);
|
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",
|
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}}, {});
|
{{1, chat_lastMsgId + 1}, {2, chat_HistoryId_BEFORE_MSG + 1}, {3, chatId}}, {});
|
||||||
return MSG_ID;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
json::JSON internalapi_sendMessage(SqliteConnection& conn, int64_t uid, const json::JSON& Sent) {
|
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);
|
int64_t my_role_here = get_role_of_user_in_chat(conn, uid, chatId);
|
||||||
if (my_role_here == user_chat_role_deleted)
|
if (my_role_here == user_chat_role_deleted)
|
||||||
een9_THROW("Unauthorized user tries to access internalapi_getChatInfo");
|
een9_THROW("Unauthorized user tries to access internalapi_getChatInfo");
|
||||||
if (my_role_here == user_chat_role_read_only)
|
if (my_role_here == user_chat_role_read_only)
|
||||||
een9_THROW("read-only user can't send messages");
|
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())
|
if (!is_orthodox_string(text) || text.empty())
|
||||||
een9_THROW("Bad input text");
|
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;
|
json::JSON Recv;
|
||||||
Recv["status"] = json::JSON(0l);
|
poll_update_chat(conn, Sent, Recv);
|
||||||
json::JSON hist_ent_response = Recv["update"][0].g();
|
|
||||||
event_polling_fill_chat_hist_entity_response(conn, hist_ent_response, uid, chatId, LocalHistoryId);
|
|
||||||
return Recv;
|
return Recv;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,64 +20,45 @@ namespace iu9cawebchat {
|
|||||||
if (ret_logged_in_user >= 0) {
|
if (ret_logged_in_user >= 0) {
|
||||||
ret_userinfo["uid"] = json::JSON(ret_logged_in_user);
|
ret_userinfo["uid"] = json::JSON(ret_logged_in_user);
|
||||||
ret_userinfo["nickname"] = json::JSON(tried.nickname);
|
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,
|
std::string http_R200(const std::string &el_name, WorkerGuestData &wgd,
|
||||||
const json::JSON& config_presentation,
|
const std::vector<const json::JSON *> &args) {
|
||||||
const json::JSON& userinfo) {
|
std::string page = wgd.templater->render(el_name, args);
|
||||||
|
|
||||||
std::string page = wgd.templater->render(el_name, {&config_presentation, &userinfo});
|
|
||||||
return een9::form_http_server_response_200("text/html", page);
|
return een9::form_http_server_response_200("text/html", page);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string R200_pres_uinfo_msges(const std::string& el_name, WorkerGuestData& wgd,
|
json::JSON jsonify_html_message_list(const std::vector<HtmlMsgBox>& messages) {
|
||||||
const json::JSON& config_presentation,
|
json::JSON jmessages(json::array);
|
||||||
const json::JSON& userinfo, const std::vector<HtmlMsgBox>& messages) {
|
|
||||||
|
|
||||||
json::JSON jmessages;
|
|
||||||
// todo: optimize
|
|
||||||
for (size_t i = 0; i < messages.size(); i++) {
|
for (size_t i = 0; i < messages.size(); i++) {
|
||||||
jmessages[i]["class"] = json::JSON(messages[i].class_);
|
jmessages[i]["class"].asString() = messages[i].class_;
|
||||||
jmessages[i]["text"] = json::JSON(messages[i].text);
|
jmessages[i]["text"].asString() = messages[i].text;
|
||||||
}
|
}
|
||||||
std::string page = wgd.templater->render(el_name, {&config_presentation, &userinfo, &jmessages});
|
return jmessages;
|
||||||
return een9::form_http_server_response_200("text/html", page);
|
}
|
||||||
|
|
||||||
|
std::string page_E404(WorkerGuestData &wgd) {
|
||||||
|
return een9::form_http_server_response_404("text/html",
|
||||||
|
wgd.templater->render("err-404", {}));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ========================= API =========================*/
|
/* ========================= API =========================*/
|
||||||
|
|
||||||
std::string when_internalapi(WorkerGuestData& wgd, const een9::ClientRequest& req, int64_t uid,
|
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);
|
const json::JSON& Sent = json::parse_str_flawless(req.body);
|
||||||
std::string result = json::generate_str(F(*wgd.db, uid, Sent), json::print_pretty);
|
std::string result = json::generate_str(F(*wgd.db, uid, Sent), json::print_pretty);
|
||||||
return een9::form_http_server_response_200("text/json", result);
|
return een9::form_http_server_response_200("text/json", result);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string when_internalapi_pollevents(WorkerGuestData& wgd, const een9::ClientRequest& req, int64_t uid) {
|
std::string when_internalapi_chatpollevents(WorkerGuestData& wgd, const een9::ClientRequest& req, int64_t uid) {
|
||||||
return when_internalapi(wgd, req, uid, internalapi_pollEvents);
|
return when_internalapi(wgd, req, uid, internalapi_chatPollEvents);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string when_internalapi_getchatlist(WorkerGuestData& wgd, const een9::ClientRequest& req, int64_t uid) {
|
std::string when_internalapi_chatlistpollevents(WorkerGuestData &wgd, const een9::ClientRequest &req, int64_t uid) {
|
||||||
return when_internalapi(wgd, req, uid, internalapi_getChatList);
|
return when_internalapi(wgd, req, uid, internalapi_chatListPollEvents);
|
||||||
}
|
|
||||||
|
|
||||||
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_getmessageneighbours(WorkerGuestData &wgd, const een9::ClientRequest &req, int64_t uid) {
|
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);
|
return when_internalapi(wgd, req, uid, internalapi_createChat);
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
||||||
return when_internalapi(wgd, req, uid, internalapi_removeChat);
|
return when_internalapi(wgd, req, uid, internalapi_leaveChat);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,18 +27,17 @@ namespace iu9cawebchat {
|
|||||||
int64_t& ret_logged_in_user
|
int64_t& ret_logged_in_user
|
||||||
);
|
);
|
||||||
|
|
||||||
std::string R200_pres_uinfo(const std::string& el_name, WorkerGuestData& wgd,
|
std::string http_R200(const std::string& el_name, WorkerGuestData& wgd,
|
||||||
const json::JSON& config_presentation,
|
const std::vector<const json::JSON*>& args);
|
||||||
const json::JSON& userinfo);
|
|
||||||
|
|
||||||
struct HtmlMsgBox {
|
struct HtmlMsgBox {
|
||||||
std::string class_;
|
std::string class_;
|
||||||
std::string text;
|
std::string text;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::string R200_pres_uinfo_msges(const std::string& el_name, WorkerGuestData& wgd,
|
json::JSON jsonify_html_message_list(const std::vector<HtmlMsgBox>& messages);
|
||||||
const json::JSON& config_presentation,
|
|
||||||
const json::JSON& userinfo, const std::vector<HtmlMsgBox>& messages);
|
std::string page_E404(WorkerGuestData& wgd);
|
||||||
|
|
||||||
/* ========================== PAGES ================================== */
|
/* ========================== PAGES ================================== */
|
||||||
|
|
||||||
@ -52,22 +51,13 @@ namespace iu9cawebchat {
|
|||||||
const een9::ClientRequest& req, const json::JSON& userinfo);
|
const een9::ClientRequest& req, const json::JSON& userinfo);
|
||||||
|
|
||||||
std::string when_page_user(WorkerGuestData& wgd, const json::JSON& config_presentation,
|
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 ============================== */
|
/* ======================== 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_chatlistpollevents(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_getmessageneighbours(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_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
|
#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/baza_throw.h>
|
||||||
#include <engine_engine_number_9/http_structures/cookies.h>
|
#include <engine_engine_number_9/http_structures/cookies.h>
|
||||||
|
#include "../str_fields.h"
|
||||||
|
|
||||||
namespace iu9cawebchat {
|
namespace iu9cawebchat {
|
||||||
const char* stringify_user_chat_role(int64_t role) {
|
const char* stringify_user_chat_role(int64_t role) {
|
||||||
@ -27,7 +28,7 @@ namespace iu9cawebchat {
|
|||||||
return -1;
|
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?");
|
een9_ASSERT(uid >= 0, "Are you crazy?");
|
||||||
SqliteStatement sql_req(conn,
|
SqliteStatement sql_req(conn,
|
||||||
"SELECT `name` FROM `user` WHERE `id` = ?1",
|
"SELECT `name` FROM `user` WHERE `id` = ?1",
|
||||||
@ -50,7 +51,20 @@ namespace iu9cawebchat {
|
|||||||
fsql_text8_or_null name_col;
|
fsql_text8_or_null name_col;
|
||||||
int status = sqlite_stmt_step(sql_req, {}, {{0, &nickname_col}, {1, &name_col}});
|
int status = sqlite_stmt_step(sql_req, {}, {{0, &nickname_col}, {1, &name_col}});
|
||||||
if (status == SQLITE_ROW) {
|
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");
|
een9_THROW("No such user");
|
||||||
}
|
}
|
||||||
@ -65,7 +79,22 @@ namespace iu9cawebchat {
|
|||||||
fsql_integer_or_null last_msg_id_col;
|
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}});
|
int status = sqlite_stmt_step(sql_req, {{2, &last_msg_id_col}}, {{0, &nickname_col}, {1, &name_col}});
|
||||||
if (status == SQLITE_ROW) {
|
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};
|
last_msg_id_col.exist ? last_msg_id_col.value : -1};
|
||||||
}
|
}
|
||||||
een9_THROW("No such chat");
|
een9_THROW("No such chat");
|
||||||
@ -73,39 +102,21 @@ namespace iu9cawebchat {
|
|||||||
|
|
||||||
RowMessage_Content lookup_message_content(SqliteConnection& conn, int64_t chatId, int64_t msgId) {
|
RowMessage_Content lookup_message_content(SqliteConnection& conn, int64_t chatId, int64_t msgId) {
|
||||||
SqliteStatement req(conn,
|
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}}, {});
|
"`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;
|
fsql_text8_or_null msg_text;
|
||||||
int status = sqlite_stmt_step(req, {{0, &previousId}, {1, &senderUserId}, {2, &exists}, {3, &isSystem}},
|
int status = sqlite_stmt_step(req, {{0, &senderUserId}, {1, &exists}, {2, &isSystem}},
|
||||||
{{4, &msg_text}});
|
{{3, &msg_text}});
|
||||||
if (status == SQLITE_ROW) {
|
if (status == SQLITE_ROW) {
|
||||||
if (!(bool)exists.value)
|
if (!(bool)exists.value)
|
||||||
een9_THROW("Message existed, but now it isn't");
|
een9_THROW("Message existed, but now it does not");
|
||||||
return {(bool)isSystem.value, msg_text.value, senderUserId.exist ? senderUserId.value : -1,
|
return {msgId, senderUserId.exist ? senderUserId.value : -1, (bool)exists.value,
|
||||||
previousId.exist ? previousId.value : -1};
|
(bool)isSystem.value, msg_text.value};
|
||||||
}
|
}
|
||||||
een9_THROW("No such message");
|
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) {
|
int64_t get_role_of_user_in_chat(SqliteConnection& conn, int64_t userId, int64_t chatId) {
|
||||||
SqliteStatement req(conn,
|
SqliteStatement req(conn,
|
||||||
"SELECT `role` FROM `user_chat_membership` WHERE `userId` = ?1 AND `chatId` = ?2",
|
"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 the api calls processing is done in dedicated files.
|
||||||
* All functions related to polling are defined in api_pollevents.cpp */
|
* 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);
|
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);
|
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 {
|
struct RowUser_Content {
|
||||||
|
int64_t id;
|
||||||
std::string nickname;
|
std::string nickname;
|
||||||
std::string name;
|
std::string name;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RowChat_Content {
|
struct RowChat_Content {
|
||||||
|
int64_t id;
|
||||||
std::string nickname;
|
std::string nickname;
|
||||||
std::string name;
|
std::string name;
|
||||||
int64_t lastMsgId; // Negative if it does not exist
|
int64_t lastMsgId; // Negative if it does not exist
|
||||||
};
|
};
|
||||||
|
|
||||||
RowUser_Content lookup_user_content(SqliteConnection& conn, int64_t uid);
|
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 */
|
/* Does not make authorization check */
|
||||||
RowChat_Content lookup_chat_content(SqliteConnection& conn, int64_t chatId);
|
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 {
|
struct RowMessage_Content {
|
||||||
|
int64_t id;
|
||||||
|
int64_t senderUserId;
|
||||||
|
bool exists;
|
||||||
bool isSystem;
|
bool isSystem;
|
||||||
std::string text;
|
std::string text;
|
||||||
int64_t senderUserId;
|
|
||||||
int64_t previous = -1;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
RowMessage_Content lookup_message_content(SqliteConnection& conn, int64_t chatId, int64_t msgId);
|
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 */
|
/* Does not make authorization check */
|
||||||
int64_t get_role_of_user_in_chat(SqliteConnection& conn, int64_t userId, int64_t chatId);
|
int64_t get_role_of_user_in_chat(SqliteConnection& conn, int64_t userId, int64_t chatId);
|
||||||
/* Does not make authorization check */
|
/* Does not make authorization check */
|
||||||
int64_t get_lastMsgId_of_chat(SqliteConnection& conn, int64_t chatId);
|
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_chat(SqliteConnection& conn, int64_t chatId);
|
||||||
int64_t get_current_history_id_of_user_chatList(SqliteConnection& conn, int64_t userId);
|
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,
|
json::JSON poll_update_chat_list_resp(SqliteConnection& conn, int64_t userId, int64_t LocalHistoryId);
|
||||||
int64_t uid, int64_t chatId, int64_t LocalHistoryId);
|
void poll_update_chat_list(SqliteConnection& conn, int64_t userId, const json::JSON& Sent, json::JSON& Recv);
|
||||||
/* Returns HistoryId of chat list (latest) */
|
|
||||||
int64_t event_polling_fill_chatlist_hist_entity_response(SqliteConnection& conn, json::JSON& hist_entity_response,
|
json::JSON poll_update_chat_ONE_MSG_resp(SqliteConnection& conn, int64_t chatId, int64_t selectedMsg);
|
||||||
int64_t uid, int64_t LocalHistoryId);
|
void poll_update_chat(SqliteConnection& conn, const json::JSON& Sent, json::JSON& Recv);
|
||||||
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);
|
void make_her_a_member_of_the_midnight_crew(SqliteConnection& conn, int64_t chatId, int64_t alienUserId, int64_t role);
|
||||||
json::JSON internalapi_getChatInfo(SqliteConnection& conn, int64_t uid, const json::JSON& Sent);
|
void kick_from_chat(SqliteConnection& conn, int64_t alienUserId, int64_t chatId);
|
||||||
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);
|
bool is_nickname_taken(SqliteConnection& conn, const std::string& nickname);
|
||||||
json::JSON internalapi_getMessageInfo(SqliteConnection& conn, int64_t uid, const json::JSON& Sent);
|
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_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_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_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_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_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_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
|
#endif
|
||||||
|
@ -1,8 +1,54 @@
|
|||||||
#include "client_server_interact.h"
|
#include "client_server_interact.h"
|
||||||
|
|
||||||
|
#include <engine_engine_number_9/baza_throw.h>
|
||||||
|
#include "../str_fields.h"
|
||||||
|
|
||||||
namespace iu9cawebchat {
|
namespace iu9cawebchat {
|
||||||
std::string when_page_chat(WorkerGuestData& wgd, const json::JSON& config_presentation,
|
std::string when_page_chat(WorkerGuestData& wgd, const json::JSON& config_presentation,
|
||||||
const een9::ClientRequest& req, const json::JSON& userinfo) {
|
const een9::ClientRequest& req, const json::JSON& userinfo) {
|
||||||
return R200_pres_uinfo("chat", config_presentation, wgd, 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()) {
|
if (userinfo.isNull()) {
|
||||||
return een9::form_http_server_response_303("/login");
|
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){}
|
} catch(const std::exception& e){}
|
||||||
if (uid < 0) {
|
if (uid < 0) {
|
||||||
printf("Redirecting back to /login because of incorrect credentials\n");
|
printf("Redirecting back to /login because of incorrect credentials\n");
|
||||||
// class will be successfully ignored
|
json::JSON msg_list = jsonify_html_message_list({{"",
|
||||||
return R200_pres_uinfo_msges("login", wgd, config_presentation, userinfo, {{"",
|
config_presentation["phr"]["decl"]["incorrect-nickname-or-password"].asString()}});
|
||||||
config_presentation["phr"]["decl"]["incorrect-nickname-or-password"].g().asString()}});
|
return http_R200("login", wgd, {&config_presentation, &userinfo, &msg_list});
|
||||||
}
|
}
|
||||||
std::vector<std::pair<std::string, std::string>> response_hlines;
|
std::vector<std::pair<std::string, std::string>> response_hlines;
|
||||||
LoginCookie new_login_cookie = create_login_cookie(nickname, password);
|
LoginCookie new_login_cookie = create_login_cookie(nickname, password);
|
||||||
add_set_cookie_headers_to_login(login_cookies, response_hlines, new_login_cookie);
|
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 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 "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 {
|
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,
|
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) {
|
||||||
return R200_pres_uinfo("profile", config_presentation, wgd, 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{
|
namespace iu9cawebchat{
|
||||||
int find_db_sqlite_file_path(const json::JSON& config, std::string& res_path) {
|
int find_db_sqlite_file_path(const json::JSON& config, std::string& res_path) {
|
||||||
const json::JSON& type = config["database"]["type"].g();
|
try {
|
||||||
if (!type.isString() && type.asString() == "sqlite3")
|
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;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -44,36 +44,38 @@ namespace iu9cawebchat {
|
|||||||
"`nickname` TEXT UNIQUE REFERENCES `nickname` NOT NULL,"
|
"`nickname` TEXT UNIQUE REFERENCES `nickname` NOT NULL,"
|
||||||
"`name` TEXT NOT NULL,"
|
"`name` TEXT NOT NULL,"
|
||||||
"`chatList_HistoryId` INTEGER 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` ("
|
sqlite_nooutput(conn, "CREATE TABLE `chat` ("
|
||||||
"`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,"
|
"`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,"
|
||||||
"`nickname` TEXT UNIQUE REFERENCES `nickname` NOT NULL,"
|
"`nickname` TEXT UNIQUE REFERENCES `nickname` NOT NULL,"
|
||||||
"`name` TEXT NOT NULL,"
|
"`name` TEXT NOT NULL,"
|
||||||
"`it_HistoryId` INTEGER NOT NULL,"
|
"`it_HistoryId` INTEGER NOT NULL,"
|
||||||
"`lastMsgId` INTEGER REFERENCES `message`"
|
"`lastMsgId` INTEGER NOT NULL"
|
||||||
")");
|
")");
|
||||||
sqlite_nooutput(conn, "CREATE TABLE `user_chat_membership` ("
|
sqlite_nooutput(conn, "CREATE TABLE `user_chat_membership` ("
|
||||||
"`userId` INTEGER REFERENCES `user` NOT NULL,"
|
"`userId` INTEGER REFERENCES `user` NOT NULL,"
|
||||||
"`chatId` INTEGER REFERENCES `chat` NOT NULL,"
|
"`chatId` INTEGER REFERENCES `chat` NOT NULL,"
|
||||||
"`user_chatList_IncHistoryId` INTEGER NOT NULL,"
|
"`user_chatList_IncHistoryId` INTEGER NOT NULL,"
|
||||||
"`chat_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` ("
|
sqlite_nooutput(conn, "CREATE TABLE `message` ("
|
||||||
"`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,"
|
|
||||||
"`chatId` INTEGER REFERENCES `chat` NOT NULL,"
|
"`chatId` INTEGER REFERENCES `chat` NOT NULL,"
|
||||||
"`previous` INTEGER REFERENCES `message`,"
|
"`id` INTEGER NOT NULL,"
|
||||||
"`senderUserId` INTEGER REFERENCES `user`,"
|
"`senderUserId` INTEGER REFERENCES `user`,"
|
||||||
"`exists` BOOLEAN NOT NULL,"
|
"`exists` BOOLEAN NOT NULL,"
|
||||||
"`isSystem` BOOLEAN NOT NULL,"
|
"`isSystem` BOOLEAN NOT NULL,"
|
||||||
"`text` TEXT NOT NULL,"
|
"`text` TEXT,"
|
||||||
"`chat_IncHistoryId` INTEGER NOT NULL"
|
"`chat_IncHistoryId` INTEGER NOT NULL,"
|
||||||
|
"PRIMARY KEY (`chatId`, `id`)"
|
||||||
")");
|
")");
|
||||||
sqlite_nooutput(conn, "INSERT INTO `nickname` VALUES (?1)", {}, {{1, "root"}});
|
sqlite_nooutput(conn, "INSERT INTO `nickname` VALUES (?1)", {}, {{1, "root"}});
|
||||||
sqlite_nooutput(conn, "INSERT INTO `user` (`id`, `nickname`, `name`, `chatList_HistoryId`, `password`) VALUES "
|
sqlite_nooutput(conn, "INSERT INTO `user` (`id`, `nickname`, `name`, `chatList_HistoryId`, `password`, "
|
||||||
"(0, ?1, ?2, 0, ?3)", {},
|
"`bio` ) VALUES (0, ?1, ?2, 0, ?3, ?4)", {},
|
||||||
{{1, "root"}, {2, "Rootov Root Rootovich"}, {3, root_pw}});
|
{{1, "root"}, {2, "Rootov Root Rootovich"}, {3, root_pw}, {4, "One admin to rule them all"}});
|
||||||
sqlite_nooutput(conn, "END");
|
sqlite_nooutput(conn, "END");
|
||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
sqlite_nooutput(conn, "ROLLBACK", {}, {});
|
sqlite_nooutput(conn, "ROLLBACK", {}, {});
|
||||||
|
@ -23,8 +23,8 @@ namespace iu9cawebchat {
|
|||||||
uint64_t nsec = std::stoull(ft.substr(s_ + 1, ft.size() - s_ - 1));
|
uint64_t nsec = std::stoull(ft.substr(s_ + 1, ft.size() - s_ - 1));
|
||||||
een9_ASSERT_pl(nsec < 1000000000);
|
een9_ASSERT_pl(nsec < 1000000000);
|
||||||
const json::JSON cnt = json::parse_str_flawless(base64_decode(login_cookie_encoded.second));
|
const json::JSON cnt = json::parse_str_flawless(base64_decode(login_cookie_encoded.second));
|
||||||
std::string nickname = cnt[0].g().asString();
|
std::string nickname = cnt[0].asString();
|
||||||
std::string password = cnt[1].g().asString();
|
std::string password = cnt[1].asString();
|
||||||
return LoginCookie{{(time_t)sec, (time_t)nsec}, nickname, password};
|
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) {
|
std::pair<std::string, std::string> encode_login_cookie(const LoginCookie& cookie) {
|
||||||
json::JSON cnt;
|
json::JSON cnt;
|
||||||
cnt[1].g() = cookie.password;
|
cnt[1].asString() = cookie.password;
|
||||||
cnt[0].g() = cookie.nickname;
|
cnt[0].asString() = cookie.nickname;
|
||||||
return {"login_" + std::to_string(cookie.login_time.tv_sec) + "_" + std::to_string(cookie.login_time.tv_nsec),
|
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))};
|
base64_encode(json::generate_str(cnt, json::print_compact))};
|
||||||
}
|
}
|
||||||
|
@ -16,9 +16,25 @@ namespace iu9cawebchat {
|
|||||||
termination = true;
|
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) {
|
void run_website(const json::JSON& config) {
|
||||||
een9_ASSERT(config["assets"].g().isString(), "config[\"assets\"] is not string");
|
een9_ASSERT(config["assets"].isString(), "config[\"assets\"] is not string");
|
||||||
std::string assets_dir = config["assets"].g().asString();
|
const std::string& assets_dir = config["assets"].asString();
|
||||||
een9_ASSERT(een9::isDirectory(assets_dir), "\"" + assets_dir + "\" is not a directory");
|
een9_ASSERT(een9::isDirectory(assets_dir), "\"" + assets_dir + "\" is not a directory");
|
||||||
|
|
||||||
een9::StaticAssetManagerSlaveModule samI;
|
een9::StaticAssetManagerSlaveModule samI;
|
||||||
@ -30,8 +46,8 @@ namespace iu9cawebchat {
|
|||||||
} },
|
} },
|
||||||
});
|
});
|
||||||
|
|
||||||
const json::JSON& config_presentation = config["presentation"].g();
|
const json::JSON& config_presentation = config["presentation"];
|
||||||
int64_t slave_number = config["server"]["workers"].g().asInteger().get_int();
|
int64_t slave_number = config["server"]["workers"].asInteger().get_int();
|
||||||
een9_ASSERT(slave_number > 0 && slave_number <= 200, "E");
|
een9_ASSERT(slave_number > 0 && slave_number <= 200, "E");
|
||||||
|
|
||||||
std::string sqlite_db_path;
|
std::string sqlite_db_path;
|
||||||
@ -52,13 +68,7 @@ namespace iu9cawebchat {
|
|||||||
een9_ASSERT_pl(0 <= worker_id && worker_id < worker_guest_data.size());
|
een9_ASSERT_pl(0 <= worker_id && worker_id < worker_guest_data.size());
|
||||||
WorkerGuestData& wgd = worker_guest_data[worker_id];
|
WorkerGuestData& wgd = worker_guest_data[worker_id];
|
||||||
een9::StaticAsset sa;
|
een9::StaticAsset sa;
|
||||||
sqlite_nooutput(*wgd.db, "BEGIN", {}, {});
|
ONE_SQLITE_TRANSACTION_GUARD conn_guard(*wgd.db);
|
||||||
struct guard {SqliteConnection& conn; bool rollback = false; ~guard() {
|
|
||||||
if (rollback)
|
|
||||||
sqlite_nooutput(conn, "ROLLBACK", {}, {});
|
|
||||||
else
|
|
||||||
sqlite_nooutput(conn, "END", {}, {});
|
|
||||||
}} guard_{*wgd.db};
|
|
||||||
try {
|
try {
|
||||||
std::vector<std::pair<std::string, std::string>> cookies;
|
std::vector<std::pair<std::string, std::string>> cookies;
|
||||||
std::vector<LoginCookie> login_cookies;
|
std::vector<LoginCookie> login_cookies;
|
||||||
@ -72,53 +82,42 @@ namespace iu9cawebchat {
|
|||||||
if (req.uri_path == "/login") {
|
if (req.uri_path == "/login") {
|
||||||
return when_page_login(wgd, config_presentation, req, login_cookies, userinfo);
|
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);
|
return when_page_chat(wgd, config_presentation, req, userinfo);
|
||||||
}
|
}
|
||||||
if (req.uri_path == "/user") {
|
if (een9::beginsWith(req.uri_path, "/user/")) {
|
||||||
return when_page_user(wgd, config_presentation, req, userinfo);
|
return when_page_user(wgd, config_presentation, req, login_cookies, userinfo);
|
||||||
}
|
}
|
||||||
if (req.uri_path == "/internalapi/pollEvents") {
|
if (req.uri_path == "/api/chatPollEvents") {
|
||||||
return when_internalapi_pollevents(wgd, req, logged_in_user);
|
return when_internalapi_chatpollevents(wgd, req, logged_in_user);
|
||||||
}
|
}
|
||||||
if (req.uri_path == "/internalapi/getChatList") {
|
if (req.uri_path == "/api/chatListPollEvents") {
|
||||||
return when_internalapi_getchatlist(wgd, req, logged_in_user);
|
return when_internalapi_chatlistpollevents(wgd, req, logged_in_user);
|
||||||
}
|
}
|
||||||
if (req.uri_path == "/internalapi/getChatInfo") {
|
if (req.uri_path == "/api/getMessageNeighbours") {
|
||||||
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") {
|
|
||||||
return when_internalapi_getmessageneighbours(wgd, req, logged_in_user);
|
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);
|
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);
|
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);
|
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);
|
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);
|
return when_internalapi_createchat(wgd, req, logged_in_user);
|
||||||
}
|
}
|
||||||
if (req.uri_path == "/internalapi/removeChat") {
|
if (req.uri_path == "/api/leaveChat") {
|
||||||
return when_internalapi_removechat(wgd, req, logged_in_user);
|
return when_internalapi_leavechat(wgd, req, logged_in_user);
|
||||||
}
|
}
|
||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
guard_.rollback = true;
|
conn_guard.rollback = true;
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
/* Trying to interpret request as asset lookup */
|
/* 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 {
|
(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());
|
een9_ASSERT_pl(0 <= worker_id && worker_id < worker_guest_data.size());
|
||||||
WorkerGuestData& wgd = worker_guest_data[worker_id];
|
WorkerGuestData& wgd = worker_guest_data[worker_id];
|
||||||
|
ONE_SQLITE_TRANSACTION_GUARD conn_guad(*wgd.db);
|
||||||
try {
|
try {
|
||||||
if (req == "hello") {
|
return admin_control_procedure(*wgd.db, req, termination);
|
||||||
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";
|
|
||||||
} catch (std::exception& e) {
|
} catch (std::exception& e) {
|
||||||
|
conn_guad.rollback = true;
|
||||||
return std::string("Server error\n") + e.what();
|
return std::string("Server error\n") + e.what();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -171,8 +152,8 @@ namespace iu9cawebchat {
|
|||||||
een9_ASSERT(ret == 0, "Incorrect ear address: " + source[i].asString());
|
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.client_regular_listened, config["server"]["http-listen"].asArray());
|
||||||
translate_addr_list_conf(params.admin_control_listened, config["server"]["admin-command-listen"].g().asArray());
|
translate_addr_list_conf(params.admin_control_listened, config["server"]["admin-command-listen"].asArray());
|
||||||
|
|
||||||
signal(SIGINT, sigterm_action);
|
signal(SIGINT, sigterm_action);
|
||||||
signal(SIGTERM, sigterm_action);
|
signal(SIGTERM, sigterm_action);
|
||||||
|
@ -28,11 +28,15 @@ namespace iu9cawebchat {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool check_password(const std::string &pwd) {
|
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) {
|
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) {
|
bool check_nickname(const std::string &nickname) {
|
||||||
@ -42,7 +46,7 @@ namespace iu9cawebchat {
|
|||||||
if (!isUNCHAR(ch))
|
if (!isUNCHAR(ch))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return nickname.size() <= 150;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Yeah baby, it's base64 time!!! */
|
/* Yeah baby, it's base64 time!!! */
|
||||||
|
@ -13,6 +13,7 @@ namespace iu9cawebchat {
|
|||||||
bool is_orthodox_string(const std::string& str);
|
bool is_orthodox_string(const std::string& str);
|
||||||
|
|
||||||
bool check_password(const std::string& pwd);
|
bool check_password(const std::string& pwd);
|
||||||
|
bool check_strong_password(const std::string& pwd);
|
||||||
bool check_name(const std::string& name);
|
bool check_name(const std::string& name);
|
||||||
bool check_nickname(const std::string& nickname);
|
bool check_nickname(const std::string& nickname);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user