Skip to content

Commit

Permalink
add sls
Browse files Browse the repository at this point in the history
  • Loading branch information
dispherical committed Oct 19, 2024
1 parent c126b53 commit e1245a0
Show file tree
Hide file tree
Showing 7 changed files with 623 additions and 4 deletions.
1 change: 0 additions & 1 deletion buttons/hardware.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ Hack Club has started the process of getting teenagers into more hardware-based
<#C078GBDKC03>: Join Hack Clubbers in building an open source 3D printer
<#C056AMWSFKJ>:
- OnBoard: Get $100 to build your own custom PCB. Learn more at https://hackclub.com/onboard
- Bin: Design a project online, get parts shipped to your door, and build it IRL. Learn more at https://hackclub.com/bin/
All of these events and programs are *free* for you to participate in.`;
},
};
119 changes: 119 additions & 0 deletions buttons/local.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
const Airtable = require("airtable");
const base = new Airtable({ apiKey: process.env.AIRTABLE_TOKEN }).base(
process.env.AIRTABLE_BASE,
);
const geolib = require("geolib");
const { PrismaClient } = require("@prisma/client");
const prisma = new PrismaClient();
const geoIp2 = require("geoip-lite2");

async function lookupCity(lat, lon) {
const response = await (
await fetch(
"https://nominatim.openstreetmap.org/reverse?" +
new URLSearchParams({
lat,
lon,
format: "jsonv2",
}),
)
).json();
if (response.error) return "Unknown city";
else return response.display_name;
}

module.exports = {
title: "Find Local Hack Clubbers",
/**
* @param {{app: import('@slack/bolt').App}} param1
*/
render: async function ({ app, body }) {
if (!body?.user?.id) return `this isn't good at all :(`;

const user = await app.client.users.info({
user: body?.user?.id,
});
if (!user.user.profile.email)
return `Sorry, I couldn't lookup your location. This appears to be an issue on our side. Tell an admin that the bot may not have been installed with the \`users:read.email\` scope.`;
const tableIds = process.env.AIRTABLE_TABLES.split(",");
var u = null;

for (const tableId of tableIds) {
const table = await base(tableId)
.select({
filterByFormula:
tableId == "tblLXcLHjzTy08IeK"
? `fldwcOLKym9dRvKvW = "${user.user.profile.email}"`
: `fldFDUVB1h83LchKg = "${user.user.profile.email}"`,
})
.all();

u = table.find(
(record) =>
record.get("Email") == user.user.profile.email ||
record.get("Email Address") == user.user.profile.email,
);
if (u) {
break;
}
}

if (!u || !u?.get("IP"))
return `Sorry, I couldn't lookup your location. This appears to be an issue on our side. Tell an admin that our system may have failed to record user information.`;

var locations = [];
const channels = await prisma.channel.findMany({
where: {
optout: false,
},
});
const userRecord = await prisma.user.findFirst({
where: {
id: body.user.id,
},
});
var lookup = geoIp2.lookup(u.get("IP"));
var location = lookup.ll;

if (userRecord && userRecord.lat && userRecord.lon)
location = [userRecord.lat, userRecord.lon];

channels.forEach((channel) => {
if (!channel.lat || !channel.lon || channel.optout) return;
const distance = geolib.getPreciseDistance(
{
latitude: channel.lat,
longitude: channel.lon,
},
{
latitude: location[0],
longitude: location[1],
},
);
locations.push({
km: geolib.convertDistance(distance, "km"),
mi: geolib.convertDistance(distance, "mi"),
id: channel.id,
});
});
var filter = locations
.sort((a, b) => a.km - b.km)
.filter((a) => a.mi <= 350);
if (filter.length > 2) locations = filter;
else locations = locations.sort((a, b) => a.km - b.km).slice(0, 3);

var text = !userRecord
? `I assumed you live in ${await lookupCity(location[0], location[1])} based on information based the IP address of when you joined Hack Club. If it's not correct, please set it manually using /setuserlocation [location]. Here are some channels with people near you:\n\n`
: `Showing channels near \`${await lookupCity(location[0], location[1])}\`:\n\n`;

locations.forEach(
(loc) =>
(text += `- <#${loc.id}> (${loc.mi.toFixed(2)} mi/${loc.km.toFixed(2)} km away)\n`),
);

if (locations.length < 1)
text +=
"There are no channels for Hack Clubbers near you. Go make one and invite people!";
return text;
},
};
11 changes: 10 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ const { createClient } = require("redis");
const cron = require("node-cron");
const { PrismaClient } = require("@prisma/client");
const prisma = new PrismaClient();

const getCloseChannels = require("./utils/getCloseChannels")
const receiver = new ExpressReceiver({
signingSecret: process.env.SLACK_SIGNING_SECRET,
});
Expand All @@ -31,6 +31,15 @@ Array.prototype.random = function () {
receiver.router.get("/", async (req, res) => {
res.redirect(302, "https://github.com/hackclub/channel-directory");
});
receiver.router.get("/sls/:id", async (req, res) => {
const { id } = req.params
try {
const text = await getCloseChannels(id)
res.set("Content-Type","text/plain").send(text)
} catch(e){
res.set("Content-Type","text/plain").send("User not found").status(404)
}
});

await require("./commands/optout")({ app, client, prisma });
await require("./commands/setlocation")({ app, client, prisma });
Expand Down
4 changes: 3 additions & 1 deletion interactions/channel_created.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ module.exports = ({ app, client, prisma }) => {
await app.client.chat.postEphemeral({
channel: channelId,
user: userId,
text: `Nice channel you got there. I'm librarian, which is created by HQ to help people find new and active channels. No message data is collected/stored, just how many messages are sent in a certain timeframe. If you do not want me in this channel and you do not want your channel in #directory, please run the command /optout-directory.`,
text: `Nice channel you got there. I'm librarian, which is created by HQ to help people find new and active channels. No message data is collected/stored, just how many messages are sent in a certain timeframe. If you do not want me in this channel and you do not want your channel in #directory, please run the command /optout-directory.
*NOTE:* PLEASE SET A CUSTOM CHANNEL EMOJI USING THE /setemoji COMMAND, otherwise you'll get a random emoji.`,
});
});
};
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,11 @@
"dependencies": {
"@prisma/client": "5.17.0",
"@slack/bolt": "^3.18.0",
"airtable": "^0.12.2",
"dotenv": "^16.4.5",
"figlet": "^1.7.0",
"geoip-lite2": "^2.1.43",
"geolib": "^3.3.4",
"node-cron": "^3.0.3",
"pretty-ms": "7.0.1",
"prisma": "^5.17.0",
Expand Down
121 changes: 121 additions & 0 deletions utils/getCloseChannels.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
const Airtable = require("airtable");
require("dotenv").config();
const { App } = require("@slack/bolt");
const base = new Airtable({ apiKey: process.env.AIRTABLE_TOKEN }).base(
process.env.AIRTABLE_BASE,
);
const geolib = require("geolib");
const { PrismaClient } = require("@prisma/client");
const prisma = new PrismaClient();
const geoIp2 = require("geoip-lite2");
const app = new App({
token: process.env.SLACK_BOT_TOKEN,
signingSecret: process.env.SLACK_SIGNING_SECRET,

});

async function lookupCity(lat, lon) {
const response = await (
await fetch(
"https://nominatim.openstreetmap.org/reverse?" +
new URLSearchParams({
lat,
lon,
format: "jsonv2",
}),
)
).json();
if (response.error) return "Unknown city";
else return response.display_name;
}

module.exports = async function (id, ip) {
var u = null;
if (id) {
const user = await app.client.users.info({
user: id
});
if (!user.user.profile.email)
return `Sorry, I couldn't lookup your location. This appears to be an issue on our side. Tell an admin that the bot may not have been installed with the \`users:read.email\` scope.`;
const tableIds = process.env.AIRTABLE_TABLES.split(",");


for (const tableId of tableIds) {
const table = await base(tableId)
.select({
filterByFormula:
tableId == "tblLXcLHjzTy08IeK"
? `fldwcOLKym9dRvKvW = "${user.user.profile.email}"`
: `fldFDUVB1h83LchKg = "${user.user.profile.email}"`,
})
.all();

u = table.find(
(record) =>
record.get("Email") == user.user.profile.email ||
record.get("Email Address") == user.user.profile.email,
);
if (u) {
break;
}
}
}
if (!u?.get("IP") && !ip)
return `Sorry, I couldn't lookup your location. This appears to be an issue on our side. Tell an admin that our system may have failed to record user information.`;

var locations = [];
const channels = await prisma.channel.findMany({
where: {
optout: false,
},
});
const userRecord = await prisma.user.findFirst({
where: {
id,
},
});
var lookup = geoIp2.lookup(u.get("IP") || ip);
var location = lookup.ll;

if (userRecord && userRecord.lat && userRecord.lon)
location = [userRecord.lat, userRecord.lon];

channels.forEach((channel) => {
if (!channel.lat || !channel.lon || channel.optout) return;
const distance = geolib.getPreciseDistance(
{
latitude: channel.lat,
longitude: channel.lon,
},
{
latitude: location[0],
longitude: location[1],
},
);
locations.push({
km: geolib.convertDistance(distance, "km"),
mi: geolib.convertDistance(distance, "mi"),
id: channel.id,
});
});
var filter = locations
.sort((a, b) => a.km - b.km)
.filter((a) => a.mi <= 350);
if (filter.length > 2) locations = filter;
else locations = locations.sort((a, b) => a.km - b.km).slice(0, 3);

var text = !userRecord
? `I assumed you live in ${await lookupCity(location[0], location[1])} based on information based the IP address of when you joined Hack Club. If it's not correct, please set it manually using /setuserlocation [location]. Here are some channels with people near you:\n\n`
: `Showing channels near \`${await lookupCity(location[0], location[1])}\`:\n\n`;

locations.forEach(
(loc) =>
(text += `- <#${loc.id}> (${loc.mi.toFixed(2)} mi/${loc.km.toFixed(2)} km away)\n`),
);

if (locations.length < 1)
text +=
"There are no channels for Hack Clubbers near you. Go make one and invite people!";
return text;

}
Loading

0 comments on commit e1245a0

Please sign in to comment.