🚧 Templating, styling, logic and structuring
Rename /emaildomains to /domains and return a list Minor cleanups
This commit is contained in:
1 parent
2026da8ef2
commit
39942447ed
9 files changed
+381
-106
No files matched your search
@@ -0,0 +1,44 @@
|
||||
/* Hide for mobile, show later */
|
||||
.sidebar {
|
||||
.orgunit-list {
|
||||
display: none;
|
||||
@media (min-width: 768px) {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
.search-field {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.orgunit-list {
|
||||
margin-bottom: 40px;
|
||||
|
||||
li {
|
||||
&.active {
|
||||
a,
|
||||
a:hover,
|
||||
a:focus {
|
||||
color: #fff;
|
||||
background-color: $primary;
|
||||
}
|
||||
}
|
||||
a {
|
||||
padding: 0.5rem 0.8rem;
|
||||
display: block;
|
||||
|
||||
|
||||
&:hover {
|
||||
text-decoration: none;
|
||||
background-color: #eee;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.orgunit-select-container {
|
||||
display: block;
|
||||
margin-bottom: 20px;
|
||||
|
||||
@media (min-width: map-get($grid-breakpoints, "md")) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
@@ -1,22 +1,238 @@
|
||||
import React from 'react';
|
||||
// import { parseEmails } from '../utils';
|
||||
import React, { useState } from 'react';
|
||||
import { groupBy, sortBy } from 'lodash';
|
||||
import { useQuery } from '@apollo/react-hooks';
|
||||
import ctx from 'classnames';
|
||||
|
||||
import { parseEmails } from '../utils';
|
||||
import { GET_ALIASES, GET_DOMAINS, GET_ORG_UNITS } from '../queries';
|
||||
|
||||
const ListCreate = () => {
|
||||
const { data, loading, error } = useQuery(GET_ORG_UNITS);
|
||||
const { data: emailData, loading: emailLoading, error: emailError } = useQuery(GET_DOMAINS);
|
||||
const [textareaVisible, setTextareaVisible] = useState(false);
|
||||
const [listName, setListName] = useState('');
|
||||
const [selectedPrefix, setSelectedPrefix] = useState(null);
|
||||
|
||||
if (loading || emailLoading || error || emailError) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { orgUnits } = data;
|
||||
const { domains } = emailData;
|
||||
const emailDomain = domains[0];
|
||||
|
||||
return (
|
||||
<div className="new-list-container">
|
||||
<button type="button" className="btn btn-default new-list-btn">
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-outline-primary new-list-btn"
|
||||
onClick={() => {
|
||||
setTextareaVisible(!textareaVisible);
|
||||
}}
|
||||
>
|
||||
<span className="fas fa-plus" aria-hidden="true" /> Opprett ny liste
|
||||
</button>
|
||||
<div className="new-list fwdlist" data-list-name="newlist@example.com"></div>
|
||||
<div className="new-list-result"></div>
|
||||
<div className={ctx('new-list fwdlist card', { visible: textareaVisible })}>
|
||||
<div className="card-header">
|
||||
<span className="fas fa-list-alt icon-faded" aria-hidden="true" /> <span className="">Ny liste</span>
|
||||
</div>
|
||||
<div className="card-body">
|
||||
<div className="new-list-name input-group">
|
||||
<div className="input-group-prepend">
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn btn-outline-secondary dropdown-toggle"
|
||||
data-toggle="dropdown"
|
||||
aria-haspopup="true"
|
||||
aria-expanded="false"
|
||||
>
|
||||
{selectedPrefix || orgUnits[0].prefixes[0]}- <span className="caret" />
|
||||
</button>
|
||||
<div className="dropdown-menu prefix-select">
|
||||
{orgUnits.map((ou) =>
|
||||
ou.prefixes.map((prefix) => (
|
||||
<a
|
||||
key={`${ou.id}-${prefix}`}
|
||||
className="dropdown-item"
|
||||
href="#"
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
setSelectedPrefix(prefix);
|
||||
}}
|
||||
>
|
||||
{prefix}-
|
||||
</a>
|
||||
))
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<input
|
||||
type="text"
|
||||
className="form-control js-new-list-name"
|
||||
value={listName}
|
||||
onChange={(e) => setListName(e.target.value)}
|
||||
/>
|
||||
<div className="input-group-append">
|
||||
<span className="input-group-text">{`@${emailDomain.name}`}</span>
|
||||
</div>
|
||||
</div>
|
||||
<EmailsTextarea listName={listName} selectedPrefix={selectedPrefix} newList={true} />
|
||||
</div>
|
||||
</div>
|
||||
{/* <div className="new-list-result"></div> */}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const Forwards = () => {
|
||||
const AliasRow = ({ id, destination, updateDeletionList }) => {
|
||||
const [checked, setChecked] = useState(false);
|
||||
return (
|
||||
<tr className="">
|
||||
<td>{destination}</td>
|
||||
<td className="del-cell">
|
||||
<div className="custom-control custom-checkbox custom-control-inline">
|
||||
<input
|
||||
id={`alias-delete-${id}`}
|
||||
type="checkbox"
|
||||
className="custom-control-input"
|
||||
value={checked}
|
||||
onChange={(e) => {
|
||||
setChecked(e.target.checked);
|
||||
updateDeletionList(id, e.target.checked);
|
||||
}}
|
||||
/>
|
||||
<label className="custom-control-label" htmlFor={`alias-delete-${id}`} />
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
};
|
||||
|
||||
const ActionRow = ({ onAddEmailClick, deleteVisible, onDelete }) => {
|
||||
return (
|
||||
<tr className="action-row">
|
||||
<td>
|
||||
<a href="#" className="link-add" onClick={onAddEmailClick}>
|
||||
<span className="fas fa-plus" aria-hidden="true" /> Legg til
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<a href="#" className={ctx('link-del', { visible: deleteVisible })} type="button" onClick={onDelete}>
|
||||
<span className="fas fa-trash" aria-hidden="true" />
|
||||
Slett
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
};
|
||||
|
||||
const EmailsTextarea = ({ list, selectedPrefix, newList = false }) => {
|
||||
const [rawAliases, setRawAliases] = useState('');
|
||||
const [aliases, setAliases] = useState([]);
|
||||
|
||||
const createAliases = () => {
|
||||
console.log(list, aliases, selectedPrefix, newList);
|
||||
// TODO: POST /aliases
|
||||
};
|
||||
return (
|
||||
<>
|
||||
<h5>
|
||||
Eposter{' '}
|
||||
<span className="badge badge-secondary email-counter">{aliases.length === 0 ? '' : aliases.length}</span>
|
||||
</h5>
|
||||
<textarea
|
||||
className="form-control"
|
||||
placeholder="asdf@studentersamfundet.no, qwerty@studentersamfundet.no f.eks. Klipp og lim så mye du orker"
|
||||
rows="4"
|
||||
value={rawAliases}
|
||||
onChange={(e) => {
|
||||
setRawAliases(e.target.value);
|
||||
setAliases(parseEmails(e.target.value));
|
||||
}}
|
||||
/>
|
||||
<div className="text-right">
|
||||
<button type="button" className="btn btn-primary btn-add-list" onClick={createAliases}>
|
||||
<span className="fas fa-plus" /> {newList ? 'Opprett liste' : 'Legg til'}
|
||||
</button>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const ForwardContainer = ({ filterQuery }) => {
|
||||
// TODO: Filter aliases by filterQuery
|
||||
const { data, loading, error } = useQuery(GET_ALIASES);
|
||||
|
||||
const [textareaVisible, setTextareaVisible] = useState(false);
|
||||
const [deletionList, setdeletionList] = useState([]);
|
||||
|
||||
const deleteAliases = (aliases) => {
|
||||
// TODO: delete aliases
|
||||
console.log(aliases);
|
||||
};
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<div className="forwards-container">
|
||||
<span className="fas fa-sync spin" aria-hidden="true" /> Laster...
|
||||
</div>
|
||||
);
|
||||
}
|
||||
if (error) {
|
||||
return null;
|
||||
}
|
||||
const lists = groupBy(
|
||||
sortBy(data.aliases, (alias) => {
|
||||
return alias.source;
|
||||
}),
|
||||
(alias) => alias.source
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="forwards-container">
|
||||
<span className="fas fa-refresh spin" aria-hidden="true" /> Laster...
|
||||
{Object.entries(lists).map(([list, aliases]) => {
|
||||
return (
|
||||
<div key={list} className="card">
|
||||
<div className="card-header">
|
||||
<span className="fas fa-list-alt icon-faded" aria-hidden="true" /> {list}{' '}
|
||||
<span className="badge badge-secondary badge-list-total">{aliases.length}</span>
|
||||
</div>
|
||||
<table className="table table-striped table-hover table-condensed">
|
||||
<tbody>
|
||||
{aliases.map((alias) => (
|
||||
<AliasRow
|
||||
key={alias.id}
|
||||
{...alias}
|
||||
updateDeletionList={(aliasId, checked) => {
|
||||
if (checked) {
|
||||
setdeletionList([...deletionList, aliasId]); // add
|
||||
} else {
|
||||
setdeletionList(deletionList.filter((id) => id !== aliasId)); // remove
|
||||
}
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
<ActionRow
|
||||
onAddEmailClick={() => {
|
||||
setTextareaVisible(!textareaVisible);
|
||||
}}
|
||||
deleteVisible={Boolean(deletionList.length)}
|
||||
onDelete={(e) => {
|
||||
e.preventDefault();
|
||||
deleteAliases(deletionList);
|
||||
}}
|
||||
/>
|
||||
|
||||
<tr className={ctx('textarea-row', { visible: textareaVisible })}>
|
||||
<td colSpan="2">
|
||||
<EmailsTextarea list={list} />
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -24,9 +240,9 @@ const Forwards = () => {
|
||||
const MainArea = () => {
|
||||
return (
|
||||
<div className="col-sm-8">
|
||||
<div className="orgunit-select-container"></div>
|
||||
{/* <div className="orgunit-select-container"></div> */}
|
||||
<ListCreate />
|
||||
<Forwards />
|
||||
<ForwardContainer />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import React, { useState } from 'react';
|
||||
import React, { useState, useCallback } from 'react';
|
||||
import { useQuery } from '@apollo/react-hooks';
|
||||
import gql from 'graphql-tag';
|
||||
import ctx from 'classnames';
|
||||
|
||||
import { setQueryString } from '../utils';
|
||||
import { GET_ORG_UNITS } from '../queries';
|
||||
|
||||
const Search = ({ query, setQuery }) => {
|
||||
return (
|
||||
@@ -24,19 +25,21 @@ const OrgUnit = ({ id, name, selected, onClick }) => (
|
||||
</li>
|
||||
);
|
||||
|
||||
const GET_ORG_UNITS = gql`
|
||||
query OrgUnits {
|
||||
orgUnits @rest(type: "OrgUnit", path: "orgunits/") {
|
||||
id
|
||||
name
|
||||
prefixes
|
||||
}
|
||||
}
|
||||
`;
|
||||
const OrgUnitList = () => {
|
||||
const [query, setQuery] = useState(new URLSearchParams(window.location.search).get('q') || '');
|
||||
const [selected, setSelected] = useState(null);
|
||||
const { data, loading, error } = useQuery(GET_ORG_UNITS);
|
||||
|
||||
const setSearchQuery = useCallback(
|
||||
(e) => {
|
||||
e.preventDefault();
|
||||
const q = e.target.value;
|
||||
setQuery(q);
|
||||
setQueryString(q ? { q } : null);
|
||||
},
|
||||
[setQuery]
|
||||
);
|
||||
|
||||
if (loading || error) {
|
||||
return null;
|
||||
}
|
||||
@@ -49,16 +52,8 @@ const OrgUnitList = () => {
|
||||
|
||||
return (
|
||||
<div className="col-sm-4 sidebar">
|
||||
<Search
|
||||
query={query}
|
||||
setQuery={(e) => {
|
||||
e.preventDefault();
|
||||
const q = e.target.value;
|
||||
setQuery(q);
|
||||
setQueryString(q ? { q } : null);
|
||||
}}
|
||||
/>
|
||||
<h4>Foreninger/Utvalg</h4>
|
||||
<Search query={query} setQuery={setSearchQuery} />
|
||||
<h5>Foreninger/Utvalg</h5>
|
||||
<ul className="nav nav-sidebar orgunit-list">
|
||||
<li className={ctx({ active: selected === null })}>
|
||||
<a
|
||||
|
||||
@@ -4,6 +4,7 @@ $icon-font-path: "../fonts/";
|
||||
@import "pnotify.core";
|
||||
|
||||
@import "./animations";
|
||||
@import "./sidebar";
|
||||
|
||||
.login-form {
|
||||
margin: 0 auto;
|
||||
@@ -14,55 +15,24 @@ $icon-font-path: "../fonts/";
|
||||
}
|
||||
}
|
||||
|
||||
/* Hide for mobile, show later */
|
||||
.sidebar {
|
||||
.orgunit-list {
|
||||
display: none;
|
||||
@media (min-width: 768px) {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
.search-field {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.orgunit-list {
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
.orgunit-select-container {
|
||||
display: block;
|
||||
margin-bottom: 20px;
|
||||
|
||||
@media (min-width: 768px) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* Sidebar navigation */
|
||||
.nav-sidebar > .active > a,
|
||||
.nav-sidebar > .active > a:hover,
|
||||
.nav-sidebar > .active > a:focus {
|
||||
color: #fff;
|
||||
background-color: #428bca;
|
||||
}
|
||||
|
||||
/* Sticky footer styles */
|
||||
|
||||
.footer {
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
/* Lists */
|
||||
.del-cell {
|
||||
text-align: center;
|
||||
width: 82px;
|
||||
padding: 0 !important;
|
||||
text-align: right;
|
||||
width: 54px;
|
||||
padding: 2px 0 0 !important;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.del-label {
|
||||
display: block;
|
||||
height: 30px;
|
||||
margin: 0;
|
||||
text-align: center;
|
||||
|
||||
input {
|
||||
margin: 0;
|
||||
position: relative;
|
||||
@@ -70,26 +40,28 @@ $icon-font-path: "../fonts/";
|
||||
}
|
||||
}
|
||||
|
||||
.forwards-container table > tbody > tr > td:first-child {
|
||||
padding-left: 16px;
|
||||
padding-right: 16px;
|
||||
}
|
||||
.forwards-container .badge-list-total {
|
||||
.badge-list-total {
|
||||
float: right;
|
||||
margin-right: 14px;
|
||||
position: relative;
|
||||
top: 3px;
|
||||
}
|
||||
|
||||
.new-list-btn {
|
||||
margin-bottom: 20px;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
.new-list {
|
||||
display: none;
|
||||
margin-bottom: 1rem;
|
||||
|
||||
&.visible {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
.new-list-name {
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
.btn-add-list {
|
||||
float: right;
|
||||
margin-top: 10px;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
/* Forward list */
|
||||
.panel-heading {
|
||||
@@ -97,24 +69,43 @@ $icon-font-path: "../fonts/";
|
||||
font-size: 16px;
|
||||
}
|
||||
.icon-faded {
|
||||
font-size: 14px;
|
||||
color: #ccc;
|
||||
position: relative;
|
||||
top: 1px;
|
||||
margin-right: 4px;
|
||||
top: 2px;
|
||||
color: #ccc;
|
||||
}
|
||||
.forwards-container table > tbody > tr.action-row > td:first-child,
|
||||
.table-condensed > tbody > tr.action-row > td {
|
||||
.table-condensed {
|
||||
margin-bottom: 0;
|
||||
|
||||
> tbody > tr > td {
|
||||
padding: 5px;
|
||||
|
||||
&:first-child {
|
||||
padding-left: 20px;
|
||||
padding-right: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
> tbody > tr.action-row > td {
|
||||
padding: 0;
|
||||
|
||||
&:first-child {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
.fwdlist tr:nth-child(even) > td {
|
||||
background-color: #f5f5f5;
|
||||
.custom-control-label:after, .custom-control-label:before {
|
||||
width: 1.3rem;
|
||||
height: 1.3rem;
|
||||
}
|
||||
.action-row {
|
||||
.link-add {
|
||||
display: block;
|
||||
}
|
||||
.link-del {
|
||||
white-space: nowrap;
|
||||
display: none;
|
||||
|
||||
&.visible {
|
||||
display: block;
|
||||
}
|
||||
@@ -153,13 +144,17 @@ $icon-font-path: "../fonts/";
|
||||
left: 20px;
|
||||
margin-top: 7px;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* Responsive fixes */
|
||||
@media(max-width: 500px){
|
||||
.panel-heading {
|
||||
@media(max-width: map-get($grid-breakpoints, "sm")){
|
||||
.card-header {
|
||||
font-size: 13px;
|
||||
font-weight: bold;
|
||||
}
|
||||
.panel-heading .icon-faded {
|
||||
.card-header .icon-faded {
|
||||
display: none;
|
||||
}
|
||||
td {
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
import gql from 'graphql-tag';
|
||||
|
||||
export const GET_ORG_UNITS = gql`
|
||||
query OrgUnits {
|
||||
orgUnits @rest(type: "OrgUnit", path: "orgunits/") {
|
||||
id
|
||||
name
|
||||
prefixes
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
// FIXME: only a single domain
|
||||
export const GET_DOMAINS = gql`
|
||||
query Domains {
|
||||
domains @rest(type: "Domain", path: "domains/") {
|
||||
id
|
||||
name
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const GET_ALIASES = gql`
|
||||
query OrgUnits {
|
||||
aliases @rest(type: "Alias", path: "aliases/") {
|
||||
id
|
||||
source
|
||||
destination
|
||||
}
|
||||
}
|
||||
`;
|
||||
@@ -1,5 +1,3 @@
|
||||
/* global _ */
|
||||
|
||||
import PNotify from 'pnotify/dist/es/PNotify';
|
||||
import * as queryString from 'query-string';
|
||||
|
||||
@@ -14,14 +12,15 @@ export function parseEmails(text) {
|
||||
const re = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
|
||||
|
||||
// For each of the words, add to the array of emails if the word matches the email regex.
|
||||
let emails = _.filter(words, (word) => {
|
||||
return word.match(re);
|
||||
});
|
||||
emails = _.map(emails, (el) => {
|
||||
return el.toLowerCase();
|
||||
});
|
||||
const emails = words
|
||||
.filter((word) => {
|
||||
return word.match(re);
|
||||
})
|
||||
.map((el) => {
|
||||
return el.toLowerCase();
|
||||
});
|
||||
|
||||
return _.unique(emails);
|
||||
return [...new Set(emails)];
|
||||
}
|
||||
|
||||
export function setQueryString(obj) {
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
from django.conf.urls import url
|
||||
from rest_framework.routers import DefaultRouter
|
||||
|
||||
from mailadmin.views import MyUserViewSet, MyOrgUnitViewSet, OrgUnitViewSet, AliasesView, get_domain, index, lists
|
||||
from mailadmin.views import MyUserViewSet, MyOrgUnitViewSet, OrgUnitViewSet, AliasesView, get_domains, index, lists
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^$', index, name='index'),
|
||||
@@ -17,5 +17,5 @@ urlpatterns += router.urls
|
||||
|
||||
urlpatterns += [
|
||||
url(r'^api/aliases/', AliasesView.as_view(), name='aliases'),
|
||||
url(r'^api/emaildomain/', get_domain, name='email-domain'),
|
||||
url(r'^api/domains/', get_domains, name='email-domains'),
|
||||
]
|
||||
+2
-2
@@ -137,8 +137,8 @@ class OrgUnitViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
|
||||
|
||||
@api_view(['GET'])
|
||||
def get_domain(request):
|
||||
def get_domains(request):
|
||||
api = DjangoPostfixDovecotAPI()
|
||||
domains = api.list_domains(name=settings.NEUF_EMAIL_DOMAIN_NAME)
|
||||
|
||||
return Response({'domain': domains[0] if len(domains) == 1 else domains})
|
||||
return Response(domains)
|
||||
@@ -86,11 +86,11 @@ USE_TZ = True
|
||||
STATIC_URL = '/static/'
|
||||
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
|
||||
STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.StaticFilesStorage'
|
||||
# TODO: add to local_settings.py
|
||||
|
||||
LOGIN_REDIRECT_URL = '/lists/'
|
||||
|
||||
DPD_API_URL = 'http://localhost'
|
||||
# Django Postfix Dovecot
|
||||
DPD_API_URL = 'http://localhost:8080/api'
|
||||
DPD_API_USERNAME = ""
|
||||
DPD_API_PASSWORD = ""
|
||||
|
||||
@@ -120,10 +120,6 @@ AUTH_LDAP_U_USER_FLAGS_BY_GROUP = {
|
||||
"is_staff": "cn=edb,ou=Groups,dc=neuf,dc=no",
|
||||
"is_superuser": "cn=edbadmin,ou=Groups,dc=neuf,dc=no"
|
||||
}
|
||||
# Group to profile flag mappings, not used.
|
||||
AUTH_LDAP_U_PROFILE_FLAGS_BY_GROUP = {
|
||||
#"is_edb": "cn=edb,ou=Groups,dc=neuf,dc=no"
|
||||
}
|
||||
# User attribute mappings
|
||||
AUTH_LDAP_U_USER_ATTR_MAP = {
|
||||
"first_name": "givenName",
|
||||
@@ -148,7 +144,6 @@ AUTH_LDAP_E_GROUP_SEARCH = AUTH_LDAP_U_GROUP_SEARCH
|
||||
AUTH_LDAP_E_GROUP_TYPE = AUTH_LDAP_U_GROUP_TYPE
|
||||
AUTH_LDAP_E_MIRROR_GROUPS = AUTH_LDAP_U_MIRROR_GROUPS
|
||||
AUTH_LDAP_E_USER_FLAGS_BY_GROUP = AUTH_LDAP_U_USER_FLAGS_BY_GROUP
|
||||
AUTH_LDAP_E_PROFILE_FLAGS_BY_GROUP = AUTH_LDAP_U_PROFILE_FLAGS_BY_GROUP
|
||||
AUTH_LDAP_E_USER_ATTR_MAP = AUTH_LDAP_U_USER_ATTR_MAP
|
||||
AUTH_LDAP_E_PROFILE_ATTR_MAP = AUTH_LDAP_U_PROFILE_ATTR_MAP
|
||||
AUTH_LDAP_E_ALWAYS_UPDATE_USER = AUTH_LDAP_U_ALWAYS_UPDATE_USER
|
||||
|
||||
Reference in new issue
Block a user