sendall button for mails, update icons for peer creation buttons (#35)

This commit is contained in:
Christoph Haas 2021-07-30 13:43:39 +02:00
parent e6ad82ec6e
commit fbc0b26631
15 changed files with 215 additions and 147 deletions

13
assets/js/bootstrap-confirmation.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -30,6 +30,10 @@
this.form.submit(); this.form.submit();
}); });
}); });
$('[data-toggle=confirmation]').confirmation({
rootSelector: '[data-toggle=confirmation]',
// other options
});
})(jQuery); // End of use strict })(jQuery); // End of use strict

5
assets/js/popper.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -40,9 +40,10 @@
</div> </div>
{{template "prt_footer.html" .}} {{template "prt_footer.html" .}}
<script src="/js/jquery.min.js"></script> <script src="/js/jquery.min.js"></script>
<script src="/js/bootstrap.bundle.min.js"></script>
<script src="/js/jquery.easing.js"></script> <script src="/js/jquery.easing.js"></script>
<script src="/js/jquery-ui.min.js"></script> <script src="/js/popper.min.js"></script>
<script src="/js/bootstrap.bundle.min.js"></script>
<script src="/js/bootstrap-confirmation.min.js"></script>
<script src="/js/bootstrap-tokenfield.min.js"></script> <script src="/js/bootstrap-tokenfield.min.js"></script>
<script src="/js/custom.js"></script> <script src="/js/custom.js"></script>
<script>$('#inputEmail').on('tokenfield:createdtoken', function (e) { <script>$('#inputEmail').on('tokenfield:createdtoken', function (e) {

View File

@ -203,8 +203,10 @@
</div> </div>
{{template "prt_footer.html" .}} {{template "prt_footer.html" .}}
<script src="/js/jquery.min.js"></script> <script src="/js/jquery.min.js"></script>
<script src="/js/bootstrap.bundle.min.js"></script>
<script src="/js/jquery.easing.js"></script> <script src="/js/jquery.easing.js"></script>
<script src="/js/popper.min.js"></script>
<script src="/js/bootstrap.bundle.min.js"></script>
<script src="/js/bootstrap-confirmation.min.js"></script>
<script src="/js/custom.js"></script> <script src="/js/custom.js"></script>
</body> </body>

View File

@ -253,8 +253,10 @@
</div> </div>
{{template "prt_footer.html" .}} {{template "prt_footer.html" .}}
<script src="/js/jquery.min.js"></script> <script src="/js/jquery.min.js"></script>
<script src="/js/bootstrap.bundle.min.js"></script>
<script src="/js/jquery.easing.js"></script> <script src="/js/jquery.easing.js"></script>
<script src="/js/popper.min.js"></script>
<script src="/js/bootstrap.bundle.min.js"></script>
<script src="/js/bootstrap-confirmation.min.js"></script>
<script src="/js/custom.js"></script> <script src="/js/custom.js"></script>
</body> </body>

View File

@ -11,8 +11,8 @@
</head> </head>
<body id="page-top" class="d-flex flex-column min-vh-100"> <body id="page-top" class="d-flex flex-column min-vh-100">
{{template "prt_nav.html" .}} {{template "prt_nav.html" .}}
<div class="container mt-5"> <div class="container mt-5">
{{if eq .User.CreatedAt .Epoch}} {{if eq .User.CreatedAt .Epoch}}
<h1>Create a new user</h1> <h1>Create a new user</h1>
{{else}} {{else}}
@ -77,12 +77,14 @@
<button type="submit" class="btn btn-primary">Save</button> <button type="submit" class="btn btn-primary">Save</button>
<a href="/admin/users/" class="btn btn-secondary">Cancel</a> <a href="/admin/users/" class="btn btn-secondary">Cancel</a>
</form> </form>
</div> </div>
{{template "prt_footer.html" .}} {{template "prt_footer.html" .}}
<script src="/js/jquery.min.js"></script> <script src="/js/jquery.min.js"></script>
<script src="/js/bootstrap.bundle.min.js"></script> <script src="/js/jquery.easing.js"></script>
<script src="/js/jquery.easing.js"></script> <script src="/js/popper.min.js"></script>
<script src="/js/custom.js"></script> <script src="/js/bootstrap.bundle.min.js"></script>
<script src="/js/bootstrap-confirmation.min.js"></script>
<script src="/js/custom.js"></script>
</body> </body>
</html> </html>

View File

@ -125,7 +125,7 @@
</div> </div>
</div> </div>
<div class="mt-4 row"> <div class="mt-4 row">
<div class="col-sm-10 col-12"> <div class="col-sm-8 col-12">
{{if eq $.Device.Type "server"}} {{if eq $.Device.Type "server"}}
<h2 class="mt-2">Current VPN Peers</h2> <h2 class="mt-2">Current VPN Peers</h2>
{{end}} {{end}}
@ -133,11 +133,12 @@
<h2 class="mt-2">Current VPN Endpoints</h2> <h2 class="mt-2">Current VPN Endpoints</h2>
{{end}} {{end}}
</div> </div>
<div class="col-sm-2 col-12 text-right"> <div class="col-sm-4 col-12 text-right">
<a href="/admin/peer/emailall" data-toggle="confirmation" data-title="Send mail to all peers?" title="Send mail to all peers" class="btn btn-light"><i class="fa fa-fw fa-paper-plane"></i></a>
{{if eq $.Device.Type "server"}} {{if eq $.Device.Type "server"}}
<a href="/admin/peer/createldap" title="Add multiple peers" class="btn btn-primary"><i class="fa fa-fw fa-user-plus"></i></a> <a href="/admin/peer/createldap" title="Add multiple peers" class="btn btn-primary"><i class="fa fa-fw fa-plus"></i><i class="fa fa-fw fa-users"></i></a>
{{end}} {{end}}
<a href="/admin/peer/create" title="Add a peer" class="btn btn-primary"><i class="fa fa-fw fa-plus"></i>M</a> <a href="/admin/peer/create" title="Add a peer" class="btn btn-primary"><i class="fa fa-fw fa-plus"></i><i class="fa fa-fw fa-user"></i></a>
</div> </div>
</div> </div>
<div class="mt-2 table-responsive"> <div class="mt-2 table-responsive">
@ -261,8 +262,10 @@
</div> </div>
{{template "prt_footer.html" .}} {{template "prt_footer.html" .}}
<script src="/js/jquery.min.js"></script> <script src="/js/jquery.min.js"></script>
<script src="/js/bootstrap.bundle.min.js"></script>
<script src="/js/jquery.easing.js"></script> <script src="/js/jquery.easing.js"></script>
<script src="/js/popper.min.js"></script>
<script src="/js/bootstrap.bundle.min.js"></script>
<script src="/js/bootstrap-confirmation.min.js"></script>
<script src="/js/custom.js"></script> <script src="/js/custom.js"></script>
</body> </body>

View File

@ -59,8 +59,10 @@
</div> </div>
{{template "prt_footer.html" .}} {{template "prt_footer.html" .}}
<script src="/js/jquery.min.js"></script> <script src="/js/jquery.min.js"></script>
<script src="/js/bootstrap.bundle.min.js"></script>
<script src="/js/jquery.easing.js"></script> <script src="/js/jquery.easing.js"></script>
<script src="/js/popper.min.js"></script>
<script src="/js/bootstrap.bundle.min.js"></script>
<script src="/js/bootstrap-confirmation.min.js"></script>
<script src="/js/custom.js"></script> <script src="/js/custom.js"></script>
</body> </body>

View File

@ -11,8 +11,8 @@
</head> </head>
<body id="page-top"> <body id="page-top">
{{template "prt_nav.html" .}} {{template "prt_nav.html" .}}
<div class="container"> <div class="container">
<div class="text-center mt-5"> <div class="text-center mt-5">
<div class="error mx-auto" data-text="{{.Data.Code}}"> <div class="error mx-auto" data-text="{{.Data.Code}}">
<p class="m-0">{{.Data.Code}}</p> <p class="m-0">{{.Data.Code}}</p>
@ -20,12 +20,14 @@
<p class="text-dark mb-5 lead">{{.Data.Message}}</p> <p class="text-dark mb-5 lead">{{.Data.Message}}</p>
<p class="text-black-50 mb-0">{{.Data.Details}}</p><a href="/">← Back to Dashboard</a> <p class="text-black-50 mb-0">{{.Data.Details}}</p><a href="/">← Back to Dashboard</a>
</div> </div>
</div> </div>
{{template "prt_footer.html" .}} {{template "prt_footer.html" .}}
<script src="/js/jquery.min.js"></script> <script src="/js/jquery.min.js"></script>
<script src="/js/bootstrap.bundle.min.js"></script> <script src="/js/jquery.easing.js"></script>
<script src="/js/jquery.easing.js"></script> <script src="/js/popper.min.js"></script>
<script src="/js/custom.js"></script> <script src="/js/bootstrap.bundle.min.js"></script>
<script src="/js/bootstrap-confirmation.min.js"></script>
<script src="/js/custom.js"></script>
</body> </body>
</html> </html>

View File

@ -79,8 +79,10 @@
</div> </div>
{{template "prt_footer.html" .}} {{template "prt_footer.html" .}}
<script src="/js/jquery.min.js"></script> <script src="/js/jquery.min.js"></script>
<script src="/js/bootstrap.bundle.min.js"></script>
<script src="/js/jquery.easing.js"></script> <script src="/js/jquery.easing.js"></script>
<script src="/js/popper.min.js"></script>
<script src="/js/bootstrap.bundle.min.js"></script>
<script src="/js/bootstrap-confirmation.min.js"></script>
<script src="/js/custom.js"></script> <script src="/js/custom.js"></script>
</body> </body>

View File

@ -56,8 +56,10 @@
{{template "prt_flashes.html" .}} {{template "prt_flashes.html" .}}
</div> </div>
<script src="/js/jquery.min.js"></script> <script src="/js/jquery.min.js"></script>
<script src="/js/bootstrap.bundle.min.js"></script>
<script src="/js/jquery.easing.js"></script> <script src="/js/jquery.easing.js"></script>
<script src="/js/popper.min.js"></script>
<script src="/js/bootstrap.bundle.min.js"></script>
<script src="/js/bootstrap-confirmation.min.js"></script>
<script src="/js/custom.js"></script> <script src="/js/custom.js"></script>
</body> </body>

View File

@ -102,8 +102,10 @@
</div> </div>
{{template "prt_footer.html" .}} {{template "prt_footer.html" .}}
<script src="/js/jquery.min.js"></script> <script src="/js/jquery.min.js"></script>
<script src="/js/bootstrap.bundle.min.js"></script>
<script src="/js/jquery.easing.js"></script> <script src="/js/jquery.easing.js"></script>
<script src="/js/popper.min.js"></script>
<script src="/js/bootstrap.bundle.min.js"></script>
<script src="/js/bootstrap-confirmation.min.js"></script>
<script src="/js/custom.js"></script> <script src="/js/custom.js"></script>
</body> </body>

View File

@ -12,6 +12,7 @@ import (
"github.com/h44z/wg-portal/internal/common" "github.com/h44z/wg-portal/internal/common"
"github.com/h44z/wg-portal/internal/users" "github.com/h44z/wg-portal/internal/users"
"github.com/h44z/wg-portal/internal/wireguard" "github.com/h44z/wg-portal/internal/wireguard"
"github.com/pkg/errors"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/tatsushid/go-fastping" "github.com/tatsushid/go-fastping"
csrf "github.com/utrack/gin-csrf" csrf "github.com/utrack/gin-csrf"
@ -254,59 +255,7 @@ func (s *Server) GetPeerConfigMail(c *gin.Context) {
return return
} }
user := s.users.GetUser(peer.Email) if err := s.sendPeerConfigMail(peer); err != nil {
cfg, err := peer.GetConfigFile(s.peers.GetDevice(currentSession.DeviceName))
if err != nil {
s.GetHandleError(c, http.StatusInternalServerError, "ConfigFile error", err.Error())
return
}
png, err := peer.GetQRCode()
if err != nil {
s.GetHandleError(c, http.StatusInternalServerError, "QRCode error", err.Error())
return
}
// Apply mail template
qrcodeFileName := "wireguard-qrcode.png"
var tplBuff bytes.Buffer
if err := s.mailTpl.Execute(&tplBuff, struct {
Peer wireguard.Peer
User *users.User
QrcodePngName string
PortalUrl string
}{
Peer: peer,
User: user,
QrcodePngName: qrcodeFileName,
PortalUrl: s.config.Core.ExternalUrl,
}); err != nil {
s.GetHandleError(c, http.StatusInternalServerError, "Template error", err.Error())
return
}
// Send mail
attachments := []common.MailAttachment{
{
Name: peer.GetConfigFileName(),
ContentType: "application/config",
Data: bytes.NewReader(cfg),
},
{
Name: qrcodeFileName,
ContentType: "image/png",
Data: bytes.NewReader(png),
Embedded: true,
},
{
Name: qrcodeFileName,
ContentType: "image/png",
Data: bytes.NewReader(png),
},
}
if err := common.SendEmailWithAttachments(s.config.Email, s.config.Core.MailFrom, "", "WireGuard VPN Configuration",
"Your mail client does not support HTML. Please find the configuration attached to this mail.", tplBuff.String(),
[]string{peer.Email}, attachments); err != nil {
s.GetHandleError(c, http.StatusInternalServerError, "Email error", err.Error()) s.GetHandleError(c, http.StatusInternalServerError, "Email error", err.Error())
return return
} }
@ -367,3 +316,79 @@ func (s *Server) GetPeerStatus(c *gin.Context) {
c.JSON(http.StatusOK, isOnline) c.JSON(http.StatusOK, isOnline)
return return
} }
func (s *Server) GetAdminSendEmails(c *gin.Context) {
currentSession := GetSessionData(c)
if !currentSession.IsAdmin {
s.GetHandleError(c, http.StatusUnauthorized, "No permissions", "You don't have permissions to view this resource!")
return
}
peers := s.peers.GetActivePeers(currentSession.DeviceName)
for _, peer := range peers {
if err := s.sendPeerConfigMail(peer); err != nil {
s.GetHandleError(c, http.StatusInternalServerError, "Email error", err.Error())
return
}
}
SetFlashMessage(c, "emails sent successfully", "success")
c.Redirect(http.StatusSeeOther, "/admin")
}
func (s *Server) sendPeerConfigMail(peer wireguard.Peer) error {
user := s.users.GetUser(peer.Email)
cfg, err := peer.GetConfigFile(s.peers.GetDevice(peer.DeviceName))
if err != nil {
return errors.Wrap(err, "failed to get config file")
}
png, err := peer.GetQRCode()
if err != nil {
return errors.Wrap(err, "failed to get qr-code")
}
// Apply mail template
qrcodeFileName := "wireguard-qrcode.png"
var tplBuff bytes.Buffer
if err := s.mailTpl.Execute(&tplBuff, struct {
Peer wireguard.Peer
User *users.User
QrcodePngName string
PortalUrl string
}{
Peer: peer,
User: user,
QrcodePngName: qrcodeFileName,
PortalUrl: s.config.Core.ExternalUrl,
}); err != nil {
return errors.Wrap(err, "failed to execute mail template")
}
// Send mail
attachments := []common.MailAttachment{
{
Name: peer.GetConfigFileName(),
ContentType: "application/config",
Data: bytes.NewReader(cfg),
},
{
Name: qrcodeFileName,
ContentType: "image/png",
Data: bytes.NewReader(png),
Embedded: true,
},
{
Name: qrcodeFileName,
ContentType: "image/png",
Data: bytes.NewReader(png),
},
}
if err := common.SendEmailWithAttachments(s.config.Email, s.config.Core.MailFrom, "", "WireGuard VPN Configuration",
"Your mail client does not support HTML. Please find the configuration attached to this mail.", tplBuff.String(),
[]string{peer.Email}, attachments); err != nil {
return errors.Wrap(err, "failed to send email")
}
return nil
}

View File

@ -58,6 +58,7 @@ func SetupRoutes(s *Server) {
admin.GET("/peer/delete", s.GetAdminDeletePeer) admin.GET("/peer/delete", s.GetAdminDeletePeer)
admin.GET("/peer/download", s.GetPeerConfig) admin.GET("/peer/download", s.GetPeerConfig)
admin.GET("/peer/email", s.GetPeerConfigMail) admin.GET("/peer/email", s.GetPeerConfigMail)
admin.GET("/peer/emailall", s.GetAdminSendEmails)
admin.GET("/users/", s.GetAdminUsersIndex) admin.GET("/users/", s.GetAdminUsersIndex)
admin.GET("/users/create", s.GetAdminUsersCreate) admin.GET("/users/create", s.GetAdminUsersCreate)