Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
## Unreleased
### Added
- docs: Added license
- feat: Add admin management endpoints
- feat: Add config to setup default admin accounts

### Changed
- chore: Update dependencies
Expand Down
3 changes: 3 additions & 0 deletions config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,6 @@ images:
- png
- jpg

admin:
defaultList:
- abc@gmail.com
12 changes: 12 additions & 0 deletions docs/configs.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,15 @@ images:
- `images.maxImagesPerComment` : *(Env variable : `IMAGE_MAX_IMAGES_PER_COMMENT`)* - Max number of images per comment
- `images.maxSize` : *(Env variable : `IMAGE_MAX_SIZE`)* - Image max site in bytes
- `images.acceptedExtensions` : List of file extensions allowed for file update.


---

## Admin
```yaml
admin:
defaultList:
```

### Parameters
- `admin.defaultList` : List of default administrator of the Iris instance
53 changes: 52 additions & 1 deletion docs/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ openapi: 3.0.3
info:
title: Iris API
description: API to manage ideas, votes, and comments.
version: 1.0.0
version: 1.1.0
servers:
- url: https://api.example.com
description: Production server (example)
Expand All @@ -11,6 +11,52 @@ servers:
security:
- bearerAuth: []
paths:
/v1/admin:
get:
summary: Get all the admin in database
description: Returns the list of admins
tags: [Admin]
responses:
'200':
description: Admin list
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Admin'
default:
$ref: '#/components/responses/ErrorResponse'
post:
summary: Add an admin
description: Add an user to the admin list
tags: [Admin]
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/Admin'
responses:
'200':
description: Admin added
default:
$ref: '#/components/responses/ErrorResponse'
delete:
summary: Remove an admin
description: Remove an user to the admin list
tags: [Admin]
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/Admin'
responses:
'200':
description: Admin removed
default:
$ref: '#/components/responses/ErrorResponse'
/v1/admin/me:
get:
summary: Check if the connected user is an admin
Expand Down Expand Up @@ -352,6 +398,11 @@ components:
schema:
$ref: '#/components/schemas/EnhancedError'
schemas:
Admin:
type: object
properties:
user_email:
type: string
Links:
type: object
properties:
Expand Down
49 changes: 49 additions & 0 deletions pkg/apirouter/routes/v1/admin/admin_router.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ package admin
import (
"fmt"
"github.com/RoadTripMoustache/iris_api/pkg/apirouter/middlewares"
apiUtils "github.com/RoadTripMoustache/iris_api/pkg/apirouter/utils"
ctrl "github.com/RoadTripMoustache/iris_api/pkg/controllers/admin"
"github.com/RoadTripMoustache/iris_api/pkg/enum"
"github.com/RoadTripMoustache/iris_api/pkg/errors"
adminsvc "github.com/RoadTripMoustache/iris_api/pkg/services/admin"
"github.com/gorilla/mux"
"net/http"
)
Expand All @@ -25,6 +29,51 @@ func New(router *mux.Router, parentPath string) *AdminRouter {

// InitRoutes initializes the routes for the admin API.
func (p *AdminRouter) InitRoutes() {
// Get the admin list
middlewares.AddRoute(
p.MuxRouter,
http.MethodGet,
p.Path,
http.StatusOK,
func(ctx apiUtils.Context) ([]byte, *errors.EnhancedError) {
adm, e := adminsvc.GetAdmin(ctx, ctx.UserEmail)
if e != nil || adm == nil {
return nil, errors.New(enum.AuthUnauthorized, nil)
}

return ctrl.GetAdmins(ctx)
},
)
// Add an user as an admin
middlewares.AddRoute(
p.MuxRouter,
http.MethodPost,
p.Path,
http.StatusOK,
func(ctx apiUtils.Context) ([]byte, *errors.EnhancedError) {
adm, e := adminsvc.GetAdmin(ctx, ctx.UserEmail)
if e != nil || adm == nil {
return nil, errors.New(enum.AuthUnauthorized, nil)
}

return ctrl.AddAdmin(ctx)
},
)
// Remove an user as an admin
middlewares.AddRoute(
p.MuxRouter,
http.MethodDelete,
p.Path,
http.StatusOK,
func(ctx apiUtils.Context) ([]byte, *errors.EnhancedError) {
adm, e := adminsvc.GetAdmin(ctx, ctx.UserEmail)
if e != nil || adm == nil {
return nil, errors.New(enum.AuthUnauthorized, nil)
}

return ctrl.RemoveAdmin(ctx)
},
)
// Check if current user is admin
middlewares.AddRoute(
p.MuxRouter,
Expand Down
5 changes: 5 additions & 0 deletions pkg/config/admin_models.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package config

type AdminConfig struct {
DefaultList []string `yaml:"defaultList"`
}
1 change: 1 addition & 0 deletions pkg/config/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ type Config struct {
Database DatabaseConfig `yaml:"database"`
Server ServerConfig `yaml:"server"`
Images ImageConfig `yaml:"images"`
Admin AdminConfig `yaml:"admin"`
}
31 changes: 31 additions & 0 deletions pkg/controllers/admin/add_admin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Package admin contains all the functions exposed by the Admin controller.
package admin

import (
apiUtils "github.com/RoadTripMoustache/iris_api/pkg/apirouter/utils"
"github.com/RoadTripMoustache/iris_api/pkg/controllers/utils"
"github.com/RoadTripMoustache/iris_api/pkg/dbmodels/admin"
"github.com/RoadTripMoustache/iris_api/pkg/enum"
"github.com/RoadTripMoustache/iris_api/pkg/errors"
adminsvc "github.com/RoadTripMoustache/iris_api/pkg/services/admin"
)

// AddAdmin - Add an user as admin
func AddAdmin(ctx apiUtils.Context) ([]byte, *errors.EnhancedError) {
payload := admin.Admin{}
if err := utils.BodyFormatter(ctx.Body, &payload); err != nil {
return nil, errors.New(enum.BadRequest, err)
}

adm, _ := adminsvc.GetAdmin(ctx, payload.UserEmail)
if adm != nil {
return utils.PrepareResponse(nil)
}

e := adminsvc.AddAdmin(ctx, payload.UserEmail)
if e != nil {
return nil, e
}

return utils.PrepareResponse(nil)
}
18 changes: 18 additions & 0 deletions pkg/controllers/admin/get_admins.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Package admin contains all the functions exposed by the Admin controller.
package admin

import (
apiUtils "github.com/RoadTripMoustache/iris_api/pkg/apirouter/utils"
"github.com/RoadTripMoustache/iris_api/pkg/controllers/utils"
"github.com/RoadTripMoustache/iris_api/pkg/errors"
adminsvc "github.com/RoadTripMoustache/iris_api/pkg/services/admin"
)

// GetAdmins returns the list of admins
func GetAdmins(ctx apiUtils.Context) ([]byte, *errors.EnhancedError) {
admList, e := adminsvc.GetAdmins(ctx)
if e != nil {
return nil, e
}
return utils.PrepareResponse(admList)
}
4 changes: 2 additions & 2 deletions pkg/controllers/admin/is_admin.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ import (

// IsCurrentUserAdmin returns whether the authenticated user is an admin.
func IsCurrentUserAdmin(ctx apiUtils.Context) ([]byte, *errors.EnhancedError) {
if ctx.UserID == "" {
if ctx.UserEmail == "" {
return nil, errors.New(enum.AuthUnauthorized, nil)
}
adm, e := adminsvc.GetAdmin(ctx, ctx.UserID)
adm, e := adminsvc.GetAdmin(ctx, ctx.UserEmail)
if e != nil {
return nil, e
}
Expand Down
31 changes: 31 additions & 0 deletions pkg/controllers/admin/remove_admin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Package admin contains all the functions exposed by the Admin controller.
package admin

import (
apiUtils "github.com/RoadTripMoustache/iris_api/pkg/apirouter/utils"
"github.com/RoadTripMoustache/iris_api/pkg/controllers/utils"
"github.com/RoadTripMoustache/iris_api/pkg/enum"
"github.com/RoadTripMoustache/iris_api/pkg/errors"
"github.com/RoadTripMoustache/iris_api/pkg/models/admin"
adminsvc "github.com/RoadTripMoustache/iris_api/pkg/services/admin"
)

// RemoveAdmin - Remove an user from the admin list
func RemoveAdmin(ctx apiUtils.Context) ([]byte, *errors.EnhancedError) {
payload := admin.Admin{}
if err := utils.BodyFormatter(ctx.Body, &payload); err != nil {
return nil, errors.New(enum.BadRequest, err)
}

adm, _ := adminsvc.GetAdmin(ctx, payload.UserEmail)
if adm == nil {
return utils.PrepareResponse(nil)
}

e := adminsvc.DeleteAdmin(ctx, payload.UserEmail)
if e != nil {
return nil, e
}

return utils.PrepareResponse(nil)
}
8 changes: 4 additions & 4 deletions pkg/dbmodels/admin/admin.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,16 @@ import (

const (
AdminCollectionName string = "admins"
AdminUserIDLabel string = "user_id"
AdminUserEmailLabel string = "user_email"
)

type Admin struct {
UserID string `json:"user_id"`
UserEmail string `json:"user_email"`
}

func (a *Admin) ToMap() map[string]interface{} {
return map[string]interface{}{
"user_id": a.UserID,
"user_email": a.UserEmail,
}
}

Expand All @@ -31,7 +31,7 @@ func AdminFromMap(m map[string]interface{}) *Admin {

func ToAdminModel(admin Admin) models.Admin {
modelAdmin := models.Admin{
UserID: admin.UserID,
UserEmail: admin.UserEmail,
}

return modelAdmin
Expand Down
6 changes: 3 additions & 3 deletions pkg/dbmodels/admin/data_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@ import (

var (
adminMap = map[string]interface{}{
"user_id": "titiU",
"user_email": "titiU",
}

admin = Admin{
UserID: "titiU",
UserEmail: "titiU",
}

adminModel = models.Admin{
UserID: "titiU",
UserEmail: "titiU",
}
)
12 changes: 6 additions & 6 deletions pkg/mocks/services/admin/mock_admin_management_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ type MockAdminManagementService struct {
mock.Mock
}

func (m *MockAdminManagementService) GetAdmin(ctx utils.Context, userID string) (*dbmodels.Admin, *errors.EnhancedError) {
args := m.Called(ctx, userID)
func (m *MockAdminManagementService) GetAdmin(ctx utils.Context, userEmail string) (*dbmodels.Admin, *errors.EnhancedError) {
args := m.Called(ctx, userEmail)
var activity *dbmodels.Admin
if args.Get(0) != nil {
activity = args.Get(0).(*dbmodels.Admin)
Expand All @@ -39,17 +39,17 @@ func (m *MockAdminManagementService) GetAdmins(ctx utils.Context) ([]*dbmodels.A
return admins, enhancedError
}

func (m *MockAdminManagementService) AddAdmin(ctx utils.Context, userID string) *errors.EnhancedError {
args := m.Called(ctx, userID)
func (m *MockAdminManagementService) AddAdmin(ctx utils.Context, userEmail string) *errors.EnhancedError {
args := m.Called(ctx, userEmail)
var enhancedError *errors.EnhancedError
if args.Get(0) != nil {
enhancedError = args.Get(0).(*errors.EnhancedError)
}
return enhancedError
}

func (m *MockAdminManagementService) DeleteAdmin(ctx utils.Context, userID string) *errors.EnhancedError {
args := m.Called(ctx, userID)
func (m *MockAdminManagementService) DeleteAdmin(ctx utils.Context, userEmail string) *errors.EnhancedError {
args := m.Called(ctx, userEmail)
var enhancedError *errors.EnhancedError
if args.Get(0) != nil {
enhancedError = args.Get(0).(*errors.EnhancedError)
Expand Down
2 changes: 1 addition & 1 deletion pkg/models/admin/admin.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
package admin

type Admin struct {
UserID string `json:"user_id"`
UserEmail string `json:"user_email"`
}
Loading