Compare commits

..

40 commits
dev ... main

Author SHA1 Message Date
43263e763e Update CI file
All checks were successful
ci / build_and_publish (push) Successful in 1m36s
2026-01-14 16:20:54 +00:00
e986fdbc08 Update CI file
Some checks failed
ci / build_and_publish (push) Failing after 1m29s
2026-01-14 16:18:42 +00:00
b7787933db Add CI file
Some checks failed
ci / build_and_publish (push) Failing after 42s
2026-01-14 15:11:50 +00:00
N Pex
bd3c59397e Merge branch 'dev' into 'main'
Merge branch "dev" into "main"

See merge request keanuapp/keanuapp-weblite!380
2025-12-16 15:46:29 +00:00
N Pex
51c68269cb Merge branch 'dev' into 'main'
Build 88 Merge from dev

See merge request keanuapp/keanuapp-weblite!373
2025-11-13 08:15:47 +00:00
N Pex
a5b12c5bff Merge branch 'dev' into 'main'
Build 72 Merge from dev

See merge request keanuapp/keanuapp-weblite!357
2025-09-11 15:11:59 +00:00
N Pex
86ab6830cc
Merge branch 'dev' into 'main'
Merge from dev (build 68)

See merge request keanuapp/keanuapp-weblite!355
2025-09-05 12:41:29 +00:00
N Pex
adf6320169 Merge branch 'dev' into 'main'
Merge from dev (build 44)

See merge request keanuapp/keanuapp-weblite!345
2025-04-25 12:16:19 +00:00
N Pex
ab01d4ddc3 Merge branch 'dev' into 'main'
Build 43 - merged from dev

See merge request keanuapp/keanuapp-weblite!339
2025-03-31 14:41:48 +00:00
N-Pex
ec87ebf310 Merge branch 'dev' 2024-12-19 17:14:28 +01:00
N Pex
ecbaa4f7e7 Merge branch 'dev' into 'main'
Merge latest translations from dev

See merge request keanuapp/keanuapp-weblite!318
2024-10-01 07:32:54 +00:00
N-Pex
cbad68ecec Merge branch 'dev' 2024-08-23 09:45:13 +02:00
N-Pex
2b33ee129e Build 39 2024-07-12 13:17:35 +02:00
N-Pex
0068dd9dff Merge branch 'dev' 2024-07-12 13:16:46 +02:00
N-Pex
c333719477 Build 38 2024-05-16 16:50:04 +02:00
N-Pex
69e8afd5be Merge branch 'dev' 2024-05-16 16:48:51 +02:00
N-Pex
bd5a7d1060 Build 37 2023-12-05 17:26:10 +01:00
N-Pex
2aa1ab3931 Merge branch 'dev' 2023-12-05 17:25:39 +01:00
N-Pex
c35c96f1aa Build 36 2023-12-04 15:35:54 +01:00
N-Pex
cfafead533 Merge branch 'dev' 2023-12-04 15:35:13 +01:00
N-Pex
b0183d3cfa Build 35 2023-11-27 22:29:44 +01:00
N-Pex
5857df82ef Merge branch 'dev' 2023-11-27 18:42:38 +01:00
irl
936f911bb0 Update .gitlab-ci.yml file 2023-10-25 11:34:03 +01:00
N-Pex
2e62a5b1cc Build 34 2023-07-11 13:28:27 +02:00
N-Pex
a59f98902c Merge branch 'dev' 2023-07-11 13:16:10 +02:00
N-Pex
b18e4d3177 Build 33 2023-05-17 09:11:03 +02:00
N-Pex
f570d2ba90 Merge branch 'dev' 2023-05-17 09:06:25 +02:00
N-Pex
dfca3440d2 Build 32 2023-03-06 08:59:26 +01:00
N-Pex
abd78c2b2c Merge dev ('d81a9193') 2023-03-06 08:57:54 +01:00
N-Pex
fa23abebd7 Build 31 2023-01-18 15:12:44 +01:00
N-Pex
56edae3e4d Merge branch 'dev' 2023-01-18 15:12:08 +01:00
N-Pex
ae2baaa8f9 Build 30 2022-12-06 16:36:20 +01:00
N-Pex
ceaf5ba08f Merge branch 'dev' 2022-12-06 16:35:48 +01:00
N-Pex
2f8a4f43b0 Build 29 2022-10-29 09:35:57 +02:00
N-Pex
b70d0a975c Merge branch 'dev' 2022-10-29 09:35:41 +02:00
N-Pex
3872573d66 Build 28 2022-10-19 16:21:28 +02:00
N-Pex
d7b6d14cf8 Merge branch 'dev' 2022-10-19 16:20:38 +02:00
N-Pex
fcc010a1cf Build 27 2022-07-08 16:36:47 +02:00
N-Pex
5f33782863 Merge branch 'dev' 2022-07-08 16:33:22 +02:00
N-Pex
f3999308cc Merge branch 'dev' 2022-05-31 22:37:51 +02:00
18 changed files with 202 additions and 891 deletions

25
.github/workflows/ci.yaml vendored Normal file
View file

@ -0,0 +1,25 @@
name: ci
on:
push:
branches:
- main
pull_request:
branches:
- main
jobs:
build_and_publish:
runs-on: docker
container:
image: ghcr.io/catthehacker/ubuntu:runner-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- run: npm install
- run: sudo apt update && sudo apt install -y tar
- run: export NODE_OPTIONS=--openssl-legacy-provider
- run: npm run build
- run: tar cvzf keanu-weblite.tar.gz dist/*
- run: |
curl -H "Authorization: token ${{ secrets.PACKAGE_TOKEN }}" -X DELETE "https://guardianproject.dev/api/packages/butter/generic/keanu-weblite/latest"
- run: |
curl -H "Authorization: token ${{ secrets.PACKAGE_TOKEN }}" -X PUT --upload-file keanu-weblite.tar.gz https://guardianproject.dev/api/packages/butter/generic/keanu-weblite/latest/keanu-weblite.tar.gz

View file

@ -1,6 +1,6 @@
{ {
"name": "keanuapp-weblite", "name": "keanuapp-weblite",
"version": "0.1.96", "version": "0.1.91",
"private": true, "private": true,
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",

View file

@ -1,6 +1,6 @@
{ {
"name": "keanuapp-weblite", "name": "keanuapp-weblite",
"version": "0.1.95", "version": "0.1.90",
"private": true, "private": true,
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",

View file

@ -1,172 +0,0 @@
<html>
<head>
<meta charset="UTF-8">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap" rel="stylesheet">
<script lang="javascript">
const STORE_KEY_USER = `convene_${window.location.hostname}_user`;
const STORE_KEY_SETTINGS = `convene_${window.location.hostname}_settings`;
let windowProxy = null;
function updateNetworkState() {
if (navigator.onLine) {
document.body.classList.remove("offline");
} else {
document.body.classList.add("offline");
}
}
window.addEventListener("load", (event) => {
updateNetworkState();
});
window.addEventListener("offline", (e) => {
updateNetworkState();
});
window.addEventListener("online", (e) => {
updateNetworkState();
});
function go() {
if (navigator.onLine) {
let url = "<!--MIRROR_URL-->" + window.location.pathname + "#/?migrate=1";
if (!url.includes("://")) {
url = window.location.protocol + "//" + url;
}
windowProxy = window.open(url, "_blank");
}
}
window.addEventListener("message", function (e) {
// if (e.origin !== origin) { // TODO - What should we check here?
// return
// }
try {
const data = JSON.parse(e.data);
if (data !== null && data.cmd == "getMigrationData") {
let migrationInfo = {
};
if (window.localStorage.getItem(STORE_KEY_USER)) {
migrationInfo.type = "local";
migrationInfo.user = window.localStorage.getItem(STORE_KEY_USER);
migrationInfo.settings = window.localStorage.getItem(STORE_KEY_SETTINGS);
} else {
migrationInfo.type = "session";
migrationInfo.user = window.sessionStorage.getItem(STORE_KEY_USER);
migrationInfo.settings = window.sessionStorage.getItem(STORE_KEY_SETTINGS);
}
if (migrationInfo.user) {
try {
const user = JSON.parse(migrationInfo.user);
delete user.access_token;
delete user.device_id;
migrationInfo.user = JSON.stringify(user);
} catch (error) { }
}
event.source.postMessage(JSON.stringify(migrationInfo), event.origin);
} else if (data !== null && data.cmd == "migrationDone") {
if (windowProxy) {
windowProxy.close();
let url = "<!--MIRROR_URL-->" + window.location.pathname + "#/";
if (!url.includes("://")) {
url = window.location.protocol + "//" + url;
}
window.location.href = url;
}
}
} catch (error) {
}
});
</script>
<style>
body {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
.container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.title {
font-family: "Inter", sans-serif;
font-weight: 700;
font-style: Bold;
font-size: 16px;
leading-trim: NONE;
line-height: 125%;
letter-spacing: 0.4px;
text-align: center;
vertical-align: middle;
}
.message {
font-family: "Inter", sans-serif;
font-weight: 400;
font-style: normal;
font-size: 16px;
leading-trim: NONE;
line-height: 125%;
letter-spacing: 0.4px;
text-align: center;
vertical-align: middle;
}
button {
margin-top: 16px;
height: 40px;
border: 1px solid black;
border-radius: 20px;
background-color: white;
padding: 8px 16px;
font-family: "Poppins", sans-serif;
font-weight: 600;
font-style: SemiBold;
font-size: 14px;
leading-trim: NONE;
line-height: 18px;
letter-spacing: 0.34px;
text-align: center;
vertical-align: middle;
text-transform: uppercase;
}
button:hover {
opacity: 0.8;
cursor: pointer;
}
.offline-message {
margin-top: 40px;
visibility: hidden;
}
.offline .offline-message {
visibility: visible;
}
</style>
</head>
<body>
<div class="container">
<div class="title"><!--OFFLINE_TITLE_START-->Having trouble connecting?<!--OFFLINE_TITLE_END--></div>
<div class="message"><!--OFFLINE_MESSAGE_START-->Redirect to an alternate link to join the room<!--OFFLINE_MESSAGE_END--></div>
<button onclick="go()"><!--OFFLINE_REDIRECT_START-->Redirect me<!--OFFLINE_REDIRECT_END--></button>
<div class="offline-message">You are offline</div>
</div>
</body>
</html>

View file

@ -1,19 +1,5 @@
var periodicSyncNewMsgReminderText; var periodicSyncNewMsgReminderText;
const OFFLINE_CACHE = `offline`;
const offlineCacheFiles = ['offline.html','config.json'];
// on install we download the routes we want to cache for offline
self.addEventListener('install', evt => evt.waitUntil(caches.open(OFFLINE_CACHE).then(cache => {
console.log("SW Caching offline files");
self.skipWaiting();
return cache.addAll(offlineCacheFiles);
})));
self.addEventListener("activate", event => {
event.waitUntil(clients.claim());
});
// Notification click event listener // Notification click event listener
self.addEventListener("notificationclick", (e) => { self.addEventListener("notificationclick", (e) => {
e.notification.close(); e.notification.close();
@ -54,89 +40,3 @@ self.addEventListener('periodicsync', (event) => {
event.waitUntil(checkNewMessages()); event.waitUntil(checkNewMessages());
} }
}); });
self.addEventListener("fetch", (event) => {
if (event.request.mode === 'navigate') {
return event.respondWith(
fetch(event.request).catch((e) => {
console.log("OFFLINE, serve offline page", e);
return serveOfflinePage();
}));
} else if (event.request.url.endsWith("config.json")) {
return fetch(event.request)
.then((response) => {
console.log("Caching a new version of config.json");
let responseClone = response.clone();
caches
.open(OFFLINE_CACHE)
.then((cache) => cache.put(event.request, responseClone));
return response;
})
}
});
async function serveOfflinePage() {
let mirrorUrl = null;
const rConfig = await caches.match("config.json", { cacheName: OFFLINE_CACHE});
if (rConfig) {
const json = await rConfig.json();
const mirrors = json.mirrors;
if (mirrors && Array.isArray(mirrors) && mirrors.length > 0) {
mirrorUrl = json.mirrors[Math.floor(Math.random() * mirrors.length)];
}
}
const offlinePage = await caches.match("offline.html", { cacheName: OFFLINE_CACHE});
if (mirrorUrl && offlinePage) {
let text = await offlinePage.text();
text = text.replaceAll("<!--MIRROR_URL-->", mirrorUrl);
let title = undefined;
let message = undefined;
let redirect = undefined;
await new Promise((resolve, reject) => {
var open = indexedDB.open("ServiceWorker", 1);
open.onerror = function() {
resolve(false);
}
open.onsuccess = function() {
// Start a new transaction
var db = open.result;
var tx = db.transaction("offline_strings", "readonly");
var store = tx.objectStore("offline_strings");
var get1 = store.get("offline_title");
var get2 = store.get("offline_message");
var get3 = store.get("offline_redirect");
get1.onsuccess = function() {
title = get1.result.translation;
};
get2.onsuccess = function() {
message = get2.result.translation;
};
get3.onsuccess = function() {
redirect = get3.result.translation;
};
// Close the db when the transaction is done
tx.oncomplete = function() {
db.close();
resolve(true);
};
}
});
if (title) {
text = text.replaceAll(/<!--OFFLINE_TITLE_START-->(.*?)<!--OFFLINE_TITLE_END-->/g, title);
}
if (message) {
text = text.replaceAll(/<!--OFFLINE_MESSAGE_START-->(.*?)<!--OFFLINE_MESSAGE_END-->/g, message);
}
if (redirect) {
text = text.replaceAll(/<!--OFFLINE_REDIRECT_START-->(.*?)<!--OFFLINE_REDIRECT_END-->/g, redirect);
}
return new Response(text, { headers: {"content-type": "text/html"}});
}
throw new Error("Offline");
}

View file

@ -121,33 +121,6 @@ export default {
// Set language // Set language
this.$i18n.locale = this.$store.state.language || "en"; this.$i18n.locale = this.$store.state.language || "en";
// Store offline strings.
// TODO - Better way to to this? The service worker needs to be able to get these, OR we need multiple translated version of offline.html
//
// Inspired by https://gist.github.com/JamesMessinger/a0d6389a5d0e3a24814b
var indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB || window.shimIndexedDB;
var open = indexedDB.open("ServiceWorker", 1);
// Create the schema
open.onupgradeneeded = () => {
var db = open.result;
var store = db.createObjectStore("offline_strings", {keyPath: "id"});
};
open.onsuccess = () => {
// Start a new transaction
var db = open.result;
var tx = db.transaction("offline_strings", "readwrite");
var store = tx.objectStore("offline_strings");
store.put({id: "offline_title", translation: this.$t("offline.offline_title")});
store.put({id: "offline_message", translation: this.$t("offline.offline_message")});
store.put({id: "offline_redirect", translation: this.$t("offline.offline_redirect")});
// Close the db when the transaction is done
tx.oncomplete = function() {
db.close();
};
}
}, },
showNotification() { showNotification() {
if(document.visibilityState === "hidden") { if(document.visibilityState === "hidden") {

View file

@ -253,7 +253,6 @@
"title": "My Profile", "title": "My Profile",
"temporary_identity": "This identity is temporary. Set a password to use it again", "temporary_identity": "This identity is temporary. Set a password to use it again",
"set_password": "Set password", "set_password": "Set password",
"set_password_desc": "Convene does not store passwords and cannot recover them. We recommend storing your password in a secure location before clicking save.",
"change_name": "Change name", "change_name": "Change name",
"change_password": "Change password", "change_password": "Change password",
"my_rooms": "My rooms", "my_rooms": "My rooms",
@ -324,8 +323,7 @@
"copy_credentials": "Copy Username & Password", "copy_credentials": "Copy Username & Password",
"copied_credentials": "Copied Username & Password", "copied_credentials": "Copied Username & Password",
"copied_credentials_value": "Username: {userId} \nPassword: {password}", "copied_credentials_value": "Username: {userId} \nPassword: {password}",
"copy_credentials_desc": "Your username and password are required to regain access to your chats from a new device or browser. We recommend storing these credentials in a secure location.", "copy_credentials_desc": "Your username and password are required to regain access to your chats from a new device or browser. We recommend storing these credentials in a secure location."
"copy_credentials_desc_for_real_user": "Your username (ex: {'@user:server'}) and your password are required to regain access to your chats from a new device or browser."
}, },
"delete_post": { "delete_post": {
"confirm_text": "Are you sure you want to delete this message?", "confirm_text": "Are you sure you want to delete this message?",
@ -541,10 +539,5 @@
"generated_with_ai": "Generated with AI.", "generated_with_ai": "Generated with AI.",
"modified": "Modified.", "modified": "Modified.",
"older_than_n_months": "Older than {n} months." "older_than_n_months": "Older than {n} months."
},
"offline": {
"offline_title": "Having trouble connecting?",
"offline_message": "Redirect to an alternate link to join the room",
"offline_redirect": "Redirect me"
} }
} }

View file

@ -161,9 +161,7 @@
"learn_more": "بیش‌تر بدانید", "learn_more": "بیش‌تر بدانید",
"compressed": "فشرده", "compressed": "فشرده",
"cc_source": "منبع", "cc_source": "منبع",
"cc_location": "مکان", "cc_location": "مکان"
"captured_screenshot": "نماگرفت. ",
"screenshot": "نماگرفت. "
}, },
"project": { "project": {
"name": "تجمع", "name": "تجمع",
@ -467,11 +465,9 @@
"screenshot_probably": "تصویر شبیه به نماگرفت است.", "screenshot_probably": "تصویر شبیه به نماگرفت است.",
"generated_with_ai": "ساخته شده با هوشی.", "generated_with_ai": "ساخته شده با هوشی.",
"modified": "دستکاری شده.", "modified": "دستکاری شده.",
"older_than_n_months": "قدیمی‌تر از {n} ماه.", "older_than_n_months": "قدیمی‌تر از {n} ماه."
"download_image": "بارگیری تصویر"
}, },
"delete_post": { "delete_post": {
"confirm_text_desc": "این عمل قابل بازگشت نیست.", "confirm_text_desc": "این عمل قابل بازگشت نیست."
"confirm_text": "مطمئنید که می‌خواهید این پیام را حذف کنید؟"
} }
} }

View file

@ -259,10 +259,5 @@
}, },
"delete_post": { "delete_post": {
"confirm_text_desc": "Tätä toimintoa ei voi perua." "confirm_text_desc": "Tätä toimintoa ei voi perua."
},
"offline": {
"offline_title": "Ongelmia yhdistämisessä?",
"offline_message": "Siirry vaihtoehtoiseen linkkiin liittyäksesi huoneeseen",
"offline_redirect": "Siirrä minut"
} }
} }

View file

@ -108,7 +108,7 @@
"registration_token": "Cuir isteach comhartha clárúcháin", "registration_token": "Cuir isteach comhartha clárúcháin",
"send_token": "Seol comhartha", "send_token": "Seol comhartha",
"token_not_valid": "Comhartha míbhailí", "token_not_valid": "Comhartha míbhailí",
"username": "Ainm úsáideora (mar shampla: '@user:server')" "username": "Ainm úsáideora (m.sh.: marta)"
}, },
"join": { "join": {
"you_have_been_banned": "Cuireadh cosc ort ón seomra seo.", "you_have_been_banned": "Cuireadh cosc ort ón seomra seo.",
@ -438,8 +438,7 @@
"display_name": "Ainm taispeána", "display_name": "Ainm taispeána",
"display_name_required": "Tá ainm taispeána ag teastáil", "display_name_required": "Tá ainm taispeána ag teastáil",
"notification_label": "Fógra", "notification_label": "Fógra",
"my_rooms": "Mo sheomraí", "my_rooms": "Mo sheomraí"
"set_password_desc": "Ní stórálann Convene pasfhocail agus ní féidir leo iad a aisghabháil. Molaimid do phasfhocal a stóráil in áit shábháilte sula gcliceálann tú ar 'sábháil'."
}, },
"profile_info_popup": { "profile_info_popup": {
"you_are": "Tá tú", "you_are": "Tá tú",
@ -485,8 +484,7 @@
"copy_credentials": "Cóipeáil Ainm Úsáideora & Pasfhocal", "copy_credentials": "Cóipeáil Ainm Úsáideora & Pasfhocal",
"copied_credentials": "Ainm úsáideora & Pasfhocal cóipeáilte", "copied_credentials": "Ainm úsáideora & Pasfhocal cóipeáilte",
"copied_credentials_value": "Ainm úsáideora: {userId} \nPasfhocal: {password}", "copied_credentials_value": "Ainm úsáideora: {userId} \nPasfhocal: {password}",
"copy_credentials_desc": "Tá dainm úsáideora agus do phasfhocal ag teastáil chun rochtain a fháil ar do chomhráite arís ó ghléas nó brabhsálaí nua. Molaimid na dintiúir seo a stóráil in áit shábháilte.", "copy_credentials_desc": "Tá dainm úsáideora agus do phasfhocal ag teastáil chun rochtain a fháil ar do chomhráite arís ó ghléas nó brabhsálaí nua. Molaimid na dintiúir seo a stóráil in áit shábháilte."
"copy_credentials_desc_for_real_user": "Tá dainm úsáideora (mar shampla: '@user:server') agus do phasfhocal ag teastáil chun rochtain a fháil ar do chomhráite arís ó ghléas nó brabhsálaí nua."
}, },
"fallbacks": { "fallbacks": {
"audio_file": "Comhad fuaime", "audio_file": "Comhad fuaime",
@ -541,10 +539,5 @@
"delete_post": { "delete_post": {
"confirm_text": "An bhfuil tú cinnte gur mian leat an teachtaireacht seo a scriosadh?", "confirm_text": "An bhfuil tú cinnte gur mian leat an teachtaireacht seo a scriosadh?",
"confirm_text_desc": "Ní féidir an gníomh seo a chealú." "confirm_text_desc": "Ní féidir an gníomh seo a chealú."
},
"offline": {
"offline_title": "An bhfuil deacracht agat ceangal?",
"offline_message": "Atreoraigh chuig nasc malartach chun páirt a ghlacadh sa seomra",
"offline_redirect": "Athsheol mé"
} }
} }

View file

@ -1,188 +0,0 @@
{
"global": {
"save": "சேமி",
"show_less": "குறைவாகக் காட்டு",
"show_more": "மேலும் காட்டு",
"time": {
"recently": "இப்போது",
"minutes": "1 மணித்துளி முன்பு | {n} நிமிடங்களுக்கு முன்பு",
"hours": "1 மணி நேரத்திற்கு முன்பு | {n} மணிநேரங்களுக்கு முன்பு",
"days": "1 நாள் முன்பு | {n} சில நாட்களுக்கு முன்பு"
},
"notify": "அறிவிக்கவும்",
"retry": "மீண்டும் முயற்சிக்கவும்"
},
"menu": {
"direct_chat": "நேரடி அரட்டை",
"reply": "பதில்",
"edit": "தொகு",
"delete": "அழி",
"download": "பதிவிறக்கம்",
"done": "முடிந்தது",
"cancel": "நீக்கு",
"send": "அனுப்பு",
"login": "புகுபதிவு",
"logout": "வெளியேற்றம்",
"undo": "செயல்தவிர்",
"join": "சேர",
"ignore": "புறக்கணிக்கவும்",
"user_make_admin": "நிர்வாகி",
"user_make_moderator": "மதிப்பீட்டாளரை உருவாக்குங்கள்",
"upgrade": "மேம்படுத்தல்"
},
"message": {
"someone": "யாரோ",
"edited": "(திருத்தப்பட்டது)",
"room_joinrule_public": "பொது",
"reply_image": "படம்",
"reply_video": "ஒளிதோற்றம்",
"reply_poll": "வாக்கெடுப்பு",
"file": "கோப்பு",
"files": "கோப்புகள்",
"images": "படங்கள்",
"download_media": "மீடியாவைப் பதிவிறக்கவும்",
"download_all": "அனைத்தையும் பதிவிறக்கு",
"room_upgraded_link": "இங்கே"
},
"room": {
"leave": "விடுப்பு",
"room_list_invites": "அழைப்புகள்",
"room_list_rooms": "அறைகள்"
},
"room_welcome": {
"got_it": "கிடைத்தது",
"change": "மாற்றம்"
},
"new_room": {
"create": "உருவாக்கு",
"next": "அடுத்தது",
"options": "விருப்பங்கள்"
},
"device_list": {
"blocked": "தடுக்கப்பட்டது",
"verified": "சரிபார்க்கப்பட்டது",
"not_verified": "சரிபார்க்கப்படவில்லை"
},
"login": {
"title": "புகுபதிவு",
"password": "கடவுச்சொல்லை உள்ளிடவும்",
"login": "புகுபதிவு",
"invalid_message": "தவறான பயனர்பெயர் அல்லது கடவுச்சொல்",
"accept_terms": "ஏற்றுக்கொள்",
"resend_verification": "சரிபார்ப்பு மின்னஞ்சல் மீண்டும் அனுப்பவும்",
"token_not_valid": "தவறான கிள்ளாக்கு"
},
"getlink": {
"next": "அடுத்தது",
"continue": "தொடரவும்"
},
"create": {
"room_type_channel_name": "வாய்க்கால்",
"field_required": "இந்த புலம் தேவை"
},
"profile": {
"set_password": "கடவுச்சொல்லை அமைக்கவும்",
"change_password": "கடவுச்சொல்லை மாற்றவும்",
"select_language": "மொழி",
"password_new": "புதிய கடவுச்சொல்",
"display_name": "காட்சி பெயர்",
"notification_label": "அறிவிப்பு"
},
"profile_info_popup": {
"edit_profile": "தொகு சுயவிவரம்",
"logout": "வெளியேற்றம்"
},
"join": {
"user_name_label": "பயனர் பெயர்",
"remember_me": "என்னை நினைவில் கொள்ளுங்கள்",
"join": "அறையில் சேரவும்",
"knock": "தட்டவும்",
"enter_room": "அறையை உள்ளிடவும்"
},
"invite": {
"title": "நண்பர்களைச் சேர்க்கவும்",
"done": "முடிந்தது"
},
"leave": {
"go_back": "திரும்பிச் செல்லுங்கள்",
"leave": "விடுப்பு"
},
"delete_post": {
"confirm_text_desc": "இந்த செயலை செயல்தவிர்க்க முடியாது."
},
"purge_room": {
"button": "அழி"
},
"room_info": {
"copy_link": "இணைப்பை நகலெடு",
"members": "உறுப்பினர்கள்",
"accept_knock": "ஏற்றுக்கொள்",
"reject_knock": "மறுக்கவும்",
"hide_all": "மறை",
"leave_room": "விடுப்பு",
"user_creator": "உருவாக்கியவர்",
"user_admin": "நிர்வாகி",
"user_moderator": "மதிப்பீட்டாளர்",
"moderation": "மிதமான",
"room_type_default": "இயல்புநிலை",
"read_only_room": "படிக்கவும்",
"message_retention_2_week": "2 வாரங்கள்",
"message_retention_1_week": "1 வாரம்",
"message_retention_1_day": "1 நாள்",
"message_retention_8_hours": "8 மணி நேரம்",
"message_retention_1_hour": "1 மணி நேரம்",
"report": "அறிக்கை",
"report_reason": "காரணம்"
},
"room_info_sheet": {
"view_details": "விபரங்களை பார்"
},
"voice_recorder": {
"not_supported_title": "ஆதரிக்கப்படவில்லை"
},
"power_level": {
"default": "இயல்புநிலை"
},
"fallbacks": {
"audio_file": "ஆடியோ கோப்பு",
"video_file": "வீடியோ கோப்பு",
"download_name": "பதிவிறக்கம்"
},
"poll_create": {
"create": "வெளியிடுங்கள்",
"answer_label_n": "பதில்",
"create_poll_menu_option": "வாக்கெடுப்பை உருவாக்கவும்",
"view_results": "முடிவுகளைக் காண்க",
"poll_submit": "சமர்ப்பிக்கவும்"
},
"notification": {
"dialog": {
"enable": "இயக்கு"
}
},
"emoji": {
"categories": {
"activity": "செய்கைப்பாடு",
"flags": "கொடிகள்",
"objects": "பொருள்கள்",
"nature": "இயற்கை",
"symbols": "குறியிடுகள்",
"places": "இடங்கள்"
}
},
"file_mode": {
"sending_progress": "அனுப்புகிறது ...",
"sending": "அனுப்புகிறது",
"close": "மூடு",
"files": "கோப்புகள்",
"quality": "தகுதி",
"original": "அசல்",
"learn_more": "மேலும் அறிய",
"cc_source": "மூலம்",
"cc_location": "இடம்"
},
"cc": {
"details": "விவரங்கள்",
"download_image": "படத்தைப் பதிவிறக்கவும்"
}
}

View file

@ -183,7 +183,7 @@
"options": "Опції" "options": "Опції"
}, },
"login": { "login": {
"username": "Ім'я користувача (ex: '@user:server')", "username": "Ім'я користувача (наприклад: Марта)",
"username_required": "Потрібне ім'я користувача", "username_required": "Потрібне ім'я користувача",
"password_required": "Потрібен пароль", "password_required": "Потрібен пароль",
"create_room": "Зареєструватися та створити кімнату", "create_room": "Зареєструватися та створити кімнату",
@ -261,8 +261,7 @@
"password_old": "Старий пароль", "password_old": "Старий пароль",
"password_new": "Новий пароль", "password_new": "Новий пароль",
"display_name": "Відображуване ім'я", "display_name": "Відображуване ім'я",
"notification_label": "Сповіщення", "notification_label": "Сповіщення"
"set_password_desc": "Convene не зберігає паролі та не може їх відновити. Ми рекомендуємо зберігати пароль у безпечному місці, перш ніж натискати кнопку «Зберегти»."
}, },
"profile_info_popup": { "profile_info_popup": {
"you_are": "Ви є", "you_are": "Ви є",
@ -319,8 +318,7 @@
"copy_credentials": "Скопіювати ім'я користувача та пароль", "copy_credentials": "Скопіювати ім'я користувача та пароль",
"copied_credentials": "Скопійовано ім'я користувача та пароль", "copied_credentials": "Скопійовано ім'я користувача та пароль",
"copied_credentials_value": "Ім'я користувача: {userId} \nПароль: {password}", "copied_credentials_value": "Ім'я користувача: {userId} \nПароль: {password}",
"copy_credentials_desc": "Для відновлення доступу до чатів з нового пристрою або браузера потрібні ваші ім’я користувача та пароль. Рекомендуємо зберігати ці облікові дані в безпечному місці.", "copy_credentials_desc": "Для відновлення доступу до чатів з нового пристрою або браузера потрібні ваші ім’я користувача та пароль. Рекомендуємо зберігати ці облікові дані в безпечному місці."
"copy_credentials_desc_for_real_user": "Ваше ім’я користувача (наприклад: '@user:server') та пароль потрібні для відновлення доступу до ваших чатів з нового пристрою або браузера."
}, },
"purge_room": { "purge_room": {
"title": "Видалити кімнату?", "title": "Видалити кімнату?",
@ -541,10 +539,5 @@
"delete_post": { "delete_post": {
"confirm_text": "Ви впевнені, що хочете видалити це повідомлення?", "confirm_text": "Ви впевнені, що хочете видалити це повідомлення?",
"confirm_text_desc": "Цю дію не можна скасувати." "confirm_text_desc": "Цю дію не можна скасувати."
},
"offline": {
"offline_title": "Виникли проблеми з підключенням?",
"offline_message": "Перенаправте на альтернативне посилання для приєднання до кімнати",
"offline_redirect": "Перенаправити мене"
} }
} }

View file

@ -4,8 +4,8 @@
@click:outside="$emit('onOutsideLogoutPopupClicked')"> @click:outside="$emit('onOutsideLogoutPopupClicked')">
<div class="dialog-content text-center"> <div class="dialog-content text-center">
<h2 class="dialog-title">{{ $t("logout.confirm_text") }}</h2> <h2 class="dialog-title">{{ $t("logout.confirm_text") }}</h2>
<div class="dialog-text">{{ copyCredentialsSubText }}</div> <div class="dialog-text">{{ $t("logout.copy_credentials_desc") }}</div>
<v-row v-if="this.$matrix.currentUser.is_guest"> <v-row>
<v-col sm="12" md="6" offset-md="3" class="d-flex justify-center"> <v-col sm="12" md="6" offset-md="3" class="d-flex justify-center">
<v-btn <v-btn
ref="copyCredentialsBtn" ref="copyCredentialsBtn"
@ -59,10 +59,7 @@ export default {
]), ]),
credentials() { credentials() {
return this.$t(`logout.copied_credentials_value`, { userId: this.auth.user.user_id, password: this.auth.user.password}) return this.$t(`logout.copied_credentials_value`, { userId: this.auth.user.user_id, password: this.auth.user.password})
}, }
copyCredentialsSubText() {
return this.$t(`${this.$matrix.currentUser.is_guest ? 'logout.copy_credentials_desc': 'logout.copy_credentials_desc_for_real_user'}`)
},
}, },
methods: { methods: {
onCopyCredentials() { onCopyCredentials() {

View file

@ -1,55 +0,0 @@
<template>
<div>
<transition name="slow-fade">
<div
class="text-center d-flex flex-column goodbye-wrapper"
>
<div class="quote">Migrating...</div>
</div>
</transition>
</div>
</template>
<script>
export default {
name: "MigratingView",
data() {
return {
};
},
};
</script>
<style lang="scss">
@use "@/assets/css/chat.scss" as *;
.author {
font-size: 80%;
}
.close {
position: absolute;
bottom: 40px;
}
.slow-fade-enter-active,
.slow-fade-leave-active {
transition: opacity 2.5s;
}
.slow-fade-enter, .slow-fade-leave-to /* .fade-leave-active below version 2.1.8 */ {
opacity: 0;
}
.goodbye-wrapper {
position: fixed;
top: 0;
left: 0;
bottom: 0;
right: 0;
z-index: 100;
color: black;
background-color: white;
align-items: center;
justify-content: center;
padding: 40px;
}
</style>

View file

@ -116,7 +116,6 @@
> >
<v-card :disabled="settingPassword" class="dialog-content"> <v-card :disabled="settingPassword" class="dialog-content">
<h2 class="dialog-title">{{ $matrix.currentUser.is_guest ? $t("profile.set_password") : $t("profile.change_password") }}</h2> <h2 class="dialog-title">{{ $matrix.currentUser.is_guest ? $t("profile.set_password") : $t("profile.change_password") }}</h2>
<div class="dialog-text mb-4">{{ $t("profile.set_password_desc") }}</div>
<div class="dialog-text"> <div class="dialog-text">
<v-text-field <v-text-field
v-if="!$matrix.currentUser.is_guest" v-if="!$matrix.currentUser.is_guest"
@ -150,19 +149,17 @@
{{ passwordErrorMessage }} {{ passwordErrorMessage }}
</div> </div>
</div> </div>
<v-container fluid> <v-divider></v-divider>
<v-row cols="12"> <v-card-actions>
<v-col cols="6"> <v-spacer></v-spacer>
<v-btn variant="flat" block class="text-button" @click.stop="closeEditPasswordDialog">{{ <v-btn id="btn-password-cancel" variant="text" @click="closeEditPasswordDialog">{{
$t("menu.cancel") }}</v-btn> $t("menu.cancel")
</v-col> }}</v-btn>
<v-col cols="6" align="center">
<v-btn <v-btn
id="btn-password-set"
:disabled="!passwordsMatch" :disabled="!passwordsMatch"
color="#4642F1" color="primary"
variant="flat" variant="text"
block
class="filled-button"
@click=" @click="
setPassword( setPassword(
$matrix.currentUser.is_guest $matrix.currentUser.is_guest
@ -170,10 +167,10 @@
: password, : password,
newPassword1 newPassword1
) )
">{{ $t("global.save") }}</v-btn> "
</v-col> >{{ $t("global.save") }}</v-btn
</v-row> >
</v-container> </v-card-actions>
</v-card> </v-card>
</v-dialog> </v-dialog>
@ -183,35 +180,33 @@
class="ma-0 pa-0" class="ma-0 pa-0"
:width="$vuetify.display.smAndUp ? '940px' : '80%'" :width="$vuetify.display.smAndUp ? '940px' : '80%'"
> >
<v-card class="dialog-content"> <v-card>
<v-card-title>{{ $t("profile.display_name") }}</v-card-title> <v-card-title>{{ $t("profile.display_name") }}</v-card-title>
<div class="dialog-text"> <v-card-text>
<v-text-field <v-text-field
v-model="editValue" v-model="editValue"
:rules="[(v) => !!v || $t('profile.display_name_required')]" :rules="[(v) => !!v || $t('profile.display_name_required')]"
required required
/> />
<v-container fluid> </v-card-text>
<v-row cols="12"> <v-divider></v-divider>
<v-col cols="6"> <v-card-actions>
<v-btn variant="flat" block class="text-button" @click="showEditDisplaynameDialog = false">{{ <v-spacer></v-spacer>
$t("menu.cancel") }}</v-btn> <v-btn id="btn-displayname-cancel" variant="text" @click="showEditDisplaynameDialog = false">{{
</v-col> $t("menu.cancel")
<v-col cols="6" align="center"> }}</v-btn>
<v-btn <v-btn
:disabled="!editValue" id="btn-displayname-set"
color="#4642F1" color="primary"
variant="flat" variant="text"
block
class="filled-button"
@click=" @click="
updateDisplayName(editValue); updateDisplayName(editValue);
showEditDisplaynameDialog = false; showEditDisplaynameDialog = false;
">{{ $t("global.save") }}</v-btn> "
</v-col> :disabled="!editValue"
</v-row> >{{ $t("global.save") }}</v-btn
</v-container> >
</div> </v-card-actions>
</v-card> </v-card>
</RoundedDialog> </RoundedDialog>

View file

@ -1,141 +1,126 @@
import Home from "../components/Home.vue"; import Home from '../components/Home.vue'
import Chat from "../components/Chat.vue"; import Chat from '../components/Chat.vue'
import Join from "../components/Join.vue"; import Join from '../components/Join.vue'
import Login from "../components/Login.vue"; import Login from '../components/Login.vue'
import Profile from "../components/Profile.vue"; import Profile from '../components/Profile.vue'
import CreateRoom from "../components/CreateRoom.vue"; import CreateRoom from '../components/CreateRoom.vue'
import GetLink from "../components/GetLink.vue"; import GetLink from '../components/GetLink.vue'
import Create from "../components/Create.vue"; import Create from '../components/Create.vue'
import CreateChannel from "../components/CreateChannel.vue"; import CreateChannel from '../components/CreateChannel.vue'
import CreateFileDrop from "../components/CreateFileDrop.vue"; import CreateFileDrop from '../components/CreateFileDrop.vue'
import User from "../models/user"; import User from '../models/user'
import util from "../plugins/utils"; import util from '../plugins/utils'
import { createRouter, createWebHashHistory } from "vue-router"; import { createRouter, createWebHashHistory } from 'vue-router'
import { defineAsyncComponent } from "vue"; import { defineAsyncComponent } from 'vue'
import { STORE_KEY_SETTINGS, STORE_KEY_USER } from "../store";
const routes = [ const routes = [
{ {
path: "/", path: '/',
name: "Home", name: 'Home',
component: Home, component: Home
}, },
{ {
path: "/room/:join(join/)?:roomId?", path: '/room/:join(join/)?:roomId?',
name: "Chat", name: 'Chat',
component: Chat, component: Chat,
meta: { meta: {
includeRoom: true, includeRoom: true,
includeFavicon: true, includeFavicon: true
}, },
}, },
{ {
path: "/info", path: '/info',
name: "RoomInfo", name: 'RoomInfo',
component: () => import("../components/RoomInfo.vue"), component: () => import('../components/RoomInfo.vue'),
props: true, props: true,
meta: { meta: {
title: "Info", title: 'Info',
includeRoom: true, includeRoom: true,
includeFavicon: true, includeFavicon: true
}, }
}, },
{ {
path: "/profile", path: '/profile',
name: "Profile", name: 'Profile',
component: Profile, component: Profile,
meta: { meta: {
title: "Profile", title: 'Profile',
includeFavicon: true, includeFavicon: true
}, }
}, },
{ {
path: "/createroom", path: '/createroom',
name: "CreateRoom", name: 'CreateRoom',
component: CreateRoom, component: CreateRoom,
meta: { meta: {
title: "Create room", title: 'Create room'
}, }
}, },
{ {
path: "/getlink", path: '/getlink',
name: "GetLink", name: 'GetLink',
component: GetLink, component: GetLink,
}, },
{ {
path: "/create", path: '/create',
name: "Create", name: 'Create',
component: Create, component: Create,
}, },
{ {
path: "/createchannel", path: '/createchannel',
name: "CreateChannel", name: 'CreateChannel',
component: CreateChannel, component: CreateChannel,
}, },
{ {
path: "/createfiledrop", path: '/createfiledrop',
name: "CreateFileDrop", name: 'CreateFileDrop',
component: CreateFileDrop, component: CreateFileDrop,
}, },
{ {
path: "/login", path: '/login',
name: "Login", name: 'Login',
component: Login, component: Login,
props: true, props: true
}, },
{ {
path: "/join/:join(join/)?:roomId?", path: '/join/:join(join/)?:roomId?',
name: "Join", name: 'Join',
component: Join, component: Join,
props: (route) => { props: route => {
return { return {
roomNeedsKnock: route.query.knock ? true : false, roomNeedsKnock: (route.query.knock ? true : false),
roomDisplayName: route.query.roomName, roomDisplayName: route.query.roomName
}; }
}, }
}, },
{ {
path: "/user/:userId?", path: '/user/:userId?',
name: "User", name: 'User',
component: Join, component: Join
}, },
{ {
path: "/invite/:roomId?", path: '/invite/:roomId?',
name: "Invite", name: 'Invite',
component: defineAsyncComponent(() => import("../components/Invite.vue")), component: defineAsyncComponent(() => import('../components/Invite.vue')),
meta: { meta: {
title: "Add Friends", title: 'Add Friends'
}, }
}, },
{ {
path: "/goodbye", path: '/goodbye',
name: "Goodbye", name: 'Goodbye',
component: defineAsyncComponent(() => import("../components/QuoteView.vue")), component: defineAsyncComponent(() => import('../components/QuoteView.vue')),
props: true, props: true
}, }
{ ]
path: "/migrating",
name: "Migrating",
component: defineAsyncComponent(() => import("../components/MigratingView.vue")),
props: false,
},
];
const router = createRouter({ const router = createRouter({
history: createWebHashHistory(), history: createWebHashHistory(),
routes: routes, routes: routes
}); });
router.beforeEach((to, from, next) => { router.beforeEach((to, from, next) => {
const publicPages = [ const publicPages = ['/login', '/createroom', '/getlink', '/create', '/createchannel', '/createfiledrop'];
"/login",
"/createroom",
"/getlink",
"/create",
"/createchannel",
"/createfiledrop",
"/migrating",
];
var authRequired = !publicPages.includes(to.path); var authRequired = !publicPages.includes(to.path);
const loggedIn = router.app.$store.state.auth.user; const loggedIn = router.app.$store.state.auth.user;
@ -143,45 +128,15 @@ router.beforeEach((to, from, next) => {
// Set language via query param // Set language via query param
const lang = to.query.lang; const lang = to.query.lang;
// Check if valid translation // Check if valid translation
if (router.app.$i18n && router.app.$i18n.global && router.app.$i18n.global.messages[lang]) { if (router.app.$i18n.messages[lang]) {
router.app.$store.commit("setLanguage", lang); router.app.$store.commit('setLanguage', lang);
router.app.$i18n.global.locale = to.query.lang; if (router.app.$i18n) {
router.app.$i18n.locale = to.query.lang;
}
} }
} }
if (to.query && to.query.migrate) { if (to.name == 'Chat' || to.name == 'Join') {
try {
if (window.opener) {
console.log("Start listening for migration messages");
window.addEventListener("message", function (e) {
// if (e.origin !== origin) { // TODO - What should we check here?
// return
// }
try {
const data = JSON.parse(e.data);
if (data !== null) {
router.app.$store
.dispatch("migrate", data)
.then(() => {
console.log("Migration success");
})
.catch((error) => {
console.log("Migration error", error);
})
.finally(() => {
window.opener.postMessage(JSON.stringify({ cmd: "migrationDone" }), "*");
router.app.$navigation.push({ name: "Home" }, -1);
});
}
} catch (error) {}
});
window.opener.postMessage(JSON.stringify({ cmd: "getMigrationData" }), "*");
}
return next("/migrating");
} catch (error) {}
}
if (to.name == "Chat" || to.name == "Join") {
if (!to.params.roomId && to.hash) { if (!to.params.roomId && to.hash) {
// Public rooms start with '#', confuses the router. If hash but no roomId param, set it. // Public rooms start with '#', confuses the router. If hash but no roomId param, set it.
to.params.roomId = to.hash; to.params.roomId = to.hash;
@ -192,84 +147,62 @@ router.beforeEach((to, from, next) => {
//Invite to public room //Invite to public room
authRequired = false; authRequired = false;
} }
} else if (to.name == "Home") { } else if (to.name == 'Home') {
if (to.params.roomId !== undefined) { if (to.params.roomId !== undefined) {
const roomId = to.params.roomId ? util.sanitizeRoomId(to.params.roomId) : null; const roomId = to.params.roomId ? util.sanitizeRoomId(to.params.roomId) : null;
router.app.$matrix.setCurrentRoomId(roomId); router.app.$matrix.setCurrentRoomId(roomId);
} }
} else if (to.name == "User") { } else if (to.name == 'User') {
if (to.params.userId) { if (to.params.userId) {
let roomId = util.sanitizeUserId(to.params.userId); let roomId = util.sanitizeUserId(to.params.userId);
if (roomId && !roomId.startsWith("@")) { if (roomId && !roomId.startsWith("@")) {
// Not a full username. Assume local name on this server. // Not a full username. Assume local name on this server.
return router.app.$config return router.app.$config.load().then((config) => {
.load()
.then((config) => {
const domain = config.defaultMatrixDomainPart; const domain = config.defaultMatrixDomainPart;
if (!domain) throw new Error("No domain part for user invite!"); if (!domain) throw new Error("No domain part for user invite!");
roomId = "@" + roomId + ":" + domain; roomId = "@" + roomId + ":" + domain;
router.app.$matrix.setCurrentRoomId(roomId); router.app.$matrix.setCurrentRoomId(roomId);
}) }).catch(err => console.error(err)).finally(() => next());
.catch((err) => console.error(err))
.finally(() => next());
} else { } else {
router.app.$matrix.setCurrentRoomId(roomId); router.app.$matrix.setCurrentRoomId(roomId);
authRequired = false; authRequired = false;
} }
} }
} else if (to.name == "Invite") { } else if (to.name == 'Invite') {
if (to.params.roomId) { if (to.params.roomId) {
const roomId = util.sanitizeRoomId(to.params.roomId); const roomId = util.sanitizeRoomId(to.params.roomId);
router.app.$matrix.setCurrentRoomId(roomId); router.app.$matrix.setCurrentRoomId(roomId);
} }
} else if (to.name == "CreateRoom") { } else if (to.name == 'CreateRoom') {
return router.app.$config return router.app.$config.load().then((config) => {
.load()
.then((config) => {
if (config.hide_add_room_on_home || !config.roomTypes.includes("group_chat")) { if (config.hide_add_room_on_home || !config.roomTypes.includes("group_chat")) {
next("/"); next('/');
} else { } else {
next(); next();
} }
}) }).catch(err => { console.error(err); next('/'); });
.catch((err) => { } else if (to.name == 'CreateChannel') {
console.error(err); return router.app.$config.load().then((config) => {
next("/");
});
} else if (to.name == "CreateChannel") {
return router.app.$config
.load()
.then((config) => {
if (!config.roomTypes.includes("channel")) { if (!config.roomTypes.includes("channel")) {
next("/"); next('/');
} else { } else {
next(); next();
} }
}) }).catch(err => { console.error(err); next('/'); });
.catch((err) => { } else if (to.name == 'CreateFileDrop') {
console.error(err); return router.app.$config.load().then((config) => {
next("/");
});
} else if (to.name == "CreateFileDrop") {
return router.app.$config
.load()
.then((config) => {
if (!config.roomTypes.includes("file_drop")) { if (!config.roomTypes.includes("file_drop")) {
next("/"); next('/');
} else { } else {
next(); next();
} }
}) }).catch(err => { console.error(err); next('/'); });
.catch((err) => {
console.error(err);
next("/");
});
} }
// trying to access a restricted page + not logged in // trying to access a restricted page + not logged in
// redirect to login page // redirect to login page
if (authRequired && !loggedIn) { if (authRequired && !loggedIn) {
next("/login"); next('/login');
} else { } else {
next(); next();
} }
@ -292,21 +225,12 @@ router.getRoomLink = function (alias, roomId, roomName, mode, autojoin, knock, m
const autoJoinSegment = autojoin ? "join/" : ""; const autoJoinSegment = autojoin ? "join/" : "";
let queryString = ""; let queryString = "";
if (Object.entries(params).length > 0) { if (Object.entries(params).length > 0) {
queryString = queryString = "?" + Object.entries(params)
"?" +
Object.entries(params)
.map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`) .map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`)
.join("&"); .join('&')
} }
return ( return (mirror ? (window.location.protocol + "//" + mirror) : window.location.origin) + window.location.pathname + "#/room/" + autoJoinSegment + encodeURIComponent(util.sanitizeRoomId(alias || roomId)) + queryString;
(mirror ? window.location.protocol + "//" + mirror : window.location.origin) + }
window.location.pathname +
"#/room/" +
autoJoinSegment +
encodeURIComponent(util.sanitizeRoomId(alias || roomId)) +
queryString
);
};
router.getDMLink = function (user, config, mirror) { router.getDMLink = function (user, config, mirror) {
let userId = user.user_id; let userId = user.user_id;
@ -314,9 +238,7 @@ router.getDMLink = function (user, config, mirror) {
// Using default server, don't include it in the link // Using default server, don't include it in the link
userId = User.localPart(user.user_id); userId = User.localPart(user.user_id);
} }
return `${ return `${(mirror ? (window.location.protocol + "//" + mirror) : window.location.origin) + window.location.pathname}#/user/${encodeURIComponent(userId)}`
(mirror ? window.location.protocol + "//" + mirror : window.location.origin) + window.location.pathname }
}#/user/${encodeURIComponent(userId)}`;
};
export default router; export default router

View file

@ -141,32 +141,7 @@ export default {
} }
return this.legacyCryptoStore; return this.legacyCryptoStore;
}, },
migrate(user) { login(user, registrationFlowHandler, createUser = false) {
return util.getMatrixBaseUrl(user, this.$config)
.then((baseUrl) => {
console.log("Create temp client", user);
const tempMatrixClient = sdk.createClient({
baseUrl: baseUrl,
idBaseUrl: this.$config.identityServer,
});
user.access_token = undefined;
user.device_id = tempMatrixClient.getSessionId();
if (user.refresh_token) {
return this.refreshAccessToken(tempMatrixClient, user.refresh_token);
} else {
return Promise.resolve(true);
}
}).then(() => {
console.log("Refresh done, normal login");
return this.login(user, undefined, false, true);
});
},
login(user, registrationFlowHandler, createUser = false, isMigration = false) {
if (!isMigration && window.location.href.includes("migrate=1")) {
console.log("Migrate, so no login!");
return Promise.reject("Migrating, so no login");
}
return util.getMatrixBaseUrl(user, this.$config).then((baseUrl) => { return util.getMatrixBaseUrl(user, this.$config).then((baseUrl) => {
const tempMatrixClient = sdk.createClient({ const tempMatrixClient = sdk.createClient({
baseUrl: baseUrl, baseUrl: baseUrl,
@ -535,16 +510,12 @@ export default {
}, },
onSessionRefresh(refreshToken) { onSessionRefresh(refreshToken) {
return this.refreshAccessToken(this.matrixClient, refreshToken);
},
refreshAccessToken(matrixClient, refreshToken) {
if (this.tokenRefreshPromise) { if (this.tokenRefreshPromise) {
return this.tokenRefreshPromise; return this.tokenRefreshPromise;
} }
const now = Date.now(); const now = Date.now();
this.tokenRefreshPromise = this.tokenRefreshPromise =
matrixClient.http.request(sdk.Method.Post, "/refresh", undefined, { refresh_token: refreshToken}, { prefix: sdk.ClientPrefix.V3, inhibitLogoutEmit: true }).then((result) => { this.matrixClient.http.request(sdk.Method.Post, "/refresh", undefined, { refresh_token: refreshToken}, { prefix: sdk.ClientPrefix.V3, inhibitLogoutEmit: true }).then((result) => {
// Store new one! // Store new one!
var user = this.$store.state.auth.user; var user = this.$store.state.auth.user;
user.access_token = result.access_token; user.access_token = result.access_token;

View file

@ -136,33 +136,6 @@ const store = createStore({
this.$matrix.logout(); this.$matrix.logout();
commit('logout'); commit('logout');
}, },
migrate({ state }, migrationData) {
if (migrationData && migrationData.type) {
let storage = migrationData.type == "session" ? sessionStorage : localStorage;
if (migrationData.settings) {
try {
const settings = JSON.parse(migrationData.settings);
storage.setItem(STORE_KEY_SETTINGS, migrationData.settings);
state.useLocalStorage = migrationData.type != "session";
} catch (error) {
console.error("Failed to migrate settings", error);
}
}
if (migrationData.user) {
const user = JSON.parse(migrationData.user);
state.auth.user = user;
return this.$matrix.migrate(user).then(
(user) => {
return Promise.resolve(user);
},
(error) => {
return Promise.reject(error);
}
);
}
}
return Promise.reject("Migration error");
}
}, },
getters: { getters: {
storage: state => { storage: state => {