diff --git a/app/FrontendUnit.js b/app/FrontendUnit.js index 35365bf..31ab1e3 100644 --- a/app/FrontendUnit.js +++ b/app/FrontendUnit.js @@ -4,7 +4,7 @@ const path = require('path') class FrontendUnit extends Unit { static get services() { - return [...super.services, 'configs', 'express', 'canon', 'utility'] + return [...super.services, 'configs', 'express', 'canon', 'utility', 'models'] } constructor(...args) { @@ -40,6 +40,14 @@ class FrontendUnit extends Unit { }, Express.static(this.directory), ]) + + // Set the default setting values + const Setting = this.models.get('models::setting') // a built-in helper + const default_settings = this.configs.get('settings.default_settings') || [] + + for ( const default_setting of default_settings ) { + await Setting.guarantee(default_setting.key, default_setting.value) + } } } diff --git a/app/SeedWeeklyPlayerData.patch.js b/app/SeedWeeklyPlayerData.patch.js new file mode 100644 index 0000000..e6d3120 --- /dev/null +++ b/app/SeedWeeklyPlayerData.patch.js @@ -0,0 +1,67 @@ +const { Injectable } = require('flitter-di') + +/** + * A data patch which fetches all of the player stats for a range of + * weeks and creates WeeklyPlayerStat records for all players for all + * weeks. + * + * This builds the base of data we need to calculate the weekly team + * standings. + * + * @example + * P = require('./app/SeedWeeklyPlayerData.patch') + * p = _di.make(P) + * await p.run() + * + * @extends Injectable + */ +class SeedWeeklyPlayerDataPatch extends Injectable { + static get services() { + return [...super.services, 'models', 'sports_data', 'output'] + } + + /** + * Run the patch. + * @return {Promise} + */ + async run() { + const Player = this.models.get('Player') + const WeeklyPlayerStat = this.models.get('WeeklyPlayerStat') + const start_week = 1 + const end_week = 17 + + // Clear existing data + await WeeklyPlayerStat.deleteMany() + + // Populate the weekly player stats for all weeks in the range + for ( let week = start_week; week <= end_week; week += 1 ) { + this.output.info(`Building weekly player stats for week ${week}...`) + const player_stats = await this.sports_data.get_week_player_stats(week) + + this.output.info(` - processing ${player_stats.length} stats`) + for ( const stat of player_stats ) { + const player = await Player.findOne({ + 'patch_data.player_id': stat.PlayerID, + }) + + if ( player ) { + const weekly_stat = new WeeklyPlayerStat({ + player_id: player.id, + patch_player_id: stat.PlayerID, + week_num: week, + fantasy_points: stat.FantasyPoints, + }) + + await weekly_stat.save() + } else { + this.output.warn(` - Player ID ${stat.PlayerID} does not exist.`) + } + } + this.output.success(` - complete`) + } + + this.output.success('Complete!') + } +} + +module.exports = exports = SeedWeeklyPlayerDataPatch diff --git a/app/models/Matchup.model.js b/app/models/Matchup.model.js new file mode 100644 index 0000000..180f8c6 --- /dev/null +++ b/app/models/Matchup.model.js @@ -0,0 +1,18 @@ +const { Model } = require('flitter-orm') + +class Matchup extends Model { + static get services() { + return [...super.services, 'models'] + } + + static get schema() { + return { + home_team_id: String, + visitor_team_id: String, + week_num: Number, + complete: { type: Boolean, default: false }, + } + } +} + +module.exports = exports = Matchup diff --git a/app/models/WeeklyPlayerStat.model.js b/app/models/WeeklyPlayerStat.model.js new file mode 100644 index 0000000..39417c8 --- /dev/null +++ b/app/models/WeeklyPlayerStat.model.js @@ -0,0 +1,18 @@ +const { Model } = require('flitter-orm') + +class WeeklyPlayerStat extends Model { + static get services() { + return [...super.services, 'models'] + } + + static get schema() { + return { + player_id: String, + week_num: Number, + patch_player_id: String, + fantasy_points: Number, + } + } +} + +module.exports = exports = WeeklyPlayerStat diff --git a/app/models/WeeklyTeamStat.model.js b/app/models/WeeklyTeamStat.model.js new file mode 100644 index 0000000..681f24b --- /dev/null +++ b/app/models/WeeklyTeamStat.model.js @@ -0,0 +1,19 @@ +const { Model } = require('flitter-orm') + +class WeeklyTeamStat extends Model { + static get services() { + return [...super.services, 'models'] + } + + static get schema() { + return { + team_id: String, + lineup_id: String, + week_num: Number, + player_ids: [String], + fantasy_points: Number, + } + } +} + +module.exports = exports = WeeklyTeamStat diff --git a/app/services/sports_data.service.js b/app/services/sports_data.service.js index cc23b38..9a3156a 100644 --- a/app/services/sports_data.service.js +++ b/app/services/sports_data.service.js @@ -6,7 +6,17 @@ const axios = require('axios').default; */ class SportsDataService extends Service { static get services() { - return [...super.services, 'configs'] + return [...super.services, 'configs', 'models', 'utility'] + } + + async is_draft_stage() { + const Setting = this.models.get('models::setting') + return !!this.utility.infer(await Setting.get('in_draft_stage')) + } + + async current_play_week() { + const Setting = this.models.get('models::setting') + return !!this.utility.infer(await Setting.get('current_week')) } async get_team_players(team_key) { @@ -17,14 +27,18 @@ class SportsDataService extends Service { return this.get_request('Teams') } - async get_request(path) { - const response = await axios.get(this.url(path)) + async get_request(path, base = 'scores') { + const response = await axios.get(this.url(path, base)) return response.data } - url(path) { + async get_week_player_stats(week_num) { + return this.get_request(`PlayerGameProjectionStatsByWeek/${this.configs.get('server.sports_data.season')}/${week_num}`, 'projections') + } + + url(path, base = 'scores') { if ( path.startsWith('/') ) path = path.slice(1) - return `https://api.sportsdata.io/v3/nfl/scores/json/${path}?key=${this.configs.get('server.sports_data.api_key')}` + return `https://api.sportsdata.io/v3/nfl/${base}/json/${path}?key=${this.configs.get('server.sports_data.api_key')}` } } diff --git a/config/server.config.js b/config/server.config.js index 8822f0f..e9b2388 100644 --- a/config/server.config.js +++ b/config/server.config.js @@ -22,6 +22,7 @@ const server_config = { sports_data: { api_key: env('SPORTSDATA_API_KEY'), + season: env('SPORTSDATA_SEASON', '2020REG'), }, logging: { diff --git a/config/settings.config.js b/config/settings.config.js new file mode 100644 index 0000000..0281393 --- /dev/null +++ b/config/settings.config.js @@ -0,0 +1,15 @@ + +const settings_config = { + default_settings: [ + { + key: 'in_draft_stage', + value: true, + }, + { + key: 'current_week', + value: 1, + }, + ], +} + +module.exports = exports = settings_config