diff --git a/app/SeedAPIData.patch.js b/app/SeedAPIData.patch.js new file mode 100644 index 0000000..1112b3f --- /dev/null +++ b/app/SeedAPIData.patch.js @@ -0,0 +1,62 @@ +const { Injectable } = require('flitter-di') + +/** + * A one-time patch which populates the Player collection with + * all the players on all the active teams in the NFL using the + * sports data service's APIs. + * + * To run this, do it from "node flitter shell": + * + * @example + * Patch = require('./app/SeedAPIData.patch') + * patch = _di.make(Patch) + * await patch.run() + * + * @extends Injectable + */ +class SeedAPIDataPatch extends Injectable { + static get services() { + return [...super.services, 'models', 'sports_data', 'output'] + } + + /** + * Run the patch. + * @return {Promise} + */ + async run() { + // Clear any existing data first + const Player = this.models.get('Player') + await Player.deleteMany() + this.output.success('Cleared existing player data!') + + // Fetch all active teams + this.output.info('Fetching teams to patch data...') + const teams = await this.sports_data.get_active_teams() + this.output.info(`Fetched ${teams.length} teams.`) + let players = 0 + + // Fetch the players for each of the teams + for ( let i = 0; i < teams.length; i++ ) { + const team = teams[i] + this.output.info(`Fetching players for team ${i + 1} of ${teams.length} (${team.Key})...`) + + const team_players = await this.sports_data.get_team_players(team.Key) + this.output.info(` (patching ${team_players.length} players)`) + + // Insert Player documents for each of the player records + for ( const rec of team_players ) { + const player = Player.from_patch_data(rec) + player.patch_data.patch_team_name = team.FullName + player.patch_data.patch_team_key = team.Key + await player.save() + players += 1 + } + + this.output.success(` (patched player data)`) + } + + this.output.success(`Patch complete. Created ${players} players.`) + } +} + +module.exports = exports = SeedAPIDataPatch diff --git a/app/models/Player.model.js b/app/models/Player.model.js index 8451596..75f3f6d 100644 --- a/app/models/Player.model.js +++ b/app/models/Player.model.js @@ -1,5 +1,6 @@ const { Model } = require('flitter-orm') + /* * Player Model * ------------------------------------------------------------- @@ -14,14 +15,56 @@ class Player extends Model { */ static get schema() { return { - player_number: String, - player_name: String, - player_position: String, - team_name: String, - image_url: String, + patch_data: { + patch_team_id: Number, + patch_team_name: String, + patch_team_key: String, + player_id: Number, + draft_position: Number, + }, + player_number: Number, + first_name: String, + last_name: String, + full_name: String, + position: String, + fantasy_position: String, + height: String, + weight: Number, + birthday: String, + experience: String, + experience_string: String, + age: Number, + photo_url: String, } } + static from_patch_data(data) { + const model_data = { + patch_data: { + patch_team_id: data.TeamID, + // patch_team_name, + // patch_team_key, + player_id: data.PlayerID, + draft_position: data.AverageDraftPosition, + }, + player_number: data.Number, + first_name: data.FirstName, + last_name: data.LastName, + full_name: data.Name, + position: data.Position, + fantasy_position: data.FantasyPosition, + height: data.Height, + weight: data.Weight, + birthday: data.BirthDateString, + experience: data.Experience, + experience_string: data.ExperienceString, + age: data.Age, + photo_url: data.PhotoUrl + } + + return new this(model_data) + } + async to_api() { return { player_number: this.player_number, diff --git a/app/services/sports_data.service.js b/app/services/sports_data.service.js new file mode 100644 index 0000000..cc23b38 --- /dev/null +++ b/app/services/sports_data.service.js @@ -0,0 +1,31 @@ +const { Service } = require('flitter-di') +const axios = require('axios').default; + +/** + * A service class for interacting with data from the SportsDataIO API. + */ +class SportsDataService extends Service { + static get services() { + return [...super.services, 'configs'] + } + + async get_team_players(team_key) { + return this.get_request(`Players/${team_key}`) + } + + async get_active_teams() { + return this.get_request('Teams') + } + + async get_request(path) { + const response = await axios.get(this.url(path)) + return response.data + } + + url(path) { + 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')}` + } +} + +module.exports = exports = SportsDataService diff --git a/config/server.config.js b/config/server.config.js index e6b7e8b..8822f0f 100644 --- a/config/server.config.js +++ b/config/server.config.js @@ -20,6 +20,10 @@ const server_config = { */ frontend_path: env('FRONT_END_PATH', 'frontend'), + sports_data: { + api_key: env('SPORTSDATA_API_KEY'), + }, + logging: { /* diff --git a/example.env b/example.env index 10329b5..d43246b 100644 --- a/example.env +++ b/example.env @@ -33,3 +33,5 @@ ENVIRONMENT=development SSL_ENABLE=false SSL_CERT_FILE=cert.pem SSL_KEY_FILE=cert.key + +SPORTSDATA_API_KEY= diff --git a/package.json b/package.json index b2a4417..ee61103 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "author": "Garrett Mills (https://garrettmills.dev/)", "license": "MIT", "dependencies": { + "axios": "^0.21.0", "flitter-auth": "^0.19.1", "flitter-cli": "^0.16.0", "flitter-di": "^0.5.0", diff --git a/yarn.lock b/yarn.lock index d8c457b..0abd63c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -500,6 +500,13 @@ axios@^0.19.0: follow-redirects "1.5.10" is-buffer "^2.0.2" +axios@^0.21.0: + version "0.21.0" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.0.tgz#26df088803a2350dff2c27f96fef99fe49442aca" + integrity sha512-fmkJBknJKoZwem3/IKSSLpkdNXZeBu5Q7GA/aRsr2btgrptmSCxi2oFjZHqGdK9DoTil9PIHlPIZw2EcRJXRvw== + dependencies: + follow-redirects "^1.10.0" + babel-core@^5.4.7: version "5.8.38" resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-5.8.38.tgz#1fcaee79d7e61b750b00b8e54f6dfc9d0af86558" @@ -1652,6 +1659,11 @@ follow-redirects@1.5.10: dependencies: debug "=3.1.0" +follow-redirects@^1.10.0: + version "1.13.0" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.0.tgz#b42e8d93a2a7eea5ed88633676d6597bc8e384db" + integrity sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA== + foreground-child@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-2.0.0.tgz#71b32800c9f15aa8f2f83f4a6bd9bff35d861a53"