Commit b2067c7a authored by Frederik Wegner's avatar Frederik Wegner

Implmented /users/all. Implemented title repository.

parent 805adde3
package DBHandler
/*
* encapsulates all functions that interact with database user objects.
*
* http logic should not be implemented here. e.G. functions that require "net/http".
*
* it is important to understand how transactions, connection pools and other sql db
* concepts work to avoid serious efficience problems. Avoid coding database interaction
* you do not fully understand.
*
* very good tutorial to sql functionality http://mindbowser.com/golang-go-database-sql/
*/
import (
"database/sql"
"fmt"
)
import _ "github.com/go-sql-driver/mysql"
import sq "github.com/Masterminds/squirrel"
/*
* the data definition from an user in the sql user table
*/
type Title struct {
Id uint32
Name string
Subject uint32
Unlock_score int
Unlock_win int
}
/*
* Insert a new title into the database.
*/
func InsertTitle(name, string, subject uint32, unlock_score int, unlock_win int) (id uint32, err error){
//Test DB Functionality
db, err := sql.Open("mysql", "root:13abUtv0@/akamu")
//check for errors opening the database
if err != nil {
return 0, fmt.Errorf("Could not open database connection." + err.Error())
}
//check for errors connecting to the database
if db.Ping() != nil {
return 0, fmt.Errorf("Could not open database connection.")
}
defer db.Close()
//create transaction, following a tutorial that did not check for errors here
tx, _ := db.Begin()
//defering a Rollback here sounds strange but is advised at http://go-database-sql.org/prepared.html
defer tx.Rollback()
//creates the insert sql statement for the transaction
stmt, err := tx.Prepare("INSERT INTO title (name, subject, unlock_score, unlock_win) VALUES (?, ?, ?, ?")
//check for problems with the created sql statement
if err != nil {
//Rollback transaction in case of error
tx.Rollback()
return 0, fmt.Errorf("Failed to prepare query statement. " + err.Error())
}
defer stmt.Close()
//execute sql statement to insert the new user into the user table
_ , err = stmt.Exec(name, subject, unlock_score, unlock_win)
//check for erros while executing the insert sql statement
if err != nil {
//if an error occured Rollback the transaction
tx.Rollback()
return 0, fmt.Errorf("Failed executing insert query statement. " + err.Error())
}
//creates the sql statement to get the id in the same transaction
stmt, err = tx.Prepare("SELECT LAST_INSERT_ID()")
//check for errors creating the sql statement
if err != nil {
//if an error occured Rollback the transaction
tx.Rollback()
return 0, fmt.Errorf("Could not create statement to get id. " + err.Error())
}
//execute sql query that returns the id from the new record.
err = stmt.QueryRow().Scan(&id)
if err != nil {
//if an error occured Rollback the transaction
tx.Rollback()
return 0, fmt.Errorf("Could not get the id from the user created, rolling back transaction. " + err.Error())
}
//check for erros while executing sql statement
if err != nil {
//if an error occured Rollback the transaction
tx.Rollback()
return 0, fmt.Errorf("Failed executing select id from new user query statement. " + err.Error())
}
//commit successful transaction
tx.Commit()
//return without errors
return id, nil
}
/*
* Selects titles from the database. Parameters id and subject are filter parameters, that will be applied with sql 'where'. If a parameter has its default value, it will be ignored.
*/
func SelectTitles(id uint32, subjectid uint32, name string) ([]Title, error) {
sqStmt := sq.Select("idtitle, name, subject, unlock_score, unlock_win").From("title")
if id != 0 {
sqStmt = sqStmt.Where("id=?", id)
} else { // Id is unique. Any other filters irrelevant.
if subjectid != 0 {
sqStmt = sqStmt.Where("subject=?", subjectid)
}
if name != "" {
sqStmt = sqStmt.Where("name=?", name)
}
}
query, args, sqErr := sqStmt.ToSql()
if sqErr != nil {
return nil, sqErr
}
//Test DB Functionality
db, err := sql.Open("mysql", "root:13abUtv0@/akamu")
//check for errors opening the database
if err != nil {
return nil, fmt.Errorf("Could not open database connection." + err.Error())
}
//check for errors connecting to the database
if db.Ping() != nil {
return nil, fmt.Errorf("Could not open database connection.")
}
defer db.Close()
res, dbErr := db.Query(query, args)
if dbErr != nil {
return nil, dbErr
}
var titles []Title
for res.Next() {
var next Title
res.Scan(&next.Id,
&next.Name,
&next.Subject,
&next.Unlock_score,
&next.Unlock_win)
titles = append(titles, next)
}
return titles, nil
}
......@@ -30,7 +30,7 @@ type User struct {
Username string
Password string
Email string
Semester int
Semester int
Experience int
SelectedAvatar uint32
SelectedTitle uint32
......@@ -44,12 +44,12 @@ type User struct {
* specific data is hardcoded here. e.G. score is set to 0.
*/
func InsertUser(user *User) (id uint32, err error){
//Test DB Functionality
db, err := sql.Open("mysql", "root:13abUtv0@/akamu")
db, err := sql.Open("mysql", "root:13abUtv0@/akamu")
//check for errors opening the database
if err != nil {
//check for errors opening the database
if err != nil {
return 0, fmt.Errorf("Could not open database connection." + err.Error())
}
//check for errors connecting to the database
......@@ -63,9 +63,9 @@ func InsertUser(user *User) (id uint32, err error){
//defering a Rollback here sounds strange but is advised at http://go-database-sql.org/prepared.html
defer tx.Rollback()
//creates the insert sql statement for the transaction
//creates the insert sql statement for the transaction
stmt, err := tx.Prepare("INSERT INTO user (time_registered, username, password, email, semester, experience, selected_avatar, selected_title, verified, university) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")
//check for problems with the created sql statement
if err != nil {
//Rollback transaction in case of error
......@@ -88,10 +88,10 @@ func InsertUser(user *User) (id uint32, err error){
//creates the sql statement to get the user id in the same transaction
stmt, err = tx.Prepare("SELECT iduser FROM user WHERE username = ?")
//check for errors creating the sql statement
if err != nil {
//if an error occured Rollback the transaction
//check for errors creating the sql statement
if err != nil {
//if an error occured Rollback the transaction
tx.Rollback()
return 0, fmt.Errorf("Could not create statement to get user id. " + err.Error())
}
......@@ -120,10 +120,10 @@ func InsertUser(user *User) (id uint32, err error){
func SelectAllUsers(users []User) (error) {
//Test DB Functionality
db, err := sql.Open("mysql", "root:13abUtv0@/akamu?parseTime=true")
db, err := sql.Open("mysql", "root:13abUtv0@/akamu?parseTime=true")
//check for errors opening the database
if err != nil {
//check for errors opening the database
if err != nil {
return fmt.Errorf("Could not open database connection." + err.Error())
}
//check for errors connecting to the database
......@@ -139,12 +139,12 @@ func SelectAllUsers(users []User) (error) {
}
//make sql query and save response to the user pointer
res, err = stmt.Query()
res, err := stmt.Query()
if err != nil {
return fmt.Errorf("Could not retrieve user from Datase. " + err.Error())
}
for res.next() {
for res.Next() {
var nextUser User
err := res.Scan(&nextUser.Id,
&nextUser.TimeRegistered,
......@@ -159,12 +159,10 @@ func SelectAllUsers(users []User) (error) {
&nextUser.University)
if err != nil {
return fmt.Errorf("Failed to scan user from result set. " + err.Error())
}
else {
append(users, nextUser)
} else {
users = append(users, nextUser)
}
}
//return with no errors
return nil
}
......@@ -198,4 +196,4 @@ func SelectUserById(id uint32, user *User) (error) {
//return with no errors
return nil
}
\ No newline at end of file
}
......@@ -227,7 +227,7 @@ paths:
Returns an object representing the user with `id`. The user object is stripped down to public information if `id` is not the same as your id.
parameters:
- name: id
description: `id` of the user to get info about.
description: '`id` of the user to get info about.'
in: path
required: true
schema:
......@@ -264,7 +264,7 @@ paths:
summary: Get duel with `id`.
parameters:
- name: id
description: `id` of the deul to get.
description: '`id` of the deul to get.'
in: path
required: true
schema:
......@@ -296,6 +296,14 @@ paths:
patch:
summary: Update duel after finishing a round.
description: Send round results to the server to update the state.
parameters:
- name: id
description: '`id` of the deul to get.'
in: path
required: true
schema:
type: integer
format: uint32
requestBody:
content:
application/json:
......
......@@ -21,7 +21,7 @@ type UserInfoSchema struct {
}
type UserSchema struct {
UserInfoSchema
*UserInfoSchema
TimeRegistered string `json:"time-registered" binding:"required"` // datetime format
Semester int `json:"semester" binding:"required"`
Verified bool `json:"verified" binding:"required"`
......
......@@ -38,88 +38,112 @@ func registerUser(ctx *gin.Context) {
signUpForm := SignUpFormular{}
//grabs data from the http post request and bind it to the signUpForm struct
err := ctx.BindJSON(&signUpForm)
err := ctx.BindJSON(&signUpForm)
//test for erros binding http request data to the signUpForm
if err != nil {
//test for erros binding http request data to the signUpForm
if err != nil {
ctx.String(http.StatusBadRequest, "Failed binding payload to signUpForm. " + err.Error())
return
}
//creates an empty user struct
user := DBHandler.User{TimeRegistered:time.Now(), Username:signUpForm.Username, Password:signUpForm.Password,
Email:signUpForm.Email, Semester:signUpForm.Semester, Experience:initialUserExperience, SelectedAvatar:initialUserAvatar,
SelectedTitle:initialUserTitle, University:signUpForm.University, Verified:initialVerifiedStatus}
//insert user into the Akamu sql database and returns the id
id, err := DBHandler.InsertUser(&user)
if err != nil {
//creates an empty user struct
user := DBHandler.User{
TimeRegistered:time.Now(),
Username:signUpForm.Username,
Password:signUpForm.Password,
Email:signUpForm.Email,
Semester:signUpForm.Semester,
Experience:initialUserExperience,
SelectedAvatar:initialUserAvatar,
SelectedTitle:initialUserTitle,
University:signUpForm.University,
Verified:initialVerifiedStatus}
//insert user into the Akamu sql database and returns the id
id, err := DBHandler.InsertUser(&user)
if err != nil {
ctx.String(http.StatusInternalServerError, "Failed inserting user: " + err.Error())
return
}
//set http response
ctx.JSON(http.StatusOK, gin.H{"id":id})
ctx.JSON(http.StatusOK, gin.H{"id":id})
}
func getUser(ctx *gin.Context) {
//creates an empty user struct
//creates an empty user struct
user := DBHandler.User{}
//parse the id string into an int id
id , err := strconv.ParseUint(ctx.Param("id"), 10, 32)
id ,err := strconv.ParseUint(ctx.Param("id"), 10, 32)
//test for erros converting the payload to the id
if err != nil {
if err != nil {
ctx.String(http.StatusBadRequest, "Failed getting the user id value from the http request. " + err.Error())
return
}
//select user in the database
err = DBHandler.SelectUserById(uint32(id), &user)
err = DBHandler.SelectUserById(uint32(id), &user)
if err != nil {
if err != nil {
ctx.String(http.StatusInternalServerError, "Failed selecting user from DB. " + err.Error())
return
}
userSchema := userSchemaFromUser(&user);
userSchema := userSchemaFromUser(&user);
//set http response
ctx.JSON(http.StatusOK, &userSchema)
ctx.JSON(http.StatusOK, &userSchema)
}
func getAllUserInfos() {
func getAllUserInfos(ctx *gin.Context) {
var userInfos []UserInfo;
var allUsers []DBHandler.User;
err = DBHandler.SelectUsers();
err := DBHandler.SelectAllUsers(allUsers);
if err != nil {
ctx.String(http.StatusInternalServerError, "Failed selecting user information from DB. " + err.Error())
} else {
userInfos := make([]UserInfoSchema, len(allUsers))
for i := 0; i < len(allUsers); i++ {
userInfos[i] = userInfoSchemaFromUser(&allUsers[i])
}
ctx.JSON(http.StatusOK, &userInfos)
}
}
func userSchemaFromUser(user *User) UserSchema {
func userSchemaFromUser(user *DBHandler.User) (UserSchema) {
info := userInfoSchemaFromUser(user)
return UserSchema{
Id: user.Id,
Name: user.Username,
Avatar: user.SelectedAvatar,
Title: user.SelectedTitle,
TimeRegistered: user.TimeRegistered,
UserInfoSchema: &info,
TimeRegistered: user.TimeRegistered.String(),
Semester: user.Semester,
Verified: user.Verified,
Universiy: user.University,
University: user.University,
Experience: user.Experience,
// TODO: Memorycoins missing in DB
Memorycoins: 0
Memorycoins: 0,
}
}
func userInfoSchemaFromUser(user *User) UserInfoSchema {
return UserSchema{
/*
* Created a UserSchema struct using information of the give user. Resolves foreighn keys where necessary.
*/
func userInfoSchemaFromUser(user *DBHandler.User) (UserInfoSchema) {
// UserInfoSchema requires the title to be resolved.
titles, err := DBHandler.SelectTitles(user.SelectedTitle, 0, "")
title := ""
if err == nil && len(titles) != 0 {
title = titles[0].Name
}
return UserInfoSchema{
Id: user.Id,
Name: user.Username,
Avatar: user.SelectedAvatar,
Title: user.SelectedTitle,
Title: title,
}
}
\ No newline at end of file
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment