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

Ops/migrations #75

Merged
merged 4 commits into from
Sep 13, 2023
Merged
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,6 @@
!/src/commands/bots-playground/command.template.ts
/node_modules/
/src/config.ts
/supabase/seed.sql
build/
package-lock.json
15 changes: 11 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,24 +22,31 @@ Bring Hans to your Discord server and start using his available features right a

The list of commands & plugins can be found [here 🔗](https://github.com/en3sis/hans/wiki/Commands-&-Plugins)

### Developing Hans
## Developing Hans

> 🪬 **NOTE**: Please consider opening an issue and PR for bugs, suggestions or new features.

---

## 🔅 Prepare environment
### 🔅 Prepare environment

Before running any command, run `npm install` & `cp .env.template .env`, fill all the env variables needed. To create your application, visit [Discord's Developer Portal](https://discord.com/developers/docs/intro)
Before running any command, run `npm install && cp .env.template .env`, fill all the env variables needed. To create your application, visit [Discord's Developer Portal](https://discord.com/developers/docs/intro)

> 🪬 **IMPORTANT**: A Supabase instance is needed for the bot to work. A free cluster should be more than enough (even for small bots & communities) for development.

There's a `supabase/schema.sql` file with the necessary tables and columns needed for the bot to work. You can use it to create the tables in your Supabase instance.
### Supabase Local Development.

Supabase is used for storing the bot's configs, guilds, and users.

You can work with supabase local, just follow the instructions [here 🔗](https://supabase.io/docs/guides/local-development).
Once you run `supabase start` the local supabase will be populate with the latest schema (have a look at the `supabase/seed.template.sql` file for more configuration)

More information related to working with Supabase local development can be found [📹 here 🔗](https://www.youtube.com/watch?v=N0Wb85m3YMI)

## 👩🏼‍💻 Development

Once the `Prepare environment` section is done, you can start developing your bot.

### `npm run dev`

Will start a development server with `ts-node` and `nodemon` for livereload. A bot Invite link will be displayed in the console. Use it to invite the bot to your server.
Expand Down
16 changes: 14 additions & 2 deletions src/controllers/plugins/timezones.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { TIME_ZONES_REGEX } from '../../utils/regex'
export const timezonesController = async (interaction: ChatInputCommandInteraction) => {
try {
const command = interaction.options.getSubcommand()

if (command === 'set') {
const timezone = interaction.options.getString('zone', true).trim()

Expand Down Expand Up @@ -59,6 +60,15 @@ export const timezonesController = async (interaction: ChatInputCommandInteracti
},
],
})
} else if (command === 'unset') {
// Deletes the user's timezone configuration from the database
await supabase
.from('users_settings')
.delete()
.eq('user_id', interaction.user.id)
.eq('type', 'timezone')

await interaction.editReply({ content: 'Your timezone has been unset.' })
} else if (command === 'diff') {
// Get the target & author user
const targetUser = interaction.options.getUser('user', true)
Expand Down Expand Up @@ -92,7 +102,9 @@ export const timezonesController = async (interaction: ChatInputCommandInteracti
embeds: [
{
title: '🕑 Timezone difference',
description: `**${targetUser.username}** is currently **${timeDifference} ${
description: `**${
targetUser.displayName ?? targetUser.username
}** is currently **${timeDifference} ${
targetTimezoneIsInFuture ? 'ahead' : 'behind'
}** with his local time being **${extractHours(
getTimeZones.targetLocalTime,
Expand All @@ -104,7 +116,7 @@ export const timezonesController = async (interaction: ChatInputCommandInteracti
inline: true,
},
{
name: `${targetUser.username}'s timezone`,
name: `${targetUser.displayName ?? targetUser.username}'s timezone`,
value: `${targetUserTimezone} (${extractHours(getTimeZones.targetLocalTime)})`,
inline: true,
},
Expand Down
1 change: 1 addition & 0 deletions supabase/.gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# Supabase
.branches
.temp
.seed.sql
110 changes: 42 additions & 68 deletions supabase/schema.sql → ...ase/migrations/20230913081518_current.sql
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ create table "public"."configs" (
"monitoring_channel_id" text
);

alter table
"public"."configs" enable row level security;

alter table "public"."configs" enable row level security;

create table "public"."guilds" (
"id" integer generated by default as identity not null,
Expand All @@ -30,8 +30,8 @@ create table "public"."guilds" (
"created_at" text
);

alter table
"public"."guilds" enable row level security;

alter table "public"."guilds" enable row level security;

create table "public"."guilds_plugins" (
"id" integer generated by default as identity not null,
Expand All @@ -42,22 +42,21 @@ create table "public"."guilds_plugins" (
"created_at" text
);

alter table
"public"."guilds_plugins" enable row level security;

alter table "public"."guilds_plugins" enable row level security;

create table "public"."plugins" (
"id" integer generated by default as identity not null,
"name" text,
"description" text,
"enabled" boolean,
"premium" boolean,
"category" text default 'miscellaneous' :: text,
"category" text default 'miscellaneous'::text,
"created_at" text
);

alter table
"public"."plugins" enable row level security;

alter table "public"."plugins" enable row level security;

create table "public"."users_settings" (
"id" bigint generated by default as identity not null,
Expand All @@ -67,11 +66,8 @@ create table "public"."users_settings" (
"type" user_settings_type
);

alter table "public"."users_settings" enable row level security;

CREATE UNIQUE INDEX users_settings_pkey ON public.users_settings USING btree (id, user_id);

alter table "public"."users_settings" add constraint "users_settings_pkey" PRIMARY KEY using index "users_settings_pkey";
alter table "public"."users_settings" enable row level security;

CREATE UNIQUE INDEX configs_pkey ON public.configs USING btree (id);

Expand All @@ -85,57 +81,36 @@ CREATE UNIQUE INDEX plugins_name_key ON public.plugins USING btree (name);

CREATE UNIQUE INDEX plugins_pkey ON public.plugins USING btree (id);

alter table
"public"."configs"
add
constraint "configs_pkey" PRIMARY KEY using index "configs_pkey";

alter table
"public"."guilds"
add
constraint "guilds_pkey" PRIMARY KEY using index "guilds_pkey";

alter table
"public"."guilds_plugins"
add
constraint "guilds_plugins_pkey" PRIMARY KEY using index "guilds_plugins_pkey";

alter table
"public"."plugins"
add
constraint "plugins_pkey" PRIMARY KEY using index "plugins_pkey";

alter table
"public"."guilds"
add
constraint "guilds_guild_id_key" UNIQUE using index "guilds_guild_id_key";

alter table
"public"."guilds_plugins"
add
constraint "guilds_plugins_name_fkey" FOREIGN KEY (name) REFERENCES plugins(name) not valid;

alter table
"public"."guilds_plugins" validate constraint "guilds_plugins_name_fkey";

alter table
"public"."guilds_plugins"
add
constraint "guilds_plugins_owner_fkey" FOREIGN KEY (owner) REFERENCES guilds(guild_id) ON
DELETE
CASCADE not valid;

alter table
"public"."guilds_plugins" validate constraint "guilds_plugins_owner_fkey";

alter table
"public"."plugins"
add
constraint "plugins_name_key" UNIQUE using index "plugins_name_key";

-- Functions
CREATE
OR REPLACE FUNCTION reset_chat_gpt_plugin() RETURNS void AS $$ BEGIN
CREATE UNIQUE INDEX users_settings_pkey ON public.users_settings USING btree (id, user_id);

alter table "public"."configs" add constraint "configs_pkey" PRIMARY KEY using index "configs_pkey";

alter table "public"."guilds" add constraint "guilds_pkey" PRIMARY KEY using index "guilds_pkey";

alter table "public"."guilds_plugins" add constraint "guilds_plugins_pkey" PRIMARY KEY using index "guilds_plugins_pkey";

alter table "public"."plugins" add constraint "plugins_pkey" PRIMARY KEY using index "plugins_pkey";

alter table "public"."users_settings" add constraint "users_settings_pkey" PRIMARY KEY using index "users_settings_pkey";

alter table "public"."guilds" add constraint "guilds_guild_id_key" UNIQUE using index "guilds_guild_id_key";

alter table "public"."guilds_plugins" add constraint "guilds_plugins_name_fkey" FOREIGN KEY (name) REFERENCES plugins(name) not valid;

alter table "public"."guilds_plugins" validate constraint "guilds_plugins_name_fkey";

alter table "public"."guilds_plugins" add constraint "guilds_plugins_owner_fkey" FOREIGN KEY (owner) REFERENCES guilds(guild_id) ON DELETE CASCADE not valid;

alter table "public"."guilds_plugins" validate constraint "guilds_plugins_owner_fkey";

alter table "public"."plugins" add constraint "plugins_name_key" UNIQUE using index "plugins_name_key";

set check_function_bodies = off;

CREATE OR REPLACE FUNCTION public.reset_chat_gpt_plugin()
RETURNS void
LANGUAGE plpgsql
AS $function$ BEGIN
UPDATE
guilds_plugins
SET
Expand All @@ -145,8 +120,7 @@ OR REPLACE FUNCTION reset_chat_gpt_plugin() RETURNS void AS $$ BEGIN

END;

$$ LANGUAGE plpgsql;
$function$
;


-- Crons
SELECT
cron.schedule('0 0 * * *', 'SELECT reset_chat_gpt_plugin()');
Empty file removed supabase/seed.sql
Empty file.
7 changes: 7 additions & 0 deletions supabase/seed.template.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
-- This file is the template for your local supabase database. Remove the .template from the filename to use for seeding your local database.

-- Seed data for 'timezones' table, change the USER_ID_ONE and USER_ID_TWO to the user ids you want to seed.

INSERT INTO users_settings (id, created_at, user_id, metadata, type) VALUES
(1, '2023-09-13 08:05:31+00', USER_ID_ONE, '{"timezone":"Europe/Berlin"}', 'timezone'),
(2, '2023-09-13 08:06:04.711699+00', USER_ID_TWO, '{"timezone":"Africa/Ceuta"}', 'timezone');
2 changes: 1 addition & 1 deletion tests/utils/regex.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const invalidTimeZones = [
'Invalid_Timezone/Invalid_Timezone22',
]

describe('TIME_ZONES_REGEX', () => {
describe('Utils: Timezone', () => {
it('should match valid time zones', () => {
validTimeZones.forEach((timeZone) => {
expect(TIME_ZONES_REGEX.test(timeZone) && TIMEZONES_LIST.includes(timeZone)).eq(true)
Expand Down