mirror of
https://github.com/inverse-inc/sogo.git
synced 2026-08-30 02:37:16 +00:00
feat(core): Add message of the day
This commit is contained in:
@@ -25,3 +25,7 @@
|
||||
"No resource" = "No resource";
|
||||
"Any Authenticated User" = "Any Authenticated User";
|
||||
"Public Access" = "Public Access";
|
||||
"Save" = "Save";
|
||||
"Clear" = "Clear";
|
||||
"Message of the day" = "Message of the day";
|
||||
"Message of the day has been saved" = "Message of the day has been saved";
|
||||
|
||||
@@ -25,3 +25,7 @@
|
||||
"No resource" = "Aucune ressource";
|
||||
"Any Authenticated User" = "Tout utilisateur authentifié";
|
||||
"Public Access" = "Accès public";
|
||||
"Save" = "Sauvegarder";
|
||||
"Clear" = "Effacer";
|
||||
"Message of the day" = "Message du jour";
|
||||
"Message of the day has been saved" = "Le message du jour a été sauvegardé";
|
||||
@@ -13,7 +13,8 @@ AdministrationUI_OBJC_FILES = \
|
||||
\
|
||||
UIxAdministration.m \
|
||||
UIxAdministrationAclEditor.m \
|
||||
UIxAdministrationFilterPanel.m
|
||||
UIxAdministrationFilterPanel.m \
|
||||
UIxAdministrationMotd.m
|
||||
|
||||
AdministrationUI_RESOURCE_FILES += \
|
||||
product.plist
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
#import <SoObjects/SOGo/SOGoUser.h>
|
||||
//#import "../../Main/SOGo.h"
|
||||
|
||||
#import <SOGo/SOGoAdmin.h>
|
||||
|
||||
#import "UIxAdministration.h"
|
||||
|
||||
@implementation UIxAdministration
|
||||
@@ -53,12 +55,18 @@
|
||||
return @"Administration";
|
||||
}
|
||||
|
||||
|
||||
- (BOOL) shouldTakeValuesFromRequest: (WORequest *) request
|
||||
inContext: (WOContext*) context
|
||||
{
|
||||
return [[request method] isEqualToString: @"POST"];
|
||||
}
|
||||
|
||||
- (BOOL) isAdminTableConfigured
|
||||
{
|
||||
return [[SOGoAdmin sharedInstance] isConfigured];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
/* Theme Preview */
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
/* UIxAdministrationMotd.h - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2023 Alinto
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This file is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef UIXMOTD_H
|
||||
#define UIXMOTD_H
|
||||
|
||||
#import <SOGoUI/UIxComponent.h>
|
||||
|
||||
@interface UIxAdministrationMotd : UIxComponent
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#endif /* UIXMOTD_H */
|
||||
@@ -0,0 +1,110 @@
|
||||
/* UIxAdministrationMotd.m - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2023 Alinto
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This file is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#import "UIxAdministrationMotd.h"
|
||||
|
||||
#import <SOGo/SOGoUser.h>
|
||||
#import <SOGo/SOGoAdmin.h>
|
||||
|
||||
@implementation UIxAdministrationMotd
|
||||
|
||||
- (id) init
|
||||
{
|
||||
if ((self = [super init]))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (WOResponse *) getAction
|
||||
{
|
||||
WOResponse *response;
|
||||
SOGoAdmin *admin;
|
||||
NSDictionary *jsonResponse;
|
||||
|
||||
admin = [SOGoAdmin sharedInstance];
|
||||
if ([admin isConfigured]) {
|
||||
jsonResponse = [NSDictionary dictionaryWithObject: nil != [admin getMotd] ? [admin getMotd] : @""
|
||||
forKey: @"motd"];
|
||||
response = [self responseWithStatus: 200
|
||||
andJSONRepresentation: jsonResponse];
|
||||
} else {
|
||||
response = [self responseWithStatus: 500
|
||||
andString: @"Missing folder configuration"];
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
- (WOResponse *) saveAction
|
||||
{
|
||||
WORequest *request;
|
||||
WOResponse *response;
|
||||
SOGoUser *user;
|
||||
NSException *error;
|
||||
NSDictionary *data;
|
||||
SOGoAdmin *admin;
|
||||
|
||||
error = nil;
|
||||
admin = [SOGoAdmin sharedInstance];
|
||||
user = [context activeUser];
|
||||
|
||||
if ([user isSuperUser]) {
|
||||
if ([admin isConfigured]) {
|
||||
data = [[[context request] contentAsString] objectFromJSONString];
|
||||
if ([data objectForKey: @"motd"]
|
||||
&& [[data objectForKey: @"motd"] isKindOfClass: [NSString class]]
|
||||
&& [[data objectForKey: @"motd"] length] > 0) {
|
||||
error = [admin saveMotd: [data objectForKey: @"motd"]];
|
||||
} else {
|
||||
error = [admin deleteMotd];
|
||||
}
|
||||
|
||||
if (!error) {
|
||||
response = [self responseWithStatus: 200
|
||||
andString: @"OK"];
|
||||
} else {
|
||||
response = [self responseWithStatus: 500
|
||||
andString: @"Error while storing information"];
|
||||
}
|
||||
|
||||
} else {
|
||||
response = [self responseWithStatus: 500
|
||||
andString: @"Missing folder configuration"];
|
||||
}
|
||||
} else {
|
||||
response = [self responseWithStatus: 503
|
||||
andString: @"Forbidden"];
|
||||
}
|
||||
|
||||
response = [self responseWithStatus: 200
|
||||
andString: @"OK"];
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -22,6 +22,20 @@
|
||||
protectedBy = "View";
|
||||
pageName = "UIxThemePreview";
|
||||
};
|
||||
UIxAdministrationMotd = {
|
||||
protectedBy = "View";
|
||||
pageName = "UIxAdministrationMotd";
|
||||
};
|
||||
getMotd = {
|
||||
protectedBy = "View";
|
||||
pageName = "UIxAdministrationMotd";
|
||||
actionName = "get";
|
||||
};
|
||||
saveMotd = {
|
||||
protectedBy = "View";
|
||||
pageName = "UIxAdministrationMotd";
|
||||
actionName = "save";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -51,6 +51,7 @@
|
||||
#import <SOGo/SOGoWebAuthenticator.h>
|
||||
#import <SOGo/SOGoEmptyAuthenticator.h>
|
||||
#import <SOGo/SOGoMailer.h>
|
||||
#import <SOGo/SOGoAdmin.h>
|
||||
|
||||
#if defined(MFA_CONFIG)
|
||||
#include <liboath/oath.h>
|
||||
@@ -1043,4 +1044,20 @@ static const NSString *kJwtKey = @"jwt";
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
- (NSString *)motd
|
||||
{
|
||||
return [[SOGoAdmin sharedInstance] getMotd];
|
||||
}
|
||||
|
||||
- (NSString *)motdEscaped
|
||||
{
|
||||
return [[[SOGoAdmin sharedInstance] getMotd] stringWithoutHTMLInjection: YES];
|
||||
}
|
||||
|
||||
- (BOOL)hasMotd
|
||||
{
|
||||
return [[SOGoAdmin sharedInstance] getMotd] && [[[SOGoAdmin sharedInstance] getMotd] length] > 1;
|
||||
}
|
||||
|
||||
@end /* SOGoRootPage */
|
||||
|
||||
@@ -303,6 +303,7 @@
|
||||
"Last" = "Last used";
|
||||
"Default Module " = "Default Module";
|
||||
"SOGo Version" = "SOGo Version";
|
||||
"Administration" = "Administration";
|
||||
|
||||
/* Confirmation asked when changing the language */
|
||||
"Save preferences and reload page now?" = "Save preferences and reload page now?";
|
||||
|
||||
@@ -303,6 +303,7 @@
|
||||
"Last" = "Dernier utilisé";
|
||||
"Default Module " = "Module par défaut";
|
||||
"SOGo Version" = "Version";
|
||||
"Administration" = "Administration";
|
||||
|
||||
/* Confirmation asked when changing the language */
|
||||
"Save preferences and reload page now?" = "Sauvegarder les préférences et recharger maintenant?";
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
title="moduleName"
|
||||
const:jsFiles="Common.js, Administration.js,
|
||||
Administration.services.js, Preferences.services.js,
|
||||
Contacts.services.js, Scheduler.services.js">
|
||||
Contacts.services.js, Scheduler.services.js, vendor/ckeditor/ckeditor.js, Common/sgCkeditor.component.js">
|
||||
|
||||
<main class="view"
|
||||
layout="row" layout-fill="layout-fill"
|
||||
@@ -38,6 +38,14 @@
|
||||
<md-icon>palette</md-icon>
|
||||
<p class="sg-item-name"><var:string label:value="Theme Preview"/></p>
|
||||
</md-list-item>
|
||||
<var:if condition="isAdminTableConfigured">
|
||||
<md-list-item ng-click="app.go('motd')"
|
||||
ui-sref="administration.motd"
|
||||
ui-sref-active="md-default-theme md-background md-bg md-hue-1">
|
||||
<md-icon>insert_comment</md-icon>
|
||||
<p class="sg-item-name"><var:string label:value="Message of the day"/></p>
|
||||
</md-list-item>
|
||||
</var:if>
|
||||
</md-list>
|
||||
</md-content>
|
||||
</md-sidenav>
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" standalone="yes"?>
|
||||
<!DOCTYPE container>
|
||||
<container
|
||||
xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:var="http://www.skyrix.com/od/binding"
|
||||
xmlns:const="http://www.skyrix.com/od/constant"
|
||||
xmlns:label="OGo:label"
|
||||
>
|
||||
<md-toolbar layout="row" layout-align="space-between center" class="sg-toolbar-main">
|
||||
<var:component className="UIxTopnavToolbar" />
|
||||
</md-toolbar>
|
||||
<md-content class="md-padding ng-scope">
|
||||
<div class="pseudo-input-container ng-scope">
|
||||
<label class="pseudo-input-label"><var:string label:value="Message of the day"/></label>
|
||||
<sg-ckeditor
|
||||
class="ng-cloak"
|
||||
config="ctrl.ckConfig"
|
||||
ck-margin="8px"
|
||||
ng-model="ctrl.motd"><!-- HTML editor --></sg-ckeditor>
|
||||
<div layout="row" layout-align="end center" class="layout-align-end-center layout-row">
|
||||
<button class="md-primary md-button ng-binding md-ink-ripple" ng-click="ctrl.clear()"><var:string label:value="Clear"/></button>
|
||||
<button class="md-primary md-button ng-binding md-ink-ripple" ng-click="ctrl.save()"><var:string label:value="Save"/></button>
|
||||
</div>
|
||||
</div>
|
||||
</md-content>
|
||||
|
||||
</container>
|
||||
@@ -24,337 +24,349 @@
|
||||
layout-gt-md="row" layout-align-gt-md="center start" layout-fill="layout-fill"
|
||||
ui-view="login"
|
||||
ng-controller="LoginController as app">
|
||||
<md-content id="loginContent" class="ng-cloak md-whiteframe-3dp" flex="100"
|
||||
layout="column" layout-gt-md="row" layout-align="start stretch"
|
||||
<md-content class="ng-cloak" flex="100"
|
||||
layout="column" layout-align="start stretch"
|
||||
ng-show="app.showLogin">
|
||||
<div class="sg-logo" flex-gt-md="50">
|
||||
<div layout="row" class="md-padding">
|
||||
<div class="md-flex hide show-gt-md"><!-- push logo to the right on larger screens --></div>
|
||||
<img const:alt="*" class="md-margin" rsrc:src="img/sogo-full.svg"/>
|
||||
<var:if condition="hasMotd">
|
||||
<div flex="100" class="motd hide show-gt-md">
|
||||
<var:string var:value="motd" const:escapeHTML="NO" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="sg-login md-default-theme md-bg md-accent" flex-gt-md="50">
|
||||
<div id="login" class="sg-login-content md-padding">
|
||||
<form name="loginForm" layout="column"
|
||||
ng-cloak="ng-cloak"
|
||||
ng-submit="app.login()">
|
||||
<var:if condition="hasLoginSuffix">
|
||||
<input type="hidden" ng-model="app.creds.loginSuffix" var:value="loginSuffix"/>
|
||||
</var:if>
|
||||
<div id="loginContent" layout="column" layout-gt-md="row" flex="100" class="md-whiteframe-3dp">
|
||||
<div class="sg-logo" flex-gt-md="50">
|
||||
<div layout="row" class="md-padding">
|
||||
<div class="md-flex hide show-gt-md"><!-- push logo to the right on larger screens --></div>
|
||||
<img const:alt="*" class="md-margin" rsrc:src="img/sogo-full.svg"/>
|
||||
</div>
|
||||
<var:if condition="hasMotd">
|
||||
<div layout="row">
|
||||
<div class="motd hide-gt-md"><var:string var:value="motdEscaped" const:escapeHTML="NO" /></div>
|
||||
</div>
|
||||
</var:if>
|
||||
<div ng-if="!app.loginState">
|
||||
<md-input-container class="md-block">
|
||||
<label><var:string label:value="Username"/></label>
|
||||
<md-icon>person</md-icon>
|
||||
<input autocorrect="off" autocapitalize="off" type="text" ng-model="app.creds.username" ng-required="true" ng-change="app.usernameChanged()" ng-blur="app.retrievePasswordRecoveryEnabled()" />
|
||||
</md-input-container>
|
||||
<md-input-container class="md-block">
|
||||
<label><var:string label:value="Password"/></label>
|
||||
<md-icon>vpn_key</md-icon>
|
||||
<input id="passwordField" type="password" ng-model="app.creds.password" ng-required="true"/>
|
||||
<md-icon id="password-visibility-icon" ng-click="app.changePasswordVisibility()">visibility</md-icon>
|
||||
</md-input-container>
|
||||
|
||||
</div>
|
||||
<div class="sg-login md-default-theme md-bg md-accent" flex-gt-md="50">
|
||||
<div id="login" class="sg-login-content md-padding">
|
||||
<form name="loginForm" layout="column"
|
||||
ng-cloak="ng-cloak"
|
||||
ng-submit="app.login()">
|
||||
<var:if condition="hasLoginSuffix">
|
||||
<input type="hidden" ng-model="app.creds.loginSuffix" var:value="loginSuffix"/>
|
||||
</var:if>
|
||||
<div ng-if="!app.loginState">
|
||||
<md-input-container class="md-block">
|
||||
<label><var:string label:value="Username"/></label>
|
||||
<md-icon>person</md-icon>
|
||||
<input autocorrect="off" autocapitalize="off" type="text" ng-model="app.creds.username" ng-required="true" ng-change="app.usernameChanged()" ng-blur="app.retrievePasswordRecoveryEnabled()" />
|
||||
</md-input-container>
|
||||
<md-input-container class="md-block">
|
||||
<label><var:string label:value="Password"/></label>
|
||||
<md-icon>vpn_key</md-icon>
|
||||
<input id="passwordField" type="password" ng-model="app.creds.password" ng-required="true"/>
|
||||
<md-icon id="password-visibility-icon" ng-click="app.changePasswordVisibility()">visibility</md-icon>
|
||||
</md-input-container>
|
||||
|
||||
|
||||
<!-- LANGUAGES SELECT -->
|
||||
<div layout="row" layout-align="start end">
|
||||
<md-icon>language</md-icon>
|
||||
<md-input-container class="md-flex">
|
||||
<label><var:string label:value="choose"/></label>
|
||||
<md-select ng-model="app.creds.language"
|
||||
var:placeholder="localizedLanguage"
|
||||
ng-change="app.changeLanguage($event)">
|
||||
<var:foreach list="languages" item="item">
|
||||
<md-option var:value="item">
|
||||
<var:string value="languageText"/>
|
||||
</md-option>
|
||||
</var:foreach>
|
||||
</md-select>
|
||||
</md-input-container>
|
||||
</div>
|
||||
<!-- LANGUAGES SELECT -->
|
||||
<div layout="row" layout-align="start end">
|
||||
<md-icon>language</md-icon>
|
||||
<md-input-container class="md-flex">
|
||||
<label><var:string label:value="choose"/></label>
|
||||
<md-select ng-model="app.creds.language"
|
||||
var:placeholder="localizedLanguage"
|
||||
ng-change="app.changeLanguage($event)">
|
||||
<var:foreach list="languages" item="item">
|
||||
<md-option var:value="item">
|
||||
<var:string value="languageText"/>
|
||||
</md-option>
|
||||
</var:foreach>
|
||||
</md-select>
|
||||
</md-input-container>
|
||||
</div>
|
||||
|
||||
<!-- DOMAINS SELECT -->
|
||||
<var:if condition="hasLoginDomains">
|
||||
<div layout="row" layout-align="start end">
|
||||
<md-icon>domain</md-icon>
|
||||
<md-input-container class="md-flex">
|
||||
<md-select class="md-flex" ng-model="app.creds.domain" label:placeholder="choose" ng-change="app.retrievePasswordRecoveryEnabled()">
|
||||
<var:foreach list="loginDomains" item="item">
|
||||
<md-option var:value="item">
|
||||
<var:string value="item"/>
|
||||
</md-option>
|
||||
</var:foreach>
|
||||
</md-select>
|
||||
</md-input-container>
|
||||
</div>
|
||||
</var:if>
|
||||
|
||||
<div layout="row" layout-align="center center">
|
||||
<md-switch class="md-accent md-hue-2"
|
||||
ng-model="app.creds.rememberLogin"
|
||||
label:arial-label="Remember username">
|
||||
<var:string label:value="Remember username"/>
|
||||
</md-switch>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Password recovery -->
|
||||
<div layout="row" layout-align="center center" ng-if="app.passwordRecovery.passwordRecoveryEnabled">
|
||||
<div ng-if="app.showLogin">
|
||||
<a href="#" ng-click="app.passwordRecoveryInfo()" sg-ripple-click="loginContent" class="password-lost-link"><var:string label:value="Password lost"/></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- CONNECT BUTTON -->
|
||||
<div layout="row" layout-align="space-between center" ng-if="!app.loginState">
|
||||
<md-button class="md-icon-button"
|
||||
label:aria-label="About"
|
||||
ng-click="app.showAbout()">
|
||||
<md-icon>info</md-icon>
|
||||
</md-button>
|
||||
<div>
|
||||
<md-button class="md-fab md-accent md-hue-2" type="submit"
|
||||
label:aria-label="Connect"
|
||||
ng-if="!app.loginState"
|
||||
ng-disabled="loginForm.$invalid"
|
||||
sg-ripple-click="loginContent">
|
||||
<md-icon>arrow_forward</md-icon>
|
||||
</md-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<sg-ripple class="md-default-theme md-accent md-bg"
|
||||
ng-class="{ 'md-warn': app.loginState == 'error' }"><!-- ripple background --></sg-ripple>
|
||||
<sg-ripple-content class="md-flex ng-hide"
|
||||
layout="column" layout-align="center center" layout-fill="layout-fill"
|
||||
ng-switch="app.loginState">
|
||||
|
||||
<!-- Authenticating -->
|
||||
<div layout="column" layout-align="center center"
|
||||
ng-switch-when="authenticating">
|
||||
<md-progress-circular class="md-hue-1"
|
||||
md-mode="indeterminate"
|
||||
md-diameter="32"><!-- mailbox loading progress --></md-progress-circular>
|
||||
<div class="md-default-theme md-accent md-hue-1 md-fg md-padding">
|
||||
<var:string label:value="Authenticating"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<var:if condition="isTotpEnabled">
|
||||
<!-- TOTP Code -->
|
||||
<div layout="row" layout-align="center center" layout-fill="layout-fill"
|
||||
ng-switch-when="totpcode">
|
||||
<div flex="80" flex-sm="50" flex-gt-sm="40">
|
||||
<md-input-container class="md-block">
|
||||
<label><var:string label:value="Verification Code"/></label>
|
||||
<md-icon>lock</md-icon>
|
||||
<input type="text"
|
||||
ng-pattern="app.verificationCodePattern"
|
||||
ng-model="app.creds.verificationCode"
|
||||
ng-required="app.loginState == 'totpcode'"
|
||||
sg-focus-on="totpcode"/>
|
||||
<div class="sg-hint"><var:string label:value="Enter the 6-digit verification code from your TOTP application."/></div>
|
||||
</md-input-container>
|
||||
<div layout="row" layout-align="space-between center">
|
||||
<md-button class="md-icon-button"
|
||||
label:aria-label="Cancel"
|
||||
ng-click="app.restoreLogin()"
|
||||
sg-ripple-click="loginContent">
|
||||
<md-icon>arrow_backward</md-icon>
|
||||
</md-button>
|
||||
<md-button class="md-fab md-accent md-hue-2" type="submit"
|
||||
label:aria-label="Connect"
|
||||
ng-if="app.loginState == 'totpcode'"
|
||||
ng-disabled="loginForm.$invalid"
|
||||
ng-click="app.login()">
|
||||
<md-icon>arrow_forward</md-icon>
|
||||
</md-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- TOTP has been disabled -->
|
||||
<div layout="row" layout-align="center center" layout-fill="layout-fill"
|
||||
ng-switch-when="totpdisabled">
|
||||
<div layout="column" layout-align="center center" flex-xs="flex-xs" flex-gt-xs="50">
|
||||
<md-icon class="md-accent md-hue-1 sg-icon--large">warning</md-icon>
|
||||
<div class="md-default-theme md-accent md-hue-1 md-fg md-padding" ng-if="app.cn">
|
||||
<var:string label:value="Welcome"/> {{app.cn}}
|
||||
</div>
|
||||
<div class="md-padding" layout="row" layout-align="start center">
|
||||
<md-icon>priority_high</md-icon>
|
||||
<div class="md-padding">
|
||||
<var:string label:value="Two-factor authentication has been disabled. Visit the Preferences module to restore two-factor authentication and reconfigure your TOTP application."/>
|
||||
<!-- DOMAINS SELECT -->
|
||||
<var:if condition="hasLoginDomains">
|
||||
<div layout="row" layout-align="start end">
|
||||
<md-icon>domain</md-icon>
|
||||
<md-input-container class="md-flex">
|
||||
<md-select class="md-flex" ng-model="app.creds.domain" label:placeholder="choose" ng-change="app.retrievePasswordRecoveryEnabled()">
|
||||
<var:foreach list="loginDomains" item="item">
|
||||
<md-option var:value="item">
|
||||
<var:string value="item"/>
|
||||
</md-option>
|
||||
</var:foreach>
|
||||
</md-select>
|
||||
</md-input-container>
|
||||
</div>
|
||||
</var:if>
|
||||
|
||||
<div layout="row" layout-align="center center">
|
||||
<md-switch class="md-accent md-hue-2"
|
||||
ng-model="app.creds.rememberLogin"
|
||||
label:arial-label="Remember username">
|
||||
<var:string label:value="Remember username"/>
|
||||
</md-switch>
|
||||
</div>
|
||||
</div>
|
||||
<div layout="row" layout-align="end center">
|
||||
|
||||
<!-- Password recovery -->
|
||||
<div layout="row" layout-align="center center" ng-if="app.passwordRecovery.passwordRecoveryEnabled">
|
||||
<div ng-if="app.showLogin">
|
||||
<a href="#" ng-click="app.passwordRecoveryInfo()" sg-ripple-click="loginContent" class="password-lost-link"><var:string label:value="Password lost"/></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- CONNECT BUTTON -->
|
||||
<div layout="row" layout-align="space-between center" ng-if="!app.loginState">
|
||||
<md-button class="md-icon-button"
|
||||
label:aria-label="About"
|
||||
ng-click="app.showAbout()">
|
||||
<md-icon>info</md-icon>
|
||||
</md-button>
|
||||
<div>
|
||||
<md-button class="md-fab md-accent md-hue-2" type="submit"
|
||||
label:aria-label="Connect"
|
||||
ng-if="!app.loginState"
|
||||
ng-disabled="loginForm.$invalid"
|
||||
sg-ripple-click="loginContent">
|
||||
<md-icon>arrow_forward</md-icon>
|
||||
</md-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<sg-ripple class="md-default-theme md-accent md-bg"
|
||||
ng-class="{ 'md-warn': app.loginState == 'error' }"><!-- ripple background --></sg-ripple>
|
||||
<sg-ripple-content class="md-flex ng-hide"
|
||||
layout="column" layout-align="center center" layout-fill="layout-fill"
|
||||
ng-switch="app.loginState">
|
||||
|
||||
<!-- Authenticating -->
|
||||
<div layout="column" layout-align="center center"
|
||||
ng-switch-when="authenticating">
|
||||
<md-progress-circular class="md-hue-1"
|
||||
md-mode="indeterminate"
|
||||
md-diameter="32"><!-- mailbox loading progress --></md-progress-circular>
|
||||
<div class="md-default-theme md-accent md-hue-1 md-fg md-padding">
|
||||
<var:string label:value="Authenticating"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<var:if condition="isTotpEnabled">
|
||||
<!-- TOTP Code -->
|
||||
<div layout="row" layout-align="center center" layout-fill="layout-fill"
|
||||
ng-switch-when="totpcode">
|
||||
<div flex="80" flex-sm="50" flex-gt-sm="40">
|
||||
<md-input-container class="md-block">
|
||||
<label><var:string label:value="Verification Code"/></label>
|
||||
<md-icon>lock</md-icon>
|
||||
<input type="text"
|
||||
ng-pattern="app.verificationCodePattern"
|
||||
ng-model="app.creds.verificationCode"
|
||||
ng-required="app.loginState == 'totpcode'"
|
||||
sg-focus-on="totpcode"/>
|
||||
<div class="sg-hint"><var:string label:value="Enter the 6-digit verification code from your TOTP application."/></div>
|
||||
</md-input-container>
|
||||
<div layout="row" layout-align="space-between center">
|
||||
<md-button class="md-icon-button"
|
||||
label:aria-label="Cancel"
|
||||
ng-click="app.restoreLogin()"
|
||||
sg-ripple-click="loginContent">
|
||||
<md-icon>arrow_backward</md-icon>
|
||||
</md-button>
|
||||
<md-button class="md-fab md-accent md-hue-2" type="submit"
|
||||
label:aria-label="Connect"
|
||||
ng-if="app.loginState == 'totpcode'"
|
||||
ng-disabled="loginForm.$invalid"
|
||||
ng-click="app.login()">
|
||||
<md-icon>arrow_forward</md-icon>
|
||||
</md-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- TOTP has been disabled -->
|
||||
<div layout="row" layout-align="center center" layout-fill="layout-fill"
|
||||
ng-switch-when="totpdisabled">
|
||||
<div layout="column" layout-align="center center" flex-xs="flex-xs" flex-gt-xs="50">
|
||||
<md-icon class="md-accent md-hue-1 sg-icon--large">warning</md-icon>
|
||||
<div class="md-default-theme md-accent md-hue-1 md-fg md-padding" ng-if="app.cn">
|
||||
<var:string label:value="Welcome"/> {{app.cn}}
|
||||
</div>
|
||||
<div class="md-padding" layout="row" layout-align="start center">
|
||||
<md-icon>priority_high</md-icon>
|
||||
<div class="md-padding">
|
||||
<var:string label:value="Two-factor authentication has been disabled. Visit the Preferences module to restore two-factor authentication and reconfigure your TOTP application."/>
|
||||
</div>
|
||||
</div>
|
||||
<div layout="row" layout-align="end center">
|
||||
<md-button
|
||||
ng-click="app.continueLogin()"
|
||||
sg-ripple-click="loginContent"><var:string label:value="Continue"/></md-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</var:if>
|
||||
|
||||
<!-- Password policy: Password is expired / password recovery-->
|
||||
<div layout="column" layout-align="center center"
|
||||
ng-switch-when="passwordchange">
|
||||
<md-icon class="md-accent md-hue-1 sg-icon--large" ng-if="!app.isInPasswordRecoveryMode()">watch_later</md-icon>
|
||||
<md-icon class="md-accent md-hue-1 sg-icon--large" ng-if="app.isInPasswordRecoveryMode()">vpn_key</md-icon>
|
||||
<div class="md-default-theme md-accent md-hue-1 md-fg md-padding" ng-if="!app.isInPasswordRecoveryMode()">
|
||||
<var:string label:value="Your password has expired, please enter a new one below"/>
|
||||
</div>
|
||||
<div class="md-default-theme md-accent md-hue-1 md-fg md-padding" ng-if="app.isInPasswordRecoveryMode()">
|
||||
<var:string label:value="Please enter a new password below"/>
|
||||
</div>
|
||||
<div flex="100">
|
||||
<div layout="row" layout-xs="column">
|
||||
<md-input-container class="md-block" flex="flex" ng-if="!app.isInPasswordRecoveryMode()">
|
||||
<label><var:string label:value="Current password"/>
|
||||
</label>
|
||||
<input type="password" sg-no-dirty-check="true" ng-model="app.passwords.oldPassword"/>
|
||||
</md-input-container>
|
||||
<md-input-container class="md-block" flex="flex">
|
||||
<label><var:string label:value="New password"/>
|
||||
</label>
|
||||
<input type="password" sg-no-dirty-check="true" ng-model="app.passwords.newPassword"/>
|
||||
</md-input-container>
|
||||
<md-input-container class="md-block" flex="flex">
|
||||
<label><var:string label:value="Confirmation"/>
|
||||
</label>
|
||||
<input type="password" name="newPasswordConfirmation" sg-no-dirty-check="true" ng-model="app.passwords.newPasswordConfirmation"/>
|
||||
<div ng-messages="loginForm.newPasswordConfirmation.$error">
|
||||
<div ng-message="newPasswordMismatch"><var:string label:value="Passwords don't match"/></div>
|
||||
</div>
|
||||
</md-input-container>
|
||||
</div>
|
||||
<div layout="row" layout-align="end center">
|
||||
<md-button ng-click="app.changePassword()" type="button" ng-disabled="!app.canChangePassword(loginForm)">
|
||||
<var:string label:value="Change"/>
|
||||
</md-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Password policy: Grace period -->
|
||||
<div layout="row" layout-align="center center" layout-fill="layout-fill"
|
||||
ng-switch-when="passwordwillexpire">
|
||||
<div layout="column" layout-align="center center" flex-xs="flex-xs" flex-gt-xs="50">
|
||||
<md-icon class="md-accent md-hue-1 sg-icon--large">warning</md-icon>
|
||||
<div class="md-default-theme md-accent md-hue-1 md-fg md-padding" ng-if="app.cn">
|
||||
<var:string label:value="Welcome"/> {{app.cn}}
|
||||
</div>
|
||||
<div class="md-padding" layout="row" layout-align="start center">
|
||||
<md-icon>priority_high</md-icon>
|
||||
<div class="md-padding">{{app.errorMessage}}</div>
|
||||
</div>
|
||||
<div layout="row" layout-align="end center">
|
||||
<md-button
|
||||
ng-click="app.loginState = 'passwordexpired'"><var:string label:value="Change your Password"/></md-button>
|
||||
<md-button
|
||||
ng-click="app.continueLogin()"
|
||||
sg-ripple-click="loginContent"><var:string label:value="Continue"/></md-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Password recovery -->
|
||||
<var:if condition="hasPasswordRecovery">
|
||||
<div layout="column" layout-align="center center"
|
||||
ng-switch-when="passwordrecovery">
|
||||
<md-icon class="md-accent md-hue-1 sg-icon--large">vpn_key</md-icon>
|
||||
<div flex="100">
|
||||
<div layout="row" layout-xs="column" class="md-padding" layout-align="center center">
|
||||
<div ng-if="app.passwordRecovery.showLoader">
|
||||
<md-progress-circular class="md-hue-1"
|
||||
md-mode="indeterminate"
|
||||
md-diameter="32"><!-- password recovery progress --></md-progress-circular>
|
||||
</div>
|
||||
<div ng-if="'SecretQuestion' === app.passwordRecovery.passwordRecoveryMode">
|
||||
<div ng-if="!app.passwordRecovery.showLoader">
|
||||
{{ app.passwordRecovery.passwordRecoveryQuestion }}
|
||||
<md-input-container class="md-block">
|
||||
<label><var:string label:value="Answer"/></label>
|
||||
<input autocorrect="off" autocapitalize="off" type="text" ng-model="app.passwordRecovery.passwordRecoveryQuestionAnswer" />
|
||||
</md-input-container>
|
||||
</div>
|
||||
</div>
|
||||
<div ng-if="'SecondaryEmail' === app.passwordRecovery.passwordRecoveryMode">
|
||||
<div ng-if="!app.passwordRecovery.showLoader">
|
||||
{{ app.passwordRecovery.passwordRecoverySecondaryEmailText }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div layout="row" layout-align="end center" ng-if="!app.passwordRecovery.showLoader">
|
||||
<md-button ng-click="app.passwordRecoveryAbort()" type="button" >
|
||||
<var:string label:value="Back"/>
|
||||
</md-button>
|
||||
<div ng-if="'SecretQuestion' === app.passwordRecovery.passwordRecoveryMode">
|
||||
<md-button ng-click="app.passwordRecoveryCheck()" type="button" >
|
||||
<var:string label:value="Next"/>
|
||||
</md-button>
|
||||
</div>
|
||||
<div ng-if="'SecondaryEmail' === app.passwordRecovery.passwordRecoveryMode">
|
||||
<md-button ng-click="app.passwordRecoveryEmail()" type="button" >
|
||||
<var:string label:value="Next"/>
|
||||
</md-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div layout="column" layout-align="center center"
|
||||
ng-switch-when="sendrecoverymail">
|
||||
<md-icon class="md-accent md-hue-1 sg-icon--large">local_shipping</md-icon>
|
||||
<div flex="100">
|
||||
<div layout="row" layout-xs="column" class="md-padding">
|
||||
<div ng-if="'SecondaryEmail' === app.passwordRecovery.passwordRecoveryMode">
|
||||
<var:string label:value="A password reset link has been sent, please check your recovery e-mail mailbox and click on the link"/>
|
||||
</div>
|
||||
</div>
|
||||
<div layout="row" layout-align="end center">
|
||||
<md-button ng-click="app.passwordRecoveryAbort()" type="button" >
|
||||
<var:string label:value="Back"/>
|
||||
</md-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</var:if>
|
||||
|
||||
<!-- Logged in -->
|
||||
<div layout="column" layout-align="center center"
|
||||
ng-switch-when="logged">
|
||||
<md-icon class="md-accent md-hue-1 sg-icon--large">done</md-icon>
|
||||
<div class="md-default-theme md-accent md-hue-1 md-fg md-padding">
|
||||
<var:string label:value="Welcome"/> {{app.cn}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div layout="column" layout-align="center center"
|
||||
ng-switch-when="message">
|
||||
<md-icon class="md-accent md-hue-1 sg-icon--large">done</md-icon>
|
||||
<div class="md-default-theme md-accent md-hue-1 md-fg md-padding">
|
||||
{{app.errorMessage}}
|
||||
</div>
|
||||
<md-button
|
||||
ng-click="app.continueLogin()"
|
||||
sg-ripple-click="loginContent"><var:string label:value="Continue"/></md-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</var:if>
|
||||
|
||||
<!-- Password policy: Password is expired / password recovery-->
|
||||
<div layout="column" layout-align="center center"
|
||||
ng-switch-when="passwordchange">
|
||||
<md-icon class="md-accent md-hue-1 sg-icon--large" ng-if="!app.isInPasswordRecoveryMode()">watch_later</md-icon>
|
||||
<md-icon class="md-accent md-hue-1 sg-icon--large" ng-if="app.isInPasswordRecoveryMode()">vpn_key</md-icon>
|
||||
<div class="md-default-theme md-accent md-hue-1 md-fg md-padding" ng-if="!app.isInPasswordRecoveryMode()">
|
||||
<var:string label:value="Your password has expired, please enter a new one below"/>
|
||||
</div>
|
||||
<div class="md-default-theme md-accent md-hue-1 md-fg md-padding" ng-if="app.isInPasswordRecoveryMode()">
|
||||
<var:string label:value="Please enter a new password below"/>
|
||||
</div>
|
||||
<div flex="100">
|
||||
<div layout="row" layout-xs="column">
|
||||
<md-input-container class="md-block" flex="flex" ng-if="!app.isInPasswordRecoveryMode()">
|
||||
<label><var:string label:value="Current password"/>
|
||||
</label>
|
||||
<input type="password" sg-no-dirty-check="true" ng-model="app.passwords.oldPassword"/>
|
||||
</md-input-container>
|
||||
<md-input-container class="md-block" flex="flex">
|
||||
<label><var:string label:value="New password"/>
|
||||
</label>
|
||||
<input type="password" sg-no-dirty-check="true" ng-model="app.passwords.newPassword"/>
|
||||
</md-input-container>
|
||||
<md-input-container class="md-block" flex="flex">
|
||||
<label><var:string label:value="Confirmation"/>
|
||||
</label>
|
||||
<input type="password" name="newPasswordConfirmation" sg-no-dirty-check="true" ng-model="app.passwords.newPasswordConfirmation"/>
|
||||
<div ng-messages="loginForm.newPasswordConfirmation.$error">
|
||||
<div ng-message="newPasswordMismatch"><var:string label:value="Passwords don't match"/></div>
|
||||
</div>
|
||||
</md-input-container>
|
||||
</div>
|
||||
<div layout="row" layout-align="end center">
|
||||
<md-button ng-click="app.changePassword()" type="button" ng-disabled="!app.canChangePassword(loginForm)">
|
||||
<var:string label:value="Change"/>
|
||||
</md-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Password policy: Grace period -->
|
||||
<div layout="row" layout-align="center center" layout-fill="layout-fill"
|
||||
ng-switch-when="passwordwillexpire">
|
||||
<div layout="column" layout-align="center center" flex-xs="flex-xs" flex-gt-xs="50">
|
||||
<md-icon class="md-accent md-hue-1 sg-icon--large">warning</md-icon>
|
||||
<div class="md-default-theme md-accent md-hue-1 md-fg md-padding" ng-if="app.cn">
|
||||
<var:string label:value="Welcome"/> {{app.cn}}
|
||||
</div>
|
||||
<div class="md-padding" layout="row" layout-align="start center">
|
||||
<md-icon>priority_high</md-icon>
|
||||
<div class="md-padding">{{app.errorMessage}}</div>
|
||||
</div>
|
||||
<div layout="row" layout-align="end center">
|
||||
<!-- Error -->
|
||||
<div layout="column" layout-align="center center"
|
||||
ng-switch-when="error">
|
||||
<md-icon class="md-accent md-hue-1 sg-icon--large">error</md-icon>
|
||||
<div class="md-default-theme md-accent md-hue-1 md-fg md-padding">
|
||||
{{app.errorMessage}}
|
||||
</div>
|
||||
<md-button
|
||||
ng-click="app.loginState = 'passwordexpired'"><var:string label:value="Change your Password"/></md-button>
|
||||
<md-button
|
||||
ng-click="app.continueLogin()"
|
||||
sg-ripple-click="loginContent"><var:string label:value="Continue"/></md-button>
|
||||
ng-click="app.restoreLogin()"
|
||||
sg-ripple-click="loginContent"><var:string label:value="Retry"/></md-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</sg-ripple-content>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Password recovery -->
|
||||
<var:if condition="hasPasswordRecovery">
|
||||
<div layout="column" layout-align="center center"
|
||||
ng-switch-when="passwordrecovery">
|
||||
<md-icon class="md-accent md-hue-1 sg-icon--large">vpn_key</md-icon>
|
||||
<div flex="100">
|
||||
<div layout="row" layout-xs="column" class="md-padding" layout-align="center center">
|
||||
<div ng-if="app.passwordRecovery.showLoader">
|
||||
<md-progress-circular class="md-hue-1"
|
||||
md-mode="indeterminate"
|
||||
md-diameter="32"><!-- password recovery progress --></md-progress-circular>
|
||||
</div>
|
||||
<div ng-if="'SecretQuestion' === app.passwordRecovery.passwordRecoveryMode">
|
||||
<div ng-if="!app.passwordRecovery.showLoader">
|
||||
{{ app.passwordRecovery.passwordRecoveryQuestion }}
|
||||
<md-input-container class="md-block">
|
||||
<label><var:string label:value="Answer"/></label>
|
||||
<input autocorrect="off" autocapitalize="off" type="text" ng-model="app.passwordRecovery.passwordRecoveryQuestionAnswer" />
|
||||
</md-input-container>
|
||||
</div>
|
||||
</div>
|
||||
<div ng-if="'SecondaryEmail' === app.passwordRecovery.passwordRecoveryMode">
|
||||
<div ng-if="!app.passwordRecovery.showLoader">
|
||||
{{ app.passwordRecovery.passwordRecoverySecondaryEmailText }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div layout="row" layout-align="end center" ng-if="!app.passwordRecovery.showLoader">
|
||||
<md-button ng-click="app.passwordRecoveryAbort()" type="button" >
|
||||
<var:string label:value="Back"/>
|
||||
</md-button>
|
||||
<div ng-if="'SecretQuestion' === app.passwordRecovery.passwordRecoveryMode">
|
||||
<md-button ng-click="app.passwordRecoveryCheck()" type="button" >
|
||||
<var:string label:value="Next"/>
|
||||
</md-button>
|
||||
</div>
|
||||
<div ng-if="'SecondaryEmail' === app.passwordRecovery.passwordRecoveryMode">
|
||||
<md-button ng-click="app.passwordRecoveryEmail()" type="button" >
|
||||
<var:string label:value="Next"/>
|
||||
</md-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div layout="column" layout-align="center center"
|
||||
ng-switch-when="sendrecoverymail">
|
||||
<md-icon class="md-accent md-hue-1 sg-icon--large">local_shipping</md-icon>
|
||||
<div flex="100">
|
||||
<div layout="row" layout-xs="column" class="md-padding">
|
||||
<div ng-if="'SecondaryEmail' === app.passwordRecovery.passwordRecoveryMode">
|
||||
<var:string label:value="A password reset link has been sent, please check your recovery e-mail mailbox and click on the link"/>
|
||||
</div>
|
||||
</div>
|
||||
<div layout="row" layout-align="end center">
|
||||
<md-button ng-click="app.passwordRecoveryAbort()" type="button" >
|
||||
<var:string label:value="Back"/>
|
||||
</md-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</var:if>
|
||||
|
||||
<!-- Logged in -->
|
||||
<div layout="column" layout-align="center center"
|
||||
ng-switch-when="logged">
|
||||
<md-icon class="md-accent md-hue-1 sg-icon--large">done</md-icon>
|
||||
<div class="md-default-theme md-accent md-hue-1 md-fg md-padding">
|
||||
<var:string label:value="Welcome"/> {{app.cn}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div layout="column" layout-align="center center"
|
||||
ng-switch-when="message">
|
||||
<md-icon class="md-accent md-hue-1 sg-icon--large">done</md-icon>
|
||||
<div class="md-default-theme md-accent md-hue-1 md-fg md-padding">
|
||||
{{app.errorMessage}}
|
||||
</div>
|
||||
<md-button
|
||||
ng-click="app.continueLogin()"
|
||||
sg-ripple-click="loginContent"><var:string label:value="Continue"/></md-button>
|
||||
</div>
|
||||
|
||||
<!-- Error -->
|
||||
<div layout="column" layout-align="center center"
|
||||
ng-switch-when="error">
|
||||
<md-icon class="md-accent md-hue-1 sg-icon--large">error</md-icon>
|
||||
<div class="md-default-theme md-accent md-hue-1 md-fg md-padding">
|
||||
{{app.errorMessage}}
|
||||
</div>
|
||||
<md-button
|
||||
ng-click="app.restoreLogin()"
|
||||
sg-ripple-click="loginContent"><var:string label:value="Retry"/></md-button>
|
||||
</div>
|
||||
|
||||
</sg-ripple-content>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</md-content>
|
||||
|
||||
</main>
|
||||
|
||||
@@ -1493,4 +1493,4 @@
|
||||
</script>
|
||||
|
||||
|
||||
</var:component>
|
||||
</var:component>
|
||||
@@ -4,7 +4,7 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
angular.module('SOGo.AdministrationUI', ['ui.router', 'SOGo.Common', 'SOGo.Authentication', 'SOGo.PreferencesUI', 'SOGo.ContactsUI', 'SOGo.SchedulerUI'])
|
||||
angular.module('SOGo.AdministrationUI', ['ui.router', 'SOGo.Common', 'SOGo.Authentication', 'SOGo.PreferencesUI', 'SOGo.ContactsUI', 'SOGo.SchedulerUI', 'sgCkeditor'])
|
||||
.config(configure)
|
||||
.run(runBlock);
|
||||
|
||||
@@ -56,6 +56,16 @@
|
||||
controllerAs: 'ctrl'
|
||||
}
|
||||
}
|
||||
})
|
||||
.state('administration.motd', {
|
||||
url: '/motd',
|
||||
views: {
|
||||
module: {
|
||||
templateUrl: 'UIxAdministrationMotd', // UI/Templates/Administration/UIxAdministrationMotd.wox
|
||||
controller: 'AdministrationMotdController',
|
||||
controllerAs: 'ctrl'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// if none of the above states are matched, use this as the fallback
|
||||
|
||||
@@ -29,6 +29,34 @@
|
||||
return new Administration(); // return unique instance
|
||||
}];
|
||||
|
||||
/**
|
||||
* @function $getMotd
|
||||
* @memberof Administration.prototype
|
||||
* @desc Get the motd to the server.
|
||||
*/
|
||||
Administration.prototype.$getMotd = function () {
|
||||
var _this = this;
|
||||
|
||||
return Administration.$$resource.fetch("Administration/getMotd")
|
||||
.then(function (data) {
|
||||
return data;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @function $saveMotd
|
||||
* @memberof Administration.prototype
|
||||
* @desc Save the motd to the server.
|
||||
*/
|
||||
Administration.prototype.$saveMotd = function (message) {
|
||||
var _this = this;
|
||||
|
||||
return Administration.$$resource.save("Administration", { motd: message }, { action: "saveMotd" })
|
||||
.then(function (data) {
|
||||
return data;
|
||||
});
|
||||
};
|
||||
|
||||
/* Initialize module if necessary */
|
||||
try {
|
||||
angular.module('SOGo.AdministrationUI');
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* JavaScript for SOGoAdministration */
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* @ngInject
|
||||
*/
|
||||
AdministrationMotdController.$inject = ['$timeout', '$state', '$mdMedia', '$mdToast', 'sgConstant', 'Administration', 'sgSettings'];
|
||||
function AdministrationMotdController($timeout, $state, $mdMedia, $mdToast, sgConstant, Administration, Settings) {
|
||||
var vm = this;
|
||||
vm.administration = Administration;
|
||||
vm.motd = null;
|
||||
vm.save = save;
|
||||
vm.clear = clear;
|
||||
vm.ckConfig = {
|
||||
'autoGrow_minHeight': 200,
|
||||
removeButtons: 'Save,NewPage,Preview,Print,Templates,Cut,Copy,Paste,PasteText,PasteFromWord,Undo,Redo,Find,Replace,SelectAll,Scayt,Form,Checkbox,Radio,TextField,Textarea,Select,Button,Image,HiddenField,CopyFormatting,RemoveFormat,NumberedList,BulletedList,Outdent,Indent,Blockquote,CreateDiv,BidiLtr,BidiRtl,Language,Unlink,Anchor,Flash,Table,HorizontalRule,Smiley,SpecialChar,PageBreak,Iframe,Styles,Format,Maximize,ShowBlocks,About,Strike,Subscript,Superscript,Underline,Emojipanel,Emoji,'
|
||||
};
|
||||
|
||||
this.administration.$getMotd().then(function (data) {
|
||||
if (data && data.motd) {
|
||||
vm.motd = data.motd;
|
||||
}
|
||||
});
|
||||
|
||||
function save() {
|
||||
this.administration.$saveMotd(vm.motd).then(function () {
|
||||
$mdToast.show(
|
||||
$mdToast.simple()
|
||||
.textContent(l('Message of the day has been saved'))
|
||||
.position(sgConstant.toastPosition)
|
||||
.hideDelay(3000));
|
||||
});
|
||||
}
|
||||
|
||||
function clear() {
|
||||
console.log('HEY');
|
||||
vm.motd = '';
|
||||
}
|
||||
}
|
||||
|
||||
angular
|
||||
.module('SOGo.AdministrationUI')
|
||||
.controller('AdministrationMotdController', AdministrationMotdController);
|
||||
|
||||
})();
|
||||
@@ -1,4 +1,5 @@
|
||||
/// LoginUI.scss -*- Mode: scss; indent-tabs-mode: nil; basic-offset: 2 -*-
|
||||
@use "sass:color";
|
||||
|
||||
$sg-login-width: grid-step(5);
|
||||
|
||||
@@ -7,6 +8,12 @@ $sg-login-width: grid-step(5);
|
||||
// Keep content centered
|
||||
margin: auto;
|
||||
overflow: hidden;
|
||||
background: transparent;
|
||||
|
||||
#loginContent {
|
||||
background-color: $colorGrey50;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.sg-logo {
|
||||
// Center image
|
||||
@@ -17,6 +24,31 @@ $sg-login-width: grid-step(5);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fade-in {
|
||||
0% {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.motd {
|
||||
margin-top: 50px;
|
||||
margin-bottom: 50px;
|
||||
justify-content: center;
|
||||
margin-left: 2%;
|
||||
margin-right: 2%;
|
||||
padding: 50px;
|
||||
animation: fade-in ease 1.5s;
|
||||
border: solid 5px sg-color($sogoGreen, 500);
|
||||
}
|
||||
|
||||
.md-whiteframe-3dp {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.password-lost-link {
|
||||
color: rgb(255, 255, 255);
|
||||
font-size: 0.9em;
|
||||
@@ -52,6 +84,9 @@ $sg-login-width: grid-step(5);
|
||||
max-width: 75%;
|
||||
}
|
||||
}
|
||||
#loginContent {
|
||||
margin-top: 0;
|
||||
}
|
||||
.sg-login {
|
||||
// Let the form take all available space
|
||||
flex-grow: 1;
|
||||
@@ -61,6 +96,11 @@ $sg-login-width: grid-step(5);
|
||||
margin: auto;
|
||||
max-width: $sg-login-width;
|
||||
}
|
||||
.motd {
|
||||
margin-bottom: 10px;
|
||||
padding: 10px;
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user