Skip to content

Commit

Permalink
Challonge Integration
Browse files Browse the repository at this point in the history
This PR introduces the following new routes:
- [X] `/seasons/challonge` POST call - requires a `tournament_id` and `import_teams`. Tournament ID is defined as per [Challonge's API](https://api.challonge.com/v1/documents/tournaments/show)
- [x] `/teams/challonge` POST call - allows a user to import teams from a tournament ID if it was missed on the initial import. This will import _all_ teams again, so be warned. You either want to import them during the season import, or after. Not both.
- [x] Additional features in the map and series finalizing calls to auto-update the Challonge bracket.
- [X] Update scores in the bracket on each round if a BO1, or update map scores if BO3/5/7
- [X] Update the matches route to include a pagination call for matches.
- [X] Close out a season when matches are all played out.

There are a few new database table adjustments as well:
- [X] Users now have a `challonge_api` field in the table. Individual users can have their own API keys, allowing for multiple users on a single panel to use their own API key. This is stored and encrypted.
- [X] Boolean value for telling if a season was imported from Challonge in the season table.
- [X] String value that stores the URL of the bracket's SVG, allowing it to be implemented on a front end without having to call Challonge every time.
- [X] Teams now have an Int value stored in the table as well to show if it is a team brought in by Challonge or not. Used by challonge calls only, so it shouldn't have to be made public at all.
- [x] End a season when the last match is completed.

And some minor test adjustments:
- [X] Include a global teardown for each Jest test, so we don't have open handles and are able to close the tests successfully without forcing an exit.

All these changes are also reflected in the API documentation as well.

Please note this is only the API right now, and the front end may come shortly once this has been tested and implemented. Closes #175
  • Loading branch information
PhlexPlexico authored Apr 4, 2022
2 parents c07bbb0 + 33bd625 commit 91982bb
Show file tree
Hide file tree
Showing 25 changed files with 1,359 additions and 991 deletions.
3 changes: 3 additions & 0 deletions .github/FUNDING.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# These are supported funding model platforms

ko_fi: phlexplexico
patreon: phlexplexico
github: phlexplexico
custom: https://steamcommunity.com/tradeoffer/new/?partner=65378466&token=G3t4Gn5V
22 changes: 16 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
# G5API - API Backend for Get5
# G5API - A Tournament Management API Backend for Get5
_**Status: Under active development.**_

G5API is a replacement for the get5-webpanel. This is the backend only, as it will allow the plugin to interface with a database and Steam OAuth, as well as make various calls to functionality that is seen in the [get5-web](https://github.com/phlexplexico/get5-web).
G5API is a replacement for the get5-webpanel. This is the backend only, as it will allow the plugin to interface with a database, Steam OAuth, Local Logins, and API Keys, as well as make various calls to functionality that is seen in the [get5-web](https://github.com/phlexplexico/get5-web).

If you would like a supplemental front-end, please see [Get5Vue](https://github.com/phlexplexico/g5v) or use the [docker-compose](https://github.com/PhlexPlexico/G5API/blob/master/docker-compose.yml) located in the repo!

---

Like The Project? Feel free to sponsor it! Click the Sponsor button on the repo to see all the possible ways of supporting this development!
![Sponsor me](https://phlexplexi.co/sponsor.png)

If you've donated and would like to have your name listed as a sponsor, please message me on Twitter!

---

## What does it do?
G5API is an API that will allow users to create, manage, and control Counter-Strike: Global Offensive matches. Add teams, create matches, and most importantly, track statistics across matches, and create Seasons/Tournaments to track stats within date ranges.
Expand All @@ -17,15 +25,17 @@ Game server interaction will still take place under the `/matches/:match_id` dir

The webapi plugin for this can be downloaded from [here](https://github.com/PhlexPlexico/G5WS) to include the use of vetoes being recorded, as well as demoes being uploaded to the API server once the match is complete.

## What does it NOT do?
There is also Challonge integration within the API. If a user provides a tournament ID to create a season, it will auto-fill a season start date, empty teams, and will auto-update the brackets at the end of each match if the match exists under the Season/Tournament.

# What does it NOT do?
This is simply a back-end to get myself used to JavaScript and Node. You will need a [front end](https://github.com/phlexplexico/g5v) or create something that can make it work!

## Why?
# Why?
[Get5-web](https://github.com/phlexplexico/get5-web) is a now out-dated webpanel, with python2.7 being officially EOL. Being built all on Flask, with ORM (SQLAlchemy), and Jinja2, its tech spans more than a few years old. While it works really well for now, it is becoming increasingly harder to deploy to more modern hardware/software (such as Ubuntu 19) to ensure easy setup.

The intent will to be provide similar functionality with the use of NodeJS and Express, and this API will take care of session authentication as well, via the use of [`passport-steam`](https://github.com/liamcurry/passport-steam), and rcon server commands via [`rcon`](https://github.com/pushrax/node-rcon), as well as more normalization in the database.

## Building
# Building
In order to build this application, I've opted to use [Yarn](https://yarnpkg.com/lang/en/).

First you will need to copy over the ```development/test/production.json.template``` and update any values that are required. These include server values, and database passwords and connections. For more information, please see [configuration](https://github.com/PhlexPlexico/G5API/wiki/Configuration).
Expand Down Expand Up @@ -101,7 +111,7 @@ Steam OAuth will be mocked in order to check if a user is "logged in", and creat

Will *require* `test.json` to exist in projects `config` folder. It will grab the value from `./utility/mockProfile.js` to set it as a `super_admin` temporarily, then remove it after. These tests are mainly meant for CI, and will be the go-to to test if any changes break the application.

## Contribution
# Contribution
If you have a knack for APIs and a penchant for JavaScript, I could always use help! Create a fork of this application, make your changes, and submit a PR. I will be using the [Issues](https://github.com/phlexplexico/G5API/issues) page to track what calls still need to be completed. Even though this project is "complete" in a sense of it does what is on the tin, I wouldn't be opposed to new features or suggestions on how to make the API better!

If you so choose to contribute, please make sure you include documentation for the API calls, as it is how I am keeping track of all the functionality. I'm using [JSDoc](https://devdocs.io/jsdoc/) as well as [Swagger](https://swagger.io) to provide documentation. Please read over some of the files to get accustomed to usage.
Expand Down
3 changes: 0 additions & 3 deletions __test__/users.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,6 @@ describe("Test the user routes", () => {
.expect(302);
return;
});
afterAll(async () => {
await new Promise(resolve => setTimeout(() => resolve(), 500)); // avoid jest open handle error
});
it("Should get 200 from all users", () => {
return request
.get('/users')
Expand Down
2 changes: 1 addition & 1 deletion jest_config/jest.gameservers.config.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ module.exports = {
// globalSetup: undefined,

// A path to a module which exports an async function that is triggered once after all test suites
// globalTeardown: undefined,
globalTeardown: "./test-teardown-globals.cjs",

// A set of global variables that need to be available in all test environments
// globals: {},
Expand Down
2 changes: 1 addition & 1 deletion jest_config/jest.maplist.config.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ module.exports = {
// globalSetup: undefined,

// A path to a module which exports an async function that is triggered once after all test suites
// globalTeardown: undefined,
globalTeardown: "./test-teardown-globals.cjs",

// A set of global variables that need to be available in all test environments
// globals: {},
Expand Down
2 changes: 1 addition & 1 deletion jest_config/jest.mapstats.config.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ module.exports = {
// globalSetup: undefined,

// A path to a module which exports an async function that is triggered once after all test suites
// globalTeardown: undefined,
globalTeardown: "./test-teardown-globals.cjs",

// A set of global variables that need to be available in all test environments
// globals: {},
Expand Down
2 changes: 1 addition & 1 deletion jest_config/jest.matches.config.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ module.exports = {
// globalSetup: undefined,

// A path to a module which exports an async function that is triggered once after all test suites
// globalTeardown: undefined,
globalTeardown: "./test-teardown-globals.cjs",

// A set of global variables that need to be available in all test environments
// globals: {},
Expand Down
2 changes: 1 addition & 1 deletion jest_config/jest.playerstats.config.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ module.exports = {
// globalSetup: undefined,

// A path to a module which exports an async function that is triggered once after all test suites
// globalTeardown: undefined,
globalTeardown: "./test-teardown-globals.cjs",

// A set of global variables that need to be available in all test environments
// globals: {},
Expand Down
2 changes: 1 addition & 1 deletion jest_config/jest.seasons.config.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ module.exports = {
// globalSetup: undefined,

// A path to a module which exports an async function that is triggered once after all test suites
// globalTeardown: undefined,
globalTeardown: "./test-teardown-globals.cjs",

// A set of global variables that need to be available in all test environments
// globals: {},
Expand Down
2 changes: 1 addition & 1 deletion jest_config/jest.teams.config.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ module.exports = {
// globalSetup: undefined,

// A path to a module which exports an async function that is triggered once after all test suites
// globalTeardown: undefined,
globalTeardown: "./test-teardown-globals.cjs",

// A set of global variables that need to be available in all test environments
// globals: {},
Expand Down
2 changes: 1 addition & 1 deletion jest_config/jest.users.config.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ module.exports = {
// globalSetup: undefined,

// A path to a module which exports an async function that is triggered once after all test suites
// globalTeardown: undefined,
globalTeardown: "./test-teardown-globals.cjs",

// A set of global variables that need to be available in all test environments
// globals: {},
Expand Down
2 changes: 1 addition & 1 deletion jest_config/jest.vetoes.config.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ module.exports = {
// globalSetup: undefined,

// A path to a module which exports an async function that is triggered once after all test suites
// globalTeardown: undefined,
globalTeardown: "./test-teardown-globals.cjs",

// A set of global variables that need to be available in all test environments
// globals: {},
Expand Down
2 changes: 1 addition & 1 deletion jest_config/jest.vetosides.config.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ module.exports = {
// globalSetup: undefined,

// A path to a module which exports an async function that is triggered once after all test suites
// globalTeardown: undefined,
globalTeardown: "./test-teardown-globals.cjs",

// A set of global variables that need to be available in all test environments
// globals: {},
Expand Down
4 changes: 4 additions & 0 deletions jest_config/test-teardown-globals.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// Forgive me for this, maybe it's time to rewrite the unit tests.
module.exports = () => {
process.exit(0)
};
39 changes: 39 additions & 0 deletions migrations/development/20220325155055-get5db.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
'use strict';

var dbm;
var type;
var seed;
var async = require('async');

/**
* We receive the dbmigrate dependency from dbmigrate initially.
* This enables us to not have to rely on NODE_PATH.
*/
exports.setup = function(options, seedLink) {
dbm = options.dbmigrate;
type = dbm.dataType;
seed = seedLink;
};

exports.up = function(db, callback) {
async.series([
db.runSql('ALTER TABLE season ADD COLUMN is_challonge boolean AFTER end_date;'),
db.runSql('ALTER TABLE season ADD COLUMN challonge_svg VARCHAR(256) AFTER is_challonge;'),
db.runSql('ALTER TABLE season ADD COLUMN challonge_url VARCHAR(256) AFTER challonge_svg;'),
db.runSql('ALTER TABLE team ADD COLUMN challonge_team_id INT AFTER public_team;'),
db.addColumn('user', 'challonge_api_key', { type: 'string', length: 170, unique: true }),
], callback());
};

exports.down = function(db, callback) {
async.series([
db.removeColumn('season', 'is_challonge'),
db.removeColumn('season', 'challonge_svg'),
db.removeColumn('season', 'challonge_url'),
db.removeColumn('team', 'challonge_team_id'),
db.removeColumn('user', 'challonge_api_key'),
], callback());
};
exports._meta = {
"version": 19
};
39 changes: 39 additions & 0 deletions migrations/production/20220325155055-get5db.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
'use strict';

var dbm;
var type;
var seed;
var async = require('async');

/**
* We receive the dbmigrate dependency from dbmigrate initially.
* This enables us to not have to rely on NODE_PATH.
*/
exports.setup = function(options, seedLink) {
dbm = options.dbmigrate;
type = dbm.dataType;
seed = seedLink;
};

exports.up = function(db, callback) {
async.series([
db.runSql('ALTER TABLE season ADD COLUMN is_challonge boolean AFTER end_date;'),
db.runSql('ALTER TABLE season ADD COLUMN challonge_svg VARCHAR(256) AFTER is_challonge;'),
db.runSql('ALTER TABLE season ADD COLUMN challonge_url VARCHAR(256) AFTER challonge_svg;'),
db.runSql('ALTER TABLE team ADD COLUMN challonge_team_id INT AFTER public_team;'),
db.addColumn('user', 'challonge_api_key', { type: 'string', length: 170, unique: true }),
], callback());
};

exports.down = function(db, callback) {
async.series([
db.removeColumn('season', 'is_challonge'),
db.removeColumn('season', 'challonge_svg'),
db.removeColumn('season', 'challonge_url'),
db.removeColumn('team', 'challonge_team_id'),
db.removeColumn('user', 'challonge_api_key'),
], callback());
};
exports._meta = {
"version": 19
};
39 changes: 39 additions & 0 deletions migrations/test/20220325155055-get5db.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
'use strict';

var dbm;
var type;
var seed;
var async = require('async');

/**
* We receive the dbmigrate dependency from dbmigrate initially.
* This enables us to not have to rely on NODE_PATH.
*/
exports.setup = function(options, seedLink) {
dbm = options.dbmigrate;
type = dbm.dataType;
seed = seedLink;
};

exports.up = function(db, callback) {
async.series([
db.runSql('ALTER TABLE season ADD COLUMN is_challonge boolean AFTER end_date;'),
db.runSql('ALTER TABLE season ADD COLUMN challonge_svg VARCHAR(256) AFTER is_challonge;'),
db.runSql('ALTER TABLE season ADD COLUMN challonge_url VARCHAR(256) AFTER challonge_svg;'),
db.runSql('ALTER TABLE team ADD COLUMN challonge_team_id INT AFTER public_team;'),
db.addColumn('user', 'challonge_api_key', { type: 'string', length: 170, unique: true }),
], callback());
};

exports.down = function(db, callback) {
async.series([
db.removeColumn('season', 'is_challonge'),
db.removeColumn('season', 'challonge_svg'),
db.removeColumn('season', 'challonge_url'),
db.removeColumn('team', 'challonge_team_id'),
db.removeColumn('user', 'challonge_api_key'),
], callback());
};
exports._meta = {
"version": 19
};
24 changes: 12 additions & 12 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "g5api",
"version": "1.5.0.0",
"version": "1.6.0.0",
"private": true,
"type": "module",
"licenses": [
Expand Down Expand Up @@ -49,18 +49,18 @@
"migrate-drop-test": "MYSQL_FLAGS=\"-CONNECT_WITH_DB\" db-migrate --env test --config config/test.json db:drop get5test",
"prod": "NODE_ENV=production yarn migrate-create-prod && yarn migrate-prod-upgrade",
"test": "NODE_ENV=test && yarn test:setup-user && yarn migrate-drop-test && yarn migrate-create-test && yarn migrate-test-upgrade && yarn test:user && yarn test:gameservers && yarn test:teams && yarn test:matches && yarn test:seasons && yarn test:vetoes && yarn test:mapstats && yarn test:playerstats && yarn test:vetosides && yarn test:maplists",
"test:gameservers": "yarn test:removeID && NODE_OPTIONS=--experimental-vm-modules jest --testTimeout=10000 --forceExit --config ./jest_config/jest.gameservers.config.cjs",
"test:mapstats": "NODE_OPTIONS=--experimental-vm-modules jest --testTimeout=10000 --forceExit --config ./jest_config/jest.mapstats.config.cjs",
"test:maplists": "NODE_OPTIONS=--experimental-vm-modules jest --testTimeout=10000 --forceExit --config ./jest_config/jest.maplist.config.cjs",
"test:matches": "NODE_OPTIONS=--experimental-vm-modules jest --testTimeout=10000 --forceExit --config ./jest_config/jest.matches.config.cjs",
"test:playerstats": "NODE_OPTIONS=--experimental-vm-modules jest --testTimeout=10000 --forceExit --config ./jest_config/jest.playerstats.config.cjs",
"test:gameservers": "yarn test:removeID && NODE_OPTIONS=--experimental-vm-modules jest --testTimeout=10000 --detectOpenHandles --config ./jest_config/jest.gameservers.config.cjs",
"test:mapstats": "NODE_OPTIONS=--experimental-vm-modules jest --testTimeout=10000 --detectOpenHandles --config ./jest_config/jest.mapstats.config.cjs",
"test:maplists": "NODE_OPTIONS=--experimental-vm-modules jest --testTimeout=10000 --detectOpenHandles --config ./jest_config/jest.maplist.config.cjs",
"test:matches": "NODE_OPTIONS=--experimental-vm-modules jest --testTimeout=10000 --detectOpenHandles --config ./jest_config/jest.matches.config.cjs",
"test:playerstats": "NODE_OPTIONS=--experimental-vm-modules jest --testTimeout=10000 --detectOpenHandles --config ./jest_config/jest.playerstats.config.cjs",
"test:removeID": "sed -i -e 's.\"steam_ids\": \"[0-9][0-9]*\".\"steam_ids\": \"super_admins,go,here\".g' ./config/test.json",
"test:seasons": "NODE_OPTIONS=--experimental-vm-modules jest --testTimeout=10000 --forceExit --config ./jest_config/jest.seasons.config.cjs",
"test:seasons": "NODE_OPTIONS=--experimental-vm-modules jest --testTimeout=10000 --detectOpenHandles --config ./jest_config/jest.seasons.config.cjs",
"test:setup-user": "export STEAMID=`grep -o -m 1 '[0-9][0-9]*' utility/mockProfile.js` && sed -i -e \"s/\\\"super_admins,go,here\\\"/\\\"$STEAMID\\\"/g\" config/test.json",
"test:teams": "NODE_OPTIONS=--experimental-vm-modules jest --testTimeout=10000 --forceExit --config ./jest_config/jest.teams.config.cjs",
"test:user": "NODE_OPTIONS=--experimental-vm-modules jest --testTimeout=10000 --forceExit --config ./jest_config/jest.users.config.cjs",
"test:vetoes": "NODE_OPTIONS=--experimental-vm-modules jest --testTimeout=10000 --forceExit --config ./jest_config/jest.vetoes.config.cjs",
"test:vetosides": "NODE_OPTIONS=--experimental-vm-modules jest --testTimeout=10000 --forceExit --config ./jest_config/jest.vetosides.config.cjs"
"test:teams": "NODE_OPTIONS=--experimental-vm-modules jest --testTimeout=10000 --detectOpenHandles --config ./jest_config/jest.teams.config.cjs",
"test:user": "NODE_OPTIONS=--experimental-vm-modules jest --testTimeout=10000 --detectOpenHandles --config ./jest_config/jest.users.config.cjs",
"test:vetoes": "NODE_OPTIONS=--experimental-vm-modules jest --testTimeout=10000 --detectOpenHandles --config ./jest_config/jest.vetoes.config.cjs",
"test:vetosides": "NODE_OPTIONS=--experimental-vm-modules jest --testTimeout=10000 --detectOpenHandles --config ./jest_config/jest.vetosides.config.cjs"
},
"dependencies": {
"@node-steam/id": "^1.1.0",
Expand Down Expand Up @@ -95,7 +95,7 @@
"swagger-ui-express": "^4.3.0"
},
"devDependencies": {
"jest": "^27.4.7",
"jest": "^27.5",
"jsdoc": "^3.6.7",
"nodemon": "^2.0.15",
"passport-mock-strategy": "^2.0.0",
Expand Down
Loading

0 comments on commit 91982bb

Please sign in to comment.