Version 7 #53

Merged
vlbeaudoin merged 33 commits from rewrite/v7 into main 2024-09-03 11:17:26 -04:00
7 changed files with 315 additions and 0 deletions
Showing only changes of commit e4ff1013d0 - Show all commits

View file

@ -133,3 +133,38 @@ func (c APIClient) UpdateMembrePreferedName(membreID string, name string) (err e
return nil return nil
} }
func (c APIClient) GetMembreForDisplay(membreID string) (membre MembreForDisplay, err error) {
var request MembreDisplayGETRequest
request.Param.MembreID = membreID
response, err := request.Request(c.Voki)
if err != nil {
return
}
if code, message := response.StatusCode(), response.Message; code >= 400 {
err = fmt.Errorf("%d: %s", code, message)
return
}
return response.Data.Membre, nil
}
func (c APIClient) GetMembresForDisplay(limit int) (membres []MembreForDisplay, err error) {
var request MembresDisplayGETRequest
request.Query.Limit = limit
response, err := request.Request(c.Voki)
if err != nil {
return
}
if code, message := response.StatusCode(), response.Message; code >= 400 {
err = fmt.Errorf("%d: %s", code, message)
return
}
return response.Data.Membres, nil
}

View file

@ -122,4 +122,22 @@ func TestAPI(t *testing.T) {
} }
t.Log(membres) t.Log(membres)
}) })
t.Run("get membre for display",
func(t *testing.T) {
membre, err := apiClient.GetMembreForDisplay(testMembres[0].ID)
if err != nil {
t.Error(err)
}
t.Log(membre)
})
t.Run("get membres for display, max 5",
func(t *testing.T) {
membres, err := apiClient.GetMembresForDisplay(5)
if err != nil {
t.Error(err)
}
t.Log(membres)
})
} }

80
db.go
View file

@ -272,3 +272,83 @@ WHERE
} }
return return
} }
func (d *PostgresClient) GetMembreForDisplay(membreID string) (membre MembreForDisplay, err error) {
select {
case <-d.Ctx.Done():
err = fmt.Errorf("PostgresClient.Ctx closed: %s", d.Ctx.Err())
return
default:
if err = d.Pool.QueryRow(d.Ctx, `
SELECT
"membres_for_display".id,
"membres_for_display".name,
"membres_for_display".programme_id,
"membres_for_display".programme_name
FROM
"membres_for_display"
WHERE
"membres_for_display".id = $1
LIMIT
1;
`, membreID).Scan(
&membre.ID,
&membre.Name,
&membre.ProgrammeID,
&membre.ProgrammeName,
); err != nil {
return
}
if membre.ID == "" {
return membre, fmt.Errorf("Aucun membre trouvé avec numéro '%s'", membre.ID)
}
return membre, nil
}
}
func (d *PostgresClient) GetMembresForDisplay(limit int) (membres []MembreForDisplay, err error) {
select {
case <-d.Ctx.Done():
return nil, fmt.Errorf("PostgresClient.Ctx closed: %s", d.Ctx.Err())
default:
rows, err := d.Pool.Query(d.Ctx, `
SELECT
"membres_for_display".id,
"membres_for_display".name,
"membres_for_display".programme_id,
"membres_for_display".programme_name
FROM
"membres_for_display"
ORDER BY
"membres_for_display".id
LIMIT
$1;
`, limit)
if err != nil {
return nil, err
}
defer rows.Close()
for rows.Next() {
var membre MembreForDisplay
if err = rows.Scan(
&membre.ID,
&membre.Name,
&membre.ProgrammeID,
&membre.ProgrammeName,
); err != nil {
return nil, err
}
membres = append(membres, membre)
}
if rows.Err() != nil {
return membres, rows.Err()
}
return membres, nil
}
}

View file

@ -15,6 +15,14 @@ type Membre struct {
ProgrammeID string `db:"programme_id" json:"programme_id" csv:"programme_id"` ProgrammeID string `db:"programme_id" json:"programme_id" csv:"programme_id"`
} }
// MembreForDisplay maps to the `membres_for_display` view declared in `sql/views.sql`
type MembreForDisplay struct {
ID string `db:"id" json:"membre_id" csv:"membre_id"`
Name string `db:"name" json:"name" csv:"name"`
ProgrammeID string `db:"programme_id" json:"programme_id" csv:"programme_id"`
ProgrammeName string `db:"programme_name" json:"programme_name" csv:"programme_name"`
}
func IsMembreID(membre_id string) bool { func IsMembreID(membre_id string) bool {
if len(membre_id) != 7 { if len(membre_id) != 7 {
return false return false

View file

@ -273,3 +273,78 @@ func (request ProgrammesGETRequest) Request(v *voki.Voki) (response ProgrammesGE
return return
} }
var _ voki.Requester[MembresDisplayGETResponse] = MembresDisplayGETRequest{}
type MembresDisplayGETRequest struct {
Query struct {
Limit int `json:"limit" query:"limit"`
}
}
func (request MembresDisplayGETRequest) Complete() bool { return true }
func (request MembresDisplayGETRequest) Request(v *voki.Voki) (response MembresDisplayGETResponse, err error) {
if !request.Complete() {
err = fmt.Errorf("Incomplete MembresDisplayGETRequest")
return
}
statusCode, body, err := v.CallAndParse(
http.MethodGet,
fmt.Sprintf("/api/v7/membre/display/?limit=%d", request.Query.Limit),
nil,
true,
)
if err != nil {
err = fmt.Errorf("code=%d err=%s", statusCode, err)
return
}
response.SetStatusCode(statusCode)
if err = json.Unmarshal(body, &response); err != nil {
return
}
return
}
var _ voki.Requester[MembreDisplayGETResponse] = MembreDisplayGETRequest{}
type MembreDisplayGETRequest struct {
Param struct {
MembreID string `json:"membre_id" param:"membre_id"`
}
}
func (request MembreDisplayGETRequest) Complete() bool {
return request.Param.MembreID != ""
}
func (request MembreDisplayGETRequest) Request(v *voki.Voki) (response MembreDisplayGETResponse, err error) {
if !request.Complete() {
err = fmt.Errorf("Incomplete MembreDisplayGETRequest")
return
}
if id := request.Param.MembreID; !IsMembreID(id) {
err = fmt.Errorf("MembreID '%s' invalide", id)
return
}
statusCode, body, err := v.CallAndParse(
http.MethodGet,
fmt.Sprintf("/api/v7/membre/%s/display/", request.Param.MembreID),
nil,
true,
)
if err != nil {
err = fmt.Errorf("code=%d err=%s", statusCode, err)
return
}
response.SetStatusCode(statusCode)
if err = json.Unmarshal(body, &response); err != nil {
return
}
return
}

View file

@ -46,6 +46,23 @@ type MembresGETResponseData struct {
Membres []Membre `json:"membres"` Membres []Membre `json:"membres"`
} }
type MembreDisplayGETResponse struct {
APIResponse
Data MembreDisplayGETResponseData `json:"data"`
}
type MembreDisplayGETResponseData struct {
Membre MembreForDisplay `json:"membre_for_display"`
}
type MembresDisplayGETResponse struct {
APIResponse
Data MembresDisplayGETResponseData `json:"data"`
}
type MembresDisplayGETResponseData struct {
Membres []MembreForDisplay `json:"membres_for_display"`
}
type MembresPOSTResponse struct { type MembresPOSTResponse struct {
APIResponse APIResponse
Data MembresPOSTResponseData `json:"data"` Data MembresPOSTResponseData `json:"data"`

View file

@ -297,5 +297,87 @@ func addRoutes(e *echo.Echo, db *PostgresClient) error {
return err return err
} }
if err := pave.EchoRegister[MembresDisplayGETRequest](
apiGroup,
&p,
apiPath,
http.MethodGet,
"/membre/display/",
"Get membres",
"MembresDisplayGET", func(c echo.Context) (err error) {
var request, response = MembresDisplayGETRequest{}, MembresDisplayGETResponse{}
request.Query.Limit, err = strconv.Atoi(c.QueryParam("limit"))
if err != nil {
var response voki.ResponseBadRequest
response.Message = fmt.Sprintf("parsing limit: %s", err)
return c.JSON(response.StatusCode(), response)
}
if !request.Complete() {
var response voki.ResponseBadRequest
response.Message = "Incomplete MembresDisplayGET request received"
return c.JSON(response.StatusCode(), response)
}
response.Data.Membres, err = db.GetMembresForDisplay(request.Query.Limit)
if err != nil {
var response voki.ResponseBadRequest
response.Message = fmt.Sprintf("db: %s", err)
return c.JSON(response.StatusCode(), response)
}
if err := response.SetStatusCode(http.StatusOK); err != nil {
var response voki.ResponseInternalServerError
response.Message = fmt.Sprintf("handler: %s", err)
return c.JSON(response.StatusCode(), response)
}
response.Message = "ok"
return c.JSON(response.StatusCode(), response)
}); err != nil {
return err
}
if err := pave.EchoRegister[MembreDisplayGETRequest](
apiGroup,
&p,
apiPath,
http.MethodGet,
"/membre/:membre_id/display/",
"Get membre",
"MembreDisplayGET", func(c echo.Context) error {
var request, response = MembreDisplayGETRequest{}, MembreDisplayGETResponse{}
request.Param.MembreID = c.Param("membre_id")
if !request.Complete() {
var response voki.ResponseBadRequest
response.Message = "Incomplete MembreDisplayGET request received"
return c.JSON(response.StatusCode(), response)
}
membre, err := db.GetMembreForDisplay(request.Param.MembreID)
if err != nil {
var response voki.ResponseBadRequest
response.Message = fmt.Sprintf("db: %s", err)
return c.JSON(response.StatusCode(), response)
}
response.Data.Membre = membre
if err := response.SetStatusCode(http.StatusOK); err != nil {
var response voki.ResponseInternalServerError
response.Message = fmt.Sprintf("handler: %s", err)
return c.JSON(response.StatusCode(), response)
}
response.Message = "ok"
return c.JSON(response.StatusCode(), response)
}); err != nil {
return err
}
return nil return nil
} }