backend moved to separate directory

backend: deleted the old structure
This commit is contained in:
Alex
2025-02-28 08:52:04 +01:00
parent ad599ae3f4
commit 2ffd1f439f
88 changed files with 112 additions and 9 deletions

View File

@@ -0,0 +1,12 @@
package services
import (
"GoMembership/internal/repositories"
)
type BankAccountServiceInterface interface {
}
type BankAccountService struct {
Repo repositories.BankAccountRepositoryInterface
}

View File

@@ -0,0 +1,22 @@
package services
import (
"time"
"GoMembership/internal/models"
"GoMembership/internal/repositories"
)
type ConsentServiceInterface interface {
RegisterConsent(consent *models.Consent) (uint, error)
}
type ConsentService struct {
Repo repositories.ConsentRepositoryInterface
}
func (service *ConsentService) RegisterConsent(consent *models.Consent) (uint, error) {
consent.CreatedAt = time.Now()
consent.UpdatedAt = time.Now()
return service.Repo.CreateConsent(consent)
}

View File

@@ -0,0 +1,240 @@
package services
import (
"bytes"
"html/template"
"gopkg.in/gomail.v2"
"GoMembership/internal/config"
"GoMembership/internal/constants"
"GoMembership/internal/models"
"GoMembership/pkg/logger"
)
type EmailService struct {
dialer *gomail.Dialer
}
func NewEmailService(host string, port int, username string, password string) *EmailService {
dialer := gomail.NewDialer(host, port, username, password)
return &EmailService{dialer: dialer}
}
func (s *EmailService) SendEmail(to string, subject string, body string, bodyTXT string, replyTo string) error {
msg := gomail.NewMessage()
msg.SetHeader("From", s.dialer.Username)
msg.SetHeader("To", to)
msg.SetHeader("Subject", subject)
if replyTo != "" {
msg.SetHeader("REPLY_TO", replyTo)
}
if bodyTXT != "" {
msg.SetBody("text/plain", bodyTXT)
}
msg.AddAlternative("text/html", body)
// msg.WriteTo(os.Stdout)
if err := s.dialer.DialAndSend(msg); err != nil {
logger.Error.Printf("Could not send email to %s: %v", to, err)
return err
}
logger.Info.Printf("Email sent to %s", to)
return nil
}
func ParseTemplate(filename string, data interface{}) (string, error) {
// Read the email template file
templateDir := config.Templates.MailPath
tpl, err := template.ParseFiles(templateDir + "/" + filename)
if err != nil {
logger.Error.Printf("Failed to parse email template: %v", err)
return "", err
}
// Buffer to hold the rendered template
var tplBuffer bytes.Buffer
if err := tpl.Execute(&tplBuffer, data); err != nil {
logger.Error.Printf("Failed to execute email template: %v", err)
return "", err
}
return tplBuffer.String(), nil
}
func (s *EmailService) SendVerificationEmail(user *models.User, token *string) error {
// Prepare data to be injected into the template
data := struct {
FirstName string
LastName string
Token string
BASEURL string
}{
FirstName: user.FirstName,
LastName: user.LastName,
Token: *token,
BASEURL: config.Site.BaseURL,
}
subject := constants.MailVerificationSubject
body, err := ParseTemplate("mail_verification.tmpl", data)
if err != nil {
logger.Error.Print("Couldn't send verification mail")
return err
}
return s.SendEmail(user.Email, subject, body, "", "")
}
func (s *EmailService) SendChangePasswordEmail(user *models.User, token *string) error {
// Prepare data to be injected into the template
data := struct {
FirstName string
LastName string
Token string
BASEURL string
UserID uint
}{
FirstName: user.FirstName,
LastName: user.LastName,
Token: *token,
BASEURL: config.Site.BaseURL,
UserID: user.ID,
}
subject := constants.MailChangePasswordSubject
htmlBody, err := ParseTemplate("mail_change_password.tmpl", data)
if err != nil {
logger.Error.Print("Couldn't parse password mail")
return err
}
plainBody, err := ParseTemplate("mail_change_password.txt.tmpl", data)
if err != nil {
logger.Error.Print("Couldn't parse password mail")
return err
}
return s.SendEmail(user.Email, subject, htmlBody, plainBody, "")
}
func (s *EmailService) SendWelcomeEmail(user *models.User) error {
// Prepare data to be injected into the template
data := struct {
Company string
FirstName string
MembershipModel string
BASEURL string
MembershipID uint
MembershipFee float32
Logo string
WebsiteTitle string
RentalFee float32
}{
Company: user.Company,
FirstName: user.FirstName,
MembershipModel: user.Membership.SubscriptionModel.Name,
MembershipID: user.Membership.ID,
MembershipFee: float32(user.Membership.SubscriptionModel.MonthlyFee),
RentalFee: float32(user.Membership.SubscriptionModel.HourlyRate),
BASEURL: config.Site.BaseURL,
WebsiteTitle: config.Site.WebsiteTitle,
Logo: config.Templates.LogoURI,
}
subject := constants.MailWelcomeSubject
htmlBody, err := ParseTemplate("mail_welcome.tmpl", data)
if err != nil {
logger.Error.Print("Couldn't send welcome mail")
return err
}
plainBody, err := ParseTemplate("mail_welcome.txt.tmpl", data)
if err != nil {
logger.Error.Print("Couldn't parse password mail")
return err
}
return s.SendEmail(user.Email, subject, htmlBody, plainBody, "")
}
func (s *EmailService) SendRegistrationNotification(user *models.User) error {
// Prepare data to be injected into the template
data := struct {
FirstName string
DateOfBirth string
LastName string
MembershipModel string
Address string
IBAN string
Email string
Phone string
City string
Company string
ZipCode string
BASEURL string
MembershipID uint
RentalFee float32
MembershipFee float32
Logo string
WebsiteTitle string
}{
Company: user.Company,
FirstName: user.FirstName,
LastName: user.LastName,
MembershipModel: user.Membership.SubscriptionModel.Name,
MembershipID: user.Membership.ID,
MembershipFee: float32(user.Membership.SubscriptionModel.MonthlyFee),
RentalFee: float32(user.Membership.SubscriptionModel.HourlyRate),
Address: user.Address,
ZipCode: user.ZipCode,
City: user.City,
DateOfBirth: user.DateOfBirth.Format("20060102"),
Email: user.Email,
Phone: user.Phone,
IBAN: user.BankAccount.IBAN,
BASEURL: config.Site.BaseURL,
Logo: config.Templates.LogoURI,
WebsiteTitle: config.Site.WebsiteTitle,
}
subject := constants.MailRegistrationSubject
htmlBody, err := ParseTemplate("mail_registration.tmpl", data)
if err != nil {
logger.Error.Print("Couldn't send admin notification mail")
return err
}
plainBody, err := ParseTemplate("mail_registration.txt.tmpl", data)
if err != nil {
logger.Error.Print("Couldn't parse password mail")
return err
}
return s.SendEmail(config.Recipients.UserRegistration, subject, htmlBody, plainBody, "")
}
func (s *EmailService) RelayContactFormMessage(sender string, name string, message string) error {
data := struct {
Message string
Name string
BASEURL string
Logo string
WebsiteTitle string
}{
Message: message,
Name: name,
BASEURL: config.Site.BaseURL,
Logo: config.Templates.LogoURI,
WebsiteTitle: config.Site.WebsiteTitle,
}
subject := constants.MailContactSubject
htmlBody, err := ParseTemplate("mail_contact_form.tmpl", data)
if err != nil {
logger.Error.Print("Couldn't send contact form message mail")
return err
}
plainBody, err := ParseTemplate("mail_contact_form.txt.tmpl", data)
if err != nil {
logger.Error.Print("Couldn't parse password mail")
return err
}
return s.SendEmail(config.Recipients.ContactForm, subject, htmlBody, plainBody, sender)
}

View File

@@ -0,0 +1,18 @@
package services
import (
"GoMembership/internal/models"
"GoMembership/internal/repositories"
)
type LicenceInterface interface {
GetAllCategories() ([]models.Category, error)
}
type LicenceService struct {
Repo repositories.LicenceInterface
}
func (s *LicenceService) GetAllCategories() ([]models.Category, error) {
return s.Repo.GetAllCategories()
}

View File

@@ -0,0 +1,100 @@
package services
import (
"time"
"GoMembership/internal/models"
"GoMembership/internal/repositories"
"GoMembership/pkg/errors"
)
type MembershipServiceInterface interface {
RegisterMembership(membership *models.Membership) (uint, error)
FindMembershipByUserID(userID uint) (*models.Membership, error)
RegisterSubscription(subscription *models.SubscriptionModel) (uint, error)
UpdateSubscription(subscription *models.SubscriptionModel) (*models.SubscriptionModel, error)
DeleteSubscription(id *uint, name *string) error
GetSubscriptionModelNames() ([]string, error)
GetSubscriptionByName(modelname *string) (*models.SubscriptionModel, error)
GetSubscriptions(where map[string]interface{}) (*[]models.SubscriptionModel, error)
}
type MembershipService struct {
Repo repositories.MembershipRepositoryInterface
SubscriptionRepo repositories.SubscriptionModelsRepositoryInterface
}
func (service *MembershipService) RegisterMembership(membership *models.Membership) (uint, error) {
membership.StartDate = time.Now()
return service.Repo.CreateMembership(membership)
}
func (service *MembershipService) UpdateSubscription(subscription *models.SubscriptionModel) (*models.SubscriptionModel, error) {
existingSubscription, err := repositories.GetSubscriptionByName(&subscription.Name)
if err != nil {
return nil, err
}
if existingSubscription == nil {
return nil, errors.ErrSubscriptionNotFound
}
if existingSubscription.MonthlyFee != subscription.MonthlyFee ||
existingSubscription.HourlyRate != subscription.HourlyRate ||
existingSubscription.Conditions != subscription.Conditions ||
existingSubscription.IncludedPerYear != subscription.IncludedPerYear ||
existingSubscription.IncludedPerMonth != subscription.IncludedPerMonth {
return nil, errors.ErrInvalidSubscriptionData
}
subscription.ID = existingSubscription.ID
return service.SubscriptionRepo.UpdateSubscription(subscription)
}
func (service *MembershipService) DeleteSubscription(id *uint, name *string) error {
if *name == "" {
return errors.ErrNoData
}
exists, err := repositories.GetSubscriptionByName(name)
if err != nil {
return err
}
if exists == nil {
return errors.ErrNotFound
}
if *id != exists.ID {
return errors.ErrInvalidSubscriptionData
}
usersInSubscription, err := repositories.GetUsersBySubscription(*id)
if err != nil {
return err
}
if len(*usersInSubscription) > 0 {
return errors.ErrSubscriptionInUse
}
return service.SubscriptionRepo.DeleteSubscription(id)
}
func (service *MembershipService) FindMembershipByUserID(userID uint) (*models.Membership, error) {
return service.Repo.FindMembershipByUserID(userID)
}
// Membership_Subscriptions
func (service *MembershipService) RegisterSubscription(subscription *models.SubscriptionModel) (uint, error) {
return service.SubscriptionRepo.CreateSubscriptionModel(subscription)
}
func (service *MembershipService) GetSubscriptionModelNames() ([]string, error) {
return service.SubscriptionRepo.GetSubscriptionModelNames()
}
func (service *MembershipService) GetSubscriptionByName(modelname *string) (*models.SubscriptionModel, error) {
return repositories.GetSubscriptionByName(modelname)
}
func (service *MembershipService) GetSubscriptions(where map[string]interface{}) (*[]models.SubscriptionModel, error) {
if where == nil {
where = map[string]interface{}{}
}
return service.SubscriptionRepo.GetSubscriptions(where)
}

View File

@@ -0,0 +1,21 @@
package services
import (
"GoMembership/internal/constants"
"GoMembership/internal/models"
)
func (s *UserService) HandlePasswordChangeRequest(user *models.User) (token string, err error) {
// Deactivate user and reset Verification
if err := s.SetUserStatus(user.ID, constants.DisabledStatus); err != nil {
return "", err
}
if err := s.RevokeVerification(&user.ID, constants.VerificationTypes.Password); err != nil {
return "", err
}
// Generate a token
return s.SetVerificationToken(&user.ID, &constants.VerificationTypes.Password)
}

View File

@@ -0,0 +1,5 @@
package services
func (s *UserService) SetUserStatus(id uint, status uint) error {
return s.Repo.SetUserStatus(id, status)
}

View File

@@ -0,0 +1,116 @@
package services
import (
"strings"
"GoMembership/internal/constants"
"GoMembership/internal/models"
"GoMembership/internal/repositories"
"GoMembership/pkg/errors"
"gorm.io/gorm"
"time"
)
type UserServiceInterface interface {
RegisterUser(user *models.User) (id uint, token string, err error)
GetUserByEmail(email string) (*models.User, error)
GetUserByID(id uint) (*models.User, error)
GetUsers(where map[string]interface{}) (*[]models.User, error)
UpdateUser(user *models.User) (*models.User, error)
DeleteUser(lastname string, id uint) error
SetUserStatus(id uint, status uint) error
VerifyUser(token *string, verificationType *string) (*models.Verification, error)
SetVerificationToken(id *uint, verificationType *string) (string, error)
RevokeVerification(id *uint, verificationType string) error
HandlePasswordChangeRequest(user *models.User) (token string, err error)
}
type UserService struct {
Repo repositories.UserRepositoryInterface
Licences repositories.LicenceInterface
}
func (service *UserService) DeleteUser(lastname string, id uint) error {
if id == 0 || lastname == "" {
return errors.ErrNoData
}
user, err := service.GetUserByID(id)
if err != nil {
return err
}
if user == nil {
return errors.ErrUserNotFound
}
return service.Repo.DeleteUser(id)
}
func (service *UserService) UpdateUser(user *models.User) (*models.User, error) {
if user.ID == 0 {
return nil, errors.ErrUserNotFound
}
user.SetPassword(user.Password)
// Validate subscription model
selectedModel, err := repositories.GetSubscriptionByName(&user.Membership.SubscriptionModel.Name)
if err != nil {
return nil, errors.ErrSubscriptionNotFound
}
user.Membership.SubscriptionModel = *selectedModel
user.Membership.SubscriptionModelID = selectedModel.ID
updatedUser, err := service.Repo.UpdateUser(user)
if err != nil {
if err == gorm.ErrRecordNotFound {
return nil, errors.ErrUserNotFound
}
if strings.Contains(err.Error(), "UNIQUE constraint failed") {
return nil, errors.ErrDuplicateEntry
}
return nil, err
}
return updatedUser, nil
}
func (service *UserService) RegisterUser(user *models.User) (id uint, token string, err error) {
user.SetPassword(user.Password)
user.Status = constants.UnverifiedStatus
user.CreatedAt = time.Now()
user.UpdatedAt = time.Now()
user.PaymentStatus = constants.AwaitingPaymentStatus
user.BankAccount.MandateDateSigned = time.Now()
id, err = service.Repo.CreateUser(user)
if err != nil {
return 0, "", err
}
token, err = service.SetVerificationToken(&id, &constants.VerificationTypes.Email)
if err != nil {
return 0, "", err
}
return id, token, nil
}
func (service *UserService) GetUserByID(id uint) (*models.User, error) {
return repositories.GetUserByID(&id)
}
func (service *UserService) GetUserByEmail(email string) (*models.User, error) {
return service.Repo.GetUserByEmail(email)
}
func (service *UserService) GetUsers(where map[string]interface{}) (*[]models.User, error) {
if where == nil {
where = map[string]interface{}{}
}
return service.Repo.GetUsers(where)
}

View File

@@ -0,0 +1,59 @@
package services
import (
"GoMembership/internal/models"
"GoMembership/internal/utils"
"GoMembership/pkg/errors"
"time"
)
func (s *UserService) SetVerificationToken(id *uint, verificationType *string) (string, error) {
token, err := utils.GenerateVerificationToken()
if err != nil {
return "", err
}
// Check if user is already verified
verified, err := s.Repo.IsVerified(id)
if err != nil {
return "", err
}
if verified {
return "", errors.ErrAlreadyVerified
}
// Prepare the Verification record
verification := models.Verification{
UserID: *id,
VerificationToken: token,
Type: *verificationType,
}
return s.Repo.SetVerificationToken(&verification)
}
func (s *UserService) RevokeVerification(id *uint, verificationType string) error {
return s.Repo.DeleteVerification(*id, verificationType)
}
func (service *UserService) VerifyUser(token *string, verificationType *string) (*models.Verification, error) {
verification, err := service.Repo.GetVerificationOfToken(token, verificationType)
if err != nil {
return nil, err
}
// Check if the user is already verified
verified, err := service.Repo.IsVerified(&verification.UserID)
if err != nil {
return nil, err
}
if verified {
return nil, errors.ErrAlreadyVerified
}
t := time.Now()
verification.VerifiedAt = &t
return verification, nil
}