diff --git a/api/.DS_Store b/api/.DS_Store new file mode 100644 index 0000000..eace314 Binary files /dev/null and b/api/.DS_Store differ diff --git a/api/notification/.DS_Store b/api/notification/.DS_Store new file mode 100644 index 0000000..c82e4d9 Binary files /dev/null and b/api/notification/.DS_Store differ diff --git a/api/notification/.air.toml b/api/notification/.air.toml new file mode 100644 index 0000000..8b52776 --- /dev/null +++ b/api/notification/.air.toml @@ -0,0 +1,57 @@ +# Config file for [Air](https://github.com/air-verse/air) in TOML format + +# Working directory +# . or absolute path, please note that the directories following must be under root. +root = "./.." +tmp_dir = "tmp" + +[build] +# Just plain old shell command. You could use `make` as well. +cmd = "go build -o app -ldflags \"-X 'github.com/tech/sendico/notification/internal/appversion.BuildUser=$(whoami)' -X 'github.com/tech/sendico/notification/internal/appversion.Version=$APP_V' -X 'github.com/tech/sendico/notification/internal/appversion.Branch=$BUILD_BRANCH' -X 'github.com/tech/sendico/notification/internal/appversion.Revision=$GIT_REV' -X 'github.com/tech/sendico/notification/internal/appversion.BuildDate=$(date)' -X 'github.com/tech/sendico/notification/internal/mutil/ampli.Version=$APP_V'\"" +# Binary file yields from `cmd`. +bin = "./app" +# Customize binary, can setup environment variables when run your app. +full_bin = "./app --debug" +# Watch these filename extensions. +include_ext = ["go", "tpl", "tmpl", "html"] +# Ignore these filename extensions or directories. +exclude_dir = ["notification/.git", "pkg/.git", "notification/tmp", "notification/resources", "notification/env"] +# Watch these directories if you specified. +include_dir = [] +# Watch these files. +include_file = [] +# Exclude files. +exclude_file = [] +# Exclude specific regular expressions. +exclude_regex = ["_test\\.go"] +# Exclude unchanged files. +exclude_unchanged = true +# Follow symlink for directories +follow_symlink = true +# This log file places in your tmp_dir. +log = "air.log" +# It's not necessary to trigger build each time file changes if it's too frequent. +delay = 0 # ms +# Stop running old binary when build errors occur. +stop_on_error = true +# Send Interrupt signal before killing process (windows does not support this feature) +send_interrupt = true +# Delay after sending Interrupt signal +kill_delay = 500 # ms +# Add additional arguments when running binary (bin/full_bin). Will run './tmp/main hello world'. +args_bin = [] + +[log] +# Show log time +time = false + +[color] +# Customize each part's color. If no color found, use the raw app log. +main = "magenta" +watcher = "cyan" +build = "yellow" +runner = "green" + +[misc] +# Delete tmp directory on exit +clean_on_exit = true \ No newline at end of file diff --git a/api/notification/.gitignore b/api/notification/.gitignore new file mode 100644 index 0000000..c14a297 --- /dev/null +++ b/api/notification/.gitignore @@ -0,0 +1 @@ +go.sum \ No newline at end of file diff --git a/api/notification/ampli.json b/api/notification/ampli.json new file mode 100644 index 0000000..2635e30 --- /dev/null +++ b/api/notification/ampli.json @@ -0,0 +1,14 @@ +{ + "Zone": "eu", + "OrgId": "100001828", + "WorkspaceId": "c75043a3-1fad-45ec-bd71-c807a99c650d", + "SourceId": "81b24ac7-e285-4519-9e82-bb575601120c", + "Branch": "main", + "Version": "2.0.0", + "VersionId": "4fa6851a-4ff0-42f1-b440-8b39f07870e4", + "Runtime": "go:go-ampli", + "Platform": "Go", + "Language": "Go", + "SDK": "analytics-go", + "Path": "./internal/ampli" +} \ No newline at end of file diff --git a/api/notification/config.yml b/api/notification/config.yml new file mode 100755 index 0000000..884d5ec --- /dev/null +++ b/api/notification/config.yml @@ -0,0 +1,85 @@ +http_server: + listen_address: :8081 + read_header_timeout: 60 + shutdown_timeout: 5 + +api: + amplitude: + ampli_environment_env: AMPLI_ENVIRONMENT + middleware: + api_protocol_env: API_PROTOCOL + domain_env: SERVICE_HOST + api_endpoint_env: API_ENDPOINT + signature: + secret_key_env: API_ENDPOINT_SECRET + algorithm: HS256 + CORS: + max_age: 300 + allowed_origins: + - "http://*" + - "https://*" + allowed_methods: + - "GET" + - "POST" + - "PATCH" + - "DELETE" + - "OPTIONS" + allowed_headers: + - "Accept" + - "Authorization" + - "Content-Type" + exposed_headers: + allow_credentials: false + websocket: + endpoint_env: WS_ENDPOINT + timeout: 60 + message_broker: + driver: NATS + settings: + host_env: NATS_HOST + port_env: NATS_PORT + username_env: NATS_USER + password_env: NATS_PASSWORD + broker_name: Sendico Notification server + max_reconnects: 10 + reconnect_wait: 5 + # type: in-process + # settings: + # buffer_size: 10 + notification: + driver: client + settings: + username_env: MAIL_USER + password_env: MAIL_SECRET + host: "smtp.mail.ru" + port: 465 + from: "MeetX Tech" + network_timeout: 10 + +localizer: + path: "./i18n" + languages: ["en", "ru", "uk"] + service_name: "MeetX Connectica" + support: "support@meetx.space" + +app: + +database: + driver: mongodb + settings: + host_env: MONGO_HOST + port_env: MONGO_PORT + database_env: MONGO_DATABASE + user_env: MONGO_USER + password_env: MONGO_PASSWORD + auth_source_env: MONGO_AUTH_SOURCE + replica_set_env: MONGO_REPLICA_SET + enforcer: + driver: native + settings: + model_path_env: PERMISSION_MODEL + adapter: + collection_name_env: PERMISSION_COLLECTION + database_name_env: MONGO_DATABASE + timeout_seconds_env: PERMISSION_TIMEOUT + is_filtered_env: PERMISSION_IS_FILTERED \ No newline at end of file diff --git a/api/notification/env/.gitignore b/api/notification/env/.gitignore new file mode 100644 index 0000000..d71ab6c --- /dev/null +++ b/api/notification/env/.gitignore @@ -0,0 +1 @@ +.env.api \ No newline at end of file diff --git a/api/notification/go.mod b/api/notification/go.mod new file mode 100644 index 0000000..02e9a91 --- /dev/null +++ b/api/notification/go.mod @@ -0,0 +1,58 @@ +module github.com/tech/sendico/notification + +go 1.25.3 + +replace github.com/tech/sendico/pkg => ../pkg + +require ( + github.com/amplitude/analytics-go v1.2.0 + github.com/go-chi/chi/v5 v5.2.3 + github.com/mitchellh/mapstructure v1.5.0 + github.com/nicksnyder/go-i18n/v2 v2.6.0 + github.com/sendgrid/sendgrid-go v3.16.1+incompatible + github.com/tech/sendico/pkg v0.1.0 + github.com/xhit/go-simple-mail/v2 v2.16.0 + go.mongodb.org/mongo-driver v1.17.6 + go.uber.org/zap v1.27.0 + golang.org/x/text v0.30.0 + gopkg.in/yaml.v3 v3.0.1 +) + +require ( + github.com/beorn7/perks v1.0.1 // indirect + github.com/bmatcuk/doublestar/v4 v4.9.1 // indirect + github.com/casbin/casbin/v2 v2.132.0 // indirect + github.com/casbin/govaluate v1.10.0 // indirect + github.com/casbin/mongodb-adapter/v3 v3.7.0 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/go-test/deep v1.1.1 // indirect + github.com/golang/snappy v1.0.0 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/klauspost/compress v1.18.1 // indirect + github.com/mattn/go-colorable v0.1.14 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/montanaflynn/stats v0.7.1 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/nats-io/nats.go v1.47.0 // indirect + github.com/nats-io/nkeys v0.4.11 // indirect + github.com/nats-io/nuid v1.0.1 // indirect + github.com/prometheus/client_golang v1.23.2 // indirect + github.com/prometheus/client_model v0.6.2 // indirect + github.com/prometheus/common v0.67.2 // indirect + github.com/prometheus/procfs v0.19.2 // indirect + github.com/sendgrid/rest v2.6.9+incompatible // indirect + github.com/toorop/go-dkim v0.0.0-20250226130143-9025cce95817 // indirect + github.com/xdg-go/pbkdf2 v1.0.0 // indirect + github.com/xdg-go/scram v1.1.2 // indirect + github.com/xdg-go/stringprep v1.0.4 // indirect + github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect + go.uber.org/multierr v1.11.0 // indirect + go.yaml.in/yaml/v2 v2.4.3 // indirect + golang.org/x/crypto v0.43.0 // indirect + golang.org/x/net v0.46.0 // indirect + golang.org/x/sync v0.17.0 // indirect + golang.org/x/sys v0.37.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20251103181224-f26f9409b101 // indirect + google.golang.org/grpc v1.76.0 // indirect + google.golang.org/protobuf v1.36.10 // indirect +) diff --git a/api/notification/i18n/en.json b/api/notification/i18n/en.json new file mode 100644 index 0000000..0cc34ad --- /dev/null +++ b/api/notification/i18n/en.json @@ -0,0 +1,59 @@ +{ + "service.owner": "Dudina Yuliia Oleksandrivna SP #3307203248", + "service.address": "Ukraine, 62100, Kharkiv region, Bogoduhiv district, Bogoduhiv city, Svyato-Dukhivska square, b. 5, a. 1", + "service.phone": "phone: +380 (93) 106-29-50", + + "calendar.summary": "Meeting with {{.BookerName}}", + "calendar.description": "Hi<\/h1>\r\n
\r\nMeeting with {{.BookerName}} is confirmed on {{.Date}} at {{.Time}}.\r\n
\r\nNotes:\r\n
{{.Note}}\r\n
\r\n
Should you feel like rescheduling your meeting, follow this link<\/a>.\r\n
If you want to cancel your meeting, click here<\/a>. \r\n
\r\n
Yours faithfully,\r\n
{{.ServiceName}} team\r\n <\/p>\r\n <\/div>\r\n \r\n <\/center>\r\n <\/td>\r\n <\/tr>\r\n <\/table>\r\n <\/body>\r\n<\/html>",
+
+ "mail.welcome.subj": "Welcome to {{.ServiceName}}",
+ "mail.welcome.greeting": "Welcome, {{.Name}}",
+ "mail.welcome.body": "You're receiving this message because you recently signed up for a {{.ServiceName}} account.
Confirm your email address by clicking the button below. This step adds extra security by verifying you own this email.",
+ "btn.welcome": "Confirm email",
+
+ "mail.invitation.subj": "{{.InviterName}} invited you to join {{.ServiceName}}",
+ "mail.invitation.greeting": "Hello, {{.Name}}",
+ "mail.invitation.body": "{{.InviterName}} has invited you to join {{.ServiceName}}.
Click the button below to accept the invitation and create your account.",
+ "btn.invitation": "Accept invitation",
+
+ "mail.reset-password.subj": "{{.ServiceName}}: reset password request",
+ "mail.reset-password.greeting": "Hi, {{.Name}}",
+ "mail.reset-password.body": "It looks like you requested a new password.
If that sounds right, you can enter a new password by clicking the followinglink<\/a>.
If you have not requested a passowrd change please contact us under {{.SupportMail}}<\/a>.",
+
+ "mail.email-verification.subj": "{{.ServiceName}}: verify your email address",
+ "mail.email-verification.greeting": "Hi, {{.Name}}",
+ "mail.email-verification.body": "It looks like you have changed your email address.
If that sounds right, verify your email address by clicking the following link<\/a>.
If you have not changed your email address please contact us under {{.SupportMail}}<\/a>.",
+
+ "mail.email-successful-verification.subj": "{{.ServiceName}}: your email address is now verified",
+ "mail.email-successful-verification.greeting": "Congrats, {{.Name}}",
+ "mail.email-successful-verification.body": "Your e-mail has been successfully verified. Now it's time to log in and add content to your profile.",
+
+ "mail.email-changed.subj": "{{.ServiceName}}: your email address has been changed",
+ "mail.email-changed.greeting": "Hi, {{.Name}}",
+ "mail.email-changed.body": "You changed your email address to {{.NewEmail}}.
If you have not changed your email address please contact us under {{.SupportMail}}<\/a>",
+
+ "mail.booking-confirmation.subj": "{{.ServiceName}}: your meeting confirmation",
+ "mail.booking-confirmation.greeting": "Hi, {{.Name}}",
+ "mail.booking-confirmation.body": "Your meeting time slot is confirmed on {{.Date}} at {{.Time}}.
Should you feel like rescheduling your meeting, follow this link<\/a>.
If you want to cancel your meeting, click here<\/a>.",
+
+ "mail.booking-cancellation.subj": "{{.ServiceName}}: your meeting was cancelled",
+ "mail.booking-cancellation.greeting": "Hi, {{.Name}}",
+ "mail.booking-cancellation.body": "Your meeting on {{.Date}} at {{.Time}} was cancelled.",
+
+ "mail.booking-reschedule.subj": "{{.ServiceName}}: your meeting was rescheduled",
+ "mail.booking-reschedule.greeting": "Hi, {{.Name}}",
+ "mail.booking-reschedule.body": "Your meeting was rescheduled for a new time on {{.Date}} at {{.Time}}.
Should you feel like rescheduling your meeting again, follow this link<\/a>.
If you want to cancel your meeting, click here<\/a>.",
+
+ "mail.template.one_button": "\r\n\r\n \r\n \r\n \r\n \r\n \r\n \r\n