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
11 changes: 11 additions & 0 deletions server/action/admin/analytics/router.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package analytics

import "github.com/go-chi/chi"

func Router() chi.Router {
r := chi.NewRouter()

r.Get("/users", details)

return r
}
93 changes: 93 additions & 0 deletions server/action/admin/analytics/user.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package analytics

import (
"net/http"
"time"

"github.com/factly/kavach-server/model"
"github.com/factly/x/errorx"
"github.com/factly/x/loggerx"
"github.com/factly/x/renderx"
)

type Data struct {
Name string `json:"name"`
Count int64 `json:"count"`
}

type response struct {
TotalUsers int64 `json:"total_users"`
Analytics []Data `json:"analytics"`
}

type rawdata struct {
Name time.Time
Count int64
}

func details(w http.ResponseWriter, r *http.Request) {
result := &response{}
from := r.URL.Query().Get("from")
to := r.URL.Query().Get("to")

// Get total users
err := model.DB.Model(&model.User{}).Count(&result.TotalUsers).Error
if err != nil {
loggerx.Error(err)
errorx.Render(w, errorx.Parser(errorx.DBError()))
return
}

if from == "" || to == "" {
renderx.JSON(w, http.StatusOK, result)
return
}

fromTime, err := time.Parse("2006-01-02", from)
if err != nil {
loggerx.Error(err)
errorx.Render(w, errorx.Parser(errorx.InvalidID()))
return
}
toTime, err := time.Parse("2006-01-02", to)
if err != nil {
loggerx.Error(err)
errorx.Render(w, errorx.Parser(errorx.InvalidID()))
return
}
toTime = toTime.Add(23*time.Hour + 59*time.Minute + 59*time.Second)

if toTime.Sub(fromTime).Hours() > 24*30*12 {
errorx.Render(w, errorx.Parser(errorx.GetMessage("range cannot be more than 12 months", http.StatusUnprocessableEntity)))
return
}

var format, level string

if toTime.Sub(fromTime).Hours() <= 24*30 {
format = "02/01/2006"
level = "day"
} else {
format = "Jan 2006"
level = "month"
}

tx := model.DB.Model(&model.User{}).Select("count(id) as count, date_trunc('"+level+"', created_at) as name").Where("created_at BETWEEN ? AND ?", fromTime, toTime).Group("name").Order("name")

rawAnalytics := make([]rawdata, 0)
err = tx.Scan(&rawAnalytics).Error
if err != nil {
loggerx.Error(err)
errorx.Render(w, errorx.Parser(errorx.DBError()))
return
}

for _, raw := range rawAnalytics {
result.Analytics = append(result.Analytics, Data{
Name: raw.Name.Format(format),
Count: raw.Count,
})
}

renderx.JSON(w, http.StatusOK, result)
}
2 changes: 2 additions & 0 deletions server/action/admin/route.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"errors"
"net/http"

"github.com/factly/kavach-server/action/admin/analytics"
"github.com/factly/kavach-server/action/admin/application"
"github.com/factly/kavach-server/action/admin/organisation"
"github.com/factly/kavach-server/action/admin/user"
Expand All @@ -19,6 +20,7 @@ func AdminRouter() chi.Router {
r.With(CheckMasterKey).Route("/", func(r chi.Router) {
r.Mount("/users", user.Router())
r.Mount("/organisations", organisation.Router())
r.Mount("/analytics", analytics.Router())
r.Post("/applications/user", application.AddUser)
r.Get("/applications/{application_id}", application.ListOrgs)
})
Expand Down
13 changes: 13 additions & 0 deletions server/action/admin/user/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package user
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"net/http"

Expand Down Expand Up @@ -73,6 +74,18 @@ func create(w http.ResponseWriter, r *http.Request) {
return
}

if response.StatusCode != http.StatusCreated {
if response.StatusCode == http.StatusConflict {
msg := "user email already exists"
loggerx.Error(errors.New(msg))
errorx.Render(w, errorx.Parser(errorx.GetMessage(msg, http.StatusConflict)))
return
}
loggerx.Error(errors.New("kratos returned status " + fmt.Sprint(response.StatusCode)))
errorx.Render(w, errorx.Parser(errorx.InternalServerError()))
return
}

responseBody := make(map[string]interface{})

err = json.NewDecoder(response.Body).Decode(&responseBody)
Expand Down
56 changes: 50 additions & 6 deletions server/action/admin/user/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package user

import (
"net/http"
"time"

"github.com/factly/kavach-server/model"
"github.com/factly/x/errorx"
Expand All @@ -20,6 +21,9 @@ func list(w http.ResponseWriter, r *http.Request) {
userIDs := r.URL.Query()["id"]
searchQuery := r.URL.Query().Get("q")
sort := r.URL.Query().Get("sort")
from := r.URL.Query().Get("from")
to := r.URL.Query().Get("to")
isReport := r.URL.Query().Get("is_report")
res := &response{}

if sort != "asc" {
Expand All @@ -28,12 +32,52 @@ func list(w http.ResponseWriter, r *http.Request) {

if len(userIDs) == 0 {
qs := "%" + searchQuery + "%"
offset, limit := paginationx.Parse(r.URL.Query())
err := model.DB.Model(&model.User{}).Preload("Organisations").Where("display_name ILIKE ? OR email ILIKE ?", qs, qs).Order("created_at " + sort).Count(&res.Total).Offset(offset).Limit(limit).Find(&res.Nodes).Error
if err != nil {
loggerx.Error(err)
errorx.Render(w, errorx.Parser(errorx.DBError()))
return
tx := model.DB.Model(&model.User{}).Preload("Organisations").Where("display_name ILIKE ? OR email ILIKE ?", qs, qs).Order("created_at " + sort)

if isReport == "true" {
var fromTime, toTime time.Time
var err error
if from == "" || to == "" {
toTime = time.Now()
fromTime = toTime.AddDate(0, 0, -30)
} else {
fromTime, err = time.Parse("2006-01-02", from)
if err != nil {
loggerx.Error(err)
errorx.Render(w, errorx.Parser(errorx.InvalidID()))
return
}
toTime, err = time.Parse("2006-01-02", to)
if err != nil {
loggerx.Error(err)
errorx.Render(w, errorx.Parser(errorx.InvalidID()))
return
}
toTime = toTime.Add(23*time.Hour + 59*time.Minute + 59*time.Second)
}

if toTime.Sub(fromTime).Hours() > 24*30*3 {
errorx.Render(w, errorx.Parser(errorx.GetMessage("range cannot be more than 3 months", http.StatusUnprocessableEntity)))
return
}

tx.Where("created_at BETWEEN ? AND ?", fromTime, toTime)

err = tx.Find(&res.Nodes).Error
if err != nil {
loggerx.Error(err)
errorx.Render(w, errorx.Parser(errorx.DBError()))
return
}
res.Total = int64(len(res.Nodes))
} else {
offset, limit := paginationx.Parse(r.URL.Query())
err := tx.Count(&res.Total).Offset(offset).Limit(limit).Find(&res.Nodes).Error
if err != nil {
loggerx.Error(err)
errorx.Render(w, errorx.Parser(errorx.DBError()))
return
}
}
} else {
err := model.DB.Model(&model.User{}).Preload("Organisations").Where(userIDs).Find(&res.Nodes).Error
Expand Down
Loading