user invitations

This commit is contained in:
Lars Hoogestraat 2018-10-31 15:52:11 +01:00
parent aa6e183dac
commit 82e9e65565
10 changed files with 86 additions and 16 deletions

View File

@ -45,11 +45,16 @@ type Mail struct {
func (m Mail) buildMessage(s Service) []byte {
var buf bytes.Buffer
buf.WriteString("To: ")
buf.WriteString(m.To)
buf.WriteString("\r\n")
buf.WriteString("Subject: ")
buf.WriteString(s.SubjectPrefix)
if len(s.SubjectPrefix) > 0 {
buf.WriteString(fmt.Sprintf("%s%s%s", "[", s.SubjectPrefix, "] "))
}
buf.WriteString(m.Subject)
buf.WriteString("\r\n")
buf.WriteString(m.Body)

View File

@ -157,15 +157,21 @@ func ActivateAccountPostHandler(ctx *middleware.AppContext, w http.ResponseWrite
user.Password = []byte(password)
user.Active = true
_, err = ctx.UserService.CreateUser(user)
if err != nil {
if _, err := ctx.UserService.CreateUser(user); err != nil {
return &middleware.Template{
Name: tplAdminActivateAccount,
Err: err,
}
}
if err := ctx.UserInviteService.RemoveInvite(ui.ID); err != nil {
return &middleware.Template{
Name: tplAdminUserDelete,
Active: "users",
Err: err,
}
}
return &middleware.Template{
RedirectPath: "admin",
SuccessMsg: "The account was successfully activated. You can now log in.",

View File

@ -56,6 +56,43 @@ func AdminUserInviteNewPostHandler(ctx *middleware.AppContext, w http.ResponseWr
}
}
func AdminUserInviteResendPostHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
inviteID, err := parseInt(getVar(r, "inviteID"))
if err != nil {
return &middleware.Template{
RedirectPath: "admin/user-invite",
Active: "users",
Err: err,
}
}
ui, err := ctx.UserInviteService.GetInvite(inviteID)
if err != nil {
return &middleware.Template{
Name: tplAdminUsers,
Err: err,
Active: "users",
}
}
err = ctx.Mailer.SendActivationLink(ui)
if err != nil {
logger.Log.Error(err)
}
return &middleware.Template{
RedirectPath: "admin/users",
Active: "users",
SuccessMsg: "Successfully invited user " + ui.Email,
Data: map[string]interface{}{
"userID": inviteID,
},
}
}
func AdminUserInviteDeleteHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
inviteID, err := parseInt(getVar(r, "inviteID"))

View File

@ -42,7 +42,7 @@ blog_articles_per_page = 20
blog_rss_feed_items = 10
# mail server server
mail_smtp_address =
mail_smtp_host =
mail_smtp_port =
mail_smtp_user =
mail_smtp_password =

View File

@ -19,7 +19,7 @@ func (m Mailer) SendActivationLink(ui *UserInvite) error {
mail := mail.Mail{
To: ui.Email,
Subject: "Password change",
Body: fmt.Sprintf("Hi %s, \n\n you are invited join %s. Please click the following link to enter a password and activate your account: %s", ui.DisplayName, m.AppConfig.Title, activation),
Body: fmt.Sprintf("Hi %s, \n\n you are invited join %s. To activate your account click the following link and enter a password %s", ui.DisplayName, m.AppConfig.Title, activation),
}
return m.MailService.SendAsync(mail)

View File

@ -35,6 +35,7 @@ type UserInviteDatasourceService interface {
Get(inviteID int) (*UserInvite, error)
GetByHash(hash string) (*UserInvite, error)
Create(ui *UserInvite) (int, error)
Update(ui *UserInvite) error
Remove(inviteID int) error
}
@ -62,8 +63,14 @@ func (uis UserInviteService) ListUserInvites() ([]UserInvite, error) {
return uis.Datasource.List()
}
func (uis UserInviteService) ResendUserInvites() ([]UserInvite, error) {
return uis.Datasource.List()
func (uis UserInviteService) UpdateUserInvites(ui *UserInvite) error {
ui.Hash = utils.RandomHash(32)
if err := ui.validate(uis); err != nil {
return err
}
return uis.Datasource.Update(ui)
}
func (uis UserInviteService) CreateUserInvite(ui *UserInvite) (int, error) {

View File

@ -54,13 +54,13 @@ func (rdb SQLiteUserInviteDatasource) Get(inviteID int) (*UserInvite, error) {
var u User
var ui UserInvite
if err := rdb.SQLConn.QueryRow("SELECT ui.rowid, ui.username, ui.email, ui.display_name, ui.created_at, ui.is_admin, "+
if err := rdb.SQLConn.QueryRow("SELECT ui.rowid, ui.hash, ui.username, ui.email, ui.display_name, ui.created_at, ui.is_admin, "+
"u.rowid, u.username, u.email, u.display_name "+
"FROM user_invite as ui "+
"INNER JOIN user as u "+
"ON u.rowid = ui.created_by "+
"WHERE ui.rowid=? ", inviteID).
Scan(&ui.ID, &ui.Username, &ui.Email, &ui.DisplayName, &ui.CreatedAt, &ui.IsAdmin, &u.ID, &u.Username, &u.Email, &u.DisplayName); err != nil {
Scan(&ui.ID, &ui.Hash, &ui.Username, &ui.Email, &ui.DisplayName, &ui.CreatedAt, &ui.IsAdmin, &u.ID, &u.Username, &u.Email, &u.DisplayName); err != nil {
return nil, err
}
@ -73,13 +73,13 @@ func (rdb SQLiteUserInviteDatasource) GetByHash(hash string) (*UserInvite, error
var ui UserInvite
var u User
if err := rdb.SQLConn.QueryRow("SELECT ui.rowid, ui.username, ui.email, ui.display_name, ui.created_at, ui.is_admin, "+
if err := rdb.SQLConn.QueryRow("SELECT ui.rowid, ui.hash, ui.username, ui.email, ui.display_name, ui.created_at, ui.is_admin, "+
"u.rowid, u.username, u.email, u.display_name "+
"FROM user_invite as ui "+
"INNER JOIN user as u "+
"ON u.rowid = ui.created_by "+
"WHERE ui.hash=? ", hash).
Scan(&ui.ID, &ui.Username, &ui.Email, &ui.DisplayName, &ui.CreatedAt, &ui.IsAdmin, &u.ID, &u.Username, &u.Email, &u.DisplayName); err != nil {
Scan(&ui.ID, &ui.Hash, &ui.Username, &ui.Email, &ui.DisplayName, &ui.CreatedAt, &ui.IsAdmin, &u.ID, &u.Username, &u.Email, &u.DisplayName); err != nil {
return nil, err
}
@ -88,7 +88,16 @@ func (rdb SQLiteUserInviteDatasource) GetByHash(hash string) (*UserInvite, error
return &ui, nil
}
//Create creates an new user
func (rdb SQLiteUserInviteDatasource) Update(ui *UserInvite) error {
if _, err := rdb.SQLConn.Exec("UPDATE user_invite SET hash=?, username=?, email=?, display_name=?, is_admin=?, created_at=?, created_by=? "+
"WHERE rowid=? ", ui.Hash, ui.Username, ui.Email, ui.DisplayName, ui.IsAdmin, ui.CreatedBy.ID, ui.ID); err != nil {
return err
}
return nil
}
//Create creates an new user invitation
func (rdb SQLiteUserInviteDatasource) Create(ui *UserInvite) (int, error) {
res, err := rdb.SQLConn.Exec("INSERT INTO user_invite (hash, username, email, display_name, is_admin, created_at, created_by) VALUES(?, ?, ?, ?, ?, ?, ?);",
ui.Hash, ui.Username, ui.Email, ui.DisplayName, ui.IsAdmin, time.Now(), ui.CreatedBy.ID)
@ -105,7 +114,7 @@ func (rdb SQLiteUserInviteDatasource) Create(ui *UserInvite) (int, error) {
return int(i), nil
}
//Count retuns the amount of users
//Count retuns the amount of users invitations
func (rdb SQLiteUserInviteDatasource) Count() (int, error) {
var total int

View File

@ -98,6 +98,7 @@ func restrictedRoutes(ctx *m.AppContext, router *mux.Router, chain alice.Chain)
//user invites
router.Handle("/user-invite/new", chain.Append(ctx.RequireAdmin).Then(useTemplateHandler(ctx, c.AdminUserInviteNewHandler))).Methods("GET")
router.Handle("/user-invite/new", chain.Append(ctx.RequireAdmin).Then(useTemplateHandler(ctx, c.AdminUserInviteNewPostHandler))).Methods("POST")
router.Handle("/user-invite/resend/{inviteID}", chain.Append(ctx.RequireAdmin).Then(useTemplateHandler(ctx, c.AdminUserInviteResendPostHandler))).Methods("POST")
router.Handle("/user-invite/delete/{inviteID}", chain.Append(ctx.RequireAdmin).Then(useTemplateHandler(ctx, c.AdminUserInviteDeleteHandler))).Methods("GET")
router.Handle("/user-invite/delete/{inviteID}", chain.Append(ctx.RequireAdmin).Then(useTemplateHandler(ctx, c.AdminUserInviteDeletePostHandler))).Methods("POST")

View File

@ -19,7 +19,7 @@
<input type="text" value="{{.DisplayName}}" id="displayname" name="displayname" placeholder="Display name..." required>
<label for="password">New password</label>
<input type="password" id="password" name="password" placeholder="Password..." required>
<input type="password" id="password" name="password" placeholder="Password...">
<div class="checkbox">
<label><input type="checkbox" id="admin" name="admin" value="on"{{if .IsAdmin}} checked{{end}}>Admin?</label>

View File

@ -34,7 +34,12 @@
<td>{{.IsAdmin | BoolToIcon}}</td>
<td>{{.CreatedBy.DisplayName}}</td>
<td class="action-data">
<a href="/admin/user-invite/resend/{{.ID}}" title="Invite">Resend invite link</a>
<form method="post" action="/admin/user-invite/resend/{{.ID}}">
<button type="submit" name="direction" value="resendinvite">
Resend invite link
</button>
{{$.csrfField}}
</form>
<a href="/admin/user-invite/delete/{{.ID}}" title="Remove">Remove</a>
</td>
</tr>