Skip to content

Commit

Permalink
457 upload the last image from hypso 1 and hypso 2 (#461)
Browse files Browse the repository at this point in the history
* feat: adding a tab bar for the satellite individual page

* feat: uploading the last images of satellite

* fix: lint

* fix lint
  • Loading branch information
Thibault authored and GitHub committed Jun 26, 2025
1 parent 4ae5217 commit f9e3e9f
Show file tree
Hide file tree
Showing 17 changed files with 1,082 additions and 81 deletions.
3 changes: 3 additions & 0 deletions backend/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ API_TOKEN_SALT=toBeGenerated
ADMIN_JWT_SECRET=toBeGenerated
TRANSFER_TOKEN_SALT=toBeGenerated
JWT_SECRET=toBeGenerated
SLACK_BOT_TOKEN=toGetFromGitHub
SLACK_USER_TOKEN=toGetFromGitHub
SLACK_CHANNEL_ID=toGetFromGitHub

DATABASE_CLIENT=sqlite
DATABASE_FILENAME=dbLocation.sqlite # in dev, will use backend root dir, in prod, will be from server os root dir so should be /var/data/strapi.db or similar
133 changes: 133 additions & 0 deletions backend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 10 additions & 10 deletions backend/package.json
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
{
"name": "backend",
"private": true,
"version": "0.1.0",
"private": true,
"description": "A Strapi application",
"license": "MIT",
"author": {
"name": "A Strapi developer"
},
"scripts": {
"build": "strapi build",
"develop": "strapi develop",
"start": "strapi start",
"build": "strapi build",
"strapi": "strapi"
},
"devDependencies": {},
"dependencies": {
"@slack/web-api": "^7.9.3",
"@strapi/plugin-cloud": "4.20.5",
"@strapi/plugin-graphql": "4.20.5",
"@strapi/plugin-i18n": "4.20.5",
Expand All @@ -22,15 +26,11 @@
"react-router-dom": "5.3.4",
"styled-components": "5.3.3"
},
"author": {
"name": "A Strapi developer"
},
"strapi": {
"uuid": "93a36a2f-b139-4841-a8b1-b0d444d507e1"
},
"engines": {
"node": ">=18.0.0 <=20.x.x",
"npm": ">=6.0.0"
},
"license": "MIT"
"strapi": {
"uuid": "93a36a2f-b139-4841-a8b1-b0d444d507e1"
}
}
6 changes: 3 additions & 3 deletions backend/src/api/satellite/controllers/satellite.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
'use strict';
"use strict";

/**
* satellite controller
*/

const { createCoreController } = require('@strapi/strapi').factories;
const { createCoreController } = require("@strapi/strapi").factories;

module.exports = createCoreController('api::satellite.satellite');
module.exports = createCoreController("api::satellite.satellite");
6 changes: 3 additions & 3 deletions backend/src/api/satellite/routes/satellite.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
'use strict';
"use strict";

/**
* satellite router
*/

const { createCoreRouter } = require('@strapi/strapi').factories;
const { createCoreRouter } = require("@strapi/strapi").factories;

module.exports = createCoreRouter('api::satellite.satellite');
module.exports = createCoreRouter("api::satellite.satellite");
58 changes: 58 additions & 0 deletions backend/src/api/slack/controllers/slack.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
"use strict";

/**
* A set of functions called "actions" for `slack`
*/

// esl-lint-disable-next-line no-unused-vars
const fetchImagesFromSlack = require("../services/slack");
const fetch = require("node-fetch");

module.exports = {
fetchImages: async (ctx) => {
try {
const images = await strapi
.service("api::slack.slack")
.fetchImagesFromSlack();
return ctx.send(images);
} catch (error) {
return ctx.throw(
500,
"Error fetching images from Slack: " + error.message
);
}
},
getSharedURL: async (ctx) => {
const { fileId } = ctx.request.body;
const slackToken = process.env.SLACK_BOT_TOKEN;

if (!fileId) {
return ctx.badRequest("File ID is required");
}

try {
const response = await fetch(
"https://slack.com/api/files.sharedPublicURL",
{
method: "POST",
headers: {
Authorization: `Bearer ${process.env.SLACK_USER_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ file: fileId }),
}
);

const data = await response.json();
if (!data.ok && !data.error.includes("already_public")) {
throw new Error(data.error || "Failed to make the image public");
}
ctx.send({
message: "Image has been made public successfully",
});
} catch (error) {
console.error("Error generating public URL:", error);
ctx.internalServerError("Failed to make the image URL " + fileId);
}
},
};
25 changes: 25 additions & 0 deletions backend/src/api/slack/routes/slack.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
"use strict";

/**
* slack routes
*/
module.exports = {
routes: [
{
method: "GET",
path: "/slack-images",
handler: "slack.fetchImages",
config: {
auth: false,
},
},
{
method: "POST",
path: "/slack-shared-url",
handler: "slack.getSharedURL",
config: {
auth: false,
},
},
],
};
45 changes: 45 additions & 0 deletions backend/src/api/slack/services/slack.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
"use strict";

const { WebClient } = require("@slack/web-api");
const slack = new WebClient(process.env.SLACK_BOT_TOKEN);

/**
* slack service
*/

let cachedImages = null;
let cacheTimestamp = null;

module.exports = {
fetchImagesFromSlack: async () => {
const CACHE_DURATION = 60 * 1000; // 1 minute
const now = Date.now();

if (
cachedImages &&
cacheTimestamp &&
now - cacheTimestamp < CACHE_DURATION
) {
console.log("Returning cached images");
return cachedImages;
}

try {
const result = await slack.conversations.history({
channel: process.env.SLACK_CHANNEL_ID,
limit: 20,
});
cachedImages = result.messages.filter(
(msg) =>
msg.bot_profile?.name === "hypso1bot" &&
msg.files &&
msg.files.some((file) => file.mimetype.startsWith("image/"))
);
cacheTimestamp = now;
return cachedImages;
} catch (error) {
console.error("Error fetching images from Slack:", error);
throw error;
}
},
};
Loading

0 comments on commit f9e3e9f

Please sign in to comment.