Skip to content

Commit

Permalink
Merge pull request #7 from SwimResults/develop
Browse files Browse the repository at this point in the history
Register Notification User
  • Loading branch information
konrad2002 authored Sep 23, 2024
2 parents 85f6e25 + 9b3f614 commit 7046ddc
Show file tree
Hide file tree
Showing 11 changed files with 424 additions and 3 deletions.
1 change: 1 addition & 0 deletions controller/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ func Run() {
userController()
widgetController()
dashboardController()
notificationUserController()

router.GET("/actuator", actuator)

Expand Down
165 changes: 165 additions & 0 deletions controller/notification_user_controller.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
package controller

import (
"github.com/gin-gonic/gin"
"github.com/swimresults/user-service/dto"
"github.com/swimresults/user-service/model"
"github.com/swimresults/user-service/service"
"go.mongodb.org/mongo-driver/bson/primitive"
"net/http"
)

func notificationUserController() {
router.GET("/notification_users", getNotificationUsers)
router.GET("/notification_user", getNotificationUser)
router.GET("/notification_user/:id", getNotificationUserById)

router.POST("/notification_user", addNotificationUser)
router.POST("/notification_user/register", registerNotificationUser)

router.DELETE("/notification_user/:id", removeNotificationUser)

router.PUT("/notification_user", updateNotificationUser)

router.OPTIONS("/notification_user", okay)
router.OPTIONS("/notification_user/register", okay)
}

func getNotificationUsers(c *gin.Context) {

if failIfNotRoot(c) {
return
}

users, err := service.GetNotificationUsers()
if err != nil {
c.IndentedJSON(http.StatusInternalServerError, gin.H{"message": err.Error()})
return
}

c.IndentedJSON(http.StatusOK, users)
}

func getNotificationUser(c *gin.Context) {

claims, err1 := getClaimsFromAuthHeader(c)

if err1 != nil {
c.IndentedJSON(http.StatusNotFound, gin.H{"message": err1.Error()})
return
}

user, err := service.GetUserByKeycloakId(claims.Sub)
if err != nil {
c.IndentedJSON(http.StatusNotFound, gin.H{"message": err.Error()})
return
}

notificationUser, err2 := service.GetNotificationUserById(user.Identifier)
if err2 != nil {
c.IndentedJSON(http.StatusNotFound, gin.H{"message": err.Error()})
return
}

c.IndentedJSON(http.StatusOK, notificationUser)
}

func getNotificationUserById(c *gin.Context) {

if failIfNotRoot(c) {
return
}

id, convErr := primitive.ObjectIDFromHex(c.Param("id"))
if convErr != nil {
c.IndentedJSON(http.StatusBadRequest, gin.H{"message": "given id was not of type ObjectID"})
return
}

user, err := service.GetNotificationUserById(id)
if err != nil {
c.IndentedJSON(http.StatusNotFound, gin.H{"message": err.Error()})
return
}

c.IndentedJSON(http.StatusOK, user)
}

func removeNotificationUser(c *gin.Context) {

if failIfNotRoot(c) {
return
}

id, convErr := primitive.ObjectIDFromHex(c.Param("id"))
if convErr != nil {
c.IndentedJSON(http.StatusBadRequest, gin.H{"message": "given id was not of type ObjectID"})
return
}

err := service.RemoveNotificationUserById(id)
if err != nil {
c.IndentedJSON(http.StatusNotFound, gin.H{"message": err.Error()})
return
}

c.IndentedJSON(http.StatusNoContent, "")
}

func addNotificationUser(c *gin.Context) {

if failIfNotRoot(c) {
return
}

var user model.NotificationUser
if err := c.BindJSON(&user); err != nil {
c.IndentedJSON(http.StatusInternalServerError, gin.H{"message": err.Error()})
return
}

r, err := service.AddNotificationUser(user)
if err != nil {
c.IndentedJSON(http.StatusInternalServerError, gin.H{"message": err.Error()})
return
}

c.IndentedJSON(http.StatusOK, r)
}

func updateNotificationUser(c *gin.Context) {

if failIfNotRoot(c) {
return
}

var user model.NotificationUser
if err := c.BindJSON(&user); err != nil {
c.IndentedJSON(http.StatusInternalServerError, gin.H{"message": err.Error()})
return
}

r, err := service.UpdateNotificationUser(user)
if err != nil {
c.IndentedJSON(http.StatusNotFound, gin.H{"message": err.Error()})
return
}

c.IndentedJSON(http.StatusOK, r)
}

func registerNotificationUser(c *gin.Context) {
var request dto.RegisterNotificationUserRequestDto
if err := c.BindJSON(&request); err != nil {
c.IndentedJSON(http.StatusInternalServerError, gin.H{"message": err.Error()})
return
}

r, err := service.RegisterNotificationUser(request.Token)
if err != nil {
c.IndentedJSON(http.StatusInternalServerError, gin.H{"message": err.Error()})
return
}

c.IndentedJSON(http.StatusOK, r)
}
95 changes: 95 additions & 0 deletions docs/notifications.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
- different options in terms of complexity:
- special notification settings for each combination of
- meeting
- athlete
- team
- only default settings
- some settings for different notification types
- files
- favorites
- team mates
- myself
- settings for time of notification → 15 min before start?

# Notify about…

- free text

## Before Meeting

- ~~new files → prob only interesting for start list? other publications?~~
- start list available/published → to find own starts and add favourites
- meeting upcoming reminder → to remember that SwimResults exists for this meeting (only when subscribed)
- new meeting with your athlete → remember user that app exists (only if not subscribed but meeting with his athlete, instead of two previous ones?)

## During Meeting

- live stream info → maybe as part of start notification (meeting has been started on time, see live timing and stream)
- me → be informed about my own start
- upcoming start → reminder to not miss a start
- new result published → to know places as fast as possible
- new start imported → final qualification, changes in the start list
- favourites
- upcoming start → don’t miss your friend’s/child’s/favourite’s starts
- new result published → to know places as fast as possible, really necessary?
- ~~swimming right now? → live link + stream → upcoming start is enough~~
- new start imported → final qualification, changes in the start list
- team mates
- ~~upcoming start → too much~~
- ~~new result published → too much~~
- ~~swimming right now? → live link + stream~~
- new start imported → final qualification (only finals!)
- schedule
- next start delayed → to know if you have more break time
- next start early → to not miss starts
- changes/updates (break shortened, etc.) → to know about changed breaks/warmup times

## After Meeting

- results and results file published → to receive final results without checking all the time

# Notification Settings

configure which…

Athlete Notifications

Favourites Notifications

Schedule Notifications

Meeting Notifications

… you want to receive

# Notification Service vs. User Service

| Notification Service | Notifications in User Service |
| --- | --- |
| not affected by user service availability | no new micro service |
| | no inter-service relations since notifications are user-related |
| | less server resources needed |
| | user settings and notification settings in one place |
| | closer relation to subscriptions |

# SwimResults User ↔ Notification User

- Notifications are pay feature
- with SwimResults PLUS or SwimResults PRO user has notifications
- for both an account is required
- notifications per account
- no notification user without account?
- but what about general notifications for everyone?! → notification identifier required
- what about multiple devices of the same user?
- maybe subscription not related to account?!
- app only with account?

# Questions to clarify

## How prevent multiple notifications for the same reason?

## Should subscriptions always be related to a user account?

## How to handle multiple devices of the same user?

## Are there notifications without subscription?
5 changes: 5 additions & 0 deletions dto/register_notification_user_request.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package dto

type RegisterNotificationUserRequestDto struct {
Token string `json:"token,omitempty"`
}
14 changes: 13 additions & 1 deletion model/following.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,19 @@ import (
"time"
)

type Following struct {
type FollowingAthlete struct {
AthleteId primitive.ObjectID `json:"athlete_id" bson:"athlete_id"`
AddedAt time.Time `json:"added_at,omitempty" bson:"added_at,omitempty"`
}

// FollowingTeam TODO make teams followable
type FollowingTeam struct {
TeamId primitive.ObjectID `json:"team_id" bson:"team_id"`
AddedAt time.Time `json:"added_at,omitempty" bson:"added_at,omitempty"`
}

// Following TODO use merged struct
type Following struct {
FollowingAthletes []FollowingAthlete `json:"following_athletes,omitempty" bson:"following_athletes,omitempty"`
FollowingTeams []FollowingTeam `json:"following_teams,omitempty" bson:"following_teams,omitempty"`
}
11 changes: 11 additions & 0 deletions model/notification_user.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package model

import "go.mongodb.org/mongo-driver/bson/primitive"

type NotificationUser struct {
Identifier primitive.ObjectID `json:"_id,omitempty" bson:"_id,omitempty"`
UserId primitive.ObjectID `json:"user_id,omitempty" bson:"user_id,omitempty"`
Token string `json:"token,omitempty" bson:"token,omitempty"`
Settings Settings `json:"settings,omitempty" bson:"settings,omitempty"`
Meetings []string `json:"meetings,omitempty" bson:"meetings,omitempty"`
}
2 changes: 1 addition & 1 deletion model/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
type User struct {
Identifier primitive.ObjectID `json:"_id,omitempty" bson:"_id,omitempty"`
KeycloakId string `json:"keycloak_id,omitempty" bson:"keycloak_id,omitempty"`
Following []Following `json:"following,omitempty" bson:"following,omitempty"`
Following []FollowingAthlete `json:"following,omitempty" bson:"following,omitempty"`
OwnAthleteId *primitive.ObjectID `json:"own_athlete_id,omitempty" bson:"own_athlete_id,omitempty"`
Settings Settings `json:"settings,omitempty" bson:"settings,omitempty"`
Meetings []string `json:"meetings,omitempty" bson:"meetings,omitempty"`
Expand Down
1 change: 1 addition & 0 deletions model/widget_tile.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ import "go.mongodb.org/mongo-driver/bson/primitive"
type WidgetTile struct {
WidgetID primitive.ObjectID `json:"-" bson:"widget_id,omitempty"`
Widget Widget `json:"widget,omitempty" bson:"-"`
Data any `json:"data,omitempty" bson:"data,omitempty"`
OrderPosition int `json:"order_position,omitempty" bson:"order_position,omitempty"`
}
Loading

0 comments on commit 7046ddc

Please sign in to comment.