mirror of
https://github.com/vkaelin/LeagueStats.git
synced 2026-03-25 12:57:28 +00:00
feat: add ranks back in match-details
This commit is contained in:
parent
973355c201
commit
6f0beec0d2
17 changed files with 291 additions and 31 deletions
|
|
@ -5,6 +5,7 @@
|
|||
:data="allyTeam"
|
||||
:all-players="[...allyTeam.players, ...enemyTeam.players]"
|
||||
:ally-team="true"
|
||||
:ranks-loaded="data.ranksLoaded"
|
||||
/>
|
||||
|
||||
<div class="flex items-start justify-between px-3 py-2">
|
||||
|
|
@ -23,6 +24,7 @@
|
|||
:data="enemyTeam"
|
||||
:all-players="[...allyTeam.players, ...enemyTeam.players]"
|
||||
:ally-team="false"
|
||||
:ranks-loaded="data.ranksLoaded"
|
||||
/>
|
||||
</div>
|
||||
<div v-else-if="data.status === 'loading' && detailsOpen">
|
||||
|
|
|
|||
|
|
@ -228,7 +228,7 @@
|
|||
{{ player.rank.shortName }}
|
||||
</div>
|
||||
</div>
|
||||
<div v-else-if="player.rank === undefined">
|
||||
<div v-else-if="!ranksLoaded">
|
||||
<DotsLoader width="30px" dot-width="10px" />
|
||||
</div>
|
||||
<div v-else class="w-5 h-5">
|
||||
|
|
@ -350,6 +350,10 @@ export default {
|
|||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
ranksLoaded: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
|
|
|
|||
|
|
@ -14,16 +14,39 @@ export const mutations = {
|
|||
state.matches.push({ matchId, status: 'loading' })
|
||||
}
|
||||
},
|
||||
MATCH_FOUND(state, matchDetails) {
|
||||
MATCH_FOUND(state, {matchDetails, ranksLoaded }) {
|
||||
matchDetails.status = 'loaded'
|
||||
matchDetails.ranksLoaded = ranksLoaded
|
||||
|
||||
// Set SoloQ as rank for now
|
||||
if(ranksLoaded) {
|
||||
for (const player of matchDetails.blueTeam.players) {
|
||||
player.rank = player.rank && player.rank[420]
|
||||
}
|
||||
for (const player of matchDetails.redTeam.players) {
|
||||
player.rank = player.rank && player.rank[420]
|
||||
}
|
||||
}
|
||||
|
||||
const index = state.matches.findIndex(m => m.gameId === matchDetails.gameId)
|
||||
Vue.set(state.matches, index, matchDetails)
|
||||
},
|
||||
MATCH_RANKS_FOUND(state, { gameId, blueTeam, redTeam }) {
|
||||
MATCH_RANKS_FOUND(state, { gameId, ranksByPlayer }) {
|
||||
const match = state.matches.find(m => m.gameId === gameId)
|
||||
match.blueTeam.players = blueTeam
|
||||
match.redTeam.players = redTeam
|
||||
|
||||
for (const player of match.blueTeam.players) {
|
||||
const ranks = ranksByPlayer[player.id]
|
||||
if(!ranks) continue
|
||||
Vue.set(player, 'rank', ranks[420])
|
||||
}
|
||||
|
||||
for (const player of match.redTeam.players) {
|
||||
const ranks = ranksByPlayer[player.id]
|
||||
if(!ranks) continue
|
||||
Vue.set(player, 'rank', ranks[420])
|
||||
}
|
||||
|
||||
match.ranksLoaded = true
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -35,17 +58,17 @@ export const actions = {
|
|||
const resp = await axios(({ url: 'match/details', data: { matchId }, method: 'POST' })).catch(() => { })
|
||||
console.log('--- DETAILS INFOS ---')
|
||||
console.log(resp.data)
|
||||
commit('MATCH_FOUND', resp.data.matchDetails)
|
||||
const {matchDetails, ranksLoaded} = resp.data
|
||||
commit('MATCH_FOUND', {matchDetails, ranksLoaded })
|
||||
|
||||
// TODO: add ranks back when it's done on the API
|
||||
// // If the ranks of the players are not yet known
|
||||
// if (resp.data.matchDetails.blueTeam.players[0].rank === undefined) {
|
||||
// const ranks = await axios(({ url: 'match/details/ranks', data: { gameId, region }, method: 'POST' })).catch(() => { })
|
||||
// if (!ranks) return
|
||||
// console.log('--- RANK OF MATCH DETAILS ---')
|
||||
// console.log(ranks.data)
|
||||
// commit('MATCH_RANKS_FOUND', { gameId, ...ranks.data })
|
||||
// }
|
||||
// If the ranks of the players are not yet known
|
||||
if (!ranksLoaded) {
|
||||
const ranks = await axios(({ url: 'match/details/ranks', data: { matchId }, method: 'POST' })).catch(() => { })
|
||||
if (!ranks) return
|
||||
console.log('--- RANK OF MATCH DETAILS ---')
|
||||
console.log(ranks.data)
|
||||
commit('MATCH_RANKS_FOUND', { matchId, ranksByPlayer: ranks.data })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
|
||||
import Match from 'App/Models/Match'
|
||||
import MatchPlayerRankParser from 'App/Parsers/MatchPlayerRankParser'
|
||||
import DetailedMatchSerializer from 'App/Serializers/DetailedMatchSerializer'
|
||||
import MatchPlayerRankSerializer from 'App/Serializers/MatchPlayerRankSerializer'
|
||||
import MatchService from 'App/Services/MatchService'
|
||||
import StatsService from 'App/Services/StatsService'
|
||||
import DetailedMatchValidator from 'App/Validators/DetailedMatchValidator'
|
||||
|
|
@ -8,7 +10,7 @@ import MatchesIndexValidator from 'App/Validators/MatchesIndexValidator'
|
|||
|
||||
export default class MatchesController {
|
||||
/**
|
||||
* POST - Return data from matches searched by gameIds
|
||||
* POST - Return data from matches searched by matchIds
|
||||
* @param ctx
|
||||
*/
|
||||
public async index({ request, response }: HttpContextContract) {
|
||||
|
|
@ -33,15 +35,33 @@ export default class MatchesController {
|
|||
const match = await Match.query()
|
||||
.where('id', matchId)
|
||||
.preload('teams')
|
||||
.preload('players')
|
||||
.preload('players', (playersQuery) => {
|
||||
playersQuery.preload('ranks')
|
||||
})
|
||||
.firstOrFail()
|
||||
|
||||
const matchDetails = DetailedMatchSerializer.serializeOneMatch(match)
|
||||
const { match: matchDetails, ranksLoaded } = DetailedMatchSerializer.serializeOneMatch(match)
|
||||
|
||||
console.timeEnd('MatchDetails')
|
||||
|
||||
return response.json({
|
||||
matchDetails,
|
||||
ranksLoaded,
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* POST - Return ranks of players for a specific game
|
||||
* @param ctx
|
||||
*/
|
||||
public async showRanks({ request, response }: HttpContextContract) {
|
||||
console.time('Ranks')
|
||||
const { matchId } = await request.validate(DetailedMatchValidator)
|
||||
const match = await Match.query().where('id', matchId).preload('players').firstOrFail()
|
||||
const parsedRanks = await MatchPlayerRankParser.parse(match)
|
||||
const serializedRanks = MatchPlayerRankSerializer.serialize(parsedRanks)
|
||||
|
||||
console.timeEnd('Ranks')
|
||||
return response.json(serializedRanks)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ export default class SummonersController {
|
|||
finalJSON.current = currentGame
|
||||
|
||||
// RANKED STATS
|
||||
finalJSON.ranked = await SummonerService.getRanked(account, region)
|
||||
finalJSON.ranked = await SummonerService.getRanked(account.id, region)
|
||||
|
||||
// RECENT ACTIVITY
|
||||
finalJSON.recentActivity = await StatsService.getRecentActivity(account.puuid)
|
||||
|
|
@ -78,7 +78,6 @@ export default class SummonersController {
|
|||
|
||||
finalJSON.matchesDetails = await MatchService.getMatches(region, matchIds, puuid)
|
||||
|
||||
// TODO: STATS
|
||||
console.time('STATS')
|
||||
finalJSON.stats = await StatsService.getSummonerStats(puuid, season)
|
||||
console.timeEnd('STATS')
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { BaseModel, BelongsTo, belongsTo, column } from '@ioc:Adonis/Lucid/Orm'
|
||||
import { BaseModel, BelongsTo, belongsTo, column, HasMany, hasMany } from '@ioc:Adonis/Lucid/Orm'
|
||||
import Match from './Match'
|
||||
import MatchPlayerRank from './MatchPlayerRank'
|
||||
import Summoner from './Summoner'
|
||||
|
||||
export default class MatchPlayer extends BaseModel {
|
||||
|
|
@ -12,6 +13,12 @@ export default class MatchPlayer extends BaseModel {
|
|||
@belongsTo(() => Match)
|
||||
public match: BelongsTo<typeof Match>
|
||||
|
||||
@hasMany(() => MatchPlayerRank, {
|
||||
localKey: 'id',
|
||||
foreignKey: 'playerId',
|
||||
})
|
||||
public ranks: HasMany<typeof MatchPlayerRank>
|
||||
|
||||
@column()
|
||||
public participantId: number
|
||||
|
||||
|
|
|
|||
38
server-v2/app/Models/MatchPlayerRank.ts
Normal file
38
server-v2/app/Models/MatchPlayerRank.ts
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
import { DateTime } from 'luxon'
|
||||
import { BaseModel, BelongsTo, belongsTo, column } from '@ioc:Adonis/Lucid/Orm'
|
||||
import MatchPlayer from './MatchPlayer'
|
||||
|
||||
export default class MatchPlayerRank extends BaseModel {
|
||||
@column({ isPrimary: true })
|
||||
public id: number
|
||||
|
||||
@column()
|
||||
public playerId: number
|
||||
|
||||
@belongsTo(() => MatchPlayer, {
|
||||
localKey: 'id',
|
||||
foreignKey: 'playerId',
|
||||
})
|
||||
public player: BelongsTo<typeof MatchPlayer>
|
||||
|
||||
@column()
|
||||
public gamemode: number
|
||||
|
||||
@column()
|
||||
public tier: string
|
||||
|
||||
@column()
|
||||
public rank: number
|
||||
|
||||
@column()
|
||||
public lp: number
|
||||
|
||||
@column()
|
||||
public wins: number
|
||||
|
||||
@column()
|
||||
public losses: number
|
||||
|
||||
@column.dateTime({ autoCreate: true })
|
||||
public createdAt: DateTime
|
||||
}
|
||||
43
server-v2/app/Parsers/MatchPlayerRankParser.ts
Normal file
43
server-v2/app/Parsers/MatchPlayerRankParser.ts
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
import Database from '@ioc:Adonis/Lucid/Database'
|
||||
import { notEmpty } from 'App/helpers'
|
||||
import Match from 'App/Models/Match'
|
||||
import MatchPlayer from 'App/Models/MatchPlayer'
|
||||
import SummonerService from 'App/Services/SummonerService'
|
||||
import { PlayerRankParsed } from './ParsedType'
|
||||
|
||||
class MatchPlayerRankParser {
|
||||
public async parse(match: Match): Promise<PlayerRankParsed[]> {
|
||||
const requests = match.players.map((p) => SummonerService.getRanked(p.summonerId, match.region))
|
||||
const ranks = await Promise.all(requests)
|
||||
|
||||
const parsedRanks = ranks
|
||||
.map((rank) => {
|
||||
return Object.entries(rank).map(([queue, data]) => {
|
||||
let player: MatchPlayer | undefined
|
||||
if (!data || !(player = match.players.find((p) => p.summonerId === data.summonerId))) {
|
||||
return
|
||||
}
|
||||
|
||||
const rank: PlayerRankParsed = {
|
||||
player_id: player.id,
|
||||
gamemode: queue === 'soloQ' ? 420 : 440,
|
||||
tier: data.tier,
|
||||
rank: SummonerService.leaguesNumbers[data.rank],
|
||||
lp: data.leaguePoints,
|
||||
wins: data.wins,
|
||||
losses: data.losses,
|
||||
}
|
||||
return rank
|
||||
})
|
||||
})
|
||||
.flat()
|
||||
.filter(notEmpty)
|
||||
|
||||
// Store ranks in DB
|
||||
await Database.table('match_player_ranks').multiInsert(parsedRanks)
|
||||
|
||||
return parsedRanks
|
||||
}
|
||||
}
|
||||
|
||||
export default new MatchPlayerRankParser()
|
||||
|
|
@ -15,3 +15,13 @@ export enum TeamPosition {
|
|||
BOTTOM,
|
||||
UTILITY,
|
||||
}
|
||||
|
||||
export interface PlayerRankParsed {
|
||||
player_id: number
|
||||
gamemode: number
|
||||
tier: string
|
||||
rank: number
|
||||
lp: number
|
||||
wins: number
|
||||
losses: number
|
||||
}
|
||||
|
|
|
|||
|
|
@ -75,11 +75,19 @@ class DetailedMatchSerializer extends MatchSerializer {
|
|||
).toFixed(1) + '%',
|
||||
dmgTaken: +((player.damageTaken * 100) / teamStats.dmgTaken).toFixed(1) + '%',
|
||||
}
|
||||
const rank = player.ranks.length
|
||||
? player.ranks.reduce((acc, rank) => {
|
||||
acc[rank.gamemode] = this.getPlayerRank(rank)
|
||||
return acc
|
||||
}, {})
|
||||
: undefined
|
||||
return {
|
||||
...this.getPlayerBase(player),
|
||||
...this.getRuneIcons(player.perksSelected, player.perksSecondaryStyle),
|
||||
id: player.id,
|
||||
stats,
|
||||
percentStats,
|
||||
rank,
|
||||
}
|
||||
})
|
||||
.sort(sortTeamByRole)
|
||||
|
|
@ -106,18 +114,24 @@ class DetailedMatchSerializer extends MatchSerializer {
|
|||
}
|
||||
}
|
||||
|
||||
public serializeOneMatch(match: Match): SerializedDetailedMatch {
|
||||
public serializeOneMatch(match: Match): { match: SerializedDetailedMatch; ranksLoaded: boolean } {
|
||||
const blueTeam = match.teams.find((team) => team.color === 100)!
|
||||
const redTeam = match.teams.find((team) => team.color === 200)!
|
||||
|
||||
const bluePlayers: MatchPlayer[] = []
|
||||
const redPlayers: MatchPlayer[] = []
|
||||
|
||||
let ranksLoaded = false
|
||||
|
||||
for (const p of match.players) {
|
||||
p.team === 100 ? bluePlayers.push(p) : redPlayers.push(p)
|
||||
|
||||
if (p.ranks.length) {
|
||||
ranksLoaded = true
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
const serializedMatch = {
|
||||
blueTeam: this.getTeamDetailed(blueTeam, bluePlayers, match.gameDuration),
|
||||
date: match.date,
|
||||
matchId: match.id,
|
||||
|
|
@ -128,6 +142,11 @@ class DetailedMatchSerializer extends MatchSerializer {
|
|||
season: match.season,
|
||||
time: match.gameDuration,
|
||||
}
|
||||
|
||||
return {
|
||||
match: serializedMatch,
|
||||
ranksLoaded,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
20
server-v2/app/Serializers/MatchPlayerRankSerializer.ts
Normal file
20
server-v2/app/Serializers/MatchPlayerRankSerializer.ts
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
import { PlayerRankParsed } from 'App/Parsers/ParsedType'
|
||||
import MatchSerializer from './MatchSerializer'
|
||||
import { SerializedPlayerRanksList } from './SerializedTypes'
|
||||
|
||||
class MatchPlayerRankSerializer extends MatchSerializer {
|
||||
public serialize(ranks: PlayerRankParsed[]): SerializedPlayerRanksList {
|
||||
const result = ranks.reduce((acc, rank) => {
|
||||
if (!acc[rank.player_id]) {
|
||||
acc[rank.player_id] = {}
|
||||
}
|
||||
|
||||
acc[rank.player_id][rank.gamemode] = this.getPlayerRank(rank)
|
||||
return acc
|
||||
}, {} as SerializedPlayerRanksList)
|
||||
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
export default new MatchPlayerRankSerializer()
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
import MatchPlayer from 'App/Models/MatchPlayer'
|
||||
import { TeamPosition } from 'App/Parsers/ParsedType'
|
||||
import { PlayerRankParsed, TeamPosition } from 'App/Parsers/ParsedType'
|
||||
import CDragonService from 'App/Services/CDragonService'
|
||||
import SummonerService from 'App/Services/SummonerService'
|
||||
import {
|
||||
SerializedBasePlayer,
|
||||
SerializedMatchChampion,
|
||||
|
|
@ -99,4 +100,15 @@ export default abstract class MatchSerializer {
|
|||
summonerSpell2: this.getSummonerSpell(player.summoner2Id),
|
||||
}
|
||||
}
|
||||
|
||||
protected getPlayerRank(rank: PlayerRankParsed) {
|
||||
return {
|
||||
tier: rank.tier,
|
||||
rank: rank.rank,
|
||||
lp: rank.lp,
|
||||
wins: rank.wins,
|
||||
losses: rank.losses,
|
||||
shortName: SummonerService.getRankedShortName(rank),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -121,6 +121,7 @@ export interface SerializedDetailedMatchBan {
|
|||
}
|
||||
|
||||
export interface SerializedDetailedMatchPlayer extends SerializedBasePlayer {
|
||||
id: number
|
||||
stats: SerializedDetailedMatchStats
|
||||
percentStats: SerializedDetailedMatchPercentStats
|
||||
primaryRune: string | null
|
||||
|
|
@ -160,3 +161,20 @@ export interface SerializedDetailedMatchPercentStats {
|
|||
minions: number
|
||||
vision: number
|
||||
}
|
||||
|
||||
export interface SerializedPlayerRanksList {
|
||||
[summonerId: string]: SerializedPlayerRanks
|
||||
}
|
||||
|
||||
export interface SerializedPlayerRanks {
|
||||
[gamemode: number]: SerializedPlayerRank
|
||||
}
|
||||
|
||||
export interface SerializedPlayerRank {
|
||||
tier: string
|
||||
rank: number
|
||||
lp: number
|
||||
wins: number
|
||||
losses: number
|
||||
shortName: number | string
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ import Jax from './Jax'
|
|||
import { SummonerDTO } from 'App/Services/Jax/src/Endpoints/SummonerEndpoint'
|
||||
import { LeagueEntryDTO } from './Jax/src/Endpoints/LeagueEndpoint'
|
||||
import Summoner from 'App/Models/Summoner'
|
||||
import { PlayerRankParsed } from 'App/Parsers/ParsedType'
|
||||
import MatchPlayerRank from 'App/Models/MatchPlayerRank'
|
||||
|
||||
export interface LeagueEntriesByQueue {
|
||||
soloQ?: LeagueEntryByQueue
|
||||
|
|
@ -15,8 +17,16 @@ export interface LeagueEntryByQueue extends LeagueEntryDTO {
|
|||
}
|
||||
|
||||
class SummonerService {
|
||||
private uniqueLeagues = ['CHALLENGER', 'GRANDMASTER', 'MASTER']
|
||||
private leaguesNumbers = { I: 1, II: 2, III: 3, IV: 4 }
|
||||
private readonly uniqueLeagues = ['CHALLENGER', 'GRANDMASTER', 'MASTER']
|
||||
public readonly leaguesNumbers = { I: 1, II: 2, III: 3, IV: 4 }
|
||||
|
||||
public getRankedShortName(rank: PlayerRankParsed | MatchPlayerRank) {
|
||||
return this.uniqueLeagues.includes(rank.tier) ? rank.lp : rank.tier[0] + rank.rank
|
||||
}
|
||||
|
||||
public getWinrate(wins: number, losses: number) {
|
||||
return +((wins * 100) / (wins + losses)).toFixed(1) + '%'
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to transform League Data from the Riot API
|
||||
|
|
@ -29,7 +39,7 @@ class SummonerService {
|
|||
const fullRank = this.uniqueLeagues.includes(league.tier)
|
||||
? league.tier
|
||||
: `${league.tier} ${league.rank}`
|
||||
const winrate = +((league.wins * 100) / (league.wins + league.losses)).toFixed(1) + '%'
|
||||
const winrate = this.getWinrate(league.wins, league.losses)
|
||||
const shortName = this.uniqueLeagues.includes(league.tier)
|
||||
? league.leaguePoints
|
||||
: league.tier[0] + this.leaguesNumbers[league.rank]
|
||||
|
|
@ -70,8 +80,8 @@ class SummonerService {
|
|||
* @param account
|
||||
* @param region
|
||||
*/
|
||||
public async getRanked(account: SummonerDTO, region: string): Promise<LeagueEntriesByQueue> {
|
||||
const ranked = await Jax.League.summonerID(account.id, region)
|
||||
public async getRanked(summonerId: string, region: string): Promise<LeagueEntriesByQueue> {
|
||||
const ranked = await Jax.League.summonerID(summonerId, region)
|
||||
const result: LeagueEntriesByQueue = {}
|
||||
|
||||
if (ranked && ranked.length) {
|
||||
|
|
@ -80,7 +90,6 @@ class SummonerService {
|
|||
result.flex5v5 =
|
||||
this.getleagueData(ranked.find((e) => e.queueType === 'RANKED_FLEX_SR')) || undefined
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -110,3 +110,10 @@ export function sortTeamByRole<T extends SortableByRole>(a: T, b: T) {
|
|||
const sortingArr = ['TOP', 'JUNGLE', 'MIDDLE', 'BOTTOM', 'UTILITY']
|
||||
return sortingArr.indexOf(a.role) - sortingArr.indexOf(b.role)
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/a/46700791/9188650
|
||||
export function notEmpty<TValue>(value: TValue | null | undefined): value is TValue {
|
||||
if (value === null || value === undefined) return false
|
||||
const testDummy: TValue = value
|
||||
return true
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,29 @@
|
|||
import BaseSchema from '@ioc:Adonis/Lucid/Schema'
|
||||
|
||||
export default class MatchPlayerRanks extends BaseSchema {
|
||||
protected tableName = 'match_player_ranks'
|
||||
|
||||
public async up() {
|
||||
this.schema.createTable(this.tableName, (table) => {
|
||||
table.increments('id')
|
||||
|
||||
table.integer('player_id').unsigned().notNullable()
|
||||
|
||||
table.integer('gamemode').notNullable()
|
||||
table.string('tier', 11).notNullable()
|
||||
table.integer('rank').notNullable()
|
||||
table.integer('lp').notNullable()
|
||||
table.integer('wins').notNullable()
|
||||
table.integer('losses').notNullable()
|
||||
|
||||
/**
|
||||
* Uses timestamptz for PostgreSQL and DATETIME2 for MSSQL
|
||||
*/
|
||||
table.timestamp('created_at', { useTz: true })
|
||||
})
|
||||
}
|
||||
|
||||
public async down() {
|
||||
this.schema.dropTable(this.tableName)
|
||||
}
|
||||
}
|
||||
|
|
@ -37,6 +37,6 @@ Route.post('/summoner/records', 'SummonersController.records')
|
|||
|
||||
Route.post('/match', 'MatchesController.index')
|
||||
Route.post('/match/details', 'MatchesController.show')
|
||||
// Route.post('/match/details/ranks', 'MatchesController.showRanks')
|
||||
Route.post('/match/details/ranks', 'MatchesController.showRanks')
|
||||
|
||||
Route.get('/cdragon/runes', 'CDragonController.runes')
|
||||
|
|
|
|||
Loading…
Reference in a new issue