initial commit

This commit is contained in:
_Bastler 2021-10-03 17:07:01 +02:00
commit 456332f24e
246 changed files with 24590 additions and 0 deletions

8
.gitignore vendored Executable file
View File

@ -0,0 +1,8 @@
bin/
target/
.settings/
.project
.classpath
hs_err*.log
application.properties
usernames.txt

661
LICENSE Normal file
View File

@ -0,0 +1,661 @@
GNU AFFERO GENERAL PUBLIC LICENSE
Version 3, 19 November 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU Affero General Public License is a free, copyleft license for
software and other kinds of works, specifically designed to ensure
cooperation with the community in the case of network server software.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
our General Public Licenses are 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.
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.
Developers that use our General Public Licenses protect your rights
with two steps: (1) assert copyright on the software, and (2) offer
you this License which gives you legal permission to copy, distribute
and/or modify the software.
A secondary benefit of defending all users' freedom is that
improvements made in alternate versions of the program, if they
receive widespread use, become available for other developers to
incorporate. Many developers of free software are heartened and
encouraged by the resulting cooperation. However, in the case of
software used on network servers, this result may fail to come about.
The GNU General Public License permits making a modified version and
letting the public access it on a server without ever releasing its
source code to the public.
The GNU Affero General Public License is designed specifically to
ensure that, in such cases, the modified source code becomes available
to the community. It requires the operator of a network server to
provide the source code of the modified version running there to the
users of that server. Therefore, public use of a modified version, on
a publicly accessible server, gives the public access to the source
code of the modified version.
An older license, called the Affero General Public License and
published by Affero, was designed to accomplish similar goals. This is
a different license, not a version of the Affero GPL, but Affero has
released a new version of the Affero GPL which permits relicensing under
this license.
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 Affero 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. Remote Network Interaction; Use with the GNU General Public License.
Notwithstanding any other provision of this License, if you modify the
Program, your modified version must prominently offer all users
interacting with it remotely through a computer network (if your version
supports such interaction) an opportunity to receive the Corresponding
Source of your version by providing access to the Corresponding Source
from a network server at no charge, through some standard or customary
means of facilitating copying of software. This Corresponding Source
shall include the Corresponding Source for any work covered by version 3
of the GNU General Public License that is incorporated pursuant to the
following paragraph.
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 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 work with which it is combined will remain governed by version
3 of the GNU General Public License.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU Affero 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 Affero 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 Affero 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 Affero 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 Affero 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If your software can interact with users remotely through a computer
network, you should also make sure that it provides a way for users to
get its source. For example, if your program is a web application, its
interface could display a "Source" link that leads users to an archive
of the code. There are many ways you could offer source, and different
solutions will be better for different programs; see section 13 for the
specific requirements.
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 AGPL, see
<https://www.gnu.org/licenses/>.

3
README.md Executable file
View File

@ -0,0 +1,3 @@
# we.bstly backend
Backend of we.bstly created with Spring Framework.

142
application/pom.xml Executable file
View File

@ -0,0 +1,142 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>de.bstly.we</groupId>
<artifactId>webstly-main</artifactId>
<version>${revision}</version>
</parent>
<name>application</name>
<artifactId>application</artifactId>
<dependencies>
<dependency>
<groupId>de.bstly.we</groupId>
<artifactId>webstly-core</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>de.bstly.we</groupId>
<artifactId>webstly-email</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>de.bstly.we</groupId>
<artifactId>webstly-i18n</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>de.bstly.we</groupId>
<artifactId>webstly-invite</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>de.bstly.we</groupId>
<artifactId>webstly-jitsi</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>de.bstly.we</groupId>
<artifactId>webstly-membership</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>de.bstly.we</groupId>
<artifactId>webstly-minetest</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>de.bstly.we</groupId>
<artifactId>webstly-oidc</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>de.bstly.we</groupId>
<artifactId>webstly-partey</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>de.bstly.we</groupId>
<artifactId>webstly-services</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>de.bstly.we</groupId>
<artifactId>webstly-urlshortener</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>de.bstly.we</groupId>
<artifactId>webstly-wireguard</artifactId>
<version>${revision}</version>
</dependency>
</dependencies>
<!-- Database -->
<profiles>
<profile>
<id>db-inmemory</id>
<dependencies>
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
</dependency>
</dependencies>
</profile>
<profile>
<id>db-mariadb</id>
<dependencies>
<dependency>
<groupId>org.mariadb.jdbc</groupId>
<artifactId>mariadb-java-client</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
</profile>
<profile>
<id>db-mysql</id>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
</profile>
<profile>
<id>db-postgresql</id>
<dependencies>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
</profile>
</profiles>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>de.bstly.we.Application</mainClass>
<finalName>we.bstly</finalName>
<executable>true</executable>
<layout>ZIP</layout>
</configuration>
<executions>
<execution>
<id>build-info</id>
<goals>
<goal>build-info</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1 @@
loader.path=config/

View File

@ -0,0 +1,44 @@
/**
*
*/
package de.bstly.we;
import java.util.EnumSet;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.SessionTrackingMode;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.scheduling.annotation.EnableScheduling;
/**
*
* @author _bastler@bstly.de
*
*/
@SpringBootApplication
@EnableScheduling
public class Application extends SpringBootServletInitializer {
/**
* @param args
*/
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
/*
*
* @see
* org.springframework.boot.web.servlet.support.SpringBootServletInitializer#
* onStartup(javax.servlet.ServletContext)
*/
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
super.onStartup(servletContext);
servletContext.setSessionTrackingModes(EnumSet.of(SessionTrackingMode.COOKIE));
}
}

99
core/pom.xml Executable file
View File

@ -0,0 +1,99 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>de.bstly.we</groupId>
<artifactId>webstly-main</artifactId>
<version>${revision}</version>
</parent>
<name>core</name>
<artifactId>webstly-core</artifactId>
<dependencies>
<!-- Spring -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-jdbc</artifactId>
</dependency>
<!-- Query DSL -->
<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-apt</artifactId>
</dependency>
<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-jpa</artifactId>
</dependency>
<!-- Utils -->
<dependency>
<groupId>commons-validator</groupId>
<artifactId>commons-validator</artifactId>
<version>1.7</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
<dependency>
<groupId>org.passay</groupId>
<artifactId>passay</artifactId>
<version>1.6.0</version>
</dependency>
<dependency>
<groupId>dev.samstevens.totp</groupId>
<artifactId>totp-spring-boot-starter</artifactId>
<version>1.7.1</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.66</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>javax.measure</groupId>
<artifactId>unit-api</artifactId>
<version>2.1.2</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-csv</artifactId>
<version>1.9.0</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,30 @@
/**
*
*/
package de.bstly.we;
import javax.persistence.EntityManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.querydsl.jpa.impl.JPAQueryFactory;
/**
*
* @author _bastler@bstly.de
*
*/
@Configuration
public class CoreConfiguration {
@Autowired
private EntityManager em;
@Bean
public JPAQueryFactory jpaQueryFactory() {
return new JPAQueryFactory(em);
}
}

View File

@ -0,0 +1,369 @@
/**
*
*/
package de.bstly.we.businesslogic;
import java.time.Instant;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import com.google.common.collect.Lists;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import de.bstly.we.businesslogic.support.InstantHelper;
import de.bstly.we.model.Permission;
import de.bstly.we.model.PermissionMapping;
import de.bstly.we.model.QPermission;
import de.bstly.we.model.UserData;
import de.bstly.we.repository.PermissionRepository;
/**
*
* @author _bastler@bstly.de
*
*/
@Component
public class PermissionManager implements UserDataProvider {
@Autowired
private PermissionRepository permissionRepository;
@Autowired
private PermissionMappingManager permissionMappingManager;
private QPermission qPermission = QPermission.permission;
DateTimeFormatter pretixOffsetDateTime = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ssx");
/**
*
* @param target
* @param name
* @return
*/
public List<Permission> get(Long target, String name) {
if (target != null) {
return Lists.newArrayList(permissionRepository
.findAll(qPermission.name.eq(name).and(qPermission.target.eq(target))));
}
return Lists.newArrayList();
}
/**
*
* @param target
* @return
*/
public List<Permission> getAllByTarget(Long target) {
if (target != null) {
return Lists.newArrayList(permissionRepository.findAll(qPermission.target.eq(target)));
}
return Lists.newArrayList();
}
/**
*
* @param target
* @return
*/
public List<Permission> getNotExpiresByTarget(Long target) {
if (target != null) {
return Lists.newArrayList(permissionRepository.findAll(qPermission.target.eq(target)
.and(qPermission.expires.after(Instant.now()).and(qPermission.starts.isNull()
.or(qPermission.starts.before(Instant.now()))))));
}
return Lists.newArrayList();
}
/**
*
* @param name
* @return
*/
public List<Permission> getNotExpiresByName(String name) {
if (name != null) {
return Lists.newArrayList(permissionRepository.findAll(qPermission.name.eq(name)
.and(qPermission.expires.after(Instant.now()).and(qPermission.starts.isNull()
.or(qPermission.starts.before(Instant.now()))))));
}
return Lists.newArrayList();
}
/**
*
* @param target
* @return
*/
public List<Permission> getNotExpiresByTargetIgnoreStart(Long target) {
if (target != null) {
return Lists.newArrayList(permissionRepository.findAll(
qPermission.target.eq(target).and(qPermission.expires.after(Instant.now()))));
}
return Lists.newArrayList();
}
/**
*
* @param target
* @return
*/
public boolean isFullUser(Long target) {
return permissionRepository.exists(qPermission.target.eq(target)
.and(qPermission.addon.isFalse()).and(qPermission.expires.after(Instant.now()).and(
qPermission.starts.isNull().or(qPermission.starts.before(Instant.now())))));
}
/**
*
* @param target
* @param name
* @return
*/
public boolean hasPermission(Long target, String name) {
if (!Permissions.ROLE_ADMIN.equals(name) && hasPermission(target, Permissions.ROLE_ADMIN)) {
return true;
}
return target != null && permissionRepository.exists(qPermission.name.eq(name)
.and(qPermission.target.eq(target))
.and(qPermission.expires.after(Instant.now()).and(
qPermission.starts.isNull().or(qPermission.starts.before(Instant.now())))));
}
/**
*
* @param target
* @param name
* @param addon
* @param expires
* @return
*/
public Permission create(Long target, String name, boolean addon, Instant starts,
Instant expires) {
Permission newPermission = new Permission();
newPermission.setTarget(target);
newPermission.setName(name);
newPermission.setAddon(addon);
newPermission.setStarts(starts);
newPermission.setExpires(expires);
return permissionRepository.save(newPermission);
}
/**
*
* @param permission
* @return
*/
public Permission update(Permission permission) {
Assert.isTrue(
permissionRepository.exists(qPermission.target.eq(permission.getTarget())
.and(qPermission.name.eq(permission.getName()))),
"Permission '" + permission.getName() + "' for target + '" + permission.getTarget()
+ "' not exists!");
Permission updatePermission = permissionRepository.findOne(qPermission.target
.eq(permission.getTarget()).and(qPermission.name.eq(permission.getName()))).get();
updatePermission.setStarts(permission.getStarts());
updatePermission.setExpires(permission.getExpires());
updatePermission.setAddon(permission.isAddon());
return permissionRepository.save(updatePermission);
}
/**
*
* @param name
* @param clone
* @return
*/
public List<Permission> clone(String name, String clone) {
List<Permission> permissions = Lists.newArrayList();
for (Permission permission : permissionRepository
.findAll(qPermission.name.eq(name).and(qPermission.expires.after(Instant.now())))) {
if (!permissionRepository.exists(
qPermission.name.eq(clone).and(qPermission.target.eq(permission.getTarget()))
.and(qPermission.expires.goe(permission.getExpires())))) {
permissions.add(create(permission.getTarget(), clone, permission.isAddon(),
permission.getStarts(), permission.getExpires()));
}
}
return permissions;
}
/**
*
* @param target
* @param name
*/
public void delete(Long target, String name) {
Assert.isTrue(
permissionRepository
.exists(qPermission.target.eq(target).and(qPermission.name.eq(name))),
"Permission '" + name + "' for target + '" + target + "' not exists!");
Permission delete = permissionRepository
.findOne(qPermission.target.eq(target).and(qPermission.name.eq(name))).get();
permissionRepository.delete(delete);
}
/**
*
* @param target
*/
public void deleteAll(Long target) {
permissionRepository.deleteAll(permissionRepository.findAll(qPermission.target.eq(target)));
}
/**
*
* @param name
*/
public void deleteAll(String name) {
permissionRepository.deleteAll(permissionRepository.findAll(qPermission.name.eq(name)));
}
/**
*
* @param target
* @param item
* @param answers
*/
public void applyItem(Long target, Integer item, JsonArray answers, Instant start) {
for (Permission permission : getForItem(target, item, answers, start)) {
permissionRepository.save(permission);
}
}
/**
*
* @param target
* @param item
* @param answers
* @return
*/
public List<Permission> getForItem(Long target, Integer item, JsonArray answers,
Instant start) {
List<Permission> permissions = Lists.newArrayList();
if (start == null) {
start = Instant.now();
}
for (PermissionMapping permissionMapping : permissionMappingManager.getAllByItem(item)) {
for (String name : permissionMapping.getNames()) {
Instant starts = null;
Instant expires = InstantHelper.plus(start, permissionMapping.getLifetime(),
permissionMapping.getLifetimeUnit());
boolean additional = true;
for (JsonElement anwser : answers) {
if (anwser.isJsonObject()
&& anwser.getAsJsonObject().has("question_identifier")) {
if (StringUtils.hasText(permissionMapping.getStartsQuestion())
&& permissionMapping.getStartsQuestion()
.equals(anwser.getAsJsonObject().get("question_identifier")
.getAsString())
&& anwser.getAsJsonObject().has("answer")) {
String dateTimeString = anwser.getAsJsonObject().get("answer")
.getAsString();
if (StringUtils.hasText(dateTimeString)) {
dateTimeString = dateTimeString.replace(" ", "T");
starts = OffsetDateTime.parse(dateTimeString).toInstant();
expires = InstantHelper.plus(starts,
permissionMapping.getLifetime(),
permissionMapping.getLifetimeUnit());
additional = false;
}
}
if (StringUtils.hasText(permissionMapping.getExpiresQuestion())
&& permissionMapping.getExpiresQuestion()
.equals(anwser.getAsJsonObject().get("question_identifier")
.getAsString())
&& anwser.getAsJsonObject().has("answer")) {
String dateTimeString = anwser.getAsJsonObject().get("answer")
.getAsString();
if (StringUtils.hasText(dateTimeString)) {
dateTimeString = dateTimeString.replace(" ", "T");
expires = InstantHelper.plus(
OffsetDateTime.parse(dateTimeString).toInstant(),
permissionMapping.getLifetime(),
permissionMapping.getLifetimeUnit());
additional = false;
}
}
}
}
Permission permission = null;
List<Permission> existingPermissions = get(target, name);
for (Permission existingPermission : existingPermissions) {
if (existingPermission.getStarts() == null) {
permission = existingPermission;
break;
}
}
if (permission == null || !additional) {
permission = new Permission();
permission.setTarget(target);
permission.setName(name);
permission.setAddon(permissionMapping.isAddon());
permission.setStarts(starts);
permission.setExpires(expires);
} else {
permission.setExpires(InstantHelper.plus(permission.getExpires(),
permissionMapping.getLifetime(), permissionMapping.getLifetimeUnit()));
}
if (permissionMapping.isLifetimeRound()) {
permission.setExpires(InstantHelper.truncate(permission.getExpires(),
permissionMapping.getLifetimeUnit()));
}
permissions.add(permission);
}
}
return permissions;
}
/*
* @see de.bstly.we.businesslogic.UserDataProvider#getId()
*/
@Override
public String getId() {
return "permissions";
}
/*
* @see de.bstly.we.businesslogic.UserDataProvider#getUserData(java.lang.Long)
*/
@Override
public List<UserData> getUserData(Long userId) {
List<UserData> result = Lists.newArrayList();
for (Permission permission : getAllByTarget(userId)) {
result.add(permission);
}
return result;
}
/*
* @see de.bstly.we.businesslogic.UserDataProvider#purgeUserData(java.lang.Long)
*/
@Override
public void purgeUserData(Long userId) {
for (Permission permission : getAllByTarget(userId)) {
permissionRepository.delete(permission);
}
}
}

View File

@ -0,0 +1,139 @@
/**
*
*/
package de.bstly.we.businesslogic;
import java.time.temporal.ChronoUnit;
import java.util.List;
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import com.google.common.collect.Lists;
import de.bstly.we.model.PermissionMapping;
import de.bstly.we.model.QPermissionMapping;
import de.bstly.we.repository.PermissionMappingRepository;
/**
*
* @author _bastler@bstly.de
*
*/
@Component
public class PermissionMappingManager {
@Autowired
private PermissionMappingRepository permissionMappingRepository;
private QPermissionMapping qPermissionMapping = QPermissionMapping.permissionMapping;
/**
*
* @param item
* @return
*/
public List<PermissionMapping> getAllByItem(Integer item) {
return Lists.newArrayList(
permissionMappingRepository.findAll(qPermissionMapping.item.eq(item)));
}
/**
*
* @param name
* @return
*/
public List<PermissionMapping> getAllByName(String name) {
return Lists.newArrayList(
permissionMappingRepository.findAll(qPermissionMapping.names.contains(name)));
}
/**
*
* @param item
* @return
*/
public boolean exists(Integer item) {
return permissionMappingRepository.exists(qPermissionMapping.item.eq(item));
}
/**
*
* @param item
* @param name
* @return
*/
public boolean exists(Integer item, String name) {
return permissionMappingRepository.exists(
qPermissionMapping.item.eq(item).and(qPermissionMapping.names.contains(name)));
}
/**
*
* @param item
* @param names
* @param lifetime
* @param lifetimeUnit
* @param addon
* @param product
* @return
*/
public PermissionMapping create(Integer item, Set<String> names, Long lifetime,
ChronoUnit lifetimeUnit, boolean lifetimeRound, boolean addon, String product,
String startsQuestion, String expiresQuestion) {
for (String name : names) {
Assert.isTrue(!exists(item, name), "PermissionMapping for item '" + item
+ "' with permission '" + name + "' already exists!");
}
PermissionMapping permissionMapping = new PermissionMapping();
permissionMapping.setItem(item);
permissionMapping.setNames(names);
permissionMapping.setLifetime(lifetime);
permissionMapping.setLifetimeUnit(lifetimeUnit);
permissionMapping.setLifetimeRound(lifetimeRound);
permissionMapping.setAddon(addon);
permissionMapping.setProduct(product);
permissionMapping.setStartsQuestion(startsQuestion);
permissionMapping.setExpiresQuestion(expiresQuestion);
return permissionMappingRepository.save(permissionMapping);
}
/**
*
* @param permissionMapping
* @return
*/
public PermissionMapping update(PermissionMapping permissionMapping) {
return permissionMappingRepository.save(permissionMapping);
}
/**
*
* @param item
* @param name
*/
public void delete(Long id) {
Assert.isTrue(permissionMappingRepository.existsById(id),
"Permission Mapping '" + id + "' does not exists!");
PermissionMapping permissionMapping = permissionMappingRepository.findById(id).get();
permissionMappingRepository.delete(permissionMapping);
}
/**
*
* @param page
* @param size
* @param sortBy
* @param descending
* @return
*/
public Page<PermissionMapping> get(int page, int size, String sortBy, boolean descending) {
Sort sort = descending ? Sort.by(sortBy).descending() : Sort.by(sortBy).ascending();
return permissionMappingRepository.findAll(PageRequest.of(page, size, sort));
}
}

View File

@ -0,0 +1,18 @@
/**
*
*/
package de.bstly.we.businesslogic;
/**
* @author _bastler@bstly.de
*
*/
public interface Permissions {
public static final String ROLE_ADMIN = "ROLE_ADMIN";
public static final String ROLE_USER = "ROLE_USER";
public static final String ROLE_MEMBER = "ROLE_MEMBER";
public static final String ROLE_GUEST = "ROLE_GUEST";
public static final String MAIL = "mail";
}

View File

@ -0,0 +1,12 @@
/**
*
*/
package de.bstly.we.businesslogic;
/**
* @author _bastler@bstly.de
*
*/
public enum PretixItemStatus {
ERROR, NOT_FOUND, PENDING, PAID, EXPIRED, CANCELED, REDEEMED
}

View File

@ -0,0 +1,542 @@
/**
*
*/
package de.bstly.we.businesslogic;
import java.time.Instant;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.reactive.function.client.WebClientResponseException;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
/**
*
* @author _bastler@bstly.de
*
*/
@Component
public class PretixManager implements SmartInitializingSingleton {
public static final int invalid_item = -1;
private Logger logger = LoggerFactory.getLogger(PretixManager.class);
@Autowired
private Environment environment;
@Autowired
private SystemPropertyManager systemPropertyManager;
protected static Gson gson = new Gson();
public static final String SYSTEM_PROPERTY_PRETIX_HOST = "pretix.host";
public static final String SYSTEM_PROPERTY_PRETIX_TOKEN = "pretix.token";
public static final String SYSTEM_PROPERTY_PRETIX_ORGANIZER = "pretix.organizer";
public static final String SYSTEM_PROPERTY_PRETIX_EVENT = "pretix.event";
public static final String SYSTEM_PROPERTY_PRETIX_CHECKINLIST = "pretix.checkinlist";
public static final String SYSTEM_PROPERTY_PRETIX_QUOTA_REGISTRATIONS = "pretix.quota.registrations";
public static final String SYSTEM_PROPERTY_PRETIX_QUOTA_ADDONS = "pretix.quota.addons";
public static final String SYSTEM_PROPERTY_PRETIX_MEMBERSHIP_ITEM = "pretix.membership.item";
public static final String SYSTEM_PROPERTY_PRETIX_MEMBERSHIPFEE_ITEM = "pretix.membershipfee.item";
// membership ID management
public static final String SYSTEM_PROPERTY_PRETIX_MEMBERSHIP_ID_QUESTION = "pretix.membershipid.question";
public static final String SYSTEM_PROPERTY_PRETIX_MEMBERSHIPFEE_REFERENCE_QUESTION = "pretix.membershipfeereference.question";
public static final String SYSTEM_PROPERTY_PRETIX_MEMBERSHIPFEE_CODE_QUESTION = "pretix.membershipfeecode.question";
public static final String SYSTEM_PROPERTY_PRETIX_MEMBERSHIP_INTERNAL_ID_QUESTION = "pretix.membershipinternalid.question";
public static final String SYSTEM_PROPERTY_PRETIX_MEMBERSHIP_ACTIVE_QUESTION = "pretix.membershipactive.question";
public static final String SYSTEM_PROPERTY_PRETIX_MEMBERSHIP_DISCOUNT_PERIOD = "pretix.membership.discount.period";
public static final String SYSTEM_PROPERTY_PRETIX_MEMBERSHIPFEE_ORDER_DAYS = "pretix.membershipfee.order.days";
public static final String SYSTEM_PROPERTY_PRETIX_MEMBERSHIPFEE_REMINDER_DAYS = "pretix.membershipfee.reminder.days";
public static final String SYSTEM_PROPERTY_PRETIX_MEMBERSHIPFEE_REMINDER_QUESTION = "pretix.membershipfee.reminder.question";
public static final String SYSTEM_PROPERTY_PRETIX_ORDER_SENDMAIL = "pretix.order.sendmail";
public static final String SYSTEM_PROPERTY_PRETIX_ORDER_TESTMODE = "pretix.order.testmode";
public static final String SYSTEM_PROPERTY_PRETIX_ORDER_SIMULATE = "pretix.order.simulate";
public enum ITEM_STATUS {
ERROR, NOT_FOUND, PENDING, PAID, EXPIRED, CANCELED, REDEEMED
}
private String host;
private String token;
private String organizer;
private String event;
private String checkinlist;
private int quotaRegistration;
private int quotaAddons;
protected WebClient webClient;
/*
* @see org.springframework.beans.factory.SmartInitializingSingleton#
* afterSingletonsInstantiated()
*/
@Override
public void afterSingletonsInstantiated() {
if (!systemPropertyManager.has(SYSTEM_PROPERTY_PRETIX_HOST)) {
systemPropertyManager.add(SYSTEM_PROPERTY_PRETIX_HOST,
environment.getProperty("we.bstly." + SYSTEM_PROPERTY_PRETIX_HOST, ""));
}
if (!systemPropertyManager.has(SYSTEM_PROPERTY_PRETIX_TOKEN)) {
systemPropertyManager.add(SYSTEM_PROPERTY_PRETIX_TOKEN,
environment.getProperty("we.bstly." + SYSTEM_PROPERTY_PRETIX_TOKEN, ""));
}
if (!systemPropertyManager.has(SYSTEM_PROPERTY_PRETIX_ORGANIZER)) {
systemPropertyManager.add(SYSTEM_PROPERTY_PRETIX_ORGANIZER,
environment.getProperty("we.bstly." + SYSTEM_PROPERTY_PRETIX_ORGANIZER, ""));
}
if (!systemPropertyManager.has(SYSTEM_PROPERTY_PRETIX_EVENT)) {
systemPropertyManager.add(SYSTEM_PROPERTY_PRETIX_EVENT,
environment.getProperty("we.bstly." + SYSTEM_PROPERTY_PRETIX_EVENT, ""));
}
if (!systemPropertyManager.has(SYSTEM_PROPERTY_PRETIX_CHECKINLIST)) {
systemPropertyManager.add(SYSTEM_PROPERTY_PRETIX_CHECKINLIST,
environment.getProperty("we.bstly." + SYSTEM_PROPERTY_PRETIX_CHECKINLIST, ""));
}
if (!systemPropertyManager.has(SYSTEM_PROPERTY_PRETIX_QUOTA_REGISTRATIONS)) {
systemPropertyManager.add(SYSTEM_PROPERTY_PRETIX_QUOTA_REGISTRATIONS, environment
.getProperty("we.bstly." + SYSTEM_PROPERTY_PRETIX_QUOTA_REGISTRATIONS, "0"));
}
if (!systemPropertyManager.has(SYSTEM_PROPERTY_PRETIX_QUOTA_ADDONS)) {
systemPropertyManager.add(SYSTEM_PROPERTY_PRETIX_QUOTA_ADDONS, environment
.getProperty("we.bstly." + SYSTEM_PROPERTY_PRETIX_QUOTA_ADDONS, "0"));
}
if (!systemPropertyManager.has(SYSTEM_PROPERTY_PRETIX_MEMBERSHIP_ITEM)) {
systemPropertyManager.add(SYSTEM_PROPERTY_PRETIX_MEMBERSHIP_ITEM, environment
.getProperty("we.bstly." + SYSTEM_PROPERTY_PRETIX_MEMBERSHIP_ITEM, "0"));
}
if (!systemPropertyManager.has(SYSTEM_PROPERTY_PRETIX_MEMBERSHIPFEE_ITEM)) {
systemPropertyManager.add(SYSTEM_PROPERTY_PRETIX_MEMBERSHIPFEE_ITEM, environment
.getProperty("we.bstly." + SYSTEM_PROPERTY_PRETIX_MEMBERSHIPFEE_ITEM, "0"));
}
buildWebClient();
}
/**
*
*/
public void buildWebClient() {
host = systemPropertyManager.get(SYSTEM_PROPERTY_PRETIX_HOST);
token = systemPropertyManager.get(SYSTEM_PROPERTY_PRETIX_TOKEN);
organizer = systemPropertyManager.get(SYSTEM_PROPERTY_PRETIX_ORGANIZER);
event = systemPropertyManager.get(SYSTEM_PROPERTY_PRETIX_EVENT);
checkinlist = systemPropertyManager.get(SYSTEM_PROPERTY_PRETIX_CHECKINLIST);
quotaRegistration = systemPropertyManager
.getInteger(SYSTEM_PROPERTY_PRETIX_QUOTA_REGISTRATIONS);
quotaAddons = systemPropertyManager.getInteger(SYSTEM_PROPERTY_PRETIX_QUOTA_ADDONS);
webClient = WebClient.builder().baseUrl(host)
.defaultHeader(HttpHeaders.CONTENT_TYPE, "application/json")
.defaultHeader(HttpHeaders.AUTHORIZATION, "Token " + token).build();
}
/**
*
* @param secret
* @return
*/
public ITEM_STATUS getItemStatus(String secret) {
try {
JsonObject item = getCheckInItemBySecret(secret);
if (item != null) {
if (item.get("secret").getAsString().equals(secret)) {
if (item.getAsJsonArray("checkins").size() < 1
&& "p".equals(item.get("order__status").getAsString())) {
return ITEM_STATUS.PAID;
} else if (item.getAsJsonArray("checkins").size() > 0) {
return ITEM_STATUS.REDEEMED;
}
} else {
return ITEM_STATUS.ERROR;
}
} else {
item = getOrderBySecret(secret);
if (item != null) {
logger.warn("Checked secret: '" + secret + "' without valid payment!");
return ITEM_STATUS.ERROR;
}
}
return ITEM_STATUS.NOT_FOUND;
} catch (WebClientResponseException e) {
return ITEM_STATUS.ERROR;
}
}
/**
*
* @param secret
* @return
*/
public JsonObject getCheckInItemBySecret(String secret) {
MultiValueMap<String, String> queryParams = new LinkedMultiValueMap<String, String>();
queryParams.add("secret", secret);
JsonObject orderPositions = request(
String.format("/api/v1/organizers/%s/events/%s/checkinlists/%s/positions/",
organizer, event, checkinlist),
HttpMethod.GET, queryParams).getAsJsonObject();
JsonArray results = orderPositions.getAsJsonArray("results");
if (results.size() == 1) {
return results.get(0).getAsJsonObject();
}
return null;
}
/**
*
* @param code
* @return
*/
public JsonObject getOrder(String code) {
return request(
String.format("/api/v1/organizers/%s/events/%s/orders/%s/", organizer, event, code),
HttpMethod.GET).getAsJsonObject();
}
/**
*
* @param secret
* @return
*/
public JsonObject getOrderBySecret(String secret) {
MultiValueMap<String, String> queryParams = new LinkedMultiValueMap<String, String>();
queryParams.add("secret", secret);
JsonObject orderPositions = request(
String.format("/api/v1/organizers/%s/events/%s/orderpositions/", organizer, event),
HttpMethod.GET, queryParams).getAsJsonObject();
JsonArray results = orderPositions.getAsJsonArray("results");
if (results.size() == 1) {
JsonObject orderPosition = results.get(0).getAsJsonObject();
return request(String.format("/api/v1/organizers/%s/events/%s/orders/%s/", organizer,
event, orderPosition.get("order").getAsString()), HttpMethod.GET)
.getAsJsonObject();
}
return null;
}
/**
*
* @param order
* @return
*/
public JsonObject createOrder(JsonObject order) {
return request(String.format("/api/v1/organizers/%s/events/%s/orders/", organizer, event),
HttpMethod.POST, order).getAsJsonObject();
}
/**
*
* @param order
* @return
*/
public JsonObject extendOrder(String code, JsonObject expire) {
return request(String.format("/api/v1/organizers/%s/events/%s/orders/%s/extend/", organizer,
event, code), HttpMethod.POST, expire).getAsJsonObject();
}
/**
*
* @param code
*/
public void sendEmail(String code) {
request(String.format("/api/v1/organizers/%s/events/%s/orders/%s/resend_link/", organizer,
event, code), HttpMethod.POST);
}
/**
*
* @param secret
* @return
*/
public Instant getLastPaymentDateBySecret(String secret) {
MultiValueMap<String, String> queryParams = new LinkedMultiValueMap<String, String>();
queryParams.add("secret", secret);
JsonObject orderPositions = request(
String.format("/api/v1/organizers/%s/events/%s/orderpositions/", organizer, event),
HttpMethod.GET, queryParams).getAsJsonObject();
JsonArray results = orderPositions.getAsJsonArray("results");
if (results.size() == 1) {
JsonObject orderPosition = results.get(0).getAsJsonObject();
return getLastPaymentDateForOrder(orderPosition.get("order").getAsString());
}
return null;
}
/**
*
* @param secret
* @return
*/
public Instant getLastPaymentDateForOrder(String order) {
JsonArray paymentResults = request(
String.format("/api/v1/organizers/%s/events/%s/orders/%s/payments/", organizer,
event, order),
HttpMethod.GET).getAsJsonObject().getAsJsonArray("results");
Instant lastDate = null;
for (JsonElement element : paymentResults) {
JsonObject payment = element.getAsJsonObject();
if ("confirmed".equalsIgnoreCase(payment.get("state").getAsString())) {
Instant currentDate = Instant.parse(payment.get("payment_date").getAsString());
if (lastDate == null) {
lastDate = currentDate;
} else if (currentDate.isAfter(lastDate)) {
lastDate = currentDate;
}
}
}
return lastDate;
}
/**
*
* @param secret
* @return
*/
public JsonObject getCheckInItemByItem(Integer item) {
MultiValueMap<String, String> queryParams = new LinkedMultiValueMap<String, String>();
queryParams.add("item", String.valueOf(item));
JsonObject orderPositions = request(
String.format("/api/v1/organizers/%s/events/%s/checkinlists/%s/positions/",
organizer, event, checkinlist),
HttpMethod.GET, queryParams).getAsJsonObject();
JsonArray results = orderPositions.getAsJsonArray("results");
if (results.size() == 1) {
return results.get(0).getAsJsonObject();
}
return null;
}
/**
*
* @param secret
* @return
*/
public JsonObject redeemItem(String secret) {
if (getItemStatus(secret) == ITEM_STATUS.PAID) {
JsonObject checkIn = getCheckInPositions(secret);
return redeem(checkIn.get("id").getAsString());
}
return null;
}
/**
*
* @param idOrSecret
* @return
*/
public JsonObject getCheckInPositions(String idOrSecret) {
return request(
String.format("/api/v1/organizers/%s/events/%s/checkinlists/%s/positions/%s/",
organizer, event, checkinlist, idOrSecret),
HttpMethod.GET).getAsJsonObject();
}
/**
*
* @param idOrSecret
* @return
*/
public JsonObject redeem(String idOrSecret) {
return request(String.format(
"/api/v1/organizers/%s/events/%s/checkinlists/%s/positions/%s/redeem/", organizer,
event, checkinlist, idOrSecret), HttpMethod.POST).getAsJsonObject();
}
/**
*
* @return
*/
public JsonObject createRegistrationVoucher() {
return createVoucher(quotaRegistration);
}
/**
*
* @return
*/
public JsonObject createAddOnVoucher() {
return createVoucher(quotaAddons);
}
/**
*
* @param quotaId
* @return
*/
public JsonObject createVoucher(int quotaId) {
JsonObject voucher = new JsonObject();
voucher.addProperty("max_usages", 1);
voucher.addProperty("quota", quotaId);
voucher.addProperty("block_quota", true);
return request(String.format("/api/v1/organizers/%s/events/%s/vouchers/", organizer, event),
HttpMethod.POST, voucher).getAsJsonObject();
}
/**
*
* @param secret
* @return
*/
public JsonObject getItem(Integer item) {
return request(
String.format("/api/v1/organizers/%s/events/%s/items/%s/", organizer, event, item),
HttpMethod.GET).getAsJsonObject();
}
public JsonArray getVariations(Integer item) {
return request(String.format("/api/v1/organizers/%s/events/%s/items/%s/variations/",
organizer, event, item), HttpMethod.GET).getAsJsonObject()
.getAsJsonArray("results");
}
/**
*
* @param item
* @param variationId
* @param variation
*/
public void updateVariation(Integer item, Integer variationId, JsonObject variation) {
request(String.format("/api/v1/organizers/%s/events/%s/items/%s/variations/%s/", organizer,
event, item, variationId), HttpMethod.PATCH, variation);
}
/**
*
* @param item
* @param variation
*/
public void deleteVariation(Integer item, Integer variation) {
request(String.format("/api/v1/organizers/%s/events/%s/items/%s/variations/%s/", organizer,
event, item, variation), HttpMethod.DELETE);
}
/**
*
* @param item
*/
public void deleteVariations(Integer item) {
for (JsonElement variationElement : getVariations(item)) {
JsonObject variation = variationElement.getAsJsonObject();
deleteVariation(item, variation.get("id").getAsInt());
}
}
/**
*
* @param path
* @param method
* @return
*/
public JsonElement request(String path, HttpMethod method) {
return request(path, method, null, new LinkedMultiValueMap<String, String>());
}
/**
*
* @param path
* @param method
* @param queryParameters
* @return
*/
public JsonElement request(String path, HttpMethod method,
MultiValueMap<String, String> queryParameters) {
return request(path, method, null, queryParameters);
}
/**
*
* @param path
* @param method
* @param queryParameters
* @return
*/
public JsonElement request(String path, HttpMethod method, JsonElement payload) {
return request(path, method, payload, new LinkedMultiValueMap<String, String>());
}
/**
*
* @param path
* @param payload
* @param method
* @param queryParameters
* @return
*/
public JsonElement request(String path, HttpMethod method, JsonElement payload,
MultiValueMap<String, String> queryParameters) {
WebClient.RequestBodySpec request = webClient.method(method)
.uri(uriBuilder -> uriBuilder.path(path).queryParams(queryParameters).build());
if (payload != null) {
request.bodyValue(gson.toJson(payload));
}
String jsonString = request.retrieve().bodyToMono(String.class).block();
if (StringUtils.hasText(jsonString)) {
return JsonParser.parseString(jsonString);
}
return null;
}
/**
* @return the organizer
*/
public String getOrganizer() {
return organizer;
}
/**
* @return the event
*/
public String getEvent() {
return event;
}
/**
* @return the checkinlist
*/
public String getCheckinlist() {
return checkinlist;
}
}

View File

@ -0,0 +1,233 @@
/**
*
*/
package de.bstly.we.businesslogic;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import com.google.common.collect.Lists;
import de.bstly.we.model.QQuota;
import de.bstly.we.model.Quota;
import de.bstly.we.model.QuotaMapping;
import de.bstly.we.model.UserData;
import de.bstly.we.repository.QuotaRepository;
/**
*
* @author _bastler@bstly.de
*
*/
@Component
public class QuotaManager implements UserDataProvider {
@Autowired
private QuotaRepository quotaRepository;
@Autowired
private QuotaMappingManager quotaMappingManager;
private QQuota qQuota = QQuota.quota;
/**
*
* @param target
* @param name
* @return
*/
public Quota get(Long target, String name) {
if (target != null && name != null) {
return quotaRepository.findOne(qQuota.name.eq(name).and(qQuota.target.eq(target)))
.orElse(null);
}
return null;
}
/**
*
* @param name
* @return
*/
public List<Quota> getAllByName(String name) {
return Lists.newArrayList(quotaRepository.findAll(qQuota.name.eq(name)));
}
/**
*
* @param target
* @return
*/
public List<Quota> getAllByTarget(Long target) {
if (target != null) {
return Lists.newArrayList(quotaRepository.findAll(qQuota.target.eq(target)));
}
return Lists.newArrayList();
}
/**
*
* @param target
* @return
*/
public List<Quota> getNotExpiresByTarget(Long target) {
if (target != null) {
return Lists.newArrayList(
quotaRepository.findAll(qQuota.target.eq(target).and(qQuota.value.gt(0))));
}
return Lists.newArrayList();
}
/**
*
* @param target
* @param name
* @return
*/
public boolean hasQuota(Long target, String name) {
return target != null && quotaRepository
.exists(qQuota.name.eq(name).and(qQuota.target.eq(target)).and(qQuota.value.gt(0)));
}
/**
*
* @param target
* @param name
* @param addon
* @param value
* @param unit
* @return
*/
public Quota create(Long target, String name, long value, String unit, boolean disposable) {
Quota newQuota = new Quota();
newQuota.setTarget(target);
newQuota.setName(name);
newQuota.setValue(value);
newQuota.setUnit(unit);
newQuota.setDisposable(disposable);
return quotaRepository.save(newQuota);
}
/**
*
* @param quota
* @return
*/
public Quota update(Quota quota) {
Assert.isTrue(
quotaRepository.exists(
qQuota.target.eq(quota.getTarget()).and(qQuota.name.eq(quota.getName()))),
"Quota '" + quota.getName() + "' for target + '" + quota.getTarget()
+ "' not exists!");
Quota updateQuota = quotaRepository
.findOne(qQuota.target.eq(quota.getTarget()).and(qQuota.name.eq(quota.getName())))
.get();
updateQuota.setValue(quota.getValue());
updateQuota.setUnit(quota.getUnit());
updateQuota.setDisposable(quota.isDisposable());
return quotaRepository.save(updateQuota);
}
/**
*
* @param name
* @param clone
* @return
*/
public List<Quota> clone(String name, String clone, long value) {
List<Quota> quotas = Lists.newArrayList();
for (Quota quota : quotaRepository.findAll(qQuota.name.eq(name))) {
if (!quotaRepository
.exists(qQuota.name.eq(clone).and(qQuota.target.eq(quota.getTarget())))) {
quotas.add(create(quota.getTarget(), clone, value >= 0 ? value : quota.getValue(),
quota.getUnit(), quota.isDisposable()));
}
}
return quotas;
}
/**
*
* @param target
* @param name
*/
public void delete(Long target, String name) {
Assert.isTrue(quotaRepository.exists(qQuota.target.eq(target).and(qQuota.name.eq(name))),
"Quota '" + name + "' for target + '" + target + "' not exists!");
Quota delete = quotaRepository.findOne(qQuota.target.eq(target).and(qQuota.name.eq(name)))
.get();
quotaRepository.delete(delete);
}
/**
*
* @param target
*/
public void deleteAll(Long target) {
quotaRepository.deleteAll(quotaRepository.findAll(qQuota.target.eq(target)));
}
/**
*
* @param name
*/
public void deleteAll(String name) {
quotaRepository.deleteAll(quotaRepository.findAll(qQuota.name.eq(name)));
}
/**
*
* @param target
* @param item
*/
public void applyItem(Long target, Integer item) {
for (QuotaMapping quotaMapping : quotaMappingManager.getAllByItem(item)) {
Quota quota = get(target, quotaMapping.getName());
if (quota == null) {
quota = create(target, quotaMapping.getName(), quotaMapping.getValue(),
quotaMapping.getUnit(), quotaMapping.isDisposable());
} else {
quota.setValue(quotaMapping.isAppend() ? quota.getValue() + quotaMapping.getValue()
: quotaMapping.getValue());
quota = update(quota);
}
}
}
/*
* @see de.bstly.we.businesslogic.UserDataProvider#getId()
*/
@Override
public String getId() {
return "quotas";
}
/*
* @see de.bstly.we.businesslogic.UserDataProvider#getUserData(java.lang.Long)
*/
@Override
public List<UserData> getUserData(Long userId) {
List<UserData> result = Lists.newArrayList();
for (Quota quota : getAllByTarget(userId)) {
result.add(quota);
}
return result;
}
/*
* @see de.bstly.we.businesslogic.UserDataProvider#purgeUserData(java.lang.Long)
*/
@Override
public void purgeUserData(Long userId) {
for (Quota quota : getAllByTarget(userId)) {
quotaRepository.delete(quota);
}
}
}

View File

@ -0,0 +1,134 @@
/**
*
*/
package de.bstly.we.businesslogic;
import java.util.List;
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import com.google.common.collect.Lists;
import de.bstly.we.model.QQuotaMapping;
import de.bstly.we.model.QuotaMapping;
import de.bstly.we.repository.QuotaMappingRepository;
/**
*
* @author _bastler@bstly.de
*
*/
@Component
public class QuotaMappingManager {
@Autowired
private QuotaMappingRepository quotaMappingRepository;
private QQuotaMapping qQuotaMapping = QQuotaMapping.quotaMapping;
/**
*
* @param item
* @return
*/
public List<QuotaMapping> getAllByItem(Integer item) {
return Lists
.newArrayList(quotaMappingRepository.findAll(qQuotaMapping.items.contains(item)));
}
/**
*
* @param item
* @return
*/
public boolean exists(Integer item) {
return quotaMappingRepository.exists(qQuotaMapping.items.contains(item));
}
/**
*
* @param item
* @param name
* @return
*/
public boolean exists(Integer item, String name) {
return quotaMappingRepository
.exists(qQuotaMapping.items.contains(item).and(qQuotaMapping.name.eq(name)));
}
/**
*
* @param item
* @param quota
* @param lifetime
* @return
*/
public QuotaMapping create(Set<Integer> items, String name, long value, String unit,
boolean append, Set<String> products, boolean disposable) {
for (Integer item : items) {
Assert.isTrue(!exists(item, name), "QuotaMapping for item '" + item + "' with quota '"
+ name + "' already exists!");
}
QuotaMapping quotaMapping = new QuotaMapping();
quotaMapping.setItems(items);
quotaMapping.setName(name);
quotaMapping.setValue(value);
quotaMapping.setUnit(unit);
quotaMapping.setAppend(append);
quotaMapping.setProducts(products);
quotaMapping.setDisposable(disposable);
return quotaMappingRepository.save(quotaMapping);
}
/**
*
* @param quotaMapping
* @return
*/
public QuotaMapping update(QuotaMapping quotaMapping) {
Assert.isTrue(
quotaMapping.getId() != null
&& quotaMappingRepository.existsById(quotaMapping.getId()),
"QuotaMapping '" + quotaMapping.getId() + "' does not exists!");
QuotaMapping updateQuotaMapping = quotaMappingRepository.findById(quotaMapping.getId())
.get();
updateQuotaMapping.setProducts(quotaMapping.getProducts());
updateQuotaMapping.setItems(quotaMapping.getItems());
updateQuotaMapping.setValue(quotaMapping.getValue());
updateQuotaMapping.setUnit(quotaMapping.getUnit());
updateQuotaMapping.setAppend(quotaMapping.isAppend());
updateQuotaMapping.setDisposable(quotaMapping.isDisposable());
return quotaMappingRepository.save(updateQuotaMapping);
}
/**
*
* @param item
* @param name
*/
public void delete(Long id) {
Assert.isTrue(quotaMappingRepository.existsById(id),
"QuotaMapping '" + id + "' does not exists!");
quotaMappingRepository.deleteById(id);
}
/**
*
* @param page
* @param size
* @param sortBy
* @param descending
* @return
*/
public Page<QuotaMapping> get(int page, int size, String sortBy, boolean descending) {
Sort sort = descending ? Sort.by(sortBy).descending() : Sort.by(sortBy).ascending();
return quotaMappingRepository.findAll(PageRequest.of(page, size, sort));
}
}

View File

@ -0,0 +1,15 @@
/**
*
*/
package de.bstly.we.businesslogic;
/**
* @author _bastler@bstly.de
*
*/
public interface Quotas {
public static final String REGISTRATION_VOUCHERS = "registration_vouchers";
public static final String ALIAS_CREATION = "alias_creation";
}

View File

@ -0,0 +1,107 @@
/**
*
*/
package de.bstly.we.businesslogic;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.List;
import org.apache.commons.lang3.RandomStringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import com.google.common.collect.Lists;
import de.bstly.we.businesslogic.support.InstantHelper;
import de.bstly.we.controller.validation.UserModelValidator;
import de.bstly.we.model.User;
import de.bstly.we.model.UserStatus;
/**
*
* @author _bastler@bstly.de
*
*/
@Component
public class Setup implements SmartInitializingSingleton {
@Autowired
private UserManager userManager;
@Autowired
private PermissionManager permissionManager;
@Autowired
private ResourceLoader resourceLoader;
@Autowired
private SystemPropertyManager systemPropertyManager;
protected static final long TAUSEND_JAHRE = 1000;
@Value("${we.bstly.admin.password:}")
private String adminPassword;
@Value("${we.bstly.setup:true}")
private boolean setup;
private Logger logger = LoggerFactory.getLogger(Setup.class);
/*
* @see org.springframework.beans.factory.SmartInitializingSingleton#
* afterSingletonsInstantiated()
*/
@Override
public void afterSingletonsInstantiated() {
// create admin account if not found
if (!setup || !systemPropertyManager.has("setup")) {
if (!StringUtils.hasText(adminPassword)) {
adminPassword = RandomStringUtils.random(24, true, true);
logger.error("password for 'admin': " + adminPassword);
}
User admin = userManager.create("admin", adminPassword, UserStatus.SLEEP);
permissionManager.create(admin.getId(), Permissions.ROLE_ADMIN, false, null,
InstantHelper.plus(Instant.now(), TAUSEND_JAHRE, ChronoUnit.YEARS));
systemPropertyManager.add("setup", "true");
}
try {
Resource resource = resourceLoader.getResource("classpath:usernames.txt");
if (resource.exists()) {
BufferedReader br = new BufferedReader(
new InputStreamReader(resource.getInputStream()));
List<String> usernames = Lists.newArrayList();
String line;
while ((line = br.readLine()) != null) {
if (StringUtils.hasText(line) && !usernames.contains(line)
&& !line.startsWith("#")) {
usernames.add(line);
}
}
if (systemPropertyManager.has(UserModelValidator.RESERVED_USERNAMES)) {
systemPropertyManager.update(UserModelValidator.RESERVED_USERNAMES,
org.apache.commons.lang3.StringUtils.join(usernames, ","));
} else {
systemPropertyManager.add(UserModelValidator.RESERVED_USERNAMES,
org.apache.commons.lang3.StringUtils.join(usernames, ","));
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}

View File

@ -0,0 +1,64 @@
/**
*
*/
package de.bstly.we.businesslogic;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Component;
import de.bstly.we.model.SystemProfileField;
import de.bstly.we.repository.SystemProfileFieldRepository;
/**
* @author _bastler@bstly.de
*
*/
@Component
public class SystemProfileFieldManager {
@Autowired
private SystemProfileFieldRepository systemProfileFieldRepository;
/**
*
* @param systemProfileField
* @return
*/
public SystemProfileField save(SystemProfileField systemProfileField) {
return systemProfileFieldRepository.save(systemProfileField);
}
/**
*
* @param name
* @return
*/
public SystemProfileField get(String name) {
return systemProfileFieldRepository.findById(name).orElse(null);
}
/**
*
* @param page
* @param size
* @param sortBy
* @param descending
* @return
*/
public Page<SystemProfileField> get(int page, int size, String sortBy, boolean descending) {
Sort sort = descending ? Sort.by(sortBy).descending() : Sort.by(sortBy).ascending();
return systemProfileFieldRepository.findAll(PageRequest.of(page, size, sort));
}
/**
*
* @param name
*/
public void delete(String name) {
systemProfileFieldRepository.deleteById(name);
}
}

View File

@ -0,0 +1,133 @@
/**
*
*/
package de.bstly.we.businesslogic;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import de.bstly.we.model.SystemProperty;
import de.bstly.we.repository.SystemPropertyRepository;
/**
*
* @author _bastler@bstly.de
*
*/
@Component
public class SystemPropertyManager {
@Autowired
private SystemPropertyRepository systemPropertyRepository;
/**
*
* @param key
* @return
*/
public boolean has(String key) {
return systemPropertyRepository.existsById(key);
}
/**
*
* @param key
* @return
*/
public String get(String key) {
return systemPropertyRepository.findById(key).orElse(new SystemProperty()).getValue();
}
/**
*
* @param key
* @param defaultValue
* @return
*/
public String get(String key, String defaultValue) {
return systemPropertyRepository.findById(key).orElse(new SystemProperty(key, defaultValue)).getValue();
}
/**
*
* @param key
* @return
*/
public boolean getBoolean(String key) {
return getBoolean(key, false);
}
/**
*
* @param key
* @param defaultValue
* @return
*/
public boolean getBoolean(String key, boolean defaultValue) {
return Boolean.valueOf(get(key, String.valueOf(defaultValue)));
}
/**
*
* @param key
* @return
*/
public int getInteger(String key) {
return getInteger(key, 0);
}
/**
*
* @param key
* @param defaultValue
* @return
*/
public int getInteger(String key, int defaultValue) {
return Integer.valueOf(get(key, String.valueOf(defaultValue)));
}
/**
*
* @param key
* @return
*/
public long getLong(String key) {
return getLong(key, 0L);
}
/**
*
* @param key
* @param defaultValue
* @return
*/
public long getLong(String key, long defaultValue) {
return Long.valueOf(get(key, String.valueOf(defaultValue)));
}
/**
*
* @param key
* @param value
*/
public void add(String key, String value) {
Assert.isTrue(!systemPropertyRepository.existsById(key),
"System Property already exists, use update method to change value!");
systemPropertyRepository.save(new SystemProperty(key, value));
}
/**
*
* @param key
* @param value
*/
public void update(String key, String value) {
Assert.isTrue(systemPropertyRepository.existsById(key),
"System Property does not exists, use add method to add new!");
SystemProperty systemProperty = systemPropertyRepository.findById(key).get();
systemProperty.setValue(value);
systemPropertyRepository.save(systemProperty);
}
}

View File

@ -0,0 +1,128 @@
/**
*
*/
package de.bstly.we.businesslogic;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import com.google.common.collect.Lists;
import de.bstly.we.model.QUserAlias;
import de.bstly.we.model.UserAlias;
import de.bstly.we.model.UserData;
import de.bstly.we.repository.UserAliasRepository;
/**
* @author _bastler@bstly.de
*
*/
@Component
public class UserAliasManager implements UserDataProvider {
@Autowired
private UserManager userManager;
@Autowired
private UserAliasRepository userAliasRepository;
private QUserAlias qUserAlias = QUserAlias.userAlias;
/**
*
* @param id
* @return
*/
public UserAlias get(Long id) {
return userAliasRepository.findById(id).orElse(null);
}
/**
*
* @param userAlias
* @return
*/
public UserAlias save(UserAlias userAlias) {
Assert.notNull(userAlias.getAlias(), "No alias defined!");
Assert.notNull(userAlias.getTarget(), "No target defined!");
Assert.notNull(userManager.get(userAlias.getTarget()), "Invalid target defined!");
return userAliasRepository.save(userAlias);
}
/**
*
* @param alias
* @return
*/
public UserAlias getByAlias(String alias) {
return userAliasRepository.findOne(qUserAlias.alias.eq(alias)).orElse(null);
}
/**
*
* @param userId
* @return
*/
public List<UserAlias> getAllByTarget(Long userId) {
return Lists.newArrayList(userAliasRepository.findAll(qUserAlias.target.eq(userId)));
}
/**
*
* @param id
*/
public void delete(Long id) {
UserAlias userAlias = get(id);
if (userAlias != null) {
userAliasRepository.delete(userAlias);
}
}
/**
*
* @param page
* @param size
* @param sortBy
* @param descending
* @return
*/
public Page<UserAlias> get(int page, int size, String sortBy, boolean descending) {
Sort sort = descending ? Sort.by(sortBy).descending() : Sort.by(sortBy).ascending();
return userAliasRepository.findAll(PageRequest.of(page, size, sort));
}
/*
* @see de.bstly.we.businesslogic.UserDataProvider#getId()
*/
@Override
public String getId() {
return "aliases";
}
/*
* @see de.bstly.we.businesslogic.UserDataProvider#getUserData(java.lang.Long)
*/
@Override
public List<UserData> getUserData(Long userId) {
List<UserData> result = Lists.newArrayList();
for (UserAlias userAlias : getAllByTarget(userId)) {
result.add(userAlias);
}
return result;
}
/*
* @see de.bstly.we.businesslogic.UserDataProvider#purgeUserData(java.lang.Long)
*/
@Override
public void purgeUserData(Long userId) {
for (UserAlias userAlias : getAllByTarget(userId)) {
userAliasRepository.delete(userAlias);
}
}
}

View File

@ -0,0 +1,181 @@
/**
*
*/
package de.bstly.we.businesslogic;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import com.beust.jcommander.internal.Maps;
import com.google.common.collect.Lists;
import com.google.gson.Gson;
import de.bstly.we.model.Permission;
import de.bstly.we.model.User;
import de.bstly.we.model.UserData;
import de.bstly.we.model.UserStatus;
import de.bstly.we.repository.UserRepository;
/**
* @author _bastler@bstly.de
*
*/
@Component
public class UserDataManager implements SmartInitializingSingleton {
@Autowired
private ApplicationContext context;
public static final String SYSTEM_PROPERTY_USERDATA_DAYS = "userdata.days";
public static final long SYSTEM_PROPERTY_USERDATA_DAYS_DEFAULT = 30;
private Logger logger = LoggerFactory.getLogger(UserDataManager.class);
@Autowired
private UserRepository userRepository;
@Autowired
private PermissionManager permissionManager;
@Autowired
private SystemPropertyManager systemPropertyManager;
@Value("${we.bstly.userdata.purge:false}")
private boolean purge;
/**
* UserData Provider
*/
private List<UserDataProvider> providers;
private Gson gson = new Gson();
/*
* @see org.springframework.beans.factory.SmartInitializingSingleton#
* afterSingletonsInstantiated()
*/
@Override
public void afterSingletonsInstantiated() {
providers = Lists.newArrayList();
for (UserDataProvider provider : context.getBeansOfType(UserDataProvider.class).values()) {
providers.add(provider);
}
}
/**
*
*/
@Scheduled(cron = "${we.bstly.userdata.cron:0 0 0 * * * }")
public void purge() {
long days = systemPropertyManager.getLong(SYSTEM_PROPERTY_USERDATA_DAYS,
SYSTEM_PROPERTY_USERDATA_DAYS_DEFAULT);
Pageable pageable = PageRequest.of(0, 100, Sort.by("id"));
Page<User> page;
do {
page = userRepository.findAll(pageable);
for (User user : page.getContent()) {
if (!UserStatus.SLEEP.equals(user.getStatus())) {
if (permissionManager.getNotExpiresByTargetIgnoreStart(user.getId())
.isEmpty()) {
if (UserStatus.PURGE.equals(user.getStatus())) {
purge(user, !purge);
} else if (UserStatus.NORMAL.equals(user.getStatus())) {
Instant last = Instant.MIN;
for (Permission permission : permissionManager
.getAllByTarget(user.getId())) {
if (permission.getExpires().isAfter(last)) {
last = permission.getExpires();
}
}
if (Instant.now().minus(days, ChronoUnit.DAYS).isAfter(last)) {
purge(user, !purge);
}
}
}
}
}
pageable = page.nextPageable();
} while (page.hasNext());
}
/**
*
* @param username
*/
public void purge(User user, boolean dry) {
Long userId = user.getId();
if (dry) {
logger.debug("Would purge all data of user '" + user.getUsername() + "' [id="
+ user.getId() + "]!");
} else {
logger.warn("Purge all data of user '" + user.getUsername() + "' [id=" + user.getId()
+ "]!");
}
for (UserDataProvider provider : providers) {
if (dry) {
List<UserData> result = provider.getUserData(userId);
if (!result.isEmpty()) {
logger.debug("\tWould have purged '" + provider.getId() + "' data of user '"
+ user.getUsername() + "' [id=" + user.getId() + "]!");
if (logger.isTraceEnabled()) {
for (UserData userData : result) {
logger.trace("\t\t" + gson.toJson(userData));
}
}
}
} else {
List<UserData> result = provider.getUserData(userId);
if (!result.isEmpty()) {
logger.warn("\tPurge '" + provider.getId() + "' data of user '"
+ user.getUsername() + "' [id=" + user.getId() + "]!");
if (logger.isTraceEnabled()) {
for (UserData userData : result) {
logger.trace("\t\t" + gson.toJson(userData));
}
}
provider.purgeUserData(userId);
}
}
}
if (!dry) {
logger.warn("Purged all data of user '" + user.getUsername() + "' [id=" + user.getId()
+ "]!");
}
}
/**
*
* @param userId
* @return
*/
public Map<String, List<UserData>> get(Long userId) {
Map<String, List<UserData>> userData = Maps.newHashMap();
for (UserDataProvider provider : providers) {
List<UserData> result = provider.getUserData(userId);
if (!result.isEmpty()) {
userData.put(provider.getId(), result);
}
}
return userData;
}
}

View File

@ -0,0 +1,36 @@
/**
*
*/
package de.bstly.we.businesslogic;
import java.util.List;
import de.bstly.we.model.UserData;
/**
* @author _bastler@bstly.de
*
*/
public interface UserDataProvider {
/**
*
* @return
*/
String getId();
/**
*
* @param userId
* @return
*/
List<UserData> getUserData(Long userId);
/**
*
* @param userId
* @return
*/
void purgeUserData(Long userId);
}

View File

@ -0,0 +1,202 @@
/**
*
*/
package de.bstly.we.businesslogic;
import java.util.Hashtable;
import java.util.List;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.InitialDirContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import com.google.common.collect.Lists;
import com.querydsl.core.BooleanBuilder;
import de.bstly.we.model.QUserDomain;
import de.bstly.we.model.UserData;
import de.bstly.we.model.UserDomain;
import de.bstly.we.repository.UserDomainRepository;
/**
* @author _bastler@bstly.de
*
*/
@Component
public class UserDomainManager implements UserDataProvider {
public static final int DEFAULT_SECRET_LENGTH = 64;
@Autowired
private UserManager userManager;
@Autowired
private UserDomainRepository userDomainRepository;
private QUserDomain qUserDomain = QUserDomain.userDomain;
private InitialDirContext dirContext;
/**
*
*/
public UserDomainManager() {
Hashtable<String, String> env = new Hashtable<String, String>();
env.put("java.naming.factory.initial", "com.sun.jndi.dns.DnsContextFactory");
env.put("java.naming.provider.url", "dns:");
try {
dirContext = new InitialDirContext(env);
} catch (NamingException e) {
e.printStackTrace();
throw new RuntimeException("Could not crate InitialDirContext");
}
}
/**
*
* @param id
* @return
*/
public UserDomain get(Long id) {
return userDomainRepository.findById(id).orElse(null);
}
/**
*
* @param userDomain
* @return
*/
public UserDomain save(UserDomain userDomain) {
Assert.notNull(userDomain.getDomain(), "No domain defined!");
Assert.notNull(userDomain.getTarget(), "No target defined!");
Assert.notNull(userManager.get(userDomain.getTarget()), "Invalid target defined!");
return userDomainRepository.save(userDomain);
}
/**
*
* @param domain
* @return
*/
public UserDomain getByDomain(String domain) {
return userDomainRepository.findOne(qUserDomain.domain.eq(domain)).orElse(null);
}
/**
*
* @param userId
* @return
*/
public List<UserDomain> getAllByTarget(Long userId) {
return Lists.newArrayList(userDomainRepository.findAll(qUserDomain.target.eq(userId)));
}
/**
*
* @param id
*/
public void delete(Long id) {
UserDomain userDomain = get(id);
if (userDomain != null) {
userDomainRepository.delete(userDomain);
}
}
/**
*
* @param page
* @param size
* @param sortBy
* @param descending
* @return
*/
public Page<UserDomain> get(int page, int size, String sortBy, boolean descending) {
Sort sort = descending ? Sort.by(sortBy).descending() : Sort.by(sortBy).ascending();
return userDomainRepository.findAll(PageRequest.of(page, size, sort));
}
/**
*
*/
@Scheduled(cron = "0 */15 * * * *")
public void validate() {
Pageable pageable = PageRequest.of(0, 100, Sort.by("id"));
BooleanBuilder filter = new BooleanBuilder();
filter.and(qUserDomain.validated.isFalse()
.and(qUserDomain.secret.isNotNull().and(qUserDomain.secret.isNotEmpty())));
Page<UserDomain> page;
do {
page = userDomainRepository.findAll(filter.getValue(), pageable);
for (UserDomain userDomain : page.getContent()) {
try {
validate(userDomain);
} catch (NamingException e) {
e.printStackTrace();
}
}
pageable = page.nextPageable();
} while (page.hasNext());
}
/**
*
* @param userDomain
* @throws NamingException
*/
public boolean validate(UserDomain userDomain) throws NamingException {
Attributes attributes = dirContext.getAttributes("_bstly." + userDomain.getDomain(),
new String[] { "TXT" });
NamingEnumeration<? extends Attribute> attributeEnumeration = attributes.getAll();
while (attributeEnumeration.hasMore()) {
if (attributeEnumeration.next().toString().endsWith(userDomain.getSecret())) {
userDomain.setValidated(true);
save(userDomain);
return true;
}
}
return false;
}
/*
* @see de.bstly.we.businesslogic.UserDataProvider#getId()
*/
@Override
public String getId() {
return "domains";
}
/*
* @see de.bstly.we.businesslogic.UserDataProvider#getUserData(java.lang.Long)
*/
@Override
public List<UserData> getUserData(Long userId) {
List<UserData> result = Lists.newArrayList();
for (UserDomain userDomain : getAllByTarget(userId)) {
result.add(userDomain);
}
return result;
}
/*
* @see de.bstly.we.businesslogic.UserDataProvider#purgeUserData(java.lang.Long)
*/
@Override
public void purgeUserData(Long userId) {
for (UserDomain userDomain : getAllByTarget(userId)) {
userDomainRepository.delete(userDomain);
}
}
}

View File

@ -0,0 +1,318 @@
/**
*
*/
package de.bstly.we.businesslogic;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletOutputStream;
import org.apache.commons.lang3.RandomStringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.session.FindByIndexNameSessionRepository;
import org.springframework.session.Session;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import com.beust.jcommander.internal.Lists;
import de.bstly.we.model.QUser;
import de.bstly.we.model.User;
import de.bstly.we.model.UserData;
import de.bstly.we.model.UserStatus;
import de.bstly.we.repository.UserRepository;
/**
*
* @author _bastler@bstly.de
*
*/
@Component
public class UserManager implements UserDataProvider {
private Logger logger = LoggerFactory.getLogger(UserManager.class);
@Autowired
private UserRepository userRepository;
@Autowired
private PasswordEncoder passwordEncoder;
@Autowired
private UserDataManager userDataManager;
@Autowired
private FindByIndexNameSessionRepository<? extends Session> sessionRepository;
private QUser qUser = QUser.user;
@Value("${we.bstly.userdata.directory}")
private String userDataDirectory;
@Value("${we.bstly.email.domain:we.bstly.de}")
private String userEmailDomain;
/**
* @param id
* @return
*/
public User get(Long id) {
return userRepository.findById(id).orElse(null);
}
/**
*
* @param username
* @return
*/
public User getByUsername(String username) {
return userRepository.findOne(qUser.username.equalsIgnoreCase(username)).orElse(null);
}
/**
*
* @param resetToken
* @return
*/
public User getByResetToken(String resetToken) {
return userRepository.findOne(qUser.resetToken.eq(resetToken)).orElse(null);
}
/**
* @param id
* @return
*/
public String getPasswordHash(Long id) {
Assert.isTrue(userRepository.existsById(id), "User with id '" + id + "' not exists!");
return userRepository.findById(id).get().getPasswordHash();
}
/**
*
* @param id
* @param passwordHash
*/
public User setPassword(Long id, String password) {
Assert.isTrue(userRepository.existsById(id), "User with id '" + id + "' not exists!");
User user = userRepository.findById(id).get();
user.setPasswordHash(passwordEncoder.encode(password));
return userRepository.save(user);
}
/**
*
* @param username
* @param email
* @param password
* @param publicKey
* @return
*/
public User create(String username, String password, UserStatus status) {
Assert.isTrue(!userRepository.exists(qUser.username.equalsIgnoreCase(username)),
"Username '" + username + "' already exists!");
User user = new User();
user.setUsername(username);
if (StringUtils.hasText(password)) {
user.setPasswordHash(passwordEncoder.encode(password));
}
user.setDisabled(false);
user.setLocked(false);
user.setStatus(status);
user = userRepository.save(user);
return user;
}
/**
*
* @param page
* @param size
* @param sortBy
* @param descending
* @return
*/
public Page<User> get(int page, int size, String sortBy, boolean descending) {
Sort sort = descending ? Sort.by(sortBy).descending() : Sort.by(sortBy).ascending();
return userRepository.findAll(PageRequest.of(page, size, sort));
}
/**
* @param user
* @return
*/
public User update(User user) {
Assert.isTrue(userRepository.existsById(user.getId()),
"User with id '" + user.getId() + "' not exists!");
User merge = get(user.getId());
merge.setUsername(user.getUsername());
merge.setStatus(user.getStatus());
merge.setDisabled(user.isDisabled());
merge.setLocked(user.isLocked());
if (merge.isDisabled() || merge.isLocked()) {
deleteSessionsForUser(merge);
}
return userRepository.save(merge);
}
/**
*
* @param user
*/
public void delete(User user) {
Assert.isTrue(userRepository.existsById(user.getId()),
"User with id '" + user.getId() + "' not exists!");
File publicKey = new File(getPublicKeyPath(user.getUsername()));
if (publicKey.exists()) {
publicKey.delete();
}
deleteSessionsForUser(user);
userDataManager.purge(user, false);
}
/**
*
* @param username
* @return
*/
public String getBstlyEmail(String username) {
return username + "@" + userEmailDomain;
}
/**
*
* @param username
* @param publicKey
*/
public void writePublicKey(String username, String publicKey) {
if (StringUtils.hasText(publicKey)) {
if (!userDataDirectory.endsWith(File.separator)) {
userDataDirectory += File.separator;
}
File userDir = new File(userDataDirectory + username);
if (!userDir.exists()) {
userDir.mkdirs();
}
try {
String publicKeyPath = getPublicKeyPath(username);
FileWriter myWriter = new FileWriter(publicKeyPath);
myWriter.write(publicKey);
myWriter.close();
String command = "gpg --import " + publicKeyPath;
Runtime.getRuntime().exec(command);
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
*
* @param username
* @return
*/
public String getPublicKeyPath(String username) {
return userDataDirectory + username + File.separator + "public.key";
}
/**
* @param user
* @param outputStream
*/
public void passwordReset(User user, ServletOutputStream outputStream) {
String resetToken = RandomStringUtils.random(64, true, true);
String command = "echo \"" + resetToken + "\" | gpg -ear "
+ getBstlyEmail(user.getUsername()) + " --always-trust";
user.setResetToken(resetToken);
try {
ProcessBuilder b = new ProcessBuilder("/bin/bash", "-c", command);
Process process = b.start();
BufferedReader reader = new BufferedReader(
new InputStreamReader(process.getInputStream()));
BufferedReader errorReader = new BufferedReader(
new InputStreamReader(process.getErrorStream()));
int c;
while ((c = reader.read()) != -1) {
outputStream.write(c);
}
String error = "";
String line;
while ((line = errorReader.readLine()) != null) {
error += line;
}
if (StringUtils.hasText(error)) {
logger.warn(error);
}
reader.close();
errorReader.close();
} catch (IOException e) {
return;
}
update(user);
}
/**
*
* @param user
*/
protected void deleteSessionsForUser(User user) {
Map<String, ? extends Session> usersSessions = sessionRepository
.findByPrincipalName(user.getUsername());
for (Session session : usersSessions.values()) {
sessionRepository.deleteById(session.getId());
}
}
/*
* @see de.bstly.we.businesslogic.UserDataProvider#getId()
*/
@Override
public String getId() {
return "user";
}
/*
* @see de.bstly.we.businesslogic.UserDataProvider#getUserData(java.lang.Long)
*/
@Override
public List<UserData> getUserData(Long userId) {
List<UserData> result = Lists.newArrayList();
result.add(get(userId));
return result;
}
/*
* @see de.bstly.we.businesslogic.UserDataProvider#purgeUserData(java.lang.Long)
*/
@Override
public void purgeUserData(Long userId) {
userRepository.deleteById(userId);
}
}

View File

@ -0,0 +1,143 @@
/**
*
*/
package de.bstly.we.businesslogic;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import com.google.common.collect.Lists;
import de.bstly.we.model.QUserProfileField;
import de.bstly.we.model.UserData;
import de.bstly.we.model.UserProfileField;
import de.bstly.we.model.Visibility;
import de.bstly.we.repository.UserProfileFieldRepository;
/**
* @author _bastler@bstly.de
*
*/
@Component
public class UserProfileFieldManager implements UserDataProvider {
@Autowired
private UserProfileFieldRepository userProfileFieldRepository;
private QUserProfileField qUserProfileField = QUserProfileField.userProfileField;
/**
*
* @param target
* @param name
* @return
*/
public UserProfileField get(Long target, String name) {
return userProfileFieldRepository
.findOne(qUserProfileField.name.eq(name).and(qUserProfileField.target.eq(target)))
.orElse(null);
}
/**
*
* @param target
* @return
*/
public List<UserProfileField> getAllByTarget(Long target) {
return Lists.newArrayList(userProfileFieldRepository.findAll(
qUserProfileField.target.eq(target), Sort.by("index", "name").ascending()));
}
/**
*
* @param target
* @return
*/
public List<UserProfileField> getByTargetFiltered(Long target, List<String> names) {
return Lists.newArrayList(userProfileFieldRepository.findAll(
qUserProfileField.target.eq(target).and(qUserProfileField.name.in(names)),
Sort.by("index", "name").ascending()));
}
/**
*
* @param target
* @param visibilities
* @return
*/
public List<UserProfileField> getAllByTargetAndVisibilities(Long target,
List<Visibility> visibilities) {
return Lists.newArrayList(userProfileFieldRepository.findAll(
qUserProfileField.target.eq(target)
.and(qUserProfileField.visibility.in(visibilities)),
Sort.by("index", "name").ascending()));
}
/**
*
* @param userProfileField
* @return
*/
public UserProfileField save(UserProfileField userProfileField) {
return userProfileFieldRepository.save(userProfileField);
}
/**
*
* @param target
* @param name
*/
public void delete(Long target, String name) {
Assert.isTrue(
userProfileFieldRepository.exists(
qUserProfileField.target.eq(target).and(qUserProfileField.name.eq(name))),
"ProfileField '" + name + "' for target + '" + target + "' not exists!");
UserProfileField delete = userProfileFieldRepository
.findOne(qUserProfileField.target.eq(target).and(qUserProfileField.name.eq(name)))
.get();
userProfileFieldRepository.delete(delete);
}
/**
*
* @param target
*/
public void deleteAll(Long target) {
userProfileFieldRepository
.deleteAll(userProfileFieldRepository.findAll(qUserProfileField.target.eq(target)));
}
/*
* @see de.bstly.we.businesslogic.UserDataProvider#getId()
*/
@Override
public String getId() {
return "profilefields";
}
/*
* @see de.bstly.we.businesslogic.UserDataProvider#getUserData(java.lang.Long)
*/
@Override
public List<UserData> getUserData(Long userId) {
List<UserData> result = Lists.newArrayList();
for (UserProfileField userProfileField : getAllByTarget(userId)) {
result.add(userProfileField);
}
return result;
}
/*
* @see de.bstly.we.businesslogic.UserDataProvider#purgeUserData(java.lang.Long)
*/
@Override
public void purgeUserData(Long userId) {
for (UserProfileField userProfileField : getAllByTarget(userId)) {
userProfileFieldRepository.delete(userProfileField);
}
}
}

View File

@ -0,0 +1,15 @@
/**
*
*/
package de.bstly.we.businesslogic;
/**
* @author _bastler@bstly.de
*
*/
public interface UserProfileFields {
public static final String PROFILE_FIELD_EMAIL = "email";
public static final String PROFILE_FIELD_EMAIL_PRIMARY = "primaryEmail";
public static final String PROFILE_FIELD_LOCALE = "locale";
}

View File

@ -0,0 +1,178 @@
/**
*
*/
package de.bstly.we.businesslogic;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.beust.jcommander.internal.Lists;
import de.bstly.we.model.QUserTotp;
import de.bstly.we.model.User;
import de.bstly.we.model.UserData;
import de.bstly.we.model.UserTotp;
import de.bstly.we.repository.UserTotpRepository;
import de.bstly.we.security.businesslogic.SecondFactorProvider;
import dev.samstevens.totp.code.CodeVerifier;
import dev.samstevens.totp.qr.QrData;
import dev.samstevens.totp.qr.QrDataFactory;
import dev.samstevens.totp.recovery.RecoveryCodeGenerator;
import dev.samstevens.totp.secret.SecretGenerator;
/**
* @author _bastler@bstly.de
*
*/
@Component
public class UserTotpManager implements SecondFactorProvider<UserTotp> {
@Autowired
private UserTotpRepository userTotpRepository;
@Autowired
private UserManager userManager;
@Autowired
private SecretGenerator secretGenerator;
@Autowired
private CodeVerifier verifier;
@Autowired
private QrDataFactory qrDataFactory;
@Autowired
private RecoveryCodeGenerator recoveryCodeGenerator;
private QUserTotp qUserTotp = QUserTotp.userTotp;
/*
* @see de.bstly.we.security.businesslogic.SecondFactorProvider#getId()
*/
@Override
public String getId() {
return "totp";
}
/*
* @see
* de.bstly.we.security.businesslogic.SecondFactorProvider#supports(java.lang.
* String)
*/
@Override
public boolean supports(String provider) {
return getId().equals(provider);
}
/*
*
* @see
* de.bstly.we.security.businesslogic.SecondFactorProvider#isEnabled(java.lang.
* Long)
*/
@Override
public boolean isEnabled(Long userId) {
return userTotpRepository
.exists(qUserTotp.target.eq(userId).and(qUserTotp.enabled.isTrue()));
}
/*
*
* @see
* de.bstly.we.security.businesslogic.SecondFactorProvider#validate(java.lang.
* Long, java.lang.String)
*/
@Override
public boolean validate(Long userId, String code) {
UserTotp userTotp = userTotpRepository.findOne(qUserTotp.target.eq(userId)).orElse(null);
if (userTotp != null) {
return verifier.isValidCode(userTotp.getSecret(), code);
}
return false;
}
/*
* @see
* de.bstly.we.security.businesslogic.SecondFactorProvider#getForUser(java.lang.
* Long)
*/
@Override
public UserTotp get(Long userId) {
return userTotpRepository.findOne(qUserTotp.target.eq(userId)).orElse(null);
}
/*
* @see
* de.bstly.we.security.businesslogic.SecondFactorProvider#createByUser(java.
* lang.Long)
*/
@Override
public UserTotp create(Long userId) {
if (!isEnabled(userId)) {
delete(userId);
UserTotp userTotp = new UserTotp();
userTotp.setTarget(userId);
userTotp.setSecret(secretGenerator.generate());
User user = userManager.get(userId);
QrData data = qrDataFactory.newBuilder().label(user.getUsername())
.secret(userTotp.getSecret()).issuer("we.bstly").build();
userTotp.setQrData(data.getUri());
userTotp.setRecoveryCodes(Lists.newArrayList(recoveryCodeGenerator.generateCodes(16)));
return userTotpRepository.save(userTotp);
}
return userTotpRepository.findOne(qUserTotp.target.eq(userId)).orElse(null);
}
/*
* @see
* de.bstly.we.security.businesslogic.SecondFactorProvider#enableByUser(java.
* lang.Long, java.lang.String)
*/
@Override
public boolean enable(Long userId, String code) {
if (validate(userId, code)) {
UserTotp userTotp = userTotpRepository.findOne(qUserTotp.target.eq(userId))
.orElse(null);
userTotp.setEnabled(true);
userTotpRepository.save(userTotp);
return true;
}
return false;
}
/*
* @see
* de.bstly.we.security.businesslogic.SecondFactorProvider#deleteByUser(java.
* lang.Long)
*/
@Override
public void delete(Long userId) {
UserTotp userTotp = get(userId);
if (userTotp != null) {
userTotpRepository.delete(userTotp);
}
}
/*
* @see de.bstly.we.businesslogic.UserDataProvider#getUserData(java.lang.Long)
*/
@Override
public List<UserData> getUserData(Long userId) {
List<UserData> result = Lists.newArrayList();
UserTotp userTotp = get(userId);
if (userTotp != null) {
result.add(userTotp);
}
return result;
}
/*
* @see de.bstly.we.businesslogic.UserDataProvider#purgeUserData(java.lang.Long)
*/
@Override
public void purgeUserData(Long userId) {
delete(userId);
}
}

View File

@ -0,0 +1,67 @@
/**
*
*/
package de.bstly.we.businesslogic.support;
import javax.persistence.PostLoad;
import javax.persistence.PostPersist;
import javax.persistence.PostRemove;
import javax.persistence.PostUpdate;
import javax.persistence.PrePersist;
import javax.persistence.PreRemove;
import javax.persistence.PreUpdate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;
import de.bstly.we.event.AbstractModelEvent;
import de.bstly.we.event.AbstractModelEventType;
import de.bstly.we.model.AbstractModel;
/**
* @author Lurkars
*
*/
@Component
public class AbstractModelEventListener {
@Autowired
private ApplicationEventPublisher applicationEventPublisher;
@PrePersist
private void prePersist(AbstractModel model) {
applicationEventPublisher.publishEvent(new AbstractModelEvent(AbstractModelEventType.PRE_PERSIST, model));
}
@PreUpdate
private void preUpdate(AbstractModel model) {
applicationEventPublisher.publishEvent(new AbstractModelEvent(AbstractModelEventType.PRE_UPDATE, model));
}
@PreRemove
private void preRemove(AbstractModel model) {
applicationEventPublisher.publishEvent(new AbstractModelEvent(AbstractModelEventType.PRE_REMOVE, model));
}
@PostPersist
private void postPersist(AbstractModel model) {
applicationEventPublisher.publishEvent(new AbstractModelEvent(AbstractModelEventType.POST_PERSIST, model));
}
@PostUpdate
private void postUpdate(AbstractModel model) {
applicationEventPublisher.publishEvent(new AbstractModelEvent(AbstractModelEventType.POST_UPDATE, model));
}
@PostRemove
private void postRemove(AbstractModel model) {
applicationEventPublisher.publishEvent(new AbstractModelEvent(AbstractModelEventType.POST_REMOVE, model));
}
@PostLoad
private void postLoad(AbstractModel model) {
applicationEventPublisher.publishEvent(new AbstractModelEvent(AbstractModelEventType.POST_LOAD, model));
}
}

View File

@ -0,0 +1,83 @@
/**
*
*/
package de.bstly.we.businesslogic.support;
import java.time.Instant;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoField;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAmount;
import java.time.temporal.TemporalUnit;
/**
* @author _bastler@bstly.de
*
*/
public class InstantHelper {
/**
*
* @param instant
* @param amount
* @return
*/
public static Instant plus(Instant instant, TemporalAmount amount) {
return ZonedDateTime.ofInstant(instant, ZoneOffset.UTC).plus(amount).toInstant();
}
/**
*
* @param instant
* @param amountToAdd
* @param unit
* @return
*/
public static Instant plus(Instant instant, long amountToAdd, TemporalUnit unit) {
return ZonedDateTime.ofInstant(instant, ZoneOffset.UTC).plus(amountToAdd, unit).toInstant();
}
/**
*
* @param instant
* @param amount
* @return
*/
public static Instant minus(Instant instant, TemporalAmount amount) {
return ZonedDateTime.ofInstant(instant, ZoneOffset.UTC).minus(amount).toInstant();
}
/**
*
* @param instant
* @param amountToAdd
* @param unit
* @return
*/
public static Instant minus(Instant instant, long amountToAdd, TemporalUnit unit) {
return ZonedDateTime.ofInstant(instant, ZoneOffset.UTC).minus(amountToAdd, unit)
.toInstant();
}
/**
*
* @param instant
* @param unit
* @return
*/
public static Instant truncate(Instant instant, TemporalUnit unit) {
if (ChronoUnit.YEARS.equals(unit)) {
instant = instant.truncatedTo(ChronoUnit.DAYS);
return ZonedDateTime.ofInstant(instant, ZoneOffset.UTC)
.with(ChronoField.DAY_OF_YEAR, 1L).toInstant();
} else if (ChronoUnit.MONTHS.equals(unit)) {
instant = instant.truncatedTo(ChronoUnit.DAYS);
return ZonedDateTime.ofInstant(instant, ZoneOffset.UTC)
.with(ChronoField.DAY_OF_MONTH, 1L).toInstant();
}
return ZonedDateTime.ofInstant(instant, ZoneOffset.UTC).truncatedTo(unit).toInstant();
}
}

View File

@ -0,0 +1,202 @@
/**
*
*/
package de.bstly.we.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.beust.jcommander.internal.Lists;
import de.bstly.we.controller.model.SecondFactorProviderModel;
import de.bstly.we.controller.support.EntityResponseStatusException;
import de.bstly.we.model.SecondFactor;
import de.bstly.we.security.businesslogic.SecondFactorProvider;
import de.bstly.we.security.businesslogic.SecondFactorProviderManager;
import de.bstly.we.security.businesslogic.SecondFactorRequestProvider;
import de.bstly.we.security.model.LocalUserDetails;
/**
*
* @author _bastler@bstly.de
*
*/
@RestController
@RequestMapping("/auth/2fa")
public class Authentication2FAController extends BaseController {
@Autowired
private SecondFactorProviderManager secondFactorProviderManager;
/**
*
* @return
*/
protected Long getPreAuthenticationId() {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth != null && auth.getPrincipal() instanceof LocalUserDetails) {
return ((LocalUserDetails) auth.getPrincipal()).getUserId();
}
return null;
}
/**
*
* @return
*/
@GetMapping
public List<SecondFactorProviderModel> getEnabled() {
Long userId = getPreAuthenticationId();
if (userId == null) {
throw new EntityResponseStatusException(HttpStatus.UNAUTHORIZED);
}
List<SecondFactorProviderModel> result = Lists.newArrayList();
for (SecondFactorProvider<?> provider : secondFactorProviderManager.getEnabled(userId)) {
result.add(new SecondFactorProviderModel(provider.getId(),
provider instanceof SecondFactorRequestProvider<?>));
}
return result;
}
/**
*
* @return
*/
@GetMapping("/available")
public List<SecondFactorProviderModel> getAvailable() {
Long userId = getPreAuthenticationId();
if (userId == null) {
throw new EntityResponseStatusException(HttpStatus.UNAUTHORIZED);
}
List<SecondFactorProviderModel> result = Lists.newArrayList();
for (SecondFactorProvider<?> provider : secondFactorProviderManager.getAll()) {
result.add(new SecondFactorProviderModel(provider.getId(),
provider instanceof SecondFactorRequestProvider<?>));
}
for (SecondFactorProvider<?> provider : secondFactorProviderManager.getEnabled(userId)) {
SecondFactorProviderModel enabledProvider = new SecondFactorProviderModel(
provider.getId(), provider instanceof SecondFactorRequestProvider<?>);
result.remove(enabledProvider);
}
return result;
}
/**
*
* @return
*/
@PreAuthorize("authentication.authenticated")
@GetMapping("/{id}")
public void isSecondFactorEnabled(@PathVariable("id") String providerId) {
SecondFactorProvider<?> provider = secondFactorProviderManager.getProvider(providerId);
if (provider == null) {
throw new EntityResponseStatusException(HttpStatus.UNAUTHORIZED);
}
if (!provider.isEnabled(getCurrentUserId())) {
throw new EntityResponseStatusException(HttpStatus.NOT_MODIFIED);
}
}
/**
*
*/
@PreAuthorize("hasRole('ROLE_PRE_AUTH_USER')")
@PostMapping("/{id}")
public void requestSecondFactorMail(@PathVariable("id") String providerId) {
Long userId = getPreAuthenticationId();
if (userId == null) {
throw new EntityResponseStatusException(HttpStatus.UNAUTHORIZED);
}
SecondFactorProvider<?> provider = secondFactorProviderManager.getProvider(providerId);
if (provider == null) {
throw new EntityResponseStatusException(HttpStatus.UNAUTHORIZED);
}
if (!(provider instanceof SecondFactorRequestProvider<?>)) {
throw new EntityResponseStatusException(HttpStatus.UNAUTHORIZED);
}
SecondFactorRequestProvider<?> requestProvider = (SecondFactorRequestProvider<?>) provider;
requestProvider.request(userId);
}
/**
*
* @return
*/
@PreAuthorize("authentication.authenticated")
@PutMapping("/{id}")
public SecondFactor createSecondFactor(@PathVariable("id") String providerId) {
SecondFactorProvider<?> provider = secondFactorProviderManager.getProvider(providerId);
if (provider == null) {
throw new EntityResponseStatusException(HttpStatus.UNAUTHORIZED);
}
if (provider.isEnabled(getCurrentUserId())) {
throw new EntityResponseStatusException(HttpStatus.CONFLICT);
}
return provider.create(getCurrentUserId());
}
/**
*
* @return
*/
@PreAuthorize("authentication.authenticated")
@PatchMapping("/{id}")
public void enableSecondFactor(@PathVariable("id") String providerId,
@RequestBody String token) {
SecondFactorProvider<?> provider = secondFactorProviderManager.getProvider(providerId);
if (provider == null) {
throw new EntityResponseStatusException(HttpStatus.UNAUTHORIZED);
}
if (!provider.enable(getCurrentUserId(), token)) {
throw new EntityResponseStatusException(HttpStatus.UNAUTHORIZED);
}
}
/**
*
*/
@PreAuthorize("authentication.authenticated")
@DeleteMapping("/{id}")
public void removeSecondFactorMail(@PathVariable("id") String providerId) {
SecondFactorProvider<?> provider = secondFactorProviderManager.getProvider(providerId);
if (provider == null) {
throw new EntityResponseStatusException(HttpStatus.UNAUTHORIZED);
}
provider.delete(getCurrentUserId());
}
}

View File

@ -0,0 +1,107 @@
/**
*
*/
package de.bstly.we.controller;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.validation.Errors;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import de.bstly.we.businesslogic.UserManager;
import de.bstly.we.controller.model.PasswordResetModel;
import de.bstly.we.controller.support.EntityResponseStatusException;
import de.bstly.we.controller.support.RequestBodyErrors;
import de.bstly.we.controller.validation.PasswordModelValidator;
import de.bstly.we.model.User;
/**
*
* @author _bastler@bstly.de
*
*/
@RestController
@RequestMapping("/auth")
public class AuthenticationController extends BaseController {
@Autowired
private UserManager userManager;
@Autowired
private PasswordModelValidator passwordModelValidator;
/**
*
* @return
*/
@GetMapping("/me")
public Authentication me() {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
return auth;
}
/**
*
* @param username
* @param req
* @param resp
* @throws IOException
*/
@PreAuthorize("isAnonymous()")
@PostMapping("/password/request")
public void passwordRequest(@RequestBody String username, HttpServletRequest req,
HttpServletResponse resp) throws IOException {
User user = userManager.getByUsername(username);
if (user != null) {
resp.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN_VALUE);
userManager.passwordReset(user, resp.getOutputStream());
resp.getOutputStream().flush();
resp.getOutputStream().close();
}
}
/**
*
* @param passwordResetModel
* @param req
* @param resp
*/
@PreAuthorize("isAnonymous()")
@PostMapping("/password/reset")
public void passwordReset(@RequestBody PasswordResetModel passwordResetModel,
HttpServletRequest req, HttpServletResponse resp) {
User user = userManager.getByResetToken(passwordResetModel.getToken().trim());
if (user == null) {
throw new EntityResponseStatusException(HttpStatus.UNAUTHORIZED);
}
Errors errors = new RequestBodyErrors(passwordResetModel);
passwordModelValidator.validate(passwordResetModel, errors);
if (errors.hasErrors()) {
throw new EntityResponseStatusException(errors.getAllErrors(), HttpStatus.CONFLICT);
}
user = userManager.setPassword(user.getId(), passwordResetModel.getPassword());
user.setResetToken(null);
userManager.update(user);
}
}

View File

@ -0,0 +1,32 @@
/**
*
*/
package de.bstly.we.controller;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import de.bstly.we.security.model.LocalUserDetails;
/**
*
* @author _bastler@bstly.de
*
*/
public class BaseController {
/**
*
* @return
*/
public Long getCurrentUserId() {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth != null && auth.isAuthenticated() && auth.getPrincipal() instanceof LocalUserDetails) {
LocalUserDetails details = (LocalUserDetails) auth.getPrincipal();
return details.getUserId();
}
return null;
}
}

View File

@ -0,0 +1,147 @@
/**
*
*/
package de.bstly.we.controller;
import java.util.Map;
import java.util.Set;
import javax.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.gson.JsonObject;
import de.bstly.we.businesslogic.PretixManager;
import de.bstly.we.businesslogic.PretixManager.ITEM_STATUS;
import de.bstly.we.businesslogic.UserManager;
import de.bstly.we.controller.model.ItemModel;
import de.bstly.we.controller.model.ItemResultModel;
import de.bstly.we.controller.support.EntityResponseStatusException;
import de.bstly.we.controller.support.TokenSessionManager;
import de.bstly.we.model.User;
/**
*
* @author _bastler@bstly.de
*
*/
@RestController
@RequestMapping("/items")
public class ItemController extends BaseController {
@Autowired
private TokenSessionManager tokenSessionManager;
@Autowired
private PretixManager pretixManager;
@Autowired
private UserManager userManager;
/**
*
*/
@GetMapping
public Set<ItemModel> getItems(HttpSession session) {
Set<ItemModel> result = Sets.newHashSet();
if (tokenSessionManager.getTokenFromSession(session).isEmpty()) {
return result;
}
for (String token : tokenSessionManager.getTokenFromSession(session)) {
JsonObject checkInItem = pretixManager.getCheckInItemBySecret(token);
JsonObject item = pretixManager.getItem(checkInItem.get("item").getAsInt());
ItemModel itemModel = new ItemModel();
itemModel.setSecret(token);
Map<String, String> name = Maps.newHashMap();
for (String lang : item.getAsJsonObject("name").keySet()) {
name.put(lang, item.getAsJsonObject("name").get(lang).getAsString());
}
itemModel.setName(name);
result.add(itemModel);
}
return result;
}
/**
*
* @param secret
*/
@PutMapping("")
public void addItem(@RequestBody String secret, HttpSession session) {
ITEM_STATUS status = pretixManager.getItemStatus(secret);
if (status == ITEM_STATUS.PAID) {
tokenSessionManager.addTokenToSession(secret, session);
throw new EntityResponseStatusException(HttpStatus.ACCEPTED);
} else if (pretixManager.getItemStatus(secret) == ITEM_STATUS.REDEEMED) {
throw new EntityResponseStatusException(HttpStatus.GONE);
}
throw new EntityResponseStatusException(HttpStatus.NOT_ACCEPTABLE);
}
/**
*
* @param secret
*/
@DeleteMapping
public void removeItem(@RequestBody String secret, HttpSession session) {
tokenSessionManager.removeTokenFromSession(secret, session);
}
/**
*
* @return
*/
@PreAuthorize("isAuthenticated()")
@PostMapping
public ItemResultModel redeem(HttpSession session) {
if (tokenSessionManager.getTokenFromSession(session).isEmpty()) {
throw new EntityResponseStatusException(HttpStatus.NOT_MODIFIED);
}
ItemResultModel result = tokenSessionManager.applyTokens(getCurrentUserId(),
tokenSessionManager.getTokenFromSession(session));
tokenSessionManager.removeTokensFromSession(session);
return result;
}
/**
*
* @param username
* @param session
*/
@PreAuthorize("isAuthenticated()")
@PostMapping("/{username}")
public void redeemForUser(@PathVariable("username") String username, HttpSession session) {
if (tokenSessionManager.getTokenFromSession(session).isEmpty()) {
throw new EntityResponseStatusException(HttpStatus.NOT_MODIFIED);
}
User user = userManager.getByUsername(username);
if (user == null) {
throw new EntityResponseStatusException(HttpStatus.CONFLICT);
}
tokenSessionManager.applyTokens(user.getId(),
tokenSessionManager.getTokenFromSession(session));
tokenSessionManager.removeTokensFromSession(session);
}
}

View File

@ -0,0 +1,81 @@
/**
*
*/
package de.bstly.we.controller;
import java.util.List;
import javax.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.google.common.collect.Lists;
import de.bstly.we.businesslogic.PermissionManager;
import de.bstly.we.controller.support.TokenSessionManager;
import de.bstly.we.model.Permission;
/**
*
* @author _bastler@bstly.de
*
*/
@RestController
@RequestMapping("/permissions")
public class PermissionController extends BaseController {
@Autowired
private PermissionManager permissionManager;
@Autowired
private TokenSessionManager tokenSessionManager;
/**
*
* @return
*/
@GetMapping
public List<Permission> getPermissions() {
if (getCurrentUserId() == null) {
return Lists.newArrayList();
}
return permissionManager.getNotExpiresByTargetIgnoreStart(getCurrentUserId());
}
/**
*
* @return
*/
@GetMapping("/new")
public List<Permission> getNewPermissions(HttpSession session) {
List<Permission> permissions = Lists.newArrayList();
if (tokenSessionManager.getTokenFromSession(session).isEmpty()) {
return permissions;
}
for (String token : tokenSessionManager.getTokenFromSession(session)) {
permissions
.addAll(tokenSessionManager.getPermissionsForToken(getCurrentUserId(), token));
}
return permissions;
}
/**
*
* @return
*/
@GetMapping("/all")
public List<Permission> getAllPermissions() {
if (getCurrentUserId() == null) {
return Lists.newArrayList();
}
return permissionManager.getAllByTarget(getCurrentUserId());
}
}

View File

@ -0,0 +1,153 @@
/**
*
*/
package de.bstly.we.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import de.bstly.we.businesslogic.PermissionManager;
import de.bstly.we.businesslogic.UserManager;
import de.bstly.we.controller.support.EntityResponseStatusException;
import de.bstly.we.model.Permission;
import de.bstly.we.model.User;
/**
*
* @author _bastler@bstly.de
*
*/
@RestController
@RequestMapping("/permissions/manage")
public class PermissionManagementController extends BaseController {
@Autowired
private PermissionManager permissionManager;
@Autowired
private UserManager userManager;
/**
*
* @param username
* @return
*/
@PreAuthorize("hasRole('ROLE_ADMIN')")
@GetMapping("/{username}")
public List<Permission> getPermissionsForUser(@PathVariable("username") String username) {
User user = userManager.getByUsername(username);
if (user == null) {
throw new EntityResponseStatusException(HttpStatus.NO_CONTENT);
}
return permissionManager.getNotExpiresByTargetIgnoreStart(user.getId());
}
/**
*
* @param username
* @return
*/
@PreAuthorize("hasRole('ROLE_ADMIN')")
@GetMapping("/{username}/all")
public List<Permission> getAllPermissionsForUser(@PathVariable("username") String username) {
User user = userManager.getByUsername(username);
if (user == null) {
throw new EntityResponseStatusException(HttpStatus.NO_CONTENT);
}
return permissionManager.getAllByTarget(user.getId());
}
/**
*
* @param permission
* @return
*/
@PreAuthorize("hasRole('ROLE_ADMIN')")
@PostMapping
public Permission createPermission(@RequestBody Permission permission) {
return permissionManager.create(permission.getTarget(), permission.getName(),
permission.isAddon(), permission.getStarts(), permission.getExpires());
}
/**
*
* @param permission
* @return
*/
@PreAuthorize("hasRole('ROLE_ADMIN')")
@PatchMapping
public Permission updatePermission(@RequestBody Permission permission) {
if (permission.getId() == null) {
throw new EntityResponseStatusException(HttpStatus.CONFLICT);
}
return permissionManager.update(permission);
}
/**
*
* @param name
* @param clone
* @return
*/
@PreAuthorize("hasRole('ROLE_ADMIN')")
@PostMapping("/{name}/clone/{clone}")
public List<Permission> clone(@PathVariable("name") String name,
@PathVariable("clone") String clone) {
if (name.equals(clone)) {
throw new EntityResponseStatusException(HttpStatus.CONFLICT);
}
return permissionManager.clone(name, clone);
}
/**
*
* @param permission
*/
@PreAuthorize("hasRole('ROLE_ADMIN')")
@DeleteMapping
public void deletePermission(@RequestBody Permission permission) {
if (permissionManager.get(permission.getTarget(), permission.getName()) == null) {
throw new EntityResponseStatusException(HttpStatus.NOT_MODIFIED);
}
permissionManager.delete(permission.getTarget(), permission.getName());
}
/**
*
* @param target
*/
@PreAuthorize("hasRole('ROLE_ADMIN')")
@DeleteMapping("/{target}")
public void deleteAll(@PathVariable("target") Long target) {
permissionManager.deleteAll(target);
}
/**
*
* @param name
*/
@PreAuthorize("hasRole('ROLE_ADMIN')")
@DeleteMapping("/byname/{name}")
public void deleteAllByName(@PathVariable("name") String name) {
permissionManager.deleteAll(name);
}
}

View File

@ -0,0 +1,152 @@
/**
*
*/
package de.bstly.we.controller;
import java.util.List;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.Errors;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.google.common.collect.Lists;
import de.bstly.we.businesslogic.PermissionMappingManager;
import de.bstly.we.controller.support.EntityResponseStatusException;
import de.bstly.we.controller.support.RequestBodyErrors;
import de.bstly.we.controller.validation.PermissionMappingValidator;
import de.bstly.we.model.PermissionMapping;
/**
*
* @author _bastler@bstly.de
*
*/
@RestController
@RequestMapping("/permissions/mappings")
public class PermissionMappingController extends BaseController {
@Autowired
private PermissionMappingManager permissionMappingManager;
@Autowired
private PermissionMappingValidator permissionMappingValidator;
/**
*
* @param pageParameter
* @param sizeParameter
* @return
*/
@PreAuthorize("hasRole('ROLE_ADMIN')")
@GetMapping
public Page<PermissionMapping> getPermissionMappings(
@RequestParam("page") Optional<Integer> pageParameter,
@RequestParam("size") Optional<Integer> sizeParameter) {
return permissionMappingManager.get(pageParameter.orElse(0), sizeParameter.orElse(10), "item", true);
}
/**
*
* @param permissionMapping
* @return
*/
@PreAuthorize("hasRole('ROLE_ADMIN')")
@PostMapping
public PermissionMapping create(@RequestBody PermissionMapping permissionMapping) {
Errors errors = new RequestBodyErrors(permissionMapping);
permissionMappingValidator.validate(permissionMapping, errors);
if (errors.hasErrors()) {
throw new EntityResponseStatusException(errors.getAllErrors(), HttpStatus.CONFLICT);
}
return permissionMappingManager.create(permissionMapping.getItem(),
permissionMapping.getNames(), permissionMapping.getLifetime(),
permissionMapping.getLifetimeUnit(), permissionMapping.isLifetimeRound(),
permissionMapping.isAddon(), permissionMapping.getProduct(),
permissionMapping.getStartsQuestion(), permissionMapping.getExpiresQuestion());
}
/**
*
* @param permissionMappings
* @return
*/
@PreAuthorize("hasRole('ROLE_ADMIN')")
@PostMapping("/list")
public List<PermissionMapping> createList(
@RequestBody List<PermissionMapping> permissionMappings) {
List<PermissionMapping> result = Lists.newArrayList();
for (PermissionMapping permissionMapping : permissionMappings) {
Errors errors = new RequestBodyErrors(permissionMapping);
permissionMappingValidator.validate(permissionMapping, errors);
if (errors.hasErrors()) {
throw new EntityResponseStatusException(errors.getAllErrors(), HttpStatus.CONFLICT);
}
result.add(permissionMappingManager.create(permissionMapping.getItem(),
permissionMapping.getNames(), permissionMapping.getLifetime(),
permissionMapping.getLifetimeUnit(), permissionMapping.isLifetimeRound(),
permissionMapping.isAddon(), permissionMapping.getProduct(),
permissionMapping.getStartsQuestion(), permissionMapping.getExpiresQuestion()));
}
return result;
}
/**
*
* @param permissionMapping
* @return
*/
@PreAuthorize("hasRole('ROLE_ADMIN')")
@PatchMapping
public PermissionMapping update(@RequestBody PermissionMapping permissionMapping) {
Errors errors = new RequestBodyErrors(permissionMapping);
if (errors.hasErrors()) {
throw new EntityResponseStatusException(errors.getAllErrors(), HttpStatus.CONFLICT);
}
return permissionMappingManager.update(permissionMapping);
}
/**
*
* @param permissionMappings
* @return
*/
@PreAuthorize("hasRole('ROLE_ADMIN')")
@PatchMapping("/list")
public List<PermissionMapping> updateList(
@RequestBody List<PermissionMapping> permissionMappings) {
List<PermissionMapping> result = Lists.newArrayList();
for (PermissionMapping permissionMapping : permissionMappings) {
Errors errors = new RequestBodyErrors(permissionMapping);
if (errors.hasErrors()) {
throw new EntityResponseStatusException(errors.getAllErrors(), HttpStatus.CONFLICT);
}
result.add(permissionMappingManager.update(permissionMapping));
}
return result;
}
/**
*
* @param permissionMapping
*/
@PreAuthorize("hasRole('ROLE_ADMIN')")
@DeleteMapping
public void delete(@RequestBody PermissionMapping permissionMapping) {
permissionMappingManager.delete(permissionMapping.getId());
}
}

View File

@ -0,0 +1,71 @@
/**
*
*/
package de.bstly.we.controller;
import java.io.IOException;
import java.util.Map.Entry;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.reactive.function.client.WebClientResponseException;
import com.google.common.collect.Lists;
import com.google.gson.Gson;
import com.google.gson.JsonIOException;
import de.bstly.we.businesslogic.PretixManager;
import de.bstly.we.controller.model.PretixRequest;
import de.bstly.we.controller.support.EntityResponseStatusException;
/**
*
* @author _bastler@bstly.de
*
*/
@RestController
@RequestMapping("/pretix")
public class PretixApiController extends BaseController {
@Autowired
private PretixManager pretixManager;
private Gson gson = new Gson();
/**
*
* @param pretixRequest
* @return
* @throws IOException
* @throws JsonIOException
*/
@PreAuthorize("hasRole('ROLE_ADMIN')")
@PostMapping("/debug")
public void debug(@RequestBody PretixRequest pretixRequest, HttpServletResponse response)
throws JsonIOException, IOException {
try {
MultiValueMap<String, String> queryParemeters = new LinkedMultiValueMap<String, String>();
if (pretixRequest.getQueryParameters() != null) {
for (Entry<String, String> entry : pretixRequest.getQueryParameters().entrySet()) {
queryParemeters.put(entry.getKey(), Lists.newArrayList(entry.getValue()));
}
}
gson.toJson(
pretixManager.request(pretixRequest.getPath(), pretixRequest.getMethod(),
gson.toJsonTree(pretixRequest.getPayload()), queryParemeters),
response.getWriter());
} catch (WebClientResponseException e) {
throw new EntityResponseStatusException(e.getMessage(), e.getStatusCode());
}
}
}

View File

@ -0,0 +1,114 @@
/**
*
*/
package de.bstly.we.controller;
import java.util.List;
import javax.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.google.common.collect.Lists;
import de.bstly.we.businesslogic.QuotaManager;
import de.bstly.we.controller.support.TokenSessionManager;
import de.bstly.we.model.Quota;
import de.bstly.we.model.QuotaMapping;
/**
*
* @author _bastler@bstly.de
*
*/
@RestController
@RequestMapping("/quotas")
public class QuotaController extends BaseController {
@Autowired
private QuotaManager quotaManager;
@Autowired
private TokenSessionManager tokenSessionManager;
/**
*
* @return
*/
@GetMapping
public List<Quota> getQuotas() {
if (getCurrentUserId() == null) {
return Lists.newArrayList();
}
return quotaManager.getNotExpiresByTarget(getCurrentUserId());
}
/**
*
* @return
*/
@GetMapping("/new")
public List<Quota> getNewQuotas(HttpSession session) {
List<Quota> quotas = Lists.newArrayList();
if (tokenSessionManager.getTokenFromSession(session).isEmpty()) {
return quotas;
}
for (String token : tokenSessionManager.getTokenFromSession(session)) {
for (QuotaMapping quotaMapping : tokenSessionManager
.getQuotaMappingsForToken(getCurrentUserId(), token)) {
boolean added = false;
for (Quota quota : quotas) {
if (quota.getName().equals(quotaMapping.getName())) {
quota.setValue(
quotaMapping.isAppend() ? quota.getValue() + quotaMapping.getValue()
: quotaMapping.getValue());
added = true;
}
}
if (!added) {
if (quotaManager.hasQuota(getCurrentUserId(), quotaMapping.getName())) {
Quota quota = quotaManager.get(getCurrentUserId(), quotaMapping.getName());
quota.setValue(
quotaMapping.isAppend() ? quota.getValue() + quotaMapping.getValue()
: quotaMapping.getValue());
quotas.add(quota);
added = true;
}
if (!added) {
Quota quota = new Quota();
quota.setName(quotaMapping.getName());
quota.setValue(quotaMapping.getValue());
quota.setUnit(quotaMapping.getUnit());
quota.setDisposable(quotaMapping.isDisposable());
quotas.add(quota);
}
}
}
}
return quotas;
}
/**
*
* @return
*/
@GetMapping("/all")
public List<Quota> getAllQuotas() {
if (getCurrentUserId() == null) {
return Lists.newArrayList();
}
return quotaManager.getAllByTarget(getCurrentUserId());
}
}

View File

@ -0,0 +1,190 @@
/**
*
*/
package de.bstly.we.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.beust.jcommander.internal.Lists;
import de.bstly.we.businesslogic.QuotaManager;
import de.bstly.we.businesslogic.UserManager;
import de.bstly.we.controller.support.EntityResponseStatusException;
import de.bstly.we.model.Quota;
import de.bstly.we.model.User;
/**
*
* @author _bastler@bstly.de
*
*/
@RestController
@RequestMapping("/quotas/manage")
public class QuotaManagementController extends BaseController {
@Autowired
private QuotaManager quotaManager;
@Autowired
private UserManager userManager;
/**
*
* @param username
* @return
*/
@PreAuthorize("hasRole('ROLE_ADMIN')")
@GetMapping("/{username}")
public List<Quota> getQuotasForUser(@PathVariable("username") String username) {
User user = userManager.getByUsername(username);
if (user == null) {
throw new EntityResponseStatusException(HttpStatus.NO_CONTENT);
}
return quotaManager.getNotExpiresByTarget(user.getId());
}
/**
*
* @param username
* @return
*/
@PreAuthorize("hasRole('ROLE_ADMIN')")
@GetMapping("/{username}/all")
public List<Quota> getAllQuotasForUser(@PathVariable("username") String username) {
User user = userManager.getByUsername(username);
if (user == null) {
throw new EntityResponseStatusException(HttpStatus.NO_CONTENT);
}
return quotaManager.getAllByTarget(user.getId());
}
/**
*
* @param name
* @return
*/
@PreAuthorize("hasRole('ROLE_ADMIN')")
@GetMapping("/byname/{name}")
public List<Quota> getQuotasByName(@PathVariable("name") String name) {
return quotaManager.getAllByName(name);
}
/**
*
* @param quota
* @return
*/
@PreAuthorize("hasRole('ROLE_ADMIN')")
@PostMapping
public Quota createQuota(@RequestBody Quota quota) {
if (quotaManager.get(quota.getTarget(), quota.getName()) != null) {
throw new EntityResponseStatusException(HttpStatus.CONFLICT);
}
return quotaManager.create(quota.getTarget(), quota.getName(), quota.getValue(),
quota.getUnit(), quota.isDisposable());
}
/**
*
* @param quota
* @return
*/
@PreAuthorize("hasRole('ROLE_ADMIN')")
@PatchMapping
public Quota updateQuota(@RequestBody Quota quota) {
if (quotaManager.get(quota.getTarget(), quota.getName()) == null) {
throw new EntityResponseStatusException(HttpStatus.CONFLICT);
}
return quotaManager.update(quota);
}
/**
*
* @param quotas
* @return
*/
@PreAuthorize("hasRole('ROLE_ADMIN')")
@PatchMapping("/list")
public List<Quota> updateQuotaList(@RequestBody List<Quota> quotas) {
List<Quota> result = Lists.newArrayList();
for (Quota quota : quotas) {
if (quotaManager.get(quota.getTarget(), quota.getName()) == null) {
throw new EntityResponseStatusException(HttpStatus.CONFLICT);
}
result.add(quotaManager.update(quota));
}
return result;
}
/**
*
* @param name
* @param clone
* @return
*/
@PreAuthorize("hasRole('ROLE_ADMIN')")
@PostMapping("/{name}/clone/{clone}")
public List<Quota> clone(@PathVariable("name") String name, @PathVariable("clone") String clone,
@RequestBody long value) {
if (name.equals(clone)) {
throw new EntityResponseStatusException(HttpStatus.CONFLICT);
}
return quotaManager.clone(name, clone, value);
}
/**
*
* @param quota
*/
@PreAuthorize("hasRole('ROLE_ADMIN')")
@DeleteMapping
public void deleteQuota(@RequestBody Quota quota) {
if (quotaManager.get(quota.getTarget(), quota.getName()) == null) {
throw new EntityResponseStatusException(HttpStatus.NOT_MODIFIED);
}
quotaManager.delete(quota.getTarget(), quota.getName());
}
/**
*
* @param target
*/
@PreAuthorize("hasRole('ROLE_ADMIN')")
@DeleteMapping("/{target}")
public void deleteAll(@PathVariable("target") Long target) {
quotaManager.deleteAll(target);
}
/**
*
* @param name
*/
@PreAuthorize("hasRole('ROLE_ADMIN')")
@DeleteMapping("/byname/{name}")
public void deleteAllByName(@PathVariable("name") String name) {
quotaManager.deleteAll(name);
}
}

View File

@ -0,0 +1,136 @@
/**
*
*/
package de.bstly.we.controller;
import java.util.List;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.Errors;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.google.common.collect.Lists;
import de.bstly.we.businesslogic.QuotaMappingManager;
import de.bstly.we.controller.support.EntityResponseStatusException;
import de.bstly.we.controller.support.RequestBodyErrors;
import de.bstly.we.controller.validation.QuotaMappingValidator;
import de.bstly.we.model.QuotaMapping;
/**
*
* @author _bastler@bstly.de
*
*/
@RestController
@RequestMapping("/quotas/mappings")
public class QuotaMappingController extends BaseController {
@Autowired
private QuotaMappingManager quotaMappingManager;
@Autowired
private QuotaMappingValidator quotaMappingValidator;
/**
*
* @param pageParameter
* @param sizeParameter
* @return
*/
@PreAuthorize("hasRole('ROLE_ADMIN')")
@GetMapping
public Page<QuotaMapping> getQuotaMappings(
@RequestParam("page") Optional<Integer> pageParameter,
@RequestParam("size") Optional<Integer> sizeParameter) {
return quotaMappingManager.get(pageParameter.orElse(0), sizeParameter.orElse(10), "name",
true);
}
/**
*
* @param userModel
* @return
*/
@PreAuthorize("hasRole('ROLE_ADMIN')")
@PostMapping
public QuotaMapping create(@RequestBody QuotaMapping quotaMapping) {
Errors errors = new RequestBodyErrors(quotaMapping);
quotaMappingValidator.validate(quotaMapping, errors);
if (errors.hasErrors()) {
throw new EntityResponseStatusException(errors.getAllErrors(), HttpStatus.CONFLICT);
}
return quotaMappingManager.create(quotaMapping.getItems(), quotaMapping.getName(),
quotaMapping.getValue(), quotaMapping.getUnit(), quotaMapping.isAppend(),
quotaMapping.getProducts(), quotaMapping.isDisposable());
}
/**
*
* @param userModel
* @return
*/
@PreAuthorize("hasRole('ROLE_ADMIN')")
@PostMapping("/list")
public List<QuotaMapping> createList(@RequestBody List<QuotaMapping> quotaMappings) {
List<QuotaMapping> result = Lists.newArrayList();
for (QuotaMapping quotaMapping : quotaMappings) {
Errors errors = new RequestBodyErrors(quotaMapping);
quotaMappingValidator.validate(quotaMapping, errors);
if (errors.hasErrors()) {
throw new EntityResponseStatusException(errors.getAllErrors(), HttpStatus.CONFLICT);
}
result.add(quotaMappingManager.create(quotaMapping.getItems(), quotaMapping.getName(),
quotaMapping.getValue(), quotaMapping.getUnit(), quotaMapping.isAppend(),
quotaMapping.getProducts(), quotaMapping.isDisposable()));
}
return result;
}
/**
*
* @param userModel
* @return
*/
@PreAuthorize("hasRole('ROLE_ADMIN')")
@PatchMapping
public QuotaMapping update(@RequestBody QuotaMapping quotaMapping) {
Errors errors = new RequestBodyErrors(quotaMapping);
if (errors.hasErrors()) {
throw new EntityResponseStatusException(errors.getAllErrors(), HttpStatus.CONFLICT);
}
return quotaMappingManager.update(quotaMapping);
}
/**
*
* @param userModel
* @return
*/
@PreAuthorize("hasRole('ROLE_ADMIN')")
@DeleteMapping
public void delete(@RequestBody QuotaMapping quotaMapping) {
quotaMappingManager.delete(quotaMapping.getId());
}
}

View File

@ -0,0 +1,107 @@
/**
*
*/
package de.bstly.we.controller;
import java.util.List;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import de.bstly.we.businesslogic.PretixManager;
import de.bstly.we.controller.support.EntityResponseStatusException;
import de.bstly.we.model.SystemProperty;
import de.bstly.we.repository.SystemPropertyRepository;
/**
*
* @author _bastler@bstly.de
*
*/
@RestController
@RequestMapping("/system")
public class SystemController extends BaseController {
@Autowired
private SystemPropertyRepository systemPropertyRepository;
@Autowired
private PretixManager pretixManager;
/**
*
*/
@PreAuthorize("hasRole('ROLE_ADMIN')")
@PostMapping("/pretix")
public void updatePretixClient() {
pretixManager.buildWebClient();
}
/**
*
* @param pageParameter
* @param sizeParameter
* @return
*/
@PreAuthorize("hasRole('ROLE_ADMIN')")
@GetMapping("/properties")
public List<SystemProperty> getProperties(@RequestParam("page") Optional<Integer> pageParameter,
@RequestParam("size") Optional<Integer> sizeParameter) {
Sort sort = Sort.by("key").ascending();
return systemPropertyRepository
.findAll(PageRequest.of(pageParameter.orElse(0), sizeParameter.orElse(10), sort))
.getContent();
}
/**
*
* @param key
* @return
*/
@PreAuthorize("hasRole('ROLE_ADMIN')")
@GetMapping("/properties/{key}")
public SystemProperty getProperty(@PathVariable("key") String key) {
if (!systemPropertyRepository.existsById(key)) {
throw new EntityResponseStatusException(HttpStatus.NO_CONTENT);
}
return systemPropertyRepository.findById(key).get();
}
/**
*
* @param systemProperty
* @return
*/
@PreAuthorize("hasRole('ROLE_ADMIN')")
@PostMapping("/properties")
public SystemProperty createOrUpdate(@RequestBody SystemProperty systemProperty) {
return systemPropertyRepository.save(systemProperty);
}
/**
*
* @param key
* @return
*/
@PreAuthorize("hasRole('ROLE_ADMIN')")
@DeleteMapping("/properties/{key}")
public void deleteProperty(@PathVariable("key") String key) {
if (!systemPropertyRepository.existsById(key)) {
throw new EntityResponseStatusException(HttpStatus.NOT_MODIFIED);
}
systemPropertyRepository.deleteById(key);
}
}

View File

@ -0,0 +1,115 @@
/**
*
*/
package de.bstly.we.controller;
import java.util.List;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.beust.jcommander.internal.Lists;
import de.bstly.we.businesslogic.SystemProfileFieldManager;
import de.bstly.we.controller.support.EntityResponseStatusException;
import de.bstly.we.model.SystemProfileField;
/**
* @author _bastler@bstly.de
*
*/
@RestController
@RequestMapping("/profiles/system")
public class SystemProfileFieldController extends BaseController {
@Autowired
private SystemProfileFieldManager systemProfileFieldManager;
/**
*
* @param pageParameter
* @param sizeParameter
* @return
*/
@PreAuthorize("hasRole('ROLE_ADMIN')")
@GetMapping
public Page<SystemProfileField> get(@RequestParam("page") Optional<Integer> pageParameter,
@RequestParam("size") Optional<Integer> sizeParameter) {
return systemProfileFieldManager.get(pageParameter.orElse(0), sizeParameter.orElse(10),
"name", true);
}
/**
*
* @param name
* @return
*/
@PreAuthorize("hasRole('ROLE_ADMIN')")
@GetMapping("/{name}")
public SystemProfileField getByName(@PathVariable("name") String name) {
SystemProfileField systemProfileField = systemProfileFieldManager.get(name);
if (systemProfileField == null) {
throw new EntityResponseStatusException(HttpStatus.NO_CONTENT);
}
return systemProfileField;
}
/**
*
* @param systemProfileField
* @return
*/
@PreAuthorize("hasRole('ROLE_ADMIN')")
@PostMapping
public SystemProfileField update(@RequestBody SystemProfileField systemProfileField) {
return systemProfileFieldManager.save(systemProfileField);
}
/**
*
* @param systemProfileField
* @return
*/
@PreAuthorize("hasRole('ROLE_ADMIN')")
@PostMapping("/list")
public List<SystemProfileField> updateList(
@RequestBody List<SystemProfileField> systemProfileFields) {
List<SystemProfileField> result = Lists.newArrayList();
for (SystemProfileField systemProfileField : systemProfileFields) {
result.add(systemProfileFieldManager.save(systemProfileField));
}
return result;
}
/**
*
* @param name
*/
@PreAuthorize("hasRole('ROLE_ADMIN')")
@DeleteMapping("/{name}")
public void deleteByName(@PathVariable("name") String name) {
SystemProfileField systemProfileField = systemProfileFieldManager.get(name);
if (systemProfileField == null) {
throw new EntityResponseStatusException(HttpStatus.NOT_MODIFIED);
}
systemProfileFieldManager.delete(name);
}
}

View File

@ -0,0 +1,141 @@
/**
*
*/
package de.bstly.we.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.Errors;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import de.bstly.we.businesslogic.PermissionManager;
import de.bstly.we.businesslogic.QuotaManager;
import de.bstly.we.businesslogic.Quotas;
import de.bstly.we.businesslogic.UserAliasManager;
import de.bstly.we.controller.support.EntityResponseStatusException;
import de.bstly.we.controller.support.RequestBodyErrors;
import de.bstly.we.controller.validation.UserAliasValidator;
import de.bstly.we.model.Quota;
import de.bstly.we.model.UserAlias;
/**
* @author _bastler@bstly.de
*
*/
@RestController
@RequestMapping("/users/aliases")
public class UserAliasController extends BaseController {
@Autowired
private QuotaManager quotaManager;
@Autowired
private UserAliasManager userAliasManager;
@Autowired
private UserAliasValidator userAliasValidator;
@Autowired
private PermissionManager permissionManager;
/**
*
* @param alias
* @return
*/
@PreAuthorize("isAuthenticated()")
@PostMapping
public UserAlias createAlias(@RequestBody UserAlias userAlias) {
if (!permissionManager.isFullUser(getCurrentUserId())) {
throw new EntityResponseStatusException(HttpStatus.FORBIDDEN);
}
Quota aliasCreation = quotaManager.get(getCurrentUserId(), Quotas.ALIAS_CREATION);
if (aliasCreation == null || aliasCreation.getValue() < 1) {
throw new EntityResponseStatusException(HttpStatus.CONFLICT);
}
userAlias.setTarget(getCurrentUserId());
Errors errors = new RequestBodyErrors(userAlias);
userAliasValidator.validate(userAlias, errors);
if (errors.hasErrors()) {
throw new EntityResponseStatusException(errors.getAllErrors(), HttpStatus.CONFLICT);
}
aliasCreation.setValue(aliasCreation.getValue() - 1);
quotaManager.update(aliasCreation);
return userAliasManager.save(userAlias);
}
/**
*
* @param alias
* @return
*/
@PreAuthorize("isAuthenticated()")
@PatchMapping
public UserAlias updateAlias(@RequestBody UserAlias userAlias) {
if (userAlias.getId() == null) {
throw new EntityResponseStatusException(HttpStatus.CONFLICT);
}
UserAlias oldAlias = userAliasManager.get(userAlias.getId());
if (oldAlias == null) {
throw new EntityResponseStatusException(HttpStatus.CONFLICT);
}
if (!oldAlias.getTarget().equals(getCurrentUserId())) {
throw new EntityResponseStatusException(HttpStatus.FORBIDDEN);
}
oldAlias.setVisibility(userAlias.getVisibility());
return userAliasManager.save(oldAlias);
}
/**
*
* @return
*/
@PreAuthorize("isAuthenticated()")
@GetMapping
public List<UserAlias> getAliases() {
return userAliasManager.getAllByTarget(getCurrentUserId());
}
/**
*
* @param id
*/
@PreAuthorize("isAuthenticated()")
@DeleteMapping("/{id}")
public void deleteAlias(@PathVariable("id") Long id) {
UserAlias userAlias = userAliasManager.get(id);
if (userAlias == null || !userAlias.getTarget().equals(getCurrentUserId())) {
throw new EntityResponseStatusException(HttpStatus.CONFLICT);
}
Quota aliasCreation = quotaManager.get(getCurrentUserId(), Quotas.ALIAS_CREATION);
if (aliasCreation == null) {
aliasCreation = quotaManager.create(getCurrentUserId(), Quotas.ALIAS_CREATION, 0, "#",
true);
}
aliasCreation.setValue(aliasCreation.getValue() + 1);
quotaManager.update(aliasCreation);
userAliasManager.delete(id);
}
}

View File

@ -0,0 +1,105 @@
/**
*
*/
package de.bstly.we.controller;
import java.util.List;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.Errors;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import de.bstly.we.businesslogic.UserAliasManager;
import de.bstly.we.businesslogic.UserManager;
import de.bstly.we.controller.support.EntityResponseStatusException;
import de.bstly.we.controller.support.RequestBodyErrors;
import de.bstly.we.controller.validation.UserAliasValidator;
import de.bstly.we.model.User;
import de.bstly.we.model.UserAlias;
/**
* @author _bastler@bstly.de
*
*/
@RestController
@RequestMapping("/users/aliases/manage")
public class UserAliasManagementController extends BaseController {
@Autowired
private UserManager userManager;
@Autowired
private UserAliasManager userAliasManager;
@Autowired
private UserAliasValidator userAliasValidator;
/**
*
* @return
*/
@PreAuthorize("hasRole('ROLE_ADMIN')")
@GetMapping
public Page<UserAlias> getAliases(@RequestParam("page") Optional<Integer> pageParameter,
@RequestParam("size") Optional<Integer> sizeParameter) {
return userAliasManager.get(pageParameter.orElse(0), sizeParameter.orElse(10), "id", true);
}
/**
*
* @return
*/
@PreAuthorize("hasRole('ROLE_ADMIN')")
@GetMapping("/{username}")
public List<UserAlias> getAliasesForUser(@PathVariable("username") String username) {
User user = userManager.getByUsername(username);
if (user == null) {
throw new EntityResponseStatusException(HttpStatus.CONFLICT);
}
return userAliasManager.getAllByTarget(user.getId());
}
/**
*
* @param alias
* @return
*/
@PreAuthorize("hasRole('ROLE_ADMIN')")
@PostMapping
public UserAlias createOrUpdateAlias(@RequestBody UserAlias userAlias) {
Errors errors = new RequestBodyErrors(userAlias);
userAliasValidator.validate(userAlias, errors);
if (errors.hasErrors()) {
throw new EntityResponseStatusException(errors.getAllErrors(), HttpStatus.CONFLICT);
}
return userAliasManager.save(userAlias);
}
/**
*
* @param id
*/
@PreAuthorize("hasRole('ROLE_ADMIN')")
@DeleteMapping("/{id}")
public void deleteAlias(@PathVariable("id") Long id) {
UserAlias userAlias = userAliasManager.get(id);
if (userAlias == null) {
throw new EntityResponseStatusException(HttpStatus.CONFLICT);
}
userAliasManager.delete(id);
}
}

View File

@ -0,0 +1,257 @@
/**
*
*/
package de.bstly.we.controller;
import javax.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.util.StringUtils;
import org.springframework.validation.Errors;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.beust.jcommander.internal.Lists;
import de.bstly.we.businesslogic.PermissionManager;
import de.bstly.we.businesslogic.PretixManager;
import de.bstly.we.businesslogic.PretixManager.ITEM_STATUS;
import de.bstly.we.businesslogic.QuotaManager;
import de.bstly.we.businesslogic.UserManager;
import de.bstly.we.businesslogic.UserProfileFieldManager;
import de.bstly.we.controller.model.ItemResultModel;
import de.bstly.we.controller.model.PasswordModel;
import de.bstly.we.controller.model.UserModel;
import de.bstly.we.controller.support.EntityResponseStatusException;
import de.bstly.we.controller.support.RequestBodyErrors;
import de.bstly.we.controller.support.TokenSessionManager;
import de.bstly.we.controller.validation.PasswordModelValidator;
import de.bstly.we.controller.validation.UserModelValidator;
import de.bstly.we.controller.validation.UserProfileFieldValidator;
import de.bstly.we.model.PermissionMapping;
import de.bstly.we.model.ProfileFieldType;
import de.bstly.we.model.User;
import de.bstly.we.model.UserProfileField;
import de.bstly.we.model.Visibility;
import de.bstly.we.model.UserStatus;
/**
*
* @author _bastler@bstly.de
*
*/
@RestController
@RequestMapping("/users")
public class UserController extends BaseController {
@Autowired
private UserManager userManager;
@Autowired
private UserProfileFieldManager userProfileFieldManager;
@Autowired
private PermissionManager permissionManager;
@Autowired
private QuotaManager quotaManager;
@Autowired
private PasswordModelValidator passwordModelValidator;
@Autowired
private UserModelValidator userModelValidator;
@Autowired
private UserProfileFieldValidator userProfileFieldValidator;
@Autowired
private TokenSessionManager tokenSessionManager;
@Autowired
private PretixManager pretixManager;
@Autowired
private PasswordEncoder passwordEncoder;
/**
*
* @return
*/
@PreAuthorize("isAuthenticated()")
@GetMapping
public UserModel get() {
User user = userManager.get(getCurrentUserId());
UserModel userModel = new UserModel();
userModel.setUsername(user.getUsername());
userModel.setStatus(user.getStatus());
return userModel;
}
/**
*
* @param userModel
* @param session
* @return
*/
@PostMapping("/model")
public UserModel checkModel(@RequestBody UserModel userModel, HttpSession session) {
Errors errors = new RequestBodyErrors(userModel);
userModelValidator.validate(userModel, errors);
if (errors.hasErrors()) {
throw new EntityResponseStatusException(errors.getAllErrors(), HttpStatus.CONFLICT);
}
return userModel;
}
/**
*
* @param userModel
* @param session
* @return
*/
@PreAuthorize("isAnonymous()")
@PostMapping
public UserModel register(@RequestBody UserModel userModel, HttpSession session) {
Errors errors = new RequestBodyErrors(userModel);
if (tokenSessionManager.getTokenFromSession(session).isEmpty()) {
if (StringUtils.hasText(userModel.getToken())) {
String secret = userModel.getToken();
ITEM_STATUS status = pretixManager.getItemStatus(secret);
if (status == ITEM_STATUS.PAID) {
tokenSessionManager.addTokenToSession(secret, session);
} else if (pretixManager.getItemStatus(secret) == ITEM_STATUS.REDEEMED) {
throw new EntityResponseStatusException(HttpStatus.GONE);
}
} else {
throw new EntityResponseStatusException(HttpStatus.UNAUTHORIZED);
}
}
boolean register = false;
for (String token : tokenSessionManager.getTokenFromSession(session)) {
for (PermissionMapping permissionMapping : tokenSessionManager
.getPermissionMappingsForToken(getCurrentUserId(), token)) {
if (!permissionMapping.isAddon()) {
register = true;
break;
}
}
}
if (!register) {
throw new EntityResponseStatusException(HttpStatus.UNAUTHORIZED);
}
userModelValidator.validate(userModel, errors);
passwordModelValidator.validate(userModel, errors);
if (userModel.getProfileFields() == null) {
userModel.setProfileFields(Lists.newArrayList());
}
if (userModel.getStatus() == null) {
userModel.setStatus(UserStatus.NORMAL);
}
for (UserProfileField userProfileField : userModel.getProfileFields()) {
userProfileFieldValidator.validate(userProfileField, errors);
}
if (errors.hasErrors()) {
throw new EntityResponseStatusException(errors.getAllErrors(), HttpStatus.CONFLICT);
}
User user = userManager.create(userModel.getUsername(), userModel.getPassword(),
userModel.getStatus());
for (UserProfileField userProfileField : userModel.getProfileFields()) {
userProfileField.setTarget(user.getId());
if (userProfileField.getType() == null) {
userProfileField.setType(ProfileFieldType.TEXT);
}
if (userProfileField.getVisibility() == null) {
userProfileField.setVisibility(Visibility.PRIVATE);
}
userProfileField = userProfileFieldManager.save(userProfileField);
}
UserModel responseModel = new UserModel();
responseModel.setUsername(user.getUsername());
responseModel.setStatus(user.getStatus());
ItemResultModel result = tokenSessionManager.applyTokens(user.getId(),
tokenSessionManager.getTokenFromSession(session));
responseModel.setPermissionMappings(result.getPermissionMappings());
responseModel.setPermissions(permissionManager.getNotExpiresByTarget(user.getId()));
responseModel.setQuotaMappings(result.getQuotaMappings());
responseModel.setQuotas(quotaManager.getNotExpiresByTarget(user.getId()));
responseModel.setProfileFields(userProfileFieldManager.getAllByTarget(user.getId()));
tokenSessionManager.removeTokensFromSession(session);
return responseModel;
}
/**
*
* @param passwordModel
*/
@PreAuthorize("isAuthenticated()")
@PatchMapping("/password")
public void changePassword(@RequestBody PasswordModel passwordModel) {
Errors errors = new RequestBodyErrors(passwordModel);
User user = userManager.get(getCurrentUserId());
if (!StringUtils.hasText(passwordModel.getOld()) || !passwordEncoder
.matches(passwordModel.getOld(), userManager.getPasswordHash(user.getId()))) {
throw new EntityResponseStatusException(HttpStatus.UNAUTHORIZED);
}
passwordModelValidator.validate(passwordModel, errors);
if (errors.hasErrors()) {
throw new EntityResponseStatusException(errors.getAllErrors(), HttpStatus.CONFLICT);
}
userManager.setPassword(user.getId(), passwordModel.getPassword());
}
/**
*
* @param userModel
*/
@PreAuthorize("isAuthenticated()")
@PatchMapping
public void update(@RequestBody UserModel userModel) {
User user = userManager.get(getCurrentUserId());
if (StringUtils.hasText(userModel.getOld())) {
Errors errors = new RequestBodyErrors(userModel);
if (!passwordEncoder.matches(userModel.getOld(),
userManager.getPasswordHash(getCurrentUserId()))) {
throw new EntityResponseStatusException(HttpStatus.UNAUTHORIZED);
}
passwordModelValidator.validate(userModel, errors);
if (errors.hasErrors()) {
throw new EntityResponseStatusException(errors.getAllErrors(), HttpStatus.CONFLICT);
}
user = userManager.setPassword(user.getId(), userModel.getPassword());
}
if (userModel.getStatus() != null) {
user.setStatus(userModel.getStatus());
}
user = userManager.update(user);
}
}

View File

@ -0,0 +1,129 @@
/**
*
*/
package de.bstly.we.controller;
import java.util.List;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.Errors;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import de.bstly.we.businesslogic.PermissionManager;
import de.bstly.we.businesslogic.UserDomainManager;
import de.bstly.we.controller.support.EntityResponseStatusException;
import de.bstly.we.controller.support.RequestBodyErrors;
import de.bstly.we.controller.validation.UserDomainValidator;
import de.bstly.we.model.UserDomain;
import de.bstly.we.model.Visibility;
/**
* @author _bastler@bstly.de
*
*/
@RestController
@RequestMapping("/users/domains")
public class UserDomainController extends BaseController {
@Autowired
private UserDomainManager userDomainManager;
@Autowired
private UserDomainValidator userDomainValidator;
@Autowired
private PermissionManager permissionManager;
/**
*
* @param userDomain
* @return
*/
@PreAuthorize("isAuthenticated()")
@PostMapping
public UserDomain createDomain(@RequestBody UserDomain userDomain) {
if (!permissionManager.isFullUser(getCurrentUserId())) {
throw new EntityResponseStatusException(HttpStatus.FORBIDDEN);
}
if (userDomain.getVisibility() == null) {
userDomain.setVisibility(Visibility.PRIVATE);
}
userDomain.setTarget(getCurrentUserId());
userDomain.setValidated(false);
userDomain.setSecret(
RandomStringUtils.random(UserDomainManager.DEFAULT_SECRET_LENGTH, true, true));
Errors errors = new RequestBodyErrors(userDomain);
userDomainValidator.validate(userDomain, errors);
if (errors.hasErrors()) {
throw new EntityResponseStatusException(errors.getAllErrors(), HttpStatus.CONFLICT);
}
return userDomainManager.save(userDomain);
}
/**
*
* @param userDomain
* @return
*/
@PreAuthorize("isAuthenticated()")
@PatchMapping
public UserDomain updateDomain(@RequestBody UserDomain userDomain) {
if (userDomain.getId() == null) {
throw new EntityResponseStatusException(HttpStatus.CONFLICT);
}
UserDomain oldDomain = userDomainManager.get(userDomain.getId());
if (oldDomain == null) {
throw new EntityResponseStatusException(HttpStatus.CONFLICT);
}
if (!oldDomain.getTarget().equals(getCurrentUserId())) {
throw new EntityResponseStatusException(HttpStatus.FORBIDDEN);
}
oldDomain.setVisibility(userDomain.getVisibility());
return userDomainManager.save(oldDomain);
}
/**
*
* @return
*/
@PreAuthorize("isAuthenticated()")
@GetMapping
public List<UserDomain> getDomains() {
return userDomainManager.getAllByTarget(getCurrentUserId());
}
/**
*
* @param id
*/
@PreAuthorize("isAuthenticated()")
@DeleteMapping("/{id}")
public void deleteDomain(@PathVariable("id") Long id) {
UserDomain userDomain = userDomainManager.get(id);
if (userDomain == null || !userDomain.getTarget().equals(getCurrentUserId())) {
throw new EntityResponseStatusException(HttpStatus.CONFLICT);
}
userDomainManager.delete(id);
}
}

View File

@ -0,0 +1,142 @@
/**
*
*/
package de.bstly.we.controller;
import java.util.List;
import java.util.Optional;
import javax.naming.NamingException;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.Errors;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import de.bstly.we.businesslogic.UserDomainManager;
import de.bstly.we.businesslogic.UserManager;
import de.bstly.we.controller.support.EntityResponseStatusException;
import de.bstly.we.controller.support.RequestBodyErrors;
import de.bstly.we.controller.validation.UserDomainValidator;
import de.bstly.we.model.User;
import de.bstly.we.model.UserDomain;
import de.bstly.we.model.Visibility;
/**
* @author _bastler@bstly.de
*
*/
@RestController
@RequestMapping("/users/domains/manage")
public class UserDomainManagementController extends BaseController {
@Autowired
private UserManager userManager;
@Autowired
private UserDomainManager userDomainManager;
@Autowired
private UserDomainValidator userDomainValidator;
/**
*
* @return
*/
@PreAuthorize("hasRole('ROLE_ADMIN')")
@GetMapping
public Page<UserDomain> getDomains(@RequestParam("page") Optional<Integer> pageParameter,
@RequestParam("size") Optional<Integer> sizeParameter) {
return userDomainManager.get(pageParameter.orElse(0), sizeParameter.orElse(10), "id", true);
}
/**
*
* @return
*/
@PreAuthorize("hasRole('ROLE_ADMIN')")
@GetMapping("/{username}")
public List<UserDomain> getDomainsForUser(@PathVariable("username") String username) {
User user = userManager.getByUsername(username);
if (user == null) {
throw new EntityResponseStatusException(HttpStatus.CONFLICT);
}
return userDomainManager.getAllByTarget(user.getId());
}
/**
*
* @param alias
* @return
*/
@PreAuthorize("hasRole('ROLE_ADMIN')")
@PostMapping
public UserDomain createOrUpdateDomain(@RequestBody UserDomain userDomain) {
if (userDomain.getVisibility() == null) {
userDomain.setVisibility(Visibility.PRIVATE);
}
Errors errors = new RequestBodyErrors(userDomain);
userDomainValidator.validate(userDomain, errors);
if (errors.hasErrors()) {
throw new EntityResponseStatusException(errors.getAllErrors(), HttpStatus.CONFLICT);
}
if (userDomain.getId() == null) {
userDomain.setValidated(false);
userDomain.setSecret(
RandomStringUtils.random(UserDomainManager.DEFAULT_SECRET_LENGTH, true, true));
}
return userDomainManager.save(userDomain);
}
/**
*
* @param id
*/
@PreAuthorize("hasRole('ROLE_ADMIN')")
@DeleteMapping("/{id}")
public void deleteDomain(@PathVariable("id") Long id) {
UserDomain userDomain = userDomainManager.get(id);
if (userDomain == null) {
throw new EntityResponseStatusException(HttpStatus.CONFLICT);
}
userDomainManager.delete(id);
}
/**
*
* @param id
*/
@PreAuthorize("hasRole('ROLE_ADMIN')")
@PostMapping("/validate/{id}")
public void validate(@PathVariable("id") Long id) {
UserDomain userDomain = userDomainManager.get(id);
if (userDomain == null) {
throw new EntityResponseStatusException(HttpStatus.CONFLICT);
}
try {
if (userDomainManager.validate(userDomain)) {
throw new EntityResponseStatusException(HttpStatus.ACCEPTED);
}
} catch (NamingException e) {
e.printStackTrace();
}
throw new EntityResponseStatusException(HttpStatus.NOT_ACCEPTABLE);
}
}

View File

@ -0,0 +1,229 @@
/**
*
*/
package de.bstly.we.controller;
import java.time.Instant;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.Errors;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.beust.jcommander.internal.Lists;
import de.bstly.we.businesslogic.PermissionManager;
import de.bstly.we.businesslogic.QuotaManager;
import de.bstly.we.businesslogic.UserDataManager;
import de.bstly.we.businesslogic.UserManager;
import de.bstly.we.businesslogic.UserProfileFieldManager;
import de.bstly.we.businesslogic.support.InstantHelper;
import de.bstly.we.controller.model.UserModel;
import de.bstly.we.controller.support.EntityResponseStatusException;
import de.bstly.we.controller.support.RequestBodyErrors;
import de.bstly.we.controller.validation.PasswordModelValidator;
import de.bstly.we.controller.validation.UserModelValidator;
import de.bstly.we.controller.validation.UserProfileFieldValidator;
import de.bstly.we.model.Permission;
import de.bstly.we.model.PermissionMapping;
import de.bstly.we.model.ProfileFieldType;
import de.bstly.we.model.Quota;
import de.bstly.we.model.QuotaMapping;
import de.bstly.we.model.User;
import de.bstly.we.model.UserProfileField;
import de.bstly.we.model.UserStatus;
import de.bstly.we.model.Visibility;
/**
*
* @author _bastler@bstly.de
*
*/
@RestController
@RequestMapping("/users/manage")
public class UserManagementController extends BaseController {
@Autowired
private UserManager userManager;
@Autowired
private PermissionManager permissionManager;
@Autowired
private QuotaManager quotaManager;
@Autowired
private UserProfileFieldManager userProfileFieldManager;
@Autowired
private PasswordModelValidator passwordModelValidator;
@Autowired
private UserModelValidator userModelValidator;
@Autowired
private UserProfileFieldValidator userProfileFieldValidator;
@Autowired
private UserDataManager userDataManager;
/**
*
* @param pageParameter
* @param sizeParameter
* @return
*/
@PreAuthorize("hasRole('ROLE_ADMIN')")
@GetMapping
public Page<User> getUsers(@RequestParam("page") Optional<Integer> pageParameter,
@RequestParam("size") Optional<Integer> sizeParameter) {
return userManager.get(pageParameter.orElse(0), sizeParameter.orElse(10), "username", true);
}
/**
*
* @param username
* @return
*/
@PreAuthorize("hasRole('ROLE_ADMIN')")
@GetMapping("/{username}")
public User getUserByUsername(@PathVariable("username") String username) {
User user = userManager.getByUsername(username);
if (user == null) {
throw new EntityResponseStatusException(HttpStatus.NO_CONTENT);
}
return user;
}
/**
*
* @param userModel
* @return
*/
@PreAuthorize("hasRole('ROLE_ADMIN')")
@PostMapping
public User create(@RequestBody UserModel userModel) {
Errors errors = new RequestBodyErrors(userModel);
userModelValidator.validate(userModel, errors);
passwordModelValidator.validate(userModel, errors);
if (userModel.getStatus() == null) {
userModel.setStatus(UserStatus.SLEEP);
}
if (userModel.getProfileFields() == null) {
userModel.setProfileFields(Lists.newArrayList());
}
for (UserProfileField userProfileField : userModel.getProfileFields()) {
userProfileFieldValidator.validate(userProfileField, errors);
}
if (errors.hasErrors()) {
throw new EntityResponseStatusException(errors.getAllErrors(), HttpStatus.CONFLICT);
}
User user = userManager.create(userModel.getUsername(), userModel.getPassword(),
userModel.getStatus());
if (userModel.getPermissionMappings() != null) {
for (PermissionMapping permissionMapping : userModel.getPermissionMappings()) {
for (String name : permissionMapping.getNames()) {
permissionManager.create(user.getId(), name, permissionMapping.isAddon(), null,
InstantHelper.plus(Instant.now(), permissionMapping.getLifetime(),
permissionMapping.getLifetimeUnit()));
}
}
}
if (userModel.getPermissions() != null) {
for (Permission permission : userModel.getPermissions()) {
permissionManager.create(user.getId(), permission.getName(), permission.isAddon(),
permission.getStarts(), permission.getExpires());
}
}
if (userModel.getQuotaMappings() != null) {
for (QuotaMapping quotaMapping : userModel.getQuotaMappings()) {
quotaManager.create(user.getId(), quotaMapping.getName(), quotaMapping.getValue(),
quotaMapping.getUnit(), quotaMapping.isDisposable());
}
}
if (userModel.getQuotas() != null) {
for (Quota quota : userModel.getQuotas()) {
quotaManager.create(user.getId(), quota.getName(), quota.getValue(),
quota.getUnit(), quota.isDisposable());
}
}
for (UserProfileField userProfileField : userModel.getProfileFields()) {
userProfileField.setTarget(user.getId());
if (userProfileField.getType() == null) {
userProfileField.setType(ProfileFieldType.TEXT);
}
if (userProfileField.getVisibility() == null) {
userProfileField.setVisibility(Visibility.PRIVATE);
}
userProfileField = userProfileFieldManager.save(userProfileField);
}
return user;
}
/**
*
* @param user
* @return
*/
@PreAuthorize("hasRole('ROLE_ADMIN')")
@PatchMapping
public User update(@RequestBody User user) {
return userManager.update(user);
}
/**
*
* @param username
*/
@PreAuthorize("hasRole('ROLE_ADMIN')")
@DeleteMapping("/{username}")
public void deleteUserByUsername(@PathVariable("username") String username) {
User user = userManager.getByUsername(username);
if (user == null) {
throw new EntityResponseStatusException(HttpStatus.NOT_MODIFIED);
}
userManager.delete(user);
}
/**
*
*/
@PreAuthorize("hasRole('ROLE_ADMIN')")
@PostMapping("/purge")
public void purge(@RequestParam("username") Optional<String> username,
@RequestParam("dry") Optional<Boolean> dry) {
if (username.isPresent()) {
User user = userManager.getByUsername(username.get());
if (user == null) {
throw new EntityResponseStatusException(HttpStatus.NOT_MODIFIED);
}
userDataManager.purge(user, dry.isPresent() && dry.get());
} else {
userDataManager.purge();
}
}
}

View File

@ -0,0 +1,284 @@
/**
*
*/
package de.bstly.we.controller;
import java.util.List;
import java.util.Optional;
import org.apache.commons.lang3.RandomUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.Errors;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.beust.jcommander.internal.Lists;
import de.bstly.we.businesslogic.PermissionManager;
import de.bstly.we.businesslogic.UserAliasManager;
import de.bstly.we.businesslogic.UserManager;
import de.bstly.we.businesslogic.UserProfileFieldManager;
import de.bstly.we.controller.model.ProfileModel;
import de.bstly.we.controller.support.EntityResponseStatusException;
import de.bstly.we.controller.support.RequestBodyErrors;
import de.bstly.we.controller.validation.UserProfileFieldValidator;
import de.bstly.we.model.ProfileFieldType;
import de.bstly.we.model.User;
import de.bstly.we.model.UserAlias;
import de.bstly.we.model.UserProfileField;
import de.bstly.we.model.Visibility;
/**
* @author _bastler@bstly.de
*
*/
@RestController
@RequestMapping("/profiles")
public class UserProfileFieldController extends BaseController {
@Autowired
private UserProfileFieldManager userProfileFieldManager;
@Autowired
private UserManager userManager;
@Autowired
private UserAliasManager userAliasManager;
@Autowired
private UserProfileFieldValidator userProfileFieldModelValidator;
@Autowired
private PermissionManager permissionManager;
/**
*
* @return
*/
@PreAuthorize("isAuthenticated()")
@GetMapping
public List<UserProfileField> get(@RequestParam("filter") Optional<String> filter) {
if (filter.isEmpty()) {
return userProfileFieldManager.getAllByTarget(getCurrentUserId());
}
return userProfileFieldManager.getByTargetFiltered(getCurrentUserId(),
Lists.newArrayList(filter.get().split(",")));
}
/**
*
* @return
*/
@PreAuthorize("isAuthenticated()")
@GetMapping("/field/{name}")
public UserProfileField getField(@PathVariable("name") String name) {
UserProfileField userProfileField = userProfileFieldManager.get(getCurrentUserId(), name);
if (userProfileField == null) {
throw new EntityResponseStatusException(HttpStatus.NO_CONTENT);
}
return userProfileField;
}
/**
*
* @return
*/
@GetMapping("/{username}")
public ProfileModel getForUser(@PathVariable("username") String username) {
Long currentUserId = getCurrentUserId();
User user = userManager.getByUsername(username);
if (user == null) {
UserAlias userAlias = userAliasManager.getByAlias(username);
if (userAlias != null) {
switch (userAlias.getVisibility()) {
case PRIVATE:
if (currentUserId != null && currentUserId.equals(userAlias.getTarget())) {
user = userManager.get(userAlias.getTarget());
}
break;
case PROTECTED:
if (currentUserId != null && permissionManager.isFullUser(getCurrentUserId())) {
user = userManager.get(userAlias.getTarget());
}
break;
case PUBLIC:
user = userManager.get(userAlias.getTarget());
break;
}
}
}
if (user == null) {
throttleForbidden();
}
List<UserProfileField> profileFields = Lists.newArrayList();
List<Visibility> visibilities = Lists.newArrayList(Visibility.PUBLIC);
if (currentUserId != null) {
visibilities.add(Visibility.PROTECTED);
if (currentUserId.equals(user.getId())) {
visibilities.add(Visibility.PRIVATE);
}
}
profileFields.addAll(
userProfileFieldManager.getAllByTargetAndVisibilities(user.getId(), visibilities));
if (profileFields.isEmpty()) {
throttleForbidden();
}
List<String> aliases = Lists.newArrayList();
for (UserAlias userAlias : userAliasManager.getAllByTarget(user.getId())) {
switch (userAlias.getVisibility()) {
case PRIVATE:
if (currentUserId != null && currentUserId.equals(user.getId())) {
aliases.add(userAlias.getAlias());
}
break;
case PROTECTED:
if (currentUserId != null) {
aliases.add(userAlias.getAlias());
}
break;
case PUBLIC:
aliases.add(userAlias.getAlias());
break;
}
}
ProfileModel profileModel = new ProfileModel();
profileModel.setUsername(user.getUsername());
profileModel.setProfileFields(profileFields);
profileModel.setAliases(aliases);
return profileModel;
}
/**
*
* @return
*/
@GetMapping("/{username}/field/{name}")
public UserProfileField getFieldForUser(@PathVariable("username") String username,
@PathVariable("name") String name) {
User user = userManager.getByUsername(username);
if (user == null) {
throttleForbidden();
}
UserProfileField userProfileField = userProfileFieldManager.get(user.getId(), name);
if (userProfileField == null) {
throttleForbidden();
}
Long currentUserId = getCurrentUserId();
if (currentUserId == null && !Visibility.PUBLIC.equals(userProfileField.getVisibility())) {
throttleForbidden();
}
if (currentUserId != null && !currentUserId.equals(user.getId())
&& Visibility.PRIVATE.equals(userProfileField.getVisibility())) {
throttleForbidden();
}
return userProfileField;
}
/**
*
* @param userProfileField
* @return
*/
@PreAuthorize("isAuthenticated()")
@PostMapping
public UserProfileField createOrupdate(@RequestBody UserProfileField userProfileField) {
UserProfileField oldUserProfileField = userProfileFieldManager.get(getCurrentUserId(),
userProfileField.getName());
userProfileField.setTarget(getCurrentUserId());
Errors errors = new RequestBodyErrors(userProfileField);
userProfileFieldModelValidator.validate(userProfileField, errors);
if (errors.hasErrors()) {
throw new EntityResponseStatusException(errors.getAllErrors(), HttpStatus.CONFLICT);
}
if (oldUserProfileField == null) {
if (userProfileField.getType() == null) {
userProfileField.setType(ProfileFieldType.TEXT);
}
if (userProfileField.getVisibility() == null) {
userProfileField.setVisibility(Visibility.PRIVATE);
}
return userProfileFieldManager.save(userProfileField);
} else {
oldUserProfileField.setValue(userProfileField.getValue());
oldUserProfileField.setBlob(userProfileField.getBlob());
if (userProfileField.getType() != null) {
oldUserProfileField.setType(userProfileField.getType());
}
if (userProfileField.getVisibility() != null) {
oldUserProfileField.setVisibility(userProfileField.getVisibility());
}
if (userProfileField.getIndex() != null) {
oldUserProfileField.setIndex(userProfileField.getIndex());
}
return userProfileFieldManager.save(oldUserProfileField);
}
}
/**
*
* @param name
*/
@PreAuthorize("isAuthenticated()")
@DeleteMapping("/{name}")
public void delete(@PathVariable("name") String name) {
if (userProfileFieldManager.get(getCurrentUserId(), name) == null) {
throw new EntityResponseStatusException(HttpStatus.NOT_MODIFIED);
}
userProfileFieldManager.delete(getCurrentUserId(), name);
}
/**
*
*/
protected void throttleForbidden() {
try {
Thread.sleep(RandomUtils.nextInt(10, 500));
} catch (InterruptedException e) {
throw new EntityResponseStatusException(HttpStatus.FORBIDDEN);
}
throw new EntityResponseStatusException(HttpStatus.FORBIDDEN);
}
}

View File

@ -0,0 +1,75 @@
/**
*
*/
package de.bstly.we.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import de.bstly.we.businesslogic.PermissionManager;
import de.bstly.we.businesslogic.PretixManager;
import de.bstly.we.businesslogic.QuotaManager;
import de.bstly.we.businesslogic.Quotas;
import de.bstly.we.controller.support.EntityResponseStatusException;
import de.bstly.we.model.Quota;
/**
*
* @author _bastler@bstly.de
*
*/
@RestController
@RequestMapping("/vouchers")
public class VoucherController extends BaseController {
@Autowired
private QuotaManager quotaManager;
@Autowired
private PretixManager pretixManager;
@Autowired
private PermissionManager permissionManager;
/**
*
* @return
*/
@PreAuthorize("isAuthenticated()")
@PostMapping("/registration")
public String getRegistrationVoucher() {
Quota registrationVouchers = quotaManager.get(getCurrentUserId(),
Quotas.REGISTRATION_VOUCHERS);
if (registrationVouchers == null || registrationVouchers.getValue() < 1) {
throw new EntityResponseStatusException(HttpStatus.CONFLICT);
}
if (!permissionManager.isFullUser(getCurrentUserId())) {
throw new EntityResponseStatusException(HttpStatus.FORBIDDEN);
}
String result = pretixManager.createRegistrationVoucher().get("code").getAsString();
registrationVouchers.setValue(registrationVouchers.getValue() - 1);
quotaManager.update(registrationVouchers);
return result;
}
/**
*
* @return
*/
@PreAuthorize("isAuthenticated()")
@PostMapping("/addon")
public String getAddonVoucher() {
if (!permissionManager.isFullUser(getCurrentUserId())) {
throw new EntityResponseStatusException(HttpStatus.FORBIDDEN);
}
return pretixManager.createAddOnVoucher().get("code").getAsString();
}
}

View File

@ -0,0 +1,64 @@
/**
*
*/
package de.bstly.we.controller.debug;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.session.FindByIndexNameSessionRepository;
import org.springframework.session.Session;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import de.bstly.we.controller.BaseController;
import de.bstly.we.model.User;
import de.bstly.we.repository.UserRepository;
/**
* @author _bastler@bstly.de
*
*/
@RestController
@RequestMapping("/migration")
public class MigrationController extends BaseController {
@Autowired
private UserRepository userRepository;
@Autowired
private FindByIndexNameSessionRepository<? extends Session> sessionRepository;
/**
*
*/
@PreAuthorize("hasRole('ROLE_ADMIN')")
@DeleteMapping("/sessions")
public void deleteAllSessions() {
Pageable pageable = PageRequest.of(0, 100, Sort.by("id"));
Page<User> page;
do {
page = userRepository.findAll(pageable);
for (User user : page.getContent()) {
try {
Map<String, ? extends Session> usersSessions = sessionRepository
.findByPrincipalName(user.getUsername());
for (Session session : usersSessions.values()) {
sessionRepository.deleteById(session.getId());
}
} catch (Exception e) {
e.printStackTrace();
}
}
pageable = page.nextPageable();
} while (page.hasNext());
}
}

View File

@ -0,0 +1,45 @@
/**
*
*/
package de.bstly.we.controller.model;
import java.util.Map;
/**
* @author _bastler@bstly.de
*
*/
public class ItemModel {
private Map<String, String> name;
private String secret;
/**
* @return the name
*/
public Map<String, String> getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName(Map<String, String> name) {
this.name = name;
}
/**
* @return the secret
*/
public String getSecret() {
return secret;
}
/**
* @param secret the secret to set
*/
public void setSecret(String secret) {
this.secret = secret;
}
}

View File

@ -0,0 +1,48 @@
/**
*
*/
package de.bstly.we.controller.model;
import java.util.List;
import de.bstly.we.model.PermissionMapping;
import de.bstly.we.model.QuotaMapping;
/**
* @author _bastler@bstly.de
*
*/
public class ItemResultModel {
private List<PermissionMapping> permissionMappings;
private List<QuotaMapping> quotaMappings;
/**
* @return the permissionMappings
*/
public List<PermissionMapping> getPermissionMappings() {
return permissionMappings;
}
/**
* @param permissionMappings the permissionMappings to set
*/
public void setPermissionMappings(List<PermissionMapping> permissionMappings) {
this.permissionMappings = permissionMappings;
}
/**
* @return the quotaMappings
*/
public List<QuotaMapping> getQuotaMappings() {
return quotaMappings;
}
/**
* @param quotaMappings the quotaMappings to set
*/
public void setQuotaMappings(List<QuotaMapping> quotaMappings) {
this.quotaMappings = quotaMappings;
}
}

View File

@ -0,0 +1,44 @@
/**
*
*/
package de.bstly.we.controller.model;
/**
*
* @author _bastler@bstly.de
*
*/
public class LoginModel {
private String username;
private String password;
/**
* @return the username
*/
public String getUsername() {
return username;
}
/**
* @param username the username to set
*/
public void setUsername(String username) {
this.username = username;
}
/**
* @return the password
*/
public String getPassword() {
return password;
}
/**
* @param password the password to set
*/
public void setPassword(String password) {
this.password = password;
}
}

View File

@ -0,0 +1,90 @@
/**
*
*/
package de.bstly.we.controller.model;
import java.util.List;
/**
* @author _bastler@bstly.de
*
*/
public class PagesResult<T extends Object> {
private List<T> result;
private int size;
private int page;
private int totalElements;
private int totalPages;
/**
* @return the result
*/
public List<T> getResult() {
return result;
}
/**
* @param result the result to set
*/
public void setResult(List<T> result) {
this.result = result;
}
/**
* @return the size
*/
public int getSize() {
return size;
}
/**
* @param size the size to set
*/
public void setSize(int size) {
this.size = size;
}
/**
* @return the page
*/
public int getPage() {
return page;
}
/**
* @param page the page to set
*/
public void setPage(int page) {
this.page = page;
}
/**
* @return the totalElements
*/
public int getTotalElements() {
return totalElements;
}
/**
* @param totalElements the totalElements to set
*/
public void setTotalElements(int totalElements) {
this.totalElements = totalElements;
}
/**
* @return the totalPages
*/
public int getTotalPages() {
return totalPages;
}
/**
* @param totalPages the totalPages to set
*/
public void setTotalPages(int totalPages) {
this.totalPages = totalPages;
}
}

View File

@ -0,0 +1,58 @@
/**
*
*/
package de.bstly.we.controller.model;
/**
*
* @author _bastler@bstly.de
*
*/
public class PasswordModel {
private String old;
private String password;
private String password2;
/**
* @return the old
*/
public String getOld() {
return old;
}
/**
* @param old the old to set
*/
public void setOld(String old) {
this.old = old;
}
/**
* @return the password
*/
public String getPassword() {
return password;
}
/**
* @param password the password to set
*/
public void setPassword(String password) {
this.password = password;
}
/**
* @return the password2
*/
public String getPassword2() {
return password2;
}
/**
* @param password2 the password2 to set
*/
public void setPassword2(String password2) {
this.password2 = password2;
}
}

View File

@ -0,0 +1,28 @@
/**
*
*/
package de.bstly.we.controller.model;
/**
* @author _bastler@bstly.de
*
*/
public class PasswordResetModel extends PasswordModel {
private String token;
/**
* @return the token
*/
public String getToken() {
return token;
}
/**
* @param token the token to set
*/
public void setToken(String token) {
this.token = token;
}
}

View File

@ -0,0 +1,78 @@
/**
*
*/
package de.bstly.we.controller.model;
import java.util.Map;
import org.springframework.http.HttpMethod;
/**
*
* @author _bastler@bstly.de
*
*/
public class PretixRequest {
private String path;
private HttpMethod method;
private Map<String, String> queryParameters;
private Object payload;
/**
* @return the path
*/
public String getPath() {
return path;
}
/**
* @param path the path to set
*/
public void setPath(String path) {
this.path = path;
}
/**
* @return the method
*/
public HttpMethod getMethod() {
return method;
}
/**
* @param method the method to set
*/
public void setMethod(HttpMethod method) {
this.method = method;
}
/**
* @return the queryParameters
*/
public Map<String, String> getQueryParameters() {
return queryParameters;
}
/**
* @param queryParameters the queryParameters to set
*/
public void setQueryParameters(Map<String, String> queryParameters) {
this.queryParameters = queryParameters;
}
/**
* @return the payload
*/
public Object getPayload() {
return payload;
}
/**
* @param payload the payload to set
*/
public void setPayload(Object payload) {
this.payload = payload;
}
}

View File

@ -0,0 +1,62 @@
/**
*
*/
package de.bstly.we.controller.model;
import java.util.List;
import de.bstly.we.model.UserProfileField;
/**
* @author _bastler@bstly.de
*
*/
public class ProfileModel {
private String username;
private List<String> aliases;
private List<UserProfileField> profileFields;
/**
* @return the username
*/
public String getUsername() {
return username;
}
/**
* @param username the username to set
*/
public void setUsername(String username) {
this.username = username;
}
/**
* @return the aliases
*/
public List<String> getAliases() {
return aliases;
}
/**
* @param aliases the aliases to set
*/
public void setAliases(List<String> aliases) {
this.aliases = aliases;
}
/**
* @return the profileFields
*/
public List<UserProfileField> getProfileFields() {
return profileFields;
}
/**
* @param profileFields the profileFields to set
*/
public void setProfileFields(List<UserProfileField> profileFields) {
this.profileFields = profileFields;
}
}

View File

@ -0,0 +1,53 @@
/**
*
*/
package de.bstly.we.controller.model;
/**
* @author _bastler@bstly.de
*
*/
public class SecondFactorProviderModel {
private String id;
private boolean request;
/**
* @param provider
* @param request
*/
public SecondFactorProviderModel(String id, boolean request) {
super();
this.id = id;
this.request = request;
}
/**
* @return the id
*/
public String getId() {
return id;
}
/**
* @param id the id to set
*/
public void setId(String id) {
this.id = id;
}
/**
* @return the request
*/
public boolean isRequest() {
return request;
}
/**
* @param request the request to set
*/
public void setRequest(boolean request) {
this.request = request;
}
}

View File

@ -0,0 +1,143 @@
/**
*
*/
package de.bstly.we.controller.model;
import java.util.List;
import de.bstly.we.model.Permission;
import de.bstly.we.model.PermissionMapping;
import de.bstly.we.model.Quota;
import de.bstly.we.model.QuotaMapping;
import de.bstly.we.model.UserProfileField;
import de.bstly.we.model.UserStatus;
/**
*
* @author _bastler@bstly.de
*
*/
public class UserModel extends PasswordModel {
private String username;
private List<Permission> permissions;
private List<PermissionMapping> permissionMappings;
private List<Quota> quotas;
private List<QuotaMapping> quotaMappings;
private UserStatus status;
private String token;
private List<UserProfileField> profileFields;
/**
* @return the username
*/
public String getUsername() {
return username;
}
/**
* @param username the username to set
*/
public void setUsername(String username) {
this.username = username;
}
/**
* @return the permissions
*/
public List<Permission> getPermissions() {
return permissions;
}
/**
* @param permissions the permissions to set
*/
public void setPermissions(List<Permission> permissions) {
this.permissions = permissions;
}
/**
* @return the permissionMappings
*/
public List<PermissionMapping> getPermissionMappings() {
return permissionMappings;
}
/**
* @param permissionMappings the permissionMappings to set
*/
public void setPermissionMappings(List<PermissionMapping> permissionMappings) {
this.permissionMappings = permissionMappings;
}
/**
* @return the quotas
*/
public List<Quota> getQuotas() {
return quotas;
}
/**
* @param quotas the quotas to set
*/
public void setQuotas(List<Quota> quotas) {
this.quotas = quotas;
}
/**
* @return the quotaMappings
*/
public List<QuotaMapping> getQuotaMappings() {
return quotaMappings;
}
/**
* @param quotaMappings the quotaMappings to set
*/
public void setQuotaMappings(List<QuotaMapping> quotaMappings) {
this.quotaMappings = quotaMappings;
}
/**
* @return the status
*/
public UserStatus getStatus() {
return status;
}
/**
* @param status the status to set
*/
public void setStatus(UserStatus status) {
this.status = status;
}
/**
* @return the token
*/
public String getToken() {
return token;
}
/**
* @param token the token to set
*/
public void setToken(String token) {
this.token = token;
}
/**
* @return the profileFields
*/
public List<UserProfileField> getProfileFields() {
return profileFields;
}
/**
* @param profileFields the profileFields to set
*/
public void setProfileFields(List<UserProfileField> profileFields) {
this.profileFields = profileFields;
}
}

View File

@ -0,0 +1,47 @@
/**
*
*/
package de.bstly.we.controller.support;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
/**
*
* @author _bastler@bstly.de
*
*/
@ControllerAdvice
public class ControllerExceptionHandler extends ResponseEntityExceptionHandler {
/**
*
* @param exception
* @param request
* @return
*/
@ExceptionHandler(value = { EntityResponseStatusException.class })
protected ResponseEntity<Object> handleResponseEntityStatusException(RuntimeException exception,
WebRequest request) {
EntityResponseStatusException entityResponseStatusException = (EntityResponseStatusException) exception;
return handleExceptionInternal(exception, entityResponseStatusException.getBody(), new HttpHeaders(),
entityResponseStatusException.getStatus(), request);
}
// /**
// *
// * @param exception
// * @param request
// * @return
// */
// @ExceptionHandler(value = { IllegalArgumentException.class })
// protected ResponseEntity<Object> handleRIllegalArgumentException(RuntimeException exception, WebRequest request) {
// IllegalArgumentException illegalArgumentException = (IllegalArgumentException) exception;
// return handleExceptionInternal(exception, illegalArgumentException.getMessage(), new HttpHeaders(),
// HttpStatus.BAD_REQUEST, request);
// }
}

View File

@ -0,0 +1,87 @@
/**
*
*/
package de.bstly.we.controller.support;
import javax.annotation.Nullable;
import org.springframework.core.NestedExceptionUtils;
import org.springframework.core.NestedRuntimeException;
import org.springframework.http.HttpStatus;
import org.springframework.util.Assert;
/**
*
* @author _bastler@bstly.de
*
*/
public class EntityResponseStatusException extends NestedRuntimeException {
/**
* default serialVersionUID
*/
private static final long serialVersionUID = 1L;
private final HttpStatus status;
@Nullable
private final Object body;
/**
*
* @param status
*/
public EntityResponseStatusException(HttpStatus status) {
this(null, status);
}
/**
*
* @param body
* @param status
*/
public EntityResponseStatusException(@Nullable Object body, HttpStatus status) {
this(body, status, null);
}
/**
*
* @param body
* @param status
* @param cause
*/
public EntityResponseStatusException(@Nullable Object body, HttpStatus status, @Nullable Throwable cause) {
super(null, cause);
Assert.notNull(status, "HttpStatus is required");
this.status = status;
this.body = body;
}
/**
*
* @return
*/
public HttpStatus getStatus() {
return this.status;
}
/**
*
* @return
*/
@Nullable
public Object getBody() {
return this.body;
}
/**
*
* @return
*/
@Override
public String getMessage() {
String msg = this.status + (this.body != null ? " \"" + this.body + "\"" : "");
return NestedExceptionUtils.buildMessage(msg, getCause());
}
}

View File

@ -0,0 +1,107 @@
/**
*
*/
package de.bstly.we.controller.support;
import java.io.IOException;
import java.lang.reflect.Type;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
import com.google.gson.Gson;
import com.google.gson.JsonPrimitive;
/**
* @author _bastler@bstly.de
*
*/
@ControllerAdvice
public class JsonStringBodyControllerAdvice implements RequestBodyAdvice, ResponseBodyAdvice<String> {
private Gson gson = new Gson();
/*
* @see org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdvice#
* supports(org.springframework.core.MethodParameter, java.lang.reflect.Type,
* java.lang.Class)
*/
@Override
public boolean supports(MethodParameter methodParameter, Type targetType,
Class<? extends HttpMessageConverter<?>> converterType) {
return targetType instanceof Class && String.class.equals((Class<?>) targetType);
}
/*
* @see org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdvice#
* beforeBodyRead(org.springframework.http.HttpInputMessage,
* org.springframework.core.MethodParameter, java.lang.reflect.Type,
* java.lang.Class)
*/
@Override
public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType,
Class<? extends HttpMessageConverter<?>> converterType) throws IOException {
return inputMessage;
}
/*
* @see org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdvice#
* afterBodyRead(java.lang.Object, org.springframework.http.HttpInputMessage,
* org.springframework.core.MethodParameter, java.lang.reflect.Type,
* java.lang.Class)
*/
@Override
public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType,
Class<? extends HttpMessageConverter<?>> converterType) {
body = ((String) body).replaceAll("^\"|\"$", "");
return body;
}
/*
* @see org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdvice#
* handleEmptyBody(java.lang.Object, org.springframework.http.HttpInputMessage,
* org.springframework.core.MethodParameter, java.lang.reflect.Type,
* java.lang.Class)
*/
@Override
public Object handleEmptyBody(Object body, HttpInputMessage inputMessage, MethodParameter parameter,
Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
return body;
}
/*
* @see
* org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice#
* supports(org.springframework.core.MethodParameter, java.lang.Class)
*/
@Override
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
return converterType == StringHttpMessageConverter.class;
}
/*
* @see
* org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice#
* beforeBodyWrite(java.lang.Object, org.springframework.core.MethodParameter,
* org.springframework.http.MediaType, java.lang.Class,
* org.springframework.http.server.ServerHttpRequest,
* org.springframework.http.server.ServerHttpResponse)
*/
@Override
public String beforeBodyWrite(String body, MethodParameter returnType, MediaType selectedContentType,
Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request,
ServerHttpResponse response) {
response.getHeaders().set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
return gson.toJson(new JsonPrimitive(body));
}
}

View File

@ -0,0 +1,49 @@
/**
*
*/
package de.bstly.we.controller.support;
import org.springframework.lang.Nullable;
import org.springframework.validation.AbstractBindingResult;
/**
*
* @author _bastler@bstly.de
*
*/
@SuppressWarnings("serial")
public class RequestBodyErrors extends AbstractBindingResult {
@Nullable
private final Object target;
/**
*
* @param target
* @param objectName
*/
public RequestBodyErrors(@Nullable Object target) {
super("request-body");
this.target = target;
}
/*
* @see org.springframework.validation.AbstractBindingResult#getTarget()
*/
@Override
public Object getTarget() {
return target;
}
/*
* @see
* org.springframework.validation.AbstractBindingResult#getActualFieldValue(java
* .lang.String)
*/
@Override
protected Object getActualFieldValue(String field) {
// Not necessary
return null;
}
}

View File

@ -0,0 +1,277 @@
/**
*
*/
package de.bstly.we.controller.support;
import java.time.Instant;
import java.util.List;
import java.util.Set;
import javax.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.google.gson.JsonObject;
import de.bstly.we.businesslogic.PermissionManager;
import de.bstly.we.businesslogic.PermissionMappingManager;
import de.bstly.we.businesslogic.PretixManager;
import de.bstly.we.businesslogic.QuotaManager;
import de.bstly.we.businesslogic.QuotaMappingManager;
import de.bstly.we.controller.model.ItemResultModel;
import de.bstly.we.model.Permission;
import de.bstly.we.model.PermissionMapping;
import de.bstly.we.model.QuotaMapping;
import de.bstly.we.security.model.LocalUserDetails;
import de.bstly.we.security.token.LocalAnonymousAuthenticationToken;
/**
*
* @author _bastler@bstly.de
*
*/
@Component
public class TokenSessionManager {
public static final String HTTP_SESSION_ATTRIBUTE_TOKENS = "tokens";
@Autowired
private PermissionMappingManager permissionMappingManager;
@Autowired
private PermissionManager permissionManager;
@Autowired
private QuotaMappingManager quotaMappingManager;
@Autowired
private QuotaManager quotaManager;
@Autowired
private PretixManager pretixManager;
/**
*
* @param userId
* @param token
* @return
*/
public List<PermissionMapping> getPermissionMappingsForToken(Long userId, String token) {
List<PermissionMapping> permissionMappings = Lists.newArrayList();
try {
JsonObject result = pretixManager.getCheckInItemBySecret(token);
if (result != null && result.get("secret").getAsString().equals(token)
&& result.getAsJsonArray("checkins").size() < 1
&& "p".equals(result.get("order__status").getAsString())) {
int item = result.get("item").getAsInt();
permissionMappings.addAll(permissionMappingManager.getAllByItem(item));
}
} catch (Exception e) {
// ignore
}
return permissionMappings;
}
/**
*
* @param userId
* @param token
* @return
*/
public List<Permission> getPermissionsForToken(Long userId, String token) {
List<Permission> permissions = Lists.newArrayList();
try {
JsonObject orderPosition = pretixManager.getCheckInItemBySecret(token);
if (orderPosition != null && orderPosition.get("secret").getAsString().equals(token)
&& orderPosition.getAsJsonArray("checkins").size() < 1
&& "p".equals(orderPosition.get("order__status").getAsString())) {
int item = orderPosition.get("item").getAsInt();
Instant lastPaymentDate = pretixManager
.getLastPaymentDateForOrder(orderPosition.get("order").getAsString());
if (lastPaymentDate == null) {
throw new Exception("This should not happen!");
}
permissions.addAll(permissionManager.getForItem(userId, item,
orderPosition.get("answers").getAsJsonArray(), lastPaymentDate));
}
} catch (Exception e) {
// ignore
e.printStackTrace();
}
return permissions;
}
/**
*
* @param userId
* @param token
* @return
*/
public List<QuotaMapping> getQuotaMappingsForToken(Long userId, String token) {
List<QuotaMapping> quotaMappings = Lists.newArrayList();
try {
JsonObject result = pretixManager.getCheckInItemBySecret(token);
if (result != null && result.get("secret").getAsString().equals(token)
&& result.getAsJsonArray("checkins").size() < 1
&& "p".equals(result.get("order__status").getAsString())) {
int item = result.get("item").getAsInt();
quotaMappings.addAll(quotaMappingManager.getAllByItem(item));
}
} catch (Exception e) {
// ignore
}
return quotaMappings;
}
/**
*
* @param userId
* @param tokens
* @return
*/
public ItemResultModel applyTokens(Long userId, Set<String> tokens) {
ItemResultModel itemResultModel = new ItemResultModel();
List<PermissionMapping> permissionMappings = Lists.newArrayList();
List<QuotaMapping> quotaMappings = Lists.newArrayList();
for (String token : tokens) {
try {
JsonObject result = pretixManager.redeem(token);
if ("ok".equals(result.get("status").getAsString())) {
JsonObject position = result.get("position").getAsJsonObject();
int item = position.get("item").getAsInt();
Instant lastPaymentDate = pretixManager
.getLastPaymentDateForOrder(position.get("order").getAsString());
if (lastPaymentDate == null) {
throw new Exception("This should not happen!");
}
permissionManager.applyItem(userId, item,
position.get("answers").getAsJsonArray(), lastPaymentDate);
permissionMappings.addAll(permissionMappingManager.getAllByItem(item));
quotaManager.applyItem(userId, item);
quotaMappings.addAll(quotaMappingManager.getAllByItem(item));
}
} catch (Exception e) {
// ignore
}
}
itemResultModel.setPermissionMappings(permissionMappings);
itemResultModel.setQuotaMappings(quotaMappings);
return itemResultModel;
}
/**
*
* @param session
* @return
*/
public Set<String> getTokenFromSession(HttpSession session) {
Set<String> tokens = Sets.newHashSet();
Object sessionAttribute = session.getAttribute(HTTP_SESSION_ATTRIBUTE_TOKENS);
if (sessionAttribute != null && sessionAttribute instanceof String) {
for (String token : ((String) sessionAttribute).split(",")) {
if (StringUtils.hasText(token)) {
tokens.add(token);
}
}
}
return tokens;
}
/**
*
* @param secret
* @return
*/
public void addTokenToSession(String secret, HttpSession session) {
String tokens = "";
Object sessionAttribute = session.getAttribute(HTTP_SESSION_ATTRIBUTE_TOKENS);
if (sessionAttribute != null && sessionAttribute instanceof String) {
tokens = (String) sessionAttribute;
}
if (StringUtils.hasLength(tokens)) {
tokens += "," + secret;
} else {
tokens = secret;
}
session.setAttribute(HTTP_SESSION_ATTRIBUTE_TOKENS, tokens);
}
/**
*
* @param secret
* @return
*/
public void removeTokenFromSession(String secret, HttpSession session) {
String tokens = "";
Object sessionAttribute = session.getAttribute(HTTP_SESSION_ATTRIBUTE_TOKENS);
if (sessionAttribute != null && sessionAttribute instanceof String) {
for (String token : ((String) sessionAttribute).split(",")) {
if (!token.equals(secret)) {
if (StringUtils.hasLength(tokens)) {
tokens += "," + secret;
} else {
tokens = secret;
}
}
}
}
session.setAttribute(HTTP_SESSION_ATTRIBUTE_TOKENS, tokens);
}
/**
*
* @param secret
* @return
*/
public void removeTokensFromSession(HttpSession session) {
session.setAttribute(HTTP_SESSION_ATTRIBUTE_TOKENS, null);
}
/**
*
* @param auth
* @param details
* @return
*/
protected Authentication createNewAuth(Authentication auth, LocalUserDetails details) {
Authentication newAuth = null;
if (auth instanceof UsernamePasswordAuthenticationToken) {
newAuth = new UsernamePasswordAuthenticationToken(details, auth.getCredentials(),
details.getAuthorities());
} else {
newAuth = new LocalAnonymousAuthenticationToken(details);
}
if (!auth.isAuthenticated()) {
newAuth.setAuthenticated(false);
}
return newAuth;
}
}

View File

@ -0,0 +1,101 @@
/**
*
*/
package de.bstly.we.controller.validation;
import java.util.ArrayList;
import java.util.List;
import org.passay.CharacterRule;
import org.passay.EnglishCharacterData;
import org.passay.LengthRule;
import org.passay.PasswordData;
import org.passay.PasswordValidator;
import org.passay.Rule;
import org.passay.RuleResult;
import org.passay.RuleResultDetail;
import org.passay.WhitespaceRule;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
import de.bstly.we.businesslogic.SystemPropertyManager;
import de.bstly.we.controller.model.PasswordModel;
/**
*
* @author _bastler@bstly.de
*
*/
@Component
public class PasswordModelValidator implements Validator {
@Autowired
private SystemPropertyManager systemPropertyManager;
public static final String SYSTEM_PROPERTY_PASSWORD_RULE_WHITESPACE = "password.rule.whitespace";
public static final String SYSTEM_PROPERTY_PASSWORD_RULE_LENGTH = "password.rule.length";
public static final String SYSTEM_PROPERTY_PASSWORD_RULE_UPPERCASE = "password.rule.uppercase";
public static final String SYSTEM_PROPERTY_PASSWORD_RULE_DIGIT = "password.rule.digit";
public static final String SYSTEM_PROPERTY_PASSWORD_RULE_SPECIAL = "password.rule.special";
/*
* @see org.springframework.validation.Validator#supports(java.lang.Class)
*/
@Override
public boolean supports(Class<?> clazz) {
return clazz.isAssignableFrom(PasswordModel.class);
}
/*
*
* @see org.springframework.validation.Validator#validate(java.lang.Object,
* org.springframework.validation.Errors)
*/
@Override
public void validate(Object target, Errors errors) {
PasswordModel passwordModel = (PasswordModel) target;
List<Rule> rules = new ArrayList<Rule>();
if (systemPropertyManager.getBoolean(SYSTEM_PROPERTY_PASSWORD_RULE_WHITESPACE, true)) {
rules.add(new WhitespaceRule());
}
int length = systemPropertyManager.getInteger(SYSTEM_PROPERTY_PASSWORD_RULE_LENGTH, 8);
if (length > 0) {
rules.add(new LengthRule(length, 4096));
}
int uppercase = systemPropertyManager.getInteger(SYSTEM_PROPERTY_PASSWORD_RULE_UPPERCASE, 1);
if (uppercase > 0) {
rules.add(new CharacterRule(EnglishCharacterData.UpperCase, uppercase));
}
int digit = systemPropertyManager.getInteger(SYSTEM_PROPERTY_PASSWORD_RULE_DIGIT, 1);
if (digit > 0) {
rules.add(new CharacterRule(EnglishCharacterData.Digit, digit));
}
int special = systemPropertyManager.getInteger(SYSTEM_PROPERTY_PASSWORD_RULE_SPECIAL, 1);
if (special > 0) {
rules.add(new CharacterRule(EnglishCharacterData.Special, special));
}
PasswordValidator validator = new PasswordValidator(rules);
PasswordData password = new PasswordData(passwordModel.getPassword());
RuleResult result = validator.validate(password);
if (!result.isValid()) {
for (RuleResultDetail ruleResultDetail : result.getDetails()) {
errors.rejectValue("password", ruleResultDetail.getErrorCode());
}
}
if (!passwordModel.getPassword().equals(passwordModel.getPassword2())) {
errors.rejectValue("password2", "NOT_MATCH");
}
}
}

View File

@ -0,0 +1,53 @@
/**
*
*/
package de.bstly.we.controller.validation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
import de.bstly.we.businesslogic.PermissionMappingManager;
import de.bstly.we.model.PermissionMapping;
/**
*
* @author _bastler@bstly.de
*
*/
@Component
public class PermissionMappingValidator implements Validator {
@Autowired
private PermissionMappingManager permissionMappingManager;
/*
* @see org.springframework.validation.Validator#supports(java.lang.Class)
*/
@Override
public boolean supports(Class<?> clazz) {
return clazz.isAssignableFrom(PermissionMapping.class);
}
/*
*
* @see org.springframework.validation.Validator#validate(java.lang.Object,
* org.springframework.validation.Errors)
*/
@Override
public void validate(Object target, Errors errors) {
PermissionMapping permissionMapping = (PermissionMapping) target;
for (String name : permissionMapping.getNames())
if (permissionMappingManager.exists(permissionMapping.getItem(), name)) {
errors.rejectValue("item", "ALREADY_EXISTS");
errors.rejectValue("names." + name, "ALREADY_EXISTS");
}
if (permissionMapping.getLifetime() <= 0) {
errors.rejectValue("lifetime", "TOO_SHORT");
}
}
}

View File

@ -0,0 +1,54 @@
/**
*
*/
package de.bstly.we.controller.validation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
import de.bstly.we.businesslogic.QuotaMappingManager;
import de.bstly.we.model.QuotaMapping;
/**
*
* @author _bastler@bstly.de
*
*/
@Component
public class QuotaMappingValidator implements Validator {
@Autowired
private QuotaMappingManager quotaMappingManager;
/*
* @see org.springframework.validation.Validator#supports(java.lang.Class)
*/
@Override
public boolean supports(Class<?> clazz) {
return clazz.isAssignableFrom(QuotaMapping.class);
}
/*
*
* @see org.springframework.validation.Validator#validate(java.lang.Object,
* org.springframework.validation.Errors)
*/
@Override
public void validate(Object target, Errors errors) {
QuotaMapping quotaMapping = (QuotaMapping) target;
for (Integer item : quotaMapping.getItems()) {
if (quotaMappingManager.exists(item, quotaMapping.getName())) {
errors.rejectValue("item", "ALREADY_EXISTS");
errors.rejectValue("name", "ALREADY_EXISTS");
}
}
if (quotaMapping.getValue() <= 0) {
errors.rejectValue("value", "TOO_SHORT");
}
}
}

View File

@ -0,0 +1,59 @@
/**
*
*/
package de.bstly.we.controller.validation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
import de.bstly.we.model.UserAlias;
/**
* @author _bastler@bstly.de
*
*/
@Component
public class UserAliasValidator implements Validator {
@Autowired
private UserModelValidator userModelValidator;
/*
* @see org.springframework.validation.Validator#supports(java.lang.Class)
*/
@Override
public boolean supports(Class<?> clazz) {
return clazz.isAssignableFrom(UserAlias.class);
}
/*
* @see org.springframework.validation.Validator#validate(java.lang.Object,
* org.springframework.validation.Errors)
*/
@Override
public void validate(Object target, Errors errors) {
UserAlias userAlias = (UserAlias) target;
if (!StringUtils.hasText(userAlias.getAlias())) {
errors.rejectValue("alias", "REQUIRED");
return;
}
if (userAlias.getTarget() == null) {
errors.rejectValue("target", "REQUIRED");
return;
}
if (userAlias.getVisibility() == null) {
errors.rejectValue("visibility", "REQUIRED");
return;
}
userModelValidator.validateUsername(userAlias.getAlias(), "alias", errors);
}
}

View File

@ -0,0 +1,73 @@
/**
*
*/
package de.bstly.we.controller.validation;
import org.apache.commons.validator.routines.DomainValidator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
import de.bstly.we.businesslogic.UserDomainManager;
import de.bstly.we.model.UserDomain;
/**
* @author _bastler@bstly.de
*
*/
@Component
public class UserDomainValidator implements Validator {
private DomainValidator domainValidator = DomainValidator.getInstance();
@Autowired
private UserDomainManager userDomainManager;
/*
* @see org.springframework.validation.Validator#supports(java.lang.Class)
*/
@Override
public boolean supports(Class<?> clazz) {
return clazz.isAssignableFrom(UserDomain.class);
}
/*
* @see org.springframework.validation.Validator#validate(java.lang.Object,
* org.springframework.validation.Errors)
*/
@Override
public void validate(Object target, Errors errors) {
UserDomain userDomain = (UserDomain) target;
if (!StringUtils.hasText(userDomain.getDomain())) {
errors.rejectValue("domain", "REQUIRED");
return;
}
if (!domainValidator.isValid(userDomain.getDomain())) {
errors.rejectValue("domain", "NOT_VALID");
return;
}
UserDomain existingDomain = userDomainManager.getByDomain(userDomain.getDomain());
if (existingDomain != null && (userDomain.getId() == null
|| !(existingDomain.getId().equals(userDomain.getId())))) {
errors.rejectValue("domain", "NOT_VALID");
return;
}
if (userDomain.getTarget() == null) {
errors.rejectValue("target", "REQUIRED");
return;
}
if (userDomain.getVisibility() == null) {
errors.rejectValue("visibility", "REQUIRED");
return;
}
}
}

View File

@ -0,0 +1,91 @@
/**
*
*/
package de.bstly.we.controller.validation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
import de.bstly.we.businesslogic.SystemPropertyManager;
import de.bstly.we.businesslogic.UserAliasManager;
import de.bstly.we.businesslogic.UserManager;
import de.bstly.we.controller.model.UserModel;
/**
*
* @author _bastler@bstly.de
*
*/
@Component
public class UserModelValidator implements Validator {
public static final String RESERVED_USERNAMES = "usernames.reserved";
protected static final String localPart = "^[a-zA-Z0-9_!#$%&'*+/=?`{|}~^-]+(?:\\\\.[A-Z0-9_!#$%&'*+/=?`{|}~^-]+)*$";
@Autowired
private UserManager userManager;
@Autowired
private UserAliasManager userAliasManager;
@Autowired
private SystemPropertyManager systemPropertyManager;
/*
* @see org.springframework.validation.Validator#supports(java.lang.Class)
*/
@Override
public boolean supports(Class<?> clazz) {
return clazz.isAssignableFrom(UserModel.class);
}
/*
*
* @see org.springframework.validation.Validator#validate(java.lang.Object,
* org.springframework.validation.Errors)
*/
@Override
public void validate(Object target, Errors errors) {
UserModel userModel = (UserModel) target;
if (!StringUtils.hasText(userModel.getUsername())) {
errors.rejectValue("username", "REQUIRED");
return;
}
validateUsername(userModel.getUsername(), "username", errors);
}
/**
*
* @param username
* @param field
* @param errors
*/
public void validateUsername(String username, String field, Errors errors) {
for (String systemUsername : systemPropertyManager.get(RESERVED_USERNAMES, "").split(",")) {
if (StringUtils.hasText(systemUsername)
&& (username.toLowerCase().equals(systemUsername)
|| username.toLowerCase().matches(systemUsername))) {
errors.rejectValue(field, "NOT_VALID");
break;
}
}
if (userManager.getByUsername(username) != null) {
errors.rejectValue(field, "NOT_VALID");
return;
}
if (userAliasManager.getByAlias(username) != null) {
errors.rejectValue(field, "NOT_VALID");
return;
}
if (!username.matches(localPart)) {
errors.rejectValue(field, "NOT_VALID");
}
}
}

View File

@ -0,0 +1,157 @@
/**
*
*/
package de.bstly.we.controller.validation;
import java.time.Instant;
import java.time.format.DateTimeParseException;
import java.util.List;
import org.apache.commons.validator.routines.DoubleValidator;
import org.apache.commons.validator.routines.EmailValidator;
import org.apache.commons.validator.routines.UrlValidator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
import com.google.common.collect.Lists;
import com.querydsl.core.BooleanBuilder;
import de.bstly.we.businesslogic.SystemProfileFieldManager;
import de.bstly.we.model.ProfileFieldType;
import de.bstly.we.model.QUserProfileField;
import de.bstly.we.model.SystemProfileField;
import de.bstly.we.model.UserProfileField;
import de.bstly.we.repository.UserProfileFieldRepository;
/**
* @author _bastler@bstly.de
*
*/
@Component
public class UserProfileFieldValidator implements Validator {
@Autowired
private SystemProfileFieldManager systemProfileFieldManager;
@Autowired
private UserProfileFieldRepository userProfileFieldRepository;
private QUserProfileField qUserProfileField = QUserProfileField.userProfileField;
private DoubleValidator doubleValidator = DoubleValidator.getInstance();
private EmailValidator emailValidator = EmailValidator.getInstance();
private UrlValidator urlValidator = new UrlValidator(UrlValidator.ALLOW_ALL_SCHEMES);
private List<String> validBoolean = Lists.newArrayList("true", "True", "TRUE", "1", "false",
"False", "FALSE", "0");
/*
* @see org.springframework.validation.Validator#supports(java.lang.Class)
*/
@Override
public boolean supports(Class<?> clazz) {
return clazz.isAssignableFrom(UserProfileField.class);
}
/*
* @see org.springframework.validation.Validator#validate(java.lang.Object,
* org.springframework.validation.Errors)
*/
@Override
public void validate(Object target, Errors errors) {
UserProfileField userProfileField = (UserProfileField) target;
if (userProfileField.getName() == null || userProfileField.getName().length() < 3) {
errors.rejectValue("name", "TOO_SHORT");
} else if (userProfileField.getName().length() > 255) {
errors.rejectValue("name", "TOO_LONG");
}
SystemProfileField systemProfileField = systemProfileFieldManager
.get(userProfileField.getName());
if (systemProfileField != null) {
if (!systemProfileField.getType().equals(userProfileField.getType())) {
errors.rejectValue("type", "INVALID_TYPE", userProfileField.getName());
return;
}
if (systemProfileField.isUniqueValue()) {
BooleanBuilder builder = new BooleanBuilder();
builder.and(qUserProfileField.name.eq(userProfileField.getName()));
if (userProfileField.getTarget() != null) {
builder.and(qUserProfileField.target.ne(userProfileField.getTarget()));
}
if (ProfileFieldType.BLOB.equals(userProfileField.getType())) {
if (userProfileField.getBlob() == null) {
errors.rejectValue("blob", "NOT_SPECIFIED", userProfileField.getName());
return;
}
builder.and(qUserProfileField.blob.eq(userProfileField.getBlob()));
} else if (userProfileField.getValue() == null) {
errors.rejectValue("value", "NOT_SPECIFIED", userProfileField.getName());
} else {
builder.and(qUserProfileField.value.eq(userProfileField.getValue()));
}
if (userProfileFieldRepository.exists(builder.getValue())) {
errors.rejectValue("value", "NOT_VALID", userProfileField.getName());
return;
}
}
}
switch (userProfileField.getType()) {
case BOOL:
if (!validBoolean.contains(userProfileField.getValue())) {
errors.rejectValue("value", "INVALID_BOOLEAN", userProfileField.getName());
}
break;
case DATE:
try {
Instant.parse(userProfileField.getValue());
} catch (DateTimeParseException e) {
errors.rejectValue("value", "INVALID_DATE", userProfileField.getName());
}
break;
case DATETIME:
try {
Instant.parse(userProfileField.getValue());
} catch (DateTimeParseException e) {
errors.rejectValue("value", "INVALID_DATE", userProfileField.getName());
}
break;
case TIME:
try {
Instant.parse(userProfileField.getValue());
} catch (DateTimeParseException e) {
errors.rejectValue("value", "INVALID_DATE", userProfileField.getName());
}
break;
case EMAIL:
if (!emailValidator.isValid(userProfileField.getValue())) {
errors.rejectValue("value", "INVALID_EMAIL", userProfileField.getName());
}
break;
case NUMBER:
if (!doubleValidator.isValid(userProfileField.getValue())) {
errors.rejectValue("value", "INVALID_NUMBER", userProfileField.getName());
}
break;
case TEXT:
if (userProfileField.getValue() != null && userProfileField.getValue().length() > 255) {
errors.rejectValue("value", "TOO_LONG", userProfileField.getName());
}
break;
case URL:
if (!urlValidator.isValid(userProfileField.getValue())) {
errors.rejectValue("value", "INVALID_URL", userProfileField.getName());
}
break;
case BLOB:
break;
}
}
}

View File

@ -0,0 +1,63 @@
/**
*
*/
package de.bstly.we.event;
import org.springframework.context.ApplicationEvent;
import de.bstly.we.model.AbstractModel;
/**
* @author Lurkars
*
*/
public class AbstractModelEvent extends ApplicationEvent {
/**
* default serialVersionUID
*/
private static final long serialVersionUID = 1L;
private AbstractModelEventType type;
private AbstractModel model;
/**
*
* @param type
* @param model
*/
public AbstractModelEvent(AbstractModelEventType type, AbstractModel model) {
super(model);
this.type = type;
this.model = model;
}
/**
* @return the type
*/
public AbstractModelEventType getType() {
return type;
}
/**
* @param type the type to set
*/
public void setType(AbstractModelEventType type) {
this.type = type;
}
/**
* @return the model
*/
public AbstractModel getModel() {
return model;
}
/**
* @param model the model to set
*/
public void setModel(AbstractModel model) {
this.model = model;
}
}

View File

@ -0,0 +1,14 @@
/**
*
*/
package de.bstly.we.event;
/**
* @author Lurkars
*
*/
public enum AbstractModelEventType {
PRE_PERSIST, PRE_UPDATE, PRE_REMOVE, POST_PERSIST, POST_UPDATE, POST_REMOVE, POST_LOAD
}

View File

@ -0,0 +1,12 @@
/**
*
*/
package de.bstly.we.model;
/**
* @author Lurkars
*
*/
public interface AbstractModel {
}

View File

@ -0,0 +1,123 @@
/**
*
*/
package de.bstly.we.model;
import java.time.Instant;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
/**
*
* @author _bastler@bstly.de
*
*/
@Entity
@Table(name = "permissions")
public class Permission implements UserData {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;
@Column(name = "name", nullable = false)
private String name;
@Column(name = "target", nullable = false)
private Long target;
@Column(name = "addon", columnDefinition = "boolean default false")
private boolean addon;
@Column(name = "starts", nullable = true)
private Instant starts;
@Column(name = "expires")
private Instant expires;
/**
* @return the id
*/
public Long getId() {
return id;
}
/**
* @param id the id to set
*/
public void setId(Long id) {
this.id = id;
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @return the target
*/
public Long getTarget() {
return target;
}
/**
* @param target the target to set
*/
public void setTarget(Long target) {
this.target = target;
}
/**
* @return the addon
*/
public boolean isAddon() {
return addon;
}
/**
* @param addon the addon to set
*/
public void setAddon(boolean addon) {
this.addon = addon;
}
/**
* @return the starts
*/
public Instant getStarts() {
return starts;
}
/**
* @param starts the starts to set
*/
public void setStarts(Instant starts) {
this.starts = starts;
}
/**
* @return the expires
*/
public Instant getExpires() {
return expires;
}
/**
* @param expires the expires to set
*/
public void setExpires(Instant expires) {
this.expires = expires;
}
}

View File

@ -0,0 +1,214 @@
/**
*
*/
package de.bstly.we.model;
import java.time.temporal.ChronoUnit;
import java.util.Set;
import javax.persistence.AttributeConverter;
import javax.persistence.CollectionTable;
import javax.persistence.Column;
import javax.persistence.Convert;
import javax.persistence.Converter;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.annotations.LazyCollection;
import org.hibernate.annotations.LazyCollectionOption;
/**
*
* @author _bastler@bstly.de
*
*/
@Entity
@Table(name = "permission_mappings")
public class PermissionMapping {
public static final ChronoUnit DEFAULT_LIFETIME_UNIT = ChronoUnit.DAYS;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;
@Column(name = "product")
private String product;
@Column(name = "item", nullable = false)
private Integer item;
@ElementCollection
@LazyCollection(LazyCollectionOption.FALSE)
@CollectionTable(name = "permission_mappings_names")
private Set<String> names;
@Column(name = "addon", columnDefinition = "boolean default false")
private boolean addon;
@Column(name = "lifetime")
private Long lifetime;
@Column(name = "lifetime_unit")
@Convert(converter = ChronoUnitConverter.class)
private ChronoUnit lifetimeUnit = DEFAULT_LIFETIME_UNIT;
@Column(name = "lifetime_round", columnDefinition = "boolean default false")
private boolean lifetimeRound;
@Column(name = "starts_question")
private String startsQuestion;
@Column(name = "expires_question")
private String expiresQuestion;
/**
* @return the id
*/
public Long getId() {
return id;
}
/**
* @param id the id to set
*/
public void setId(Long id) {
this.id = id;
}
/**
* @return the product
*/
public String getProduct() {
return product;
}
/**
* @param product the product to set
*/
public void setProduct(String product) {
this.product = product;
}
/**
* @return the item
*/
public Integer getItem() {
return item;
}
/**
* @param item the item to set
*/
public void setItem(Integer item) {
this.item = item;
}
/**
* @return the names
*/
public Set<String> getNames() {
return names;
}
/**
* @param names the names to set
*/
public void setNames(Set<String> names) {
this.names = names;
}
/**
* @return the addon
*/
public boolean isAddon() {
return addon;
}
/**
* @param addon the addon to set
*/
public void setAddon(boolean addon) {
this.addon = addon;
}
/**
* @return the lifetime
*/
public Long getLifetime() {
return lifetime;
}
/**
* @param lifetime the lifetime to set
*/
public void setLifetime(Long lifetime) {
this.lifetime = lifetime;
}
/**
* @return the lifetimeUnit
*/
public ChronoUnit getLifetimeUnit() {
return lifetimeUnit;
}
/**
* @param lifetimeUnit the lifetimeUnit to set
*/
public void setLifetimeUnit(ChronoUnit lifetimeUnit) {
this.lifetimeUnit = lifetimeUnit;
}
/**
* @return the lifetimeRound
*/
public boolean isLifetimeRound() {
return lifetimeRound;
}
/**
* @param lifetimeRound the lifetimeRound to set
*/
public void setLifetimeRound(boolean lifetimeRound) {
this.lifetimeRound = lifetimeRound;
}
/**
* @return the startsQuestion
*/
public String getStartsQuestion() {
return startsQuestion;
}
/**
* @param startsQuestion the startsQuestion to set
*/
public void setStartsQuestion(String startsQuestion) {
this.startsQuestion = startsQuestion;
}
/**
* @return the expiresQuestion
*/
public String getExpiresQuestion() {
return expiresQuestion;
}
/**
* @param expiresQuestion the expiresQuestion to set
*/
public void setExpiresQuestion(String expiresQuestion) {
this.expiresQuestion = expiresQuestion;
}
@Converter
public static class ChronoUnitConverter implements AttributeConverter<ChronoUnit, String> {
@Override
public String convertToDatabaseColumn(ChronoUnit chronoUnit) {
return chronoUnit.name();
}
@Override
public ChronoUnit convertToEntityAttribute(String value) {
return ChronoUnit.valueOf(value);
}
}
}

View File

@ -0,0 +1,88 @@
/**
*
*/
package de.bstly.we.model;
import java.time.Instant;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
/**
*
* @author _bastler@bstly.de
*
*/
@Entity
@Table(name = "persistent_logins")
public class PersistentLogin {
@Column(name = "username", length = 64, nullable = false)
private String username;
@Id
@Column(name = "series", length = 64)
private String series;
@Column(name = "token", length = 64, nullable = false)
private String token;
@Column(name = "last_used", nullable = false)
private Instant last_used;
/**
* @return the username
*/
public String getUsername() {
return username;
}
/**
* @param username the username to set
*/
public void setUsername(String username) {
this.username = username;
}
/**
* @return the series
*/
public String getSeries() {
return series;
}
/**
* @param series the series to set
*/
public void setSeries(String series) {
this.series = series;
}
/**
* @return the token
*/
public String getToken() {
return token;
}
/**
* @param token the token to set
*/
public void setToken(String token) {
this.token = token;
}
/**
* @return the last_used
*/
public Instant getLast_used() {
return last_used;
}
/**
* @param last_used the last_used to set
*/
public void setLast_used(Instant last_used) {
this.last_used = last_used;
}
}

View File

@ -0,0 +1,14 @@
/**
*
*/
package de.bstly.we.model;
/**
* @author _bastler@bstly.de
*
*/
public enum ProfileFieldType {
TEXT, NUMBER, DATE, URL, EMAIL, BOOL, BLOB, DATETIME, TIME
}

View File

@ -0,0 +1,120 @@
/**
*
*/
package de.bstly.we.model;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
/**
* @author _bastler@bstly.de
*
*/
@Entity
@Table(name = "quotas")
public class Quota implements UserData {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", updatable = false)
private Long id;
@Column(name = "target", nullable = false)
private Long target;
@Column(name = "name", nullable = false)
private String name;
@Column(name = "value", nullable = false)
private long value;
@Column(name = "unit", nullable = true)
private String unit;
@Column(name = "disposable", columnDefinition = "boolean default false")
private boolean disposable;
/**
* @return the id
*/
public Long getId() {
return id;
}
/**
* @param id the id to set
*/
public void setId(Long id) {
this.id = id;
}
/**
* @return the target
*/
public Long getTarget() {
return target;
}
/**
* @param target the target to set
*/
public void setTarget(Long target) {
this.target = target;
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @return the value
*/
public long getValue() {
return value;
}
/**
* @param value the value to set
*/
public void setValue(long value) {
this.value = value;
}
/**
* @return the unit
*/
public String getUnit() {
return unit;
}
/**
* @param unit the unit to set
*/
public void setUnit(String unit) {
this.unit = unit;
}
/**
* @return the disposable
*/
public boolean isDisposable() {
return disposable;
}
/**
* @param disposable the disposable to set
*/
public void setDisposable(boolean disposable) {
this.disposable = disposable;
}
}

View File

@ -0,0 +1,164 @@
/**
*
*/
package de.bstly.we.model;
import java.util.Set;
import javax.persistence.CollectionTable;
import javax.persistence.Column;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.annotations.LazyCollection;
import org.hibernate.annotations.LazyCollectionOption;
/**
*
* @author _bastler@bstly.de
*
*/
@Entity
@Table(name = "quota_mappings")
public class QuotaMapping {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", updatable = false)
private Long id;
@ElementCollection
@LazyCollection(LazyCollectionOption.FALSE)
@CollectionTable(name = "quota_mappings_products")
private Set<String> products;
@ElementCollection
@LazyCollection(LazyCollectionOption.FALSE)
@CollectionTable(name = "quota_mappings_items")
private Set<Integer> items;
@Column(name = "name", nullable = false)
private String name;
@Column(name = "value", nullable = false)
private long value;
@Column(name = "unit", nullable = true)
private String unit;
@Column(name = "append", columnDefinition = "boolean default false")
private boolean append;
@Column(name = "disposable", columnDefinition = "boolean default false")
private boolean disposable;
/**
* @return the id
*/
public Long getId() {
return id;
}
/**
* @param id the id to set
*/
public void setId(Long id) {
this.id = id;
}
/**
* @return the products
*/
public Set<String> getProducts() {
return products;
}
/**
* @param products the products to set
*/
public void setProducts(Set<String> products) {
this.products = products;
}
/**
* @return the items
*/
public Set<Integer> getItems() {
return items;
}
/**
* @param items the items to set
*/
public void setItems(Set<Integer> items) {
this.items = items;
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @return the value
*/
public long getValue() {
return value;
}
/**
* @param value the value to set
*/
public void setValue(long value) {
this.value = value;
}
/**
* @return the unit
*/
public String getUnit() {
return unit;
}
/**
* @param unit the unit to set
*/
public void setUnit(String unit) {
this.unit = unit;
}
/**
* @return the append
*/
public boolean isAppend() {
return append;
}
/**
* @param append the append to set
*/
public void setAppend(boolean append) {
this.append = append;
}
/**
* @return the disposable
*/
public boolean isDisposable() {
return disposable;
}
/**
* @param disposable the disposable to set
*/
public void setDisposable(boolean disposable) {
this.disposable = disposable;
}
}

View File

@ -0,0 +1,12 @@
/**
*
*/
package de.bstly.we.model;
/**
* @author _bastler@bstly.de
*
*/
public interface SecondFactor extends UserData {
}

View File

@ -0,0 +1,69 @@
/**
*
*/
package de.bstly.we.model;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
/**
* @author _bastler@bstly.de
*
*/
@Entity
@Table(name = "system_profile_fields")
public class SystemProfileField {
@Id
@Column(name = "name", nullable = false)
private String name;
@Column(name = "type", nullable = false)
private ProfileFieldType type;
@Column(name = "unique_value", columnDefinition = "boolean default false")
private boolean uniqueValue;
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @return the type
*/
public ProfileFieldType getType() {
return type;
}
/**
* @param type the type to set
*/
public void setType(ProfileFieldType type) {
this.type = type;
}
/**
* @return the uniqueValue
*/
public boolean isUniqueValue() {
return uniqueValue;
}
/**
* @param uniqueValue the uniqueValue to set
*/
public void setUniqueValue(boolean uniqueValue) {
this.uniqueValue = uniqueValue;
}
}

View File

@ -0,0 +1,73 @@
/**
*
*/
package de.bstly.we.model;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Lob;
import javax.persistence.Table;
/**
*
* @author _bastler@bstly.de
*
*/
@Entity
@Table(name = "system_properties")
public class SystemProperty {
@Id
@Column(name = "id")
private String key;
@Lob
@Column(name = "value")
private String value;
/**
*
*/
public SystemProperty() {
super();
}
/**
* @param key
* @param value
*/
public SystemProperty(String key, String value) {
super();
this.key = key;
this.value = value;
}
/**
* @return the key
*/
public String getKey() {
return key;
}
/**
* @param key the key to set
*/
public void setKey(String key) {
this.key = key;
}
/**
* @return the value
*/
public String getValue() {
return value;
}
/**
* @param value the value to set
*/
public void setValue(String value) {
this.value = value;
}
}

View File

@ -0,0 +1,156 @@
/**
*
*/
package de.bstly.we.model;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
import com.fasterxml.jackson.annotation.JsonIgnore;
/**
*
* @author _bastler@bstly.de
*
*/
@Entity
@Table(name = "users", uniqueConstraints = @UniqueConstraint(columnNames = { "username" }))
public class User implements UserData {
@Id
@Column(name = "id", updatable = false, unique = true, nullable = false)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "username", unique = true, nullable = false)
private String username;
@JsonIgnore
@Column(name = "password", nullable = false)
private String passwordHash;
@Column(name = "disabled", columnDefinition = "boolean default false")
private boolean disabled;
@Column(name = "locked", columnDefinition = "boolean default false")
private boolean locked;
@Column(name = "status", nullable = false)
private UserStatus status;
@Column(name = "secret")
private String secret;
@Column(name = "reset_token")
private String resetToken;
/**
* @return the id
*/
public Long getId() {
return id;
}
/**
* @param id the id to set
*/
public void setId(Long id) {
this.id = id;
}
/**
* @return the username
*/
public String getUsername() {
return username;
}
/**
* @param username the username to set
*/
public void setUsername(String username) {
this.username = username;
}
/**
* @return the passwordHash
*/
public String getPasswordHash() {
return passwordHash;
}
/**
* @param passwordHash the passwordHash to set
*/
public void setPasswordHash(String passwordHash) {
this.passwordHash = passwordHash;
}
/**
* @return the disabled
*/
public boolean isDisabled() {
return disabled;
}
/**
* @param disabled the disabled to set
*/
public void setDisabled(boolean disabled) {
this.disabled = disabled;
}
/**
* @return the locked
*/
public boolean isLocked() {
return locked;
}
/**
* @param locked the locked to set
*/
public void setLocked(boolean locked) {
this.locked = locked;
}
/**
* @return the status
*/
public UserStatus getStatus() {
return status;
}
/**
* @param status the status to set
*/
public void setStatus(UserStatus status) {
this.status = status;
}
/**
* @return the secret
*/
public String getSecret() {
return secret;
}
/**
* @param secret the secret to set
*/
public void setSecret(String secret) {
this.secret = secret;
}
/**
* @return the resetToken
*/
public String getResetToken() {
return resetToken;
}
/**
* @param resetToken the resetToken to set
*/
public void setResetToken(String resetToken) {
this.resetToken = resetToken;
}
}

View File

@ -0,0 +1,89 @@
/**
*
*/
package de.bstly.we.model;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
/**
* @author _bastler@bstly.de
*
*/
@Entity
@Table(name = "aliases", uniqueConstraints = @UniqueConstraint(columnNames = { "alias" }))
public class UserAlias implements UserData {
@Id
@Column(name = "id", updatable = false, unique = true, nullable = false)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "target", nullable = false)
private Long target;
@Column(name = "alias", unique = true, nullable = false)
private String alias;
@Column(name = "visibility", nullable = false)
private Visibility visibility = Visibility.PROTECTED;
/**
* @return the id
*/
public Long getId() {
return id;
}
/**
* @param id the id to set
*/
public void setId(Long id) {
this.id = id;
}
/**
* @return the target
*/
public Long getTarget() {
return target;
}
/**
* @param target the target to set
*/
public void setTarget(Long target) {
this.target = target;
}
/**
* @return the alias
*/
public String getAlias() {
return alias;
}
/**
* @param alias the alias to set
*/
public void setAlias(String alias) {
this.alias = alias;
}
/**
* @return the visibility
*/
public Visibility getVisibility() {
return visibility;
}
/**
* @param visibility the visibility to set
*/
public void setVisibility(Visibility visibility) {
this.visibility = visibility;
}
}

View File

@ -0,0 +1,12 @@
/**
*
*/
package de.bstly.we.model;
/**
* @author _bastler@bstly.de
*
*/
public interface UserData {
}

View File

@ -0,0 +1,120 @@
/**
*
*/
package de.bstly.we.model;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
/**
* @author _bastler@bstly.de
*
*/
@Entity
@Table(name = "domains", uniqueConstraints = @UniqueConstraint(columnNames = { "domain" }))
public class UserDomain implements UserData {
@Id
@Column(name = "id", updatable = false, unique = true, nullable = false)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "target", nullable = false)
private Long target;
@Column(name = "domain", unique = true, nullable = false)
private String domain;
@Column(name = "visibility", nullable = false)
private Visibility visibility = Visibility.PROTECTED;
@Column(name = "secret")
private String secret;
@Column(name = "validated", columnDefinition = "boolean default false")
private boolean validated;
/**
* @return the id
*/
public Long getId() {
return id;
}
/**
* @param id the id to set
*/
public void setId(Long id) {
this.id = id;
}
/**
* @return the target
*/
public Long getTarget() {
return target;
}
/**
* @param target the target to set
*/
public void setTarget(Long target) {
this.target = target;
}
/**
* @return the domain
*/
public String getDomain() {
return domain;
}
/**
* @param domain the domain to set
*/
public void setDomain(String domain) {
this.domain = domain;
}
/**
* @return the visibility
*/
public Visibility getVisibility() {
return visibility;
}
/**
* @param visibility the visibility to set
*/
public void setVisibility(Visibility visibility) {
this.visibility = visibility;
}
/**
* @return the secret
*/
public String getSecret() {
return secret;
}
/**
* @param secret the secret to set
*/
public void setSecret(String secret) {
this.secret = secret;
}
/**
* @return the validated
*/
public boolean isValidated() {
return validated;
}
/**
* @param validated the validated to set
*/
public void setValidated(boolean validated) {
this.validated = validated;
}
}

View File

@ -0,0 +1,208 @@
/**
*
*/
package de.bstly.we.model;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.IdClass;
import javax.persistence.Lob;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
import de.bstly.we.model.UserProfileField.UserProfileFieldId;
/**
* @author _bastler@bstly.de
*
*/
@Entity
@IdClass(UserProfileFieldId.class)
@Table(name = "profile_fields", uniqueConstraints = @UniqueConstraint(columnNames = { "target",
"name" }))
public class UserProfileField implements UserData {
@Id
@Column(name = "name", nullable = false)
private String name;
@Id
@Column(name = "target", nullable = false)
private Long target;
@Column(name = "value", nullable = true)
private String value;
@Lob
@Column(name = "blob_value", nullable = true)
private String blob;
@Column(name = "type", nullable = false)
private ProfileFieldType type;
@Column(name = "visibility", nullable = false)
private Visibility visibility;
@Column(name = "order_index", nullable = true)
private Integer index = 0;
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @return the target
*/
public Long getTarget() {
return target;
}
/**
* @param target the target to set
*/
public void setTarget(Long target) {
this.target = target;
}
/**
* @return the value
*/
public String getValue() {
return value;
}
/**
* @param value the value to set
*/
public void setValue(String value) {
this.value = value;
}
/**
* @return the blob
*/
public String getBlob() {
return blob;
}
/**
* @param blob the blob to set
*/
public void setBlob(String blob) {
this.blob = blob;
}
/**
* @return the type
*/
public ProfileFieldType getType() {
return type;
}
/**
* @param type the type to set
*/
public void setType(ProfileFieldType type) {
this.type = type;
}
/**
* @return the visibility
*/
public Visibility getVisibility() {
return visibility;
}
/**
* @param visibility the visibility to set
*/
public void setVisibility(Visibility visibility) {
this.visibility = visibility;
}
/**
* @return the index
*/
public Integer getIndex() {
return index;
}
/**
* @param index the index to set
*/
public void setIndex(Integer index) {
this.index = index;
}
/**
*
* @author _bastler@bstly.de
*
*/
public static class UserProfileFieldId implements Serializable {
/**
* default serialVersionUID
*/
private static final long serialVersionUID = 1L;
private Long target;
private String name;
/**
* @return the target
*/
public Long getTarget() {
return target;
}
/**
* @param target the target to set
*/
public void setTarget(Long target) {
this.target = target;
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
/*
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
if (obj instanceof UserProfileFieldId) {
UserProfileFieldId userProfileFieldId = (UserProfileFieldId) obj;
return this.name.equals(userProfileFieldId.getName())
&& this.target.equals(userProfileFieldId.getTarget());
}
return false;
}
/*
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
return this.name.hashCode() * this.target.hashCode();
}
}
}

View File

@ -0,0 +1,14 @@
/**
*
*/
package de.bstly.we.model;
/**
* @author _bastler@bstly.de
*
*/
public enum UserStatus {
NORMAL, SLEEP, PURGE
}

View File

@ -0,0 +1,128 @@
/**
*
*/
package de.bstly.we.model;
import java.util.List;
import javax.persistence.CollectionTable;
import javax.persistence.Column;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
import org.hibernate.annotations.LazyCollection;
import org.hibernate.annotations.LazyCollectionOption;
/**
* @author _bastler@bstly.de
*
*/
@Entity
@Table(name = "user_totps", uniqueConstraints = @UniqueConstraint(columnNames = { "target" }))
public class UserTotp implements SecondFactor {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;
private Long target;
private boolean enabled;
@Column(name = "totp_secret", nullable = false)
private String secret;
@Column(name = "totp_qr_data", nullable = false)
private String qrData;
@ElementCollection
@LazyCollection(LazyCollectionOption.FALSE)
@CollectionTable(name = "user_totps_recovery_codes")
private List<String> recoveryCodes;
/**
* @return the id
*/
public Long getId() {
return id;
}
/**
* @param id the id to set
*/
public void setId(Long id) {
this.id = id;
}
/**
* @return the target
*/
public Long getTarget() {
return target;
}
/**
* @param target the target to set
*/
public void setTarget(Long target) {
this.target = target;
}
/**
* @return the enabled
*/
public boolean isEnabled() {
return enabled;
}
/**
* @param enabled the enabled to set
*/
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
/**
* @return the secret
*/
public String getSecret() {
return secret;
}
/**
* @param secret the secret to set
*/
public void setSecret(String secret) {
this.secret = secret;
}
/**
* @return the qrData
*/
public String getQrData() {
return qrData;
}
/**
* @param qrData the qrData to set
*/
public void setQrData(String qrData) {
this.qrData = qrData;
}
/**
* @return the recoveryCodes
*/
public List<String> getRecoveryCodes() {
return recoveryCodes;
}
/**
* @param recoveryCodes the recoveryCodes to set
*/
public void setRecoveryCodes(List<String> recoveryCodes) {
this.recoveryCodes = recoveryCodes;
}
}

View File

@ -0,0 +1,14 @@
/**
*
*/
package de.bstly.we.model;
/**
* @author _bastler@bstly.de
*
*/
public enum Visibility {
PRIVATE, PROTECTED, PUBLIC
}

View File

@ -0,0 +1,21 @@
/**
*
*/
package de.bstly.we.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.querydsl.QuerydslPredicateExecutor;
import org.springframework.stereotype.Repository;
import de.bstly.we.model.PermissionMapping;
/**
*
* @author _bastler@bstly.de
*
*/
@Repository
public interface PermissionMappingRepository
extends JpaRepository<PermissionMapping, Long>, QuerydslPredicateExecutor<PermissionMapping> {
}

View File

@ -0,0 +1,21 @@
/**
*
*/
package de.bstly.we.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.querydsl.QuerydslPredicateExecutor;
import org.springframework.stereotype.Repository;
import de.bstly.we.model.Permission;
/**
*
* @author _bastler@bstly.de
*
*/
@Repository
public interface PermissionRepository
extends JpaRepository<Permission, Long>, QuerydslPredicateExecutor<Permission> {
}

View File

@ -0,0 +1,21 @@
/**
*
*/
package de.bstly.we.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.querydsl.QuerydslPredicateExecutor;
import org.springframework.stereotype.Repository;
import de.bstly.we.model.QuotaMapping;
/**
*
* @author _bastler@bstly.de
*
*/
@Repository
public interface QuotaMappingRepository
extends JpaRepository<QuotaMapping, Long>, QuerydslPredicateExecutor<QuotaMapping> {
}

View File

@ -0,0 +1,20 @@
/**
*
*/
package de.bstly.we.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.querydsl.QuerydslPredicateExecutor;
import org.springframework.stereotype.Repository;
import de.bstly.we.model.Quota;
/**
*
* @author _bastler@bstly.de
*
*/
@Repository
public interface QuotaRepository extends JpaRepository<Quota, Long>, QuerydslPredicateExecutor<Quota> {
}

View File

@ -0,0 +1,21 @@
/**
*
*/
package de.bstly.we.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.querydsl.QuerydslPredicateExecutor;
import org.springframework.stereotype.Repository;
import de.bstly.we.model.SystemProfileField;
/**
*
* @author _bastler@bstly.de
*
*/
@Repository
public interface SystemProfileFieldRepository extends JpaRepository<SystemProfileField, String>,
QuerydslPredicateExecutor<SystemProfileField> {
}

View File

@ -0,0 +1,21 @@
/**
*
*/
package de.bstly.we.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.querydsl.QuerydslPredicateExecutor;
import org.springframework.stereotype.Repository;
import de.bstly.we.model.SystemProperty;
/**
*
* @author _bastler@bstly.de
*
*/
@Repository
public interface SystemPropertyRepository
extends JpaRepository<SystemProperty, String>, QuerydslPredicateExecutor<SystemProperty> {
}

View File

@ -0,0 +1,21 @@
/**
*
*/
package de.bstly.we.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.querydsl.QuerydslPredicateExecutor;
import org.springframework.stereotype.Repository;
import de.bstly.we.model.UserAlias;
/**
*
* @author _bastler@bstly.de
*
*/
@Repository
public interface UserAliasRepository
extends JpaRepository<UserAlias, Long>, QuerydslPredicateExecutor<UserAlias> {
}

Some files were not shown because too many files have changed in this diff Show More