Added teacher registration mailer
This commit is contained in:
parent
fb5eb47f5b
commit
0f6be6c7b6
12
.example.env
12
.example.env
|
@ -1,4 +1,12 @@
|
|||
POSTGRES_USER="mw"
|
||||
POSTGRES_PASSWORD="SUPERDUPERSECRET"
|
||||
POSTGRES_PASSWORD=
|
||||
|
||||
API_JWT_SECRET="SUPERDUPERSECRET"
|
||||
URL=
|
||||
|
||||
BACKEND_JWT_SECRET=
|
||||
BACKEND_SMTP_HELO=
|
||||
BACKEND_SMTP_ADDRESS=
|
||||
BACKEND_SMTP_PORT=
|
||||
BACKEND_SMTP_NAME=
|
||||
BACKEND_SMTP_USERNAME=
|
||||
BACKEND_SMTP_PASSWORD=
|
||||
|
|
|
@ -54,9 +54,16 @@ services:
|
|||
- db
|
||||
- redis
|
||||
environment:
|
||||
URL: ${URL}
|
||||
BACKEND_DATABASE_URL: postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_USER}
|
||||
BACKEND_JWT_SECRET: ${API_JWT_SECRET}
|
||||
BACKEND_JWT_SECRET: ${BACKEND_JWT_SECRET}
|
||||
BACKEND_WORKER_REDIS_URL: redis://redis:6379
|
||||
BACKEND_SMTP_HELO: ${BACKEND_SMTP_HELO}
|
||||
BACKEND_SMTP_ADDRESS: ${BACKEND_SMTP_ADDRESS}
|
||||
BACKEND_SMTP_PORT: ${BACKEND_SMTP_PORT}
|
||||
BACKEND_SMTP_NAME: ${BACKEND_SMTP_NAME}
|
||||
BACKEND_SMTP_USERNAME: ${BACKEND_SMTP_USERNAME}
|
||||
BACKEND_SMTP_PASSWORD: ${BACKEND_SMTP_PASSWORD}
|
||||
depends_on:
|
||||
- db
|
||||
- redis
|
||||
|
|
|
@ -11,20 +11,20 @@ COPY --from=deps /app/shard.yml /app/shard.lock ./
|
|||
COPY --from=deps /app/lib ./lib
|
||||
COPY ./src ./src
|
||||
RUN if [ "${BUILD_ENV}" = "development" ]; then \
|
||||
shards build --static --verbose -s -p -t; \
|
||||
time shards build --static --verbose -s -p -t; \
|
||||
else \
|
||||
shards build --static --release --no-debug --verbose -s -p -t; \
|
||||
time shards build --static --release --no-debug --verbose -s -p -t; \
|
||||
fi
|
||||
|
||||
FROM ubuntu:latest as user
|
||||
RUN useradd -u 10001 backend
|
||||
|
||||
FROM scratch as runner
|
||||
FROM alpine as runner
|
||||
WORKDIR /app
|
||||
COPY --from=user /etc/passwd /etc/passwd
|
||||
COPY --from=builder /app/bin /bin
|
||||
COPY --from=builder /app/bin ./bin
|
||||
COPY ./db ./db
|
||||
USER backend
|
||||
EXPOSE 80
|
||||
ENTRYPOINT [ "backend" ]
|
||||
ENTRYPOINT [ "./bin/backend" ]
|
||||
CMD [ "run" ]
|
||||
|
|
|
@ -24,6 +24,10 @@ shards:
|
|||
git: https://github.com/crystal-lang/crystal-db.git
|
||||
version: 0.10.1
|
||||
|
||||
email:
|
||||
git: https://github.com/arcage/crystal-email.git
|
||||
version: 0.6.3
|
||||
|
||||
fancyline:
|
||||
git: https://github.com/papierkorb/fancyline.git
|
||||
version: 0.4.1
|
||||
|
@ -48,13 +52,17 @@ shards:
|
|||
git: https://github.com/crystal-community/jwt.git
|
||||
version: 1.6.0
|
||||
|
||||
kilt:
|
||||
git: https://github.com/jeromegn/kilt.git
|
||||
version: 0.6.1
|
||||
|
||||
micrate:
|
||||
git: https://github.com/juanedi/micrate.git
|
||||
version: 0.12.0
|
||||
|
||||
mosquito:
|
||||
git: https://github.com/mosquito-cr/mosquito.git
|
||||
version: 0.11.1
|
||||
version: 0.11.2
|
||||
|
||||
openssl_ext:
|
||||
git: https://github.com/spider-gazelle/openssl_ext.git
|
||||
|
@ -62,12 +70,16 @@ shards:
|
|||
|
||||
pg:
|
||||
git: https://github.com/will/crystal-pg.git
|
||||
version: 0.24.0
|
||||
version: 0.25.0
|
||||
|
||||
pool:
|
||||
git: https://github.com/ysbaddaden/pool.git
|
||||
version: 0.2.4
|
||||
|
||||
quartz_mailer:
|
||||
git: https://github.com/amberframework/quartz-mailer.git
|
||||
version: 0.8.0
|
||||
|
||||
redis:
|
||||
git: https://github.com/stefanwille/crystal-redis.git
|
||||
version: 2.8.3
|
||||
|
@ -88,3 +100,7 @@ shards:
|
|||
git: https://github.com/soveran/toro.git
|
||||
version: 0.4.3
|
||||
|
||||
version_from_shard:
|
||||
git: https://github.com/hugopl/version_from_shard.git
|
||||
version: 1.2.5
|
||||
|
||||
|
|
|
@ -43,3 +43,11 @@ dependencies:
|
|||
github: mosquito-cr/mosquito
|
||||
secrets-env:
|
||||
github: spider-gazelle/secrets-env
|
||||
quartz_mailer:
|
||||
github: amberframework/quartz-mailer
|
||||
version_from_shard:
|
||||
github: hugopl/version_from_shard
|
||||
kilt:
|
||||
github: jeromegn/kilt
|
||||
email:
|
||||
github: arcage/crystal-email
|
||||
|
|
|
@ -19,12 +19,7 @@ module Backend
|
|||
end
|
||||
|
||||
private def create_jwt(data, expiration : Int) : String
|
||||
payload = {
|
||||
"data" => data.to_h,
|
||||
"exp" => expiration,
|
||||
}
|
||||
|
||||
JWT.encode(payload.to_h, SAFE_ENV["BACKEND_JWT_SECRET"], JWT::Algorithm::HS256)
|
||||
JWT.encode({"data" => data.to_h, "exp" => expiration}, SAFE_ENV["BACKEND_JWT_SECRET"], JWT::Algorithm::HS256)
|
||||
end
|
||||
|
||||
def create_user_jwt(user_id : Int, expiration : Int = (Time.utc + Time::Span.new(hours: 6)).to_unix) : String
|
||||
|
|
|
@ -22,18 +22,16 @@ module Backend
|
|||
return if @user.nil? || @user.not_nil!.blocked
|
||||
|
||||
if @user
|
||||
@role = Schema::UserRole.parse?(@user.as(Db::User).role).not_nil!
|
||||
if @role
|
||||
@external =
|
||||
case Schema::UserRole.parse?(@user.not_nil!.role)
|
||||
when Schema::UserRole::Admin
|
||||
@user.not_nil!.admin
|
||||
when Schema::UserRole::Teacher
|
||||
@user.not_nil!.teacher
|
||||
when Schema::UserRole::Student
|
||||
@user.not_nil!.student
|
||||
end
|
||||
end
|
||||
@role = Schema::UserRole.parse(@user.not_nil!.role).not_nil!
|
||||
@external =
|
||||
case @role.not_nil!
|
||||
when .admin?
|
||||
@user.not_nil!.admin
|
||||
when .teacher?
|
||||
@user.not_nil!.teacher
|
||||
when .student?
|
||||
@user.not_nil!.student
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -42,15 +42,6 @@ module Backend
|
|||
role: input.role.to_s,
|
||||
blocked: input.blocked,
|
||||
)
|
||||
if input.create_external && input.role
|
||||
case input.role
|
||||
when UserRole::Teacher
|
||||
user.teacher = Db::Teacher.create!(user_id: user.id, max_students: input.teacher.not_nil!.max_students)
|
||||
when UserRole::Student
|
||||
user.student = Db::Student.create!(user_id: user.id, skif: input.student.not_nil!.skif)
|
||||
end
|
||||
user.save!
|
||||
end
|
||||
|
||||
User.new(user)
|
||||
end
|
||||
|
@ -83,6 +74,15 @@ module Backend
|
|||
id
|
||||
end
|
||||
|
||||
@[GraphQL::Field]
|
||||
def send_teachers_registration_email(context : Context) : Bool
|
||||
context.admin!
|
||||
|
||||
Worker::Jobs::SendTeachersRegistrationEmailJob.new.enqueue
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
@[GraphQL::Field]
|
||||
def create_teacher(context : Context, input : TeacherCreateInput) : Teacher
|
||||
context.admin!
|
||||
|
@ -115,7 +115,7 @@ module Backend
|
|||
context.admin!
|
||||
|
||||
user = Db::User.find!(input.user_id)
|
||||
raise "User not a student" unless UserRole.parse(user.role) == UserRole::Student
|
||||
raise "User not a student" unless Db::UserRole.parse(user.role).student?
|
||||
|
||||
student = Db::Student.create!(user_id: user.id)
|
||||
Student.new(student)
|
||||
|
|
|
@ -40,11 +40,11 @@ module Backend
|
|||
@[GraphQL::Field]
|
||||
def external_id : Int32?
|
||||
case Db::UserRole.parse(find!.role)
|
||||
when Db::UserRole::Admin
|
||||
when .admin?
|
||||
find!.admin
|
||||
when Db::UserRole::Teacher
|
||||
when .teacher?
|
||||
find!.teacher
|
||||
when Db::UserRole::Student
|
||||
when .student?
|
||||
find!.student
|
||||
end.not_nil!.id.not_nil!.to_i
|
||||
rescue NilAssertionError
|
||||
|
@ -88,9 +88,6 @@ module Backend
|
|||
getter email
|
||||
getter password
|
||||
getter role
|
||||
getter teacher
|
||||
getter student
|
||||
getter create_external
|
||||
getter blocked
|
||||
|
||||
@[GraphQL::Field]
|
||||
|
@ -100,9 +97,6 @@ module Backend
|
|||
@email : String,
|
||||
@password : String,
|
||||
@role : UserRole,
|
||||
@teacher : TeacherInput? = nil,
|
||||
@student : StudentInput? = nil,
|
||||
@create_external : Bool = false,
|
||||
@blocked : Bool = false
|
||||
)
|
||||
end
|
||||
|
|
|
@ -32,6 +32,15 @@ module Backend
|
|||
puts cmd.help
|
||||
end
|
||||
|
||||
cmd.commands.add do |c|
|
||||
c.use = "version"
|
||||
c.long = "Print version"
|
||||
|
||||
c.run do
|
||||
puts Backend::VERSION
|
||||
end
|
||||
end
|
||||
|
||||
cmd.commands.add do |c|
|
||||
c.use = "run"
|
||||
c.long = "Run the backend"
|
||||
|
|
|
@ -17,12 +17,16 @@ module Backend
|
|||
column role : String
|
||||
column blocked : Bool = false
|
||||
|
||||
def name : String
|
||||
"#{@firstname} #{@lastname}"
|
||||
end
|
||||
|
||||
validate :email, "needs to be an email address" do |user|
|
||||
CrystalEmail::Rfc5322::Public.validates?(user.email)
|
||||
end
|
||||
|
||||
validate :role, "needs to be a valid role" do |user|
|
||||
UserRole.parse?(user.role).in?(UserRole.values)
|
||||
UserRole.parse(user.role).in?(UserRole.values)
|
||||
end
|
||||
|
||||
validate :role, "user external needs to be a valid role" do |user|
|
||||
|
|
23
docker/backend/src/backend/mailers.cr
Normal file
23
docker/backend/src/backend/mailers.cr
Normal file
|
@ -0,0 +1,23 @@
|
|||
require "quartz_mailer"
|
||||
require "email"
|
||||
require "kilt"
|
||||
|
||||
require "./mailers/*"
|
||||
|
||||
module Backend
|
||||
module Mailers
|
||||
NAME = SAFE_ENV["BACKEND_SMTP_NAME"]
|
||||
EMAIL = SAFE_ENV["BACKEND_SMTP_USERNAME"]
|
||||
|
||||
Quartz.config do |config|
|
||||
config.smtp_enabled = true
|
||||
config.smtp_address = SAFE_ENV["BACKEND_SMTP_ADDRESS"]
|
||||
config.smtp_port = SAFE_ENV["BACKEND_SMTP_PORT"]
|
||||
config.helo_domain = SAFE_ENV["BACKEND_SMTP_HELO"]
|
||||
config.use_tls = EMail::Client::TLSMode::STARTTLS
|
||||
config.username = EMAIL
|
||||
config.password = SAFE_ENV["BACKEND_SMTP_PASSWORD"]
|
||||
config.use_authentication = true
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,15 @@
|
|||
module Backend
|
||||
module Mailers
|
||||
class TeacherRegistrationMailer < Quartz::Composer
|
||||
def sender : Quartz::Message::Address
|
||||
address email: EMAIL, name: NAME
|
||||
end
|
||||
|
||||
def initialize(user : Db::User)
|
||||
to name: user.name, email: user.email
|
||||
subject "Mentorenwahl Lehrer Registrierung"
|
||||
text Kilt.render("#{__DIR__}/templates/teacher_registration_mailer.txt.ecr")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,5 @@
|
|||
Hey, <%= user.name %>!
|
||||
|
||||
Du wurdest erfolgreich als Lehrer registriert.
|
||||
Initialisiere deinen Account, indem du auf den folgenden Link klickst und deine Daten eingibst:
|
||||
<%= Path[SAFE_ENV["URL"], "register/teacher?jwt=TEST"] %>
|
|
@ -1,11 +1,18 @@
|
|||
require "senf"
|
||||
|
||||
module Backend
|
||||
SAFE_ENV = Senf::SafeEnv.new([
|
||||
"BACKEND_DATABASE_URL",
|
||||
"BACKEND_ADMIN_EMAIL",
|
||||
"BACKEND_ADMIN_PASSWORD",
|
||||
"BACKEND_JWT_SECRET",
|
||||
"BACKEND_WORKER_REDIS_URL",
|
||||
])
|
||||
SAFE_ENV = Senf::SafeEnv.new(%w(
|
||||
URL
|
||||
BACKEND_DATABASE_URL
|
||||
BACKEND_ADMIN_EMAIL
|
||||
BACKEND_ADMIN_PASSWORD
|
||||
BACKEND_JWT_SECRET
|
||||
BACKEND_WORKER_REDIS_URL
|
||||
BACKEND_SMTP_HELO
|
||||
BACKEND_SMTP_ADDRESS
|
||||
BACKEND_SMTP_PORT
|
||||
BACKEND_SMTP_NAME
|
||||
BACKEND_SMTP_USERNAME
|
||||
BACKEND_SMTP_PASSWORD
|
||||
))
|
||||
end
|
||||
|
|
5
docker/backend/src/backend/version.cr
Normal file
5
docker/backend/src/backend/version.cr
Normal file
|
@ -0,0 +1,5 @@
|
|||
require "version_from_shard"
|
||||
|
||||
module Backend
|
||||
VersionFromShard.declare
|
||||
end
|
|
@ -1,5 +1,23 @@
|
|||
require "mosquito"
|
||||
|
||||
module Mosquito::Serializers::Array
|
||||
end
|
||||
|
||||
module Mosquito::Serializers::Granite
|
||||
macro serialize_granite_model(klass)
|
||||
{% method_suffix = klass.resolve.stringify.underscore.gsub(/::/, "__").id %}
|
||||
|
||||
def serialize_{{ method_suffix }}(model : {{ klass.id }}) : String
|
||||
model.id.to_s
|
||||
end
|
||||
|
||||
def deserialize_{{ method_suffix }}(raw : String) : {{ klass.id }}
|
||||
id = raw.to_i
|
||||
{{ klass.id }}.find(id).not_nil!
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
require "./worker/*"
|
||||
|
||||
module Backend
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
module Backend
|
||||
module Worker
|
||||
module Jobs
|
||||
class HelloWorldJob < Mosquito::PeriodicJob
|
||||
run_every 30.seconds
|
||||
|
||||
def perform : Nil
|
||||
log "Hello World!"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,34 @@
|
|||
require "../../db/user"
|
||||
|
||||
module Backend
|
||||
module Worker
|
||||
module Jobs
|
||||
class SendTeachersRegistrationEmailJob < Mosquito::QueuedJob
|
||||
def perform : Nil
|
||||
users = Db::User.where(role: Db::UserRole::Teacher.to_s, teacher_id: nil)
|
||||
count = users.count.run.as(Int64).to_i
|
||||
|
||||
channel = Channel(Nil).new(count)
|
||||
|
||||
users.each do |user|
|
||||
spawn do
|
||||
unless Db::UserRole.parse(user.role).teacher?
|
||||
fail
|
||||
end
|
||||
|
||||
log "Sending teacher registration email to #{user.email} (#{user.id})"
|
||||
Mailers::TeacherRegistrationMailer.new(user).deliver
|
||||
|
||||
channel.send(nil)
|
||||
end
|
||||
end
|
||||
|
||||
count.times do
|
||||
channel.receive
|
||||
end
|
||||
Fiber.yield
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,3 +1,3 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
docker-compose exec backend backend "$@"
|
||||
docker-compose exec backend ./bin/backend "$@"
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
docker-compose exec backend micrate "$@"
|
||||
docker-compose exec backend ./bin/micrate "$@"
|
||||
|
|
Loading…
Reference in a new issue