Skip to content

Commit

Permalink
Ops/migrations (#75)
Browse files Browse the repository at this point in the history
* ops: improves supabase migrations
* feat: allows user to unset his/her `timezone`
  • Loading branch information
en3sis authored Sep 13, 2023
1 parent 6e0f6dc commit 09e07cd
Show file tree
Hide file tree
Showing 8 changed files with 77 additions and 75 deletions.
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

0 comments on commit 09e07cd

Please sign in to comment.