mirror of
https://github.com/BookStackApp/BookStack.git
synced 2026-02-16 19:06:45 +03:00
Compare commits
65 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
02dfe11ce6 | ||
|
|
83d06beb70 | ||
|
|
d2a9b312e9 | ||
|
|
a8cfc059c8 | ||
|
|
1614b2bab0 | ||
|
|
01260d95f3 | ||
|
|
d69ba6b47a | ||
|
|
098128aafb | ||
|
|
92c9837157 | ||
|
|
18e5f86ffa | ||
|
|
c860645a5a | ||
|
|
fcb93dc7c8 | ||
|
|
fcdb39e428 | ||
|
|
1b3e1863f4 | ||
|
|
fbc2175789 | ||
|
|
8099c431bb | ||
|
|
efbfe0f7af | ||
|
|
66402b474c | ||
|
|
f47f0e05d6 | ||
|
|
4bdec0d214 | ||
|
|
6a7d7e7c2b | ||
|
|
c83a51f7e2 | ||
|
|
b922c8029e | ||
|
|
653761e67d | ||
|
|
d59ff132ab | ||
|
|
e6e740b2a1 | ||
|
|
af6f4e6c8c | ||
|
|
69a0f8d502 | ||
|
|
6d35fb5237 | ||
|
|
79d0f707e6 | ||
|
|
369dc02e78 | ||
|
|
9d2e65b73d | ||
|
|
f421d83627 | ||
|
|
be2ca9d4bb | ||
|
|
17bca662a7 | ||
|
|
1776204870 | ||
|
|
985e214d94 | ||
|
|
2bcc159fd6 | ||
|
|
fb7c12438d | ||
|
|
b2cd363539 | ||
|
|
f668bee88b | ||
|
|
642f2760cc | ||
|
|
37aa8b05f8 | ||
|
|
d640cc1eee | ||
|
|
c2d6e98985 | ||
|
|
84b4fe6176 | ||
|
|
decdf5714b | ||
|
|
9da600caf9 | ||
|
|
45aee2a1c1 | ||
|
|
f5df5ac7d5 | ||
|
|
fb29f4119d | ||
|
|
93795b6eda | ||
|
|
f7b808a9e6 | ||
|
|
448068e318 | ||
|
|
7d81a95156 | ||
|
|
a9bf2ed398 | ||
|
|
771f781e7f | ||
|
|
78be8535f7 | ||
|
|
6c4c1ccb58 | ||
|
|
562225a77b | ||
|
|
b936e1f403 | ||
|
|
b3cc3130f0 | ||
|
|
0363fc4ea1 | ||
|
|
134a96fa32 | ||
|
|
56f444a8a7 |
2
.browserslistrc
Normal file
2
.browserslistrc
Normal file
@@ -0,0 +1,2 @@
|
||||
>0.25%
|
||||
not op_mini all
|
||||
@@ -56,6 +56,8 @@ TWITCH_APP_SECRET=false
|
||||
GITLAB_APP_ID=false
|
||||
GITLAB_APP_SECRET=false
|
||||
GITLAB_BASE_URI=false
|
||||
DISCORD_APP_ID=false
|
||||
DISCORD_APP_SECRET=false
|
||||
|
||||
# External services such as Gravatar and Draw.IO
|
||||
DISABLE_EXTERNAL_SERVICES=false
|
||||
@@ -67,6 +69,13 @@ LDAP_DN=false
|
||||
LDAP_PASS=false
|
||||
LDAP_USER_FILTER=false
|
||||
LDAP_VERSION=false
|
||||
# Do you want to sync LDAP groups to BookStack roles for a user
|
||||
LDAP_USER_TO_GROUPS=false
|
||||
# What is the LDAP attribute for group memberships
|
||||
LDAP_GROUP_ATTRIBUTE="memberOf"
|
||||
# Would you like to remove users from roles on BookStack if they do not match on LDAP
|
||||
# If false, the ldap groups-roles sync will only add users to roles
|
||||
LDAP_REMOVE_FROM_GROUPS=false
|
||||
|
||||
# Mail settings
|
||||
MAIL_DRIVER=smtp
|
||||
|
||||
21
.github/ISSUE_TEMPLATE.md
vendored
21
.github/ISSUE_TEMPLATE.md
vendored
@@ -1,21 +0,0 @@
|
||||
### For Feature Requests
|
||||
|
||||
Desired Feature:
|
||||
|
||||
### For Bug Reports
|
||||
|
||||
* BookStack Version *(Found in settings, Please don't put 'latest')*:
|
||||
* PHP Version:
|
||||
* MySQL Version:
|
||||
|
||||
##### Expected Behavior
|
||||
|
||||
|
||||
|
||||
##### Current Behavior
|
||||
|
||||
|
||||
|
||||
##### Steps to Reproduce
|
||||
|
||||
|
||||
29
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
29
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**Steps To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Your Configuration (please complete the following information):**
|
||||
- Exact BookStack Version (Found in settings):
|
||||
- PHP Version:
|
||||
- Hosting Method (Nginx/Apache/Docker):
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
14
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
14
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
|
||||
---
|
||||
|
||||
**Describe the feature you'd like**
|
||||
A clear description of the feature you'd like implemented in BookStack.
|
||||
|
||||
**Describe the benefits this feature would bring to BookStack users**
|
||||
Explain the measurable benefits this feature would achieve.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
@@ -5,6 +5,7 @@ namespace BookStack\Http\Controllers\Auth;
|
||||
use BookStack\Exceptions\AuthException;
|
||||
use BookStack\Http\Controllers\Controller;
|
||||
use BookStack\Repos\UserRepo;
|
||||
use BookStack\Services\LdapService;
|
||||
use BookStack\Services\SocialAuthService;
|
||||
use Illuminate\Contracts\Auth\Authenticatable;
|
||||
use Illuminate\Foundation\Auth\AuthenticatesUsers;
|
||||
@@ -36,18 +37,21 @@ class LoginController extends Controller
|
||||
protected $redirectAfterLogout = '/login';
|
||||
|
||||
protected $socialAuthService;
|
||||
protected $ldapService;
|
||||
protected $userRepo;
|
||||
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
* @param SocialAuthService $socialAuthService
|
||||
* @param LdapService $ldapService
|
||||
* @param UserRepo $userRepo
|
||||
*/
|
||||
public function __construct(SocialAuthService $socialAuthService, UserRepo $userRepo)
|
||||
public function __construct(SocialAuthService $socialAuthService, LdapService $ldapService, UserRepo $userRepo)
|
||||
{
|
||||
$this->middleware('guest', ['only' => ['getLogin', 'postLogin']]);
|
||||
$this->socialAuthService = $socialAuthService;
|
||||
$this->ldapService = $ldapService;
|
||||
$this->userRepo = $userRepo;
|
||||
$this->redirectPath = baseUrl('/');
|
||||
$this->redirectAfterLogout = baseUrl('/login');
|
||||
@@ -66,6 +70,7 @@ class LoginController extends Controller
|
||||
* @param Authenticatable $user
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
* @throws AuthException
|
||||
* @throws \BookStack\Exceptions\LdapException
|
||||
*/
|
||||
protected function authenticated(Request $request, Authenticatable $user)
|
||||
{
|
||||
@@ -96,6 +101,11 @@ class LoginController extends Controller
|
||||
auth()->login($user);
|
||||
}
|
||||
|
||||
// Sync LDAP groups if required
|
||||
if ($this->ldapService->shouldSyncGroups()) {
|
||||
$this->ldapService->syncGroups($user, $request->get($this->username()));
|
||||
}
|
||||
|
||||
$path = session()->pull('url.intended', '/');
|
||||
$path = baseUrl($path, true);
|
||||
return redirect($path);
|
||||
@@ -125,6 +135,7 @@ class LoginController extends Controller
|
||||
* Redirect to the relevant social site.
|
||||
* @param $socialDriver
|
||||
* @return \Symfony\Component\HttpFoundation\RedirectResponse
|
||||
* @throws \BookStack\Exceptions\SocialDriverNotConfigured
|
||||
*/
|
||||
public function getSocialLogin($socialDriver)
|
||||
{
|
||||
|
||||
@@ -5,7 +5,6 @@ use BookStack\Exceptions\NotFoundException;
|
||||
use BookStack\Repos\EntityRepo;
|
||||
use BookStack\Repos\UserRepo;
|
||||
use BookStack\Services\ExportService;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
use Views;
|
||||
@@ -38,11 +37,18 @@ class PageController extends Controller
|
||||
* @param string $chapterSlug
|
||||
* @return Response
|
||||
* @internal param bool $pageSlug
|
||||
* @throws NotFoundException
|
||||
*/
|
||||
public function create($bookSlug, $chapterSlug = null)
|
||||
{
|
||||
$book = $this->entityRepo->getBySlug('book', $bookSlug);
|
||||
$chapter = $chapterSlug ? $this->entityRepo->getBySlug('chapter', $chapterSlug, $bookSlug) : null;
|
||||
if ($chapterSlug !== null) {
|
||||
$chapter = $this->entityRepo->getBySlug('chapter', $chapterSlug, $bookSlug);
|
||||
$book = $chapter->book;
|
||||
} else {
|
||||
$chapter = null;
|
||||
$book = $this->entityRepo->getBySlug('book', $bookSlug);
|
||||
}
|
||||
|
||||
$parent = $chapter ? $chapter : $book;
|
||||
$this->checkOwnablePermission('page-create', $parent);
|
||||
|
||||
@@ -52,7 +58,7 @@ class PageController extends Controller
|
||||
return redirect($draft->getUrl());
|
||||
}
|
||||
|
||||
// Otherwise show edit view
|
||||
// Otherwise show the edit view if they're a guest
|
||||
$this->setPageTitle(trans('entities.pages_new'));
|
||||
return view('pages/guest-create', ['parent' => $parent]);
|
||||
}
|
||||
@@ -71,8 +77,14 @@ class PageController extends Controller
|
||||
'name' => 'required|string|max:255'
|
||||
]);
|
||||
|
||||
$book = $this->entityRepo->getBySlug('book', $bookSlug);
|
||||
$chapter = $chapterSlug ? $this->entityRepo->getBySlug('chapter', $chapterSlug, $bookSlug) : null;
|
||||
if ($chapterSlug !== null) {
|
||||
$chapter = $this->entityRepo->getBySlug('chapter', $chapterSlug, $bookSlug);
|
||||
$book = $chapter->book;
|
||||
} else {
|
||||
$chapter = null;
|
||||
$book = $this->entityRepo->getBySlug('book', $bookSlug);
|
||||
}
|
||||
|
||||
$parent = $chapter ? $chapter : $book;
|
||||
$this->checkOwnablePermission('page-create', $parent);
|
||||
|
||||
@@ -93,7 +105,7 @@ class PageController extends Controller
|
||||
public function editDraft($bookSlug, $pageId)
|
||||
{
|
||||
$draft = $this->entityRepo->getById('page', $pageId, true);
|
||||
$this->checkOwnablePermission('page-create', $draft->book);
|
||||
$this->checkOwnablePermission('page-create', $draft->parent);
|
||||
$this->setPageTitle(trans('entities.pages_edit_draft'));
|
||||
|
||||
$draftsEnabled = $this->signedIn;
|
||||
@@ -119,12 +131,10 @@ class PageController extends Controller
|
||||
]);
|
||||
|
||||
$input = $request->all();
|
||||
$book = $this->entityRepo->getBySlug('book', $bookSlug);
|
||||
|
||||
$draftPage = $this->entityRepo->getById('page', $pageId, true);
|
||||
$book = $draftPage->book;
|
||||
|
||||
$chapterId = intval($draftPage->chapter_id);
|
||||
$parent = $chapterId !== 0 ? $this->entityRepo->getById('chapter', $chapterId) : $book;
|
||||
$parent = $draftPage->parent;
|
||||
$this->checkOwnablePermission('page-create', $parent);
|
||||
|
||||
if ($parent->isA('chapter')) {
|
||||
|
||||
@@ -78,6 +78,7 @@ class PermissionController extends Controller
|
||||
* @param $id
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
|
||||
* @throws PermissionsException
|
||||
*/
|
||||
public function updateRole($id, Request $request)
|
||||
{
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class Localization
|
||||
{
|
||||
@@ -15,21 +16,33 @@ class Localization
|
||||
public function handle($request, Closure $next)
|
||||
{
|
||||
$defaultLang = config('app.locale');
|
||||
if (user()->isDefault()) {
|
||||
$locale = $defaultLang;
|
||||
$availableLocales = config('app.locales');
|
||||
foreach ($request->getLanguages() as $lang) {
|
||||
if (!in_array($lang, $availableLocales)) {
|
||||
continue;
|
||||
}
|
||||
$locale = $lang;
|
||||
break;
|
||||
}
|
||||
|
||||
if (user()->isDefault() && config('app.auto_detect_locale')) {
|
||||
$locale = $this->autoDetectLocale($request, $defaultLang);
|
||||
} else {
|
||||
$locale = setting()->getUser(user(), 'language', $defaultLang);
|
||||
}
|
||||
|
||||
app()->setLocale($locale);
|
||||
Carbon::setLocale($locale);
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Autodetect the visitors locale by matching locales in their headers
|
||||
* against the locales supported by BookStack.
|
||||
* @param Request $request
|
||||
* @param string $default
|
||||
* @return string
|
||||
*/
|
||||
protected function autoDetectLocale(Request $request, string $default)
|
||||
{
|
||||
$availableLocales = config('app.locales');
|
||||
foreach ($request->getLanguages() as $lang) {
|
||||
if (in_array($lang, $availableLocales)) {
|
||||
return $lang;
|
||||
}
|
||||
}
|
||||
return $default;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,15 @@ class Page extends Entity
|
||||
return $this->belongsTo(Book::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the parent item
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
*/
|
||||
public function parent()
|
||||
{
|
||||
return $this->chapter_id ? $this->chapter() : $this->book();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the chapter that this page is in, If applicable.
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
|
||||
@@ -20,6 +20,7 @@ class EventServiceProvider extends ServiceProvider
|
||||
'SocialiteProviders\Okta\OktaExtendSocialite@handle',
|
||||
'SocialiteProviders\GitLab\GitLabExtendSocialite@handle',
|
||||
'SocialiteProviders\Twitch\TwitchExtendSocialite@handle',
|
||||
'SocialiteProviders\Discord\DiscordExtendSocialite@handle',
|
||||
],
|
||||
];
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
class Role extends Model
|
||||
{
|
||||
|
||||
protected $fillable = ['display_name', 'description'];
|
||||
protected $fillable = ['display_name', 'description', 'external_auth_id'];
|
||||
|
||||
/**
|
||||
* The roles that belong to the role.
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
<?php namespace BookStack\Services;
|
||||
|
||||
use BookStack\Exceptions\LdapException;
|
||||
use BookStack\Repos\UserRepo;
|
||||
use BookStack\Role;
|
||||
use BookStack\User;
|
||||
use Illuminate\Contracts\Auth\Authenticatable;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
/**
|
||||
* Class LdapService
|
||||
@@ -14,15 +18,55 @@ class LdapService
|
||||
protected $ldap;
|
||||
protected $ldapConnection;
|
||||
protected $config;
|
||||
protected $userRepo;
|
||||
protected $enabled;
|
||||
|
||||
/**
|
||||
* LdapService constructor.
|
||||
* @param Ldap $ldap
|
||||
* @param UserRepo $userRepo
|
||||
*/
|
||||
public function __construct(Ldap $ldap)
|
||||
public function __construct(Ldap $ldap, UserRepo $userRepo)
|
||||
{
|
||||
$this->ldap = $ldap;
|
||||
$this->config = config('services.ldap');
|
||||
$this->userRepo = $userRepo;
|
||||
$this->enabled = config('auth.method') === 'ldap';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if groups should be synced.
|
||||
* @return bool
|
||||
*/
|
||||
public function shouldSyncGroups()
|
||||
{
|
||||
return $this->enabled && $this->config['user_to_groups'] !== false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for attributes for a specific user on the ldap
|
||||
* @param string $userName
|
||||
* @param array $attributes
|
||||
* @return null|array
|
||||
* @throws LdapException
|
||||
*/
|
||||
private function getUserWithAttributes($userName, $attributes)
|
||||
{
|
||||
$ldapConnection = $this->getConnection();
|
||||
$this->bindSystemUser($ldapConnection);
|
||||
|
||||
// Find user
|
||||
$userFilter = $this->buildFilter($this->config['user_filter'], ['user' => $userName]);
|
||||
$baseDn = $this->config['base_dn'];
|
||||
|
||||
$followReferrals = $this->config['follow_referrals'] ? 1 : 0;
|
||||
$this->ldap->setOption($ldapConnection, LDAP_OPT_REFERRALS, $followReferrals);
|
||||
$users = $this->ldap->searchAndGetEntries($ldapConnection, $baseDn, $userFilter, $attributes);
|
||||
if ($users['count'] === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $users[0];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -34,21 +78,13 @@ class LdapService
|
||||
*/
|
||||
public function getUserDetails($userName)
|
||||
{
|
||||
$ldapConnection = $this->getConnection();
|
||||
$this->bindSystemUser($ldapConnection);
|
||||
|
||||
// Find user
|
||||
$userFilter = $this->buildFilter($this->config['user_filter'], ['user' => $userName]);
|
||||
$baseDn = $this->config['base_dn'];
|
||||
$emailAttr = $this->config['email_attribute'];
|
||||
$followReferrals = $this->config['follow_referrals'] ? 1 : 0;
|
||||
$this->ldap->setOption($ldapConnection, LDAP_OPT_REFERRALS, $followReferrals);
|
||||
$users = $this->ldap->searchAndGetEntries($ldapConnection, $baseDn, $userFilter, ['cn', 'uid', 'dn', $emailAttr]);
|
||||
if ($users['count'] === 0) {
|
||||
$user = $this->getUserWithAttributes($userName, ['cn', 'uid', 'dn', $emailAttr]);
|
||||
|
||||
if ($user === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$user = $users[0];
|
||||
return [
|
||||
'uid' => (isset($user['uid'])) ? $user['uid'][0] : $user['dn'],
|
||||
'name' => $user['cn'][0],
|
||||
@@ -162,4 +198,173 @@ class LdapService
|
||||
}
|
||||
return strtr($filterString, $newAttrs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the groups a user is a part of on ldap
|
||||
* @param string $userName
|
||||
* @return array
|
||||
* @throws LdapException
|
||||
*/
|
||||
public function getUserGroups($userName)
|
||||
{
|
||||
$groupsAttr = $this->config['group_attribute'];
|
||||
$user = $this->getUserWithAttributes($userName, [$groupsAttr]);
|
||||
|
||||
if ($user === null) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$userGroups = $this->groupFilter($user);
|
||||
$userGroups = $this->getGroupsRecursive($userGroups, []);
|
||||
return $userGroups;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the parent groups of an array of groups
|
||||
* @param array $groupsArray
|
||||
* @param array $checked
|
||||
* @return array
|
||||
* @throws LdapException
|
||||
*/
|
||||
private function getGroupsRecursive($groupsArray, $checked)
|
||||
{
|
||||
$groups_to_add = [];
|
||||
foreach ($groupsArray as $groupName) {
|
||||
if (in_array($groupName, $checked)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$groupsToAdd = $this->getGroupGroups($groupName);
|
||||
$groups_to_add = array_merge($groups_to_add, $groupsToAdd);
|
||||
$checked[] = $groupName;
|
||||
}
|
||||
$groupsArray = array_unique(array_merge($groupsArray, $groups_to_add), SORT_REGULAR);
|
||||
|
||||
if (!empty($groups_to_add)) {
|
||||
return $this->getGroupsRecursive($groupsArray, $checked);
|
||||
} else {
|
||||
return $groupsArray;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the parent groups of a single group
|
||||
* @param string $groupName
|
||||
* @return array
|
||||
* @throws LdapException
|
||||
*/
|
||||
private function getGroupGroups($groupName)
|
||||
{
|
||||
$ldapConnection = $this->getConnection();
|
||||
$this->bindSystemUser($ldapConnection);
|
||||
|
||||
$followReferrals = $this->config['follow_referrals'] ? 1 : 0;
|
||||
$this->ldap->setOption($ldapConnection, LDAP_OPT_REFERRALS, $followReferrals);
|
||||
|
||||
$baseDn = $this->config['base_dn'];
|
||||
$groupsAttr = strtolower($this->config['group_attribute']);
|
||||
|
||||
$groups = $this->ldap->searchAndGetEntries($ldapConnection, $baseDn, 'CN='.$groupName, [$groupsAttr]);
|
||||
if ($groups['count'] === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$groupGroups = $this->groupFilter($groups[0]);
|
||||
return $groupGroups;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter out LDAP CN and DN language in a ldap search return
|
||||
* Gets the base CN (common name) of the string
|
||||
* @param string $ldapSearchReturn
|
||||
* @return array
|
||||
*/
|
||||
protected function groupFilter($ldapSearchReturn)
|
||||
{
|
||||
$groupsAttr = strtolower($this->config['group_attribute']);
|
||||
$ldapGroups = [];
|
||||
$count = 0;
|
||||
if (isset($ldapSearchReturn[$groupsAttr]['count'])) {
|
||||
$count = (int) $ldapSearchReturn[$groupsAttr]['count'];
|
||||
}
|
||||
for ($i=0; $i<$count; $i++) {
|
||||
$dnComponents = ldap_explode_dn($ldapSearchReturn[$groupsAttr][$i], 1);
|
||||
if (!in_array($dnComponents[0], $ldapGroups)) {
|
||||
$ldapGroups[] = $dnComponents[0];
|
||||
}
|
||||
}
|
||||
return $ldapGroups;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sync the LDAP groups to the user roles for the current user
|
||||
* @param \BookStack\User $user
|
||||
* @param string $username
|
||||
* @throws LdapException
|
||||
*/
|
||||
public function syncGroups(User $user, string $username)
|
||||
{
|
||||
$userLdapGroups = $this->getUserGroups($username);
|
||||
|
||||
// Get the ids for the roles from the names
|
||||
$ldapGroupsAsRoles = $this->matchLdapGroupsToSystemsRoles($userLdapGroups);
|
||||
|
||||
// Sync groups
|
||||
if ($this->config['remove_from_groups']) {
|
||||
$user->roles()->sync($ldapGroupsAsRoles);
|
||||
$this->userRepo->attachDefaultRole($user);
|
||||
} else {
|
||||
$user->roles()->syncWithoutDetaching($ldapGroupsAsRoles);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Match an array of group names from LDAP to BookStack system roles.
|
||||
* Formats LDAP group names to be lower-case and hyphenated.
|
||||
* @param array $groupNames
|
||||
* @return \Illuminate\Support\Collection
|
||||
*/
|
||||
protected function matchLdapGroupsToSystemsRoles(array $groupNames)
|
||||
{
|
||||
foreach ($groupNames as $i => $groupName) {
|
||||
$groupNames[$i] = str_replace(' ', '-', trim(strtolower($groupName)));
|
||||
}
|
||||
|
||||
$roles = Role::query()->where(function(Builder $query) use ($groupNames) {
|
||||
$query->whereIn('name', $groupNames);
|
||||
foreach ($groupNames as $groupName) {
|
||||
$query->orWhere('external_auth_id', 'LIKE', '%' . $groupName . '%');
|
||||
}
|
||||
})->get();
|
||||
|
||||
$matchedRoles = $roles->filter(function(Role $role) use ($groupNames) {
|
||||
return $this->roleMatchesGroupNames($role, $groupNames);
|
||||
});
|
||||
|
||||
return $matchedRoles->pluck('id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check a role against an array of group names to see if it matches.
|
||||
* Checked against role 'external_auth_id' if set otherwise the name of the role.
|
||||
* @param Role $role
|
||||
* @param array $groupNames
|
||||
* @return bool
|
||||
*/
|
||||
protected function roleMatchesGroupNames(Role $role, array $groupNames)
|
||||
{
|
||||
if ($role->external_auth_id) {
|
||||
$externalAuthIds = explode(',', strtolower($role->external_auth_id));
|
||||
foreach ($externalAuthIds as $externalAuthId) {
|
||||
if (in_array(trim($externalAuthId), $groupNames)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
$roleName = str_replace(' ', '-', trim(strtolower($role->display_name)));
|
||||
return in_array($roleName, $groupNames);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ class SocialAuthService
|
||||
protected $socialite;
|
||||
protected $socialAccount;
|
||||
|
||||
protected $validSocialDrivers = ['google', 'github', 'facebook', 'slack', 'twitter', 'azure', 'okta', 'gitlab', 'twitch'];
|
||||
protected $validSocialDrivers = ['google', 'github', 'facebook', 'slack', 'twitter', 'azure', 'okta', 'gitlab', 'twitch', 'discord'];
|
||||
|
||||
/**
|
||||
* SocialAuthService constructor.
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"type": "project",
|
||||
"require": {
|
||||
"php": ">=7.0.0",
|
||||
"laravel/framework": "~5.5.22",
|
||||
"laravel/framework": "~5.5.42",
|
||||
"fideloper/proxy": "~3.3",
|
||||
"ext-tidy": "*",
|
||||
"intervention/image": "^2.4",
|
||||
@@ -20,7 +20,8 @@
|
||||
"socialiteproviders/microsoft-azure": "^3.0",
|
||||
"socialiteproviders/okta": "^1.0",
|
||||
"socialiteproviders/gitlab": "^3.0",
|
||||
"socialiteproviders/twitch": "^3.0"
|
||||
"socialiteproviders/twitch": "^3.0",
|
||||
"socialiteproviders/discord": "^2.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"filp/whoops": "~2.0",
|
||||
|
||||
357
composer.lock
generated
357
composer.lock
generated
@@ -4,20 +4,20 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "3bf33ab103b15b06ca06c85fd8ae3b78",
|
||||
"content-hash": "b98be6702f1293174f785f99895e798b",
|
||||
"packages": [
|
||||
{
|
||||
"name": "aws/aws-sdk-php",
|
||||
"version": "3.56.4",
|
||||
"version": "3.64.10",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/aws/aws-sdk-php.git",
|
||||
"reference": "03273bb5c1d8098ff6c23b3fa9ee444c4cc1dcee"
|
||||
"reference": "4aa66872c4428d0db08c861a34559b0923eaae23"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/03273bb5c1d8098ff6c23b3fa9ee444c4cc1dcee",
|
||||
"reference": "03273bb5c1d8098ff6c23b3fa9ee444c4cc1dcee",
|
||||
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/4aa66872c4428d0db08c861a34559b0923eaae23",
|
||||
"reference": "4aa66872c4428d0db08c861a34559b0923eaae23",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -84,7 +84,7 @@
|
||||
"s3",
|
||||
"sdk"
|
||||
],
|
||||
"time": "2018-05-18T19:53:15+00:00"
|
||||
"time": "2018-08-10T21:49:00+00:00"
|
||||
},
|
||||
{
|
||||
"name": "barryvdh/laravel-dompdf",
|
||||
@@ -829,16 +829,16 @@
|
||||
},
|
||||
{
|
||||
"name": "intervention/image",
|
||||
"version": "2.4.1",
|
||||
"version": "2.4.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Intervention/image.git",
|
||||
"reference": "3603dbcc9a17d307533473246a6c58c31cf17919"
|
||||
"reference": "e82d274f786e3d4b866a59b173f42e716f0783eb"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Intervention/image/zipball/3603dbcc9a17d307533473246a6c58c31cf17919",
|
||||
"reference": "3603dbcc9a17d307533473246a6c58c31cf17919",
|
||||
"url": "https://api.github.com/repos/Intervention/image/zipball/e82d274f786e3d4b866a59b173f42e716f0783eb",
|
||||
"reference": "e82d274f786e3d4b866a59b173f42e716f0783eb",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -858,7 +858,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.3-dev"
|
||||
"dev-master": "2.4-dev"
|
||||
},
|
||||
"laravel": {
|
||||
"providers": [
|
||||
@@ -895,7 +895,7 @@
|
||||
"thumbnail",
|
||||
"watermark"
|
||||
],
|
||||
"time": "2017-09-21T16:29:17+00:00"
|
||||
"time": "2018-05-29T14:19:03+00:00"
|
||||
},
|
||||
{
|
||||
"name": "knplabs/knp-snappy",
|
||||
@@ -965,16 +965,16 @@
|
||||
},
|
||||
{
|
||||
"name": "laravel/framework",
|
||||
"version": "v5.5.40",
|
||||
"version": "v5.5.42",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/laravel/framework.git",
|
||||
"reference": "d724ce0aa61bbd9adf658215eec484f5dd6711d6"
|
||||
"reference": "6550ae917b0c49a5915a52cd7c7eafd16fc0b538"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/laravel/framework/zipball/d724ce0aa61bbd9adf658215eec484f5dd6711d6",
|
||||
"reference": "d724ce0aa61bbd9adf658215eec484f5dd6711d6",
|
||||
"url": "https://api.github.com/repos/laravel/framework/zipball/6550ae917b0c49a5915a52cd7c7eafd16fc0b538",
|
||||
"reference": "6550ae917b0c49a5915a52cd7c7eafd16fc0b538",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1095,20 +1095,20 @@
|
||||
"framework",
|
||||
"laravel"
|
||||
],
|
||||
"time": "2018-03-30T13:29:30+00:00"
|
||||
"time": "2018-08-08T18:22:44+00:00"
|
||||
},
|
||||
{
|
||||
"name": "laravel/socialite",
|
||||
"version": "v3.0.11",
|
||||
"version": "v3.0.12",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/laravel/socialite.git",
|
||||
"reference": "4d29ba66fdb38ec994b778e5e51657555cc10511"
|
||||
"reference": "b5f465847b1d637efa86bbfe2fc1c9d2bd12f60f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/laravel/socialite/zipball/4d29ba66fdb38ec994b778e5e51657555cc10511",
|
||||
"reference": "4d29ba66fdb38ec994b778e5e51657555cc10511",
|
||||
"url": "https://api.github.com/repos/laravel/socialite/zipball/b5f465847b1d637efa86bbfe2fc1c9d2bd12f60f",
|
||||
"reference": "b5f465847b1d637efa86bbfe2fc1c9d2bd12f60f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1157,7 +1157,7 @@
|
||||
"laravel",
|
||||
"oauth"
|
||||
],
|
||||
"time": "2018-05-12T17:44:53+00:00"
|
||||
"time": "2018-06-01T15:06:47+00:00"
|
||||
},
|
||||
{
|
||||
"name": "league/flysystem",
|
||||
@@ -1532,16 +1532,16 @@
|
||||
},
|
||||
{
|
||||
"name": "nesbot/carbon",
|
||||
"version": "1.27.0",
|
||||
"version": "1.33.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/briannesbitt/Carbon.git",
|
||||
"reference": "ef81c39b67200dcd7401c24363dcac05ac3a4fe9"
|
||||
"reference": "55667c1007a99e82030874b1bb14d24d07108413"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/ef81c39b67200dcd7401c24363dcac05ac3a4fe9",
|
||||
"reference": "ef81c39b67200dcd7401c24363dcac05ac3a4fe9",
|
||||
"url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/55667c1007a99e82030874b1bb14d24d07108413",
|
||||
"reference": "55667c1007a99e82030874b1bb14d24d07108413",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1553,6 +1553,13 @@
|
||||
"phpunit/phpunit": "^4.8.35 || ^5.7"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"providers": [
|
||||
"Carbon\\Laravel\\ServiceProvider"
|
||||
]
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"": "src/"
|
||||
@@ -1576,37 +1583,33 @@
|
||||
"datetime",
|
||||
"time"
|
||||
],
|
||||
"time": "2018-04-23T09:02:57+00:00"
|
||||
"time": "2018-08-07T08:39:47+00:00"
|
||||
},
|
||||
{
|
||||
"name": "paragonie/random_compat",
|
||||
"version": "v2.0.12",
|
||||
"version": "v9.99.99",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/paragonie/random_compat.git",
|
||||
"reference": "258c89a6b97de7dfaf5b8c7607d0478e236b04fb"
|
||||
"reference": "84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/paragonie/random_compat/zipball/258c89a6b97de7dfaf5b8c7607d0478e236b04fb",
|
||||
"reference": "258c89a6b97de7dfaf5b8c7607d0478e236b04fb",
|
||||
"url": "https://api.github.com/repos/paragonie/random_compat/zipball/84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95",
|
||||
"reference": "84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.2.0"
|
||||
"php": "^7"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "4.*|5.*"
|
||||
"phpunit/phpunit": "4.*|5.*",
|
||||
"vimeo/psalm": "^1"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes."
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"files": [
|
||||
"lib/random.php"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
@@ -1621,10 +1624,11 @@
|
||||
"description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7",
|
||||
"keywords": [
|
||||
"csprng",
|
||||
"polyfill",
|
||||
"pseudorandom",
|
||||
"random"
|
||||
],
|
||||
"time": "2018-04-04T21:24:14+00:00"
|
||||
"time": "2018-07-02T15:55:56+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phenx/php-font-lib",
|
||||
@@ -1665,16 +1669,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phenx/php-svg-lib",
|
||||
"version": "v0.3",
|
||||
"version": "v0.3.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/PhenX/php-svg-lib.git",
|
||||
"reference": "a85f7fe9fe08d093a4a8583cdd306b553ff918aa"
|
||||
"reference": "ccc46ef6340d4b8a4a68047e68d8501ea961442c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/PhenX/php-svg-lib/zipball/a85f7fe9fe08d093a4a8583cdd306b553ff918aa",
|
||||
"reference": "a85f7fe9fe08d093a4a8583cdd306b553ff918aa",
|
||||
"url": "https://api.github.com/repos/PhenX/php-svg-lib/zipball/ccc46ef6340d4b8a4a68047e68d8501ea961442c",
|
||||
"reference": "ccc46ef6340d4b8a4a68047e68d8501ea961442c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1701,7 +1705,7 @@
|
||||
],
|
||||
"description": "A library to read, parse and export to PDF SVG files.",
|
||||
"homepage": "https://github.com/PhenX/php-svg-lib",
|
||||
"time": "2017-05-24T10:07:27+00:00"
|
||||
"time": "2018-06-03T10:10:03+00:00"
|
||||
},
|
||||
{
|
||||
"name": "predis/predis",
|
||||
@@ -1949,21 +1953,22 @@
|
||||
},
|
||||
{
|
||||
"name": "ramsey/uuid",
|
||||
"version": "3.7.3",
|
||||
"version": "3.8.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/ramsey/uuid.git",
|
||||
"reference": "44abcdad877d9a46685a3a4d221e3b2c4b87cb76"
|
||||
"reference": "d09ea80159c1929d75b3f9c60504d613aeb4a1e3"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/ramsey/uuid/zipball/44abcdad877d9a46685a3a4d221e3b2c4b87cb76",
|
||||
"reference": "44abcdad877d9a46685a3a4d221e3b2c4b87cb76",
|
||||
"url": "https://api.github.com/repos/ramsey/uuid/zipball/d09ea80159c1929d75b3f9c60504d613aeb4a1e3",
|
||||
"reference": "d09ea80159c1929d75b3f9c60504d613aeb4a1e3",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"paragonie/random_compat": "^1.0|^2.0",
|
||||
"php": "^5.4 || ^7.0"
|
||||
"paragonie/random_compat": "^1.0|^2.0|9.99.99",
|
||||
"php": "^5.4 || ^7.0",
|
||||
"symfony/polyfill-ctype": "^1.8"
|
||||
},
|
||||
"replace": {
|
||||
"rhumsaa/uuid": "self.version"
|
||||
@@ -1971,16 +1976,17 @@
|
||||
"require-dev": {
|
||||
"codeception/aspect-mock": "^1.0 | ~2.0.0",
|
||||
"doctrine/annotations": "~1.2.0",
|
||||
"goaop/framework": "1.0.0-alpha.2 | ^1.0 | ^2.1",
|
||||
"goaop/framework": "1.0.0-alpha.2 | ^1.0 | ~2.1.0",
|
||||
"ircmaxell/random-lib": "^1.1",
|
||||
"jakub-onderka/php-parallel-lint": "^0.9.0",
|
||||
"mockery/mockery": "^0.9.9",
|
||||
"moontoast/math": "^1.1",
|
||||
"php-mock/php-mock-phpunit": "^0.3|^1.1",
|
||||
"phpunit/phpunit": "^4.7|^5.0",
|
||||
"phpunit/phpunit": "^4.7|^5.0|^6.5",
|
||||
"squizlabs/php_codesniffer": "^2.3"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-ctype": "Provides support for PHP Ctype functions",
|
||||
"ext-libsodium": "Provides the PECL libsodium extension for use with the SodiumRandomGenerator",
|
||||
"ext-uuid": "Provides the PECL UUID extension for use with the PeclUuidTimeGenerator and PeclUuidRandomGenerator",
|
||||
"ircmaxell/random-lib": "Provides RandomLib for use with the RandomLibAdapter",
|
||||
@@ -2025,7 +2031,7 @@
|
||||
"identifier",
|
||||
"uuid"
|
||||
],
|
||||
"time": "2018-01-20T00:28:24+00:00"
|
||||
"time": "2018-07-19T23:38:55+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sabberworm/php-css-parser",
|
||||
@@ -2072,17 +2078,54 @@
|
||||
"time": "2016-07-19T19:14:21+00:00"
|
||||
},
|
||||
{
|
||||
"name": "socialiteproviders/gitlab",
|
||||
"version": "v3.0.2",
|
||||
"name": "socialiteproviders/discord",
|
||||
"version": "v2.0.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/SocialiteProviders/GitLab.git",
|
||||
"reference": "bab80e8e16853e062c58013b1c1f474bd5a5c49a"
|
||||
"url": "https://github.com/SocialiteProviders/Discord.git",
|
||||
"reference": "e0cd8895f321943b36f533e7bf21ad29bcdece9a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/SocialiteProviders/GitLab/zipball/bab80e8e16853e062c58013b1c1f474bd5a5c49a",
|
||||
"reference": "bab80e8e16853e062c58013b1c1f474bd5a5c49a",
|
||||
"url": "https://api.github.com/repos/SocialiteProviders/Discord/zipball/e0cd8895f321943b36f533e7bf21ad29bcdece9a",
|
||||
"reference": "e0cd8895f321943b36f533e7bf21ad29bcdece9a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^5.6 || ^7.0",
|
||||
"socialiteproviders/manager": "~2.0 || ~3.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"SocialiteProviders\\Discord\\": ""
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Christopher Eklund",
|
||||
"email": "eklundchristopher@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "Discord OAuth2 Provider for Laravel Socialite",
|
||||
"time": "2018-05-26T03:40:07+00:00"
|
||||
},
|
||||
{
|
||||
"name": "socialiteproviders/gitlab",
|
||||
"version": "v3.0.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/SocialiteProviders/GitLab.git",
|
||||
"reference": "7839d22fad3179cd77f1b35af62f81d15d78e93b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/SocialiteProviders/GitLab/zipball/7839d22fad3179cd77f1b35af62f81d15d78e93b",
|
||||
"reference": "7839d22fad3179cd77f1b35af62f81d15d78e93b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -2106,7 +2149,7 @@
|
||||
}
|
||||
],
|
||||
"description": "GitLab OAuth2 Provider for Laravel Socialite",
|
||||
"time": "2018-05-11T03:10:27+00:00"
|
||||
"time": "2018-06-20T11:00:01+00:00"
|
||||
},
|
||||
{
|
||||
"name": "socialiteproviders/manager",
|
||||
@@ -2307,16 +2350,16 @@
|
||||
},
|
||||
{
|
||||
"name": "swiftmailer/swiftmailer",
|
||||
"version": "v6.0.2",
|
||||
"version": "v6.1.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/swiftmailer/swiftmailer.git",
|
||||
"reference": "412333372fb6c8ffb65496a2bbd7321af75733fc"
|
||||
"reference": "7d760881d266d63c5e7a1155cbcf2ac656a31ca8"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/412333372fb6c8ffb65496a2bbd7321af75733fc",
|
||||
"reference": "412333372fb6c8ffb65496a2bbd7321af75733fc",
|
||||
"url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/7d760881d266d63c5e7a1155cbcf2ac656a31ca8",
|
||||
"reference": "7d760881d266d63c5e7a1155cbcf2ac656a31ca8",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -2327,10 +2370,14 @@
|
||||
"mockery/mockery": "~0.9.1",
|
||||
"symfony/phpunit-bridge": "~3.3@dev"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-intl": "Needed to support internationalized email addresses",
|
||||
"true/punycode": "Needed to support internationalized email addresses, if ext-intl is not installed"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "6.0-dev"
|
||||
"dev-master": "6.1-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@@ -2352,13 +2399,13 @@
|
||||
}
|
||||
],
|
||||
"description": "Swiftmailer, free feature-rich PHP mailer",
|
||||
"homepage": "http://swiftmailer.symfony.com",
|
||||
"homepage": "https://swiftmailer.symfony.com",
|
||||
"keywords": [
|
||||
"email",
|
||||
"mail",
|
||||
"mailer"
|
||||
],
|
||||
"time": "2017-09-30T22:39:41+00:00"
|
||||
"time": "2018-07-13T07:04:35+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
@@ -2790,17 +2837,75 @@
|
||||
"time": "2017-08-01T10:25:59+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-mbstring",
|
||||
"version": "v1.8.0",
|
||||
"name": "symfony/polyfill-ctype",
|
||||
"version": "v1.9.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-mbstring.git",
|
||||
"reference": "3296adf6a6454a050679cde90f95350ad604b171"
|
||||
"url": "https://github.com/symfony/polyfill-ctype.git",
|
||||
"reference": "e3d826245268269cd66f8326bd8bc066687b4a19"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/3296adf6a6454a050679cde90f95350ad604b171",
|
||||
"reference": "3296adf6a6454a050679cde90f95350ad604b171",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/e3d826245268269cd66f8326bd8bc066687b4a19",
|
||||
"reference": "e3d826245268269cd66f8326bd8bc066687b4a19",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-ctype": "For best performance"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.9-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Polyfill\\Ctype\\": ""
|
||||
},
|
||||
"files": [
|
||||
"bootstrap.php"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
},
|
||||
{
|
||||
"name": "Gert de Pagter",
|
||||
"email": "BackEndTea@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "Symfony polyfill for ctype functions",
|
||||
"homepage": "https://symfony.com",
|
||||
"keywords": [
|
||||
"compatibility",
|
||||
"ctype",
|
||||
"polyfill",
|
||||
"portable"
|
||||
],
|
||||
"time": "2018-08-06T14:22:27+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-mbstring",
|
||||
"version": "v1.9.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-mbstring.git",
|
||||
"reference": "d0cd638f4634c16d8df4508e847f14e9e43168b8"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/d0cd638f4634c16d8df4508e847f14e9e43168b8",
|
||||
"reference": "d0cd638f4634c16d8df4508e847f14e9e43168b8",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -2812,7 +2917,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.8-dev"
|
||||
"dev-master": "1.9-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@@ -2846,7 +2951,7 @@
|
||||
"portable",
|
||||
"shim"
|
||||
],
|
||||
"time": "2018-04-26T10:06:28+00:00"
|
||||
"time": "2018-08-06T14:22:27+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/process",
|
||||
@@ -3157,28 +3262,28 @@
|
||||
},
|
||||
{
|
||||
"name": "vlucas/phpdotenv",
|
||||
"version": "v2.4.0",
|
||||
"version": "v2.5.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/vlucas/phpdotenv.git",
|
||||
"reference": "3cc116adbe4b11be5ec557bf1d24dc5e3a21d18c"
|
||||
"reference": "8abb4f9aa89ddea9d52112c65bbe8d0125e2fa8e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/3cc116adbe4b11be5ec557bf1d24dc5e3a21d18c",
|
||||
"reference": "3cc116adbe4b11be5ec557bf1d24dc5e3a21d18c",
|
||||
"url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/8abb4f9aa89ddea9d52112c65bbe8d0125e2fa8e",
|
||||
"reference": "8abb4f9aa89ddea9d52112c65bbe8d0125e2fa8e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.9"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^4.8 || ^5.0"
|
||||
"phpunit/phpunit": "^4.8.35 || ^5.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.4-dev"
|
||||
"dev-master": "2.5-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@@ -3188,7 +3293,7 @@
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause-Attribution"
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
@@ -3203,22 +3308,22 @@
|
||||
"env",
|
||||
"environment"
|
||||
],
|
||||
"time": "2016-09-01T10:05:43+00:00"
|
||||
"time": "2018-07-29T20:33:41+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [
|
||||
{
|
||||
"name": "barryvdh/laravel-debugbar",
|
||||
"version": "v3.1.4",
|
||||
"version": "v3.1.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/barryvdh/laravel-debugbar.git",
|
||||
"reference": "7a91480cc6e597caed5117a3c5d685f06d35c5a1"
|
||||
"reference": "d3cdca2ad6cc6e67735b4a63e7551c690a497f5f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/barryvdh/laravel-debugbar/zipball/7a91480cc6e597caed5117a3c5d685f06d35c5a1",
|
||||
"reference": "7a91480cc6e597caed5117a3c5d685f06d35c5a1",
|
||||
"url": "https://api.github.com/repos/barryvdh/laravel-debugbar/zipball/d3cdca2ad6cc6e67735b4a63e7551c690a497f5f",
|
||||
"reference": "d3cdca2ad6cc6e67735b4a63e7551c690a497f5f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -3273,7 +3378,7 @@
|
||||
"profiler",
|
||||
"webprofiler"
|
||||
],
|
||||
"time": "2018-03-06T08:35:31+00:00"
|
||||
"time": "2018-05-03T18:27:04+00:00"
|
||||
},
|
||||
{
|
||||
"name": "barryvdh/laravel-ide-helper",
|
||||
@@ -3453,16 +3558,16 @@
|
||||
},
|
||||
{
|
||||
"name": "filp/whoops",
|
||||
"version": "2.1.14",
|
||||
"version": "2.2.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/filp/whoops.git",
|
||||
"reference": "c6081b8838686aa04f1e83ba7e91f78b7b2a23e6"
|
||||
"reference": "181c4502d8f34db7aed7bfe88d4f87875b8e947a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/filp/whoops/zipball/c6081b8838686aa04f1e83ba7e91f78b7b2a23e6",
|
||||
"reference": "c6081b8838686aa04f1e83ba7e91f78b7b2a23e6",
|
||||
"url": "https://api.github.com/repos/filp/whoops/zipball/181c4502d8f34db7aed7bfe88d4f87875b8e947a",
|
||||
"reference": "181c4502d8f34db7aed7bfe88d4f87875b8e947a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -3470,9 +3575,9 @@
|
||||
"psr/log": "^1.0.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"mockery/mockery": "0.9.*",
|
||||
"mockery/mockery": "^0.9 || ^1.0",
|
||||
"phpunit/phpunit": "^4.8.35 || ^5.7",
|
||||
"symfony/var-dumper": "^2.6 || ^3.0"
|
||||
"symfony/var-dumper": "^2.6 || ^3.0 || ^4.0"
|
||||
},
|
||||
"suggest": {
|
||||
"symfony/var-dumper": "Pretty print complex values better with var-dumper available",
|
||||
@@ -3481,7 +3586,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.0-dev"
|
||||
"dev-master": "2.1-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@@ -3510,20 +3615,20 @@
|
||||
"throwable",
|
||||
"whoops"
|
||||
],
|
||||
"time": "2017-11-23T18:22:44+00:00"
|
||||
"time": "2018-03-03T17:56:25+00:00"
|
||||
},
|
||||
{
|
||||
"name": "fzaninotto/faker",
|
||||
"version": "v1.7.1",
|
||||
"version": "v1.8.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/fzaninotto/Faker.git",
|
||||
"reference": "d3ed4cc37051c1ca52d22d76b437d14809fc7e0d"
|
||||
"reference": "f72816b43e74063c8b10357394b6bba8cb1c10de"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/fzaninotto/Faker/zipball/d3ed4cc37051c1ca52d22d76b437d14809fc7e0d",
|
||||
"reference": "d3ed4cc37051c1ca52d22d76b437d14809fc7e0d",
|
||||
"url": "https://api.github.com/repos/fzaninotto/Faker/zipball/f72816b43e74063c8b10357394b6bba8cb1c10de",
|
||||
"reference": "f72816b43e74063c8b10357394b6bba8cb1c10de",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -3531,7 +3636,7 @@
|
||||
},
|
||||
"require-dev": {
|
||||
"ext-intl": "*",
|
||||
"phpunit/phpunit": "^4.0 || ^5.0",
|
||||
"phpunit/phpunit": "^4.8.35 || ^5.7",
|
||||
"squizlabs/php_codesniffer": "^1.5"
|
||||
},
|
||||
"type": "library",
|
||||
@@ -3560,7 +3665,7 @@
|
||||
"faker",
|
||||
"fixtures"
|
||||
],
|
||||
"time": "2017-08-15T16:48:10+00:00"
|
||||
"time": "2018-07-12T10:23:15+00:00"
|
||||
},
|
||||
{
|
||||
"name": "hamcrest/hamcrest-php",
|
||||
@@ -4086,16 +4191,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpspec/prophecy",
|
||||
"version": "1.7.6",
|
||||
"version": "1.8.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpspec/prophecy.git",
|
||||
"reference": "33a7e3c4fda54e912ff6338c48823bd5c0f0b712"
|
||||
"reference": "4ba436b55987b4bf311cb7c6ba82aa528aac0a06"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpspec/prophecy/zipball/33a7e3c4fda54e912ff6338c48823bd5c0f0b712",
|
||||
"reference": "33a7e3c4fda54e912ff6338c48823bd5c0f0b712",
|
||||
"url": "https://api.github.com/repos/phpspec/prophecy/zipball/4ba436b55987b4bf311cb7c6ba82aa528aac0a06",
|
||||
"reference": "4ba436b55987b4bf311cb7c6ba82aa528aac0a06",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -4107,12 +4212,12 @@
|
||||
},
|
||||
"require-dev": {
|
||||
"phpspec/phpspec": "^2.5|^3.2",
|
||||
"phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5"
|
||||
"phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5 || ^7.1"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.7.x-dev"
|
||||
"dev-master": "1.8.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@@ -4145,7 +4250,7 @@
|
||||
"spy",
|
||||
"stub"
|
||||
],
|
||||
"time": "2018-04-18T13:57:24+00:00"
|
||||
"time": "2018-08-05T17:53:17+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-code-coverage",
|
||||
@@ -4398,16 +4503,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpunit/phpunit",
|
||||
"version": "6.5.8",
|
||||
"version": "6.5.11",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
||||
"reference": "4f21a3c6b97c42952fd5c2837bb354ec0199b97b"
|
||||
"reference": "7bab54cb366076023bbf457a2a0d513332cd40f2"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/4f21a3c6b97c42952fd5c2837bb354ec0199b97b",
|
||||
"reference": "4f21a3c6b97c42952fd5c2837bb354ec0199b97b",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/7bab54cb366076023bbf457a2a0d513332cd40f2",
|
||||
"reference": "7bab54cb366076023bbf457a2a0d513332cd40f2",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -4425,7 +4530,7 @@
|
||||
"phpunit/php-file-iterator": "^1.4.3",
|
||||
"phpunit/php-text-template": "^1.2.1",
|
||||
"phpunit/php-timer": "^1.0.9",
|
||||
"phpunit/phpunit-mock-objects": "^5.0.5",
|
||||
"phpunit/phpunit-mock-objects": "^5.0.9",
|
||||
"sebastian/comparator": "^2.1",
|
||||
"sebastian/diff": "^2.0",
|
||||
"sebastian/environment": "^3.1",
|
||||
@@ -4478,20 +4583,20 @@
|
||||
"testing",
|
||||
"xunit"
|
||||
],
|
||||
"time": "2018-04-10T11:38:34+00:00"
|
||||
"time": "2018-08-07T07:05:35+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/phpunit-mock-objects",
|
||||
"version": "5.0.6",
|
||||
"version": "5.0.10",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git",
|
||||
"reference": "33fd41a76e746b8fa96d00b49a23dadfa8334cdf"
|
||||
"reference": "cd1cf05c553ecfec36b170070573e540b67d3f1f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/33fd41a76e746b8fa96d00b49a23dadfa8334cdf",
|
||||
"reference": "33fd41a76e746b8fa96d00b49a23dadfa8334cdf",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/cd1cf05c553ecfec36b170070573e540b67d3f1f",
|
||||
"reference": "cd1cf05c553ecfec36b170070573e540b67d3f1f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -4504,7 +4609,7 @@
|
||||
"phpunit/phpunit": "<6.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^6.5"
|
||||
"phpunit/phpunit": "^6.5.11"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-soap": "*"
|
||||
@@ -4537,7 +4642,7 @@
|
||||
"mock",
|
||||
"xunit"
|
||||
],
|
||||
"time": "2018-01-06T05:45:45+00:00"
|
||||
"time": "2018-08-09T05:50:03+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/code-unit-reverse-lookup",
|
||||
@@ -5100,16 +5205,16 @@
|
||||
},
|
||||
{
|
||||
"name": "squizlabs/php_codesniffer",
|
||||
"version": "3.2.3",
|
||||
"version": "3.3.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/squizlabs/PHP_CodeSniffer.git",
|
||||
"reference": "4842476c434e375f9d3182ff7b89059583aa8b27"
|
||||
"reference": "628a481780561150481a9ec74709092b9759b3ec"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/4842476c434e375f9d3182ff7b89059583aa8b27",
|
||||
"reference": "4842476c434e375f9d3182ff7b89059583aa8b27",
|
||||
"url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/628a481780561150481a9ec74709092b9759b3ec",
|
||||
"reference": "628a481780561150481a9ec74709092b9759b3ec",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -5147,7 +5252,7 @@
|
||||
"phpcs",
|
||||
"standards"
|
||||
],
|
||||
"time": "2018-02-20T21:35:23+00:00"
|
||||
"time": "2018-07-26T23:47:18+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/class-loader",
|
||||
|
||||
@@ -77,8 +77,21 @@ return [
|
||||
*/
|
||||
|
||||
'locale' => env('APP_LANG', 'en'),
|
||||
|
||||
'locales' => ['en', 'de', 'es', 'es_AR', 'fr', 'nl', 'pt_BR', 'sk', 'sv', 'ja', 'pl', 'it', 'ru', 'zh_CN', 'zh_TW'],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Auto-detect the locale for public users
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| For public users their locale can be guessed by headers sent by their
|
||||
| browser. This is usually set by users in their browser settings.
|
||||
| If not found the default app locale will be used.
|
||||
|
|
||||
*/
|
||||
'auto_detect_locale' => env('APP_AUTO_LANG_PUBLIC', true),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Application Fallback Locale
|
||||
@@ -245,7 +258,7 @@ return [
|
||||
'Activity' => BookStack\Services\Facades\Activity::class,
|
||||
'Setting' => BookStack\Services\Facades\Setting::class,
|
||||
'Views' => BookStack\Services\Facades\Views::class,
|
||||
'Images' => \BookStack\Services\Facades\Images::class,
|
||||
'Images' => BookStack\Services\Facades\Images::class,
|
||||
|
||||
],
|
||||
|
||||
|
||||
@@ -108,6 +108,12 @@ return [
|
||||
'redirect' => env('APP_URL') . '/login/service/twitch/callback',
|
||||
'name' => 'Twitch',
|
||||
],
|
||||
'discord' => [
|
||||
'client_id' => env('DISCORD_APP_ID'),
|
||||
'client_secret' => env('DISCORD_APP_SECRET'),
|
||||
'redirect' => env('APP_URL') . '/login/service/discord/callback',
|
||||
'name' => 'Discord',
|
||||
],
|
||||
|
||||
'ldap' => [
|
||||
'server' => env('LDAP_SERVER', false),
|
||||
@@ -118,6 +124,9 @@ return [
|
||||
'version' => env('LDAP_VERSION', false),
|
||||
'email_attribute' => env('LDAP_EMAIL_ATTRIBUTE', 'mail'),
|
||||
'follow_referrals' => env('LDAP_FOLLOW_REFERRALS', false),
|
||||
]
|
||||
'user_to_groups' => env('LDAP_USER_TO_GROUPS',false),
|
||||
'group_attribute' => env('LDAP_GROUP_ATTRIBUTE', 'memberOf'),
|
||||
'remove_from_groups' => env('LDAP_REMOVE_FROM_GROUPS',false),
|
||||
]
|
||||
|
||||
];
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class AddRoleExternalAuthId extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('roles', function (Blueprint $table) {
|
||||
$table->string('external_auth_id', 200)->default('');
|
||||
$table->index('external_auth_id');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('roles', function (Blueprint $table) {
|
||||
$table->dropColumn('external_auth_id');
|
||||
});
|
||||
}
|
||||
}
|
||||
6312
package-lock.json
generated
6312
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -11,20 +11,20 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.0.0-beta.40",
|
||||
"@babel/polyfill": "^7.0.0-beta.40",
|
||||
"@babel/preset-env": "^7.0.0-beta.40",
|
||||
"autoprefixer": "^8.1.0",
|
||||
"babel-loader": "^8.0.0-beta.0",
|
||||
"@babel/polyfill": "^7.0.0-beta.40",
|
||||
"css-loader": "^0.28.10",
|
||||
"extract-text-webpack-plugin": "^4.0.0-beta.0",
|
||||
"livereload": "^0.7.0",
|
||||
"node-sass": "^4.7.2",
|
||||
"node-sass": "^4.9.2",
|
||||
"npm-run-all": "^4.1.2",
|
||||
"postcss-loader": "^2.1.1",
|
||||
"sass-loader": "^7.0.1",
|
||||
"style-loader": "^0.21.0",
|
||||
"uglifyjs-webpack-plugin": "^1.2.3",
|
||||
"webpack": "^4.1.1",
|
||||
"webpack": "^4.16.3",
|
||||
"webpack-cli": "^2.0.11"
|
||||
},
|
||||
"dependencies": {
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
<env name="APP_ENV" value="testing"/>
|
||||
<env name="APP_DEBUG" value="false"/>
|
||||
<env name="APP_LANG" value="en"/>
|
||||
<env name="APP_AUTO_LANG_PUBLIC" value="true"/>
|
||||
<env name="CACHE_DRIVER" value="array"/>
|
||||
<env name="SESSION_DRIVER" value="array"/>
|
||||
<env name="QUEUE_DRIVER" value="sync"/>
|
||||
|
||||
2
public/dist/app.js
vendored
2
public/dist/app.js
vendored
File diff suppressed because one or more lines are too long
34
public/dist/export-styles.css
vendored
34
public/dist/export-styles.css
vendored
@@ -1326,9 +1326,9 @@ div[class^="col-"] img {
|
||||
border: 1px solid #E84F4F; }
|
||||
.input-base.pos, .pos.fake-input, input.pos[type="text"], input.pos[type="number"], input.pos[type="email"], input.pos[type="date"], input.pos[type="search"], input.pos[type="url"], input.pos[type="password"], select.pos, textarea.pos, .input-base.valid, .valid.fake-input, input.valid[type="text"], input.valid[type="number"], input.valid[type="email"], input.valid[type="date"], input.valid[type="search"], input.valid[type="url"], input.valid[type="password"], select.valid, textarea.valid {
|
||||
border: 1px solid #52A256; }
|
||||
.input-base.disabled, .disabled.fake-input, input.disabled[type="text"], input.disabled[type="number"], input.disabled[type="email"], input.disabled[type="date"], input.disabled[type="search"], input.disabled[type="url"], input.disabled[type="password"], select.disabled, textarea.disabled, .input-base[disabled], [disabled].fake-input, input[disabled][type="text"], input[disabled][type="number"], input[disabled][type="email"], input[disabled][type="date"], input[disabled][type="search"], input[disabled][type="url"], input[disabled][type="password"], select[disabled], textarea[disabled] {
|
||||
.input-base.disabled, .disabled.fake-input, input.disabled[type="text"], input.disabled[type="number"], input.disabled[type="email"], input.disabled[type="date"], input.disabled[type="search"], input.disabled[type="url"], input.disabled[type="password"], select.disabled, textarea.disabled, .input-base[disabled], .fake-input[disabled], input[disabled][type="text"], input[disabled][type="number"], input[disabled][type="email"], input[disabled][type="date"], input[disabled][type="search"], input[disabled][type="url"], input[disabled][type="password"], select[disabled], textarea[disabled] {
|
||||
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAHCAYAAADEUlfTAAAAMUlEQVQIW2NkwAGuXbv2nxGbHEhCS0uLEUMSJgHShCKJLIEiiS4Bl8QmAZbEJQGSBAC62BuJ+tt7zgAAAABJRU5ErkJggg==); }
|
||||
.input-base:focus, .fake-input:focus, input[type="text"]:focus, input[type="number"]:focus, input[type="email"]:focus, input[type="date"]:focus, input[type="search"]:focus, input[type="url"]:focus, input[type="password"]:focus, select:focus, textarea:focus {
|
||||
.input-base:focus, .fake-input:focus, input:focus[type="text"], input:focus[type="number"], input:focus[type="email"], input:focus[type="date"], input:focus[type="search"], input:focus[type="url"], input:focus[type="password"], select:focus, textarea:focus {
|
||||
outline: 0; }
|
||||
|
||||
.fake-input {
|
||||
@@ -2042,8 +2042,6 @@ ul.pagination {
|
||||
padding: 3px 12px;
|
||||
border: 1px solid #CCC;
|
||||
margin-left: -1px;
|
||||
color: #888;
|
||||
fill: #888;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
@@ -2051,13 +2049,7 @@ ul.pagination {
|
||||
ul.pagination a.disabled, ul.pagination span.disabled {
|
||||
cursor: not-allowed; }
|
||||
ul.pagination li.active span {
|
||||
background-color: rgba(2, 136, 209, 0.8);
|
||||
color: #EEE;
|
||||
fill: #EEE;
|
||||
border-color: rgba(2, 136, 209, 0.8); }
|
||||
ul.pagination a {
|
||||
color: #0288D1;
|
||||
fill: #0288D1; }
|
||||
color: #FFF; }
|
||||
|
||||
.compact ul.pagination {
|
||||
margin: 0; }
|
||||
@@ -2262,6 +2254,8 @@ ul.pagination {
|
||||
background: #dbffdb; }
|
||||
.page-content del {
|
||||
background: #FFECEC; }
|
||||
.page-content.page-revision pre code {
|
||||
white-space: pre-wrap; }
|
||||
|
||||
.pointer-container {
|
||||
position: relative;
|
||||
@@ -2278,8 +2272,10 @@ ul.pagination {
|
||||
position: absolute;
|
||||
top: -60px;
|
||||
background-color: #FFF;
|
||||
width: 272px;
|
||||
width: 275px;
|
||||
z-index: 55; }
|
||||
.pointer.is-page-editable {
|
||||
width: 328px; }
|
||||
.pointer:before {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
@@ -2303,12 +2299,13 @@ ul.pagination {
|
||||
color: #666;
|
||||
width: 172px;
|
||||
z-index: 40; }
|
||||
.pointer input, .pointer button {
|
||||
.pointer input, .pointer button, .pointer a {
|
||||
position: relative;
|
||||
border-radius: 0;
|
||||
height: 28px;
|
||||
font-size: 12px;
|
||||
vertical-align: top; }
|
||||
vertical-align: top;
|
||||
padding: 5px 16px; }
|
||||
.pointer > i {
|
||||
color: #888;
|
||||
font-size: 18px;
|
||||
@@ -2319,10 +2316,17 @@ ul.pagination {
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none; }
|
||||
.pointer .button {
|
||||
.pointer .input-group .button {
|
||||
line-height: 1;
|
||||
margin: 0 0 0 -4px;
|
||||
box-shadow: none; }
|
||||
.pointer a.button {
|
||||
margin: 0 0 0 0; }
|
||||
.pointer a.button:hover {
|
||||
fill: #fff; }
|
||||
.pointer .svg-icon {
|
||||
width: 1.2em;
|
||||
height: 1.2em; }
|
||||
|
||||
.floating-toolbox {
|
||||
background-color: #FFF;
|
||||
|
||||
112
public/dist/styles.css
vendored
112
public/dist/styles.css
vendored
@@ -1369,13 +1369,13 @@ div[class^="col-"] img {
|
||||
text-transform: uppercase;
|
||||
border: 1px solid #0288D1;
|
||||
vertical-align: top; }
|
||||
.button-base:hover, .button:hover, input[type="button"]:hover, input[type="submit"]:hover {
|
||||
.button-base:hover, .button:hover, input:hover[type="button"], input:hover[type="submit"] {
|
||||
background-color: #02a2f9;
|
||||
text-decoration: none;
|
||||
color: #EEE; }
|
||||
.button-base:active, .button:active, input[type="button"]:active, input[type="submit"]:active {
|
||||
.button-base:active, .button:active, input:active[type="button"], input:active[type="submit"] {
|
||||
background-color: #026ea9; }
|
||||
.button-base:focus, .button:focus, input[type="button"]:focus, input[type="submit"]:focus {
|
||||
.button-base:focus, .button:focus, input:focus[type="button"], input:focus[type="submit"] {
|
||||
background-color: #0295e5;
|
||||
box-shadow: 0 0 4px 1px #CCC;
|
||||
text-decoration: none;
|
||||
@@ -1630,9 +1630,9 @@ table.list-table {
|
||||
border: 1px solid #E84F4F; }
|
||||
.input-base.pos, .pos.fake-input, input.pos[type="text"], input.pos[type="number"], input.pos[type="email"], input.pos[type="date"], input.pos[type="search"], input.pos[type="url"], input.pos[type="password"], select.pos, textarea.pos, .input-base.valid, .valid.fake-input, input.valid[type="text"], input.valid[type="number"], input.valid[type="email"], input.valid[type="date"], input.valid[type="search"], input.valid[type="url"], input.valid[type="password"], select.valid, textarea.valid {
|
||||
border: 1px solid #52A256; }
|
||||
.input-base.disabled, .disabled.fake-input, input.disabled[type="text"], input.disabled[type="number"], input.disabled[type="email"], input.disabled[type="date"], input.disabled[type="search"], input.disabled[type="url"], input.disabled[type="password"], select.disabled, textarea.disabled, .input-base[disabled], [disabled].fake-input, input[disabled][type="text"], input[disabled][type="number"], input[disabled][type="email"], input[disabled][type="date"], input[disabled][type="search"], input[disabled][type="url"], input[disabled][type="password"], select[disabled], textarea[disabled] {
|
||||
.input-base.disabled, .disabled.fake-input, input.disabled[type="text"], input.disabled[type="number"], input.disabled[type="email"], input.disabled[type="date"], input.disabled[type="search"], input.disabled[type="url"], input.disabled[type="password"], select.disabled, textarea.disabled, .input-base[disabled], .fake-input[disabled], input[disabled][type="text"], input[disabled][type="number"], input[disabled][type="email"], input[disabled][type="date"], input[disabled][type="search"], input[disabled][type="url"], input[disabled][type="password"], select[disabled], textarea[disabled] {
|
||||
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAHCAYAAADEUlfTAAAAMUlEQVQIW2NkwAGuXbv2nxGbHEhCS0uLEUMSJgHShCKJLIEiiS4Bl8QmAZbEJQGSBAC62BuJ+tt7zgAAAABJRU5ErkJggg==); }
|
||||
.input-base:focus, .fake-input:focus, input[type="text"]:focus, input[type="number"]:focus, input[type="email"]:focus, input[type="date"]:focus, input[type="search"]:focus, input[type="url"]:focus, input[type="password"]:focus, select:focus, textarea:focus {
|
||||
.input-base:focus, .fake-input:focus, input:focus[type="text"], input:focus[type="number"], input:focus[type="email"], input:focus[type="date"], input:focus[type="search"], input:focus[type="url"], input:focus[type="password"], select:focus, textarea:focus {
|
||||
outline: 0; }
|
||||
|
||||
.fake-input {
|
||||
@@ -2600,49 +2600,87 @@ span.CodeMirror-selectedtext {
|
||||
width: 100%;
|
||||
height: 100%; }
|
||||
|
||||
/**
|
||||
* Custom Copy Button
|
||||
*/
|
||||
.CodeMirror-copy {
|
||||
position: absolute;
|
||||
top: -1px;
|
||||
right: -1px;
|
||||
background-color: #EEE;
|
||||
padding: 6px;
|
||||
line-height: 0;
|
||||
border: 1px solid #DDD;
|
||||
cursor: pointer;
|
||||
fill: #444;
|
||||
z-index: 5;
|
||||
transition: all ease-in 180ms;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
opacity: 0.7; }
|
||||
.CodeMirror-copy svg {
|
||||
transition: -webkit-transform ease-in 180ms;
|
||||
transition: transform ease-in 180ms;
|
||||
transition: transform ease-in 180ms, -webkit-transform ease-in 180ms;
|
||||
-webkit-transform: translateY(0);
|
||||
transform: translateY(0); }
|
||||
.CodeMirror-copy.success {
|
||||
background-color: #70b774;
|
||||
fill: #FFF; }
|
||||
.CodeMirror-copy.success svg {
|
||||
-webkit-transform: translateY(-3px);
|
||||
transform: translateY(-3px); }
|
||||
|
||||
.CodeMirror:hover .CodeMirror-copy {
|
||||
-webkit-user-select: all;
|
||||
-moz-user-select: all;
|
||||
-ms-user-select: all;
|
||||
user-select: all;
|
||||
opacity: 1; }
|
||||
|
||||
[notification] {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
margin: 64px 32px;
|
||||
padding: 24px 32px;
|
||||
padding: 16px 24px;
|
||||
background-color: #EEE;
|
||||
border-radius: 3px;
|
||||
box-shadow: 0 1px 3px 1px rgba(76, 76, 76, 0.26);
|
||||
box-shadow: 0 1px 3px 1px rgba(76, 76, 76, 0.26), 0 1px 12px 0px rgba(76, 76, 76, 0.2);
|
||||
z-index: 999999;
|
||||
cursor: pointer;
|
||||
max-width: 360px;
|
||||
transition: -webkit-transform ease-in-out 280ms;
|
||||
transition: transform ease-in-out 280ms;
|
||||
transition: transform ease-in-out 280ms, -webkit-transform ease-in-out 280ms;
|
||||
-webkit-transform: translate3d(580px, 0, 0);
|
||||
transform: translate3d(580px, 0, 0);
|
||||
-webkit-transform: translateX(580px);
|
||||
transform: translateX(580px);
|
||||
display: grid;
|
||||
grid-template-columns: 64px 1fr; }
|
||||
grid-template-columns: 42px 1fr;
|
||||
color: #FFF; }
|
||||
[notification] span, [notification] svg {
|
||||
vertical-align: middle;
|
||||
justify-self: center;
|
||||
align-self: center; }
|
||||
[notification] svg {
|
||||
fill: #EEEEEE;
|
||||
width: 4em;
|
||||
height: 4em;
|
||||
padding-right: 16px; }
|
||||
width: 2.8rem;
|
||||
height: 2.8rem;
|
||||
padding-right: 12px; }
|
||||
[notification] span {
|
||||
vertical-align: middle;
|
||||
line-height: 1.3; }
|
||||
[notification].pos {
|
||||
background-color: #52A256;
|
||||
color: #EEE; }
|
||||
background-color: #52A256; }
|
||||
[notification].neg {
|
||||
background-color: #E84F4F;
|
||||
color: #EEE; }
|
||||
background-color: #E84F4F; }
|
||||
[notification].warning {
|
||||
background-color: #e27b41;
|
||||
color: #EEE; }
|
||||
background-color: #e27b41; }
|
||||
[notification].showing {
|
||||
-webkit-transform: translate3d(0, 0, 0);
|
||||
transform: translate3d(0, 0, 0); }
|
||||
-webkit-transform: translateX(0);
|
||||
transform: translateX(0); }
|
||||
[notification].showing:hover {
|
||||
-webkit-transform: translate3d(0, -2px, 0);
|
||||
transform: translate3d(0, -2px, 0); }
|
||||
@@ -2749,7 +2787,7 @@ body.flexbox-support #entity-selector-wrap .popup-body .form-group {
|
||||
width: 16.66667%;
|
||||
height: auto;
|
||||
border: 1px solid #DDD;
|
||||
box-shadow: 0 0 0 0 transparent;
|
||||
box-shadow: 0 0 0 0 rgba(0, 0, 0, 0);
|
||||
transition: all cubic-bezier(0.4, 0, 1, 1) 160ms;
|
||||
overflow: hidden; }
|
||||
.image-manager-list .image.selected {
|
||||
@@ -3592,8 +3630,6 @@ ul.pagination {
|
||||
padding: 3px 12px;
|
||||
border: 1px solid #CCC;
|
||||
margin-left: -1px;
|
||||
color: #888;
|
||||
fill: #888;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
@@ -3601,13 +3637,7 @@ ul.pagination {
|
||||
ul.pagination a.disabled, ul.pagination span.disabled {
|
||||
cursor: not-allowed; }
|
||||
ul.pagination li.active span {
|
||||
background-color: rgba(2, 136, 209, 0.8);
|
||||
color: #EEE;
|
||||
fill: #EEE;
|
||||
border-color: rgba(2, 136, 209, 0.8); }
|
||||
ul.pagination a {
|
||||
color: #0288D1;
|
||||
fill: #0288D1; }
|
||||
color: #FFF; }
|
||||
|
||||
.compact ul.pagination {
|
||||
margin: 0; }
|
||||
@@ -3812,6 +3842,8 @@ ul.pagination {
|
||||
background: #dbffdb; }
|
||||
.page-content del {
|
||||
background: #FFECEC; }
|
||||
.page-content.page-revision pre code {
|
||||
white-space: pre-wrap; }
|
||||
|
||||
.pointer-container {
|
||||
position: relative;
|
||||
@@ -3828,8 +3860,10 @@ ul.pagination {
|
||||
position: absolute;
|
||||
top: -60px;
|
||||
background-color: #FFF;
|
||||
width: 272px;
|
||||
width: 275px;
|
||||
z-index: 55; }
|
||||
.pointer.is-page-editable {
|
||||
width: 328px; }
|
||||
.pointer:before {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
@@ -3853,12 +3887,13 @@ ul.pagination {
|
||||
color: #666;
|
||||
width: 172px;
|
||||
z-index: 40; }
|
||||
.pointer input, .pointer button {
|
||||
.pointer input, .pointer button, .pointer a {
|
||||
position: relative;
|
||||
border-radius: 0;
|
||||
height: 28px;
|
||||
font-size: 12px;
|
||||
vertical-align: top; }
|
||||
vertical-align: top;
|
||||
padding: 5px 16px; }
|
||||
.pointer > i {
|
||||
color: #888;
|
||||
font-size: 18px;
|
||||
@@ -3869,10 +3904,17 @@ ul.pagination {
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none; }
|
||||
.pointer .button {
|
||||
.pointer .input-group .button {
|
||||
line-height: 1;
|
||||
margin: 0 0 0 -4px;
|
||||
box-shadow: none; }
|
||||
.pointer a.button {
|
||||
margin: 0 0 0 0; }
|
||||
.pointer a.button:hover {
|
||||
fill: #fff; }
|
||||
.pointer .svg-icon {
|
||||
width: 1.2em;
|
||||
height: 1.2em; }
|
||||
|
||||
.floating-toolbox {
|
||||
background-color: #FFF;
|
||||
|
||||
1
resources/assets/icons/auth/discord.svg
Normal file
1
resources/assets/icons/auth/discord.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 245 240"><style>.st0{fill:#7289DA;}</style><path class="st0" d="M104.4 103.9c-5.7 0-10.2 5-10.2 11.1s4.6 11.1 10.2 11.1c5.7 0 10.2-5 10.2-11.1.1-6.1-4.5-11.1-10.2-11.1zM140.9 103.9c-5.7 0-10.2 5-10.2 11.1s4.6 11.1 10.2 11.1c5.7 0 10.2-5 10.2-11.1s-4.5-11.1-10.2-11.1z"/><path class="st0" d="M189.5 20h-134C44.2 20 35 29.2 35 40.6v135.2c0 11.4 9.2 20.6 20.5 20.6h113.4l-5.3-18.5 12.8 11.9 12.1 11.2 21.5 19V40.6c0-11.4-9.2-20.6-20.5-20.6zm-38.6 130.6s-3.6-4.3-6.6-8.1c13.1-3.7 18.1-11.9 18.1-11.9-4.1 2.7-8 4.6-11.5 5.9-5 2.1-9.8 3.5-14.5 4.3-9.6 1.8-18.4 1.3-25.9-.1-5.7-1.1-10.6-2.7-14.7-4.3-2.3-.9-4.8-2-7.3-3.4-.3-.2-.6-.3-.9-.5-.2-.1-.3-.2-.4-.3-1.8-1-2.8-1.7-2.8-1.7s4.8 8 17.5 11.8c-3 3.8-6.7 8.3-6.7 8.3-22.1-.7-30.5-15.2-30.5-15.2 0-32.2 14.4-58.3 14.4-58.3 14.4-10.8 28.1-10.5 28.1-10.5l1 1.2c-18 5.2-26.3 13.1-26.3 13.1s2.2-1.2 5.9-2.9c10.7-4.7 19.2-6 22.7-6.3.6-.1 1.1-.2 1.7-.2 6.1-.8 13-1 20.2-.2 9.5 1.1 19.7 3.9 30.1 9.6 0 0-7.9-7.5-24.9-12.7l1.4-1.6s13.7-.3 28.1 10.5c0 0 14.4 26.1 14.4 58.3 0 0-8.5 14.5-30.6 15.2z"/></svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
@@ -18,6 +18,13 @@ class MarkdownEditor {
|
||||
|
||||
this.onMarkdownScroll = this.onMarkdownScroll.bind(this);
|
||||
this.init();
|
||||
|
||||
// Scroll to text if needed.
|
||||
const queryParams = (new URL(window.location)).searchParams;
|
||||
const scrollText = queryParams.get('content-text');
|
||||
if (scrollText) {
|
||||
this.scrollToText(scrollText);
|
||||
}
|
||||
}
|
||||
|
||||
init() {
|
||||
@@ -387,6 +394,33 @@ class MarkdownEditor {
|
||||
});
|
||||
}
|
||||
|
||||
// Scroll to a specified text
|
||||
scrollToText(searchText) {
|
||||
if (!searchText) {
|
||||
return;
|
||||
}
|
||||
|
||||
const content = this.cm.getValue();
|
||||
const lines = content.split(/\r?\n/);
|
||||
let lineNumber = lines.findIndex(line => {
|
||||
return line && line.indexOf(searchText) !== -1;
|
||||
});
|
||||
|
||||
if (lineNumber === -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.cm.scrollIntoView({
|
||||
line: lineNumber,
|
||||
}, 200);
|
||||
this.cm.focus();
|
||||
// set the cursor location.
|
||||
this.cm.setCursor({
|
||||
line: lineNumber,
|
||||
char: lines[lineNumber].length
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = MarkdownEditor ;
|
||||
@@ -6,11 +6,16 @@ class Notification {
|
||||
this.type = elem.getAttribute('notification');
|
||||
this.textElem = elem.querySelector('span');
|
||||
this.autohide = this.elem.hasAttribute('data-autohide');
|
||||
this.elem.style.display = 'grid';
|
||||
|
||||
window.$events.listen(this.type, text => {
|
||||
this.show(text);
|
||||
});
|
||||
elem.addEventListener('click', this.hide.bind(this));
|
||||
if (elem.hasAttribute('data-show')) this.show(this.textElem.textContent);
|
||||
|
||||
if (elem.hasAttribute('data-show')) {
|
||||
setTimeout(() => this.show(this.textElem.textContent), 100);
|
||||
}
|
||||
|
||||
this.hideCleanup = this.hideCleanup.bind(this);
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ class PageDisplay {
|
||||
|
||||
// Sidebar page nav click event
|
||||
$('.sidebar-page-nav').on('click', 'a', event => {
|
||||
goToText(event.target.getAttribute('href').substr(1));
|
||||
this.goToText(event.target.getAttribute('href').substr(1));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -74,11 +74,23 @@ class PageDisplay {
|
||||
pointerShowing = false;
|
||||
});
|
||||
|
||||
let updatePointerContent = () => {
|
||||
let updatePointerContent = ($elem) => {
|
||||
let inputText = pointerModeLink ? window.baseUrl(`/link/${this.pageId}#${pointerSectionId}`) : `{{@${this.pageId}#${pointerSectionId}}}`;
|
||||
if (pointerModeLink && inputText.indexOf('http') !== 0) inputText = window.location.protocol + "//" + window.location.host + inputText;
|
||||
|
||||
$pointer.find('input').val(inputText);
|
||||
|
||||
// update anchor if present
|
||||
const $editAnchor = $pointer.find('#pointer-edit');
|
||||
if ($editAnchor.length !== 0 && $elem) {
|
||||
const editHref = $editAnchor.data('editHref');
|
||||
const element = $elem[0];
|
||||
const elementId = element.id;
|
||||
|
||||
// get the first 50 characters.
|
||||
let queryContent = element.textContent && element.textContent.substring(0, 50);
|
||||
$editAnchor[0].href = `${editHref}?content-id=${elementId}&content-text=${encodeURIComponent(queryContent)}`;
|
||||
}
|
||||
};
|
||||
|
||||
// Show pointer when selecting a single block of tagged content
|
||||
@@ -90,7 +102,7 @@ class PageDisplay {
|
||||
// Show pointer and set link
|
||||
let $elem = $(this);
|
||||
pointerSectionId = $elem.attr('id');
|
||||
updatePointerContent();
|
||||
updatePointerContent($elem);
|
||||
|
||||
$elem.before($pointer);
|
||||
$pointer.show();
|
||||
@@ -219,7 +231,6 @@ class PageDisplay {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = PageDisplay;
|
||||
module.exports = PageDisplay;
|
||||
|
||||
@@ -483,13 +483,36 @@ class WysiwygEditor {
|
||||
},
|
||||
setup: function (editor) {
|
||||
|
||||
editor.on('init ExecCommand change input NodeChange ObjectResized', editorChange);
|
||||
editor.on('ExecCommand change input NodeChange ObjectResized', editorChange);
|
||||
|
||||
editor.on('init', () => {
|
||||
editorChange();
|
||||
// Scroll to the content if needed.
|
||||
const queryParams = (new URL(window.location)).searchParams;
|
||||
const scrollId = queryParams.get('content-id');
|
||||
if (scrollId) {
|
||||
scrollToText(scrollId);
|
||||
}
|
||||
});
|
||||
|
||||
function editorChange() {
|
||||
let content = editor.getContent();
|
||||
window.$events.emit('editor-html-change', content);
|
||||
}
|
||||
|
||||
function scrollToText(scrollId) {
|
||||
const element = editor.dom.get(encodeURIComponent(scrollId).replace(/!/g, '%21'));
|
||||
if (!element) {
|
||||
return;
|
||||
}
|
||||
|
||||
// scroll the element into the view and put the cursor at the end.
|
||||
element.scrollIntoView();
|
||||
editor.selection.select(element, true);
|
||||
editor.selection.collapse(false);
|
||||
editor.focus();
|
||||
}
|
||||
|
||||
window.$events.listen('editor-html-update', html => {
|
||||
editor.setContent(html);
|
||||
editor.selection.select(editor.getBody(), true);
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
// Global Polyfills
|
||||
import "@babel/polyfill"
|
||||
import "./services/dom-polyfills"
|
||||
|
||||
// Url retrieval function
|
||||
|
||||
@@ -16,6 +16,8 @@ require('codemirror/mode/toml/toml');
|
||||
require('codemirror/mode/xml/xml');
|
||||
require('codemirror/mode/yaml/yaml');
|
||||
|
||||
const Clipboard = require("clipboard");
|
||||
|
||||
const CodeMirror = require('codemirror');
|
||||
|
||||
const modeMap = {
|
||||
@@ -77,7 +79,7 @@ function highlightElem(elem) {
|
||||
elem.innerHTML = elem.innerHTML.replace(/<br\s*[\/]?>/gi ,'\n');
|
||||
let content = elem.textContent.trim();
|
||||
|
||||
CodeMirror(function(elt) {
|
||||
let cm = CodeMirror(function(elt) {
|
||||
elem.parentNode.replaceChild(elt, elem);
|
||||
}, {
|
||||
value: content,
|
||||
@@ -86,6 +88,33 @@ function highlightElem(elem) {
|
||||
theme: getTheme(),
|
||||
readOnly: true
|
||||
});
|
||||
|
||||
addCopyIcon(cm);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a button to a CodeMirror instance which copies the contents to the clipboard upon click.
|
||||
* @param cmInstance
|
||||
*/
|
||||
function addCopyIcon(cmInstance) {
|
||||
const copyIcon = `<svg viewBox="0 0 24 24" width="16" height="16" xmlns="http://www.w3.org/2000/svg"><path d="M0 0h24v24H0z" fill="none"/><path d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z"/></svg>`;
|
||||
const copyButton = document.createElement('div');
|
||||
copyButton.classList.add('CodeMirror-copy');
|
||||
copyButton.innerHTML = copyIcon;
|
||||
cmInstance.display.wrapper.appendChild(copyButton);
|
||||
|
||||
const clipboard = new Clipboard(copyButton, {
|
||||
text: function(trigger) {
|
||||
return cmInstance.getValue()
|
||||
}
|
||||
});
|
||||
|
||||
clipboard.on('success', event => {
|
||||
copyButton.classList.add('success');
|
||||
setTimeout(() => {
|
||||
copyButton.classList.remove('success');
|
||||
}, 360);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -12,4 +12,13 @@ export function utcTimeStampToLocalTime(timestamp) {
|
||||
let hours = date.getHours();
|
||||
let mins = date.getMinutes();
|
||||
return `${(hours>9?'':'0') + hours}:${(mins>9?'':'0') + mins}`;
|
||||
}
|
||||
|
||||
export function formatDateTime(date) {
|
||||
let month = date.getMonth() + 1;
|
||||
let day = date.getDate();
|
||||
let hours = date.getHours();
|
||||
let mins = date.getMinutes();
|
||||
|
||||
return `${date.getFullYear()}-${(month>9?'':'0') + month}-${(day>9?'':'0') + day} ${(hours>9?'':'0') + hours}:${(mins>9?'':'0') + mins}`;
|
||||
}
|
||||
@@ -52,7 +52,9 @@ let methods = {
|
||||
},
|
||||
|
||||
deleteFile(file) {
|
||||
if (!file.deleting) return file.deleting = true;
|
||||
if (!file.deleting) {
|
||||
return this.$set(file, 'deleting', true);
|
||||
}
|
||||
|
||||
this.$http.delete(window.baseUrl(`/attachments/${file.id}`)).then(resp => {
|
||||
this.$events.emit('success', resp.data.message);
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
|
||||
import * as Dates from "../services/dates";
|
||||
|
||||
const dropzone = require('./components/dropzone');
|
||||
|
||||
let page = 0;
|
||||
@@ -168,7 +171,7 @@ const methods = {
|
||||
},
|
||||
|
||||
getDate(stringDate) {
|
||||
return new Date(stringDate);
|
||||
return Dates.formatDateTime(new Date(stringDate));
|
||||
},
|
||||
|
||||
uploadSuccess(event) {
|
||||
|
||||
@@ -403,4 +403,38 @@ span.CodeMirror-selectedtext { background: none; }
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom Copy Button
|
||||
*/
|
||||
.CodeMirror-copy {
|
||||
position: absolute;
|
||||
top: -1px;
|
||||
right: -1px;
|
||||
background-color: #EEE;
|
||||
padding: $-xs;
|
||||
line-height: 0;
|
||||
border: 1px solid #DDD;
|
||||
cursor: pointer;
|
||||
fill: #444;
|
||||
z-index: 5;
|
||||
transition: all ease-in 180ms;
|
||||
user-select: none;
|
||||
opacity: 0.7;
|
||||
svg {
|
||||
transition: transform ease-in 180ms;
|
||||
transform: translateY(0);
|
||||
}
|
||||
&.success {
|
||||
background-color: lighten($positive, 10%);
|
||||
fill: #FFF;
|
||||
svg {
|
||||
transform: translateY(-3px);
|
||||
}
|
||||
}
|
||||
}
|
||||
.CodeMirror:hover .CodeMirror-copy {
|
||||
user-select: all;
|
||||
opacity: 1;
|
||||
}
|
||||
@@ -4,17 +4,18 @@
|
||||
top: 0;
|
||||
right: 0;
|
||||
margin: $-xl*2 $-xl;
|
||||
padding: $-l $-xl;
|
||||
padding: $-m $-l;
|
||||
background-color: #EEE;
|
||||
border-radius: 3px;
|
||||
box-shadow: $bs-med;
|
||||
box-shadow: $bs-card;
|
||||
z-index: 999999;
|
||||
cursor: pointer;
|
||||
max-width: 360px;
|
||||
transition: transform ease-in-out 280ms;
|
||||
transform: translate3d(580px, 0, 0);
|
||||
transform: translateX(580px);
|
||||
display: grid;
|
||||
grid-template-columns: 64px 1fr;
|
||||
grid-template-columns: 42px 1fr;
|
||||
color: #FFF;
|
||||
span, svg {
|
||||
vertical-align: middle;
|
||||
justify-self: center;
|
||||
@@ -22,9 +23,9 @@
|
||||
}
|
||||
svg {
|
||||
fill: #EEEEEE;
|
||||
width: 4em;
|
||||
height: 4em;
|
||||
padding-right: $-m;
|
||||
width: 2.8rem;
|
||||
height: 2.8rem;
|
||||
padding-right: $-s;
|
||||
}
|
||||
span {
|
||||
vertical-align: middle;
|
||||
@@ -32,18 +33,15 @@
|
||||
}
|
||||
&.pos {
|
||||
background-color: $positive;
|
||||
color: #EEE;
|
||||
}
|
||||
&.neg {
|
||||
background-color: $negative;
|
||||
color: #EEE;
|
||||
}
|
||||
&.warning {
|
||||
background-color: $secondary;
|
||||
color: #EEE;
|
||||
}
|
||||
&.showing {
|
||||
transform: translate3d(0, 0, 0);
|
||||
transform: translateX(0);
|
||||
}
|
||||
&.showing:hover {
|
||||
transform: translate3d(0, -2px, 0);
|
||||
|
||||
@@ -266,22 +266,13 @@ ul.pagination {
|
||||
padding: $-xxs $-s;
|
||||
border: 1px solid #CCC;
|
||||
margin-left: -1px;
|
||||
color: #888;
|
||||
fill: #888;
|
||||
user-select: none;
|
||||
&.disabled {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
li.active span {
|
||||
background-color: rgba($primary, 0.8);
|
||||
color: #EEE;
|
||||
fill: #EEE;
|
||||
border-color: rgba($primary, 0.8);
|
||||
}
|
||||
a {
|
||||
color: $primary;
|
||||
fill: $primary;
|
||||
color: #FFF;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -89,6 +89,12 @@
|
||||
del {
|
||||
background: #FFECEC;
|
||||
}
|
||||
|
||||
&.page-revision {
|
||||
pre code {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Page content pointers
|
||||
@@ -107,8 +113,13 @@
|
||||
position: absolute;
|
||||
top: -60px;
|
||||
background-color:#FFF;
|
||||
width: 272px;
|
||||
width: 275px;
|
||||
z-index: 55;
|
||||
|
||||
&.is-page-editable {
|
||||
width: 328px;
|
||||
}
|
||||
|
||||
&:before {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
@@ -132,12 +143,13 @@
|
||||
width: 172px;
|
||||
z-index: 40;
|
||||
}
|
||||
input, button {
|
||||
input, button, a {
|
||||
position: relative;
|
||||
border-radius: 0;
|
||||
height: 28px;
|
||||
font-size: 12px;
|
||||
vertical-align: top;
|
||||
padding: 5px 16px;
|
||||
}
|
||||
> i {
|
||||
color: #888;
|
||||
@@ -148,11 +160,22 @@
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
.button {
|
||||
.input-group .button {
|
||||
line-height: 1;
|
||||
margin: 0 0 0 -4px;
|
||||
box-shadow: none;
|
||||
}
|
||||
a.button {
|
||||
margin: 0 0 0 0;
|
||||
|
||||
&:hover {
|
||||
fill: #fff;
|
||||
}
|
||||
}
|
||||
.svg-icon {
|
||||
width: 1.2em;
|
||||
height: 1.2em;
|
||||
}
|
||||
}
|
||||
|
||||
// Attribute form
|
||||
|
||||
@@ -59,4 +59,5 @@ $text-light: #EEE;
|
||||
// Shadows
|
||||
$bs-light: 0 0 4px 1px #CCC;
|
||||
$bs-med: 0 1px 3px 1px rgba(76, 76, 76, 0.26);
|
||||
$bs-card: 0 1px 3px 1px rgba(76, 76, 76, 0.26), 0 1px 12px 0px rgba(76, 76, 76, 0.2);
|
||||
$bs-hover: 0 2px 2px 1px rgba(0,0,0,.13);
|
||||
@@ -8,34 +8,34 @@ return [
|
||||
*/
|
||||
|
||||
// Pages
|
||||
'page_create' => 'hat Seite erstellt:',
|
||||
'page_create_notification' => 'hat Seite erfolgreich erstellt:',
|
||||
'page_update' => 'hat Seite aktualisiert:',
|
||||
'page_update_notification' => 'hat Seite erfolgreich aktualisiert:',
|
||||
'page_delete' => 'hat Seite gelöscht:',
|
||||
'page_delete_notification' => 'hat Seite erfolgreich gelöscht:',
|
||||
'page_restore' => 'hat Seite wiederhergstellt:',
|
||||
'page_restore_notification' => 'hat Seite erfolgreich wiederhergstellt:',
|
||||
'page_move' => 'hat Seite verschoben:',
|
||||
'page_create' => 'Seite erstellt',
|
||||
'page_create_notification' => 'Die Seite wurde erfolgreich erstellt.',
|
||||
'page_update' => 'Seite aktualisiert',
|
||||
'page_update_notification' => 'Die Seite wurde erfolgreich aktualisiert.',
|
||||
'page_delete' => 'Seite gelöscht',
|
||||
'page_delete_notification' => 'Die Seite wurde erfolgreich gelöscht.',
|
||||
'page_restore' => 'Seite wiederhergstellt',
|
||||
'page_restore_notification' => 'Die Seite wurde erfolgreich wiederhergstellt.',
|
||||
'page_move' => 'Seite verschoben',
|
||||
|
||||
// Chapters
|
||||
'chapter_create' => 'hat Kapitel erstellt:',
|
||||
'chapter_create_notification' => 'hat Kapitel erfolgreich erstellt:',
|
||||
'chapter_update' => 'hat Kapitel aktualisiert:',
|
||||
'chapter_update_notification' => 'hat Kapitel erfolgreich aktualisiert:',
|
||||
'chapter_delete' => 'hat Kapitel gelöscht',
|
||||
'chapter_delete_notification' => 'hat Kapitel erfolgreich gelöscht:',
|
||||
'chapter_move' => 'hat Kapitel verschoben:',
|
||||
'chapter_create' => 'Kapitel erstellt',
|
||||
'chapter_create_notification' => 'Das Kapitel wurde erfolgreich erstellt.',
|
||||
'chapter_update' => 'Kapitel aktualisiert',
|
||||
'chapter_update_notification' => 'Das Kapitel wurde erfolgreich aktualisiert.',
|
||||
'chapter_delete' => 'Kapitel gelöscht',
|
||||
'chapter_delete_notification' => 'Das Kapitel wurde erfolgreich gelöscht.',
|
||||
'chapter_move' => 'Kapitel verschoben',
|
||||
|
||||
// Books
|
||||
'book_create' => 'hat Buch erstellt:',
|
||||
'book_create_notification' => 'hat Buch erfolgreich erstellt:',
|
||||
'book_update' => 'hat Buch aktualisiert:',
|
||||
'book_update_notification' => 'hat Buch erfolgreich aktualisiert:',
|
||||
'book_delete' => 'hat Buch gelöscht:',
|
||||
'book_delete_notification' => 'hat Buch erfolgreich gelöscht:',
|
||||
'book_sort' => 'hat Buch sortiert:',
|
||||
'book_sort_notification' => 'hat Buch erfolgreich neu sortiert:',
|
||||
'book_create' => 'Buch erstellt',
|
||||
'book_create_notification' => 'Das Buch wurde erfolgreich erstellt.',
|
||||
'book_update' => 'Buch aktualisiert',
|
||||
'book_update_notification' => 'Das Buch wurde erfolgreich aktualisiert.',
|
||||
'book_delete' => 'Buch gelöscht',
|
||||
'book_delete_notification' => 'Das Buch wurde erfolgreich gelöscht.',
|
||||
'book_sort' => 'Buch sortiert',
|
||||
'book_sort_notification' => 'Das Buch wurde erfolgreich neu sortiert.',
|
||||
|
||||
// Other
|
||||
'commented_on' => 'kommentierte',
|
||||
|
||||
@@ -179,6 +179,7 @@ return [
|
||||
'pages_revisions_restore' => 'Wiederherstellen',
|
||||
'pages_revisions_none' => 'Diese Seite hat keine älteren Versionen.',
|
||||
'pages_copy_link' => 'Link kopieren',
|
||||
'pages_edit_content_link' => 'Inhalt bearbeiten',
|
||||
'pages_permissions_active' => 'Seiten-Berechtigungen aktiv',
|
||||
'pages_initial_revision' => 'Erste Veröffentlichung',
|
||||
'pages_initial_name' => 'Neue Seite',
|
||||
|
||||
@@ -185,6 +185,7 @@ return [
|
||||
'pages_revisions_restore' => 'Restore',
|
||||
'pages_revisions_none' => 'This page has no revisions',
|
||||
'pages_copy_link' => 'Copy Link',
|
||||
'pages_edit_content_link' => 'Edit Content',
|
||||
'pages_permissions_active' => 'Page Permissions Active',
|
||||
'pages_initial_revision' => 'Initial publish',
|
||||
'pages_initial_name' => 'New Page',
|
||||
|
||||
@@ -82,6 +82,7 @@ return [
|
||||
'role_details' => 'Role Details',
|
||||
'role_name' => 'Role Name',
|
||||
'role_desc' => 'Short Description of Role',
|
||||
'role_external_auth_id' => 'External Authentication IDs',
|
||||
'role_system' => 'System Permissions',
|
||||
'role_manage_users' => 'Manage users',
|
||||
'role_manage_roles' => 'Manage roles & role permissions',
|
||||
|
||||
@@ -35,6 +35,8 @@ return [
|
||||
'book_delete' => 'libro borrado',
|
||||
'book_delete_notification' => 'Libro borrado exitosamente',
|
||||
'book_sort' => 'libro ordenado',
|
||||
'book_sort_notification' => 'Libro re-ordenado exitosamente',
|
||||
'book_sort_notification' => 'Libro reordenado exitosamente',
|
||||
|
||||
// Other
|
||||
'commented_on' => 'comentada el',
|
||||
];
|
||||
|
||||
@@ -31,6 +31,7 @@ return [
|
||||
'edit' => 'Editar',
|
||||
'sort' => 'Ordenar',
|
||||
'move' => 'Mover',
|
||||
'copy' => 'Copiar',
|
||||
'reply' => 'Responder',
|
||||
'delete' => 'Borrar',
|
||||
'search' => 'Buscar',
|
||||
|
||||
@@ -166,6 +166,9 @@ return [
|
||||
'pages_not_in_chapter' => 'La página no está en un capítulo',
|
||||
'pages_move' => 'Mover página',
|
||||
'pages_move_success' => 'Página movida a ":parentName"',
|
||||
'pages_copy' => 'Copiar página',
|
||||
'pages_copy_desination' => 'Destino de la copia',
|
||||
'pages_copy_success' => 'Página copiada a correctamente',
|
||||
'pages_permissions' => 'Permisos de página',
|
||||
'pages_permissions_success' => 'Permisos de página actualizados',
|
||||
'pages_revision' => 'Revisión',
|
||||
@@ -182,6 +185,7 @@ return [
|
||||
'pages_revisions_restore' => 'Restaurar',
|
||||
'pages_revisions_none' => 'Esta página no tiene revisiones',
|
||||
'pages_copy_link' => 'Copiar Enlace',
|
||||
'pages_edit_content_link' => 'Contenido editado',
|
||||
'pages_permissions_active' => 'Permisos de página activos',
|
||||
'pages_initial_revision' => 'Publicación inicial',
|
||||
'pages_initial_name' => 'Página nueva',
|
||||
|
||||
@@ -7,7 +7,7 @@ return [
|
||||
*/
|
||||
|
||||
// Permissions
|
||||
'permission' => 'UNo tiene permisos para visualizar la página solicitada.',
|
||||
'permission' => 'No tiene permisos para visualizar la página solicitada.',
|
||||
'permissionJson' => 'No tiene permisos para ejecutar la acción solicitada.',
|
||||
|
||||
// Auth
|
||||
@@ -65,7 +65,7 @@ return [
|
||||
'role_system_cannot_be_deleted' => 'Este rol es un rol de sistema y no puede ser borrado',
|
||||
'role_registration_default_cannot_delete' => 'Este rol no puede ser borrado mientras sea el rol por defecto de nuevos registros',
|
||||
|
||||
// Comments
|
||||
// Comments
|
||||
'comment_list' => 'Se ha producido un error al buscar los comentarios.',
|
||||
'cannot_add_comment_to_draft' => 'No puedes añadir comentarios a un borrador.',
|
||||
'comment_add' => 'Se ha producido un error al añadir el comentario.',
|
||||
|
||||
@@ -34,6 +34,7 @@ return [
|
||||
'app_homepage' => 'Página de inicio',
|
||||
'app_homepage_desc' => 'Elija la página que se mostrará al inicio en lugar de la vista predeterminada. Se ignorarán los permisos de la página seleccionada.',
|
||||
'app_homepage_default' => 'Página de inicio seleccionada',
|
||||
'app_homepage_books' => 'O selecciona la página de libros como página de inicio. Esto prevalecerá sobre cualquier página seleccionada como página de inicio.',
|
||||
'app_disable_comments' => 'Deshabilitar comentarios',
|
||||
'app_disable_comments_desc' => 'Deshabilita los comentarios en todas las páginas de la aplicación. Los comentarios existentes no se muestran.',
|
||||
|
||||
@@ -50,6 +51,19 @@ return [
|
||||
'reg_confirm_restrict_domain_desc' => 'Introduzca una lista separada por comas de los dominio a los que les gustaría restringir el registro de usuarios. A los usuarios les será enviado un correo electrónico para confirmar la dirección antes de que se le permita interactuar con la aplicación. <br> Tenga en cuenta que los usuarios podrán cambiar sus direcciones de correo electrónico después de registrarse exitosamente.',
|
||||
'reg_confirm_restrict_domain_placeholder' => 'Ninguna restricción establecida',
|
||||
|
||||
/**
|
||||
* Maintenance settings
|
||||
*/
|
||||
|
||||
'maint' => 'Mantenimiento',
|
||||
'maint_image_cleanup' => 'Limpiar imágenes',
|
||||
'maint_image_cleanup_desc' => "Analiza las páginas y sus revisiones para comprobar qué imágenes y dibujos están siendo utilizadas y cuales no son necesarias. Asegúrate de crear una copia completa de la base de datos y de las imágenes antes de lanzar esta opción.",
|
||||
'maint_image_cleanup_ignore_revisions' => 'Ignorar imágenes en revisiones',
|
||||
'maint_image_cleanup_run' => 'Lanzar limpieza',
|
||||
'maint_image_cleanup_warning' => 'Se han encontrado :count imágenes posiblemente no utilizadas . ¿Estás seguro de querer borrar estas imágenes?',
|
||||
'maint_image_cleanup_success' => '¡Se han encontrado y borrado :count imágenes posiblemente no utilizadas!',
|
||||
'maint_image_cleanup_nothing_found' => '¡No se han encontrado imágenes sin utilizar, no se han borrado imágenes!',
|
||||
|
||||
/**
|
||||
* Role settings
|
||||
*/
|
||||
@@ -68,6 +82,7 @@ return [
|
||||
'role_details' => 'Detalles de rol',
|
||||
'role_name' => 'Nombre de rol',
|
||||
'role_desc' => 'Descripción corta de rol',
|
||||
'role_external_auth_id' => 'ID externo de autenticación',
|
||||
'role_system' => 'Permisos de sistema',
|
||||
'role_manage_users' => 'Gestionar usuarios',
|
||||
'role_manage_roles' => 'Gestionar roles y permisos de roles',
|
||||
|
||||
@@ -124,7 +124,7 @@ return [
|
||||
'chapters_permissions_active' => 'Permisos de capítulo activado',
|
||||
'chapters_permissions_success' => 'Permisos de capítulo actualizados',
|
||||
'chapters_search_this' => 'Buscar en este capítulo',
|
||||
|
||||
|
||||
/**
|
||||
* Pages
|
||||
*/
|
||||
@@ -185,6 +185,7 @@ return [
|
||||
'pages_revisions_restore' => 'Restaurar',
|
||||
'pages_revisions_none' => 'Esta página no tiene revisiones',
|
||||
'pages_copy_link' => 'Copiar enlace',
|
||||
'pages_edit_content_link' => 'Contenido editado',
|
||||
'pages_permissions_active' => 'Permisos de página activos',
|
||||
'pages_initial_revision' => 'Publicación inicial',
|
||||
'pages_initial_name' => 'Página nueva',
|
||||
|
||||
@@ -34,10 +34,10 @@ return [
|
||||
'app_homepage' => 'Página de inicio de la Aplicación',
|
||||
'app_homepage_desc' => 'Seleccione una página de inicio para mostrar en lugar de la vista por defecto. Se ignoran los permisos de página para las páginas seleccionadas.',
|
||||
'app_homepage_default' => 'Página de inicio por defecto seleccionadad',
|
||||
'app_homepage_books' => 'O seleccione la página de libros como su página de inicio. Esto tendrá preferencia sobre cualquier página seleccionada como página de inicio.',
|
||||
'app_disable_comments' => 'Deshabilitar comentarios',
|
||||
'app_disable_comments_desc' => 'Deshabilitar comentarios en todas las páginas de la aplicación. Los comentarios existentes no se muestran.',
|
||||
|
||||
|
||||
/**
|
||||
* Registration settings
|
||||
*/
|
||||
@@ -51,6 +51,19 @@ return [
|
||||
'reg_confirm_restrict_domain_desc' => 'Introduzca una lista separada por comas de los correos electrónicos del dominio a los que les gustaría restringir el registro por dominio. A los usuarios les será enviado un correo elctrónico para confirmar la dirección antes de que se le permita interactuar con la aplicación. <br> Note que a los usuarios se les permitirá cambiar sus direcciones de correo electrónico luego de un registro éxioso.',
|
||||
'reg_confirm_restrict_domain_placeholder' => 'Ninguna restricción establecida',
|
||||
|
||||
/**
|
||||
* Maintenance settings
|
||||
*/
|
||||
|
||||
'maint' => 'Mantenimiento',
|
||||
'maint_image_cleanup' => 'Limpiar imágenes',
|
||||
'maint_image_cleanup_desc' => "Analizar contenido de páginas y revisiones para detectar cuáles imágenes y dibujos están en uso y cuáles son redundantes. Asegúrese de crear un respaldo completo de imágenes y base de datos antes de ejecutar esta tarea.",
|
||||
'maint_image_cleanup_ignore_revisions' => 'Ignorar imágenes en revisión',
|
||||
'maint_image_cleanup_run' => 'Ejecutar limpieza',
|
||||
'maint_image_cleanup_warning' => 'Se encontraron :count imágenes pontencialmente sin uso. Está seguro de que quiere eliminarlas?',
|
||||
'maint_image_cleanup_success' => 'Se encontraron y se eliminaron :count imágenes pontencialmente sin uso!',
|
||||
'maint_image_cleanup_nothing_found' => 'No se encotraron imágenes sin usar, Nada eliminado!',
|
||||
|
||||
/**
|
||||
* Role settings
|
||||
*/
|
||||
@@ -69,6 +82,7 @@ return [
|
||||
'role_details' => 'Detalles de rol',
|
||||
'role_name' => 'Nombre de rol',
|
||||
'role_desc' => 'Descripción corta de rol',
|
||||
'role_external_auth_id' => 'IDs de Autenticación Externa',
|
||||
'role_system' => 'Permisos de sistema',
|
||||
'role_manage_users' => 'Gestionar usuarios',
|
||||
'role_manage_roles' => 'Gestionar roles y permisos de roles',
|
||||
|
||||
@@ -15,7 +15,7 @@ return [
|
||||
'page_delete' => 'a supprimé la page',
|
||||
'page_delete_notification' => 'Page supprimée avec succès',
|
||||
'page_restore' => 'a restauré la page',
|
||||
'page_restore_notification' => 'Page réstaurée avec succès',
|
||||
'page_restore_notification' => 'Page restaurée avec succès',
|
||||
'page_move' => 'a déplacé la page',
|
||||
|
||||
// Chapters
|
||||
@@ -39,5 +39,4 @@ return [
|
||||
|
||||
// Other
|
||||
'commented_on' => 'a commenté'
|
||||
|
||||
];
|
||||
|
||||
@@ -73,4 +73,4 @@ return [
|
||||
'email_not_confirmed_click_link' => 'Merci de cliquer sur le lien dans l\'e-mail qui vous a été envoyé après l\'enregistrement.',
|
||||
'email_not_confirmed_resend' => 'Si vous ne retrouvez plus l\'e-mail, vous pouvez renvoyer un e-mail de confirmation en utilisant le formulaire ci-dessous.',
|
||||
'email_not_confirmed_resend_button' => 'Renvoyez l\'e-mail de confirmation',
|
||||
];
|
||||
];
|
||||
@@ -20,6 +20,7 @@ return [
|
||||
'role' => 'Rôle',
|
||||
'cover_image' => 'Image de couverture',
|
||||
'cover_image_description' => 'Cette image doit être environ 300x170px.',
|
||||
|
||||
/**
|
||||
* Actions
|
||||
*/
|
||||
@@ -30,6 +31,7 @@ return [
|
||||
'edit' => 'Editer',
|
||||
'sort' => 'Trier',
|
||||
'move' => 'Déplacer',
|
||||
'copy' => 'Copier',
|
||||
'reply' => 'Répondre',
|
||||
'delete' => 'Supprimer',
|
||||
'search' => 'Chercher',
|
||||
@@ -38,7 +40,6 @@ return [
|
||||
'remove' => 'Enlever',
|
||||
'add' => 'Ajouter',
|
||||
|
||||
|
||||
/**
|
||||
* Misc
|
||||
*/
|
||||
@@ -63,4 +64,4 @@ return [
|
||||
*/
|
||||
'email_action_help' => 'Si vous rencontrez des problèmes pour cliquer sur le bouton ":actionText", copiez et collez l\'adresse ci-dessous dans votre navigateur :',
|
||||
'email_rights' => 'Tous droits réservés',
|
||||
];
|
||||
];
|
||||
@@ -4,7 +4,7 @@ return [
|
||||
/**
|
||||
* Image Manager
|
||||
*/
|
||||
'image_select' => 'Selectionner une image',
|
||||
'image_select' => 'Sélectionner une image',
|
||||
'image_all' => 'Toutes',
|
||||
'image_all_title' => 'Voir toutes les images',
|
||||
'image_book_title' => 'Voir les images ajoutées à ce livre',
|
||||
@@ -15,19 +15,20 @@ return [
|
||||
'image_image_name' => 'Nom de l\'image',
|
||||
'image_delete_used' => 'Cette image est utilisée dans les pages ci-dessous.',
|
||||
'image_delete_confirm' => 'Confirmez que vous souhaitez bien supprimer cette image.',
|
||||
'image_select_image' => 'Selectionner l\'image',
|
||||
'image_select_image' => 'Sélectionner l\'image',
|
||||
'image_dropzone' => 'Glissez les images ici ou cliquez pour les ajouter',
|
||||
'images_deleted' => 'Images supprimées',
|
||||
'image_preview' => 'Prévisualiser l\'image',
|
||||
'image_upload_success' => 'Image ajoutée avec succès',
|
||||
'image_update_success' => 'Détails de l\'image mis à jour',
|
||||
'image_delete_success' => 'Image supprimée avec succès',
|
||||
'image_upload_remove' => 'Supprimer',
|
||||
|
||||
/**
|
||||
* Code editor
|
||||
*/
|
||||
'code_editor' => 'Editer le code',
|
||||
'code_language' => 'Language du code',
|
||||
'code_language' => 'Langage du code',
|
||||
'code_content' => 'Contenu du code',
|
||||
'code_save' => 'Enregistrer le code',
|
||||
];
|
||||
|
||||
@@ -19,7 +19,6 @@ return [
|
||||
'meta_created_name' => 'Créé :timeLength par :user',
|
||||
'meta_updated' => 'Mis à jour :timeLength',
|
||||
'meta_updated_name' => 'Mis à jour :timeLength par :user',
|
||||
'x_pages' => ':count pages',
|
||||
'entity_select' => 'Sélectionner l\'entité',
|
||||
'images' => 'Images',
|
||||
'my_recent_drafts' => 'Mes brouillons récents',
|
||||
@@ -36,7 +35,7 @@ return [
|
||||
* Permissions and restrictions
|
||||
*/
|
||||
'permissions' => 'Permissions',
|
||||
'permissions_intro' => 'Une fois activées ces permission prendont la priorité sur tous les sets de permissions pré-existants.',
|
||||
'permissions_intro' => 'Une fois activées ces permissions prendront la priorité sur tous les sets de permissions préexistants.',
|
||||
'permissions_enable' => 'Activer les permissions personnalisées',
|
||||
'permissions_save' => 'Enregistrer les permissions',
|
||||
|
||||
@@ -131,6 +130,7 @@ return [
|
||||
*/
|
||||
'page' => 'Page',
|
||||
'pages' => 'Pages',
|
||||
'x_pages' => ':count Page|:count Pages',
|
||||
'pages_popular' => 'Pages populaires',
|
||||
'pages_new' => 'Nouvelle page',
|
||||
'pages_attachments' => 'Fichiers joints',
|
||||
@@ -166,6 +166,9 @@ return [
|
||||
'pages_not_in_chapter' => 'La page n\'est pas dans un chapitre',
|
||||
'pages_move' => 'Déplacer la page',
|
||||
'pages_move_success' => 'Page déplacée à ":parentName"',
|
||||
'pages_copy' => 'Copier la page',
|
||||
'pages_copy_desination' => 'Destination de la copie',
|
||||
'pages_copy_success' => 'Page copiée avec succès',
|
||||
'pages_permissions' => 'Permissions de la page',
|
||||
'pages_permissions_success' => 'Permissions de la page mises à jour',
|
||||
'pages_revision' => 'Révision',
|
||||
@@ -182,6 +185,7 @@ return [
|
||||
'pages_revisions_restore' => 'Restaurer',
|
||||
'pages_revisions_none' => 'Cette page n\'a aucune révision',
|
||||
'pages_copy_link' => 'Copier le lien',
|
||||
'pages_edit_content_link' => 'Modifier le contenu',
|
||||
'pages_permissions_active' => 'Permissions de page actives',
|
||||
'pages_initial_revision' => 'Publication initiale',
|
||||
'pages_initial_name' => 'Nouvelle page',
|
||||
@@ -200,10 +204,12 @@ return [
|
||||
* Editor sidebar
|
||||
*/
|
||||
'page_tags' => 'Mots-clés de la page',
|
||||
'chapter_tags' => 'Mots-clés du chapitre',
|
||||
'book_tags' => 'Mots-clés du livre',
|
||||
'tag' => 'Mot-clé',
|
||||
'tags' => 'Mots-clé',
|
||||
'tags' => 'Mots-clés',
|
||||
'tag_value' => 'Valeur du mot-clé (Optionnel)',
|
||||
'tags_explain' => "Ajouter des mot-clés pour catégoriser votre contenu.",
|
||||
'tags_explain' => "Ajouter des mots-clés pour catégoriser votre contenu.",
|
||||
'tags_add' => 'Ajouter un autre mot-clé',
|
||||
'attachments' => 'Fichiers joints',
|
||||
'attachments_explain' => 'Ajouter des fichiers ou des liens pour les afficher sur votre page. Ils seront affichés dans la barre latérale',
|
||||
@@ -257,6 +263,6 @@ return [
|
||||
'comment_deleted_success' => 'Commentaire supprimé',
|
||||
'comment_created_success' => 'Commentaire ajouté',
|
||||
'comment_updated_success' => 'Commentaire mis à jour',
|
||||
'comment_delete_confirm' => 'Etes-vous sûr de vouloir supprimer ce commentaire?',
|
||||
'comment_delete_confirm' => 'Etes-vous sûr de vouloir supprimer ce commentaire ?',
|
||||
'comment_in_reply_to' => 'En réponse à :commentId',
|
||||
];
|
||||
];
|
||||
@@ -14,12 +14,13 @@ return [
|
||||
'error_user_exists_different_creds' => 'Un utilisateur avec l\'adresse :email existe déjà.',
|
||||
'email_already_confirmed' => 'Cet e-mail a déjà été validé, vous pouvez vous connecter.',
|
||||
'email_confirmation_invalid' => 'Cette confirmation est invalide. Veuillez essayer de vous inscrire à nouveau.',
|
||||
'email_confirmation_expired' => 'Le jeton de confirmation est perimé. Un nouvel e-mail vous a été envoyé.',
|
||||
'email_confirmation_expired' => 'Le jeton de confirmation est périmé. Un nouvel e-mail vous a été envoyé.',
|
||||
'ldap_fail_anonymous' => 'L\'accès LDAP anonyme n\'a pas abouti',
|
||||
'ldap_fail_authed' => 'L\'accès LDAP n\'a pas abouti avec cet utilisateur et ce mot de passe',
|
||||
'ldap_extension_not_installed' => 'L\'extention LDAP PHP n\'est pas installée',
|
||||
'ldap_extension_not_installed' => 'L\'extension LDAP PHP n\'est pas installée',
|
||||
'ldap_cannot_connect' => 'Impossible de se connecter au serveur LDAP, la connexion initiale a échoué',
|
||||
'social_no_action_defined' => 'Pas d\'action définie',
|
||||
'social_login_bad_response' => "Erreur pendant la tentative de connexion à :socialAccount : \n:error",
|
||||
'social_account_in_use' => 'Ce compte :socialAccount est déjà utilisé. Essayez de vous connecter via :socialAccount.',
|
||||
'social_account_email_in_use' => 'L\'email :email est déjà utilisé. Si vous avez déjà un compte :socialAccount, vous pouvez le joindre à votre profil existant.',
|
||||
'social_account_existing' => 'Ce compte :socialAccount est déjà rattaché à votre profil.',
|
||||
@@ -34,13 +35,17 @@ return [
|
||||
'cannot_get_image_from_url' => 'Impossible de récupérer l\'image depuis :url',
|
||||
'cannot_create_thumbs' => 'Le serveur ne peut pas créer de miniature, vérifier que l\'extension PHP GD est installée.',
|
||||
'server_upload_limit' => 'La taille du fichier est trop grande.',
|
||||
'uploaded' => 'Le serveur n\'autorise pas l\'envoi d\'un fichier de cette taille. Veuillez essayer avec une taille de fichier réduite.',
|
||||
'image_upload_error' => 'Une erreur est survenue pendant l\'envoi de l\'image',
|
||||
'image_upload_type_error' => 'LE format de l\'image envoyée n\'est pas valide',
|
||||
|
||||
// Attachments
|
||||
'attachment_page_mismatch' => 'Page mismatch during attachment update',
|
||||
'attachment_page_mismatch' => 'Page incorrecte durant la mise à jour du fichier joint',
|
||||
'attachment_not_found' => 'Fichier joint non trouvé',
|
||||
|
||||
// Pages
|
||||
'page_draft_autosave_fail' => 'Le brouillon n\'a pas pu être sauvé. Vérifiez votre connexion internet',
|
||||
'page_custom_home_deletion' => 'Impossible de supprimer une page définie comme page d\'accueil',
|
||||
|
||||
// Entities
|
||||
'entity_not_found' => 'Entité non trouvée',
|
||||
|
||||
@@ -34,8 +34,10 @@ return [
|
||||
'app_homepage' => 'Page d\'accueil de l\'application',
|
||||
'app_homepage_desc' => 'Choisissez une page à afficher sur la page d\'accueil au lieu de la vue par défaut. Les permissions sont ignorées pour les pages sélectionnées.',
|
||||
'app_homepage_default' => 'Page d\'accueil par défaut sélectionnée',
|
||||
'app_homepage_books' => 'Ou sélectionner la page des livres comme page d\'accueil. Cela va ignorer la page séléctionnée comme page d\'accueil.',
|
||||
'app_disable_comments' => 'Désactiver les commentaires',
|
||||
'app_disable_comments_desc' => 'Désactive les commentaires sur toutes les pages de l\'application. Les commentaires existants ne sont pas affichés.',
|
||||
|
||||
/**
|
||||
* Registration settings
|
||||
*/
|
||||
@@ -46,9 +48,22 @@ return [
|
||||
'reg_confirm_email' => 'Obliger la confirmation par e-mail ?',
|
||||
'reg_confirm_email_desc' => 'Si la restriction de domaine est activée, la confirmation sera automatiquement obligatoire et cette valeur sera ignorée.',
|
||||
'reg_confirm_restrict_domain' => 'Restreindre l\'inscription à un domaine',
|
||||
'reg_confirm_restrict_domain_desc' => 'Entrez une liste de domaines acceptés lors de l\'inscription, séparés par une virgule. Les utilisateur recevront un e-mail de confirmation à cette adresse. <br> Les utilisateurs pourront changer leur adresse après inscription s\'ils le souhaitent.',
|
||||
'reg_confirm_restrict_domain_desc' => 'Entrez une liste de domaines acceptés lors de l\'inscription, séparés par une virgule. Les utilisateurs recevront un e-mail de confirmation à cette adresse. <br> Les utilisateurs pourront changer leur adresse après inscription s\'ils le souhaitent.',
|
||||
'reg_confirm_restrict_domain_placeholder' => 'Aucune restriction en place',
|
||||
|
||||
/**
|
||||
* Maintenance settings
|
||||
*/
|
||||
|
||||
'maint' => 'Maintenance',
|
||||
'maint_image_cleanup' => 'Nettoyer les images',
|
||||
'maint_image_cleanup_desc' => "Scan le contenu des pages et des révisions pour vérifier les images et les dessins en cours d'utilisation et lesquels sont redondant. Veuillez à faire une sauvegarde de la base de données et des images avant de lancer ceci.",
|
||||
'maint_image_cleanup_ignore_revisions' => 'Ignorer les images dans les révisions',
|
||||
'maint_image_cleanup_run' => 'Lancer le nettoyage',
|
||||
'maint_image_cleanup_warning' => ':count images potentiellement inutilisées trouvées. Etes-vous sûr de vouloir supprimer ces images ?',
|
||||
'maint_image_cleanup_success' => ':count images potentiellement inutilisées trouvées et supprimées !',
|
||||
'maint_image_cleanup_nothing_found' => 'Aucune image inutilisée trouvée, rien à supprimer !',
|
||||
|
||||
/**
|
||||
* Role settings
|
||||
*/
|
||||
@@ -61,23 +76,24 @@ return [
|
||||
'role_delete_confirm' => 'Ceci va supprimer le rôle \':roleName\'.',
|
||||
'role_delete_users_assigned' => 'Ce rôle a :userCount utilisateurs assignés. Vous pouvez choisir un rôle de remplacement pour ces utilisateurs.',
|
||||
'role_delete_no_migration' => "Ne pas assigner de nouveau rôle",
|
||||
'role_delete_sure' => 'Êtes vous sûr(e) de vouloir supprimer ce rôle ?',
|
||||
'role_delete_sure' => 'Êtes-vous sûr de vouloir supprimer ce rôle ?',
|
||||
'role_delete_success' => 'Le rôle a été supprimé avec succès',
|
||||
'role_edit' => 'Modifier le rôle',
|
||||
'role_details' => 'Détails du rôle',
|
||||
'role_name' => 'Nom du rôle',
|
||||
'role_desc' => 'Courte description du rôle',
|
||||
'role_external_auth_id' => 'Identifiants d\'authentification externes',
|
||||
'role_system' => 'Permissions système',
|
||||
'role_manage_users' => 'Gérer les utilisateurs',
|
||||
'role_manage_roles' => 'Gérer les rôles et permissions',
|
||||
'role_manage_entity_permissions' => 'Gérer les permissions sur les livres, chapitres et pages',
|
||||
'role_manage_own_entity_permissions' => 'Gérer les permissions de ses propres livres, chapitres, et pages',
|
||||
'role_manage_settings' => 'Gérer les préférences de l\'application',
|
||||
'role_asset' => 'Asset Permissions',
|
||||
'role_asset_desc' => 'These permissions control default access to the assets within the system. Permissions on Books, Chapters and Pages will override these permissions.',
|
||||
'role_asset' => 'Permissions des ressources',
|
||||
'role_asset_desc' => 'Ces permissions contrôlent l\'accès par défaut des ressources dans le système. Les permissions dans les livres, les chapitres et les pages ignoreront ces permissions',
|
||||
'role_all' => 'Tous',
|
||||
'role_own' => 'Propres',
|
||||
'role_controlled_by_asset' => 'Controlled by the asset they are uploaded to',
|
||||
'role_controlled_by_asset' => 'Contrôlé par les ressources les ayant envoyés',
|
||||
'role_save' => 'Enregistrer le rôle',
|
||||
'role_update_success' => 'Rôle mis à jour avec succès',
|
||||
'role_users' => 'Utilisateurs ayant ce rôle',
|
||||
@@ -93,7 +109,7 @@ return [
|
||||
'users_search' => 'Chercher les utilisateurs',
|
||||
'users_role' => 'Rôles des utilisateurs',
|
||||
'users_external_auth_id' => 'Identifiant d\'authentification externe',
|
||||
'users_password_warning' => 'Remplissez ce fomulaire uniquement si vous souhaitez changer de mot de passe:',
|
||||
'users_password_warning' => 'Remplissez ce formulaire uniquement si vous souhaitez changer de mot de passe:',
|
||||
'users_system_public' => 'Cet utilisateur représente les invités visitant votre instance. Il est assigné automatiquement aux invités.',
|
||||
'users_books_view_type' => 'Disposition d\'affichage préférée pour les livres',
|
||||
'users_delete' => 'Supprimer un utilisateur',
|
||||
|
||||
@@ -182,6 +182,7 @@ return [
|
||||
'pages_revisions_restore' => 'Ripristina',
|
||||
'pages_revisions_none' => 'Questa pagina non ha versioni',
|
||||
'pages_copy_link' => 'Copia Link',
|
||||
'pages_edit_content_link' => 'Modifica contenuto',
|
||||
'pages_permissions_active' => 'Permessi Pagina Attivi',
|
||||
'pages_initial_revision' => 'Pubblicazione iniziale',
|
||||
'pages_initial_name' => 'Nuova Pagina',
|
||||
|
||||
@@ -179,6 +179,7 @@ return [
|
||||
'pages_revisions_restore' => '復元',
|
||||
'pages_revisions_none' => 'このページにはリビジョンがありません',
|
||||
'pages_copy_link' => 'リンクをコピー',
|
||||
'pages_edit_content_link' => 'コンテンツの編集',
|
||||
'pages_permissions_active' => 'ページの権限は有効です',
|
||||
'pages_initial_revision' => '初回の公開',
|
||||
'pages_initial_name' => '新規ページ',
|
||||
|
||||
@@ -14,7 +14,7 @@ return [
|
||||
'recent_activity' => 'Recente Activiteit',
|
||||
'create_now' => 'Maak er zelf één',
|
||||
'revisions' => 'Revisies',
|
||||
'meta_revision' => 'Revisie #:revisionCount',
|
||||
'meta_revision' => 'Revisie #:revisionCount',
|
||||
'meta_created' => 'Aangemaakt :timeLength',
|
||||
'meta_created_name' => 'Aangemaakt: :timeLength door :user',
|
||||
'meta_updated' => ':timeLength Aangepast',
|
||||
@@ -44,7 +44,7 @@ return [
|
||||
* Search
|
||||
*/
|
||||
'search_results' => 'Zoekresultaten',
|
||||
'search_total_results_found' => ':count resultaten gevonden|:count resultaten gevonden',
|
||||
'search_total_results_found' => ':count resultaten gevonden|:count resultaten gevonden',
|
||||
'search_clear' => 'Zoekopdracht wissen',
|
||||
'search_no_pages' => 'Er zijn geen pagina\'s gevonden',
|
||||
'search_for_term' => 'Zoeken op :term',
|
||||
@@ -105,7 +105,7 @@ return [
|
||||
*/
|
||||
'chapter' => 'Hoofdstuk',
|
||||
'chapters' => 'Hoofdstukken',
|
||||
'x_chapters' => ':count Hoofdstuk|:count Hoofdstukken',
|
||||
'x_chapters' => ':count Hoofdstuk|:count Hoofdstukken',
|
||||
'chapters_popular' => 'Populaire Hoofdstukken',
|
||||
'chapters_new' => 'Nieuw Hoofdstuk',
|
||||
'chapters_create' => 'Hoofdstuk Toevoegen',
|
||||
@@ -124,14 +124,14 @@ return [
|
||||
'chapters_empty' => 'Er zijn geen pagina\'s in dit hoofdstuk aangemaakt.',
|
||||
'chapters_permissions_active' => 'Hoofdstuk Permissies Actief',
|
||||
'chapters_permissions_success' => 'Hoofdstuk Permissies Bijgewerkt',
|
||||
'chapters_search_this' => 'Doorzoek dit hoofdstuk',
|
||||
'chapters_search_this' => 'Doorzoek dit hoofdstuk',
|
||||
|
||||
/**
|
||||
* Pages
|
||||
*/
|
||||
'page' => 'Pagina',
|
||||
'pages' => 'Pagina\'s',
|
||||
'x_pages' => ':count Pagina|:count Pagina\'s',
|
||||
'x_pages' => ':count Pagina|:count Pagina\'s',
|
||||
'pages_popular' => 'Populaire Pagina\'s',
|
||||
'pages_new' => 'Nieuwe Pagina',
|
||||
'pages_attachments' => 'Bijlages',
|
||||
@@ -168,7 +168,7 @@ return [
|
||||
'pages_move_success' => 'Pagina verplaatst naar ":parentName"',
|
||||
'pages_permissions' => 'Pagina Permissies',
|
||||
'pages_permissions_success' => 'Pagina Permissies bijgwerkt',
|
||||
'pages_revision' => 'Revisie',
|
||||
'pages_revision' => 'Revisie',
|
||||
'pages_revisions' => 'Pagina Revisies',
|
||||
'pages_revisions_named' => 'Pagina Revisies voor :pageName',
|
||||
'pages_revision_named' => 'Pagina Revisie voor :pageName',
|
||||
@@ -182,6 +182,7 @@ return [
|
||||
'pages_revisions_restore' => 'Herstellen',
|
||||
'pages_revisions_none' => 'Deze pagina heeft geen revisies',
|
||||
'pages_copy_link' => 'Link Kopiëren',
|
||||
'pages_edit_content_link' => 'Bewerk inhoud',
|
||||
'pages_permissions_active' => 'Pagina Permissies Actief',
|
||||
'pages_initial_revision' => 'Eerste publicatie',
|
||||
'pages_initial_name' => 'Nieuwe Pagina',
|
||||
|
||||
@@ -179,6 +179,7 @@ return [
|
||||
'pages_revisions_restore' => 'Przywróć',
|
||||
'pages_revisions_none' => 'Ta strona nie posiada żadnych rewizji',
|
||||
'pages_copy_link' => 'Kopiuj link',
|
||||
'pages_edit_content_link' => 'Edytuj zawartość',
|
||||
'pages_permissions_active' => 'Uprawnienia strony aktywne',
|
||||
'pages_initial_revision' => 'Wydanie pierwotne',
|
||||
'pages_initial_name' => 'Nowa strona',
|
||||
|
||||
@@ -20,6 +20,7 @@ return [
|
||||
'role' => 'Regra',
|
||||
'cover_image' => 'Imagem de capa',
|
||||
'cover_image_description' => 'Esta imagem deve ser aproximadamente 300x170px.',
|
||||
|
||||
/**
|
||||
* Actions
|
||||
*/
|
||||
@@ -30,6 +31,7 @@ return [
|
||||
'edit' => 'Editar',
|
||||
'sort' => 'Ordenar',
|
||||
'move' => 'Mover',
|
||||
'copy' => 'Copiar',
|
||||
'reply' => 'Responder',
|
||||
'delete' => 'Excluir',
|
||||
'search' => 'Pesquisar',
|
||||
@@ -48,6 +50,8 @@ return [
|
||||
'toggle_details' => 'Alternar Detalhes',
|
||||
'toggle_thumbnails' => 'Alternar Miniaturas',
|
||||
'details' => 'Detalhes',
|
||||
'grid_view' => 'Visualização em Grade',
|
||||
'list_view' => 'Visualização em Lista',
|
||||
|
||||
/**
|
||||
* Header
|
||||
|
||||
@@ -181,6 +181,7 @@ return [
|
||||
'pages_revisions_restore' => 'Restaurar',
|
||||
'pages_revisions_none' => 'Essa página não tem revisões',
|
||||
'pages_copy_link' => 'Copia Link',
|
||||
'pages_edit_content_link' => 'Editar conteúdo',
|
||||
'pages_permissions_active' => 'Permissões de Página Ativas',
|
||||
'pages_initial_revision' => 'Publicação Inicial',
|
||||
'pages_initial_name' => 'Nova Página',
|
||||
|
||||
@@ -181,6 +181,7 @@ return [
|
||||
'pages_revisions_restore' => 'Восстановить',
|
||||
'pages_revisions_none' => 'У этой страницы нет других версий',
|
||||
'pages_copy_link' => 'Копировать ссылку',
|
||||
'pages_edit_content_link' => 'Изменить содержание',
|
||||
'pages_permissions_active' => 'Действующие разрешения на страницу',
|
||||
'pages_initial_revision' => 'Первоначальное издание',
|
||||
'pages_initial_name' => 'Новая страница',
|
||||
|
||||
@@ -166,6 +166,7 @@ return [
|
||||
'pages_revisions_restore' => 'Obnoviť',
|
||||
'pages_revisions_none' => 'Táto stránka nemá žiadne revízie',
|
||||
'pages_copy_link' => 'Kopírovať odkaz',
|
||||
'pages_edit_content_link' => 'Upraviť obsah',
|
||||
'pages_permissions_active' => 'Oprávnienia stránky aktívne',
|
||||
'pages_initial_revision' => 'Prvé zverejnenie',
|
||||
'pages_initial_name' => 'Nová stránka',
|
||||
|
||||
@@ -31,6 +31,7 @@ return [
|
||||
'edit' => 'Redigera',
|
||||
'sort' => 'Sortera',
|
||||
'move' => 'Flytta',
|
||||
'copy' => 'Kopiera',
|
||||
'reply' => 'Svara',
|
||||
'delete' => 'Ta bort',
|
||||
'search' => 'Sök',
|
||||
|
||||
@@ -166,6 +166,9 @@ return [
|
||||
'pages_not_in_chapter' => 'Sidan ligger inte i något kapitel',
|
||||
'pages_move' => 'Flytta sida',
|
||||
'pages_move_success' => 'Sidan har flyttats till ":parentName"',
|
||||
'pages_copy' => 'Kopiera sida',
|
||||
'pages_copy_desination' => 'Destination',
|
||||
'pages_copy_success' => 'Sidan har kopierats',
|
||||
'pages_permissions' => 'Rättigheter för sida',
|
||||
'pages_permissions_success' => 'Rättigheterna för sidan har uppdaterats',
|
||||
'pages_revision' => 'Revision',
|
||||
@@ -182,6 +185,7 @@ return [
|
||||
'pages_revisions_restore' => 'Återställ',
|
||||
'pages_revisions_none' => 'Sidan har inga revisioner',
|
||||
'pages_copy_link' => 'Kopiera länk',
|
||||
'pages_edit_content_link' => 'Redigera innehåll',
|
||||
'pages_permissions_active' => 'Anpassade rättigheter är i bruk',
|
||||
'pages_initial_revision' => 'Första publicering',
|
||||
'pages_initial_name' => 'Ny sida',
|
||||
|
||||
@@ -34,6 +34,7 @@ return [
|
||||
'app_homepage' => 'Startsida',
|
||||
'app_homepage_desc' => 'Välj en sida att använda som startsida istället för standardvyn. Den valda sidans rättigheter kommer att ignoreras.',
|
||||
'app_homepage_default' => 'Vald vy för startsida',
|
||||
'app_homepage_books' => 'Eller välj att ha listan med böcker som startsida. Om du har valt någon annan sida som startsida ovan kommer den inställningen att ignoreras.',
|
||||
'app_disable_comments' => 'Inaktivera kommentarer',
|
||||
'app_disable_comments_desc' => 'Inaktivera kommentarer på alla sidor i applikationen. Befintliga kommentarer visas inte.',
|
||||
|
||||
@@ -50,6 +51,19 @@ return [
|
||||
'reg_confirm_restrict_domain_desc' => 'Ange en kommaseparerad lista över e-postdomäner till vilka du vill begränsa registrering. Användare kommer att skickas ett mail för att bekräfta deras e-post innan de får logga in. <br> Notera att användare kommer att kunna ändra sin e-postadress efter lyckad registrering.',
|
||||
'reg_confirm_restrict_domain_placeholder' => 'Ingen begränsning satt',
|
||||
|
||||
/**
|
||||
* Maintenance settings
|
||||
*/
|
||||
|
||||
'maint' => 'Underhåll',
|
||||
'maint_image_cleanup' => 'Rensa bilder',
|
||||
'maint_image_cleanup_desc' => "Söker igenom innehåll i sidor & revisioner för att se vilka bilder och teckningar som är i bruk och vilka som är överflödiga. Se till att ta en komplett backup av databas och bilder innan du kör detta.",
|
||||
'maint_image_cleanup_ignore_revisions' => 'Ignorera bilder i revisioner',
|
||||
'maint_image_cleanup_run' => 'Kör rensning',
|
||||
'maint_image_cleanup_warning' => 'Hittade :count bilder som potentiellt inte används. Vill du verkligen ta bort dessa bilder?',
|
||||
'maint_image_cleanup_success' => 'Hittade och raderade :count bilder som potentiellt inte används!',
|
||||
'maint_image_cleanup_nothing_found' => 'Hittade inga oanvända bilder, så inget har raderats!',
|
||||
|
||||
/**
|
||||
* Role settings
|
||||
*/
|
||||
@@ -68,6 +82,7 @@ return [
|
||||
'role_details' => 'Om rollen',
|
||||
'role_name' => 'Rollens namn',
|
||||
'role_desc' => 'Kort beskrivning av rollen',
|
||||
'role_external_auth_id' => 'Externa autentiserings-ID:n',
|
||||
'role_system' => 'Systemrättigheter',
|
||||
'role_manage_users' => 'Hanter användare',
|
||||
'role_manage_roles' => 'Hantera roller & rättigheter',
|
||||
@@ -96,7 +111,6 @@ return [
|
||||
'users_external_auth_id' => 'Externt ID för autentisering',
|
||||
'users_password_warning' => 'Fyll i nedanstående fält endast om du vill byta lösenord:',
|
||||
'users_system_public' => 'Den här användaren representerar eventuella gäster som använder systemet. Den kan inte användas för att logga in utan tilldeles automatiskt.',
|
||||
'users_books_view_type' => 'Layout för visning av böcker',
|
||||
'users_delete' => 'Ta bort användare',
|
||||
'users_delete_named' => 'Ta bort användaren :userName',
|
||||
'users_delete_warning' => 'Detta kommer att ta bort användaren \':userName\' från systemet helt och hållet.',
|
||||
@@ -113,26 +127,5 @@ return [
|
||||
'users_social_connect' => 'Anslut konto',
|
||||
'users_social_disconnect' => 'Koppla från konto',
|
||||
'users_social_connected' => ':socialAccount har kopplats till ditt konto.',
|
||||
'users_social_disconnected' => ':socialAccount har kopplats bort från ditt konto.',
|
||||
|
||||
// Since these labels are already localized this array does not need to be
|
||||
// translated in the language-specific files.
|
||||
// DELETE BELOW IF COPIED FROM EN
|
||||
///////////////////////////////////
|
||||
'language_select' => [
|
||||
'en' => 'English',
|
||||
'de' => 'Deutsch',
|
||||
'es' => 'Español',
|
||||
'es_AR' => 'Español Argentina',
|
||||
'fr' => 'Français',
|
||||
'nl' => 'Nederlands',
|
||||
'pt_BR' => 'Português do Brasil',
|
||||
'sk' => 'Slovensky',
|
||||
'sv' => 'Svenska',
|
||||
'ja' => '日本語',
|
||||
'pl' => 'Polski',
|
||||
'it' => 'Italian',
|
||||
'ru' => 'Русский'
|
||||
]
|
||||
///////////////////////////////////
|
||||
'users_social_disconnected' => ':socialAccount har kopplats bort från ditt konto.'
|
||||
];
|
||||
|
||||
@@ -181,6 +181,7 @@ return [
|
||||
'pages_revisions_restore' => '恢复',
|
||||
'pages_revisions_none' => '此页面没有修订',
|
||||
'pages_copy_link' => '复制链接',
|
||||
'pages_edit_content_link' => '编辑内容',
|
||||
'pages_permissions_active' => '有效的页面权限',
|
||||
'pages_initial_revision' => '初始发布',
|
||||
'pages_initial_name' => '新页面',
|
||||
|
||||
@@ -50,6 +50,19 @@ return [
|
||||
'reg_confirm_restrict_domain_desc' => '输入您想要限制注册的Email域名列表,用逗号隔开。在被允许与应用程序交互之前,用户将被发送一封Email来确认他们的地址。<br>注意用户在注册成功后可以修改他们的Email地址。',
|
||||
'reg_confirm_restrict_domain_placeholder' => '尚未设置限制',
|
||||
|
||||
/**
|
||||
* Maintenance settings
|
||||
*/
|
||||
|
||||
'maint' => '维护',
|
||||
'maint_image_cleanup' => '清理图像',
|
||||
'maint_image_cleanup_desc' => "扫描页面和修订内容以检查哪些图像是正在使用的以及哪些图像是多余的。确保在运行前创建完整的数据库和映像备份。",
|
||||
'maint_image_cleanup_ignore_revisions' => '忽略修订记录中的图像',
|
||||
'maint_image_cleanup_run' => '运行清理',
|
||||
'maint_image_cleanup_warning' => '发现了 :count 张可能未使用的图像。您确定要删除这些图像吗?',
|
||||
'maint_image_cleanup_success' => '找到并删除了 :count 张可能未使用的图像!',
|
||||
'maint_image_cleanup_nothing_found' => '找不到未使用的图像,没有删除!',
|
||||
|
||||
/**
|
||||
* Role settings
|
||||
*/
|
||||
|
||||
@@ -182,6 +182,7 @@ return [
|
||||
'pages_revisions_restore' => '恢複',
|
||||
'pages_revisions_none' => '此頁面沒有修訂',
|
||||
'pages_copy_link' => '複製連結',
|
||||
'pages_edit_content_link' => '编辑内容',
|
||||
'pages_permissions_active' => '有效的頁面權限',
|
||||
'pages_initial_revision' => '初次發布',
|
||||
'pages_initial_name' => '新頁面',
|
||||
|
||||
@@ -50,6 +50,19 @@ return [
|
||||
'reg_confirm_restrict_domain_desc' => '輸入您想要限制註冊的Email域域名稱列表,用逗號隔開。在被允許與本系統連結之前,使用者會收到一封Email來確認他們的位址。<br>注意,使用者在註冊成功後可以修改他們的Email位址。',
|
||||
'reg_confirm_restrict_domain_placeholder' => '尚未設定限制的網域',
|
||||
|
||||
/**
|
||||
* Maintenance settings
|
||||
*/
|
||||
|
||||
'maint' => '維護',
|
||||
'maint_image_cleanup' => '清理圖像',
|
||||
'maint_image_cleanup_desc' => "掃描頁面和修訂內容以檢查哪些圖像是正在使用的以及哪些圖像是多余的。確保在運行前創建完整的數據庫和映像備份。",
|
||||
'maint_image_cleanup_ignore_revisions' => '忽略修訂記錄中的圖像',
|
||||
'maint_image_cleanup_run' => '運行清理',
|
||||
'maint_image_cleanup_warning' => '發現了 :count 張可能未使用的圖像。您確定要刪除這些圖像嗎?',
|
||||
'maint_image_cleanup_success' => '找到並刪除了 :count 張可能未使用的圖像!',
|
||||
'maint_image_cleanup_nothing_found' => '找不到未使用的圖像,沒有刪除!',
|
||||
|
||||
/**
|
||||
* Role settings
|
||||
*/
|
||||
|
||||
@@ -42,8 +42,8 @@
|
||||
<span class="text-primary small" @click="file.deleting = false;">{{ trans('common.cancel') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div @click="startEdit(file)" class="drag-card-action text-center text-primary" style="padding: 0;">@icon('edit')</div>
|
||||
<div @click="deleteFile(file)" class="drag-card-action text-center text-neg" style="padding: 0;">@icon('close')</div>
|
||||
<div @click="startEdit(file)" class="drag-card-action text-center text-primary">@icon('edit')</div>
|
||||
<div @click="deleteFile(file)" class="drag-card-action text-center text-neg">@icon('close')</div>
|
||||
</div>
|
||||
</draggable>
|
||||
<p class="small muted" v-if="files.length === 0">
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-9">
|
||||
<div class="page-content">
|
||||
<div class="page-content page-revision">
|
||||
@include('pages.page-display')
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -124,10 +124,16 @@
|
||||
<div class="page-content flex" page-display="{{ $page->id }}">
|
||||
|
||||
<div class="pointer-container" id="pointer">
|
||||
<div class="pointer anim" >
|
||||
<div class="pointer anim {{ userCan('page-update', $page) ? 'is-page-editable' : ''}}" >
|
||||
<span class="icon text-primary">@icon('link') @icon('include', ['style' => 'display:none;'])</span>
|
||||
<input readonly="readonly" type="text" id="pointer-url" placeholder="url">
|
||||
<button class="button icon" data-clipboard-target="#pointer-url" type="button" title="{{ trans('entities.pages_copy_link') }}">@icon('copy')</button>
|
||||
<span class="input-group">
|
||||
<input readonly="readonly" type="text" id="pointer-url" placeholder="url">
|
||||
<button class="button icon" data-clipboard-target="#pointer-url" type="button" title="{{ trans('entities.pages_copy_link') }}">@icon('copy')</button>
|
||||
</span>
|
||||
@if(userCan('page-update', $page))
|
||||
<a href="{{ $page->getUrl('/edit') }}" id="pointer-edit" data-edit-href="{{ $page->getUrl('/edit') }}"
|
||||
class="button icon heading-edit-icon" title="{{ trans('entities.pages_edit_content_link')}}">@icon('edit')</a>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
|
||||
<div notification="success" data-autohide class="pos" @if(session()->has('success')) data-show @endif>
|
||||
<div notification="success" style="display: none;" data-autohide class="pos" @if(session()->has('success')) data-show @endif>
|
||||
@icon('check-circle') <span>{!! nl2br(htmlentities(session()->get('success'))) !!}</span>
|
||||
</div>
|
||||
|
||||
<div notification="warning" class="warning" @if(session()->has('warning')) data-show @endif>
|
||||
<div notification="warning" style="display: none;" class="warning" @if(session()->has('warning')) data-show @endif>
|
||||
@icon('info') <span>{!! nl2br(htmlentities(session()->get('warning'))) !!}</span>
|
||||
</div>
|
||||
|
||||
<div notification="error" class="neg" @if(session()->has('error')) data-show @endif>
|
||||
<div notification="error" style="display: none;" class="neg" @if(session()->has('error')) data-show @endif>
|
||||
@icon('danger') <span>{!! nl2br(htmlentities(session()->get('error'))) !!}</span>
|
||||
</div>
|
||||
|
||||
@@ -15,6 +15,14 @@
|
||||
<label for="name">{{ trans('settings.role_desc') }}</label>
|
||||
@include('form/text', ['name' => 'description'])
|
||||
</div>
|
||||
|
||||
@if(config('auth.method') === 'ldap')
|
||||
<div class="form-group">
|
||||
<label for="name">{{ trans('settings.role_external_auth_id') }}</label>
|
||||
@include('form/text', ['name' => 'external_auth_id'])
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<h5>{{ trans('settings.role_system') }}</h5>
|
||||
<label>@include('settings/roles/checkbox', ['permission' => 'users-manage']) {{ trans('settings.role_manage_users') }}</label>
|
||||
<label>@include('settings/roles/checkbox', ['permission' => 'user-roles-manage']) {{ trans('settings.role_manage_roles') }}</label>
|
||||
|
||||
36
resources/views/vendor/pagination/default.blade.php
vendored
Normal file
36
resources/views/vendor/pagination/default.blade.php
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
@if ($paginator->hasPages())
|
||||
<ul class="pagination">
|
||||
{{-- Previous Page Link --}}
|
||||
@if ($paginator->onFirstPage())
|
||||
<li class="disabled"><span>«</span></li>
|
||||
@else
|
||||
<li><a href="{{ $paginator->previousPageUrl() }}" rel="prev">«</a></li>
|
||||
@endif
|
||||
|
||||
{{-- Pagination Elements --}}
|
||||
@foreach ($elements as $element)
|
||||
{{-- "Three Dots" Separator --}}
|
||||
@if (is_string($element))
|
||||
<li class="disabled"><span>{{ $element }}</span></li>
|
||||
@endif
|
||||
|
||||
{{-- Array Of Links --}}
|
||||
@if (is_array($element))
|
||||
@foreach ($element as $page => $url)
|
||||
@if ($page == $paginator->currentPage())
|
||||
<li class="active primary-background"><span>{{ $page }}</span></li>
|
||||
@else
|
||||
<li><a href="{{ $url }}">{{ $page }}</a></li>
|
||||
@endif
|
||||
@endforeach
|
||||
@endif
|
||||
@endforeach
|
||||
|
||||
{{-- Next Page Link --}}
|
||||
@if ($paginator->hasMorePages())
|
||||
<li><a href="{{ $paginator->nextPageUrl() }}" rel="next">»</a></li>
|
||||
@else
|
||||
<li class="disabled"><span>»</span></li>
|
||||
@endif
|
||||
</ul>
|
||||
@endif
|
||||
@@ -1,10 +1,17 @@
|
||||
<?php namespace Tests;
|
||||
use BookStack\Role;
|
||||
use BookStack\Services\Ldap;
|
||||
use BookStack\User;
|
||||
use Mockery\MockInterface;
|
||||
|
||||
class LdapTest extends BrowserKitTest
|
||||
{
|
||||
|
||||
/**
|
||||
* @var MockInterface
|
||||
*/
|
||||
protected $mockLdap;
|
||||
|
||||
protected $mockUser;
|
||||
protected $resourceId = 'resource-test';
|
||||
|
||||
@@ -12,9 +19,15 @@ class LdapTest extends BrowserKitTest
|
||||
{
|
||||
parent::setUp();
|
||||
if (!defined('LDAP_OPT_REFERRALS')) define('LDAP_OPT_REFERRALS', 1);
|
||||
app('config')->set(['auth.method' => 'ldap', 'services.ldap.base_dn' => 'dc=ldap,dc=local', 'auth.providers.users.driver' => 'ldap']);
|
||||
$this->mockLdap = \Mockery::mock(\BookStack\Services\Ldap::class);
|
||||
$this->app['BookStack\Services\Ldap'] = $this->mockLdap;
|
||||
app('config')->set([
|
||||
'auth.method' => 'ldap',
|
||||
'services.ldap.base_dn' => 'dc=ldap,dc=local',
|
||||
'services.ldap.email_attribute' => 'mail',
|
||||
'services.ldap.user_to_groups' => false,
|
||||
'auth.providers.users.driver' => 'ldap',
|
||||
]);
|
||||
$this->mockLdap = \Mockery::mock(Ldap::class);
|
||||
$this->app[Ldap::class] = $this->mockLdap;
|
||||
$this->mockUser = factory(User::class)->make();
|
||||
}
|
||||
|
||||
@@ -133,4 +146,156 @@ class LdapTest extends BrowserKitTest
|
||||
->dontSee('External Authentication');
|
||||
}
|
||||
|
||||
public function test_login_maps_roles_and_retains_existsing_roles()
|
||||
{
|
||||
$roleToReceive = factory(Role::class)->create(['name' => 'ldaptester', 'display_name' => 'LdapTester']);
|
||||
$roleToReceive2 = factory(Role::class)->create(['name' => 'ldaptester-second', 'display_name' => 'LdapTester Second']);
|
||||
$existingRole = factory(Role::class)->create(['name' => 'ldaptester-existing']);
|
||||
$this->mockUser->forceFill(['external_auth_id' => $this->mockUser->name])->save();
|
||||
$this->mockUser->attachRole($existingRole);
|
||||
|
||||
app('config')->set([
|
||||
'services.ldap.user_to_groups' => true,
|
||||
'services.ldap.group_attribute' => 'memberOf',
|
||||
'services.ldap.remove_from_groups' => false,
|
||||
]);
|
||||
$this->mockLdap->shouldReceive('connect')->times(2)->andReturn($this->resourceId);
|
||||
$this->mockLdap->shouldReceive('setVersion')->times(2);
|
||||
$this->mockLdap->shouldReceive('setOption')->times(5);
|
||||
$this->mockLdap->shouldReceive('searchAndGetEntries')->times(5)
|
||||
->with($this->resourceId, config('services.ldap.base_dn'), \Mockery::type('string'), \Mockery::type('array'))
|
||||
->andReturn(['count' => 1, 0 => [
|
||||
'uid' => [$this->mockUser->name],
|
||||
'cn' => [$this->mockUser->name],
|
||||
'dn' => ['dc=test' . config('services.ldap.base_dn')],
|
||||
'mail' => [$this->mockUser->email],
|
||||
'memberof' => [
|
||||
'count' => 2,
|
||||
0 => "cn=ldaptester,ou=groups,dc=example,dc=com",
|
||||
1 => "cn=ldaptester-second,ou=groups,dc=example,dc=com",
|
||||
]
|
||||
]]);
|
||||
$this->mockLdap->shouldReceive('bind')->times(6)->andReturn(true);
|
||||
|
||||
$this->visit('/login')
|
||||
->see('Username')
|
||||
->type($this->mockUser->name, '#username')
|
||||
->type($this->mockUser->password, '#password')
|
||||
->press('Log In')
|
||||
->seePageIs('/');
|
||||
|
||||
$user = User::where('email', $this->mockUser->email)->first();
|
||||
$this->seeInDatabase('role_user', [
|
||||
'user_id' => $user->id,
|
||||
'role_id' => $roleToReceive->id
|
||||
]);
|
||||
$this->seeInDatabase('role_user', [
|
||||
'user_id' => $user->id,
|
||||
'role_id' => $roleToReceive2->id
|
||||
]);
|
||||
$this->seeInDatabase('role_user', [
|
||||
'user_id' => $user->id,
|
||||
'role_id' => $existingRole->id
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_login_maps_roles_and_removes_old_roles_if_set()
|
||||
{
|
||||
$roleToReceive = factory(Role::class)->create(['name' => 'ldaptester', 'display_name' => 'LdapTester']);
|
||||
$existingRole = factory(Role::class)->create(['name' => 'ldaptester-existing']);
|
||||
$this->mockUser->forceFill(['external_auth_id' => $this->mockUser->name])->save();
|
||||
$this->mockUser->attachRole($existingRole);
|
||||
|
||||
app('config')->set([
|
||||
'services.ldap.user_to_groups' => true,
|
||||
'services.ldap.group_attribute' => 'memberOf',
|
||||
'services.ldap.remove_from_groups' => true,
|
||||
]);
|
||||
$this->mockLdap->shouldReceive('connect')->times(2)->andReturn($this->resourceId);
|
||||
$this->mockLdap->shouldReceive('setVersion')->times(2);
|
||||
$this->mockLdap->shouldReceive('setOption')->times(4);
|
||||
$this->mockLdap->shouldReceive('searchAndGetEntries')->times(4)
|
||||
->with($this->resourceId, config('services.ldap.base_dn'), \Mockery::type('string'), \Mockery::type('array'))
|
||||
->andReturn(['count' => 1, 0 => [
|
||||
'uid' => [$this->mockUser->name],
|
||||
'cn' => [$this->mockUser->name],
|
||||
'dn' => ['dc=test' . config('services.ldap.base_dn')],
|
||||
'mail' => [$this->mockUser->email],
|
||||
'memberof' => [
|
||||
'count' => 1,
|
||||
0 => "cn=ldaptester,ou=groups,dc=example,dc=com",
|
||||
]
|
||||
]]);
|
||||
$this->mockLdap->shouldReceive('bind')->times(5)->andReturn(true);
|
||||
|
||||
$this->visit('/login')
|
||||
->see('Username')
|
||||
->type($this->mockUser->name, '#username')
|
||||
->type($this->mockUser->password, '#password')
|
||||
->press('Log In')
|
||||
->seePageIs('/');
|
||||
|
||||
$user = User::where('email', $this->mockUser->email)->first();
|
||||
$this->seeInDatabase('role_user', [
|
||||
'user_id' => $user->id,
|
||||
'role_id' => $roleToReceive->id
|
||||
]);
|
||||
$this->dontSeeInDatabase('role_user', [
|
||||
'user_id' => $user->id,
|
||||
'role_id' => $existingRole->id
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_external_auth_id_visible_in_roles_page_when_ldap_active()
|
||||
{
|
||||
$role = factory(Role::class)->create(['name' => 'ldaptester', 'external_auth_id' => 'ex-auth-a, test-second-param']);
|
||||
$this->asAdmin()->visit('/settings/roles/' . $role->id)
|
||||
->see('ex-auth-a');
|
||||
}
|
||||
|
||||
public function test_login_maps_roles_using_external_auth_ids_if_set()
|
||||
{
|
||||
$roleToReceive = factory(Role::class)->create(['name' => 'ldaptester', 'external_auth_id' => 'test-second-param, ex-auth-a']);
|
||||
$roleToNotReceive = factory(Role::class)->create(['name' => 'ldaptester-not-receive', 'display_name' => 'ex-auth-a', 'external_auth_id' => 'test-second-param']);
|
||||
|
||||
app('config')->set([
|
||||
'services.ldap.user_to_groups' => true,
|
||||
'services.ldap.group_attribute' => 'memberOf',
|
||||
'services.ldap.remove_from_groups' => true,
|
||||
]);
|
||||
$this->mockLdap->shouldReceive('connect')->times(2)->andReturn($this->resourceId);
|
||||
$this->mockLdap->shouldReceive('setVersion')->times(2);
|
||||
$this->mockLdap->shouldReceive('setOption')->times(4);
|
||||
$this->mockLdap->shouldReceive('searchAndGetEntries')->times(4)
|
||||
->with($this->resourceId, config('services.ldap.base_dn'), \Mockery::type('string'), \Mockery::type('array'))
|
||||
->andReturn(['count' => 1, 0 => [
|
||||
'uid' => [$this->mockUser->name],
|
||||
'cn' => [$this->mockUser->name],
|
||||
'dn' => ['dc=test' . config('services.ldap.base_dn')],
|
||||
'mail' => [$this->mockUser->email],
|
||||
'memberof' => [
|
||||
'count' => 1,
|
||||
0 => "cn=ex-auth-a,ou=groups,dc=example,dc=com",
|
||||
]
|
||||
]]);
|
||||
$this->mockLdap->shouldReceive('bind')->times(5)->andReturn(true);
|
||||
|
||||
$this->visit('/login')
|
||||
->see('Username')
|
||||
->type($this->mockUser->name, '#username')
|
||||
->type($this->mockUser->password, '#password')
|
||||
->press('Log In')
|
||||
->seePageIs('/');
|
||||
|
||||
$user = User::where('email', $this->mockUser->email)->first();
|
||||
$this->seeInDatabase('role_user', [
|
||||
'user_id' => $user->id,
|
||||
'role_id' => $roleToReceive->id
|
||||
]);
|
||||
$this->dontSeeInDatabase('role_user', [
|
||||
'user_id' => $user->id,
|
||||
'role_id' => $roleToNotReceive->id
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -31,6 +31,16 @@ class LanguageTest extends TestCase
|
||||
$loginPageFrenchReq->assertSee('Se Connecter');
|
||||
}
|
||||
|
||||
public function test_public_lang_autodetect_can_be_disabled()
|
||||
{
|
||||
config()->set('app.auto_detect_locale', false);
|
||||
$loginReq = $this->get('/login');
|
||||
$loginReq->assertSee('Log In');
|
||||
|
||||
$loginPageFrenchReq = $this->get('/login', ['Accept-Language' => 'fr']);
|
||||
$loginPageFrenchReq->assertDontSee('Se Connecter');
|
||||
}
|
||||
|
||||
public function test_js_endpoint_for_each_language()
|
||||
{
|
||||
|
||||
|
||||
@@ -592,4 +592,26 @@ class RestrictionsTest extends BrowserKitTest
|
||||
->see('You do not have permission')
|
||||
->seePageIs('/');
|
||||
}
|
||||
|
||||
public function test_can_create_page_if_chapter_has_permissions_when_book_not_visible()
|
||||
{
|
||||
$book = Book::first();
|
||||
$this->setEntityRestrictions($book, []);
|
||||
$bookChapter = $book->chapters->first();
|
||||
$this->setEntityRestrictions($bookChapter, ['view']);
|
||||
|
||||
$this->actingAs($this->user)->visit($bookChapter->getUrl())
|
||||
->dontSee('New Page');
|
||||
|
||||
$this->setEntityRestrictions($bookChapter, ['view', 'create']);
|
||||
|
||||
$this->actingAs($this->user)->visit($bookChapter->getUrl())
|
||||
->click('New Page')
|
||||
->seeStatusCode(200)
|
||||
->type('test page', 'name')
|
||||
->type('test content', 'html')
|
||||
->press('Save Page')
|
||||
->seePageIs($book->getUrl('/page/test-page'))
|
||||
->seeStatusCode(200);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,11 @@ const config = {
|
||||
use: {
|
||||
loader: 'babel-loader',
|
||||
options: {
|
||||
presets: ['@babel/preset-env']
|
||||
presets: [[
|
||||
'@babel/preset-env', {
|
||||
useBuiltIns: 'usage'
|
||||
}
|
||||
]]
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user