From 53acb45d6d4510c897da86bcf87df67365d4c894 Mon Sep 17 00:00:00 2001
From: RandomChars <random@chars.jp>
Date: Sat, 25 Dec 2021 13:56:22 +0900
Subject: [PATCH] ensure role assignment

---
 assets/templates/tournament-config.tmpl |  5 ++++
 routes.go                               | 18 +++++++++++++
 tournament.go                           |  9 ++++---
 user.go                                 | 35 +++++++++++++++++++++++++
 4 files changed, 63 insertions(+), 4 deletions(-)

diff --git a/assets/templates/tournament-config.tmpl b/assets/templates/tournament-config.tmpl
index cdcdcd6..42f5c2f 100644
--- a/assets/templates/tournament-config.tmpl
+++ b/assets/templates/tournament-config.tmpl
@@ -53,6 +53,11 @@
                                             <input type="text" name="Prize" value="{{.tournament.Prize}}" placeholder="Turnuva Ödülü">
                                         </label>
                                     </div>
+                                    <div class="col-md-6">
+                                        <label>
+                                            <input type="number" name="Role" value="{{.tournament.Role}}" placeholder="Role ID">
+                                        </label>
+                                    </div>
                                 </div>
                                 <button type="submit">EKLE</button>
                             </form>
diff --git a/routes.go b/routes.go
index 9cc9729..9968155 100644
--- a/routes.go
+++ b/routes.go
@@ -87,6 +87,17 @@ func registerRoutes() {
 			ts.E = true
 		}
 
+		var role int
+		if r, ok := t.Attributes["role"]; ok {
+			if rid, err := strconv.Atoi(r); err != nil {
+				log.Printf("error parsing role ID for tournament %s: %s", t.ID.String(), err)
+				context.String(http.StatusInternalServerError, "Internal Server Error")
+				return
+			} else {
+				role = rid
+			}
+		}
+
 		sy, sm, sd := t.StartTime.Date()
 		dy, dm, dd := t.Deadline.Date()
 		context.HTML(http.StatusOK, "form.tmpl", gin.H{
@@ -98,6 +109,7 @@ func registerRoutes() {
 				DeadlineString:  fmt.Sprintf("%d-%.2d-%.2d", dy, dm, dd),
 				TeamSizeString:  t.Attributes["size"],
 				Prize:           t.Attributes["prize"],
+				Role:            uint64(role),
 			},
 			"team_size": ts,
 		})
@@ -157,6 +169,12 @@ func registerRoutes() {
 			return
 		}
 
+		if err := ensureRoleEnrollment(user, t); err != nil {
+			log.Printf("error ensuring role assignment for user %s: %s", user.ID, err)
+			context.String(http.StatusInternalServerError, "Internal Server Error")
+			return
+		}
+
 		context.Redirect(http.StatusFound, "/")
 	})
 
diff --git a/tournament.go b/tournament.go
index bc43a72..c3bb0c4 100644
--- a/tournament.go
+++ b/tournament.go
@@ -32,9 +32,10 @@ type tournamentPayload struct {
 	st              *time.Time
 	DeadlineString  string
 	dl              *time.Time
-	TeamSize        int
+	TeamSize        uint8
 	TeamSizeString  string
 	Prize           string
+	Role            uint64
 	Delete          bool
 }
 
@@ -279,14 +280,14 @@ func bindTournament(context *gin.Context) (*tournament, bool) {
 		Attributes: map[string]string{
 			"title": payload.Title,
 			"prize": payload.Prize,
-			"size":  strconv.Itoa(payload.TeamSize),
+			"size":  strconv.Itoa(int(payload.TeamSize)),
+			"role":  strconv.Itoa(int(payload.Role)),
 		},
 	}, payload.Delete
 }
 
 func validatePayloadTournament(payload *tournamentPayload) bool {
-	return payload.TeamSize >= 0 &&
-		payload.TeamSize <= 4 &&
+	return payload.TeamSize <= 4 &&
 		len(payload.Title) < 2048 &&
 		len(payload.Prize) < 4096 &&
 		payload.StartTime().After(payload.Deadline()) &&
diff --git a/user.go b/user.go
index 2e81f5e..2d08972 100644
--- a/user.go
+++ b/user.go
@@ -253,6 +253,41 @@ func ensureJoinEnrollment(context *gin.Context, user *discordgo.User) error {
 	}
 }
 
+func ensureRoleEnrollment(user *discordgo.User, t *tournament) error {
+	var roleID string
+	if r, ok := t.Attributes["role"]; !ok {
+		return nil
+	} else {
+		if r == "0" || r == "" {
+			return nil
+		}
+		roleID = r
+	}
+
+	if req, err := http.NewRequest(http.MethodPut,
+		fmt.Sprintf("https://discordapp.com/api/guilds/%s/members/%s/roles/%s", guildID, user.ID, roleID),
+		nil); err != nil {
+		return err
+	} else {
+		req.Header.Set("Authorization", "Bot "+config.Discord.BotToken)
+
+		var resp *http.Response
+		if resp, err = http.DefaultClient.Do(req); err != nil {
+			return err
+		} else {
+			var body []byte
+			if body, err = io.ReadAll(resp.Body); err != nil {
+				return err
+			} else {
+				if resp.StatusCode != 204 {
+					return fmt.Errorf("discord returned %d: %s", resp.StatusCode, string(body))
+				}
+			}
+			return resp.Body.Close()
+		}
+	}
+}
+
 func validateEnrollment(payload *userEnrollment) bool {
 	return len(payload.TeamName) <= 64 &&
 		len(payload.FirstName) > 0 && len(payload.FirstName) <= 64 &&
-- 
GitLab