Initial commit,修正
@@ -0,0 +1,28 @@
|
||||
# phpstorm project files
|
||||
.idea
|
||||
|
||||
# netbeans project files
|
||||
nbproject
|
||||
/nbproject/private/
|
||||
|
||||
# zend studio for eclipse project files
|
||||
.buildpath
|
||||
.project
|
||||
.settings
|
||||
|
||||
# windows thumbnail cache
|
||||
Thumbs.db
|
||||
|
||||
# composer vendor dir
|
||||
/vendor
|
||||
|
||||
# composer itself is not needed
|
||||
composer.phar
|
||||
|
||||
# Mac DS_Store Files
|
||||
.DS_Store
|
||||
|
||||
# phpunit itself is not needed
|
||||
phpunit.phar
|
||||
# local phpunit config
|
||||
/phpunit.xml
|
||||
@@ -0,0 +1,42 @@
|
||||
language: php
|
||||
|
||||
php:
|
||||
- 5.4
|
||||
- 5.5
|
||||
- 5.6
|
||||
- 7.0
|
||||
# - hhvm
|
||||
|
||||
# faster builds on new travis setup not using sudo
|
||||
sudo: false
|
||||
|
||||
# cache vendor dirs
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/.composer/cache
|
||||
|
||||
install:
|
||||
- travis_retry composer self-update && composer --version
|
||||
- travis_retry composer global require "fxp/composer-asset-plugin:~1.1.1"
|
||||
- export PATH="$HOME/.composer/vendor/bin:$PATH"
|
||||
- travis_retry composer install --dev --prefer-dist --no-interaction
|
||||
# codeception
|
||||
- travis_retry composer global require "codeception/codeception=2.0.*" "codeception/specify=*" "codeception/verify=*"
|
||||
# setup application:
|
||||
- |
|
||||
cd tests
|
||||
codecept build
|
||||
cd ..
|
||||
|
||||
before_script:
|
||||
- mysql --version
|
||||
|
||||
# initialize databases
|
||||
- mysql -e 'CREATE DATABASE mdm_admin_test;';
|
||||
|
||||
script:
|
||||
- |
|
||||
cd tests/web
|
||||
php -S localhost:8080 > /dev/null 2>&1 &
|
||||
cd ..
|
||||
codecept run
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace mdm\admin;
|
||||
|
||||
use yii\web\AssetBundle;
|
||||
|
||||
/**
|
||||
* Description of AnimateAsset
|
||||
*
|
||||
* @author Misbahul D Munir <misbahuldmunir@gmail.com>
|
||||
* @since 2.5
|
||||
*/
|
||||
class AnimateAsset extends AssetBundle
|
||||
{
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public $sourcePath = '@mdm/admin/assets';
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public $css = [
|
||||
'animate.css',
|
||||
];
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace mdm\admin;
|
||||
|
||||
use yii\web\AssetBundle;
|
||||
|
||||
/**
|
||||
* AutocompleteAsset
|
||||
*
|
||||
* @author Misbahul D Munir <misbahuldmunir@gmail.com>
|
||||
* @since 1.0
|
||||
*/
|
||||
class AutocompleteAsset extends AssetBundle
|
||||
{
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public $sourcePath = '@mdm/admin/assets';
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public $css = [
|
||||
'jquery-ui.css',
|
||||
];
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public $js = [
|
||||
'jquery-ui.js',
|
||||
];
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public $depends = [
|
||||
'yii\web\JqueryAsset',
|
||||
];
|
||||
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
Yii2 Admin Change Log
|
||||
==========================
|
||||
|
||||
2.5
|
||||
-----
|
||||
|
||||
- Enh: Add code testing (mdmunir).
|
||||
- Enh: Add more documentation (mdmunir).
|
||||
|
||||
2.0
|
||||
---------------------
|
||||
|
||||
- Chg: Remove dependenci to `yiisoft/yii2-jui` (mdmunir).
|
||||
- Chg: Add asset bundle for jui autocomplete (mdmunir).
|
||||
|
||||
|
||||
1.0.4
|
||||
-----------------------
|
||||
|
||||
- Bug: #102: Unique validation of the permission and role (mdmunir).
|
||||
- Enh: Clear cache when menu change (mdmunir).
|
||||
- Enh: Ensure get latest state of `user` component (mdmunir).
|
||||
|
||||
|
||||
1.0.3
|
||||
------
|
||||
|
||||
|
||||
1.0.2
|
||||
------
|
||||
|
||||
- Enh: Add Portuguese language to translation message (iforme).
|
||||
- Enh: configurable Navbar defined in module config (Stefano Mtangoo).
|
||||
- Enh: Add Italian language to translation message (realtebo).
|
||||
|
||||
1.0.1
|
||||
-----
|
||||
|
||||
- Enh: Add Persian language to translation message (jafaripur).
|
||||
- Enh: Add French language to translation message (marsuboss).
|
||||
|
||||
|
||||
1.0.0
|
||||
-----
|
||||
|
||||
- Enh: Internationalization (sosojni).
|
||||
- Enh: Add Russian language to translation message (m0zart89).
|
||||
|
||||
|
||||
1.0.0-rc
|
||||
--------
|
||||
|
||||
- Bug #12: Allow another module name (mdmunir).
|
||||
- Bug: #19: Added table prefix to table `menu` for some query (mdmunir, liu0472).
|
||||
- Bug: #24: change `$cache === null` to `isset($cache)` (mdmunir).
|
||||
- Bug: Bug fix. Ensure array has index before check `in_array()` (mdmunir).
|
||||
- Bug: Typo fix, replace `AssigmentController` to `AssignmentController` (mdmunir).
|
||||
- Enh: Custom side menu via `mdm\admin\Module::items` (mdmunir).
|
||||
- Enh: Added menu manager (mdmunir).
|
||||
- Enh: Migration for table menu (mdmunir).
|
||||
- Enh: Added Menu order (mdmunir).
|
||||
- Enh: Add `db` and `cache` configuration (mdmunir).
|
||||
- Enh: Add comment docs for entire class (mdmunir).
|
||||
- Enh: Add documentation (mdmunir).
|
||||
- Enh #57: Allow user to assign permission directly (mdmunir).
|
||||
- Chg #10: `cache` is not used anymore (mdmunir).
|
||||
- Chg #11: Only use required style sheet (mdmunir).
|
||||
- Chg: Using `VarDumper::export` to save `data` of `mdm\models\AuthItem` (mdmunir).
|
||||
- Chg: Allow using another `yii\rbac\Rule` instance (mdmunir).
|
||||
- Chg: Remove prefix `menu_` from column name of table `menu` (mdmunir).
|
||||
- Chg: Added column `data` to table `menu` (mdmunir).
|
||||
- Chg: Can customize return of `mdm\admin\components\AccessHelper::getAssignedMenu()` with provide a callback to method (mdmunir).
|
||||
- Chg: Add require "yiisoft/yii2-jui" to composer.json (mdmunir, hashie5).
|
||||
- Chg: #21: Force set allow `null` to column `parent` in database migration (mdmunir).
|
||||
- Chg: Remove `mdm\admin\components\BizRule` (mdmunir).
|
||||
- Chg: Change convert string to `yii\rbac\Item::$data` with `Json::decode()` (mdmunir).
|
||||
- Chg: Add extra param to route (mdmunir).
|
||||
- Chg: Add ability to get sparated menu. See [Using Menu](docs/guide/using-menu.md) (mdmunir).
|
||||
- Chg: Refactor layout (mdmunir).
|
||||
- Chg: Change `AccessHelper` to `MenuHelper` (mdmunir).
|
||||
- Chg: Change migration path name (mdmunir).
|
||||
- Chg: `db` and `cache` configuration via `$app->params['mdm.admin.configs']` (mdmunir).
|
||||
- Chg: #29: Change `yii\caching\GroupDependency` to `yii\caching\TagDependency` (mdmunir).
|
||||
- Chg: Remove `mdm\admin\Module::allowActions`. Set access control directly with `mdm\admin\components\AccessControl` (mdmunir).
|
||||
- Chg: Change cache strategy (mdmunir).
|
||||
- Chg: `mdm\admin\components\DbManager` now inherited from `yii\rbac\DbManager` (mdmunir).
|
||||
- Chg: Change module default layout (mdmunir).
|
||||
- Chg: Change back items to controllers (mdmunir).
|
||||
- Chg: Set default layout to `null` (mdmunir).
|
||||
- Chg #53: Fixed typo. Change Role to Permission (mdmunir).
|
||||
- Chg: Simplify using layout (mdmunir).
|
||||
@@ -0,0 +1,675 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
{one line to give the program's name and a brief idea of what it does.}
|
||||
Copyright (C) {year} {name of author}
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
{project} Copyright (C) {year} {fullname}
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
||||
|
||||
@@ -0,0 +1,187 @@
|
||||
<?php
|
||||
|
||||
namespace mdm\admin;
|
||||
|
||||
use Yii;
|
||||
use yii\helpers\Inflector;
|
||||
use yii\helpers\ArrayHelper;
|
||||
|
||||
/**
|
||||
* GUI manager for RBAC.
|
||||
*
|
||||
* Use [[\yii\base\Module::$controllerMap]] to change property of controller.
|
||||
* To change listed menu, use property [[$menus]].
|
||||
*
|
||||
* ```
|
||||
* 'layout' => 'left-menu', // default to null mean use application layout.
|
||||
* 'controllerMap' => [
|
||||
* 'assignment' => [
|
||||
* 'class' => 'mdm\admin\controllers\AssignmentController',
|
||||
* 'userClassName' => 'app\models\User',
|
||||
* 'idField' => 'id'
|
||||
* ]
|
||||
* ],
|
||||
* 'menus' => [
|
||||
* 'assignment' => [
|
||||
* 'label' => 'Grand Access' // change label
|
||||
* ],
|
||||
* 'route' => null, // disable menu
|
||||
* ],
|
||||
* ```
|
||||
*
|
||||
* @property string $mainLayout Main layout using for module. Default to layout of parent module.
|
||||
* Its used when `layout` set to 'left-menu', 'right-menu' or 'top-menu'.
|
||||
* @property array $menus List avalible menu of module.
|
||||
* It generated by module items .
|
||||
*
|
||||
* @author Misbahul D Munir <misbahuldmunir@gmail.com>
|
||||
* @since 1.0
|
||||
*/
|
||||
class Module extends \yii\base\Module
|
||||
{
|
||||
/**
|
||||
* @var array Nav bar items.
|
||||
*/
|
||||
public $navbar;
|
||||
/**
|
||||
* @var string Main layout using for module. Default to layout of parent module.
|
||||
* Its used when `layout` set to 'left-menu', 'right-menu' or 'top-menu'.
|
||||
*/
|
||||
public $mainLayout = '@mdm/admin/views/layouts/main.php';
|
||||
/**
|
||||
* @var array
|
||||
* @see [[menus]]
|
||||
*/
|
||||
private $_menus = [];
|
||||
/**
|
||||
* @var array
|
||||
* @see [[menus]]
|
||||
*/
|
||||
private $_coreItems = [
|
||||
'user' => 'Users',
|
||||
'assignment' => 'Assignments',
|
||||
'role' => 'Roles',
|
||||
'permission' => 'Permissions',
|
||||
'route' => 'Routes',
|
||||
'rule' => 'Rules',
|
||||
'menu' => 'Menus',
|
||||
];
|
||||
/**
|
||||
* @var array
|
||||
* @see [[items]]
|
||||
*/
|
||||
private $_normalizeMenus;
|
||||
|
||||
/**
|
||||
* @var string Default url for breadcrumb
|
||||
*/
|
||||
public $defaultUrl;
|
||||
|
||||
/**
|
||||
* @var string Default url label for breadcrumb
|
||||
*/
|
||||
public $defaultUrlLabel;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
parent::init();
|
||||
if (!isset(Yii::$app->i18n->translations['rbac-admin'])) {
|
||||
Yii::$app->i18n->translations['rbac-admin'] = [
|
||||
'class' => 'yii\i18n\PhpMessageSource',
|
||||
'sourceLanguage' => 'en',
|
||||
'basePath' => '@mdm/admin/messages'
|
||||
];
|
||||
}
|
||||
$userClass = ArrayHelper::getValue(Yii::$app->components, 'user.identityClass');
|
||||
if ($this->defaultRoute == 'default' && $userClass && is_subclass_of($userClass, 'yii\db\BaseActiveRecord')) {
|
||||
$this->defaultRoute = 'assignment';
|
||||
}
|
||||
//user did not define the Navbar?
|
||||
if ($this->navbar === null && Yii::$app instanceof \yii\web\Application) {
|
||||
$this->navbar = [
|
||||
['label' => Yii::t('rbac-admin', 'Help'), 'url' => ['default/index']],
|
||||
['label' => Yii::t('rbac-admin', 'Application'), 'url' => Yii::$app->homeUrl]
|
||||
];
|
||||
}
|
||||
if (class_exists('yii\jui\JuiAsset')) {
|
||||
Yii::$container->set('mdm\admin\AutocompleteAsset', 'yii\jui\JuiAsset');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get avalible menu.
|
||||
* @return array
|
||||
*/
|
||||
public function getMenus()
|
||||
{
|
||||
if ($this->_normalizeMenus === null) {
|
||||
$mid = '/' . $this->getUniqueId() . '/';
|
||||
// resolve core menus
|
||||
$this->_normalizeMenus = [];
|
||||
|
||||
$config = components\Configs::instance();
|
||||
print_r($config);
|
||||
$conditions = [
|
||||
'user' => $config->db && $config->db->schema->getTableSchema($config->userTable),
|
||||
'assignment' => ($userClass = Yii::$app->getUser()->identityClass) && is_subclass_of($userClass, 'yii\db\BaseActiveRecord'),
|
||||
'menu' => $config->db && $config->db->schema->getTableSchema($config->menuTable),
|
||||
];
|
||||
foreach ($this->_coreItems as $id => $lable) {
|
||||
if (!isset($conditions[$id]) || $conditions[$id]) {
|
||||
$this->_normalizeMenus[$id] = ['label' => Yii::t('rbac-admin', $lable), 'url' => [$mid . $id]];
|
||||
}
|
||||
}
|
||||
foreach (array_keys($this->controllerMap) as $id) {
|
||||
$this->_normalizeMenus[$id] = ['label' => Yii::t('rbac-admin', Inflector::humanize($id)), 'url' => [$mid . $id]];
|
||||
}
|
||||
|
||||
// user configure menus
|
||||
foreach ($this->_menus as $id => $value) {
|
||||
if (empty($value)) {
|
||||
unset($this->_normalizeMenus[$id]);
|
||||
continue;
|
||||
}
|
||||
if (is_string($value)) {
|
||||
$value = ['label' => $value];
|
||||
}
|
||||
$this->_normalizeMenus[$id] = isset($this->_normalizeMenus[$id]) ? array_merge($this->_normalizeMenus[$id], $value)
|
||||
: $value;
|
||||
if (!isset($this->_normalizeMenus[$id]['url'])) {
|
||||
$this->_normalizeMenus[$id]['url'] = [$mid . $id];
|
||||
}
|
||||
}
|
||||
}
|
||||
return $this->_normalizeMenus;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set or add avalible menu.
|
||||
* @param array $menus
|
||||
*/
|
||||
public function setMenus($menus)
|
||||
{
|
||||
$this->_menus = array_merge($this->_menus, $menus);
|
||||
$this->_normalizeMenus = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function beforeAction($action)
|
||||
{
|
||||
if (parent::beforeAction($action)) {
|
||||
/* @var $action \yii\base\Action */
|
||||
$view = $action->controller->getView();
|
||||
|
||||
$view->params['breadcrumbs'][] = [
|
||||
'label' => ($this->defaultUrlLabel ?: Yii::t('rbac-admin', 'Admin')),
|
||||
'url' => ['/' . ($this->defaultUrl ?: $this->uniqueId)]
|
||||
];
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
RBAC Manager for Yii 2
|
||||
======================
|
||||
GUI manager for RABC (Role Base Access Control) Yii2. Easy to manage authorization of user :smile:.
|
||||
|
||||
[](https://packagist.org/packages/mdmsoft/yii2-admin)
|
||||
[](https://packagist.org/packages/mdmsoft/yii2-admin)
|
||||
[](https://packagist.org/packages/mdmsoft/yii2-admin)
|
||||
[](https://packagist.org/packages/mdmsoft/yii2-admin)
|
||||
[](https://www.versioneye.com/php/mdmsoft:yii2-admin/references)
|
||||
[](http://travis-ci.org/mdmsoft/yii2-admin)
|
||||
[](https://www.versioneye.com/php/mdmsoft:yii2-admin/dev-master)
|
||||
[](https://scrutinizer-ci.com/g/mdmsoft/yii2-admin/?branch=master)
|
||||
[](https://codeclimate.com/github/mdmsoft/yii2-admin)
|
||||
|
||||
Documentation
|
||||
-------------
|
||||
> **Important: If you install version 3.x, please see [this readme](https://github.com/mdmsoft/yii2-admin/blob/3.master/README.md#upgrade-from-2x).**
|
||||
|
||||
|
||||
- [Change Log](CHANGELOG.md).
|
||||
- [Authorization Guide](http://www.yiiframework.com/doc-2.0/guide-security-authorization.html). Important, read this first before you continue.
|
||||
- [Basic Configuration](docs/guide/configuration.md)
|
||||
- [Basic Usage](docs/guide/basic-usage.md).
|
||||
- [User Management](docs/guide/user-management.md).
|
||||
- [Using Menu](docs/guide/using-menu.md).
|
||||
- [Api](https://mdmsoft.github.io/yii2-admin/index.html).
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
### Install With Composer
|
||||
|
||||
The preferred way to install this extension is through [composer](http://getcomposer.org/download/).
|
||||
|
||||
Either run
|
||||
|
||||
```
|
||||
php composer.phar require mdmsoft/yii2-admin "~1.0"
|
||||
or
|
||||
php composer.phar require mdmsoft/yii2-admin "~2.0"
|
||||
```
|
||||
|
||||
or for the dev-master
|
||||
|
||||
```
|
||||
php composer.phar require mdmsoft/yii2-admin "2.x-dev"
|
||||
```
|
||||
|
||||
Or, you may add
|
||||
|
||||
```
|
||||
"mdmsoft/yii2-admin": "~2.0"
|
||||
```
|
||||
|
||||
to the require section of your `composer.json` file and execute `php composer.phar update`.
|
||||
|
||||
### Install From the Archive
|
||||
|
||||
Download the latest release from here [releases](https://github.com/mdmsoft/yii2-admin/releases), then extract it to your project.
|
||||
In your application config, add the path alias for this extension.
|
||||
|
||||
```php
|
||||
return [
|
||||
...
|
||||
'aliases' => [
|
||||
'@mdm/admin' => 'path/to/your/extracted',
|
||||
// for example: '@mdm/admin' => '@app/extensions/mdm/yii2-admin-2.0.0',
|
||||
...
|
||||
]
|
||||
];
|
||||
```
|
||||
|
||||
[**More...**](docs/guide/configuration.md)
|
||||
|
||||
[screenshots](https://goo.gl/r8RizT)
|
||||
@@ -0,0 +1,21 @@
|
||||
.glyphicon-refresh-animate {
|
||||
-animation: spin .7s infinite linear;
|
||||
-ms-animation: spin .7s infinite linear;
|
||||
-webkit-animation: spinw .7s infinite linear;
|
||||
-moz-animation: spinm .7s infinite linear;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
from { transform: scale(1) rotate(0deg);}
|
||||
to { transform: scale(1) rotate(360deg);}
|
||||
}
|
||||
|
||||
@-webkit-keyframes spinw {
|
||||
from { -webkit-transform: rotate(0deg);}
|
||||
to { -webkit-transform: rotate(360deg);}
|
||||
}
|
||||
|
||||
@-moz-keyframes spinm {
|
||||
from { -moz-transform: rotate(0deg);}
|
||||
to { -moz-transform: rotate(360deg);}
|
||||
}
|
||||
@@ -0,0 +1,544 @@
|
||||
/*! jQuery UI - v1.11.4 - 2015-06-03
|
||||
* http://jqueryui.com
|
||||
* Includes: core.css, autocomplete.css, menu.css, theme.css
|
||||
* To view and modify this theme, visit http://jqueryui.com/themeroller/
|
||||
* Copyright 2015 jQuery Foundation and other contributors; Licensed MIT */
|
||||
|
||||
/* Layout helpers
|
||||
----------------------------------*/
|
||||
.ui-helper-hidden {
|
||||
display: none;
|
||||
}
|
||||
.ui-helper-hidden-accessible {
|
||||
border: 0;
|
||||
clip: rect(0 0 0 0);
|
||||
height: 1px;
|
||||
margin: -1px;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
}
|
||||
.ui-helper-reset {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
outline: 0;
|
||||
line-height: 1.3;
|
||||
text-decoration: none;
|
||||
font-size: 100%;
|
||||
list-style: none;
|
||||
}
|
||||
.ui-helper-clearfix:before,
|
||||
.ui-helper-clearfix:after {
|
||||
content: "";
|
||||
display: table;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
.ui-helper-clearfix:after {
|
||||
clear: both;
|
||||
}
|
||||
.ui-helper-clearfix {
|
||||
min-height: 0; /* support: IE7 */
|
||||
}
|
||||
.ui-helper-zfix {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
filter:Alpha(Opacity=0); /* support: IE8 */
|
||||
}
|
||||
|
||||
.ui-front {
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
|
||||
/* Interaction Cues
|
||||
----------------------------------*/
|
||||
.ui-state-disabled {
|
||||
cursor: default !important;
|
||||
}
|
||||
|
||||
|
||||
/* Icons
|
||||
----------------------------------*/
|
||||
|
||||
/* states and images */
|
||||
.ui-icon {
|
||||
display: block;
|
||||
text-indent: -99999px;
|
||||
overflow: hidden;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
|
||||
/* Misc visuals
|
||||
----------------------------------*/
|
||||
|
||||
/* Overlays */
|
||||
.ui-widget-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.ui-autocomplete {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
cursor: default;
|
||||
}
|
||||
.ui-menu {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
display: block;
|
||||
outline: none;
|
||||
}
|
||||
.ui-menu .ui-menu {
|
||||
position: absolute;
|
||||
}
|
||||
.ui-menu .ui-menu-item {
|
||||
position: relative;
|
||||
margin: 0;
|
||||
padding: 3px 1em 3px .4em;
|
||||
cursor: pointer;
|
||||
min-height: 0; /* support: IE7 */
|
||||
/* support: IE10, see #8844 */
|
||||
list-style-image: url("data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7");
|
||||
}
|
||||
.ui-menu .ui-menu-divider {
|
||||
margin: 5px 0;
|
||||
height: 0;
|
||||
font-size: 0;
|
||||
line-height: 0;
|
||||
border-width: 1px 0 0 0;
|
||||
}
|
||||
.ui-menu .ui-state-focus,
|
||||
.ui-menu .ui-state-active {
|
||||
margin: -1px;
|
||||
}
|
||||
|
||||
/* icon support */
|
||||
.ui-menu-icons {
|
||||
position: relative;
|
||||
}
|
||||
.ui-menu-icons .ui-menu-item {
|
||||
padding-left: 2em;
|
||||
}
|
||||
|
||||
/* left-aligned */
|
||||
.ui-menu .ui-icon {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: .2em;
|
||||
margin: auto 0;
|
||||
}
|
||||
|
||||
/* right-aligned */
|
||||
.ui-menu .ui-menu-icon {
|
||||
left: auto;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
/* Component containers
|
||||
----------------------------------*/
|
||||
.ui-widget {
|
||||
font-family: Verdana,Arial,sans-serif;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
.ui-widget .ui-widget {
|
||||
font-size: 1em;
|
||||
}
|
||||
.ui-widget input,
|
||||
.ui-widget select,
|
||||
.ui-widget textarea,
|
||||
.ui-widget button {
|
||||
font-family: Verdana,Arial,sans-serif;
|
||||
font-size: 1em;
|
||||
}
|
||||
.ui-widget-content {
|
||||
border: 1px solid #aaaaaa;
|
||||
background: #ffffff url("images/ui-bg_flat_75_ffffff_40x100.png") 50% 50% repeat-x;
|
||||
color: #222222;
|
||||
}
|
||||
.ui-widget-content a {
|
||||
color: #222222;
|
||||
}
|
||||
.ui-widget-header {
|
||||
border: 1px solid #aaaaaa;
|
||||
background: #cccccc url("images/ui-bg_highlight-soft_75_cccccc_1x100.png") 50% 50% repeat-x;
|
||||
color: #222222;
|
||||
font-weight: bold;
|
||||
}
|
||||
.ui-widget-header a {
|
||||
color: #222222;
|
||||
}
|
||||
|
||||
/* Interaction states
|
||||
----------------------------------*/
|
||||
.ui-state-default,
|
||||
.ui-widget-content .ui-state-default,
|
||||
.ui-widget-header .ui-state-default {
|
||||
border: 1px solid #d3d3d3;
|
||||
background: #e6e6e6 url("images/ui-bg_glass_75_e6e6e6_1x400.png") 50% 50% repeat-x;
|
||||
font-weight: normal;
|
||||
color: #555555;
|
||||
}
|
||||
.ui-state-default a,
|
||||
.ui-state-default a:link,
|
||||
.ui-state-default a:visited {
|
||||
color: #555555;
|
||||
text-decoration: none;
|
||||
}
|
||||
.ui-state-hover,
|
||||
.ui-widget-content .ui-state-hover,
|
||||
.ui-widget-header .ui-state-hover,
|
||||
.ui-state-focus,
|
||||
.ui-widget-content .ui-state-focus,
|
||||
.ui-widget-header .ui-state-focus {
|
||||
border: 1px solid #999999;
|
||||
background: #dadada url("images/ui-bg_glass_75_dadada_1x400.png") 50% 50% repeat-x;
|
||||
font-weight: normal;
|
||||
color: #212121;
|
||||
}
|
||||
.ui-state-hover a,
|
||||
.ui-state-hover a:hover,
|
||||
.ui-state-hover a:link,
|
||||
.ui-state-hover a:visited,
|
||||
.ui-state-focus a,
|
||||
.ui-state-focus a:hover,
|
||||
.ui-state-focus a:link,
|
||||
.ui-state-focus a:visited {
|
||||
color: #212121;
|
||||
text-decoration: none;
|
||||
}
|
||||
.ui-state-active,
|
||||
.ui-widget-content .ui-state-active,
|
||||
.ui-widget-header .ui-state-active {
|
||||
border: 1px solid #aaaaaa;
|
||||
background: #ffffff url("images/ui-bg_glass_65_ffffff_1x400.png") 50% 50% repeat-x;
|
||||
font-weight: normal;
|
||||
color: #212121;
|
||||
}
|
||||
.ui-state-active a,
|
||||
.ui-state-active a:link,
|
||||
.ui-state-active a:visited {
|
||||
color: #212121;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/* Interaction Cues
|
||||
----------------------------------*/
|
||||
.ui-state-highlight,
|
||||
.ui-widget-content .ui-state-highlight,
|
||||
.ui-widget-header .ui-state-highlight {
|
||||
border: 1px solid #fcefa1;
|
||||
background: #fbf9ee url("images/ui-bg_glass_55_fbf9ee_1x400.png") 50% 50% repeat-x;
|
||||
color: #363636;
|
||||
}
|
||||
.ui-state-highlight a,
|
||||
.ui-widget-content .ui-state-highlight a,
|
||||
.ui-widget-header .ui-state-highlight a {
|
||||
color: #363636;
|
||||
}
|
||||
.ui-state-error,
|
||||
.ui-widget-content .ui-state-error,
|
||||
.ui-widget-header .ui-state-error {
|
||||
border: 1px solid #cd0a0a;
|
||||
background: #fef1ec url("images/ui-bg_glass_95_fef1ec_1x400.png") 50% 50% repeat-x;
|
||||
color: #cd0a0a;
|
||||
}
|
||||
.ui-state-error a,
|
||||
.ui-widget-content .ui-state-error a,
|
||||
.ui-widget-header .ui-state-error a {
|
||||
color: #cd0a0a;
|
||||
}
|
||||
.ui-state-error-text,
|
||||
.ui-widget-content .ui-state-error-text,
|
||||
.ui-widget-header .ui-state-error-text {
|
||||
color: #cd0a0a;
|
||||
}
|
||||
.ui-priority-primary,
|
||||
.ui-widget-content .ui-priority-primary,
|
||||
.ui-widget-header .ui-priority-primary {
|
||||
font-weight: bold;
|
||||
}
|
||||
.ui-priority-secondary,
|
||||
.ui-widget-content .ui-priority-secondary,
|
||||
.ui-widget-header .ui-priority-secondary {
|
||||
opacity: .7;
|
||||
filter:Alpha(Opacity=70); /* support: IE8 */
|
||||
font-weight: normal;
|
||||
}
|
||||
.ui-state-disabled,
|
||||
.ui-widget-content .ui-state-disabled,
|
||||
.ui-widget-header .ui-state-disabled {
|
||||
opacity: .35;
|
||||
filter:Alpha(Opacity=35); /* support: IE8 */
|
||||
background-image: none;
|
||||
}
|
||||
.ui-state-disabled .ui-icon {
|
||||
filter:Alpha(Opacity=35); /* support: IE8 - See #6059 */
|
||||
}
|
||||
|
||||
/* Icons
|
||||
----------------------------------*/
|
||||
|
||||
/* states and images */
|
||||
.ui-icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
.ui-icon,
|
||||
.ui-widget-content .ui-icon {
|
||||
background-image: url("images/ui-icons_222222_256x240.png");
|
||||
}
|
||||
.ui-widget-header .ui-icon {
|
||||
background-image: url("images/ui-icons_222222_256x240.png");
|
||||
}
|
||||
.ui-state-default .ui-icon {
|
||||
background-image: url("images/ui-icons_888888_256x240.png");
|
||||
}
|
||||
.ui-state-hover .ui-icon,
|
||||
.ui-state-focus .ui-icon {
|
||||
background-image: url("images/ui-icons_454545_256x240.png");
|
||||
}
|
||||
.ui-state-active .ui-icon {
|
||||
background-image: url("images/ui-icons_454545_256x240.png");
|
||||
}
|
||||
.ui-state-highlight .ui-icon {
|
||||
background-image: url("images/ui-icons_2e83ff_256x240.png");
|
||||
}
|
||||
.ui-state-error .ui-icon,
|
||||
.ui-state-error-text .ui-icon {
|
||||
background-image: url("images/ui-icons_cd0a0a_256x240.png");
|
||||
}
|
||||
|
||||
/* positioning */
|
||||
.ui-icon-blank { background-position: 16px 16px; }
|
||||
.ui-icon-carat-1-n { background-position: 0 0; }
|
||||
.ui-icon-carat-1-ne { background-position: -16px 0; }
|
||||
.ui-icon-carat-1-e { background-position: -32px 0; }
|
||||
.ui-icon-carat-1-se { background-position: -48px 0; }
|
||||
.ui-icon-carat-1-s { background-position: -64px 0; }
|
||||
.ui-icon-carat-1-sw { background-position: -80px 0; }
|
||||
.ui-icon-carat-1-w { background-position: -96px 0; }
|
||||
.ui-icon-carat-1-nw { background-position: -112px 0; }
|
||||
.ui-icon-carat-2-n-s { background-position: -128px 0; }
|
||||
.ui-icon-carat-2-e-w { background-position: -144px 0; }
|
||||
.ui-icon-triangle-1-n { background-position: 0 -16px; }
|
||||
.ui-icon-triangle-1-ne { background-position: -16px -16px; }
|
||||
.ui-icon-triangle-1-e { background-position: -32px -16px; }
|
||||
.ui-icon-triangle-1-se { background-position: -48px -16px; }
|
||||
.ui-icon-triangle-1-s { background-position: -64px -16px; }
|
||||
.ui-icon-triangle-1-sw { background-position: -80px -16px; }
|
||||
.ui-icon-triangle-1-w { background-position: -96px -16px; }
|
||||
.ui-icon-triangle-1-nw { background-position: -112px -16px; }
|
||||
.ui-icon-triangle-2-n-s { background-position: -128px -16px; }
|
||||
.ui-icon-triangle-2-e-w { background-position: -144px -16px; }
|
||||
.ui-icon-arrow-1-n { background-position: 0 -32px; }
|
||||
.ui-icon-arrow-1-ne { background-position: -16px -32px; }
|
||||
.ui-icon-arrow-1-e { background-position: -32px -32px; }
|
||||
.ui-icon-arrow-1-se { background-position: -48px -32px; }
|
||||
.ui-icon-arrow-1-s { background-position: -64px -32px; }
|
||||
.ui-icon-arrow-1-sw { background-position: -80px -32px; }
|
||||
.ui-icon-arrow-1-w { background-position: -96px -32px; }
|
||||
.ui-icon-arrow-1-nw { background-position: -112px -32px; }
|
||||
.ui-icon-arrow-2-n-s { background-position: -128px -32px; }
|
||||
.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }
|
||||
.ui-icon-arrow-2-e-w { background-position: -160px -32px; }
|
||||
.ui-icon-arrow-2-se-nw { background-position: -176px -32px; }
|
||||
.ui-icon-arrowstop-1-n { background-position: -192px -32px; }
|
||||
.ui-icon-arrowstop-1-e { background-position: -208px -32px; }
|
||||
.ui-icon-arrowstop-1-s { background-position: -224px -32px; }
|
||||
.ui-icon-arrowstop-1-w { background-position: -240px -32px; }
|
||||
.ui-icon-arrowthick-1-n { background-position: 0 -48px; }
|
||||
.ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
|
||||
.ui-icon-arrowthick-1-e { background-position: -32px -48px; }
|
||||
.ui-icon-arrowthick-1-se { background-position: -48px -48px; }
|
||||
.ui-icon-arrowthick-1-s { background-position: -64px -48px; }
|
||||
.ui-icon-arrowthick-1-sw { background-position: -80px -48px; }
|
||||
.ui-icon-arrowthick-1-w { background-position: -96px -48px; }
|
||||
.ui-icon-arrowthick-1-nw { background-position: -112px -48px; }
|
||||
.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }
|
||||
.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }
|
||||
.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }
|
||||
.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }
|
||||
.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }
|
||||
.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }
|
||||
.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }
|
||||
.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }
|
||||
.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }
|
||||
.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }
|
||||
.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }
|
||||
.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }
|
||||
.ui-icon-arrowreturn-1-w { background-position: -64px -64px; }
|
||||
.ui-icon-arrowreturn-1-n { background-position: -80px -64px; }
|
||||
.ui-icon-arrowreturn-1-e { background-position: -96px -64px; }
|
||||
.ui-icon-arrowreturn-1-s { background-position: -112px -64px; }
|
||||
.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }
|
||||
.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }
|
||||
.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }
|
||||
.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }
|
||||
.ui-icon-arrow-4 { background-position: 0 -80px; }
|
||||
.ui-icon-arrow-4-diag { background-position: -16px -80px; }
|
||||
.ui-icon-extlink { background-position: -32px -80px; }
|
||||
.ui-icon-newwin { background-position: -48px -80px; }
|
||||
.ui-icon-refresh { background-position: -64px -80px; }
|
||||
.ui-icon-shuffle { background-position: -80px -80px; }
|
||||
.ui-icon-transfer-e-w { background-position: -96px -80px; }
|
||||
.ui-icon-transferthick-e-w { background-position: -112px -80px; }
|
||||
.ui-icon-folder-collapsed { background-position: 0 -96px; }
|
||||
.ui-icon-folder-open { background-position: -16px -96px; }
|
||||
.ui-icon-document { background-position: -32px -96px; }
|
||||
.ui-icon-document-b { background-position: -48px -96px; }
|
||||
.ui-icon-note { background-position: -64px -96px; }
|
||||
.ui-icon-mail-closed { background-position: -80px -96px; }
|
||||
.ui-icon-mail-open { background-position: -96px -96px; }
|
||||
.ui-icon-suitcase { background-position: -112px -96px; }
|
||||
.ui-icon-comment { background-position: -128px -96px; }
|
||||
.ui-icon-person { background-position: -144px -96px; }
|
||||
.ui-icon-print { background-position: -160px -96px; }
|
||||
.ui-icon-trash { background-position: -176px -96px; }
|
||||
.ui-icon-locked { background-position: -192px -96px; }
|
||||
.ui-icon-unlocked { background-position: -208px -96px; }
|
||||
.ui-icon-bookmark { background-position: -224px -96px; }
|
||||
.ui-icon-tag { background-position: -240px -96px; }
|
||||
.ui-icon-home { background-position: 0 -112px; }
|
||||
.ui-icon-flag { background-position: -16px -112px; }
|
||||
.ui-icon-calendar { background-position: -32px -112px; }
|
||||
.ui-icon-cart { background-position: -48px -112px; }
|
||||
.ui-icon-pencil { background-position: -64px -112px; }
|
||||
.ui-icon-clock { background-position: -80px -112px; }
|
||||
.ui-icon-disk { background-position: -96px -112px; }
|
||||
.ui-icon-calculator { background-position: -112px -112px; }
|
||||
.ui-icon-zoomin { background-position: -128px -112px; }
|
||||
.ui-icon-zoomout { background-position: -144px -112px; }
|
||||
.ui-icon-search { background-position: -160px -112px; }
|
||||
.ui-icon-wrench { background-position: -176px -112px; }
|
||||
.ui-icon-gear { background-position: -192px -112px; }
|
||||
.ui-icon-heart { background-position: -208px -112px; }
|
||||
.ui-icon-star { background-position: -224px -112px; }
|
||||
.ui-icon-link { background-position: -240px -112px; }
|
||||
.ui-icon-cancel { background-position: 0 -128px; }
|
||||
.ui-icon-plus { background-position: -16px -128px; }
|
||||
.ui-icon-plusthick { background-position: -32px -128px; }
|
||||
.ui-icon-minus { background-position: -48px -128px; }
|
||||
.ui-icon-minusthick { background-position: -64px -128px; }
|
||||
.ui-icon-close { background-position: -80px -128px; }
|
||||
.ui-icon-closethick { background-position: -96px -128px; }
|
||||
.ui-icon-key { background-position: -112px -128px; }
|
||||
.ui-icon-lightbulb { background-position: -128px -128px; }
|
||||
.ui-icon-scissors { background-position: -144px -128px; }
|
||||
.ui-icon-clipboard { background-position: -160px -128px; }
|
||||
.ui-icon-copy { background-position: -176px -128px; }
|
||||
.ui-icon-contact { background-position: -192px -128px; }
|
||||
.ui-icon-image { background-position: -208px -128px; }
|
||||
.ui-icon-video { background-position: -224px -128px; }
|
||||
.ui-icon-script { background-position: -240px -128px; }
|
||||
.ui-icon-alert { background-position: 0 -144px; }
|
||||
.ui-icon-info { background-position: -16px -144px; }
|
||||
.ui-icon-notice { background-position: -32px -144px; }
|
||||
.ui-icon-help { background-position: -48px -144px; }
|
||||
.ui-icon-check { background-position: -64px -144px; }
|
||||
.ui-icon-bullet { background-position: -80px -144px; }
|
||||
.ui-icon-radio-on { background-position: -96px -144px; }
|
||||
.ui-icon-radio-off { background-position: -112px -144px; }
|
||||
.ui-icon-pin-w { background-position: -128px -144px; }
|
||||
.ui-icon-pin-s { background-position: -144px -144px; }
|
||||
.ui-icon-play { background-position: 0 -160px; }
|
||||
.ui-icon-pause { background-position: -16px -160px; }
|
||||
.ui-icon-seek-next { background-position: -32px -160px; }
|
||||
.ui-icon-seek-prev { background-position: -48px -160px; }
|
||||
.ui-icon-seek-end { background-position: -64px -160px; }
|
||||
.ui-icon-seek-start { background-position: -80px -160px; }
|
||||
/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */
|
||||
.ui-icon-seek-first { background-position: -80px -160px; }
|
||||
.ui-icon-stop { background-position: -96px -160px; }
|
||||
.ui-icon-eject { background-position: -112px -160px; }
|
||||
.ui-icon-volume-off { background-position: -128px -160px; }
|
||||
.ui-icon-volume-on { background-position: -144px -160px; }
|
||||
.ui-icon-power { background-position: 0 -176px; }
|
||||
.ui-icon-signal-diag { background-position: -16px -176px; }
|
||||
.ui-icon-signal { background-position: -32px -176px; }
|
||||
.ui-icon-battery-0 { background-position: -48px -176px; }
|
||||
.ui-icon-battery-1 { background-position: -64px -176px; }
|
||||
.ui-icon-battery-2 { background-position: -80px -176px; }
|
||||
.ui-icon-battery-3 { background-position: -96px -176px; }
|
||||
.ui-icon-circle-plus { background-position: 0 -192px; }
|
||||
.ui-icon-circle-minus { background-position: -16px -192px; }
|
||||
.ui-icon-circle-close { background-position: -32px -192px; }
|
||||
.ui-icon-circle-triangle-e { background-position: -48px -192px; }
|
||||
.ui-icon-circle-triangle-s { background-position: -64px -192px; }
|
||||
.ui-icon-circle-triangle-w { background-position: -80px -192px; }
|
||||
.ui-icon-circle-triangle-n { background-position: -96px -192px; }
|
||||
.ui-icon-circle-arrow-e { background-position: -112px -192px; }
|
||||
.ui-icon-circle-arrow-s { background-position: -128px -192px; }
|
||||
.ui-icon-circle-arrow-w { background-position: -144px -192px; }
|
||||
.ui-icon-circle-arrow-n { background-position: -160px -192px; }
|
||||
.ui-icon-circle-zoomin { background-position: -176px -192px; }
|
||||
.ui-icon-circle-zoomout { background-position: -192px -192px; }
|
||||
.ui-icon-circle-check { background-position: -208px -192px; }
|
||||
.ui-icon-circlesmall-plus { background-position: 0 -208px; }
|
||||
.ui-icon-circlesmall-minus { background-position: -16px -208px; }
|
||||
.ui-icon-circlesmall-close { background-position: -32px -208px; }
|
||||
.ui-icon-squaresmall-plus { background-position: -48px -208px; }
|
||||
.ui-icon-squaresmall-minus { background-position: -64px -208px; }
|
||||
.ui-icon-squaresmall-close { background-position: -80px -208px; }
|
||||
.ui-icon-grip-dotted-vertical { background-position: 0 -224px; }
|
||||
.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }
|
||||
.ui-icon-grip-solid-vertical { background-position: -32px -224px; }
|
||||
.ui-icon-grip-solid-horizontal { background-position: -48px -224px; }
|
||||
.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }
|
||||
.ui-icon-grip-diagonal-se { background-position: -80px -224px; }
|
||||
|
||||
|
||||
/* Misc visuals
|
||||
----------------------------------*/
|
||||
|
||||
/* Corner radius */
|
||||
.ui-corner-all,
|
||||
.ui-corner-top,
|
||||
.ui-corner-left,
|
||||
.ui-corner-tl {
|
||||
border-top-left-radius: 4px;
|
||||
}
|
||||
.ui-corner-all,
|
||||
.ui-corner-top,
|
||||
.ui-corner-right,
|
||||
.ui-corner-tr {
|
||||
border-top-right-radius: 4px;
|
||||
}
|
||||
.ui-corner-all,
|
||||
.ui-corner-bottom,
|
||||
.ui-corner-left,
|
||||
.ui-corner-bl {
|
||||
border-bottom-left-radius: 4px;
|
||||
}
|
||||
.ui-corner-all,
|
||||
.ui-corner-bottom,
|
||||
.ui-corner-right,
|
||||
.ui-corner-br {
|
||||
border-bottom-right-radius: 4px;
|
||||
}
|
||||
|
||||
/* Overlays */
|
||||
.ui-widget-overlay {
|
||||
background: #aaaaaa url("images/ui-bg_flat_0_aaaaaa_40x100.png") 50% 50% repeat-x;
|
||||
opacity: .3;
|
||||
filter: Alpha(Opacity=30); /* support: IE8 */
|
||||
}
|
||||
.ui-widget-shadow {
|
||||
margin: -8px 0 0 -8px;
|
||||
padding: 8px;
|
||||
background: #aaaaaa url("images/ui-bg_flat_0_aaaaaa_40x100.png") 50% 50% repeat-x;
|
||||
opacity: .3;
|
||||
filter: Alpha(Opacity=30); /* support: IE8 */
|
||||
border-radius: 8px;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
/*
|
||||
To change this license header, choose License Headers in Project Properties.
|
||||
To change this template file, choose Tools | Templates
|
||||
and open the template in the editor.
|
||||
*/
|
||||
/*
|
||||
Created on : Jul 16, 2014, 8:10:29 AM
|
||||
Author : mdmunirdeb
|
||||
*/
|
||||
|
||||
#manager-menu .pull-right {
|
||||
float: right;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
body {
|
||||
padding-top: 70px;
|
||||
}
|
||||
|
||||
.footer {
|
||||
border-top: 1px solid #ddd;
|
||||
margin-top: 30px;
|
||||
padding: 15px 0 30px;
|
||||
}
|
||||
|
||||
.navbar-brand {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
<?php
|
||||
|
||||
namespace mdm\admin\components;
|
||||
|
||||
use yii\web\ForbiddenHttpException;
|
||||
use yii\base\Module;
|
||||
use Yii;
|
||||
use yii\web\User;
|
||||
use yii\di\Instance;
|
||||
|
||||
/**
|
||||
* Access Control Filter (ACF) is a simple authorization method that is best used by applications that only need some simple access control.
|
||||
* As its name indicates, ACF is an action filter that can be attached to a controller or a module as a behavior.
|
||||
* ACF will check a set of access rules to make sure the current user can access the requested action.
|
||||
*
|
||||
* To use AccessControl, declare it in the application config as behavior.
|
||||
* For example.
|
||||
*
|
||||
* ```
|
||||
* 'as access' => [
|
||||
* 'class' => 'mdm\admin\components\AccessControl',
|
||||
* 'allowActions' => ['site/login', 'site/error']
|
||||
* ]
|
||||
* ```
|
||||
*
|
||||
* @property User $user
|
||||
*
|
||||
* @author Misbahul D Munir <misbahuldmunir@gmail.com>
|
||||
* @since 1.0
|
||||
*/
|
||||
class AccessControl extends \yii\base\ActionFilter
|
||||
{
|
||||
/**
|
||||
* @var User User for check access.
|
||||
*/
|
||||
private $_user = 'user';
|
||||
/**
|
||||
* @var array List of action that not need to check access.
|
||||
*/
|
||||
public $allowActions = [];
|
||||
|
||||
/**
|
||||
* Get user
|
||||
* @return User
|
||||
*/
|
||||
public function getUser()
|
||||
{
|
||||
if (!$this->_user instanceof User) {
|
||||
$this->_user = Instance::ensure($this->_user, User::className());
|
||||
}
|
||||
return $this->_user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set user
|
||||
* @param User|string $user
|
||||
*/
|
||||
public function setUser($user)
|
||||
{
|
||||
$this->_user = $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function beforeAction($action)
|
||||
{
|
||||
$actionId = $action->getUniqueId();
|
||||
$user = $this->getUser();
|
||||
if (Helper::checkRoute('/' . $actionId, Yii::$app->getRequest()->get(), $user)) {
|
||||
return true;
|
||||
}
|
||||
$this->denyAccess($user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Denies the access of the user.
|
||||
* The default implementation will redirect the user to the login page if he is a guest;
|
||||
* if the user is already logged, a 403 HTTP exception will be thrown.
|
||||
* @param User $user the current user
|
||||
* @throws ForbiddenHttpException if the user is already logged in.
|
||||
*/
|
||||
protected function denyAccess($user)
|
||||
{
|
||||
if ($user->getIsGuest()) {
|
||||
$user->loginRequired();
|
||||
} else {
|
||||
throw new ForbiddenHttpException(Yii::t('yii', 'You are not allowed to perform this action.'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected function isActive($action)
|
||||
{
|
||||
$uniqueId = $action->getUniqueId();
|
||||
if ($uniqueId === Yii::$app->getErrorHandler()->errorAction) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$user = $this->getUser();
|
||||
if ($user->getIsGuest() && is_array($user->loginUrl) && isset($user->loginUrl[0]) && $uniqueId === trim($user->loginUrl[0], '/')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->owner instanceof Module) {
|
||||
// convert action uniqueId into an ID relative to the module
|
||||
$mid = $this->owner->getUniqueId();
|
||||
$id = $uniqueId;
|
||||
if ($mid !== '' && strpos($id, $mid . '/') === 0) {
|
||||
$id = substr($id, strlen($mid) + 1);
|
||||
}
|
||||
} else {
|
||||
$id = $action->id;
|
||||
}
|
||||
|
||||
foreach ($this->allowActions as $route) {
|
||||
if (substr($route, -1) === '*') {
|
||||
$route = rtrim($route, "*");
|
||||
if ($route === '' || strpos($id, $route) === 0) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if ($id === $route) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($action->controller->hasMethod('allowAction') && in_array($action->id, $action->controller->allowAction())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,202 @@
|
||||
<?php
|
||||
|
||||
namespace mdm\admin\components;
|
||||
|
||||
use Yii;
|
||||
use yii\db\Connection;
|
||||
use yii\caching\Cache;
|
||||
use yii\helpers\ArrayHelper;
|
||||
use yii\di\Instance;
|
||||
|
||||
/**
|
||||
* Configs
|
||||
* Used for configure some value. To set config you can use [[\yii\base\Application::$params]]
|
||||
*
|
||||
* ```
|
||||
* return [
|
||||
*
|
||||
* 'mdm.admin.configs' => [
|
||||
* 'db' => 'customDb',
|
||||
* 'menuTable' => '{{%admin_menu}}',
|
||||
* 'cache' => [
|
||||
* 'class' => 'yii\caching\DbCache',
|
||||
* 'db' => ['dsn' => 'sqlite:@runtime/admin-cache.db'],
|
||||
* ],
|
||||
* ]
|
||||
* ];
|
||||
* ```
|
||||
*
|
||||
* or use [[\Yii::$container]]
|
||||
*
|
||||
* ```
|
||||
* Yii::$container->set('mdm\admin\components\Configs',[
|
||||
* 'db' => 'customDb',
|
||||
* 'menuTable' => 'admin_menu',
|
||||
* ]);
|
||||
* ```
|
||||
*
|
||||
* @author Misbahul D Munir <misbahuldmunir@gmail.com>
|
||||
* @since 1.0
|
||||
*/
|
||||
// class Configs extends \yii\base\Object //更新使用7.2以上版本PHP后,不再可使用Object类 By fm453
|
||||
class Configs extends \yii\base\BaseObject
|
||||
{
|
||||
const CACHE_TAG = 'mdm.admin';
|
||||
|
||||
/**
|
||||
* @var Connection Database connection.
|
||||
*/
|
||||
public $db = 'db';
|
||||
/**
|
||||
* @var Cache Cache component.
|
||||
*/
|
||||
public $cache = 'cache';
|
||||
/**
|
||||
* @var integer Cache duration. Default to a hour.
|
||||
*/
|
||||
public $cacheDuration = 3600;
|
||||
/**
|
||||
* @var string Menu table name.
|
||||
*/
|
||||
public $menuTable = '{{%c_menu}}';
|
||||
/**
|
||||
* @var string Menu table name.
|
||||
*/
|
||||
//public $userTable = '{{%user}}';
|
||||
public $userTable = '{{%c_adminer}}';
|
||||
/**
|
||||
* @var integer Default status user signup. 10 mean active.
|
||||
*/
|
||||
public $defaultUserStatus = 10;
|
||||
/**
|
||||
* @var boolean If true then AccessControl only check if route are registered.
|
||||
*/
|
||||
public $onlyRegisteredRoute = false;
|
||||
/**
|
||||
* @var boolean If false then AccessControl will check without Rule.
|
||||
*/
|
||||
public $strict = true;
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
public $options;
|
||||
/**
|
||||
* @var self Instance of self
|
||||
*/
|
||||
private static $_instance;
|
||||
private static $_classes = [
|
||||
'db' => 'yii\db\Connection',
|
||||
'cache' => 'yii\caching\Cache',
|
||||
];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
foreach (self::$_classes as $key => $class) {
|
||||
try {
|
||||
$this->{$key} = empty($this->{$key}) ? null : Instance::ensure($this->{$key}, $class);
|
||||
} catch (\Exception $exc) {
|
||||
$this->{$key} = null;
|
||||
Yii::error($exc->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create instance of self
|
||||
* @return static
|
||||
*/
|
||||
public static function instance()
|
||||
{
|
||||
if (self::$_instance === null) {
|
||||
$type = ArrayHelper::getValue(Yii::$app->params, 'mdm.admin.configs', []);
|
||||
if (is_array($type) && !isset($type['class'])) {
|
||||
$type['class'] = static::className();
|
||||
}
|
||||
|
||||
return self::$_instance = Yii::createObject($type);
|
||||
}
|
||||
|
||||
return self::$_instance;
|
||||
}
|
||||
|
||||
public static function __callStatic($name, $arguments)
|
||||
{
|
||||
$instance = static::instance();
|
||||
if ($instance->hasProperty($name)) {
|
||||
return $instance->$name;
|
||||
} else {
|
||||
if (count($arguments)) {
|
||||
$instance->options[$name] = reset($arguments);
|
||||
} else {
|
||||
return array_key_exists($name, $instance->options) ? $instance->options[$name] : null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Connection
|
||||
*/
|
||||
public static function db()
|
||||
{
|
||||
return static::instance()->db;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Cache
|
||||
*/
|
||||
public static function cache()
|
||||
{
|
||||
return static::instance()->cache;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return integer
|
||||
*/
|
||||
public static function cacheDuration()
|
||||
{
|
||||
return static::instance()->cacheDuration;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public static function menuTable()
|
||||
{
|
||||
return static::instance()->menuTable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public static function userTable()
|
||||
{
|
||||
return static::instance()->userTable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public static function defaultUserStatus()
|
||||
{
|
||||
return static::instance()->defaultUserStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return boolean
|
||||
*/
|
||||
public static function onlyRegisteredRoute()
|
||||
{
|
||||
return static::instance()->onlyRegisteredRoute;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return boolean
|
||||
*/
|
||||
public static function strict()
|
||||
{
|
||||
return static::instance()->strict;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
namespace mdm\admin\components;
|
||||
|
||||
/**
|
||||
* DbManager represents an authorization manager that stores authorization information in database.
|
||||
*
|
||||
* The database connection is specified by [[$db]]. The database schema could be initialized by applying migration:
|
||||
*
|
||||
* ```
|
||||
* yii migrate --migrationPath=@yii/rbac/migrations/
|
||||
* ```
|
||||
*
|
||||
* If you don't want to use migration and need SQL instead, files for all databases are in migrations directory.
|
||||
*
|
||||
* You may change the names of the three tables used to store the authorization data by setting [[\yii\rbac\DbManager::$itemTable]],
|
||||
* [[\yii\rbac\DbManager::$itemChildTable]] and [[\yii\rbac\DbManager::$assignmentTable]].
|
||||
*
|
||||
* @author Misbahul D Munir <misbahuldmunir@gmail.com>
|
||||
* @since 1.0
|
||||
*/
|
||||
class DbManager extends \yii\rbac\DbManager
|
||||
{
|
||||
/**
|
||||
* Memory cache of assignments
|
||||
* @var array
|
||||
*/
|
||||
private $_assignments = [];
|
||||
private $_childrenList;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getAssignments($userId)
|
||||
{
|
||||
if (!isset($this->_assignments[$userId])) {
|
||||
$this->_assignments[$userId] = parent::getAssignments($userId);
|
||||
}
|
||||
return $this->_assignments[$userId];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected function getChildrenList()
|
||||
{
|
||||
if ($this->_childrenList === null) {
|
||||
$this->_childrenList = parent::getChildrenList();
|
||||
}
|
||||
return $this->_childrenList;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace mdm\admin\components;
|
||||
|
||||
use yii\rbac\Rule;
|
||||
|
||||
/**
|
||||
* Description of GuestRule
|
||||
*
|
||||
* @author Misbahul D Munir <misbahuldmunir@gmail.com>
|
||||
* @since 2.5
|
||||
*/
|
||||
class GuestRule extends Rule
|
||||
{
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public $name = 'guest_rule';
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function execute($user, $item, $params)
|
||||
{
|
||||
return $user->getIsGuest();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,237 @@
|
||||
<?php
|
||||
|
||||
namespace mdm\admin\components;
|
||||
|
||||
use Yii;
|
||||
use yii\web\User;
|
||||
use yii\helpers\ArrayHelper;
|
||||
use yii\caching\TagDependency;
|
||||
|
||||
/**
|
||||
* Description of Helper
|
||||
*
|
||||
* @author Misbahul D Munir <misbahuldmunir@gmail.com>
|
||||
* @since 2.3
|
||||
*/
|
||||
class Helper
|
||||
{
|
||||
private static $_userRoutes = [];
|
||||
private static $_defaultRoutes;
|
||||
private static $_routes;
|
||||
|
||||
public static function getRegisteredRoutes()
|
||||
{
|
||||
if (self::$_routes === null) {
|
||||
self::$_routes = [];
|
||||
$manager = Yii::$app->getAuthManager();
|
||||
foreach ($manager->getPermissions() as $item) {
|
||||
if ($item->name[0] === '/') {
|
||||
self::$_routes[$item->name] = $item->name;
|
||||
}
|
||||
}
|
||||
}
|
||||
return self::$_routes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get assigned routes by default roles
|
||||
* @return array
|
||||
*/
|
||||
protected static function getDefaultRoutes()
|
||||
{
|
||||
if (self::$_defaultRoutes === null) {
|
||||
$manager = Yii::$app->getAuthManager();
|
||||
$roles = $manager->defaultRoles;
|
||||
$cache = Configs::cache();
|
||||
if ($cache && ($routes = $cache->get($roles)) !== false) {
|
||||
self::$_defaultRoutes = $routes;
|
||||
} else {
|
||||
$permissions = self::$_defaultRoutes = [];
|
||||
foreach ($roles as $role) {
|
||||
$permissions = array_merge($permissions, $manager->getPermissionsByRole($role));
|
||||
}
|
||||
foreach ($permissions as $item) {
|
||||
if ($item->name[0] === '/') {
|
||||
self::$_defaultRoutes[$item->name] = true;
|
||||
}
|
||||
}
|
||||
if ($cache) {
|
||||
$cache->set($roles, self::$_defaultRoutes, Configs::cacheDuration(), new TagDependency([
|
||||
'tags' => Configs::CACHE_TAG
|
||||
]));
|
||||
}
|
||||
}
|
||||
}
|
||||
return self::$_defaultRoutes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get assigned routes of user.
|
||||
* @param integer $userId
|
||||
* @return array
|
||||
*/
|
||||
public static function getRoutesByUser($userId)
|
||||
{
|
||||
if (!isset(self::$_userRoutes[$userId])) {
|
||||
$cache = Configs::cache();
|
||||
if ($cache && ($routes = $cache->get([__METHOD__, $userId])) !== false) {
|
||||
self::$_userRoutes[$userId] = $routes;
|
||||
} else {
|
||||
$routes = static::getDefaultRoutes();
|
||||
$manager = Yii::$app->getAuthManager();
|
||||
foreach ($manager->getPermissionsByUser($userId) as $item) {
|
||||
if ($item->name[0] === '/') {
|
||||
$routes[$item->name] = true;
|
||||
}
|
||||
}
|
||||
self::$_userRoutes[$userId] = $routes;
|
||||
if ($cache) {
|
||||
$cache->set([__METHOD__, $userId], $routes, Configs::cacheDuration(), new TagDependency([
|
||||
'tags' => Configs::CACHE_TAG
|
||||
]));
|
||||
}
|
||||
}
|
||||
}
|
||||
return self::$_userRoutes[$userId];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check access route for user.
|
||||
* @param string|array $route
|
||||
* @param integer|User $user
|
||||
* @return boolean
|
||||
*/
|
||||
public static function checkRoute($route, $params = [], $user = null)
|
||||
{
|
||||
$config = Configs::instance();
|
||||
$r = static::normalizeRoute($route);
|
||||
if ($config->onlyRegisteredRoute && !isset(static::getRegisteredRoutes()[$r])) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($user === null) {
|
||||
$user = Yii::$app->getUser();
|
||||
}
|
||||
$userId = $user instanceof User ? $user->getId() : $user;
|
||||
|
||||
if ($config->strict) {
|
||||
if ($user->can($r, $params)) {
|
||||
return true;
|
||||
}
|
||||
while (($pos = strrpos($r, '/')) > 0) {
|
||||
$r = substr($r, 0, $pos);
|
||||
if ($user->can($r . '/*', $params)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return $user->can('/*', $params);
|
||||
} else {
|
||||
$routes = static::getRoutesByUser($userId);
|
||||
if (isset($routes[$r])) {
|
||||
return true;
|
||||
}
|
||||
while (($pos = strrpos($r, '/')) > 0) {
|
||||
$r = substr($r, 0, $pos);
|
||||
if (isset($routes[$r . '/*'])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return isset($routes['/*']);
|
||||
}
|
||||
}
|
||||
|
||||
protected static function normalizeRoute($route)
|
||||
{
|
||||
if ($route === '') {
|
||||
return '/' . Yii::$app->controller->getRoute();
|
||||
} elseif (strncmp($route, '/', 1) === 0) {
|
||||
return $route;
|
||||
} elseif (strpos($route, '/') === false) {
|
||||
return '/' . Yii::$app->controller->getUniqueId() . '/' . $route;
|
||||
} elseif (($mid = Yii::$app->controller->module->getUniqueId()) !== '') {
|
||||
return '/' . $mid . '/' . $route;
|
||||
}
|
||||
return '/' . $route;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter menu items
|
||||
* @param array $items
|
||||
* @param integer|User $user
|
||||
*/
|
||||
public static function filter($items, $user = null)
|
||||
{
|
||||
if ($user === null) {
|
||||
$user = Yii::$app->getUser();
|
||||
}
|
||||
return static::filterRecursive($items, $user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter menu recursive
|
||||
* @param array $items
|
||||
* @param integer|User $user
|
||||
* @return array
|
||||
*/
|
||||
protected static function filterRecursive($items, $user)
|
||||
{
|
||||
$result = [];
|
||||
foreach ($items as $i => $item) {
|
||||
$url = ArrayHelper::getValue($item, 'url', '#');
|
||||
$allow = is_array($url) ? static::checkRoute($url[0], array_slice($url, 1), $user) : true;
|
||||
|
||||
if (isset($item['items']) && is_array($item['items'])) {
|
||||
$subItems = self::filterRecursive($item['items'], $user);
|
||||
if (count($subItems)) {
|
||||
$allow = true;
|
||||
}
|
||||
$item['items'] = $subItems;
|
||||
}
|
||||
if ($allow) {
|
||||
$result[$i] = $item;
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter action column button. Use with [[yii\grid\GridView]]
|
||||
* ```php
|
||||
* 'columns' => [
|
||||
* ...
|
||||
* [
|
||||
* 'class' => 'yii\grid\ActionColumn',
|
||||
* 'template' => Helper::filterActionColumn(['view','update','activate'])
|
||||
* ]
|
||||
* ],
|
||||
* ```
|
||||
* @param array|string $buttons
|
||||
* @param integer|User $user
|
||||
* @return string
|
||||
*/
|
||||
public static function filterActionColumn($buttons = [], $user = null)
|
||||
{
|
||||
if (is_array($buttons)) {
|
||||
$result = [];
|
||||
foreach ($buttons as $button) {
|
||||
if (static::checkRoute($button, [], $user)) {
|
||||
$result[] = "{{$button}}";
|
||||
}
|
||||
}
|
||||
return implode(' ', $result);
|
||||
}
|
||||
return preg_replace_callback('/\\{([\w\-\/]+)\\}/', function ($matches) use ($user) {
|
||||
return static::checkRoute($matches[1], [], $user) ? "{{$matches[1]}}" : '';
|
||||
}, $buttons);
|
||||
}
|
||||
|
||||
/**
|
||||
* Use to invalidate cache.
|
||||
*/
|
||||
public static function invalidate()
|
||||
{
|
||||
if (Configs::cache() !== null) {
|
||||
TagDependency::invalidate(Configs::cache(), Configs::CACHE_TAG);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,190 @@
|
||||
<?php
|
||||
|
||||
namespace mdm\admin\components;
|
||||
|
||||
use Yii;
|
||||
use mdm\admin\models\AuthItem;
|
||||
use mdm\admin\models\searchs\AuthItem as AuthItemSearch;
|
||||
use yii\web\Controller;
|
||||
use yii\web\NotFoundHttpException;
|
||||
use yii\base\NotSupportedException;
|
||||
use yii\filters\VerbFilter;
|
||||
use yii\rbac\Item;
|
||||
|
||||
/**
|
||||
* AuthItemController implements the CRUD actions for AuthItem model.
|
||||
*
|
||||
* @property integer $type
|
||||
* @property array $labels
|
||||
*
|
||||
* @author Misbahul D Munir <misbahuldmunir@gmail.com>
|
||||
* @since 1.0
|
||||
*/
|
||||
class ItemController extends Controller
|
||||
{
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function behaviors()
|
||||
{
|
||||
return [
|
||||
'verbs' => [
|
||||
'class' => VerbFilter::className(),
|
||||
'actions' => [
|
||||
'delete' => ['post'],
|
||||
'assign' => ['post'],
|
||||
'remove' => ['post'],
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Lists all AuthItem models.
|
||||
* @return mixed
|
||||
*/
|
||||
public function actionIndex()
|
||||
{
|
||||
$searchModel = new AuthItemSearch(['type' => $this->type]);
|
||||
$dataProvider = $searchModel->search(Yii::$app->request->getQueryParams());
|
||||
|
||||
return $this->render('index', [
|
||||
'dataProvider' => $dataProvider,
|
||||
'searchModel' => $searchModel,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays a single AuthItem model.
|
||||
* @param string $id
|
||||
* @return mixed
|
||||
*/
|
||||
public function actionView($id)
|
||||
{
|
||||
$model = $this->findModel($id);
|
||||
|
||||
return $this->render('view', ['model' => $model]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new AuthItem model.
|
||||
* If creation is successful, the browser will be redirected to the 'view' page.
|
||||
* @return mixed
|
||||
*/
|
||||
public function actionCreate()
|
||||
{
|
||||
$model = new AuthItem(null);
|
||||
$model->type = $this->type;
|
||||
if ($model->load(Yii::$app->getRequest()->post()) && $model->save()) {
|
||||
return $this->redirect(['view', 'id' => $model->name]);
|
||||
} else {
|
||||
return $this->render('create', ['model' => $model]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates an existing AuthItem model.
|
||||
* If update is successful, the browser will be redirected to the 'view' page.
|
||||
* @param string $id
|
||||
* @return mixed
|
||||
*/
|
||||
public function actionUpdate($id)
|
||||
{
|
||||
$model = $this->findModel($id);
|
||||
if ($model->load(Yii::$app->getRequest()->post()) && $model->save()) {
|
||||
return $this->redirect(['view', 'id' => $model->name]);
|
||||
}
|
||||
|
||||
return $this->render('update', ['model' => $model]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes an existing AuthItem model.
|
||||
* If deletion is successful, the browser will be redirected to the 'index' page.
|
||||
* @param string $id
|
||||
* @return mixed
|
||||
*/
|
||||
public function actionDelete($id)
|
||||
{
|
||||
$model = $this->findModel($id);
|
||||
Yii::$app->getAuthManager()->remove($model->item);
|
||||
Helper::invalidate();
|
||||
|
||||
return $this->redirect(['index']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign items
|
||||
* @param string $id
|
||||
* @return array
|
||||
*/
|
||||
public function actionAssign($id)
|
||||
{
|
||||
$items = Yii::$app->getRequest()->post('items', []);
|
||||
$model = $this->findModel($id);
|
||||
$success = $model->addChildren($items);
|
||||
Yii::$app->getResponse()->format = 'json';
|
||||
|
||||
return array_merge($model->getItems(), ['success' => $success]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign or remove items
|
||||
* @param string $id
|
||||
* @return array
|
||||
*/
|
||||
public function actionRemove($id)
|
||||
{
|
||||
$items = Yii::$app->getRequest()->post('items', []);
|
||||
$model = $this->findModel($id);
|
||||
$success = $model->removeChildren($items);
|
||||
Yii::$app->getResponse()->format = 'json';
|
||||
|
||||
return array_merge($model->getItems(), ['success' => $success]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getViewPath()
|
||||
{
|
||||
return $this->module->getViewPath() . DIRECTORY_SEPARATOR . 'item';
|
||||
}
|
||||
|
||||
/**
|
||||
* Label use in view
|
||||
* @throws NotSupportedException
|
||||
*/
|
||||
public function labels()
|
||||
{
|
||||
throw new NotSupportedException(get_class($this) . ' does not support labels().');
|
||||
}
|
||||
|
||||
/**
|
||||
* Type of Auth Item.
|
||||
* @return integer
|
||||
*/
|
||||
public function getType()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the AuthItem model based on its primary key value.
|
||||
* If the model is not found, a 404 HTTP exception will be thrown.
|
||||
* @param string $id
|
||||
* @return AuthItem the loaded model
|
||||
* @throws NotFoundHttpException if the model cannot be found
|
||||
*/
|
||||
protected function findModel($id)
|
||||
{
|
||||
$auth = Yii::$app->getAuthManager();
|
||||
$item = $this->type === Item::TYPE_ROLE ? $auth->getRole($id) : $auth->getPermission($id);
|
||||
if ($item) {
|
||||
return new AuthItem($item);
|
||||
} else {
|
||||
throw new NotFoundHttpException('The requested page does not exist.');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,222 @@
|
||||
<?php
|
||||
|
||||
namespace mdm\admin\components;
|
||||
|
||||
use Yii;
|
||||
use yii\caching\TagDependency;
|
||||
use mdm\admin\models\Menu;
|
||||
|
||||
/**
|
||||
* MenuHelper used to generate menu depend of user role.
|
||||
* Usage
|
||||
*
|
||||
* ```
|
||||
* use mdm\admin\components\MenuHelper;
|
||||
* use yii\bootstrap\Nav;
|
||||
*
|
||||
* echo Nav::widget([
|
||||
* 'items' => MenuHelper::getAssignedMenu(Yii::$app->user->id)
|
||||
* ]);
|
||||
* ```
|
||||
*
|
||||
* To reformat returned, provide callback to method.
|
||||
*
|
||||
* ```
|
||||
* $callback = function ($menu) {
|
||||
* $data = eval($menu['data']);
|
||||
* return [
|
||||
* 'label' => $menu['name'],
|
||||
* 'url' => [$menu['route']],
|
||||
* 'options' => $data,
|
||||
* 'items' => $menu['children']
|
||||
* ]
|
||||
* ]
|
||||
* }
|
||||
*
|
||||
* $items = MenuHelper::getAssignedMenu(Yii::$app->user->id, null, $callback);
|
||||
* ```
|
||||
*
|
||||
* @author Misbahul D Munir <misbahuldmunir@gmail.com>
|
||||
* @since 1.0
|
||||
*/
|
||||
class MenuHelper
|
||||
{
|
||||
/**
|
||||
* Use to get assigned menu of user.
|
||||
* @param mixed $userId
|
||||
* @param integer $root
|
||||
* @param \Closure $callback use to reformat output.
|
||||
* callback should have format like
|
||||
*
|
||||
* ```
|
||||
* function ($menu) {
|
||||
* return [
|
||||
* 'label' => $menu['name'],
|
||||
* 'url' => [$menu['route']],
|
||||
* 'options' => $data,
|
||||
* 'items' => $menu['children']
|
||||
* ]
|
||||
* ]
|
||||
* }
|
||||
* ```
|
||||
* @param boolean $refresh
|
||||
* @return array
|
||||
*/
|
||||
public static function getAssignedMenu($userId, $root = null, $callback = null, $refresh = false)
|
||||
{
|
||||
$config = Configs::instance();
|
||||
|
||||
/* @var $manager \yii\rbac\BaseManager */
|
||||
$manager = Yii::$app->getAuthManager();
|
||||
$menus = Menu::find()->asArray()->indexBy('id')->all();
|
||||
$key = [__METHOD__, $userId, $manager->defaultRoles];
|
||||
$cache = $config->cache;
|
||||
|
||||
if ($refresh || $cache === null || ($assigned = $cache->get($key)) === false) {
|
||||
$routes = $filter1 = $filter2 = [];
|
||||
if ($userId !== null) {
|
||||
foreach ($manager->getPermissionsByUser($userId) as $name => $value) {
|
||||
if ($name[0] === '/') {
|
||||
if (substr($name, -2) === '/*') {
|
||||
$name = substr($name, 0, -1);
|
||||
}
|
||||
$routes[] = $name;
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach ($manager->defaultRoles as $role) {
|
||||
foreach ($manager->getPermissionsByRole($role) as $name => $value) {
|
||||
if ($name[0] === '/') {
|
||||
if (substr($name, -2) === '/*') {
|
||||
$name = substr($name, 0, -1);
|
||||
}
|
||||
$routes[] = $name;
|
||||
}
|
||||
}
|
||||
}
|
||||
$routes = array_unique($routes);
|
||||
sort($routes);
|
||||
$prefix = '\\';
|
||||
foreach ($routes as $route) {
|
||||
if (strpos($route, $prefix) !== 0) {
|
||||
if (substr($route, -1) === '/') {
|
||||
$prefix = $route;
|
||||
$filter1[] = $route . '%';
|
||||
} else {
|
||||
$filter2[] = $route;
|
||||
}
|
||||
}
|
||||
}
|
||||
$assigned = [];
|
||||
$query = Menu::find()->select(['id'])->asArray();
|
||||
if (count($filter2)) {
|
||||
$assigned = $query->where(['route' => $filter2])->column();
|
||||
}
|
||||
if (count($filter1)) {
|
||||
$query->where('route like :filter');
|
||||
foreach ($filter1 as $filter) {
|
||||
$assigned = array_merge($assigned, $query->params([':filter' => $filter])->column());
|
||||
}
|
||||
}
|
||||
$assigned = static::requiredParent($assigned, $menus);
|
||||
if ($cache !== null) {
|
||||
$cache->set($key, $assigned, $config->cacheDuration, new TagDependency([
|
||||
'tags' => Configs::CACHE_TAG
|
||||
]));
|
||||
}
|
||||
}
|
||||
|
||||
$key = [__METHOD__, $assigned, $root];
|
||||
if ($refresh || $callback !== null || $cache === null || (($result = $cache->get($key)) === false)) {
|
||||
$result = static::normalizeMenu($assigned, $menus, $callback, $root);
|
||||
if ($cache !== null && $callback === null) {
|
||||
$cache->set($key, $result, $config->cacheDuration, new TagDependency([
|
||||
'tags' => Configs::CACHE_TAG
|
||||
]));
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure all item menu has parent.
|
||||
* @param array $assigned
|
||||
* @param array $menus
|
||||
* @return array
|
||||
*/
|
||||
private static function requiredParent($assigned, &$menus)
|
||||
{
|
||||
$l = count($assigned);
|
||||
for ($i = 0; $i < $l; $i++) {
|
||||
$id = $assigned[$i];
|
||||
$parent_id = $menus[$id]['parent'];
|
||||
if ($parent_id !== null && !in_array($parent_id, $assigned)) {
|
||||
$assigned[$l++] = $parent_id;
|
||||
}
|
||||
}
|
||||
|
||||
return $assigned;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse route
|
||||
* @param string $route
|
||||
* @return mixed
|
||||
*/
|
||||
public static function parseRoute($route)
|
||||
{
|
||||
if (!empty($route)) {
|
||||
$url = [];
|
||||
$r = explode('&', $route);
|
||||
$url[0] = $r[0];
|
||||
unset($r[0]);
|
||||
foreach ($r as $part) {
|
||||
$part = explode('=', $part);
|
||||
$url[$part[0]] = isset($part[1]) ? $part[1] : '';
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
return '#';
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize menu
|
||||
* @param array $assigned
|
||||
* @param array $menus
|
||||
* @param Closure $callback
|
||||
* @param integer $parent
|
||||
* @return array
|
||||
*/
|
||||
private static function normalizeMenu(&$assigned, &$menus, $callback, $parent = null)
|
||||
{
|
||||
$result = [];
|
||||
$order = [];
|
||||
foreach ($assigned as $id) {
|
||||
$menu = $menus[$id];
|
||||
if ($menu['parent'] == $parent) {
|
||||
$menu['children'] = static::normalizeMenu($assigned, $menus, $callback, $id);
|
||||
if ($callback !== null) {
|
||||
$item = call_user_func($callback, $menu);
|
||||
} else {
|
||||
$item = [
|
||||
'label' => $menu['name'],
|
||||
'url' => static::parseRoute($menu['route']),
|
||||
];
|
||||
if ($menu['children'] != []) {
|
||||
$item['items'] = $menu['children'];
|
||||
}
|
||||
}
|
||||
$result[] = $item;
|
||||
$order[] = $menu['order'];
|
||||
}
|
||||
}
|
||||
if ($result != []) {
|
||||
array_multisort($order, $result);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace mdm\admin\components;
|
||||
|
||||
use Yii;
|
||||
use yii\rbac\Rule;
|
||||
|
||||
/**
|
||||
* RouteRule Rule for check route with extra params.
|
||||
*
|
||||
* @author Misbahul D Munir <misbahuldmunir@gmail.com>
|
||||
* @since 1.0
|
||||
*/
|
||||
class RouteRule extends Rule
|
||||
{
|
||||
const RULE_NAME = 'route_rule';
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public $name = self::RULE_NAME;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function execute($user, $item, $params)
|
||||
{
|
||||
$routeParams = isset($item->data['params']) ? $item->data['params'] : [];
|
||||
foreach ($routeParams as $key => $value) {
|
||||
if (!array_key_exists($key, $params) || $params[$key] != $value) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"name": "mdmsoft/yii2-admin",
|
||||
"description": "RBAC Auth manager for Yii2 ",
|
||||
"keywords": ["yii", "admin", "auth", "rbac"],
|
||||
"type": "yii2-extension",
|
||||
"license": "BSD-3-Clause",
|
||||
"support": {
|
||||
"issues": "https://github.com/mdmsoft/yii2-admin/issues",
|
||||
"source": "https://github.com/mdmsoft/yii2-admin"
|
||||
},
|
||||
"authors": [
|
||||
{
|
||||
"name": "Misbahul Munir",
|
||||
"email": "misbahuldmunir@gmail.com"
|
||||
}
|
||||
],
|
||||
"minimum-stability": "dev",
|
||||
"require": {
|
||||
"yiisoft/yii2": "~2.0.7"
|
||||
},
|
||||
"require-dev": {
|
||||
"yiisoft/yii2-codeception": "~2.0"
|
||||
},
|
||||
"suggest": {
|
||||
"yiisoft/yii2-bootstrap": "Used when using layout 'left-menu', 'right-menu' or 'top-menu'"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"mdm\\admin\\": ""
|
||||
}
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-1.0.master": "1.0.x-dev",
|
||||
"dev-master": "2.x-dev"
|
||||
},
|
||||
"asset-installer-paths": {
|
||||
"npm-asset-library": "vendor/npm",
|
||||
"bower-asset-library": "vendor/bower"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"name": "mdmsoft/yii2-admin",
|
||||
"description": "RBAC Auth manager for Yii2 ",
|
||||
"keywords": ["yii", "admin", "auth", "rbac"],
|
||||
"type": "yii2-extension",
|
||||
"license": "BSD-3-Clause",
|
||||
"support": {
|
||||
"issues": "https://github.com/mdmsoft/yii2-admin/issues",
|
||||
"source": "https://github.com/mdmsoft/yii2-admin"
|
||||
},
|
||||
"authors": [
|
||||
{
|
||||
"name": "Misbahul Munir",
|
||||
"email": "misbahuldmunir@gmail.com"
|
||||
}
|
||||
],
|
||||
"minimum-stability": "dev",
|
||||
"require": {
|
||||
"yiisoft/yii2": "~2.0.7"
|
||||
},
|
||||
"require-dev": {
|
||||
"yiisoft/yii2-codeception": "~2.0"
|
||||
},
|
||||
"suggest": {
|
||||
"yiisoft/yii2-bootstrap": "Used when using layout 'left-menu', 'right-menu' or 'top-menu'"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"mdm\\admin\\": ""
|
||||
}
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-1.0.master": "1.0.x-dev",
|
||||
"dev-master": "2.x-dev"
|
||||
},
|
||||
"asset-installer-paths": {
|
||||
"npm-asset-library": "vendor/npm",
|
||||
"bower-asset-library": "vendor/bower"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,449 @@
|
||||
{
|
||||
"_readme": [
|
||||
"This file locks the dependencies of your project to a known state",
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"hash": "27f234f381401d13247052003f84ee94",
|
||||
"content-hash": "bbf56943dae6c15ad0d26061df3dec4f",
|
||||
"packages": [
|
||||
{
|
||||
"name": "bower-asset/jquery",
|
||||
"version": "2.2.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/jquery/jquery-dist.git",
|
||||
"reference": "788eaba2f83e7b7445c7a83a50c81c0704423874"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/jquery/jquery-dist/zipball/788eaba2f83e7b7445c7a83a50c81c0704423874",
|
||||
"reference": "788eaba2f83e7b7445c7a83a50c81c0704423874",
|
||||
"shasum": ""
|
||||
},
|
||||
"type": "bower-asset-library",
|
||||
"extra": {
|
||||
"bower-asset-main": "dist/jquery.js",
|
||||
"bower-asset-ignore": [
|
||||
"package.json"
|
||||
]
|
||||
},
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"keywords": [
|
||||
"browser",
|
||||
"javascript",
|
||||
"jquery",
|
||||
"library"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "bower-asset/jquery.inputmask",
|
||||
"version": "3.2.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/RobinHerbots/jquery.inputmask.git",
|
||||
"reference": "5a72c563b502b8e05958a524cdfffafe9987be38"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/RobinHerbots/jquery.inputmask/zipball/5a72c563b502b8e05958a524cdfffafe9987be38",
|
||||
"reference": "5a72c563b502b8e05958a524cdfffafe9987be38",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"bower-asset/jquery": ">=1.7"
|
||||
},
|
||||
"type": "bower-asset-library",
|
||||
"extra": {
|
||||
"bower-asset-main": [
|
||||
"./dist/inputmask/inputmask.js"
|
||||
],
|
||||
"bower-asset-ignore": [
|
||||
"**/*",
|
||||
"!dist/*",
|
||||
"!dist/inputmask/*",
|
||||
"!dist/min/*",
|
||||
"!dist/min/inputmask/*",
|
||||
"!extra/bindings/*",
|
||||
"!extra/dependencyLibs/*",
|
||||
"!extra/phone-codes/*"
|
||||
]
|
||||
},
|
||||
"license": [
|
||||
"http://opensource.org/licenses/mit-license.php"
|
||||
],
|
||||
"description": "jquery.inputmask is a jquery plugin which create an input mask.",
|
||||
"keywords": [
|
||||
"form",
|
||||
"input",
|
||||
"inputmask",
|
||||
"jquery",
|
||||
"mask",
|
||||
"plugins"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "bower-asset/punycode",
|
||||
"version": "v1.3.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/bestiejs/punycode.js.git",
|
||||
"reference": "38c8d3131a82567bfef18da09f7f4db68c84f8a3"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/bestiejs/punycode.js/zipball/38c8d3131a82567bfef18da09f7f4db68c84f8a3",
|
||||
"reference": "38c8d3131a82567bfef18da09f7f4db68c84f8a3",
|
||||
"shasum": ""
|
||||
},
|
||||
"type": "bower-asset-library",
|
||||
"extra": {
|
||||
"bower-asset-main": "punycode.js",
|
||||
"bower-asset-ignore": [
|
||||
"coverage",
|
||||
"tests",
|
||||
".*",
|
||||
"component.json",
|
||||
"Gruntfile.js",
|
||||
"node_modules",
|
||||
"package.json"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "bower-asset/yii2-pjax",
|
||||
"version": "v2.0.6",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/yiisoft/jquery-pjax.git",
|
||||
"reference": "60728da6ade5879e807a49ce59ef9a72039b8978"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/yiisoft/jquery-pjax/zipball/60728da6ade5879e807a49ce59ef9a72039b8978",
|
||||
"reference": "60728da6ade5879e807a49ce59ef9a72039b8978",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"bower-asset/jquery": ">=1.8"
|
||||
},
|
||||
"type": "bower-asset-library",
|
||||
"extra": {
|
||||
"bower-asset-main": "./jquery.pjax.js",
|
||||
"bower-asset-ignore": [
|
||||
".travis.yml",
|
||||
"Gemfile",
|
||||
"Gemfile.lock",
|
||||
"CONTRIBUTING.md",
|
||||
"vendor/",
|
||||
"script/",
|
||||
"test/"
|
||||
]
|
||||
},
|
||||
"license": [
|
||||
"MIT"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "cebe/markdown",
|
||||
"version": "dev-master",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/cebe/markdown.git",
|
||||
"reference": "e4499350d8a94c4c693a7e784295eff7a717ae67"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/cebe/markdown/zipball/e4499350d8a94c4c693a7e784295eff7a717ae67",
|
||||
"reference": "e4499350d8a94c4c693a7e784295eff7a717ae67",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"lib-pcre": "*",
|
||||
"php": ">=5.4.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"cebe/indent": "*",
|
||||
"facebook/xhprof": "*@dev",
|
||||
"phpunit/phpunit": "4.1.*"
|
||||
},
|
||||
"bin": [
|
||||
"bin/markdown"
|
||||
],
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.1.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"cebe\\markdown\\": ""
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Carsten Brandt",
|
||||
"email": "mail@cebe.cc",
|
||||
"homepage": "http://cebe.cc/",
|
||||
"role": "Creator"
|
||||
}
|
||||
],
|
||||
"description": "A super fast, highly extensible markdown parser for PHP",
|
||||
"homepage": "https://github.com/cebe/markdown#readme",
|
||||
"keywords": [
|
||||
"extensible",
|
||||
"fast",
|
||||
"gfm",
|
||||
"markdown",
|
||||
"markdown-extra"
|
||||
],
|
||||
"time": "2016-02-09 22:09:46"
|
||||
},
|
||||
{
|
||||
"name": "ezyang/htmlpurifier",
|
||||
"version": "v4.7.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/ezyang/htmlpurifier.git",
|
||||
"reference": "ae1828d955112356f7677c465f94f7deb7d27a40"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/ae1828d955112356f7677c465f94f7deb7d27a40",
|
||||
"reference": "ae1828d955112356f7677c465f94f7deb7d27a40",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.2"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"HTMLPurifier": "library/"
|
||||
},
|
||||
"files": [
|
||||
"library/HTMLPurifier.composer.php"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"LGPL"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Edward Z. Yang",
|
||||
"email": "admin@htmlpurifier.org",
|
||||
"homepage": "http://ezyang.com"
|
||||
}
|
||||
],
|
||||
"description": "Standards compliant HTML filter written in PHP",
|
||||
"homepage": "http://htmlpurifier.org/",
|
||||
"keywords": [
|
||||
"html"
|
||||
],
|
||||
"time": "2015-08-05 01:03:42"
|
||||
},
|
||||
{
|
||||
"name": "yiisoft/yii2",
|
||||
"version": "dev-master",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/yiisoft/yii2-framework.git",
|
||||
"reference": "1c42b9ab26dcf7f9bbc80e29ad2f0cab9329116c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/yiisoft/yii2-framework/zipball/1c42b9ab26dcf7f9bbc80e29ad2f0cab9329116c",
|
||||
"reference": "1c42b9ab26dcf7f9bbc80e29ad2f0cab9329116c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"bower-asset/jquery": "2.2.*@stable | 2.1.*@stable | 1.11.*@stable",
|
||||
"bower-asset/jquery.inputmask": "~3.2.2",
|
||||
"bower-asset/punycode": "1.3.*",
|
||||
"bower-asset/yii2-pjax": "~2.0.1",
|
||||
"cebe/markdown": "~1.0.0 | ~1.1.0",
|
||||
"ext-ctype": "*",
|
||||
"ext-mbstring": "*",
|
||||
"ezyang/htmlpurifier": "~4.6",
|
||||
"lib-pcre": "*",
|
||||
"php": ">=5.4.0",
|
||||
"yiisoft/yii2-composer": "~2.0.4"
|
||||
},
|
||||
"bin": [
|
||||
"yii"
|
||||
],
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.0.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"yii\\": ""
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Qiang Xue",
|
||||
"email": "qiang.xue@gmail.com",
|
||||
"homepage": "http://www.yiiframework.com/",
|
||||
"role": "Founder and project lead"
|
||||
},
|
||||
{
|
||||
"name": "Alexander Makarov",
|
||||
"email": "sam@rmcreative.ru",
|
||||
"homepage": "http://rmcreative.ru/",
|
||||
"role": "Core framework development"
|
||||
},
|
||||
{
|
||||
"name": "Maurizio Domba",
|
||||
"homepage": "http://mdomba.info/",
|
||||
"role": "Core framework development"
|
||||
},
|
||||
{
|
||||
"name": "Carsten Brandt",
|
||||
"email": "mail@cebe.cc",
|
||||
"homepage": "http://cebe.cc/",
|
||||
"role": "Core framework development"
|
||||
},
|
||||
{
|
||||
"name": "Timur Ruziev",
|
||||
"email": "resurtm@gmail.com",
|
||||
"homepage": "http://resurtm.com/",
|
||||
"role": "Core framework development"
|
||||
},
|
||||
{
|
||||
"name": "Paul Klimov",
|
||||
"email": "klimov.paul@gmail.com",
|
||||
"role": "Core framework development"
|
||||
},
|
||||
{
|
||||
"name": "Dmitry Naumenko",
|
||||
"email": "d.naumenko.a@gmail.com",
|
||||
"role": "Core framework development"
|
||||
}
|
||||
],
|
||||
"description": "Yii PHP Framework Version 2",
|
||||
"homepage": "http://www.yiiframework.com/",
|
||||
"keywords": [
|
||||
"framework",
|
||||
"yii2"
|
||||
],
|
||||
"time": "2016-03-13 17:22:32"
|
||||
},
|
||||
{
|
||||
"name": "yiisoft/yii2-composer",
|
||||
"version": "dev-master",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/yiisoft/yii2-composer.git",
|
||||
"reference": "d33d1046a5951f2f7823fe343f28ddc58b3421a4"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/yiisoft/yii2-composer/zipball/d33d1046a5951f2f7823fe343f28ddc58b3421a4",
|
||||
"reference": "d33d1046a5951f2f7823fe343f28ddc58b3421a4",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"composer-plugin-api": "^1.0"
|
||||
},
|
||||
"type": "composer-plugin",
|
||||
"extra": {
|
||||
"class": "yii\\composer\\Plugin",
|
||||
"branch-alias": {
|
||||
"dev-master": "2.0.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"yii\\composer\\": ""
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Qiang Xue",
|
||||
"email": "qiang.xue@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "The composer plugin for Yii extension installer",
|
||||
"keywords": [
|
||||
"composer",
|
||||
"extension installer",
|
||||
"yii2"
|
||||
],
|
||||
"time": "2016-02-06 01:03:32"
|
||||
}
|
||||
],
|
||||
"packages-dev": [
|
||||
{
|
||||
"name": "yiisoft/yii2-codeception",
|
||||
"version": "dev-master",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/yiisoft/yii2-codeception.git",
|
||||
"reference": "ee239c244fd011f11c8827f97ebe7600d03f1841"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/yiisoft/yii2-codeception/zipball/ee239c244fd011f11c8827f97ebe7600d03f1841",
|
||||
"reference": "ee239c244fd011f11c8827f97ebe7600d03f1841",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"yiisoft/yii2": ">=2.0.4"
|
||||
},
|
||||
"type": "yii2-extension",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.0.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"yii\\codeception\\": ""
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Mark Jebri",
|
||||
"email": "mark.github@yandex.ru"
|
||||
}
|
||||
],
|
||||
"description": "The Codeception integration for the Yii framework",
|
||||
"keywords": [
|
||||
"codeception",
|
||||
"yii2"
|
||||
],
|
||||
"time": "2015-11-20 08:52:21"
|
||||
}
|
||||
],
|
||||
"aliases": [],
|
||||
"minimum-stability": "dev",
|
||||
"stability-flags": [],
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": [],
|
||||
"platform-dev": []
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
<?php
|
||||
|
||||
namespace mdm\admin\controllers;
|
||||
|
||||
use Yii;
|
||||
use mdm\admin\models\Assignment;
|
||||
use mdm\admin\models\searchs\Assignment as AssignmentSearch;
|
||||
use yii\web\Controller;
|
||||
use yii\web\NotFoundHttpException;
|
||||
use yii\filters\VerbFilter;
|
||||
|
||||
/**
|
||||
* AssignmentController implements the CRUD actions for Assignment model.
|
||||
*
|
||||
* @author Misbahul D Munir <misbahuldmunir@gmail.com>
|
||||
* @since 1.0
|
||||
*/
|
||||
class AssignmentController extends Controller
|
||||
{
|
||||
public $userClassName;
|
||||
public $idField = 'id';
|
||||
public $usernameField = 'username';
|
||||
public $fullnameField;
|
||||
public $searchClass;
|
||||
public $extraColumns = [];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
parent::init();
|
||||
if ($this->userClassName === null) {
|
||||
$this->userClassName = Yii::$app->getUser()->identityClass;
|
||||
$this->userClassName = $this->userClassName ? : 'mdm\admin\models\User';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function behaviors()
|
||||
{
|
||||
return [
|
||||
'verbs' => [
|
||||
'class' => VerbFilter::className(),
|
||||
'actions' => [
|
||||
'assign' => ['post'],
|
||||
'assign' => ['post'],
|
||||
'revoke' => ['post'],
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Lists all Assignment models.
|
||||
* @return mixed
|
||||
*/
|
||||
public function actionIndex()
|
||||
{
|
||||
|
||||
if ($this->searchClass === null) {
|
||||
$searchModel = new AssignmentSearch;
|
||||
$dataProvider = $searchModel->search(Yii::$app->getRequest()->getQueryParams(), $this->userClassName, $this->usernameField);
|
||||
} else {
|
||||
$class = $this->searchClass;
|
||||
$searchModel = new $class;
|
||||
$dataProvider = $searchModel->search(Yii::$app->getRequest()->getQueryParams());
|
||||
}
|
||||
|
||||
return $this->render('index', [
|
||||
'dataProvider' => $dataProvider,
|
||||
'searchModel' => $searchModel,
|
||||
'idField' => $this->idField,
|
||||
'usernameField' => $this->usernameField,
|
||||
'extraColumns' => $this->extraColumns,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays a single Assignment model.
|
||||
* @param integer $id
|
||||
* @return mixed
|
||||
*/
|
||||
public function actionView($id)
|
||||
{
|
||||
$model = $this->findModel($id);
|
||||
|
||||
return $this->render('view', [
|
||||
'model' => $model,
|
||||
'idField' => $this->idField,
|
||||
'usernameField' => $this->usernameField,
|
||||
'fullnameField' => $this->fullnameField,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign items
|
||||
* @param string $id
|
||||
* @return array
|
||||
*/
|
||||
public function actionAssign($id)
|
||||
{
|
||||
$items = Yii::$app->getRequest()->post('items', []);
|
||||
$model = new Assignment($id);
|
||||
$success = $model->assign($items);
|
||||
Yii::$app->getResponse()->format = 'json';
|
||||
return array_merge($model->getItems(), ['success' => $success]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign items
|
||||
* @param string $id
|
||||
* @return array
|
||||
*/
|
||||
public function actionRevoke($id)
|
||||
{
|
||||
$items = Yii::$app->getRequest()->post('items', []);
|
||||
$model = new Assignment($id);
|
||||
$success = $model->revoke($items);
|
||||
Yii::$app->getResponse()->format = 'json';
|
||||
return array_merge($model->getItems(), ['success' => $success]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the Assignment model based on its primary key value.
|
||||
* If the model is not found, a 404 HTTP exception will be thrown.
|
||||
* @param integer $id
|
||||
* @return Assignment the loaded model
|
||||
* @throws NotFoundHttpException if the model cannot be found
|
||||
*/
|
||||
protected function findModel($id)
|
||||
{
|
||||
$class = $this->userClassName;
|
||||
if (($user = $class::findIdentity($id)) !== null) {
|
||||
return new Assignment($id, $user);
|
||||
} else {
|
||||
throw new NotFoundHttpException('The requested page does not exist.');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace mdm\admin\controllers;
|
||||
|
||||
use Yii;
|
||||
|
||||
/**
|
||||
* DefaultController
|
||||
*
|
||||
* @author Misbahul D Munir <misbahuldmunir@gmail.com>
|
||||
* @since 1.0
|
||||
*/
|
||||
class DefaultController extends \yii\web\Controller
|
||||
{
|
||||
|
||||
/**
|
||||
* Action index
|
||||
*/
|
||||
public function actionIndex($page = 'README.md')
|
||||
{
|
||||
if (strpos($page, '.png') !== false) {
|
||||
$file = Yii::getAlias("@mdm/admin/{$page}");
|
||||
return Yii::$app->getResponse()->sendFile($file);
|
||||
}
|
||||
return $this->render('index', ['page' => $page]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
<?php
|
||||
|
||||
namespace mdm\admin\controllers;
|
||||
|
||||
use Yii;
|
||||
use mdm\admin\models\Menu;
|
||||
use mdm\admin\models\searchs\Menu as MenuSearch;
|
||||
use yii\web\Controller;
|
||||
use yii\web\NotFoundHttpException;
|
||||
use yii\filters\VerbFilter;
|
||||
use mdm\admin\components\Helper;
|
||||
|
||||
/**
|
||||
* MenuController implements the CRUD actions for Menu model.
|
||||
*
|
||||
* @author Misbahul D Munir <misbahuldmunir@gmail.com>
|
||||
* @since 1.0
|
||||
*/
|
||||
class MenuController extends Controller
|
||||
{
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function behaviors()
|
||||
{
|
||||
return [
|
||||
'verbs' => [
|
||||
'class' => VerbFilter::className(),
|
||||
'actions' => [
|
||||
'delete' => ['get'],
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Lists all Menu models.
|
||||
* @return mixed
|
||||
*/
|
||||
public function actionIndex()
|
||||
{
|
||||
$searchModel = new MenuSearch;
|
||||
$dataProvider = $searchModel->search(Yii::$app->request->getQueryParams());
|
||||
|
||||
return $this->render('index', [
|
||||
'dataProvider' => $dataProvider,
|
||||
'searchModel' => $searchModel,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays a single Menu model.
|
||||
* @param integer $id
|
||||
* @return mixed
|
||||
*/
|
||||
public function actionView($id)
|
||||
{
|
||||
return $this->render('view', [
|
||||
'model' => $this->findModel($id),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Menu model.
|
||||
* If creation is successful, the browser will be redirected to the 'view' page.
|
||||
* @return mixed
|
||||
*/
|
||||
public function actionCreate()
|
||||
{
|
||||
$model = new Menu;
|
||||
|
||||
if ($model->load(Yii::$app->request->post()) && $model->save()) {
|
||||
Helper::invalidate();
|
||||
return $this->redirect(['view', 'id' => $model->id]);
|
||||
} else {
|
||||
return $this->render('create', [
|
||||
'model' => $model,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates an existing Menu model.
|
||||
* If update is successful, the browser will be redirected to the 'view' page.
|
||||
* @param integer $id
|
||||
* @return mixed
|
||||
*/
|
||||
public function actionUpdate($id)
|
||||
{
|
||||
$model = $this->findModel($id);
|
||||
if ($model->menuParent) {
|
||||
$model->parent_name = $model->menuParent->name;
|
||||
}
|
||||
if ($model->load(Yii::$app->request->post()) && $model->save()) {
|
||||
Helper::invalidate();
|
||||
return $this->redirect(['view', 'id' => $model->id]);
|
||||
} else {
|
||||
return $this->render('update', [
|
||||
'model' => $model,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes an existing Menu model.
|
||||
* If deletion is successful, the browser will be redirected to the 'index' page.
|
||||
* @param integer $id
|
||||
* @return mixed
|
||||
*/
|
||||
public function actionDelete($id)
|
||||
{
|
||||
$this->findModel($id)->delete();
|
||||
Helper::invalidate();
|
||||
|
||||
return $this->redirect(['index']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the Menu model based on its primary key value.
|
||||
* If the model is not found, a 404 HTTP exception will be thrown.
|
||||
* @param integer $id
|
||||
* @return Menu the loaded model
|
||||
* @throws NotFoundHttpException if the model cannot be found
|
||||
*/
|
||||
protected function findModel($id)
|
||||
{
|
||||
if (($model = Menu::findOne($id)) !== null) {
|
||||
return $model;
|
||||
} else {
|
||||
throw new NotFoundHttpException('The requested page does not exist.');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace mdm\admin\controllers;
|
||||
|
||||
use mdm\admin\components\ItemController;
|
||||
use yii\rbac\Item;
|
||||
|
||||
/**
|
||||
* PermissionController implements the CRUD actions for AuthItem model.
|
||||
*
|
||||
* @author Misbahul D Munir <misbahuldmunir@gmail.com>
|
||||
* @since 1.0
|
||||
*/
|
||||
class PermissionController extends ItemController
|
||||
{
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function labels()
|
||||
{
|
||||
return[
|
||||
'Item' => 'Permission',
|
||||
'Items' => 'Permissions',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getType()
|
||||
{
|
||||
return Item::TYPE_PERMISSION;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace mdm\admin\controllers;
|
||||
|
||||
use mdm\admin\components\ItemController;
|
||||
use yii\rbac\Item;
|
||||
|
||||
/**
|
||||
* RoleController implements the CRUD actions for AuthItem model.
|
||||
*
|
||||
* @author Misbahul D Munir <misbahuldmunir@gmail.com>
|
||||
* @since 1.0
|
||||
*/
|
||||
class RoleController extends ItemController
|
||||
{
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function labels()
|
||||
{
|
||||
return[
|
||||
'Item' => 'Role',
|
||||
'Items' => 'Roles',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getType()
|
||||
{
|
||||
return Item::TYPE_ROLE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
|
||||
namespace mdm\admin\controllers;
|
||||
|
||||
use Yii;
|
||||
use mdm\admin\models\Route;
|
||||
use yii\web\Controller;
|
||||
use yii\filters\VerbFilter;
|
||||
|
||||
/**
|
||||
* Description of RuleController
|
||||
*
|
||||
* @author Misbahul D Munir <misbahuldmunir@gmail.com>
|
||||
* @since 1.0
|
||||
*/
|
||||
class RouteController extends Controller
|
||||
{
|
||||
public function behaviors()
|
||||
{
|
||||
return [
|
||||
'verbs' => [
|
||||
'class' => VerbFilter::className(),
|
||||
'actions' => [
|
||||
'create' => ['post'],
|
||||
'assign' => ['post'],
|
||||
'remove' => ['post'],
|
||||
'refresh' => ['post'],
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
/**
|
||||
* Lists all Route models.
|
||||
* @return mixed
|
||||
*/
|
||||
public function actionIndex()
|
||||
{
|
||||
$model = new Route();
|
||||
return $this->render('index', ['routes' => $model->getRoutes()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new AuthItem model.
|
||||
* If creation is successful, the browser will be redirected to the 'view' page.
|
||||
* @return mixed
|
||||
*/
|
||||
public function actionCreate()
|
||||
{
|
||||
Yii::$app->getResponse()->format = 'json';
|
||||
$routes = Yii::$app->getRequest()->post('route', '');
|
||||
$routes = preg_split('/\s*,\s*/', trim($routes), -1, PREG_SPLIT_NO_EMPTY);
|
||||
$model = new Route();
|
||||
$model->addNew($routes);
|
||||
return $model->getRoutes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign routes
|
||||
* @return array
|
||||
*/
|
||||
public function actionAssign()
|
||||
{
|
||||
$routes = Yii::$app->getRequest()->post('routes', []);
|
||||
$model = new Route();
|
||||
$model->addNew($routes);
|
||||
Yii::$app->getResponse()->format = 'json';
|
||||
return $model->getRoutes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove routes
|
||||
* @return array
|
||||
*/
|
||||
public function actionRemove()
|
||||
{
|
||||
$routes = Yii::$app->getRequest()->post('routes', []);
|
||||
$model = new Route();
|
||||
$model->remove($routes);
|
||||
Yii::$app->getResponse()->format = 'json';
|
||||
return $model->getRoutes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh cache
|
||||
* @return type
|
||||
*/
|
||||
public function actionRefresh()
|
||||
{
|
||||
$model = new Route();
|
||||
$model->invalidate();
|
||||
Yii::$app->getResponse()->format = 'json';
|
||||
return $model->getRoutes();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
<?php
|
||||
|
||||
namespace mdm\admin\controllers;
|
||||
|
||||
use Yii;
|
||||
use mdm\admin\models\BizRule;
|
||||
use yii\web\Controller;
|
||||
use mdm\admin\models\searchs\BizRule as BizRuleSearch;
|
||||
use yii\filters\VerbFilter;
|
||||
use yii\web\NotFoundHttpException;
|
||||
use mdm\admin\components\Helper;
|
||||
|
||||
/**
|
||||
* Description of RuleController
|
||||
*
|
||||
* @author Misbahul D Munir <misbahuldmunir@gmail.com>
|
||||
* @since 1.0
|
||||
*/
|
||||
class RuleController extends Controller
|
||||
{
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function behaviors()
|
||||
{
|
||||
return [
|
||||
'verbs' => [
|
||||
'class' => VerbFilter::className(),
|
||||
'actions' => [
|
||||
'delete' => ['post'],
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Lists all AuthItem models.
|
||||
* @return mixed
|
||||
*/
|
||||
public function actionIndex()
|
||||
{
|
||||
$searchModel = new BizRuleSearch();
|
||||
$dataProvider = $searchModel->search(Yii::$app->request->getQueryParams());
|
||||
|
||||
return $this->render('index', [
|
||||
'dataProvider' => $dataProvider,
|
||||
'searchModel' => $searchModel,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays a single AuthItem model.
|
||||
* @param string $id
|
||||
* @return mixed
|
||||
*/
|
||||
public function actionView($id)
|
||||
{
|
||||
$model = $this->findModel($id);
|
||||
|
||||
return $this->render('view', ['model' => $model]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new AuthItem model.
|
||||
* If creation is successful, the browser will be redirected to the 'view' page.
|
||||
* @return mixed
|
||||
*/
|
||||
public function actionCreate()
|
||||
{
|
||||
$model = new BizRule(null);
|
||||
if ($model->load(Yii::$app->request->post()) && $model->save()) {
|
||||
Helper::invalidate();
|
||||
|
||||
return $this->redirect(['view', 'id' => $model->name]);
|
||||
} else {
|
||||
return $this->render('create', ['model' => $model,]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates an existing AuthItem model.
|
||||
* If update is successful, the browser will be redirected to the 'view' page.
|
||||
* @param string $id
|
||||
* @return mixed
|
||||
*/
|
||||
public function actionUpdate($id)
|
||||
{
|
||||
$model = $this->findModel($id);
|
||||
if ($model->load(Yii::$app->request->post()) && $model->save()) {
|
||||
Helper::invalidate();
|
||||
|
||||
return $this->redirect(['view', 'id' => $model->name]);
|
||||
}
|
||||
|
||||
return $this->render('update', ['model' => $model,]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes an existing AuthItem model.
|
||||
* If deletion is successful, the browser will be redirected to the 'index' page.
|
||||
* @param string $id
|
||||
* @return mixed
|
||||
*/
|
||||
public function actionDelete($id)
|
||||
{
|
||||
$model = $this->findModel($id);
|
||||
Yii::$app->authManager->remove($model->item);
|
||||
Helper::invalidate();
|
||||
|
||||
return $this->redirect(['index']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the AuthItem model based on its primary key value.
|
||||
* If the model is not found, a 404 HTTP exception will be thrown.
|
||||
* @param string $id
|
||||
* @return AuthItem the loaded model
|
||||
* @throws HttpException if the model cannot be found
|
||||
*/
|
||||
protected function findModel($id)
|
||||
{
|
||||
$item = Yii::$app->authManager->getRule($id);
|
||||
if ($item) {
|
||||
return new BizRule($item);
|
||||
} else {
|
||||
throw new NotFoundHttpException('The requested page does not exist.');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,276 @@
|
||||
<?php
|
||||
|
||||
namespace mdm\admin\controllers;
|
||||
|
||||
use Yii;
|
||||
use mdm\admin\models\form\Login;
|
||||
use mdm\admin\models\form\PasswordResetRequest;
|
||||
use mdm\admin\models\form\ResetPassword;
|
||||
use mdm\admin\models\form\Signup;
|
||||
use mdm\admin\models\form\ChangePassword;
|
||||
use mdm\admin\models\User;
|
||||
use mdm\admin\models\searchs\User as UserSearch;
|
||||
use yii\base\InvalidParamException;
|
||||
use yii\web\BadRequestHttpException;
|
||||
use yii\web\Controller;
|
||||
use yii\filters\VerbFilter;
|
||||
use yii\filters\AccessControl;
|
||||
use yii\web\NotFoundHttpException;
|
||||
use yii\base\UserException;
|
||||
use yii\mail\BaseMailer;
|
||||
|
||||
/**
|
||||
* User controller
|
||||
*/
|
||||
class UserController extends Controller
|
||||
{
|
||||
private $_oldMailPath;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function behaviors()
|
||||
{
|
||||
return [
|
||||
// 'access' => [
|
||||
// 'class' => AccessControl::className(),
|
||||
// 'rules' => [
|
||||
// [
|
||||
// 'actions' => ['signup', 'reset-password', 'login', 'request-password-reset'],
|
||||
// 'allow' => true,
|
||||
// 'roles' => ['?'],
|
||||
// ],
|
||||
// [
|
||||
// 'actions' => ['logout', 'change-password', 'index', 'view', 'delete', 'activate'],
|
||||
// 'allow' => true,
|
||||
// 'roles' => ['@'],
|
||||
// ],
|
||||
// ],
|
||||
// ],
|
||||
'verbs' => [
|
||||
'class' => VerbFilter::className(),
|
||||
'actions' => [
|
||||
'delete' => ['post'],
|
||||
'logout' => ['post'],
|
||||
'activate' => ['post'],
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function beforeAction($action)
|
||||
{
|
||||
if (parent::beforeAction($action)) {
|
||||
if (Yii::$app->has('mailer') && ($mailer = Yii::$app->getMailer()) instanceof BaseMailer) {
|
||||
/* @var $mailer BaseMailer */
|
||||
$this->_oldMailPath = $mailer->getViewPath();
|
||||
$mailer->setViewPath('@mdm/admin/mail');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function afterAction($action, $result)
|
||||
{
|
||||
if ($this->_oldMailPath !== null) {
|
||||
Yii::$app->getMailer()->setViewPath($this->_oldMailPath);
|
||||
}
|
||||
return parent::afterAction($action, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Lists all User models.
|
||||
* @return mixed
|
||||
*/
|
||||
public function actionIndex()
|
||||
{
|
||||
$searchModel = new UserSearch();
|
||||
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
|
||||
|
||||
return $this->render('index', [
|
||||
'searchModel' => $searchModel,
|
||||
'dataProvider' => $dataProvider,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays a single User model.
|
||||
* @param integer $id
|
||||
* @return mixed
|
||||
*/
|
||||
public function actionView($id)
|
||||
{
|
||||
return $this->render('view', [
|
||||
'model' => $this->findModel($id),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes an existing User model.
|
||||
* If deletion is successful, the browser will be redirected to the 'index' page.
|
||||
* @param integer $id
|
||||
* @return mixed
|
||||
*/
|
||||
public function actionDelete($id)
|
||||
{
|
||||
$this->findModel($id)->delete();
|
||||
|
||||
return $this->redirect(['index']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Login
|
||||
* @return string
|
||||
*/
|
||||
public function actionLogin()
|
||||
{
|
||||
if (!Yii::$app->getUser()->isGuest) {
|
||||
return $this->goHome();
|
||||
}
|
||||
|
||||
$model = new Login();
|
||||
if ($model->load(Yii::$app->getRequest()->post()) && $model->login()) {
|
||||
return $this->goBack();
|
||||
} else {
|
||||
return $this->render('login', [
|
||||
'model' => $model,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Logout
|
||||
* @return string
|
||||
*/
|
||||
public function actionLogout()
|
||||
{
|
||||
Yii::$app->getUser()->logout();
|
||||
|
||||
return $this->goHome();
|
||||
}
|
||||
|
||||
/**
|
||||
* Signup new user
|
||||
* @return string
|
||||
*/
|
||||
public function actionSignup()
|
||||
{
|
||||
$model = new Signup();
|
||||
if ($model->load(Yii::$app->getRequest()->post())) {
|
||||
if ($user = $model->signup()) {
|
||||
return $this->goHome();
|
||||
}
|
||||
}
|
||||
|
||||
return $this->render('signup', [
|
||||
'model' => $model,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Request reset password
|
||||
* @return string
|
||||
*/
|
||||
public function actionRequestPasswordReset()
|
||||
{
|
||||
$model = new PasswordResetRequest();
|
||||
if ($model->load(Yii::$app->getRequest()->post()) && $model->validate()) {
|
||||
if ($model->sendEmail()) {
|
||||
Yii::$app->getSession()->setFlash('success', 'Check your email for further instructions.');
|
||||
|
||||
return $this->goHome();
|
||||
} else {
|
||||
Yii::$app->getSession()->setFlash('error', 'Sorry, we are unable to reset password for email provided.');
|
||||
}
|
||||
}
|
||||
|
||||
return $this->render('requestPasswordResetToken', [
|
||||
'model' => $model,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset password
|
||||
* @return string
|
||||
*/
|
||||
public function actionResetPassword($token)
|
||||
{
|
||||
try {
|
||||
$model = new ResetPassword($token);
|
||||
} catch (InvalidParamException $e) {
|
||||
throw new BadRequestHttpException($e->getMessage());
|
||||
}
|
||||
|
||||
if ($model->load(Yii::$app->getRequest()->post()) && $model->validate() && $model->resetPassword()) {
|
||||
Yii::$app->getSession()->setFlash('success', 'New password was saved.');
|
||||
|
||||
return $this->goHome();
|
||||
}
|
||||
|
||||
return $this->render('resetPassword', [
|
||||
'model' => $model,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset password
|
||||
* @return string
|
||||
*/
|
||||
public function actionChangePassword()
|
||||
{
|
||||
$model = new ChangePassword();
|
||||
if ($model->load(Yii::$app->getRequest()->post()) && $model->change()) {
|
||||
return $this->goHome();
|
||||
}
|
||||
|
||||
return $this->render('change-password', [
|
||||
'model' => $model,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Activate new user
|
||||
* @param integer $id
|
||||
* @return type
|
||||
* @throws UserException
|
||||
* @throws NotFoundHttpException
|
||||
*/
|
||||
public function actionActivate($id)
|
||||
{
|
||||
/* @var $user User */
|
||||
$user = $this->findModel($id);
|
||||
if ($user->status == User::STATUS_INACTIVE) {
|
||||
$user->status = User::STATUS_ACTIVE;
|
||||
if ($user->save()) {
|
||||
return $this->goHome();
|
||||
} else {
|
||||
$errors = $user->firstErrors;
|
||||
throw new UserException(reset($errors));
|
||||
}
|
||||
}
|
||||
return $this->goHome();
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the User model based on its primary key value.
|
||||
* If the model is not found, a 404 HTTP exception will be thrown.
|
||||
* @param integer $id
|
||||
* @return User the loaded model
|
||||
* @throws NotFoundHttpException if the model cannot be found
|
||||
*/
|
||||
protected function findModel($id)
|
||||
{
|
||||
if (($model = User::findOne($id)) !== null) {
|
||||
return $model;
|
||||
} else {
|
||||
throw new NotFoundHttpException('The requested page does not exist.');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
Assignment
|
||||
---------
|
||||
Assignment menu used for grant or revoke role to/from user.
|
||||
|
||||

|
||||

|
||||
|
||||
Route
|
||||
-----
|
||||
Route is special `permission`. Its related with application route. Because `route` is `permission`,
|
||||
so you can assign it to another `permission` or `role`.
|
||||
By default, listed route is automatic read from application structure.
|
||||
Click button '>>' to save it and button '<<' to delete.
|
||||
|
||||
If route that you need not avaliable in list. You can create it manually. You can also create route
|
||||
with extra parameter. Use `&` to sparate main route with parameter. E.g. `site/page&view=about`.
|
||||
|
||||

|
||||
|
||||
Role and Permission
|
||||
-------------------
|
||||
This sesction used for manage role/permission. You can create, delete or update role/permission from this menu.
|
||||
Adding and remove child of role can be doing there.
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
Rule
|
||||
----
|
||||
To using rule, define your own rule class. It should be inherited from
|
||||
[`yii\rbac\Rule`](http://www.yiiframework.com/doc-2.0/yii-rbac-rule.html).
|
||||
See [Rules](http://www.yiiframework.com/doc-2.0/guide-security-authorization.html#using-rules) for more information.
|
||||
Add rule to `authManager` by provide rule classname.
|
||||
|
||||

|
||||
|
||||
More...
|
||||
--------
|
||||
|
||||
- [**User Management**](user-management.md)
|
||||
- [**Using Menu**](using-menu.md)
|
||||
- [**Basic Configuration**](configuration.md)
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
Admin Module
|
||||
------------
|
||||
- `layout` default to 'left-menu'. Set to null if you want use your current layout.
|
||||
- `menus` Change listed menu avaliable for module.
|
||||
|
||||
Using module in configuration
|
||||
|
||||
```php
|
||||
'modules' => [
|
||||
...
|
||||
'admin' => [
|
||||
'class' => 'mdm\admin\Module',
|
||||
'layout' => 'left-menu', // it can be '@path/to/your/layout'.
|
||||
'controllerMap' => [
|
||||
'assignment' => [
|
||||
'class' => 'mdm\admin\controllers\AssignmentController',
|
||||
'userClassName' => 'app\models\User',
|
||||
'idField' => 'user_id'
|
||||
],
|
||||
'other' => [
|
||||
'class' => 'path\to\OtherController', // add another controller
|
||||
],
|
||||
],
|
||||
'menus' => [
|
||||
'assignment' => [
|
||||
'label' => 'Grand Access' // change label
|
||||
],
|
||||
'route' => null, // disable menu route
|
||||
]
|
||||
],
|
||||
],
|
||||
```
|
||||
|
||||
Access Control Filter
|
||||
---------------------
|
||||
Access Control Filter (ACF) is a simple authorization method that is best used by applications that only need some simple access control.
|
||||
As its name indicates, ACF is an action filter that can be attached to a controller or a module as a behavior.
|
||||
ACF will check a set of access rules to make sure the current user can access the requested action.
|
||||
|
||||
The code below shows how to use ACF which is implemented as `mdm\admin\components\AccessControl`:
|
||||
|
||||
```php
|
||||
'as access' => [
|
||||
'class' => 'mdm\admin\components\AccessControl',
|
||||
'allowActions' => [
|
||||
'site/login',
|
||||
'site/error',
|
||||
]
|
||||
]
|
||||
```
|
||||
|
||||
Filter ActionColumn Buttons
|
||||
---------------------------
|
||||
When you use `GridView`, you can also filtering button visibility.
|
||||
```php
|
||||
use mdm\admin\components\Helper;
|
||||
|
||||
'columns' => [
|
||||
...
|
||||
[
|
||||
'class' => 'yii\grid\ActionColumn',
|
||||
'template' => Helper::filterActionColumn('{view}{delete}{posting}'),
|
||||
]
|
||||
]
|
||||
```
|
||||
It will check authorization access of button and show or hide it.
|
||||
|
||||
To check access for route, you can use
|
||||
```php
|
||||
use mdm\admin\components\Helper;
|
||||
|
||||
if(Helper::checkRoute('delete')){
|
||||
echo Html::a(Yii::t('rbac-admin', 'Delete'), ['delete', 'id' => $model->name], [
|
||||
'class' => 'btn btn-danger',
|
||||
'data-confirm' => Yii::t('rbac-admin', 'Are you sure to delete this item?'),
|
||||
'data-method' => 'post',
|
||||
]);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
More...
|
||||
---------------
|
||||
|
||||
- [**User Management**](user-management.md)
|
||||
- [**Using Menu**](using-menu.md)
|
||||
- [**Basic Configuration**](configuration.md)
|
||||
@@ -0,0 +1,191 @@
|
||||
Basic Configuration
|
||||
-------------------
|
||||
|
||||
Once the extension is installed, simply modify your application configuration as follows:
|
||||
|
||||
```php
|
||||
return [
|
||||
'modules' => [
|
||||
'admin' => [
|
||||
'class' => 'mdm\admin\Module',
|
||||
...
|
||||
]
|
||||
...
|
||||
],
|
||||
...
|
||||
'components' => [
|
||||
...
|
||||
'authManager' => [
|
||||
'class' => 'yii\rbac\PhpManager', // or use 'yii\rbac\DbManager'
|
||||
]
|
||||
],
|
||||
'as access' => [
|
||||
'class' => 'mdm\admin\components\AccessControl',
|
||||
'allowActions' => [
|
||||
'site/*',
|
||||
'admin/*',
|
||||
'some-controller/some-action',
|
||||
// The actions listed here will be allowed to everyone including guests.
|
||||
// So, 'admin/*' should not appear here in the production, of course.
|
||||
// But in the earlier stages of your development, you may probably want to
|
||||
// add a lot of actions here until you finally completed setting up rbac,
|
||||
// otherwise you may not even take a first step.
|
||||
]
|
||||
],
|
||||
];
|
||||
```
|
||||
See [Yii RBAC](http://www.yiiframework.com/doc-2.0/guide-security-authorization.html#role-based-access-control-rbac) for more detail.
|
||||
You can then access Auth manager through the following URL:
|
||||
|
||||
```
|
||||
http://localhost/path/to/index.php?r=admin
|
||||
http://localhost/path/to/index.php?r=admin/route
|
||||
http://localhost/path/to/index.php?r=admin/permission
|
||||
http://localhost/path/to/index.php?r=admin/menu
|
||||
http://localhost/path/to/index.php?r=admin/role
|
||||
http://localhost/path/to/index.php?r=admin/assignment
|
||||
http://localhost/path/to/index.php?r=admin/user
|
||||
```
|
||||
|
||||
To use the menu manager (optional), execute the migration here:
|
||||
```
|
||||
yii migrate --migrationPath=@mdm/admin/migrations
|
||||
```
|
||||
|
||||
If you use database (class 'yii\rbac\DbManager') to save rbac data, execute the migration here:
|
||||
```
|
||||
yii migrate --migrationPath=@yii/rbac/migrations
|
||||
```
|
||||
|
||||
Customizing Assignment Controller
|
||||
---------------------------------
|
||||
|
||||
Assignment controller properties may need to be adjusted to the User model of your app.
|
||||
To do that, change them via `controllerMap` property. For example:
|
||||
|
||||
```php
|
||||
'modules' => [
|
||||
'admin' => [
|
||||
...
|
||||
'controllerMap' => [
|
||||
'assignment' => [
|
||||
'class' => 'mdm\admin\controllers\AssignmentController',
|
||||
/* 'userClassName' => 'app\models\User', */
|
||||
'idField' => 'user_id',
|
||||
'usernameField' => 'username',
|
||||
'fullnameField' => 'profile.full_name',
|
||||
'extraColumns' => [
|
||||
[
|
||||
'attribute' => 'full_name',
|
||||
'label' => 'Full Name',
|
||||
'value' => function($model, $key, $index, $column) {
|
||||
return $model->profile->full_name;
|
||||
},
|
||||
],
|
||||
[
|
||||
'attribute' => 'dept_name',
|
||||
'label' => 'Department',
|
||||
'value' => function($model, $key, $index, $column) {
|
||||
return $model->profile->dept->name;
|
||||
},
|
||||
],
|
||||
[
|
||||
'attribute' => 'post_name',
|
||||
'label' => 'Post',
|
||||
'value' => function($model, $key, $index, $column) {
|
||||
return $model->profile->post->name;
|
||||
},
|
||||
],
|
||||
],
|
||||
'searchClass' => 'app\models\UserSearch'
|
||||
],
|
||||
],
|
||||
...
|
||||
]
|
||||
...
|
||||
],
|
||||
|
||||
```
|
||||
|
||||
- Required properties
|
||||
- **userClassName** Fully qualified class name of your User model
|
||||
Usually you don't need to specify it explicitly, since the module will detect it automatically
|
||||
- **idField** ID field of your User model
|
||||
The field that corresponds to Yii::$app->user->id.
|
||||
The default value is 'id'.
|
||||
- **usernameField** User name field of your User model
|
||||
The default value is 'username'.
|
||||
- Optional properties
|
||||
- **fullnameField** The field that specifies the full name of the user used in "view" page.
|
||||
This can either be a field of the user model or of a related model (e.g. profile model).
|
||||
When the field is of a related model, the name should be specified with a dot-separated notation (e.g. 'profile.full_name').
|
||||
The default value is null.
|
||||
- **extraColumns** The definition of the extra columns used in the "index" page
|
||||
This should be an array of the definitions of the grid view columns.
|
||||
You may include the attributes of the related models as you see in the example above.
|
||||
The default value is an empty array.
|
||||
- **searchClass** Fully qualified class name of your model for searching the user model
|
||||
You have to supply the proper search model in order to enable the filtering and the sorting by the extra columns.
|
||||
The default value is null.
|
||||
|
||||
|
||||
Customizing Layout
|
||||
------------------
|
||||
|
||||
By default, the admin module will use the layout specified in the application level.
|
||||
In that case you have to write the menu for this module on your own.
|
||||
|
||||
By specifying the `layout` property, you can use one of the built-in layouts of the module:
|
||||
'left-menu', 'right-menu' or 'top-menu', all equipped with the menu for this module.
|
||||
|
||||
```php
|
||||
'modules' => [
|
||||
'admin' => [
|
||||
...
|
||||
'layout' => 'left-menu', // defaults to null, using the application's layout without the menu
|
||||
// other avaliable values are 'right-menu' and 'top-menu'
|
||||
],
|
||||
...
|
||||
],
|
||||
```
|
||||
|
||||
If you use one of them, you can also customize the menu. You can change menu label or disable it.
|
||||
|
||||
```php
|
||||
'modules' => [
|
||||
'admin' => [
|
||||
...
|
||||
'layout' => 'left-menu',
|
||||
'menus' => [
|
||||
'assignment' => [
|
||||
'label' => 'Grant Access' // change label
|
||||
],
|
||||
'route' => null, // disable menu
|
||||
],
|
||||
],
|
||||
...
|
||||
],
|
||||
```
|
||||
|
||||
While using a dedicated layout of the module, you may still want to have it wrapped in your application's main layout
|
||||
that has your application's nav bar and your brand logo on it.
|
||||
You can do it by specifying the `mainLayout` property with the application's main layout. For example:
|
||||
|
||||
```php
|
||||
'modules' => [
|
||||
'admin' => [
|
||||
...
|
||||
'layout' => 'left-menu',
|
||||
'mainLayout' => '@app/views/layouts/main.php',
|
||||
...
|
||||
],
|
||||
...
|
||||
],
|
||||
```
|
||||
|
||||
More...
|
||||
---------------
|
||||
|
||||
- [**Basic Usage...**](basic-usage.md)
|
||||
- [**User Management**](user-management.md)
|
||||
- [**Using Menu**](using-menu.md)
|
||||
@@ -0,0 +1,48 @@
|
||||
User Management
|
||||
===============
|
||||
|
||||
For `basic application template` that want to have user stored in database.
|
||||
To use this feature, create required table by execute migration.
|
||||
```
|
||||
./yii migrate --migrationPath=@mdm/admin/migrations
|
||||
```
|
||||
Then, change config of user component
|
||||
```php
|
||||
'components' => [
|
||||
...
|
||||
'user' => [
|
||||
'identityClass' => 'mdm\admin\models\User',
|
||||
'loginUrl' => ['admin/user/login'],
|
||||
]
|
||||
]
|
||||
```
|
||||
Then you can access this menu at `index.php?r=admin/user`.
|
||||
|
||||
Signup User
|
||||
-----------
|
||||
```
|
||||
http://localhost/myapp/index.php?r=admin/user/signup
|
||||
```
|
||||
Default registered user has status `ACTIVE`, mean user can login without activation needed.
|
||||
To change that, you can change at config/params.php
|
||||
```php
|
||||
// config/params.php
|
||||
|
||||
return [
|
||||
...
|
||||
'mdm.admin.configs' => [
|
||||
'defaultUserStatus' => 0, // 0 = inactive, 10 = active
|
||||
]
|
||||
];
|
||||
```
|
||||
|
||||
Login Page
|
||||
----------
|
||||
Login page can access at `index.php?r=admin/user/login`
|
||||
|
||||
More...
|
||||
---------------
|
||||
|
||||
- [**Basic Usage**](basic-usage.md)
|
||||
- [**Using Menu**](using-menu.md)
|
||||
- [**Basic Configuration**](configuration.md)
|
||||
@@ -0,0 +1,181 @@
|
||||
Using Menu
|
||||
==========
|
||||
|
||||
Menu manager used for build hierarchical menu. This is automatically look of user
|
||||
role and permision then return menus that he has access.
|
||||
|
||||
```php
|
||||
use mdm\admin\components\MenuHelper;
|
||||
use yii\bootstrap\Nav;
|
||||
|
||||
echo Nav::widget([
|
||||
'items' => MenuHelper::getAssignedMenu(Yii::$app->user->id)
|
||||
]);
|
||||
```
|
||||
|
||||
Return of `mdm\admin\components\MenuHelper::getAssignedMenu()` has default format like:
|
||||
|
||||
```php
|
||||
[
|
||||
[
|
||||
'label' => $menu['name'],
|
||||
'url' => [$menu['route']],
|
||||
'items' => [
|
||||
[
|
||||
'label' => $menu['name'],
|
||||
'url' => [$menu['route']]
|
||||
],
|
||||
....
|
||||
]
|
||||
],
|
||||
[
|
||||
'label' => $menu['name'],
|
||||
'url' => [$menu['route']],
|
||||
'items' => [
|
||||
[
|
||||
'label' => $menu['name'],
|
||||
'url' => [$menu['route']]
|
||||
]
|
||||
]
|
||||
],
|
||||
....
|
||||
]
|
||||
```
|
||||
|
||||
where `$menu` variable correspond with a record of table `menu`. You can customize
|
||||
return format of `mdm\admin\components\MenuHelper::getAssignedMenu()` by provide a callback to this method.
|
||||
The callback must have format `function($menu){}`. E.g:
|
||||
|
||||
You can add html options attribute to Your menu, for example "title". When You create a menu, in field data (textarea) fill this :
|
||||
``` return ['title'=>'Title of Your Link Here']; ```
|
||||
|
||||
and then in Your view:
|
||||
|
||||
```php
|
||||
$callback = function($menu){
|
||||
$data = eval($menu['data']);
|
||||
return [
|
||||
'label' => $menu['name'],
|
||||
'url' => [$menu['route']],
|
||||
'options' => $data,
|
||||
'items' => $menu['children']
|
||||
];
|
||||
}
|
||||
|
||||
$items = MenuHelper::getAssignedMenu(Yii::$app->user->id, null, $callback);
|
||||
```
|
||||
|
||||
Default result is get from `cache`. If you want to force regenerate, provide boolean `true` as forth parameter.
|
||||
|
||||
You can modify callback function for advanced usage.
|
||||
|
||||

|
||||

|
||||
|
||||
Using Sparated Menu
|
||||
-------------------
|
||||
Second parameter of `mdm\admin\components\MenuHelper::getAssignedMenu()` used to get menu on it's own hierarchy.
|
||||
E.g. Your menu structure:
|
||||
|
||||
* Side Menu
|
||||
* Menu 1
|
||||
* Menu 1.1
|
||||
* Menu 1.2
|
||||
* Menu 1.3
|
||||
* Menu 2
|
||||
* Menu 2.1
|
||||
* Menu 2.2
|
||||
* Menu 2.3
|
||||
* Top Menu
|
||||
* Top Menu 1
|
||||
* Top Menu 1.1
|
||||
* Top Menu 1.2
|
||||
* Top Menu 1.3
|
||||
* Top Menu 2
|
||||
* Top Menu 3
|
||||
* Top Menu 4
|
||||
|
||||
You can get 'Side Menu' chldren by calling
|
||||
|
||||
```php
|
||||
$items = MenuHelper::getAssignedMenu(Yii::$app->user->id, $sideMenuId);
|
||||
```
|
||||
|
||||
It will result in
|
||||
* Menu 1
|
||||
* Menu 1.1
|
||||
* Menu 1.2
|
||||
* Menu 1.3
|
||||
* Menu 2
|
||||
* Menu 2.1
|
||||
* Menu 2.2
|
||||
* Menu 2.3
|
||||
|
||||
Filtering Menu
|
||||
--------------
|
||||
If you have `NavBar` menu items and want to filtering according user login. You can use Helper class
|
||||
```php
|
||||
<?php
|
||||
user mdm\admin\components\Helper;
|
||||
|
||||
$menuItems = [
|
||||
['label' => 'Home', 'url' => ['/site/index']],
|
||||
['label' => 'About', 'url' => ['/site/about']],
|
||||
['label' => 'Contact', 'url' => ['/site/contact']],
|
||||
['label' => 'Login', 'url' => ['/user/login']],
|
||||
[
|
||||
'label' => 'Logout (' . \Yii::$app->user->identity->username . ')',
|
||||
'url' => ['/user/logout'],
|
||||
'linkOptions' => ['data-method' => 'post']
|
||||
],
|
||||
['label' => 'App', 'items' => [
|
||||
['label' => 'New Sales', 'url' => ['/sales/pos']],
|
||||
['label' => 'New Purchase', 'url' => ['/purchase/create']],
|
||||
['label' => 'GR', 'url' => ['/movement/create', 'type' => 'receive']],
|
||||
['label' => 'GI', 'url' => ['/movement/create', 'type' => 'issue']],
|
||||
]]
|
||||
];
|
||||
|
||||
$menuItems = Helper::filter($menuItems);
|
||||
|
||||
echo Nav::widget([
|
||||
'options' => ['class' => 'navbar-nav navbar-right'],
|
||||
'items' => $menuItems,
|
||||
]);
|
||||
```
|
||||
|
||||
You can also check for individual route.
|
||||
```php
|
||||
use mdm\admin\components\Helper;
|
||||
|
||||
if(Helper::checkRoute('delete')){
|
||||
echo Html::a(Yii::t('rbac-admin', 'Delete'), ['delete', 'id' => $model->name], [
|
||||
'class' => 'btn btn-danger',
|
||||
'data-confirm' => Yii::t('rbac-admin', 'Are you sure to delete this item?'),
|
||||
'data-method' => 'post',
|
||||
]);
|
||||
}
|
||||
```
|
||||
|
||||
Filter ActionColumn Buttons
|
||||
---------------------------
|
||||
When you use `GridView`, you can also filtering button visibility.
|
||||
```php
|
||||
use mdm\admin\components\Helper;
|
||||
|
||||
'columns' => [
|
||||
...
|
||||
[
|
||||
'class' => 'yii\grid\ActionColumn',
|
||||
'template' => Helper::filterActionColumn('{view}{delete}{posting}'),
|
||||
]
|
||||
]
|
||||
```
|
||||
It will check authorization access of button and show or hide it.
|
||||
|
||||
More...
|
||||
---------------
|
||||
|
||||
- [**User Management**](user-management.md)
|
||||
- [**Basic Usage**](basic-usage.md)
|
||||
- [**Basic Configuration**](configuration.md)
|
||||
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 46 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 42 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 32 KiB |
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
use yii\helpers\Html;
|
||||
|
||||
/* @var $this \yii\web\View view component instance */
|
||||
/* @var $message \yii\mail\MessageInterface the message being composed */
|
||||
/* @var $content string main view render result */
|
||||
?>
|
||||
<?php $this->beginPage() ?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=<?= Yii::$app->charset ?>" />
|
||||
<title><?= Html::encode($this->title) ?></title>
|
||||
<?php $this->head() ?>
|
||||
</head>
|
||||
<body>
|
||||
<?php $this->beginBody() ?>
|
||||
<?= $content ?>
|
||||
<?php $this->endBody() ?>
|
||||
</body>
|
||||
</html>
|
||||
<?php $this->endPage() ?>
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
/* @var $this \yii\web\View view component instance */
|
||||
/* @var $message \yii\mail\MessageInterface the message being composed */
|
||||
/* @var $content string main view render result */
|
||||
?>
|
||||
<?php $this->beginPage() ?>
|
||||
<?php $this->beginBody() ?>
|
||||
<?= $content ?>
|
||||
<?php $this->endBody() ?>
|
||||
<?php $this->endPage() ?>
|
||||
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
use yii\helpers\Html;
|
||||
use yii\helpers\Url;
|
||||
|
||||
/* @var $this yii\web\View */
|
||||
/* @var $user mdm\admin\models\User */
|
||||
|
||||
$resetLink = Url::to(['user/reset-password','token'=>$user->password_reset_token], true);
|
||||
?>
|
||||
<div class="password-reset">
|
||||
<p>Hello <?= Html::encode($user->username) ?>,</p>
|
||||
|
||||
<p>Follow the link below to reset your password:</p>
|
||||
|
||||
<p><?= Html::a(Html::encode($resetLink), $resetLink) ?></p>
|
||||
</div>
|
||||
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
use yii\helpers\Url;
|
||||
|
||||
/* @var $this yii\web\View */
|
||||
/* @var $user mdm\admin\models\User */
|
||||
|
||||
$resetLink = Url::to(['user/reset-password','token'=>$user->password_reset_token], true);
|
||||
?>
|
||||
Hello <?= $user->username ?>,
|
||||
|
||||
Follow the link below to reset your password:
|
||||
|
||||
<?= $resetLink ?>
|
||||
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Message translations for \mdmsoft\yii2-admin.
|
||||
*
|
||||
* It contains the localizable messages extracted from source code.
|
||||
* You may modify this file by translating the extracted messages.
|
||||
*
|
||||
* Each array element represents the translation (value) of a message (key).
|
||||
* If the value is empty, the message is considered as not translated.
|
||||
* Messages that no longer need translation will have their translations
|
||||
* enclosed between a pair of '@@' marks.
|
||||
*
|
||||
* Message string can be used with plural forms format. Check i18n section
|
||||
* of the guide for details.
|
||||
*
|
||||
* NOTE: this file must be saved in UTF-8 encoding.
|
||||
*/
|
||||
return [
|
||||
'Assignments' => 'Zuweisungen',
|
||||
'Users' => 'Benutzer',
|
||||
'User' => 'Benutzer',
|
||||
'Avaliable' => 'Verfügbar',
|
||||
'Assigned' => 'Zugewiesen',
|
||||
'Create' => 'Erstellen',
|
||||
'Update' => 'Aktualisieren',
|
||||
'Roles' => 'Rollen',
|
||||
'Create Role' => 'Rolle erstellen',
|
||||
'Name' => 'Name',
|
||||
'Type' => 'Typ',
|
||||
'Description' => 'Beschreibung',
|
||||
'Rule Name' => 'Regelname',
|
||||
'Data' => 'Daten',
|
||||
'Update Role' => 'Rolle aktualisieren',
|
||||
'Delete' => 'Löschen',
|
||||
'Are you sure to delete this item?' => 'Wollen Sie dieses Eintrag wirklich löschen?',
|
||||
'ID' => 'ID',
|
||||
'Parent' => 'Elternteil',
|
||||
'Parent Name' => 'Elternname',
|
||||
'Route' => 'Route',
|
||||
'Username' => 'Benutzername',
|
||||
'Update Permission' => 'Berechtigung aktualisieren',
|
||||
'Permissions' => 'Berechtigungen',
|
||||
'Permission' => 'Berechtigung',
|
||||
'Create Permission' => 'Berechtigung erstellen',
|
||||
'Create Permissions' => 'Berechtigungen erstellen',
|
||||
'Routes' => 'Routen',
|
||||
'Create route' => 'Route erstellen',
|
||||
'New' => 'Neu',
|
||||
'Generate Routes' => 'Generiere Routen',
|
||||
'Append' => 'Anhängen',
|
||||
'Create Rule' => 'Regel erstellen',
|
||||
'Rules' => 'Regeln',
|
||||
'Update Rule' => 'Regel aktualisieren',
|
||||
'Create Menu' => 'Menü erstellen',
|
||||
'Menus' => 'Menüs',
|
||||
'Search' => 'Suche',
|
||||
'Reset' => 'Zurücksetzen',
|
||||
'Update Menu' => 'Menü aktualisieren',
|
||||
'Menus' => 'Menüs',
|
||||
'Order' => 'Zuordnung',
|
||||
'Class Name' => 'Klassenname',
|
||||
'Assignment' => 'Zuordnung',
|
||||
'Role' => 'Rolle',
|
||||
'Rule' => 'Regel',
|
||||
'Menu' => 'Menü',
|
||||
'Help' => 'Hilfe',
|
||||
'Application' => 'Anwendung',
|
||||
];
|
||||
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Message translations for \mdmsoft\yii2-admin.
|
||||
*
|
||||
* It contains the localizable messages extracted from source code.
|
||||
* You may modify this file by translating the extracted messages.
|
||||
*
|
||||
* Each array element represents the translation (value) of a message (key).
|
||||
* If the value is empty, the message is considered as not translated.
|
||||
* Messages that no longer need translation will have their translations
|
||||
* enclosed between a pair of '@@' marks.
|
||||
*
|
||||
* Message string can be used with plural forms format. Check i18n section
|
||||
* of the guide for details.
|
||||
*
|
||||
* NOTE: this file must be saved in UTF-8 encoding.
|
||||
*/
|
||||
return [
|
||||
'Activate' => 'Activate',
|
||||
'Add' => 'Add',
|
||||
'Assignments' => 'Assignments',
|
||||
'Users' => 'Users',
|
||||
'User' => 'User',
|
||||
'Change' => 'Change',
|
||||
'Change Password' => 'Change Password',
|
||||
'Signup' => 'Signup',
|
||||
'Login' => 'Login',
|
||||
'Send' => 'Send',
|
||||
'Avaliable' => 'Avaliable',
|
||||
'Assigned' => 'Assigned',
|
||||
'Create' => 'Create',
|
||||
'Update' => 'Update',
|
||||
'Roles' => 'Roles',
|
||||
'Create New' => 'Create New',
|
||||
'Create Role' => 'Create Role',
|
||||
'Name' => 'Name',
|
||||
'Type' => 'Type',
|
||||
'Description' => 'Description',
|
||||
'Rule Name' => 'Rule Name',
|
||||
'Data' => 'Data',
|
||||
'Update Role' => 'Update Role',
|
||||
'Delete' => 'Delete',
|
||||
'Are you sure to delete this item?' => 'Are you sure to delete this item?',
|
||||
'Are you sure you want to activate this user?' => 'Are you sure you want to activate this user?',
|
||||
'ID' => 'ID',
|
||||
'Parent' => 'Parent',
|
||||
'Parent Name' => 'Parent Name',
|
||||
'Route' => 'Route',
|
||||
'Username' => 'Username',
|
||||
'Update Permission' => 'Update Permission',
|
||||
'Permissions' => 'Permissions',
|
||||
'Permission' => 'Permission',
|
||||
'Create Permission' => 'Create Permission',
|
||||
'Create Permissions' => 'Create Permissions',
|
||||
'Routes' => 'Routes',
|
||||
'Create route' => 'Create route',
|
||||
'New' => 'New',
|
||||
'New route(s)' => 'New route(s)',
|
||||
'Generate Routes' => 'Generate Routes',
|
||||
'Append' => 'Append',
|
||||
'Create Rule' => 'Create Rule',
|
||||
'Rules' => 'Rules',
|
||||
'Rules' => 'Rules',
|
||||
'Select Rule' => 'Select Rule',
|
||||
'Update Rule' => 'Update Rule',
|
||||
'Create Menu' => 'Create Menu',
|
||||
'Menus' => 'Menus',
|
||||
'Search' => 'Search',
|
||||
'Search for avaliable' => 'Search for avaliable',
|
||||
'Search for assigned' => 'Search for assigned',
|
||||
'Reset' => 'Reset',
|
||||
'Update Menu' => 'Update Menu',
|
||||
'Menus' => 'Menus',
|
||||
'Order' => 'Order',
|
||||
'Class Name' => 'Class Name',
|
||||
'Assignment' => 'Assignment',
|
||||
'Role' => 'Role',
|
||||
'Rule' => 'Rule',
|
||||
'Menu' => 'Menu',
|
||||
'Help' => 'Help',
|
||||
'Application' => 'Application',
|
||||
];
|
||||
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Message translations for \mdmsoft\yii2-admin.
|
||||
*
|
||||
* It contains the localizable messages extracted from source code.
|
||||
* You may modify this file by translating the extracted messages.
|
||||
*
|
||||
* Each array element represents the translation (value) of a message (key).
|
||||
* If the value is empty, the message is considered as not translated.
|
||||
* Messages that no longer need translation will have their translations
|
||||
* enclosed between a pair of '@@' marks.
|
||||
*
|
||||
* Message string can be used with plural forms format. Check i18n section
|
||||
* of the guide for details.
|
||||
*
|
||||
* NOTE: this file must be saved in UTF-8 encoding.
|
||||
*/
|
||||
return [
|
||||
'Activate' => 'Activar',
|
||||
'Add' => 'Agregar',
|
||||
'Assignments' => 'Asignaciones',
|
||||
'Users' => 'Usuarios',
|
||||
'User' => 'Usuario',
|
||||
'Change' => 'Cambiar',
|
||||
'Change Password' => 'Cambiar Contraseña',
|
||||
'Signup' => 'Regístrate',
|
||||
'Login' => 'Iniciar Sesión',
|
||||
'Send' => 'Enviar',
|
||||
'Avaliable' => 'Disponible(s)',
|
||||
'Assigned' => 'Asignado',
|
||||
'Create' => 'Crear',
|
||||
'Update' => 'Actualizar',
|
||||
'Roles' => 'Roles',
|
||||
'Create New' => 'Crear Nuevo',
|
||||
'Create Role' => 'Crear Rol',
|
||||
'Name' => 'Nombre',
|
||||
'Type' => 'Tipo',
|
||||
'Description' => 'Descripción',
|
||||
'Rule Name' => 'Nombre de regla',
|
||||
'Data' => 'Datos',
|
||||
'Update Role' => 'Actualizar Rol',
|
||||
'Delete' => 'Borrar',
|
||||
'Are you sure to delete this item?' => '¿Está seguro de querer borrar este item?',
|
||||
'Are you sure you want to activate this user?' => '¿Esta seguro de querer actualizar este usuario?',
|
||||
'ID' => 'ID',
|
||||
'Parent' => 'Padre',
|
||||
'Parent Name' => 'Nombre del Padre',
|
||||
'Route' => 'Ruta',
|
||||
'Username' => 'Nombre de usuario',
|
||||
'Update Permission' => 'Actualizar Permiso',
|
||||
'Permissions' => 'Permisos',
|
||||
'Permission' => 'Permiso',
|
||||
'Create Permission' => 'Crear Permiso',
|
||||
'Create Permissions' => 'Crear Permisos',
|
||||
'Routes' => 'Rutas',
|
||||
'Create route' => 'Crear Ruta',
|
||||
'New' => 'Nuevo(a)',
|
||||
'New route(s)' => 'Nueva Ruta(s)',
|
||||
'Generate Routes' => 'Generar Rutas',
|
||||
'Append' => 'Añadir',
|
||||
'Create Rule' => 'Crear Regla',
|
||||
'Rules' => 'Reglas',
|
||||
'Select Rule' => 'Seleccione la Regla',
|
||||
'Update Rule' => 'Actualizar Regla',
|
||||
'Create Menu' => 'Crear Menú',
|
||||
'Menus' => 'Menús',
|
||||
'Search' => 'Buscar',
|
||||
'Search for avaliable' => 'Buscar Disponible',
|
||||
'Search for assigned' => 'Buscar Asignado',
|
||||
'Reset' => 'Reiniciar',
|
||||
'Update Menu' => 'Actualizar Menú',
|
||||
'Menus' => 'Menús',
|
||||
'Order' => 'Orden',
|
||||
'Class Name' => 'Nombre de la Clase',
|
||||
'Assignment' => 'Asignación',
|
||||
'Role' => 'Rol',
|
||||
'Rule' => 'Regla',
|
||||
'Menu' => 'Menú',
|
||||
'Help' => 'Ayuda',
|
||||
'Application' => 'Aplicación',
|
||||
];
|
||||
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Message translations for \mdmsoft\yii2-admin.
|
||||
*
|
||||
* It contains the localizable messages extracted from source code.
|
||||
* You may modify this file by translating the extracted messages.
|
||||
*
|
||||
* Each array element represents the translation (value) of a message (key).
|
||||
* If the value is empty, the message is considered as not translated.
|
||||
* Messages that no longer need translation will have their translations
|
||||
* enclosed between a pair of '@@' marks.
|
||||
*
|
||||
* Message string can be used with plural forms format. Check i18n section
|
||||
* of the guide for details.
|
||||
*
|
||||
* NOTE: this file must be saved in UTF-8 encoding.
|
||||
*/
|
||||
return [
|
||||
'Assignments' => 'اختصاص داده شده ها',
|
||||
'Users' => 'کاربران',
|
||||
'User' => 'کاربر',
|
||||
'Avaliable' => 'در دسترس',
|
||||
'Assigned' => 'اختصاص یافته',
|
||||
'Create' => 'ایجاد',
|
||||
'Update' => 'بروز رسانی',
|
||||
'Roles' => 'نقش ها',
|
||||
'Create Role' => 'ایجاد نقش',
|
||||
'Name' => 'نام',
|
||||
'Type' => 'نوع',
|
||||
'Description' => 'توضیحات',
|
||||
'Rule Name' => 'نام Rule',
|
||||
'Data' => 'داده',
|
||||
'Update Role' => 'بروز رسانی نقش',
|
||||
'Delete' => 'حذف',
|
||||
'Are you sure to delete this item?' => 'مایل به حذف هستید؟',
|
||||
'ID' => 'شماره اختصاصی',
|
||||
'Parent' => 'والد',
|
||||
'Parent Name' => 'نام والد',
|
||||
'Route' => 'مسیر',
|
||||
'Username' => 'نام کاربری',
|
||||
'Update Permission' => 'بروز رسانی دسترسی',
|
||||
'Permissions' => 'دسترسی ها',
|
||||
'Permission' => 'دسترسی',
|
||||
'Create Permission' => 'ایجاد دسترسی',
|
||||
'Create Permissions' => 'ایجاد دسترسی ها',
|
||||
'Routes' => 'Routes',
|
||||
'Create route' => 'ایجاد Route',
|
||||
'New' => 'جدید',
|
||||
'Generate Routes' => 'ساخت Routes',
|
||||
'Append' => 'الحاق',
|
||||
'Create Rule' => 'ایجاد Rule',
|
||||
'Rules' => 'Rules',
|
||||
'Update Rule' => 'بروزرسانی',
|
||||
'Create Menu' => 'ساخت منو',
|
||||
'Menus' => 'منوها',
|
||||
'Search' => 'جستجو',
|
||||
'Reset' => 'راه اندازی مجدد',
|
||||
'Update Menu' => 'بروزرسانی منو',
|
||||
'Order' => 'چینش',
|
||||
'Class Name' => 'نام کلاس',
|
||||
'Assignment' => 'اختصاص',
|
||||
'Role' => 'نقش',
|
||||
'Rule' => 'Rule',
|
||||
'Menu' => 'منو',
|
||||
'Help' => 'راهنمایی',
|
||||
'Application' => 'برنامه',
|
||||
'Admin' => 'مدیریت دسترسی ها'
|
||||
];
|
||||
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Message translations for \mdmsoft\yii2-admin.
|
||||
*
|
||||
* It contains the localizable messages extracted from source code.
|
||||
* You may modify this file by translating the extracted messages.
|
||||
*
|
||||
* Each array element represents the translation (value) of a message (key).
|
||||
* If the value is empty, the message is considered as not translated.
|
||||
* Messages that no longer need translation will have their translations
|
||||
* enclosed between a pair of '@@' marks.
|
||||
*
|
||||
* Message string can be used with plural forms format. Check i18n section
|
||||
* of the guide for details.
|
||||
*
|
||||
* NOTE: this file must be saved in UTF-8 encoding.
|
||||
*/
|
||||
return [
|
||||
'Assignments' => 'Assignements',
|
||||
'Users' => 'Utilisateurs',
|
||||
'User' => 'Utilisateur',
|
||||
'Avaliable' => 'Disponible',
|
||||
'Assigned' => 'Assigner',
|
||||
'Create' => 'Créer',
|
||||
'Update' => 'Modifier',
|
||||
'Roles' => 'Rôles',
|
||||
'Create Role' => 'Créer Rôle',
|
||||
'Name' => 'Nom',
|
||||
'Type' => 'Type',
|
||||
'Description' => 'Description',
|
||||
'Rule Name' => 'Nom de la règle',
|
||||
'Data' => 'Données',
|
||||
'Update Role' => 'Modifier Rôle',
|
||||
'Delete' => 'Supprimer',
|
||||
'Are you sure to delete this item?' => 'Etes-vous sûr de vouloir supprimer cet item ?',
|
||||
'ID' => 'ID',
|
||||
'Parent' => 'Parent',
|
||||
'Parent Name' => 'Nom Parent',
|
||||
'Route' => 'Route',
|
||||
'Username' => 'Nom d\'utilisateur',
|
||||
'Update Permission' => 'Modifier Autorisation',
|
||||
'Permissions' => 'Autorisations',
|
||||
'Permission' => 'Autorisation',
|
||||
'Create Permission' => 'Créer Autorisation',
|
||||
'Create Permissions' => 'Créer Autorisations',
|
||||
'Routes' => 'Routes',
|
||||
'Create route' => 'Créer route',
|
||||
'New' => 'Nouveau',
|
||||
'Generate Routes' => 'Générer Routes',
|
||||
'Append' => 'Ajouter',
|
||||
'Create Rule' => 'Créer Règle',
|
||||
'Rules' => 'Règles',
|
||||
'Update Rule' => 'Modifier Règle',
|
||||
'Create Menu' => 'Créer Menu',
|
||||
'Menus' => 'Menus',
|
||||
'Search' => 'Rechercher',
|
||||
'Reset' => 'Réinitialiser',
|
||||
'Update Menu' => 'Modifier Menu',
|
||||
'Menus' => 'Menus',
|
||||
'Order' => 'Ordre',
|
||||
'Class Name' => 'Nom de la Classe',
|
||||
'Assignment' => 'Assignement',
|
||||
'Role' => 'Rôle',
|
||||
'Rule' => 'Règle',
|
||||
'Menu' => 'Menu',
|
||||
'Help' => 'Aide',
|
||||
'Application' => 'Application',
|
||||
];
|
||||
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Message translations for \mdmsoft\yii2-admin.
|
||||
*
|
||||
* It contains the localizable messages extracted from source code.
|
||||
* You may modify this file by translating the extracted messages.
|
||||
*
|
||||
* Each array element represents the translation (value) of a message (key).
|
||||
* If the value is empty, the message is considered as not translated.
|
||||
* Messages that no longer need translation will have their translations
|
||||
* enclosed between a pair of '@@' marks.
|
||||
*
|
||||
* Message string can be used with plural forms format. Check i18n section
|
||||
* of the guide for details.
|
||||
*
|
||||
* NOTE: this file must be saved in UTF-8 encoding.
|
||||
*/
|
||||
return [
|
||||
'Assignments' => 'Dodjeljivanje prava',
|
||||
'Users' => 'Korisnici',
|
||||
'User' => 'Korisnik',
|
||||
'Avaliable' => 'Dostupno',
|
||||
'Assigned' => 'Dodjeljeno',
|
||||
'Create' => 'Kreiraj',
|
||||
'Update' => 'Ažuriraj',
|
||||
'Roles' => 'Uloge',
|
||||
'Create Role' => 'Kreiraj ulogu',
|
||||
'Name' => 'Naziv',
|
||||
'Type' => 'Tip',
|
||||
'Description' => 'Opis',
|
||||
'Rule Name' => 'Naziv pravila',
|
||||
'Data' => 'Podaci',
|
||||
'Update Role' => 'Ažuriraj ulogu',
|
||||
'Delete' => 'Izbriši',
|
||||
'Are you sure to delete this item?' => 'Potvrdite brisanje',
|
||||
'ID' => 'ID',
|
||||
'Parent' => 'Roditelj',
|
||||
'Parent Name' => 'Naziv roditelja',
|
||||
'Route' => 'Ruta',
|
||||
'Username' => 'Korisničko ime',
|
||||
'Update Permission' => 'Ažuriraj dopuštenje',
|
||||
'Permissions' => 'Dopuštenja',
|
||||
'Permission' => 'Dopuštenje',
|
||||
'Create Permission' => 'Kreiraj dopuštenje',
|
||||
'Create Permissions' => 'Kreiraj dopuštenja',
|
||||
'Routes' => 'Rute',
|
||||
'Create route' => 'Kreiraj rutu',
|
||||
'New' => 'Novo',
|
||||
'Generate Routes' => 'Generiraj rute',
|
||||
'Append' => 'Dodaj',
|
||||
'Create Rule' => 'Kreiraj pravilo',
|
||||
'Rules' => 'Pravila',
|
||||
'Update Rule' => 'Ažuriraj pravilo',
|
||||
'Create Menu' => 'Kreiraj izbornik',
|
||||
'Menus' => 'Izbornici',
|
||||
'Search' => 'Traži',
|
||||
'Reset' => 'Resetiraj',
|
||||
'Update Menu' => 'Ažuriraj izbornik',
|
||||
'Menus' => 'Izbornici',
|
||||
'Order' => 'Redosljed',
|
||||
'Class Name' => 'Naziv klase',
|
||||
'Assignment' => 'Dodjeljivanje',
|
||||
'Role' => 'Uloge',
|
||||
'Rule' => 'Pravila',
|
||||
'Menu' => 'Izbornici',
|
||||
'Help' => 'Pomoć',
|
||||
'Application' => 'Aplikacija',
|
||||
];
|
||||
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Message translations for \mdmsoft\yii2-admin.
|
||||
*
|
||||
* It contains the localizable messages extracted from source code.
|
||||
* You may modify this file by translating the extracted messages.
|
||||
*
|
||||
* Each array element represents the translation (value) of a message (key).
|
||||
* If the value is empty, the message is considered as not translated.
|
||||
* Messages that no longer need translation will have their translations
|
||||
* enclosed between a pair of '@@' marks.
|
||||
*
|
||||
* Message string can be used with plural forms format. Check i18n section
|
||||
* of the guide for details.
|
||||
*
|
||||
* NOTE: this file must be saved in UTF-8 encoding.
|
||||
*/
|
||||
return [
|
||||
'Assignments' => 'Assegnazioni',
|
||||
'Users' => 'Utenti',
|
||||
'User' => 'Utente',
|
||||
'Avaliable' => 'Disponibile',
|
||||
'Assigned' => 'Assegnato',
|
||||
'Create' => 'Crea',
|
||||
'Update' => 'Aggiorna',
|
||||
'Roles' => 'Ruoli',
|
||||
'Create Role' => 'Crea ruolo',
|
||||
'Name' => 'Nome',
|
||||
'Type' => 'Tipo',
|
||||
'Description' => 'Descrizione',
|
||||
'Rule Name' => 'Nome della regola',
|
||||
'Data' => 'Data',
|
||||
'Update Role' => 'Aggiorna ruolo',
|
||||
'Delete' => 'Elimina',
|
||||
'Are you sure to delete this item?' => 'Sei certo di voler eliminare questa voce?',
|
||||
'ID' => 'ID',
|
||||
'Parent' => 'Genitore',
|
||||
'Parent Name' => 'Nome del genitore',
|
||||
'Route' => 'Rotta',
|
||||
'Username' => 'Nome utente',
|
||||
'Update Permission' => 'Aggiorna permesso',
|
||||
'Permissions' => 'Permessi',
|
||||
'Permission' => 'Permesso',
|
||||
'Create Permission' => 'Crea permesso',
|
||||
'Create Permissions' => 'Crea permessi',
|
||||
'Routes' => 'Rotte',
|
||||
'Create route' => 'Crea rotta',
|
||||
'New' => 'Nuova',
|
||||
'Generate Routes' => 'Genera rotte',
|
||||
'Append' => 'Appendi',
|
||||
'Create Rule' => 'Crea regola',
|
||||
'Rules' => 'Regole',
|
||||
'Update Rule' => 'Aggiorna regola',
|
||||
'Create Menu' => 'Crea Menu',
|
||||
'Menus' => 'Menu',
|
||||
'Search' => 'Cerca',
|
||||
'Reset' => 'Ripristina',
|
||||
'Update Menu' => 'Aggiorna Menu',
|
||||
'Menus' => 'Menu',
|
||||
'Order' => 'Ordinamento',
|
||||
'Class Name' => 'Nome della classe',
|
||||
'Assignment' => 'Assegnazione',
|
||||
'Role' => 'Ruolo',
|
||||
'Rule' => 'Regola',
|
||||
'Menu' => 'Menu',
|
||||
'Help' => 'Guida',
|
||||
'Application' => 'Applicazione',
|
||||
];
|
||||
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
/**
|
||||
* Message translations.
|
||||
*
|
||||
* This file is automatically generated by 'yii message' command.
|
||||
* It contains the localizable messages extracted from source code.
|
||||
* You may modify this file by translating the extracted messages.
|
||||
*
|
||||
* Each array element represents the translation (value) of a message (key).
|
||||
* If the value is empty, the message is considered as not translated.
|
||||
* Messages that no longer need translation will have their translations
|
||||
* enclosed between a pair of '@@' marks.
|
||||
*
|
||||
* Message string can be used with plural forms format. Check i18n section
|
||||
* of the guide for details.
|
||||
*
|
||||
* NOTE: this file must be saved in UTF-8 encoding.
|
||||
*/
|
||||
return [
|
||||
'Append' => '追加',
|
||||
'Application' => 'アプリケーション',
|
||||
'Are you sure to delete this item?' => 'この項目を削除します。よろしいですか?',
|
||||
'Assigned' => '割当て済み',
|
||||
'Assignment' => '権限の割当て',
|
||||
'Assignments' => '権限の割当て',
|
||||
'Avaliable' => '割当て可能',
|
||||
'Class Name' => 'クラス名',
|
||||
'Create' => '作成',
|
||||
'Create Menu' => 'メニューを作成',
|
||||
'Create Permission' => '許可を作成',
|
||||
'Create Role' => 'ロールを作成',
|
||||
'Create Route' => 'ルートを作成',
|
||||
'Create Rule' => '規則を作成',
|
||||
'Create route' => 'ルートを作成',
|
||||
'Data' => 'データ',
|
||||
'Delete' => '削除',
|
||||
'Description' => '説明',
|
||||
'Generate Routes' => 'ルートを生成',
|
||||
'Help' => 'ヘルプ',
|
||||
'ID' => 'ID',
|
||||
'Menus' => 'メニュー',
|
||||
'Name' => '名前',
|
||||
'Order' => '順序',
|
||||
'Parent' => '親',
|
||||
'Parent Name' => '親の名前',
|
||||
'Permission' => '許可',
|
||||
'Permissions' => '許可',
|
||||
'Reset' => 'リセット',
|
||||
'Roles' => 'ロール',
|
||||
'Route' => 'ルート',
|
||||
'Routes' => 'ルート',
|
||||
'Rule Name' => '規則の名前',
|
||||
'Rules' => '規則',
|
||||
'Search' => '検索',
|
||||
'Type' => 'タイプ',
|
||||
'Update' => '更新',
|
||||
'Update Menu' => 'メニューを更新',
|
||||
'Update Permission' => '許可を更新',
|
||||
'Update Role' => 'ロールを更新',
|
||||
'Update Rule' => '規則を更新',
|
||||
'User' => 'ユーザ',
|
||||
'Username' => 'ユーザ名',
|
||||
'Users' => 'ユーザ',
|
||||
];
|
||||
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Message translations for \mdmsoft\yii2-admin.
|
||||
*
|
||||
* It contains the localizable messages extracted from source code.
|
||||
* You may modify this file by translating the extracted messages.
|
||||
*
|
||||
* Each array element represents the translation (value) of a message (key).
|
||||
* If the value is empty, the message is considered as not translated.
|
||||
* Messages that no longer need translation will have their translations
|
||||
* enclosed between a pair of '@@' marks.
|
||||
*
|
||||
* Message string can be used with plural forms format. Check i18n section
|
||||
* of the guide for details.
|
||||
*
|
||||
* NOTE: this file must be saved in UTF-8 encoding.
|
||||
*/
|
||||
return [
|
||||
'Assignments' => 'Toekenning',
|
||||
'Users' => 'Gebruikers',
|
||||
'User' => 'Gebruiker',
|
||||
'Avaliable' => 'Beschikbaar',
|
||||
'Assigned' => 'Toegekend',
|
||||
'Create' => 'Aanmaken',
|
||||
'Update' => 'Opslaan',
|
||||
'Roles' => 'Gebruikers rollen',
|
||||
'Create Role' => 'Nieuwe rol',
|
||||
'Name' => 'Naam',
|
||||
'Type' => 'Type',
|
||||
'Description' => 'Omschrijving',
|
||||
'Rule Name' => 'Rule naam',
|
||||
'Data' => 'Data',
|
||||
'Update Role' => 'Bewerk rol',
|
||||
'Delete' => 'Verwijderen',
|
||||
'Are you sure to delete this item?' => 'Weet u zeker dat u dit wilt verwijderen?',
|
||||
'ID' => 'ID',
|
||||
'Parent' => 'Ouder',
|
||||
'Parent Name' => 'Ouder naam',
|
||||
'Route' => 'Route',
|
||||
'Username' => 'Gebruiker',
|
||||
'Update Permission' => 'Bewerk authorisatie',
|
||||
'Permissions' => 'Authorisaties',
|
||||
'Permission' => 'Authorisatie',
|
||||
'Create Permission' => 'Nieuwe authorisatie',
|
||||
'Create Permissions' => 'Nieuwe authorisaties',
|
||||
'Routes' => 'Routes',
|
||||
'Create route' => 'Nieuwe Route',
|
||||
'New' => 'Nieuw',
|
||||
'Generate Routes' => 'Genereer Routes',
|
||||
'Append' => 'Toevoegen',
|
||||
'Create Rule' => 'Nieuwe Rule',
|
||||
'Rules' => 'Rules',
|
||||
'Update Rule' => 'Bewerk Rule',
|
||||
'Create Menu' => 'Nieuw Menu',
|
||||
'Menus' => 'Menus',
|
||||
'Search' => 'Zoek',
|
||||
'Reset' => 'Reset',
|
||||
'Update Menu' => 'Bewerk Menu',
|
||||
'Menus' => 'Menus',
|
||||
'Order' => 'Volgorde',
|
||||
'Class Name' => 'Class Name',
|
||||
'Assignment' => 'Toekenning',
|
||||
'Role' => 'Rol',
|
||||
'Rule' => 'Rule',
|
||||
'Menu' => 'Menu',
|
||||
'Help' => 'Help',
|
||||
'Application' => 'Applicatie',
|
||||
];
|
||||
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Message translations for \mdmsoft\yii2-admin.
|
||||
*
|
||||
* It contains the localizable messages extracted from source code.
|
||||
* You may modify this file by translating the extracted messages.
|
||||
*
|
||||
* Each array element represents the translation (value) of a message (key).
|
||||
* If the value is empty, the message is considered as not translated.
|
||||
* Messages that no longer need translation will have their translations
|
||||
* enclosed between a pair of '@@' marks.
|
||||
*
|
||||
* Message string can be used with plural forms format. Check i18n section
|
||||
* of the guide for details.
|
||||
*
|
||||
* NOTE: this file must be saved in UTF-8 encoding.
|
||||
*/
|
||||
return [
|
||||
'Assignments' => 'Powiązania',
|
||||
'Users' => 'Użytkownicy',
|
||||
'User' => 'Użytkownik',
|
||||
'Avaliable' => 'Dostępny',
|
||||
'Assigned' => 'Powiązany',
|
||||
'Create' => 'Utwórz',
|
||||
'Update' => 'Aktualizuj',
|
||||
'Roles' => 'Role',
|
||||
'Create Role' => 'Utwórz Role',
|
||||
'Name' => 'Nazwa',
|
||||
'Type' => 'Typ',
|
||||
'Description' => 'Opis',
|
||||
'Rule Name' => 'Nazwa Reguły',
|
||||
'Data' => 'Data',
|
||||
'Update Role' => 'Aktualizuj Role',
|
||||
'Delete' => 'Usuń',
|
||||
'Are you sure to delete this item?' => 'Czy napewno chcesz usunąć ten element?',
|
||||
'ID' => 'ID',
|
||||
'Parent' => 'Parent',
|
||||
'Parent Name' => 'Parent Name',
|
||||
'Route' => 'Route',
|
||||
'Username' => 'Nazwa użytkownika',
|
||||
'Update Permission' => 'Aktualizuj Uprawnienia',
|
||||
'Permissions' => 'Uprawnienia',
|
||||
'Permission' => 'Uprawnienie',
|
||||
'Create Permission' => 'Utwórz Uprawnienie',
|
||||
'Create Permissions' => 'Utwórz Uprawnienia',
|
||||
'Routes' => 'Ścieżki',
|
||||
'Create route' => 'Stwórz Ścieżkę',
|
||||
'New' => 'Nowy',
|
||||
'Generate Routes' => 'Wygeneruj Ścieżkę',
|
||||
'Append' => 'Dopisz',
|
||||
'Create Rule' => 'Utwórz regułę',
|
||||
'Rules' => 'Reguły',
|
||||
'Update Rule' => 'Aktualizuj Regułę',
|
||||
'Create Menu' => 'Stwórz Menu',
|
||||
'Menus' => 'Menus',
|
||||
'Search' => 'Szukaj',
|
||||
'Reset' => 'Reset',
|
||||
'Update Menu' => 'Aktualizuj Menu',
|
||||
'Menus' => 'Menus',
|
||||
'Order' => 'Order',
|
||||
'Class Name' => 'Class Name',
|
||||
'Assignment' => 'Assignment',
|
||||
'Role' => 'Rola',
|
||||
'Rule' => 'Reguła',
|
||||
'Menu' => 'Menu',
|
||||
'Help' => 'Pomoc',
|
||||
'Application' => 'Aplikacja',
|
||||
];
|
||||
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Message translations for \mdmsoft\yii2-admin.
|
||||
*
|
||||
* It contains the localizable messages extracted from source code.
|
||||
* You may modify this file by translating the extracted messages.
|
||||
*
|
||||
* Each array element represents the translation (value) of a message (key).
|
||||
* If the value is empty, the message is considered as not translated.
|
||||
* Messages that no longer need translation will have their translations
|
||||
* enclosed between a pair of '@@' marks.
|
||||
*
|
||||
* Message string can be used with plural forms format. Check i18n section
|
||||
* of the guide for details.
|
||||
*
|
||||
* NOTE: this file must be saved in UTF-8 encoding.
|
||||
*/
|
||||
return [
|
||||
'Assignments' => 'Atribuições',
|
||||
'Users' => 'Usuários',
|
||||
'User' => 'Usuário',
|
||||
'Avaliable' => 'Disponível',
|
||||
'Assigned' => 'Atribuído',
|
||||
'Create' => 'Criar',
|
||||
'Update' => 'Atualizar',
|
||||
'Roles' => 'Funções',
|
||||
'Create Role' => 'Criar Função',
|
||||
'Name' => 'Nome',
|
||||
'Type' => 'Tipo',
|
||||
'Description' => 'Descrição',
|
||||
'Rule Name' => 'Nome da Regra',
|
||||
'Data' => 'Dados',
|
||||
'Update Role' => 'Atualizar Função',
|
||||
'Delete' => 'Deletar',
|
||||
'Are you sure to delete this item?' => 'Tem certeza que deseja excluir este item?',
|
||||
'ID' => 'ID',
|
||||
'Parent' => 'Pai',
|
||||
'Parent Name' => 'Nome pai',
|
||||
'Route' => 'Rota',
|
||||
'Username' => 'Usuário',
|
||||
'Update Permission' => 'Atualizar Permissão',
|
||||
'Permissions' => 'Permissões',
|
||||
'Permission' => 'Permissão',
|
||||
'Create Permission' => 'Criar Permissão',
|
||||
'Create Permissions' => 'Criar Permissões',
|
||||
'Routes' => 'Rotas',
|
||||
'Create route' => 'Criar Rotas',
|
||||
'New' => 'Novo',
|
||||
'Generate Routes' => 'Gerar Rotas',
|
||||
'Append' => 'Anexar',
|
||||
'Create Rule' => 'Criar Regra',
|
||||
'Rules' => 'Regras',
|
||||
'Update Rule' => 'Atualizar Regra',
|
||||
'Create Menu' => 'Criar Menu',
|
||||
'Menus' => 'Menus',
|
||||
'Search' => 'Pesquisa',
|
||||
'Reset' => 'Resetar',
|
||||
'Update Menu' => 'Atualizar Menu',
|
||||
'Menus' => 'Menus',
|
||||
'Order' => 'Ordem',
|
||||
'Class Name' => 'Nome da Classe',
|
||||
'Assignment' => 'Atribuição',
|
||||
'Role' => 'Função',
|
||||
'Rule' => 'Regra',
|
||||
'Menu' => 'Menu',
|
||||
'Help' => 'Ajuda',
|
||||
'Application' => 'Aplicação',
|
||||
];
|
||||
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Message translations for \mdmsoft\yii2-admin.
|
||||
*
|
||||
* It contains the localizable messages extracted from source code.
|
||||
* You may modify this file by translating the extracted messages.
|
||||
*
|
||||
* Each array element represents the translation (value) of a message (key).
|
||||
* If the value is empty, the message is considered as not translated.
|
||||
* Messages that no longer need translation will have their translations
|
||||
* enclosed between a pair of '@@' marks.
|
||||
*
|
||||
* Message string can be used with plural forms format. Check i18n section
|
||||
* of the guide for details.
|
||||
*
|
||||
* NOTE: this file must be saved in UTF-8 encoding.
|
||||
*/
|
||||
return [
|
||||
'Assignments' => 'Назначения',
|
||||
'Users' => 'Пользователи',
|
||||
'User' => 'Пользователь',
|
||||
'Avaliable' => 'Доступно',
|
||||
'Assigned' => 'Назначено',
|
||||
'Create' => 'Создать',
|
||||
'Update' => 'Обновить',
|
||||
'Roles' => 'Роли',
|
||||
'Create Role' => 'Создать роль',
|
||||
'Name' => 'Имя',
|
||||
'Type' => 'Тип',
|
||||
'Description' => 'Описание',
|
||||
'Rule Name' => 'Имя правила',
|
||||
'Data' => 'Данные',
|
||||
'Update Role' => 'Обновить роль',
|
||||
'Delete' => 'Удалить',
|
||||
'Are you sure to delete this item?' => 'Вы действительно хотите удалить этот элемент?',
|
||||
'ID' => 'ID',
|
||||
'Parent' => 'Родитель',
|
||||
'Parent Name' => 'Имя родителя',
|
||||
'Route' => 'Маршрут',
|
||||
'Username' => 'Имя пользователя',
|
||||
'Update Permission' => 'Обновить разрешение',
|
||||
'Permissions' => 'Разрешения',
|
||||
'Permission' => 'Разрешение',
|
||||
'Create Permission' => 'Создать разрешение',
|
||||
'Create Permissions' => 'Создать разрешения',
|
||||
'Routes' => 'Маршруты',
|
||||
'Create route' => 'Создать маршрут',
|
||||
'New' => 'Новый',
|
||||
'Generate Routes' => 'Сгенерировать маршруты',
|
||||
'Append' => 'Добавить',
|
||||
'Create Rule' => 'Создать правило',
|
||||
'Rules' => 'Правила',
|
||||
'Update Rule' => 'Обновить правило',
|
||||
'Create Menu' => 'Создать меню',
|
||||
'Menus' => 'Меню',
|
||||
'Search' => 'Поиск',
|
||||
'Reset' => 'Сбросить',
|
||||
'Update Menu' => 'Обновить меню',
|
||||
'Order' => 'Порядок',
|
||||
'Class Name' => 'Имя класса',
|
||||
'Assignment' => 'Назначение',
|
||||
'Role' => 'Роль',
|
||||
'Rule' => 'Правило',
|
||||
'Menu' => 'Меню',
|
||||
'Help' => 'Помощь',
|
||||
'Application' => 'Приложение',
|
||||
'Search for avaliable' => 'Поиск по доступным',
|
||||
'Search for assigned' => 'Поиск по присвоенным',
|
||||
'New route(s)' => 'Новый маршрут',
|
||||
'Add' => 'Добавить',
|
||||
'Assign' => 'Назначить',
|
||||
'Remove' => 'Удалить',
|
||||
' --select rule' => ' --выберите правило'
|
||||
];
|
||||
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
/**
|
||||
* Message translations for \mdmsoft\yii2-admin.
|
||||
*
|
||||
* It contains the localizable messages extracted from source code.
|
||||
* You may modify this file by translating the extracted messages.
|
||||
*
|
||||
* Each array element represents the translation (value) of a message (key).
|
||||
* If the value is empty, the message is considered as not translated.
|
||||
* Messages that no longer need translation will have their translations
|
||||
* enclosed between a pair of '@@' marks.
|
||||
*
|
||||
* Message string can be used with plural forms format. Check i18n section
|
||||
* of the guide for details.
|
||||
*
|
||||
* NOTE: this file must be saved in UTF-8 encoding.
|
||||
*/
|
||||
return [
|
||||
'Assignments' => 'การกำหนด',
|
||||
'Users' => 'ผู้ใช้งาน',
|
||||
'User' => 'ผู้ใช้งาน',
|
||||
'Avaliable' => 'ที่มีอยู่',
|
||||
'Assigned' => 'ที่กำหนดให้',
|
||||
'Create' => 'สร้าง',
|
||||
'Update' => 'ปรับปรุง',
|
||||
'Roles' => 'บทบาท',
|
||||
'Create Role' => 'สร้างบทบาท',
|
||||
'Name' => 'ชื่อ',
|
||||
'Type' => 'ชนิด',
|
||||
'Description' => 'รายละเอียด',
|
||||
'Rule Name' => 'ชื่อกฏ',
|
||||
'Data' => 'ข้อมูล',
|
||||
'Update Role' => 'ปรับปรุงกฏ',
|
||||
'Delete' => 'ลบ',
|
||||
'Are you sure to delete this item?' => 'คุณแน่ใจนะว่าต้องการลบอันนี้?',
|
||||
'ID' => 'ไอดี',
|
||||
'Parent' => 'ตัวหลัก',
|
||||
'Parent Name' => 'ชื่อ ตัวหลัก',
|
||||
'Route' => 'เส้นทาง',
|
||||
'Username' => 'ชื่อผู้ใช้งาน',
|
||||
'Update Permission' => 'ปรับปรุงสิทธิ์',
|
||||
'Permissions' => 'สิทธิ์',
|
||||
'Permission' => 'สิทธิ์',
|
||||
'Create Permission' => 'สร้างสิทธิ์',
|
||||
'Create Permissions' => 'สร้างสิทธิ์',
|
||||
'Routes' => 'เส้นทาง',
|
||||
'Create route' => 'สร้างเส้นทาง',
|
||||
'New' => 'ใหม่',
|
||||
'Generate Routes' => 'สร้างเส้นทางอัตโนมัติ',
|
||||
'Append' => 'ผนวก',
|
||||
'Create Rule' => 'สร้างกฏ',
|
||||
'Rules' => 'กฏ',
|
||||
'Update Rule' => 'ปรับปรุงกฏ',
|
||||
'Create Menu' => 'สร้างเมนู',
|
||||
'Menus' => 'เมนู',
|
||||
'Search' => 'ค้นหา',
|
||||
'Reset' => 'เริ่มใหม่',
|
||||
'Update Menu' => 'ปรับปรุงเมนู',
|
||||
'Menus' => 'เมนู',
|
||||
'Order' => 'เรียงลำดับ',
|
||||
'Class Name' => 'ชื่อคลาส',
|
||||
'Assignment' => 'การกำหนด',
|
||||
'Role' => 'บทบาท',
|
||||
'Rule' => 'กฏ',
|
||||
'Menu' => 'เมนู',
|
||||
'Help' => 'ช่วยเหลือ',
|
||||
'Application' => 'แอพพลิเคชั่น',
|
||||
];
|
||||
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
/**
|
||||
* Message translations.
|
||||
*
|
||||
* This file is automatically generated by 'yii message' command.
|
||||
* It contains the localizable messages extracted from source code.
|
||||
* You may modify this file by translating the extracted messages.
|
||||
*
|
||||
* Each array element represents the translation (value) of a message (key).
|
||||
* If the value is empty, the message is considered as not translated.
|
||||
* Messages that no longer need translation will have their translations
|
||||
* enclosed between a pair of '@@' marks.
|
||||
*
|
||||
* Message string can be used with plural forms format. Check i18n section
|
||||
* of the guide for details.
|
||||
*
|
||||
* NOTE: this file must be saved in UTF-8 encoding.
|
||||
* @author dinhtrung.
|
||||
*/
|
||||
return [
|
||||
'Append' => 'Thêm vào',
|
||||
'Application' => 'Ứng dụng',
|
||||
'Are you sure to delete this item?' => 'Bạn có chắc chắn xóa mục này?',
|
||||
'Assigned' => 'Giao',
|
||||
'Assignments' => 'Cấp quyền',
|
||||
'Avaliable' => 'Có sẵn',
|
||||
'Class Name' => 'Tên lớp',
|
||||
'Create' => 'Tạo mới',
|
||||
'Create Menu' => 'tạo menu',
|
||||
'Create Permission' => 'Tạo Quyền',
|
||||
'Create Role' => 'Tạo Vai trò',
|
||||
'Create Route' => 'Tạo Route',
|
||||
'Create Rule' => 'Tạo Quy tắc',
|
||||
'Create route' => 'Tạo Route',
|
||||
'Data' => 'Dữ liệu',
|
||||
'Delete' => 'Xóa bỏ',
|
||||
'Description' => 'Mô tả',
|
||||
'Generate Routes' => 'Tạo Route',
|
||||
'Help' => 'Trợ giúp',
|
||||
'ID' => 'ID',
|
||||
'Menus' => 'Trình đơn',
|
||||
'Name' => 'Tên',
|
||||
'Order' => 'Thứ tự',
|
||||
'Parent' => 'Cha mẹ',
|
||||
'Parent Name' => 'Tên cha',
|
||||
'Permission' => 'Quyền',
|
||||
'Permissions' => 'Quyền',
|
||||
'Reset' => 'Thiết lập lại',
|
||||
'Roles' => 'Vai trò',
|
||||
'Route' => 'Route',
|
||||
'Routes' => 'Các Route',
|
||||
'Rule Name' => 'Tên Quy tắc',
|
||||
'Rules' => 'Quy tắc',
|
||||
'Search' => 'Tìm kiếm',
|
||||
'Type' => 'Kiểu',
|
||||
'Update' => 'Sửa',
|
||||
'Update Menu' => 'Sửa Menu',
|
||||
'Update Permission' => 'Sửa Quyền',
|
||||
'Update Role' => 'Sửa Vai trò',
|
||||
'Update Rule' => 'Sửa Quy tắc',
|
||||
'Username' => 'Tên đăng nhập',
|
||||
];
|
||||
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
/**
|
||||
* Message translations for \mdmsoft\yii2-admin.
|
||||
*
|
||||
* It contains the localizable messages extracted from source code.
|
||||
* You may modify this file by translating the extracted messages.
|
||||
*
|
||||
* Each array element represents the translation (value) of a message (key).
|
||||
* If the value is empty, the message is considered as not translated.
|
||||
* Messages that no longer need translation will have their translations
|
||||
* enclosed between a pair of '@@' marks.
|
||||
*
|
||||
* Message string can be used with plural forms format. Check i18n section
|
||||
* of the guide for details.
|
||||
*
|
||||
* NOTE: this file must be saved in UTF-8 encoding.
|
||||
*/
|
||||
return [
|
||||
'Assignments' => '分配',
|
||||
'Users' => '用户列表',
|
||||
'User' => '用户',
|
||||
'Avaliable' => '可用',
|
||||
'Assigned' => '分配',
|
||||
'Create' => '新增',
|
||||
'Update' => '更新',
|
||||
'Roles' => '角色列表',
|
||||
'Create Role' => '创建角色',
|
||||
'Name' => '名称',
|
||||
'Type' => '类型',
|
||||
'Description' => '描述',
|
||||
'Rule Name' => '规则名称',
|
||||
'Data' => '数据',
|
||||
'Update Role' => '更新角色',
|
||||
'Delete' => '删除',
|
||||
'Add' => '添加',
|
||||
'Are you sure to delete this item?' => '确认要删除吗?',
|
||||
'ID' => 'ID',
|
||||
'Parent' => '父级',
|
||||
'Parent Name' => '父级名称',
|
||||
'Route' => '路由',
|
||||
'Username' => '用户名',
|
||||
'Update Permission' => '更新权限',
|
||||
'Permissions' => '权限列表',
|
||||
'Permission' => '权限',
|
||||
'Create Permission' => '新增权限',
|
||||
'Create Permissions' => '新增权限列表',
|
||||
'Routes' => '路由列表',
|
||||
'Create route' => '新增路由',
|
||||
'New' => '新增',
|
||||
'Generate Routes' => '生成路由',
|
||||
'Append' => '追加',
|
||||
'Create Rule' => '新增规则',
|
||||
'Rules' => '规则列表',
|
||||
'Update Rule' => '更新规则',
|
||||
'Create Menu' => '新增菜单',
|
||||
'Menus' => '菜单列表',
|
||||
'Search' => '查询',
|
||||
'Reset' => '重置',
|
||||
'Update Menu' => '更新菜单',
|
||||
'Menus' => '菜单列表',
|
||||
'Order' => '排序',
|
||||
'Class Name' => '类名',
|
||||
'Assignment' => '分配',
|
||||
'Role' => '角色',
|
||||
'Rule' => '规则',
|
||||
'Menu' => '菜单',
|
||||
'Help' => '帮助',
|
||||
'Application' => '应用',
|
||||
'Search for assigned' => '搜索已分配项',
|
||||
'Search for avaliable' => '搜索剩余可用项',
|
||||
'New route(s)' => '添加新路由',
|
||||
];
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
use mdm\admin\components\Configs;
|
||||
|
||||
/**
|
||||
* Migration table of table_menu
|
||||
*
|
||||
* @author Misbahul D Munir <misbahuldmunir@gmail.com>
|
||||
* @since 1.0
|
||||
*/
|
||||
class m140602_111327_create_menu_table extends \yii\db\Migration
|
||||
{
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
$menuTable = Configs::instance()->menuTable;
|
||||
$tableOptions = null;
|
||||
if ($this->db->driverName === 'mysql') {
|
||||
$tableOptions = 'CHARACTER SET utf8 COLLATE utf8_general_ci ENGINE=InnoDB';
|
||||
}
|
||||
|
||||
$this->createTable($menuTable, [
|
||||
'id' => $this->primaryKey(),
|
||||
'name' => $this->string(128)->notNull(),
|
||||
'parent' => $this->integer(),
|
||||
'route' => $this->string(),
|
||||
'order' => $this->integer(),
|
||||
'data' => $this->binary(),
|
||||
"FOREIGN KEY ([[parent]]) REFERENCES {$menuTable}([[id]]) ON DELETE SET NULL ON UPDATE CASCADE",
|
||||
], $tableOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
$this->dropTable(Configs::instance()->menuTable);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
use yii\db\Migration;
|
||||
use mdm\admin\components\Configs;
|
||||
|
||||
class m160312_050000_create_user extends Migration
|
||||
{
|
||||
|
||||
public function up()
|
||||
{
|
||||
$tableOptions = null;
|
||||
if ($this->db->driverName === 'mysql') {
|
||||
// http://stackoverflow.com/questions/766809/whats-the-difference-between-utf8-general-ci-and-utf8-unicode-ci
|
||||
$tableOptions = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB';
|
||||
}
|
||||
|
||||
$userTable = Configs::instance()->userTable;
|
||||
|
||||
// Check if the table exists
|
||||
if ($this->db->schema->getTableSchema($userTable, true) === null) {
|
||||
$this->createTable($userTable, [
|
||||
'id' => $this->primaryKey(),
|
||||
'username' => $this->string(32)->notNull(),
|
||||
'auth_key' => $this->string(32)->notNull(),
|
||||
'password_hash' => $this->string()->notNull(),
|
||||
'password_reset_token' => $this->string(),
|
||||
'email' => $this->string()->notNull(),
|
||||
'status' => $this->smallInteger()->notNull()->defaultValue(10),
|
||||
'created_at' => $this->integer()->notNull(),
|
||||
'updated_at' => $this->integer()->notNull(),
|
||||
], $tableOptions);
|
||||
}
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$userTable = Configs::instance()->userTable;
|
||||
if ($this->db->schema->getTableSchema($userTable, true) !== null) {
|
||||
$this->dropTable($userTable);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* Database schema required by yii2-admin.
|
||||
*
|
||||
* @author Misbahul D Munir <misbahuldmunir@gmail.com>
|
||||
* @since 2.5
|
||||
*/
|
||||
|
||||
drop table if exists [menu];
|
||||
drop table if exists [user];
|
||||
|
||||
create table [menu]
|
||||
(
|
||||
[id] int IDENTITY PRIMARY KEY,
|
||||
[name] varchar(128),
|
||||
[parent] int(11),
|
||||
[route] varchar(256),
|
||||
[order] int(11),
|
||||
[data] text,
|
||||
foreign key (parent) references [menu]([id]) ON DELETE SET NULL ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
create table [user]
|
||||
(
|
||||
[id] int IDENTITY PRIMARY KEY,
|
||||
[username] varchar(32) NOT NULL,
|
||||
[auth_key] varchar(32) NOT NULL,
|
||||
[password_hash] varchar(256) NOT NULL,
|
||||
[password_reset_token] varchar(256),
|
||||
[email] varchar(256) NOT NULL,
|
||||
[status] integer not null default 10,
|
||||
[created_at] integer not null,
|
||||
[updated_at] integer not null
|
||||
);
|
||||
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* Database schema required by yii2-admin.
|
||||
*
|
||||
* @author Misbahul D Munir <misbahuldmunir@gmail.com>
|
||||
* @since 2.5
|
||||
*/
|
||||
|
||||
drop table if exists `menu`;
|
||||
drop table if exists `user` cascade;
|
||||
|
||||
create table `menu`
|
||||
(
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
`name` varchar(128),
|
||||
`parent` int(11),
|
||||
`route` varchar(256),
|
||||
`order` int(11),
|
||||
`data` blob,
|
||||
foreign key (`parent`) references `menu`(`id`) ON DELETE SET NULL ON UPDATE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
create table `user`
|
||||
(
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
`username` varchar(32) NOT NULL,
|
||||
`auth_key` varchar(32) NOT NULL,
|
||||
`password_hash` varchar(256) NOT NULL,
|
||||
`password_reset_token` varchar(256),
|
||||
`email` varchar(256) NOT NULL,
|
||||
`status` integer not null default 10,
|
||||
`created_at` integer not null,
|
||||
`updated_at` integer not null
|
||||
)ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* Database schema required by yii2-admin.
|
||||
*
|
||||
* @author Misbahul D Munir <misbahuldmunir@gmail.com>
|
||||
* @since 2.5
|
||||
*/
|
||||
|
||||
drop table if exists "menu";
|
||||
drop table if exists "user";
|
||||
|
||||
create table "menu"
|
||||
(
|
||||
"id" NUMBER(10) NOT NULL PRIMARY KEY,
|
||||
"name" varchar(128),
|
||||
"parent" number(10),
|
||||
"route" varchar(256),
|
||||
"order" number(10),
|
||||
"data" BYTEA,
|
||||
foreign key (parent) references "menu"("id") ON DELETE SET NULL ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
create table "user"
|
||||
(
|
||||
"id" NUMBER(10) NOT NULL PRIMARY KEY,
|
||||
"username" varchar(32) NOT NULL,
|
||||
"auth_key" varchar(32) NOT NULL,
|
||||
"password_hash" varchar(256) NOT NULL,
|
||||
"password_reset_token" varchar(256),
|
||||
"email" varchar(256) NOT NULL,
|
||||
"status" integer not null default 10,
|
||||
"created_at" number(10) not null,
|
||||
"updated_at" number(10) not null
|
||||
);
|
||||
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* Database schema required by yii2-admin.
|
||||
*
|
||||
* @author Misbahul D Munir <misbahuldmunir@gmail.com>
|
||||
* @since 2.5
|
||||
*/
|
||||
|
||||
drop table if exists "menu";
|
||||
drop table if exists "user";
|
||||
|
||||
create table "menu"
|
||||
(
|
||||
"id" serial NOT NULL PRIMARY KEY,
|
||||
"name" varchar(128),
|
||||
"parent" integer,
|
||||
"route" varchar(256),
|
||||
"order" integer,
|
||||
"data" bytea,
|
||||
foreign key ("parent") references "menu"("id") ON DELETE SET NULL ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
create table "user"
|
||||
(
|
||||
"id" serial NOT NULL PRIMARY KEY,
|
||||
"username" varchar(32) NOT NULL,
|
||||
"auth_key" varchar(32) NOT NULL,
|
||||
"password_hash" varchar(256) NOT NULL,
|
||||
"password_reset_token" varchar(256),
|
||||
"email" varchar(256) NOT NULL,
|
||||
"status" integer not null default 10,
|
||||
"created_at" integer not null,
|
||||
"updated_at" integer not null
|
||||
);
|
||||
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* Database schema required by yii2-admin.
|
||||
*
|
||||
* @author Misbahul D Munir <misbahuldmunir@gmail.com>
|
||||
* @since 2.5
|
||||
*/
|
||||
|
||||
drop table if exists "menu";
|
||||
drop table if exists "user";
|
||||
|
||||
create table "menu"
|
||||
(
|
||||
"id" integer PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||
"name" varchar(128),
|
||||
"parent" int(11),
|
||||
"route" varchar(256),
|
||||
"order" int(11),
|
||||
"data" LONGBLOB,
|
||||
foreign key ("parent") references "menu"("id") ON DELETE SET NULL ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
create table "user"
|
||||
(
|
||||
"id" integer PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||
"username" varchar(32) NOT NULL,
|
||||
"auth_key" varchar(32) NOT NULL,
|
||||
"password_hash" varchar(256) NOT NULL,
|
||||
"password_reset_token" varchar(256),
|
||||
"email" varchar(256) NOT NULL,
|
||||
"status" integer not null default 10,
|
||||
"created_at" integer not null,
|
||||
"updated_at" integer not null
|
||||
);
|
||||
@@ -0,0 +1,121 @@
|
||||
<?php
|
||||
|
||||
namespace mdm\admin\models;
|
||||
|
||||
use Yii;
|
||||
use yii\base\BaseObject;
|
||||
use mdm\admin\components\Helper;
|
||||
|
||||
/**
|
||||
* Description of Assignment
|
||||
*
|
||||
* @author Misbahul D Munir <misbahuldmunir@gmail.com>
|
||||
* @since 2.5
|
||||
*/
|
||||
class Assignment extends BaseObject
|
||||
{
|
||||
/**
|
||||
* @var integer User id
|
||||
*/
|
||||
public $id;
|
||||
/**
|
||||
* @var \yii\web\IdentityInterface User
|
||||
*/
|
||||
public $user;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function __construct($id, $user = null, $config = array())
|
||||
{
|
||||
$this->id = $id;
|
||||
$this->user = $user;
|
||||
parent::__construct($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Grands a roles from a user.
|
||||
* @param array $items
|
||||
* @return integer number of successful grand
|
||||
*/
|
||||
public function assign($items)
|
||||
{
|
||||
$manager = Yii::$app->getAuthManager();
|
||||
$success = 0;
|
||||
foreach ($items as $name) {
|
||||
try {
|
||||
$item = $manager->getRole($name);
|
||||
$item = $item ? : $manager->getPermission($name);
|
||||
$manager->assign($item, $this->id);
|
||||
$success++;
|
||||
} catch (\Exception $exc) {
|
||||
Yii::error($exc->getMessage(), __METHOD__);
|
||||
}
|
||||
}
|
||||
Helper::invalidate();
|
||||
return $success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Revokes a roles from a user.
|
||||
* @param array $items
|
||||
* @return integer number of successful revoke
|
||||
*/
|
||||
public function revoke($items)
|
||||
{
|
||||
$manager = Yii::$app->getAuthManager();
|
||||
$success = 0;
|
||||
foreach ($items as $name) {
|
||||
try {
|
||||
$item = $manager->getRole($name);
|
||||
$item = $item ? : $manager->getPermission($name);
|
||||
$manager->revoke($item, $this->id);
|
||||
$success++;
|
||||
} catch (\Exception $exc) {
|
||||
Yii::error($exc->getMessage(), __METHOD__);
|
||||
}
|
||||
}
|
||||
Helper::invalidate();
|
||||
return $success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all avaliable and assigned roles/permission
|
||||
* @return array
|
||||
*/
|
||||
public function getItems()
|
||||
{
|
||||
$manager = Yii::$app->getAuthManager();
|
||||
$avaliable = [];
|
||||
foreach (array_keys($manager->getRoles()) as $name) {
|
||||
$avaliable[$name] = 'role';
|
||||
}
|
||||
|
||||
foreach (array_keys($manager->getPermissions()) as $name) {
|
||||
if ($name[0] != '/') {
|
||||
$avaliable[$name] = 'permission';
|
||||
}
|
||||
}
|
||||
|
||||
$assigned = [];
|
||||
foreach ($manager->getAssignments($this->id) as $item) {
|
||||
$assigned[$item->roleName] = $avaliable[$item->roleName];
|
||||
unset($avaliable[$item->roleName]);
|
||||
}
|
||||
|
||||
return[
|
||||
'avaliable' => $avaliable,
|
||||
'assigned' => $assigned
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function __get($name)
|
||||
{
|
||||
if ($this->user) {
|
||||
return $this->user->$name;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,296 @@
|
||||
<?php
|
||||
|
||||
namespace mdm\admin\models;
|
||||
|
||||
use Yii;
|
||||
use yii\rbac\Item;
|
||||
use yii\helpers\Json;
|
||||
use yii\base\Model;
|
||||
use mdm\admin\components\Helper;
|
||||
|
||||
/**
|
||||
* This is the model class for table "tbl_auth_item".
|
||||
*
|
||||
* @property string $name
|
||||
* @property integer $type
|
||||
* @property string $description
|
||||
* @property string $ruleName
|
||||
* @property string $data
|
||||
*
|
||||
* @property Item $item
|
||||
*
|
||||
* @author Misbahul D Munir <misbahuldmunir@gmail.com>
|
||||
* @since 1.0
|
||||
*/
|
||||
class AuthItem extends Model
|
||||
{
|
||||
public $name;
|
||||
public $type;
|
||||
public $description;
|
||||
public $ruleName;
|
||||
public $data;
|
||||
/**
|
||||
* @var Item
|
||||
*/
|
||||
private $_item;
|
||||
|
||||
/**
|
||||
* Initialize object
|
||||
* @param Item $item
|
||||
* @param array $config
|
||||
*/
|
||||
public function __construct($item = null, $config = [])
|
||||
{
|
||||
$this->_item = $item;
|
||||
if ($item !== null) {
|
||||
$this->name = $item->name;
|
||||
$this->type = $item->type;
|
||||
$this->description = $item->description;
|
||||
$this->ruleName = $item->ruleName;
|
||||
$this->data = $item->data === null ? null : Json::encode($item->data);
|
||||
}
|
||||
parent::__construct($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
[['ruleName'], 'checkRule'],
|
||||
[['name', 'type'], 'required'],
|
||||
[['name'], 'unique', 'when' => function() {
|
||||
return $this->isNewRecord || ($this->_item->name != $this->name);
|
||||
}],
|
||||
[['type'], 'integer'],
|
||||
[['description', 'data', 'ruleName'], 'default'],
|
||||
[['name'], 'string', 'max' => 64]
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check role is unique
|
||||
*/
|
||||
public function unique()
|
||||
{
|
||||
$authManager = Yii::$app->authManager;
|
||||
$value = $this->name;
|
||||
if ($authManager->getRole($value) !== null || $authManager->getPermission($value) !== null) {
|
||||
$message = Yii::t('yii', '{attribute} "{value}" has already been taken.');
|
||||
$params = [
|
||||
'attribute' => $this->getAttributeLabel('name'),
|
||||
'value' => $value,
|
||||
];
|
||||
$this->addError('name', Yii::$app->getI18n()->format($message, $params, Yii::$app->language));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for rule
|
||||
*/
|
||||
public function checkRule()
|
||||
{
|
||||
$name = $this->ruleName;
|
||||
if (!Yii::$app->getAuthManager()->getRule($name)) {
|
||||
try {
|
||||
$rule = Yii::createObject($name);
|
||||
if ($rule instanceof \yii\rbac\Rule) {
|
||||
$rule->name = $name;
|
||||
Yii::$app->getAuthManager()->add($rule);
|
||||
} else {
|
||||
$this->addError('ruleName', Yii::t('rbac-admin', 'Invalid rule "{value}"', ['value' => $name]));
|
||||
}
|
||||
} catch (\Exception $exc) {
|
||||
$this->addError('ruleName', Yii::t('rbac-admin', 'Rule "{value}" does not exists', ['value' => $name]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function attributeLabels()
|
||||
{
|
||||
return [
|
||||
'name' => Yii::t('rbac-admin', 'Name'),
|
||||
'type' => Yii::t('rbac-admin', 'Type'),
|
||||
'description' => Yii::t('rbac-admin', 'Description'),
|
||||
'ruleName' => Yii::t('rbac-admin', 'Rule Name'),
|
||||
'data' => Yii::t('rbac-admin', 'Data'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if is new record.
|
||||
* @return boolean
|
||||
*/
|
||||
public function getIsNewRecord()
|
||||
{
|
||||
return $this->_item === null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find role
|
||||
* @param string $id
|
||||
* @return null|\self
|
||||
*/
|
||||
public static function find($id)
|
||||
{
|
||||
$item = Yii::$app->authManager->getRole($id);
|
||||
if ($item !== null) {
|
||||
return new self($item);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save role to [[\yii\rbac\authManager]]
|
||||
* @return boolean
|
||||
*/
|
||||
public function save()
|
||||
{
|
||||
if ($this->validate()) {
|
||||
$manager = Yii::$app->authManager;
|
||||
if ($this->_item === null) {
|
||||
if ($this->type == Item::TYPE_ROLE) {
|
||||
$this->_item = $manager->createRole($this->name);
|
||||
} else {
|
||||
$this->_item = $manager->createPermission($this->name);
|
||||
}
|
||||
$isNew = true;
|
||||
} else {
|
||||
$isNew = false;
|
||||
$oldName = $this->_item->name;
|
||||
}
|
||||
$this->_item->name = $this->name;
|
||||
$this->_item->description = $this->description;
|
||||
$this->_item->ruleName = $this->ruleName;
|
||||
$this->_item->data = $this->data === null || $this->data === '' ? null : Json::decode($this->data);
|
||||
if ($isNew) {
|
||||
$manager->add($this->_item);
|
||||
} else {
|
||||
$manager->update($oldName, $this->_item);
|
||||
}
|
||||
Helper::invalidate();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an item as a child of another item.
|
||||
* @param array $items
|
||||
* @return int
|
||||
*/
|
||||
public function addChildren($items)
|
||||
{
|
||||
$manager = Yii::$app->getAuthManager();
|
||||
$success = 0;
|
||||
if ($this->_item) {
|
||||
foreach ($items as $name) {
|
||||
$child = $manager->getPermission($name);
|
||||
if ($this->type == Item::TYPE_ROLE && $child === null) {
|
||||
$child = $manager->getRole($name);
|
||||
}
|
||||
try {
|
||||
$manager->addChild($this->_item, $child);
|
||||
$success++;
|
||||
} catch (\Exception $exc) {
|
||||
Yii::error($exc->getMessage(), __METHOD__);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($success > 0) {
|
||||
Helper::invalidate();
|
||||
}
|
||||
return $success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an item as a child of another item.
|
||||
* @param array $items
|
||||
* @return int
|
||||
*/
|
||||
public function removeChildren($items)
|
||||
{
|
||||
$manager = Yii::$app->getAuthManager();
|
||||
$success = 0;
|
||||
if ($this->_item !== null) {
|
||||
foreach ($items as $name) {
|
||||
$child = $manager->getPermission($name);
|
||||
if ($this->type == Item::TYPE_ROLE && $child === null) {
|
||||
$child = $manager->getRole($name);
|
||||
}
|
||||
try {
|
||||
$manager->removeChild($this->_item, $child);
|
||||
$success++;
|
||||
} catch (\Exception $exc) {
|
||||
Yii::error($exc->getMessage(), __METHOD__);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($success > 0) {
|
||||
Helper::invalidate();
|
||||
}
|
||||
return $success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get items
|
||||
* @return array
|
||||
*/
|
||||
public function getItems()
|
||||
{
|
||||
$manager = Yii::$app->getAuthManager();
|
||||
$avaliable = [];
|
||||
if ($this->type == Item::TYPE_ROLE) {
|
||||
foreach (array_keys($manager->getRoles()) as $name) {
|
||||
$avaliable[$name] = 'role';
|
||||
}
|
||||
}
|
||||
foreach (array_keys($manager->getPermissions()) as $name) {
|
||||
$avaliable[$name] = $name[0] == '/' ? 'route' : 'permission';
|
||||
}
|
||||
|
||||
$assigned = [];
|
||||
foreach ($manager->getChildren($this->_item->name) as $item) {
|
||||
$assigned[$item->name] = $item->type == 1 ? 'role' : ($item->name[0] == '/' ? 'route' : 'permission');
|
||||
unset($avaliable[$item->name]);
|
||||
}
|
||||
unset($avaliable[$this->name]);
|
||||
return[
|
||||
'avaliable' => $avaliable,
|
||||
'assigned' => $assigned
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get item
|
||||
* @return Item
|
||||
*/
|
||||
public function getItem()
|
||||
{
|
||||
return $this->_item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get type name
|
||||
* @param mixed $type
|
||||
* @return string|array
|
||||
*/
|
||||
public static function getTypeName($type = null)
|
||||
{
|
||||
$result = [
|
||||
Item::TYPE_PERMISSION => 'Permission',
|
||||
Item::TYPE_ROLE => 'Role'
|
||||
];
|
||||
if ($type === null) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
return $result[$type];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
<?php
|
||||
|
||||
namespace mdm\admin\models;
|
||||
|
||||
use yii\rbac\Rule;
|
||||
use Yii;
|
||||
|
||||
/**
|
||||
* BizRule
|
||||
*
|
||||
* @author Misbahul D Munir <misbahuldmunir@gmail.com>
|
||||
* @since 1.0
|
||||
*/
|
||||
class BizRule extends \yii\base\Model
|
||||
{
|
||||
/**
|
||||
* @var string name of the rule
|
||||
*/
|
||||
public $name;
|
||||
|
||||
/**
|
||||
* @var integer UNIX timestamp representing the rule creation time
|
||||
*/
|
||||
public $createdAt;
|
||||
|
||||
/**
|
||||
* @var integer UNIX timestamp representing the rule updating time
|
||||
*/
|
||||
public $updatedAt;
|
||||
|
||||
/**
|
||||
* @var string Rule classname.
|
||||
*/
|
||||
public $className;
|
||||
|
||||
/**
|
||||
* @var Rule
|
||||
*/
|
||||
private $_item;
|
||||
|
||||
/**
|
||||
* Initilaize object
|
||||
* @param \yii\rbac\Rule $item
|
||||
* @param array $config
|
||||
*/
|
||||
public function __construct($item, $config = [])
|
||||
{
|
||||
$this->_item = $item;
|
||||
if ($item !== null) {
|
||||
$this->name = $item->name;
|
||||
$this->className = get_class($item);
|
||||
}
|
||||
parent::__construct($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
[['name', 'className'], 'required'],
|
||||
[['className'], 'string'],
|
||||
[['className'], 'classExists']
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate class exists
|
||||
*/
|
||||
public function classExists()
|
||||
{
|
||||
if (!class_exists($this->className)) {
|
||||
$message = Yii::t('rbac-admin', "Unknown class '{class}'", ['class' => $this->className]);
|
||||
$this->addError('className', $message);
|
||||
return;
|
||||
}
|
||||
if (!is_subclass_of($this->className, Rule::className())) {
|
||||
$message = Yii::t('rbac-admin', "'{class}' must extend from 'yii\rbac\Rule' or its child class", [
|
||||
'class' => $this->className]);
|
||||
$this->addError('className', $message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function attributeLabels()
|
||||
{
|
||||
return [
|
||||
'name' => Yii::t('rbac-admin', 'Name'),
|
||||
'className' => Yii::t('rbac-admin', 'Class Name'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if new record.
|
||||
* @return boolean
|
||||
*/
|
||||
public function getIsNewRecord()
|
||||
{
|
||||
return $this->_item === null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find model by id
|
||||
* @param type $id
|
||||
* @return null|static
|
||||
*/
|
||||
public static function find($id)
|
||||
{
|
||||
$item = Yii::$app->getAuthManager()->getRule($id);
|
||||
if ($item !== null) {
|
||||
return new static($item);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save model to authManager
|
||||
* @return boolean
|
||||
*/
|
||||
public function save()
|
||||
{
|
||||
if ($this->validate()) {
|
||||
$manager = Yii::$app->getAuthManager();
|
||||
$class = $this->className;
|
||||
if ($this->_item === null) {
|
||||
$this->_item = new $class();
|
||||
$isNew = true;
|
||||
} else {
|
||||
$isNew = false;
|
||||
$oldName = $this->_item->name;
|
||||
}
|
||||
$this->_item->name = $this->name;
|
||||
|
||||
if ($isNew) {
|
||||
$manager->add($this->_item);
|
||||
} else {
|
||||
$manager->update($oldName, $this->_item);
|
||||
}
|
||||
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get item
|
||||
* @return Item
|
||||
*/
|
||||
public function getItem()
|
||||
{
|
||||
return $this->_item;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
<?php
|
||||
|
||||
namespace mdm\admin\models;
|
||||
|
||||
use Yii;
|
||||
use mdm\admin\components\Configs;
|
||||
use yii\db\Query;
|
||||
|
||||
/**
|
||||
* This is the model class for table "menu".
|
||||
*
|
||||
* @property integer $id Menu id(autoincrement)
|
||||
* @property string $name Menu name
|
||||
* @property integer $parent Menu parent
|
||||
* @property string $route Route for this menu
|
||||
* @property integer $order Menu order
|
||||
* @property string $data Extra information for this menu
|
||||
*
|
||||
* @property Menu $menuParent Menu parent
|
||||
* @property Menu[] $menus Menu children
|
||||
*
|
||||
* @author Misbahul D Munir <misbahuldmunir@gmail.com>
|
||||
* @since 1.0
|
||||
*/
|
||||
class Menu extends \yii\db\ActiveRecord
|
||||
{
|
||||
public $parent_name;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static function tableName()
|
||||
{
|
||||
return Configs::instance()->menuTable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static function getDb()
|
||||
{
|
||||
if (Configs::instance()->db !== null) {
|
||||
return Configs::instance()->db;
|
||||
} else {
|
||||
return parent::getDb();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
[['name'], 'required'],
|
||||
[['parent_name'], 'in',
|
||||
'range' => static::find()->select(['name'])->column(),
|
||||
'message' => 'Menu "{value}" not found.'],
|
||||
[['parent', 'route', 'data', 'order'], 'default'],
|
||||
[['parent'], 'filterParent', 'when' => function() {
|
||||
return !$this->isNewRecord;
|
||||
}],
|
||||
[['order'], 'integer'],
|
||||
[['route'], 'in',
|
||||
'range' => static::getSavedRoutes(),
|
||||
'message' => 'Route "{value}" not found.']
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Use to loop detected.
|
||||
*/
|
||||
public function filterParent()
|
||||
{
|
||||
$parent = $this->parent;
|
||||
$db = static::getDb();
|
||||
$query = (new Query)->select(['parent'])
|
||||
->from(static::tableName())
|
||||
->where('[[id]]=:id');
|
||||
while ($parent) {
|
||||
if ($this->id == $parent) {
|
||||
$this->addError('parent_name', 'Loop detected.');
|
||||
return;
|
||||
}
|
||||
$parent = $query->params([':id' => $parent])->scalar($db);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function attributeLabels()
|
||||
{
|
||||
return [
|
||||
'id' => Yii::t('rbac-admin', 'ID'),
|
||||
'name' => Yii::t('rbac-admin', 'Name'),
|
||||
'parent' => Yii::t('rbac-admin', 'Parent'),
|
||||
'parent_name' => Yii::t('rbac-admin', 'Parent Name'),
|
||||
'route' => Yii::t('rbac-admin', 'Route'),
|
||||
'order' => Yii::t('rbac-admin', 'Order'),
|
||||
'data' => Yii::t('rbac-admin', 'Data'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get menu parent
|
||||
* @return \yii\db\ActiveQuery
|
||||
*/
|
||||
public function getMenuParent()
|
||||
{
|
||||
return $this->hasOne(Menu::className(), ['id' => 'parent']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get menu children
|
||||
* @return \yii\db\ActiveQuery
|
||||
*/
|
||||
public function getMenus()
|
||||
{
|
||||
return $this->hasMany(Menu::className(), ['parent' => 'id']);
|
||||
}
|
||||
private static $_routes;
|
||||
|
||||
/**
|
||||
* Get saved routes.
|
||||
* @return array
|
||||
*/
|
||||
public static function getSavedRoutes()
|
||||
{
|
||||
if (self::$_routes === null) {
|
||||
self::$_routes = [];
|
||||
foreach (Yii::$app->getAuthManager()->getPermissions() as $name => $value) {
|
||||
if ($name[0] === '/' && substr($name, -1) != '*') {
|
||||
self::$_routes[] = $name;
|
||||
}
|
||||
}
|
||||
}
|
||||
return self::$_routes;
|
||||
}
|
||||
|
||||
public static function getMenuSource()
|
||||
{
|
||||
$tableName = static::tableName();
|
||||
return (new \yii\db\Query())
|
||||
->select(['m.id', 'm.name', 'm.route', 'parent_name' => 'p.name'])
|
||||
->from(['m' => $tableName])
|
||||
->leftJoin(['p' => $tableName], '[[m.parent]]=[[p.id]]')
|
||||
->all(static::getDb());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,268 @@
|
||||
<?php
|
||||
|
||||
namespace mdm\admin\models;
|
||||
|
||||
use Yii;
|
||||
use mdm\admin\components\Helper;
|
||||
use yii\caching\TagDependency;
|
||||
use mdm\admin\components\RouteRule;
|
||||
use mdm\admin\components\Configs;
|
||||
use yii\helpers\VarDumper;
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Description of Route
|
||||
*
|
||||
* @author Misbahul D Munir <misbahuldmunir@gmail.com>
|
||||
* @since 1.0
|
||||
*/
|
||||
|
||||
class Route extends \yii\base\BaseObject
|
||||
{
|
||||
const CACHE_TAG = 'mdm.admin.route';
|
||||
|
||||
/**
|
||||
* Assign or remove items
|
||||
* @param array $routes
|
||||
* @return array
|
||||
*/
|
||||
public function addNew($routes)
|
||||
{
|
||||
$manager = Yii::$app->getAuthManager();
|
||||
foreach ($routes as $route) {
|
||||
try {
|
||||
$r = explode('&', $route);
|
||||
$item = $manager->createPermission('/' . trim($route, '/'));
|
||||
if (count($r) > 1) {
|
||||
$action = '/' . trim($r[0], '/');
|
||||
if (($itemAction = $manager->getPermission($action)) === null) {
|
||||
$itemAction = $manager->createPermission($action);
|
||||
$manager->add($itemAction);
|
||||
}
|
||||
unset($r[0]);
|
||||
foreach ($r as $part) {
|
||||
$part = explode('=', $part);
|
||||
$item->data['params'][$part[0]] = isset($part[1]) ? $part[1] : '';
|
||||
}
|
||||
$this->setDefaultRule();
|
||||
$item->ruleName = RouteRule::RULE_NAME;
|
||||
$manager->add($item);
|
||||
$manager->addChild($item, $itemAction);
|
||||
} else {
|
||||
$manager->add($item);
|
||||
}
|
||||
} catch (Exception $exc) {
|
||||
Yii::error($exc->getMessage(), __METHOD__);
|
||||
}
|
||||
}
|
||||
Helper::invalidate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign or remove items
|
||||
* @param array $routes
|
||||
* @return array
|
||||
*/
|
||||
public function remove($routes)
|
||||
{
|
||||
$manager = Yii::$app->getAuthManager();
|
||||
foreach ($routes as $route) {
|
||||
try {
|
||||
$item = $manager->createPermission('/' . trim($route, '/'));
|
||||
$manager->remove($item);
|
||||
} catch (Exception $exc) {
|
||||
Yii::error($exc->getMessage(), __METHOD__);
|
||||
}
|
||||
}
|
||||
Helper::invalidate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get avaliable and assigned routes
|
||||
* @return array
|
||||
*/
|
||||
public function getRoutes()
|
||||
{
|
||||
$manager = Yii::$app->getAuthManager();
|
||||
$routes = $this->getAppRoutes();
|
||||
$exists = [];
|
||||
foreach (array_keys($manager->getPermissions()) as $name) {
|
||||
if ($name[0] !== '/') {
|
||||
continue;
|
||||
}
|
||||
$exists[] = $name;
|
||||
unset($routes[$name]);
|
||||
}
|
||||
return[
|
||||
'avaliable' => array_keys($routes),
|
||||
'assigned' => $exists
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get list of application routes
|
||||
* @return array
|
||||
*/
|
||||
public function getAppRoutes($module = null)
|
||||
{
|
||||
if ($module === null) {
|
||||
$module = Yii::$app;
|
||||
} elseif (is_string($module)) {
|
||||
$module = Yii::$app->getModule($module);
|
||||
}
|
||||
$key = [__METHOD__, $module->getUniqueId()];
|
||||
$cache = Configs::instance()->cache;
|
||||
if ($cache === null || ($result = $cache->get($key)) === false) {
|
||||
$result = [];
|
||||
$this->getRouteRecrusive($module, $result);
|
||||
if ($cache !== null) {
|
||||
$cache->set($key, $result, Configs::instance()->cacheDuration, new TagDependency([
|
||||
'tags' => self::CACHE_TAG,
|
||||
]));
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get route(s) recrusive
|
||||
* @param \yii\base\Module $module
|
||||
* @param array $result
|
||||
*/
|
||||
protected function getRouteRecrusive($module, &$result)
|
||||
{
|
||||
$token = "Get Route of '" . get_class($module) . "' with id '" . $module->uniqueId . "'";
|
||||
Yii::beginProfile($token, __METHOD__);
|
||||
try {
|
||||
foreach ($module->getModules() as $id => $child) {
|
||||
if (($child = $module->getModule($id)) !== null) {
|
||||
$this->getRouteRecrusive($child, $result);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($module->controllerMap as $id => $type) {
|
||||
$this->getControllerActions($type, $id, $module, $result);
|
||||
}
|
||||
|
||||
$namespace = trim($module->controllerNamespace, '\\') . '\\';
|
||||
$this->getControllerFiles($module, $namespace, '', $result);
|
||||
$all = '/' . ltrim($module->uniqueId . '/*', '/');
|
||||
$result[$all] = $all;
|
||||
} catch (\Exception $exc) {
|
||||
Yii::error($exc->getMessage(), __METHOD__);
|
||||
}
|
||||
Yii::endProfile($token, __METHOD__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get list controller under module
|
||||
* @param \yii\base\Module $module
|
||||
* @param string $namespace
|
||||
* @param string $prefix
|
||||
* @param mixed $result
|
||||
* @return mixed
|
||||
*/
|
||||
protected function getControllerFiles($module, $namespace, $prefix, &$result)
|
||||
{
|
||||
$path = Yii::getAlias('@' . str_replace('\\', '/', $namespace), false);
|
||||
$token = "Get controllers from '$path'";
|
||||
Yii::beginProfile($token, __METHOD__);
|
||||
try {
|
||||
if (!is_dir($path)) {
|
||||
return;
|
||||
}
|
||||
foreach (scandir($path) as $file) {
|
||||
if ($file == '.' || $file == '..') {
|
||||
continue;
|
||||
}
|
||||
if (is_dir($path . '/' . $file) && preg_match('%^[a-z0-9_/]+$%i', $file . '/')) {
|
||||
$this->getControllerFiles($module, $namespace . $file . '\\', $prefix . $file . '/', $result);
|
||||
} elseif (strcmp(substr($file, -14), 'Controller.php') === 0) {
|
||||
$baseName = substr(basename($file), 0, -14);
|
||||
$name = strtolower(preg_replace('/(?<![A-Z])[A-Z]/', ' \0', $baseName));
|
||||
$id = ltrim(str_replace(' ', '-', $name), '-');
|
||||
$className = $namespace . $baseName . 'Controller';
|
||||
if (strpos($className, '-') === false && class_exists($className) && is_subclass_of($className, 'yii\base\Controller')) {
|
||||
$this->getControllerActions($className, $prefix . $id, $module, $result);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (\Exception $exc) {
|
||||
Yii::error($exc->getMessage(), __METHOD__);
|
||||
}
|
||||
Yii::endProfile($token, __METHOD__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get list action of controller
|
||||
* @param mixed $type
|
||||
* @param string $id
|
||||
* @param \yii\base\Module $module
|
||||
* @param string $result
|
||||
*/
|
||||
protected function getControllerActions($type, $id, $module, &$result)
|
||||
{
|
||||
$token = "Create controller with cofig=" . VarDumper::dumpAsString($type) . " and id='$id'";
|
||||
Yii::beginProfile($token, __METHOD__);
|
||||
try {
|
||||
/* @var $controller \yii\base\Controller */
|
||||
$controller = Yii::createObject($type, [$id, $module]);
|
||||
$this->getActionRoutes($controller, $result);
|
||||
$all = "/{$controller->uniqueId}/*";
|
||||
$result[$all] = $all;
|
||||
} catch (\Exception $exc) {
|
||||
Yii::error($exc->getMessage(), __METHOD__);
|
||||
}
|
||||
Yii::endProfile($token, __METHOD__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get route of action
|
||||
* @param \yii\base\Controller $controller
|
||||
* @param array $result all controller action.
|
||||
*/
|
||||
protected function getActionRoutes($controller, &$result)
|
||||
{
|
||||
$token = "Get actions of controller '" . $controller->uniqueId . "'";
|
||||
Yii::beginProfile($token, __METHOD__);
|
||||
try {
|
||||
$prefix = '/' . $controller->uniqueId . '/';
|
||||
foreach ($controller->actions() as $id => $value) {
|
||||
$result[$prefix . $id] = $prefix . $id;
|
||||
}
|
||||
$class = new \ReflectionClass($controller);
|
||||
foreach ($class->getMethods() as $method) {
|
||||
$name = $method->getName();
|
||||
if ($method->isPublic() && !$method->isStatic() && strpos($name, 'action') === 0 && $name !== 'actions') {
|
||||
$name = strtolower(preg_replace('/(?<![A-Z])[A-Z]/', ' \0', substr($name, 6)));
|
||||
$id = $prefix . ltrim(str_replace(' ', '-', $name), '-');
|
||||
$result[$id] = $id;
|
||||
}
|
||||
}
|
||||
} catch (\Exception $exc) {
|
||||
Yii::error($exc->getMessage(), __METHOD__);
|
||||
}
|
||||
Yii::endProfile($token, __METHOD__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ivalidate cache
|
||||
*/
|
||||
public static function invalidate()
|
||||
{
|
||||
if (Configs::cache() !== null) {
|
||||
TagDependency::invalidate(Configs::cache(), self::CACHE_TAG);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set default rule of parameterize route.
|
||||
*/
|
||||
protected function setDefaultRule()
|
||||
{
|
||||
if (Yii::$app->getAuthManager()->getRule(RouteRule::RULE_NAME) === null) {
|
||||
Yii::$app->getAuthManager()->add(new RouteRule());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,192 @@
|
||||
<?php
|
||||
|
||||
namespace mdm\admin\models;
|
||||
|
||||
use Yii;
|
||||
use yii\base\NotSupportedException;
|
||||
use yii\behaviors\TimestampBehavior;
|
||||
use yii\db\ActiveRecord;
|
||||
use yii\web\IdentityInterface;
|
||||
use mdm\admin\components\Configs;
|
||||
|
||||
/**
|
||||
* User model
|
||||
*
|
||||
* @property integer $id
|
||||
* @property string $username
|
||||
* @property string $password_hash
|
||||
* @property string $password_reset_token
|
||||
* @property string $email
|
||||
* @property string $auth_key
|
||||
* @property integer $status
|
||||
* @property integer $created_at
|
||||
* @property integer $updated_at
|
||||
* @property string $password write-only password
|
||||
*
|
||||
* @property UserProfile $profile
|
||||
*/
|
||||
class User extends ActiveRecord implements IdentityInterface
|
||||
{
|
||||
const STATUS_INACTIVE = 0;
|
||||
const STATUS_ACTIVE = 10;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static function tableName()
|
||||
{
|
||||
return Configs::instance()->userTable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function behaviors()
|
||||
{
|
||||
return [
|
||||
TimestampBehavior::className(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
['status', 'default', 'value' => self::STATUS_ACTIVE],
|
||||
['status', 'in', 'range' => [self::STATUS_ACTIVE, self::STATUS_INACTIVE]],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static function findIdentity($id)
|
||||
{
|
||||
return static::findOne(['id' => $id, 'status' => self::STATUS_ACTIVE]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static function findIdentityByAccessToken($token, $type = null)
|
||||
{
|
||||
throw new NotSupportedException('"findIdentityByAccessToken" is not implemented.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds user by username
|
||||
*
|
||||
* @param string $username
|
||||
* @return static|null
|
||||
*/
|
||||
public static function findByUsername($username)
|
||||
{
|
||||
return static::findOne(['username' => $username, 'status' => self::STATUS_ACTIVE]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds user by password reset token
|
||||
*
|
||||
* @param string $token password reset token
|
||||
* @return static|null
|
||||
*/
|
||||
public static function findByPasswordResetToken($token)
|
||||
{
|
||||
if (!static::isPasswordResetTokenValid($token)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return static::findOne([
|
||||
'password_reset_token' => $token,
|
||||
'status' => self::STATUS_ACTIVE,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds out if password reset token is valid
|
||||
*
|
||||
* @param string $token password reset token
|
||||
* @return boolean
|
||||
*/
|
||||
public static function isPasswordResetTokenValid($token)
|
||||
{
|
||||
if (empty($token)) {
|
||||
return false;
|
||||
}
|
||||
$expire = Yii::$app->params['user.passwordResetTokenExpire'];
|
||||
$parts = explode('_', $token);
|
||||
$timestamp = (int) end($parts);
|
||||
return $timestamp + $expire >= time();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return $this->getPrimaryKey();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getAuthKey()
|
||||
{
|
||||
return $this->auth_key;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function validateAuthKey($authKey)
|
||||
{
|
||||
return $this->getAuthKey() === $authKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates password
|
||||
*
|
||||
* @param string $password password to validate
|
||||
* @return boolean if password provided is valid for current user
|
||||
*/
|
||||
public function validatePassword($password)
|
||||
{
|
||||
return Yii::$app->security->validatePassword($password, $this->password_hash);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates password hash from password and sets it to the model
|
||||
*
|
||||
* @param string $password
|
||||
*/
|
||||
public function setPassword($password)
|
||||
{
|
||||
$this->password_hash = Yii::$app->security->generatePasswordHash($password);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates "remember me" authentication key
|
||||
*/
|
||||
public function generateAuthKey()
|
||||
{
|
||||
$this->auth_key = Yii::$app->security->generateRandomString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates new password reset token
|
||||
*/
|
||||
public function generatePasswordResetToken()
|
||||
{
|
||||
$this->password_reset_token = Yii::$app->security->generateRandomString() . '_' . time();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes password reset token
|
||||
*/
|
||||
public function removePasswordResetToken()
|
||||
{
|
||||
$this->password_reset_token = null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
namespace mdm\admin\models\form;
|
||||
|
||||
use Yii;
|
||||
use mdm\admin\models\User;
|
||||
use yii\base\Model;
|
||||
|
||||
/**
|
||||
* Description of ChangePassword
|
||||
*
|
||||
* @author Misbahul D Munir <misbahuldmunir@gmail.com>
|
||||
* @since 1.0
|
||||
*/
|
||||
class ChangePassword extends Model
|
||||
{
|
||||
public $oldPassword;
|
||||
public $newPassword;
|
||||
public $retypePassword;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
[['oldPassword', 'newPassword', 'retypePassword'], 'required'],
|
||||
[['oldPassword'], 'validatePassword'],
|
||||
[['newPassword'], 'string', 'min' => 6],
|
||||
[['retypePassword'], 'compare', 'compareAttribute' => 'newPassword'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the password.
|
||||
* This method serves as the inline validation for password.
|
||||
*/
|
||||
public function validatePassword()
|
||||
{
|
||||
/* @var $user User */
|
||||
$user = Yii::$app->user->identity;
|
||||
if (!$user || !$user->validatePassword($this->oldPassword)) {
|
||||
$this->addError('oldPassword', 'Incorrect old password.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Change password.
|
||||
*
|
||||
* @return User|null the saved model or null if saving fails
|
||||
*/
|
||||
public function change()
|
||||
{
|
||||
if ($this->validate()) {
|
||||
/* @var $user User */
|
||||
$user = Yii::$app->user->identity;
|
||||
$user->setPassword($this->newPassword);
|
||||
$user->generateAuthKey();
|
||||
if ($user->save()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
namespace mdm\admin\models\form;
|
||||
|
||||
use Yii;
|
||||
use yii\base\Model;
|
||||
use mdm\admin\models\User;
|
||||
|
||||
/**
|
||||
* Login form
|
||||
*/
|
||||
class Login extends Model
|
||||
{
|
||||
public $username;
|
||||
public $password;
|
||||
public $rememberMe = true;
|
||||
|
||||
private $_user = false;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
// username and password are both required
|
||||
[['username', 'password'], 'required'],
|
||||
// rememberMe must be a boolean value
|
||||
['rememberMe', 'boolean'],
|
||||
// password is validated by validatePassword()
|
||||
['password', 'validatePassword'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the password.
|
||||
* This method serves as the inline validation for password.
|
||||
*
|
||||
* @param string $attribute the attribute currently being validated
|
||||
* @param array $params the additional name-value pairs given in the rule
|
||||
*/
|
||||
public function validatePassword($attribute, $params)
|
||||
{
|
||||
if (!$this->hasErrors()) {
|
||||
$user = $this->getUser();
|
||||
if (!$user || !$user->validatePassword($this->password)) {
|
||||
$this->addError($attribute, 'Incorrect username or password.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs in a user using the provided username and password.
|
||||
*
|
||||
* @return boolean whether the user is logged in successfully
|
||||
*/
|
||||
public function login()
|
||||
{
|
||||
if ($this->validate()) {
|
||||
return Yii::$app->getUser()->login($this->getUser(), $this->rememberMe ? 3600 * 24 * 30 : 0);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds user by [[username]]
|
||||
*
|
||||
* @return User|null
|
||||
*/
|
||||
public function getUser()
|
||||
{
|
||||
if ($this->_user === false) {
|
||||
$this->_user = User::findByUsername($this->username);
|
||||
}
|
||||
|
||||
return $this->_user;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
namespace mdm\admin\models\form;
|
||||
|
||||
use Yii;
|
||||
use mdm\admin\models\User;
|
||||
use yii\base\Model;
|
||||
|
||||
/**
|
||||
* Password reset request form
|
||||
*/
|
||||
class PasswordResetRequest extends Model
|
||||
{
|
||||
public $email;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
['email', 'filter', 'filter' => 'trim'],
|
||||
['email', 'required'],
|
||||
['email', 'email'],
|
||||
['email', 'exist',
|
||||
'targetClass' => 'mdm\admin\models\User',
|
||||
'filter' => ['status' => User::STATUS_ACTIVE],
|
||||
'message' => 'There is no user with such email.'
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends an email with a link, for resetting the password.
|
||||
*
|
||||
* @return boolean whether the email was send
|
||||
*/
|
||||
public function sendEmail()
|
||||
{
|
||||
/* @var $user User */
|
||||
$user = User::findOne([
|
||||
'status' => User::STATUS_ACTIVE,
|
||||
'email' => $this->email,
|
||||
]);
|
||||
|
||||
if ($user) {
|
||||
if (!User::isPasswordResetTokenValid($user->password_reset_token)) {
|
||||
$user->generatePasswordResetToken();
|
||||
}
|
||||
|
||||
if ($user->save()) {
|
||||
return Yii::$app->mailer->compose(['html' => 'passwordResetToken-html', 'text' => 'passwordResetToken-text'], ['user' => $user])
|
||||
->setFrom([Yii::$app->params['supportEmail'] => Yii::$app->name . ' robot'])
|
||||
->setTo($this->email)
|
||||
->setSubject('Password reset for ' . Yii::$app->name)
|
||||
->send();
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
namespace mdm\admin\models\form;
|
||||
|
||||
use Yii;
|
||||
use mdm\admin\models\User;
|
||||
use yii\base\InvalidParamException;
|
||||
use yii\base\Model;
|
||||
|
||||
/**
|
||||
* Password reset form
|
||||
*/
|
||||
class ResetPassword extends Model
|
||||
{
|
||||
public $password;
|
||||
/**
|
||||
* @var User
|
||||
*/
|
||||
private $_user;
|
||||
|
||||
/**
|
||||
* Creates a form model given a token.
|
||||
*
|
||||
* @param string $token
|
||||
* @param array $config name-value pairs that will be used to initialize the object properties
|
||||
* @throws \yii\base\InvalidParamException if token is empty or not valid
|
||||
*/
|
||||
public function __construct($token, $config = [])
|
||||
{
|
||||
if (empty($token) || !is_string($token)) {
|
||||
throw new InvalidParamException('Password reset token cannot be blank.');
|
||||
}
|
||||
$this->_user = User::findByPasswordResetToken($token);
|
||||
if (!$this->_user) {
|
||||
throw new InvalidParamException('Wrong password reset token.');
|
||||
}
|
||||
parent::__construct($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
['password', 'required'],
|
||||
['password', 'string', 'min' => 6],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets password.
|
||||
*
|
||||
* @return boolean if password was reset.
|
||||
*/
|
||||
public function resetPassword()
|
||||
{
|
||||
$user = $this->_user;
|
||||
$user->setPassword($this->password);
|
||||
$user->removePasswordResetToken();
|
||||
|
||||
return $user->save(false);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
namespace mdm\admin\models\form;
|
||||
|
||||
use Yii;
|
||||
use mdm\admin\models\User;
|
||||
use yii\base\Model;
|
||||
|
||||
/**
|
||||
* Signup form
|
||||
*/
|
||||
class Signup extends Model
|
||||
{
|
||||
public $username;
|
||||
public $email;
|
||||
public $password;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
['username', 'filter', 'filter' => 'trim'],
|
||||
['username', 'required'],
|
||||
['username', 'unique', 'targetClass' => 'mdm\admin\models\User', 'message' => 'This username has already been taken.'],
|
||||
['username', 'string', 'min' => 2, 'max' => 255],
|
||||
|
||||
['email', 'filter', 'filter' => 'trim'],
|
||||
['email', 'required'],
|
||||
['email', 'email'],
|
||||
['email', 'unique', 'targetClass' => 'mdm\admin\models\User', 'message' => 'This email address has already been taken.'],
|
||||
|
||||
['password', 'required'],
|
||||
['password', 'string', 'min' => 6],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Signs user up.
|
||||
*
|
||||
* @return User|null the saved model or null if saving fails
|
||||
*/
|
||||
public function signup()
|
||||
{
|
||||
if ($this->validate()) {
|
||||
$user = new User();
|
||||
$user->username = $this->username;
|
||||
$user->email = $this->email;
|
||||
$user->setPassword($this->password);
|
||||
$user->generateAuthKey();
|
||||
if ($user->save()) {
|
||||
return $user;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
namespace mdm\admin\models\searchs;
|
||||
|
||||
use Yii;
|
||||
use yii\base\Model;
|
||||
use yii\data\ActiveDataProvider;
|
||||
|
||||
/**
|
||||
* AssignmentSearch represents the model behind the search form about Assignment.
|
||||
*
|
||||
* @author Misbahul D Munir <misbahuldmunir@gmail.com>
|
||||
* @since 1.0
|
||||
*/
|
||||
class Assignment extends Model
|
||||
{
|
||||
public $id;
|
||||
public $username;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
[['id', 'username'], 'safe'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function attributeLabels()
|
||||
{
|
||||
return [
|
||||
'id' => Yii::t('rbac-admin', 'ID'),
|
||||
'username' => Yii::t('rbac-admin', 'Username'),
|
||||
'name' => Yii::t('rbac-admin', 'Name'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Create data provider for Assignment model.
|
||||
* @param array $params
|
||||
* @param \yii\db\ActiveRecord $class
|
||||
* @param string $usernameField
|
||||
* @return \yii\data\ActiveDataProvider
|
||||
*/
|
||||
public function search($params, $class, $usernameField)
|
||||
{
|
||||
$query = $class::find();
|
||||
$dataProvider = new ActiveDataProvider([
|
||||
'query' => $query,
|
||||
]);
|
||||
|
||||
if (!($this->load($params) && $this->validate())) {
|
||||
return $dataProvider;
|
||||
}
|
||||
|
||||
$query->andFilterWhere(['like', $usernameField, $this->username]);
|
||||
|
||||
return $dataProvider;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
namespace mdm\admin\models\searchs;
|
||||
|
||||
use Yii;
|
||||
use yii\base\Model;
|
||||
use yii\data\ArrayDataProvider;
|
||||
use yii\rbac\Item;
|
||||
|
||||
/**
|
||||
* AuthItemSearch represents the model behind the search form about AuthItem.
|
||||
*
|
||||
* @author Misbahul D Munir <misbahuldmunir@gmail.com>
|
||||
* @since 1.0
|
||||
*/
|
||||
class AuthItem extends Model
|
||||
{
|
||||
const TYPE_ROUTE = 101;
|
||||
|
||||
public $name;
|
||||
public $type;
|
||||
public $description;
|
||||
public $ruleName;
|
||||
public $data;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
[['name', 'ruleName', 'description'], 'safe'],
|
||||
[['type'], 'integer'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function attributeLabels()
|
||||
{
|
||||
return [
|
||||
'name' => Yii::t('rbac-admin', 'Name'),
|
||||
'item_name' => Yii::t('rbac-admin', 'Name'),
|
||||
'type' => Yii::t('rbac-admin', 'Type'),
|
||||
'description' => Yii::t('rbac-admin', 'Description'),
|
||||
'ruleName' => Yii::t('rbac-admin', 'Rule Name'),
|
||||
'data' => Yii::t('rbac-admin', 'Data'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Search authitem
|
||||
* @param array $params
|
||||
* @return \yii\data\ActiveDataProvider|\yii\data\ArrayDataProvider
|
||||
*/
|
||||
public function search($params)
|
||||
{
|
||||
/* @var \yii\rbac\Manager $authManager */
|
||||
$authManager = Yii::$app->getAuthManager();
|
||||
if ($this->type == Item::TYPE_ROLE) {
|
||||
$items = $authManager->getRoles();
|
||||
} else {
|
||||
$items = array_filter($authManager->getPermissions(), function($item) {
|
||||
return $this->type == Item::TYPE_PERMISSION xor strncmp($item->name, '/', 1) === 0;
|
||||
});
|
||||
}
|
||||
$this->load($params);
|
||||
if ($this->validate()) {
|
||||
$search = empty($this->name) ? '' : strtolower(trim($this->name));
|
||||
$desc = empty($this->description) ? '' : strtolower(trim($this->description));
|
||||
$ruleName = $this->ruleName;
|
||||
foreach ($items as $name => $item) {
|
||||
$f = (empty($search) || strpos(strtolower($item->name), $search) !== false) &&
|
||||
(empty($desc) || strpos(strtolower($item->description), $desc) !== false) &&
|
||||
(empty($ruleName) || $item->ruleName == $ruleName);
|
||||
if (!$f) {
|
||||
unset($items[$name]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new ArrayDataProvider([
|
||||
'allModels' => $items,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
namespace mdm\admin\models\searchs;
|
||||
|
||||
use Yii;
|
||||
use yii\base\Model;
|
||||
use yii\data\ArrayDataProvider;
|
||||
use mdm\admin\models\BizRule as MBizRule;
|
||||
use mdm\admin\components\RouteRule;
|
||||
|
||||
/**
|
||||
* Description of BizRule
|
||||
*
|
||||
* @author Misbahul D Munir <misbahuldmunir@gmail.com>
|
||||
* @since 1.0
|
||||
*/
|
||||
class BizRule extends Model
|
||||
{
|
||||
/**
|
||||
* @var string name of the rule
|
||||
*/
|
||||
public $name;
|
||||
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
[['name'], 'safe']
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function attributeLabels()
|
||||
{
|
||||
return [
|
||||
'name' => Yii::t('rbac-admin', 'Name'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Search BizRule
|
||||
* @param array $params
|
||||
* @return \yii\data\ActiveDataProvider|\yii\data\ArrayDataProvider
|
||||
*/
|
||||
public function search($params)
|
||||
{
|
||||
/* @var \yii\rbac\Manager $authManager */
|
||||
$authManager = Yii::$app->authManager;
|
||||
$models = [];
|
||||
$included = !($this->load($params) && $this->validate() && trim($this->name) !== '');
|
||||
foreach ($authManager->getRules() as $name => $item) {
|
||||
if ($name != RouteRule::RULE_NAME && ($included || stripos($item->name, $this->name) !== false)) {
|
||||
$models[$name] = new MBizRule($item);
|
||||
}
|
||||
}
|
||||
|
||||
return new ArrayDataProvider([
|
||||
'allModels' => $models,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
namespace mdm\admin\models\searchs;
|
||||
|
||||
use Yii;
|
||||
use yii\base\Model;
|
||||
use yii\data\ActiveDataProvider;
|
||||
use mdm\admin\models\Menu as MenuModel;
|
||||
|
||||
/**
|
||||
* Menu represents the model behind the search form about [[\mdm\admin\models\Menu]].
|
||||
*
|
||||
* @author Misbahul D Munir <misbahuldmunir@gmail.com>
|
||||
* @since 1.0
|
||||
*/
|
||||
class Menu extends MenuModel
|
||||
{
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
[['id', 'parent', 'order'], 'integer'],
|
||||
[['name', 'route', 'parent_name'], 'safe'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function scenarios()
|
||||
{
|
||||
// bypass scenarios() implementation in the parent class
|
||||
return Model::scenarios();
|
||||
}
|
||||
|
||||
/**
|
||||
* Searching menu
|
||||
* @param array $params
|
||||
* @return \yii\data\ActiveDataProvider
|
||||
*/
|
||||
public function search($params)
|
||||
{
|
||||
$query = MenuModel::find()
|
||||
->from(MenuModel::tableName() . ' t')
|
||||
->joinWith(['menuParent' => function ($q) {
|
||||
$q->from(MenuModel::tableName() . ' parent');
|
||||
}]);
|
||||
|
||||
$dataProvider = new ActiveDataProvider([
|
||||
'query' => $query
|
||||
]);
|
||||
|
||||
$sort = $dataProvider->getSort();
|
||||
$sort->attributes['menuParent.name'] = [
|
||||
'asc' => ['parent.name' => SORT_ASC],
|
||||
'desc' => ['parent.name' => SORT_DESC],
|
||||
'label' => 'parent',
|
||||
];
|
||||
$sort->attributes['order'] = [
|
||||
'asc' => ['parent.order' => SORT_ASC, 't.order' => SORT_ASC],
|
||||
'desc' => ['parent.order' => SORT_DESC, 't.order' => SORT_DESC],
|
||||
'label' => 'order',
|
||||
];
|
||||
$sort->defaultOrder = ['menuParent.name' => SORT_ASC];
|
||||
|
||||
if (!($this->load($params) && $this->validate())) {
|
||||
return $dataProvider;
|
||||
}
|
||||
|
||||
$query->andFilterWhere([
|
||||
't.id' => $this->id,
|
||||
't.parent' => $this->parent,
|
||||
]);
|
||||
|
||||
$query->andFilterWhere(['like', 'lower(t.name)', strtolower($this->name)])
|
||||
->andFilterWhere(['like', 't.route', $this->route])
|
||||
->andFilterWhere(['like', 'lower(parent.name)', strtolower($this->parent_name)]);
|
||||
|
||||
return $dataProvider;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
namespace mdm\admin\models\searchs;
|
||||
|
||||
use Yii;
|
||||
use yii\base\Model;
|
||||
use yii\data\ActiveDataProvider;
|
||||
use mdm\admin\models\User as UserModel;
|
||||
|
||||
/**
|
||||
* User represents the model behind the search form about `mdm\admin\models\User`.
|
||||
*/
|
||||
class User extends UserModel
|
||||
{
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
[['id', 'status', 'created_at', 'updated_at'], 'integer'],
|
||||
[['username', 'auth_key', 'password_hash', 'password_reset_token', 'email'], 'safe'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function scenarios()
|
||||
{
|
||||
// bypass scenarios() implementation in the parent class
|
||||
return Model::scenarios();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates data provider instance with search query applied
|
||||
*
|
||||
* @param array $params
|
||||
*
|
||||
* @return ActiveDataProvider
|
||||
*/
|
||||
public function search($params)
|
||||
{
|
||||
$query = UserModel::find();
|
||||
|
||||
$dataProvider = new ActiveDataProvider([
|
||||
'query' => $query,
|
||||
]);
|
||||
|
||||
$this->load($params);
|
||||
if (!$this->validate()) {
|
||||
$query->where('1=0');
|
||||
return $dataProvider;
|
||||
}
|
||||
|
||||
$query->andFilterWhere([
|
||||
'id' => $this->id,
|
||||
'status' => $this->status,
|
||||
'created_at' => $this->created_at,
|
||||
'updated_at' => $this->updated_at,
|
||||
]);
|
||||
|
||||
$query->andFilterWhere(['like', 'username', $this->username])
|
||||
->andFilterWhere(['like', 'auth_key', $this->auth_key])
|
||||
->andFilterWhere(['like', 'password_hash', $this->password_hash])
|
||||
->andFilterWhere(['like', 'password_reset_token', $this->password_reset_token])
|
||||
->andFilterWhere(['like', 'email', $this->email]);
|
||||
|
||||
return $dataProvider;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
This directory contains various tests for the basic application.
|
||||
|
||||
Tests in `codeception` directory are developed with [Codeception PHP Testing Framework](http://codeception.com/).
|
||||
|
||||
After creating the basic application, follow these steps to prepare for the tests:
|
||||
|
||||
1. Install Codeception if it's not yet installed:
|
||||
|
||||
```
|
||||
composer global require "codeception/codeception=2.0.*"
|
||||
composer global require "codeception/specify=*"
|
||||
composer global require "codeception/verify=*"
|
||||
```
|
||||
|
||||
If you've never used Composer for global packages run `composer global status`. It should output:
|
||||
|
||||
```
|
||||
Changed current directory to <directory>
|
||||
```
|
||||
|
||||
Then add `<directory>/vendor/bin` to you `PATH` environment variable. Now we're able to use `codecept` from command
|
||||
line globally.
|
||||
|
||||
2. Install faker extension by running the following from template root directory where `composer.json` is:
|
||||
|
||||
```
|
||||
composer require --dev "yiisoft/yii2-faker:*"
|
||||
```
|
||||
|
||||
3. Create `yii2_basic_tests` database and update it by applying migrations (you may skip this step if you do not have created any migrations yet):
|
||||
|
||||
```
|
||||
codeception/bin/yii migrate
|
||||
```
|
||||
|
||||
The command needs to be run in the `tests` directory.
|
||||
The database configuration can be found at `tests/codeception/config/config.php`.
|
||||
|
||||
4. Build the test suites:
|
||||
|
||||
```
|
||||
codecept build
|
||||
```
|
||||
|
||||
5. In order to be able to run acceptance tests you need to start a webserver. The simplest way is to use PHP built in
|
||||
webserver. In the `web` directory execute the following:
|
||||
|
||||
```
|
||||
php -S localhost:8080
|
||||
```
|
||||
|
||||
6. Now you can run the tests with the following commands:
|
||||
|
||||
```
|
||||
# run all available tests
|
||||
codecept run
|
||||
# run acceptance tests
|
||||
codecept run acceptance
|
||||
# run functional tests
|
||||
codecept run functional
|
||||
# run unit tests
|
||||
codecept run unit
|
||||
```
|
||||
|
||||
Fixtures Default Configuration
|
||||
------------------------------
|
||||
The `fixture` commands refer to the following `ActiveFixture` configuration by default:
|
||||
|
||||
- Fixtures path: `@tests/unit/fixtures`
|
||||
- Fixtures data path: `@tests/unit/fixtures/data`
|
||||
- Template files path: `@tests/unit/templates/fixtures`
|
||||
- Namespace: `tests\unit\fixtures`
|
||||
|
||||
Where `@tests` refers to `@mdm/admin/tests/codeception`.
|
||||
|
||||
Code coverage support
|
||||
---------------------
|
||||
|
||||
By default, code coverage is disabled in `codeception.yml` configuration file, you should uncomment needed rows to be able
|
||||
to collect code coverage. You can run your tests and collect coverage with the following command:
|
||||
|
||||
```
|
||||
#collect coverage for all tests
|
||||
codecept run --coverage-html --coverage-xml
|
||||
|
||||
#collect coverage only for unit tests
|
||||
codecept run unit --coverage-html --coverage-xml
|
||||
|
||||
#collect coverage for unit and functional tests
|
||||
codecept run functional,unit --coverage-html --coverage-xml
|
||||
```
|
||||
|
||||
You can see code coverage output under the `tests/_output` directory.
|
||||
|
||||
###Remote code coverage
|
||||
|
||||
When you run your tests not in the same process where code coverage is collected, then you should uncomment `remote` option and its
|
||||
related options, to be able to collect code coverage correctly. To setup remote code coverage you should follow [instructions](http://codeception.com/docs/11-Codecoverage)
|
||||
from codeception site.
|
||||
|
||||
1. install `Codeception c3` remote support `composer require "codeception/c3:*"`;
|
||||
|
||||
2. copy `c3.php` file under your `web` directory;
|
||||
|
||||
3. include `c3.php` file in your `index-test.php` file before application run, so it can catch needed requests.
|
||||
|
||||
4. edit `c3.php` to update config file path (~ line 55) with `$config_file = realpath(__DIR__ . '/../tests/codeception.yml');`
|
||||
|
||||
Configuration options that are used by remote code coverage:
|
||||
|
||||
- c3_url: url pointing to entry script that includes `c3.php` file, so `Codeception` will be able to produce code coverage;
|
||||
- remote: whether to enable remote code coverage or not;
|
||||
- remote_config: path to the `codeception.yml` configuration file, from the directory where `c3.php` file is located. This is needed
|
||||
so that `Codeception` can create itself instance and collect code coverage correctly.
|
||||
|
||||
By default `c3_url` and `remote_config` setup correctly, you only need to copy and include `c3.php` file in your `index-test.php`
|
||||
|
||||
After that you should be able to collect code coverage from tests that run through `PhpBrowser` or `WebDriver` with same command
|
||||
as for other tests:
|
||||
|
||||
```
|
||||
#collect coverage from remote
|
||||
codecept run acceptance --coverage-html --coverage-xml
|
||||
```
|
||||
|
||||
Please refer to [Codeception tutorial](http://codeception.com/docs/01-Introduction) for
|
||||
more details about writing and running acceptance, functional and unit tests.
|
||||
@@ -0,0 +1,17 @@
|
||||
actor: Tester
|
||||
|
||||
paths:
|
||||
tests: codeception
|
||||
log: codeception/_output
|
||||
data: codeception/_data
|
||||
helpers: codeception/_support
|
||||
settings:
|
||||
bootstrap: _bootstrap.php
|
||||
suite_class: \PHPUnit_Framework_TestSuite
|
||||
memory_limit: 1024M
|
||||
log: true
|
||||
colors: true
|
||||
config:
|
||||
# the entry script URL (with host info) for functional and acceptance tests
|
||||
# PLEASE ADJUST IT TO THE ACTUAL ENTRY SCRIPT URL
|
||||
test_entry_url: http://localhost:8080/index-test.php
|
||||
@@ -0,0 +1,4 @@
|
||||
# these files are auto generated by codeception build
|
||||
/unit/UnitTester.php
|
||||
/functional/FunctionalTester.php
|
||||
/acceptance/AcceptanceTester.php
|
||||
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
defined('YII_DEBUG') or define('YII_DEBUG', true);
|
||||
defined('YII_ENV') or define('YII_ENV', 'test');
|
||||
|
||||
defined('YII_TEST_ENTRY_URL') or define('YII_TEST_ENTRY_URL', parse_url(\Codeception\Configuration::config()['config']['test_entry_url'], PHP_URL_PATH));
|
||||
defined('YII_TEST_ENTRY_FILE') or define('YII_TEST_ENTRY_FILE', __DIR__ . '/../web/index-test.php');
|
||||
|
||||
require_once(__DIR__ . '/../../vendor/autoload.php');
|
||||
require_once(__DIR__ . '/../../vendor/yiisoft/yii2/Yii.php');
|
||||
|
||||
$_SERVER['SCRIPT_FILENAME'] = YII_TEST_ENTRY_FILE;
|
||||
$_SERVER['SCRIPT_NAME'] = YII_TEST_ENTRY_URL;
|
||||
$_SERVER['SERVER_NAME'] = parse_url(\Codeception\Configuration::config()['config']['test_entry_url'], PHP_URL_HOST);
|
||||
$_SERVER['SERVER_PORT'] = parse_url(\Codeception\Configuration::config()['config']['test_entry_url'], PHP_URL_PORT) ?: '80';
|
||||
|
||||
Yii::setAlias('@tests', dirname(__DIR__));
|
||||
@@ -0,0 +1,2 @@
|
||||
*
|
||||
!.gitignore
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace tests\codeception\_pages;
|
||||
|
||||
use yii\codeception\BasePage;
|
||||
|
||||
/**
|
||||
* Represents create role or permission
|
||||
* @property \AcceptanceTester|\FunctionalTester $actor
|
||||
*/
|
||||
class CreateItemPage extends BasePage
|
||||
{
|
||||
public $route = 'admin/role/create';
|
||||
|
||||
/**
|
||||
* @param array $roleData
|
||||
*/
|
||||
public function submit(array $roleData)
|
||||
{
|
||||
$inputTypes = [
|
||||
'name' => 'input',
|
||||
'description' => 'textarea',
|
||||
'ruleName' => 'select',
|
||||
'data' => 'textarea',
|
||||
];
|
||||
foreach ($roleData as $field => $value) {
|
||||
$inputType = isset($inputTypes[$field]) ? $inputTypes[$field] : 'input';
|
||||
$this->actor->fillField($inputType . '[name="AuthItem[' . $field . ']"]', $value);
|
||||
}
|
||||
$this->actor->click('submit-button');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace tests\codeception\_pages;
|
||||
|
||||
use yii\codeception\BasePage;
|
||||
|
||||
/**
|
||||
* Represents about page
|
||||
* @property \AcceptanceTester|\FunctionalTester $actor
|
||||
*/
|
||||
class RoutePage extends BasePage
|
||||
{
|
||||
public $route = 'admin/route/index';
|
||||
|
||||
/**
|
||||
* @param array $route
|
||||
*/
|
||||
public function addRoute($route)
|
||||
{
|
||||
$this->actor->fillField('#inp-route', $route);
|
||||
$this->actor->click('add-route');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
namespace tests\codeception\_support;
|
||||
|
||||
use Codeception\Module;
|
||||
use yii\test\FixtureTrait;
|
||||
use tests\codeception\fixtures\AdminFixture;
|
||||
|
||||
/**
|
||||
* This helper is used to populate the database with needed fixtures before any tests are run.
|
||||
* In this example, the database is populated with the demo login user, which is used in acceptance
|
||||
* and functional tests. All fixtures will be loaded before the suite is started and unloaded after it
|
||||
* completes.
|
||||
*/
|
||||
class FixtureHelper extends Module
|
||||
{
|
||||
|
||||
/**
|
||||
* Redeclare visibility because codeception includes all public methods that do not start with "_"
|
||||
* and are not excluded by module settings, in actor class.
|
||||
*/
|
||||
use FixtureTrait {
|
||||
loadFixtures as public;
|
||||
fixtures as public;
|
||||
globalFixtures as public;
|
||||
createFixtures as public;
|
||||
unloadFixtures as protected;
|
||||
getFixtures as protected;
|
||||
getFixture as protected;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method called before any suite tests run. Loads User fixture login user
|
||||
* to use in acceptance and functional tests.
|
||||
* @param array $settings
|
||||
*/
|
||||
public function _beforeSuite($settings = [])
|
||||
{
|
||||
$this->loadFixtures();
|
||||
}
|
||||
|
||||
/**
|
||||
* Method is called after all suite tests run
|
||||
*/
|
||||
public function _afterSuite()
|
||||
{
|
||||
$this->unloadFixtures();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function globalFixtures()
|
||||
{
|
||||
return [
|
||||
AdminFixture::className(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function fixtures()
|
||||
{
|
||||
return [
|
||||
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
# Codeception Test Suite Configuration
|
||||
|
||||
# suite for acceptance tests.
|
||||
# perform tests in browser using the Selenium-like tools.
|
||||
# powered by Mink (http://mink.behat.org).
|
||||
# (tip: that's what your customer will see).
|
||||
# (tip: test your ajax and javascript by one of Mink drivers).
|
||||
|
||||
# RUN `build` COMMAND AFTER ADDING/REMOVING MODULES.
|
||||
|
||||
class_name: AcceptanceTester
|
||||
modules:
|
||||
enabled:
|
||||
- PhpBrowser
|
||||
- tests\codeception\_support\FixtureHelper
|
||||
# you can use WebDriver instead of PhpBrowser to test javascript and ajax.
|
||||
# This will require you to install selenium. See http://codeception.com/docs/04-AcceptanceTests#Selenium
|
||||
# "restart" option is used by the WebDriver to start each time per test-file new session and cookies,
|
||||
# it is useful if you want to login in your app in each test.
|
||||
# - WebDriver
|
||||
config:
|
||||
PhpBrowser:
|
||||
# PLEASE ADJUST IT TO THE ACTUAL ENTRY POINT WITHOUT PATH INFO
|
||||
url: http://localhost:8080
|
||||
# WebDriver:
|
||||
# url: http://localhost:8080
|
||||
# browser: firefox
|
||||
# restart: true
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
use tests\codeception\_pages\CreateItemPage;
|
||||
|
||||
/* @var $scenario Codeception\Scenario */
|
||||
|
||||
$I = new AcceptanceTester($scenario);
|
||||
$I->wantTo('ensure that create role item work');
|
||||
|
||||
$createItemPage = CreateItemPage::openBy($I);
|
||||
|
||||
$I->see('Create Role', 'h1');
|
||||
|
||||
$I->amGoingTo('submit role form with no data');
|
||||
$createItemPage->submit([]);
|
||||
if (method_exists($I, 'wait')) {
|
||||
$I->wait(3); // only for selenium
|
||||
}
|
||||
$I->expectTo('see validations errors');
|
||||
$I->see('Create Role', 'h1');
|
||||
$I->see('Name cannot be blank');
|
||||
|
||||
$I->amGoingTo('submit role form with correct data');
|
||||
$createItemPage->submit([
|
||||
'name' => 'roleTesterAcp',
|
||||
'description' => 'Role created for test',
|
||||
]);
|
||||
if (method_exists($I, 'wait')) {
|
||||
$I->wait(3); // only for selenium
|
||||
}
|
||||
$I->dontSeeElement('#item-form');
|
||||
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
use tests\codeception\_pages\RoutePage;
|
||||
|
||||
/* @var $scenario Codeception\Scenario */
|
||||
|
||||
$I = new AcceptanceTester($scenario);
|
||||
$I->wantTo('ensure that create route work');
|
||||
RoutePage::openBy($I);
|
||||
$I->see('Routes', 'h1');
|
||||