Translated to english
This commit is contained in:
parent
b0d7a35eb2
commit
0ed8150c4e
25
README.md
25
README.md
@ -60,6 +60,31 @@ regexis024_build_system.sh
|
||||
Утилита `iu9-ca-web-chat-admin-cli` позволяет администратору сервиса контролировать его через сокет
|
||||
(адрес указан в `config["server"]["admin-command-listen"]`).
|
||||
|
||||
По адресам `config.server.admin-command-listen` идёт прослушивание так называемых "команд администратора".
|
||||
iu9cawebchat определяет свой простой протокол для передачи этих команд.
|
||||
Утилита iu9-ca-web-chat-admin-cli может отправить текст с некой командой на сервер на этот адрес и получить
|
||||
ответ от сервера.
|
||||
|
||||
```shell
|
||||
iu9-ca-web-chat-admin-cli <server admin-control address> <command text> [<command text> ...]
|
||||
```
|
||||
|
||||
Дополнительные параметры конкатенируются, разделяясь переводом строки.
|
||||
Команды администратора:
|
||||
|
||||
`updateroopw <new root password>` - сменить пароль пользователя с номером 0
|
||||
|
||||
`adduser <user nickname> <user name> <user password> <user bio>` - зарегистрировать пользователя сайта
|
||||
|
||||
Если нужно ввести пробел или символ `\ ` в любое из этих полей, перед ними нужно поставить `\ `;
|
||||
|
||||
Параметры конфигурации `config.lang.whitelist` и `config.lang.force-order` определяют на
|
||||
какие языки будет локализован сервер, и какие переводы приоритетнее каких.
|
||||
На данный момент поддерживаются
|
||||
- `ru-RU`
|
||||
- `en-US`
|
||||
Все переводы хранятся в папке `assets/lang`.
|
||||
|
||||
# Список участников
|
||||
|
||||
1. [Китанин Фёдор](https://gitflic.ru/user/fed-kit)
|
||||
|
@ -8,25 +8,25 @@
|
||||
<link rel="stylesheet" href="/assets/css/common.css">
|
||||
<link rel="stylesheet" href="/assets/css/common-popup.css">
|
||||
<link rel="stylesheet" href="/assets/css/chat-members.css">
|
||||
<title>Chat Members</title>
|
||||
<title>{%w pres.chat-members.members-of %} {%w openedchat.name %}</title>
|
||||
</head>
|
||||
<body>
|
||||
{% PUT chat.pass pres userinfo openedchat initial_chatUpdResp %}
|
||||
|
||||
<div id="user-summoning-win" class="popup-window">
|
||||
<h1 class="popup-window-msg">Nickname for summoned user</h1>
|
||||
<h1 class="popup-window-msg">{%w pres.chat-members.summon-label-nickname %}</h1>
|
||||
<input class="one-line-input" id="summoned-user-nickname">
|
||||
<input type="checkbox" id="summoned-user-is-read-only">
|
||||
<label>Make read only</label><br>
|
||||
<button class="popup-window-btn-yes" id="user-summoning-yes">Yes, summon</button>
|
||||
<button class="popup-window-btn-no" id="user-summoning-no">No, cancel</button>
|
||||
<label>{%w pres.chat-members.summon-label-ro %}</label><br>
|
||||
<button class="popup-window-btn-yes" id="user-summoning-yes">{%w pres.chat-members.yes-summon %}</button>
|
||||
<button class="popup-window-btn-no" id="user-summoning-no">{%w pres.chat-members.no-summon %}</button>
|
||||
</div>
|
||||
|
||||
<div id="user-deletion-win" class="popup-window">
|
||||
<!-- header will actually be rewritten before showing the window to include user nickname -->
|
||||
<h1 id="user-deletion-win-title" class="popup-window-msg">Are you sure you want to ban user?</h1>
|
||||
<button class="popup-window-btn-yes" id="user-deletion-yes">Yes, delete</button>
|
||||
<button class="popup-window-btn-no" id="user-deletion-no">No, cancel</button>
|
||||
<h1 id="user-deletion-win-title" class="popup-window-msg"> ||||||||| </h1>
|
||||
<button class="popup-window-btn-yes" id="user-deletion-yes">{%w pres.chat-members.yes-kick %}</button>
|
||||
<button class="popup-window-btn-no" id="user-deletion-no">{%w pres.chat-members.no-kick %}</button>
|
||||
</div>
|
||||
|
||||
<div class="document-container resp-container">
|
||||
@ -37,7 +37,9 @@
|
||||
<a href="/user/{% W userinfo.nickname %}" id="go-to-my-profile" class="panel-thing">
|
||||
<img alt="Go to my profile" src="/assets/img/user.svg" width="32px">
|
||||
</a>
|
||||
<p class="panel-thing panel-header-txt"> Members list of {% W openedchat.name %} ({% W openedchat.nickname %})</p>
|
||||
<p class="panel-thing panel-header-txt">
|
||||
{%w pres.chat-members.members-list-of %} {% W openedchat.name %} ({% W openedchat.nickname %})
|
||||
</p>
|
||||
<a href="/chat/{% W openedchat.nickname %}" id="go-to-chat-settings" class="panel-thing">
|
||||
<img alt="Back to chat" src="/assets/img/return.svg" width="32px">
|
||||
</a>
|
||||
|
@ -18,17 +18,17 @@
|
||||
<link rel="stylesheet" href="/assets/css/common.css">
|
||||
<link rel="stylesheet" href="/assets/css/common-popup.css">
|
||||
<link rel="stylesheet" href="/assets/css/chat.css">
|
||||
<title>Chat</title>
|
||||
<title>{%w pres.chat.header-chat %} {%w openedchat.name %}</title>
|
||||
</head>
|
||||
<body>
|
||||
{% PUT chat.pass pres userinfo openedchat initial_chatUpdResp %}
|
||||
|
||||
<div id="msg-deletion-win" class="popup-window">
|
||||
<h1 class="popup-window-msg">Are you sure you want to delete this message?</h1>
|
||||
<!-- message preview will be actually rewritten before each window activation-->
|
||||
<p class="message-in-popup-preview" id="win-deletion-msg-preview">Lorem ipsum dolor</p>
|
||||
<button class="popup-window-btn-yes" id="msg-deletion-yes">Yes, delete</button>
|
||||
<button class="popup-window-btn-no" id="msg-deletion-no">No, cancel</button>
|
||||
<h1 class="popup-window-msg">{%w pres.chat.reask-delete-message %}</h1>
|
||||
<!-- mesage preview will be actually rewritten before each window activation-->
|
||||
<p class="message-in-popup-preview" id="win-deletion-msg-preview">|||||||||</p>
|
||||
<button class="popup-window-btn-yes" id="msg-deletion-yes">{%w pres.chat.yes-delete %}</button>
|
||||
<button class="popup-window-btn-no" id="msg-deletion-no">{%w pres.chat.no-delete %}</button>
|
||||
</div>
|
||||
|
||||
<div class="fullscreen-container resp-container">
|
||||
|
@ -7,7 +7,7 @@
|
||||
<link rel="icon" type="image/png" href="/assets/img/favicon.png">
|
||||
<link rel="stylesheet" href="/assets/css/common.css">
|
||||
<link rel="stylesheet" href="/assets/css/edit-profile.css">
|
||||
<title>Edit user Profile</title>
|
||||
<title>{%w pres.edit-profile.header-profile-of %} {%w alienprofile.name %}</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@ -29,37 +29,39 @@
|
||||
|
||||
<div class="profile-container">
|
||||
<h2 class="profile-name-text">{% W alienprofile.name %}</h2>
|
||||
<h3 class="profile-nickname-text">Nickname: {% W alienprofile.nickname %}</h3>
|
||||
<h3 class="profile-nickname-text">{%w pres.edit-profile.directive-nickname %} {% W alienprofile.nickname %}</h3>
|
||||
<p class="profile-bio-text">
|
||||
{% W alienprofile.bio %}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="profile-container resp-container">
|
||||
<h1 class="wide-centered-header">Change user attributes</h1>
|
||||
<div class="profile-container">
|
||||
<h1 class="wide-centered-header">{%w pres.edit-profile.change-user-attributes %}</h1>
|
||||
<form action = "/user/{% W alienprofile.nickname %}" method="post" enctype="application/x-www-form-urlencoded">
|
||||
<table class="logins-input-table">
|
||||
<tr>
|
||||
<td class="logins-input-td1">
|
||||
<label for="new-name-input">Enter new name:</label>
|
||||
<label for="new-name-input">{%w pres.edit-profile.directive-name %}</label>
|
||||
</td>
|
||||
<td class="logins-input-td2">
|
||||
<input name="name" id="new-name-input" type="text" placeholder="New name" class="one-line-input">
|
||||
<input name="name" id="new-name-input" type="text"
|
||||
placeholder="{%w pres.edit-profile.placeholder-name %}" class="one-line-input">
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="logins-input-td1">
|
||||
<label for="new-password-input">Enter new password: </label>
|
||||
<label for="new-password-input">{%w pres.edit-profile.directive-password %}</label>
|
||||
</td>
|
||||
<td class="logins-input-td2">
|
||||
<input name="password" id="new-password-input" type="password" placeholder="New password" class="one-line-input">
|
||||
<input name="password" id="new-password-input" type="password"
|
||||
placeholder="{%w pres.edit-profile.placeholder-password %}" class="one-line-input">
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<label for="input-change-bio">Change description:</label>
|
||||
<label for="input-change-bio">{%w pres.edit-profile.directive-bio %}</label>
|
||||
<br>
|
||||
<textarea name="bio" id="input-change-bio" class="multiline-input"></textarea>
|
||||
<button class="action-button centered-block-el" type="submit">Submit changes</button>
|
||||
<button class="action-button centered-block-el" type="submit">{%w pres.edit-profile.act-submit %}</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -4,7 +4,7 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>List of chat rooms</title>
|
||||
<title>{%w pres.list-rooms.header %}</title>
|
||||
<link rel="icon" type="image/png" href="/assets/img/favicon.png">
|
||||
<link rel="stylesheet" href="/assets/css/common.css">
|
||||
<link rel="stylesheet" href="/assets/css/common-popup.css">
|
||||
@ -17,45 +17,47 @@
|
||||
let initial_chatListUpdResp = {% PUT jsinsert initial_chatListUpdResp %};
|
||||
</script>
|
||||
<div id="chat-creation-win" class="popup-window">
|
||||
<h1 class="popup-window-msg">Input identifying information for your new chat</h1>
|
||||
<h1 class="popup-window-msg">{%w pres.list-rooms.new-chat-header %}</h1>
|
||||
<table class="id-str-input-table">
|
||||
<tr>
|
||||
<td class="id-str-input-td1">
|
||||
<label for="chat-nickname-input">Enter nickname for new chat:</label>
|
||||
<label for="chat-nickname-input">{%w pres.list-rooms.directive-nickname %}</label>
|
||||
</td>
|
||||
<td class="id-str-input-td2">
|
||||
<input id="chat-nickname-input" type="text" placeholder="Take a nickname" class="one-line-input" required>
|
||||
<input id="chat-nickname-input" type="text" class="one-line-input"
|
||||
placeholder="{%w pres.list-rooms.placeholder-nickname %}" required>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="id-str-input-td1">
|
||||
<label for="chat-name-input">Enter name for new chat:</label>
|
||||
<label for="chat-name-input">{%w pres.list-rooms.directive-name %}</label>
|
||||
</td>
|
||||
<td class="id-str-input-td2">
|
||||
<input id="chat-name-input" type="text" placeholder="Come up with name" class="one-line-input" required>
|
||||
<input id="chat-name-input" type="text" class="one-line-input"
|
||||
placeholder="{%w pres.list-rooms.placeholder-name %}" required>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<h1 class="popup-window-msg">Create new chat?</h1>
|
||||
<button class="popup-window-btn-yes" id="chat-creation-win-yes">Yes, create</button>
|
||||
<button class="popup-window-btn-no" id="chat-creation-win-no">No, cancel</button>
|
||||
<h1 class="popup-window-msg">{%w pres.list-rooms.reask-create-new-chat %}</h1>
|
||||
<button class="popup-window-btn-yes" id="chat-creation-win-yes">{%w pres.list-rooms.yes-create %}</button>
|
||||
<button class="popup-window-btn-no" id="chat-creation-win-no">{%w pres.list-rooms.no-create %}</button>
|
||||
</div>
|
||||
|
||||
<div id="chat-renunciation-win" class="popup-window">
|
||||
<!-- header will actually be rewritten before showing the window to include chat nickname -->
|
||||
<h1 id="chat-renunciation-win-title" class="popup-window-msg">Are you sure you want to leave chat?</h1>
|
||||
<button class="popup-window-btn-yes" id="chat-renunciation-win-yes">Yes, leave</button>
|
||||
<button class="popup-window-btn-no" id="chat-renunciation-win-no">No, cancel</button>
|
||||
<h1 id="chat-renunciation-win-title" class="popup-window-msg">||||||||||</h1>
|
||||
<button class="popup-window-btn-yes" id="chat-renunciation-win-yes">{%w pres.list-rooms.yes-leave %}</button>
|
||||
<button class="popup-window-btn-no" id="chat-renunciation-win-no">{%w pres.list-rooms.no-leave %}</button>
|
||||
</div>
|
||||
|
||||
x
|
||||
<div class="document-container resp-container">
|
||||
<div id="navigation-panel" class="panel">
|
||||
<a href="/user/{% W userinfo.nickname %}" id="go-to-my-profile" class="panel-thing">
|
||||
<a href="/user/{%w userinfo.nickname %}" id="go-to-my-profile" class="panel-thing">
|
||||
<img alt="Go to my profile" src="/assets/img/user.svg" width="32px">
|
||||
</a>
|
||||
<p class="panel-thing panel-header-txt">
|
||||
List of available rooms
|
||||
{%w pres.list-rooms.page-description %}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
<link rel="icon" type="image/png" href="/assets/img/favicon.png">
|
||||
<link rel="stylesheet" href="/assets/css/common.css">
|
||||
<link rel="stylesheet" href="/assets/css/login.css">
|
||||
<title>{% W pres.loginP.header %}</title>
|
||||
<title>{% W pres.login.header %}</title>
|
||||
</head>
|
||||
<body>
|
||||
{% FOR error IN errors %}
|
||||
@ -17,25 +17,25 @@
|
||||
{% ENDFOR %}
|
||||
|
||||
<div class="form-container">
|
||||
<h1 class="wide-centered-header">{% W pres.loginP.header %}</h1>
|
||||
<h1 class="wide-centered-header">{% W pres.login.header %}</h1>
|
||||
<form action="/login" method="post" enctype="application/x-www-form-urlencoded">
|
||||
<table class="logins-input-table">
|
||||
<tr>
|
||||
<td class="logins-input-td1"><label for="input-nickname">{% W pres.loginP.directive-nickname %}</label></td>
|
||||
<td class="logins-input-td1"><label for="input-nickname">{% W pres.login.directive-nickname %}</label></td>
|
||||
<td class="logins-input-td2">
|
||||
<input type="text" name="nickname" id="input-nickname"
|
||||
placeholder="{% W pres.loginP.placeholder-nickname %}" class="one-line-input" required>
|
||||
placeholder="{% W pres.login.placeholder-nickname %}" class="one-line-input" required>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="logins-input-td1"><label for="input-password">{% W pres.loginP.directive-password %}</label></td>
|
||||
<td class="logins-input-td1"><label for="input-password">{% W pres.login.directive-password %}</label></td>
|
||||
<td class="logins-input-td2">
|
||||
<input name="password" id="input-password" type="password"
|
||||
placeholder="{% W pres.loginP.placeholder-password %}" class="one-line-input" required>
|
||||
placeholder="{% W pres.login.placeholder-password %}" class="one-line-input" required>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<button class="action-button centered-block-el" type="submit">{% W pres.loginP.act %}</button>
|
||||
<button class="action-button centered-block-el" type="submit">{% W pres.login.act %}</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
<link rel="icon" type="image/png" href="/assets/img/favicon.png">
|
||||
<link rel="stylesheet" href="/assets/css/common.css">
|
||||
<!-- This page is so simple, that it does not even have it's separate css file -->
|
||||
<title>User Profile</title>
|
||||
<title>{%w pres.view-profile.header-profile-of %} {%w alienprofile.name %}</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@ -22,10 +22,10 @@
|
||||
</div>
|
||||
|
||||
<div class="profile-container">
|
||||
<h2 class="profile-name-text">{% W alienprofile.name %}</h2>
|
||||
<h3 class="profile-nickname-text">Nickname: {% W alienprofile.nickname %}</h3>
|
||||
<h2 class="profile-name-text">{%w alienprofile.name %}</h2>
|
||||
<h3 class="profile-nickname-text">{%w pres.view-profile.directive-nickname%} {%w alienprofile.nickname %}</h3>
|
||||
<p class="profile-bio-text">
|
||||
{% W alienprofile.bio %}
|
||||
{%w alienprofile.bio %}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -62,7 +62,7 @@ function convertMemberStToBox(memberSt){
|
||||
return;
|
||||
userDeletionWinStoredUId = ID;
|
||||
document.getElementById("user-deletion-win-title").innerText =
|
||||
"Do you really want to kick user " + memberSt.nickname + "?";
|
||||
pres['chat-members']['reask-kick-user-X'] + " " + memberSt.nickname + "?";
|
||||
activatePopupWindowById("user-deletion-win");
|
||||
};
|
||||
box.querySelector(".CM-member-box-leave-btn").style.display =
|
||||
@ -124,7 +124,7 @@ function configureSummonUserInterface(){
|
||||
updateLocalStateFromRecv(Recv);
|
||||
}).catch((e) => {
|
||||
console.log(e);
|
||||
alert("Failed to add user to chat");
|
||||
alert(pres['chat-members']["failed-summon-member"]);
|
||||
});
|
||||
};
|
||||
|
||||
@ -158,7 +158,7 @@ function configureKickUserInterfaceWinPart(){
|
||||
updateLocalStateFromRecv(Recv);
|
||||
}).catch((e) => {
|
||||
console.log(e);
|
||||
alert("Failed to kick user from chat");
|
||||
alert(pres['chat-members']["failed-kick-member"]);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,7 @@ let storeHiddenMsgIdForDeletionWin = -1;
|
||||
// Positive in production, negative for debug
|
||||
let softZoneSz = -150;
|
||||
let chatPadding = 300;
|
||||
const msgErased = pres.chat.msgErased;
|
||||
|
||||
function genSentBase(){
|
||||
return {
|
||||
@ -168,13 +169,13 @@ function decodeSystemMessage(text){
|
||||
let subjectRef = members.has(subjectId) ? members.get(subjectId).nickname : "???";
|
||||
let objectRef = members.has(objectId) ? members.get(objectId).nickname : "???";
|
||||
if (verb === "kicked"){
|
||||
return subjectRef + " kicked " + objectRef;
|
||||
return subjectRef + " " + pres.chat.syslog.kicked + " " + objectRef;
|
||||
} else if (verb === "summoned"){
|
||||
return subjectRef + " summoned " + objectRef;
|
||||
return subjectRef + " " + pres.chat.syslog.summoned + " " + objectRef;
|
||||
} else if (verb === "left"){
|
||||
return subjectRef + " left chat";
|
||||
return subjectRef + " " + pres.chat.syslog.left;
|
||||
} else if (verb === "created"){
|
||||
return subjectRef + " created this chat";
|
||||
return subjectRef + " " + pres.chat.syslog.created;
|
||||
}
|
||||
return "... Bad log ...";
|
||||
}
|
||||
@ -239,7 +240,6 @@ function convertMessageStToSupercontainer(messageSt){
|
||||
return;
|
||||
let URI = window.location.host + "/chat/" + openedchat.nickname + "/m/" + String(ID);
|
||||
document.getElementById("message-input").innerText += (" " + URI + "");
|
||||
console.log("Tried to get link on message " + ID);
|
||||
};
|
||||
}
|
||||
|
||||
@ -389,7 +389,7 @@ function configureMsgDeletionPopupButtons(){
|
||||
deactivateActivePopup();
|
||||
let Sent = genSentBase();
|
||||
Sent.id = storeHiddenMsgIdForDeletionWin;
|
||||
safeApiRequestWithLocalStUpdate("deleteMessage", Sent, "Failed to delete message");
|
||||
safeApiRequestWithLocalStUpdate("deleteMessage", Sent, pres.chat['failed-delete-message']);
|
||||
};
|
||||
|
||||
document.getElementById("msg-deletion-no").onclick = function (ev){
|
||||
@ -426,7 +426,7 @@ window.onload = function (){
|
||||
let Sent = genSentBase();
|
||||
Sent.content = {};
|
||||
Sent.content.text = text;
|
||||
safeApiRequestWithLocalStUpdate("sendMessage", Sent, "Failed to send message");
|
||||
safeApiRequestWithLocalStUpdate("sendMessage", Sent, pres.chat['failed-send-message']);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -57,9 +57,6 @@ function roleToColor(role) {
|
||||
return "#286500" // Bug
|
||||
}
|
||||
|
||||
// todo: replace it with translation
|
||||
const msgErased = "[ ERASED ]";
|
||||
|
||||
function hideHTMLElement(el){
|
||||
el.style.display = "none";
|
||||
}
|
||||
|
@ -13,7 +13,8 @@ let chatBoxes = new Map();
|
||||
|
||||
/* Generate text that is displayed on the right side of chat intro box */
|
||||
function youAreXHere(myRoleHere){
|
||||
return "You are " + myRoleHere + " here";
|
||||
// todo: TRANSLATE IT
|
||||
return pres['list-rooms']['you-are-X-here'][0] + " " + myRoleHere + " " + pres['list-rooms']['you-are-X-here'][1];
|
||||
}
|
||||
|
||||
|
||||
@ -67,7 +68,7 @@ function convertMyMembershipStToBox(myMembershipSt){
|
||||
return;
|
||||
chatRenunciationWinStoredId = ID;
|
||||
document.getElementById("chat-renunciation-win-title").innerText =
|
||||
"Do you really want to leave chat " + myMembershipSt.chatNickname + "?";
|
||||
pres['list-rooms']['reask-leave-chat-X'] + " " + myMembershipSt.chatNickname + "?";
|
||||
activatePopupWindowById("chat-renunciation-win");
|
||||
};
|
||||
box.querySelector(".CL-my-chat-box-leave-btn").style.display =
|
||||
@ -119,7 +120,7 @@ function configureChatCreationInterface(){
|
||||
).then((Recv) => {
|
||||
updateLocalStateFromRecv(Recv);
|
||||
}).catch((e) => {
|
||||
alert("Failed to create chat");
|
||||
alert(pres['list-rooms']["failed-create-chat"]);
|
||||
console.log(e);
|
||||
});
|
||||
};
|
||||
@ -138,7 +139,6 @@ function configureChatCreationInterface(){
|
||||
chatNicknameInput.value = "";
|
||||
chatNameInput.value = "";
|
||||
activatePopupWindowById("chat-creation-win");
|
||||
console.log("Tried to show chat creation window");
|
||||
};
|
||||
}
|
||||
|
||||
@ -156,7 +156,7 @@ function configureChatRenunciationInterfaceWinPart(){
|
||||
).then((Recv) => {
|
||||
updateLocalStateFromRecv(Recv);
|
||||
}).catch((e) => {
|
||||
alert("Failed to leave chat");
|
||||
alert(pres['list-rooms']["failed-create-chat"]);
|
||||
console.log(e);
|
||||
});
|
||||
}
|
||||
|
@ -1,11 +1,76 @@
|
||||
{
|
||||
"lang": "en",
|
||||
"loginP": {
|
||||
"login": {
|
||||
"header": "Login",
|
||||
"directive-nickname": "Enter your nickname:",
|
||||
"placeholder-nickname": "Nickname",
|
||||
"directive-password": "Enter password:",
|
||||
"placeholder-password": "Password",
|
||||
"act": "Login"
|
||||
"act": "Login",
|
||||
"incorrect-nickname-or-password": "Incorrect nickname or password"
|
||||
},
|
||||
"view-profile": {
|
||||
"header-profile-of": "Profile of",
|
||||
"directive-nickname": "Nickname:"
|
||||
},
|
||||
"edit-profile": {
|
||||
"header-profile-of": "Profile of",
|
||||
"change-user-attributes": "Change user attributes",
|
||||
"directive-nickname": "Nickname:",
|
||||
"directive-name": "Enter new name:",
|
||||
"placeholder-name": "New name",
|
||||
"directive-password": "Enter new password:",
|
||||
"placeholder-password": "New password",
|
||||
"directive-bio": "Change description:",
|
||||
"act-submit": "Submit changes",
|
||||
"incorrect-profile-data": "Incorrec profile data"
|
||||
},
|
||||
"list-rooms": {
|
||||
"header": "List of chat rooms",
|
||||
"new-chat-header": "Input identifying information for your new chat",
|
||||
"directive-nickname": "Enter nickname for new chat:",
|
||||
"placeholder-nickname": "Take a nickname",
|
||||
"directive-name": "Enter name for new chat:",
|
||||
"placeholder-name": "Come up with name",
|
||||
"reask-create-new-chat": "Create new chat?",
|
||||
"yes-create": "Yes, create",
|
||||
"no-create": "No, cancel",
|
||||
"reask-leave-chat-X": "Do you really want to leave chat",
|
||||
"yes-leave": "Yes, leave",
|
||||
"no-leave": "No, cancel",
|
||||
"page-description": "List of available rooms",
|
||||
"you-are-X-here": ["You are", "here"],
|
||||
|
||||
"failed-create-chat": "Failed to create chat",
|
||||
"failed-to-leave-chat": "Failed to leave chat"
|
||||
},
|
||||
"chat-members": {
|
||||
"members-of": "Members of",
|
||||
"summon-label-nickname": "Nickname for summoned user",
|
||||
"summon-label-ro": "Make read only",
|
||||
"yes-summon": "Yes, summon",
|
||||
"no-summon": "No, cancel",
|
||||
"yes-kick": "Yes, delete",
|
||||
"no-kick": "No, cancel",
|
||||
"members-list-of": "Members list of",
|
||||
"reask-kick-user-X" : "Do you really want to kick user",
|
||||
|
||||
"failed-summon-member": "Failed to add user to chat",
|
||||
"failed-kick-member": "Failed to kick user from chat"
|
||||
},
|
||||
"chat": {
|
||||
"header-chat": "Chat",
|
||||
"reask-delete-message": "Are you sure you want to delete this message?",
|
||||
"yes-delete": "Yes, delete",
|
||||
"no-delete": "No, cancel",
|
||||
"msgErased": "[ ERASED ]",
|
||||
"syslog": {
|
||||
"kicked": "kicked",
|
||||
"summoned": "summoned",
|
||||
"left": "left chat",
|
||||
"created": "created this chat"
|
||||
},
|
||||
"failed-delete-message": "Failed to delete message",
|
||||
"failed-send-message": "Failed to send message"
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,21 @@
|
||||
{
|
||||
"lang": "ru",
|
||||
"loginP": {
|
||||
"login": {
|
||||
"header": "Вход",
|
||||
"directive-nickname": "Введите свой никнейм:",
|
||||
"placeholder-nickname": "",
|
||||
"placeholder-nickname": "Никнейм",
|
||||
"directive-password": "Введите пароль:",
|
||||
"placeholder-password": "",
|
||||
"act": "Войти"
|
||||
"placeholder-password": "Пароль",
|
||||
"act": "Войти",
|
||||
"incorrect-nickname-or-password": "Неверный логин или пароль"
|
||||
},
|
||||
"view-profile": {
|
||||
"header-profile-of": "Профиль",
|
||||
"directive-nickname": "Никнейм:"
|
||||
},
|
||||
"edit-profile": {
|
||||
"header-profile-of": "Профиль",
|
||||
"directive-nickname": "Никнейм:",
|
||||
"change-user-attributes": "Изменить аттрибуты пользователя"
|
||||
}
|
||||
}
|
@ -1,8 +1,6 @@
|
||||
{% ELDEF main JSON cba %}
|
||||
{% ELDEF main JSON userprofile %}
|
||||
AAA
|
||||
{% FOR val IN cba.arr %}
|
||||
--> {% WRITE val %}
|
||||
{% ENDFOR %}
|
||||
--> {% WRITE userprofile.name %}
|
||||
AAA
|
||||
|
||||
{% ENDELDEF %}
|
||||
|
@ -9,15 +9,11 @@ int main(int argc, char** argv) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
std::string dir_path = argv[1];
|
||||
// std::string dir_path = "./src/http_server/misc_tests/HypertextPages";
|
||||
std::string dir_path = "/home/gregory/cpp_projects/iu9-ca-web-chat/assets/HypertextPages";
|
||||
nytl::Templater templater(nytl::TemplaterSettings{nytl::TemplaterDetourRules{dir_path}});
|
||||
templater.update();
|
||||
|
||||
std::string config_file = argv[2];
|
||||
std::string config_text;
|
||||
een9::readFile(config_file, config_text);
|
||||
const json::JSON config = json::parse_str_flawless(config_text);
|
||||
|
||||
json::JSON userprofile;
|
||||
userprofile["uid"].asInteger() = json::Integer(0l);
|
||||
userprofile["name"].asString() = "radasdasdasdadsdasd";
|
||||
@ -25,7 +21,7 @@ int main(int argc, char** argv) {
|
||||
userprofile["bio"].asString() = "Your mother";
|
||||
json::JSON errors;
|
||||
errors = json::JSON(json::array);
|
||||
std::string answer2 = templater.render("edit-profile", {&config["presentation"], &userprofile, &errors});
|
||||
std::string answer2 = templater.render("err-404", {});
|
||||
printf("%s\n<a><f><t><e><r><><l><f>\n", answer2.c_str());
|
||||
|
||||
return 0;
|
||||
|
@ -7,8 +7,13 @@ namespace nytl {
|
||||
void debug_print_templater(const Templater& T) {
|
||||
printf("===== TEMPLATER INTERNAL RESOURCES =====\n");
|
||||
for (auto& p: T.elements) {
|
||||
if (!p.second.is_element) {
|
||||
printf("=== %s is empty =====\n", p.first.c_str());
|
||||
continue;
|
||||
}
|
||||
printf("=== %s element =====\n", p.first.c_str());
|
||||
const Element& el = p.second;
|
||||
assert(p.second.when_element);
|
||||
const Element& el = *p.second.when_element;
|
||||
printf("%s, %s\n", el.base ? "BASE" : "NOT BASE", el.is_hidden ? "HIDDEN" : "NOT HIDDEN");
|
||||
if (!el.is_hidden) {
|
||||
std::string signature;
|
||||
|
@ -150,17 +150,41 @@ namespace nytl {
|
||||
return concatenateLines(lines);
|
||||
}
|
||||
|
||||
void parse_bare_file(const std::string& filename, const std::string& content,
|
||||
global_elem_set_t& result)
|
||||
{
|
||||
if (result.count(filename) != 0)
|
||||
THROW("Repeated element " + filename);
|
||||
Element& add_hidden_element(const std::string& new_el_name, global_elem_set_t& result) {
|
||||
if (result.count(new_el_name) != 0)
|
||||
THROW("Repated element " + new_el_name);
|
||||
TemplaterRegPref& rp = result[new_el_name];
|
||||
rp.is_element = 1;
|
||||
rp.when_element = std::make_unique<Element>();
|
||||
rp.when_element->is_hidden = true;
|
||||
return *rp.when_element;
|
||||
}
|
||||
|
||||
Element& add_new_element(const std::string& new_el_name, global_elem_set_t& result) {
|
||||
if (!is_uname_dotted_sequence(new_el_name))
|
||||
THROW("Krabovaya oshibka");
|
||||
if (result.count(new_el_name) != 0 && result.at(new_el_name).is_element)
|
||||
THROW("Repated element " + new_el_name);
|
||||
size_t n = new_el_name.size();
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
if (new_el_name[i] == '.') {
|
||||
std::string pref = new_el_name.substr(0, i);
|
||||
result[pref];
|
||||
}
|
||||
}
|
||||
TemplaterRegPref& rp = result[new_el_name];
|
||||
rp.is_element = 1;
|
||||
rp.when_element = std::make_unique<Element>();
|
||||
return *rp.when_element;
|
||||
}
|
||||
|
||||
void parse_bare_file(const std::string& filename, const std::string& content, global_elem_set_t& result) {
|
||||
Element& el = add_new_element(filename, result);
|
||||
std::string txt = clement_lstrip(content);
|
||||
rstrip(txt);
|
||||
size_t cut = 9999999999999;
|
||||
one_part_update_min_start_wsp_non_empty(txt, 0, 1, cut);
|
||||
txt = one_part_cut_excess_tab(txt, 0, 1, cut);
|
||||
Element& el = result[filename];
|
||||
el.parts = {ElementPart{}};
|
||||
el.parts[0].when_code.lines = mv(txt);
|
||||
}
|
||||
@ -379,8 +403,7 @@ namespace nytl {
|
||||
skipWhitespace(ctx);
|
||||
P.ref_over = parse_expression(ctx, local_var_names);
|
||||
P.internal_element = el_name + ".~" + std::to_string(free_hidden++);
|
||||
Element& newborn = elem_ns[P.internal_element];
|
||||
newborn.is_hidden = true;
|
||||
Element& newborn = add_hidden_element(P.internal_element, elem_ns);
|
||||
arg_name_list_t local_var_names_of_nxt = local_var_names;
|
||||
if (V1 != "_") {
|
||||
if (local_var_names_of_nxt.count(V1) != 0)
|
||||
@ -417,8 +440,7 @@ namespace nytl {
|
||||
skipWhitespace(ctx);
|
||||
P.ref_over = parse_expression(ctx, local_var_names);
|
||||
P.internal_element = el_name + ".~" + std::to_string(free_hidden++);
|
||||
Element& newborn = elem_ns[P.internal_element];
|
||||
newborn.is_hidden = true;
|
||||
Element& newborn = add_hidden_element(P.internal_element, elem_ns);
|
||||
arg_name_list_t local_var_names_of_nxt = local_var_names;
|
||||
size_t k = local_var_names_of_nxt.size();
|
||||
local_var_names_of_nxt.emplace(Vn, k);
|
||||
@ -427,7 +449,7 @@ namespace nytl {
|
||||
return std::make_unique<ECPFrame>(P.internal_element, gone_for_ref, local_var_names_of_nxt,
|
||||
ret_data_int, newborn);
|
||||
}
|
||||
if (op == "PUT") {
|
||||
if (op == "PUT" || op == "P") {
|
||||
result.parts.emplace_back();
|
||||
result.parts.back().type = ElementPart::p_put;
|
||||
ElementPart::when_put_S& P = result.parts.back().when_put;
|
||||
@ -549,9 +571,7 @@ namespace nytl {
|
||||
if (elname_postfix == "_")
|
||||
THROW("Can't use _ as element name");
|
||||
std::string fullname = elname_postfix == "main" ? filename : filename + "." + elname_postfix;
|
||||
if (result.count(fullname) != 0)
|
||||
THROW("Element " + fullname + " has been already defined");
|
||||
Element& newborn = result[fullname];
|
||||
Element& newborn = add_new_element(fullname, result);
|
||||
arg_name_list_t arglist;
|
||||
while (true) {
|
||||
skipWhitespace(ctx);
|
||||
|
@ -23,37 +23,41 @@ namespace nytl {
|
||||
result(result) {
|
||||
}
|
||||
|
||||
void descend(const json::JSON& what) {
|
||||
void descend(const json::JSON& what, const global_elem_set_t& global_elems) {
|
||||
if (result.is_json) {
|
||||
const json::JSON& P = *result.JSON_subval;
|
||||
if (P.isArray() && what.isInteger()) {
|
||||
const std::vector<json::JSON>& arr_p = P.asArray();
|
||||
int64_t ind_w = what.asInteger().get_int();
|
||||
ASSERT(ind_w > 0 && ind_w < arr_p.size(), "Expression \"array[integer]\" caused out-of-bound situation");
|
||||
if (!(ind_w > 0 && ind_w < arr_p.size()))
|
||||
THROW("Expression \"array[integer]\" caused out-of-bound situation");
|
||||
result = LocalVarValue{true, "", &arr_p[ind_w]};
|
||||
} else if (P.isDictionary() && what.isString()) {
|
||||
const std::map<std::string, json::JSON>& dict_p = P.asDictionary();
|
||||
const std::string& key_w = what.asString();
|
||||
ASSERT(dict_p.count(key_w) == 1, "No such key exception (" + key_w + ")");
|
||||
if (dict_p.count(key_w) != 1)
|
||||
THROW("No such key exception (" + key_w + ")");
|
||||
result = LocalVarValue{true, "", &dict_p.at(key_w)};
|
||||
} else
|
||||
THROW("Incorrect type of \"json[json]\" expression. Unallowed signature of [] operator");
|
||||
} else {
|
||||
ASSERT(what.isString(), "Expression \"element[X]\" allowed only if X is string (json object)");
|
||||
if (what.asString().empty())
|
||||
return;
|
||||
if (!is_uname_dotted_sequence(what.asString()))
|
||||
THROW("Incorrect X in \"element[X]\"");
|
||||
if (!what.isString())
|
||||
THROW("Expression \"element[X]\" allowed only if X is string (json object)");
|
||||
if (!isUname(what.asString()))
|
||||
THROW("Expression \"element[str]\" has incorrect str (" + what.asString() + ")");
|
||||
result.EL_name += ("." + what.asString());
|
||||
if (global_elems.count(result.EL_name) != 1)
|
||||
THROW("Can't descend. No such element (" + result.EL_name + ")");
|
||||
}
|
||||
}
|
||||
|
||||
uptr<EEFrame> toMe(bool returned, const global_elem_set_t& global_elems,
|
||||
const std::vector<LocalVarValue>& local_vars) {
|
||||
if (returned) {
|
||||
ASSERT(temp_ret.is_json, "Expression \"X[ element ]\" is not allowed");
|
||||
if (!temp_ret.is_json)
|
||||
THROW("Expression \"X[ element ]\" is not allowed");
|
||||
assert(temp_ret.JSON_subval);
|
||||
descend(*(temp_ret.JSON_subval));
|
||||
descend(*(temp_ret.JSON_subval), global_elems);
|
||||
} else {
|
||||
assert(expr.isDictionary());
|
||||
const json::JSON& val = expr["V"];
|
||||
@ -63,6 +67,8 @@ namespace nytl {
|
||||
result = local_vars[lv_ind];
|
||||
} else if (val.isString()) {
|
||||
std::string cur_el_name_str = expr["V"].asString();
|
||||
if (global_elems.count(cur_el_name_str) != 1)
|
||||
THROW("Bad expression, no such element (" + cur_el_name_str + ")");
|
||||
result = LocalVarValue{false, cur_el_name_str, NULL};
|
||||
} else
|
||||
assert(false);
|
||||
@ -74,7 +80,7 @@ namespace nytl {
|
||||
const json::JSON& t = chain[chain_el++];
|
||||
if (t.isDictionary())
|
||||
return std::make_unique<EEFrame>(t, temp_ret);
|
||||
descend(t);
|
||||
descend(t, global_elems);
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -84,6 +90,8 @@ namespace nytl {
|
||||
* and dictionaries. They are stored in json in rendering stack */
|
||||
LocalVarValue rendering_core_execute_expression(const global_elem_set_t& global_elems,
|
||||
const std::vector<LocalVarValue>& local_vars, const json::JSON& expr) {
|
||||
|
||||
// todo: check if root element exists (if root value is not local variable, then it is element of package)
|
||||
bool returned = false;
|
||||
std::vector<uptr<EEFrame>> stack;
|
||||
LocalVarValue result;
|
||||
@ -211,9 +219,9 @@ namespace nytl {
|
||||
uptr<RFrame> RFrame_OverParts::toMe(bool returned, const global_elem_set_t &elem_ns, Ditch &result,
|
||||
const std::function<std::string(std::string)> &escape) {
|
||||
if (!returned)
|
||||
if (elem_ns.count(name) != 1)
|
||||
THROW("No such element (" + name + ")");
|
||||
const Element& el = elem_ns.at(name);
|
||||
if ((elem_ns.count(name) != 1) || (!elem_ns.at(name).is_element))
|
||||
THROW("Can't render. No such element (" + name + ")");
|
||||
const Element& el = *elem_ns.at(name).when_element;
|
||||
if (!returned) {
|
||||
/* Continue to do checks */
|
||||
/* hidden elements (internal) do not need any check */
|
||||
@ -222,16 +230,17 @@ namespace nytl {
|
||||
ASSERT(n == passed_args.size(), "Argument count mismatch");
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
if (el.arguments[i].type == json::true_symbol) {
|
||||
ASSERT(passed_args[i].is_json, "Expected json element argument, got element");
|
||||
if (!passed_args[i].is_json)
|
||||
THROW("Expected json element argument, got element");
|
||||
} else {
|
||||
// If not json is expected, element must be expected
|
||||
assert(el.arguments[i].isArray());
|
||||
ASSERT(!passed_args[i].is_json, "Expected element element arguemnt, got json");
|
||||
if (passed_args[i].is_json)
|
||||
THROW("Expected element element arguemnt, got json");
|
||||
const std::string& passed_el_as_arg = passed_args[i].EL_name;
|
||||
if (elem_ns.count(passed_el_as_arg) != 1)
|
||||
if ((elem_ns.count(passed_el_as_arg) != 1) || !elem_ns.at(passed_el_as_arg).is_element)
|
||||
THROW("No such element, can't compare signatures of argument value (" + passed_el_as_arg + ")");
|
||||
const Element& arg_element = elem_ns.at(passed_args[i].EL_name);
|
||||
// ASSERT(passed_args);
|
||||
const Element& arg_element = elem_ns.at(passed_el_as_arg).when_element.operator*();
|
||||
if(el.arguments[i].asArray() != arg_element.arguments)
|
||||
THROW("Signature of argument " + std::to_string(i) + " does not match");
|
||||
}
|
||||
|
@ -109,16 +109,17 @@ namespace nytl {
|
||||
return result;
|
||||
}
|
||||
|
||||
TemplaterRegPref gen_base_element() {
|
||||
Element* e = new Element{{json::JSON(true)}, true, false, {}};
|
||||
return {1, std::unique_ptr<Element>(e)};
|
||||
}
|
||||
|
||||
void Templater::update() {
|
||||
elements = {
|
||||
{"jsinsert", Element{{json::JSON(true)}, true}},
|
||||
{"jesc", Element{{json::JSON(true)}, true}},
|
||||
{"jesccomp", Element{{json::JSON(true)}, true}},
|
||||
/* str2text base element has a dedicated operator - WRITE */
|
||||
{"str2text", Element{{json::JSON(true)}, true}},
|
||||
/* str2code base element has a dedicated operator - ROUGHINSERT */
|
||||
{"str2code", Element{{json::JSON(true)}, true}},
|
||||
};
|
||||
elements[""] = TemplaterRegPref{0, NULL};
|
||||
elements["jsinsert"] = gen_base_element();
|
||||
elements["jesc"] = gen_base_element();
|
||||
elements["str2text"] = gen_base_element();
|
||||
elements["str2code"] = gen_base_element();
|
||||
std::vector<InterestingFile> intersting_files = indexing_detour(settings.det);
|
||||
for (const InterestingFile& file: intersting_files) {
|
||||
std::string content = readFile(file.path);
|
||||
@ -132,7 +133,8 @@ namespace nytl {
|
||||
|
||||
/* Still can throw some stuff derived from std::exception (like bad alloc) */
|
||||
std::string Templater::render(const std::string& element, const std::vector<const json::JSON*> &arguments) const {
|
||||
ASSERT(is_uname_dotted_sequence(element), "Incorrect entry element name");
|
||||
if (!is_uname_dotted_sequence(element))
|
||||
THROW("Incorrect entry element name");
|
||||
return rendering_core(element, arguments, elements, settings.escape);
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,8 @@
|
||||
#include <jsonincpp/jsonobj.h>
|
||||
#include <functional>
|
||||
#include "html_case.h"
|
||||
#include <memory>
|
||||
#include <forward_list>
|
||||
|
||||
namespace nytl {
|
||||
typedef json::JSON expression_t;
|
||||
@ -61,7 +63,12 @@ namespace nytl {
|
||||
std::function<std::string(std::string)> escape = html_case_espace_string;
|
||||
};
|
||||
|
||||
typedef std::map<std::string, Element> global_elem_set_t;
|
||||
struct TemplaterRegPref {
|
||||
int is_element = 0;
|
||||
std::unique_ptr<Element> when_element = NULL;
|
||||
};
|
||||
|
||||
typedef std::map<std::string, TemplaterRegPref> global_elem_set_t;
|
||||
|
||||
struct Templater {
|
||||
TemplaterSettings settings;
|
||||
|
@ -28,7 +28,7 @@ namespace iu9cawebchat {
|
||||
if (uid < 0) {
|
||||
printf("Redirecting back to /login because of incorrect credentials\n");
|
||||
json::JSON msg_list = jsonify_html_message_list({{"",
|
||||
config_presentation["phr"]["decl"]["incorrect-nickname-or-password"].asString()}});
|
||||
config_presentation["loginP"]["incorrect-nickname-or-password"].asString()}});
|
||||
return http_R200("login", wgd, {&config_presentation, &userinfo, &msg_list});
|
||||
}
|
||||
std::vector<std::pair<std::string, std::string>> response_hlines;
|
||||
|
@ -104,7 +104,7 @@ namespace iu9cawebchat {
|
||||
} 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()}});
|
||||
config_presentation["edit-profile"]["incorrect-profile-data"].asString()}});
|
||||
json::JSON alien_userprofile = user_row_to_userprofile_obj(conn, alien);
|
||||
return http_R200("edit-profile", wgd, {&config_presentation, &userinfo, &alien_userprofile, &msg_list});
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user