diff --git a/assets/js/bootstrap-confirmation.min.js b/assets/js/bootstrap-confirmation.min.js new file mode 100644 index 0000000..7859afd --- /dev/null +++ b/assets/js/bootstrap-confirmation.min.js @@ -0,0 +1,13 @@ +/** + * Minified by jsDelivr using Terser v5.3.5. + * Original file: /npm/bootstrap-confirmation2@4.2.1/dist/bootstrap-confirmation.js + * + * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files + */ +/*! + * Bootstrap Confirmation (v4.2.1) + * @copyright 2013 Nimit Suwannagate + * @copyright 2014-2021 Damien "Mistic" Sorel + * @licence Apache License, Version 2.0 + */ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(require("jquery"),require("bootstrap")):"function"==typeof define&&define.amd?define(["jquery","bootstrap"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).jQuery)}(this,(function(t){"use strict";function e(t,e){for(var n=0;n\n
\n

\n
\n

\n
\n
\n
\n
\n'});f.whiteList&&f.whiteList["*"].push("data-apply","data-dismiss");var u,h="fade",p="show",g=".popover-header",d=".confirmation-content",b=".confirmation-buttons .btn-group",C={13:"Enter",27:"Escape",39:"ArrowRight",40:"ArrowDown"},v={HIDE:"hide"+c,HIDDEN:"hidden"+c,SHOW:"show"+c,SHOWN:"shown"+c,INSERTED:"inserted"+c,CLICK:"click"+c,FOCUSIN:"focusin"+c,FOCUSOUT:"focusout"+c,MOUSEENTER:"mouseenter"+c,MOUSELEAVE:"mouseleave"+c,CONFIRMED:"confirmed"+c,CANCELED:"canceled"+c,KEYUP:"keyup"+c},y=function(i){var a,y;function m(t,e){var n;if(((n=i.call(this,t,e)||this).config.popout||n.config.singleton)&&!n.config.rootSelector)throw new Error("The rootSelector option is required to use popout and singleton features since jQuery 3.");return n._isDelegate=!1,e.selector?(e._selector=e.rootSelector+" "+e.selector,n.config._selector=e._selector):e._selector?(n.config._selector=e._selector,n._isDelegate=!0):n.config._selector=e.rootSelector,void 0===n.config.confirmationEvent&&(n.config.confirmationEvent=n.config.trigger),n.config.selector||n._copyAttributes(),n._setConfirmationListeners(),n}y=i,(a=m).prototype=Object.create(y.prototype),a.prototype.constructor=a,o(a,y);var E,_,O,I=m.prototype;return I.isWithContent=function(){return!0},I.setContent=function(){var e=t(this.getTipElement()),n=this._getContent();"function"==typeof n&&(n=n.call(this.element)),this.setElementContent(e.find(g),this.getTitle()),e.find(d).toggle(!!n),n&&this.setElementContent(e.find(d),n),this.config.buttons.length>0?this._setButtons(e,this.config.buttons):this._setStandardButtons(e),e.removeClass(h+" "+p),this._setupKeyupEvent()},I.dispose=function(){t("body").off(v.CLICK+"."+this.uid),this.eventBody=!1,this._cleanKeyupEvent(),i.prototype.dispose.call(this)},I.hide=function(t){this._cleanKeyupEvent(),i.prototype.hide.call(this,t)},I._getConfig=function(e){e=i.prototype._getConfig.call(this,e);var o=t(this.element).data();return Object.keys(o).forEach((function(t){0!==t.indexOf("btn")&&delete o[t]})),n({},e,o)},I._copyAttributes=function(){var e=this;this.config._attributes={},this.config.copyAttributes?"string"==typeof this.config.copyAttributes&&(this.config.copyAttributes=this.config.copyAttributes.split(" ")):this.config.copyAttributes=[],this.config.copyAttributes.forEach((function(n){e.config._attributes[n]=t(e.element).attr(n)}))},I._setConfirmationListeners=function(){var e=this;this.config.selector?t(this.element).on(this.config.trigger,this.config.selector,(function(t,e){e||(t.preventDefault(),t.stopPropagation(),t.stopImmediatePropagation())})):(t(this.element).on(this.config.trigger,(function(t,e){e||(t.preventDefault(),t.stopPropagation(),t.stopImmediatePropagation())})),t(this.element).on(v.SHOWN,(function(){e.config.singleton&&t(e.config._selector).not(t(this)).filter((function(){return void 0!==t(this).data(s)})).confirmation("hide")}))),this._isDelegate||(this.eventBody=!1,this.uid=this.element.id||m.getUID(r+"_group"),t(this.element).on(v.SHOWN,(function(){e.config.popout&&!e.eventBody&&(e.eventBody=t("body").on(v.CLICK+"."+e.uid,(function(n){t(e.config._selector).is(n.target)||t(e.config._selector).has(n.target).length>0||(t(e.config._selector).filter((function(){return void 0!==t(this).data(s)})).confirmation("hide"),t("body").off(v.CLICK+"."+e.uid),e.eventBody=!1)})))})))},I._setStandardButtons=function(t){var e=[{class:this.config.btnOkClass,label:this.config.btnOkLabel,iconClass:this.config.btnOkIconClass,iconContent:this.config.btnOkIconContent,attr:this.config._attributes},{class:this.config.btnCancelClass,label:this.config.btnCancelLabel,iconClass:this.config.btnCancelIconClass,iconContent:this.config.btnCancelIconContent,cancel:!0}];this._setButtons(t,e)},I._setButtons=function(e,n){var o=this,i=e.find(b).empty();n.forEach((function(e){var n=t('').addClass("h-100 d-flex align-items-center").addClass(e.class||"btn btn-sm btn-secondary").html(e.label||"").attr(e.attr||(e.cancel?{}:o.config._attributes));(e.iconClass||e.iconContent)&&n.prepend(t("").addClass(e.iconClass||"").text(e.iconContent||"")),n.one("click",(function(n){"#"===t(this).attr("href")&&n.preventDefault(),e.onClick&&e.onClick.call(t(o.element)),e.cancel?(o.config.onCancel.call(o.element,e.value),t(o.element).trigger(v.CANCELED,[e.value])):(o.config.onConfirm.call(o.element,e.value),t(o.element).trigger(v.CONFIRMED,[e.value]),t(o.element).trigger(o.config.confirmationEvent,[!0])),o.hide()})),i.append(n)}))},I._setupKeyupEvent=function(){u=this,t(window).off(v.KEYUP).on(v.KEYUP,this._onKeyup.bind(this))},I._cleanKeyupEvent=function(){u===this&&(u=void 0,t(window).off(v.KEYUP))},I._onKeyup=function(e){if(this.tip){var n,o=t(this.getTipElement()),i=e.key||C[e.keyCode||e.which],r=o.find(b),s=r.find(".active");switch(i){case"Escape":this.hide();break;case"ArrowRight":n=s.length&&s.next().length?s.next():r.children().first(),s.removeClass("active"),n.addClass("active").focus();break;case"ArrowLeft":n=s.length&&s.prev().length?s.prev():r.children().last(),s.removeClass("active"),n.addClass("active").focus()}}else this._cleanKeyupEvent()},m.getUID=function(t){var e=t;do{e+=~~(1e6*Math.random())}while(document.getElementById(e));return e},m._jQueryInterface=function(e){return this.each((function(){var n=t(this).data(s),o="object"==typeof e?e:{};if(o.rootSelector=t(this).selector||o.rootSelector,(n||!/destroy|hide/.test(e))&&(n||(n=new m(this,o),t(this).data(s,n)),"string"==typeof e)){if(void 0===n[e])throw new TypeError('No method named "'+e+'"');n[e]()}}))},E=m,O=[{key:"VERSION",get:function(){return"4.2.1"}},{key:"Default",get:function(){return f}},{key:"NAME",get:function(){return r}},{key:"DATA_KEY",get:function(){return s}},{key:"Event",get:function(){return v}},{key:"EVENT_KEY",get:function(){return c}},{key:"DefaultType",get:function(){return l}}],(_=null)&&e(E.prototype,_),O&&e(E,O),m}(i);t.fn[r]=y._jQueryInterface,t.fn[r].Constructor=y,t.fn[r].noConflict=function(){return t.fn[r]=a,y._jQueryInterface}})); \ No newline at end of file diff --git a/assets/js/custom.js b/assets/js/custom.js index df3eaac..9cd7e27 100644 --- a/assets/js/custom.js +++ b/assets/js/custom.js @@ -30,6 +30,10 @@ this.form.submit(); }); }); + $('[data-toggle=confirmation]').confirmation({ + rootSelector: '[data-toggle=confirmation]', + // other options + }); })(jQuery); // End of use strict diff --git a/assets/js/popper.min.js b/assets/js/popper.min.js new file mode 100644 index 0000000..2eeb406 --- /dev/null +++ b/assets/js/popper.min.js @@ -0,0 +1,5 @@ +/** + * @popperjs/core v2.9.2 - MIT License + */ + +"use strict";!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).Popper={})}(this,(function(e){function t(e){return{width:(e=e.getBoundingClientRect()).width,height:e.height,top:e.top,right:e.right,bottom:e.bottom,left:e.left,x:e.left,y:e.top}}function n(e){return null==e?window:"[object Window]"!==e.toString()?(e=e.ownerDocument)&&e.defaultView||window:e}function o(e){return{scrollLeft:(e=n(e)).pageXOffset,scrollTop:e.pageYOffset}}function r(e){return e instanceof n(e).Element||e instanceof Element}function i(e){return e instanceof n(e).HTMLElement||e instanceof HTMLElement}function a(e){return"undefined"!=typeof ShadowRoot&&(e instanceof n(e).ShadowRoot||e instanceof ShadowRoot)}function s(e){return e?(e.nodeName||"").toLowerCase():null}function f(e){return((r(e)?e.ownerDocument:e.document)||window.document).documentElement}function p(e){return t(f(e)).left+o(e).scrollLeft}function c(e){return n(e).getComputedStyle(e)}function l(e){return e=c(e),/auto|scroll|overlay|hidden/.test(e.overflow+e.overflowY+e.overflowX)}function u(e,r,a){void 0===a&&(a=!1);var c=f(r);e=t(e);var u=i(r),d={scrollLeft:0,scrollTop:0},m={x:0,y:0};return(u||!u&&!a)&&(("body"!==s(r)||l(c))&&(d=r!==n(r)&&i(r)?{scrollLeft:r.scrollLeft,scrollTop:r.scrollTop}:o(r)),i(r)?((m=t(r)).x+=r.clientLeft,m.y+=r.clientTop):c&&(m.x=p(c))),{x:e.left+d.scrollLeft-m.x,y:e.top+d.scrollTop-m.y,width:e.width,height:e.height}}function d(e){var n=t(e),o=e.offsetWidth,r=e.offsetHeight;return 1>=Math.abs(n.width-o)&&(o=n.width),1>=Math.abs(n.height-r)&&(r=n.height),{x:e.offsetLeft,y:e.offsetTop,width:o,height:r}}function m(e){return"html"===s(e)?e:e.assignedSlot||e.parentNode||(a(e)?e.host:null)||f(e)}function h(e){return 0<=["html","body","#document"].indexOf(s(e))?e.ownerDocument.body:i(e)&&l(e)?e:h(m(e))}function v(e,t){var o;void 0===t&&(t=[]);var r=h(e);return e=r===(null==(o=e.ownerDocument)?void 0:o.body),o=n(r),r=e?[o].concat(o.visualViewport||[],l(r)?r:[]):r,t=t.concat(r),e?t:t.concat(v(m(r)))}function g(e){return i(e)&&"fixed"!==c(e).position?e.offsetParent:null}function y(e){for(var t=n(e),o=g(e);o&&0<=["table","td","th"].indexOf(s(o))&&"static"===c(o).position;)o=g(o);if(o&&("html"===s(o)||"body"===s(o)&&"static"===c(o).position))return t;if(!o)e:{if(o=-1!==navigator.userAgent.toLowerCase().indexOf("firefox"),-1===navigator.userAgent.indexOf("Trident")||!i(e)||"fixed"!==c(e).position)for(e=m(e);i(e)&&0>["html","body"].indexOf(s(e));){var r=c(e);if("none"!==r.transform||"none"!==r.perspective||"paint"===r.contain||-1!==["transform","perspective"].indexOf(r.willChange)||o&&"filter"===r.willChange||o&&r.filter&&"none"!==r.filter){o=e;break e}e=e.parentNode}o=null}return o||t}function b(e){function t(e){o.add(e.name),[].concat(e.requires||[],e.requiresIfExists||[]).forEach((function(e){o.has(e)||(e=n.get(e))&&t(e)})),r.push(e)}var n=new Map,o=new Set,r=[];return e.forEach((function(e){n.set(e.name,e)})),e.forEach((function(e){o.has(e.name)||t(e)})),r}function w(e){var t;return function(){return t||(t=new Promise((function(n){Promise.resolve().then((function(){t=void 0,n(e())}))}))),t}}function x(e){return e.split("-")[0]}function O(e,t){var n=t.getRootNode&&t.getRootNode();if(e.contains(t))return!0;if(n&&a(n))do{if(t&&e.isSameNode(t))return!0;t=t.parentNode||t.host}while(t);return!1}function j(e){return Object.assign({},e,{left:e.x,top:e.y,right:e.x+e.width,bottom:e.y+e.height})}function E(e,r){if("viewport"===r){r=n(e);var a=f(e);r=r.visualViewport;var s=a.clientWidth;a=a.clientHeight;var l=0,u=0;r&&(s=r.width,a=r.height,/^((?!chrome|android).)*safari/i.test(navigator.userAgent)||(l=r.offsetLeft,u=r.offsetTop)),e=j(e={width:s,height:a,x:l+p(e),y:u})}else i(r)?((e=t(r)).top+=r.clientTop,e.left+=r.clientLeft,e.bottom=e.top+r.clientHeight,e.right=e.left+r.clientWidth,e.width=r.clientWidth,e.height=r.clientHeight,e.x=e.left,e.y=e.top):(u=f(e),e=f(u),s=o(u),r=null==(a=u.ownerDocument)?void 0:a.body,a=_(e.scrollWidth,e.clientWidth,r?r.scrollWidth:0,r?r.clientWidth:0),l=_(e.scrollHeight,e.clientHeight,r?r.scrollHeight:0,r?r.clientHeight:0),u=-s.scrollLeft+p(u),s=-s.scrollTop,"rtl"===c(r||e).direction&&(u+=_(e.clientWidth,r?r.clientWidth:0)-a),e=j({width:a,height:l,x:u,y:s}));return e}function D(e,t,n){return t="clippingParents"===t?function(e){var t=v(m(e)),n=0<=["absolute","fixed"].indexOf(c(e).position)&&i(e)?y(e):e;return r(n)?t.filter((function(e){return r(e)&&O(e,n)&&"body"!==s(e)})):[]}(e):[].concat(t),(n=(n=[].concat(t,[n])).reduce((function(t,n){return n=E(e,n),t.top=_(n.top,t.top),t.right=U(n.right,t.right),t.bottom=U(n.bottom,t.bottom),t.left=_(n.left,t.left),t}),E(e,n[0]))).width=n.right-n.left,n.height=n.bottom-n.top,n.x=n.left,n.y=n.top,n}function L(e){return 0<=["top","bottom"].indexOf(e)?"x":"y"}function P(e){var t=e.reference,n=e.element,o=(e=e.placement)?x(e):null;e=e?e.split("-")[1]:null;var r=t.x+t.width/2-n.width/2,i=t.y+t.height/2-n.height/2;switch(o){case"top":r={x:r,y:t.y-n.height};break;case"bottom":r={x:r,y:t.y+t.height};break;case"right":r={x:t.x+t.width,y:i};break;case"left":r={x:t.x-n.width,y:i};break;default:r={x:t.x,y:t.y}}if(null!=(o=o?L(o):null))switch(i="y"===o?"height":"width",e){case"start":r[o]-=t[i]/2-n[i]/2;break;case"end":r[o]+=t[i]/2-n[i]/2}return r}function M(e){return Object.assign({},{top:0,right:0,bottom:0,left:0},e)}function k(e,t){return t.reduce((function(t,n){return t[n]=e,t}),{})}function A(e,n){void 0===n&&(n={});var o=n;n=void 0===(n=o.placement)?e.placement:n;var i=o.boundary,a=void 0===i?"clippingParents":i,s=void 0===(i=o.rootBoundary)?"viewport":i;i=void 0===(i=o.elementContext)?"popper":i;var p=o.altBoundary,c=void 0!==p&&p;o=M("number"!=typeof(o=void 0===(o=o.padding)?0:o)?o:k(o,C));var l=e.elements.reference;p=e.rects.popper,a=D(r(c=e.elements[c?"popper"===i?"reference":"popper":i])?c:c.contextElement||f(e.elements.popper),a,s),c=P({reference:s=t(l),element:p,strategy:"absolute",placement:n}),p=j(Object.assign({},p,c)),s="popper"===i?p:s;var u={top:a.top-s.top+o.top,bottom:s.bottom-a.bottom+o.bottom,left:a.left-s.left+o.left,right:s.right-a.right+o.right};if(e=e.modifiersData.offset,"popper"===i&&e){var d=e[n];Object.keys(u).forEach((function(e){var t=0<=["right","bottom"].indexOf(e)?1:-1,n=0<=["top","bottom"].indexOf(e)?"y":"x";u[e]+=d[n]*t}))}return u}function W(){for(var e=arguments.length,t=Array(e),n=0;n(g.devicePixelRatio||1)?"translate("+e+"px, "+u+"px)":"translate3d("+e+"px, "+u+"px, 0)",m)):Object.assign({},o,((t={})[v]=a?u+"px":"",t[h]=d?e+"px":"",t.transform="",t))}function H(e){return e.replace(/left|right|bottom|top/g,(function(e){return $[e]}))}function R(e){return e.replace(/start|end/g,(function(e){return ee[e]}))}function S(e,t,n){return void 0===n&&(n={x:0,y:0}),{top:e.top-t.height-n.y,right:e.right-t.width+n.x,bottom:e.bottom-t.height+n.y,left:e.left-t.width-n.x}}function q(e){return["top","right","bottom","left"].some((function(t){return 0<=e[t]}))}var C=["top","bottom","right","left"],N=C.reduce((function(e,t){return e.concat([t+"-start",t+"-end"])}),[]),V=[].concat(C,["auto"]).reduce((function(e,t){return e.concat([t,t+"-start",t+"-end"])}),[]),I="beforeRead read afterRead beforeMain main afterMain beforeWrite write afterWrite".split(" "),_=Math.max,U=Math.min,z=Math.round,F={placement:"bottom",modifiers:[],strategy:"absolute"},X={passive:!0},Y={name:"eventListeners",enabled:!0,phase:"write",fn:function(){},effect:function(e){var t=e.state,o=e.instance,r=(e=e.options).scroll,i=void 0===r||r,a=void 0===(e=e.resize)||e,s=n(t.elements.popper),f=[].concat(t.scrollParents.reference,t.scrollParents.popper);return i&&f.forEach((function(e){e.addEventListener("scroll",o.update,X)})),a&&s.addEventListener("resize",o.update,X),function(){i&&f.forEach((function(e){e.removeEventListener("scroll",o.update,X)})),a&&s.removeEventListener("resize",o.update,X)}},data:{}},G={name:"popperOffsets",enabled:!0,phase:"read",fn:function(e){var t=e.state;t.modifiersData[e.name]=P({reference:t.rects.reference,element:t.rects.popper,strategy:"absolute",placement:t.placement})},data:{}},J={top:"auto",right:"auto",bottom:"auto",left:"auto"},K={name:"computeStyles",enabled:!0,phase:"beforeWrite",fn:function(e){var t=e.state,n=e.options;e=void 0===(e=n.gpuAcceleration)||e;var o=n.adaptive;o=void 0===o||o,n=void 0===(n=n.roundOffsets)||n,e={placement:x(t.placement),popper:t.elements.popper,popperRect:t.rects.popper,gpuAcceleration:e},null!=t.modifiersData.popperOffsets&&(t.styles.popper=Object.assign({},t.styles.popper,T(Object.assign({},e,{offsets:t.modifiersData.popperOffsets,position:t.options.strategy,adaptive:o,roundOffsets:n})))),null!=t.modifiersData.arrow&&(t.styles.arrow=Object.assign({},t.styles.arrow,T(Object.assign({},e,{offsets:t.modifiersData.arrow,position:"absolute",adaptive:!1,roundOffsets:n})))),t.attributes.popper=Object.assign({},t.attributes.popper,{"data-popper-placement":t.placement})},data:{}},Q={name:"applyStyles",enabled:!0,phase:"write",fn:function(e){var t=e.state;Object.keys(t.elements).forEach((function(e){var n=t.styles[e]||{},o=t.attributes[e]||{},r=t.elements[e];i(r)&&s(r)&&(Object.assign(r.style,n),Object.keys(o).forEach((function(e){var t=o[e];!1===t?r.removeAttribute(e):r.setAttribute(e,!0===t?"":t)})))}))},effect:function(e){var t=e.state,n={popper:{position:t.options.strategy,left:"0",top:"0",margin:"0"},arrow:{position:"absolute"},reference:{}};return Object.assign(t.elements.popper.style,n.popper),t.styles=n,t.elements.arrow&&Object.assign(t.elements.arrow.style,n.arrow),function(){Object.keys(t.elements).forEach((function(e){var o=t.elements[e],r=t.attributes[e]||{};e=Object.keys(t.styles.hasOwnProperty(e)?t.styles[e]:n[e]).reduce((function(e,t){return e[t]="",e}),{}),i(o)&&s(o)&&(Object.assign(o.style,e),Object.keys(r).forEach((function(e){o.removeAttribute(e)})))}))}},requires:["computeStyles"]},Z={name:"offset",enabled:!0,phase:"main",requires:["popperOffsets"],fn:function(e){var t=e.state,n=e.name,o=void 0===(e=e.options.offset)?[0,0]:e,r=(e=V.reduce((function(e,n){var r=t.rects,i=x(n),a=0<=["left","top"].indexOf(i)?-1:1,s="function"==typeof o?o(Object.assign({},r,{placement:n})):o;return r=(r=s[0])||0,s=((s=s[1])||0)*a,i=0<=["left","right"].indexOf(i)?{x:s,y:r}:{x:r,y:s},e[n]=i,e}),{}))[t.placement],i=r.x;r=r.y,null!=t.modifiersData.popperOffsets&&(t.modifiersData.popperOffsets.x+=i,t.modifiersData.popperOffsets.y+=r),t.modifiersData[n]=e}},$={left:"right",right:"left",bottom:"top",top:"bottom"},ee={start:"end",end:"start"},te={name:"flip",enabled:!0,phase:"main",fn:function(e){var t=e.state,n=e.options;if(e=e.name,!t.modifiersData[e]._skip){var o=n.mainAxis;o=void 0===o||o;var r=n.altAxis;r=void 0===r||r;var i=n.fallbackPlacements,a=n.padding,s=n.boundary,f=n.rootBoundary,p=n.altBoundary,c=n.flipVariations,l=void 0===c||c,u=n.allowedAutoPlacements;c=x(n=t.options.placement),i=i||(c!==n&&l?function(e){if("auto"===x(e))return[];var t=H(e);return[R(e),t,R(t)]}(n):[H(n)]);var d=[n].concat(i).reduce((function(e,n){return e.concat("auto"===x(n)?function(e,t){void 0===t&&(t={});var n=t.boundary,o=t.rootBoundary,r=t.padding,i=t.flipVariations,a=t.allowedAutoPlacements,s=void 0===a?V:a,f=t.placement.split("-")[1];0===(i=(t=f?i?N:N.filter((function(e){return e.split("-")[1]===f})):C).filter((function(e){return 0<=s.indexOf(e)}))).length&&(i=t);var p=i.reduce((function(t,i){return t[i]=A(e,{placement:i,boundary:n,rootBoundary:o,padding:r})[x(i)],t}),{});return Object.keys(p).sort((function(e,t){return p[e]-p[t]}))}(t,{placement:n,boundary:s,rootBoundary:f,padding:a,flipVariations:l,allowedAutoPlacements:u}):n)}),[]);n=t.rects.reference,i=t.rects.popper;var m=new Map;c=!0;for(var h=d[0],v=0;vi[O]&&(b=H(b)),O=H(b),w=[],o&&w.push(0>=j[y]),r&&w.push(0>=j[b],0>=j[O]),w.every((function(e){return e}))){h=g,c=!1;break}m.set(g,w)}if(c)for(o=function(e){var t=d.find((function(t){if(t=m.get(t))return t.slice(0,e).every((function(e){return e}))}));if(t)return h=t,"break"},r=l?3:1;0 {{template "prt_footer.html" .}} - - + + + - + + + diff --git a/assets/tpl/admin_edit_interface.html b/assets/tpl/admin_edit_interface.html index dfcce2c..841c6c7 100644 --- a/assets/tpl/admin_edit_interface.html +++ b/assets/tpl/admin_edit_interface.html @@ -253,8 +253,10 @@ {{template "prt_footer.html" .}} - + + + diff --git a/assets/tpl/admin_edit_user.html b/assets/tpl/admin_edit_user.html index 80a7324..9891f32 100644 --- a/assets/tpl/admin_edit_user.html +++ b/assets/tpl/admin_edit_user.html @@ -11,78 +11,80 @@ -{{template "prt_nav.html" .}} -
- {{if eq .User.CreatedAt .Epoch}} -

Create a new user

- {{else}} -

Edit user {{.User.Email}}

- {{end}} - - {{template "prt_flashes.html" .}} - -
- + {{template "prt_nav.html" .}} +
{{if eq .User.CreatedAt .Epoch}} -
-
- - -
-
+

Create a new user

{{else}} - +

Edit user {{.User.Email}}

{{end}} -
-
- - -
-
-
-
- - -
-
-
-
- - -
-
-
-
- - -
-
-
-
-
- - -
-
- - -
-
-
- - Cancel - -
-{{template "prt_footer.html" .}} - - - - + {{template "prt_flashes.html" .}} + +
+ + {{if eq .User.CreatedAt .Epoch}} +
+
+ + +
+
+ {{else}} + + {{end}} +
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+
+ + +
+
+ + +
+
+
+ + + Cancel +
+
+ {{template "prt_footer.html" .}} + + + + + + \ No newline at end of file diff --git a/assets/tpl/admin_index.html b/assets/tpl/admin_index.html index 089e6ad..8a3c572 100644 --- a/assets/tpl/admin_index.html +++ b/assets/tpl/admin_index.html @@ -125,7 +125,7 @@
-
+
{{if eq $.Device.Type "server"}}

Current VPN Peers

{{end}} @@ -133,11 +133,12 @@

Current VPN Endpoints

{{end}}
-
+
+ {{if eq $.Device.Type "server"}} - + {{end}} - M +
@@ -261,8 +262,10 @@
{{template "prt_footer.html" .}} - + + + diff --git a/assets/tpl/admin_user_index.html b/assets/tpl/admin_user_index.html index 6c431e8..87dd814 100644 --- a/assets/tpl/admin_user_index.html +++ b/assets/tpl/admin_user_index.html @@ -59,8 +59,10 @@
{{template "prt_footer.html" .}} - + + + diff --git a/assets/tpl/error.html b/assets/tpl/error.html index 611381b..b2cda50 100644 --- a/assets/tpl/error.html +++ b/assets/tpl/error.html @@ -11,21 +11,23 @@ -{{template "prt_nav.html" .}} -
-
-
-

{{.Data.Code}}

+ {{template "prt_nav.html" .}} +
+
+
+

{{.Data.Code}}

+
+

{{.Data.Message}}

+

{{.Data.Details}}

← Back to Dashboard
-

{{.Data.Message}}

-

{{.Data.Details}}

← Back to Dashboard
-
-{{template "prt_footer.html" .}} - - - - + {{template "prt_footer.html" .}} + + + + + + \ No newline at end of file diff --git a/assets/tpl/index.html b/assets/tpl/index.html index aaf7e0b..c5ac342 100644 --- a/assets/tpl/index.html +++ b/assets/tpl/index.html @@ -79,8 +79,10 @@
{{template "prt_footer.html" .}} - + + + diff --git a/assets/tpl/login.html b/assets/tpl/login.html index 74e2bb0..15b3287 100644 --- a/assets/tpl/login.html +++ b/assets/tpl/login.html @@ -56,8 +56,10 @@ {{template "prt_flashes.html" .}}
- + + + diff --git a/assets/tpl/user_index.html b/assets/tpl/user_index.html index 6f6f1b3..1694af7 100644 --- a/assets/tpl/user_index.html +++ b/assets/tpl/user_index.html @@ -102,8 +102,10 @@
{{template "prt_footer.html" .}} - + + + diff --git a/internal/server/handlers_peer.go b/internal/server/handlers_peer.go index d1a3679..9c8b30d 100644 --- a/internal/server/handlers_peer.go +++ b/internal/server/handlers_peer.go @@ -12,6 +12,7 @@ import ( "github.com/h44z/wg-portal/internal/common" "github.com/h44z/wg-portal/internal/users" "github.com/h44z/wg-portal/internal/wireguard" + "github.com/pkg/errors" "github.com/sirupsen/logrus" "github.com/tatsushid/go-fastping" csrf "github.com/utrack/gin-csrf" @@ -254,59 +255,7 @@ func (s *Server) GetPeerConfigMail(c *gin.Context) { return } - user := s.users.GetUser(peer.Email) - - 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 { + if err := s.sendPeerConfigMail(peer); err != nil { s.GetHandleError(c, http.StatusInternalServerError, "Email error", err.Error()) return } @@ -367,3 +316,79 @@ func (s *Server) GetPeerStatus(c *gin.Context) { c.JSON(http.StatusOK, isOnline) 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 +} diff --git a/internal/server/routes.go b/internal/server/routes.go index db169ef..21451e2 100644 --- a/internal/server/routes.go +++ b/internal/server/routes.go @@ -58,6 +58,7 @@ func SetupRoutes(s *Server) { admin.GET("/peer/delete", s.GetAdminDeletePeer) admin.GET("/peer/download", s.GetPeerConfig) admin.GET("/peer/email", s.GetPeerConfigMail) + admin.GET("/peer/emailall", s.GetAdminSendEmails) admin.GET("/users/", s.GetAdminUsersIndex) admin.GET("/users/create", s.GetAdminUsersCreate)