RefreshToken support and matrix fixes
Also, some initial TypeScript.
This commit is contained in:
parent
f8f6c2ed94
commit
a6d932ddb5
8 changed files with 169 additions and 120 deletions
|
|
@ -90,17 +90,17 @@
|
||||||
|
|
||||||
<interactive-auth ref="interactiveAuth" />
|
<interactive-auth ref="interactiveAuth" />
|
||||||
|
|
||||||
<v-btn id="btn-join" class="btn-dark" :disabled="!acceptUA || (room && room.selfMembership == 'ban')" size="large"
|
<v-btn id="btn-join" class="btn-dark" :disabled="!acceptUA || (room && room.getMyMembership() == 'ban')" size="large"
|
||||||
@click.stop="handleJoin" :loading="loading" v-if="!currentUser">{{
|
@click.stop="handleJoin" :loading="loading" v-if="!currentUser">{{
|
||||||
roomId && roomId.startsWith("@") ? $t("join.enter_room_user") : $t("join.enter_room")
|
roomId && roomId.startsWith("@") ? $t("join.enter_room_user") : $t("join.enter_room")
|
||||||
}}</v-btn>
|
}}</v-btn>
|
||||||
<v-btn id="btn-join" class="btn-dark" :disabled="!acceptUA || (room && room.selfMembership == 'ban')" size="large"
|
<v-btn id="btn-join" class="btn-dark" :disabled="!acceptUA || (room && room.getMyMembership() == 'ban')" size="large"
|
||||||
block @click.stop="handleJoin" :loading="loading" v-else>{{
|
block @click.stop="handleJoin" :loading="loading" v-else>{{
|
||||||
roomId && roomId.startsWith("@") ? $t("join.join_user") : $t("join.join")
|
roomId && roomId.startsWith("@") ? $t("join.join_user") : $t("join.join")
|
||||||
}}</v-btn>
|
}}</v-btn>
|
||||||
|
|
||||||
<div v-if="loadingMessage" class="text-center">{{ loadingMessage }}</div>
|
<div v-if="loadingMessage" class="text-center">{{ loadingMessage }}</div>
|
||||||
<div v-if="room && room.selfMembership == 'ban'" class="text-center">{{ $t("join.you_have_been_banned") }}</div>
|
<div v-if="room && room.getMyMembership() == 'ban'" class="text-center">{{ $t("join.you_have_been_banned") }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
export default class User {
|
|
||||||
constructor(user_id, password, is_guest) {
|
|
||||||
this.user_id = user_id;
|
|
||||||
this.password = password;
|
|
||||||
this.is_guest = is_guest || false
|
|
||||||
}
|
|
||||||
|
|
||||||
static localPart(user_id) {
|
|
||||||
if (user_id && user_id.startsWith('@') && user_id.includes(':')) {
|
|
||||||
const parts = user_id.split(":");
|
|
||||||
return parts[0].substring(1);
|
|
||||||
}
|
|
||||||
return user_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
static domainPart(user_id) {
|
|
||||||
if (user_id && user_id.startsWith('@') && user_id.includes(':')) {
|
|
||||||
const parts = user_id.split(":");
|
|
||||||
return parts[1];
|
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
27
src/models/user.ts
Normal file
27
src/models/user.ts
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
export default class User {
|
||||||
|
user_id: string;
|
||||||
|
password: string | null;
|
||||||
|
is_guest: boolean;
|
||||||
|
|
||||||
|
constructor(user_id: string, password: string | null, is_guest?: boolean) {
|
||||||
|
this.user_id = user_id;
|
||||||
|
this.password = password;
|
||||||
|
this.is_guest = is_guest || false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static localPart(user_id: string | null) {
|
||||||
|
if (user_id && user_id.startsWith("@") && user_id.includes(":")) {
|
||||||
|
const parts = user_id.split(":");
|
||||||
|
return parts[0].substring(1);
|
||||||
|
}
|
||||||
|
return user_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
static domainPart(user_id: string | null) {
|
||||||
|
if (user_id && user_id.startsWith("@") && user_id.includes(":")) {
|
||||||
|
const parts = user_id.split(":");
|
||||||
|
return parts[1];
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,9 +1,23 @@
|
||||||
import cleaninsights from "./cleaninsights.service";
|
import cleaninsights from "./cleaninsights.service";
|
||||||
import matomo from "./matomo.service";
|
import matomo from "./matomo.service";
|
||||||
|
|
||||||
|
export interface AnalyticsEngine {
|
||||||
|
event(category: string, action: string);
|
||||||
|
}
|
||||||
|
|
||||||
|
type AnalyticsEvent = {
|
||||||
|
category: string;
|
||||||
|
action: string;
|
||||||
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
install(app) {
|
install(app) {
|
||||||
class AnalyticsServiceClass {
|
class AnalyticsServiceClass {
|
||||||
|
|
||||||
|
engines: AnalyticsEngine[];
|
||||||
|
cachedEvents: AnalyticsEvent[];
|
||||||
|
initialized: boolean;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.engines = [];
|
this.engines = [];
|
||||||
this.cachedEvents = [];
|
this.cachedEvents = [];
|
||||||
|
|
@ -37,7 +51,7 @@ export default {
|
||||||
this.initialized = true;
|
this.initialized = true;
|
||||||
|
|
||||||
// Handle cached events
|
// Handle cached events
|
||||||
this.cachedEvents.forEach(([category, action]) => {
|
this.cachedEvents.forEach(({category, action}) => {
|
||||||
this.event(category, action);
|
this.event(category, action);
|
||||||
});
|
});
|
||||||
this.cachedEvents = [];
|
this.cachedEvents = [];
|
||||||
|
|
@ -46,7 +60,7 @@ export default {
|
||||||
|
|
||||||
event(category, action) {
|
event(category, action) {
|
||||||
if (!this.initialized) {
|
if (!this.initialized) {
|
||||||
this.cachedEvents.push([category, action]);
|
this.cachedEvents.push({category, action});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -85,19 +85,19 @@ export default {
|
||||||
|
|
||||||
joinedRooms() {
|
joinedRooms() {
|
||||||
return this.rooms.filter((room) => {
|
return this.rooms.filter((room) => {
|
||||||
return room.selfMembership === "join";
|
return room.getMyMembership() === "join";
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
invites() {
|
invites() {
|
||||||
return this.rooms.filter((room) => {
|
return this.rooms.filter((room) => {
|
||||||
return room.selfMembership === "invite";
|
return room.getMyMembership() === "invite";
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
joinedAndInvitedRooms() {
|
joinedAndInvitedRooms() {
|
||||||
return this.rooms.filter((room) => {
|
return this.rooms.filter((room) => {
|
||||||
return room.selfMembership === "join" || room.selfMembership === "invite";
|
return room.getMyMembership() === "join" || room.getMyMembership() === "invite";
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -313,6 +313,8 @@ export default {
|
||||||
store: matrixStore,
|
store: matrixStore,
|
||||||
deviceId: user.device_id,
|
deviceId: user.device_id,
|
||||||
accessToken: user.access_token,
|
accessToken: user.access_token,
|
||||||
|
refreshToken: user.refresh_token,
|
||||||
|
tokenRefreshFunction: this.onSessionRefresh,
|
||||||
timelineSupport: true,
|
timelineSupport: true,
|
||||||
unstableClientRelationAggregation: true,
|
unstableClientRelationAggregation: true,
|
||||||
cryptoStore: cryptoStore
|
cryptoStore: cryptoStore
|
||||||
|
|
@ -413,7 +415,7 @@ export default {
|
||||||
case "m.room.join_rules":
|
case "m.room.join_rules":
|
||||||
{
|
{
|
||||||
const room = this.matrixClient.getRoom(event.getRoomId());
|
const room = this.matrixClient.getRoom(event.getRoomId());
|
||||||
if (room && room.getJoinRule() == "private" && room.selfMembership == "invite") {
|
if (room && room.getJoinRule() == "private" && room.getMyMembership() == "invite") {
|
||||||
// We have an invite to a room that's now "private"? This is most probably a deleted DM room.
|
// We have an invite to a room that's now "private"? This is most probably a deleted DM room.
|
||||||
// Reject the invite, i.e. call "leave" on it.
|
// Reject the invite, i.e. call "leave" on it.
|
||||||
this.matrixClient.leave(room.roomId);
|
this.matrixClient.leave(room.roomId);
|
||||||
|
|
@ -451,7 +453,7 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
onRoom(room) {
|
onRoom(room) {
|
||||||
if (room.selfMembership === "invite") {
|
if (room.getMyMembership() === "invite") {
|
||||||
this.matrixClient
|
this.matrixClient
|
||||||
.getRoomTags(room.roomId)
|
.getRoomTags(room.roomId)
|
||||||
.then((reply) => {
|
.then((reply) => {
|
||||||
|
|
@ -468,7 +470,7 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
onRoomMyMembership(room) {
|
onRoomMyMembership(room) {
|
||||||
if (room.selfMembership === "invite") {
|
if (room.getMyMembership() === "invite") {
|
||||||
// Invitation. Need to call "recalculate" to pick
|
// Invitation. Need to call "recalculate" to pick
|
||||||
// up room name, not sure why exactly.
|
// up room name, not sure why exactly.
|
||||||
room.recalculate();
|
room.recalculate();
|
||||||
|
|
@ -476,6 +478,28 @@ export default {
|
||||||
this.reloadRooms();
|
this.reloadRooms();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onSessionRefresh(refreshToken) {
|
||||||
|
const now = Date.now();
|
||||||
|
return this.matrixClient.refreshToken(refreshToken).then((result) => {
|
||||||
|
// Store new one!
|
||||||
|
var user = this.$store.state.auth.user;
|
||||||
|
user.access_token = result.access_token;
|
||||||
|
user.refresh_token = result.refresh_token;
|
||||||
|
user.expires_in_ms = result.expires_in_ms;
|
||||||
|
this.$store.commit("setUser", user);
|
||||||
|
|
||||||
|
// Return AccessTokens struct
|
||||||
|
let accesssTokens = {
|
||||||
|
accessToken: result.access_token,
|
||||||
|
refreshToken: result.refresh_token
|
||||||
|
};
|
||||||
|
if (result.expires_in_ms) {
|
||||||
|
accesssTokens.expiry = new Date(now + result.expires_in_ms);
|
||||||
|
};
|
||||||
|
return accesssTokens;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
onSessionLoggedOut() {
|
onSessionLoggedOut() {
|
||||||
console.log("Logged out!");
|
console.log("Logged out!");
|
||||||
if (this.matrixClient) {
|
if (this.matrixClient) {
|
||||||
|
|
@ -517,7 +541,7 @@ export default {
|
||||||
// each time!
|
// each time!
|
||||||
var updatedRooms = this.matrixClient.getVisibleRooms();
|
var updatedRooms = this.matrixClient.getVisibleRooms();
|
||||||
updatedRooms = updatedRooms.filter((room) => {
|
updatedRooms = updatedRooms.filter((room) => {
|
||||||
return room.selfMembership && (room.selfMembership == "invite" || room.selfMembership == "join") && room.currentState.getStateEvents(STATE_EVENT_ROOM_DELETED).length == 0;
|
return room.getMyMembership() && (room.getMyMembership() == "invite" || room.getMyMembership() == "join") && room.currentState.getStateEvents(STATE_EVENT_ROOM_DELETED).length == 0;
|
||||||
});
|
});
|
||||||
updatedRooms.forEach((room) => {
|
updatedRooms.forEach((room) => {
|
||||||
room["avatar"] = room.getAvatarUrl(this.matrixClient.getHomeserverUrl(), 80, 80, "scale", true, this.useAuthedMedia);
|
room["avatar"] = room.getAvatarUrl(this.matrixClient.getHomeserverUrl(), 80, 80, "scale", true, this.useAuthedMedia);
|
||||||
|
|
@ -567,7 +591,7 @@ export default {
|
||||||
var ids = {};
|
var ids = {};
|
||||||
const ret = [];
|
const ret = [];
|
||||||
for (const room of this.rooms) {
|
for (const room of this.rooms) {
|
||||||
if (room.selfMembership == "join" && this.getRoomJoinRule(room) == "invite") {
|
if (room.getMyMembership() == "join" && this.getRoomJoinRule(room) == "invite") {
|
||||||
for (const member of room.getJoinedMembers()) {
|
for (const member of room.getJoinedMembers()) {
|
||||||
if (member.userId != this.currentUserId && !ids[member.userId]) {
|
if (member.userId != this.currentUserId && !ids[member.userId]) {
|
||||||
ids[member.userId] = member;
|
ids[member.userId] = member;
|
||||||
|
|
@ -842,7 +866,7 @@ export default {
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
//console.log("Purge: create timeline");
|
//console.log("Purge: create timeline");
|
||||||
return timelineWindow.load(null, 100);
|
return timelineWindow.load(undefined, 100);
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
const getMoreIfAvailable = function _getMoreIfAvailable() {
|
const getMoreIfAvailable = function _getMoreIfAvailable() {
|
||||||
|
|
@ -1234,7 +1258,7 @@ export default {
|
||||||
since: response.next_batch,
|
since: response.next_batch,
|
||||||
})
|
})
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
return _findOrGetMore(client, response);
|
return _findOrGetMore(client, useAuthedMedia, response);
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
return Promise.reject("Failed to find room: " + err);
|
return Promise.reject("Failed to find room: " + err);
|
||||||
|
|
|
||||||
|
|
@ -1,82 +0,0 @@
|
||||||
export default {
|
|
||||||
install(app, router) {
|
|
||||||
var routes = [];
|
|
||||||
var nextRoutes = null;
|
|
||||||
var zeroIndex = undefined;
|
|
||||||
|
|
||||||
router.beforeResolve((to, ignoredfrom, next) => {
|
|
||||||
if (!zeroIndex) {
|
|
||||||
routes = [to];
|
|
||||||
zeroIndex = window.history.length;
|
|
||||||
}
|
|
||||||
next();
|
|
||||||
})
|
|
||||||
|
|
||||||
router.beforeEach((to, from, next) => {
|
|
||||||
if (nextRoutes) {
|
|
||||||
console.log("Nav: next routes set, going:", routes, nextRoutes);
|
|
||||||
routes = nextRoutes;
|
|
||||||
nextRoutes = null;
|
|
||||||
if (routes.length > 0) {
|
|
||||||
console.log("Redirecting to", routes[routes.length - 1]);
|
|
||||||
next(routes[routes.length - 1]);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
next();
|
|
||||||
})
|
|
||||||
|
|
||||||
const navigationService = {
|
|
||||||
/***
|
|
||||||
* @param mode Mode of operation. -1 = push as root, 0 = replace, 1 = normal push
|
|
||||||
*/
|
|
||||||
push(route, mode) {
|
|
||||||
if (mode === undefined) {
|
|
||||||
mode = 1;
|
|
||||||
}
|
|
||||||
if (mode == -1) {
|
|
||||||
nextRoutes = [route];
|
|
||||||
} else if (mode == 0) {
|
|
||||||
// Replace
|
|
||||||
nextRoutes = [...routes];
|
|
||||||
nextRoutes.pop();
|
|
||||||
nextRoutes.push(route);
|
|
||||||
} else {
|
|
||||||
nextRoutes = [...routes];
|
|
||||||
nextRoutes.push(route);
|
|
||||||
}
|
|
||||||
|
|
||||||
const index = nextRoutes.length - routes.length;
|
|
||||||
const targetIndex = nextRoutes.length - 1;
|
|
||||||
console.log("Nav - index " + index + " Target " + targetIndex);
|
|
||||||
if (index < 0) {
|
|
||||||
console.log("Nav - go " + index);
|
|
||||||
router.go(index);
|
|
||||||
} else if (index == 0) {
|
|
||||||
console.log("Nav - replace");
|
|
||||||
routes = nextRoutes;
|
|
||||||
nextRoutes = null;
|
|
||||||
router.replace(route).catch((ignoredErr) => {});
|
|
||||||
} else {
|
|
||||||
console.log("Nav - push");
|
|
||||||
router.push(route).catch((ignoredErr) => {});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
canPop() {
|
|
||||||
if (nextRoutes) {
|
|
||||||
return nextRoutes.length > 1;
|
|
||||||
}
|
|
||||||
return routes.length > 1;
|
|
||||||
},
|
|
||||||
|
|
||||||
pop() {
|
|
||||||
routes.pop();
|
|
||||||
router.go(-1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
app.$navigation = navigationService;
|
|
||||||
app.config.globalProperties.$navigation = navigationService;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
84
src/services/navigation.service.ts
Normal file
84
src/services/navigation.service.ts
Normal file
|
|
@ -0,0 +1,84 @@
|
||||||
|
import { RouteLocationNormalizedGeneric, Router } from "vue-router";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
install(app, router: Router) {
|
||||||
|
var routes: RouteLocationNormalizedGeneric[] = [];
|
||||||
|
var nextRoutes: RouteLocationNormalizedGeneric[] | null = null;
|
||||||
|
var zeroIndex: number | undefined = undefined;
|
||||||
|
|
||||||
|
router.beforeResolve((to, ignoredfrom, next) => {
|
||||||
|
if (!zeroIndex) {
|
||||||
|
routes = [to];
|
||||||
|
zeroIndex = window.history.length;
|
||||||
|
}
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
|
||||||
|
router.beforeEach((to, from, next) => {
|
||||||
|
if (nextRoutes) {
|
||||||
|
console.log("Nav: next routes set, going:", routes, nextRoutes);
|
||||||
|
routes = nextRoutes;
|
||||||
|
nextRoutes = null;
|
||||||
|
if (routes.length > 0) {
|
||||||
|
console.log("Redirecting to", routes[routes.length - 1]);
|
||||||
|
next(routes[routes.length - 1]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
|
||||||
|
const navigationService = {
|
||||||
|
/***
|
||||||
|
* @param mode Mode of operation. -1 = push as root, 0 = replace, 1 = normal push
|
||||||
|
*/
|
||||||
|
push(route, mode) {
|
||||||
|
if (mode === undefined) {
|
||||||
|
mode = 1;
|
||||||
|
}
|
||||||
|
if (mode == -1) {
|
||||||
|
nextRoutes = [route];
|
||||||
|
} else if (mode == 0) {
|
||||||
|
// Replace
|
||||||
|
nextRoutes = [...routes];
|
||||||
|
nextRoutes.pop();
|
||||||
|
nextRoutes.push(route);
|
||||||
|
} else {
|
||||||
|
nextRoutes = [...routes];
|
||||||
|
nextRoutes.push(route);
|
||||||
|
}
|
||||||
|
|
||||||
|
const index = nextRoutes.length - routes.length;
|
||||||
|
const targetIndex = nextRoutes.length - 1;
|
||||||
|
console.log("Nav - index " + index + " Target " + targetIndex);
|
||||||
|
if (index < 0) {
|
||||||
|
console.log("Nav - go " + index);
|
||||||
|
router.go(index);
|
||||||
|
} else if (index == 0) {
|
||||||
|
console.log("Nav - replace");
|
||||||
|
routes = nextRoutes;
|
||||||
|
nextRoutes = null;
|
||||||
|
router.replace(route).catch((ignoredErr) => {});
|
||||||
|
} else {
|
||||||
|
console.log("Nav - push");
|
||||||
|
router.push(route).catch((ignoredErr) => {});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
canPop() {
|
||||||
|
if (nextRoutes) {
|
||||||
|
return nextRoutes.length > 1;
|
||||||
|
}
|
||||||
|
return routes.length > 1;
|
||||||
|
},
|
||||||
|
|
||||||
|
pop() {
|
||||||
|
routes.pop();
|
||||||
|
router.go(-1);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
app.$navigation = navigationService;
|
||||||
|
app.config.globalProperties.$navigation = navigationService;
|
||||||
|
},
|
||||||
|
};
|
||||||
5
tsconfig.json
Normal file
5
tsconfig.json
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"strict": true
|
||||||
|
},
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue