From 681deda3d299e0691d82b8e4cacd9ae4ef679743 Mon Sep 17 00:00:00 2001
From: Darkstack <1835601+darkstack@users.noreply.github.com>
Date: Sun, 7 Oct 2018 15:15:11 +0200
Subject: [PATCH] Challonge Provider can create tournament
---
.../LaDOSE.Api.DTO/LaDOSE.Api.DTO.csproj | 7 ++
.../LaDOSE.Api/Controllers/EventController.cs | 43 ++++++++++
LaDOSE.Src/LaDOSE.Api/LaDOSE.Api.csproj | 1 +
LaDOSE.Src/LaDOSE.Api/Startup.cs | 13 ++-
LaDOSE.Src/LaDOSE.Api/appsettings.json | 3 +
.../Service/ChallongeService.cs | 30 ++++---
.../LaDOSE.Entity/Context/LaDOSEDbContext.cs | 15 ++++
LaDOSE.Src/LaDOSE.Entity/Event.cs | 5 ++
LaDOSE.Src/LaDOSE.Entity/EventGame.cs | 12 +++
LaDOSE.Src/LaDOSE.Entity/Game.cs | 2 +
.../Interface/IChallongeProvider.cs | 12 +++
.../LaDOSE.Service/Interface/IEventService.cs | 2 +-
.../LaDOSE.Service/LaDOSE.Business.csproj | 6 ++
.../Provider/ChallongeProvider.cs | 78 ++++++++++++++++++
.../LaDOSE.Service/Service/EventService.cs | 32 ++++++-
.../LaDOSE.Service/Service/GameService.cs | 2 +-
Library/ChallongeCSharpDriver.dll | Bin 44032 -> 44032 bytes
17 files changed, 245 insertions(+), 18 deletions(-)
create mode 100644 LaDOSE.Src/LaDOSE.Api.DTO/LaDOSE.Api.DTO.csproj
create mode 100644 LaDOSE.Src/LaDOSE.Api/Controllers/EventController.cs
create mode 100644 LaDOSE.Src/LaDOSE.Entity/EventGame.cs
create mode 100644 LaDOSE.Src/LaDOSE.Service/Interface/IChallongeProvider.cs
create mode 100644 LaDOSE.Src/LaDOSE.Service/Provider/ChallongeProvider.cs
diff --git a/LaDOSE.Src/LaDOSE.Api.DTO/LaDOSE.Api.DTO.csproj b/LaDOSE.Src/LaDOSE.Api.DTO/LaDOSE.Api.DTO.csproj
new file mode 100644
index 0000000..5766db6
--- /dev/null
+++ b/LaDOSE.Src/LaDOSE.Api.DTO/LaDOSE.Api.DTO.csproj
@@ -0,0 +1,7 @@
+
+
+
+ netcoreapp2.0
+
+
+
diff --git a/LaDOSE.Src/LaDOSE.Api/Controllers/EventController.cs b/LaDOSE.Src/LaDOSE.Api/Controllers/EventController.cs
new file mode 100644
index 0000000..2c7dd4a
--- /dev/null
+++ b/LaDOSE.Src/LaDOSE.Api/Controllers/EventController.cs
@@ -0,0 +1,43 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using LaDOSE.Business.Interface;
+using LaDOSE.Entity;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+
+namespace LaDOSE.Api.Controllers
+{
+ [Produces("application/json")]
+ [Route("api/[controller]")]
+ public class EventController : Controller
+ {
+ private IEventService _eventService;
+
+ public EventController(IEventService eventService)
+ {
+ _eventService = eventService;
+ }
+
+ [HttpPost]
+ public Event Post([FromBody]Event dto)
+ {
+ return _eventService.Create(dto);
+ }
+
+ [HttpGet("{id}")]
+ public Event Get(int id)
+ {
+ return _eventService.GetById(id);
+
+ }
+
+ [HttpGet("Generate/{dto}")]
+ public bool GenerateChallonge(int dto)
+ {
+ return _eventService.CreateChallonge(dto);
+
+ }
+ }
+}
\ No newline at end of file
diff --git a/LaDOSE.Src/LaDOSE.Api/LaDOSE.Api.csproj b/LaDOSE.Src/LaDOSE.Api/LaDOSE.Api.csproj
index 26c785f..adfc078 100644
--- a/LaDOSE.Src/LaDOSE.Api/LaDOSE.Api.csproj
+++ b/LaDOSE.Src/LaDOSE.Api/LaDOSE.Api.csproj
@@ -11,6 +11,7 @@
+
diff --git a/LaDOSE.Src/LaDOSE.Api/Startup.cs b/LaDOSE.Src/LaDOSE.Api/Startup.cs
index d8c889b..51b151f 100644
--- a/LaDOSE.Src/LaDOSE.Api/Startup.cs
+++ b/LaDOSE.Src/LaDOSE.Api/Startup.cs
@@ -4,6 +4,7 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
using LaDOSE.Business.Interface;
+using LaDOSE.Business.Provider;
using LaDOSE.Business.Service;
using LaDOSE.Entity;
using LaDOSE.Entity.Context;
@@ -40,6 +41,7 @@ namespace LaDOSE.Api
var MySqlDatabase = this.Configuration["MySql:Database"];
var MySqlUser = this.Configuration["MySql:User"];
var MySqlPassword = this.Configuration["MySql:Password"];
+
services.AddCors();
services.AddMvc().AddJsonOptions(x => x.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);
services.AddDbContextPool( // replace "YourDbContext" with the class name of your DbContext
@@ -86,11 +88,18 @@ namespace LaDOSE.Api
});
// configure DI for application services
+ AddDIConfig(services);
+ }
+
+ private void AddDIConfig(IServiceCollection services)
+ {
+
services.AddScoped();
services.AddScoped();
+ services.AddScoped();
+ services.AddTransient(p => new ChallongeProvider(this.Configuration["ApiKey:ChallongeApiKey"]));
}
-
-
+
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
diff --git a/LaDOSE.Src/LaDOSE.Api/appsettings.json b/LaDOSE.Src/LaDOSE.Api/appsettings.json
index ca6066c..4a73694 100644
--- a/LaDOSE.Src/LaDOSE.Api/appsettings.json
+++ b/LaDOSE.Src/LaDOSE.Api/appsettings.json
@@ -14,6 +14,9 @@
"User": "User",
"Password": "Password"
},
+ "ApiKey": {
+ "ChallongeApiKey": "Challonge ApiKey"
+ },
"AllowedHosts": "*",
"Port": 5000,
"JWTTokenSecret": "here goes the custom Secret key for authnetication"
diff --git a/LaDOSE.Src/LaDOSE.DiscordBot/Service/ChallongeService.cs b/LaDOSE.Src/LaDOSE.DiscordBot/Service/ChallongeService.cs
index a74dd27..22198c9 100644
--- a/LaDOSE.Src/LaDOSE.DiscordBot/Service/ChallongeService.cs
+++ b/LaDOSE.Src/LaDOSE.DiscordBot/Service/ChallongeService.cs
@@ -35,25 +35,29 @@ namespace LaDOSE.DiscordBot.Service
try
{
-
- List tournamentResultList = await new TournamentsQuery()
+
+ List tournamentResultList = await new TournamentsQuery()
{
state = TournamentState.Ended
}
- .call(this.ApiCaller);
+ .call(this.ApiCaller);
- var lastDate = tournamentResultList.Max(e => e.completed_at);
- var lastRankingDate = new DateTime(lastDate.Year, lastDate.Month, lastDate.Day);
- var lastTournament = tournamentResultList.Where(e => e.completed_at > lastRankingDate).ToList();
- string returnValue = "Les derniers tournois : \n";
- foreach (var tournamentResult in lastTournament)
- {
- returnValue += $"{tournamentResult.name} : \n";
- }
+ var lastDate = tournamentResultList.Max(e => e.completed_at);
+ if (lastDate.HasValue)
+ {
+ var lastRankingDate = new DateTime(lastDate.Value.Year, lastDate.Value.Month, lastDate.Value.Day);
- DernierTournois = returnValue;
- return true;
+ var lastTournament = tournamentResultList.Where(e => e.completed_at > lastRankingDate).ToList();
+ string returnValue = "Les derniers tournois : \n";
+ foreach (var tournamentResult in lastTournament)
+ {
+ returnValue += $"{tournamentResult.name} : \n";
+ }
+
+ DernierTournois = returnValue;
+ }
+ return true;
}
catch
{
diff --git a/LaDOSE.Src/LaDOSE.Entity/Context/LaDOSEDbContext.cs b/LaDOSE.Src/LaDOSE.Entity/Context/LaDOSEDbContext.cs
index ed00c13..39b0bed 100644
--- a/LaDOSE.Src/LaDOSE.Entity/Context/LaDOSEDbContext.cs
+++ b/LaDOSE.Src/LaDOSE.Entity/Context/LaDOSEDbContext.cs
@@ -21,12 +21,16 @@ namespace LaDOSE.Entity.Context
base.OnModelCreating(modelBuilder);
modelBuilder.Entity()
.HasKey(t => new { t.SeasonId, t.GameId });
+ modelBuilder.Entity()
+ .HasKey(t => new { t.EventId, t.GameId });
modelBuilder.Entity()
.HasOne(s => s.Season)
.WithMany(p => p.Event)
.HasForeignKey(fk => fk.SeasonId);
+
+
modelBuilder.Entity()
.HasOne(pt => pt.Season)
.WithMany(p => p.Games)
@@ -37,6 +41,17 @@ namespace LaDOSE.Entity.Context
.WithMany(p => p.Seasons)
.HasForeignKey(pt => pt.GameId);
+
+ modelBuilder.Entity()
+ .HasOne(pt => pt.Event)
+ .WithMany(p => p.Games)
+ .HasForeignKey(pt => pt.EventId);
+
+ modelBuilder.Entity()
+ .HasOne(pt => pt.Game)
+ .WithMany(p => p.Events)
+ .HasForeignKey(pt => pt.GameId);
+
}
}
diff --git a/LaDOSE.Src/LaDOSE.Entity/Event.cs b/LaDOSE.Src/LaDOSE.Entity/Event.cs
index 2201f5a..0d55573 100644
--- a/LaDOSE.Src/LaDOSE.Entity/Event.cs
+++ b/LaDOSE.Src/LaDOSE.Entity/Event.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace LaDOSE.Entity
@@ -13,5 +14,9 @@ namespace LaDOSE.Entity
public Season Season { get; set; }
public bool Ranking { get; set; }
+
+ public virtual IEnumerable Games { get; set; }
+
+
}
}
\ No newline at end of file
diff --git a/LaDOSE.Src/LaDOSE.Entity/EventGame.cs b/LaDOSE.Src/LaDOSE.Entity/EventGame.cs
new file mode 100644
index 0000000..6c1bda9
--- /dev/null
+++ b/LaDOSE.Src/LaDOSE.Entity/EventGame.cs
@@ -0,0 +1,12 @@
+namespace LaDOSE.Entity
+{
+ public class EventGame
+ {
+
+ public int EventId { get; set; }
+ public Event Event { get; set; }
+ public int GameId { get; set; }
+ public Game Game { get; set; }
+
+ }
+}
\ No newline at end of file
diff --git a/LaDOSE.Src/LaDOSE.Entity/Game.cs b/LaDOSE.Src/LaDOSE.Entity/Game.cs
index c20751b..8180f14 100644
--- a/LaDOSE.Src/LaDOSE.Entity/Game.cs
+++ b/LaDOSE.Src/LaDOSE.Entity/Game.cs
@@ -12,5 +12,7 @@ namespace LaDOSE.Entity
public string ImgUrl { get; set; }
public virtual IEnumerable Seasons { get; set; }
+ public virtual IEnumerable Events { get; set; }
+
}
}
diff --git a/LaDOSE.Src/LaDOSE.Service/Interface/IChallongeProvider.cs b/LaDOSE.Src/LaDOSE.Service/Interface/IChallongeProvider.cs
new file mode 100644
index 0000000..f46edc0
--- /dev/null
+++ b/LaDOSE.Src/LaDOSE.Service/Interface/IChallongeProvider.cs
@@ -0,0 +1,12 @@
+using System;
+using System.Threading.Tasks;
+
+namespace LaDOSE.Business.Interface
+{
+ public interface IChallongeProvider
+ {
+ Task GetLastTournament();
+ string GetLastTournamentMessage();
+ Task> CreateTournament(string name, string url);
+ }
+}
\ No newline at end of file
diff --git a/LaDOSE.Src/LaDOSE.Service/Interface/IEventService.cs b/LaDOSE.Src/LaDOSE.Service/Interface/IEventService.cs
index cdc762d..fa841e0 100644
--- a/LaDOSE.Src/LaDOSE.Service/Interface/IEventService.cs
+++ b/LaDOSE.Src/LaDOSE.Service/Interface/IEventService.cs
@@ -4,6 +4,6 @@ namespace LaDOSE.Business.Interface
{
public interface IEventService : IBaseService
{
-
+ bool CreateChallonge(int dto);
}
}
\ No newline at end of file
diff --git a/LaDOSE.Src/LaDOSE.Service/LaDOSE.Business.csproj b/LaDOSE.Src/LaDOSE.Service/LaDOSE.Business.csproj
index 10f635d..9b0eda5 100644
--- a/LaDOSE.Src/LaDOSE.Service/LaDOSE.Business.csproj
+++ b/LaDOSE.Src/LaDOSE.Service/LaDOSE.Business.csproj
@@ -10,4 +10,10 @@
+
+
+ ..\..\Library\ChallongeCSharpDriver.dll
+
+
+
diff --git a/LaDOSE.Src/LaDOSE.Service/Provider/ChallongeProvider.cs b/LaDOSE.Src/LaDOSE.Service/Provider/ChallongeProvider.cs
new file mode 100644
index 0000000..4d00fe3
--- /dev/null
+++ b/LaDOSE.Src/LaDOSE.Service/Provider/ChallongeProvider.cs
@@ -0,0 +1,78 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using ChallongeCSharpDriver;
+using ChallongeCSharpDriver.Caller;
+using ChallongeCSharpDriver.Core.Queries;
+using ChallongeCSharpDriver.Core.Results;
+using LaDOSE.Business.Interface;
+
+namespace LaDOSE.Business.Provider
+{
+ public class ChallongeProvider : IChallongeProvider
+ {
+ private ChallongeConfig Config;
+ public string ApiKey { get; set; }
+
+ public ChallongeHTTPClientAPICaller ApiCaller { get; set; }
+
+ public string DernierTournois { get; set; }
+
+
+ public ChallongeProvider(string apiKey)
+ {
+ this.ApiKey = apiKey;
+ this.Config = new ChallongeConfig(this.ApiKey);
+ this.ApiCaller = new ChallongeHTTPClientAPICaller(Config);
+ DernierTournois = "Aucun tournois.";
+ }
+
+ public async Task> CreateTournament(string name, string url)
+ {
+ var p = await new CreateTournamentQuery(name, TournamentType.Double_Elimination, url).call(ApiCaller);
+ return new Tuple(p.id, p.url);
+
+
+ }
+
+ public async Task GetLastTournament()
+ {
+ try
+ {
+
+
+ List tournamentResultList = await new TournamentsQuery()
+ {
+ state = TournamentState.Ended
+ }
+ .call(this.ApiCaller);
+
+
+ var lastDate = tournamentResultList.Max(e => e.completed_at);
+ if (lastDate.HasValue)
+ {
+ var lastRankingDate = new DateTime(lastDate.Value.Year, lastDate.Value.Month, lastDate.Value.Day);
+
+ var lastTournament = tournamentResultList.Where(e => e.completed_at > lastRankingDate).ToList();
+ string returnValue = "Les derniers tournois : \n";
+ foreach (var tournamentResult in lastTournament)
+ {
+ returnValue += $"{tournamentResult.name} : \n";
+ }
+
+ DernierTournois = returnValue;
+ }
+ return true;
+ }
+ catch
+ {
+ return false;
+ }
+ }
+ public string GetLastTournamentMessage()
+ {
+ return DernierTournois;
+ }
+ }
+}
\ No newline at end of file
diff --git a/LaDOSE.Src/LaDOSE.Service/Service/EventService.cs b/LaDOSE.Src/LaDOSE.Service/Service/EventService.cs
index fe092b8..440937d 100644
--- a/LaDOSE.Src/LaDOSE.Service/Service/EventService.cs
+++ b/LaDOSE.Src/LaDOSE.Service/Service/EventService.cs
@@ -1,14 +1,24 @@
using System;
+using System.Linq;
using LaDOSE.Business.Interface;
using LaDOSE.Entity;
using LaDOSE.Entity.Context;
+using Microsoft.EntityFrameworkCore;
namespace LaDOSE.Business.Service
{
public class EventService : BaseService, IEventService
{
- public EventService(LaDOSEDbContext context) : base(context)
+ private IChallongeProvider _challongeProvider;
+
+ public EventService(LaDOSEDbContext context,IChallongeProvider challongeProvider) : base(context)
{
+ this._challongeProvider = challongeProvider;
+ }
+
+ public override Event GetById(int id)
+ {
+ return _context.Event.Include(e=>e.Season).Include(e=>e.Games).ThenInclude(e=>e.Game).FirstOrDefault(e=>e.Id == id);
}
public override Event Create(Event e)
@@ -22,5 +32,25 @@ namespace LaDOSE.Business.Service
_context.SaveChanges();
return eventAdded.Entity;
}
+
+ public bool CreateChallonge(int dto)
+ {
+ var currentEvent = _context.Event.Include(e=>e.Games).ThenInclude(e=>e.Game).FirstOrDefault(e=>e.Id == dto);
+ if (currentEvent != null)
+ {
+ var games = currentEvent.Games.Select(e => e.Game);
+ var s = currentEvent.Date.ToString("MM/dd/yy");
+ foreach (var game in games)
+ {
+ var url = $"TestDev{game.Id}{game.Name}";
+ var name = $"[{s}]Ranking {currentEvent.Name}{game.Name}";
+ _challongeProvider.CreateTournament(name,url);
+ }
+
+ return true;
+ }
+
+ return false;
+ }
}
}
\ No newline at end of file
diff --git a/LaDOSE.Src/LaDOSE.Service/Service/GameService.cs b/LaDOSE.Src/LaDOSE.Service/Service/GameService.cs
index 1e60406..cbe5ed2 100644
--- a/LaDOSE.Src/LaDOSE.Service/Service/GameService.cs
+++ b/LaDOSE.Src/LaDOSE.Service/Service/GameService.cs
@@ -17,7 +17,7 @@ namespace LaDOSE.Business.Service
public override IEnumerable GetAll()
{
- return _context.Game.Include(e => e.Seasons).ToList();
+ return _context.Game.Include(e => e.Seasons).ThenInclude(e=>e.Season).ToList();
}
diff --git a/Library/ChallongeCSharpDriver.dll b/Library/ChallongeCSharpDriver.dll
index 0e1f2b597f988450966aede25c77abb481cde07e..d0b5f85d8554fc84a60827ed59b3b94a7ce1ec2c 100644
GIT binary patch
delta 3623
zcmZp;!PIbrX+j6fgGZ}gP3)0joHcP}IHSj8Mn-j3g@X(XA(IuEbS6hKsxvN_+{jqZ
zSTmWCNtpFT76Sw0IoZz90M5#(kKtxxn9Nbez{XI-`G<>*
zA&?iuW)Mu_W@PYS$lzvUFyWfYz{aqJuaKLKfkChqEZ&GD-p9?x@Q(?k1}2NFYZ^Bj
z!yYCvu-<;;QN+lwo}CxT2u2<@h7f)Ruo_MtkOh1^j0|Vk1(DQ<
zBdJjUt5M}am>id=Z`IVBLRCJcu)@nG2t+_)WD
z&mforR+Ne1n<6Bq)PvQu@Gzn|cOsG+4sh(wSlUKW#>wM&qV)zGE(#FBT`He@4fn5cpp^am|;2$1o27V~-svslpWIk67
zes*3t25+b!i;(DKS658|C0==kE{GVzOlC&j$#t$$j2e??y1Mck@v1UZse(+L#xQ}$
zV)9#8>3Ta}4TcX;u^JvbUQGsdHINEW_%SkQftU;o499rwxm+#SBpU(VZ-EhH%)CKO=g|M89w>8n{<6FuQuFWZ5&6L;XGD$ku-!HYnwASDMjca-}cGhK;@;8_xQg*BkSd
zF|09!r~>(=jNu5F2l7iIUm1g-5lF6$!#
zD9g>im_g15BnSzI#SCg-UNeIj1OH^^AWeQz{-q2~zF-v`Y9ePRTL+o*OYtvfF!O_m
zEfrCi+!z$hug<@UfhhnY_Lb+wv(~E6Bi@%+M^Dz?jUin@w;5V=}}4&6$Z4
z8CAW77&$ABr{x^ET8OXDnamI_+ze(f;7n$i
zDSQ~rX66FP9^gu5xF!66E15wJmpU1_NaqB}J{KzHXJGipyT@-rwgtQ6VB&%p4L=KxFyDgqbZ?3t;rB(UeR
z)#;TB7`z+aF8Fz?DU*M5N4Fd|J13i{U_&e8<`vT(F$r@iFo1c24O6)l7#TtA&68(F
zGIDTfKqNN5pQXrQSa#)1D+8l%022cP!&(LghLVE}3?+*}nGAv%85kIZ85kHqjR3_%
z3=E2s9T%(cx8(cGe0$Av^VZ2%f1ZOJE`19kvPwfUg{
delta 3611
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