diff --git a/.env.example b/.env.example index e2dd4e4f..3679a62b 100644 --- a/.env.example +++ b/.env.example @@ -6,9 +6,9 @@ STRIPE_PUBLISHABLE_KEY="" STRIPE_SECRET_KEY="" STRIPE_SIGNING_KEY="" JWT_SECRET="" -FRONTEND_URL="" -NEXT_PUBLIC_BACKEND_URL="" -BACKEND_INTERNAL_URL="" +FRONTEND_URL="http://localhost:4200" +NEXT_PUBLIC_BACKEND_URL="http://localhost:3000" +BACKEND_INTERNAL_URL="http://localhost:3000" X_API_KEY="" X_API_SECRET="" LINKEDIN_CLIENT_ID="" diff --git a/apps/backend/src/api/api.module.ts b/apps/backend/src/api/api.module.ts index 3da6804a..64f16b22 100644 --- a/apps/backend/src/api/api.module.ts +++ b/apps/backend/src/api/api.module.ts @@ -38,13 +38,18 @@ const authenticatedController = [ BullMqModule.forRoot({ connection: ioRedis, }), - ServeStaticModule.forRoot({ - rootPath: process.env.UPLOAD_DIRECTORY, - serveRoot: '/' + process.env.NEXT_PUBLIC_UPLOAD_STATIC_DIRECTORY, - serveStaticOptions: { - index: false, - }, - }), + ...(!!process.env.UPLOAD_DIRECTORY && + !!process.env.NEXT_PUBLIC_UPLOAD_STATIC_DIRECTORY + ? [ + ServeStaticModule.forRoot({ + rootPath: process.env.UPLOAD_DIRECTORY, + serveRoot: '/' + process.env.NEXT_PUBLIC_UPLOAD_STATIC_DIRECTORY, + serveStaticOptions: { + index: false, + }, + }), + ] + : []), ], controllers: [StripeController, AuthController, ...authenticatedController], providers: [ diff --git a/apps/docs/emails.mdx b/apps/docs/emails.mdx new file mode 100644 index 00000000..1e45b704 --- /dev/null +++ b/apps/docs/emails.mdx @@ -0,0 +1,16 @@ +--- +title: Email Notifications +description: How to send notifications to users +--- + +At the moment we are using Resend to send email notifications to users, and might be changed the Novu later. + +Register to [Resend](https://resend.com) connect your domain. +Copy your API Key. +Head over to .env file and add the following line. + +```env +RESEND_API_KEY="" +``` + +Feel free to contribute other providers to send email notifications. \ No newline at end of file diff --git a/apps/docs/github.mdx b/apps/docs/github.mdx new file mode 100644 index 00000000..f45b05f7 --- /dev/null +++ b/apps/docs/github.mdx @@ -0,0 +1,15 @@ +--- +title: GitHub +--- + +Gitroom uses GitHub for oAuth2 authentication during login and for the initial stars sync. +To use GitHub open settings of either your profile or and organization and click on "Developers Settings". +And it left menu, click on "oAuth Apps" and then "New oAuth App". + +In the `Authorization callback URL` add `http://localhost:4200/settings`
+Then copy the GitHub `Client ID` and `Client Secret` and paste them in the `.env` file. + +```env +GITHUB_CLIENT_ID="" +GITHUB_CLIENT_SECRET="" +``` \ No newline at end of file diff --git a/apps/docs/howitworks.mdx b/apps/docs/howitworks.mdx index 83a69c54..8232d9d8 100644 --- a/apps/docs/howitworks.mdx +++ b/apps/docs/howitworks.mdx @@ -3,7 +3,6 @@ title: How it works description: 'Learn the architecture of the project' --- -Gitroom is a tool to convert private communication into public knowledge.
The entire project is built under [NX](https://nx.dev/) to have a monorepo with multiple projects.

Unlike other NX project, this project has one `.env` file that is shared between all the apps.
It makes it easier to develop and deploy the project.

@@ -12,10 +11,9 @@ When deploying to websites like [Railway](https://railway.app) or [Heroku](https **At the moment it has 6 project:** - **Backend** - NestJS based system -- **Panel** - NextJS based control panel. -- **Tenants** - NextJS based multi-tenant website. -- **Discord** - NestJS based Discord bot. -- **Marketing** - NextJS based marketing website. +- **Workers** - NestJS based workers connected to a Redis Queue. +- **Cron** - NestJS scheduler to run cron jobs. +- **Frontend** - NextJS based control panel. - **Docs** - Mintlify based documentation website. ## Architecture +### Frontend +The frontend is built with [NextJS](https://nextjs.org/) and [TailwindCSS](https://tailwindcss.com/).
+It works directly with the Backend to: +- Show analytics +- Schedule posts +- Manage users + ### Backend -The project has a centralized backend that both the bots and the client interact with.
The backend is built with [NestJS](https://nestjs.com/) with a basic architecture of controllers, services, repositories and dtos.

It uses [Prisma](https://www.prisma.io/) as an ORM to interact with the database.
By default Prisma uses [Postgres](https://www.postgresql.org/) as a database, but it can be easily changed to any other database since there are no native queries.

-The project doesn't have a control panel login, it works with an SSO using the different bots.
-Once somebody uses a command like `/add` or `/signin` the backend will receive the server id and the internal user id from the bot.

-The backend will auto-create an organization and a user if it doesn't exist.
-It will return a URL with the JWT token embedded in the url to sign in into the control panel. +It uses Redis to schedule posts and run background jobs. -### Panel -The panel is built with [NextJS](https://nextjs.org/) and [TailwindCSS](https://tailwindcss.com/).
-The panel has 4 main pages: -- The main control panel to create and manage the FAQ. -- A style page to customize the FAQ. -- A "Create an faq" page, it takes an entire conversation and converts it into an FAQ with OpenAI ChatGPT. -- Domains page to manage the domains and subdomains that lead to the tenant website. -- An integrations page to add bots to different platforms such as: Discord, Slack, Intercom, etc. +### Cron +The backend is built with [NestJS](https://nestjs.com/) and share components with the backend.
+At the moment the use of the cron is: +- Refresh tokens from different social media platforms. +- Check for trending change every hour and inform users about it. +- Sync the amount of stars for every repository at the end of the day. -### Tenants -The tenants is built with [NextJS](https://nextjs.org/) and [TailwindCSS](https://tailwindcss.com/).
-It's the website for the end-users to see the FAQ.
-It contains a simple search bar and a list of questions.
-The search bar uses [Algolia](https://www.algolia.com/) to search through the questions.
-It uses the style from the control panel to customize the website.
-The tenants cache each pages on the `Gitroom.com/[domainName]` path, it uses a middleware to rewrite the Vercel apex domain or the custom domain to the route.
- -### Discord -The Discord bot is built with [Discord.JS](https://discord.js.org/) and [NestJS](https://nestjs.com/).
-It runs in a loop and listens to every message in every server it's in.
-Once somebody runs a command such as `/add` or `/signin` it will send a request to the backend with the server id and the user id.
-This is a simple server and in the future there will be many other bots for different platforms. - -### Marketing -The marketing website is built with [NextJS](https://nextjs.org/) and [TailwindCSS](https://tailwindcss.com/).
-It's a simple static websites with a few pages. +### Worker +The backend is built with [NestJS](https://nestjs.com/) and share components with the backend.
+At the moment the use of the worker is: +- Post scheduled posts to social media platforms. +- Perform multiple jobs coming from the cron. ### Docs The documentation website is built with [Mintlify](https://www.mintlify.com/).
diff --git a/apps/docs/images/arch.png b/apps/docs/images/arch.png index c7b64e4f..2a45a0e5 100644 Binary files a/apps/docs/images/arch.png and b/apps/docs/images/arch.png differ diff --git a/apps/docs/images/providers/linkedin/linkedin-001.png b/apps/docs/images/providers/linkedin/linkedin-001.png new file mode 100644 index 00000000..3226cc13 Binary files /dev/null and b/apps/docs/images/providers/linkedin/linkedin-001.png differ diff --git a/apps/docs/images/providers/linkedin/linkedin-002.png b/apps/docs/images/providers/linkedin/linkedin-002.png new file mode 100644 index 00000000..18138aa7 Binary files /dev/null and b/apps/docs/images/providers/linkedin/linkedin-002.png differ diff --git a/apps/docs/images/providers/reddit/reddit-001.png b/apps/docs/images/providers/reddit/reddit-001.png new file mode 100644 index 00000000..7507a0e3 Binary files /dev/null and b/apps/docs/images/providers/reddit/reddit-001.png differ diff --git a/apps/docs/images/providers/x/x-001.png b/apps/docs/images/providers/x/x-001.png new file mode 100644 index 00000000..bd8253a6 Binary files /dev/null and b/apps/docs/images/providers/x/x-001.png differ diff --git a/apps/docs/images/providers/x/x-002.png b/apps/docs/images/providers/x/x-002.png new file mode 100644 index 00000000..59f0d47c Binary files /dev/null and b/apps/docs/images/providers/x/x-002.png differ diff --git a/apps/docs/images/providers/x/x-003.png b/apps/docs/images/providers/x/x-003.png new file mode 100644 index 00000000..d54a5f19 Binary files /dev/null and b/apps/docs/images/providers/x/x-003.png differ diff --git a/apps/docs/images/providers/x/x-004.png b/apps/docs/images/providers/x/x-004.png new file mode 100644 index 00000000..8e62bf5e Binary files /dev/null and b/apps/docs/images/providers/x/x-004.png differ diff --git a/apps/docs/introduction.mdx b/apps/docs/introduction.mdx index 64e7fe65..67c5e21b 100644 --- a/apps/docs/introduction.mdx +++ b/apps/docs/introduction.mdx @@ -37,8 +37,6 @@ When deploying to websites like [Railway](https://railway.app) or [Heroku](https - `cron` - NestJS cron jobs that run every X to update the database with new trending, refresh tokens and more. - `workers` - NestJS workers that run every X to process scheduled posts, sync GitHub stars and more. -In the future there will also be a bot of Slack, Intercom, Telegram, and more. - +
  • + ### The backend logic: +
      +
    • Define DTO for the settings of the provider
    • +
    • Generate an authentication URL
    • +
    • Authenticate the user from the callback
    • +
    • Refresh the user token
    • +
    +
  • +
  • + ### The frontend logic: +
      +
    • Implement the settings page
    • +
    • Implement the preview page
    • +
    • Upload the provider image
    • +
    +
  • + + +## Social Media + +### Backend +For our example, we will use the X provider.
    +1. First, we need to create a DTO for the settings of the provider.
    +head over to `nestjs-libraries/src/dtos/posts/providers-settings` +And create a new file `x-provider-settings.dto.ts`
    +(you don't have to create a DTO if there are no settings)

    +Once created head over to `nestjs-libraries/src/dtos/posts/providers-settings/all.providers.settings.ts` +And add the new DTO.

    +Head to `libraries/nestjs-libraries/src/dtos/posts/create.post.dto.ts`
    +look for the discriminator and add another line in the format of
    + +```typescript +{ value: DTOClassName, name: 'providerName' }, +``` + +2. head over to `libraries/nestjs-libraries/src/integrations/social`
    +And create a new provider file `providerName.provider.ts`
    +The content of the file should look like this: + +### For oAuth2 providers + +```typescript +import { + AuthTokenDetails, + PostDetails, + PostResponse, + SocialProvider, +} from '@gitroom/nestjs-libraries/integrations/social/social.integrations.interface'; + +export class XProvider implements SocialProvider { + identifier = 'providerName'; + name = 'Provider Name'; + async refreshToken(refreshToken: string): Promise { + ...refresh the token + } + + async generateAuthUrl() { + ...generate the auth url + } + + async authenticate(params: { code: string; codeVerifier: string }) { + ...authenticate the user + } + + async post( + id: string, + accessToken: string, + postDetails: PostDetails[] + ): Promise { + ...post the content + } +} +``` +Take a look at the exising providers to see how to implement the methods. + +### For Token providers + +```typescript +import { ArticleProvider } from '@gitroom/nestjs-libraries/integrations/article/article.integrations.interface'; + +export class DevToProvider implements ArticleProvider { + identifier = 'providerName'; + name = 'ProviderName'; + async authenticate(token: string) { + + } + + async post(token: string, content: string, settings: DTOClassName) { + + } +} +``` + +### Custom functions +You might want to create custom functions for the providers for example: get available orgs, get available pages, etc.
    +You can create a public function in the provider for example `organizations` and later call it from a special hook from the frontend. + +### Integration Manager +Open `libraries/nestjs-libraries/src/integrations/integration.manager.ts` +And add the new provider to either `socialIntegrationList` (oAuth2) or `articleIntegrationList` (Token) + +--- + +### Frontend + +1. Head over to `apps/frontend/src/components/launches/providers` +Create a new folder with the providerName
    +Add a new file `providerName.provider.tsx`
    +The content of the file should look like this: + +```typescript +import { FC } from 'react'; +import { withProvider } from '@gitroom/frontend/components/launches/providers/high.order.provider'; +import { useSettings } from '@gitroom/frontend/components/launches/helpers/use.values'; +import { useIntegration } from '@gitroom/frontend/components/launches/helpers/use.integration'; + +const ProviderPreview: FC = () => { + const { value } = useIntegration(); + const settings = useSettings(); + + return ( + ...Preview + ); +}; + +const ProviderSettings: FC = () => { + const form = useSettings(); + const { date } = useIntegration(); + return ( + ...Settings + ); +}; + +export default withProvider(DevtoSettings, DevtoPreview, DTOClassName); +``` + +If you want to use a custom function for the provider you can use the `useCustomProviderFunction` hook. + +```typescript +import { useCustomProviderFunction } from '@gitroom/frontend/components/launches/helpers/use.custom.provider.function'; +import { useCallback } from 'react'; +const customFunc = useCustomProviderFunction(); + +// and use it like that: +const getOrgs = useCallback(() => { + customFunc.get('organizations', { + anyKey: 'anyValue' + }) +}, []); +``` + +It will automatically interact with the right provider saved for the user. + +You can look at the other integration to understand what data to put inside. + +2. Open `apps/frontend/src/components/launches/providers/show.all.providers.tsx` +And add the new provider to the list. +```typescript + {identifier: 'providerName', component: DefaultImportFromHighOrderProvider}, +``` \ No newline at end of file diff --git a/apps/docs/providers/linkedin/linkedin.mdx b/apps/docs/providers/linkedin/linkedin.mdx new file mode 100644 index 00000000..0bba5cb9 --- /dev/null +++ b/apps/docs/providers/linkedin/linkedin.mdx @@ -0,0 +1,20 @@ +--- +title: Linkedin +description: How to add Linkedin to your system +--- + +Head over to [Linkedin developers](https://www.linkedin.com/developers/apps) and create a new app. +![Linkedin](/images/providers/linkedin/linkedin-001.png) + +Fill in all the details, once created head over to Products and make sure you add all the required products. +![Linkedin](/images/providers/linkedin/linkedin-002.png) + +It is important to have the special permissions or you will not have the ability to refresh your tokens. + +Make sure your redirect URL is set to `http://localhost:4200/integrations/social/linkedin` for local development. +Copy the created `Client ID` and `Client Secret` and add them to your `.env` file. + +```env +LINKEDIN_CLIENT_ID="" +LINKEDIN_CLIENT_SECRET="" +``` diff --git a/apps/docs/providers/reddit/reddit.mdx b/apps/docs/providers/reddit/reddit.mdx new file mode 100644 index 00000000..95081849 --- /dev/null +++ b/apps/docs/providers/reddit/reddit.mdx @@ -0,0 +1,16 @@ +--- +title: Reddit +description: How to add Reddit to your system +--- + +Head over to [Reddit developers](https://www.reddit.com/prefs/apps) and create a new app. +In the type of app, select `web app` and in the redirect uri, add `http://localhost:4200/integrations/social/reddit`. + +Copy the Reddit client id and client secret and add them to your `.env` file. + +![Reddit](/images/providers/reddit/reddit-001.png) + +```env +REDDIT_CLIENT_ID="" +REDDIT_CLIENT_SECRET="" +``` \ No newline at end of file diff --git a/apps/docs/providers/x/x.mdx b/apps/docs/providers/x/x.mdx new file mode 100644 index 00000000..f9f75d46 --- /dev/null +++ b/apps/docs/providers/x/x.mdx @@ -0,0 +1,33 @@ +--- +title: X +description: How to add X to your system +--- + +X is a bit different.
    +They created an oAuth2 flow, but it works only with Twitter v2 API.
    +But in order to upload pictures to X, you need to use the old Twitter v1 API.
    +So we are going to use the normal oAuth1 flow for that (that supports Twitter v2 also 🤷🏻‍).

    + +Head over the [Twitter developers page](https://developer.twitter.com/en/portal/dashboard) and create a new app.
    +Click to sign-up for a new free account + +![X](/images/providers/x/x-001.png) + +Click to edit the application settings +![X](/images/providers/x/x-002.png) + +The click to set up an authentication flow +![X](/images/providers/x/x-003.png) + +In the App Permission set it to `Read and Write` +In the Type of App set it to `Web App, Automated App or Bot` +In the App Info set the `Callback URI / Redirect URL` to `http://localhost:4200/integrations/social/x` +Save it and go to "Keys and Tokens" tab + +Click on "Regenerate" inside "Consumer Keys" and copy the `API Key` and `API Key Secret`. +Open .env file and add the following: + +```env +X_API_KEY="" +X_API_SECRET="" +``` \ No newline at end of file diff --git a/apps/docs/quickstart.mdx b/apps/docs/quickstart.mdx index 00e81459..3770b8fb 100644 --- a/apps/docs/quickstart.mdx +++ b/apps/docs/quickstart.mdx @@ -3,17 +3,22 @@ title: 'Quickstart' --- ## Prerequisites + To run the project you need to have multiple things: + - Node.js (version 18+) - PostgresSQL (or any other SQL database) - Redis - Resend account +- Cloudflare R2 for uploads (optional, can use local machine) - Social Media Client and Secret (more details later) -### NodeJS +### NodeJS (version 18+) + A complete guide of how to install NodeJS can be found [here](https://nodejs.org/en/download/). -### PostgresSQL +### PostgresSQL (or any other SQL database) + Make sure you have PostgreSQL installed on your machine.
    If you don't, you can install [Docker](https://www.docker.com/products/docker-desktop) and run: @@ -21,69 +26,51 @@ If you don't, you can install [Docker](https://www.docker.com/products/docker-de docker run -e POSTGRES_USER=root -e POSTGRES_PASSWORD=your_password --name postgres -p 5432:5432 -d postgres ``` -### Discord client id and token -Head over to the [Discord Developer Portal](https://discord.com/developers/applications) and create a new application.
    -After that, go to the bot tab and create a new bot.
    -Save the token and client id for later. +### Redis -### Vercel Blob Store -Head over to the [Vercel Blob Store](https://vercel.com/dashboard/stores) and create a new database.
    -Choose Blob (currently in beta) and save the token for later. +Make sure you have Redis installed on your machine.
    +If you don't, you can install [Docker](https://www.docker.com/products/docker-desktop) and run: -### Vercel Project ID, Team ID and Token - -1. Create a new Vercel empty project. -2. Head over to Vercel teams settings, scroll down to "Team ID" copy the id and save it for later. -3. Head over to Vercel project settings, scroll down to "Project ID" copy the id and save it for later. -4. Head over to Vercel account settings, scroll down to "Tokens" and create a new token, copy the token and save it for later. - -### Stripe account - -If you don't provide the Stripe `PAYMENT_PUBLIC_KEY`, you will be automatically granted all the features without limitations. - -1. Register a new account on [Stripe](https://stripe.com/).
    -2. Head over to the [Stripe API keys](https://dashboard.stripe.com/test/apikeys) and copy the Publishable and Secret key, save it for later. -3. Head over to the [Stripe Webhooks](https://dashboard.stripe.com/test/webhooks) and create a new local webhook.
    -Copy the token and save it for later. - -### OpenAI API key -Create a new [OpenAI](https://platform.openai.com) account, head over to the [API keys](https://platform.openai.com/api-keys), copy the key, and save it for later. - -### Algolia account -Create a new [Algolia](https://www.algolia.com/) account, head over to the [API keys](https://www.algolia.com/api-keys), copy the APP ID, Search Key, and Admin API Key, and save it for later. +```bash +docker run --name redis -p 6379:6379 -d redis +``` ## Installation ### Clone the repository ```bash -git clone https://github.com/github-20k/Gitroom +git clone https://github.com/gitroomhq/gitroom ``` ### Copy environment variables + Copy the `.env.example` file to `.env` and fill in the values ```bash -DISCORD_CLIENT= -DISCORD_TOKEN= -DATABASE_URL=postgres://root:your_password@localhost:5432/Gitroom -BACKEND_URL=http://localhost:3000 -NEXT_PUBLIC_BACKEND_URL=http://localhost:3000 -BACKEND_TOKEN_PROTECTOR= -OPENAI_API_KEY= -JWT_SECRET= -FRONTEND_URL=http://localhost:4200 -BLOB_READ_WRITE_TOKEN= -PROJECT_ID_VERCEL= -TEAM_ID_VERCEL= -PAYMENT_PUBLIC_KEY= -PAYMENT_SECRET_KEY= -PAYMENT_SIGNING_SECRET= -MARKETING_WEBSITE_URL=http://localhost:4201 -DOCS_URL=https://localhost:3000 -NEXT_PUBLIC_ALGOLIA_APP_ID= -NEXT_PUBLIC_ALGOLIA_SEARCH_KEY= -ALGOLIA_ADMIN_API_KEY= +DATABASE_URL="postgres database URL" +REDIS_URL="redis database URL" +JWT_SECRET="random string for your JWT secret, make it long" +FRONTEND_URL="By default: http://localhost:4200" +NEXT_PUBLIC_BACKEND_URL="By default: http://localhost:3000" +BACKEND_INTERNAL_URL="If you use docker, you might want something like: http://backend:3000" +X_API_KEY="Twitter API key for normal oAuth not oAuth2" +X_API_SECRET="Twitter API secret for normal oAuth not oAuth2" +LINKEDIN_CLIENT_ID="Linkedin Client ID" +LINKEDIN_CLIENT_SECRET="Linkedin Client Secret" +REDDIT_CLIENT_ID="Reddit Client ID" +REDDIT_CLIENT_SECRET="Linkedin Client Secret" +GITHUB_CLIENT_ID="GitHub Client ID" +GITHUB_CLIENT_SECRET="GitHub Client Secret" +RESEND_API_KEY="Resend API KEY" +UPLOAD_DIRECTORY="optional: your upload directory path if you host your files locally" +NEXT_PUBLIC_UPLOAD_STATIC_DIRECTORY="optional: your upload directory slug if you host your files locally" +CLOUDFLARE_ACCOUNT_ID="Cloudflare R2 Account ID" +CLOUDFLARE_ACCESS_KEY="Cloudflare R2 Access Key" +CLOUDFLARE_SECRET_ACCESS_KEY="Cloudflare R2 Secret Access Key" +CLOUDFLARE_BUCKETNAME="Cloudflare R2 Bucket Name" +CLOUDFLARE_BUCKET_URL="Cloudflare R2 Backet URL" +NX_ADD_PLUGINS=false ``` ### Install the dependencies @@ -95,7 +82,7 @@ npm install ### Generate the prisma client and run the migrations ```bash -npm run update-prisma +npm run prisma-db-push ``` ### Run the project @@ -104,3 +91,19 @@ npm run update-prisma npm run dev ``` +You have to follow all the tabs in the "Developers" menu to install Gitroom + + + + Learn the architecture of the project + + + Set up email for notifications + + + Set up github for authentication and sync + + + Set up providers such as Linkedin, X and Reddit + +