modified backend to recalculate file privacy upon add/remove from public collection

This commit is contained in:
Martina 2021-08-06 18:13:45 -07:00
parent cb697088b0
commit c86a738266
12 changed files with 89 additions and 104 deletions

View File

@ -404,14 +404,6 @@ export const updateFile = async (data) => {
}); });
}; };
export const toggleFilePrivacy = async (data) => {
await Websockets.checkWebsocket();
return await returnJSON(`/api/data/toggle-privacy`, {
...DEFAULT_OPTIONS,
body: JSON.stringify({ data }),
});
};
export const deleteFiles = async (data) => { export const deleteFiles = async (data) => {
await Websockets.checkWebsocket(); await Websockets.checkWebsocket();
return await returnJSON(`/api/data/delete`, { return await returnJSON(`/api/data/delete`, {

View File

@ -210,8 +210,8 @@ export default class SidebarCreateSlate extends React.Component {
marginTop: 12, marginTop: 12,
}} }}
> >
All collections are public by default. This means they can be discovered and seen by Public collections can be discovered and seen by anyone on the internet. If you make it
anyone on the internet. If you make it private, only you will be able to see it. private, only you will be able to see it.
</System.P1> </System.P1>
<RadioGroup <RadioGroup
name="isPublic" name="isPublic"

View File

@ -25,9 +25,8 @@ import getFilesByUserId from "~/node_common/data/methods/get-files-by-user-id";
import deleteFilesByIds from "~/node_common/data/methods/delete-files-by-ids"; import deleteFilesByIds from "~/node_common/data/methods/delete-files-by-ids";
import deleteFilesByUserId from "~/node_common/data/methods/delete-files-by-user-id"; import deleteFilesByUserId from "~/node_common/data/methods/delete-files-by-user-id";
import updateFileById from "~/node_common/data/methods/update-file-by-id"; import updateFileById from "~/node_common/data/methods/update-file-by-id";
import updateFilePrivacy from "~/node_common/data/methods/update-file-privacy";
import updateFilesPublic from "~/node_common/data/methods/update-files-public";
import incrementFileSavecount from "~/node_common/data/methods/increment-file-savecount"; import incrementFileSavecount from "~/node_common/data/methods/increment-file-savecount";
import recalcFilePrivacy from "~/node_common/data/methods/recalc-file-privacy";
// NOTE(martina): // NOTE(martina):
// Like postgres queries // Like postgres queries
@ -121,9 +120,8 @@ export {
deleteFilesByIds, deleteFilesByIds,
deleteFilesByUserId, deleteFilesByUserId,
updateFileById, updateFileById,
updateFilePrivacy,
updateFilesPublic,
incrementFileSavecount, incrementFileSavecount,
recalcFilePrivacy,
// NOTE(martina): Like postgres queries // NOTE(martina): Like postgres queries
createLike, createLike,
deleteLikeByFile, deleteLikeByFile,

View File

@ -0,0 +1,42 @@
import { runQuery } from "~/node_common/data/utilities";
export default async ({ fileId }) => {
return await runQuery({
label: "RECALC_FILE_PRIVACY",
queryFn: async (DB) => {
const slateIds = `(SELECT ?? FROM ?? WHERE ?? = ?)`;
const slateIdsFields = ["slateId", "slate_files", "fileId", fileId];
const filePrivacy = `(SELECT EXISTS (SELECT * FROM ?? JOIN ?? ON ?? = ?? WHERE ?? = ?))`;
const filePrivacyFields = [
"slates",
"slate_ids",
"slates.id",
"slate_ids.slateId",
"isPublic",
true,
];
const update = `UPDATE ?? SET ?? = ${filePrivacy} WHERE ?? = ?`;
const updateFields = ["files", "isPublic", ...filePrivacyFields, "id", fileId];
const updatedFile = await DB.raw(`WITH ?? AS ${slateIds} ${update} RETURNING *`, [
"slate_ids",
...slateIdsFields,
...updateFields,
]);
let rows = updatedFile.rows;
if (rows?.length) {
return rows.first();
}
return;
},
errorFn: async (e) => {
return {
error: true,
decorator: "RECALC_FILE_PRIVACY",
};
},
});
};

View File

@ -6,6 +6,8 @@ import * as Social from "~/node_common/social";
import * as Logging from "~/common/logging"; import * as Logging from "~/common/logging";
import * as ArrayUtilities from "~/node_common/array-utilities"; import * as ArrayUtilities from "~/node_common/array-utilities";
import * as Monitor from "~/node_common/monitor"; import * as Monitor from "~/node_common/monitor";
import * as Arrays from "~/common/arrays";
import * as SearchManager from "~/node_common/managers/search";
import crypto from "crypto"; import crypto from "crypto";
import JWT from "jsonwebtoken"; import JWT from "jsonwebtoken";
@ -285,3 +287,35 @@ export const addToSlate = async ({ slate, files, user, saveCopy = false }) => {
return { added: response.length }; return { added: response.length };
}; };
export const removeFromPublicCollectionUpdatePrivacy = async ({ files }) => {
let targetFiles = Arrays.filterPublic(files);
let madePrivate = [];
for (let file of targetFiles) {
let updatedFile = await Data.recalcFilePrivacy({ fileId: file.id });
if (!updatedFile) continue;
if (file.isPublic && !updatedFile.isPublic) {
madePrivate.push(updatedFile);
}
}
if (madePrivate.length) {
SearchManager.updateFile(madePrivate, "REMOVE");
}
return madePrivate;
};
export const addToPublicCollectionUpdatePrivacy = async ({ files }) => {
let targetFiles = Arrays.filterPrivate(files);
let madePublic = [];
for (let file of targetFiles) {
let updatedFile = await Data.recalcFilePrivacy({ fileId: file.id });
if (!updatedFile) continue;
if (!file.isPublic && updatedFile.isPublic) {
madePublic.push(updatedFile);
}
}
if (madePublic.length) {
SearchManager.updateFile(madePublic, "ADD");
}
return madePublic;
};

View File

@ -35,20 +35,7 @@ export default async (req, res) => {
SearchManager.updateSlate(slate, "REMOVE"); SearchManager.updateSlate(slate, "REMOVE");
if (slate.isPublic) { if (slate.isPublic) {
//NOTE(martina): if any of the files in it are now private (because they are no longer in any public slates) remove them from search Utilities.removeFromPublicCollectionUpdatePrivacy({ files: slate.objects });
const files = slate.objects;
const publicFiles = await Data.getFilesByIds({
ids: files.map((file) => file.id),
publicOnly: true,
});
const publicIds = publicFiles.map((file) => file.id);
let privateFiles = files.filter((file) => !publicIds.includes(file.id));
if (privateFiles.length) {
SearchManager.updateFile(privateFiles, "REMOVE");
}
} }
return res.status(200).send({ decorator: "SERVER_DELETE_SLATE", error: false }); return res.status(200).send({ decorator: "SERVER_DELETE_SLATE", error: false });

View File

@ -20,7 +20,7 @@ export default async (req, res) => {
}); });
} }
const slate = await Data.getSlateById({ id: req.body.data.slateId }); const slate = await Data.getSlateById({ id: req.body.data.slateId, includeFiles: true });
if (!slate) { if (!slate) {
return res.status(404).send({ return res.status(404).send({
@ -46,18 +46,7 @@ export default async (req, res) => {
} }
if (slate.isPublic) { if (slate.isPublic) {
const publicFiles = await Data.getFilesByIds({ ids: fileIds, publicOnly: true }); Utilities.removeFromPublicCollectionUpdatePrivacy({ files: slate.objects });
const publicIds = publicFiles.map((file) => file.id);
let privateFiles = fileIds
.filter((id) => !publicIds.includes(id))
.map((id) => {
return { id };
});
if (privateFiles.length) {
SearchManager.updateFile(privateFiles, "REMOVE");
}
} }
ViewerManager.hydratePartial(id, { slates: true }); ViewerManager.hydratePartial(id, { slates: true });

View File

@ -48,28 +48,6 @@ export default async (req, res) => {
.status(500) .status(500)
.send({ decorator: "SERVER_UPDATE_SLATE_UPDATE_PRIVACY_FAILED", error: true }); .send({ decorator: "SERVER_UPDATE_SLATE_UPDATE_PRIVACY_FAILED", error: true });
} }
if (!updates.isPublic) {
//NOTE(martina): if any of the files in it are now private (because they are no longer in any public slates) remove them from search
const files = slate.objects;
const publicFiles = await Data.getFilesByIds({
ids: files.map((file) => file.id),
publicOnly: true,
});
const publicIds = publicFiles.map((file) => file.id);
let privateFiles = files.filter((file) => !publicIds.includes(file.id));
if (privateFiles.length) {
SearchManager.updateFile(privateFiles, "REMOVE");
}
} else {
//NOTE(martina): make sure all the now-public files are in search if they weren't already
const files = slate.objects;
SearchManager.updateFile(files, "ADD");
}
} }
if (updates.data.name && updates.data.name !== slate.data.name) { if (updates.data.name && updates.data.name !== slate.data.name) {
@ -111,8 +89,12 @@ export default async (req, res) => {
if (slate.isPublic && !updates.isPublic) { if (slate.isPublic && !updates.isPublic) {
SearchManager.updateSlate(response, "REMOVE"); SearchManager.updateSlate(response, "REMOVE");
Utilities.removeFromPublicCollectionUpdatePrivacy({ files: slate.objects });
} else if (!slate.isPublic && updates.isPublic) { } else if (!slate.isPublic && updates.isPublic) {
SearchManager.updateSlate(response, "ADD"); SearchManager.updateSlate(response, "ADD");
Utilities.addToPublicCollectionUpdatePrivacy({ files: slate.objects });
} else { } else {
SearchManager.updateSlate(response, "EDIT"); SearchManager.updateSlate(response, "EDIT");
} }

View File

@ -59,28 +59,6 @@ export default async (req, res) => {
if (privacyResponse.error) { if (privacyResponse.error) {
return res.status(500).send({ decorator: "UPDATE_COLLECTION_PRIVACY_FAILED", error: true }); return res.status(500).send({ decorator: "UPDATE_COLLECTION_PRIVACY_FAILED", error: true });
} }
if (!updates.isPublic) {
//NOTE(martina): if any of the files in it are now private (because they are no longer in any public slates) remove them from search
const files = slate.objects;
const publicFiles = await Data.getFilesByIds({
ids: files.map((file) => file.id),
publicOnly: true,
});
const publicIds = publicFiles.map((file) => file.id);
let privateFiles = files.filter((file) => !publicIds.includes(file.id));
if (privateFiles.length) {
SearchManager.updateFile(privateFiles, "REMOVE");
}
} else {
//NOTE(martina): make sure all the now-public files are in search if they weren't already
const files = slate.objects;
SearchManager.updateFile(files, "ADD");
}
} }
if (updates.data.name && updates.data.name !== slate.data.name) { if (updates.data.name && updates.data.name !== slate.data.name) {
@ -118,8 +96,10 @@ export default async (req, res) => {
if (slate.isPublic && !updates.isPublic) { if (slate.isPublic && !updates.isPublic) {
SearchManager.updateSlate(updatedSlate, "REMOVE"); SearchManager.updateSlate(updatedSlate, "REMOVE");
Utilities.removeFromPublicCollectionUpdatePrivacy({ files: slate.objects });
} else if (!slate.isPublic && updates.isPublic) { } else if (!slate.isPublic && updates.isPublic) {
SearchManager.updateSlate(updatedSlate, "ADD"); SearchManager.updateSlate(updatedSlate, "ADD");
Utilities.addToPublicCollectionUpdatePrivacy({ files: slate.objects });
} else { } else {
SearchManager.updateSlate(updatedSlate, "EDIT"); SearchManager.updateSlate(updatedSlate, "EDIT");
} }

View File

@ -16,7 +16,6 @@ export default async (req, res) => {
//NOTE(martina): cleans the input to remove fields they should not be changing like ownerId, createdAt, filename, size, type etc. //NOTE(martina): cleans the input to remove fields they should not be changing like ownerId, createdAt, filename, size, type etc.
let updates = { let updates = {
id: req.body.data.id, id: req.body.data.id,
isPublic: req.body.data.isPublic,
data: { data: {
name: req.body.data.data?.name, name: req.body.data.data?.name,
body: req.body.data.data?.body, body: req.body.data.data?.body,
@ -34,24 +33,6 @@ export default async (req, res) => {
}); });
} }
if (typeof updates.isPublic !== "undefined" && updates.isPublic !== file.isPublic) {
let response = await Data.updateFilePrivacy({
ownerId: file.ownerId,
id: updates.id,
isPublic: updates.isPublic,
});
if (!response || response.error) {
return res.status(500).send({ decorator: "UPDATE_FILE_PRIVACY_FAILED", error: true });
}
if (response.isPublic) {
SearchManager.updateFile(response, "ADD");
} else {
SearchManager.updateFile(response, "REMOVE");
}
}
let response = await Data.updateFileById(updates); let response = await Data.updateFileById(updates);
if (!response || response.error) { if (!response || response.error) {