2024-03-01 13:37:01 +05:30

123 lines
4.6 KiB
Go

package family
import (
"context"
"database/sql"
"errors"
"fmt"
"github.com/ente-io/museum/ente"
"github.com/ente-io/stacktrace"
"github.com/sirupsen/logrus"
)
// LeaveFamily removes the actor user from the family in which the user belongs to.
func (c *Controller) LeaveFamily(ctx context.Context, userID int64) error {
user, err := c.UserRepo.Get(userID)
if err != nil {
return stacktrace.Propagate(err, "")
}
if user.FamilyAdminID == nil {
logrus.WithField("user_id", userID).Info("not part of any family group")
// user has either not joined any group or already left it.
return nil
}
if *user.FamilyAdminID == userID {
return stacktrace.Propagate(ente.ErrPermissionDenied, "admin can not leave the family group")
}
err = c.FamilyRepo.RemoveMember(ctx, *user.FamilyAdminID, userID, ente.LEFT)
if err != nil {
return stacktrace.Propagate(err, "")
}
go func() {
notificationErr := c.sendNotification(ctx, *user.FamilyAdminID, userID, ente.LEFT, nil)
if notificationErr != nil {
logrus.WithError(notificationErr).Error("family-plan: left notification failed")
}
}()
return nil
}
// InviteInfo return basic information about the invite
func (c *Controller) InviteInfo(ctx context.Context, token string) (ente.InviteInfoResponse, error) {
familyMember, err := c.FamilyRepo.GetInvite(token)
if err != nil && errors.Is(err, sql.ErrNoRows) {
return ente.InviteInfoResponse{}, stacktrace.Propagate(err, "invite not found")
} else if err != nil {
return ente.InviteInfoResponse{}, stacktrace.Propagate(err, "failed to fetch invite info")
}
if familyMember.Status != ente.INVITED {
return ente.InviteInfoResponse{}, stacktrace.Propagate(ente.ErrBadRequest, "invited is not valid any more: %s ", familyMember.Status)
}
adminUser, err := c.UserRepo.Get(familyMember.AdminUserID)
if err != nil {
return ente.InviteInfoResponse{}, stacktrace.Propagate(err, "failed to fetch user")
}
// verify that the invitor is still an admin
if adminUser.FamilyAdminID == nil || *adminUser.FamilyAdminID != adminUser.ID {
return ente.InviteInfoResponse{}, stacktrace.Propagate(fmt.Errorf("inviter is no longer a admin of family plam "), "")
}
return ente.InviteInfoResponse{
ID: familyMember.ID,
AdminEmail: adminUser.Email,
}, nil
}
// AcceptInvite accepts a family invite as long as it's in invited state.
func (c *Controller) AcceptInvite(ctx context.Context, token string) (ente.AcceptInviteResponse, error) {
familyMember, err := c.FamilyRepo.GetInvite(token)
if err != nil {
return ente.AcceptInviteResponse{}, stacktrace.Propagate(err, "invite not found")
}
adminUser, err := c.UserRepo.Get(familyMember.AdminUserID)
if err != nil {
return ente.AcceptInviteResponse{}, stacktrace.Propagate(err, "failed to fetch user")
}
// verify that the invitor is still an admin
if adminUser.FamilyAdminID == nil || *adminUser.FamilyAdminID != adminUser.ID {
return ente.AcceptInviteResponse{}, stacktrace.Propagate(fmt.Errorf("inviter is no longer a admin of family plam "), "")
}
// Accept invitation and notify admin if it's not accepted already
if familyMember.Status != ente.ACCEPTED {
// if the state is invited, accept the invitation and send email notification to the admin.
if familyMember.Status == ente.INVITED {
err = c.FamilyRepo.AcceptInvite(ctx, familyMember.AdminUserID, familyMember.MemberUserID, token)
if err != nil {
return ente.AcceptInviteResponse{}, stacktrace.Propagate(err, "")
}
go func() {
notificationErr := c.sendNotification(ctx, familyMember.AdminUserID, familyMember.MemberUserID, ente.ACCEPTED, nil)
if notificationErr != nil {
logrus.WithError(notificationErr).Error("family-plan: accepted notification failed")
}
}()
} else {
return ente.AcceptInviteResponse{}, stacktrace.Propagate(ente.ErrInvalidPassword, "invited state is not valid any more: %s ", familyMember.Status)
}
}
bonus, bonusErr := c.UserCacheCtrl.GetActiveStorageBonus(ctx, adminUser.ID)
if bonusErr != nil {
return ente.AcceptInviteResponse{}, bonusErr
}
adminSubscription, subErr := c.BillingCtrl.GetActiveSubscription(adminUser.ID)
if subErr != nil && !errors.Is(subErr, ente.ErrNoActiveSubscription) {
return ente.AcceptInviteResponse{}, stacktrace.Propagate(subErr, "")
}
adminUsableBonus := int64(0)
if subErr != nil && errors.Is(subErr, ente.ErrNoActiveSubscription) {
adminUsableBonus = bonus.GetUsableBonus(0)
} else {
adminUsableBonus = bonus.GetUsableBonus(adminSubscription.Storage)
}
return ente.AcceptInviteResponse{
AdminEmail: adminUser.Email,
Storage: adminSubscription.Storage + adminUsableBonus,
ExpiryTime: adminSubscription.ExpiryTime,
}, nil
}