Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Coffee Chat Image API #642

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions backend/src/API/coffeeChatImageAPI.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { bucket } from '../firebase';
import { NotFoundError } from '../utils/errors';

/**
* Gets Coffee Chat proof image for member
* @param name - the name of the image
* @param user - the member who made the request
* @throws NotFoundError if the requested image does not exist
* @returns a Promise to the signed URL to the image file
*/
export const getCoffeeChatProofImage = async (name: string): Promise<string> => {
const file = bucket.file(`${name}.jpg`);
const fileExists = await file.exists().then((result) => result[0]);
if (!fileExists) {
throw new NotFoundError(`The requested image (${name}) does not exist`);
}
const signedUrl = await file.getSignedUrl({
action: 'read',
expires: Date.now() + 15 * 60000
});
return signedUrl[0];
};

/**
* Sets Coffee Chat proof image for member
* @param name - the name of the image
* @param user - the member who made the request
* @returns a Promise to the signed URL to the image file
*/
export const setCoffeeChatProofImage = async (name: string): Promise<string> => {
const file = bucket.file(`${name}.jpg`);
const signedURL = await file.getSignedUrl({
action: 'write',
version: 'v4',
expires: Date.now() + 15 * 60000 // 15 min
});
return signedURL[0];
};

/**
* Deletes Coffee Chat proof image for member
* @param name - the name of the image
* @param user - the member who made the request
*/
export const deleteCoffeeChatProofImage = async (name: string): Promise<void> => {
const imageFile = bucket.file(`${name}.jpg`);
await imageFile.delete();
};
13 changes: 5 additions & 8 deletions backend/src/API/teamEventsImageAPI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,9 @@ import { NotFoundError } from '../utils/errors';
/**
* Sets TEC proof image for member
* @param name - the name of the image
* @param user - the member who made the request
* @returns a Promise to the signed URL to the image file
*/
export const setEventProofImage = async (name: string, user: IdolMember): Promise<string> => {
export const setEventProofImage = async (name: string): Promise<string> => {
const file = bucket.file(`${name}.jpg`);
const signedURL = await file.getSignedUrl({
action: 'write',
Expand All @@ -21,11 +20,10 @@ export const setEventProofImage = async (name: string, user: IdolMember): Promis
/**
* Gets TEC proof image for member
* @param name - the name of the image
* @param user - the member who made the request
* @throws NotFoundError if the requested image does not exist
* @returns a Promise to the signed URL to the image file
*/
export const getEventProofImage = async (name: string, user: IdolMember): Promise<string> => {
export const getEventProofImage = async (name: string): Promise<string> => {
const file = bucket.file(`${name}.jpg`);
const fileExists = await file.exists().then((result) => result[0]);
if (!fileExists) {
Expand All @@ -41,11 +39,11 @@ export const getEventProofImage = async (name: string, user: IdolMember): Promis
/**
* Gets all TEC proof images associated with the IdolMember
* @param user - the member who made the request
* @returns a Promise which results in an array of EventProofImage with file name and signed URL
* @returns a Promise which results in an array of ProofImage with file name and signed URL
*/
export const allEventProofImagesForMember = async (
user: IdolMember
): Promise<readonly EventProofImage[]> => {
): Promise<readonly ProofImage[]> => {
const netId: string = getNetIDFromEmail(user.email);
const files = await bucket.getFiles({ prefix: `eventProofs/${netId}` });
const images = await Promise.all(
Expand Down Expand Up @@ -75,9 +73,8 @@ export const allEventProofImagesForMember = async (
/**
* Deletes TEC proof image for member
* @param name - the name of the image
* @param user - the member who made the request
*/
export const deleteEventProofImage = async (name: string, user: IdolMember): Promise<void> => {
export const deleteEventProofImage = async (name: string): Promise<void> => {
const imageFile = bucket.file(`${name}.jpg`);
await imageFile.delete();
};
Expand Down
33 changes: 27 additions & 6 deletions backend/src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,11 @@ import {
regradeSubmissions,
updateSubmissions
} from './API/devPortfolioAPI';
import {
getCoffeeChatProofImage,
setCoffeeChatProofImage,
deleteCoffeeChatProofImage
} from './API/coffeeChatImageAPI';
import DPSubmissionRequestLogDao from './dao/DPSubmissionRequestLogDao';
import AdminsDao from './dao/AdminsDao';
import { sendMail } from './API/mailAPI';
Expand Down Expand Up @@ -288,6 +293,7 @@ loginCheckedDelete('/shoutout/:uuid', async (req, user) => {
return {};
});

// Coffee Chats
loginCheckedGet('/coffee-chat', async () => ({
coffeeChats: await getAllCoffeeChats()
}));
Expand Down Expand Up @@ -315,6 +321,20 @@ loginCheckedPut('/coffee-chat', async (req, user) => ({
coffeeChats: await updateCoffeeChat(req.body, user)
}));

// Coffee Chat Proof Image
loginCheckedGet('/coffee-chat-proof-image/:name(*)', async (req) => ({
url: await getCoffeeChatProofImage(req.params.name)
}));

loginCheckedGet('/coffee-chat-proof-image-signed-url/:name(*)', async (req) => ({
url: await setCoffeeChatProofImage(req.params.name)
}));

loginCheckedDelete('/coffee-chat-proof-image/:name(*)', async (req) => {
await deleteCoffeeChatProofImage(req.params.name);
return {};
});

// Pull from IDOL
loginCheckedPost('/pullIDOLChanges', (_, user) => requestIDOLPullDispatch(user));
loginCheckedGet('/getIDOLChangesPR', (_, user) => getIDOLChangesPR(user));
Expand Down Expand Up @@ -382,16 +402,17 @@ loginCheckedPost('/team-event-reminder', async (req, user) => ({
}));

// Team Events Proof Image
loginCheckedGet('/event-proof-image/:name(*)', async (req, user) => ({
url: await getEventProofImage(req.params.name, user)
loginCheckedGet('/event-proof-image/:name(*)', async (req) => ({
url: await getEventProofImage(req.params.name)
}));

// TODO: Modify this endpoint to /event-proof-image/* to be more RESTful
loginCheckedGet('/event-proof-image-signed-url/:name(*)', async (req, user) => ({
url: await setEventProofImage(req.params.name, user)
loginCheckedGet('/event-proof-image-signed-url/:name(*)', async (req) => ({
url: await setEventProofImage(req.params.name)
}));
loginCheckedDelete('/event-proof-image/:name(*)', async (req, user) => {
await deleteEventProofImage(req.params.name, user);

loginCheckedDelete('/event-proof-image/:name(*)', async (req) => {
await deleteEventProofImage(req.params.name);
return {};
});

Expand Down
2 changes: 1 addition & 1 deletion common-types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ interface TeamEvent extends TeamEventInfo {
readonly requests: TeamEventAttendance[];
}

interface EventProofImage {
interface ProofImage {
readonly url: string;
readonly fileName: string;
}
Expand Down
36 changes: 34 additions & 2 deletions frontend/src/API/ImagesAPI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import APIWrapper from './APIWrapper';
import HeadshotPlaceholder from '../static/images/headshot-placeholder.png';

export default class ImagesAPI {
// member images
// Member Images
public static getMemberImage(email: string): Promise<string> {
const responseProm = APIWrapper.get(`${backendURL}/member-image/${email}`).then(
(res) => res.data
Expand Down Expand Up @@ -31,13 +31,14 @@ export default class ImagesAPI {
});
}

// Event proof images
// Event Proof Images
public static getEventProofImage(name: string): Promise<string> {
const responseProm = APIWrapper.get(`${backendURL}/event-proof-image/${name}`).then(
(res) => res.data
);
return responseProm.then((val) => {
if (val.error) {
// console.log(val.error)
return HeadshotPlaceholder.src;
}
return val.url;
Expand All @@ -61,4 +62,35 @@ export default class ImagesAPI {
public static async deleteEventProofImage(name: string): Promise<void> {
await APIWrapper.delete(`${backendURL}/event-proof-image/${name}`);
}

// Coffee Chat Proof Images
public static getCoffeeChatProofImage(name: string): Promise<string> {
const responseProm = APIWrapper.get(`${backendURL}/coffee-chat-proof-image/${name}`).then(
(res) => res.data
);
return responseProm.then((val) => {
if (val.error) {
return HeadshotPlaceholder.src;
}
return val.url;
});
}

private static getCoffeeChatProofImageSignedURL(name: string): Promise<string> {
const responseProm = APIWrapper.get(
`${backendURL}/coffee-chat-proof-image-signed-url/${name}`
).then((res) => res.data);
return responseProm.then((val) => val.url);
}

public static uploadCoffeeChatProofImage(body: Blob, name: string): Promise<void> {
return this.getCoffeeChatProofImageSignedURL(name).then((url) => {
const headers = { 'content-type': 'image/jpeg' };
APIWrapper.put(url, body, headers).then((res) => res.data);
});
}

public static async deleteCoffeeChatProofImage(name: string): Promise<void> {
await APIWrapper.delete(`${backendURL}/coffee-chat-proof-image/${name}`);
}
}
Loading