├── achievements
├── .gitignore
├── src
│ ├── dev-tools
│ │ ├── utils.ts
│ │ └── mocks.ts
│ ├── achievement.abstract.ts
│ ├── __snapshots__
│ │ ├── use-github-bot.achievement.spec.ts.snap
│ │ ├── member.achievement.spec.ts.snap
│ │ ├── cutting-edges.achievement.spec.ts.snap
│ │ ├── optimus-prime.achievement.spec.ts.snap
│ │ ├── label-baby-junior.achievement.spec.ts.snap
│ │ ├── the-godfather-consigliere.achievement.spec.ts.snap
│ │ ├── mr-miyagi.achievement.spec.ts.snap
│ │ ├── never-go-full-retard.achievement.spec.ts.snap
│ │ ├── double-review.achievement.spec.ts.snap
│ │ └── dont-yell-at-me.achievement.spec.ts.snap
│ ├── label-baby-junior.achievement.ts
│ ├── cutting-edges.achievement.ts
│ ├── member.achievement.spec.ts
│ ├── use-github-bot.achievement.ts
│ ├── member.achievement.ts
│ ├── the-godfather-consigliere.achievement.ts
│ ├── index.ts
│ ├── double-review.achievement.ts
│ ├── use-github-bot.achievement.spec.ts
│ ├── bi-winning.achievement.ts
│ └── reaction-on-every-comment.achievement.ts
└── tsconfig.json
├── client
├── src
│ ├── assets
│ │ ├── .gitkeep
│ │ ├── favicon.ico
│ │ ├── all-new-rpg.png
│ │ ├── layers
│ │ │ ├── sky.png
│ │ │ ├── trees.png
│ │ │ ├── mountains.png
│ │ │ ├── far-clouds.png
│ │ │ ├── near-clouds.png
│ │ │ └── far-mountains.png
│ │ ├── logo-more-details.png
│ │ ├── private.svg
│ │ └── public.svg
│ ├── app
│ │ ├── pages
│ │ │ ├── organizations
│ │ │ │ ├── organizations.component.scss
│ │ │ │ ├── organizations.component.html
│ │ │ │ ├── organizations-all
│ │ │ │ │ ├── organizations-all.component.scss
│ │ │ │ │ └── organizations-all.component.spec.ts
│ │ │ │ ├── organizations.component.ts
│ │ │ │ ├── org-by-name-resolver.ts
│ │ │ │ ├── organizations.component.spec.ts
│ │ │ │ ├── organization-profile
│ │ │ │ │ ├── organization-profile.component.spec.ts
│ │ │ │ │ └── organization-profile.component.html
│ │ │ │ └── organizations.routes.ts
│ │ │ ├── pull-requests
│ │ │ │ ├── pull-requests.component.scss
│ │ │ │ ├── pull-request-profile
│ │ │ │ │ ├── pull-request-profile.component.scss
│ │ │ │ │ ├── pull-request-profile.component.html
│ │ │ │ │ ├── pull-request-profile.component.ts
│ │ │ │ │ └── pull-request-profile.component.spec.ts
│ │ │ │ ├── pull-request-all
│ │ │ │ │ ├── pull-request-all.component.scss
│ │ │ │ │ └── pull-request-all.component.spec.ts
│ │ │ │ ├── pull-requests.component.html
│ │ │ │ ├── pull-requests.component.ts
│ │ │ │ ├── pr-by-id-resolver.ts
│ │ │ │ ├── pull-requests.component.spec.ts
│ │ │ │ └── pull-requests.routes.ts
│ │ │ ├── repositories
│ │ │ │ ├── repositories.component.scss
│ │ │ │ ├── repositories.component.html
│ │ │ │ ├── repositories-all
│ │ │ │ │ ├── repositories-all.component.scss
│ │ │ │ │ └── repositories-all.component.spec.ts
│ │ │ │ ├── repositories.component.ts
│ │ │ │ ├── repo-by-fullname-resolver.ts
│ │ │ │ ├── repositories.component.spec.ts
│ │ │ │ ├── repository-profile
│ │ │ │ │ ├── repository-profile.component.spec.ts
│ │ │ │ │ └── repository-profile.component.html
│ │ │ │ └── repositories.routes.ts
│ │ │ ├── user-profile
│ │ │ │ ├── profile-settings
│ │ │ │ │ ├── profile-settings.component.scss
│ │ │ │ │ ├── profile-settings.component.spec.ts
│ │ │ │ │ └── profile-settings.component.html
│ │ │ │ ├── profile-integrations
│ │ │ │ │ ├── profile-integrations.component.scss
│ │ │ │ │ └── profile-integrations.component.spec.ts
│ │ │ │ ├── profile-overview
│ │ │ │ │ ├── profile-overview.component.scss
│ │ │ │ │ ├── profile-overview.component.html
│ │ │ │ │ ├── profile-overview.component.ts
│ │ │ │ │ └── profile-overview.component.spec.ts
│ │ │ │ ├── user-profile.service.spec.ts
│ │ │ │ ├── user-profile.component.spec.ts
│ │ │ │ ├── user-profile.component.ts
│ │ │ │ ├── user-profile.component.html
│ │ │ │ └── user-profile.routes.ts
│ │ │ ├── users
│ │ │ │ ├── users.component.scss
│ │ │ │ ├── users-all
│ │ │ │ │ ├── users-all.component.scss
│ │ │ │ │ └── users-all.component.spec.ts
│ │ │ │ ├── users.component.html
│ │ │ │ ├── users.component.ts
│ │ │ │ ├── user-by-username-resolver.ts
│ │ │ │ ├── users.component.spec.ts
│ │ │ │ ├── user-profile
│ │ │ │ │ ├── user-profile.component.spec.ts
│ │ │ │ │ └── user-profile.component.html
│ │ │ │ └── users.routes.ts
│ │ │ ├── app-status
│ │ │ │ ├── app-status.routes.ts
│ │ │ │ ├── app-status.component.scss
│ │ │ │ ├── app-status.component.spec.ts
│ │ │ │ └── app-status.component.ts
│ │ │ └── home
│ │ │ │ ├── home.component.html
│ │ │ │ └── home.component.spec.ts
│ │ ├── shared
│ │ │ ├── user-lives
│ │ │ │ ├── user-lives.component.scss
│ │ │ │ ├── user-lives.component.html
│ │ │ │ ├── user-lives.component.spec.ts
│ │ │ │ └── user-lives.component.ts
│ │ │ ├── minidenticon-avatar
│ │ │ │ ├── minidenticon-avatar.component.scss
│ │ │ │ ├── minidenticon-avatar.component.html
│ │ │ │ ├── minidenticon-avatar.component.ts
│ │ │ │ └── minidenticon-avatar.component.spec.ts
│ │ │ ├── achievement
│ │ │ │ ├── achievement.component.scss
│ │ │ │ ├── achievement.component.html
│ │ │ │ ├── fade-in-up.animation.ts
│ │ │ │ └── achievement.component.spec.ts
│ │ │ ├── pipes
│ │ │ │ ├── first-error.pipe.spec.ts
│ │ │ │ └── first-error.pipe.ts
│ │ │ ├── directives
│ │ │ │ ├── has-role.directive.spec.ts
│ │ │ │ ├── back-button.directive.spec.ts
│ │ │ │ ├── back-button.directive.ts
│ │ │ │ └── has-role.directive.ts
│ │ │ ├── header
│ │ │ │ ├── header.component.scss
│ │ │ │ └── header.component.spec.ts
│ │ │ ├── achievement-one-love
│ │ │ │ ├── achievement-one-love.component.html
│ │ │ │ ├── achievement-one-love.component.ts
│ │ │ │ ├── achievement-one-love.component.scss
│ │ │ │ └── achievement-one-love.component.spec.ts
│ │ │ ├── an-achievement
│ │ │ │ ├── an-achievement.component.ts
│ │ │ │ └── an-achievement.component.spec.ts
│ │ │ ├── guards
│ │ │ │ ├── role.guard.spec.ts
│ │ │ │ ├── active-user.guard.spec.ts
│ │ │ │ ├── role.guard.ts
│ │ │ │ └── active-user.guard.ts
│ │ │ ├── achievibit-logo
│ │ │ │ ├── achievibit-logo.component.html
│ │ │ │ ├── achievibit-logo.component.spec.ts
│ │ │ │ └── achievibit-logo.component.scss
│ │ │ └── mini-game
│ │ │ │ ├── mini-game.component.html
│ │ │ │ ├── mini-game.component.spec.ts
│ │ │ │ └── mini-game.component.scss
│ │ ├── app.component.scss
│ │ ├── app.service.ts
│ │ ├── app.component.html
│ │ ├── services
│ │ │ ├── active-user-resolver.ts
│ │ │ ├── loader.service.ts
│ │ │ ├── api
│ │ │ │ ├── api.service.spec.ts
│ │ │ │ └── general.service.ts
│ │ │ ├── auth.service.spec.ts
│ │ │ ├── loader.service.spec.ts
│ │ │ └── auth.service.ts
│ │ ├── app.service.spec.ts
│ │ ├── auth.interceptor.spec.ts
│ │ ├── app.config.ts
│ │ ├── app.component.spec.ts
│ │ └── app.routes.ts
│ ├── environments
│ │ ├── environment.ts
│ │ └── environment.development.ts
│ ├── favicon.ico
│ ├── main.ts
│ └── styles.scss
├── favicon.ico
├── favicon-16x16.png
├── favicon-32x32.png
├── apple-touch-icon.png
├── android-chrome-192x192.png
├── android-chrome-512x512.png
├── .vscode
│ ├── extensions.json
│ ├── launch.json
│ └── tasks.json
├── site.webmanifest
├── tsconfig.app.json
├── tsconfig.spec.json
├── .editorconfig
├── private.svg
├── proxy.conf.json
├── public.svg
├── git-branch-svgrepo-com.svg
├── .gitignore
├── logout-svgrepo-com.svg
├── tsconfig.json
└── README.md
├── server
├── .husky
│ └── pre-commit
├── src
│ ├── migrations
│ │ ├── .gitkeep
│ │ └── index.ts
│ ├── setup-globals.ts
│ ├── models
│ │ ├── authorization
│ │ │ ├── permissions.enum.ts
│ │ │ ├── roles.enum.ts
│ │ │ └── role-permissions.map.ts
│ │ ├── pr-status.enum.ts
│ │ ├── system.enum.ts
│ │ ├── pagination
│ │ │ └── page.model.ts
│ │ ├── api.model.ts
│ │ └── index.ts
│ ├── middleware
│ │ ├── index.ts
│ │ └── logger
│ │ │ └── logger.middleware.spec.ts
│ ├── filters
│ │ ├── index.ts
│ │ └── http-exception
│ │ │ ├── db-exception.filter.spec.ts
│ │ │ └── db-exception.filter.ts
│ ├── openai
│ │ ├── index.ts
│ │ ├── openai.module.ts
│ │ └── openai.service.spec.ts
│ ├── tasks
│ │ ├── index.ts
│ │ ├── tasks.module.ts
│ │ └── tasks.service.spec.ts
│ ├── shields
│ │ ├── index.ts
│ │ ├── shields.module.ts
│ │ ├── shields.service.spec.ts
│ │ └── shields.service.ts
│ ├── users
│ │ ├── index.ts
│ │ ├── users.module.ts
│ │ ├── users.service.spec.ts
│ │ └── users.controller.spec.ts
│ ├── guards
│ │ ├── jwt-auth.guard.ts
│ │ ├── github-auth.guard.ts
│ │ ├── gitlab-auth.guard.ts
│ │ ├── bitbucket-auth.guard.ts
│ │ ├── github-webhook
│ │ │ ├── github-webhook.guard.spec.ts
│ │ │ └── github-webhook.guard.ts
│ │ ├── gitlab-webhook
│ │ │ ├── gitlab-webhook.guard.spec.ts
│ │ │ └── gitlab-webhook.guard.ts
│ │ ├── bitbucket-webhook
│ │ │ ├── bitbucket-webhook.guard.spec.ts
│ │ │ └── bitbucket-webhook.guard.ts
│ │ ├── disable-in-production
│ │ │ ├── disable-in-production.guard.spec.ts
│ │ │ └── disable-in-production.guard.ts
│ │ ├── index.ts
│ │ └── jwt-auth-optional.guard.ts
│ ├── health
│ │ ├── index.ts
│ │ ├── health.controller.spec.ts
│ │ └── health.module.ts
│ ├── repositories
│ │ ├── index.ts
│ │ ├── repositories.service.spec.ts
│ │ ├── repositories.controller.spec.ts
│ │ └── repositories.module.ts
│ ├── session-user
│ │ ├── index.ts
│ │ ├── session-user.service.spec.ts
│ │ ├── session-user.controller.spec.ts
│ │ └── session-user.module.ts
│ ├── organizations
│ │ ├── index.ts
│ │ ├── organizations.module.ts
│ │ ├── organizations.service.spec.ts
│ │ └── organizations.controller.spec.ts
│ ├── pull-requests
│ │ ├── index.ts
│ │ ├── pull-requests.module.ts
│ │ ├── pull-requests.service.spec.ts
│ │ └── pull-requests.controller.spec.ts
│ ├── config
│ │ ├── smee
│ │ │ ├── webhooks-capture
│ │ │ │ └── github-webhook-mock.type.ts
│ │ │ └── smee.service.spec.ts
│ │ ├── index.ts
│ │ └── __mocks__
│ │ │ └── config.service.ts
│ ├── events
│ │ ├── index.ts
│ │ ├── events.module.ts
│ │ ├── events.service.spec.ts
│ │ ├── events.gateway.spec.ts
│ │ ├── mini-games
│ │ │ └── mini-games.gateway.spec.ts
│ │ └── events.service.ts
│ ├── webhooks
│ │ ├── index.ts
│ │ ├── webhooks.module.ts
│ │ ├── webhooks.service.spec.ts
│ │ ├── webhooks.controller.spec.ts
│ │ └── engines
│ │ │ └── github.event.ts
│ ├── systems
│ │ ├── index.ts
│ │ ├── github
│ │ │ └── github.service.spec.ts
│ │ ├── gitlab
│ │ │ └── gitlab.service.spec.ts
│ │ ├── bitbucket
│ │ │ └── bitbucket.service.spec.ts
│ │ └── systems.module.ts
│ ├── decorators
│ │ ├── index.ts
│ │ ├── disable-in-production.decorator.ts
│ │ ├── is-safe-query.decorator.ts
│ │ ├── api-ok-response-paginated.decorator.ts
│ │ └── req-user.decorator.ts
│ ├── __snapshots__
│ │ └── app.controller.spec.ts.snap
│ ├── data-source.ts
│ ├── auth
│ │ ├── jwt
│ │ │ ├── jwt.service.spec.ts
│ │ │ ├── jwt.module.ts
│ │ │ ├── jwt.service.ts
│ │ │ └── jwt.strategy.ts
│ │ ├── auth.controller.spec.ts
│ │ ├── github
│ │ │ ├── github.module.ts
│ │ │ └── github.controller.spec.ts
│ │ ├── gitlab
│ │ │ ├── gitlab.module.ts
│ │ │ └── gitlab.controller.spec.ts
│ │ ├── bitbucket
│ │ │ ├── bitbucket.module.ts
│ │ │ └── bitbucket.controller.spec.ts
│ │ ├── index.ts
│ │ ├── auth.controller.ts
│ │ └── auth.module.ts
│ ├── custom-socket-io.adapter.ts
│ ├── app.controller.spec.ts
│ └── logo.ts
├── .dockerignore
├── achieveebeet.mp3
├── achieveebit.mp3
├── achieve-a-bit.mp3
├── client
│ ├── favicon.ico
│ └── index.html
├── login-app
│ ├── favicon.ico
│ ├── favicon-16x16.png
│ ├── favicon-32x32.png
│ ├── apple-touch-icon.png
│ ├── android-chrome-192x192.png
│ ├── android-chrome-512x512.png
│ ├── site.webmanifest
│ ├── private.svg
│ ├── public.svg
│ ├── git-branch-svgrepo-com.svg
│ └── logout-svgrepo-com.svg
├── tsconfig.build.json
├── nest-cli.json
├── test
│ ├── jest-e2e.json
│ └── app.e2e-spec.ts
├── .editorconfig
├── commitlint.config.js
├── scripts
│ ├── to-env.ts
│ └── migration-create.ts
├── .devcontainer
│ ├── Dockerfile
│ └── docker-compose.yml
└── .gitignore
├── .dockerignore
├── sdk
├── src
│ ├── rxjsify
│ │ └── index.ts
│ ├── decorators
│ │ └── index.ts
│ ├── sockets
│ │ ├── index.ts
│ │ ├── base-event-map.type.ts
│ │ └── server-to-client.events.ts
│ └── generated
│ │ ├── index.ts
│ │ └── SocketIo.ts
├── index.ts
├── tsconfig.json
└── package.json
├── .eslintignore
├── screenshots
├── tour-terminal-client-prefix.png
├── tour-terminal-secrets-error.png
└── tour-terminal-server-prefix.png
├── angular-sdk-options.json
├── plugins
└── eslint-plugin-attribute-formatting
│ ├── index.js
│ └── package.json
├── .vscode
└── extensions.json
├── pnpm-workspace.yaml
├── docker-compose.yml
├── .github
└── workflows
│ └── playwright.yml
├── .devcontainer
└── docker-compose.dev.yml
└── .gitignore
/achievements/.gitignore:
--------------------------------------------------------------------------------
1 | lib
--------------------------------------------------------------------------------
/client/src/assets/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/server/.husky/pre-commit:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/server/src/migrations/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/server/.dockerignore:
--------------------------------------------------------------------------------
1 | # ignore node_modules
2 | node_modules
--------------------------------------------------------------------------------
/client/src/app/pages/organizations/organizations.component.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/client/src/app/pages/pull-requests/pull-requests.component.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/client/src/app/pages/repositories/repositories.component.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/server/src/setup-globals.ts:
--------------------------------------------------------------------------------
1 | jest.mock('./config/config.service');
--------------------------------------------------------------------------------
/client/src/environments/environment.ts:
--------------------------------------------------------------------------------
1 | export const environment = {};
2 |
--------------------------------------------------------------------------------
/client/src/app/pages/user-profile/profile-settings/profile-settings.component.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/client/src/environments/environment.development.ts:
--------------------------------------------------------------------------------
1 | export const environment = {};
2 |
--------------------------------------------------------------------------------
/client/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kibibit/achievibit-v3/main/client/favicon.ico
--------------------------------------------------------------------------------
/client/src/app/pages/pull-requests/pull-request-profile/pull-request-profile.component.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/client/src/app/pages/user-profile/profile-integrations/profile-integrations.component.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/client/src/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kibibit/achievibit-v3/main/client/src/favicon.ico
--------------------------------------------------------------------------------
/server/achieveebeet.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kibibit/achievibit-v3/main/server/achieveebeet.mp3
--------------------------------------------------------------------------------
/server/achieveebit.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kibibit/achievibit-v3/main/server/achieveebit.mp3
--------------------------------------------------------------------------------
/.dockerignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | dist
3 | .git
4 | Dockerfile
5 | .github
6 | .env*
7 | **/*private-key.pem
--------------------------------------------------------------------------------
/client/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kibibit/achievibit-v3/main/client/favicon-16x16.png
--------------------------------------------------------------------------------
/client/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kibibit/achievibit-v3/main/client/favicon-32x32.png
--------------------------------------------------------------------------------
/client/src/app/pages/users/users.component.scss:
--------------------------------------------------------------------------------
1 | :host {
2 | display: block;
3 | min-height: 100%;
4 | }
--------------------------------------------------------------------------------
/server/achieve-a-bit.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kibibit/achievibit-v3/main/server/achieve-a-bit.mp3
--------------------------------------------------------------------------------
/server/client/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kibibit/achievibit-v3/main/server/client/favicon.ico
--------------------------------------------------------------------------------
/client/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kibibit/achievibit-v3/main/client/apple-touch-icon.png
--------------------------------------------------------------------------------
/server/login-app/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kibibit/achievibit-v3/main/server/login-app/favicon.ico
--------------------------------------------------------------------------------
/client/src/app/pages/users/users-all/users-all.component.scss:
--------------------------------------------------------------------------------
1 | :host {
2 | display:block;
3 | padding: 1em;
4 | }
--------------------------------------------------------------------------------
/client/src/assets/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kibibit/achievibit-v3/main/client/src/assets/favicon.ico
--------------------------------------------------------------------------------
/client/android-chrome-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kibibit/achievibit-v3/main/client/android-chrome-192x192.png
--------------------------------------------------------------------------------
/client/android-chrome-512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kibibit/achievibit-v3/main/client/android-chrome-512x512.png
--------------------------------------------------------------------------------
/client/src/app/pages/users/users.component.html:
--------------------------------------------------------------------------------
1 |
pull-request-profile works!
2 | -------------------------------------------------------------------------------- /client/src/assets/layers/mountains.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kibibit/achievibit-v3/main/client/src/assets/layers/mountains.png -------------------------------------------------------------------------------- /server/login-app/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kibibit/achievibit-v3/main/server/login-app/apple-touch-icon.png -------------------------------------------------------------------------------- /server/src/models/authorization/permissions.enum.ts: -------------------------------------------------------------------------------- 1 | export enum Permission { 2 | VIEW_PULL_REQUESTS = 'view:pull-requests' 3 | } -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | **/.storybook/**/* 2 | **/tester-app/**/* 3 | **/dist/**/* 4 | **/.eslintrc.js 5 | # server/** 6 | plugins/** 7 | **/lib/**/* -------------------------------------------------------------------------------- /client/src/app/pages/organizations/organizations.component.html: -------------------------------------------------------------------------------- 1 |
11 | You have contributed to Kibibit! We really appreciate it!
Accept this achievement as gift on my daughter's wedding day
", 7 | "name": "The Godfather Consigliere", 8 | "relatedPullRequest": "test", 9 | "short": "Great men are not born great, they contribute to Kibibit . . .", 10 | } 11 | `; 12 | -------------------------------------------------------------------------------- /server/src/session-user/session-user.controller.spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | 3 | import { SessionUserController } from './session-user.controller'; 4 | 5 | describe('SessionUserController', () => { 6 | let controller: SessionUserController; 7 | 8 | beforeEach(async () => { 9 | const module: TestingModule = await Test.createTestingModule({ 10 | controllers: [ SessionUserController ] 11 | }).compile(); 12 | 13 | controller = module.getTest your skills in this mini game!
7 |You have contributed to Kibibit! We really ', 15 | 'appreciate it!
', 16 | 'Accept this achievement as gift on ', 17 | 'my daughter\'s wedding day
' 18 | ].join(''), 19 | relatedPullRequest: pullRequest.id 20 | }; 21 | 22 | shall.grant(pullRequest.creator.username, achievement); 23 | } 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /client/src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { AppComponent } from './app.component'; 4 | 5 | describe('AppComponent', () => { 6 | beforeEach(async () => { 7 | await TestBed.configureTestingModule({ 8 | imports: [ AppComponent ] 9 | }).compileComponents(); 10 | }); 11 | 12 | it('should create the app', () => { 13 | const fixture = TestBed.createComponent(AppComponent); 14 | const app = fixture.componentInstance; 15 | expect(app).toBeTruthy(); 16 | }); 17 | 18 | it('should have the \'client\' title', () => { 19 | const fixture = TestBed.createComponent(AppComponent); 20 | const app = fixture.componentInstance; 21 | expect(app.title).toEqual('client'); 22 | }); 23 | 24 | it('should render title', () => { 25 | const fixture = TestBed.createComponent(AppComponent); 26 | fixture.detectChanges(); 27 | const compiled = fixture.nativeElement as HTMLElement; 28 | expect(compiled.querySelector('h1')?.textContent).toContain('Hello, client'); 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /server/src/app.controller.spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | 3 | import { AppController } from './app.controller'; 4 | import { AppService } from './app.service'; 5 | import { SmeeService } from '@kb-config'; 6 | 7 | jest.mock('fs-extra', () => ({ 8 | readJSON: jest.fn().mockResolvedValue({ 9 | name: 'test', 10 | description: 'test', 11 | version: 'test', 12 | license: 'test', 13 | repository: 'test', 14 | }) 15 | })); 16 | 17 | describe('AppController', () => { 18 | let appController: AppController; 19 | 20 | beforeEach(async () => { 21 | const app: TestingModule = await Test.createTestingModule({ 22 | controllers: [ AppController ], 23 | providers: [ 24 | AppService, 25 | SmeeService 26 | ] 27 | }).compile(); 28 | 29 | appController = app.get
8 |
8 |
8 | All the commits in your pull-request have passing statuses! ', 16 | 'WINNING!
', 17 | 'I\'m different. I have a different constitution, I have a ', 18 | 'different brain, I have a different heart. I got tiger blood, man. ', 19 | 'Dying\'s for fools, dying\'s for amateurs.
' 20 | ].join(''), 21 | relatedPullRequest: pullRequest._id 22 | }; 23 | 24 | shall.grant(pullRequest.creator.username, achievement); 25 | } 26 | } 27 | }; 28 | 29 | function allStatusesPassed(commit) { 30 | return !isEmpty(commit.statuses) && 31 | every(commit.statuses, { state: 'success' }); 32 | } 33 | -------------------------------------------------------------------------------- /client/src/app/pages/user-profile/user-profile.routes.ts: -------------------------------------------------------------------------------- 1 | import { Routes } from '@angular/router'; 2 | 3 | import { activeUserResolver } from '../../services/active-user-resolver'; 4 | import { ProfileIntegrationsComponent } from './profile-integrations/profile-integrations.component'; 5 | import { ProfileOverviewComponent } from './profile-overview/profile-overview.component'; 6 | import { ProfileSettingsComponent } from './profile-settings/profile-settings.component'; 7 | import { UserProfileComponent } from './user-profile.component'; 8 | 9 | export const userProfileRoutes: Routes = [ 10 | { 11 | path: 'profile', 12 | component: UserProfileComponent, 13 | children: [ 14 | { 15 | path: '', 16 | redirectTo: 'overview', 17 | pathMatch: 'full' 18 | }, 19 | { 20 | path: 'overview', 21 | component: ProfileOverviewComponent, 22 | resolve: { user: activeUserResolver } 23 | }, 24 | { 25 | path: 'integrations', 26 | component: ProfileIntegrationsComponent, 27 | resolve: { user: activeUserResolver } 28 | }, 29 | { 30 | path: 'settings', 31 | component: ProfileSettingsComponent, 32 | resolve: { user: activeUserResolver } 33 | } 34 | ] 35 | } 36 | ]; 37 | -------------------------------------------------------------------------------- /achievements/src/__snapshots__/dont-yell-at-me.achievement.spec.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`dontYellAtMe achievement should be granted to PR creator if both reasons 1`] = ` 4 | { 5 | "avatar": "images/achievements/dontYellAtMe.achievement.jpg", 6 | "description": "You've used ALL CAPS and 3 or more exclamation marks in your Pull Request title", 7 | "name": "Don't Yell At Me!!!", 8 | "relatedPullRequest": "test", 9 | "short": "I don't know what we're yelling about", 10 | } 11 | `; 12 | 13 | exports[`dontYellAtMe achievement should be granted to PR creator if more than 2 '!' 1`] = ` 14 | { 15 | "avatar": "images/achievements/dontYellAtMe.achievement.jpg", 16 | "description": "You've used 3 or more exclamation marks in your Pull Request title", 17 | "name": "Don't Yell At Me!!!", 18 | "relatedPullRequest": "test", 19 | "short": "I don't know what we're yelling about", 20 | } 21 | `; 22 | 23 | exports[`dontYellAtMe achievement should be granted to PR creator if title is all caps 1`] = ` 24 | { 25 | "avatar": "images/achievements/dontYellAtMe.achievement.jpg", 26 | "description": "You've used ALL CAPS in your Pull Request title", 27 | "name": "Don't Yell At Me!!!", 28 | "relatedPullRequest": "test", 29 | "short": "I don't know what we're yelling about", 30 | } 31 | `; 32 | -------------------------------------------------------------------------------- /server/src/auth/jwt/jwt.strategy.ts: -------------------------------------------------------------------------------- 1 | import { Request } from 'express'; 2 | import { ExtractJwt, Strategy } from 'passport-jwt'; 3 | 4 | import { Injectable, UnauthorizedException } from '@nestjs/common'; 5 | import { PassportStrategy } from '@nestjs/passport'; 6 | 7 | import { configService } from '@kb-config'; 8 | import { UsersService } from '@kb-users'; 9 | 10 | @Injectable() 11 | export class JwtStrategy extends PassportStrategy(Strategy) { 12 | constructor( 13 | private readonly usersService: UsersService 14 | ) { 15 | super({ 16 | jwtFromRequest: ExtractJwt.fromExtractors([ 17 | JwtStrategy.extractJWT, 18 | ExtractJwt.fromAuthHeaderAsBearerToken() 19 | ]), 20 | ignoreExpiration: false, 21 | secretOrKey: configService.config.JWT_SECRET 22 | }); 23 | } 24 | 25 | async validate(payload: any) { 26 | const dbUser = await this.usersService.findOne(payload.username); 27 | if (!dbUser) { 28 | throw new UnauthorizedException(); 29 | } 30 | 31 | return dbUser; 32 | } 33 | 34 | private static extractJWT(req: Request): string | null { 35 | if ( 36 | req.cookies && 37 | 'kibibit-jwt' in req.cookies && 38 | req.cookies['kibibit-jwt'].length > 0 39 | ) { 40 | return req.cookies['kibibit-jwt']; 41 | } 42 | return null; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /achievements/src/reaction-on-every-comment.achievement.ts: -------------------------------------------------------------------------------- 1 | import { every, get, isArray } from 'lodash'; 2 | 3 | import { IAchievement } from './achievement.abstract'; 4 | 5 | export const reactionOnEveryComment: IAchievement = { 6 | name: 'Royal Flush', 7 | check: function(pullRequest, shall) { 8 | const doesCommentsExist = 9 | get(pullRequest.inlineComments, 'length') > 0 || 10 | get(pullRequest.comments, 'length') > 0; 11 | const isReactionOnEverything = 12 | every(pullRequest.inlineComments, haveReactions) && 13 | every(pullRequest.comments, haveReactions) && 14 | every([ pullRequest ], haveReactions); 15 | 16 | if (doesCommentsExist && isReactionOnEverything) { 17 | shall.grant(pullRequest.creator.username, { 18 | avatar: 'images/achievements/reactionOnEveryComment.achievement.png', 19 | name: 'royal flush', 20 | short: 'emojis on all of the comments', 21 | description: [ 22 | 'got for having at least one comment\\inline comment, ', 23 | 'and all of them (including the PR description) had reactions' 24 | ].join(''), 25 | relatedPullRequest: pullRequest.id 26 | }); 27 | } 28 | } 29 | }; 30 | 31 | function haveReactions(comment) { 32 | return isArray(comment.reactions) && 33 | get(comment.reactions, 'length') !== 0; 34 | } 35 | -------------------------------------------------------------------------------- /server/scripts/migration-create.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ts-node 2 | 3 | import { execSync } from 'child_process'; 4 | 5 | import { bgRed, blue, green } from 'colors'; 6 | import { readdirSync } from 'fs-extra'; 7 | 8 | const migrationName = process.argv[2]; 9 | 10 | if (!migrationName) { 11 | console.error('Please provide a migration name.'); 12 | process.exit(1); 13 | } 14 | 15 | const command = `npm run typeorm migration:create src/migrations/${ migrationName }`; 16 | 17 | try { 18 | execSync(command, { stdio: 'inherit' }); 19 | const generatedMigration = findGeneratedMigration(migrationName); 20 | const lintCreatedMigration = `npm run lint:fix src/migrations/${ generatedMigration }`; 21 | execSync(lintCreatedMigration, { stdio: null }); 22 | console.log(green(`Migration ${ blue('linted') } successfully.`)); 23 | } catch (error) { 24 | console.error(bgRed.white('Error creating migration:')); 25 | console.error(error); 26 | process.exit(1); 27 | } 28 | 29 | function findGeneratedMigration(migrationName: string) { 30 | const migrationFolderContent = readdirSync('src/migrations'); 31 | const migrationFile = migrationFolderContent.find((file) => file.endsWith(`-${ migrationName }.ts`)); 32 | 33 | if (!migrationFile) { 34 | console.error('Could not find the generated migration file.'); 35 | process.exit(1); 36 | } 37 | 38 | return migrationFile; 39 | } 40 | --------------------------------------------------------------------------------