Improve frontend api part 1

This commit is contained in:
Rohan Sircar 2020-08-09 10:55:44 +05:30
parent e4041f9e41
commit de2ad81f8e
9 changed files with 195 additions and 214 deletions

View File

@ -0,0 +1,56 @@
import { UserModel } from "../model/UserModel";
import { ChatModel } from "../model/ChatModel";
import { UserView } from "../view/UserView";
import { ChatView } from "../view/ChatView";
import { UserController } from "../controller/UserController";
import { ChatController } from "../controller/ChatController";
import { Client } from "@stomp/stompjs";
import { ChatMessageDTO } from "../../common/dto/ChatMessageDTO";
import log from "loglevel";
import { ChatMessageViewModel } from "../viewmodel/ChatMessageViewModel";
export interface Props {
// userModel: UserModel;
// chatModel: ChatModel;
// userView: UserView;
// chatView: ChatView;
userController: UserController;
chatController: ChatController;
chatStompClient: Client;
}
export interface State {}
export class ChatComponent {
private readonly _props: Props;
private readonly _state: State;
constructor(props: Props, state: State) {
this._props = props;
this._state = state;
}
private async wsHandler() {
this._props.chatStompClient.onConnect = () => {
this._props.chatStompClient.subscribe("/user/queue/reply", (reply) => {
const data = JSON.parse(reply.body) as ChatMessageDTO;
const plainText = this._props.userController.decryptForUser(
data,
data.fromUser
);
this._props.chatController.store(data.fromUser, <ChatMessageViewModel>{
...data,
message: plainText,
messageTime: new Date(data.messageTime),
});
// log.debug(
// message,
// this._props.encryptionService.decrypt(
// "password",
// message.messageCipher
// )
// );
});
};
}
}

View File

@ -1,41 +1,42 @@
import { Controller } from "./AbstractController";
import "../model/AbstractModel"
import "../model/UserModel"
import "../view/AbstractView"
import "../view/UserView"
import "../model/AbstractModel";
import "../model/UserModel";
import "../view/AbstractView";
import "../view/UserView";
import { Model } from "../model/AbstractModel";
import { View } from "../view/AbstractView";
import { ChatMessageViewModel } from "../viewmodel/ChatMessageViewModel";
import { ChatModel } from "../model/ChatModel";
import { ChatView } from "../view/ChatView";
import { Client } from "@stomp/stompjs";
import { EncryptionService } from "../../common/service/EncryptionService";
import { ChatMessageDTO } from "../../common/dto/ChatMessageDTO";
import log from "loglevel";
export interface Props {
model: ChatModel;
view: ChatView;
chatStompClient: Client;
encryptionService: EncryptionService;
}
export class ChatController {
private _model: ChatModel;
private _view: ChatView;
constructor(model: ChatModel, view: ChatView) {
this._model = model;
this._view = view;
}
/**
* eventHandler
*/
public eventHandler(vm: ChatMessageViewModel[]): void {
this._model.someBusinessMethod(vm);
}
public test(): void {
const chatMessageViewModels: ChatMessageViewModel[] = [];
let chatMessageViewModelMock = new ChatMessageViewModel();
chatMessageViewModelMock.fromUser = "user1";
chatMessageViewModelMock.toUser = "user2";
chatMessageViewModelMock.message = "";
chatMessageViewModelMock.messageTime = new Date();
chatMessageViewModels.push(chatMessageViewModelMock);
}
private readonly _props: Props;
constructor(props: Props) {
this._props = props;
}
public test(): void {
const chatMessageViewModels: ChatMessageViewModel[] = [];
let chatMessageViewModelMock = new ChatMessageViewModel();
chatMessageViewModelMock.fromUser = "user1";
chatMessageViewModelMock.toUser = "user2";
chatMessageViewModelMock.message = "";
chatMessageViewModelMock.messageTime = new Date();
chatMessageViewModels.push(chatMessageViewModelMock);
}
public store(userName: string, message: ChatMessageViewModel): void {
this._props.model.storeUserMessages(userName, Array(message), "new");
}
}

View File

@ -1,50 +1,30 @@
import { Controller } from "./AbstractController";
import "../model/AbstractModel"
import "../model/UserModel"
import "../view/AbstractView"
import "../view/UserView"
import "../model/AbstractModel";
import "../model/UserModel";
import "../view/AbstractView";
import "../view/UserView";
import { Model } from "../model/AbstractModel";
import { View } from "../view/AbstractView";
import { ActiveUserViewModel } from "../viewmodel/ActiveUserViewModel";
import { UserView } from "../view/UserView";
import { UserModel } from "../model/UserModel";
import { ChatMessageDTO } from "../../common/dto/ChatMessageDTO";
import { ChatMessageViewModel } from "../viewmodel/ChatMessageViewModel";
export class UserController {
private _model: UserModel;
private _view: UserView;
private _model: UserModel;
private _view: UserView;
constructor(model: UserModel, view: UserView) {
this._model = model;
this._view = view;
}
constructor(model: UserModel, view: UserView) {
this._model = model;
this._view = view;
}
/**
* eventHandler
*/
public eventHandler(vm: ActiveUserViewModel[]): void {
this._model.someBusinessMethod(vm);
}
public test(): void {
const activeUsersMock: ActiveUserViewModel[] = [];
let activeUserViewModelMock = new ActiveUserViewModel();
activeUserViewModelMock.userName = "some user";
// activeUserViewModelMock.lastActive = "3 hrs ago";
activeUserViewModelMock.online = true;
activeUsersMock.push(activeUserViewModelMock);
activeUserViewModelMock = new ActiveUserViewModel();
// activeUserViewModelMock.lastActive = "3 hrs ago";
activeUserViewModelMock.online = true;
activeUserViewModelMock.userName = "some user 2";
activeUsersMock.push(activeUserViewModelMock);
this.eventHandler(activeUsersMock);
}
public getActiveUsers(): void {
this._model.getActiveUsers();
}
// public getActiveUsers(): void {
// this._model.getActiveUsers();
// }
decryptForUser(dto: ChatMessageDTO, userName: string): string {
return this._model.decryptForUser(dto, userName);
}
}

View File

@ -21,8 +21,10 @@ import { ChatViewDeps } from "./view/ChatViewDeps";
import { UserView } from "./view/UserView";
import { UserViewDeps } from "./view/UserViewDeps";
import { ActiveUserViewModel } from "./viewmodel/ActiveUserViewModel";
import { Credentials } from "../common/global/Credentials";
// log.setLevel("TRACE");
const authToken = Credentials.authToken;
const chatStompClient = new Client();
chatStompClient.webSocketFactory = () => new SockJS("/chat");
@ -56,7 +58,11 @@ const encryptionService = EncryptionServiceFactory.getEncryptionService();
const chatModelHelper = new ChatModelHelper(encryptionService, ns);
const chatModel = new ChatModel(chatModelHelper);
const userModel = new UserModel(ns);
const userModel = new UserModel({
notificationService: ns,
encryptionService,
authToken,
});
const cvDeps: ChatViewDeps = {
chatModel: chatModel,
// @ts-ignore: Argument of type 'HTMLElement | null' is not assignable to parameter of type 'HTMLElement'. Type 'null' is not assignable to type 'HTMLElement'.
@ -66,14 +72,19 @@ const cvDeps: ChatViewDeps = {
),
messageReceiveTemplate: TemplateFactory.getTemplate("msg_container_template"),
markdownService: new MarkDownItMarkDownService(),
encryptionService: encryptionService,
encryptionService,
notificationService: ns,
userModel: userModel,
chatStompClient: chatStompClient,
chatStompClient,
};
const chatView = new ChatView(cvDeps);
chatModel.attach(chatView);
const chatController = new ChatController(chatModel, chatView);
const chatController = new ChatController({
model: chatModel,
view: chatView,
chatStompClient,
encryptionService,
});
const uvDeps: UserViewDeps = {
model: userModel,
@ -97,7 +108,7 @@ const uvDeps: UserViewDeps = {
const userView = new UserView(uvDeps);
userModel.attach(userView);
const userController = new UserController(userModel, userView);
userController.getActiveUsers();
// userController.getActiveUsers();
// @ts-ignore
Handlebars.registerHelper("moment", require("helper-moment"));

View File

@ -44,7 +44,7 @@ export class ChatModel implements Subject<ChatMessageViewModel> {
log.info("Subject: Detached an observer.");
}
private storeUserMessages(
public storeUserMessages(
username: string,
messages: ChatMessageViewModel[],
op: string
@ -52,25 +52,28 @@ export class ChatModel implements Subject<ChatMessageViewModel> {
switch (op) {
case "clear":
this._messagesMap.set(username, []);
this.notify({ userName: username, data: [], op: op });
break;
case "page":
this._messagesMap.set(
username,
messages.concat(this.getStoredUserMessages(username))
);
this.notify({ userName: username, data: messages, op: op });
break;
// case "page": this._messagesMap.set(username, messages);
case "new":
this._messagesMap.set(
username,
this.getStoredUserMessages(username).concat(messages)
);
this.notify({ userName: username, data: messages, op: op });
break;
case "update":
this._messagesMap.set(
username,
this.getStoredUserMessages(username).concat(messages)
);
this.notify({ userName: username, data: messages, op: op });
break;
default:
new Error("Invalid option");
@ -102,47 +105,18 @@ export class ChatModel implements Subject<ChatMessageViewModel> {
}
}
break;
case "new":
{
const od: ObserverData<ChatMessageViewModel> = {
data: p.data,
op: p.op,
};
for (const observer of this._observers) {
observer.update(od);
}
}
break;
case "page":
{
const od: ObserverData<ChatMessageViewModel> = {
data: p.data,
op: p.op,
};
for (const observer of this._observers) {
observer.update(od);
}
}
break;
case "update":
{
const od: ObserverData<ChatMessageViewModel> = {
data: p.data,
op: p.op,
};
for (const observer of this._observers) {
observer.update(od);
}
}
break;
default: {
log.error("error");
const od: ObserverData<ChatMessageViewModel> = {
data: p.data,
op: p.op,
};
for (const observer of this._observers) {
observer.update(od);
}
}
}
}
public someBusinessMethod(chatMessageList: ChatMessageViewModel[]): void {}
public clear(): void {
log.info("Clearing model");
this._messagePageMap.set(JsonAPI.contactName!, 0);
@ -200,7 +174,7 @@ export class ChatModel implements Subject<ChatMessageViewModel> {
}
this.storeUserMessages(aVm.userName!, cVMsFiltered, op);
this.notify({ userName: aVm.userName!, data: cVMsFiltered, op: op });
// this.notify({ userName: aVm.userName!, data: cVMsFiltered, op: op });
}
return cVMsFiltered;

View File

@ -1,11 +1,21 @@
import log from "loglevel";
import { ChatMessageDTO } from "../../common/dto/ChatMessageDTO";
import { NotificationService } from "../../common/service/NotificationService";
import { Subject } from "../observe/Observable";
import { Observer } from "../observe/Observer";
import { JsonAPI } from "../singleton/JsonAPI";
import { ActiveUserViewModel } from "../viewmodel/ActiveUserViewModel";
import { ChatMessageViewModel } from "../viewmodel/ChatMessageViewModel";
import { fetchErrorHandler } from "./FetchErrorHandler";
import { EncryptionService } from "../../common/service/EncryptionService";
import { createApiHeaders } from "../../common/ajax/util";
import { getActiveUsers } from "../../common/ajax/Users";
export interface Props {
encryptionService: EncryptionService;
notificationService: NotificationService;
authToken: string;
}
export class UserModel implements Subject<ActiveUserViewModel> {
/**
* @type {Observer[]} List of subscribers. In real life, the list of
@ -14,12 +24,18 @@ export class UserModel implements Subject<ActiveUserViewModel> {
*/
private readonly observers: Observer<ActiveUserViewModel>[] = [];
private _activeUsersList: ActiveUserViewModel[] = Array();
private readonly _notificationService: NotificationService;
private readonly _activeUsersList: ActiveUserViewModel[] = Array();
private readonly _props: Props;
constructor(notificationService: NotificationService) {
constructor(props: Props) {
this._activeUsersList = [];
this._notificationService = notificationService;
this._props = props;
getActiveUsers(props.authToken).then((data) => {
log.debug(data);
this._activeUsersList.push(...data);
this.notify();
});
}
/**
@ -54,63 +70,16 @@ export class UserModel implements Subject<ActiveUserViewModel> {
}
}
public someBusinessMethod(activeuserList: ActiveUserViewModel[]): void {
this._activeUsersList = activeuserList;
this.helperMethod();
log.info(`Subject: My state has just changed`);
log.trace(activeuserList);
this.notify();
}
updateLastActive(username: String, lastActive: Date): void {
this._activeUsersList
.filter((u) => u.userName == username)
.forEach((u) => (u.lastActive = lastActive));
}
/**
* getActiveUsers
*/
public getActiveUsers(): void {
if (JsonAPI.authToken != null) {
this._getActiveUsersAjax(JsonAPI.authToken).then((data) => {
// // activeUsers = data;
// sessionStorage.setItem('activeUsers', JSON.stringify(data));
// log.trace(sessionStorage.getItem('activeUsers'));
log.info(`Subject: received ajax active users`);
data.map((d: any) => {
if (d.lastActive == null) return null;
d.lastActive = new Date(d.lastActive);
return d;
});
this._activeUsersList = data;
this.notify();
});
} else {
log.error("Auth token is null");
}
public decryptForUser(dto: ChatMessageDTO, userName: string): string {
const passphrase =
this._activeUsersList.find((u) => u.userName === userName)?.passphrase ||
"";
return this._props.encryptionService.decrypt(passphrase, dto.messageCipher);
}
private async _getActiveUsersAjax(authToken: string): Promise<any> {
let headers = new Headers();
headers.append("X-AUTH-TOKEN", authToken);
let response = await fetch(JsonAPI.ACTIVE_USERS_GET, {
method: "GET",
headers: headers,
});
log.debug(response.clone());
if (fetchErrorHandler(response.clone(), this._notificationService)) {
return null;
}
let data = await response.json();
// return data;
return new Promise((resolve, reject) => {
if (data != null) {
resolve(data);
} else reject("Response data null");
});
}
private helperMethod() {}
}

View File

@ -41,16 +41,6 @@ export class ChatView implements Observer<ChatMessageViewModel> {
this._deps = deps;
this._initEventListeners();
this._deps.chatStompClient.onConnect = () => {
this._deps.chatStompClient.subscribe("/user/queue/reply", (reply) => {
const message = JSON.parse(reply.body) as ChatMessageDTO;
log.debug(
message,
this._encryptionService.decrypt("password", message.messageCipher)
);
});
};
$(document).ready(function () {
$("#action_menu_btn").click(function () {
$(".action_menu").toggle();
@ -219,27 +209,6 @@ export class ChatView implements Observer<ChatMessageViewModel> {
// }
}
private _sendMessageAJAX(chatMessageDTO: any): void {
let headers = new Headers();
// console.log("Token = " + btoa("hmm" + ":" + "hmm"))
// headers.append('Accept','application/json')
headers.append("Content-Type", "application/json");
// headers.append('Authorization', basicAuthToken);
// @ts-ignore
headers.append("X-AUTH-TOKEN", JsonAPI.authToken);
fetch(JsonAPI.MESSAGE_POST, {
method: "POST",
headers: headers,
body: JSON.stringify(chatMessageDTO),
})
.then((response) => {
log.debug(response);
return response.clone();
})
.then((response) => fetchHandler(response, this._notificationService));
}
private _chatMessagePageLoadAjax() {
this._messageContainer.addEventListener("scroll", (e) => {
if (

View File

@ -28,17 +28,11 @@ export async function sendReencryptedMessages(
rencryptionDTOs: ReencryptionDTO[],
authToken: string
) {
let headers = new Headers();
// console.log("Token = " + btoa("hmm" + ":" + "hmm"))
// headers.append('Accept','application/json')
headers.append("Content-Type", "application/json");
headers.append("X-AUTH-TOKEN", authToken);
fetch(Routes.Admin.reencrypt, {
return fetch(Routes.Admin.reencrypt, {
method: "POST",
headers: headers,
headers: createApiHeaders(authToken),
body: JSON.stringify(rencryptionDTOs),
}).then((response) => console.log(response));
});
}
export async function getOneMessage(
@ -52,10 +46,6 @@ export async function getOneMessage(
method: "GET",
headers: createApiHeaders(authToken),
});
log.debug(response.clone());
// if (fetchErrorHandler(response.clone(), this._notificationService)) {
// return null;
// }
const data: Promise<any> = await response.json();
function func(data: any) {
const d1 = data.map((d: any) => {
@ -77,3 +67,15 @@ export async function getStats(authToken: string) {
});
return (await response.json()) as StatsDTO;
}
export async function sendMessageAJAX(
chatMessageDTO: ChatMessageDTO,
authToken: string
) {
const response = fetch(JsonAPI.MESSAGE_POST, {
method: "POST",
headers: createApiHeaders(authToken),
body: JSON.stringify(chatMessageDTO),
});
return response;
}

View File

@ -1,6 +1,8 @@
import { Routes } from "../routes/Routes";
import { createApiHeaders } from "./util";
import { AdminUserDTO } from "../dto/AdminUserDTO";
import { ActiveUserViewModel } from "../../chat/viewmodel/ActiveUserViewModel";
import { JsonAPI } from "../../chat/singleton/JsonAPI";
export async function getOtherUsers(
authToken: string
@ -13,3 +15,20 @@ export async function getOtherUsers(
let data = (await response.json()) as AdminUserDTO[];
return data;
}
export async function getActiveUsers(
authToken: string
): Promise<ActiveUserViewModel[]> {
const response = await fetch(JsonAPI.ACTIVE_USERS_GET, {
method: "GET",
headers: createApiHeaders(authToken),
});
const data = await response.json();
const data2 = data.map((d: any) => {
if (d.lastActive == null) return d;
d.lastActive = new Date(d.lastActive);
return d;
}) as ActiveUserViewModel[];
return data2;
}