add: email delivery test; baseURL config
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
{
|
{
|
||||||
|
"base_url": "https://domain.de",
|
||||||
"db": {
|
"db": {
|
||||||
"Path": "data/db.sqlite3"
|
"Path": "data/db.sqlite3"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ type TemplateConfig struct {
|
|||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
ConfigFilePath string `json:"config_file_path" envconfig:"CONFIG_FILE_PATH"`
|
ConfigFilePath string `json:"config_file_path" envconfig:"CONFIG_FILE_PATH"`
|
||||||
|
BaseURL string `json:"base_url" envconfig:"BASE_URL"`
|
||||||
Auth AuthenticationConfig `json:"auth"`
|
Auth AuthenticationConfig `json:"auth"`
|
||||||
DB DatabaseConfig `json:"db"`
|
DB DatabaseConfig `json:"db"`
|
||||||
Templates TemplateConfig `json:"templates"`
|
Templates TemplateConfig `json:"templates"`
|
||||||
@@ -52,6 +53,7 @@ type Config struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
BaseURL string
|
||||||
CFGPath string
|
CFGPath string
|
||||||
CFG Config
|
CFG Config
|
||||||
Auth AuthenticationConfig
|
Auth AuthenticationConfig
|
||||||
@@ -83,6 +85,7 @@ func LoadConfig() {
|
|||||||
DB = CFG.DB
|
DB = CFG.DB
|
||||||
Templates = CFG.Templates
|
Templates = CFG.Templates
|
||||||
SMTP = CFG.SMTP
|
SMTP = CFG.SMTP
|
||||||
|
BaseURL = CFG.BaseURL
|
||||||
}
|
}
|
||||||
|
|
||||||
// readFile reads the configuration from the specified file path into the provided Config struct.
|
// readFile reads the configuration from the specified file path into the provided Config struct.
|
||||||
|
|||||||
@@ -9,4 +9,7 @@ const (
|
|||||||
DelayedPaymentStatus
|
DelayedPaymentStatus
|
||||||
SettledPaymentStatus
|
SettledPaymentStatus
|
||||||
AwaitingPaymentStatus
|
AwaitingPaymentStatus
|
||||||
|
MailVerificationSubject = "Nur noch ein kleiner Schritt!"
|
||||||
|
MailRegistrationSubject = "Neues Mitglied hat sich registriert"
|
||||||
|
MailWelcomeSubject = "Willkommen beim Dörpsmobil Hasloh e.V."
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -3,9 +3,10 @@ package controllers
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
// "io/ioutil"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"os"
|
"os"
|
||||||
@@ -13,9 +14,10 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"gorm.io/gorm"
|
smtpmock "github.com/mocktools/go-smtp-mock/v2"
|
||||||
|
|
||||||
"GoMembership/internal/config"
|
"GoMembership/internal/config"
|
||||||
|
"GoMembership/internal/constants"
|
||||||
"GoMembership/internal/database"
|
"GoMembership/internal/database"
|
||||||
"GoMembership/internal/models"
|
"GoMembership/internal/models"
|
||||||
"GoMembership/internal/repositories"
|
"GoMembership/internal/repositories"
|
||||||
@@ -95,45 +97,137 @@ func TestUserController(t *testing.T) {
|
|||||||
tests := getTestUsers()
|
tests := getTestUsers()
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
runSingleTest(t, &tt)
|
if err := runSingleTest(&tt); err != nil {
|
||||||
|
t.Errorf("Test failed: %v", err.Error())
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := utils.SMTPStop(); err != nil {
|
||||||
|
t.Errorf("Failed to stop SMTP Mockup Server: %#v", err)
|
||||||
|
}
|
||||||
|
|
||||||
if err := deleteTestDB("test.db"); err != nil {
|
if err := deleteTestDB("test.db"); err != nil {
|
||||||
t.Errorf("Failed to tear down DB: %#v", err)
|
t.Errorf("Failed to tear down DB: %#v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func runSingleTest(t *testing.T, tt *test) {
|
func runSingleTest(tt *test) error {
|
||||||
|
|
||||||
c, w := getMockedContext([]byte(tt.input))
|
c, w := getMockedContext([]byte(tt.input))
|
||||||
uc.RegisterUser(c)
|
uc.RegisterUser(c)
|
||||||
|
|
||||||
if w.Code != int(tt.wantResponse) {
|
if w.Code != int(tt.wantResponse) {
|
||||||
t.Errorf("Didn't get the expected response code: got: %v; expected: %v", w.Code, tt.wantResponse)
|
return fmt.Errorf("Didn't get the expected response code: got: %v; expected: %v", w.Code, tt.wantResponse)
|
||||||
}
|
}
|
||||||
validateUser(t, tt.assert, tt.wantDBData)
|
return validateUser(tt.assert, tt.wantDBData)
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleError(t *testing.T, err error, assert bool) {
|
func validateUser(assert bool, wantDBData map[string]interface{}) error {
|
||||||
if err == gorm.ErrRecordNotFound && !assert {
|
|
||||||
return // Expected case: user not found and assertion is false
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Error during testing: %#v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func validateUser(t *testing.T, assert bool, wantDBData map[string]interface{}) {
|
|
||||||
users, err := uc.Service.GetUsers(wantDBData)
|
users, err := uc.Service.GetUsers(wantDBData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Error in database ops: %#v", err)
|
return fmt.Errorf("Error in database ops: %#v", err)
|
||||||
}
|
|
||||||
if assert != (len(*users) != 0) {
|
|
||||||
t.Errorf("User entry query didn't met expectation: %v != %#v", assert, *users)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if assert != (len(*users) != 0) {
|
||||||
|
return fmt.Errorf("User entry query didn't met expectation: %v != %#v", assert, *users)
|
||||||
|
}
|
||||||
|
|
||||||
|
if assert {
|
||||||
|
//check for email delivery
|
||||||
|
messages := utils.SMTPGetMessages()
|
||||||
|
for _, message := range messages {
|
||||||
|
|
||||||
|
if strings.Contains(message.MsgRequest(), constants.MailWelcomeSubject) {
|
||||||
|
if err := checkWelcomeMail(&message); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else if strings.Contains(message.MsgRequest(), constants.MailRegistrationSubject) {
|
||||||
|
if err := checkRegistrationMail(&message, &(*users)[0]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else if strings.Contains(message.MsgRequest(), constants.MailVerificationSubject) {
|
||||||
|
if err := checkVerificationMail(&message, &(*users)[0]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return fmt.Errorf("Subject not expected: %v", message.MsgRequest())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkWelcomeMail(message *smtpmock.Message) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkRegistrationMail(message *smtpmock.Message, user *models.User) error {
|
||||||
|
|
||||||
|
for _, responses := range message.RcpttoRequestResponse() {
|
||||||
|
if !strings.Contains(responses[0], AdminMail) {
|
||||||
|
return fmt.Errorf("Registration Information didn't reach admin! Recipient was: %v instead of %v", responses[0], AdminMail)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !strings.Contains(message.MailfromRequest(), User) {
|
||||||
|
return fmt.Errorf("Registration Information was sent from unexpected address! Sender was: %v instead of %v", message.MailfromRequest(), User)
|
||||||
|
}
|
||||||
|
//Check if all the relevant data has been passed to the mail.
|
||||||
|
if !strings.Contains(message.MsgRequest(), user.FirstName+" "+user.LastName) {
|
||||||
|
return fmt.Errorf("User first and last name(%v) has not been rendered in registration mail.", user.FirstName+" "+user.LastName)
|
||||||
|
}
|
||||||
|
if !strings.Contains(message.MsgRequest(), fmt.Sprintf("Preis/Monat</strong>: %v", user.Membership.SubscriptionModel.MonthlyFee)) {
|
||||||
|
return fmt.Errorf("Users monthly subscription fee(%v) has not been rendered in registration mail.", user.Membership.SubscriptionModel.MonthlyFee)
|
||||||
|
}
|
||||||
|
if !strings.Contains(message.MsgRequest(), fmt.Sprintf("Preis/h</strong>: %v", user.Membership.SubscriptionModel.HourlyRate)) {
|
||||||
|
return fmt.Errorf("Users hourly subscription fee(%v) has not been rendered in registration mail.", user.Membership.SubscriptionModel.HourlyRate)
|
||||||
|
}
|
||||||
|
if user.Company != "" && !strings.Contains(message.MsgRequest(), user.Company) {
|
||||||
|
return fmt.Errorf("Users Company(%v) has not been rendered in registration mail.", user.Company)
|
||||||
|
}
|
||||||
|
if !strings.Contains(message.MsgRequest(), fmt.Sprintf("Mitgliedsnr:</strong> %v", user.Membership.ID)) {
|
||||||
|
return fmt.Errorf("Users membership Id(%v) has not been rendered in registration mail.", user.Membership.ID)
|
||||||
|
}
|
||||||
|
if !strings.Contains(message.MsgRequest(), user.Address+","+user.ZipCode) {
|
||||||
|
return fmt.Errorf("Users address(%v) has not been rendered in registration mail.", user.Address+","+user.ZipCode)
|
||||||
|
}
|
||||||
|
if !strings.Contains(message.MsgRequest(), user.City) {
|
||||||
|
return fmt.Errorf("Users city(%v) has not been rendered in registration mail.", user.City)
|
||||||
|
}
|
||||||
|
if !strings.Contains(message.MsgRequest(), user.DateOfBirth.Format("20060102")) {
|
||||||
|
return fmt.Errorf("Users birthday(%v) has not been rendered in registration mail.", user.DateOfBirth.Format("20060102"))
|
||||||
|
}
|
||||||
|
if !strings.Contains(message.MsgRequest(), "Email:</strong> "+user.Email) {
|
||||||
|
return fmt.Errorf("Users email(%v) has not been rendered in registration mail.", user.Email)
|
||||||
|
}
|
||||||
|
if !strings.Contains(message.MsgRequest(), user.Phone) {
|
||||||
|
return fmt.Errorf("Users phone(%v) has not been rendered in registration mail.", user.Phone)
|
||||||
|
}
|
||||||
|
if !strings.Contains(message.MsgRequest(), user.BankAccount.IBAN) {
|
||||||
|
return fmt.Errorf("Users IBAN(%v) has not been rendered in registration mail.", user.BankAccount.IBAN)
|
||||||
|
}
|
||||||
|
if !strings.Contains(message.MsgRequest(), config.BaseURL) {
|
||||||
|
return fmt.Errorf("Base Url (%v) has not been rendered in registration mail.", config.BaseURL)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkVerificationMail(message *smtpmock.Message, user *models.User) error {
|
||||||
|
for _, responses := range message.RcpttoRequestResponse() {
|
||||||
|
if !strings.Contains(responses[0], "RCPT TO:<"+user.Email) {
|
||||||
|
return fmt.Errorf("Registration Information didn't reach client! Recipient was: %v instead of %v", responses[0], user.Email)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// the email is encoded with a lowercase %3d while the url.encodeQuery returns an uppercase %3D. Therefore we remove the last char(padded base64 '='
|
||||||
|
if !strings.Contains(message.MsgRequest(), user.Verification.VerificationToken[:len(user.Verification.VerificationToken)-1]) {
|
||||||
|
return fmt.Errorf("Users Verification link token(%v) has not been rendered in email verification mail. %v", user.Verification.VerificationToken, message.MsgRequest())
|
||||||
|
}
|
||||||
|
if !strings.Contains(message.MsgRequest(), config.BaseURL) {
|
||||||
|
return fmt.Errorf("Base Url (%v) has not been rendered in email verification mail.", config.BaseURL)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
|
||||||
|
}
|
||||||
func initSubscriptionPlans() error {
|
func initSubscriptionPlans() error {
|
||||||
subscription := models.SubscriptionModel{
|
subscription := models.SubscriptionModel{
|
||||||
Name: "Basic",
|
Name: "Basic",
|
||||||
@@ -331,5 +425,16 @@ func getTestUsers() []test {
|
|||||||
return user
|
return user
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "Company present should pass",
|
||||||
|
wantResponse: http.StatusCreated,
|
||||||
|
wantDBData: map[string]interface{}{"Email": "john.doe2@example.com"},
|
||||||
|
assert: true,
|
||||||
|
input: generateInputJSON(func(user models.User) models.User {
|
||||||
|
user.Email = "john.doe2@example.com"
|
||||||
|
user.Company = "ACME"
|
||||||
|
return user
|
||||||
|
}),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package services
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"GoMembership/internal/config"
|
"GoMembership/internal/config"
|
||||||
|
"GoMembership/internal/constants"
|
||||||
"GoMembership/internal/models"
|
"GoMembership/internal/models"
|
||||||
"GoMembership/pkg/logger"
|
"GoMembership/pkg/logger"
|
||||||
"bytes"
|
"bytes"
|
||||||
@@ -60,13 +61,15 @@ func (s *EmailService) SendVerificationEmail(user *models.User, token *string) e
|
|||||||
FirstName string
|
FirstName string
|
||||||
LastName string
|
LastName string
|
||||||
Token string
|
Token string
|
||||||
|
BASEURL string
|
||||||
}{
|
}{
|
||||||
FirstName: user.FirstName,
|
FirstName: user.FirstName,
|
||||||
LastName: user.LastName,
|
LastName: user.LastName,
|
||||||
Token: *token,
|
Token: *token,
|
||||||
|
BASEURL: config.BaseURL,
|
||||||
}
|
}
|
||||||
|
|
||||||
subject := "Nur noch ein kleiner Schritt!"
|
subject := constants.MailVerificationSubject
|
||||||
body, err := ParseTemplate("mail_verification.html", data)
|
body, err := ParseTemplate("mail_verification.html", data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error.Print("Couldn't send verification mail")
|
logger.Error.Print("Couldn't send verification mail")
|
||||||
@@ -85,6 +88,7 @@ func (s *EmailService) SendWelcomeEmail(user *models.User) error {
|
|||||||
MembershipID int64
|
MembershipID int64
|
||||||
MembershipFee float32
|
MembershipFee float32
|
||||||
RentalFee float32
|
RentalFee float32
|
||||||
|
BASEURL string
|
||||||
}{
|
}{
|
||||||
Company: user.Company,
|
Company: user.Company,
|
||||||
FirstName: user.FirstName,
|
FirstName: user.FirstName,
|
||||||
@@ -92,9 +96,10 @@ func (s *EmailService) SendWelcomeEmail(user *models.User) error {
|
|||||||
MembershipID: user.Membership.ID,
|
MembershipID: user.Membership.ID,
|
||||||
MembershipFee: float32(user.Membership.SubscriptionModel.MonthlyFee),
|
MembershipFee: float32(user.Membership.SubscriptionModel.MonthlyFee),
|
||||||
RentalFee: float32(user.Membership.SubscriptionModel.HourlyRate),
|
RentalFee: float32(user.Membership.SubscriptionModel.HourlyRate),
|
||||||
|
BASEURL: config.BaseURL,
|
||||||
}
|
}
|
||||||
|
|
||||||
subject := "Willkommen beim Dörpsmobil Hasloh e.V."
|
subject := constants.MailWelcomeSubject
|
||||||
body, err := ParseTemplate("mail_welcome.html", data)
|
body, err := ParseTemplate("mail_welcome.html", data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error.Print("Couldn't send welcome mail")
|
logger.Error.Print("Couldn't send welcome mail")
|
||||||
@@ -120,6 +125,7 @@ func (s *EmailService) NotifyAdminOfNewUser(user *models.User) error {
|
|||||||
MembershipID int64
|
MembershipID int64
|
||||||
RentalFee float32
|
RentalFee float32
|
||||||
MembershipFee float32
|
MembershipFee float32
|
||||||
|
BASEURL string
|
||||||
}{
|
}{
|
||||||
Company: user.Company,
|
Company: user.Company,
|
||||||
FirstName: user.FirstName,
|
FirstName: user.FirstName,
|
||||||
@@ -135,9 +141,10 @@ func (s *EmailService) NotifyAdminOfNewUser(user *models.User) error {
|
|||||||
Email: user.Email,
|
Email: user.Email,
|
||||||
Phone: user.Phone,
|
Phone: user.Phone,
|
||||||
IBAN: user.BankAccount.IBAN,
|
IBAN: user.BankAccount.IBAN,
|
||||||
|
BASEURL: config.BaseURL,
|
||||||
}
|
}
|
||||||
|
|
||||||
subject := "Neues Mitglied hat sich registriert"
|
subject := constants.MailRegistrationSubject
|
||||||
body, err := ParseTemplate("mail_registration.html", data)
|
body, err := ParseTemplate("mail_registration.html", data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error.Print("Couldn't send admin notification mail")
|
logger.Error.Print("Couldn't send admin notification mail")
|
||||||
|
|||||||
@@ -31,12 +31,12 @@
|
|||||||
<td>
|
<td>
|
||||||
<div style="padding: 0px 24px 0px 24px">
|
<div style="padding: 0px 24px 0px 24px">
|
||||||
<a
|
<a
|
||||||
href="https://carsharing-hasloh.de"
|
href="{{.BASEURL}}"
|
||||||
style="text-decoration: none"
|
style="text-decoration: none"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
><img
|
><img
|
||||||
alt="Carsharing-Hasloh"
|
alt="Carsharing-Hasloh"
|
||||||
src="https://carsharing-hasloh.de/images/CarsharingSH-Hasloh-LOGO.jpeg"
|
src="{{.BASEURL}}/images/CarsharingSH-Hasloh-LOGO.jpeg"
|
||||||
style="
|
style="
|
||||||
outline: none;
|
outline: none;
|
||||||
border: none;
|
border: none;
|
||||||
|
|||||||
@@ -31,12 +31,12 @@
|
|||||||
<td>
|
<td>
|
||||||
<div style="padding: 24px 24px 24px 24px; text-align: center">
|
<div style="padding: 24px 24px 24px 24px; text-align: center">
|
||||||
<a
|
<a
|
||||||
href="https://carsharing-hasloh.de"
|
href="{{.BASEURL}}"
|
||||||
style="text-decoration: none"
|
style="text-decoration: none"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
><img
|
><img
|
||||||
alt="Dörpsmobil Hasloh"
|
alt="Dörpsmobil Hasloh"
|
||||||
src="https://carsharing-hasloh.de/images/CarsharingSH-Hasloh-LOGO.jpeg"
|
src="{{.BASEURL}}/images/CarsharingSH-Hasloh-LOGO.jpeg"
|
||||||
style="
|
style="
|
||||||
outline: none;
|
outline: none;
|
||||||
border: none;
|
border: none;
|
||||||
@@ -70,7 +70,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div style="text-align: center; padding: 16px 24px 16px 24px">
|
<div style="text-align: center; padding: 16px 24px 16px 24px">
|
||||||
<a
|
<a
|
||||||
href="https://carsharing-hasloh.de/backend/verify?token={{.Token}}"
|
href="{{.BASEURL}}/backend/verify?token={{.Token}}"
|
||||||
style="
|
style="
|
||||||
color: #ffffff;
|
color: #ffffff;
|
||||||
font-size: 26px;
|
font-size: 26px;
|
||||||
@@ -122,7 +122,7 @@
|
|||||||
padding: 4px 24px 16px 24px;
|
padding: 4px 24px 16px 24px;
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
https://carsharing-hasloh.de/backend/verify?token={{.Token}}
|
{{.BASEURL}}/backend/verify?token={{.Token}}
|
||||||
</div>
|
</div>
|
||||||
<div style="font-weight: normal; padding: 16px 24px 16px 24px">
|
<div style="font-weight: normal; padding: 16px 24px 16px 24px">
|
||||||
Nachdem wir Ihre E-Mail Adresse bestätigen konnten, schicken wir
|
Nachdem wir Ihre E-Mail Adresse bestätigen konnten, schicken wir
|
||||||
@@ -170,7 +170,7 @@
|
|||||||
<div style="padding: 16px 24px 16px 24px">
|
<div style="padding: 16px 24px 16px 24px">
|
||||||
<img
|
<img
|
||||||
alt=""
|
alt=""
|
||||||
src="https://carsharing-hasloh.de/images/favicon_hu5543b2b337a87a169e2c722ef0122802_211442_96x0_resize_lanczos_3.png"
|
src="{{.BASEURL}}/images/favicon_hu5543b2b337a87a169e2c722ef0122802_211442_96x0_resize_lanczos_3.png"
|
||||||
height="80"
|
height="80"
|
||||||
width="80"
|
width="80"
|
||||||
style="
|
style="
|
||||||
|
|||||||
@@ -31,12 +31,12 @@
|
|||||||
<td>
|
<td>
|
||||||
<div style="padding: 24px 24px 24px 24px">
|
<div style="padding: 24px 24px 24px 24px">
|
||||||
<a
|
<a
|
||||||
href="https://carsharing-hasloh.de"
|
href="{{.BASEURL}}"
|
||||||
style="text-decoration: none"
|
style="text-decoration: none"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
><img
|
><img
|
||||||
alt="Carsharing Hasloh"
|
alt="Carsharing Hasloh"
|
||||||
src="https://carsharing-hasloh.de/images/CarsharingSH-Hasloh-LOGO.jpeg"
|
src="{{.BASEURL}}/images/CarsharingSH-Hasloh-LOGO.jpeg"
|
||||||
style="
|
style="
|
||||||
outline: none;
|
outline: none;
|
||||||
border: none;
|
border: none;
|
||||||
@@ -206,7 +206,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div style="text-align: center; padding: 16px 24px 16px 24px">
|
<div style="text-align: center; padding: 16px 24px 16px 24px">
|
||||||
<a
|
<a
|
||||||
href="https://carsharing-hasloh.de"
|
href="{{.BASEURL}}"
|
||||||
style="
|
style="
|
||||||
color: #ffffff;
|
color: #ffffff;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
|
|||||||
@@ -30,12 +30,12 @@
|
|||||||
<td>
|
<td>
|
||||||
<div style="padding: 0px 24px 0px 24px">
|
<div style="padding: 0px 24px 0px 24px">
|
||||||
<a
|
<a
|
||||||
href="https://carsharing-hasloh.de"
|
href="{{ .BASEURL }}"
|
||||||
style="text-decoration: none"
|
style="text-decoration: none"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
><img
|
><img
|
||||||
alt="Carsharing-Hasloh"
|
alt="Carsharing-Hasloh"
|
||||||
src="https://carsharing-hasloh.de/images/CarsharingSH-Hasloh-LOGO.jpeg"
|
src="{{ .BASEURL }}/images/CarsharingSH-Hasloh-LOGO.jpeg"
|
||||||
style="
|
style="
|
||||||
outline: none;
|
outline: none;
|
||||||
border: none;
|
border: none;
|
||||||
|
|||||||
@@ -30,12 +30,12 @@
|
|||||||
<td>
|
<td>
|
||||||
<div style="padding: 0px 24px 0px 24px">
|
<div style="padding: 0px 24px 0px 24px">
|
||||||
<a
|
<a
|
||||||
href="https://carsharing-hasloh.de"
|
href="{{ .BASEURL }}"
|
||||||
style="text-decoration: none"
|
style="text-decoration: none"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
><img
|
><img
|
||||||
alt="Carsharing-Hasloh"
|
alt="Carsharing-Hasloh"
|
||||||
src="https://carsharing-hasloh.de/images/CarsharingSH-Hasloh-LOGO.jpeg"
|
src="{{ .BASEURL }}/images/CarsharingSH-Hasloh-LOGO.jpeg"
|
||||||
style="
|
style="
|
||||||
outline: none;
|
outline: none;
|
||||||
border: none;
|
border: none;
|
||||||
|
|||||||
Reference in New Issue
Block a user