Skip to content

Commit

Permalink
🛠 Implement endpoint to get message file and other fixes (#2416)
Browse files Browse the repository at this point in the history
* Fix medias migration script

* Fix support for images preview

* Implement new messages-files service

* Implemented the controllers

* Add some comments

* Fix delay requests with async calls

* Maybe fixed open on desktop app

* Fix linter
  • Loading branch information
RomaricMourgues authored and Labels Bot committed Jul 12, 2022
1 parent b53199a commit f4b3fb2
Show file tree
Hide file tree
Showing 21 changed files with 276 additions and 324 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -62,16 +62,20 @@ class MessageReferenceRepair {
);

for (const item of items.getEntities()) {
const msgFile = await repositoryMessageFile.findOne({
message_id: item.message_id,
id: item.message_file_id,
});
if (msgFile) {
count++;
const isMedia = fileIsMedia(msgFile);
const ref = _.cloneDeep(item);
ref.target_type = isMedia ? "channel_media" : "channel_file";
await repository.save(ref);
try {
const msgFile = await repositoryMessageFile.findOne({
message_id: item.message_id,
id: item.message_file_id,
});
if (msgFile) {
count++;
const isMedia = fileIsMedia(msgFile);
const ref = _.cloneDeep(item);
ref.target_type = isMedia ? "channel_media" : "channel_file";
await repository.save(ref);
}
} catch (e) {
console.log("Error", e);
}
}

Expand All @@ -87,16 +91,18 @@ class MessageReferenceRepair {
}

const services = [
"storage",
"counter",
"platform-services",
"user",
"search",
"channels",
"database",
"webserver",
"auth",
"counter",
"cron",
"pubsub",
"messages",
"push",
"realtime",
"storage",
"tracker",
"websocket",
];

const command: yargs.CommandModule<unknown, unknown> = {
Expand Down
3 changes: 3 additions & 0 deletions twake/backend/node/src/services/global-resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import {
MessageViewsServiceAPI,
} from "./messages/api";
import { ThreadMessagesService } from "./messages/services/messages";
import { MessagesFilesService } from "./messages/services/messages-files";
import { ThreadsService } from "./messages/services/threads";
import { UserBookmarksService } from "./messages/services/user-bookmarks";
import { SearchServiceAPI } from "../core/platform/services/search/api";
Expand Down Expand Up @@ -113,6 +114,7 @@ type TwakeServices = {
};
messages: {
messages: MessageThreadMessagesServiceAPI;
messagesFiles: MessagesFilesService;
threads: MessageThreadsServiceAPI;
userBookmarks: MessageUserBookmarksServiceAPI;
views: MessageViewsServiceAPI;
Expand Down Expand Up @@ -195,6 +197,7 @@ class GlobalResolver {
},
messages: {
messages: await new ThreadMessagesService().init(platform),
messagesFiles: await new MessagesFilesService().init(),
threads: await new ThreadsService().init(platform),
userBookmarks: await new UserBookmarksService().init(platform),
views: await new ViewsServiceImpl().init(platform),
Expand Down
125 changes: 125 additions & 0 deletions twake/backend/node/src/services/messages/services/messages-files.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import { Channel } from "../../../services/channels/entities";
import { fileIsMedia } from "../../../services/files/utils";
import { UserObject } from "../../../services/user/web/types";
import { formatUser } from "../../../utils/users";
import { Initializable } from "../../../core/platform/framework";
import Repository from "../../../core/platform/services/database/services/orm/repository/repository";
import gr from "../../../services/global-resolver";
import { MessageFileRef, TYPE as TYPERef } from "../entities/message-file-refs";
import { MessageFile, TYPE } from "../entities/message-files";
import { Message } from "../entities/messages";

export class MessagesFilesService implements Initializable {
version: "1";
msgFilesRepository: Repository<MessageFile>;
msgFilesRefRepository: Repository<MessageFileRef>;

constructor() {}

async init() {
this.msgFilesRepository = await gr.database.getRepository(TYPE, MessageFile);
this.msgFilesRefRepository = await gr.database.getRepository(TYPERef, MessageFileRef);
return this;
}

/**
* Delete a message file and test this files belongs to the right user
* @param message_id
* @param id
* @param user_id
* @returns
*/
async deleteMessageFile(message_id: string, id: string, user_id: string) {
const msgFile = await this.getMessageFile(message_id, id);
if (!msgFile) return null;

if (msgFile.message.user_id !== user_id) return null;

await this.msgFilesRepository.remove(msgFile);

for (const target_type of ["channel_media", "channel_file", "channel"]) {
const ref = await this.msgFilesRefRepository.findOne({
target_type,
company_id: msgFile.channel.company_id,
target_id: msgFile.channel.id,
id: msgFile.id,
});
if (ref) await this.msgFilesRefRepository.remove(ref);
}

return msgFile;
}

/**
* Get a message file and returns more contextual data
* @param message_id
* @param id
* @returns
*/
async getMessageFile(
message_id: string,
id: string,
): Promise<
MessageFile & {
user: UserObject;
message: Message;
channel: Channel;
navigation: { next: string; previous: string };
}
> {
const msgFile = await this.msgFilesRepository.findOne({ message_id, id });
if (!msgFile) return null;

const message = await gr.services.messages.messages.get({
thread_id: msgFile.thread_id,
id: message_id,
});
const channel = await gr.services.channels.channels.get({
company_id: message.cache.company_id,
workspace_id: message.cache.workspace_id,
id: message.cache.channel_id,
});
const user = await formatUser(await gr.services.users.get({ id: message.user_id }));

const navigationPk = {
target_type: fileIsMedia(msgFile) ? "channel_media" : "channel_file",
company_id: channel.company_id,
target_id: channel.id,
};
const next = (
await this.msgFilesRefRepository.find(navigationPk, {
pagination: {
page_token: null,
limitStr: "2",
reversed: true,
},
$gte: [["id", msgFile.id]],
})
)
.getEntities()
.filter(a => a.id !== msgFile.id)?.[0]?.id;
const previous = (
await this.msgFilesRefRepository.find(navigationPk, {
pagination: {
page_token: null,
limitStr: "2",
reversed: false,
},
$gte: [["id", msgFile.id]],
})
)
.getEntities()
.filter(a => a.id !== msgFile.id)?.[0]?.id;

return {
...msgFile,
user,
message,
channel,
navigation: {
next,
previous,
},
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import gr from "../../../global-resolver";
import { FastifyRequest, FastifyReply } from "fastify";

export class MessagesFilesController {
async deleteMessageFile(
request: FastifyRequest<{
Params: {
company_id: string;
message_id: string;
id: string;
};
}>,
reply: FastifyReply,
) {
const user = request.currentUser;
const resp = await gr.services.messages.messagesFiles.deleteMessageFile(
request.params.message_id,
request.params.id,
user.id,
);

if (!resp) reply.code(404).send();

reply.send(resp);
}

async getMessageFile(
request: FastifyRequest<{
Params: {
company_id: string;
message_id: string;
id: string;
};
}>,
reply: FastifyReply,
) {
const user = request.currentUser;
const resp = await gr.services.messages.messagesFiles.getMessageFile(
request.params.message_id,
request.params.id,
);

if (!resp) reply.code(404).send();

//Check user has access to this file (check access to channel)
if (!(await gr.services.channels.members.getChannelMember(user, resp.channel))) {
reply.code(403).send();
}

reply.send(resp);
}
}
20 changes: 20 additions & 0 deletions twake/backend/node/src/services/messages/web/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ import {
UserBookmarksController,
ViewsController,
} from "./controllers";
import { MessagesFilesController } from "./controllers/messages-files";
import { listUserFiles } from "./schemas";

const routes: FastifyPluginCallback = (fastify: FastifyInstance, options, next) => {
const threadsController = new ThreadsController();
const messagesController = new MessagesController();
const userBookmarksController = new UserBookmarksController();
const viewsController = new ViewsController();
const messagesFilesController = new MessagesFilesController();

/**
* User bookmarks collection
Expand Down Expand Up @@ -187,6 +189,24 @@ const routes: FastifyPluginCallback = (fastify: FastifyInstance, options, next)
handler: viewsController.searchFiles.bind(viewsController),
});

/**
* Messages files routes
*/

fastify.route({
method: "GET",
url: "/companies/:company_id/messages/:message_id/files/:message_file_id",
preValidation: [fastify.authenticate],
handler: messagesFilesController.getMessageFile.bind(messagesFilesController),
});

fastify.route({
method: "DELETE",
url: "/companies/:company_id/messages/:message_id/files/:message_file_id",
preValidation: [fastify.authenticate],
handler: messagesFilesController.deleteMessageFile.bind(messagesFilesController),
});

next();
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ export default ({
<div
key={file.id}
onClick={(e: any) => e.stopPropagation()}
className="rounded-md border bg-white border-gray-200 hover:border-gray-300"
className="rounded-md border bg-white border-gray-200 hover:border-gray-300 mb-1"
>
<MessageResultFile file={{ ...file, message, user }} />
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export default () => {
const setTab = useSetRecoilState(SearchTabsState);

const input = useRecoilValue(SearchInputState);
const isRecent = input?.query?.length === 0;
const isRecent = input?.query?.trim()?.length === 0;

const { channels } = useSearchChannels();
const { messages } = useSearchMessages();
Expand Down
10 changes: 6 additions & 4 deletions twake/frontend/src/app/components/search-popup/tabs/channels.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import NothingFound from '../parts/nothing-found';

export default () => {
const input = useRecoilValue(SearchInputState);
const isRecent = input?.query?.length === 0;
const isRecent = input?.query?.trim()?.length === 0;
const { channels, loading, loadMore } = useSearchChannels();

if (channels.length === 0 && !loading) return <NothingFound />;
Expand Down Expand Up @@ -41,9 +41,11 @@ export default () => {
</div>
)}

<Text.Subtitle className="block">
{Languages.t('components.searchpopup.channels')}
</Text.Subtitle>
{!!isRecent && (
<Text.Subtitle className="block">
{Languages.t('components.searchpopup.channels')}
</Text.Subtitle>
)}
<div className={'-mx-2'}>
<ChannelsResults />
</div>
Expand Down
12 changes: 6 additions & 6 deletions twake/frontend/src/app/components/search-popup/tabs/files.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,18 @@ import FileResult from '../parts/file-result';

export default () => {
const input = useRecoilValue(SearchInputState);
const isRecent = input?.query?.length === 0;
const isRecent = input?.query?.trim()?.length === 0;
const { files, loading, loadMore } = useSearchMessagesFiles();

if (files.length === 0 && !loading) return <NothingFound />;

return (
<div>
<Text.Subtitle className="block">
{isRecent
? Languages.t('components.searchpopup.recent_files')
: Languages.t('components.searchpopup.files')}
</Text.Subtitle>
{!!isRecent && (
<Text.Subtitle className="block">
{Languages.t('components.searchpopup.recent_files')}
</Text.Subtitle>
)}

<div className={'-mx-2'}>
<FilesResults />
Expand Down
12 changes: 6 additions & 6 deletions twake/frontend/src/app/components/search-popup/tabs/medias.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@ import NothingFound from '../parts/nothing-found';

export default () => {
const input = useRecoilValue(SearchInputState);
const isRecent = input?.query?.length === 0;
const isRecent = input?.query?.trim()?.length === 0;

return (
<div>
<Text.Subtitle className="block">
{isRecent
? Languages.t('components.searchpopup.recent_media')
: Languages.t('components.searchpopup.media')}
</Text.Subtitle>
{!!isRecent && (
<Text.Subtitle className="block">
{Languages.t('components.searchpopup.recent_media')}
</Text.Subtitle>
)}

<div className="-mx-2">
<MediasResults showAsFiles={!isRecent} />
Expand Down
Loading

0 comments on commit f4b3fb2

Please sign in to comment.