diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 000000000..79d11cdce --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,25 @@ +{ + "name": "Gamma Devcontainer", + "dockerComposeFile": "docker-compose.yml", + "service": "app", + "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}", + "remoteUser": "root", + + "features": { + "ghcr.io/devcontainers/features/java:1": { + "version": "21", + "jdkDistro": "open" + }, + "ghcr.io/devcontainers/features/node:1": { + "version": "20" + } + }, + + "forwardPorts": [8081], + + "customizations" : { + "jetbrains" : { + "backend" : "IntelliJ" + } + } +} diff --git a/.devcontainer/docker-compose.yml b/.devcontainer/docker-compose.yml new file mode 100644 index 000000000..7c99212b8 --- /dev/null +++ b/.devcontainer/docker-compose.yml @@ -0,0 +1,31 @@ +volumes: + postgres-data: + +services: + app: + image: mcr.microsoft.com/devcontainers/base:ubuntu-22.04 + volumes: + - ../..:/workspaces:cached + command: sleep infinity + + db: + container_name: db + image: postgres:16 + restart: unless-stopped + environment: + POSTGRES_PASSWORD: "postgres" + volumes: + - postgres-data:/var/lib/postgresql/data + + redis: + container_name: redis + image: redis:5.0 + restart: always + + gotify: + container_name: gotify + image: cthit/gotify:latest + environment: + GOTIFY_PRE-SHARED-KEY: "123abc" + GOTIFY_MOCK-MODE: "true" + GOTIFY_DEBUG-MODE: "true" diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 6052c60d7..3279a13a2 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1 +1 @@ -* @portals @gurr1 +* @portals \ No newline at end of file diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml new file mode 100644 index 000000000..c1444e4e5 --- /dev/null +++ b/.github/workflows/gradle.yml @@ -0,0 +1,47 @@ +name: Build Docker Image +on: + push: + branches: [dev] + +jobs: + build: + runs-on: ubuntu-latest + permissions: + packages: write + steps: + - uses: actions/checkout@v4 + + - name: Set up JDK 21 + uses: actions/setup-java@v4 + with: + java-version: "21" + distribution: "adopt" + + - name: Validate Gradle wrapper + uses: gradle/wrapper-validation-action@e6e38bacfdf1a337459f332974bb2327a31aaf4b + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to GitHub Container Registry + if: ${{ github.ref == 'refs/heads/dev' }} + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Docker Build-Tag-Push my-app + run: | + ./gradlew bootBuildImage + docker tag gamma:2.0.0-SNAPSHOT ghcr.io/cthit/gamma:latest + docker push ghcr.io/cthit/gamma:latest + working-directory: ./app + + - name: Cleanup Gradle Cache + + # Remove some files from the Gradle cache, so they aren't cached by GitHub Actions. + # Restoring these files from a GitHub Actions cache might cause problems for future builds. + run: | + rm -f ~/.gradle/caches/modules-2/modules-2.lock + rm -f ~/.gradle/caches/modules-2/gc.properties diff --git a/.gitignore b/.gitignore index fdb5428d4..ed3b6f9a3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ -yarn-error.log -frontend/node_modules/ .idea/* +.DS_Store +uploads/ +.run diff --git a/.mailmap b/.mailmap deleted file mode 100644 index 498c2e178..000000000 --- a/.mailmap +++ /dev/null @@ -1 +0,0 @@ -Theodor Angergård \ No newline at end of file diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 661bfe23f..000000000 --- a/.travis.yml +++ /dev/null @@ -1,22 +0,0 @@ -language: java - -jdk: - - oraclejdk11 - -before_script: - - cd backend - -script: - - ./gradlew build --console 'plain' -s - -before_cache: - - rm -f $HOME/.gradle/caches/modules-2/modules-2.lock - - rm -fr $HOME/.gradle/caches/*/plugin-resolution/ - -cache: - directories: - - $HOME/.gradle/caches/ - - $HOME/.gradle/wrapper/ - -notifications: - email: false diff --git a/LICENSE b/LICENSE index be3f7b28e..e930d8e28 100644 --- a/LICENSE +++ b/LICENSE @@ -1,661 +1,13 @@ - GNU AFFERO GENERAL PUBLIC LICENSE - Version 3, 19 November 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - 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. - - - Copyright (C) - - 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 . - -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 -. +Zero-Clause BSD +============= + +Permission to use, copy, modify, and/or distribute this software for +any purpose with or without fee is hereby granted. + +THE SOFTWARE IS PROVIDED “AS IS” AND THE AUTHOR DISCLAIMS ALL +WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE +FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN +AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.: diff --git a/README.md b/README.md index 98e49b3e7..d04263a92 100644 --- a/README.md +++ b/README.md @@ -1,37 +1 @@ -# Gamma - -[![Build Status](https://travis-ci.com/cthit/Gamma.svg?branch=develop)](https://travis-ci.com/cthit/Gamma) - -# Gamma is Chalmers IT section account system - -Gamma is licensed under the GNU AGPL, see `LICENSE`. - ---- - -## More information about Gamma can be found on the [Wiki](https://github.com/cthit/Gamma/wiki) - -## Build setup - -### For production - -it's real easy. Just replace the environment variables with suitable value (see wiki) -and run: - -`docker-compose -f prod.docker-compose.yml up --build` - -Depending on your build system, things might be different, and a proxy is probably needed for a real production version of Gamma. - -### Development - -run - -`docker-compose up --build` to build the frontend, backend, database, databasemonitoring, and all microservices that's needed for Gamma. - -If developing on the backend, we recomend not running the backend in the docker-compose file. There is a docker-compose file that sets up all microservice but the backend, to use this run: `docker-compose -f no_backend.docker-compose.ym up --build` -then you will need to start the server, this is done by running the Java code in the backend, and is probably best done through an IDE. - -You'll need to run `docker-compose down` / `docker-compose -f no_backed.docker-compose.yml down` if you want to try the production build. Same if you're going from production to development. - -## API Documentation - -The API documentation is auto-generated by [Swagger](https://swagger.io/) and can be found under http://localhost:8081/api/swagger-ui.html while the application is running. +# Gamma \ No newline at end of file diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 000000000..56a0dca58 --- /dev/null +++ b/app/.gitignore @@ -0,0 +1,37 @@ +.gradle/ +/build/ +!gradle/wrapper/gradle-wrapper.jar +/uploads/ +*.run.xml +/src/main/resources/secrets.properties + +generated + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr +/out/ +.idea/ + +### NetBeans ### +/nbproject/private/ +/build/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +secrets.properties + +.DS-store \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 000000000..aad5db97d --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,99 @@ +buildscript { + repositories { + mavenCentral() + } + dependencies { + classpath "org.springframework.boot:spring-boot-gradle-plugin:3.3.0" + } +} + +plugins { + id "java" + id "org.springframework.boot" version "3.3.0" + id "io.spring.dependency-management" version "1.1.5" + id "com.diffplug.spotless" version "6.25.0" +} + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(21) + } +} + +apply plugin: "org.springframework.boot" +apply plugin: "io.spring.dependency-management" +group = "it.chalmers" +version = "2.0.0-SNAPSHOT" + +dependencies { + annotationProcessor( + // Used to generate Record Builder classes + "io.soabase.record-builder:record-builder-processor:41", + ) + + implementation( + // Used to generate Record Builder classes + "io.soabase.record-builder:record-builder-core:41", + + // Used to handle SQL specific errors + "org.postgresql:postgresql:42.7.3", + + // Spring Boot + "org.springframework.boot:spring-boot:3.3.0", + "org.springframework.boot:spring-boot-autoconfigure:3.3.0", + "org.springframework.boot:spring-boot-starter-data-jpa:3.3.0", + "org.springframework.boot:spring-boot-starter-security:3.3.0", + "org.springframework.boot:spring-boot-starter-validation:3.3.0", + "org.springframework.boot:spring-boot-starter-web:3.3.0", + "org.springframework.boot:spring-boot-starter-oauth2-authorization-server:3.3.0", + + // Spring session + "org.springframework.session:spring-session-core:3.3.0", + "org.springframework.session:spring-session-data-redis:3.3.0", + + // Redis + "org.springframework.data:spring-data-redis:3.3.0", + ) + + runtimeOnly( + // FlywayDB (Database migration) + "org.flywaydb:flyway-core:9.21.0", + + // Spring Boot + "org.springframework.boot:spring-boot-devtools:3.3.0", + "org.springframework.boot:spring-boot-starter-data-redis:3.3.0", + + // Thymeleaf + "org.springframework.boot:spring-boot-starter-thymeleaf:3.3.0", + "org.thymeleaf.extras:thymeleaf-extras-springsecurity6:3.1.2.RELEASE", + + // web dependencies + "org.webjars.npm:htmx.org:1.9.12", + "org.webjars.npm:hyperscript.org:0.9.12", + "org.webjars.npm:picocss__pico:2.0.6", + "org.webjars.npm:sortablejs:1.15.3" + ) +} + +repositories { + mavenCentral() +} + +spotless { + java { + importOrder() + removeUnusedImports() + googleJavaFormat() + formatAnnotations() + } + + yaml { + target "src/**/*.yml" + jackson() + } + + json { + target "src/**/*.json" + jackson() + } +} diff --git a/app/gradle/wrapper/gradle-wrapper.jar b/app/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 000000000..943f0cbfa Binary files /dev/null and b/app/gradle/wrapper/gradle-wrapper.jar differ diff --git a/backend/gradle/wrapper/gradle-wrapper.properties b/app/gradle/wrapper/gradle-wrapper.properties similarity index 83% rename from backend/gradle/wrapper/gradle-wrapper.properties rename to app/gradle/wrapper/gradle-wrapper.properties index 4d9ca1649..707e499ac 100644 --- a/backend/gradle/wrapper/gradle-wrapper.properties +++ b/app/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip +networkTimeout=10000 zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/app/gradlew b/app/gradlew new file mode 100755 index 000000000..65dcd68d6 --- /dev/null +++ b/app/gradlew @@ -0,0 +1,244 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/backend/gradlew.bat b/app/gradlew.bat similarity index 89% rename from backend/gradlew.bat rename to app/gradlew.bat index ac1b06f93..93e3f59f1 100644 --- a/backend/gradlew.bat +++ b/app/gradlew.bat @@ -1,89 +1,92 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/app/settings.gradle b/app/settings.gradle new file mode 100644 index 000000000..8df5f2e03 --- /dev/null +++ b/app/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'gamma' \ No newline at end of file diff --git a/app/src/main/java/it/chalmers/gamma/BootstrapRunner.java b/app/src/main/java/it/chalmers/gamma/BootstrapRunner.java new file mode 100644 index 000000000..760286f13 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/BootstrapRunner.java @@ -0,0 +1,43 @@ +package it.chalmers.gamma; + +import it.chalmers.gamma.bootstrap.*; +import org.springframework.boot.CommandLineRunner; +import org.springframework.context.annotation.Bean; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Component; + +@Component +public class BootstrapRunner { + + @Bean + public CommandLineRunner runBootStrap( + ApiKeyBootstrap apiKeyBootstrap, + EnsureAnAdminUserBootstrap ensureAnAdminUserBootstrap, + GroupBootstrap groupBootstrap, + MiscBootstrap miscBootstrap, + PostBootstrap postBootstrap, + SuperGroupBootstrap superGroupBootstrap, + UserBootstrap userBootstrap) { + return (args) -> { + try { + SecurityContextHolder.createEmptyContext(); + SecurityContextHolder.getContext().setAuthentication(new BootstrapAuthenticated()); + + miscBootstrap.runImageBootstrap(); + + ensureAnAdminUserBootstrap.ensureAnAdminUser(); + + userBootstrap.createUsers(); + postBootstrap.createPosts(); + superGroupBootstrap.createSuperGroups(); + groupBootstrap.createGroups(); + + apiKeyBootstrap.ensureApiKeys(); + + SecurityContextHolder.clearContext(); + } catch (Throwable throwable) { + throwable.printStackTrace(); + } + }; + } +} diff --git a/app/src/main/java/it/chalmers/gamma/GammaApplication.java b/app/src/main/java/it/chalmers/gamma/GammaApplication.java new file mode 100644 index 000000000..c176aaf1d --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/GammaApplication.java @@ -0,0 +1,16 @@ +package it.chalmers.gamma; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.context.properties.ConfigurationPropertiesScan; +import org.springframework.scheduling.annotation.EnableScheduling; + +@EnableScheduling +@SpringBootApplication +@ConfigurationPropertiesScan +public class GammaApplication { + + public static void main(String[] args) { + SpringApplication.run(GammaApplication.class, args); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/ScheduledTasks.java b/app/src/main/java/it/chalmers/gamma/ScheduledTasks.java new file mode 100644 index 000000000..77e142250 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/ScheduledTasks.java @@ -0,0 +1,41 @@ +package it.chalmers.gamma; + +import it.chalmers.gamma.app.user.activation.domain.UserActivationRepository; +import it.chalmers.gamma.app.user.passwordreset.domain.PasswordResetRepository; +import java.util.concurrent.TimeUnit; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +@Component +public class ScheduledTasks { + + private static final Logger LOGGER = LoggerFactory.getLogger(ScheduledTasks.class); + + private final UserActivationRepository userActivationRepository; + private final PasswordResetRepository passwordResetRepository; + + public ScheduledTasks( + UserActivationRepository userActivationRepository, + PasswordResetRepository passwordResetRepository) { + this.userActivationRepository = userActivationRepository; + this.passwordResetRepository = passwordResetRepository; + } + + @Scheduled(timeUnit = TimeUnit.MINUTES, fixedRate = 15) + public void clearInvalidActivationCodes() { + int i = userActivationRepository.removeInvalidActivationCodes(); + if (i > 0) { + LOGGER.info("Removed {} expired user activation codes", i); + } + } + + @Scheduled(timeUnit = TimeUnit.MINUTES, fixedRate = 15) + public void clearInvalidPasswordResetTokens() { + int i = passwordResetRepository.removeInvalidPasswordResetTokens(); + if (i > 0) { + LOGGER.info("Removed {} expired password reset tokens", i); + } + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/primary/api/AlreadyExistsResponse.java b/app/src/main/java/it/chalmers/gamma/adapter/primary/api/AlreadyExistsResponse.java new file mode 100644 index 000000000..026c506fb --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/primary/api/AlreadyExistsResponse.java @@ -0,0 +1,9 @@ +package it.chalmers.gamma.adapter.primary.api; + +import org.springframework.http.HttpStatus; + +public abstract class AlreadyExistsResponse extends ErrorResponse { + public AlreadyExistsResponse() { + super(HttpStatus.CONFLICT); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/primary/api/BadRequestResponse.java b/app/src/main/java/it/chalmers/gamma/adapter/primary/api/BadRequestResponse.java new file mode 100644 index 000000000..16371bf11 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/primary/api/BadRequestResponse.java @@ -0,0 +1,9 @@ +package it.chalmers.gamma.adapter.primary.api; + +import org.springframework.http.HttpStatus; + +public class BadRequestResponse extends ErrorResponse { + public BadRequestResponse() { + super(HttpStatus.BAD_REQUEST); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/primary/api/ClassNameGeneratorUtils.java b/app/src/main/java/it/chalmers/gamma/adapter/primary/api/ClassNameGeneratorUtils.java new file mode 100644 index 000000000..df7e00abc --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/primary/api/ClassNameGeneratorUtils.java @@ -0,0 +1,21 @@ +package it.chalmers.gamma.adapter.primary.api; + +public class ClassNameGeneratorUtils { + + private ClassNameGeneratorUtils() {} + + public static String classToScreamingSnakeCase(Class c) { + String className = c.getSimpleName(); + String[] camelCaseWords = className.split("(?=[A-Z])"); + StringBuilder sb = new StringBuilder(); + + for (int i = 0; i < camelCaseWords.length - 1; i++) { + sb.append(camelCaseWords[i].toUpperCase()); + sb.append("_"); + } + + sb.append(camelCaseWords[camelCaseWords.length - 1].toUpperCase()); + + return sb.toString(); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/primary/api/ErrorResponse.java b/app/src/main/java/it/chalmers/gamma/adapter/primary/api/ErrorResponse.java new file mode 100644 index 000000000..42cefc441 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/primary/api/ErrorResponse.java @@ -0,0 +1,38 @@ +package it.chalmers.gamma.adapter.primary.api; + +import java.util.Arrays; +import java.util.stream.Collectors; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpStatus; +import org.springframework.web.server.ResponseStatusException; + +public class ErrorResponse extends ResponseStatusException { + + private static final Logger LOGGER = LoggerFactory.getLogger(ErrorResponse.class); + + public ErrorResponse(HttpStatus status) { + super(status); + + LOGGER.error( + String.format( + "An exception was thrown in the application: status: %d, Reason: %s", + status.value(), ClassNameGeneratorUtils.classToScreamingSnakeCase(this.getClass()))); + LOGGER.debug( + String.format( + "Stacktrace: \n %s:", + Arrays.stream(super.fillInStackTrace().getStackTrace()) + .map(StackTraceElement::toString) + .collect(Collectors.joining("\n ")))); + } + + @Override + public synchronized Throwable fillInStackTrace() { + return null; + } + + @Override + public String getReason() { + return ClassNameGeneratorUtils.classToScreamingSnakeCase(this.getClass()); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/primary/api/NotFoundResponse.java b/app/src/main/java/it/chalmers/gamma/adapter/primary/api/NotFoundResponse.java new file mode 100644 index 000000000..d35eb43c8 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/primary/api/NotFoundResponse.java @@ -0,0 +1,9 @@ +package it.chalmers.gamma.adapter.primary.api; + +import org.springframework.http.HttpStatus; + +public abstract class NotFoundResponse extends ErrorResponse { + public NotFoundResponse() { + super(HttpStatus.NOT_FOUND); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/primary/api/SuccessResponse.java b/app/src/main/java/it/chalmers/gamma/adapter/primary/api/SuccessResponse.java new file mode 100644 index 000000000..35c232128 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/primary/api/SuccessResponse.java @@ -0,0 +1,24 @@ +package it.chalmers.gamma.adapter.primary.api; + +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; + +public class SuccessResponse extends ResponseEntity { + + public SuccessResponse() { + super(HttpStatus.OK); + } + + public SuccessResponse(HttpStatus status) { + super(status); + } + + @Override + public SuccessResponseData getBody() { + return new SuccessResponseData( + ClassNameGeneratorUtils.classToScreamingSnakeCase(this.getClass()), + this.getStatusCode().value()); + } + + public record SuccessResponseData(String name, int code) {} +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/primary/api/accountscaffold/AccountScaffoldV1ApiController.java b/app/src/main/java/it/chalmers/gamma/adapter/primary/api/accountscaffold/AccountScaffoldV1ApiController.java new file mode 100644 index 000000000..7e2c2ed00 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/primary/api/accountscaffold/AccountScaffoldV1ApiController.java @@ -0,0 +1,34 @@ +package it.chalmers.gamma.adapter.primary.api.accountscaffold; + +import it.chalmers.gamma.app.accountscaffold.AccountScaffoldFacade; +import java.util.List; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * Used by, for example, cthit/goldapps to sync + * Google accounts for the student division. + */ +@RestController +@RequestMapping(AccountScaffoldV1ApiController.URI) +public class AccountScaffoldV1ApiController { + + public static final String URI = "/api/account-scaffold/v1"; + + private final AccountScaffoldFacade accountScaffoldFacade; + + public AccountScaffoldV1ApiController(AccountScaffoldFacade accountScaffoldFacade) { + this.accountScaffoldFacade = accountScaffoldFacade; + } + + @GetMapping("/supergroups") + public List getSuperGroups() { + return this.accountScaffoldFacade.getActiveSuperGroups(); + } + + @GetMapping("/users") + public List getUsers() { + return this.accountScaffoldFacade.getActiveUsers(); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/primary/api/allowlist/AllowListV1ApiController.java b/app/src/main/java/it/chalmers/gamma/adapter/primary/api/allowlist/AllowListV1ApiController.java new file mode 100644 index 000000000..d4e048e36 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/primary/api/allowlist/AllowListV1ApiController.java @@ -0,0 +1,56 @@ +package it.chalmers.gamma.adapter.primary.api.allowlist; + +import it.chalmers.gamma.adapter.primary.api.SuccessResponse; +import it.chalmers.gamma.app.user.allowlist.AllowListFacade; +import java.util.ArrayList; +import java.util.List; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping(AllowListV1ApiController.URI) +public class AllowListV1ApiController { + + public static final String URI = "/api/allow-list/v1"; + + private static final Logger LOGGER = LoggerFactory.getLogger(AllowListV1ApiController.class); + + private final AllowListFacade allowListFacade; + + public AllowListV1ApiController(AllowListFacade allowListFacade) { + this.allowListFacade = allowListFacade; + } + + @GetMapping() + public List getAllowList() { + return this.allowListFacade.getAllowList(); + } + + @PostMapping() + public ResponseEntity addAllowedUsers(@RequestBody AddListOfAllowListRequest request) { + List failedToAdd = new ArrayList<>(); + + for (String cid : request.cids) { + try { + this.allowListFacade.allow(cid); + LOGGER.info("Added user " + cid + " to allow list"); + } catch (Exception e) { + LOGGER.info("Failed to add " + cid + " to allow list"); + failedToAdd.add(cid); + } + } + + if (!failedToAdd.isEmpty()) { + return new ResponseEntity<>(failedToAdd, HttpStatus.PARTIAL_CONTENT); + } + + return new AllowListAddedResponse(); + } + + private record AddListOfAllowListRequest(List cids) {} + + private static class AllowListAddedResponse extends SuccessResponse {} +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/primary/api/client/ClientApiV1Controller.java b/app/src/main/java/it/chalmers/gamma/adapter/primary/api/client/ClientApiV1Controller.java new file mode 100644 index 000000000..325b9f80e --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/primary/api/client/ClientApiV1Controller.java @@ -0,0 +1,157 @@ +package it.chalmers.gamma.adapter.primary.api.client; + +import it.chalmers.gamma.app.authentication.AccessGuard; +import it.chalmers.gamma.app.client.ClientAuthorityFacade; +import it.chalmers.gamma.app.group.GroupFacade; +import it.chalmers.gamma.app.post.PostFacade; +import it.chalmers.gamma.app.supergroup.SuperGroupFacade; +import it.chalmers.gamma.app.user.UserFacade; +import java.util.List; +import java.util.Optional; +import java.util.UUID; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.server.ResponseStatusException; + +@RestController +@RequestMapping(ClientApiV1Controller.URI) +public class ClientApiV1Controller { + + public static final String URI = "/api/client/v1"; + + private final UserFacade userFacade; + private final GroupFacade groupFacade; + private final SuperGroupFacade superGroupFacade; + private final ClientAuthorityFacade clientAuthorityFacade; + + public ClientApiV1Controller( + UserFacade userFacade, + GroupFacade groupFacade, + SuperGroupFacade superGroupFacade, + ClientAuthorityFacade clientAuthorityFacade) { + this.userFacade = userFacade; + this.groupFacade = groupFacade; + this.superGroupFacade = superGroupFacade; + this.clientAuthorityFacade = clientAuthorityFacade; + } + + record ClientV1SuperGroup( + UUID id, + String name, + String prettyName, + String type, + String svDescription, + String enDescription) { + ClientV1SuperGroup(SuperGroupFacade.SuperGroupDTO superGroup) { + this( + superGroup.id(), + superGroup.name(), + superGroup.prettyName(), + superGroup.type(), + superGroup.svDescription(), + superGroup.enDescription()); + } + } + + record ClientV1Post(UUID id, int version, String svName, String enName) { + public ClientV1Post(PostFacade.PostDTO post) { + this(post.id(), post.version(), post.svName(), post.enName()); + } + } + + record ClientV1UserGroup( + UUID id, String name, String prettyName, ClientV1SuperGroup superGroup, ClientV1Post post) { + ClientV1UserGroup(UserFacade.UserGroupDTO userGroup) { + this( + userGroup.group().id(), + userGroup.group().name(), + userGroup.group().prettyName(), + new ClientV1SuperGroup(userGroup.group().superGroup()), + new ClientV1Post(userGroup.post())); + } + } + + record ClientV1User( + String cid, String nick, String firstName, String lastName, UUID id, int acceptanceYear) { + ClientV1User(UserFacade.UserDTO user) { + this( + user.cid(), + user.nick(), + user.firstName(), + user.lastName(), + user.id(), + user.acceptanceYear()); + } + } + + record ClientV1Group(UUID id, String name, String prettyName, ClientV1SuperGroup superGroup) { + ClientV1Group(GroupFacade.GroupDTO group) { + this( + group.id(), group.name(), group.prettyName(), new ClientV1SuperGroup(group.superGroup())); + } + } + + @GetMapping("/groups") + List getGroups() { + return this.groupFacade.getAll().stream().map(ClientV1Group::new).toList(); + } + + @GetMapping("/superGroups") + List getSuperGroups() { + return this.superGroupFacade.getAll().stream().map(ClientV1SuperGroup::new).toList(); + } + + @GetMapping("/users") + List getUsersForClient() { + return this.userFacade.getAllByClientAccepting().stream().map(ClientV1User::new).toList(); + } + + @GetMapping("/users/{id}") + ClientV1User getUser(@PathVariable("id") UUID id) { + Optional maybeUser; + + try { + maybeUser = this.userFacade.get(id); + } catch (AccessGuard.AccessDeniedException e) { + throw new ResponseStatusException(HttpStatus.NOT_FOUND, "User Not Found Or Unauthorized"); + } + + if (maybeUser.isEmpty()) { + throw new ResponseStatusException(HttpStatus.NOT_FOUND, "User Not Found Or Unauthorized"); + } + + return maybeUser.map(ClientV1User::new).get(); + } + + @GetMapping("/groups/for/{id}") + List getGroupsForUser(@PathVariable("id") UUID id) { + Optional maybeUser; + + try { + maybeUser = this.userFacade.getWithGroups(id); + } catch (AccessGuard.AccessDeniedException e) { + throw new ResponseStatusException(HttpStatus.NOT_FOUND, "User Not Found Or Unauthorized"); + } + + if (maybeUser.isEmpty()) { + throw new ResponseStatusException(HttpStatus.NOT_FOUND, "User Not Found Or Unauthorized"); + } + + List groups = maybeUser.get().groups(); + + return groups.stream().map(ClientV1UserGroup::new).toList(); + } + + @GetMapping("/authorities") + public List getClientAuthorities() { + return this.clientAuthorityFacade.getClientAuthorities(); + } + + @GetMapping("/authorities/for/{id}") + public List getClientAuthoritiesForUser(@PathVariable("id") UUID userId) { + return this.clientAuthorityFacade.getUserAuthorities(userId); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/primary/api/info/InfoV1ApiController.java b/app/src/main/java/it/chalmers/gamma/adapter/primary/api/info/InfoV1ApiController.java new file mode 100644 index 000000000..fd1b1409d --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/primary/api/info/InfoV1ApiController.java @@ -0,0 +1,114 @@ +package it.chalmers.gamma.adapter.primary.api.info; + +import it.chalmers.gamma.adapter.primary.api.NotFoundResponse; +import it.chalmers.gamma.app.group.GroupFacade; +import it.chalmers.gamma.app.post.PostFacade; +import it.chalmers.gamma.app.supergroup.SuperGroupFacade; +import it.chalmers.gamma.app.user.UserFacade; +import java.util.List; +import java.util.UUID; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * Going to be used by chalmers.it to display groups and their members. A separate API since user + * info are going to be returned, and that should be used with caution. + */ +@RestController +@RequestMapping(InfoV1ApiController.URI) +public class InfoV1ApiController { + + public static final String URI = "/api/info/v1"; + + private final SuperGroupFacade superGroupFacade; + private final UserFacade userFacade; + + public InfoV1ApiController(SuperGroupFacade superGroupFacade, UserFacade userFacade) { + this.superGroupFacade = superGroupFacade; + this.userFacade = userFacade; + } + + @GetMapping("/users/{id}") + public UserFacade.UserWithGroupsDTO getUser(@PathVariable("id") UUID id) { + return this.userFacade.getWithGroups(id).orElseThrow(UserNotFoundResponse::new); + } + + public record BlobItem(String type, List superGroups) {} + + public record BlobSuperGroupWithMembers( + BlobSuperGroup superGroup, + boolean hasBanner, + boolean hasAvatar, + List members) { + + public BlobSuperGroupWithMembers(SuperGroupFacade.SuperGroupWithMembersDTO s) { + this( + new BlobSuperGroup(s.superGroup()), + s.hasBanner(), + s.hasAvatar(), + s.members().stream().map(BlobGroupMember::new).toList()); + } + } + + public record BlobSuperGroup( + UUID id, + String name, + String prettyName, + String type, + String svDescription, + String enDescription) { + + public BlobSuperGroup(SuperGroupFacade.SuperGroupDTO superGroup) { + this( + superGroup.id(), + superGroup.name(), + superGroup.prettyName(), + superGroup.type(), + superGroup.svDescription(), + superGroup.enDescription()); + } + } + + public record BlobGroupMember(BlobUser user, BlobPost post, String unofficialPostName) { + public BlobGroupMember(GroupFacade.GroupMemberDTO groupMember) { + this( + new BlobUser(groupMember.user()), + new BlobPost(groupMember.post()), + groupMember.unofficialPostName()); + } + } + + public record BlobUser( + String cid, String nick, String firstName, String lastName, UUID id, int acceptanceYear) { + public BlobUser(UserFacade.UserDTO user) { + this( + user.cid(), + user.nick(), + user.firstName(), + user.lastName(), + user.id(), + user.acceptanceYear()); + } + } + + public record BlobPost(UUID id, String svName, String enName, String emailPrefix) { + public BlobPost(PostFacade.PostDTO post) { + this(post.id(), post.svName(), post.enName(), post.emailPrefix()); + } + } + + @GetMapping("/blob") + public List getGroups() { + return this.superGroupFacade.getAllTypesWithSuperGroups().stream() + .map( + item -> + new BlobItem( + item.type(), + item.superGroups().stream().map(BlobSuperGroupWithMembers::new).toList())) + .toList(); + } + + private static class UserNotFoundResponse extends NotFoundResponse {} +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/primary/images/ImagesController.java b/app/src/main/java/it/chalmers/gamma/adapter/primary/images/ImagesController.java new file mode 100644 index 000000000..d6a86f17d --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/primary/images/ImagesController.java @@ -0,0 +1,81 @@ +package it.chalmers.gamma.adapter.primary.images; + +import it.chalmers.gamma.app.image.ImageFacade; +import java.util.UUID; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/images") +public class ImagesController { + + private final ImageFacade imageFacade; + + public ImagesController(ImageFacade imageFacade) { + this.imageFacade = imageFacade; + } + + @GetMapping("/user/avatar/{id}") + public ResponseEntity getUserAvatar(@PathVariable("id") UUID id) { + ImageFacade.ImageDetails imageDetails = this.imageFacade.getAvatar(id); + String type = imageDetails.imageType(); + return ResponseEntity.ok() + .contentType( + (type.equals("jpg") || type.equals("jpeg") + ? MediaType.IMAGE_JPEG + : type.equals("png") ? MediaType.IMAGE_PNG : MediaType.IMAGE_GIF)) + .body(imageDetails.data()); + } + + @GetMapping("/group/avatar/{id}") + public ResponseEntity getGroupAvatar(@PathVariable("id") UUID id) { + ImageFacade.ImageDetails imageDetails = this.imageFacade.getGroupAvatar(id); + String type = imageDetails.imageType(); + return ResponseEntity.ok() + .contentType( + (type.equals("jpg") || type.equals("jpeg") + ? MediaType.IMAGE_JPEG + : type.equals("png") ? MediaType.IMAGE_PNG : MediaType.IMAGE_GIF)) + .body(imageDetails.data()); + } + + @GetMapping("/group/banner/{id}") + public ResponseEntity getGroupBanner(@PathVariable("id") UUID id) { + ImageFacade.ImageDetails imageDetails = this.imageFacade.getGroupBanner(id); + String type = imageDetails.imageType(); + return ResponseEntity.ok() + .contentType( + (type.equals("jpg") || type.equals("jpeg") + ? MediaType.IMAGE_JPEG + : type.equals("png") ? MediaType.IMAGE_PNG : MediaType.IMAGE_GIF)) + .body(imageDetails.data()); + } + + @GetMapping("/super-group/avatar/{id}") + public ResponseEntity getSuperGroupAvatar(@PathVariable("id") UUID id) { + ImageFacade.ImageDetails imageDetails = this.imageFacade.getSuperGroupAvatar(id); + String type = imageDetails.imageType(); + return ResponseEntity.ok() + .contentType( + (type.equals("jpg") || type.equals("jpeg") + ? MediaType.IMAGE_JPEG + : type.equals("png") ? MediaType.IMAGE_PNG : MediaType.IMAGE_GIF)) + .body(imageDetails.data()); + } + + @GetMapping("/super-group/banner/{id}") + public ResponseEntity getSuperGroupBanner(@PathVariable("id") UUID id) { + ImageFacade.ImageDetails imageDetails = this.imageFacade.getSuperGroupBanner(id); + String type = imageDetails.imageType(); + return ResponseEntity.ok() + .contentType( + (type.equals("jpg") || type.equals("jpeg") + ? MediaType.IMAGE_JPEG + : type.equals("png") ? MediaType.IMAGE_PNG : MediaType.IMAGE_GIF)) + .body(imageDetails.data()); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/primary/web/AccountDeletedController.java b/app/src/main/java/it/chalmers/gamma/adapter/primary/web/AccountDeletedController.java new file mode 100644 index 000000000..55ce9dc99 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/primary/web/AccountDeletedController.java @@ -0,0 +1,13 @@ +package it.chalmers.gamma.adapter.primary.web; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; + +@Controller +public class AccountDeletedController { + + @GetMapping("/account-deleted") + public String getAccountDeleted() { + return "accountdeleted"; + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/primary/web/ActivationCodesController.java b/app/src/main/java/it/chalmers/gamma/adapter/primary/web/ActivationCodesController.java new file mode 100644 index 000000000..d54475edb --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/primary/web/ActivationCodesController.java @@ -0,0 +1,48 @@ +package it.chalmers.gamma.adapter.primary.web; + +import it.chalmers.gamma.app.user.activation.ActivationCodeFacade; +import java.util.List; +import org.springframework.stereotype.Controller; +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.RequestHeader; +import org.springframework.web.servlet.ModelAndView; + +@Controller +public class ActivationCodesController { + + private final ActivationCodeFacade activationCodeFacade; + + public ActivationCodesController(ActivationCodeFacade activationCodeFacade) { + this.activationCodeFacade = activationCodeFacade; + } + + @GetMapping("/activation-codes") + public ModelAndView getActivationCodes( + @RequestHeader(value = "HX-Request", required = false) boolean htmxRequest) { + List activationCodes = + this.activationCodeFacade.getAllUserActivations(); + + ModelAndView mv = new ModelAndView(); + if (htmxRequest) { + mv.setViewName("pages/activation-codes"); + } else { + mv.setViewName("index"); + mv.addObject("page", "pages/activation-codes"); + } + + mv.addObject("activationCodes", activationCodes); + + return mv; + } + + @DeleteMapping("/activation-codes/{cid}") + public ModelAndView deleteActivationCode( + @RequestHeader(value = "HX-Request", required = false) boolean htmxRequest, + @PathVariable("cid") String cid) { + this.activationCodeFacade.removeUserActivation(cid); + + return new ModelAndView("common/empty"); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/primary/web/AdminController.java b/app/src/main/java/it/chalmers/gamma/adapter/primary/web/AdminController.java new file mode 100644 index 000000000..e1e8bef9e --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/primary/web/AdminController.java @@ -0,0 +1,83 @@ +package it.chalmers.gamma.adapter.primary.web; + +import it.chalmers.gamma.app.admin.AdminFacade; +import it.chalmers.gamma.app.user.UserFacade; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.servlet.ModelAndView; + +@Controller +public class AdminController { + + private final UserFacade userFacade; + private final AdminFacade adminFacade; + + public AdminController(UserFacade userFacade, AdminFacade adminFacade) { + this.userFacade = userFacade; + this.adminFacade = adminFacade; + } + + @GetMapping("/admins") + public ModelAndView getAdmins( + @RequestHeader(value = "HX-Request", required = false) boolean htmxRequest) { + List admins = this.adminFacade.getAllAdmins(); + List users = + this.userFacade.getAll().stream() + .sorted( + (user1, user2) -> { + boolean user1Trained = admins.contains(user1.id()); + boolean user2Trained = admins.contains(user2.id()); + + if (user1Trained && !user2Trained) { + return -1; + } else if (!user1Trained && user2Trained) { + return 1; + } + + return user1.nick().compareToIgnoreCase(user2.nick()); + }) + .toList(); + + ModelAndView mv = new ModelAndView(); + if (htmxRequest) { + mv.setViewName("pages/admins"); + } else { + mv.setViewName("index"); + mv.addObject("page", "pages/admins"); + } + + mv.addObject("users", users); + mv.addObject("admins", admins); + + return mv; + } + + @PutMapping("/admins") + public ModelAndView setAdmins( + @RequestHeader(value = "HX-Request", required = false) boolean htmxRequest, + @RequestParam Map form) { + List oldAdmins = this.adminFacade.getAllAdmins(); + List formAdmins = + form.keySet().stream() + .filter(s -> !("_csrf".equals(s) || "_method".equals(s))) + .map(UUID::fromString) + .toList(); + + List noLongerAdmins = + oldAdmins.stream().filter(userId -> !formAdmins.contains(userId)).toList(); + + try { + this.adminFacade.updateAdmins(formAdmins, noLongerAdmins); + } catch (IllegalArgumentException e) { + return this.getAdmins(htmxRequest); + } + + return new ModelAndView("redirect:/admins"); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/primary/web/AllowListController.java b/app/src/main/java/it/chalmers/gamma/adapter/primary/web/AllowListController.java new file mode 100644 index 000000000..f749f28d1 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/primary/web/AllowListController.java @@ -0,0 +1,79 @@ +package it.chalmers.gamma.adapter.primary.web; + +import it.chalmers.gamma.app.user.activation.ActivationCodeFacade; +import it.chalmers.gamma.app.user.allowlist.AllowListFacade; +import it.chalmers.gamma.app.user.allowlist.AllowListRepository; +import java.util.Comparator; +import java.util.List; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.servlet.ModelAndView; + +@Controller +public class AllowListController { + + private final AllowListFacade allowListFacade; + private final ActivationCodeFacade activationCodeFacade; + + public AllowListController( + AllowListFacade allowListFacade, ActivationCodeFacade activationCodeFacade) { + this.allowListFacade = allowListFacade; + this.activationCodeFacade = activationCodeFacade; + } + + public record AllowListItem(String cid, boolean hasActivationCode) {} + + @GetMapping("/allow-list") + public ModelAndView getAllowList( + @RequestHeader(value = "HX-Request", required = false) boolean htmxRequest) { + ModelAndView mv = new ModelAndView(); + if (htmxRequest) { + mv.setViewName("pages/allow-list"); + } else { + mv.setViewName("index"); + mv.addObject("page", "pages/allow-list"); + } + + List allowList = this.allowListFacade.getAllowList(); + List activationList = + this.activationCodeFacade.getAllUserActivations().stream() + .map(ActivationCodeFacade.UserActivationDTO::cid) + .toList(); + + mv.addObject( + "allowList", + allowList.stream() + .sorted(Comparator.comparing(String::toLowerCase)) + .map(cid -> new AllowListItem(cid, activationList.contains(cid))) + .toList()); + + return mv; + } + + @PutMapping(value = "/allow-list") + public ModelAndView allow( + @RequestHeader(value = "HX-Request", required = false) boolean htmxRequest, + AllowCidForm request) { + try { + allowListFacade.allow(request.cid); + } catch (AllowListRepository.AlreadyAllowedException + | IllegalArgumentException + | AllowListFacade.AlreadyAUserException e) { + return getAllowList(htmxRequest); + } + + return new ModelAndView("redirect:/allow-list"); + } + + public record AllowCidForm(String cid) {} + + @DeleteMapping(value = "/allow-list/{cid}") + public ModelAndView removeCidFromAllowList( + @RequestHeader(value = "HX-Request", required = true) boolean htmxRequest, + @PathVariable("cid") String cid) { + + this.allowListFacade.removeFromAllowList(cid); + + return new ModelAndView("common/empty"); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/primary/web/ApiKeyController.java b/app/src/main/java/it/chalmers/gamma/adapter/primary/web/ApiKeyController.java new file mode 100644 index 000000000..d07457114 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/primary/web/ApiKeyController.java @@ -0,0 +1,295 @@ +package it.chalmers.gamma.adapter.primary.web; + +import static it.chalmers.gamma.adapter.primary.web.WebValidationHelper.validateObject; +import static it.chalmers.gamma.app.common.UUIDValidator.isValidUUID; + +import it.chalmers.gamma.app.apikey.ApiKeyFacade; +import it.chalmers.gamma.app.apikey.ApiKeySettingsFacade; +import it.chalmers.gamma.app.common.PrettyName.PrettyNameValidator; +import it.chalmers.gamma.app.supergroup.SuperGroupFacade; +import jakarta.annotation.Nullable; +import jakarta.servlet.http.HttpServletResponse; +import java.util.*; +import org.springframework.stereotype.Controller; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.servlet.ModelAndView; + +@Controller +public class ApiKeyController { + + private final ApiKeyFacade apiKeyFacade; + private final ApiKeySettingsFacade apiKeySettingsFacade; + private final SuperGroupFacade superGroupFacade; + + public ApiKeyController( + ApiKeyFacade apiKeyFacade, + ApiKeySettingsFacade apiKeySettingsFacade, + SuperGroupFacade superGroupFacade) { + this.apiKeyFacade = apiKeyFacade; + this.apiKeySettingsFacade = apiKeySettingsFacade; + this.superGroupFacade = superGroupFacade; + } + + @GetMapping("/api-keys") + public ModelAndView getApiKeys( + @RequestHeader(value = "HX-Request", required = false) boolean htmxRequest) { + List apiKeys = this.apiKeyFacade.getAll(); + + ModelAndView mv = new ModelAndView(); + if (htmxRequest) { + mv.setViewName("pages/api-keys"); + } else { + mv.setViewName("index"); + mv.addObject("page", "pages/api-keys"); + } + + mv.addObject("apiKeys", apiKeys); + + return mv; + } + + private ModelAndView createGetApiKey( + boolean htmxRequest, String apiKeyId, @Nullable String token) { + if (!isValidUUID(apiKeyId)) { + return createApiKeyNotFound(apiKeyId, htmxRequest); + } + + Optional maybeApiKey = + this.apiKeyFacade.getById(UUID.fromString(apiKeyId)); + + if (maybeApiKey.isEmpty()) { + return createApiKeyNotFound(apiKeyId, htmxRequest); + } + + ApiKeyFacade.ApiKeyDTO apiKey = maybeApiKey.get(); + ModelAndView mv = new ModelAndView(); + + if (htmxRequest) { + mv.setViewName("pages/api-key-details"); + } else { + mv.setViewName("index"); + mv.addObject("page", "pages/api-key-details"); + } + + mv.addObject("apiKey", apiKey); + mv.addObject("apiKeyId", apiKey.id()); + + if (apiKey.keyType().equals("ACCOUNT_SCAFFOLD")) { + loadApiKeySettingsAccountScaffold(mv, apiKey.id()); + } else if (apiKey.keyType().equals("INFO")) { + loadApiKeySettingsInfo(mv, apiKey.id()); + } + + if (token != null) { + mv.addObject("apiKeyToken", token); + } + + return mv; + } + + private void loadApiKeySettingsInfo(ModelAndView mv, UUID apiKeyId) { + var settings = this.apiKeySettingsFacade.getInfoSettings(apiKeyId); + + mv.addObject("settings_title", "Info settings"); + mv.addObject( + "settings_description", + "Set the super group types from which the information will be query from"); + mv.addObject( + "settings_form", new ApiKeySettingsForm(settings.version(), settings.superGroupTypes())); + } + + private void loadApiKeySettingsAccountScaffold(ModelAndView mv, UUID apiKeyId) { + var settings = this.apiKeySettingsFacade.getAccountScaffoldSettings(apiKeyId); + + mv.addObject("settings_title", "Account scaffold settings"); + mv.addObject( + "settings_description", + "Set the super group types from which the information will query from"); + mv.addObject( + "settings_form", new ApiKeySettingsForm(settings.version(), settings.superGroupTypes())); + } + + private ModelAndView createApiKeyNotFound(String apiKeyId, boolean htmxRequest) { + ModelAndView mv = new ModelAndView(); + if (htmxRequest) { + mv.setViewName("pages/api-key-not-found"); + } else { + mv.setViewName("index"); + mv.addObject("page", "pages/api-key-not-found"); + } + + mv.addObject("id", apiKeyId); + + return mv; + } + + public record ApiKeySettingsForm(int version, List superGroupTypes) {} + + @GetMapping("/api-keys/{id}") + public ModelAndView getApiKey( + @RequestHeader(value = "HX-Request", required = false) boolean htmxRequest, + @PathVariable("id") String apiKeyId) { + return createGetApiKey(htmxRequest, apiKeyId, null); + } + + public record CreateApiKey( + @ValidatedWith(PrettyNameValidator.class) String prettyName, + String svDescription, + String enDescription, + String keyType) {} + + public ModelAndView createGetCreateApiKey( + boolean htmxRequest, CreateApiKey form, BindingResult bindingResult) { + ModelAndView mv = new ModelAndView(); + + if (htmxRequest) { + mv.setViewName("create-api-key/page"); + } else { + mv.setViewName("index"); + mv.addObject("page", "create-api-key/page"); + } + + if (form == null) { + form = new CreateApiKey("", "", "", ""); + } + + mv.addObject("form", form); + mv.addObject("keyTypes", this.apiKeyFacade.getApiKeyTypes()); + + if (bindingResult != null && bindingResult.hasErrors()) { + mv.addObject(BindingResult.MODEL_KEY_PREFIX + "form", bindingResult); + } + + return mv; + } + + @GetMapping("/api-keys/create") + public ModelAndView getCreateApiKey( + @RequestHeader(value = "HX-Request", required = false) boolean htmxRequest) { + return createGetCreateApiKey(htmxRequest, null, null); + } + + @PostMapping("/api-keys/create") + public ModelAndView createApiKey( + @RequestHeader(value = "HX-Request", required = false) boolean htmxRequest, + CreateApiKey form, + BindingResult bindingResult, + HttpServletResponse response) { + ModelAndView mv = new ModelAndView(); + + validateObject(form, bindingResult); + + if (bindingResult.hasErrors()) { + return createGetCreateApiKey(htmxRequest, form, bindingResult); + } + + ApiKeyFacade.CreatedApiKey createdApiKey = + this.apiKeyFacade.create( + new ApiKeyFacade.NewApiKey( + form.prettyName, form.svDescription, form.enDescription, form.keyType)); + + String apiKeyId = createdApiKey.apiKey().id().toString(); + + response.addHeader("HX-Push-Url", "/api-keys/" + apiKeyId); + + return createGetApiKey(htmxRequest, apiKeyId, createdApiKey.token()); + } + + @DeleteMapping("/api-keys/{id}") + public ModelAndView deleteApiKey( + @RequestHeader(value = "HX-Request", required = false) boolean htmxRequest, + HttpServletResponse response, + @PathVariable("id") UUID id) { + try { + this.apiKeyFacade.delete(id); + } catch (ApiKeyFacade.ApiKeyNotFoundException e) { + throw new RuntimeException(e); + } + + response.addHeader("HX-Redirect", "/api-keys"); + + return new ModelAndView("common/empty"); + } + + public static final class ApiKeySettings { + public List superGroupTypes = new ArrayList<>(); + public int version; + + public List getSuperGroupTypes() { + return superGroupTypes; + } + + public void setSuperGroupTypes(List superGroupTypes) { + this.superGroupTypes = superGroupTypes; + } + + public int getVersion() { + return version; + } + + public void setVersion(int version) { + this.version = version; + } + } + + @GetMapping("/api-keys/new-super-group") + public ModelAndView getNewSuperGroupType( + @RequestHeader(value = "HX-Request", required = true) boolean htmxRequest) { + ModelAndView mv = new ModelAndView(); + + mv.setViewName("partial/new-super-group-type-to-api-settings"); + mv.addObject( + "superGroupTypes", + this.superGroupFacade.getAllTypes().stream() + .sorted(Comparator.comparing(String::toLowerCase)) + .toList()); + + return mv; + } + + @PutMapping("/api-keys/{apiKeyId}/settings") + public ModelAndView updateSettings( + @RequestHeader(value = "HX-Request", required = false) boolean htmxRequest, + @PathVariable("apiKeyId") UUID apiKeyId, + ApiKeySettings form) { + + Optional apiKeyMaybe = this.apiKeyFacade.getById(apiKeyId); + + if (apiKeyMaybe.isEmpty()) { + throw new RuntimeException(); + } + + ApiKeyFacade.ApiKeyDTO apiKey = apiKeyMaybe.get(); + + ModelAndView mv = new ModelAndView("partial/api-key-super-group-types"); + + if (apiKey.keyType().equals("ACCOUNT_SCAFFOLD")) { + this.apiKeySettingsFacade.setAccountScaffoldSettings( + apiKeyId, + new ApiKeySettingsFacade.ApiKeySettingsAccountScaffoldDTO( + form.version, form.superGroupTypes)); + + loadApiKeySettingsAccountScaffold(mv, apiKey.id()); + } else if (apiKey.keyType().equals("INFO")) { + this.apiKeySettingsFacade.setInfoSettings( + apiKeyId, + new ApiKeySettingsFacade.ApiKeySettingsInfoDTO(form.version, form.superGroupTypes)); + + loadApiKeySettingsInfo(mv, apiKey.id()); + } + + mv.addObject("apiKeyId", apiKeyId); + + return mv; + } + + @PostMapping("/api-keys/{apiKeyId}/reset") + public ModelAndView resetApiKeyToken( + @RequestHeader(value = "HX-Request", required = false) boolean htmxRequest, + @PathVariable("apiKeyId") UUID apiKeyId) { + String newToken = this.apiKeyFacade.resetApiKey(apiKeyId); + + return createGetApiKey(htmxRequest, apiKeyId.toString(), newToken); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/primary/web/ClientsController.java b/app/src/main/java/it/chalmers/gamma/adapter/primary/web/ClientsController.java new file mode 100644 index 000000000..43f357ed2 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/primary/web/ClientsController.java @@ -0,0 +1,538 @@ +package it.chalmers.gamma.adapter.primary.web; + +import static it.chalmers.gamma.adapter.primary.web.WebValidationHelper.validateObject; +import static it.chalmers.gamma.app.common.UUIDValidator.isValidUUID; + +import it.chalmers.gamma.app.client.ClientApprovalFacade; +import it.chalmers.gamma.app.client.ClientAuthorityFacade; +import it.chalmers.gamma.app.client.ClientFacade; +import it.chalmers.gamma.app.client.domain.ClientRedirectUrl.ClientRedirectUrlValidator; +import it.chalmers.gamma.app.client.domain.authority.AuthorityName.AuthorityNameValidator; +import it.chalmers.gamma.app.client.domain.authority.ClientAuthorityRepository; +import it.chalmers.gamma.app.common.PrettyName.PrettyNameValidator; +import it.chalmers.gamma.app.common.TextValue; +import it.chalmers.gamma.app.supergroup.SuperGroupFacade; +import it.chalmers.gamma.app.user.UserFacade; +import it.chalmers.gamma.security.authentication.AuthenticationExtractor; +import it.chalmers.gamma.security.authentication.UserAuthentication; +import jakarta.annotation.Nullable; +import jakarta.servlet.http.HttpServletResponse; +import java.util.*; +import java.util.stream.Collectors; +import org.springframework.stereotype.Controller; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.servlet.ModelAndView; + +@Controller +public class ClientsController { + + private final ClientFacade clientFacade; + private final ClientAuthorityFacade clientAuthorityFacade; + private final ClientApprovalFacade clientApprovalFacade; + private final SuperGroupFacade superGroupFacade; + private final UserFacade userFacade; + + public ClientsController( + ClientFacade clientFacade, + ClientAuthorityFacade clientAuthorityFacade, + ClientApprovalFacade clientApprovalFacade, + SuperGroupFacade superGroupFacade, + UserFacade userFacade) { + this.clientFacade = clientFacade; + this.clientAuthorityFacade = clientAuthorityFacade; + this.clientApprovalFacade = clientApprovalFacade; + this.superGroupFacade = superGroupFacade; + this.userFacade = userFacade; + } + + @GetMapping("/clients") + public ModelAndView getClients( + @RequestHeader(value = "HX-Request", required = false) boolean htmxRequest) { + List clients = this.clientFacade.getAll(); + + ModelAndView mv = new ModelAndView(); + if (htmxRequest) { + mv.setViewName("pages/official-clients"); + } else { + mv.setViewName("index"); + mv.addObject("page", "pages/official-clients"); + } + mv.addObject( + "clients", + clients.stream() + .filter(client -> client.owner() instanceof ClientFacade.ClientDTO.OfficialOwner) + .toList()); + + return mv; + } + + private ModelAndView createGetClient( + boolean htmxRequest, + String clientUid, + @Nullable String clientSecret, + @Nullable String apiKeyToken) { + if (!isValidUUID(clientUid)) { + return createClientNotFound(clientUid, htmxRequest); + } + + UUID uid = UUID.fromString(clientUid); + + Optional client = this.clientFacade.get(uid); + + ModelAndView mv = new ModelAndView(); + if (client.isEmpty()) { + return createClientNotFound(clientUid, htmxRequest); + } + + List clientAuthorities = + this.clientAuthorityFacade.getAll(uid); + List userApprovals = this.clientApprovalFacade.getApprovalsForClient(uid); + + if (htmxRequest) { + mv.setViewName("client-details/page"); + } else { + mv.setViewName("index"); + mv.addObject("page", "client-details/page"); + } + mv.addObject("clientUid", client.get().clientUid()); + mv.addObject("client", client.get()); + mv.addObject("clientAuthorities", clientAuthorities); + mv.addObject( + "userApprovals", + userApprovals.stream() + .sorted(Comparator.comparing(user -> user.nick().toLowerCase())) + .toList()); + + if (client.get().owner() instanceof ClientFacade.ClientDTO.UserOwner userOwner) { + if (AuthenticationExtractor.getAuthentication() instanceof UserAuthentication userPrincipal) { + boolean isOwner = userOwner.user().id().equals(userPrincipal.gammaUser().id().value()); + mv.addObject("amIOwner", isOwner); + + if (!isOwner) { + mv.addObject("owner", userOwner.user()); + } + } + } + + mv.addObject("clientSecret", clientSecret); + mv.addObject("apiKeyToken", apiKeyToken); + + return mv; + } + + private ModelAndView createClientNotFound(String clientUid, boolean htmxRequest) { + ModelAndView mv = new ModelAndView(); + if (htmxRequest) { + mv.setViewName("client-details/not-found"); + } else { + mv.setViewName("index"); + mv.addObject("page", "client-details/not-found"); + } + + mv.addObject("id", clientUid); + + return mv; + } + + @GetMapping("/clients/{id}") + public ModelAndView getClient( + @RequestHeader(value = "HX-Request", required = false) boolean htmxRequest, + @PathVariable("id") String clientUid) { + return createGetClient(htmxRequest, clientUid, null, null); + } + + public static final class CreateClient { + + @ValidatedWith(ClientRedirectUrlValidator.class) + private String redirectUrl; + + @ValidatedWith(PrettyNameValidator.class) + private String prettyName; + + @ValidatedWith(TextValue.TextValueValidator.class) + private String svDescription; + + @ValidatedWith(TextValue.TextValueValidator.class) + private String enDescription; + + private boolean generateApiKey; + private boolean emailScope; + + private List restrictions; + + public CreateClient() { + this("", "", "", "", false, false, new ArrayList<>()); + } + + public CreateClient( + String redirectUrl, + String prettyName, + String svDescription, + String enDescription, + boolean generateApiKey, + boolean emailScope, + List restrictions) { + this.redirectUrl = redirectUrl; + this.prettyName = prettyName; + this.svDescription = svDescription; + this.enDescription = enDescription; + this.generateApiKey = generateApiKey; + this.emailScope = emailScope; + this.restrictions = restrictions; + } + + public String getRedirectUrl() { + return redirectUrl; + } + + public void setRedirectUrl(String redirectUrl) { + this.redirectUrl = redirectUrl; + } + + public String getPrettyName() { + return prettyName; + } + + public void setPrettyName(String prettyName) { + this.prettyName = prettyName; + } + + public String getSvDescription() { + return svDescription; + } + + public void setSvDescription(String svDescription) { + this.svDescription = svDescription; + } + + public String getEnDescription() { + return enDescription; + } + + public void setEnDescription(String enDescription) { + this.enDescription = enDescription; + } + + public boolean isGenerateApiKey() { + return generateApiKey; + } + + public void setGenerateApiKey(boolean generateApiKey) { + this.generateApiKey = generateApiKey; + } + + public boolean isEmailScope() { + return emailScope; + } + + public void setEmailScope(boolean emailScope) { + this.emailScope = emailScope; + } + + public List getRestrictions() { + return restrictions; + } + + public void setRestrictions(List restrictions) { + this.restrictions = restrictions; + } + } + + public ModelAndView createGetCreateClient( + boolean htmxRequest, CreateClient form, BindingResult bindingResult) { + ModelAndView mv = new ModelAndView(); + + if (form == null) { + form = new CreateClient(); + } + + if (htmxRequest) { + mv.setViewName("create-client/page"); + } else { + mv.setViewName("index"); + mv.addObject("page", "create-client/page"); + } + + mv.addObject("form", form); + + if (bindingResult != null && bindingResult.hasErrors()) { + mv.addObject(BindingResult.MODEL_KEY_PREFIX + "form", bindingResult); + } + + return mv; + } + + @GetMapping("/clients/create") + public ModelAndView getCreateClient( + @RequestHeader(value = "HX-Request", required = false) boolean htmxRequest) { + return createGetCreateClient(htmxRequest, null, null); + } + + @GetMapping("/clients/create/new-restriction") + public ModelAndView newRestrictionRow( + @RequestHeader(value = "HX-Request", required = true) boolean htmxRequest) { + ModelAndView mv = new ModelAndView(); + + mv.setViewName("create-client/add-restriction-to-client"); + + mv.addObject( + "superGroups", + this.superGroupFacade.getAll().stream() + .collect( + Collectors.toMap( + SuperGroupFacade.SuperGroupDTO::id, + SuperGroupFacade.SuperGroupDTO::prettyName))); + mv.addObject( + "superGroupKeys", + this.superGroupFacade.getAll().stream() + .sorted(Comparator.comparing(superGroup -> superGroup.prettyName().toLowerCase())) + .map(SuperGroupFacade.SuperGroupDTO::id) + .toList()); + + return mv; + } + + @PostMapping("/clients/create") + public ModelAndView getCreateClient( + @RequestHeader(value = "HX-Request", required = true) boolean htmxRequest, + CreateClient form, + BindingResult bindingResult, + HttpServletResponse response) { + + validateObject(form, bindingResult); + + if (bindingResult.hasErrors()) { + return createGetCreateClient(htmxRequest, form, bindingResult); + } + + ModelAndView mv = new ModelAndView(); + + ClientFacade.CreatedClientDTO result = + this.clientFacade.createOfficialClient( + new ClientFacade.NewClient( + form.redirectUrl, + form.prettyName, + form.svDescription, + form.enDescription, + form.generateApiKey, + form.emailScope, + new ClientFacade.NewClientRestrictions(form.restrictions))); + + mv.setViewName("client-details/page"); + + response.addHeader("HX-Push-Url", "/clients/" + result.client().clientUid()); + + return createGetClient( + htmxRequest, + result.client().clientUid().toString(), + result.clientSecret(), + result.apiKeyToken()); + } + + @GetMapping("/clients/{id}/authorities") + public ModelAndView getEditAuthorities( + @RequestHeader(value = "HX-Request", required = true) boolean htmxRequest, + @PathVariable("id") UUID clientUid) { + Optional client = this.clientFacade.get(clientUid); + + if (client.isEmpty()) { + throw new RuntimeException(); + } + + List clientAuthorities = + clientAuthorityFacade.getAll(client.get().clientUid()); + + ModelAndView mv = new ModelAndView(); + + mv.setViewName("client-details/page :: client-authorities"); + mv.addObject("client", client.get()); + mv.addObject("clientAuthorities", clientAuthorities); + + return mv; + } + + @GetMapping("/clients/{id}/new-authority") + public ModelAndView newAuthority( + @RequestHeader(value = "HX-Request", required = true) boolean htmxRequest, + @PathVariable("id") UUID clientUid) { + Optional client = this.clientFacade.get(clientUid); + + if (client.isEmpty()) { + throw new RuntimeException(); + } + + ModelAndView mv = new ModelAndView(); + + mv.setViewName("client-details/add-authority-to-client"); + mv.addObject("client", client.get()); + + return mv; + } + + @GetMapping("/clients/authority/new-super-group") + public ModelAndView newSuperGroupAuthority( + @RequestHeader(value = "HX-Request", required = true) boolean htmxRequest) { + ModelAndView mv = new ModelAndView(); + + mv.setViewName("client-details/add-super-group-authority-to-client"); + + mv.addObject( + "superGroups", + this.superGroupFacade.getAll().stream() + .collect( + Collectors.toMap( + SuperGroupFacade.SuperGroupDTO::id, + SuperGroupFacade.SuperGroupDTO::prettyName))); + + return mv; + } + + @GetMapping("/clients/authority/new-user") + public ModelAndView newUserToAuthority( + @RequestHeader(value = "HX-Request", required = true) boolean htmxRequest) { + ModelAndView mv = new ModelAndView(); + + mv.setViewName("client-details/add-user-authority-to-client"); + + mv.addObject( + "users", + this.userFacade.getAll().stream() + .collect(Collectors.toMap(UserFacade.UserDTO::id, UserFacade.UserDTO::nick))); + + return mv; + } + + public static final class CreateAuthority { + private List superGroups; + private List users; + + @ValidatedWith(AuthorityNameValidator.class) + private String authority; + + public List getSuperGroups() { + return superGroups; + } + + public void setSuperGroups(List superGroups) { + this.superGroups = superGroups; + } + + public List getUsers() { + return users; + } + + public void setUsers(List users) { + this.users = users; + } + + public String getAuthority() { + return authority; + } + + public void setAuthority(String authority) { + this.authority = authority; + } + } + + @PostMapping("/clients/{id}/authority") + public ModelAndView createAuthority( + @RequestHeader(value = "HX-Request", required = true) boolean htmxRequest, + @PathVariable("id") UUID clientUid, + CreateAuthority form, + BindingResult bindingResult) { + + validateObject(form, bindingResult); + + if (bindingResult.hasErrors()) {} + + try { + this.clientAuthorityFacade.create(clientUid, form.authority); + } catch (ClientAuthorityRepository.ClientAuthorityAlreadyExistsException e) { + throw new RuntimeException(e); + } + + List superGroups = new ArrayList<>(); + List users = new ArrayList<>(); + + if (form.superGroups != null) { + form.superGroups.forEach( + superGroup -> { + try { + this.clientAuthorityFacade.addSuperGroupToClientAuthority( + clientUid, form.authority, superGroup); + } catch (ClientAuthorityFacade.ClientAuthorityNotFoundException + | ClientAuthorityFacade.SuperGroupNotFoundException e) { + throw new RuntimeException(e); + } + + superGroups.add(this.superGroupFacade.get(superGroup).orElseThrow()); + }); + } + + if (form.users != null) { + form.users.forEach( + user -> { + try { + this.clientAuthorityFacade.addUserToClientAuthority(clientUid, form.authority, user); + } catch (ClientAuthorityFacade.ClientAuthorityNotFoundException + | ClientAuthorityFacade.UserNotFoundException e) { + throw new RuntimeException(e); + } + + users.add(this.userFacade.getWithGroups(user).orElseThrow().user()); + }); + } + + ModelAndView mv = new ModelAndView("client-details/created-client-authority"); + + mv.addObject("clientUid", clientUid); + mv.addObject( + "clientAuthority", + new ClientAuthorityFacade.ClientAuthorityDTO( + clientUid, form.authority, superGroups, users)); + + return mv; + } + + @DeleteMapping("/clients/{id}") + public ModelAndView deleteClient( + @RequestHeader(value = "HX-Request", required = true) boolean htmxRequest, + @RequestHeader(value = "owner", required = false) boolean wasOwner, + @PathVariable("id") UUID clientUid) { + try { + this.clientFacade.delete(clientUid); + } catch (ClientFacade.ClientNotFoundException e) { + throw new RuntimeException(e); + } + + if (wasOwner) { + return new ModelAndView("redirect:/my-clients"); + } else { + return new ModelAndView("redirect:/clients"); + } + } + + @DeleteMapping("/clients/{id}/authority/{name}") + public ModelAndView deleteClientAuthority( + @RequestHeader(value = "HX-Request", required = true) boolean htmxRequest, + @PathVariable("id") UUID clientUid, + @PathVariable("name") String authorityName) { + try { + this.clientAuthorityFacade.delete(clientUid, authorityName); + } catch (ClientAuthorityFacade.ClientAuthorityNotFoundException e) { + throw new RuntimeException(e); + } + + return new ModelAndView("client-details/deleted-client-authority"); + } + + @PostMapping("/clients/{uid}/reset") + public ModelAndView resetClientSecret( + @RequestHeader(value = "HX-Request", required = true) boolean htmxRequest, + @PathVariable("uid") UUID clientUid) { + String clientSecret = this.clientFacade.resetClientSecret(clientUid); + + return createGetClient(htmxRequest, clientUid.toString(), clientSecret, null); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/primary/web/ConsentController.java b/app/src/main/java/it/chalmers/gamma/adapter/primary/web/ConsentController.java new file mode 100644 index 000000000..61687836f --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/primary/web/ConsentController.java @@ -0,0 +1,115 @@ +package it.chalmers.gamma.adapter.primary.web; + +import static it.chalmers.gamma.app.oauth2.GammaRegisteredClientRepository.IS_OFFICIAL; + +import it.chalmers.gamma.app.client.ClientFacade; +import it.chalmers.gamma.app.user.UserFacade; +import java.util.Arrays; +import java.util.List; +import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames; +import org.springframework.security.oauth2.server.authorization.client.RegisteredClient; +import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.servlet.ModelAndView; + +@Controller +public class ConsentController { + + private final RegisteredClientRepository registeredClientRepository; + private final ClientFacade clientFacade; + + public ConsentController( + RegisteredClientRepository registeredClientRepository, ClientFacade clientFacade) { + this.registeredClientRepository = registeredClientRepository; + this.clientFacade = clientFacade; + } + + public record UserOwner(String name) {} + + public ModelAndView createClientIssuesModelAndView( + boolean htmxRequest, String title, String description) { + ModelAndView mv = new ModelAndView(); + + if (htmxRequest) { + mv.setViewName("pages/client-authorizing-issue"); + } else { + mv.setViewName("index"); + mv.addObject("page", "pages/client-authorizing-issue"); + } + + mv.addObject("title", title); + mv.addObject("description", description); + + return mv; + } + + @GetMapping("/oauth2/consent") + public ModelAndView getOAuth2Consent( + @RequestHeader(value = "HX-Request", required = false) boolean htmxRequest, + @RequestParam(value = OAuth2ParameterNames.CLIENT_ID, required = false) String clientId, + @RequestParam(value = OAuth2ParameterNames.SCOPE, required = false) String scope, + @RequestParam(value = OAuth2ParameterNames.STATE, required = false) String state) { + + if (clientId == null) { + return createClientIssuesModelAndView( + htmxRequest, "Client id missing", "A client_id must be provided to authorize"); + } + + if (scope == null) { + return createClientIssuesModelAndView( + htmxRequest, "Client scopes missing", "A scope must be specified to authorize."); + } + + if (state == null) { + return createClientIssuesModelAndView( + htmxRequest, "Client state missing", "A state must be specified to authorize."); + } + + RegisteredClient client = this.registeredClientRepository.findByClientId(clientId); + ModelAndView mv = new ModelAndView(); + + if (client == null) { + return createClientIssuesModelAndView( + htmxRequest, "Client not found", "A client with the given client id was not found."); + } + + List scopesList = Arrays.stream(scope.split(" ")).sorted().toList(); + List clientScopesOrdered = client.getScopes().stream().sorted().toList(); + + if (!scopesList.equals(clientScopesOrdered)) { + return createClientIssuesModelAndView( + htmxRequest, + "Mismatch scopes for client", + "There is a mismatch between registered client scopes, and the scopes specified for this authorization."); + } + + if (htmxRequest) { + mv.setViewName("pages/authorize"); + } else { + mv.setViewName("index"); + mv.addObject("page", "pages/authorize"); + } + + mv.addObject("clientId", clientId); + mv.addObject("clientName", client.getClientName()); + mv.addObject("state", state); + mv.addObject("hasEmailScope", scope.contains("email")); + mv.addObject("scopes", scope.split(" ")); + + boolean isOfficial = client.getClientSettings().getSetting(IS_OFFICIAL); + + if (!isOfficial) { + UserFacade.UserDTO owner = + this.clientFacade.getClientOwner(client.getClientId()).orElseThrow(); + + mv.addObject( + "userOwner", + new UserOwner("%s '%s' %s".formatted(owner.firstName(), owner.nick(), owner.lastName()))); + } + + return mv; + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/primary/web/DeleteYourAccountController.java b/app/src/main/java/it/chalmers/gamma/adapter/primary/web/DeleteYourAccountController.java new file mode 100644 index 000000000..87dd1d97a --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/primary/web/DeleteYourAccountController.java @@ -0,0 +1,59 @@ +package it.chalmers.gamma.adapter.primary.web; + +import it.chalmers.gamma.app.user.MeFacade; +import org.springframework.stereotype.Controller; +import org.springframework.validation.BindingResult; +import org.springframework.validation.FieldError; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.servlet.ModelAndView; + +@Controller +public class DeleteYourAccountController { + + private final MeFacade meFacade; + + public DeleteYourAccountController(MeFacade meFacade) { + this.meFacade = meFacade; + } + + public record DeleteYourAccountForm(String password) {} + + @GetMapping("/delete-your-account") + public ModelAndView getDeleteYourAccount( + @RequestHeader(value = "HX-Request", required = false) boolean htmxRequest) { + ModelAndView mv = new ModelAndView(); + + if (htmxRequest) { + mv.setViewName("pages/delete-your-account"); + } else { + mv.setViewName("index"); + mv.addObject("page", "pages/delete-your-account"); + } + + mv.addObject("form", new DeleteYourAccountForm("")); + + return mv; + } + + @DeleteMapping("/delete-your-account") + public ModelAndView deleteYourAccount( + DeleteYourAccountForm form, final BindingResult bindingResult) { + try { + this.meFacade.deleteMe(form.password); + } catch (IllegalArgumentException e) { + bindingResult.addError(new FieldError("form", "password", "Incorrect password")); + + ModelAndView mv = new ModelAndView(); + + mv.setViewName("pages/delete-your-account"); + mv.addObject("form", new DeleteYourAccountForm("")); + mv.addObject(BindingResult.MODEL_KEY_PREFIX + "form", bindingResult); + + return mv; + } + + return new ModelAndView("redirect:/login?deleted"); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/primary/web/ForgotPasswordController.java b/app/src/main/java/it/chalmers/gamma/adapter/primary/web/ForgotPasswordController.java new file mode 100644 index 000000000..f32f37165 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/primary/web/ForgotPasswordController.java @@ -0,0 +1,157 @@ +package it.chalmers.gamma.adapter.primary.web; + +import static it.chalmers.gamma.adapter.primary.web.WebValidationHelper.validateObject; + +import it.chalmers.gamma.app.common.Email.EmailValidator; +import it.chalmers.gamma.app.user.domain.Cid.CidValidator; +import it.chalmers.gamma.app.user.passwordreset.UserResetPasswordFacade; +import it.chalmers.gamma.app.user.passwordreset.domain.PasswordResetRepository; +import it.chalmers.gamma.app.validation.FailedValidation; +import it.chalmers.gamma.app.validation.SuccessfulValidation; +import it.chalmers.gamma.app.validation.ValidationResult; +import it.chalmers.gamma.app.validation.Validator; +import org.springframework.stereotype.Controller; +import org.springframework.validation.BindingResult; +import org.springframework.validation.ObjectError; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.servlet.ModelAndView; + +@Controller +public class ForgotPasswordController { + + private final UserResetPasswordFacade userResetPasswordFacade; + + public ForgotPasswordController(UserResetPasswordFacade userResetPasswordFacade) { + this.userResetPasswordFacade = userResetPasswordFacade; + } + + public static final class IdentifierValidator implements Validator { + + @Override + public ValidationResult validate(String value) { + if (new CidValidator().validate(value) instanceof SuccessfulValidation) { + return new SuccessfulValidation(); + } else if (new EmailValidator().validate(value) instanceof SuccessfulValidation) { + return new SuccessfulValidation(); + } + + return new FailedValidation("Neither a valid cid or email"); + } + } + + public record ForgotPassword(@ValidatedWith(IdentifierValidator.class) String cidOrEmail) {} + + public ModelAndView createGetForgotPassword( + boolean htmxRequest, ForgotPassword form, BindingResult bindingResult, boolean hasSent) { + ModelAndView mv = new ModelAndView(); + + if (htmxRequest) { + mv.setViewName("pages/forgot-password"); + } else { + mv.setViewName("index"); + mv.addObject("page", "pages/forgot-password"); + } + + mv.addObject("form", form); + mv.addObject("hasSent", hasSent); + + if (bindingResult != null && bindingResult.hasErrors()) { + mv.addObject(BindingResult.MODEL_KEY_PREFIX + "form", bindingResult); + } + + return mv; + } + + @GetMapping("/forgot-password") + public ModelAndView getForgotPassword( + @RequestHeader(value = "HX-Request", required = false) boolean htmxRequest) { + return createGetForgotPassword(htmxRequest, new ForgotPassword(""), null, false); + } + + @PostMapping("/forgot-password") + public ModelAndView sendForgotPassword( + @RequestHeader(value = "HX-Request", required = false) boolean htmxRequest, + ForgotPassword form, + final BindingResult bindingResult) { + form = new ForgotPassword(form.cidOrEmail.toLowerCase()); + + validateObject(form, bindingResult); + + if (bindingResult.hasErrors()) { + return createGetForgotPassword(htmxRequest, form, bindingResult, false); + } + + this.userResetPasswordFacade.startResetPasswordProcess(form.cidOrEmail); + + return createGetForgotPassword(htmxRequest, form, bindingResult, true); + } + + public ModelAndView createGetFinalizeForgotPassword( + boolean htmxRequest, FinalizeForgotPassword form, BindingResult bindingResult) { + ModelAndView mv = new ModelAndView(); + + if (htmxRequest) { + mv.setViewName("pages/finalize-forgot-password"); + } else { + mv.setViewName("index"); + mv.addObject("page", "pages/finalize-forgot-password"); + } + + mv.addObject("form", form); + + if (bindingResult != null && bindingResult.hasErrors()) { + mv.addObject(BindingResult.MODEL_KEY_PREFIX + "form", bindingResult); + } + + return mv; + } + + @GetMapping("/forgot-password/finalize") + public ModelAndView getFinalizeForgotPassword( + @RequestHeader(value = "HX-Request", required = false) boolean htmxRequest, + @RequestParam(value = "token", required = true) String token) { + if (!this.userResetPasswordFacade.isValidToken(token)) { + ModelAndView mv = new ModelAndView(); + if (htmxRequest) { + mv.setViewName("pages/password-reset-token-bad"); + } else { + mv.setViewName("index"); + mv.addObject("page", "pages/password-reset-token-bad"); + } + + return mv; + } + + FinalizeForgotPassword form = new FinalizeForgotPassword(token, "", ""); + + return createGetFinalizeForgotPassword(htmxRequest, form, null); + } + + public record FinalizeForgotPassword(String token, String password, String confirmPassword) {} + + @PostMapping("/forgot-password/finalize") + public ModelAndView finalizeForgotPassword( + @RequestHeader(value = "HX-Request", required = false) boolean htmxRequest, + FinalizeForgotPassword form, + BindingResult bindingResult) { + try { + this.userResetPasswordFacade.finishResetPasswordProcess( + form.token, form.password, form.confirmPassword); + } catch (IllegalArgumentException e) { + bindingResult.addError(new ObjectError("global", e.getMessage())); + } catch (PasswordResetRepository.TokenNotFoundRuntimeException e) { + bindingResult.addError( + new ObjectError("global", "Token has expired, please restart the reset flow.")); + } + + if (bindingResult.hasErrors()) { + return createGetFinalizeForgotPassword( + htmxRequest, new FinalizeForgotPassword(form.token, "", ""), bindingResult); + } + + return new ModelAndView("redirect:/login?password-reset"); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/primary/web/GammaErrorController.java b/app/src/main/java/it/chalmers/gamma/adapter/primary/web/GammaErrorController.java new file mode 100644 index 000000000..8d6f82611 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/primary/web/GammaErrorController.java @@ -0,0 +1,56 @@ +package it.chalmers.gamma.adapter.primary.web; + +import it.chalmers.gamma.app.oauth2.GammaAuthorizationService; +import jakarta.servlet.RequestDispatcher; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.web.servlet.error.ErrorController; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.servlet.ModelAndView; + +@Controller +public class GammaErrorController implements ErrorController { + + private static final Logger LOGGER = LoggerFactory.getLogger(GammaErrorController.class); + + @GetMapping("/error") + public ModelAndView handleRuntimeException( + @RequestHeader(value = "HX-Request", required = false) boolean htmxRequest, + HttpServletResponse response, + HttpServletRequest request) { + Object statusCodeString = request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE); + + int statusCode = statusCodeString == null ? 500 : Integer.parseInt(statusCodeString.toString()); + + Exception exception = (Exception) request.getAttribute(RequestDispatcher.ERROR_EXCEPTION); + if (exception != null) { + LOGGER.error("Caught error, rendering error page...", exception); + } + + String page = "pages/error"; + + if (HttpStatus.valueOf(statusCode) == HttpStatus.NOT_FOUND) { + page = "pages/404"; + } else if (exception instanceof GammaAuthorizationService.UserNotAllowedRuntimeException) { + page = "pages/no-access-to-client"; + } + + ModelAndView mv = new ModelAndView(); + if (htmxRequest) { + response.addHeader("HX-Retarget", "body"); + response.addHeader("HX-Reswap", "innerHTML"); + + mv.setViewName(page); + } else { + mv.setViewName("index"); + mv.addObject("page", page); + } + + return mv; + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/primary/web/GdprController.java b/app/src/main/java/it/chalmers/gamma/adapter/primary/web/GdprController.java new file mode 100644 index 000000000..241fc5c6d --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/primary/web/GdprController.java @@ -0,0 +1,87 @@ +package it.chalmers.gamma.adapter.primary.web; + +import it.chalmers.gamma.app.user.UserFacade; +import it.chalmers.gamma.app.user.UserGdprTrainingFacade; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.servlet.ModelAndView; + +@Controller +public class GdprController { + + private final UserFacade userFacade; + private final UserGdprTrainingFacade userGdprTrainingFacade; + + public GdprController(UserFacade userFacade, UserGdprTrainingFacade userGdprTrainingFacade) { + this.userFacade = userFacade; + this.userGdprTrainingFacade = userGdprTrainingFacade; + } + + @GetMapping("/gdpr") + public ModelAndView getAlLGdprTrained( + @RequestHeader(value = "HX-Request", required = false) boolean htmxRequest) { + List gdprTrained = this.userGdprTrainingFacade.getGdprTrained(); + List users = + this.userFacade.getAll().stream() + .sorted( + (user1, user2) -> { + boolean user1Trained = gdprTrained.contains(user1.id()); + boolean user2Trained = gdprTrained.contains(user2.id()); + + if (user1Trained && !user2Trained) { + return -1; + } else if (!user1Trained && user2Trained) { + return 1; + } + + return user1.nick().compareToIgnoreCase(user2.nick()); + }) + .toList(); + + ModelAndView mv = new ModelAndView(); + if (htmxRequest) { + mv.setViewName("pages/gdpr"); + } else { + mv.setViewName("index"); + mv.addObject("page", "pages/gdpr"); + } + + mv.addObject("users", users); + mv.addObject("gdprTrained", gdprTrained); + + return mv; + } + + @PutMapping("/gdpr") + public ModelAndView setGdprTrained( + @RequestHeader(value = "HX-Request", required = false) boolean htmxRequest, + @RequestParam Map form) { + List gdprTrained = this.userGdprTrainingFacade.getGdprTrained(); + List newGdprTrained = + form.keySet().stream() + .filter(s -> !("_csrf".equals(s) || "_method".equals(s))) + .map(UUID::fromString) + .toList(); + + List newlyTrained = + newGdprTrained.stream().filter(userId -> !gdprTrained.contains(userId)).toList(); + List noLongerTrained = + gdprTrained.stream().filter(userId -> !newGdprTrained.contains(userId)).toList(); + + for (UUID userId : newlyTrained) { + this.userGdprTrainingFacade.updateGdprTrainedStatus(userId, true); + } + + for (UUID userId : noLongerTrained) { + this.userGdprTrainingFacade.updateGdprTrainedStatus(userId, false); + } + + return new ModelAndView("redirect:/gdpr"); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/primary/web/GroupsController.java b/app/src/main/java/it/chalmers/gamma/adapter/primary/web/GroupsController.java new file mode 100644 index 000000000..becfb78bf --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/primary/web/GroupsController.java @@ -0,0 +1,568 @@ +package it.chalmers.gamma.adapter.primary.web; + +import static it.chalmers.gamma.adapter.primary.web.WebValidationHelper.validateObject; +import static it.chalmers.gamma.app.common.UUIDValidator.isValidUUID; + +import it.chalmers.gamma.app.common.PrettyName.PrettyNameValidator; +import it.chalmers.gamma.app.group.GroupFacade; +import it.chalmers.gamma.app.group.domain.UnofficialPostName; +import it.chalmers.gamma.app.post.PostFacade; +import it.chalmers.gamma.app.supergroup.SuperGroupFacade; +import it.chalmers.gamma.app.user.UserFacade; +import it.chalmers.gamma.app.user.domain.Name.NameValidator; +import jakarta.servlet.http.HttpServletResponse; +import java.util.*; +import java.util.stream.Collectors; +import org.springframework.beans.propertyeditors.StringTrimmerEditor; +import org.springframework.data.util.Pair; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Controller; +import org.springframework.validation.BindingResult; +import org.springframework.validation.FieldError; +import org.springframework.web.bind.WebDataBinder; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.servlet.ModelAndView; + +@Controller +public class GroupsController { + + private final GroupFacade groupFacade; + private final SuperGroupFacade superGroupFacade; + private final UserFacade userFacade; + private final PostFacade postFacade; + + public GroupsController( + GroupFacade groupFacade, + SuperGroupFacade superGroupFacade, + UserFacade userFacade, + PostFacade postFacade) { + this.groupFacade = groupFacade; + this.superGroupFacade = superGroupFacade; + this.userFacade = userFacade; + this.postFacade = postFacade; + } + + @InitBinder + public void initBinder(WebDataBinder binder) { + binder.registerCustomEditor(String.class, new StringTrimmerEditor(true)); + } + + @GetMapping("/groups") + public ModelAndView getGroups( + @RequestHeader(value = "HX-Request", required = false) boolean htmxRequest) { + List groups = this.groupFacade.getAll(); + + ModelAndView mv = new ModelAndView(); + if (htmxRequest) { + mv.setViewName("groups/page"); + } else { + mv.setViewName("index"); + mv.addObject("page", "groups/page"); + } + + mv.addObject( + "groups", + groups.stream() + .sorted(Comparator.comparing(group -> group.prettyName().toLowerCase())) + .toList()); + + return mv; + } + + public record Member(String name, String post, UUID postId, UUID userId) {} + + public static class MyMembershipsForm { + + private MyMembershipsForm() { + this.postNames = new HashMap<>(); + } + + private Map postNames; + + public Map getPostNames() { + return postNames; + } + + public void setPostNames(Map postNames) { + this.postNames = postNames; + } + } + + @GetMapping("/groups/{id}") + public ModelAndView getGroup( + @RequestHeader(value = "HX-Request", required = false) boolean htmxRequest, + @PathVariable("id") String groupId) { + if (!isValidUUID(groupId)) { + return createGroupNotFound(groupId, htmxRequest); + } + + Optional group = + this.groupFacade.getWithMembers(UUID.fromString(groupId)); + + ModelAndView mv = new ModelAndView(); + if (group.isEmpty()) { + return createGroupNotFound(groupId, htmxRequest); + } + + if (htmxRequest) { + mv.setViewName("group-details/page"); + } else { + mv.setViewName("index"); + mv.addObject("page", "group-details/page"); + } + + mv.addObject("group", group.get()); + mv.addObject( + "members", + group.get().groupMembers().stream() + .map( + groupMember -> { + String post = groupMember.post().enName(); + + if (groupMember.unofficialPostName() != null) { + post += " - " + groupMember.unofficialPostName(); + } + + return new Member( + groupMember.user().nick(), + post, + groupMember.post().id(), + groupMember.user().id()); + }) + .toList()); + mv.addObject("random", Math.random()); + + boolean canEditImages = false; + if (SecurityContextHolder.getContext().getAuthentication() + instanceof UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken) { + UUID myUserId = UUID.fromString(usernamePasswordAuthenticationToken.getName()); + + canEditImages = + group.get().groupMembers().stream() + .anyMatch(groupMember -> groupMember.user().id().equals(myUserId)); + + List myGroupMembers = + group.get().groupMembers().stream() + .filter(groupMember -> groupMember.user().id().equals(myUserId)) + .toList(); + mv.addObject("myMembers", myGroupMembers); + + MyMembershipsForm form = new MyMembershipsForm(); + + myGroupMembers.forEach( + groupMember -> { + form.postNames.put( + groupMember.post().id().toString(), groupMember.unofficialPostName()); + }); + + mv.addObject("myMembershipsForm", form); + } + + mv.addObject("canEditImages", canEditImages); + + return mv; + } + + private ModelAndView createGroupNotFound(String groupId, boolean htmxRequest) { + ModelAndView mv = new ModelAndView(); + if (htmxRequest) { + mv.setViewName("group-details/not-found"); + } else { + mv.setViewName("index"); + mv.addObject("page", "group-details/not-found"); + } + + mv.addObject("id", groupId); + + return mv; + } + + @GetMapping("/groups/{id}/cancel-edit") + public ModelAndView getCancelEditGroup( + @RequestHeader(value = "HX-Request", required = true) boolean htmxRequest, + @PathVariable("id") UUID id) { + Optional group = this.groupFacade.getWithMembers(id); + + if (group.isEmpty()) { + throw new RuntimeException(); + } + + ModelAndView mv = new ModelAndView(); + mv.setViewName("group-details/page :: group-details-article"); + + mv.addObject("group", group.get()); + mv.addObject( + "members", + group.get().groupMembers().stream() + .map( + groupMember -> + new Member( + groupMember.user().nick(), + " - " + + groupMember.post().enName() + + " - " + + Objects.requireNonNullElse(groupMember.unofficialPostName(), ""), + groupMember.post().id(), + groupMember.user().id())) + .toList()); + + return mv; + } + + public static final class GroupForm { + + @ValidatedWith(NameValidator.class) + private String name; + + @ValidatedWith(PrettyNameValidator.class) + private String prettyName; + + private int version; + private UUID superGroupId; + private List members; + + public GroupForm() { + this.members = new ArrayList<>(); + } + + public GroupForm( + int version, String name, String prettyName, UUID superGroupId, List members) { + this.version = version; + this.name = name; + this.prettyName = prettyName; + this.superGroupId = superGroupId; + this.members = members; + } + + public int getVersion() { + return version; + } + + public void setVersion(int version) { + this.version = version; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getPrettyName() { + return prettyName; + } + + public void setPrettyName(String prettyName) { + this.prettyName = prettyName; + } + + public UUID getSuperGroupId() { + return superGroupId; + } + + public void setSuperGroupId(UUID superGroupId) { + this.superGroupId = superGroupId; + } + + public List getMembers() { + return members; + } + + public void setMembers(List members) { + this.members = members; + } + + public static final class Member { + private UUID userId; + private UUID postId; + + @ValidatedWith(UnofficialPostName.UnofficialPostNameValidator.class) + private String unofficialPostName; + + public Member() {} + + public Member(UUID userId, UUID postId, String unofficialPostName) { + this.userId = userId; + this.postId = postId; + this.unofficialPostName = unofficialPostName; + } + + public UUID getUserId() { + return userId; + } + + public void setUserId(UUID userId) { + this.userId = userId; + } + + public UUID getPostId() { + return postId; + } + + public void setPostId(UUID postId) { + this.postId = postId; + } + + public String getUnofficialPostName() { + return unofficialPostName; + } + + public void setUnofficialPostName(String unofficialPostName) { + this.unofficialPostName = unofficialPostName; + } + } + } + + private ModelAndView createGetGroupEdit(UUID id, GroupForm form, BindingResult bindingResult) { + Optional group = this.groupFacade.getWithMembers(id); + + if (group.isEmpty()) { + throw new RuntimeException(); + } + + ModelAndView mv = new ModelAndView(); + mv.setViewName("group-details/edit-group"); + + List superGroups = + this.superGroupFacade.getAll().stream() + .sorted(Comparator.comparing(superGroup -> superGroup.prettyName().toLowerCase())) + .toList(); + List users = this.userFacade.getAll(); + List posts = this.postFacade.getAll(); + + if (form == null) { + form = + new GroupForm( + group.get().version(), + group.get().name(), + group.get().prettyName(), + group.get().superGroup().id(), + group.get().groupMembers().stream() + .map( + groupMember -> + new GroupForm.Member( + groupMember.user().id(), + groupMember.post().id(), + groupMember.unofficialPostName())) + .toList()); + } + + mv.addObject("form", form); + mv.addObject("superGroups", superGroups); + mv.addObject("groupId", group.get().id()); + mv.addObject( + "posts", + posts.stream() + .collect(Collectors.toMap(PostFacade.PostDTO::id, PostFacade.PostDTO::enName))); + mv.addObject( + "postKeys", + posts.stream() + .sorted(Comparator.comparing(post -> post.enName().toLowerCase())) + .map(PostFacade.PostDTO::id) + .toList()); + + mv.addObject( + "users", + users.stream().collect(Collectors.toMap(UserFacade.UserDTO::id, UserFacade.UserDTO::nick))); + mv.addObject( + "userKeys", + users.stream() + .sorted(Comparator.comparing(user -> user.nick().toLowerCase())) + .map(UserFacade.UserDTO::id) + .toList()); + + if (bindingResult != null && bindingResult.hasErrors()) { + mv.addObject(BindingResult.MODEL_KEY_PREFIX + "form", bindingResult); + } + + return mv; + } + + private void checkForDuplicateEntries(GroupForm form, BindingResult bindingResult) { + Set> uniquePairs = new HashSet<>(); + for (int i = 0; i < form.getMembers().size(); i++) { + GroupForm.Member member = form.getMembers().get(i); + Pair pair = Pair.of(member.getUserId(), member.getPostId()); + if (uniquePairs.contains(pair)) { + bindingResult.addError( + new FieldError("form", "members[" + i + "]", "Duplicate user/post entry")); + } else { + uniquePairs.add(pair); + } + } + } + + @GetMapping("/groups/{id}/edit") + public ModelAndView getGroupEdit( + @RequestHeader(value = "HX-Request", required = true) boolean htmxRequest, + @PathVariable("id") UUID id) { + return createGetGroupEdit(id, null, null); + } + + @PutMapping("/groups/{id}") + public ModelAndView updateGroup( + @RequestHeader(value = "HX-Request", required = false) boolean htmxRequest, + @PathVariable("id") UUID id, + HttpServletResponse response, + final GroupForm form, + final BindingResult bindingResult) { + + validateObject(form, bindingResult); + + checkForDuplicateEntries(form, bindingResult); + + if (!bindingResult.hasErrors() && this.groupFacade.groupWithNameAlreadyExists(id, form.name)) { + bindingResult.addError( + new FieldError( + "form", "name", form.name, true, null, null, "Group with name already exists")); + } + + if (bindingResult.hasErrors()) { + response.addHeader("HX-Reswap", "outerHTML"); + response.addHeader("HX-Retarget", "closest
"); + return createGetGroupEdit(id, form, bindingResult); + } else { + this.groupFacade.update( + new GroupFacade.UpdateGroup( + id, form.version, form.name, form.prettyName, form.superGroupId)); + + this.groupFacade.setMembers( + id, + form.members.stream() + .map(m -> new GroupFacade.ShallowMember(m.userId, m.postId, m.unofficialPostName)) + .toList()); + + return new ModelAndView("redirect:/groups/" + id.toString()); + } + } + + @GetMapping("/groups/new-member") + public ModelAndView getNewMember( + @RequestHeader(value = "HX-Request", required = true) boolean htmxRequest) { + List users = this.userFacade.getAll(); + List posts = this.postFacade.getAll(); + + ModelAndView mv = new ModelAndView(); + mv.setViewName("group-details/add-member-to-group"); + + mv.addObject( + "posts", + posts.stream() + .collect(Collectors.toMap(PostFacade.PostDTO::id, PostFacade.PostDTO::enName))); + mv.addObject( + "postKeys", + posts.stream() + .sorted(Comparator.comparing(post -> post.enName().toLowerCase())) + .map(PostFacade.PostDTO::id) + .toList()); + + mv.addObject( + "users", + users.stream().collect(Collectors.toMap(UserFacade.UserDTO::id, UserFacade.UserDTO::nick))); + mv.addObject( + "userKeys", + users.stream() + .sorted(Comparator.comparing(user -> user.nick().toLowerCase())) + .map(UserFacade.UserDTO::id) + .toList()); + + return mv; + } + + public ModelAndView createGetCreateGroup( + boolean htmxRequest, GroupForm form, BindingResult bindingResult) { + ModelAndView mv = new ModelAndView(); + + if (htmxRequest) { + mv.setViewName("create-group/page"); + } else { + mv.setViewName("index"); + mv.addObject("page", "create-group/page"); + } + + if (form == null) { + form = new GroupForm(); + } + + List users = this.userFacade.getAll(); + List posts = this.postFacade.getAll(); + + mv.addObject("form", form); + mv.addObject("superGroups", this.superGroupFacade.getAll()); + mv.addObject( + "users", + users.stream().collect(Collectors.toMap(UserFacade.UserDTO::id, UserFacade.UserDTO::nick))); + mv.addObject( + "posts", + posts.stream() + .collect(Collectors.toMap(PostFacade.PostDTO::id, PostFacade.PostDTO::enName))); + + if (bindingResult != null && bindingResult.hasErrors()) { + mv.addObject(BindingResult.MODEL_KEY_PREFIX + "form", bindingResult); + } + + return mv; + } + + @GetMapping("/groups/create") + public ModelAndView getCreateGroup( + @RequestHeader(value = "HX-Request", required = false) boolean htmxRequest) { + return createGetCreateGroup(htmxRequest, null, null); + } + + @PostMapping("/groups/create") + public ModelAndView createGroup( + @RequestHeader(value = "HX-Request", required = false) boolean htmxRequest, + final GroupForm form, + final BindingResult bindingResult) { + + validateObject(form, bindingResult); + + checkForDuplicateEntries(form, bindingResult); + + if (bindingResult.hasErrors()) { + return createGetCreateGroup(htmxRequest, form, bindingResult); + } + + UUID groupId = + this.groupFacade.create( + new GroupFacade.NewGroup(form.name, form.prettyName, form.superGroupId)); + + this.groupFacade.setMembers( + groupId, + form.members.stream() + .map(m -> new GroupFacade.ShallowMember(m.userId, m.postId, m.unofficialPostName)) + .toList()); + + return new ModelAndView("redirect:/groups/" + groupId); + } + + @DeleteMapping("/groups/{groupId}") + public ModelAndView deleteGroup( + @RequestHeader(value = "HX-Request", required = false) boolean htmxRequest, + @PathVariable("groupId") UUID groupId) { + this.groupFacade.delete(groupId); + + return new ModelAndView("redirect:/groups"); + } + + @PutMapping("/groups/{groupId}/my-posts") + public ModelAndView updateUnofficialPostNames( + @PathVariable("groupId") UUID groupId, MyMembershipsForm myMembershipsForm) { + if (SecurityContextHolder.getContext().getAuthentication() + instanceof UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken) { + UUID myUserId = UUID.fromString(usernamePasswordAuthenticationToken.getName()); + + myMembershipsForm.postNames.forEach( + (postId, newUnofficialPostName) -> { + groupFacade.changeUnofficialPostName( + groupId, UUID.fromString(postId), myUserId, newUnofficialPostName); + }); + } + + return new ModelAndView("redirect:/groups/" + groupId); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/primary/web/GroupsImageController.java b/app/src/main/java/it/chalmers/gamma/adapter/primary/web/GroupsImageController.java new file mode 100644 index 000000000..6f4b16daa --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/primary/web/GroupsImageController.java @@ -0,0 +1,161 @@ +package it.chalmers.gamma.adapter.primary.web; + +import it.chalmers.gamma.adapter.secondary.image.ImageFile; +import it.chalmers.gamma.adapter.secondary.image.ImageFile.ImageFileValidator; +import it.chalmers.gamma.app.group.GroupFacade; +import it.chalmers.gamma.app.image.ImageFacade; +import it.chalmers.gamma.app.image.domain.ImageService; +import it.chalmers.gamma.app.validation.FailedValidation; +import jakarta.servlet.http.HttpServletResponse; +import java.util.UUID; +import org.springframework.http.HttpStatus; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.multipart.MultipartFile; +import org.springframework.web.servlet.ModelAndView; + +@Controller +public class GroupsImageController { + + private final GroupFacade groupFacade; + private final ImageFacade imageFacade; + + public GroupsImageController(GroupFacade groupFacade, ImageFacade imageFacade) { + this.groupFacade = groupFacade; + this.imageFacade = imageFacade; + } + + @PutMapping("/groups/avatar/{id}") + public ModelAndView editGroupAvatar( + @RequestParam("file") MultipartFile file, + @PathVariable("id") UUID id, + HttpServletResponse response) { + ModelAndView mv = new ModelAndView(); + + if (new ImageFileValidator().validate(file) instanceof FailedValidation) { + response.addHeader("HX-Reswap", "afterbegin"); + response.addHeader("HX-Retarget", "#alerts"); + mv.setStatus(HttpStatus.FORBIDDEN); + mv.setViewName("group-details/failed-to-edit-group-avatar"); + return mv; + } + + try { + this.imageFacade.setGroupAvatar(id, new ImageFile(file)); + + mv.setViewName("group-details/page :: group-avatar"); + mv.addObject("groupId", id); + mv.addObject("random", Math.random()); + + var group = this.groupFacade.getWithMembers(id); + if (group.isEmpty()) { + throw new RuntimeException(); + } + + boolean canEditImages = false; + if (SecurityContextHolder.getContext().getAuthentication() + instanceof UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken) { + canEditImages = + group.get().groupMembers().stream() + .anyMatch( + groupMember -> + groupMember + .user() + .id() + .equals( + UUID.fromString(usernamePasswordAuthenticationToken.getName()))); + } + + mv.addObject("canEditImages", canEditImages); + } catch (ImageService.ImageCouldNotBeSavedException e) { + response.addHeader("HX-Reswap", "afterbegin"); + response.addHeader("HX-Retarget", "#alerts"); + mv.setStatus(HttpStatus.FORBIDDEN); + mv.setViewName("group-details/failed-to-edit-group-avatar"); + } + + return mv; + } + + @PutMapping("/groups/banner/{id}") + public ModelAndView editGroupBanner( + @RequestParam("file") MultipartFile file, + @PathVariable("id") UUID id, + HttpServletResponse response) { + ModelAndView mv = new ModelAndView(); + + if (new ImageFileValidator().validate(file) instanceof FailedValidation) { + response.addHeader("HX-Reswap", "afterbegin"); + response.addHeader("HX-Retarget", "#alerts"); + mv.setStatus(HttpStatus.FORBIDDEN); + mv.setViewName("group-details/failed-to-edit-group-banner"); + return mv; + } + + try { + this.imageFacade.setGroupBanner(id, new ImageFile(file)); + + mv.setViewName("group-details/page :: group-banner"); + mv.addObject("groupId", id); + mv.addObject("random", Math.random()); + + var group = this.groupFacade.getWithMembers(id); + if (group.isEmpty()) { + throw new RuntimeException(); + } + + boolean canEditImages = false; + if (SecurityContextHolder.getContext().getAuthentication() + instanceof UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken) { + canEditImages = + group.get().groupMembers().stream() + .anyMatch( + groupMember -> + groupMember + .user() + .id() + .equals( + UUID.fromString(usernamePasswordAuthenticationToken.getName()))); + } + + mv.addObject("canEditImages", canEditImages); + } catch (ImageService.ImageCouldNotBeSavedException e) { + response.addHeader("HX-Reswap", "afterbegin"); + response.addHeader("HX-Retarget", "#alerts"); + mv.setStatus(HttpStatus.FORBIDDEN); + mv.setViewName("group-details/failed-to-edit-group-banner"); + } + + return mv; + } + + @DeleteMapping("/groups/avatar/{id}") + public ModelAndView deleteGroupAvatar(@PathVariable("id") UUID id) { + this.imageFacade.removeGroupAvatar(id); + + ModelAndView mv = new ModelAndView(); + + mv.setViewName("group-details/page :: group-avatar"); + mv.addObject("groupId", id); + mv.addObject("random", Math.random()); + + return mv; + } + + @DeleteMapping("/groups/banner/{id}") + public ModelAndView deleteGroupBanner(@PathVariable("id") UUID id) { + this.imageFacade.removeGroupBanner(id); + ModelAndView mv = new ModelAndView(); + + mv.setViewName("group-details/page :: group-banner"); + mv.addObject("groupId", id); + mv.addObject("random", Math.random()); + + return mv; + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/primary/web/HomeController.java b/app/src/main/java/it/chalmers/gamma/adapter/primary/web/HomeController.java new file mode 100644 index 000000000..d9f164656 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/primary/web/HomeController.java @@ -0,0 +1,211 @@ +package it.chalmers.gamma.adapter.primary.web; + +import static it.chalmers.gamma.adapter.primary.web.WebValidationHelper.validateObject; +import static it.chalmers.gamma.app.user.domain.FirstName.FirstNameValidator; +import static it.chalmers.gamma.app.user.domain.LastName.LastNameValidator; + +import it.chalmers.gamma.adapter.secondary.image.ImageFile; +import it.chalmers.gamma.app.common.Email.EmailValidator; +import it.chalmers.gamma.app.image.domain.ImageService; +import it.chalmers.gamma.app.user.MeFacade; +import it.chalmers.gamma.app.user.UserGdprTrainingFacade; +import it.chalmers.gamma.app.user.domain.Nick.NickValidator; +import it.chalmers.gamma.app.user.domain.UnencryptedPassword.UnencryptedPasswordValidator; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Controller; +import org.springframework.validation.BindingResult; +import org.springframework.validation.FieldError; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.multipart.MultipartFile; +import org.springframework.web.servlet.ModelAndView; + +@Controller +public class HomeController { + + private final MeFacade meFacade; + private final UserGdprTrainingFacade userGdprTrainingFacade; + + public HomeController(MeFacade meFacade, UserGdprTrainingFacade userGdprTrainingFacade) { + this.meFacade = meFacade; + this.userGdprTrainingFacade = userGdprTrainingFacade; + } + + @GetMapping("/") + public ModelAndView getMe( + @RequestHeader(value = "HX-Request", required = false) boolean htmxRequest) { + ModelAndView mv = new ModelAndView(); + + if (htmxRequest) { + mv.setViewName("home/page"); + } else { + mv.setViewName("index"); + mv.addObject("page", "home/page"); + } + + MeFacade.MeDTO me = this.meFacade.getMe(); + + mv.addObject("me", me); + mv.addObject("random", Math.random()); + mv.addObject("gdpr", this.userGdprTrainingFacade.hasGdprTraining(me.id())); + + return mv; + } + + public record EditMe( + @ValidatedWith(NickValidator.class) String nick, + @ValidatedWith(FirstNameValidator.class) String firstName, + @ValidatedWith(LastNameValidator.class) String lastName, + @ValidatedWith(EmailValidator.class) String email, + String language) {} + + private ModelAndView createEditMeMV(EditMe form) { + ModelAndView mv = new ModelAndView(); + mv.setViewName("home/edit-me"); + mv.addObject("form", form); + + return mv; + } + + @GetMapping("/me/edit") + public ModelAndView getEditMe( + @RequestHeader(value = "HX-Request", required = true) boolean htmxRequest) { + MeFacade.MeDTO me = this.meFacade.getMe(); + + EditMe form = new EditMe(me.nick(), me.firstName(), me.lastName(), me.email(), me.language()); + + return createEditMeMV(form); + } + + @PutMapping("/me") + public ModelAndView editMe( + @RequestHeader(value = "HX-Request", required = true) boolean htmxRequest, + EditMe form, + final BindingResult bindingResult) { + ModelAndView mv = new ModelAndView(); + + validateObject(form, bindingResult); + + if (bindingResult.hasErrors()) { + mv.setViewName("home/edit-me"); + mv.addObject("form", form); + mv.addObject(BindingResult.MODEL_KEY_PREFIX + "form", bindingResult); + + return mv; + } + + this.meFacade.updateMe( + new MeFacade.UpdateMe(form.nick, form.firstName, form.lastName, form.email, form.language)); + + MeFacade.MeDTO me = this.meFacade.getMe(); + + mv.setViewName("home/edited-me"); + mv.addObject( + "me", + new MeFacade.MeDTO( + form.nick, + form.firstName, + form.lastName, + me.cid(), + form.email, + me.id(), + me.acceptanceYear(), + me.groups(), + form.language, + me.isAdmin())); + + return mv; + } + + @GetMapping("/me/cancel-edit") + public ModelAndView getCancelEdit( + @RequestHeader(value = "HX-Request", required = true) boolean htmxRequest) { + ModelAndView mv = new ModelAndView(); + + MeFacade.MeDTO me = this.meFacade.getMe(); + + mv.setViewName("home/page :: userinfo"); + mv.addObject("me", me); + + return mv; + } + + public record EditPasswordForm( + String currentPassword, + @ValidatedWith(UnencryptedPasswordValidator.class) String newPassword, + @ValidatedWith(UnencryptedPasswordValidator.class) String confirmNewPassword) {} + + @GetMapping("/me/edit-password") + public ModelAndView getEditPassword( + @RequestHeader(value = "HX-Request", required = true) boolean htmxRequest) { + ModelAndView mv = new ModelAndView(); + + mv.setViewName("home/edit-me-password"); + mv.addObject("form", new EditPasswordForm("", "", "")); + + return mv; + } + + @PutMapping("/me/edit-password") + public ModelAndView editPassword( + @RequestHeader(value = "HX-Request", required = true) boolean htmxRequest, + EditPasswordForm form, + final BindingResult bindingResult) { + ModelAndView mv = new ModelAndView(); + + validateObject(form, bindingResult); + + try { + if (!bindingResult.hasErrors()) { + this.meFacade.updatePassword( + new MeFacade.UpdatePassword( + form.currentPassword, form.newPassword, form.confirmNewPassword)); + } + } catch (IllegalArgumentException | MeFacade.NewPasswordNotConfirmedException e) { + bindingResult.addError( + new FieldError("form", "confirmNewPassword", "Passwords were not the same")); + } catch (MeFacade.PasswordIncorrectException e) { + bindingResult.addError(new FieldError("form", "currentPassword", "Passwords not correct")); + } + + if (bindingResult.hasErrors()) { + mv.setViewName("home/edit-me-password"); + mv.addObject("form", form); + mv.addObject(BindingResult.MODEL_KEY_PREFIX + "form", bindingResult); + + return mv; + } + + MeFacade.MeDTO me = this.meFacade.getMe(); + + mv.setViewName("home/edited-me-password"); + mv.addObject("me", me); + + return mv; + } + + @PutMapping("/me/avatar") + public ModelAndView editAvatar( + @RequestParam("file") MultipartFile file, HttpServletResponse response) { + ModelAndView mv = new ModelAndView(); + try { + this.meFacade.setAvatar(new ImageFile(file)); + + MeFacade.MeDTO me = this.meFacade.getMe(); + + mv.setViewName("home/edited-me-avatar"); + mv.addObject("random", Math.random()); + mv.addObject("meId", me.id()); + } catch (ImageService.ImageCouldNotBeSavedException e) { + response.addHeader("HX-Retarget", "#alerts"); + response.addHeader("HX-Reswap", "afterbegin"); + mv.setStatus(HttpStatus.FORBIDDEN); + mv.setViewName("home/failed-to-edit-me-avatar"); + } + + return mv; + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/primary/web/LoginController.java b/app/src/main/java/it/chalmers/gamma/adapter/primary/web/LoginController.java new file mode 100644 index 000000000..a41b55b0f --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/primary/web/LoginController.java @@ -0,0 +1,58 @@ +package it.chalmers.gamma.adapter.primary.web; + +import it.chalmers.gamma.security.authentication.AuthenticationExtractor; +import it.chalmers.gamma.security.authentication.GammaAuthentication; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.servlet.ModelAndView; + +@Controller +public class LoginController { + + @GetMapping("/login") + public ModelAndView getLogin( + @RequestParam(value = "error", required = false) String error, + @RequestParam(value = "logout", required = false) String logout, + @RequestParam(value = "authorizing", required = false) String authorizing, + @RequestParam(value = "deleted", required = false) String deleted, + @RequestParam(value = "account-created", required = false) String accountCreated, + @RequestParam(value = "password-reset", required = false) String passwordReset, + @RequestHeader(value = "HX-Request", required = false) boolean htmxRequest, + @RequestParam(value = "throttle", required = false) String throttle, + HttpServletResponse response) { + + GammaAuthentication auth = AuthenticationExtractor.getAuthentication(); + if (auth != null) { + return new ModelAndView("redirect:/"); + } + + ModelAndView mv = new ModelAndView(); + if (htmxRequest) { + mv.setViewName("pages/login"); + } else { + mv.setViewName("index"); + mv.addObject("page", "pages/login"); + } + + boolean isAuthorizing = authorizing != null; + boolean isThrottled = throttle != null; + boolean isDeleted = deleted != null; + boolean isAccountCreated = accountCreated != null; + boolean isPasswordReset = passwordReset != null; + + mv.addObject("error", error); + mv.addObject("logout", logout); + mv.addObject("authorizing", isAuthorizing); + mv.addObject("deleted", isDeleted); + mv.addObject("throttle", isThrottled); + mv.addObject("accountCreated", isAccountCreated); + mv.addObject("passwordReset", isPasswordReset); + + response.addHeader("HX-Retarget", "body"); + + return mv; + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/primary/web/MyAcceptedClientsController.java b/app/src/main/java/it/chalmers/gamma/adapter/primary/web/MyAcceptedClientsController.java new file mode 100644 index 000000000..af09ca702 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/primary/web/MyAcceptedClientsController.java @@ -0,0 +1,49 @@ +package it.chalmers.gamma.adapter.primary.web; + +import it.chalmers.gamma.app.user.MeFacade; +import java.util.List; +import java.util.UUID; +import org.springframework.stereotype.Controller; +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.RequestHeader; +import org.springframework.web.servlet.ModelAndView; + +@Controller +public class MyAcceptedClientsController { + + private final MeFacade meFacade; + + public MyAcceptedClientsController(MeFacade meFacade) { + this.meFacade = meFacade; + } + + @GetMapping("/me/accepted-clients") + public ModelAndView getMyAcceptedClients( + @RequestHeader(value = "HX-Request", required = false) boolean htmxRequest) { + List acceptedClients = this.meFacade.getSignedInUserApprovals(); + + ModelAndView mv = new ModelAndView(); + + if (htmxRequest) { + mv.setViewName("pages/my-accepted-clients"); + } else { + mv.setViewName("index"); + mv.addObject("page", "pages/my-accepted-clients"); + } + + mv.addObject("acceptedClients", acceptedClients); + + return mv; + } + + @DeleteMapping("/me/accepted-clients/{uid}") + public ModelAndView deleteAcceptedClient( + @RequestHeader(value = "HX-Request", required = false) boolean htmxRequest, + @PathVariable("uid") UUID clientUid) { + this.meFacade.deleteUserApproval(clientUid); + + return new ModelAndView("partial/retracted-accepted-client"); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/primary/web/MyClientsController.java b/app/src/main/java/it/chalmers/gamma/adapter/primary/web/MyClientsController.java new file mode 100644 index 000000000..227df4c92 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/primary/web/MyClientsController.java @@ -0,0 +1,165 @@ +package it.chalmers.gamma.adapter.primary.web; + +import it.chalmers.gamma.app.client.ClientFacade; +import jakarta.servlet.http.HttpServletResponse; +import java.util.ArrayList; +import org.springframework.stereotype.Controller; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.servlet.ModelAndView; + +@Controller +public class MyClientsController { + + private final ClientFacade clientFacade; + + public MyClientsController(ClientFacade clientFacade) { + this.clientFacade = clientFacade; + } + + @GetMapping("/my-clients") + public ModelAndView getMyClients( + @RequestHeader(value = "HX-Request", required = false) boolean htmxRequest) { + ModelAndView mv = new ModelAndView(); + + if (htmxRequest) { + mv.setViewName("pages/my-clients"); + } else { + mv.setViewName("index"); + mv.addObject("page", "pages/my-clients"); + } + + mv.addObject("clients", clientFacade.getAllMyClients()); + + return mv; + } + + public static final class CreateUserClient { + private String redirectUrl; + private String prettyName; + private String svDescription; + private String enDescription; + private boolean generateApiKey; + private boolean emailScope; + + public CreateUserClient() { + this("", "", "", "", false, false); + } + + public CreateUserClient( + String redirectUrl, + String prettyName, + String svDescription, + String enDescription, + boolean generateApiKey, + boolean emailScope) { + this.redirectUrl = redirectUrl; + this.prettyName = prettyName; + this.svDescription = svDescription; + this.enDescription = enDescription; + this.generateApiKey = generateApiKey; + this.emailScope = emailScope; + } + + public String getRedirectUrl() { + return redirectUrl; + } + + public void setRedirectUrl(String redirectUrl) { + this.redirectUrl = redirectUrl; + } + + public String getPrettyName() { + return prettyName; + } + + public void setPrettyName(String prettyName) { + this.prettyName = prettyName; + } + + public String getSvDescription() { + return svDescription; + } + + public void setSvDescription(String svDescription) { + this.svDescription = svDescription; + } + + public String getEnDescription() { + return enDescription; + } + + public void setEnDescription(String enDescription) { + this.enDescription = enDescription; + } + + public boolean isGenerateApiKey() { + return generateApiKey; + } + + public void setGenerateApiKey(boolean generateApiKey) { + this.generateApiKey = generateApiKey; + } + + public boolean isEmailScope() { + return emailScope; + } + + public void setEmailScope(boolean emailScope) { + this.emailScope = emailScope; + } + } + + @GetMapping("/my-clients/create") + public ModelAndView getCreateUserClient( + @RequestHeader(value = "HX-Request", required = false) boolean htmxRequest) { + ModelAndView mv = new ModelAndView(); + + if (htmxRequest) { + mv.setViewName("pages/create-user-client"); + } else { + mv.setViewName("index"); + mv.addObject("page", "pages/create-user-client"); + } + + mv.addObject("form", new CreateUserClient()); + + return mv; + } + + @PostMapping("/my-clients") + public ModelAndView createUserClient( + @RequestHeader(value = "HX-Request", required = true) boolean htmxRequest, + CreateUserClient form, + BindingResult bindingResult, + HttpServletResponse response) { + ModelAndView mv = new ModelAndView(); + + ClientFacade.CreatedClientDTO result = + this.clientFacade.createUserClient( + new ClientFacade.NewClient( + form.redirectUrl, + form.prettyName, + form.svDescription, + form.enDescription, + form.generateApiKey, + form.emailScope, + null)); + + mv.setViewName("client-details/page"); + + mv.addObject("clientUid", result.client().clientUid()); + mv.addObject("client", result.client()); + mv.addObject("clientAuthorities", new ArrayList<>()); + mv.addObject("userApprovals", new ArrayList<>()); + mv.addObject("clientSecret", result.clientSecret()); + mv.addObject("apiKeyToken", result.apiKeyToken()); + mv.addObject("amIOwner", true); + + response.addHeader("HX-Push-Url", "/clients/" + result.client().clientUid().toString()); + + return mv; + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/primary/web/PostsController.java b/app/src/main/java/it/chalmers/gamma/adapter/primary/web/PostsController.java new file mode 100644 index 000000000..d2decbbb8 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/primary/web/PostsController.java @@ -0,0 +1,273 @@ +package it.chalmers.gamma.adapter.primary.web; + +import static it.chalmers.gamma.adapter.primary.web.WebValidationHelper.validateObject; +import static it.chalmers.gamma.app.validation.ValidationHelper.*; +import static it.chalmers.gamma.app.validation.ValidationHelper.MAX_LENGTH; + +import it.chalmers.gamma.app.common.UUIDValidator; +import it.chalmers.gamma.app.group.GroupFacade; +import it.chalmers.gamma.app.group.domain.EmailPrefix; +import it.chalmers.gamma.app.post.PostFacade; +import it.chalmers.gamma.app.post.domain.PostRepository; +import it.chalmers.gamma.app.validation.ValidationResult; +import it.chalmers.gamma.app.validation.Validator; +import jakarta.servlet.http.HttpServletResponse; +import java.util.*; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Controller; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.servlet.ModelAndView; + +@Controller +public class PostsController { + + private final PostFacade postFacade; + + public PostsController(PostFacade postFacade) { + this.postFacade = postFacade; + } + + @GetMapping("/posts") + public ModelAndView getPosts( + @RequestHeader(value = "HX-Request", required = false) boolean htmxRequest) { + List posts = postFacade.getAll(); + + ModelAndView mv = new ModelAndView(); + if (htmxRequest) { + mv.setViewName("posts/page"); + } else { + mv.setViewName("index"); + mv.addObject("page", "posts/page"); + } + + mv.addObject("posts", posts); + return mv; + } + + private ModelAndView createPostNotFound(String postId, boolean htmxRequest) { + ModelAndView mv = new ModelAndView(); + + if (htmxRequest) { + mv.setViewName("post-details/not-found"); + } else { + mv.setViewName("index"); + mv.addObject("page", "post-details/not-found"); + } + + mv.addObject("id", postId); + + return mv; + } + + public record PostUsage(UUID groupId, String groupPrettyName, UUID userId, String username) {} + + private ModelAndView createGetPost(String postId, boolean htmxRequest) { + if (!UUIDValidator.isValidUUID(postId)) { + return createPostNotFound(postId, htmxRequest); + } + + UUID id = UUID.fromString(postId); + + Optional post = postFacade.get(id); + + if (post.isEmpty()) { + return createPostNotFound(postId, htmxRequest); + } + + ModelAndView mv = new ModelAndView(); + + if (htmxRequest) { + mv.setViewName("post-details/page"); + } else { + mv.setViewName("index"); + mv.addObject("page", "post-details/page"); + } + + mv.addObject("post", post.get()); + + List usages = new ArrayList<>(); + for (GroupFacade.GroupWithMembersDTO postUsage : postFacade.getPostUsages(post.get().id())) { + for (GroupFacade.GroupMemberDTO user : postUsage.groupMembers()) { + if (user.post().id().equals(id)) { + usages.add( + new PostUsage( + postUsage.id(), + postUsage.prettyName(), + user.user().id(), + user.user().fullName())); + } + } + } + + mv.addObject("usages", usages); + + return mv; + } + + @GetMapping("/posts/{id}") + public ModelAndView getPost( + @RequestHeader(value = "HX-Request", required = false) boolean htmxRequest, + @PathVariable("id") String postId) { + + return createGetPost(postId, htmxRequest); + } + + private ModelAndView createGetEditPost( + boolean htmxRequest, UUID postId, UpdatePost form, final BindingResult bindingResult) { + Optional post = postFacade.get(postId); + + if (post.isEmpty()) { + throw new IllegalArgumentException("Not found"); + } + + ModelAndView mv = new ModelAndView(); + + if (form == null) { + form = + new UpdatePost( + post.get().svName(), + post.get().enName(), + post.get().emailPrefix(), + post.get().version()); + } + + if (bindingResult != null) { + mv.addObject(BindingResult.MODEL_KEY_PREFIX + "form", bindingResult); + } + + mv.addObject("form", form); + mv.addObject("postId", postId); + + if (htmxRequest) { + mv.setViewName("post-details/edit-post"); + } else { + mv.setViewName("index"); + mv.addObject("page", "post-details/edit-post"); + } + + return mv; + } + + @GetMapping("/posts/{id}/edit") + public ModelAndView getEditPost( + @RequestHeader(value = "HX-Request", required = true) boolean htmxRequest, + @PathVariable("id") UUID postId) { + return createGetEditPost(htmxRequest, postId, null, null); + } + + @PutMapping(value = "/posts/{id}") + public ModelAndView updateEditPost( + @RequestHeader(value = "HX-Request", required = false) boolean htmxRequest, + @PathVariable("id") UUID postId, + HttpServletResponse response, + UpdatePost form, + final BindingResult bindingResult) { + + validateObject(form, bindingResult); + + if (bindingResult.hasErrors()) { + response.addHeader("HX-Reswap", "outerHTML"); + response.addHeader("HX-Retarget", "closest
"); + return createGetEditPost(htmxRequest, postId, form, bindingResult); + } + + try { + postFacade.update( + new PostFacade.UpdatePost( + postId, form.version, form.svName, form.enName, form.emailPrefix)); + } catch (PostRepository.PostNotFoundException e) { + throw new RuntimeException(e); + } + + return new ModelAndView("redirect:/posts/" + postId.toString()); + } + + public record UpdatePost( + @ValidatedWith(NameValidator.class) String svName, + @ValidatedWith(NameValidator.class) String enName, + @ValidatedWith(EmailPrefix.EmailPrefixValidator.class) String emailPrefix, + int version) {} + + @DeleteMapping(value = "/posts/{id}", produces = MediaType.TEXT_HTML_VALUE) + public String deleteEditPost( + @RequestHeader(value = "HX-Request", required = true) boolean htmxRequest, + @PathVariable("id") UUID postId) { + try { + postFacade.delete(postId); + } catch (PostRepository.PostNotFoundException e) { + throw new RuntimeException(e); + } + + return "redirect:/posts"; + } + + public record CreatePost( + @ValidatedWith(NameValidator.class) String svName, + @ValidatedWith(NameValidator.class) String enName, + @ValidatedWith(EmailPrefix.EmailPrefixValidator.class) String emailPrefix) {} + + public static final class NameValidator implements Validator { + @Override + public ValidationResult validate(String value) { + return withValidators(IS_NOT_EMPTY, SANITIZED_HTML, MAX_LENGTH.apply(2048)).validate(value); + } + } + + private ModelAndView createGetCreatePost( + boolean htmxRequest, CreatePost form, BindingResult bindingResult) { + ModelAndView mv = new ModelAndView(); + + if (htmxRequest) { + mv.setViewName("create-post/page"); + } else { + mv.setViewName("index"); + mv.addObject("page", "create-post/page"); + } + + if (form == null) { + form = new CreatePost("", "", ""); + } + + if (bindingResult != null) { + mv.addObject(BindingResult.MODEL_KEY_PREFIX + "form", bindingResult); + } + + mv.addObject("form", form); + + return mv; + } + + @GetMapping("/posts/create") + public ModelAndView getCreatePost( + @RequestHeader(value = "HX-Request", required = false) boolean htmxRequest) { + return createGetCreatePost(htmxRequest, null, null); + } + + @PostMapping("/posts") + public ModelAndView createPost( + @RequestHeader(value = "HX-Request", required = false) boolean htmxRequest, + CreatePost form, + BindingResult bindingResult) { + + validateObject(form, bindingResult); + + if (bindingResult.hasErrors()) { + return createGetCreatePost(htmxRequest, form, bindingResult); + } + + UUID postId = + this.postFacade.create(new PostFacade.NewPost(form.svName, form.enName, form.emailPrefix)); + + return new ModelAndView("redirect:/posts/" + postId); + } + + @PutMapping("/posts/order") + public ModelAndView updateOrder( + @RequestHeader(value = "HX-Request", required = true) boolean htmxRequest, + @RequestParam("list") List list) { + this.postFacade.setOrder(list); + + return new ModelAndView("redirect:/posts"); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/primary/web/RegisterAccountController.java b/app/src/main/java/it/chalmers/gamma/adapter/primary/web/RegisterAccountController.java new file mode 100644 index 000000000..f590d5ab9 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/primary/web/RegisterAccountController.java @@ -0,0 +1,193 @@ +package it.chalmers.gamma.adapter.primary.web; + +import static it.chalmers.gamma.adapter.primary.web.WebValidationHelper.validateObject; + +import it.chalmers.gamma.app.common.Email.EmailValidator; +import it.chalmers.gamma.app.user.UserCreationFacade; +import it.chalmers.gamma.app.user.activation.domain.UserActivationRepository; +import it.chalmers.gamma.app.user.domain.AcceptanceYear.AcceptanceYearValidator; +import it.chalmers.gamma.app.user.domain.Cid.CidValidator; +import it.chalmers.gamma.app.user.domain.FirstName.FirstNameValidator; +import it.chalmers.gamma.app.user.domain.LastName.LastNameValidator; +import it.chalmers.gamma.app.user.domain.Nick.NickValidator; +import it.chalmers.gamma.app.user.domain.UnencryptedPassword.UnencryptedPasswordValidator; +import java.time.Year; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Controller; +import org.springframework.validation.BindingResult; +import org.springframework.validation.ObjectError; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.servlet.ModelAndView; + +@Controller +public class RegisterAccountController { + + private final UserCreationFacade userCreationFacade; + + private static final Logger LOGGER = + LoggerFactory.getLogger(RegisterAccountController.class.getName()); + + public RegisterAccountController(UserCreationFacade userCreationFacade) { + this.userCreationFacade = userCreationFacade; + } + + public ModelAndView createGetActivateCid( + boolean htmxRequest, ActivateCidForm form, BindingResult bindingResult) { + ModelAndView mv = new ModelAndView(); + if (htmxRequest) { + mv.setViewName("register-account/activate-cid"); + } else { + mv.setViewName("index"); + mv.addObject("page", "register-account/activate-cid"); + } + + if (form == null) { + form = new ActivateCidForm(""); + } + mv.addObject("form", form); + + if (bindingResult != null && bindingResult.hasErrors()) { + mv.addObject(BindingResult.MODEL_KEY_PREFIX + "form", bindingResult); + } + + return mv; + } + + @GetMapping("/activate-cid") + public ModelAndView getActivateCid( + @RequestHeader(value = "HX-Request", required = false) boolean htmxRequest) { + return createGetActivateCid(htmxRequest, null, null); + } + + @PostMapping("/activate-cid") + public ModelAndView activateCid( + @RequestHeader(value = "HX-Request", required = false) boolean htmxRequest, + ActivateCidForm form, + BindingResult bindingResult) { + + validateObject(form, bindingResult); + + if (bindingResult.hasErrors()) { + return createGetActivateCid(htmxRequest, form, bindingResult); + } else { + this.userCreationFacade.tryToActivateUser(form.cid); + return new ModelAndView("redirect:/email-sent"); + } + } + + public record ActivateCidForm(@ValidatedWith(CidValidator.class) String cid) {} + + @GetMapping("/email-sent") + public ModelAndView getEmailSent( + @RequestHeader(value = "HX-Request", required = false) boolean htmxRequest) { + ModelAndView mv = new ModelAndView(); + + mv.setViewName("register-account/email-sent"); + + return mv; + } + + public ModelAndView createGetRegister( + boolean htmxRequest, CreateAccountForm form, BindingResult bindingResult) { + ModelAndView mv = new ModelAndView(); + + if (htmxRequest) { + mv.setViewName("register-account/register-account"); + } else { + mv.setViewName("index"); + mv.addObject("page", "register-account/register-account"); + } + + mv.addObject("form", form); + + if (bindingResult != null && bindingResult.hasErrors()) { + mv.addObject(BindingResult.MODEL_KEY_PREFIX + "form", bindingResult); + } + + return mv; + } + + @GetMapping("/register") + public ModelAndView getRegister( + @RequestHeader(value = "HX-Request", required = false) boolean htmxRequest, + @RequestParam(value = "token", required = true) String token) { + if (!this.userCreationFacade.isValidToken(token)) { + ModelAndView mv = new ModelAndView(); + if (htmxRequest) { + mv.setViewName("pages/register-account-token-bad"); + } else { + mv.setViewName("index"); + mv.addObject("page", "pages/register-account-token-bad"); + } + + return mv; + } + + CreateAccountForm form = + new CreateAccountForm(token, "", "", "", "", "", "", Year.now().getValue(), "SV", false); + + return createGetRegister(htmxRequest, form, null); + } + + @PostMapping("/register") + public ModelAndView registerAccount( + @RequestHeader(value = "HX-Request", required = false) boolean htmxRequest, + CreateAccountForm form, + BindingResult bindingResult) { + + validateObject(form, bindingResult); + + try { + if (!bindingResult.hasErrors()) { + this.userCreationFacade.createUserWithCode( + new UserCreationFacade.NewUserByCode( + form.password, + form.nick, + form.firstName, + form.lastName, + form.email, + form.acceptanceYear, + form.language), + form.code, + form.confirmPassword, + form.acceptUserAgreement); + } + } catch (UserCreationFacade.SomePropertyNotUniqueRuntimeException e) { + bindingResult.addError( + new ObjectError( + "global", + "Please double check what you have entered. Please send an email to ita@chalmers.it if your issues persist.")); + LOGGER.info( + "Some property wasn't unique when a user tried to create an account. More info on debug level..."); + LOGGER.debug(e.getMessage()); + } catch (IllegalArgumentException e) { + throw new RuntimeException(e); + } catch (UserActivationRepository.TokenNotActivatedRuntimeException e) { + bindingResult.addError( + new ObjectError( + "global", "Token not valid anymore. Please request a new registration url.")); + } + + if (bindingResult.hasErrors()) { + return createGetRegister(htmxRequest, form, bindingResult); + } else { + return new ModelAndView("redirect:/login?account-created"); + } + } + + public record CreateAccountForm( + String code, + @ValidatedWith(UnencryptedPasswordValidator.class) String password, + @ValidatedWith(UnencryptedPasswordValidator.class) String confirmPassword, + @ValidatedWith(NickValidator.class) String nick, + @ValidatedWith(FirstNameValidator.class) String firstName, + @ValidatedWith(LastNameValidator.class) String lastName, + @ValidatedWith(EmailValidator.class) String email, + @ValidatedWith(AcceptanceYearValidator.class) int acceptanceYear, + String language, + boolean acceptUserAgreement) {} +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/primary/web/SuperGroupTypesController.java b/app/src/main/java/it/chalmers/gamma/adapter/primary/web/SuperGroupTypesController.java new file mode 100644 index 000000000..9e230a439 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/primary/web/SuperGroupTypesController.java @@ -0,0 +1,139 @@ +package it.chalmers.gamma.adapter.primary.web; + +import static it.chalmers.gamma.adapter.primary.web.WebValidationHelper.validateObject; + +import it.chalmers.gamma.app.supergroup.SuperGroupFacade; +import it.chalmers.gamma.app.supergroup.domain.SuperGroupRepository; +import it.chalmers.gamma.app.supergroup.domain.SuperGroupType; +import it.chalmers.gamma.app.supergroup.domain.SuperGroupTypeRepository; +import java.util.Comparator; +import java.util.List; +import org.springframework.stereotype.Controller; +import org.springframework.validation.BindingResult; +import org.springframework.validation.FieldError; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.servlet.ModelAndView; + +@Controller +public class SuperGroupTypesController { + + private final SuperGroupFacade superGroupFacade; + + public SuperGroupTypesController(SuperGroupFacade superGroupFacade) { + this.superGroupFacade = superGroupFacade; + } + + private ModelAndView createGetSuperGroupTypes( + boolean htmxRequest, CreateType form, final BindingResult bindingResult) { + List types = this.superGroupFacade.getAllTypes(); + + ModelAndView mv = new ModelAndView(); + if (htmxRequest) { + mv.setViewName("pages/types"); + } else { + mv.setViewName("index"); + mv.addObject("page", "pages/types"); + } + + if (form == null) { + form = new CreateType(""); + } + + if (bindingResult != null) { + mv.addObject(BindingResult.MODEL_KEY_PREFIX + "form", bindingResult); + } + + mv.addObject("form", form); + mv.addObject( + "types", types.stream().sorted(Comparator.comparing(String::toLowerCase)).toList()); + + return mv; + } + + @GetMapping("/types") + public ModelAndView getSuperGroupTypes( + @RequestHeader(value = "HX-Request", required = false) boolean htmxRequest) { + return this.createGetSuperGroupTypes(htmxRequest, null, null); + } + + public ModelAndView createSuperGroupTypeNotFound(String type, boolean htmxRequest) { + ModelAndView mv = new ModelAndView(); + + if (htmxRequest) { + mv.setViewName("type-details/not-found"); + } else { + mv.setViewName("index"); + mv.addObject("page", "type-details/not-found"); + } + + mv.addObject("type", type); + + return mv; + } + + @GetMapping("/types/{type}") + public ModelAndView getSuperGroupType( + @RequestHeader(value = "HX-Request", required = false) boolean htmxRequest, + @PathVariable("type") String type) { + List usages; + try { + usages = this.superGroupFacade.getAllSuperGroupsByType(type); + } catch (SuperGroupRepository.TypeNotFoundRuntimeException e) { + return createSuperGroupTypeNotFound(type, htmxRequest); + } + + ModelAndView mv = new ModelAndView(); + + if (htmxRequest) { + mv.setViewName("type-details/page"); + } else { + mv.setViewName("index"); + mv.addObject("page", "type-details/page"); + } + + mv.addObject("type", type); + mv.addObject("usages", usages); + + return mv; + } + + @PostMapping("/types") + public ModelAndView createType( + @RequestHeader(value = "HX-Request", required = true) boolean htmxRequest, + final CreateType form, + final BindingResult bindingResult) { + + validateObject(form, bindingResult); + + try { + if (!bindingResult.hasErrors()) { + this.superGroupFacade.addType(form.type); + } + } catch (SuperGroupTypeRepository.SuperGroupTypeAlreadyExistsException e) { + bindingResult.addError( + new FieldError("form", "type", form.type, true, null, null, "Type already exist")); + } + + if (bindingResult.hasErrors()) { + return createGetSuperGroupTypes(htmxRequest, form, bindingResult); + } + + return createGetSuperGroupTypes(htmxRequest, null, null); + } + + public record CreateType( + @ValidatedWith(SuperGroupType.SuperGroupTypeValidator.class) String type) {} + + @DeleteMapping("/types/{id}") + public ModelAndView deleteType( + @RequestHeader(value = "HX-Request", required = true) boolean htmxRequest, + @PathVariable("id") String type) + throws SuperGroupTypeRepository.SuperGroupTypeHasUsagesException, + SuperGroupTypeRepository.SuperGroupTypeNotFoundException { + this.superGroupFacade.removeType(type); + + return new ModelAndView("redirect:/types"); + } + + public record DeleteSuperGroupType() {} +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/primary/web/SuperGroupsController.java b/app/src/main/java/it/chalmers/gamma/adapter/primary/web/SuperGroupsController.java new file mode 100644 index 000000000..a5d0a0abc --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/primary/web/SuperGroupsController.java @@ -0,0 +1,279 @@ +package it.chalmers.gamma.adapter.primary.web; + +import static it.chalmers.gamma.adapter.primary.web.WebValidationHelper.validateObject; +import static it.chalmers.gamma.app.common.UUIDValidator.isValidUUID; + +import it.chalmers.gamma.app.common.PrettyName.PrettyNameValidator; +import it.chalmers.gamma.app.group.GroupFacade; +import it.chalmers.gamma.app.supergroup.SuperGroupFacade; +import it.chalmers.gamma.app.supergroup.domain.SuperGroupRepository; +import it.chalmers.gamma.app.user.domain.Name.NameValidator; +import java.util.Comparator; +import java.util.List; +import java.util.Optional; +import java.util.UUID; +import org.springframework.stereotype.Controller; +import org.springframework.validation.BindingResult; +import org.springframework.validation.FieldError; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.servlet.ModelAndView; + +@Controller +public class SuperGroupsController { + + private final SuperGroupFacade superGroupFacade; + private final GroupFacade groupFacade; + + public SuperGroupsController(SuperGroupFacade superGroupFacade, GroupFacade groupFacade) { + this.superGroupFacade = superGroupFacade; + this.groupFacade = groupFacade; + } + + @GetMapping("/super-groups") + public ModelAndView getSuperGroups( + @RequestHeader(value = "HX-Request", required = false) boolean htmxRequest) { + List superGroups = this.superGroupFacade.getAll(); + + ModelAndView mv = new ModelAndView(); + if (htmxRequest) { + mv.setViewName("pages/super-groups"); + } else { + mv.setViewName("index"); + mv.addObject("page", "pages/super-groups"); + } + + mv.addObject( + "superGroups", + superGroups.stream() + .sorted(Comparator.comparing(superGroup -> superGroup.prettyName().toLowerCase())) + .toList()); + + return mv; + } + + @GetMapping("/super-groups/{id}") + public ModelAndView getSuperGroup( + @RequestHeader(value = "HX-Request", required = false) boolean htmxRequest, + @PathVariable("id") String superGroupId) { + if (!isValidUUID(superGroupId)) { + return createSuperGroupNotFound(superGroupId, htmxRequest); + } + + Optional superGroup = + this.superGroupFacade.get(UUID.fromString(superGroupId)); + + ModelAndView mv = new ModelAndView(); + if (superGroup.isEmpty()) { + return createSuperGroupNotFound(superGroupId, htmxRequest); + } + + if (htmxRequest) { + mv.setViewName("pages/super-group-details"); + } else { + mv.setViewName("index"); + mv.addObject("page", "pages/super-group-details"); + } + + mv.addObject("superGroup", superGroup.get()); + mv.addObject("usages", this.groupFacade.getAllBySuperGroup(superGroup.get().id())); + + return mv; + } + + public ModelAndView createSuperGroupNotFound(String superGroupId, boolean htmxRequest) { + ModelAndView mv = new ModelAndView(); + if (htmxRequest) { + mv.setViewName("pages/super-group-not-found"); + } else { + mv.setViewName("index"); + mv.addObject("page", "pages/super-group-not-found"); + } + + mv.addObject("id", superGroupId); + + return mv; + } + + public record UpdateSuperGroupForm( + int version, + String name, + String prettyName, + String type, + String svDescription, + String enDescription) {} + + @GetMapping("/super-groups/{id}/edit") + public ModelAndView getSuperGroupEdit( + @RequestHeader(value = "HX-Request", required = true) boolean htmxRequest, + @PathVariable("id") UUID id) { + Optional superGroup = this.superGroupFacade.get(id); + + if (superGroup.isEmpty()) { + throw new RuntimeException(); + } + + ModelAndView mv = new ModelAndView(); + mv.setViewName("partial/edit-super-group"); + + SuperGroupFacade.SuperGroupDTO sg = superGroup.get(); + + mv.addObject("superGroupId", sg.id()); + mv.addObject( + "form", + new UpdateSuperGroupForm( + sg.version(), + sg.name(), + sg.prettyName(), + sg.type(), + sg.svDescription(), + sg.enDescription())); + mv.addObject( + "types", + this.superGroupFacade.getAllTypes().stream() + .sorted(Comparator.comparing(String::toLowerCase)) + .toList()); + mv.addObject("usages", this.groupFacade.getAllBySuperGroup(superGroup.get().id())); + + return mv; + } + + @GetMapping("/super-groups/{id}/cancel-edit") + public ModelAndView getCancelSuperGroupEdit( + @RequestHeader(value = "HX-Request", required = true) boolean htmxRequest, + @PathVariable("id") UUID id) { + Optional superGroup = this.superGroupFacade.get(id); + + if (superGroup.isEmpty()) { + throw new RuntimeException(); + } + + ModelAndView mv = new ModelAndView(); + if (htmxRequest) { + mv.setViewName("pages/super-group-details :: super-group-info"); + } else { + mv.setViewName("index"); + mv.addObject("page", "pages/super-group-details"); + } + + mv.addObject("superGroup", superGroup.get()); + + return mv; + } + + @PutMapping("/super-groups/{id}") + public ModelAndView updateSuperGroup( + @RequestHeader(value = "HX-Request", required = false) boolean htmxRequest, + @PathVariable("id") UUID id, + final UpdateSuperGroupForm form, + final BindingResult bindingResult) { + try { + this.superGroupFacade.updateSuperGroup( + new SuperGroupFacade.UpdateSuperGroup( + id, + form.version, + form.name, + form.prettyName, + form.type, + form.svDescription, + form.enDescription)); + } catch (SuperGroupRepository.SuperGroupNotFoundException e) { + throw new RuntimeException(e); + } + + ModelAndView mv = new ModelAndView(); + mv.setViewName("pages/super-group-details :: super-group-info"); + mv.addObject( + "superGroup", + new SuperGroupFacade.SuperGroupDTO( + id, + form.version + 1, + form.name, + form.prettyName, + form.type, + form.svDescription, + form.enDescription)); + + return mv; + } + + @DeleteMapping("/super-groups/{id}") + public ModelAndView deleteSuperGroup( + @RequestHeader(value = "HX-Request", required = true) boolean htmxRequest, + @PathVariable("id") UUID superGroupId) { + try { + this.superGroupFacade.deleteSuperGroup(superGroupId); + } catch (SuperGroupFacade.SuperGroupIsUsedException + | SuperGroupFacade.SuperGroupNotFoundException e) { + throw new RuntimeException(e); + } + + return new ModelAndView("redirect:/super-groups"); + } + + public record CreateSuperGroupForm( + @ValidatedWith(NameValidator.class) String name, + @ValidatedWith(PrettyNameValidator.class) String prettyName, + String type, + String svDescription, + String enDescription) {} + + public ModelAndView createGetCreateSuperGroup( + boolean htmxRequest, CreateSuperGroupForm form, BindingResult bindingResult) { + ModelAndView mv = new ModelAndView(); + + if (htmxRequest) { + mv.setViewName("create-super-group/page"); + } else { + mv.setViewName("index"); + mv.addObject("page", "create-super-group/page"); + } + + if (form == null) { + form = new CreateSuperGroupForm("", "", "", "", ""); + } + + mv.addObject("form", form); + mv.addObject( + "types", + this.superGroupFacade.getAllTypes().stream() + .sorted(Comparator.comparing(String::toLowerCase)) + .toList()); + + if (bindingResult != null && bindingResult.hasErrors()) { + mv.addObject(BindingResult.MODEL_KEY_PREFIX + "form", bindingResult); + } + + return mv; + } + + @GetMapping("/super-groups/create") + public ModelAndView getCreateSuperGroup( + @RequestHeader(value = "HX-Request", required = false) boolean htmxRequest) { + return createGetCreateSuperGroup(htmxRequest, null, null); + } + + @PostMapping("/super-groups") + public ModelAndView createSuperGroup( + @RequestHeader(value = "HX-Request", required = false) boolean htmxRequest, + CreateSuperGroupForm form, + BindingResult bindingResult) { + + validateObject(form, bindingResult); + + if (bindingResult.hasErrors()) { + return createGetCreateSuperGroup(htmxRequest, form, bindingResult); + } + + try { + UUID superGroupId = + this.superGroupFacade.createSuperGroup( + new SuperGroupFacade.NewSuperGroup( + form.name, form.prettyName, form.type, form.svDescription, form.enDescription)); + + return new ModelAndView("redirect:/super-groups/" + superGroupId); + } catch (SuperGroupRepository.SuperGroupAlreadyExistsException e) { + bindingResult.addError(new FieldError("form", "name", e.getMessage())); + return createGetCreateSuperGroup(htmxRequest, form, bindingResult); + } + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/primary/web/ThrottlingController.java b/app/src/main/java/it/chalmers/gamma/adapter/primary/web/ThrottlingController.java new file mode 100644 index 000000000..b5d2b7a30 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/primary/web/ThrottlingController.java @@ -0,0 +1,44 @@ +package it.chalmers.gamma.adapter.primary.web; + +import it.chalmers.gamma.app.throttling.ThrottlingManagementFacade; +import org.springframework.stereotype.Controller; +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.RequestHeader; +import org.springframework.web.servlet.ModelAndView; + +@Controller +public class ThrottlingController { + + private final ThrottlingManagementFacade throttlingManagementFacade; + + public ThrottlingController(ThrottlingManagementFacade throttlingManagementFacade) { + this.throttlingManagementFacade = throttlingManagementFacade; + } + + @GetMapping("/throttling") + public ModelAndView getThrottling( + @RequestHeader(value = "HX-Request", required = false) boolean htmxRequest) { + ModelAndView mv = new ModelAndView(); + if (htmxRequest) { + mv.setViewName("throttling/throttling"); + } else { + mv.setViewName("index"); + mv.addObject("page", "throttling/throttling"); + } + + mv.addObject("throttling", throttlingManagementFacade.getAll()); + + return mv; + } + + @DeleteMapping("/throttling/{key}") + public ModelAndView deleteActivationCode( + @RequestHeader(value = "HX-Request", required = false) boolean htmxRequest, + @PathVariable("key") String key) { + this.throttlingManagementFacade.deleteKey(key); + + return new ModelAndView("common/empty"); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/primary/web/ThymeleafAdvice.java b/app/src/main/java/it/chalmers/gamma/adapter/primary/web/ThymeleafAdvice.java new file mode 100644 index 000000000..828908d46 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/primary/web/ThymeleafAdvice.java @@ -0,0 +1,59 @@ +package it.chalmers.gamma.adapter.primary.web; + +import it.chalmers.gamma.app.authentication.AccessGuard; +import it.chalmers.gamma.security.authentication.AuthenticationExtractor; +import it.chalmers.gamma.security.authentication.UserAuthentication; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import java.io.IOException; +import org.springframework.http.HttpStatus; +import org.springframework.security.access.AccessDeniedException; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.multipart.MaxUploadSizeExceededException; +import org.springframework.web.servlet.ModelAndView; + +@ControllerAdvice +public class ThymeleafAdvice { + + @ModelAttribute("isAdmin") + public boolean isAdmin() { + if (AuthenticationExtractor.getAuthentication() + instanceof UserAuthentication userAuthenticated) { + return userAuthenticated.isAdmin(); + } else { + return false; + } + } + + @ExceptionHandler(AccessGuard.AccessDeniedException.class) + public ModelAndView handleAccessDeniedException(HttpServletRequest request) { + boolean htmxRequest = "true".equals(request.getHeader("HX-Request")); + + ModelAndView mv = new ModelAndView(); + if (htmxRequest) { + mv.setViewName("pages/unauthorized"); + } else { + mv.setViewName("index"); + mv.addObject("page", "pages/unauthorized"); + } + + return mv; + } + + @ExceptionHandler(MaxUploadSizeExceededException.class) + public ModelAndView handleMaxSizeException(HttpServletResponse response) { + response.addHeader("HX-Retarget", "#alerts"); + response.addHeader("HX-Reswap", "afterbegin"); + + return new ModelAndView("common/content-too-large"); + } + + @ResponseStatus(HttpStatus.FORBIDDEN) + @ExceptionHandler(AccessDeniedException.class) + public void handleAccessDeniedException(HttpServletResponse response) throws IOException { + response.sendRedirect("/"); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/primary/web/UserAgreementController.java b/app/src/main/java/it/chalmers/gamma/adapter/primary/web/UserAgreementController.java new file mode 100644 index 000000000..799a4aef9 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/primary/web/UserAgreementController.java @@ -0,0 +1,24 @@ +package it.chalmers.gamma.adapter.primary.web; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.servlet.ModelAndView; + +@Controller +public class UserAgreementController { + + @GetMapping("/user-agreement") + public ModelAndView getUserAgreement( + @RequestHeader(value = "HX-Request", required = false) boolean htmxRequest) { + ModelAndView mv = new ModelAndView(); + if (htmxRequest) { + mv.setViewName("user-agreement/page"); + } else { + mv.setViewName("index"); + mv.addObject("page", "user-agreement/page"); + } + + return mv; + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/primary/web/UserClientsController.java b/app/src/main/java/it/chalmers/gamma/adapter/primary/web/UserClientsController.java new file mode 100644 index 000000000..19356f692 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/primary/web/UserClientsController.java @@ -0,0 +1,50 @@ +package it.chalmers.gamma.adapter.primary.web; + +import it.chalmers.gamma.app.client.ClientFacade; +import it.chalmers.gamma.app.user.UserFacade; +import java.util.UUID; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.servlet.ModelAndView; + +@Controller +public class UserClientsController { + + private final ClientFacade clientFacade; + + public UserClientsController(ClientFacade clientFacade) { + this.clientFacade = clientFacade; + } + + public record UserClient(String prettyName, String fullName, UUID userId, UUID clientUid) { + public UserClient(ClientFacade.ClientDTO client, UserFacade.UserDTO user) { + this(client.prettyName(), user.fullName(), user.id(), client.clientUid()); + } + } + + @GetMapping("/user-clients") + public ModelAndView getUserClients( + @RequestHeader(value = "HX-Request", required = false) boolean htmxRequest) { + ModelAndView mv = new ModelAndView(); + + if (htmxRequest) { + mv.setViewName("pages/user-clients"); + } else { + mv.setViewName("index"); + mv.addObject("page", "pages/user-clients"); + } + + mv.addObject( + "clients", + this.clientFacade.getAll().stream() + .filter(client -> client.owner() instanceof ClientFacade.ClientDTO.UserOwner) + .map( + client -> + new UserClient( + client, ((ClientFacade.ClientDTO.UserOwner) client.owner()).user())) + .toList()); + + return mv; + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/primary/web/UsersController.java b/app/src/main/java/it/chalmers/gamma/adapter/primary/web/UsersController.java new file mode 100644 index 000000000..7e4553ce2 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/primary/web/UsersController.java @@ -0,0 +1,342 @@ +package it.chalmers.gamma.adapter.primary.web; + +import static it.chalmers.gamma.adapter.primary.web.WebValidationHelper.validateObject; +import static it.chalmers.gamma.app.common.UUIDValidator.isValidUUID; + +import it.chalmers.gamma.app.common.Email.EmailValidator; +import it.chalmers.gamma.app.user.UserCreationFacade; +import it.chalmers.gamma.app.user.UserFacade; +import it.chalmers.gamma.app.user.UserGdprTrainingFacade; +import it.chalmers.gamma.app.user.domain.AcceptanceYear.AcceptanceYearValidator; +import it.chalmers.gamma.app.user.domain.Cid.CidValidator; +import it.chalmers.gamma.app.user.domain.FirstName.FirstNameValidator; +import it.chalmers.gamma.app.user.domain.LastName.LastNameValidator; +import it.chalmers.gamma.app.user.domain.Nick.NickValidator; +import it.chalmers.gamma.app.user.domain.UnencryptedPassword.UnencryptedPasswordValidator; +import it.chalmers.gamma.app.user.passwordreset.UserResetPasswordFacade; +import it.chalmers.gamma.security.authentication.AuthenticationExtractor; +import it.chalmers.gamma.security.authentication.UserAuthentication; +import java.time.Year; +import java.util.Comparator; +import java.util.List; +import java.util.Optional; +import java.util.UUID; +import org.springframework.stereotype.Controller; +import org.springframework.validation.BindingResult; +import org.springframework.validation.FieldError; +import org.springframework.validation.ObjectError; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.servlet.ModelAndView; + +@Controller +public class UsersController { + + private final UserFacade userFacade; + private final UserCreationFacade userCreationFacade; + private final UserResetPasswordFacade userResetPasswordFacade; + private final UserGdprTrainingFacade userGdprTrainingFacade; + + public UsersController( + UserFacade userFacade, + UserCreationFacade userCreationFacade, + UserResetPasswordFacade userResetPasswordFacade, + UserGdprTrainingFacade userGdprTrainingFacade) { + this.userFacade = userFacade; + this.userCreationFacade = userCreationFacade; + this.userResetPasswordFacade = userResetPasswordFacade; + this.userGdprTrainingFacade = userGdprTrainingFacade; + } + + @GetMapping("/users") + public ModelAndView getUsers( + @RequestHeader(value = "HX-Request", required = false) boolean htmxRequest) { + List users = this.userFacade.getAll(); + + ModelAndView mv = new ModelAndView(); + if (htmxRequest) { + mv.setViewName("users/page"); + } else { + mv.setViewName("index"); + mv.addObject("page", "users/page"); + } + + mv.addObject( + "users", + users.stream().sorted(Comparator.comparing(user -> user.nick().toLowerCase())).toList()); + + return mv; + } + + public record UserGroup(String text, UUID id) {} + + @GetMapping("/users/{id}") + public ModelAndView getUser( + @RequestHeader(value = "HX-Request", required = false) boolean htmxRequest, + @PathVariable("id") String userId) { + if (!isValidUUID(userId)) { + return createUserNotFound(userId, htmxRequest); + } + + ModelAndView mv = new ModelAndView(); + if (htmxRequest) { + mv.setViewName("user-details/page"); + } else { + mv.setViewName("index"); + mv.addObject("page", "user-details/page"); + } + + if (AuthenticationExtractor.getAuthentication() + instanceof UserAuthentication userAuthenticated) { + if (userAuthenticated.isAdmin()) { + Optional userExtended = + this.userFacade.getAsAdmin(UUID.fromString(userId)); + + if (userExtended.isEmpty()) { + return createUserNotFound(userId, htmxRequest); + } + + UserFacade.UserExtendedWithGroupsDTO u = userExtended.get(); + String name = u.user().firstName() + " '" + u.user().nick() + "' " + u.user().lastName(); + + mv.addObject("userId", u.user().id()); + mv.addObject("name", name); + mv.addObject("nick", u.user().nick()); + mv.addObject("cid", u.user().cid()); + mv.addObject("acceptanceYear", u.user().acceptanceYear()); + mv.addObject( + "groups", + u.groups().stream() + .map( + userGroup -> + new UserGroup( + userGroup.group().prettyName() + " - " + userGroup.post().enName(), + userGroup.group().id())) + .toList()); + + mv.addObject("email", u.user().email()); + mv.addObject("locked", u.user().locked()); + mv.addObject("gdpr", this.userGdprTrainingFacade.hasGdprTraining(u.user().id())); + } else { + Optional user = + this.userFacade.getWithGroups(UUID.fromString(userId)); + + if (user.isEmpty()) { + return createUserNotFound(userId, htmxRequest); + } + + UserFacade.UserWithGroupsDTO u = user.get(); + String name = u.user().firstName() + " '" + u.user().nick() + "' " + u.user().lastName(); + + mv.addObject("userId", u.user().id()); + mv.addObject("name", name); + mv.addObject("nick", u.user().nick()); + mv.addObject("cid", u.user().cid()); + mv.addObject("acceptanceYear", u.user().acceptanceYear()); + mv.addObject( + "groups", + u.groups().stream() + .map( + userGroup -> + new UserGroup( + userGroup.group().prettyName() + " - " + userGroup.post().enName(), + userGroup.group().id())) + .toList()); + } + } + + return mv; + } + + private ModelAndView createUserNotFound(String userId, boolean htmxRequest) { + ModelAndView mv = new ModelAndView(); + if (htmxRequest) { + mv.setViewName("user-details/not-found"); + } else { + mv.setViewName("index"); + mv.addObject("page", "user-details/not-found"); + } + + mv.addObject("id", userId); + + return mv; + } + + public record CreateUser( + @ValidatedWith(UnencryptedPasswordValidator.class) String password, + @ValidatedWith(NickValidator.class) String nick, + @ValidatedWith(FirstNameValidator.class) String firstName, + @ValidatedWith(LastNameValidator.class) String lastName, + @ValidatedWith(EmailValidator.class) String email, + @ValidatedWith(AcceptanceYearValidator.class) int acceptanceYear, + @ValidatedWith(CidValidator.class) String cid, + String language) {} + + @GetMapping("/users/create") + public ModelAndView getCreateUser( + @RequestHeader(value = "HX-Request", required = false) boolean htmxRequest) { + ModelAndView mv = new ModelAndView(); + + if (htmxRequest) { + mv.setViewName("create-user/page"); + } else { + mv.setViewName("index"); + mv.addObject("page", "create-user/page"); + } + + mv.addObject("form", new CreateUser("", "", "", "", "", Year.now().getValue(), "", "")); + + return mv; + } + + @PostMapping("/users/create") + public ModelAndView createUser( + @RequestHeader(value = "HX-Request", required = false) boolean htmxRequest, + CreateUser form, + final BindingResult bindingResult) { + ModelAndView mv = new ModelAndView(); + + validateObject(form, bindingResult); + + try { + if (!bindingResult.hasErrors()) { + UUID userId = + this.userCreationFacade.createUser( + new UserCreationFacade.NewUser( + form.password, + form.nick, + form.firstName, + form.lastName, + form.email, + form.acceptanceYear, + form.cid, + form.language)); + + mv.setViewName("redirect:/users/" + userId); + } + } catch (IllegalArgumentException e) { + bindingResult.addError(new ObjectError("global", e.getMessage())); + } catch (UserCreationFacade.CidNotUniqueException e) { + bindingResult.addError(new FieldError("form", "cid", e.getMessage())); + } catch (UserCreationFacade.EmailNotUniqueException e) { + bindingResult.addError(new FieldError("form", "email", e.getMessage())); + } + + if (bindingResult.hasErrors()) { + if (htmxRequest) { + mv.setViewName("create-user/page"); + } else { + mv.setViewName("index"); + mv.addObject("page", "create-user/page"); + } + + mv.addObject("form", form); + mv.addObject(BindingResult.MODEL_KEY_PREFIX + "form", bindingResult); + } + + return mv; + } + + public record EditUser( + String nick, + String firstName, + String lastName, + String email, + int acceptanceYear, + String language) {} + + @GetMapping("/users/{id}/edit") + public ModelAndView getEditUser( + @RequestHeader(value = "HX-Request", required = true) boolean htmxRequest, + @PathVariable("id") UUID userId) { + Optional user = this.userFacade.getAsAdmin(userId); + + if (user.isEmpty()) { + throw new RuntimeException(); + } + + UserFacade.UserExtendedDTO u = user.get().user(); + + ModelAndView mv = new ModelAndView(); + + mv.setViewName("user-details/edit-user"); + mv.addObject("userId", u.id()); + mv.addObject( + "form", + new EditUser( + u.nick(), u.firstName(), u.lastName(), u.email(), u.acceptanceYear(), u.language())); + + return mv; + } + + @PutMapping("/users/{id}") + public ModelAndView editUser( + @RequestHeader(value = "HX-Request", required = true) boolean htmxRequest, + @PathVariable("id") UUID userId, + EditUser form, + BindingResult bindingResult) { + ModelAndView mv = new ModelAndView(); + + try { + this.userFacade.updateUser( + new UserFacade.UpdateUser( + userId, + form.nick, + form.firstName, + form.lastName, + form.email, + form.language, + form.acceptanceYear)); + } catch (IllegalArgumentException e) { + bindingResult.addError(new ObjectError("global", e.getMessage())); + + mv.setViewName("user-details/edit-user"); + mv.addObject("userId", userId); + mv.addObject("form", form); + mv.addObject(BindingResult.MODEL_KEY_PREFIX + "form", bindingResult); + + return mv; + } + + Optional user = this.userFacade.getAsAdmin(userId); + + if (user.isEmpty()) { + throw new RuntimeException(); + } + + String name = form.firstName() + " '" + form.nick() + "' " + form.lastName(); + + mv.setViewName("user-details/edited-user"); + mv.addObject("name", name); + mv.addObject("cid", user.get().user().cid()); + mv.addObject("acceptanceYear", form.acceptanceYear); + mv.addObject("email", form.email); + mv.addObject("locked", user.get().user().locked()); + mv.addObject("gdpr", this.userGdprTrainingFacade.hasGdprTraining(user.get().user().id())); + mv.addObject("userId", userId); + + return mv; + } + + @DeleteMapping("/users/{id}") + public ModelAndView deleteUser( + @RequestHeader(value = "HX-Request", required = true) boolean htmxRequest, + @PathVariable("id") UUID userId) { + + this.userFacade.deleteUser(userId); + + return new ModelAndView("redirect:/users"); + } + + @PostMapping("/users/{id}/generate-password-link") + public ModelAndView generatePasswordLink( + @RequestHeader(value = "HX-Request", required = true) boolean htmxRequest, + @PathVariable("id") UUID userId) { + String passwordResetLink = userResetPasswordFacade.generatePasswordLink(userId); + + ModelAndView mv = new ModelAndView(); + mv.setViewName("user-details/page :: password-link-generated"); + mv.addObject("passwordLink", passwordResetLink); + + return mv; + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/primary/web/ValidatedWith.java b/app/src/main/java/it/chalmers/gamma/adapter/primary/web/ValidatedWith.java new file mode 100644 index 000000000..a2b822bbd --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/primary/web/ValidatedWith.java @@ -0,0 +1,14 @@ +package it.chalmers.gamma.adapter.primary.web; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import it.chalmers.gamma.app.validation.Validator; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +@Retention(RUNTIME) +@Target(FIELD) +public @interface ValidatedWith { + Class> value(); +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/primary/web/WebValidationHelper.java b/app/src/main/java/it/chalmers/gamma/adapter/primary/web/WebValidationHelper.java new file mode 100644 index 000000000..583eace62 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/primary/web/WebValidationHelper.java @@ -0,0 +1,81 @@ +package it.chalmers.gamma.adapter.primary.web; + +import it.chalmers.gamma.app.validation.FailedValidation; +import it.chalmers.gamma.app.validation.ValidationResult; +import it.chalmers.gamma.app.validation.Validator; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Modifier; +import org.springframework.validation.BindingResult; +import org.springframework.validation.FieldError; + +public class WebValidationHelper { + + public static void validateObject(Object obj, BindingResult bindingResult) { + Field[] fields = obj.getClass().getDeclaredFields(); + for (Field field : fields) { + validateField(field, "", obj, bindingResult); + } + } + + private static void validateField( + Field field, String prefix, Object obj, BindingResult bindingResult) { + if (Modifier.isStatic(field.getModifiers())) { + return; + } + + field.setAccessible(true); + Object fieldValue; + try { + fieldValue = field.get(obj); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + + ValidatedWith validatedWith = field.getAnnotation(ValidatedWith.class); + if (validatedWith != null) { + try { + Validator validator = + (Validator) validatedWith.value().getDeclaredConstructor().newInstance(); + ValidationResult validationResult = validator.validate(fieldValue); + if (validationResult instanceof FailedValidation failedValidation) { + bindingResult.addError( + new FieldError( + "form", + prefix + field.getName(), + fieldValue, + true, + null, + null, + failedValidation.message())); + } + } catch (NoSuchMethodException + | InstantiationException + | IllegalAccessException + | InvocationTargetException e) { + throw new RuntimeException(e); + } + } + + if (fieldValue instanceof Iterable) { + int i = 0; + for (Object item : (Iterable) fieldValue) { + if (item != null + && !item.getClass().isPrimitive() + && !(item instanceof String) + && !item.getClass().getPackageName().startsWith("java")) { + String newPrefix = String.format("%s%s[%d].", prefix, field.getName(), i); + validateObject(item, newPrefix, bindingResult); + } + i++; + } + } + } + + private static void validateObject(Object obj, String prefix, BindingResult bindingResult) { + Field[] fields = obj.getClass().getDeclaredFields(); + for (Field field : fields) { + validateField(field, prefix, obj, bindingResult); + } + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/image/ImageFile.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/image/ImageFile.java new file mode 100644 index 000000000..14677a325 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/image/ImageFile.java @@ -0,0 +1,28 @@ +package it.chalmers.gamma.adapter.secondary.image; + +import static it.chalmers.gamma.app.validation.ValidationHelper.result; + +import it.chalmers.gamma.app.image.domain.Image; +import it.chalmers.gamma.app.validation.ValidationResult; +import it.chalmers.gamma.app.validation.Validator; +import java.util.Arrays; +import java.util.Objects; +import org.springframework.web.multipart.MultipartFile; + +public record ImageFile(MultipartFile file) implements Image { + + public ImageFile { + Objects.requireNonNull(file); + new ImageFileValidator().validate(file); + } + + public static final class ImageFileValidator implements Validator { + + @Override + public ValidationResult validate(MultipartFile file) { + return result( + Arrays.asList("image/jpeg", "image/png", "image/gif").contains(file.getContentType()), + "Must be an image"); + } + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/image/LocalImageService.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/image/LocalImageService.java new file mode 100644 index 000000000..352024f5d --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/image/LocalImageService.java @@ -0,0 +1,127 @@ +package it.chalmers.gamma.adapter.secondary.image; + +import it.chalmers.gamma.app.image.domain.Image; +import it.chalmers.gamma.app.image.domain.ImageService; +import it.chalmers.gamma.app.image.domain.ImageUri; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; +import java.util.UUID; +import javax.imageio.ImageIO; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; +import org.springframework.util.StreamUtils; +import org.springframework.web.multipart.MultipartFile; + +@Component +public class LocalImageService implements ImageService { + + private static final Logger LOGGER = LoggerFactory.getLogger(LocalImageService.class); + + private final String relativePath; + + public LocalImageService(@Value("${application.files.path}") String relativePath) { + this.relativePath = relativePath; + } + + public ImageUri saveImage(Image image) throws ImageCouldNotBeSavedException { + if (image instanceof ImageFile) { + MultipartFile file = ((ImageFile) image).file(); + + this.checkIfValidImageContent(file); + + String filePathString = + UUID.randomUUID() + "/" + file.getName() + "." + getExtension(file.getOriginalFilename()); + + File filePath = new File(this.relativePath + filePathString); + + File fileFolderPath = new File(filePath.getParent()); + if (!fileFolderPath.mkdirs()) { + throw new ImageCouldNotBeSavedException("File folder could not be created"); + } + + try { + if (!filePath.createNewFile()) { + throw new ImageCouldNotBeSavedException("(1) File could not be created"); + } + + try (OutputStream fos = Files.newOutputStream(Path.of(filePath.getPath()))) { + fos.write(file.getBytes()); + } + + } catch (IOException e) { + throw new ImageCouldNotBeSavedException("(2) File could not be created", e); + } + + LOGGER.info("Image " + file.getOriginalFilename() + " was uploaded."); + + return new ImageUri(filePathString); + } + throw new RuntimeException("Image not of type ImageFile"); + } + + public void removeImage(ImageUri imageUri) throws ImageCouldNotBeRemovedException { + File f = new File(relativePath + imageUri.value()); + if (!f.delete()) { + LOGGER.error("Could not delete the file: " + imageUri); + throw new ImageCouldNotBeRemovedException(); + } + } + + @Override + public ImageDetails getImage(ImageUri imageUri) { + try { + return new ImageDetails( + StreamUtils.copyToByteArray( + Files.newInputStream(Paths.get(this.relativePath + imageUri.value()))), + getType(imageUri)); + } catch (IOException e) { + e.printStackTrace(); + return null; + } + } + + private String getExtension(String fileName) { + if (fileName == null) { + throw new IllegalArgumentException(); + } + + return fileName.substring(fileName.lastIndexOf('.') + 1); + } + + private String getType(ImageUri imageUri) { + String[] split = imageUri.value().split("\\."); + return split[split.length - 1]; + } + + private void checkIfValidImageContent(MultipartFile file) throws ImageCouldNotBeSavedException { + long fileSizeInBytes = file.getSize(); + long fileSizeInKB = fileSizeInBytes / 1024; + long fileSizeInMB = fileSizeInKB / 1024; + + if (fileSizeInMB > 2) { + throw new ImageCouldNotBeSavedException("Image size exceeds the limit of 2MB"); + } + + String contentType = file.getContentType(); + if (!List.of("image/jpeg", "image/png", "image/gif").contains(contentType)) { + throw new ImageCouldNotBeSavedException("Image content type not valid"); + } + + try (InputStream is = file.getInputStream()) { + var test = ImageIO.read(is); + if (test == null) { + throw new ImageCouldNotBeSavedException("Image content not valid"); + } + } catch (IOException e) { + throw new ImageCouldNotBeSavedException("Image content not valid"); + } + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/allowlist/AllowListEntity.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/allowlist/AllowListEntity.java new file mode 100644 index 000000000..cfeadfe1f --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/allowlist/AllowListEntity.java @@ -0,0 +1,27 @@ +package it.chalmers.gamma.adapter.secondary.jpa.allowlist; + +import it.chalmers.gamma.adapter.secondary.jpa.util.AbstractEntity; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; + +@Entity +@Table(name = "g_allow_list") +public class AllowListEntity extends AbstractEntity { + + @Id + @Column(name = "cid") + private String cid; + + protected AllowListEntity() {} + + protected AllowListEntity(String cid) { + this.cid = cid; + } + + @Override + public String getId() { + return this.cid; + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/allowlist/AllowListJpaRepository.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/allowlist/AllowListJpaRepository.java new file mode 100644 index 000000000..50055b6a8 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/allowlist/AllowListJpaRepository.java @@ -0,0 +1,7 @@ +package it.chalmers.gamma.adapter.secondary.jpa.allowlist; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface AllowListJpaRepository extends JpaRepository {} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/allowlist/AllowListRepositoryAdapter.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/allowlist/AllowListRepositoryAdapter.java new file mode 100644 index 000000000..5c75f49fe --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/allowlist/AllowListRepositoryAdapter.java @@ -0,0 +1,58 @@ +package it.chalmers.gamma.adapter.secondary.jpa.allowlist; + +import it.chalmers.gamma.adapter.secondary.jpa.util.PersistenceErrorHelper; +import it.chalmers.gamma.adapter.secondary.jpa.util.PersistenceErrorState; +import it.chalmers.gamma.app.user.allowlist.AllowListRepository; +import it.chalmers.gamma.app.user.domain.Cid; +import java.util.List; +import org.springframework.dao.DataIntegrityViolationException; +import org.springframework.dao.EmptyResultDataAccessException; +import org.springframework.stereotype.Service; + +@Service +public class AllowListRepositoryAdapter implements AllowListRepository { + + private final AllowListJpaRepository allowListJpaRepository; + + private final PersistenceErrorState CID_ALREADY_ALLOWED = + new PersistenceErrorState("g_allow_list_pkey", PersistenceErrorState.Type.NOT_UNIQUE); + + public AllowListRepositoryAdapter(AllowListJpaRepository allowListJpaRepository) { + this.allowListJpaRepository = allowListJpaRepository; + } + + @Override + public void allow(Cid cid) throws AlreadyAllowedException { + try { + this.allowListJpaRepository.save(new AllowListEntity(cid.value())); + } catch (DataIntegrityViolationException e) { + PersistenceErrorState state = PersistenceErrorHelper.getState(e); + + if (CID_ALREADY_ALLOWED.equals(state)) { + throw new AlreadyAllowedException(); + } + } + } + + @Override + public void remove(Cid cid) throws NotOnAllowListException { + try { + this.allowListJpaRepository.deleteById(cid.value()); + } catch (EmptyResultDataAccessException e) { + throw new NotOnAllowListException(); + } + } + + @Override + public boolean isAllowed(Cid cid) { + return this.allowListJpaRepository.existsById(cid.value()); + } + + @Override + public List getAllowList() { + return this.allowListJpaRepository.findAll().stream() + .map(AllowListEntity::getId) + .map(Cid::new) + .toList(); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/apikey/ApiKeyEntity.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/apikey/ApiKeyEntity.java new file mode 100644 index 000000000..46bb84c36 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/apikey/ApiKeyEntity.java @@ -0,0 +1,67 @@ +package it.chalmers.gamma.adapter.secondary.jpa.apikey; + +import it.chalmers.gamma.adapter.secondary.jpa.text.TextEntity; +import it.chalmers.gamma.adapter.secondary.jpa.util.MutableEntity; +import it.chalmers.gamma.app.apikey.domain.ApiKeyType; +import jakarta.persistence.*; +import java.util.UUID; + +@Entity +@Table(name = "g_api_key") +public class ApiKeyEntity extends MutableEntity { + + @Id + @Column(name = "api_key_id", columnDefinition = "uuid") + protected UUID id; + + @Column(name = "token") + protected String token; + + @Column(name = "pretty_name") + protected String prettyName; + + @Enumerated(EnumType.STRING) + protected ApiKeyType keyType; + + @JoinColumn(name = "description") + @OneToOne(cascade = CascadeType.ALL) + protected TextEntity description; + + public ApiKeyEntity() { + description = new TextEntity(); + } + + public ApiKeyEntity( + UUID id, String token, String prettyName, ApiKeyType keyType, TextEntity description) { + this.id = id; + this.token = token; + this.prettyName = prettyName; + this.keyType = keyType; + this.description = description; + } + + @Override + public UUID getId() { + return this.id; + } + + public void setApiKeyToken(String token) { + this.token = token; + } + + public String getToken() { + return token; + } + + public String getPrettyName() { + return prettyName; + } + + public ApiKeyType getKeyType() { + return keyType; + } + + public TextEntity getDescription() { + return description; + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/apikey/ApiKeyEntityConverter.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/apikey/ApiKeyEntityConverter.java new file mode 100644 index 000000000..533686f0c --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/apikey/ApiKeyEntityConverter.java @@ -0,0 +1,20 @@ +package it.chalmers.gamma.adapter.secondary.jpa.apikey; + +import it.chalmers.gamma.app.apikey.domain.ApiKey; +import it.chalmers.gamma.app.apikey.domain.ApiKeyId; +import it.chalmers.gamma.app.apikey.domain.ApiKeyToken; +import it.chalmers.gamma.app.common.PrettyName; +import org.springframework.stereotype.Service; + +@Service +public class ApiKeyEntityConverter { + + public ApiKey toDomain(ApiKeyEntity entity) { + return new ApiKey( + new ApiKeyId(entity.getId()), + new PrettyName(entity.getPrettyName()), + entity.getDescription().toDomain(), + entity.getKeyType(), + new ApiKeyToken(entity.getToken())); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/apikey/ApiKeyJpaRepository.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/apikey/ApiKeyJpaRepository.java new file mode 100644 index 000000000..7bab1da78 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/apikey/ApiKeyJpaRepository.java @@ -0,0 +1,9 @@ +package it.chalmers.gamma.adapter.secondary.jpa.apikey; + +import java.util.Optional; +import java.util.UUID; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface ApiKeyJpaRepository extends JpaRepository { + Optional findByToken(String token); +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/apikey/ApiKeyRepositoryAdapter.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/apikey/ApiKeyRepositoryAdapter.java new file mode 100644 index 000000000..72d75bf8a --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/apikey/ApiKeyRepositoryAdapter.java @@ -0,0 +1,98 @@ +package it.chalmers.gamma.adapter.secondary.jpa.apikey; + +import it.chalmers.gamma.adapter.secondary.jpa.client.apikey.ClientApiKeyEntity; +import it.chalmers.gamma.adapter.secondary.jpa.client.apikey.ClientApiKeyJpaRepository; +import it.chalmers.gamma.app.apikey.domain.ApiKey; +import it.chalmers.gamma.app.apikey.domain.ApiKeyId; +import it.chalmers.gamma.app.apikey.domain.ApiKeyRepository; +import it.chalmers.gamma.app.apikey.domain.ApiKeyToken; +import jakarta.persistence.EntityExistsException; +import jakarta.transaction.Transactional; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; +import org.springframework.dao.DataIntegrityViolationException; +import org.springframework.dao.EmptyResultDataAccessException; +import org.springframework.stereotype.Repository; + +@Repository +public class ApiKeyRepositoryAdapter implements ApiKeyRepository { + + private final ApiKeyJpaRepository repository; + private final ApiKeyEntityConverter apiKeyEntityConverter; + private final ClientApiKeyJpaRepository clientApiKeyJpaRepository; + + public ApiKeyRepositoryAdapter( + ApiKeyJpaRepository repository, + ApiKeyEntityConverter apiKeyEntityConverter, + ClientApiKeyJpaRepository clientApiKeyJpaRepository) { + this.repository = repository; + this.apiKeyEntityConverter = apiKeyEntityConverter; + this.clientApiKeyJpaRepository = clientApiKeyJpaRepository; + } + + @Override + public void create(ApiKey apiKey) throws ApiKeyAlreadyExistRuntimeException { + try { + this.repository.saveAndFlush(toEntity(apiKey)); + } catch (DataIntegrityViolationException e) { + if (e.getCause() instanceof EntityExistsException) { + throw new ApiKeyAlreadyExistRuntimeException(); + } + throw e; + } + } + + @Transactional + @Override + public void delete(ApiKeyId apiKeyId) throws ApiKeyNotFoundException { + try { + + // First check if this ApiKey is connected to a Client. + ClientApiKeyEntity clientApiKeyEntity = + this.clientApiKeyJpaRepository.getByApiKey_Id(apiKeyId.value()); + if (clientApiKeyEntity != null) { + clientApiKeyEntity.removeApiKey(); + this.clientApiKeyJpaRepository.saveAndFlush(clientApiKeyEntity); + } else { + this.repository.deleteById(apiKeyId.value()); + } + + } catch (EmptyResultDataAccessException e) { + throw new ApiKeyNotFoundException(); + } + } + + @Override + public List getAll() { + return this.repository.findAll().stream() + .map(this.apiKeyEntityConverter::toDomain) + .collect(Collectors.toList()); + } + + @Override + public Optional getById(ApiKeyId apiKeyId) { + return this.repository.findById(apiKeyId.value()).map(this.apiKeyEntityConverter::toDomain); + } + + @Override + public void setNewGeneratedToken(ApiKeyId apiKeyId, ApiKeyToken token) { + ApiKeyEntity apiKeyEntity = this.repository.findById(apiKeyId.value()).orElseThrow(); + + apiKeyEntity.token = token.value(); + + this.repository.save(apiKeyEntity); + } + + private ApiKeyEntity toEntity(ApiKey apiKey) { + ApiKeyEntity apiKeyEntity = new ApiKeyEntity(); + + apiKeyEntity.id = apiKey.id().value(); + apiKeyEntity.token = apiKey.apiKeyToken().value(); + apiKeyEntity.prettyName = apiKey.prettyName().value(); + apiKeyEntity.keyType = apiKey.keyType(); + apiKeyEntity.description.apply(apiKey.description()); + + return apiKeyEntity; + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/apikey/settings/ApiKeySettingsEntity.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/apikey/settings/ApiKeySettingsEntity.java new file mode 100644 index 000000000..fe4fd8140 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/apikey/settings/ApiKeySettingsEntity.java @@ -0,0 +1,32 @@ +package it.chalmers.gamma.adapter.secondary.jpa.apikey.settings; + +import it.chalmers.gamma.adapter.secondary.jpa.apikey.ApiKeyEntity; +import it.chalmers.gamma.adapter.secondary.jpa.util.MutableEntity; +import jakarta.persistence.*; +import java.util.List; +import java.util.UUID; + +@Entity +@Table(name = "g_api_key_settings") +public class ApiKeySettingsEntity extends MutableEntity { + + @Id + @Column(name = "settings_id", columnDefinition = "uuid") + protected UUID id; + + @JoinColumn(name = "api_key_id") + @OneToOne(cascade = CascadeType.ALL) + protected ApiKeyEntity apiKeyEntity; + + @OneToMany( + mappedBy = "id.settings", + cascade = CascadeType.ALL, + orphanRemoval = true, + fetch = FetchType.EAGER) + protected List superGroupTypes; + + @Override + public UUID getId() { + return this.id; + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/apikey/settings/ApiKeySettingsJpaRepository.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/apikey/settings/ApiKeySettingsJpaRepository.java new file mode 100644 index 000000000..fee982441 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/apikey/settings/ApiKeySettingsJpaRepository.java @@ -0,0 +1,9 @@ +package it.chalmers.gamma.adapter.secondary.jpa.apikey.settings; + +import java.util.UUID; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface ApiKeySettingsJpaRepository extends JpaRepository { + + ApiKeySettingsEntity getApiKeySettingsEntityByApiKeyEntity_Id(UUID apiKeyId); +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/apikey/settings/ApiKeySettingsRepositoryAdapter.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/apikey/settings/ApiKeySettingsRepositoryAdapter.java new file mode 100644 index 000000000..307b2c3e4 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/apikey/settings/ApiKeySettingsRepositoryAdapter.java @@ -0,0 +1,157 @@ +package it.chalmers.gamma.adapter.secondary.jpa.apikey.settings; + +import it.chalmers.gamma.adapter.secondary.jpa.apikey.ApiKeyEntity; +import it.chalmers.gamma.adapter.secondary.jpa.apikey.ApiKeyJpaRepository; +import it.chalmers.gamma.adapter.secondary.jpa.supergroup.SuperGroupTypeJpaRepository; +import it.chalmers.gamma.app.apikey.domain.ApiKeyId; +import it.chalmers.gamma.app.apikey.domain.ApiKeyType; +import it.chalmers.gamma.app.apikey.domain.settings.ApiKeyAccountScaffoldSettings; +import it.chalmers.gamma.app.apikey.domain.settings.ApiKeyInfoSettings; +import it.chalmers.gamma.app.apikey.domain.settings.ApiKeySettingsRepository; +import jakarta.transaction.Transactional; +import java.util.ArrayList; +import java.util.UUID; +import org.springframework.stereotype.Repository; + +@Repository +public class ApiKeySettingsRepositoryAdapter implements ApiKeySettingsRepository { + + private final ApiKeyJpaRepository apiKeyJpaRepository; + private final ApiKeySettingsJpaRepository apiKeySettingsJpaRepository; + private final SuperGroupTypeJpaRepository superGroupTypeJpaRepository; + + public ApiKeySettingsRepositoryAdapter( + ApiKeyJpaRepository apiKeyJpaRepository, + ApiKeySettingsJpaRepository apiKeySettingsJpaRepository, + SuperGroupTypeJpaRepository superGroupTypeJpaRepository) { + this.apiKeyJpaRepository = apiKeyJpaRepository; + this.apiKeySettingsJpaRepository = apiKeySettingsJpaRepository; + this.superGroupTypeJpaRepository = superGroupTypeJpaRepository; + } + + @Override + public void createEmptyAccountScaffoldSettings(ApiKeyId apiKeyId) { + ApiKeySettingsEntity entity = new ApiKeySettingsEntity(); + + ApiKeyEntity apiKeyEntity = this.apiKeyJpaRepository.getReferenceById(apiKeyId.value()); + + if (apiKeyEntity.getKeyType() != ApiKeyType.ACCOUNT_SCAFFOLD) { + throw new RuntimeException( + "Can only create account scaffold settings for account scaffold api key"); + } + + entity.id = UUID.randomUUID(); + entity.apiKeyEntity = apiKeyEntity; + entity.superGroupTypes = new ArrayList<>(); + + this.apiKeySettingsJpaRepository.save(entity); + } + + @Override + public void createEmptyInfoSettings(ApiKeyId apiKeyId) { + ApiKeySettingsEntity entity = new ApiKeySettingsEntity(); + + ApiKeyEntity apiKeyEntity = this.apiKeyJpaRepository.getReferenceById(apiKeyId.value()); + + if (apiKeyEntity.getKeyType() != ApiKeyType.INFO) { + throw new RuntimeException("Can only create info settings for info api key"); + } + + entity.id = UUID.randomUUID(); + entity.apiKeyEntity = apiKeyEntity; + entity.superGroupTypes = new ArrayList<>(); + + this.apiKeySettingsJpaRepository.save(entity); + } + + @Override + public ApiKeyAccountScaffoldSettings getAccountScaffoldSettings(ApiKeyId apiKeyId) { + ApiKeySettingsEntity apiKeySettingsEntity = + this.apiKeySettingsJpaRepository.getApiKeySettingsEntityByApiKeyEntity_Id(apiKeyId.value()); + + if (apiKeySettingsEntity.apiKeyEntity == null) { + throw new RuntimeException("Unexpected null"); + } + + if (apiKeySettingsEntity.apiKeyEntity.getKeyType() != ApiKeyType.ACCOUNT_SCAFFOLD) { + throw new RuntimeException("Unexpected api key type"); + } + + return new ApiKeyAccountScaffoldSettings( + apiKeySettingsEntity.getVersion(), + apiKeySettingsEntity.superGroupTypes.stream() + .map(ApiKeySettingsSuperGroupTypeEntity::getSuperGroupType) + .toList()); + } + + @Override + public ApiKeyInfoSettings getInfoSettings(ApiKeyId apiKeyId) { + ApiKeySettingsEntity apiKeySettingsEntity = + this.apiKeySettingsJpaRepository.getApiKeySettingsEntityByApiKeyEntity_Id(apiKeyId.value()); + + if (apiKeySettingsEntity.apiKeyEntity == null) { + throw new RuntimeException("Unexpected null"); + } + + if (apiKeySettingsEntity.apiKeyEntity.getKeyType() != ApiKeyType.INFO) { + throw new RuntimeException("Unexpected api key type"); + } + + return new ApiKeyInfoSettings( + apiKeySettingsEntity.getVersion(), + apiKeySettingsEntity.superGroupTypes.stream() + .map(ApiKeySettingsSuperGroupTypeEntity::getSuperGroupType) + .toList()); + } + + @Transactional + @Override + public void setAccountScaffoldSettings( + ApiKeyId apiKeyId, ApiKeyAccountScaffoldSettings settings) { + ApiKeySettingsEntity apiKeySettingsEntity = + this.apiKeySettingsJpaRepository.getApiKeySettingsEntityByApiKeyEntity_Id(apiKeyId.value()); + + if (apiKeySettingsEntity.apiKeyEntity.getKeyType() != ApiKeyType.ACCOUNT_SCAFFOLD) { + throw new RuntimeException("Unexpected api key type"); + } + + apiKeySettingsEntity.superGroupTypes.clear(); + apiKeySettingsEntity.superGroupTypes.addAll( + settings.superGroupTypes().stream() + .map( + superGroupType -> + new ApiKeySettingsSuperGroupTypeEntity( + apiKeySettingsEntity, + superGroupTypeJpaRepository.getReferenceById(superGroupType.value()))) + .toList()); + + apiKeySettingsEntity.increaseVersion(settings.version()); + + this.apiKeySettingsJpaRepository.save(apiKeySettingsEntity); + } + + @Transactional + @Override + public void setInfoSettings(ApiKeyId apiKeyId, ApiKeyInfoSettings settings) { + ApiKeySettingsEntity apiKeySettingsEntity = + this.apiKeySettingsJpaRepository.getApiKeySettingsEntityByApiKeyEntity_Id(apiKeyId.value()); + + if (apiKeySettingsEntity.apiKeyEntity.getKeyType() != ApiKeyType.INFO) { + throw new RuntimeException("Unexpected api key type"); + } + + apiKeySettingsEntity.superGroupTypes.clear(); + apiKeySettingsEntity.superGroupTypes.addAll( + settings.superGroupTypes().stream() + .map( + superGroupType -> + new ApiKeySettingsSuperGroupTypeEntity( + apiKeySettingsEntity, + superGroupTypeJpaRepository.getReferenceById(superGroupType.value()))) + .toList()); + + apiKeySettingsEntity.increaseVersion(settings.version()); + + this.apiKeySettingsJpaRepository.save(apiKeySettingsEntity); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/apikey/settings/ApiKeySettingsSuperGroupTypeEntity.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/apikey/settings/ApiKeySettingsSuperGroupTypeEntity.java new file mode 100644 index 000000000..3def65ec5 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/apikey/settings/ApiKeySettingsSuperGroupTypeEntity.java @@ -0,0 +1,32 @@ +package it.chalmers.gamma.adapter.secondary.jpa.apikey.settings; + +import it.chalmers.gamma.adapter.secondary.jpa.supergroup.SuperGroupTypeEntity; +import it.chalmers.gamma.adapter.secondary.jpa.util.ImmutableEntity; +import it.chalmers.gamma.app.supergroup.domain.SuperGroupType; +import jakarta.persistence.EmbeddedId; +import jakarta.persistence.Entity; +import jakarta.persistence.Table; + +@Entity +@Table(name = "g_api_key_to_super_group_type") +public class ApiKeySettingsSuperGroupTypeEntity + extends ImmutableEntity { + + @EmbeddedId private ApiKeySettingsSuperGroupTypePK id; + + protected ApiKeySettingsSuperGroupTypeEntity() {} + + protected ApiKeySettingsSuperGroupTypeEntity( + ApiKeySettingsEntity apiKeySettingsEntity, SuperGroupTypeEntity superGroupTypeEntity) { + this.id = new ApiKeySettingsSuperGroupTypePK(apiKeySettingsEntity, superGroupTypeEntity); + } + + @Override + public ApiKeySettingsSuperGroupTypePK getId() { + return this.id; + } + + public SuperGroupType getSuperGroupType() { + return this.id.getValue().superGroupType(); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/apikey/settings/ApiKeySettingsSuperGroupTypePK.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/apikey/settings/ApiKeySettingsSuperGroupTypePK.java new file mode 100644 index 000000000..d6c7e7fc1 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/apikey/settings/ApiKeySettingsSuperGroupTypePK.java @@ -0,0 +1,37 @@ +package it.chalmers.gamma.adapter.secondary.jpa.apikey.settings; + +import it.chalmers.gamma.adapter.secondary.jpa.supergroup.SuperGroupTypeEntity; +import it.chalmers.gamma.adapter.secondary.jpa.util.PKId; +import it.chalmers.gamma.app.supergroup.domain.SuperGroupType; +import jakarta.persistence.*; +import java.util.UUID; + +@Embeddable +public class ApiKeySettingsSuperGroupTypePK + extends PKId { + + @ManyToOne + @JoinColumn(name = "settings_id") + private ApiKeySettingsEntity settings; + + @OneToOne(fetch = FetchType.EAGER) + @JoinColumn(name = "super_group_type_name") + private SuperGroupTypeEntity superGroupType; + + protected ApiKeySettingsSuperGroupTypePK() {} + + protected ApiKeySettingsSuperGroupTypePK( + ApiKeySettingsEntity settingsEntity, SuperGroupTypeEntity superGroupTypeEntity) { + this.settings = settingsEntity; + this.superGroupType = superGroupTypeEntity; + } + + @Override + public ApiKeySettingsSuperGroupTypePKDTO getValue() { + return new ApiKeySettingsSuperGroupTypePKDTO( + settings.getId(), new SuperGroupType(superGroupType.getId())); + } + + public record ApiKeySettingsSuperGroupTypePKDTO( + UUID apiKeySettingsId, SuperGroupType superGroupType) {} +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/client/ClientEntity.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/client/ClientEntity.java new file mode 100644 index 000000000..2458b405b --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/client/ClientEntity.java @@ -0,0 +1,61 @@ +package it.chalmers.gamma.adapter.secondary.jpa.client; + +import it.chalmers.gamma.adapter.secondary.jpa.client.apikey.ClientApiKeyEntity; +import it.chalmers.gamma.adapter.secondary.jpa.client.restriction.ClientRestrictionEntity; +import it.chalmers.gamma.adapter.secondary.jpa.client.scope.ClientScopeEntity; +import it.chalmers.gamma.adapter.secondary.jpa.text.TextEntity; +import it.chalmers.gamma.adapter.secondary.jpa.util.ImmutableEntity; +import jakarta.annotation.Nullable; +import jakarta.persistence.*; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +@Entity +@Table(name = "g_client") +public class ClientEntity extends ImmutableEntity { + + @Id + @Column(name = "client_uid", columnDefinition = "uuid") + protected UUID clientUid; + + @Column(name = "client_id") + protected String clientId; + + @Column(name = "client_secret") + protected String clientSecret; + + @Column(name = "redirect_uri") + protected String webServerRedirectUrl; + + @Column(name = "pretty_name") + protected String prettyName; + + @JoinColumn(name = "description") + @OneToOne(cascade = CascadeType.ALL) + protected TextEntity description; + + @OneToMany(mappedBy = "id.client", cascade = CascadeType.ALL, orphanRemoval = true) + protected List scopes; + + @OneToOne(mappedBy = "client", cascade = CascadeType.ALL, orphanRemoval = true) + protected ClientApiKeyEntity clientsApiKey; + + @OneToOne(mappedBy = "client", cascade = CascadeType.ALL, orphanRemoval = true) + protected ClientRestrictionEntity clientRestriction; + + @Column(name = "official") + protected Boolean official; + + @Column(name = "created_by") + @Nullable protected UUID createdBy; + + protected ClientEntity() { + this.scopes = new ArrayList<>(); + } + + @Override + public UUID getId() { + return this.clientUid; + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/client/ClientEntityConverter.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/client/ClientEntityConverter.java new file mode 100644 index 000000000..4b1aea03f --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/client/ClientEntityConverter.java @@ -0,0 +1,155 @@ +package it.chalmers.gamma.adapter.secondary.jpa.client; + +import it.chalmers.gamma.adapter.secondary.jpa.apikey.ApiKeyEntity; +import it.chalmers.gamma.adapter.secondary.jpa.apikey.ApiKeyEntityConverter; +import it.chalmers.gamma.adapter.secondary.jpa.client.apikey.ClientApiKeyEntity; +import it.chalmers.gamma.adapter.secondary.jpa.client.restriction.ClientRestrictionEntity; +import it.chalmers.gamma.adapter.secondary.jpa.client.restriction.ClientRestrictionSuperGroupEntity; +import it.chalmers.gamma.adapter.secondary.jpa.client.scope.ClientScopeEntity; +import it.chalmers.gamma.adapter.secondary.jpa.supergroup.SuperGroupJpaRepository; +import it.chalmers.gamma.adapter.secondary.jpa.text.TextEntity; +import it.chalmers.gamma.app.client.domain.*; +import it.chalmers.gamma.app.client.domain.restriction.ClientRestriction; +import it.chalmers.gamma.app.client.domain.restriction.ClientRestrictionId; +import it.chalmers.gamma.app.common.PrettyName; +import it.chalmers.gamma.app.supergroup.domain.SuperGroupRepository; +import it.chalmers.gamma.app.user.domain.UserId; +import java.util.List; +import java.util.Optional; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Service; + +@Service +public class ClientEntityConverter { + + private final ApiKeyEntityConverter apiKeyEntityConverter; + private final SuperGroupRepository superGroupRepository; + private final ClientJpaRepository clientJpaRepository; + private final SuperGroupJpaRepository superGroupJpaRepository; + private final PasswordEncoder passwordEncoder; + + public ClientEntityConverter( + ApiKeyEntityConverter apiKeyEntityConverter, + SuperGroupRepository superGroupRepository, + ClientJpaRepository clientJpaRepository, + SuperGroupJpaRepository superGroupJpaRepository, + PasswordEncoder passwordEncoder) { + this.apiKeyEntityConverter = apiKeyEntityConverter; + this.superGroupRepository = superGroupRepository; + this.clientJpaRepository = clientJpaRepository; + this.superGroupJpaRepository = superGroupJpaRepository; + this.passwordEncoder = passwordEncoder; + } + + public Client toDomain(ClientEntity clientEntity) { + List scopes = clientEntity.scopes.stream().map(ClientScopeEntity::getScope).toList(); + + ClientOwner owner; + if (clientEntity.official) { + owner = new ClientOwnerOfficial(); + } else { + owner = new ClientUserOwner(new UserId(clientEntity.createdBy)); + } + + return new Client( + new ClientUid(clientEntity.getId()), + new ClientId(clientEntity.clientId), + new ClientSecret(clientEntity.clientSecret), + new ClientRedirectUrl(clientEntity.webServerRedirectUrl), + new PrettyName(clientEntity.prettyName), + clientEntity.description.toDomain(), + scopes, + Optional.ofNullable(clientEntity.clientsApiKey) + .map(ClientApiKeyEntity::getApiKeyEntity) + .map(apiKeyEntityConverter::toDomain) + .orElse(null), + owner, + clientEntity.clientRestriction == null + ? null + : new ClientRestriction( + new ClientRestrictionId(clientEntity.clientRestriction.getId()), + clientEntity.clientRestriction.getSuperGroupRestrictions().stream() + .map( + clientRestrictionSuperGroupEntity -> + this.superGroupRepository + .get( + clientRestrictionSuperGroupEntity + .getId() + .getValue() + .superGroupId()) + .orElseThrow()) + .toList())); + } + + public ClientEntity toEntity(Client client) { + ClientEntity clientEntity = + this.clientJpaRepository.findById(client.clientUid().value()).orElse(new ClientEntity()); + + clientEntity.clientUid = client.clientUid().value(); + clientEntity.clientId = client.clientId().value(); + clientEntity.clientSecret = client.clientSecret().value(); + clientEntity.prettyName = client.prettyName().value(); + clientEntity.webServerRedirectUrl = client.clientRedirectUrl().value(); + + if (clientEntity.description == null) { + clientEntity.description = new TextEntity(); + } + + clientEntity.description.apply(client.description()); + + switch (client.owner()) { + case ClientOwnerOfficial(): + clientEntity.official = true; + clientEntity.createdBy = null; + break; + case ClientUserOwner(UserId createdBy): + clientEntity.official = false; + clientEntity.createdBy = createdBy.value(); + break; + } + + clientEntity.scopes.clear(); + clientEntity.scopes.addAll( + client.scopes().stream().map(scope -> new ClientScopeEntity(clientEntity, scope)).toList()); + + client + .clientApiKey() + .ifPresent( + apiKey -> { + ApiKeyEntity apiKeyEntity = + new ApiKeyEntity( + apiKey.id().value(), + apiKey.apiKeyToken().value(), + apiKey.prettyName().value(), + apiKey.keyType(), + new TextEntity(apiKey.description())); + + clientEntity.clientsApiKey = new ClientApiKeyEntity(clientEntity, apiKeyEntity); + }); + + client + .restrictions() + .ifPresent( + clientRestriction -> { + clientEntity.clientRestriction = + new ClientRestrictionEntity( + clientRestriction.id().value(), client.clientUid().value()); + + List clientRestrictionSuperGroupEntities = + clientRestriction.superGroups().stream() + .map( + superGroup -> + new ClientRestrictionSuperGroupEntity( + clientEntity.clientRestriction, + this.superGroupJpaRepository + .findById(superGroup.id().value()) + .orElseThrow())) + .toList(); + + clientEntity.clientRestriction.setSuperGroupRestrictions( + clientRestrictionSuperGroupEntities); + }); + + return clientEntity; + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/client/ClientJpaRepository.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/client/ClientJpaRepository.java new file mode 100644 index 000000000..b21b4c73c --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/client/ClientJpaRepository.java @@ -0,0 +1,12 @@ +package it.chalmers.gamma.adapter.secondary.jpa.client; + +import java.util.List; +import java.util.Optional; +import java.util.UUID; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface ClientJpaRepository extends JpaRepository { + Optional findByClientId(String clientId); + + List findAllByCreatedBy(UUID userId); +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/client/ClientRepositoryAdapter.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/client/ClientRepositoryAdapter.java new file mode 100644 index 000000000..f3d290885 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/client/ClientRepositoryAdapter.java @@ -0,0 +1,155 @@ +package it.chalmers.gamma.adapter.secondary.jpa.client; + +import it.chalmers.gamma.adapter.secondary.jpa.client.apikey.ClientApiKeyEntity; +import it.chalmers.gamma.adapter.secondary.jpa.client.apikey.ClientApiKeyJpaRepository; +import it.chalmers.gamma.adapter.secondary.jpa.user.UserApprovalEntity; +import it.chalmers.gamma.adapter.secondary.jpa.user.UserApprovalJpaRepository; +import it.chalmers.gamma.adapter.secondary.jpa.user.UserJpaRepository; +import it.chalmers.gamma.adapter.secondary.jpa.util.PersistenceErrorHelper; +import it.chalmers.gamma.adapter.secondary.jpa.util.PersistenceErrorState; +import it.chalmers.gamma.app.apikey.domain.ApiKeyId; +import it.chalmers.gamma.app.apikey.domain.ApiKeyToken; +import it.chalmers.gamma.app.client.domain.Client; +import it.chalmers.gamma.app.client.domain.ClientId; +import it.chalmers.gamma.app.client.domain.ClientRepository; +import it.chalmers.gamma.app.client.domain.ClientUid; +import it.chalmers.gamma.app.user.domain.UserId; +import jakarta.transaction.Transactional; +import java.util.List; +import java.util.Optional; +import org.springframework.dao.EmptyResultDataAccessException; +import org.springframework.stereotype.Service; + +@Service +@Transactional +public class ClientRepositoryAdapter implements ClientRepository { + + private static final PersistenceErrorState authorityNotFound = + new PersistenceErrorState( + "g_authority_level_restriction_authority_fkey", + PersistenceErrorState.Type.FOREIGN_KEY_VIOLATION); + private static final PersistenceErrorState userNotFound = + new PersistenceErrorState( + "g_user_approval_user_id_fkey", PersistenceErrorState.Type.FOREIGN_KEY_VIOLATION); + private static final PersistenceErrorState clientIdAlreadyExists = + new PersistenceErrorState("g_client_id_key", PersistenceErrorState.Type.NOT_UNIQUE); + private final ClientJpaRepository clientJpaRepository; + private final ClientApiKeyJpaRepository clientApiKeyJpaRepository; + private final ClientEntityConverter clientEntityConverter; + private final UserApprovalJpaRepository userApprovalJpaRepository; + private final UserJpaRepository userJpaRepository; + + public ClientRepositoryAdapter( + ClientJpaRepository clientJpaRepository, + ClientApiKeyJpaRepository clientApiKeyJpaRepository, + ClientEntityConverter clientEntityConverter, + UserApprovalJpaRepository userApprovalJpaRepository, + UserJpaRepository userJpaRepository) { + this.clientJpaRepository = clientJpaRepository; + this.clientApiKeyJpaRepository = clientApiKeyJpaRepository; + this.clientEntityConverter = clientEntityConverter; + this.userApprovalJpaRepository = userApprovalJpaRepository; + this.userJpaRepository = userJpaRepository; + } + + @Override + public void save(Client client) { + try { + this.clientJpaRepository.saveAndFlush(clientEntityConverter.toEntity(client)); + } catch (Exception e) { + PersistenceErrorState state = PersistenceErrorHelper.getState(e); + + if (state.equals(authorityNotFound)) { + throw new AuthorityNotFoundRuntimeException(); + } else if (state.equals(userNotFound)) { + throw new UserNotFoundRuntimeException(); + } else if (state.equals(clientIdAlreadyExists)) { + throw new ClientIdAlreadyExistsRuntimeException(); + } + + throw e; + } + } + + @Override + public void delete(ClientUid clientUid) throws ClientNotFoundException { + try { + this.clientJpaRepository.deleteById(clientUid.value()); + } catch (EmptyResultDataAccessException e) { + throw new ClientNotFoundException(); + } + } + + @Override + public List getAll() { + return this.clientJpaRepository.findAll().stream() + .map(clientEntityConverter::toDomain) + .toList(); + } + + @Override + public List getAllUserClients(UserId userId) { + return this.clientJpaRepository.findAllByCreatedBy(userId.value()).stream() + .map(clientEntityConverter::toDomain) + .toList(); + } + + @Override + public Optional get(ClientUid clientUid) { + return this.clientJpaRepository + .findById(clientUid.value()) + .map(this.clientEntityConverter::toDomain); + } + + @Override + public Optional get(ClientId clientId) { + return this.clientJpaRepository + .findByClientId(clientId.value()) + .map(this.clientEntityConverter::toDomain); + } + + @Override + public void addClientApproval(UserId userId, ClientUid clientUid) { + UserApprovalEntity userApprovalEntity = + new UserApprovalEntity( + this.userJpaRepository.findById(userId.value()).orElseThrow(), + this.clientJpaRepository.findById(clientUid.value()).orElseThrow()); + this.userApprovalJpaRepository.save(userApprovalEntity); + } + + @Override + public boolean isApprovedByUser(UserId userId, ClientUid clientUid) { + return this.userApprovalJpaRepository.existsById_Client_ClientUidAndId_User_Id( + clientUid.value(), userId.value()); + } + + @Override + public List getClientsByUserApproved(UserId id) { + return this.userApprovalJpaRepository.findAllById_User_Id(id.value()).stream() + .map(UserApprovalEntity::getClientEntity) + .map(this.clientEntityConverter::toDomain) + .toList(); + } + + @Override + public void deleteUserApproval(ClientUid clientUid, UserId userId) { + this.userApprovalJpaRepository.deleteById_Client_ClientUidAndId_User_Id( + clientUid.value(), userId.value()); + } + + @Override + public Optional getByApiKey(ApiKeyToken apiKeyToken) { + return this.clientApiKeyJpaRepository + .findByApiKey_Token(apiKeyToken.value()) + .map(ClientApiKeyEntity::getClient) + .map(this.clientEntityConverter::toDomain); + } + + @Override + public Optional getByApiKey(ApiKeyId apiKeyId) { + return this.clientApiKeyJpaRepository + .findById(apiKeyId.value()) + .map(ClientApiKeyEntity::getClient) + .map(this.clientEntityConverter::toDomain); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/client/apikey/ClientApiKeyEntity.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/client/apikey/ClientApiKeyEntity.java new file mode 100644 index 000000000..d770e4ed8 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/client/apikey/ClientApiKeyEntity.java @@ -0,0 +1,49 @@ +package it.chalmers.gamma.adapter.secondary.jpa.client.apikey; + +import it.chalmers.gamma.adapter.secondary.jpa.apikey.ApiKeyEntity; +import it.chalmers.gamma.adapter.secondary.jpa.client.ClientEntity; +import it.chalmers.gamma.adapter.secondary.jpa.util.ImmutableEntity; +import jakarta.persistence.*; +import java.util.UUID; + +@Entity +@Table(name = "g_client_api_key") +public class ClientApiKeyEntity extends ImmutableEntity { + + @Id + @Column(name = "client_uid", columnDefinition = "uuid") + private UUID clientUid; + + @OneToOne + @PrimaryKeyJoinColumn(name = "client_uid") + private ClientEntity client; + + @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true) + @JoinColumn(name = "api_key_id") + private ApiKeyEntity apiKey; + + protected ClientApiKeyEntity() {} + + public ClientApiKeyEntity(ClientEntity clientEntity, ApiKeyEntity apiKeyEntity) { + this.client = clientEntity; + this.clientUid = clientEntity.getId(); + this.apiKey = apiKeyEntity; + } + + @Override + public UUID getId() { + return this.clientUid; + } + + public ClientEntity getClient() { + return this.client; + } + + public ApiKeyEntity getApiKeyEntity() { + return this.apiKey; + } + + public void removeApiKey() { + this.apiKey = null; + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/client/apikey/ClientApiKeyJpaRepository.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/client/apikey/ClientApiKeyJpaRepository.java new file mode 100644 index 000000000..c80f5efc4 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/client/apikey/ClientApiKeyJpaRepository.java @@ -0,0 +1,13 @@ +package it.chalmers.gamma.adapter.secondary.jpa.client.apikey; + +import java.util.Optional; +import java.util.UUID; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface ClientApiKeyJpaRepository extends JpaRepository { + Optional findByApiKey_Token(String apiKeyToken); + + ClientApiKeyEntity getByApiKey_Id(UUID apiKeyId); +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/client/approvals/ClientApprovalsRepositoryAdapter.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/client/approvals/ClientApprovalsRepositoryAdapter.java new file mode 100644 index 000000000..42df8bc6e --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/client/approvals/ClientApprovalsRepositoryAdapter.java @@ -0,0 +1,41 @@ +package it.chalmers.gamma.adapter.secondary.jpa.client.approvals; + +import it.chalmers.gamma.adapter.secondary.jpa.user.UserApprovalEntity; +import it.chalmers.gamma.adapter.secondary.jpa.user.UserApprovalJpaRepository; +import it.chalmers.gamma.adapter.secondary.jpa.user.UserEntityConverter; +import it.chalmers.gamma.app.client.domain.ClientId; +import it.chalmers.gamma.app.client.domain.ClientUid; +import it.chalmers.gamma.app.client.domain.approval.ClientApprovalsRepository; +import it.chalmers.gamma.app.user.domain.GammaUser; +import java.util.List; +import org.springframework.stereotype.Service; + +@Service +public class ClientApprovalsRepositoryAdapter implements ClientApprovalsRepository { + + private final UserApprovalJpaRepository userApprovalJpaRepository; + private final UserEntityConverter userEntityConverter; + + public ClientApprovalsRepositoryAdapter( + UserApprovalJpaRepository userApprovalJpaRepository, + UserEntityConverter userEntityConverter) { + this.userApprovalJpaRepository = userApprovalJpaRepository; + this.userEntityConverter = userEntityConverter; + } + + @Override + public List getAllByClientId(ClientId clientId) { + throw new UnsupportedOperationException(); + } + + @Override + public List getAllByClientUid(ClientUid clientUid) { + List userApprovalEntities = + this.userApprovalJpaRepository.findAllById_Client_ClientUid(clientUid.value()); + + return userApprovalEntities.stream() + .map(UserApprovalEntity::getUserEntity) + .map(this.userEntityConverter::toDomain) + .toList(); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/client/authority/ClientAuthorityEntity.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/client/authority/ClientAuthorityEntity.java new file mode 100644 index 000000000..8c2a1da34 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/client/authority/ClientAuthorityEntity.java @@ -0,0 +1,50 @@ +package it.chalmers.gamma.adapter.secondary.jpa.client.authority; + +import it.chalmers.gamma.adapter.secondary.jpa.client.ClientEntity; +import it.chalmers.gamma.adapter.secondary.jpa.util.ImmutableEntity; +import jakarta.persistence.*; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +@Entity +@Table(name = "g_client_authority") +public class ClientAuthorityEntity extends ImmutableEntity { + + @OneToMany( + mappedBy = "id.clientAuthority", + cascade = CascadeType.ALL, + orphanRemoval = true, + fetch = FetchType.EAGER) + protected Set userEntityList; + + @OneToMany( + mappedBy = "id.clientAuthority", + cascade = CascadeType.ALL, + orphanRemoval = true, + fetch = FetchType.EAGER) + protected Set superGroupEntityList; + + @EmbeddedId private ClientAuthorityEntityPK id; + + protected ClientAuthorityEntity() {} + + public ClientAuthorityEntity(ClientEntity client, String name) { + this.id = new ClientAuthorityEntityPK(client, name); + this.userEntityList = new HashSet<>(); + this.superGroupEntityList = new HashSet<>(); + } + + @Override + public ClientAuthorityEntityPK getId() { + return this.id; + } + + public List getUsers() { + return userEntityList.stream().toList(); + } + + public List getSuperGroups() { + return superGroupEntityList.stream().toList(); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/client/authority/ClientAuthorityEntityConverter.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/client/authority/ClientAuthorityEntityConverter.java new file mode 100644 index 000000000..a793c20ca --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/client/authority/ClientAuthorityEntityConverter.java @@ -0,0 +1,45 @@ +package it.chalmers.gamma.adapter.secondary.jpa.client.authority; + +import it.chalmers.gamma.adapter.secondary.jpa.client.ClientEntityConverter; +import it.chalmers.gamma.adapter.secondary.jpa.supergroup.SuperGroupEntityConverter; +import it.chalmers.gamma.adapter.secondary.jpa.user.UserEntityConverter; +import it.chalmers.gamma.app.client.domain.authority.Authority; +import it.chalmers.gamma.app.client.domain.authority.AuthorityName; +import java.util.Objects; +import org.springframework.stereotype.Component; + +@Component +public class ClientAuthorityEntityConverter { + + private final ClientEntityConverter clientEntityConverter; + private final UserEntityConverter userEntityConverter; + private final SuperGroupEntityConverter superGroupEntityConverter; + + public ClientAuthorityEntityConverter( + ClientEntityConverter clientEntityConverter, + UserEntityConverter userEntityConverter, + SuperGroupEntityConverter superGroupEntityConverter) { + this.clientEntityConverter = clientEntityConverter; + this.userEntityConverter = userEntityConverter; + this.superGroupEntityConverter = superGroupEntityConverter; + } + + public Authority toDomain(ClientAuthorityEntity clientAuthorityEntity) { + Objects.requireNonNull(clientAuthorityEntity.getId()); + + var id = clientAuthorityEntity.getId(); + + return new Authority( + this.clientEntityConverter.toDomain(id.client), + AuthorityName.valueOf(id.name), + clientAuthorityEntity.getSuperGroups().stream() + .map(ClientAuthoritySuperGroupEntity::getSuperGroup) + .map(this.superGroupEntityConverter::toDomain) + .toList(), + clientAuthorityEntity.getUsers().stream() + .map(ClientAuthorityUserEntity::getUserEntity) + .map(this.userEntityConverter::toDomain) + .filter(Objects::nonNull) + .toList()); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/client/authority/ClientAuthorityEntityPK.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/client/authority/ClientAuthorityEntityPK.java new file mode 100644 index 000000000..5f42ce1ba --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/client/authority/ClientAuthorityEntityPK.java @@ -0,0 +1,36 @@ +package it.chalmers.gamma.adapter.secondary.jpa.client.authority; + +import it.chalmers.gamma.adapter.secondary.jpa.client.ClientEntity; +import it.chalmers.gamma.adapter.secondary.jpa.util.PKId; +import it.chalmers.gamma.app.client.domain.ClientUid; +import it.chalmers.gamma.app.client.domain.authority.AuthorityName; +import jakarta.persistence.Column; +import jakarta.persistence.Embeddable; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; + +@Embeddable +public class ClientAuthorityEntityPK extends PKId { + + @Column(name = "authority_name") + protected String name; + + @JoinColumn(name = "client_uid") + @ManyToOne + protected ClientEntity client; + + protected ClientAuthorityEntityPK() {} + + protected ClientAuthorityEntityPK(ClientEntity client, String name) { + this.client = client; + this.name = name; + } + + @Override + public AuthorityEntityPKRecord getValue() { + return new AuthorityEntityPKRecord( + new ClientUid(this.client.getId()), new AuthorityName(this.name)); + } + + public record AuthorityEntityPKRecord(ClientUid clientUid, AuthorityName authorityName) {} +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/client/authority/ClientAuthorityJpaRepository.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/client/authority/ClientAuthorityJpaRepository.java new file mode 100644 index 000000000..6669eb43e --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/client/authority/ClientAuthorityJpaRepository.java @@ -0,0 +1,34 @@ +package it.chalmers.gamma.adapter.secondary.jpa.client.authority; + +import java.util.List; +import java.util.UUID; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; + +@Repository +public interface ClientAuthorityJpaRepository + extends JpaRepository { + List findAllById_Client_Id(UUID clientUid); + + @Query( + value = + """ + SELECT DISTINCT a.* FROM g_client_authority a + LEFT JOIN g_client_authority_user uau ON a.client_uid = uau.client_uid AND a.authority_name = uau.authority_name + WHERE uau.user_id = :userId AND uau.client_uid = :clientUid + + UNION + + SELECT DISTINCT au.* FROM g_client_authority au + INNER JOIN g_client_authority_super_group sga ON au.client_uid = sga.client_uid AND au.authority_name = sga.authority_name + INNER JOIN g_super_group sg ON sg.super_group_id = sga.super_group_id + INNER JOIN g_group g ON g.super_group_id = sg.super_group_id + INNER JOIN g_membership m ON m.group_id = g.group_id + WHERE m.user_id = :userId AND au.client_uid = :clientUid + """, + nativeQuery = true) + List findAllClientAuthoritiesByUser( + @Param("clientUid") UUID clientUid, @Param("userId") UUID userId); +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/client/authority/ClientAuthorityRepositoryAdapter.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/client/authority/ClientAuthorityRepositoryAdapter.java new file mode 100644 index 000000000..a327b0ca5 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/client/authority/ClientAuthorityRepositoryAdapter.java @@ -0,0 +1,162 @@ +package it.chalmers.gamma.adapter.secondary.jpa.client.authority; + +import it.chalmers.gamma.adapter.secondary.jpa.client.ClientJpaRepository; +import it.chalmers.gamma.adapter.secondary.jpa.supergroup.SuperGroupEntity; +import it.chalmers.gamma.adapter.secondary.jpa.supergroup.SuperGroupJpaRepository; +import it.chalmers.gamma.adapter.secondary.jpa.user.UserEntity; +import it.chalmers.gamma.adapter.secondary.jpa.user.UserJpaRepository; +import it.chalmers.gamma.adapter.secondary.jpa.util.PersistenceErrorHelper; +import it.chalmers.gamma.adapter.secondary.jpa.util.PersistenceErrorState; +import it.chalmers.gamma.app.client.domain.ClientUid; +import it.chalmers.gamma.app.client.domain.authority.Authority; +import it.chalmers.gamma.app.client.domain.authority.AuthorityName; +import it.chalmers.gamma.app.client.domain.authority.ClientAuthorityRepository; +import it.chalmers.gamma.app.supergroup.domain.SuperGroup; +import it.chalmers.gamma.app.user.domain.GammaUser; +import it.chalmers.gamma.app.user.domain.UserId; +import jakarta.transaction.Transactional; +import java.util.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.dao.EmptyResultDataAccessException; +import org.springframework.stereotype.Service; + +@Transactional +@Service +public class ClientAuthorityRepositoryAdapter implements ClientAuthorityRepository { + + private static final Logger LOGGER = + LoggerFactory.getLogger(ClientAuthorityRepositoryAdapter.class); + private static final PersistenceErrorState notFoundError = + new PersistenceErrorState(null, PersistenceErrorState.Type.FOREIGN_KEY_VIOLATION); + private final ClientAuthorityJpaRepository clientAuthorityJpaRepository; + private final UserJpaRepository userJpaRepository; + private final SuperGroupJpaRepository superGroupJpaRepository; + private final ClientJpaRepository clientJpaRepository; + private final ClientAuthorityEntityConverter clientAuthorityEntityConverter; + + public ClientAuthorityRepositoryAdapter( + ClientAuthorityJpaRepository clientAuthorityJpaRepository, + UserJpaRepository userJpaRepository, + SuperGroupJpaRepository superGroupJpaRepository, + ClientJpaRepository clientJpaRepository, + ClientAuthorityEntityConverter clientAuthorityEntityConverter) { + this.clientAuthorityJpaRepository = clientAuthorityJpaRepository; + this.userJpaRepository = userJpaRepository; + this.superGroupJpaRepository = superGroupJpaRepository; + this.clientJpaRepository = clientJpaRepository; + this.clientAuthorityEntityConverter = clientAuthorityEntityConverter; + } + + @Override + public void create(ClientUid clientUid, AuthorityName authorityName) + throws ClientAuthorityAlreadyExistsException { + if (clientAuthorityJpaRepository.existsById(toAuthorityEntityPK(clientUid, authorityName))) { + throw new ClientAuthorityAlreadyExistsException(authorityName.value()); + } + + clientAuthorityJpaRepository.saveAndFlush( + new ClientAuthorityEntity( + this.clientJpaRepository.findById(clientUid.value()).orElseThrow(), + authorityName.getValue())); + } + + @Override + public void delete(ClientUid clientUid, AuthorityName authorityName) + throws ClientAuthorityNotFoundException { + try { + clientAuthorityJpaRepository.deleteById(toAuthorityEntityPK(clientUid, authorityName)); + } catch (EmptyResultDataAccessException e) { + throw new ClientAuthorityNotFoundException(); + } + } + + @Override + public void save(Authority authority) throws ClientAuthorityNotFoundRuntimeException { + ClientAuthorityEntity entity = toEntity(authority); + + try { + this.clientAuthorityJpaRepository.saveAndFlush(entity); + } catch (Exception e) { + PersistenceErrorState state = PersistenceErrorHelper.getState(e); + + if (state.equals(notFoundError)) { + throw new NotCompleteClientAuthorityException(); + } + + throw e; + } + } + + @Override + public List getAllByClient(ClientUid clientUid) { + return this.clientAuthorityJpaRepository.findAllById_Client_Id(clientUid.value()).stream() + .map(this.clientAuthorityEntityConverter::toDomain) + .toList(); + } + + @Override + public List getAllByUser(ClientUid clientUid, UserId userId) { + return this.clientAuthorityJpaRepository + .findAllClientAuthoritiesByUser(clientUid.value(), userId.value()) + .stream() + .map(ClientAuthorityEntity::getId) + .map(ClientAuthorityEntityPK::getValue) + .map(ClientAuthorityEntityPK.AuthorityEntityPKRecord::authorityName) + .toList(); + } + + @Override + public Optional get(ClientUid clientUid, AuthorityName authorityName) { + return this.clientAuthorityJpaRepository + .findById(toAuthorityEntityPK(clientUid, authorityName)) + .map(this.clientAuthorityEntityConverter::toDomain); + } + + private ClientAuthorityEntity toEntity(Authority authority) + throws ClientAuthorityNotFoundRuntimeException { + ClientAuthorityEntity clientAuthorityEntity = + this.clientAuthorityJpaRepository + .findById( + new ClientAuthorityEntityPK( + this.clientJpaRepository + .findById(authority.client().clientUid().value()) + .orElseThrow(), + authority.name().value())) + .orElseThrow(ClientAuthorityNotFoundRuntimeException::new); + + List users = + authority.users().stream() + .map(user -> new ClientAuthorityUserEntity(toEntity(user), clientAuthorityEntity)) + .toList(); + List superGroups = + authority.superGroups().stream() + .map( + superGroup -> + new ClientAuthoritySuperGroupEntity( + toEntity(superGroup), clientAuthorityEntity)) + .toList(); + + clientAuthorityEntity.userEntityList.clear(); + clientAuthorityEntity.userEntityList.addAll(users); + + clientAuthorityEntity.superGroupEntityList.clear(); + clientAuthorityEntity.superGroupEntityList.addAll(superGroups); + + return clientAuthorityEntity; + } + + private UserEntity toEntity(GammaUser user) { + return this.userJpaRepository.getReferenceById(user.id().getValue()); + } + + private SuperGroupEntity toEntity(SuperGroup superGroup) { + return this.superGroupJpaRepository.getReferenceById(superGroup.id().getValue()); + } + + private ClientAuthorityEntityPK toAuthorityEntityPK( + ClientUid clientUid, AuthorityName authorityName) { + return new ClientAuthorityEntityPK( + this.clientJpaRepository.findById(clientUid.value()).orElseThrow(), authorityName.value()); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/client/authority/ClientAuthoritySuperGroupEntity.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/client/authority/ClientAuthoritySuperGroupEntity.java new file mode 100644 index 000000000..f72676e46 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/client/authority/ClientAuthoritySuperGroupEntity.java @@ -0,0 +1,30 @@ +package it.chalmers.gamma.adapter.secondary.jpa.client.authority; + +import it.chalmers.gamma.adapter.secondary.jpa.supergroup.SuperGroupEntity; +import it.chalmers.gamma.adapter.secondary.jpa.util.ImmutableEntity; +import jakarta.persistence.EmbeddedId; +import jakarta.persistence.Entity; +import jakarta.persistence.Table; + +@Entity +@Table(name = "g_client_authority_super_group") +public class ClientAuthoritySuperGroupEntity extends ImmutableEntity { + + @EmbeddedId protected ClientAuthoritySuperGroupPK id; + + protected ClientAuthoritySuperGroupEntity() {} + + public ClientAuthoritySuperGroupEntity( + SuperGroupEntity superGroup, ClientAuthorityEntity clientAuthorityEntity) { + this.id = new ClientAuthoritySuperGroupPK(superGroup, clientAuthorityEntity); + } + + @Override + public ClientAuthoritySuperGroupPK getId() { + return this.id; + } + + protected SuperGroupEntity getSuperGroup() { + return this.id.superGroupEntity; + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/client/authority/ClientAuthoritySuperGroupJpaRepository.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/client/authority/ClientAuthoritySuperGroupJpaRepository.java new file mode 100644 index 000000000..48599d925 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/client/authority/ClientAuthoritySuperGroupJpaRepository.java @@ -0,0 +1,12 @@ +package it.chalmers.gamma.adapter.secondary.jpa.client.authority; + +import java.util.List; +import java.util.UUID; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface ClientAuthoritySuperGroupJpaRepository + extends JpaRepository { + List findAllById_SuperGroupEntity_Id(UUID id); +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/client/authority/ClientAuthoritySuperGroupPK.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/client/authority/ClientAuthoritySuperGroupPK.java new file mode 100644 index 000000000..9a38edc20 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/client/authority/ClientAuthoritySuperGroupPK.java @@ -0,0 +1,41 @@ +package it.chalmers.gamma.adapter.secondary.jpa.client.authority; + +import it.chalmers.gamma.adapter.secondary.jpa.supergroup.SuperGroupEntity; +import it.chalmers.gamma.adapter.secondary.jpa.util.PKId; +import it.chalmers.gamma.app.client.domain.ClientUid; +import it.chalmers.gamma.app.client.domain.authority.AuthorityName; +import it.chalmers.gamma.app.supergroup.domain.SuperGroupId; +import jakarta.persistence.Embeddable; +import jakarta.persistence.Embedded; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; + +@Embeddable +public class ClientAuthoritySuperGroupPK + extends PKId { + + @JoinColumn(name = "super_group_id") + @ManyToOne + protected SuperGroupEntity superGroupEntity; + + @Embedded protected ClientAuthorityEntityPK clientAuthority; + + protected ClientAuthoritySuperGroupPK() {} + + protected ClientAuthoritySuperGroupPK( + SuperGroupEntity superGroupEntity, ClientAuthorityEntity clientAuthority) { + this.superGroupEntity = superGroupEntity; + this.clientAuthority = clientAuthority.getId(); + } + + @Override + public AuthoritySuperGroupPKDTO getValue() { + return new AuthoritySuperGroupPKDTO( + new SuperGroupId(this.superGroupEntity.getId()), + new AuthorityName(this.clientAuthority.name), + new ClientUid(this.clientAuthority.client.getId())); + } + + public record AuthoritySuperGroupPKDTO( + SuperGroupId superGroupId, AuthorityName authorityName, ClientUid clientUid) {} +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/client/authority/ClientAuthorityUserEntity.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/client/authority/ClientAuthorityUserEntity.java new file mode 100644 index 000000000..3499779df --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/client/authority/ClientAuthorityUserEntity.java @@ -0,0 +1,29 @@ +package it.chalmers.gamma.adapter.secondary.jpa.client.authority; + +import it.chalmers.gamma.adapter.secondary.jpa.user.UserEntity; +import it.chalmers.gamma.adapter.secondary.jpa.util.ImmutableEntity; +import jakarta.persistence.EmbeddedId; +import jakarta.persistence.Entity; +import jakarta.persistence.Table; + +@Entity +@Table(name = "g_client_authority_user") +public class ClientAuthorityUserEntity extends ImmutableEntity { + + @EmbeddedId private ClientAuthorityUserPK id; + + protected ClientAuthorityUserEntity() {} + + public ClientAuthorityUserEntity(UserEntity user, ClientAuthorityEntity clientAuthorityEntity) { + this.id = new ClientAuthorityUserPK(user, clientAuthorityEntity); + } + + @Override + public ClientAuthorityUserPK getId() { + return this.id; + } + + public UserEntity getUserEntity() { + return this.id.getUserEntity(); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/client/authority/ClientAuthorityUserJpaRepository.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/client/authority/ClientAuthorityUserJpaRepository.java new file mode 100644 index 000000000..f1aa72116 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/client/authority/ClientAuthorityUserJpaRepository.java @@ -0,0 +1,13 @@ +package it.chalmers.gamma.adapter.secondary.jpa.client.authority; + +import java.util.List; +import java.util.UUID; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface ClientAuthorityUserJpaRepository + extends JpaRepository { + + List findAllById_UserEntity_Id(UUID userId); +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/client/authority/ClientAuthorityUserPK.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/client/authority/ClientAuthorityUserPK.java new file mode 100644 index 000000000..d86b3e612 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/client/authority/ClientAuthorityUserPK.java @@ -0,0 +1,43 @@ +package it.chalmers.gamma.adapter.secondary.jpa.client.authority; + +import it.chalmers.gamma.adapter.secondary.jpa.user.UserEntity; +import it.chalmers.gamma.adapter.secondary.jpa.util.PKId; +import it.chalmers.gamma.app.client.domain.ClientUid; +import it.chalmers.gamma.app.client.domain.authority.AuthorityName; +import it.chalmers.gamma.app.user.domain.UserId; +import jakarta.persistence.Embeddable; +import jakarta.persistence.Embedded; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; + +@Embeddable +public class ClientAuthorityUserPK extends PKId { + + @JoinColumn(name = "user_id") + @ManyToOne + private UserEntity userEntity; + + @Embedded protected ClientAuthorityEntityPK clientAuthority; + + protected ClientAuthorityUserPK() {} + + public ClientAuthorityUserPK(UserEntity userEntity, ClientAuthorityEntity clientAuthority) { + this.userEntity = userEntity; + this.clientAuthority = clientAuthority.getId(); + } + + @Override + public AuthorityUserPKRecord getValue() { + return new AuthorityUserPKRecord( + new UserId(this.userEntity.getId()), + new AuthorityName(this.clientAuthority.name), + new ClientUid(this.clientAuthority.client.getId())); + } + + public UserEntity getUserEntity() { + return this.userEntity; + } + + protected record AuthorityUserPKRecord( + UserId userId, AuthorityName authorityName, ClientUid clientUid) {} +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/client/restriction/ClientRestrictionEntity.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/client/restriction/ClientRestrictionEntity.java new file mode 100644 index 000000000..e26e86995 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/client/restriction/ClientRestrictionEntity.java @@ -0,0 +1,49 @@ +package it.chalmers.gamma.adapter.secondary.jpa.client.restriction; + +import it.chalmers.gamma.adapter.secondary.jpa.client.ClientEntity; +import it.chalmers.gamma.adapter.secondary.jpa.util.ImmutableEntity; +import jakarta.persistence.*; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +@Entity +@Table(name = "g_client_restriction") +public class ClientRestrictionEntity extends ImmutableEntity { + + @Column(name = "restriction_id", columnDefinition = "uuid") + protected UUID restrictionId; + + @Id + @Column(name = "client_uid", columnDefinition = "uuid") + protected UUID clientUid; + + @OneToOne + @PrimaryKeyJoinColumn(name = "client_uid") + protected ClientEntity client; + + @OneToMany(mappedBy = "id.clientRestriction", cascade = CascadeType.ALL, orphanRemoval = true) + protected List superGroupRestrictions; + + public ClientRestrictionEntity() {} + + public ClientRestrictionEntity(UUID restrictionId, UUID clientUid) { + this.restrictionId = restrictionId; + this.clientUid = clientUid; + this.superGroupRestrictions = new ArrayList<>(); + } + + public void setSuperGroupRestrictions( + List superGroupRestrictions) { + this.superGroupRestrictions = superGroupRestrictions; + } + + public List getSuperGroupRestrictions() { + return superGroupRestrictions; + } + + @Override + public UUID getId() { + return restrictionId; + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/client/restriction/ClientRestrictionSuperGroupEntity.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/client/restriction/ClientRestrictionSuperGroupEntity.java new file mode 100644 index 000000000..c706a7215 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/client/restriction/ClientRestrictionSuperGroupEntity.java @@ -0,0 +1,26 @@ +package it.chalmers.gamma.adapter.secondary.jpa.client.restriction; + +import it.chalmers.gamma.adapter.secondary.jpa.supergroup.SuperGroupEntity; +import it.chalmers.gamma.adapter.secondary.jpa.util.ImmutableEntity; +import jakarta.persistence.EmbeddedId; +import jakarta.persistence.Entity; +import jakarta.persistence.Table; + +@Entity +@Table(name = "g_client_restriction_super_group") +public class ClientRestrictionSuperGroupEntity + extends ImmutableEntity { + + @EmbeddedId private ClientRestrictionSuperGroupPK id; + + protected ClientRestrictionSuperGroupEntity() {} + + public ClientRestrictionSuperGroupEntity( + ClientRestrictionEntity clientRestrictionEntity, SuperGroupEntity superGroupEntity) { + this.id = new ClientRestrictionSuperGroupPK(clientRestrictionEntity, superGroupEntity); + } + + public ClientRestrictionSuperGroupPK getId() { + return this.id; + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/client/restriction/ClientRestrictionSuperGroupPK.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/client/restriction/ClientRestrictionSuperGroupPK.java new file mode 100644 index 000000000..1dd938a99 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/client/restriction/ClientRestrictionSuperGroupPK.java @@ -0,0 +1,40 @@ +package it.chalmers.gamma.adapter.secondary.jpa.client.restriction; + +import it.chalmers.gamma.adapter.secondary.jpa.supergroup.SuperGroupEntity; +import it.chalmers.gamma.adapter.secondary.jpa.util.PKId; +import it.chalmers.gamma.app.client.domain.restriction.ClientRestrictionId; +import it.chalmers.gamma.app.supergroup.domain.SuperGroupId; +import jakarta.persistence.Embeddable; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; + +@Embeddable +public class ClientRestrictionSuperGroupPK + extends PKId { + + @ManyToOne + @JoinColumn(name = "restriction_id") + private ClientRestrictionEntity clientRestriction; + + @JoinColumn(name = "super_group_id") + @ManyToOne + protected SuperGroupEntity superGroupEntity; + + protected ClientRestrictionSuperGroupPK() {} + + protected ClientRestrictionSuperGroupPK( + ClientRestrictionEntity clientRestrictionEntity, SuperGroupEntity superGroupEntity) { + this.clientRestriction = clientRestrictionEntity; + this.superGroupEntity = superGroupEntity; + } + + @Override + public ClientRestrictionPKDTO getValue() { + return new ClientRestrictionPKDTO( + new ClientRestrictionId(this.clientRestriction.restrictionId), + new SuperGroupId(this.superGroupEntity.getId())); + } + + public record ClientRestrictionPKDTO( + ClientRestrictionId clientRestrictionId, SuperGroupId superGroupId) {} +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/client/scope/ClientScopeEntity.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/client/scope/ClientScopeEntity.java new file mode 100644 index 000000000..c19b4b3bd --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/client/scope/ClientScopeEntity.java @@ -0,0 +1,29 @@ +package it.chalmers.gamma.adapter.secondary.jpa.client.scope; + +import it.chalmers.gamma.adapter.secondary.jpa.client.ClientEntity; +import it.chalmers.gamma.adapter.secondary.jpa.util.ImmutableEntity; +import it.chalmers.gamma.app.client.domain.Scope; +import jakarta.persistence.EmbeddedId; +import jakarta.persistence.Entity; +import jakarta.persistence.Table; + +@Entity +@Table(name = "g_client_scope") +public class ClientScopeEntity extends ImmutableEntity { + + @EmbeddedId private ClientScopePK id; + + protected ClientScopeEntity() {} + + public ClientScopeEntity(ClientEntity clientEntity, Scope scope) { + this.id = new ClientScopePK(clientEntity, scope); + } + + public ClientScopePK getId() { + return this.id; + } + + public Scope getScope() { + return this.id.getValue().scope(); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/client/scope/ClientScopePK.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/client/scope/ClientScopePK.java new file mode 100644 index 000000000..fcca68e94 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/client/scope/ClientScopePK.java @@ -0,0 +1,33 @@ +package it.chalmers.gamma.adapter.secondary.jpa.client.scope; + +import it.chalmers.gamma.adapter.secondary.jpa.client.ClientEntity; +import it.chalmers.gamma.adapter.secondary.jpa.util.PKId; +import it.chalmers.gamma.app.client.domain.ClientUid; +import it.chalmers.gamma.app.client.domain.Scope; +import jakarta.persistence.*; + +@Embeddable +public class ClientScopePK extends PKId { + + @ManyToOne + @JoinColumn(name = "client_uid") + private ClientEntity client; + + @Column(name = "scope") + @Enumerated(EnumType.STRING) + private Scope scope; + + protected ClientScopePK() {} + + protected ClientScopePK(ClientEntity clientEntity, Scope scope) { + this.client = clientEntity; + this.scope = scope; + } + + @Override + public ClientScopePKDTO getValue() { + return new ClientScopePKDTO(new ClientUid(this.client.getId()), this.scope); + } + + public record ClientScopePKDTO(ClientUid clientUid, Scope scope) {} +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/group/GroupEntity.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/group/GroupEntity.java new file mode 100644 index 000000000..6f26eeabe --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/group/GroupEntity.java @@ -0,0 +1,51 @@ +package it.chalmers.gamma.adapter.secondary.jpa.group; + +import it.chalmers.gamma.adapter.secondary.jpa.supergroup.SuperGroupEntity; +import it.chalmers.gamma.adapter.secondary.jpa.util.MutableEntity; +import jakarta.persistence.*; +import java.util.List; +import java.util.UUID; + +@Entity +@Table(name = "g_group") +public class GroupEntity extends MutableEntity { + + @Id + @Column(name = "group_id", columnDefinition = "uuid") + protected UUID id; + + @Column(name = "e_name") + protected String name; + + @Column(name = "pretty_name") + protected String prettyName; + + @ManyToOne + @JoinColumn(name = "super_group_id") + protected SuperGroupEntity superGroup; + + @OneToMany(mappedBy = "id.group", cascade = CascadeType.ALL, orphanRemoval = true) + protected List members; + + @OneToOne(mappedBy = "group", cascade = CascadeType.ALL, orphanRemoval = true) + protected GroupImagesEntity groupImages; + + protected GroupEntity() {} + + protected List getMembers() { + return members; + } + + @Override + public UUID getId() { + return this.id; + } + + public SuperGroupEntity getSuperGroup() { + return this.superGroup; + } + + public String getName() { + return this.name; + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/group/GroupEntityConverter.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/group/GroupEntityConverter.java new file mode 100644 index 000000000..0718b2ec0 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/group/GroupEntityConverter.java @@ -0,0 +1,73 @@ +package it.chalmers.gamma.adapter.secondary.jpa.group; + +import it.chalmers.gamma.adapter.secondary.jpa.supergroup.SuperGroupEntityConverter; +import it.chalmers.gamma.adapter.secondary.jpa.user.UserEntityConverter; +import it.chalmers.gamma.app.common.PrettyName; +import it.chalmers.gamma.app.group.domain.Group; +import it.chalmers.gamma.app.group.domain.GroupId; +import it.chalmers.gamma.app.group.domain.GroupMember; +import it.chalmers.gamma.app.group.domain.UnofficialPostName; +import it.chalmers.gamma.app.image.domain.ImageUri; +import it.chalmers.gamma.app.user.domain.GammaUser; +import it.chalmers.gamma.app.user.domain.Name; +import java.util.Comparator; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import org.springframework.stereotype.Service; + +@Service +public class GroupEntityConverter { + + private final UserEntityConverter userEntityConverter; + private final PostEntityConverter postEntityConverter; + private final SuperGroupEntityConverter superGroupEntityConverter; + + public GroupEntityConverter( + UserEntityConverter userEntityConverter, + PostEntityConverter postEntityConverter, + SuperGroupEntityConverter superGroupEntityConverter) { + this.userEntityConverter = userEntityConverter; + this.postEntityConverter = postEntityConverter; + this.superGroupEntityConverter = superGroupEntityConverter; + } + + public Group toDomain(GroupEntity entity) { + List members = + entity.getMembers().stream() + .map( + membershipEntity -> { + GammaUser user = + this.userEntityConverter.toDomain(membershipEntity.getId().getUser()); + if (user == null) { + return null; + } + + return new GroupMember( + this.postEntityConverter.toDomain(membershipEntity.getId().getPost()), + new UnofficialPostName(membershipEntity.getUnofficialPostName()), + user); + }) + .filter(Objects::nonNull) + .sorted(Comparator.comparingInt(member -> member.post().order().value())) + .toList(); + + Optional avatarUri = Optional.empty(); + Optional bannerUri = Optional.empty(); + + if (entity.groupImages != null) { + avatarUri = Optional.ofNullable(entity.groupImages.avatarUri).map(ImageUri::new); + bannerUri = Optional.ofNullable(entity.groupImages.bannerUri).map(ImageUri::new); + } + + return new Group( + new GroupId(entity.getId()), + entity.getVersion(), + new Name(entity.name), + new PrettyName(entity.prettyName), + this.superGroupEntityConverter.toDomain(entity.superGroup), + members, + avatarUri, + bannerUri); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/group/GroupImagesEntity.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/group/GroupImagesEntity.java new file mode 100644 index 000000000..18a983c96 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/group/GroupImagesEntity.java @@ -0,0 +1,32 @@ +package it.chalmers.gamma.adapter.secondary.jpa.group; + +import it.chalmers.gamma.adapter.secondary.jpa.util.MutableEntity; +import it.chalmers.gamma.app.group.domain.GroupId; +import jakarta.persistence.*; +import java.util.UUID; + +@Entity +@Table(name = "g_group_images_uri") +public class GroupImagesEntity extends MutableEntity { + + @Id + @Column(name = "group_id", columnDefinition = "uuid") + protected UUID groupId; + + @OneToOne + @PrimaryKeyJoinColumn(name = "group_id") + protected GroupEntity group; + + @Column(name = "avatar_uri") + protected String avatarUri; + + @Column(name = "banner_uri") + protected String bannerUri; + + protected GroupImagesEntity() {} + + @Override + public GroupId getId() { + return new GroupId(this.groupId); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/group/GroupJpaRepository.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/group/GroupJpaRepository.java new file mode 100644 index 000000000..6bb5aae3a --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/group/GroupJpaRepository.java @@ -0,0 +1,12 @@ +package it.chalmers.gamma.adapter.secondary.jpa.group; + +import java.util.List; +import java.util.Optional; +import java.util.UUID; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface GroupJpaRepository extends JpaRepository { + List findAllBySuperGroupId(UUID id); + + Optional findByName(String name); +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/group/GroupRepositoryAdapter.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/group/GroupRepositoryAdapter.java new file mode 100644 index 000000000..25fd43f04 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/group/GroupRepositoryAdapter.java @@ -0,0 +1,183 @@ +package it.chalmers.gamma.adapter.secondary.jpa.group; + +import it.chalmers.gamma.adapter.secondary.jpa.supergroup.SuperGroupJpaRepository; +import it.chalmers.gamma.adapter.secondary.jpa.user.UserJpaRepository; +import it.chalmers.gamma.adapter.secondary.jpa.util.PersistenceErrorHelper; +import it.chalmers.gamma.adapter.secondary.jpa.util.PersistenceErrorState; +import it.chalmers.gamma.app.group.domain.Group; +import it.chalmers.gamma.app.group.domain.GroupId; +import it.chalmers.gamma.app.group.domain.GroupRepository; +import it.chalmers.gamma.app.group.domain.UnofficialPostName; +import it.chalmers.gamma.app.image.domain.ImageUri; +import it.chalmers.gamma.app.post.domain.PostId; +import it.chalmers.gamma.app.supergroup.domain.SuperGroupId; +import it.chalmers.gamma.app.user.domain.Name; +import it.chalmers.gamma.app.user.domain.UserId; +import it.chalmers.gamma.app.user.domain.UserMembership; +import jakarta.transaction.Transactional; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import org.springframework.dao.DataIntegrityViolationException; +import org.springframework.dao.EmptyResultDataAccessException; +import org.springframework.stereotype.Service; + +@Service +@Transactional +public class GroupRepositoryAdapter implements GroupRepository { + + private static final PersistenceErrorState SUPER_GROUP_NOT_FOUND = + new PersistenceErrorState( + "g_group_super_group_id_fkey", PersistenceErrorState.Type.FOREIGN_KEY_VIOLATION); + private static final PersistenceErrorState GROUP_NAME_ALREADY_EXISTS = + new PersistenceErrorState("g_group_e_name_key", PersistenceErrorState.Type.NOT_UNIQUE); + private static final PersistenceErrorState USER_NOT_FOUND = + new PersistenceErrorState( + "g_membership_user_id_fkey", PersistenceErrorState.Type.FOREIGN_KEY_VIOLATION); + private static final PersistenceErrorState POST_NOT_FOUND = + new PersistenceErrorState( + "g_membership_post_id_fkey", PersistenceErrorState.Type.FOREIGN_KEY_VIOLATION); + private final GroupJpaRepository groupJpaRepository; + private final GroupEntityConverter groupEntityConverter; + private final MembershipJpaRepository membershipJpaRepository; + private final PostEntityConverter postEntityConverter; + private final SuperGroupJpaRepository superGroupJpaRepository; + private final PostJpaRepository postJpaRepository; + private final UserJpaRepository userJpaRepository; + + public GroupRepositoryAdapter( + GroupJpaRepository groupJpaRepository, + GroupEntityConverter groupEntityConverter, + MembershipJpaRepository membershipJpaRepository, + PostEntityConverter postEntityConverter, + SuperGroupJpaRepository superGroupJpaRepository, + PostJpaRepository postJpaRepository, + UserJpaRepository userJpaRepository) { + this.groupJpaRepository = groupJpaRepository; + this.groupEntityConverter = groupEntityConverter; + this.membershipJpaRepository = membershipJpaRepository; + this.postEntityConverter = postEntityConverter; + this.superGroupJpaRepository = superGroupJpaRepository; + this.postJpaRepository = postJpaRepository; + this.userJpaRepository = userJpaRepository; + } + + @Override + public void save(Group group) { + try { + this.groupJpaRepository.saveAndFlush(toEntity(group)); + } catch (DataIntegrityViolationException e) { + PersistenceErrorState state = PersistenceErrorHelper.getState(e); + + if (state.equals(SUPER_GROUP_NOT_FOUND)) { + throw new SuperGroupNotFoundRuntimeException(); + } else if (state.equals(GROUP_NAME_ALREADY_EXISTS)) { + throw new GroupNameAlreadyExistsRuntimeException(); + } else if (state.equals(USER_NOT_FOUND)) { + throw new UserNotFoundRuntimeException(); + } else if (state.equals(POST_NOT_FOUND)) { + throw new PostNotFoundRuntimeException(); + } + + throw e; + } + } + + @Override + public void delete(GroupId groupId) throws GroupNotFoundException { + try { + this.groupJpaRepository.deleteById(groupId.value()); + } catch (EmptyResultDataAccessException e) { + throw new GroupNotFoundException(); + } + } + + @Override + public List getAll() { + return this.groupJpaRepository.findAll().stream() + .map(this.groupEntityConverter::toDomain) + .toList(); + } + + @Override + public List getAllBySuperGroup(SuperGroupId superGroupId) { + return this.groupJpaRepository.findAllBySuperGroupId(superGroupId.value()).stream() + .map(this.groupEntityConverter::toDomain) + .toList(); + } + + @Override + public List getAllByPost(PostId postId) { + return this.membershipJpaRepository.findAllById_Post_Id(postId.value()).stream() + .map(membershipEntity -> membershipEntity.getId().getGroup()) + .map(this.groupEntityConverter::toDomain) + .distinct() + .toList(); + } + + @Override + public List getAllByUser(UserId userId) { + return this.membershipJpaRepository.findAllById_User_Id(userId.value()).stream() + .map( + membershipEntity -> + new UserMembership( + this.postEntityConverter.toDomain(membershipEntity.getId().getPost()), + this.groupEntityConverter.toDomain(membershipEntity.getId().getGroup()), + new UnofficialPostName(membershipEntity.getUnofficialPostName()))) + .toList(); + } + + @Override + public Optional get(GroupId groupId) { + return this.groupJpaRepository + .findById(groupId.value()) + .map(this.groupEntityConverter::toDomain); + } + + @Override + public Optional get(Name name) { + return this.groupJpaRepository + .findByName(name.value()) + .map(this.groupEntityConverter::toDomain); + } + + private GroupEntity toEntity(Group group) { + GroupEntity entity = + this.groupJpaRepository.findById(group.id().value()).orElse(new GroupEntity()); + + entity.increaseVersion(group.version()); + + entity.id = group.id().getValue(); + entity.name = group.name().value(); + entity.prettyName = group.prettyName().value(); + entity.superGroup = superGroupJpaRepository.getById(group.superGroup().id().value()); + + if (entity.members == null) { + entity.members = new ArrayList<>(); + } + + entity.members.clear(); + entity.members.addAll( + group.groupMembers().stream() + .map( + groupMember -> + new MembershipEntity( + new MembershipPK( + this.postJpaRepository.getById(groupMember.post().id().value()), + entity, + this.userJpaRepository.getById(groupMember.user().id().value())), + groupMember.unofficialPostName().value())) + .toList()); + + if (entity.groupImages == null) { + entity.groupImages = new GroupImagesEntity(); + } + + entity.groupImages.group = entity; + entity.groupImages.groupId = entity.id; + entity.groupImages.avatarUri = group.avatarUri().map(ImageUri::value).orElse(null); + entity.groupImages.bannerUri = group.bannerUri().map(ImageUri::value).orElse(null); + + return entity; + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/group/MembershipEntity.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/group/MembershipEntity.java new file mode 100644 index 000000000..db9788a4b --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/group/MembershipEntity.java @@ -0,0 +1,33 @@ +package it.chalmers.gamma.adapter.secondary.jpa.group; + +import it.chalmers.gamma.adapter.secondary.jpa.util.ImmutableEntity; +import jakarta.persistence.Column; +import jakarta.persistence.EmbeddedId; +import jakarta.persistence.Entity; +import jakarta.persistence.Table; + +@Entity +@Table(name = "g_membership") +public class MembershipEntity extends ImmutableEntity { + + @EmbeddedId private MembershipPK id; + + @Column(name = "unofficial_post_name") + private String unofficialPostName; + + protected MembershipEntity() {} + + protected MembershipEntity(MembershipPK id, String unofficialPostName) { + this.id = id; + this.unofficialPostName = unofficialPostName; + } + + @Override + public MembershipPK getId() { + return this.id; + } + + public String getUnofficialPostName() { + return unofficialPostName; + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/group/MembershipJpaRepository.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/group/MembershipJpaRepository.java new file mode 100644 index 000000000..b6b68f433 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/group/MembershipJpaRepository.java @@ -0,0 +1,21 @@ +package it.chalmers.gamma.adapter.secondary.jpa.group; + +import java.util.List; +import java.util.UUID; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; + +@Repository +public interface MembershipJpaRepository extends JpaRepository { + List findAllById_Post_Id(UUID postId); + + List findAllById_User_Id(UUID userId); + + @Query( + "SELECT DISTINCT g.members " + + "FROM GroupEntity g " + + "WHERE g.superGroup.id = :superGroupId") + List findAllBySuperGroup(@Param("superGroupId") UUID superGroupId); +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/group/MembershipPK.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/group/MembershipPK.java new file mode 100644 index 000000000..1b1e02480 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/group/MembershipPK.java @@ -0,0 +1,56 @@ +package it.chalmers.gamma.adapter.secondary.jpa.group; + +import it.chalmers.gamma.adapter.secondary.jpa.user.UserEntity; +import it.chalmers.gamma.adapter.secondary.jpa.util.PKId; +import it.chalmers.gamma.app.group.domain.GroupId; +import it.chalmers.gamma.app.post.domain.PostId; +import it.chalmers.gamma.app.user.domain.UserId; +import jakarta.persistence.Embeddable; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; + +@Embeddable +public class MembershipPK extends PKId { + + @JoinColumn(name = "post_id") + @ManyToOne + private PostEntity post; + + @JoinColumn(name = "group_id") + @ManyToOne + private GroupEntity group; + + @JoinColumn(name = "user_id") + @ManyToOne + private UserEntity user; + + protected MembershipPK() {} + + public MembershipPK(PostEntity post, GroupEntity group, UserEntity user) { + this.post = post; + this.group = group; + this.user = user; + } + + public PostEntity getPost() { + return post; + } + + public GroupEntity getGroup() { + return group; + } + + public UserEntity getUser() { + return user; + } + + @Override + public MembershipPK.MembershipPKDTO getValue() { + return new MembershipPKDTO( + new PostId(this.post.getId()), + new GroupId(this.group.getId()), + new UserId(this.user.getId())); + } + + public record MembershipPKDTO(PostId postId, GroupId groupId, UserId userId) {} +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/group/PostEntity.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/group/PostEntity.java new file mode 100644 index 000000000..13d80a824 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/group/PostEntity.java @@ -0,0 +1,36 @@ +package it.chalmers.gamma.adapter.secondary.jpa.group; + +import it.chalmers.gamma.adapter.secondary.jpa.text.TextEntity; +import it.chalmers.gamma.adapter.secondary.jpa.util.MutableEntity; +import jakarta.persistence.*; +import java.util.UUID; + +@Entity +@Table(name = "g_post") +public class PostEntity extends MutableEntity { + + @Id + @Column(name = "post_id", columnDefinition = "uuid") + protected UUID id; + + @JoinColumn(name = "post_name") + @OneToOne(cascade = CascadeType.ALL) + protected TextEntity postName; + + @Column(name = "email_prefix") + protected String emailPrefix; + + @Column(name = "post_order") + protected int order; + + protected PostEntity() {} + + protected PostEntity(UUID id) { + this.id = id; + } + + @Override + public UUID getId() { + return this.id; + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/group/PostEntityConverter.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/group/PostEntityConverter.java new file mode 100644 index 000000000..528bd6314 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/group/PostEntityConverter.java @@ -0,0 +1,20 @@ +package it.chalmers.gamma.adapter.secondary.jpa.group; + +import it.chalmers.gamma.app.group.domain.EmailPrefix; +import it.chalmers.gamma.app.post.domain.Order; +import it.chalmers.gamma.app.post.domain.Post; +import it.chalmers.gamma.app.post.domain.PostId; +import org.springframework.stereotype.Service; + +@Service +public class PostEntityConverter { + + public Post toDomain(PostEntity postEntity) { + return new Post( + new PostId(postEntity.id), + postEntity.getVersion(), + postEntity.postName.toDomain(), + new EmailPrefix(postEntity.emailPrefix), + new Order(postEntity.order)); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/group/PostJpaRepository.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/group/PostJpaRepository.java new file mode 100644 index 000000000..2f486bd19 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/group/PostJpaRepository.java @@ -0,0 +1,11 @@ +package it.chalmers.gamma.adapter.secondary.jpa.group; + +import java.util.List; +import java.util.UUID; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface PostJpaRepository extends JpaRepository { + List findAllByOrderByOrderAsc(); +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/group/PostRepositoryAdapter.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/group/PostRepositoryAdapter.java new file mode 100644 index 000000000..f19df0c22 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/group/PostRepositoryAdapter.java @@ -0,0 +1,78 @@ +package it.chalmers.gamma.adapter.secondary.jpa.group; + +import it.chalmers.gamma.adapter.secondary.jpa.text.TextEntity; +import it.chalmers.gamma.app.post.domain.Post; +import it.chalmers.gamma.app.post.domain.PostId; +import it.chalmers.gamma.app.post.domain.PostRepository; +import java.util.List; +import java.util.Optional; +import org.springframework.dao.EmptyResultDataAccessException; +import org.springframework.stereotype.Service; + +@Service +public class PostRepositoryAdapter implements PostRepository { + + private final PostJpaRepository repository; + private final PostEntityConverter postEntityConverter; + + public PostRepositoryAdapter( + PostJpaRepository repository, PostEntityConverter postEntityConverter) { + this.repository = repository; + this.postEntityConverter = postEntityConverter; + } + + @Override + public void save(Post post) { + this.repository.saveAndFlush(toEntity(post)); + } + + @Override + public void saveAll(List posts) { + this.repository.saveAll(posts.stream().map(this::toEntity).toList()); + } + + @Override + public void delete(PostId postId) throws PostNotFoundException { + try { + this.repository.deleteById(postId.value()); + } catch (EmptyResultDataAccessException e) { + throw new PostNotFoundException(); + } + } + + @Override + public List getAll() { + return this.repository.findAllByOrderByOrderAsc().stream() + .map(this.postEntityConverter::toDomain) + .toList(); + } + + @Override + public Optional get(PostId postId) { + return this.repository.findById(postId.value()).map(this.postEntityConverter::toDomain); + } + + @Override + public int numberOfPosts() { + return Math.toIntExact(this.repository.count()); + } + + private PostEntity toEntity(Post post) { + PostEntity postEntity = this.repository.findById(post.id().value()).orElse(new PostEntity()); + + postEntity.increaseVersion(post.version()); + + postEntity.id = post.id().value(); + postEntity.emailPrefix = post.emailPrefix().value(); + + if (postEntity.postName == null) { + postEntity.postName = new TextEntity(); + } + + postEntity.postName.apply(post.name()); + + postEntity.order = post.order().value(); + + return postEntity; + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/supergroup/SuperGroupEntity.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/supergroup/SuperGroupEntity.java new file mode 100644 index 000000000..f1acb88ec --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/supergroup/SuperGroupEntity.java @@ -0,0 +1,40 @@ +package it.chalmers.gamma.adapter.secondary.jpa.supergroup; + +import it.chalmers.gamma.adapter.secondary.jpa.text.TextEntity; +import it.chalmers.gamma.adapter.secondary.jpa.util.MutableEntity; +import jakarta.persistence.*; +import java.util.UUID; + +@Entity +@Table(name = "g_super_group") +public class SuperGroupEntity extends MutableEntity { + + @Id + @Column(name = "super_group_id", columnDefinition = "uuid") + protected UUID id; + + @JoinColumn(name = "description") + @OneToOne(cascade = CascadeType.ALL) + protected TextEntity description; + + @Column(name = "e_name") + protected String name; + + @Column(name = "pretty_name") + protected String prettyName; + + @ManyToOne + @JoinColumn(name = "super_group_type_name") + protected SuperGroupTypeEntity superGroupType; + + protected SuperGroupEntity() {} + + protected SuperGroupEntity(UUID superGroupId) { + this.id = superGroupId; + } + + @Override + public UUID getId() { + return this.id; + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/supergroup/SuperGroupEntityConverter.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/supergroup/SuperGroupEntityConverter.java new file mode 100644 index 000000000..413dfecff --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/supergroup/SuperGroupEntityConverter.java @@ -0,0 +1,28 @@ +package it.chalmers.gamma.adapter.secondary.jpa.supergroup; + +import it.chalmers.gamma.app.common.PrettyName; +import it.chalmers.gamma.app.supergroup.domain.SuperGroup; +import it.chalmers.gamma.app.supergroup.domain.SuperGroupId; +import it.chalmers.gamma.app.supergroup.domain.SuperGroupType; +import it.chalmers.gamma.app.user.domain.Name; +import org.springframework.stereotype.Service; + +@Service +public class SuperGroupEntityConverter { + + public final SuperGroupJpaRepository superGroupJpaRepository; + + public SuperGroupEntityConverter(SuperGroupJpaRepository superGroupJpaRepository) { + this.superGroupJpaRepository = superGroupJpaRepository; + } + + public SuperGroup toDomain(SuperGroupEntity entity) { + return new SuperGroup( + new SuperGroupId(entity.id), + entity.getVersion(), + new Name(entity.name), + new PrettyName(entity.prettyName), + new SuperGroupType(entity.superGroupType.getId()), + entity.description.toDomain()); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/supergroup/SuperGroupJpaRepository.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/supergroup/SuperGroupJpaRepository.java new file mode 100644 index 000000000..bcbb4aa08 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/supergroup/SuperGroupJpaRepository.java @@ -0,0 +1,11 @@ +package it.chalmers.gamma.adapter.secondary.jpa.supergroup; + +import java.util.List; +import java.util.UUID; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface SuperGroupJpaRepository extends JpaRepository { + List findAllBySuperGroupType_Name(String type); +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/supergroup/SuperGroupRepositoryAdapter.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/supergroup/SuperGroupRepositoryAdapter.java new file mode 100644 index 000000000..0104268d6 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/supergroup/SuperGroupRepositoryAdapter.java @@ -0,0 +1,122 @@ +package it.chalmers.gamma.adapter.secondary.jpa.supergroup; + +import it.chalmers.gamma.adapter.secondary.jpa.text.TextEntity; +import it.chalmers.gamma.adapter.secondary.jpa.util.PersistenceErrorHelper; +import it.chalmers.gamma.adapter.secondary.jpa.util.PersistenceErrorState; +import it.chalmers.gamma.app.supergroup.domain.SuperGroup; +import it.chalmers.gamma.app.supergroup.domain.SuperGroupId; +import it.chalmers.gamma.app.supergroup.domain.SuperGroupRepository; +import it.chalmers.gamma.app.supergroup.domain.SuperGroupType; +import java.util.List; +import java.util.Optional; +import org.springframework.dao.DataIntegrityViolationException; +import org.springframework.dao.EmptyResultDataAccessException; +import org.springframework.stereotype.Service; + +@Service +public class SuperGroupRepositoryAdapter implements SuperGroupRepository { + + private static final PersistenceErrorState typeNotFound = + new PersistenceErrorState( + "g_super_group_super_group_type_name_fkey", + PersistenceErrorState.Type.FOREIGN_KEY_VIOLATION); + private static final PersistenceErrorState nameAlreadyExists = + new PersistenceErrorState("g_super_group_e_name_key", PersistenceErrorState.Type.NOT_UNIQUE); + private static final PersistenceErrorState superGroupIsUsed = + new PersistenceErrorState( + "g_group_super_group_id_fkey", PersistenceErrorState.Type.FOREIGN_KEY_VIOLATION); + private final SuperGroupJpaRepository repository; + private final SuperGroupTypeJpaRepository superGroupTypeJpaRepository; + private final SuperGroupEntityConverter superGroupEntityConverter; + + public SuperGroupRepositoryAdapter( + SuperGroupJpaRepository repository, + SuperGroupTypeJpaRepository superGroupTypeJpaRepository, + SuperGroupEntityConverter superGroupEntityConverter) { + this.repository = repository; + this.superGroupTypeJpaRepository = superGroupTypeJpaRepository; + this.superGroupEntityConverter = superGroupEntityConverter; + } + + @Override + public void save(SuperGroup superGroup) { + try { + this.repository.saveAndFlush(toEntity(superGroup)); + } catch (DataIntegrityViolationException e) { + PersistenceErrorState state = PersistenceErrorHelper.getState(e); + + if (state.equals(typeNotFound)) { + throw new TypeNotFoundRuntimeException(); + } else if (state.equals(nameAlreadyExists)) { + throw new NameAlreadyExistsRuntimeException(); + } + + throw e; + } + } + + @Override + public void delete(SuperGroupId superGroupId) + throws SuperGroupNotFoundException, SuperGroupIsUsedException { + try { + this.repository.deleteById(superGroupId.value()); + } catch (EmptyResultDataAccessException e) { + throw new SuperGroupNotFoundException(); + } catch (Exception e) { + PersistenceErrorState state = PersistenceErrorHelper.getState(e); + + if (state.equals(superGroupIsUsed)) { + throw new SuperGroupIsUsedException(); + } + + throw e; + } + } + + @Override + public List getAll() { + return this.repository.findAll().stream() + .map(this.superGroupEntityConverter::toDomain) + .toList(); + } + + @Override + public List getAllByType(SuperGroupType superGroupType) { + boolean typeExists = this.superGroupTypeJpaRepository.existsById(superGroupType.value()); + if (!typeExists) { + throw new TypeNotFoundRuntimeException(); + } + + return this.repository.findAllBySuperGroupType_Name(superGroupType.value()).stream() + .map(this.superGroupEntityConverter::toDomain) + .toList(); + } + + @Override + public Optional get(SuperGroupId superGroupId) { + return this.repository + .findById(superGroupId.value()) + .map(this.superGroupEntityConverter::toDomain); + } + + private SuperGroupEntity toEntity(SuperGroup superGroup) { + SuperGroupEntity superGroupEntity = + this.repository.findById(superGroup.id().value()).orElse(new SuperGroupEntity()); + + superGroupEntity.increaseVersion(superGroup.version()); + + superGroupEntity.id = superGroup.id().value(); + superGroupEntity.superGroupType = + this.superGroupTypeJpaRepository.getById(superGroup.type().value()); + superGroupEntity.name = superGroup.name().value(); + superGroupEntity.prettyName = superGroup.prettyName().value(); + + if (superGroupEntity.description == null) { + superGroupEntity.description = new TextEntity(); + } + + superGroupEntity.description.apply(superGroup.description()); + + return superGroupEntity; + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/supergroup/SuperGroupTypeEntity.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/supergroup/SuperGroupTypeEntity.java new file mode 100644 index 000000000..e7bba7695 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/supergroup/SuperGroupTypeEntity.java @@ -0,0 +1,28 @@ +package it.chalmers.gamma.adapter.secondary.jpa.supergroup; + +import it.chalmers.gamma.adapter.secondary.jpa.util.AbstractEntity; +import it.chalmers.gamma.app.supergroup.domain.SuperGroupType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; + +@Entity +@Table(name = "g_super_group_type") +public class SuperGroupTypeEntity extends AbstractEntity { + + @Id + @Column(name = "super_group_type_name") + private String name; + + protected SuperGroupTypeEntity() {} + + public SuperGroupTypeEntity(SuperGroupType superGroupType) { + this.name = superGroupType.getValue(); + } + + @Override + public String getId() { + return this.name; + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/supergroup/SuperGroupTypeJpaRepository.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/supergroup/SuperGroupTypeJpaRepository.java new file mode 100644 index 000000000..034bd8efb --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/supergroup/SuperGroupTypeJpaRepository.java @@ -0,0 +1,5 @@ +package it.chalmers.gamma.adapter.secondary.jpa.supergroup; + +import org.springframework.data.jpa.repository.JpaRepository; + +public interface SuperGroupTypeJpaRepository extends JpaRepository {} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/supergroup/SuperGroupTypeRepositoryAdapter.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/supergroup/SuperGroupTypeRepositoryAdapter.java new file mode 100644 index 000000000..e7f69ace9 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/supergroup/SuperGroupTypeRepositoryAdapter.java @@ -0,0 +1,61 @@ +package it.chalmers.gamma.adapter.secondary.jpa.supergroup; + +import it.chalmers.gamma.adapter.secondary.jpa.util.PersistenceErrorHelper; +import it.chalmers.gamma.adapter.secondary.jpa.util.PersistenceErrorState; +import it.chalmers.gamma.app.supergroup.domain.SuperGroupType; +import it.chalmers.gamma.app.supergroup.domain.SuperGroupTypeRepository; +import jakarta.transaction.Transactional; +import java.util.List; +import org.springframework.dao.DataIntegrityViolationException; +import org.springframework.dao.EmptyResultDataAccessException; +import org.springframework.stereotype.Service; + +@Service +public class SuperGroupTypeRepositoryAdapter implements SuperGroupTypeRepository { + + private static final PersistenceErrorState typeIsUsed = + new PersistenceErrorState( + "g_super_group_super_group_type_name_fkey", + PersistenceErrorState.Type.FOREIGN_KEY_VIOLATION); + private final SuperGroupTypeJpaRepository repository; + + public SuperGroupTypeRepositoryAdapter(SuperGroupTypeJpaRepository repository) { + this.repository = repository; + } + + @Transactional + @Override + public void add(SuperGroupType superGroupType) throws SuperGroupTypeAlreadyExistsException { + if (this.repository.existsById(superGroupType.value())) { + throw new SuperGroupTypeAlreadyExistsException(superGroupType.value()); + } + + this.repository.saveAndFlush(new SuperGroupTypeEntity(superGroupType)); + } + + @Override + public void delete(SuperGroupType superGroupType) + throws SuperGroupTypeNotFoundException, SuperGroupTypeHasUsagesException { + try { + this.repository.deleteById(superGroupType.value()); + } catch (EmptyResultDataAccessException e) { + throw new SuperGroupTypeNotFoundException(); + } catch (DataIntegrityViolationException e) { + PersistenceErrorState state = PersistenceErrorHelper.getState(e); + + if (state.equals(typeIsUsed)) { + throw new SuperGroupTypeHasUsagesException(); + } + + throw e; + } + } + + @Override + public List getAll() { + return this.repository.findAll().stream() + .map(SuperGroupTypeEntity::getId) + .map(SuperGroupType::new) + .toList(); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/text/TextEntity.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/text/TextEntity.java new file mode 100644 index 000000000..82a8e9f5b --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/text/TextEntity.java @@ -0,0 +1,53 @@ +package it.chalmers.gamma.adapter.secondary.jpa.text; + +import it.chalmers.gamma.adapter.secondary.jpa.util.ImmutableEntity; +import it.chalmers.gamma.app.common.Text; +import it.chalmers.gamma.app.common.TextId; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import java.util.UUID; + +@Entity +@Table(name = "g_text") +public class TextEntity extends ImmutableEntity { + + @Id + @Column(name = "text_id", columnDefinition = "uuid") + private final UUID id; + + @Column(name = "sv") + private String sv; + + @Column(name = "en") + private String en; + + public TextEntity() { + this(TextId.generate().getValue(), null, null); + } + + public TextEntity(UUID id, String sv, String en) { + this.id = id; + this.sv = sv; + this.en = en; + } + + public TextEntity(Text text) { + this(TextId.generate().getValue(), text.sv().value(), text.en().value()); + } + + public Text toDomain() { + return new Text(this.sv, this.en); + } + + @Override + public TextId getId() { + return new TextId(this.id); + } + + public void apply(Text newText) { + this.sv = newText.sv().value(); + this.en = newText.en().value(); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/user/TrustedUserDetailsRepository.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/user/TrustedUserDetailsRepository.java new file mode 100644 index 000000000..ffdc0191b --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/user/TrustedUserDetailsRepository.java @@ -0,0 +1,80 @@ +package it.chalmers.gamma.adapter.secondary.jpa.user; + +import it.chalmers.gamma.app.common.Email; +import it.chalmers.gamma.app.image.domain.ImageUri; +import it.chalmers.gamma.app.user.domain.*; +import java.util.Collections; +import java.util.Optional; +import java.util.UUID; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; + +public class TrustedUserDetailsRepository implements UserDetailsService { + + private final UserJpaRepository userJpaRepository; + + public TrustedUserDetailsRepository(UserJpaRepository userJpaRepository) { + this.userJpaRepository = userJpaRepository; + } + + public GammaUser getGammaUserByUser() { + User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); + + UserEntity userEntity = + this.userJpaRepository + .findById(UUID.fromString(user.getUsername())) + .orElseThrow(() -> new UsernameNotFoundException("User not found")); + + if (userEntity.password == null) { + // Same error to masquerade the account being locked + throw new UsernameNotFoundException("User credentials needs to be created"); + } + + return new GammaUser( + new UserId(UUID.fromString(user.getUsername())), + new Cid(userEntity.cid), + new Nick(userEntity.nick), + new FirstName(userEntity.firstName), + new LastName(userEntity.lastName), + new AcceptanceYear(userEntity.acceptanceYear), + userEntity.language, + new UserExtended( + new Email(userEntity.email), + userEntity.getVersion(), + userEntity.locked, + userEntity.userAvatar == null ? null : new ImageUri(userEntity.userAvatar.avatarUri))); + } + + @Override + public UserDetails loadUserByUsername(String userIdentifier) throws UsernameNotFoundException { + UserEntity userEntity = + getUserByUsernameOrEmail(userIdentifier) + .orElseThrow(() -> new UsernameNotFoundException("User not found")); + + if (userEntity.password == null) { + // Same error to masquerade the account being locked + throw new UsernameNotFoundException("User credentials needs to be created"); + } + + return new User( + userEntity.id.toString(), + userEntity.password, + true, + true, + true, + !userEntity.locked, + Collections.emptyList()); + } + + private Optional getUserByUsernameOrEmail(String userIdentifier) { + Optional userEntity = this.userJpaRepository.findByCidIgnoreCase(userIdentifier); + if (userEntity.isEmpty()) { + userEntity = this.userJpaRepository.findByEmailIgnoreCase(userIdentifier); + } + + return userEntity; + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/user/UserActivationEntity.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/user/UserActivationEntity.java new file mode 100644 index 000000000..b4fea355c --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/user/UserActivationEntity.java @@ -0,0 +1,43 @@ +package it.chalmers.gamma.adapter.secondary.jpa.user; + +import it.chalmers.gamma.adapter.secondary.jpa.util.ImmutableEntity; +import it.chalmers.gamma.app.user.activation.domain.UserActivation; +import it.chalmers.gamma.app.user.activation.domain.UserActivationToken; +import it.chalmers.gamma.app.user.domain.Cid; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; + +@Entity +@Table(name = "g_user_activation") +public class UserActivationEntity extends ImmutableEntity { + + @Id + @Column(name = "cid") + private String cid; + + @Column(name = "token") + private String token; + + protected UserActivationEntity() {} + + protected UserActivationEntity(Cid cid, UserActivationToken token) { + this.cid = cid.getValue(); + this.token = token.value(); + } + + public UserActivation toDomain() { + return new UserActivation( + Cid.valueOf(this.cid), new UserActivationToken(this.token), this.getCreatedAt()); + } + + @Override + public String getId() { + return this.cid; + } + + public Cid cid() { + return Cid.valueOf(this.cid); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/user/UserActivationJpaRepository.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/user/UserActivationJpaRepository.java new file mode 100644 index 000000000..3fdd64293 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/user/UserActivationJpaRepository.java @@ -0,0 +1,11 @@ +package it.chalmers.gamma.adapter.secondary.jpa.user; + +import java.util.Optional; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface UserActivationJpaRepository extends JpaRepository { + + Optional findByToken(String token); +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/user/UserActivationRepositoryAdapter.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/user/UserActivationRepositoryAdapter.java new file mode 100644 index 000000000..22e83d82b --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/user/UserActivationRepositoryAdapter.java @@ -0,0 +1,108 @@ +package it.chalmers.gamma.adapter.secondary.jpa.user; + +import it.chalmers.gamma.adapter.secondary.jpa.util.PersistenceErrorHelper; +import it.chalmers.gamma.adapter.secondary.jpa.util.PersistenceErrorState; +import it.chalmers.gamma.app.user.activation.domain.UserActivation; +import it.chalmers.gamma.app.user.activation.domain.UserActivationRepository; +import it.chalmers.gamma.app.user.activation.domain.UserActivationToken; +import it.chalmers.gamma.app.user.domain.Cid; +import jakarta.transaction.Transactional; +import java.time.Duration; +import java.time.Instant; +import java.util.List; +import java.util.Optional; +import org.springframework.dao.DataIntegrityViolationException; +import org.springframework.stereotype.Service; + +@Service +public class UserActivationRepositoryAdapter implements UserActivationRepository { + + private static final PersistenceErrorState cidNotAllowed = + new PersistenceErrorState( + "g_user_activation_cid_fkey", PersistenceErrorState.Type.FOREIGN_KEY_VIOLATION); + private final UserActivationJpaRepository userActivationJpaRepository; + + public UserActivationRepositoryAdapter(UserActivationJpaRepository userActivationJpaRepository) { + this.userActivationJpaRepository = userActivationJpaRepository; + } + + @Override + public UserActivationToken createActivationToken(Cid cid) throws CidNotAllowedException { + UserActivationToken token = UserActivationToken.generate(); + + UserActivationEntity entity = + this.userActivationJpaRepository + .findById(cid.value()) + .orElse(new UserActivationEntity(cid, token)); + + try { + this.userActivationJpaRepository.saveAndFlush(entity); + return token; + } catch (DataIntegrityViolationException e) { + PersistenceErrorState state = PersistenceErrorHelper.getState(e); + + if (state.equals(cidNotAllowed)) { + throw new CidNotAllowedException(); + } + + throw e; + } + } + + @Override + public List getAll() { + return this.userActivationJpaRepository.findAll().stream() + .map(UserActivationEntity::toDomain) + .toList(); + } + + @Override + public boolean isTokenValid(UserActivationToken token) { + return this.userActivationJpaRepository + .findByToken(token.value()) + .map(this::isStillValid) + .orElse(false); + } + + @Override + @Transactional + public Cid useToken(UserActivationToken token) { + Optional maybeActivation = + this.userActivationJpaRepository.findByToken(token.value()); + if (maybeActivation.isEmpty()) { + throw new TokenNotActivatedRuntimeException(); + } + + if (!isStillValid(maybeActivation.get())) { + throw new TokenNotActivatedRuntimeException(); + } + + this.userActivationJpaRepository.deleteById(maybeActivation.get().getId()); + + return new Cid(maybeActivation.get().getId()); + } + + public boolean isStillValid(UserActivationEntity userActivationEntity) { + Instant createdAt = userActivationEntity.toDomain().createdAt(); + return Duration.between(createdAt, Instant.now()).toMinutes() < 15; + } + + @Override + public void removeActivation(Cid cid) throws CidNotActivatedException { + this.userActivationJpaRepository.deleteById(cid.value()); + } + + @Override + public int removeInvalidActivationCodes() { + int i = 0; + + for (UserActivationEntity userActivationEntity : this.userActivationJpaRepository.findAll()) { + if (!isStillValid(userActivationEntity)) { + this.userActivationJpaRepository.delete(userActivationEntity); + i++; + } + } + + return i; + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/user/UserApprovalEntity.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/user/UserApprovalEntity.java new file mode 100644 index 000000000..bcb26539f --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/user/UserApprovalEntity.java @@ -0,0 +1,33 @@ +package it.chalmers.gamma.adapter.secondary.jpa.user; + +import it.chalmers.gamma.adapter.secondary.jpa.client.ClientEntity; +import it.chalmers.gamma.adapter.secondary.jpa.util.ImmutableEntity; +import jakarta.persistence.EmbeddedId; +import jakarta.persistence.Entity; +import jakarta.persistence.Table; + +@Entity +@Table(name = "g_user_approval") +public class UserApprovalEntity extends ImmutableEntity { + + @EmbeddedId private UserApprovalEntityPK id; + + public UserApprovalEntity() {} + + public UserApprovalEntity(UserEntity user, ClientEntity client) { + this.id = new UserApprovalEntityPK(user, client); + } + + @Override + public UserApprovalEntityPK getId() { + return this.id; + } + + public UserEntity getUserEntity() { + return this.id.getUserEntity(); + } + + public ClientEntity getClientEntity() { + return this.id.getClientEntity(); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/user/UserApprovalEntityPK.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/user/UserApprovalEntityPK.java new file mode 100644 index 000000000..b2e8a93f0 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/user/UserApprovalEntityPK.java @@ -0,0 +1,43 @@ +package it.chalmers.gamma.adapter.secondary.jpa.user; + +import it.chalmers.gamma.adapter.secondary.jpa.client.ClientEntity; +import it.chalmers.gamma.adapter.secondary.jpa.util.PKId; +import it.chalmers.gamma.app.client.domain.ClientUid; +import it.chalmers.gamma.app.user.domain.UserId; +import jakarta.persistence.Embeddable; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; + +@Embeddable +public class UserApprovalEntityPK extends PKId { + + @ManyToOne + @JoinColumn(name = "user_id") + private UserEntity user; + + @ManyToOne + @JoinColumn(name = "client_uid") + private ClientEntity client; + + protected UserApprovalEntityPK() {} + + public UserApprovalEntityPK(UserEntity user, ClientEntity client) { + this.user = user; + this.client = client; + } + + public UserEntity getUserEntity() { + return this.user; + } + + public ClientEntity getClientEntity() { + return this.client; + } + + @Override + public UserApprovalPKDTO getValue() { + return new UserApprovalPKDTO(new UserId(this.user.getId()), new ClientUid(this.client.getId())); + } + + protected record UserApprovalPKDTO(UserId userId, ClientUid clientUid) {} +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/user/UserApprovalJpaRepository.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/user/UserApprovalJpaRepository.java new file mode 100644 index 000000000..a78f12a53 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/user/UserApprovalJpaRepository.java @@ -0,0 +1,18 @@ +package it.chalmers.gamma.adapter.secondary.jpa.user; + +import java.util.List; +import java.util.UUID; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface UserApprovalJpaRepository + extends JpaRepository { + List findAllById_User_Id(UUID id); + + List findAllById_Client_ClientUid(UUID id); + + List findAllById_Client_ClientId(String id); + + boolean existsById_Client_ClientUidAndId_User_Id(UUID clientUid, UUID userId); + + void deleteById_Client_ClientUidAndId_User_Id(UUID clientUid, UUID userId); +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/user/UserAvatarEntity.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/user/UserAvatarEntity.java new file mode 100644 index 000000000..b47a4b528 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/user/UserAvatarEntity.java @@ -0,0 +1,28 @@ +package it.chalmers.gamma.adapter.secondary.jpa.user; + +import it.chalmers.gamma.adapter.secondary.jpa.util.MutableEntity; +import jakarta.persistence.*; +import java.util.UUID; + +@Entity +@Table(name = "g_user_avatar_uri") +public class UserAvatarEntity extends MutableEntity { + + @Id + @Column(name = "user_id", columnDefinition = "uuid") + protected UUID userId; + + @OneToOne + @PrimaryKeyJoinColumn(name = "user_id") + protected UserEntity user; + + @Column(name = "avatar_uri") + protected String avatarUri; + + protected UserAvatarEntity() {} + + @Override + public UUID getId() { + return this.userId; + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/user/UserAvatarJpaRepository.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/user/UserAvatarJpaRepository.java new file mode 100644 index 000000000..5d2cc4168 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/user/UserAvatarJpaRepository.java @@ -0,0 +1,8 @@ +package it.chalmers.gamma.adapter.secondary.jpa.user; + +import java.util.UUID; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface UserAvatarJpaRepository extends JpaRepository {} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/user/UserAvatarRepositoryAdapter.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/user/UserAvatarRepositoryAdapter.java new file mode 100644 index 000000000..8638c270e --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/user/UserAvatarRepositoryAdapter.java @@ -0,0 +1,30 @@ +package it.chalmers.gamma.adapter.secondary.jpa.user; + +import it.chalmers.gamma.app.image.domain.ImageUri; +import it.chalmers.gamma.app.image.domain.UserAvatarRepository; +import it.chalmers.gamma.app.user.domain.UserId; +import java.util.Optional; +import java.util.UUID; +import org.springframework.stereotype.Service; + +@Service +public class UserAvatarRepositoryAdapter implements UserAvatarRepository { + + private final UserAvatarJpaRepository userAvatarJpaRepository; + + public UserAvatarRepositoryAdapter(UserAvatarJpaRepository userAvatarJpaRepository) { + this.userAvatarJpaRepository = userAvatarJpaRepository; + } + + @Override + public Optional getAvatarUri(UserId userId) { + return this.userAvatarJpaRepository + .findById(userId.value()) + .map(userAvatarEntity -> new ImageUri(userAvatarEntity.avatarUri)); + } + + @Override + public void removeAvatarUri(UUID userId) { + this.userAvatarJpaRepository.deleteById(userId); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/user/UserEntity.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/user/UserEntity.java new file mode 100644 index 000000000..d71f1155a --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/user/UserEntity.java @@ -0,0 +1,61 @@ +package it.chalmers.gamma.adapter.secondary.jpa.user; + +import it.chalmers.gamma.adapter.secondary.jpa.util.MutableEntity; +import it.chalmers.gamma.app.user.domain.Language; +import jakarta.persistence.*; +import java.time.Instant; +import java.util.UUID; + +@Entity +@Table(name = "g_user") +public class UserEntity extends MutableEntity { + + @Id + @Column(name = "user_id", columnDefinition = "uuid") + protected UUID id; + + @Column(name = "cid") + protected String cid; + + @Column(name = "password", nullable = true) + protected String password; + + @Column(name = "nick") + protected String nick; + + @Column(name = "first_name") + protected String firstName; + + @Column(name = "last_name") + protected String lastName; + + @Column(name = "email") + protected String email; + + @Column(name = "language") + @Enumerated(EnumType.STRING) + protected Language language; + + @Column(name = "user_agreement_accepted") + protected Instant userAgreementAccepted; + + @Column(name = "acceptance_year") + protected int acceptanceYear; + + @Column(name = "locked") + protected boolean locked; + + @OneToOne(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true) + protected UserAvatarEntity userAvatar; + + protected UserEntity() {} + + @Override + public UUID getId() { + return this.id; + } + + public void acceptUserAgreement() { + this.userAgreementAccepted = Instant.now(); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/user/UserEntityConverter.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/user/UserEntityConverter.java new file mode 100644 index 000000000..d7838b000 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/user/UserEntityConverter.java @@ -0,0 +1,46 @@ +package it.chalmers.gamma.adapter.secondary.jpa.user; + +import it.chalmers.gamma.app.authentication.UserAccessGuard; +import it.chalmers.gamma.app.common.Email; +import it.chalmers.gamma.app.image.domain.ImageUri; +import it.chalmers.gamma.app.user.domain.*; +import org.springframework.lang.Nullable; +import org.springframework.stereotype.Service; + +@Service +public class UserEntityConverter { + + private final UserAccessGuard userAccessGuard; + + public UserEntityConverter(UserAccessGuard userAccessGuard) { + this.userAccessGuard = userAccessGuard; + } + + @Nullable public GammaUser toDomain(UserEntity userEntity) { + UserId userId = new UserId(userEntity.id); + + if (!userAccessGuard.haveAccessToUser(userId, userEntity.locked)) { + return null; + } + + UserExtended extended = null; + if (userAccessGuard.accessToExtended(userId)) { + extended = + new UserExtended( + new Email(userEntity.email), + userEntity.getVersion(), + userEntity.locked, + userEntity.userAvatar == null ? null : new ImageUri(userEntity.userAvatar.avatarUri)); + } + + return new GammaUser( + userId, + new Cid(userEntity.cid), + new Nick(userEntity.nick), + new FirstName(userEntity.firstName), + new LastName(userEntity.lastName), + new AcceptanceYear(userEntity.acceptanceYear), + userEntity.language, + extended); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/user/UserJpaRepository.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/user/UserJpaRepository.java new file mode 100644 index 000000000..15b782170 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/user/UserJpaRepository.java @@ -0,0 +1,16 @@ +package it.chalmers.gamma.adapter.secondary.jpa.user; + +import java.util.Optional; +import java.util.UUID; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface UserJpaRepository extends JpaRepository { + + Optional findByCid(String cid); + + Optional findByCidIgnoreCase(String cid); + + Optional findByEmailIgnoreCase(String email); +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/user/UserPasswordResetEntity.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/user/UserPasswordResetEntity.java new file mode 100644 index 000000000..842da341a --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/user/UserPasswordResetEntity.java @@ -0,0 +1,39 @@ +package it.chalmers.gamma.adapter.secondary.jpa.user; + +import it.chalmers.gamma.adapter.secondary.jpa.util.ImmutableEntity; +import it.chalmers.gamma.app.user.domain.UserId; +import it.chalmers.gamma.app.user.passwordreset.domain.PasswordReset; +import it.chalmers.gamma.app.user.passwordreset.domain.PasswordResetToken; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import java.util.UUID; + +@Entity +@Table(name = "g_password_reset") +public class UserPasswordResetEntity extends ImmutableEntity { + + @Id + @Column(name = "user_id", columnDefinition = "uuid") + protected UUID userId; + + @Column(name = "token") + protected String token; + + protected UserPasswordResetEntity() {} + + @Override + public UUID getId() { + return this.userId; + } + + public PasswordReset toDomain() { + return new PasswordReset( + new UserId(this.userId), new PasswordResetToken(this.token), this.getCreatedAt()); + } + + public String getToken() { + return this.token; + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/user/UserPasswordResetJpaRepository.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/user/UserPasswordResetJpaRepository.java new file mode 100644 index 000000000..5fa9fb1bc --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/user/UserPasswordResetJpaRepository.java @@ -0,0 +1,14 @@ +package it.chalmers.gamma.adapter.secondary.jpa.user; + +import java.util.Optional; +import java.util.UUID; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface UserPasswordResetJpaRepository + extends JpaRepository { + Optional findByToken(String token); + + void deleteByToken(String token); +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/user/UserPasswordResetRepositoryAdapter.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/user/UserPasswordResetRepositoryAdapter.java new file mode 100644 index 000000000..7b408a031 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/user/UserPasswordResetRepositoryAdapter.java @@ -0,0 +1,123 @@ +package it.chalmers.gamma.adapter.secondary.jpa.user; + +import it.chalmers.gamma.app.common.Email; +import it.chalmers.gamma.app.user.domain.Cid; +import it.chalmers.gamma.app.user.domain.UserId; +import it.chalmers.gamma.app.user.passwordreset.domain.PasswordResetRepository; +import it.chalmers.gamma.app.user.passwordreset.domain.PasswordResetToken; +import jakarta.transaction.Transactional; +import java.time.Duration; +import java.time.Instant; +import java.util.Optional; +import org.springframework.stereotype.Service; + +@Service("PasswordResetRepository") +@Transactional +public class UserPasswordResetRepositoryAdapter implements PasswordResetRepository { + + private final UserJpaRepository userJpaRepository; + private final UserPasswordResetJpaRepository userPasswordResetJpaRepository; + + public UserPasswordResetRepositoryAdapter( + UserJpaRepository userJpaRepository, + UserPasswordResetJpaRepository userPasswordResetJpaRepository) { + this.userJpaRepository = userJpaRepository; + this.userPasswordResetJpaRepository = userPasswordResetJpaRepository; + } + + private PasswordReset createNewToken(UserEntity userEntity) { + PasswordResetToken token = PasswordResetToken.generate(); + + this.userPasswordResetJpaRepository.deleteById(userEntity.id); + + UserPasswordResetEntity userPasswordResetEntity = new UserPasswordResetEntity(); + + userPasswordResetEntity.userId = userEntity.id; + userPasswordResetEntity.token = token.value(); + + this.userPasswordResetJpaRepository.save(userPasswordResetEntity); + + return new PasswordReset(token, new Email(userEntity.email)); + } + + @Override + public PasswordReset createNewToken(Email email) throws UserNotFoundException { + Optional maybeUserEntity = + this.userJpaRepository.findByEmailIgnoreCase(email.value()); + + if (maybeUserEntity.isEmpty()) { + throw new UserNotFoundException(); + } + + return this.createNewToken(maybeUserEntity.get()); + } + + @Override + public PasswordReset createNewToken(Cid cid) throws UserNotFoundException { + Optional maybeUserEntity = this.userJpaRepository.findByCid(cid.value()); + + if (maybeUserEntity.isEmpty()) { + throw new UserNotFoundException(); + } + + return this.createNewToken(maybeUserEntity.get()); + } + + @Override + public PasswordReset createNewToken(UserId userId) throws UserNotFoundException { + Optional maybeUserEntity = this.userJpaRepository.findById(userId.value()); + + if (maybeUserEntity.isEmpty()) { + throw new UserNotFoundException(); + } + + return this.createNewToken(maybeUserEntity.get()); + } + + @Override + public boolean isTokenValid(PasswordResetToken token) { + return this.userPasswordResetJpaRepository + .findByToken(token.value()) + .map(this::isStillValid) + .orElse(false); + } + + @Override + @Transactional + public UserId useToken(PasswordResetToken token) { + Optional maybeReset = + this.userPasswordResetJpaRepository.findByToken(token.value()); + + if (maybeReset.isEmpty()) { + throw new TokenNotFoundRuntimeException(); + } + + if (!this.isStillValid(maybeReset.get())) { + throw new TokenNotFoundRuntimeException(); + } + + this.userPasswordResetJpaRepository.deleteByToken(token.value()); + + return new UserId(maybeReset.get().userId); + } + + @Override + public int removeInvalidPasswordResetTokens() { + int i = 0; + + for (UserPasswordResetEntity userPasswordResetEntity : + this.userPasswordResetJpaRepository.findAll()) { + if (!isStillValid(userPasswordResetEntity)) { + this.userPasswordResetJpaRepository.delete(userPasswordResetEntity); + i++; + } + } + + return i; + } + + public boolean isStillValid(UserPasswordResetEntity userPasswordResetEntity) { + Instant createdAt = userPasswordResetEntity.toDomain().createdAt(); + return Duration.between(createdAt, Instant.now()).toMinutes() < 15; + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/user/UserRepositoryAdapter.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/user/UserRepositoryAdapter.java new file mode 100644 index 000000000..e8b7ac256 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/user/UserRepositoryAdapter.java @@ -0,0 +1,154 @@ +package it.chalmers.gamma.adapter.secondary.jpa.user; + +import it.chalmers.gamma.adapter.secondary.jpa.util.PersistenceErrorHelper; +import it.chalmers.gamma.adapter.secondary.jpa.util.PersistenceErrorState; +import it.chalmers.gamma.app.common.Email; +import it.chalmers.gamma.app.user.domain.*; +import java.time.Instant; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import org.springframework.dao.DataIntegrityViolationException; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Service; + +@Service +public class UserRepositoryAdapter implements UserRepository { + + private final UserJpaRepository repository; + private final UserEntityConverter converter; + private final UserAvatarJpaRepository userAvatarJpaRepository; + private final PasswordEncoder passwordEncoder; + + private final PersistenceErrorState cidNotUnique = + new PersistenceErrorState("g_user_cid_key", PersistenceErrorState.Type.NOT_UNIQUE); + + private final PersistenceErrorState emailNotUnique = + new PersistenceErrorState("g_user_email_key", PersistenceErrorState.Type.NOT_UNIQUE); + + public UserRepositoryAdapter( + UserJpaRepository repository, + UserEntityConverter converter, + UserAvatarJpaRepository userAvatarJpaRepository, + PasswordEncoder passwordEncoder) { + this.repository = repository; + this.converter = converter; + this.userAvatarJpaRepository = userAvatarJpaRepository; + this.passwordEncoder = passwordEncoder; + } + + @Override + public void create(GammaUser user, UnencryptedPassword password) + throws CidAlreadyInUseException, EmailAlreadyInUseException { + try { + this.save(toEntity(user, password != null ? password.value() : null)); + } catch (DataIntegrityViolationException e) { + PersistenceErrorState state = PersistenceErrorHelper.getState(e); + + if (cidNotUnique.equals(state)) { + throw new CidAlreadyInUseException(); + } else if (emailNotUnique.equals(state)) { + throw new EmailAlreadyInUseException(); + } + + throw e; + } + } + + @Override + public void save(GammaUser user) { + this.save(toEntity(user, null)); + } + + private void save(UserEntity userEntity) { + this.repository.saveAndFlush(userEntity); + } + + @Override + public void delete(UserId userId) { + this.repository.deleteById(userId.value()); + } + + @Override + public List getAll() { + return this.repository.findAll().stream() + .map(this.converter::toDomain) + .filter(Objects::nonNull) + .toList(); + } + + @Override + public Optional get(UserId userId) { + return this.repository.findById(userId.getValue()).map(this.converter::toDomain); + } + + @Override + public Optional get(Cid cid) { + return this.repository.findByCid(cid.getValue()).map(this.converter::toDomain); + } + + @Override + public Optional get(Email email) { + return this.repository.findByEmailIgnoreCase(email.value()).map(this.converter::toDomain); + } + + @Override + public boolean checkPassword(UserId userId, UnencryptedPassword password) + throws UserNotFoundException { + UserEntity entity = + this.repository.findById(userId.value()).orElseThrow(UserNotFoundException::new); + return passwordEncoder.matches(password.value(), entity.password); + } + + @Override + public void setPassword(UserId userId, UnencryptedPassword newPassword) + throws UserNotFoundException { + UserEntity userEntity = + this.repository.findById(userId.value()).orElseThrow(UserNotFoundException::new); + userEntity.password = passwordEncoder.encode(newPassword.value()); + this.save(userEntity); + } + + @Override + public void acceptUserAgreement(UserId userId) { + UserEntity userEntity = + this.repository.findById(userId.value()).orElseThrow(UserNotFoundException::new); + userEntity.acceptUserAgreement(); + save(userEntity); + } + + private UserEntity toEntity(GammaUser d, String password) { + UserEntity e = this.repository.findById(d.id().value()).orElse(new UserEntity()); + UserExtended extended = d.extended(); + + e.increaseVersion(extended.version()); + + if (e.userAgreementAccepted == null) { + e.userAgreementAccepted = Instant.now(); + } + + e.id = d.id().value(); + e.cid = d.cid().value(); + e.acceptanceYear = d.acceptanceYear().value(); + e.email = extended.email().value(); + e.firstName = d.firstName().value(); + e.lastName = d.lastName().value(); + e.nick = d.nick().value(); + e.locked = d.extended().locked(); + e.language = d.language(); + + if (password != null) { + e.password = passwordEncoder.encode(password); + } + + if (d.extended().avatarUri() != null) { + e.userAvatar = + this.userAvatarJpaRepository.findById(d.id().value()).orElse(new UserAvatarEntity()); + e.userAvatar.userId = e.id; + e.userAvatar.user = e; + e.userAvatar.avatarUri = d.extended().avatarUri().value(); + } + + return e; + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/user/admin/AdminEntity.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/user/admin/AdminEntity.java new file mode 100644 index 000000000..cd0dc288a --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/user/admin/AdminEntity.java @@ -0,0 +1,28 @@ +package it.chalmers.gamma.adapter.secondary.jpa.user.admin; + +import it.chalmers.gamma.adapter.secondary.jpa.util.ImmutableEntity; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import java.util.UUID; + +@Entity +@Table(name = "g_admin_user") +public class AdminEntity extends ImmutableEntity { + + @Id + @Column(name = "user_id", columnDefinition = "uuid") + private UUID userId; + + protected AdminEntity() {} + + protected AdminEntity(UUID userId) { + this.userId = userId; + } + + @Override + public UUID getId() { + return this.userId; + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/user/admin/AdminEntityJpaRepository.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/user/admin/AdminEntityJpaRepository.java new file mode 100644 index 000000000..47e082a2e --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/user/admin/AdminEntityJpaRepository.java @@ -0,0 +1,8 @@ +package it.chalmers.gamma.adapter.secondary.jpa.user.admin; + +import java.util.UUID; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface AdminEntityJpaRepository extends JpaRepository {} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/user/admin/AdminEntityRepositoryAdapter.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/user/admin/AdminEntityRepositoryAdapter.java new file mode 100644 index 000000000..5e134ca58 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/user/admin/AdminEntityRepositoryAdapter.java @@ -0,0 +1,44 @@ +package it.chalmers.gamma.adapter.secondary.jpa.user.admin; + +import it.chalmers.gamma.app.admin.domain.AdminRepository; +import it.chalmers.gamma.app.user.domain.UserId; +import java.util.List; +import java.util.Optional; +import org.springframework.stereotype.Repository; + +@Repository +public class AdminEntityRepositoryAdapter implements AdminRepository { + + private final AdminEntityJpaRepository repository; + + public AdminEntityRepositoryAdapter(AdminEntityJpaRepository repository) { + this.repository = repository; + } + + @Override + public boolean isAdmin(UserId userId) { + return this.repository.findById(userId.value()).isPresent(); + } + + @Override + public void setAdmin(UserId userId, boolean admin) { + Optional maybeAdminEntity = this.repository.findById(userId.value()); + + if (maybeAdminEntity.isPresent()) { + if (!admin) { + this.repository.deleteById(userId.value()); + } + } else { + if (admin) { + this.repository.save(new AdminEntity(userId.value())); + } + } + } + + @Override + public List getAll() { + return this.repository.findAll().stream() + .map(adminEntity -> new UserId(adminEntity.getId())) + .toList(); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/user/gdpr/GdprTrainedEntity.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/user/gdpr/GdprTrainedEntity.java new file mode 100644 index 000000000..d888ef574 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/user/gdpr/GdprTrainedEntity.java @@ -0,0 +1,29 @@ +package it.chalmers.gamma.adapter.secondary.jpa.user.gdpr; + +import it.chalmers.gamma.adapter.secondary.jpa.user.UserEntity; +import it.chalmers.gamma.adapter.secondary.jpa.util.ImmutableEntity; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import java.util.UUID; + +@Entity +@Table(name = "g_gdpr_trained") +public class GdprTrainedEntity extends ImmutableEntity { + + @Id + @Column(name = "user_id", columnDefinition = "uuid") + private UUID userId; + + protected GdprTrainedEntity() {} + + public GdprTrainedEntity(UserEntity userEntity) { + this.userId = userEntity.getId(); + } + + @Override + public UUID getId() { + return this.userId; + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/user/gdpr/GdprTrainedJpaRepository.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/user/gdpr/GdprTrainedJpaRepository.java new file mode 100644 index 000000000..df5b44855 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/user/gdpr/GdprTrainedJpaRepository.java @@ -0,0 +1,6 @@ +package it.chalmers.gamma.adapter.secondary.jpa.user.gdpr; + +import java.util.UUID; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface GdprTrainedJpaRepository extends JpaRepository {} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/user/gdpr/GdprTrainedRepositoryAdapter.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/user/gdpr/GdprTrainedRepositoryAdapter.java new file mode 100644 index 000000000..ed3afd511 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/user/gdpr/GdprTrainedRepositoryAdapter.java @@ -0,0 +1,46 @@ +package it.chalmers.gamma.adapter.secondary.jpa.user.gdpr; + +import it.chalmers.gamma.adapter.secondary.jpa.user.UserJpaRepository; +import it.chalmers.gamma.app.user.domain.UserId; +import it.chalmers.gamma.app.user.gdpr.GdprTrainedRepository; +import java.util.List; +import java.util.Optional; +import org.springframework.stereotype.Repository; + +@Repository +public class GdprTrainedRepositoryAdapter implements GdprTrainedRepository { + + private final GdprTrainedJpaRepository gdprTrainedJpaRepository; + private final UserJpaRepository userJpaRepository; + + public GdprTrainedRepositoryAdapter( + GdprTrainedJpaRepository gdprTrainedJpaRepository, UserJpaRepository userJpaRepository) { + this.gdprTrainedJpaRepository = gdprTrainedJpaRepository; + this.userJpaRepository = userJpaRepository; + } + + @Override + public void setGdprTrainedStatus(UserId userId, boolean gdprTrained) { + Optional maybeGdprTrainedEntity = + this.gdprTrainedJpaRepository.findById(userId.value()); + + if (gdprTrained && maybeGdprTrainedEntity.isEmpty()) { + this.gdprTrainedJpaRepository.save( + new GdprTrainedEntity(userJpaRepository.findById(userId.value()).orElseThrow())); + } else if (!gdprTrained && maybeGdprTrainedEntity.isPresent()) { + this.gdprTrainedJpaRepository.deleteById(userId.value()); + } + } + + @Override + public List getAll() { + return this.gdprTrainedJpaRepository.findAll().stream() + .map(gdprTrainedEntity -> new UserId(gdprTrainedEntity.getId())) + .toList(); + } + + @Override + public boolean getGdprTrainedStatus(UserId userId) { + return this.gdprTrainedJpaRepository.existsById(userId.value()); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/util/AbstractEntity.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/util/AbstractEntity.java new file mode 100644 index 000000000..37b7900e4 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/util/AbstractEntity.java @@ -0,0 +1,55 @@ +package it.chalmers.gamma.adapter.secondary.jpa.util; + +import jakarta.persistence.*; +import java.time.Instant; +import java.util.Objects; +import org.springframework.data.domain.Persistable; + +@MappedSuperclass +public abstract class AbstractEntity implements Persistable { + + @Column(name = "created_at", updatable = false, nullable = false) + private Instant createdAt; + + @Transient private boolean persisted = false; + + @PrePersist + protected void onCreate() { + createdAt = Instant.now(); + } + + @PostPersist + @PostLoad + void setPersisted() { + persisted = true; + } + + protected Instant getCreatedAt() { + return createdAt; + } + + @Override + public boolean isNew() { + return !persisted; + } + + @Override + public final int hashCode() { + assert (getId() != null); + + return Objects.hash(getId().hashCode()); + } + + @Override + public final boolean equals(Object o) { + if (this == o) { + return true; + } + + if (o == null || getClass() != o.getClass()) { + return false; + } + + return Objects.equals(this.getId(), ((AbstractEntity) o).getId()); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/util/ImmutableEntity.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/util/ImmutableEntity.java new file mode 100644 index 000000000..2eb580513 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/util/ImmutableEntity.java @@ -0,0 +1,6 @@ +package it.chalmers.gamma.adapter.secondary.jpa.util; + +import jakarta.persistence.MappedSuperclass; + +@MappedSuperclass +public abstract class ImmutableEntity extends AbstractEntity {} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/util/MutableEntity.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/util/MutableEntity.java new file mode 100644 index 000000000..f6c2a99fb --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/util/MutableEntity.java @@ -0,0 +1,60 @@ +package it.chalmers.gamma.adapter.secondary.jpa.util; + +import jakarta.persistence.Column; +import jakarta.persistence.MappedSuperclass; +import java.time.Instant; + +@MappedSuperclass +public abstract class MutableEntity extends AbstractEntity { + + /** + * It is the responsibility of each entity converter to manage the version. Not + * using @jakarta.persistence.Version since it doesn't handle foreign keys such as members for a + * group. + */ + @Column(name = "version") + private int version; + + @Column(name = "updated_at") + private Instant updatedAt; + + @Override + protected void onCreate() { + super.onCreate(); + updatedAt = Instant.now(); + } + + protected MutableEntity() { + this.version = 0; + } + + /** + * If not the correct version is provided, then the data that is being tried to be converted is + * outdated. + */ + public void increaseVersion(int currentVersion) { + /* + * If id is null, then currentVersion must be 0. This to indicate that the incoming entity is new. + * If not, then something is trying to save an entity that has been deleted. + */ + if (this.getId() == null && currentVersion != 0) { + throw new IllegalEntityStateException(); + } + // Version has to match the current version. + else if (this.version != currentVersion) { + throw new StaleDomainObjectException(); + } + + // Checks passed, updating the version. + this.version++; + this.updatedAt = Instant.now(); + } + + public int getVersion() { + return this.version; + } + + public static class IllegalEntityStateException extends RuntimeException {} + + public static class StaleDomainObjectException extends RuntimeException {} +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/util/PKId.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/util/PKId.java new file mode 100644 index 000000000..2ed21ff73 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/util/PKId.java @@ -0,0 +1,20 @@ +package it.chalmers.gamma.adapter.secondary.jpa.util; + +import it.chalmers.gamma.app.common.Id; + +public abstract class PKId implements Id { + + @Override + public boolean equals(Object obj) { + if (obj instanceof Id otherId) { + return getValue().equals(otherId.getValue()); + } else { + return false; + } + } + + @Override + public int hashCode() { + return getValue().hashCode(); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/util/PersistenceErrorHelper.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/util/PersistenceErrorHelper.java new file mode 100644 index 000000000..5ee976773 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/util/PersistenceErrorHelper.java @@ -0,0 +1,49 @@ +package it.chalmers.gamma.adapter.secondary.jpa.util; + +import static it.chalmers.gamma.adapter.secondary.jpa.util.PersistenceErrorState.Type.FOREIGN_KEY_VIOLATION; +import static it.chalmers.gamma.adapter.secondary.jpa.util.PersistenceErrorState.Type.NOT_UNIQUE; + +import jakarta.persistence.EntityExistsException; +import jakarta.persistence.EntityNotFoundException; +import org.postgresql.util.PSQLException; +import org.postgresql.util.ServerErrorMessage; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public final class PersistenceErrorHelper { + + private static final Logger LOGGER = LoggerFactory.getLogger(PersistenceErrorHelper.class); + + private PersistenceErrorHelper() {} + + public static PersistenceErrorState getState(Exception e) { + for (Throwable t = e.getCause(); t != null; t = t.getCause()) { + + // If there's a specific PQLException such as a UNIQUE violation + if (t instanceof PSQLException postgresException) { + ServerErrorMessage serverErrorMessage = postgresException.getServerErrorMessage(); + if (serverErrorMessage != null) { + for (PersistenceErrorState.Type type : PersistenceErrorState.Type.values()) { + if (type.ERROR_CODE.equals(serverErrorMessage.getSQLState())) { + return new PersistenceErrorState(serverErrorMessage.getConstraint(), type); + } + } + } + } + + if (t instanceof EntityExistsException) { + return new PersistenceErrorState(null, NOT_UNIQUE); + } + + if (t instanceof EntityNotFoundException) { + return new PersistenceErrorState(null, FOREIGN_KEY_VIOLATION); + } + } + + e.printStackTrace(); + + throw new UnknownDataIntegrityViolationException(); + } + + public static class UnknownDataIntegrityViolationException extends RuntimeException {} +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/util/PersistenceErrorState.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/util/PersistenceErrorState.java new file mode 100644 index 000000000..b6b893cc0 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/util/PersistenceErrorState.java @@ -0,0 +1,16 @@ +package it.chalmers.gamma.adapter.secondary.jpa.util; + +public record PersistenceErrorState(String constraint, Type type) { + + public enum Type { + NOT_UNIQUE("23505"), + FOREIGN_KEY_VIOLATION("23503"), + IS_NULL("23502"); + + public final String ERROR_CODE; + + Type(String errorCode) { + this.ERROR_CODE = errorCode; + } + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/mail/GotifyMailService.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/mail/GotifyMailService.java new file mode 100644 index 000000000..49a0c95ac --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/mail/GotifyMailService.java @@ -0,0 +1,71 @@ +package it.chalmers.gamma.adapter.secondary.mail; + +import it.chalmers.gamma.app.mail.domain.MailService; +import it.chalmers.gamma.app.throttling.ThrottlingService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.web.authentication.WebAuthenticationDetails; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestClientException; +import org.springframework.web.client.RestTemplate; + +@Service +public class GotifyMailService implements MailService { + + private static final Logger LOGGER = LoggerFactory.getLogger(GotifyMailService.class); + private final String gotifyApiKey; + private final String gotifyURL; + private final ThrottlingService throttlingService; + + public GotifyMailService( + @Value("${application.gotify.key}") String gotifyApiKey, + @Value("${application.gotify.url}") String gotifyURL, + ThrottlingService throttlingService) { + this.gotifyApiKey = gotifyApiKey; + this.gotifyURL = gotifyURL; + this.throttlingService = throttlingService; + } + + /** Sends mail using Gotify Rest API, see https://github.com/cthit/gotify */ + public void sendMail(String email, String subject, String body) { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + String clientIp = null; + + if (authentication != null + && authentication.getDetails() instanceof WebAuthenticationDetails details) { + clientIp = details.getRemoteAddress(); + } + + if (clientIp != null && !throttlingService.canProceed("email:" + clientIp, 5)) { + LOGGER.warn( + "Client with IP: {} has exceeded the limit of number of emails that can be sent per day.", + clientIp); + return; + } else if (clientIp == null) { + LOGGER.error("Client IP is unexpectedly null."); + return; + } + + HttpHeaders headers = new HttpHeaders(); + headers.add(HttpHeaders.AUTHORIZATION, "pre-shared: " + this.gotifyApiKey); + headers.setContentType(MediaType.APPLICATION_JSON); + + record Request(String to, String from, String subject, String body) {} + + Request request = new Request(email, "no-reply@chalmers.it", subject, body); + + HttpEntity entity = new HttpEntity<>(request, headers); + RestTemplate restTemplate = new RestTemplate(); + try { + restTemplate.postForEntity(this.gotifyURL + "/mail", entity, String.class); + } catch (RestClientException e) { + LOGGER.error(e.getMessage()); + } + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/redis/oauth2/AuthorizationRedisRepository.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/redis/oauth2/AuthorizationRedisRepository.java new file mode 100644 index 000000000..1a8022266 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/redis/oauth2/AuthorizationRedisRepository.java @@ -0,0 +1,7 @@ +package it.chalmers.gamma.adapter.secondary.redis.oauth2; + +import org.springframework.data.repository.CrudRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface AuthorizationRedisRepository extends CrudRepository {} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/redis/oauth2/AuthorizationRepositoryAdapter.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/redis/oauth2/AuthorizationRepositoryAdapter.java new file mode 100644 index 000000000..eab5a7744 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/redis/oauth2/AuthorizationRepositoryAdapter.java @@ -0,0 +1,84 @@ +package it.chalmers.gamma.adapter.secondary.redis.oauth2; + +import it.chalmers.gamma.app.oauth2.domain.GammaAuthorizationRepository; +import it.chalmers.gamma.app.oauth2.domain.GammaAuthorizationToken; +import java.util.Optional; +import org.springframework.security.oauth2.core.OAuth2AccessToken; +import org.springframework.security.oauth2.core.oidc.OidcIdToken; +import org.springframework.security.oauth2.server.authorization.OAuth2Authorization; +import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationCode; +import org.springframework.stereotype.Component; + +@Component +public class AuthorizationRepositoryAdapter implements GammaAuthorizationRepository { + + private final AuthorizationRedisRepository authorizationRedisRepository; + private final AuthorizationTokenMapperRedisRepository authorizationTokenMapperRedisRepository; + + public AuthorizationRepositoryAdapter( + AuthorizationRedisRepository authorizationRedisRepository, + AuthorizationTokenMapperRedisRepository authorizationTokenMapperRedisRepository) { + this.authorizationRedisRepository = authorizationRedisRepository; + this.authorizationTokenMapperRedisRepository = authorizationTokenMapperRedisRepository; + } + + @Override + public void save(OAuth2Authorization authorization) { + this.authorizationRedisRepository.save(new AuthorizationValue(authorization)); + + var code = authorization.getToken(OAuth2AuthorizationCode.class); + if (code != null) { + this.authorizationTokenMapperRedisRepository.save( + new AuthorizationTokenMapperValue( + authorization.getId(), "code", code.getToken().getTokenValue())); + } + + var accessToken = authorization.getToken(OAuth2AccessToken.class); + if (accessToken != null) { + this.authorizationTokenMapperRedisRepository.save( + new AuthorizationTokenMapperValue( + authorization.getId(), "access_token", accessToken.getToken().getTokenValue())); + } + + var state = authorization.getAttribute("state"); + if (state != null) { + this.authorizationTokenMapperRedisRepository.save( + new AuthorizationTokenMapperValue(authorization.getId(), "state", state.toString())); + } + + var oidcToken = authorization.getToken(OidcIdToken.class); + if (oidcToken != null) { + this.authorizationTokenMapperRedisRepository.save( + new AuthorizationTokenMapperValue( + authorization.getId(), "oidc", oidcToken.getToken().getTokenValue())); + } + } + + @Override + public void remove(OAuth2Authorization authorization) { + this.authorizationRedisRepository.save(new AuthorizationValue(authorization)); + } + + @Override + public Optional findById(String id) { + return this.authorizationRedisRepository + .findById(id) + .map(AuthorizationValue::toOAuth2Authorization); + } + + @Override + public Optional findByToken( + GammaAuthorizationToken gammaAuthorizationToken) { + String token = + gammaAuthorizationToken.type().name().toLowerCase() + ":" + gammaAuthorizationToken.value(); + Optional maybeTokenMapper = + this.authorizationTokenMapperRedisRepository.findById(token); + if (maybeTokenMapper.isPresent()) { + Optional maybeAuthorizationValue = + this.authorizationRedisRepository.findById(maybeTokenMapper.get().authorizationKey); + return maybeAuthorizationValue.map(AuthorizationValue::toOAuth2Authorization); + } + + return Optional.empty(); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/redis/oauth2/AuthorizationTokenMapperRedisRepository.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/redis/oauth2/AuthorizationTokenMapperRedisRepository.java new file mode 100644 index 000000000..82ed4cb36 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/redis/oauth2/AuthorizationTokenMapperRedisRepository.java @@ -0,0 +1,8 @@ +package it.chalmers.gamma.adapter.secondary.redis.oauth2; + +import org.springframework.data.repository.CrudRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface AuthorizationTokenMapperRedisRepository + extends CrudRepository {} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/redis/oauth2/AuthorizationTokenMapperValue.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/redis/oauth2/AuthorizationTokenMapperValue.java new file mode 100644 index 000000000..508046066 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/redis/oauth2/AuthorizationTokenMapperValue.java @@ -0,0 +1,19 @@ +package it.chalmers.gamma.adapter.secondary.redis.oauth2; + +import org.springframework.data.annotation.Id; +import org.springframework.data.redis.core.RedisHash; + +@RedisHash(value = "rawToken", timeToLive = 3600) +public class AuthorizationTokenMapperValue { + + @Id String tokenKey; + + String authorizationKey; + + public AuthorizationTokenMapperValue() {} + + public AuthorizationTokenMapperValue(String authorizationKey, String type, String token) { + this.tokenKey = type + ":" + token; + this.authorizationKey = authorizationKey; + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/redis/oauth2/AuthorizationValue.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/redis/oauth2/AuthorizationValue.java new file mode 100644 index 000000000..a27b77431 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/redis/oauth2/AuthorizationValue.java @@ -0,0 +1,32 @@ +package it.chalmers.gamma.adapter.secondary.redis.oauth2; + +import java.io.IOException; +import org.springframework.data.annotation.Id; +import org.springframework.data.redis.core.RedisHash; +import org.springframework.security.oauth2.server.authorization.OAuth2Authorization; + +@RedisHash(value = "gamma-authorization", timeToLive = 3600) +public class AuthorizationValue { + + @Id String id; + String authorization; + + public AuthorizationValue() {} + + public AuthorizationValue(OAuth2Authorization authorization) { + this.id = authorization.getId(); + try { + this.authorization = Serializer.toString(authorization); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public OAuth2Authorization toOAuth2Authorization() { + try { + return (OAuth2Authorization) Serializer.fromString(this.authorization); + } catch (IOException | ClassNotFoundException e) { + throw new RuntimeException(e); + } + } +} diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/redis/oauth2/Serializer.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/redis/oauth2/Serializer.java new file mode 100644 index 000000000..eb77348f3 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/redis/oauth2/Serializer.java @@ -0,0 +1,25 @@ +package it.chalmers.gamma.adapter.secondary.redis.oauth2; + +import java.io.*; +import java.util.Base64; + +public final class Serializer { + + private Serializer() {} + + public static Object fromString(String s) throws IOException, ClassNotFoundException { + byte[] data = Base64.getDecoder().decode(s); + ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(data)); + Object o = ois.readObject(); + ois.close(); + return o; + } + + public static String toString(Serializable o) throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(baos); + oos.writeObject(o); + oos.close(); + return Base64.getEncoder().encodeToString(baos.toByteArray()); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/app/Facade.java b/app/src/main/java/it/chalmers/gamma/app/Facade.java new file mode 100644 index 000000000..e289d3d1d --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/Facade.java @@ -0,0 +1,12 @@ +package it.chalmers.gamma.app; + +import it.chalmers.gamma.app.authentication.AccessGuard; + +public abstract class Facade { + + protected AccessGuard accessGuard; + + public Facade(AccessGuard accessGuard) { + this.accessGuard = accessGuard; + } +} diff --git a/app/src/main/java/it/chalmers/gamma/app/Tokens.java b/app/src/main/java/it/chalmers/gamma/app/Tokens.java new file mode 100644 index 000000000..8d3ea2bbb --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/Tokens.java @@ -0,0 +1,37 @@ +package it.chalmers.gamma.app; + +import java.security.SecureRandom; +import java.util.Arrays; +import java.util.stream.Collectors; + +public final class Tokens { + + private Tokens() {} + + public static String generate(int length, CharacterTypes... types) { + String characters = + Arrays.stream(types).map(CharacterTypes::getCharacters).collect(Collectors.joining()); + SecureRandom rand = new SecureRandom(); + StringBuilder code = new StringBuilder(); + for (int i = 0; i < length; i++) { + code.append(characters.charAt(rand.nextInt(characters.length()))); + } + return code.toString(); + } + + public enum CharacterTypes { + UPPERCASE("ABCDEFGHIJKLMNOPQRSTUVWXYZ"), + LOWERCASE("abcdefghijklmnopqrstuvwxyz"), + NUMBERS("123456789"); + + private final String characters; + + CharacterTypes(String characters) { + this.characters = characters; + } + + public String getCharacters() { + return this.characters; + } + } +} diff --git a/app/src/main/java/it/chalmers/gamma/app/UnexpectedRuntimeException.java b/app/src/main/java/it/chalmers/gamma/app/UnexpectedRuntimeException.java new file mode 100644 index 000000000..3d9aeb7c6 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/UnexpectedRuntimeException.java @@ -0,0 +1,3 @@ +package it.chalmers.gamma.app; + +public class UnexpectedRuntimeException extends RuntimeException {} diff --git a/app/src/main/java/it/chalmers/gamma/app/accountscaffold/AccountScaffoldFacade.java b/app/src/main/java/it/chalmers/gamma/app/accountscaffold/AccountScaffoldFacade.java new file mode 100644 index 000000000..02760e8ef --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/accountscaffold/AccountScaffoldFacade.java @@ -0,0 +1,166 @@ +package it.chalmers.gamma.app.accountscaffold; + +import static it.chalmers.gamma.app.authentication.AccessGuard.isApi; + +import it.chalmers.gamma.app.Facade; +import it.chalmers.gamma.app.apikey.domain.ApiKeyType; +import it.chalmers.gamma.app.apikey.domain.settings.ApiKeyAccountScaffoldSettings; +import it.chalmers.gamma.app.apikey.domain.settings.ApiKeySettingsRepository; +import it.chalmers.gamma.app.authentication.AccessGuard; +import it.chalmers.gamma.app.group.domain.GroupMember; +import it.chalmers.gamma.app.group.domain.GroupRepository; +import it.chalmers.gamma.app.post.domain.Post; +import it.chalmers.gamma.app.supergroup.domain.SuperGroup; +import it.chalmers.gamma.app.supergroup.domain.SuperGroupId; +import it.chalmers.gamma.app.user.domain.GammaUser; +import it.chalmers.gamma.app.user.domain.UserId; +import it.chalmers.gamma.app.user.gdpr.GdprTrainedRepository; +import it.chalmers.gamma.security.authentication.ApiAuthentication; +import it.chalmers.gamma.security.authentication.AuthenticationExtractor; +import java.util.*; +import org.springframework.stereotype.Service; + +@Service +public class AccountScaffoldFacade extends Facade { + + private final GroupRepository groupRepository; + private final GdprTrainedRepository gdprTrainedRepository; + private final ApiKeySettingsRepository apiKeySettingsRepository; + + public AccountScaffoldFacade( + AccessGuard accessGuard, + GroupRepository groupRepository, + GdprTrainedRepository gdprTrainedRepository, + ApiKeySettingsRepository apiKeySettingsRepository) { + super(accessGuard); + this.groupRepository = groupRepository; + this.gdprTrainedRepository = gdprTrainedRepository; + this.apiKeySettingsRepository = apiKeySettingsRepository; + } + + /** + * Get all super groups that have the provided types and members that are a part of groups that + * has each supergroup + */ + public List getActiveSuperGroups() { + this.accessGuard.require(isApi(ApiKeyType.ACCOUNT_SCAFFOLD)); + + List gdprTrained = this.gdprTrainedRepository.getAll(); + Map superGroupMap = new HashMap<>(); + + ApiAuthentication apiAuthentication = + (ApiAuthentication) AuthenticationExtractor.getAuthentication(); + ApiKeyAccountScaffoldSettings settings = + this.apiKeySettingsRepository.getAccountScaffoldSettings(apiAuthentication.get().id()); + + this.groupRepository.getAll().stream() + .filter(group -> settings.superGroupTypes().contains(group.superGroup().type())) + .forEach( + group -> { + List activeGroupMember = + group.groupMembers().stream() + .filter(groupMember -> !groupMember.user().extended().locked()) + .filter(groupMember -> gdprTrained.contains(groupMember.user().id())) + .map(AccountScaffoldUserPostDTO::new) + .toList(); + + SuperGroupId superGroupId = group.superGroup().id(); + if (!superGroupMap.containsKey(superGroupId)) { + superGroupMap.put( + superGroupId, + new SuperGroupWithMembers( + group.superGroup(), new HashSet<>(activeGroupMember))); + } else { + superGroupMap.get(superGroupId).members.addAll(activeGroupMember); + } + }); + + return superGroupMap.values().stream() + .map( + superGroupWithMembers -> + new AccountScaffoldSuperGroupDTO( + superGroupWithMembers.superGroup, + new ArrayList<>(superGroupWithMembers.members))) + .toList(); + } + + /** + * Returns the users that are active right now. Takes in a list of super group types to help + * determine what kinds of groups that are deemed active. User must also be not locked, and have + * participated in gdpr training. + */ + public List getActiveUsers() { + this.accessGuard.require(isApi(ApiKeyType.ACCOUNT_SCAFFOLD)); + + List gdprTrained = this.gdprTrainedRepository.getAll(); + + ApiAuthentication apiAuthentication = + (ApiAuthentication) AuthenticationExtractor.getAuthentication(); + ApiKeyAccountScaffoldSettings settings = + this.apiKeySettingsRepository.getAccountScaffoldSettings(apiAuthentication.get().id()); + + return this.groupRepository.getAll().stream() + .filter(group -> settings.superGroupTypes().contains(group.superGroup().type())) + .flatMap(group -> group.groupMembers().stream()) + .map(GroupMember::user) + .distinct() + .filter(user -> !user.extended().locked()) + .filter(groupMember -> gdprTrained.contains(groupMember.id())) + .map(AccountScaffoldUserDTO::new) + .toList(); + } + + public record AccountScaffoldPostDTO( + UUID postId, String svText, String enText, String emailPrefix) { + public AccountScaffoldPostDTO(Post post) { + this( + post.id().value(), + post.name().sv().value(), + post.name().en().value(), + post.emailPrefix().value()); + } + } + + public record AccountScaffoldUserPostDTO( + AccountScaffoldPostDTO post, AccountScaffoldUserDTO user) { + public AccountScaffoldUserPostDTO(GroupMember groupMember) { + this( + new AccountScaffoldPostDTO(groupMember.post()), + new AccountScaffoldUserDTO(groupMember.user())); + } + } + + public record AccountScaffoldUserDTO( + String email, String cid, String firstName, String lastName, String nick) { + public AccountScaffoldUserDTO(GammaUser user) { + this( + user.extended().email().value(), + user.cid().value(), + user.firstName().value(), + user.lastName().value(), + user.nick().value()); + } + } + + public record AccountScaffoldSuperGroupDTO( + String name, String prettyName, String type, List members) { + public AccountScaffoldSuperGroupDTO( + SuperGroup superGroup, List members) { + this( + superGroup.name().value(), + superGroup.prettyName().value(), + superGroup.type().value(), + members); + } + } + + private static class SuperGroupWithMembers { + private final SuperGroup superGroup; + private final Set members; + + private SuperGroupWithMembers(SuperGroup superGroup, Set members) { + this.superGroup = superGroup; + this.members = members; + } + } +} diff --git a/app/src/main/java/it/chalmers/gamma/app/admin/AdminFacade.java b/app/src/main/java/it/chalmers/gamma/app/admin/AdminFacade.java new file mode 100644 index 000000000..cf16ef139 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/admin/AdminFacade.java @@ -0,0 +1,44 @@ +package it.chalmers.gamma.app.admin; + +import static it.chalmers.gamma.app.authentication.AccessGuard.isAdmin; + +import it.chalmers.gamma.app.Facade; +import it.chalmers.gamma.app.admin.domain.AdminRepository; +import it.chalmers.gamma.app.authentication.AccessGuard; +import it.chalmers.gamma.app.user.domain.UserId; +import java.util.List; +import java.util.UUID; +import org.springframework.stereotype.Component; + +@Component +public class AdminFacade extends Facade { + + private final AdminRepository adminRepository; + + public AdminFacade(AccessGuard accessGuard, AdminRepository adminRepository) { + super(accessGuard); + this.adminRepository = adminRepository; + } + + public void updateAdmins(List newAdmins, List adminsToRemove) { + accessGuard.require(isAdmin()); + + if (newAdmins.isEmpty()) { + throw new IllegalArgumentException("There must be at least one admin"); + } + + for (UUID userId : newAdmins) { + this.adminRepository.setAdmin(new UserId(userId), true); + } + + for (UUID userId : adminsToRemove) { + this.adminRepository.setAdmin(new UserId(userId), false); + } + } + + public List getAllAdmins() { + accessGuard.require(isAdmin()); + + return this.adminRepository.getAll().stream().map(UserId::value).toList(); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/app/admin/domain/AdminRepository.java b/app/src/main/java/it/chalmers/gamma/app/admin/domain/AdminRepository.java new file mode 100644 index 000000000..f00905396 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/admin/domain/AdminRepository.java @@ -0,0 +1,13 @@ +package it.chalmers.gamma.app.admin.domain; + +import it.chalmers.gamma.app.user.domain.UserId; +import java.util.List; + +public interface AdminRepository { + + boolean isAdmin(UserId userId); + + void setAdmin(UserId userId, boolean admin); + + List getAll(); +} diff --git a/app/src/main/java/it/chalmers/gamma/app/apikey/ApiKeyFacade.java b/app/src/main/java/it/chalmers/gamma/app/apikey/ApiKeyFacade.java new file mode 100644 index 000000000..4a96bcded --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/apikey/ApiKeyFacade.java @@ -0,0 +1,133 @@ +package it.chalmers.gamma.app.apikey; + +import static it.chalmers.gamma.app.authentication.AccessGuard.*; + +import it.chalmers.gamma.app.Facade; +import it.chalmers.gamma.app.apikey.domain.*; +import it.chalmers.gamma.app.apikey.domain.settings.ApiKeySettingsRepository; +import it.chalmers.gamma.app.authentication.AccessGuard; +import it.chalmers.gamma.app.common.PrettyName; +import it.chalmers.gamma.app.common.Text; +import jakarta.transaction.Transactional; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; +import java.util.UUID; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Component; + +@Component +public class ApiKeyFacade extends Facade { + + private final ApiKeyRepository apiKeyRepository; + private final ApiKeySettingsRepository apiKeySettingsRepository; + private final PasswordEncoder passwordEncoder; + + public ApiKeyFacade( + AccessGuard accessGuard, + ApiKeyRepository apiKeyRepository, + ApiKeySettingsRepository apiKeySettingsRepository, + PasswordEncoder passwordEncoder) { + super(accessGuard); + this.apiKeyRepository = apiKeyRepository; + this.apiKeySettingsRepository = apiKeySettingsRepository; + this.passwordEncoder = passwordEncoder; + } + + public String[] getApiKeyTypes() { + List types = + Arrays.stream(ApiKeyType.values()) + .filter(apiKeyType -> apiKeyType != ApiKeyType.CLIENT) + .toList(); + String[] s = new String[types.size()]; + for (int i = 0; i < s.length; i++) { + s[i] = types.get(i).name(); + } + return s; + } + + public record CreatedApiKey(ApiKeyDTO apiKey, String token) {} + + @Transactional + public CreatedApiKey create(NewApiKey newApiKey) { + this.accessGuard.requireEither(isAdmin(), isLocalRunner()); + + ApiKeyType type = ApiKeyType.valueOf(newApiKey.keyType); + + if (type == ApiKeyType.CLIENT) { + throw new IllegalArgumentException( + "Cannot create api key with type client without creating a client at the same time"); + } + + ApiKeyId apiKeyId = ApiKeyId.generate(); + ApiKeyToken.GeneratedApiKeyToken generated = ApiKeyToken.generate(passwordEncoder); + ApiKey apiKey = + new ApiKey( + apiKeyId, + new PrettyName(newApiKey.prettyName), + new Text(newApiKey.svDescription, newApiKey.enDescription), + type, + generated.apiKeyToken()); + + apiKeyRepository.create(apiKey); + + if (type == ApiKeyType.INFO) { + this.apiKeySettingsRepository.createEmptyInfoSettings(apiKeyId); + } else if (type == ApiKeyType.ACCOUNT_SCAFFOLD) { + this.apiKeySettingsRepository.createEmptyAccountScaffoldSettings(apiKeyId); + } + + return new CreatedApiKey(new ApiKeyDTO(apiKey), generated.rawToken()); + } + + public void delete(UUID apiKeyId) throws ApiKeyNotFoundException { + this.accessGuard.require(isAdmin()); + + try { + apiKeyRepository.delete(new ApiKeyId(apiKeyId)); + } catch (ApiKeyRepository.ApiKeyNotFoundException e) { + throw new ApiKeyNotFoundException(); + } + } + + public Optional getById(UUID apiKeyId) { + ApiKeyId id = new ApiKeyId(apiKeyId); + + this.accessGuard.requireEither(isAdmin(), ownerOfClientApi(id)); + + return this.apiKeyRepository.getById(id).map(ApiKeyDTO::new); + } + + public List getAll() { + this.accessGuard.requireEither(isAdmin(), isLocalRunner()); + + return this.apiKeyRepository.getAll().stream().map(ApiKeyDTO::new).toList(); + } + + public String resetApiKey(UUID apiKeyId) { + this.accessGuard.require(isAdmin()); + + ApiKeyId id = new ApiKeyId(apiKeyId); + ApiKeyToken.GeneratedApiKeyToken generated = ApiKeyToken.generate(passwordEncoder); + this.apiKeyRepository.setNewGeneratedToken(id, generated.apiKeyToken()); + + return generated.rawToken(); + } + + public record NewApiKey( + String prettyName, String svDescription, String enDescription, String keyType) {} + + public record ApiKeyDTO( + UUID id, String prettyName, String svDescription, String enDescription, String keyType) { + public ApiKeyDTO(ApiKey apiKey) { + this( + apiKey.id().value(), + apiKey.prettyName().value(), + apiKey.description().sv().value(), + apiKey.description().en().value(), + apiKey.keyType().name()); + } + } + + public static class ApiKeyNotFoundException extends Exception {} +} diff --git a/app/src/main/java/it/chalmers/gamma/app/apikey/ApiKeySettingsFacade.java b/app/src/main/java/it/chalmers/gamma/app/apikey/ApiKeySettingsFacade.java new file mode 100644 index 000000000..0c712a56f --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/apikey/ApiKeySettingsFacade.java @@ -0,0 +1,74 @@ +package it.chalmers.gamma.app.apikey; + +import static it.chalmers.gamma.app.authentication.AccessGuard.isAdmin; +import static it.chalmers.gamma.app.authentication.AccessGuard.isSpecificApi; + +import it.chalmers.gamma.app.Facade; +import it.chalmers.gamma.app.apikey.domain.ApiKeyId; +import it.chalmers.gamma.app.apikey.domain.settings.ApiKeyAccountScaffoldSettings; +import it.chalmers.gamma.app.apikey.domain.settings.ApiKeyInfoSettings; +import it.chalmers.gamma.app.apikey.domain.settings.ApiKeySettingsRepository; +import it.chalmers.gamma.app.authentication.AccessGuard; +import it.chalmers.gamma.app.supergroup.domain.SuperGroupType; +import java.util.List; +import java.util.UUID; +import org.springframework.stereotype.Component; + +@Component +public class ApiKeySettingsFacade extends Facade { + + private final ApiKeySettingsRepository apiKeySettingsRepository; + + public ApiKeySettingsFacade( + AccessGuard accessGuard, ApiKeySettingsRepository apiKeySettingsRepository) { + super(accessGuard); + this.apiKeySettingsRepository = apiKeySettingsRepository; + } + + public record ApiKeySettingsInfoDTO(int version, List superGroupTypes) {} + + public ApiKeySettingsInfoDTO getInfoSettings(UUID apiKeyId) { + ApiKeyId id = new ApiKeyId(apiKeyId); + + accessGuard.requireEither(isAdmin(), isSpecificApi(id)); + + ApiKeyInfoSettings infoSettings = this.apiKeySettingsRepository.getInfoSettings(id); + + return new ApiKeySettingsInfoDTO( + infoSettings.version(), + infoSettings.superGroupTypes().stream().map(SuperGroupType::value).toList()); + } + + public void setInfoSettings(UUID apiKeyId, ApiKeySettingsInfoDTO settings) { + accessGuard.require(isAdmin()); + + this.apiKeySettingsRepository.setInfoSettings( + new ApiKeyId(apiKeyId), + new ApiKeyInfoSettings( + settings.version, settings.superGroupTypes.stream().map(SuperGroupType::new).toList())); + } + + public record ApiKeySettingsAccountScaffoldDTO(int version, List superGroupTypes) {} + + public ApiKeySettingsAccountScaffoldDTO getAccountScaffoldSettings(UUID apiKeyId) { + ApiKeyId id = new ApiKeyId(apiKeyId); + + accessGuard.requireEither(isAdmin(), isSpecificApi(id)); + + ApiKeyAccountScaffoldSettings accountScaffoldSettings = + this.apiKeySettingsRepository.getAccountScaffoldSettings(id); + + return new ApiKeySettingsAccountScaffoldDTO( + accountScaffoldSettings.version(), + accountScaffoldSettings.superGroupTypes().stream().map(SuperGroupType::value).toList()); + } + + public void setAccountScaffoldSettings(UUID apiKeyId, ApiKeySettingsAccountScaffoldDTO settings) { + accessGuard.require(isAdmin()); + + this.apiKeySettingsRepository.setAccountScaffoldSettings( + new ApiKeyId(apiKeyId), + new ApiKeyAccountScaffoldSettings( + settings.version, settings.superGroupTypes.stream().map(SuperGroupType::new).toList())); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/app/apikey/domain/ApiKey.java b/app/src/main/java/it/chalmers/gamma/app/apikey/domain/ApiKey.java new file mode 100644 index 000000000..2d18e92ca --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/apikey/domain/ApiKey.java @@ -0,0 +1,23 @@ +package it.chalmers.gamma.app.apikey.domain; + +import io.soabase.recordbuilder.core.RecordBuilder; +import it.chalmers.gamma.app.common.PrettyName; +import it.chalmers.gamma.app.common.Text; +import java.util.Objects; + +@RecordBuilder +public record ApiKey( + ApiKeyId id, + PrettyName prettyName, + Text description, + ApiKeyType keyType, + ApiKeyToken apiKeyToken) + implements ApiKeyBuilder.With { + public ApiKey { + Objects.requireNonNull(id); + Objects.requireNonNull(prettyName); + Objects.requireNonNull(description); + Objects.requireNonNull(keyType); + Objects.requireNonNull(apiKeyToken); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/app/apikey/domain/ApiKeyId.java b/app/src/main/java/it/chalmers/gamma/app/apikey/domain/ApiKeyId.java new file mode 100644 index 000000000..96181d534 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/apikey/domain/ApiKeyId.java @@ -0,0 +1,25 @@ +package it.chalmers.gamma.app.apikey.domain; + +import it.chalmers.gamma.app.common.Id; +import java.util.Objects; +import java.util.UUID; + +public record ApiKeyId(UUID value) implements Id { + + public ApiKeyId { + Objects.requireNonNull(value); + } + + public ApiKeyId(String value) { + this(UUID.fromString(value)); + } + + public static ApiKeyId generate() { + return new ApiKeyId(UUID.randomUUID()); + } + + @Override + public UUID getValue() { + return this.value; + } +} diff --git a/app/src/main/java/it/chalmers/gamma/app/apikey/domain/ApiKeyRepository.java b/app/src/main/java/it/chalmers/gamma/app/apikey/domain/ApiKeyRepository.java new file mode 100644 index 000000000..9c938e8ab --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/apikey/domain/ApiKeyRepository.java @@ -0,0 +1,25 @@ +package it.chalmers.gamma.app.apikey.domain; + +import java.util.List; +import java.util.Optional; + +public interface ApiKeyRepository { + + void create(ApiKey apiKey) throws ApiKeyAlreadyExistRuntimeException; + + void delete(ApiKeyId apiKeyId) throws ApiKeyNotFoundException; + + List getAll(); + + Optional getById(ApiKeyId apiKeyId); + + void setNewGeneratedToken(ApiKeyId apiKeyId, ApiKeyToken apiKeyToken); + + class ApiKeyNotFoundException extends Exception {} + + /** + * Either the api key id or rawToken already exists. Runtime exception since id and rawToken is + * generated. + */ + class ApiKeyAlreadyExistRuntimeException extends RuntimeException {} +} diff --git a/app/src/main/java/it/chalmers/gamma/app/apikey/domain/ApiKeyToken.java b/app/src/main/java/it/chalmers/gamma/app/apikey/domain/ApiKeyToken.java new file mode 100644 index 000000000..ed5ecefdd --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/apikey/domain/ApiKeyToken.java @@ -0,0 +1,36 @@ +package it.chalmers.gamma.app.apikey.domain; + +import it.chalmers.gamma.app.Tokens; +import java.util.Objects; +import java.util.regex.Pattern; +import org.springframework.security.crypto.password.PasswordEncoder; + +public record ApiKeyToken(String value) { + + private static final Pattern apiKeyTokenStartPattern = Pattern.compile("^\\{bcrypt}.+"); + + public ApiKeyToken { + Objects.requireNonNull(value); + + if (!apiKeyTokenStartPattern.matcher(value).matches()) { + throw new IllegalArgumentException("Api key rawToken not encrypted properly"); + } + } + + public record GeneratedApiKeyToken(ApiKeyToken apiKeyToken, String rawToken) {} + + public static GeneratedApiKeyToken generate(PasswordEncoder passwordEncoder) { + String value = + Tokens.generate( + 32, + Tokens.CharacterTypes.LOWERCASE, + Tokens.CharacterTypes.UPPERCASE, + Tokens.CharacterTypes.NUMBERS); + return new GeneratedApiKeyToken(new ApiKeyToken(passwordEncoder.encode(value)), value); + } + + @Override + public String toString() { + return ""; + } +} diff --git a/app/src/main/java/it/chalmers/gamma/app/apikey/domain/ApiKeyType.java b/app/src/main/java/it/chalmers/gamma/app/apikey/domain/ApiKeyType.java new file mode 100644 index 000000000..bd9c399dc --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/apikey/domain/ApiKeyType.java @@ -0,0 +1,19 @@ +package it.chalmers.gamma.app.apikey.domain; + +import it.chalmers.gamma.adapter.primary.api.accountscaffold.AccountScaffoldV1ApiController; +import it.chalmers.gamma.adapter.primary.api.allowlist.AllowListV1ApiController; +import it.chalmers.gamma.adapter.primary.api.client.ClientApiV1Controller; +import it.chalmers.gamma.adapter.primary.api.info.InfoV1ApiController; + +public enum ApiKeyType { + CLIENT(ClientApiV1Controller.URI), + ACCOUNT_SCAFFOLD(AccountScaffoldV1ApiController.URI), + INFO(InfoV1ApiController.URI), + ALLOW_LIST(AllowListV1ApiController.URI); + + public final String URI; + + ApiKeyType(String uri) { + this.URI = uri; + } +} diff --git a/app/src/main/java/it/chalmers/gamma/app/apikey/domain/settings/ApiKeyAccountScaffoldSettings.java b/app/src/main/java/it/chalmers/gamma/app/apikey/domain/settings/ApiKeyAccountScaffoldSettings.java new file mode 100644 index 000000000..47d7313fb --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/apikey/domain/settings/ApiKeyAccountScaffoldSettings.java @@ -0,0 +1,6 @@ +package it.chalmers.gamma.app.apikey.domain.settings; + +import it.chalmers.gamma.app.supergroup.domain.SuperGroupType; +import java.util.List; + +public record ApiKeyAccountScaffoldSettings(int version, List superGroupTypes) {} diff --git a/app/src/main/java/it/chalmers/gamma/app/apikey/domain/settings/ApiKeyInfoSettings.java b/app/src/main/java/it/chalmers/gamma/app/apikey/domain/settings/ApiKeyInfoSettings.java new file mode 100644 index 000000000..2f88a62cd --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/apikey/domain/settings/ApiKeyInfoSettings.java @@ -0,0 +1,6 @@ +package it.chalmers.gamma.app.apikey.domain.settings; + +import it.chalmers.gamma.app.supergroup.domain.SuperGroupType; +import java.util.List; + +public record ApiKeyInfoSettings(int version, List superGroupTypes) {} diff --git a/app/src/main/java/it/chalmers/gamma/app/apikey/domain/settings/ApiKeySettingsRepository.java b/app/src/main/java/it/chalmers/gamma/app/apikey/domain/settings/ApiKeySettingsRepository.java new file mode 100644 index 000000000..800b5c585 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/apikey/domain/settings/ApiKeySettingsRepository.java @@ -0,0 +1,17 @@ +package it.chalmers.gamma.app.apikey.domain.settings; + +import it.chalmers.gamma.app.apikey.domain.ApiKeyId; + +public interface ApiKeySettingsRepository { + void createEmptyAccountScaffoldSettings(ApiKeyId apiKeyId); + + void createEmptyInfoSettings(ApiKeyId apiKeyId); + + ApiKeyAccountScaffoldSettings getAccountScaffoldSettings(ApiKeyId apiKeyId); + + ApiKeyInfoSettings getInfoSettings(ApiKeyId apiKeyId); + + void setAccountScaffoldSettings(ApiKeyId apiKeyId, ApiKeyAccountScaffoldSettings settings); + + void setInfoSettings(ApiKeyId apiKeyId, ApiKeyInfoSettings settings); +} diff --git a/app/src/main/java/it/chalmers/gamma/app/authentication/AccessGuard.java b/app/src/main/java/it/chalmers/gamma/app/authentication/AccessGuard.java new file mode 100644 index 000000000..78c11581a --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/authentication/AccessGuard.java @@ -0,0 +1,213 @@ +package it.chalmers.gamma.app.authentication; + +import it.chalmers.gamma.app.apikey.domain.ApiKeyId; +import it.chalmers.gamma.app.apikey.domain.ApiKeyType; +import it.chalmers.gamma.app.client.domain.*; +import it.chalmers.gamma.app.group.domain.Group; +import it.chalmers.gamma.app.user.domain.GammaUser; +import it.chalmers.gamma.app.user.domain.UnencryptedPassword; +import it.chalmers.gamma.app.user.domain.UserId; +import it.chalmers.gamma.app.user.domain.UserRepository; +import it.chalmers.gamma.security.authentication.ApiAuthentication; +import it.chalmers.gamma.security.authentication.AuthenticationExtractor; +import it.chalmers.gamma.security.authentication.LocalRunnerAuthentication; +import it.chalmers.gamma.security.authentication.UserAuthentication; +import java.util.Optional; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; + +@Service +public class AccessGuard { + + private static final Logger LOGGER = LoggerFactory.getLogger(AccessGuard.class); + + private final UserRepository userRepository; + private final ClientRepository clientRepository; + + public AccessGuard(UserRepository userRepository, ClientRepository clientRepository) { + this.userRepository = userRepository; + this.clientRepository = clientRepository; + } + + public static AccessChecker isAdmin() { + return (clientRepository, userRepository) -> { + if (AuthenticationExtractor.getAuthentication() + instanceof UserAuthentication userAuthenticated) { + return userAuthenticated.isAdmin(); + } + + return false; + }; + } + + public static AccessChecker isMe(UserId userId) { + return (clientRepository, userRepository) -> { + if (AuthenticationExtractor.getAuthentication() + instanceof UserAuthentication userAuthenticated) { + return userAuthenticated.gammaUser().id().equals(userId); + } + + return false; + }; + } + + public static AccessChecker passwordCheck(String password) { + return (clientRepository, userRepository) -> { + if (AuthenticationExtractor.getAuthentication() + instanceof UserAuthentication userAuthenticated) { + GammaUser user = userAuthenticated.gammaUser(); + return userRepository.checkPassword(user.id(), new UnencryptedPassword(password)); + } + + return false; + }; + } + + public static AccessChecker isApi(ApiKeyType apiKeyType) { + return (clientRepository, userRepository) -> { + if (AuthenticationExtractor.getAuthentication() instanceof ApiAuthentication apiPrincipal) { + return apiPrincipal.get().keyType() == apiKeyType; + } + + return false; + }; + } + + public static AccessChecker isClientApi() { + return (clientRepository, userRepository) -> { + if (AuthenticationExtractor.getAuthentication() instanceof ApiAuthentication apiPrincipal) { + return apiPrincipal.get().keyType() == ApiKeyType.CLIENT; + } + + return false; + }; + } + + public static AccessChecker isSpecificApi(ApiKeyId apiKeyId) { + return (clientRepository, userRepository) -> { + if (AuthenticationExtractor.getAuthentication() instanceof ApiAuthentication apiPrincipal) { + return apiPrincipal.get().id().equals(apiKeyId); + } + + return false; + }; + } + + public static AccessChecker isSignedInUserMemberOfGroup(Group group) { + return (clientRepository, userRepository) -> { + if (AuthenticationExtractor.getAuthentication() instanceof UserAuthentication userPrincipal) { + GammaUser user = userPrincipal.gammaUser(); + return group.groupMembers().stream() + .anyMatch(groupMember -> groupMember.user().equals(user)); + } + + return false; + }; + } + + public static AccessChecker isSignedIn() { + return (clientRepository, userRepository) -> + AuthenticationExtractor.getAuthentication() instanceof UserAuthentication; + } + + public static AccessChecker isNotSignedIn() { + return (clientRepository, userRepository) -> + AuthenticationExtractor.getAuthentication() == null; + } + + public static AccessChecker userHasAcceptedClient(UserId id) { + return (clientRepository, userRepository) -> { + if (AuthenticationExtractor.getAuthentication() instanceof ApiAuthentication apiPrincipal) { + if (apiPrincipal.getClient().isPresent()) { + Client client = apiPrincipal.getClient().get(); + return clientRepository.isApprovedByUser(id, client.clientUid()); + } + } + + return false; + }; + } + + public static AccessChecker ownerOfClient(ClientUid clientUid) { + return (clientRepository, userRepository) -> { + if (AuthenticationExtractor.getAuthentication() instanceof UserAuthentication userPrincipal) { + Optional client = clientRepository.get(clientUid); + + if (client.isPresent()) { + ClientOwner clientOwner = client.get().owner(); + + if (clientOwner instanceof ClientUserOwner(UserId userId)) { + return userId.equals(userPrincipal.gammaUser().id()); + } + } + } + + return false; + }; + } + + public static AccessChecker ownerOfClientApi(ApiKeyId apiKeyId) { + return (clientRepository, userRepository) -> { + if (AuthenticationExtractor.getAuthentication() instanceof UserAuthentication userPrincipal) { + Optional client = clientRepository.getByApiKey(apiKeyId); + + if (client.isPresent()) { + ClientOwner clientOwner = client.get().owner(); + + if (clientOwner instanceof ClientUserOwner(UserId userId)) { + return userId.equals(userPrincipal.gammaUser().id()); + } + } + } + + return false; + }; + } + + /** Such as Bootstrap */ + public static AccessChecker isLocalRunner() { + return (clientRepository, userRepository) -> + AuthenticationExtractor.getAuthentication() instanceof LocalRunnerAuthentication; + } + + public void require(AccessChecker check) { + if (!validate(check)) { + throw new AccessDeniedException(); + } + } + + public void requireEither(AccessChecker... checks) { + for (AccessChecker check : checks) { + if (validate(check)) { + return; + } + } + + // None of the check went through thus access denied + throw new AccessDeniedException(); + } + + public void requireAll(AccessChecker... checks) { + for (AccessChecker check : checks) { + if (!validate(check)) { + // If any of the checks fails, then access denied + throw new AccessDeniedException(); + } + } + } + + private boolean validate(AccessChecker check) { + return check.validate(clientRepository, userRepository); + } + + public interface AccessChecker { + boolean validate(ClientRepository clientRepository, UserRepository userRepository); + } + + public static class AccessDeniedException extends RuntimeException { + public AccessDeniedException() { + LOGGER.error("Access was denied."); + } + } +} diff --git a/app/src/main/java/it/chalmers/gamma/app/authentication/UserAccessGuard.java b/app/src/main/java/it/chalmers/gamma/app/authentication/UserAccessGuard.java new file mode 100644 index 000000000..e725fb262 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/authentication/UserAccessGuard.java @@ -0,0 +1,166 @@ +package it.chalmers.gamma.app.authentication; + +import it.chalmers.gamma.app.apikey.domain.ApiKeyType; +import it.chalmers.gamma.app.client.domain.ClientRepository; +import it.chalmers.gamma.app.user.domain.UserId; +import it.chalmers.gamma.bootstrap.BootstrapAuthenticated; +import it.chalmers.gamma.security.authentication.ApiAuthentication; +import it.chalmers.gamma.security.authentication.AuthenticationExtractor; +import it.chalmers.gamma.security.authentication.UserAuthentication; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.oauth2.server.authorization.authentication.OAuth2ClientAuthenticationToken; +import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken; +import org.springframework.stereotype.Service; + +/* + * One could think that using AuthenticatedService would be a great idea. + * The problem there is that there will be a circular dependency. + */ +@Service +public class UserAccessGuard { + + private static final Logger LOGGER = LoggerFactory.getLogger(UserAccessGuard.class); + + private final ClientRepository clientRepository; + + public UserAccessGuard(ClientRepository clientRepository) { + this.clientRepository = clientRepository; + } + + public boolean accessToExtended(UserId userId) { + return isMe(userId) + || isAdmin() + || isLocalRunnerAuthenticated() + || isApiKeyWithExtendedAccess() + || isClientWithEmailScope(); + } + + public boolean isMe(UserId userId) { + if (SecurityContextHolder.getContext().getAuthentication() + instanceof UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken) { + return UserId.valueOf(usernamePasswordAuthenticationToken.getName()).equals(userId); + } + + if (SecurityContextHolder.getContext().getAuthentication() + instanceof JwtAuthenticationToken jwtAuthenticationToken) { + return UserId.valueOf(jwtAuthenticationToken.getName()).equals(userId); + } + + return false; + } + + public boolean isAdmin() { + if (AuthenticationExtractor.getAuthentication() + instanceof UserAuthentication authenticationDetails) { + return authenticationDetails.isAdmin(); + } + + return false; + } + + public boolean haveAccessToUser(UserId userId, boolean userLocked) { + if (SecurityContextHolder.getContext().getAuthentication() == null + || !SecurityContextHolder.getContext().getAuthentication().isAuthenticated()) { + return false; + } + + // Always access to yourself + if (isMe(userId)) { + return true; + } + + /* + * If the user is locked then nothing should be returned + * unless if and only if the signed-in user is an admin. + */ + if (userLocked) { + return isAdmin(); + } + + // If one user is trying to access another user, then approve + if (isInternalAuthenticated()) { + return true; + } + + // If a client is trying to access a user that have approved the client, then approve + if (haveAcceptedClient(userId)) { + return true; + } + + if (isApiKeyWithAccess()) { + return true; + } + + // If it's a local runner, then approve + if (isLocalRunnerAuthenticated()) { + return true; + } + + LOGGER.debug("tried to access the user: {}; ", userId); + + // Return false by default + return true; + } + + private boolean isInternalAuthenticated() { + return AuthenticationExtractor.getAuthentication() instanceof UserAuthentication; + } + + private boolean isLocalRunnerAuthenticated() { + return SecurityContextHolder.getContext().getAuthentication() instanceof BootstrapAuthenticated; + } + + // If the client tries to access a user that have not accepted the client, then return null. + private boolean haveAcceptedClient(UserId userId) { + if (AuthenticationExtractor.getAuthentication() + instanceof ApiAuthentication apiAuthenticationPrincipal) { + ApiKeyType apiKeyType = apiAuthenticationPrincipal.get().keyType(); + if (apiKeyType.equals(ApiKeyType.CLIENT)) { + if (apiAuthenticationPrincipal.getClient().isEmpty()) { + throw new IllegalStateException( + "An api key that is of type CLIENT must have a client connected to them; " + + apiAuthenticationPrincipal.get()); + } + + return clientRepository.isApprovedByUser( + userId, apiAuthenticationPrincipal.getClient().get().clientUid()); + } + } + + return false; + } + + /** Api Key with type INFO or ACCOUNT_SCAFFOLD have access to user information. */ + private boolean isApiKeyWithAccess() { + if (AuthenticationExtractor.getAuthentication() + instanceof ApiAuthentication apiAuthenticationPrincipal) { + ApiKeyType apiKeyType = apiAuthenticationPrincipal.get().keyType(); + return apiKeyType.equals(ApiKeyType.INFO) || apiKeyType.equals(ApiKeyType.ACCOUNT_SCAFFOLD); + } + + return false; + } + + private boolean isApiKeyWithExtendedAccess() { + if (AuthenticationExtractor.getAuthentication() + instanceof ApiAuthentication apiAuthenticationPrincipal) { + ApiKeyType apiKeyType = apiAuthenticationPrincipal.get().keyType(); + return apiKeyType.equals(ApiKeyType.ACCOUNT_SCAFFOLD); + } + + return false; + } + + private boolean isClientWithEmailScope() { + if (SecurityContextHolder.getContext().getAuthentication() + instanceof OAuth2ClientAuthenticationToken client + && client.getRegisteredClient() != null) { + return client.getRegisteredClient().getScopes().contains("email"); + } + + return false; + } +} diff --git a/app/src/main/java/it/chalmers/gamma/app/client/ClientApprovalFacade.java b/app/src/main/java/it/chalmers/gamma/app/client/ClientApprovalFacade.java new file mode 100644 index 000000000..812c5cd50 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/client/ClientApprovalFacade.java @@ -0,0 +1,35 @@ +package it.chalmers.gamma.app.client; + +import static it.chalmers.gamma.app.authentication.AccessGuard.isAdmin; +import static it.chalmers.gamma.app.authentication.AccessGuard.ownerOfClient; + +import it.chalmers.gamma.app.Facade; +import it.chalmers.gamma.app.authentication.AccessGuard; +import it.chalmers.gamma.app.client.domain.ClientUid; +import it.chalmers.gamma.app.client.domain.approval.ClientApprovalsRepository; +import it.chalmers.gamma.app.user.UserFacade; +import java.util.List; +import java.util.UUID; +import org.springframework.stereotype.Component; + +@Component +public class ClientApprovalFacade extends Facade { + + private final ClientApprovalsRepository clientApprovalsRepository; + + public ClientApprovalFacade( + AccessGuard accessGuard, ClientApprovalsRepository clientApprovalsRepository) { + super(accessGuard); + this.clientApprovalsRepository = clientApprovalsRepository; + } + + public List getApprovalsForClient(UUID clientUid) { + ClientUid uid = new ClientUid(clientUid); + + accessGuard.requireEither(isAdmin(), ownerOfClient(uid)); + + return this.clientApprovalsRepository.getAllByClientUid(uid).stream() + .map(UserFacade.UserDTO::new) + .toList(); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/app/client/ClientAuthorityFacade.java b/app/src/main/java/it/chalmers/gamma/app/client/ClientAuthorityFacade.java new file mode 100644 index 000000000..f2a5d881e --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/client/ClientAuthorityFacade.java @@ -0,0 +1,234 @@ +package it.chalmers.gamma.app.client; + +import static it.chalmers.gamma.app.authentication.AccessGuard.*; + +import it.chalmers.gamma.app.Facade; +import it.chalmers.gamma.app.authentication.AccessGuard; +import it.chalmers.gamma.app.client.domain.Client; +import it.chalmers.gamma.app.client.domain.ClientUid; +import it.chalmers.gamma.app.client.domain.authority.Authority; +import it.chalmers.gamma.app.client.domain.authority.AuthorityName; +import it.chalmers.gamma.app.client.domain.authority.ClientAuthorityRepository; +import it.chalmers.gamma.app.supergroup.SuperGroupFacade; +import it.chalmers.gamma.app.supergroup.domain.SuperGroup; +import it.chalmers.gamma.app.supergroup.domain.SuperGroupId; +import it.chalmers.gamma.app.supergroup.domain.SuperGroupRepository; +import it.chalmers.gamma.app.user.UserFacade; +import it.chalmers.gamma.app.user.domain.GammaUser; +import it.chalmers.gamma.app.user.domain.UserId; +import it.chalmers.gamma.app.user.domain.UserRepository; +import it.chalmers.gamma.security.authentication.ApiAuthentication; +import it.chalmers.gamma.security.authentication.AuthenticationExtractor; +import jakarta.transaction.Transactional; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.UUID; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; + +@Service +public class ClientAuthorityFacade extends Facade { + + private static final Logger LOGGER = LoggerFactory.getLogger(ClientAuthorityFacade.class); + + private final ClientAuthorityRepository clientAuthorityRepository; + private final UserRepository userRepository; + private final SuperGroupRepository superGroupRepository; + + public ClientAuthorityFacade( + AccessGuard accessGuard, + ClientAuthorityRepository clientAuthorityRepository, + UserRepository userRepository, + SuperGroupRepository superGroupRepository) { + super(accessGuard); + this.clientAuthorityRepository = clientAuthorityRepository; + this.userRepository = userRepository; + this.superGroupRepository = superGroupRepository; + } + + public void create(UUID clientUid, String name) + throws ClientAuthorityRepository.ClientAuthorityAlreadyExistsException { + ClientUid uid = new ClientUid(clientUid); + + this.accessGuard.requireEither(isAdmin(), ownerOfClient(uid)); + + this.clientAuthorityRepository.create(uid, new AuthorityName(name)); + } + + public void delete(UUID clientUid, String name) throws ClientAuthorityNotFoundException { + ClientUid uid = new ClientUid(clientUid); + + this.accessGuard.requireEither(isAdmin(), ownerOfClient(uid)); + + try { + this.clientAuthorityRepository.delete(uid, new AuthorityName(name)); + } catch (ClientAuthorityRepository.ClientAuthorityNotFoundException e) { + throw new ClientAuthorityNotFoundException(); + } + } + + public Optional get(UUID clientUid, String name) { + ClientUid uid = new ClientUid(clientUid); + + this.accessGuard.requireEither(isAdmin(), ownerOfClient(uid)); + + return this.clientAuthorityRepository + .get(uid, new AuthorityName(name)) + .map(ClientAuthorityDTO::new); + } + + @Transactional + public void addSuperGroupToClientAuthority(UUID clientUid, String name, UUID superGroupId) + throws ClientAuthorityNotFoundException, SuperGroupNotFoundException { + ClientUid uid = new ClientUid(clientUid); + + this.accessGuard.requireEither(isAdmin(), ownerOfClient(uid)); + + Authority authority = + this.clientAuthorityRepository + .get(uid, new AuthorityName(name)) + .orElseThrow(ClientAuthorityNotFoundException::new); + + List superGroups = new ArrayList<>(authority.superGroups()); + superGroups.add( + this.superGroupRepository + .get(new SuperGroupId(superGroupId)) + .orElseThrow(SuperGroupNotFoundException::new)); + + this.clientAuthorityRepository.save(authority.withSuperGroups(superGroups)); + } + + @Transactional + public void addUserToClientAuthority(UUID clientUid, String name, UUID userId) + throws ClientAuthorityRepository.ClientAuthorityNotFoundRuntimeException, + ClientAuthorityNotFoundException, + UserNotFoundException { + ClientUid uid = new ClientUid(clientUid); + + this.accessGuard.requireEither(isAdmin(), isLocalRunner(), ownerOfClient(uid)); + + Authority authority = + this.clientAuthorityRepository + .get(uid, new AuthorityName(name)) + .orElseThrow(ClientAuthorityNotFoundException::new); + + List newUsersList = new ArrayList<>(authority.users()); + GammaUser newUser = + this.userRepository.get(new UserId(userId)).orElseThrow(UserNotFoundException::new); + newUsersList.add(newUser); + + this.clientAuthorityRepository.save(authority.withUsers(newUsersList)); + } + + @Transactional + public void removeSuperGroupFromClientAuthority(UUID clientUid, String name, UUID superGroupId) + throws ClientAuthorityNotFoundException { + ClientUid uid = new ClientUid(clientUid); + + this.accessGuard.requireEither(isAdmin(), ownerOfClient(uid)); + + Authority authority = + this.clientAuthorityRepository + .get(uid, new AuthorityName(name)) + .orElseThrow(ClientAuthorityNotFoundException::new); + + List newSuperGroups = new ArrayList<>(authority.superGroups()); + for (int i = 0; i < newSuperGroups.size(); i++) { + if (newSuperGroups.get(i).id().value().equals(superGroupId)) { + newSuperGroups.remove(i); + break; + } + } + + this.clientAuthorityRepository.save(authority.withSuperGroups(newSuperGroups)); + } + + public List getAll(UUID clientUid) { + ClientUid uid = new ClientUid(clientUid); + + this.accessGuard.requireEither(isAdmin(), ownerOfClient(uid)); + + var authorities = this.clientAuthorityRepository.getAllByClient(uid); + + return authorities.stream().map(ClientAuthorityDTO::new).toList(); + } + + @Transactional + public void removeUserFromClientAuthority(UUID clientUid, String name, UUID userId) + throws ClientAuthorityNotFoundException { + ClientUid uid = new ClientUid(clientUid); + + this.accessGuard.requireEither(isAdmin(), ownerOfClient(uid)); + + Authority authority = + this.clientAuthorityRepository + .get(uid, new AuthorityName(name)) + .orElseThrow(ClientAuthorityNotFoundException::new); + + List newUsers = new ArrayList<>(authority.users()); + for (int i = 0; i < newUsers.size(); i++) { + if (newUsers.get(i).id().value().equals(userId)) { + newUsers.remove(i); + break; + } + } + + this.clientAuthorityRepository.save(authority.withUsers(newUsers)); + } + + public List getClientAuthorities() { + this.accessGuard.require(isClientApi()); + + if (AuthenticationExtractor.getAuthentication() + instanceof ApiAuthentication apiAuthentication) { + Client client = apiAuthentication.getClient().orElseThrow(); + + return this.clientAuthorityRepository.getAllByClient(client.clientUid()).stream() + .map(Authority::name) + .map(AuthorityName::value) + .toList(); + } + + throw new RuntimeException(); + } + + public List getUserAuthorities(UUID userId) { + this.accessGuard.require(isClientApi()); + + if (AuthenticationExtractor.getAuthentication() + instanceof ApiAuthentication apiAuthentication) { + Client client = apiAuthentication.getClient().orElseThrow(); + + return this.clientAuthorityRepository + .getAllByUser(client.clientUid(), new UserId(userId)) + .stream() + .map(AuthorityName::value) + .toList(); + } + + throw new RuntimeException(); + } + + public record ClientAuthorityDTO( + UUID clientUid, + String authorityName, + List superGroups, + List users) { + + public ClientAuthorityDTO(Authority authority) { + this( + authority.client().clientUid().value(), + authority.name().value(), + authority.superGroups().stream().map(SuperGroupFacade.SuperGroupDTO::new).toList(), + authority.users().stream().map(UserFacade.UserDTO::new).toList()); + } + } + + public static class ClientAuthorityNotFoundException extends Exception {} + + public static class SuperGroupNotFoundException extends Exception {} + + public static class UserNotFoundException extends Exception {} +} diff --git a/app/src/main/java/it/chalmers/gamma/app/client/ClientFacade.java b/app/src/main/java/it/chalmers/gamma/app/client/ClientFacade.java new file mode 100644 index 000000000..e6b69a990 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/client/ClientFacade.java @@ -0,0 +1,271 @@ +package it.chalmers.gamma.app.client; + +import static it.chalmers.gamma.app.authentication.AccessGuard.*; + +import it.chalmers.gamma.app.Facade; +import it.chalmers.gamma.app.apikey.ApiKeyFacade; +import it.chalmers.gamma.app.apikey.domain.ApiKey; +import it.chalmers.gamma.app.apikey.domain.ApiKeyId; +import it.chalmers.gamma.app.apikey.domain.ApiKeyToken; +import it.chalmers.gamma.app.apikey.domain.ApiKeyType; +import it.chalmers.gamma.app.authentication.AccessGuard; +import it.chalmers.gamma.app.client.domain.*; +import it.chalmers.gamma.app.client.domain.restriction.ClientRestriction; +import it.chalmers.gamma.app.client.domain.restriction.ClientRestrictionId; +import it.chalmers.gamma.app.common.PrettyName; +import it.chalmers.gamma.app.common.Text; +import it.chalmers.gamma.app.supergroup.SuperGroupFacade; +import it.chalmers.gamma.app.supergroup.domain.SuperGroupId; +import it.chalmers.gamma.app.supergroup.domain.SuperGroupRepository; +import it.chalmers.gamma.app.user.UserFacade; +import it.chalmers.gamma.app.user.domain.UserId; +import it.chalmers.gamma.app.user.domain.UserRepository; +import it.chalmers.gamma.security.authentication.AuthenticationExtractor; +import it.chalmers.gamma.security.authentication.UserAuthentication; +import jakarta.transaction.Transactional; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.UUID; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Service; + +@Service +public class ClientFacade extends Facade { + + private final ClientRepository clientRepository; + private final SuperGroupRepository superGroupRepository; + private final UserRepository userRepository; + private final PasswordEncoder passwordEncoder; + + public ClientFacade( + AccessGuard accessGuard, + ClientRepository clientRepository, + SuperGroupRepository superGroupRepository, + UserRepository userRepository, + PasswordEncoder passwordEncoder) { + super(accessGuard); + this.clientRepository = clientRepository; + this.superGroupRepository = superGroupRepository; + this.userRepository = userRepository; + this.passwordEncoder = passwordEncoder; + } + + @Transactional + public CreatedClientDTO createOfficialClient(NewClient newClient) { + this.accessGuard.require(isAdmin()); + + return this.create(newClient, new ClientOwnerOfficial()); + } + + @Transactional + public CreatedClientDTO createUserClient(NewClient newClient) { + this.accessGuard.require(isSignedIn()); + + if (newClient.restrictions != null) { + throw new IllegalArgumentException("user client cannot have restrictions"); + } + + if (AuthenticationExtractor.getAuthentication() + instanceof UserAuthentication userAuthentication) { + return this.create(newClient, new ClientUserOwner(userAuthentication.gammaUser().id())); + } + + throw new IllegalStateException(); + } + + private CreatedClientDTO create(NewClient newClient, ClientOwner clientOwner) { + ClientSecret.GeneratedClientSecret generatedClientSecret = + ClientSecret.generate(passwordEncoder); + ApiKey apiKey = null; + ApiKeyToken.GeneratedApiKeyToken generatedApiKeyToken = null; + + if (newClient.generateApiKey) { + generatedApiKeyToken = ApiKeyToken.generate(passwordEncoder); + + apiKey = + new ApiKey( + ApiKeyId.generate(), + new PrettyName(newClient.prettyName), + new Text( + "Api nyckel för klienten: " + newClient.prettyName, + "Api key for client: " + newClient.prettyName), + ApiKeyType.CLIENT, + generatedApiKeyToken.apiKeyToken()); + } + + List scopes = new ArrayList<>(); + scopes.add(Scope.PROFILE); + if (newClient.emailScope) { + scopes.add(Scope.EMAIL); + } + + ClientUid clientUid = ClientUid.generate(); + ClientId clientId = ClientId.generate(); + + ClientRestriction restrictions = null; + if (newClient.restrictions != null) { + restrictions = + new ClientRestriction( + ClientRestrictionId.generate(), + newClient.restrictions.superGroups.stream() + .map( + superGroupId -> + this.superGroupRepository + .get(new SuperGroupId(superGroupId)) + .orElseThrow()) + .toList()); + } + + Client client = + new Client( + clientUid, + clientId, + generatedClientSecret.clientSecret(), + new ClientRedirectUrl(newClient.redirectUrl), + new PrettyName(newClient.prettyName), + new Text(newClient.svDescription, newClient.enDescription), + scopes, + apiKey, + clientOwner, + restrictions); + + this.clientRepository.save(client); + + return new CreatedClientDTO( + createDTO(client), + generatedClientSecret.rawSecret(), + generatedApiKeyToken == null ? null : generatedApiKeyToken.rawToken()); + } + + public void delete(UUID clientUid) throws ClientFacade.ClientNotFoundException { + ClientUid uid = new ClientUid(clientUid); + + this.accessGuard.requireEither(isAdmin(), ownerOfClient(uid)); + + try { + this.clientRepository.delete(uid); + } catch (ClientRepository.ClientNotFoundException e) { + throw new ClientFacade.ClientNotFoundException(); + } + } + + public Optional get(UUID clientUid) { + ClientUid uid = new ClientUid(clientUid); + + this.accessGuard.requireEither(isAdmin(), ownerOfClient(uid)); + + return this.clientRepository.get(uid).map(this::createDTO); + } + + public List getAll() { + this.accessGuard.require(isAdmin()); + + return this.clientRepository.getAll().stream().map(this::createDTO).toList(); + } + + public List getAllMyClients() { + this.accessGuard.require(isSignedIn()); + + if (AuthenticationExtractor.getAuthentication() + instanceof UserAuthentication userAuthentication) { + return this.clientRepository.getAllUserClients(userAuthentication.gammaUser().id()).stream() + .map(this::createDTO) + .toList(); + } + + throw new IllegalStateException(); + } + + public String resetClientSecret(UUID clientUid) { + ClientUid uid = new ClientUid(clientUid); + + this.accessGuard.requireEither(isAdmin(), ownerOfClient(uid)); + + Client client = this.clientRepository.get(uid).orElseThrow(); + ClientSecret.GeneratedClientSecret generated = ClientSecret.generate(passwordEncoder); + + Client newClient = client.withClientSecret(generated.clientSecret()); + + this.clientRepository.save(newClient); + + return generated.rawSecret(); + } + + public Optional getClientOwner(String clientId) { + accessGuard.require(isSignedIn()); + + Client client = this.clientRepository.get(new ClientId(clientId)).orElseThrow(); + + if (client.owner() instanceof ClientUserOwner(UserId userId)) { + return this.userRepository.get(userId).map(UserFacade.UserDTO::new); + } + + return Optional.empty(); + } + + public record NewClientRestrictions(List superGroups) {} + + public record NewClient( + String redirectUrl, + String prettyName, + String svDescription, + String enDescription, + boolean generateApiKey, + boolean emailScope, + NewClientRestrictions restrictions) {} + + public record CreatedClientDTO(ClientDTO client, String clientSecret, String apiKeyToken) {} + + private ClientDTO createDTO(Client client) { + return new ClientDTO( + client.clientUid().value(), + client.clientId().value(), + client.clientRedirectUrl().value(), + client.prettyName().value(), + client.description().sv().value(), + client.description().en().value(), + client.clientApiKey().map(ApiKeyFacade.ApiKeyDTO::new), + client + .restrictions() + .map( + clientRestriction -> + new ClientDTO.ClientRestrictionDTO( + clientRestriction.superGroups().stream() + .map(SuperGroupFacade.SuperGroupDTO::new) + .toList())) + .orElse(null), + convert(client.owner())); + } + + private ClientDTO.Owner convert(ClientOwner clientOwner) { + return switch (clientOwner) { + case ClientOwnerOfficial() -> new ClientDTO.OfficialOwner(); + case ClientUserOwner(UserId userId) -> + new ClientDTO.UserOwner( + new UserFacade.UserDTO(this.userRepository.get(userId).orElseThrow())); + }; + } + + public record ClientDTO( + UUID clientUid, + String clientId, + String webServerRedirectUrl, + String prettyName, + String svDescription, + String enDescription, + Optional apiKey, + ClientRestrictionDTO restriction, + Owner owner) { + + public record ClientRestrictionDTO(List superGroups) {} + + public sealed interface Owner permits OfficialOwner, UserOwner {} + + public record OfficialOwner() implements Owner {} + + public record UserOwner(UserFacade.UserDTO user) implements Owner {} + } + + public static class ClientNotFoundException extends Exception {} +} diff --git a/app/src/main/java/it/chalmers/gamma/app/client/domain/Client.java b/app/src/main/java/it/chalmers/gamma/app/client/domain/Client.java new file mode 100644 index 000000000..4efb7dae4 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/client/domain/Client.java @@ -0,0 +1,168 @@ +package it.chalmers.gamma.app.client.domain; + +import it.chalmers.gamma.app.apikey.domain.ApiKey; +import it.chalmers.gamma.app.apikey.domain.ApiKeyType; +import it.chalmers.gamma.app.client.domain.restriction.ClientRestriction; +import it.chalmers.gamma.app.common.PrettyName; +import it.chalmers.gamma.app.common.Text; +import java.util.List; +import java.util.Objects; +import java.util.Optional; + +public final class Client { + private final ClientUid clientUid; + private final ClientId clientId; + private final ClientSecret clientSecret; + private final ClientRedirectUrl clientRedirectUrl; + private final PrettyName prettyName; + private final Text description; + private final List scopes; + private final ApiKey clientApiKey; + private final ClientOwner owner; + private final ClientRestriction restriction; + + public Client( + ClientUid clientUid, + ClientId clientId, + ClientSecret clientSecret, + ClientRedirectUrl clientRedirectUrl, + PrettyName prettyName, + Text description, + List scopes, + ApiKey clientApiKey, + ClientOwner owner, + ClientRestriction restriction) { + Objects.requireNonNull(clientId); + Objects.requireNonNull(clientRedirectUrl); + Objects.requireNonNull(prettyName); + Objects.requireNonNull(description); + Objects.requireNonNull(scopes); + Objects.requireNonNull(owner); + + if (clientApiKey != null && clientApiKey.keyType() != ApiKeyType.CLIENT) { + throw new IllegalArgumentException( + "If a client has a ApiKey, then the type must be ApiKeyType.CLIENT"); + } + + this.clientUid = clientUid; + this.clientId = clientId; + this.clientSecret = clientSecret; + this.clientRedirectUrl = clientRedirectUrl; + this.prettyName = prettyName; + this.description = description; + this.scopes = scopes; + this.clientApiKey = clientApiKey; + this.owner = owner; + this.restriction = restriction; + } + + public ClientUid clientUid() { + return clientUid; + } + + public ClientId clientId() { + return clientId; + } + + public ClientSecret clientSecret() { + return clientSecret; + } + + public ClientRedirectUrl clientRedirectUrl() { + return clientRedirectUrl; + } + + public PrettyName prettyName() { + return prettyName; + } + + public Text description() { + return description; + } + + public List scopes() { + return scopes; + } + + public Optional clientApiKey() { + return Optional.ofNullable(this.clientApiKey); + } + + public Optional restrictions() { + return Optional.ofNullable(this.restriction); + } + + public ClientOwner owner() { + return owner; + } + + public Client withClientSecret(ClientSecret clientSecret) { + return new Client( + this.clientUid, + this.clientId, + clientSecret, + this.clientRedirectUrl, + this.prettyName, + this.description, + this.scopes, + this.clientApiKey, + this.owner, + this.restriction); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Client client = (Client) o; + return clientUid.equals(client.clientUid) + && clientId.equals(client.clientId) + && clientSecret.equals(client.clientSecret) + && clientRedirectUrl.equals(client.clientRedirectUrl) + && prettyName.equals(client.prettyName) + && description.equals(client.description) + && scopes.equals(client.scopes) + && Objects.equals(clientApiKey, client.clientApiKey) + && owner == client.owner + && restriction == client.restriction; + } + + @Override + public int hashCode() { + return Objects.hash( + clientUid, + clientId, + clientSecret, + clientRedirectUrl, + prettyName, + description, + scopes, + clientApiKey, + owner, + restriction); + } + + @Override + public String toString() { + return "Client{" + + "clientUid=" + + clientUid + + ", clientId=" + + clientId + + ", clientRedirectUrl=" + + clientRedirectUrl + + ", prettyName=" + + prettyName + + ", description=" + + description + + ", scopes=" + + scopes + + ", clientApiKey=" + + clientApiKey + + ", access=" + + owner + + ", restriction=" + + restriction + + '}'; + } +} diff --git a/app/src/main/java/it/chalmers/gamma/app/client/domain/ClientId.java b/app/src/main/java/it/chalmers/gamma/app/client/domain/ClientId.java new file mode 100644 index 000000000..6fea4797a --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/client/domain/ClientId.java @@ -0,0 +1,25 @@ +package it.chalmers.gamma.app.client.domain; + +import it.chalmers.gamma.app.Tokens; +import java.util.Objects; +import java.util.regex.Pattern; + +/** Id for the client that is used in the OAuth2 flow. */ +public record ClientId(String value) { + + private static final Pattern clientIdPattern = Pattern.compile("^[A-Z0-9]{30}$"); + + public ClientId { + Objects.requireNonNull(value); + + if (!clientIdPattern.matcher(value).matches()) { + throw new IllegalArgumentException( + "Client id can only have upper case characters and numbers"); + } + } + + public static ClientId generate() { + String id = Tokens.generate(30, Tokens.CharacterTypes.UPPERCASE, Tokens.CharacterTypes.NUMBERS); + return new ClientId(id); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/app/client/domain/ClientOwner.java b/app/src/main/java/it/chalmers/gamma/app/client/domain/ClientOwner.java new file mode 100644 index 000000000..46c5f2760 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/client/domain/ClientOwner.java @@ -0,0 +1,3 @@ +package it.chalmers.gamma.app.client.domain; + +public sealed interface ClientOwner permits ClientUserOwner, ClientOwnerOfficial {} diff --git a/app/src/main/java/it/chalmers/gamma/app/client/domain/ClientOwnerOfficial.java b/app/src/main/java/it/chalmers/gamma/app/client/domain/ClientOwnerOfficial.java new file mode 100644 index 000000000..aa2fc2069 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/client/domain/ClientOwnerOfficial.java @@ -0,0 +1,3 @@ +package it.chalmers.gamma.app.client.domain; + +public record ClientOwnerOfficial() implements ClientOwner {} diff --git a/app/src/main/java/it/chalmers/gamma/app/client/domain/ClientRedirectUrl.java b/app/src/main/java/it/chalmers/gamma/app/client/domain/ClientRedirectUrl.java new file mode 100644 index 000000000..ab826b98a --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/client/domain/ClientRedirectUrl.java @@ -0,0 +1,21 @@ +package it.chalmers.gamma.app.client.domain; + +import static it.chalmers.gamma.app.validation.ValidationHelper.*; + +import it.chalmers.gamma.app.validation.ValidationResult; +import it.chalmers.gamma.app.validation.Validator; + +public record ClientRedirectUrl(String value) { + + public ClientRedirectUrl { + throwIfFailed(new ClientRedirectUrlValidator().validate(value)); + } + + public static final class ClientRedirectUrlValidator implements Validator { + + @Override + public ValidationResult validate(String value) { + return withValidators(IS_NOT_EMPTY, SANITIZED_HTML).validate(value); + } + } +} diff --git a/app/src/main/java/it/chalmers/gamma/app/client/domain/ClientRepository.java b/app/src/main/java/it/chalmers/gamma/app/client/domain/ClientRepository.java new file mode 100644 index 000000000..492e954e0 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/client/domain/ClientRepository.java @@ -0,0 +1,45 @@ +package it.chalmers.gamma.app.client.domain; + +import it.chalmers.gamma.app.apikey.domain.ApiKeyId; +import it.chalmers.gamma.app.apikey.domain.ApiKeyToken; +import it.chalmers.gamma.app.user.domain.UserId; +import java.util.List; +import java.util.Optional; + +public interface ClientRepository { + + void save(Client client) + throws AuthorityNotFoundRuntimeException, + UserNotFoundRuntimeException, + ClientIdAlreadyExistsRuntimeException; + + void delete(ClientUid clientId) throws ClientNotFoundException; + + List getAll(); + + List getAllUserClients(UserId userId); + + Optional get(ClientUid clientUid); + + Optional get(ClientId clientId); + + void addClientApproval(UserId userId, ClientUid clientUid); + + boolean isApprovedByUser(UserId userId, ClientUid clientUid); + + List getClientsByUserApproved(UserId id); + + void deleteUserApproval(ClientUid clientUid, UserId userId); + + Optional getByApiKey(ApiKeyToken apiKeyToken); + + Optional getByApiKey(ApiKeyId apiKeyId); + + class ClientNotFoundException extends Exception {} + + class ClientIdAlreadyExistsRuntimeException extends RuntimeException {} + + class AuthorityNotFoundRuntimeException extends RuntimeException {} + + class UserNotFoundRuntimeException extends RuntimeException {} +} diff --git a/app/src/main/java/it/chalmers/gamma/app/client/domain/ClientSecret.java b/app/src/main/java/it/chalmers/gamma/app/client/domain/ClientSecret.java new file mode 100644 index 000000000..69a8ddd12 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/client/domain/ClientSecret.java @@ -0,0 +1,36 @@ +package it.chalmers.gamma.app.client.domain; + +import it.chalmers.gamma.app.Tokens; +import java.util.Objects; +import java.util.regex.Pattern; +import org.springframework.security.crypto.password.PasswordEncoder; + +public record ClientSecret(String value) { + + private static final Pattern clientSecretStartPattern = Pattern.compile("^\\{bcrypt}.+"); + + public ClientSecret { + Objects.requireNonNull(value); + + if (!clientSecretStartPattern.matcher(value).matches()) { + throw new IllegalArgumentException("Client rawSecret not properly encrypted"); + } + } + + public record GeneratedClientSecret(ClientSecret clientSecret, String rawSecret) {} + + public static GeneratedClientSecret generate(PasswordEncoder passwordEncoder) { + String value = + Tokens.generate( + 32, + Tokens.CharacterTypes.LOWERCASE, + Tokens.CharacterTypes.UPPERCASE, + Tokens.CharacterTypes.NUMBERS); + return new GeneratedClientSecret(new ClientSecret(passwordEncoder.encode(value)), value); + } + + @Override + public String toString() { + return ""; + } +} diff --git a/app/src/main/java/it/chalmers/gamma/app/client/domain/ClientUid.java b/app/src/main/java/it/chalmers/gamma/app/client/domain/ClientUid.java new file mode 100644 index 000000000..ff0716285 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/client/domain/ClientUid.java @@ -0,0 +1,26 @@ +package it.chalmers.gamma.app.client.domain; + +import it.chalmers.gamma.app.common.Id; +import java.util.Objects; +import java.util.UUID; + +/** UUID value for Client. */ +public record ClientUid(UUID value) implements Id { + + public ClientUid { + Objects.requireNonNull(value); + } + + public static ClientUid generate() { + return new ClientUid(UUID.randomUUID()); + } + + public static ClientUid valueOf(String uid) { + return new ClientUid(UUID.fromString(uid)); + } + + @Override + public String getValue() { + return value.toString(); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/app/client/domain/ClientUserOwner.java b/app/src/main/java/it/chalmers/gamma/app/client/domain/ClientUserOwner.java new file mode 100644 index 000000000..0042f7e33 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/client/domain/ClientUserOwner.java @@ -0,0 +1,5 @@ +package it.chalmers.gamma.app.client.domain; + +import it.chalmers.gamma.app.user.domain.UserId; + +public record ClientUserOwner(UserId userId) implements ClientOwner {} diff --git a/app/src/main/java/it/chalmers/gamma/app/client/domain/Scope.java b/app/src/main/java/it/chalmers/gamma/app/client/domain/Scope.java new file mode 100644 index 000000000..df31b6f1d --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/client/domain/Scope.java @@ -0,0 +1,6 @@ +package it.chalmers.gamma.app.client.domain; + +public enum Scope { + PROFILE, + EMAIL +} diff --git a/app/src/main/java/it/chalmers/gamma/app/client/domain/approval/ClientApprovals.java b/app/src/main/java/it/chalmers/gamma/app/client/domain/approval/ClientApprovals.java new file mode 100644 index 000000000..eab850190 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/client/domain/approval/ClientApprovals.java @@ -0,0 +1,14 @@ +package it.chalmers.gamma.app.client.domain.approval; + +import it.chalmers.gamma.app.client.domain.Client; +import it.chalmers.gamma.app.user.domain.GammaUser; +import java.util.List; +import java.util.Objects; + +public record ClientApprovals(Client client, List approvals) { + + public ClientApprovals { + Objects.requireNonNull(client); + Objects.requireNonNull(approvals); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/app/client/domain/approval/ClientApprovalsRepository.java b/app/src/main/java/it/chalmers/gamma/app/client/domain/approval/ClientApprovalsRepository.java new file mode 100644 index 000000000..3a850ad50 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/client/domain/approval/ClientApprovalsRepository.java @@ -0,0 +1,13 @@ +package it.chalmers.gamma.app.client.domain.approval; + +import it.chalmers.gamma.app.client.domain.ClientId; +import it.chalmers.gamma.app.client.domain.ClientUid; +import it.chalmers.gamma.app.user.domain.GammaUser; +import java.util.List; + +public interface ClientApprovalsRepository { + + List getAllByClientId(ClientId clientId); + + List getAllByClientUid(ClientUid clientUid); +} diff --git a/app/src/main/java/it/chalmers/gamma/app/client/domain/authority/Authority.java b/app/src/main/java/it/chalmers/gamma/app/client/domain/authority/Authority.java new file mode 100644 index 000000000..fc5d26c73 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/client/domain/authority/Authority.java @@ -0,0 +1,21 @@ +package it.chalmers.gamma.app.client.domain.authority; + +import io.soabase.recordbuilder.core.RecordBuilder; +import it.chalmers.gamma.app.client.domain.Client; +import it.chalmers.gamma.app.supergroup.domain.SuperGroup; +import it.chalmers.gamma.app.user.domain.GammaUser; +import java.util.List; +import java.util.Objects; + +@RecordBuilder +public record Authority( + Client client, AuthorityName name, List superGroups, List users) + implements AuthorityBuilder.With { + + public Authority { + Objects.requireNonNull(client); + Objects.requireNonNull(name); + Objects.requireNonNull(superGroups); + Objects.requireNonNull(users); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/app/client/domain/authority/AuthorityName.java b/app/src/main/java/it/chalmers/gamma/app/client/domain/authority/AuthorityName.java new file mode 100644 index 000000000..8aaf1e7e3 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/client/domain/authority/AuthorityName.java @@ -0,0 +1,40 @@ +package it.chalmers.gamma.app.client.domain.authority; + +import static it.chalmers.gamma.app.validation.ValidationHelper.*; + +import it.chalmers.gamma.app.common.Id; +import it.chalmers.gamma.app.validation.ValidationResult; +import it.chalmers.gamma.app.validation.Validator; +import java.util.regex.Pattern; + +public record AuthorityName(String value) implements Id { + + public AuthorityName { + throwIfFailed(new AuthorityNameValidator().validate(value)); + } + + public static AuthorityName valueOf(String name) { + return new AuthorityName(name); + } + + @Override + public String getValue() { + return this.value; + } + + public static final class AuthorityNameValidator implements Validator { + + private static final Pattern authorityNamePattern = Pattern.compile("^([0-9a-z]{2,30})$"); + + @Override + public ValidationResult validate(String value) { + return withValidators( + IS_NOT_EMPTY, + MATCHES_REGEX.apply( + new RegexMatcher( + authorityNamePattern, + "Authority name must have letter ranging a - z, and be between size 5 and 30 to be valid"))) + .validate(value); + } + } +} diff --git a/app/src/main/java/it/chalmers/gamma/app/client/domain/authority/ClientAuthorityRepository.java b/app/src/main/java/it/chalmers/gamma/app/client/domain/authority/ClientAuthorityRepository.java new file mode 100644 index 000000000..24003f3c8 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/client/domain/authority/ClientAuthorityRepository.java @@ -0,0 +1,40 @@ +package it.chalmers.gamma.app.client.domain.authority; + +import it.chalmers.gamma.app.client.domain.ClientUid; +import it.chalmers.gamma.app.user.domain.UserId; +import java.util.List; +import java.util.Optional; + +public interface ClientAuthorityRepository { + + void create(ClientUid clientUid, AuthorityName authorityName) + throws ClientAuthorityAlreadyExistsException; + + void delete(ClientUid clientUid, AuthorityName authorityName) + throws ClientAuthorityNotFoundException; + + void save(Authority authority) + throws ClientAuthorityNotFoundRuntimeException, NotCompleteClientAuthorityException; + + List getAllByClient(ClientUid clientUid); + + List getAllByUser(ClientUid clientUid, UserId userId); + + Optional get(ClientUid clientUid, AuthorityName authorityName); + + class ClientAuthorityAlreadyExistsException extends Exception { + public ClientAuthorityAlreadyExistsException(String value) { + super("Authority level: " + value + " already exists"); + } + } + + class ClientAuthorityNotFoundException extends Exception {} + + class ClientAuthorityNotFoundRuntimeException extends RuntimeException {} + + /** + * Can be avoided if you check that supergroups and users actually exists. It happens when linking + * an authority level with one of the above, and it is not found in database. + */ + class NotCompleteClientAuthorityException extends RuntimeException {} +} diff --git a/app/src/main/java/it/chalmers/gamma/app/client/domain/restriction/ClientRestriction.java b/app/src/main/java/it/chalmers/gamma/app/client/domain/restriction/ClientRestriction.java new file mode 100644 index 000000000..6b7496f09 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/client/domain/restriction/ClientRestriction.java @@ -0,0 +1,8 @@ +package it.chalmers.gamma.app.client.domain.restriction; + +import io.soabase.recordbuilder.core.RecordBuilder; +import it.chalmers.gamma.app.supergroup.domain.SuperGroup; +import java.util.List; + +@RecordBuilder +public record ClientRestriction(ClientRestrictionId id, List superGroups) {} diff --git a/app/src/main/java/it/chalmers/gamma/app/client/domain/restriction/ClientRestrictionId.java b/app/src/main/java/it/chalmers/gamma/app/client/domain/restriction/ClientRestrictionId.java new file mode 100644 index 000000000..3266c82d9 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/client/domain/restriction/ClientRestrictionId.java @@ -0,0 +1,10 @@ +package it.chalmers.gamma.app.client.domain.restriction; + +import java.util.UUID; + +public record ClientRestrictionId(UUID value) { + + public static ClientRestrictionId generate() { + return new ClientRestrictionId(UUID.randomUUID()); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/app/common/Email.java b/app/src/main/java/it/chalmers/gamma/app/common/Email.java new file mode 100644 index 000000000..edc747b36 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/common/Email.java @@ -0,0 +1,33 @@ +package it.chalmers.gamma.app.common; + +import static it.chalmers.gamma.app.validation.ValidationHelper.*; + +import it.chalmers.gamma.app.user.domain.UserIdentifier; +import it.chalmers.gamma.app.validation.ValidationResult; +import it.chalmers.gamma.app.validation.Validator; +import java.io.Serializable; +import java.util.regex.Pattern; + +public record Email(String value) implements UserIdentifier, Serializable { + + public Email { + throwIfFailed(new EmailValidator().validate(value)); + } + + public static class EmailValidator implements Validator { + + private static final Pattern emailPattern = + Pattern.compile( + "^[\\w!#$%&'*+/=?`{|}~^-]+(?:\\.[\\w!#$%&'*+/=?`{|}~^-]+)*@(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,6}$"); + + @Override + public ValidationResult validate(String value) { + return withValidators( + IS_NOT_EMPTY, + SANITIZED_HTML, + MATCHES_REGEX.apply( + new RegexMatcher(emailPattern, "Does not look like a valid email"))) + .validate(value); + } + } +} diff --git a/app/src/main/java/it/chalmers/gamma/app/common/Id.java b/app/src/main/java/it/chalmers/gamma/app/common/Id.java new file mode 100644 index 000000000..a3184ec2c --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/common/Id.java @@ -0,0 +1,8 @@ +package it.chalmers.gamma.app.common; + +import java.io.Serializable; + +public interface Id extends Serializable { + + S getValue(); +} diff --git a/app/src/main/java/it/chalmers/gamma/app/common/PrettyName.java b/app/src/main/java/it/chalmers/gamma/app/common/PrettyName.java new file mode 100644 index 000000000..e4643fade --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/common/PrettyName.java @@ -0,0 +1,23 @@ +package it.chalmers.gamma.app.common; + +import static it.chalmers.gamma.app.validation.ValidationHelper.*; + +import it.chalmers.gamma.app.validation.ValidationResult; +import it.chalmers.gamma.app.validation.Validator; +import java.io.Serializable; + +public record PrettyName(String value) implements Serializable { + + public PrettyName { + throwIfFailed(new PrettyNameValidator().validate(value)); + } + + public static final class PrettyNameValidator implements Validator { + + @Override + public ValidationResult validate(String value) { + return withValidators(IS_NOT_EMPTY, SANITIZED_HTML, BETWEEN_LENGTH.apply(2, 50)) + .validate(value); + } + } +} diff --git a/app/src/main/java/it/chalmers/gamma/app/common/Text.java b/app/src/main/java/it/chalmers/gamma/app/common/Text.java new file mode 100644 index 000000000..e6d67be20 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/common/Text.java @@ -0,0 +1,19 @@ +package it.chalmers.gamma.app.common; + +import java.util.Objects; + +public record Text(TextValue sv, TextValue en) { + + public Text { + Objects.requireNonNull(sv); + Objects.requireNonNull(en); + } + + public Text(String sv, String en) { + this(TextValue.valueOf(sv), TextValue.valueOf(en)); + } + + public Text() { + this(TextValue.empty(), TextValue.empty()); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/app/common/TextId.java b/app/src/main/java/it/chalmers/gamma/app/common/TextId.java new file mode 100644 index 000000000..4fd4d6413 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/common/TextId.java @@ -0,0 +1,20 @@ +package it.chalmers.gamma.app.common; + +import java.util.Objects; +import java.util.UUID; + +public record TextId(UUID value) implements Id { + + public TextId { + Objects.requireNonNull(value); + } + + public static TextId generate() { + return new TextId(UUID.randomUUID()); + } + + @Override + public UUID getValue() { + return this.value; + } +} diff --git a/app/src/main/java/it/chalmers/gamma/app/common/TextValue.java b/app/src/main/java/it/chalmers/gamma/app/common/TextValue.java new file mode 100644 index 000000000..3b3e743ef --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/common/TextValue.java @@ -0,0 +1,29 @@ +package it.chalmers.gamma.app.common; + +import static it.chalmers.gamma.app.validation.ValidationHelper.*; + +import it.chalmers.gamma.app.validation.ValidationResult; +import it.chalmers.gamma.app.validation.Validator; + +public record TextValue(String value) { + + public TextValue { + throwIfFailed(new TextValueValidator().validate(value)); + } + + public static TextValue empty() { + return new TextValue(""); + } + + public static TextValue valueOf(String value) { + return new TextValue(value); + } + + public static final class TextValueValidator implements Validator { + + @Override + public ValidationResult validate(String value) { + return withValidators(IS_NOT_NULL, SANITIZED_HTML, MAX_LENGTH.apply(2048)).validate(value); + } + } +} diff --git a/app/src/main/java/it/chalmers/gamma/app/common/UUIDValidator.java b/app/src/main/java/it/chalmers/gamma/app/common/UUIDValidator.java new file mode 100644 index 000000000..6c3068dda --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/common/UUIDValidator.java @@ -0,0 +1,15 @@ +package it.chalmers.gamma.app.common; + +import java.util.UUID; + +public final class UUIDValidator { + + public static boolean isValidUUID(String value) { + try { + UUID.fromString(value); + return true; + } catch (IllegalArgumentException exception) { + return false; + } + } +} diff --git a/app/src/main/java/it/chalmers/gamma/app/group/GroupFacade.java b/app/src/main/java/it/chalmers/gamma/app/group/GroupFacade.java new file mode 100644 index 000000000..b5d73f9ad --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/group/GroupFacade.java @@ -0,0 +1,254 @@ +package it.chalmers.gamma.app.group; + +import static it.chalmers.gamma.app.authentication.AccessGuard.*; + +import it.chalmers.gamma.app.Facade; +import it.chalmers.gamma.app.authentication.AccessGuard; +import it.chalmers.gamma.app.common.PrettyName; +import it.chalmers.gamma.app.group.domain.*; +import it.chalmers.gamma.app.post.PostFacade; +import it.chalmers.gamma.app.post.domain.PostId; +import it.chalmers.gamma.app.post.domain.PostRepository; +import it.chalmers.gamma.app.supergroup.SuperGroupFacade; +import it.chalmers.gamma.app.supergroup.domain.SuperGroupId; +import it.chalmers.gamma.app.supergroup.domain.SuperGroupRepository; +import it.chalmers.gamma.app.user.UserFacade; +import it.chalmers.gamma.app.user.domain.Name; +import it.chalmers.gamma.app.user.domain.UserId; +import it.chalmers.gamma.app.user.domain.UserRepository; +import jakarta.transaction.Transactional; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.UUID; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; + +@Service +public class GroupFacade extends Facade { + + private static final Logger LOGGER = LoggerFactory.getLogger(GroupFacade.class); + + private final GroupRepository groupRepository; + private final UserRepository userRepository; + private final PostRepository postRepository; + private final SuperGroupRepository superGroupRepository; + + public GroupFacade( + AccessGuard accessGuard, + GroupRepository groupRepository, + UserRepository userRepository, + PostRepository postRepository, + SuperGroupRepository superGroupRepository) { + super(accessGuard); + this.groupRepository = groupRepository; + this.userRepository = userRepository; + this.postRepository = postRepository; + this.superGroupRepository = superGroupRepository; + } + + public UUID create(NewGroup newGroup) { + accessGuard.require(isAdmin()); + + Group group = + new Group( + GroupId.generate(), + 0, + new Name(newGroup.name), + new PrettyName(newGroup.prettyName), + this.superGroupRepository + .get(new SuperGroupId(newGroup.superGroup)) + .orElseThrow(SuperGroupNotFoundRuntimeException::new), + new ArrayList<>(), + Optional.empty(), + Optional.empty()); + + this.groupRepository.save(group); + + return group.id().value(); + } + + @Transactional + public void update(UpdateGroup updateGroup) { + accessGuard.require(isAdmin()); + + GroupId groupId = new GroupId(updateGroup.id); + Group oldGroup = + this.groupRepository.get(groupId).orElseThrow(GroupNotFoundRuntimeException::new); + Group newGroup = + oldGroup + .with() + .version(updateGroup.version) + .name(new Name(updateGroup.name)) + .prettyName(new PrettyName(updateGroup.prettyName)) + .superGroup( + this.superGroupRepository + .get(new SuperGroupId(updateGroup.superGroup)) + .orElseThrow(SuperGroupNotFoundRuntimeException::new)) + .build(); + + this.groupRepository.save(newGroup); + } + + public void setMembers(UUID groupId, List newMembers) + throws GroupNotFoundRuntimeException { + accessGuard.require(isAdmin()); + + Group oldGroup = + this.groupRepository + .get(new GroupId(groupId)) + .orElseThrow(GroupNotFoundRuntimeException::new); + + List newGroupMembers = new ArrayList<>(); + + for (ShallowMember shallowMember : newMembers) { + newGroupMembers.add( + new GroupMember( + this.postRepository + .get(new PostId(shallowMember.postId)) + .orElseThrow(PostNotFoundRuntimeException::new), + new UnofficialPostName(shallowMember.unofficialPostName), + this.userRepository + .get(new UserId(shallowMember.userId)) + .orElseThrow(UserNotFoundRuntimeException::new))); + } + + this.groupRepository.save(oldGroup.withGroupMembers(newGroupMembers)); + } + + @Transactional + public void changeUnofficialPostName( + UUID groupId, UUID postId, UUID userId, String newUnofficialPostName) { + accessGuard.requireEither(isAdmin(), isMe(new UserId(userId))); + + Group group = + this.groupRepository + .get(new GroupId(groupId)) + .orElseThrow(GroupNotFoundRuntimeException::new); + + List groupMembers = new ArrayList<>(group.groupMembers()); + boolean found = false; + for (int i = 0; i < groupMembers.size() && !found; i++) { + GroupMember groupMember = groupMembers.get(i); + if (groupMember.user().id().value().equals(userId) + && groupMember.post().id().value().equals(postId)) { + GroupMember newGroupMember = + groupMember.withUnofficialPostName(new UnofficialPostName(newUnofficialPostName)); + groupMembers.set(i, newGroupMember); + found = true; + } + } + + if (!found) { + throw new PostNotFoundRuntimeException(); + } + + group = group.withGroupMembers(groupMembers); + this.groupRepository.save(group); + } + + @Transactional + public void delete(UUID id) throws GroupNotFoundRuntimeException { + accessGuard.require(isAdmin()); + + try { + this.groupRepository.delete(new GroupId(id)); + } catch (GroupRepository.GroupNotFoundException e) { + throw new GroupNotFoundRuntimeException(); + } + } + + public boolean groupWithNameAlreadyExists(UUID id, String name) { + accessGuard.require(isSignedIn()); + + Optional maybeGroup = this.groupRepository.get(new Name(name)); + + return maybeGroup.filter(group -> !group.id().value().equals(id)).isPresent(); + } + + public Optional getWithMembers(UUID groupId) { + accessGuard.require(isSignedIn()); + + return this.groupRepository.get(new GroupId(groupId)).map(GroupWithMembersDTO::new); + } + + public List getAll() { + accessGuard.requireEither(isSignedIn(), isClientApi()); + + return this.groupRepository.getAll().stream().map(GroupDTO::new).toList(); + } + + public Optional get(UUID id) { + accessGuard.requireEither(isSignedIn()); + + return this.groupRepository.get(new GroupId(id)).map(GroupDTO::new); + } + + public List getAllBySuperGroup(UUID superGroupId) { + accessGuard.require(isSignedIn()); + + return this.groupRepository.getAllBySuperGroup(new SuperGroupId(superGroupId)).stream() + .map(GroupWithMembersDTO::new) + .toList(); + } + + public record NewGroup(String name, String prettyName, UUID superGroup) {} + + public record UpdateGroup( + UUID id, int version, String name, String prettyName, UUID superGroup) {} + + public record ShallowMember(UUID userId, UUID postId, String unofficialPostName) {} + + public record GroupMemberDTO( + UserFacade.UserDTO user, PostFacade.PostDTO post, String unofficialPostName) { + public GroupMemberDTO(GroupMember groupMember) { + this( + new UserFacade.UserDTO(groupMember.user()), + new PostFacade.PostDTO(groupMember.post()), + groupMember.unofficialPostName().value()); + } + } + + public record GroupDTO( + UUID id, + String name, + String prettyName, + SuperGroupFacade.SuperGroupDTO superGroup, + int version) { + public GroupDTO(Group group) { + this( + group.id().value(), + group.name().value(), + group.prettyName().value(), + new SuperGroupFacade.SuperGroupDTO(group.superGroup()), + group.version()); + } + } + + public record GroupWithMembersDTO( + UUID id, + int version, + String name, + String prettyName, + List groupMembers, + SuperGroupFacade.SuperGroupDTO superGroup) { + public GroupWithMembersDTO(Group group) { + this( + group.id().value(), + group.version(), + group.name().value(), + group.prettyName().value(), + group.groupMembers().stream().map(GroupMemberDTO::new).toList(), + new SuperGroupFacade.SuperGroupDTO(group.superGroup())); + } + } + + public static class UserNotFoundRuntimeException extends RuntimeException {} + + public static class PostNotFoundRuntimeException extends RuntimeException {} + + public static class GroupNotFoundRuntimeException extends RuntimeException {} + + public static class SuperGroupNotFoundRuntimeException extends RuntimeException {} +} diff --git a/app/src/main/java/it/chalmers/gamma/app/group/domain/EmailPrefix.java b/app/src/main/java/it/chalmers/gamma/app/group/domain/EmailPrefix.java new file mode 100644 index 000000000..6a92351b1 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/group/domain/EmailPrefix.java @@ -0,0 +1,36 @@ +package it.chalmers.gamma.app.group.domain; + +import static it.chalmers.gamma.app.validation.ValidationHelper.*; + +import it.chalmers.gamma.app.validation.ValidationHelper; +import it.chalmers.gamma.app.validation.ValidationResult; +import it.chalmers.gamma.app.validation.Validator; +import java.util.regex.Pattern; + +public record EmailPrefix(String value) { + + public EmailPrefix { + throwIfFailed(new EmailPrefixValidator().validate(value)); + } + + public static EmailPrefix none() { + return new EmailPrefix(""); + } + + public static final class EmailPrefixValidator implements Validator { + + private static final Pattern pattern = Pattern.compile("^$|^(?:\\w+|\\w+\\.\\w+)+$"); + + @Override + public ValidationResult validate(String value) { + return withValidators( + IS_NOT_NULL, + SANITIZED_HTML, + MATCHES_REGEX.apply( + new ValidationHelper.RegexMatcher( + pattern, + "Email prefix most be letters of a - z, and each word must be seperated by a dot"))) + .validate(value); + } + } +} diff --git a/app/src/main/java/it/chalmers/gamma/app/group/domain/Group.java b/app/src/main/java/it/chalmers/gamma/app/group/domain/Group.java new file mode 100644 index 000000000..5964e87cc --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/group/domain/Group.java @@ -0,0 +1,31 @@ +package it.chalmers.gamma.app.group.domain; + +import io.soabase.recordbuilder.core.RecordBuilder; +import it.chalmers.gamma.app.common.PrettyName; +import it.chalmers.gamma.app.image.domain.ImageUri; +import it.chalmers.gamma.app.supergroup.domain.SuperGroup; +import it.chalmers.gamma.app.user.domain.Name; +import java.util.List; +import java.util.Objects; +import java.util.Optional; + +@RecordBuilder +public record Group( + GroupId id, + int version, + Name name, + PrettyName prettyName, + SuperGroup superGroup, + List groupMembers, + Optional avatarUri, + Optional bannerUri) + implements GroupBuilder.With { + + public Group { + Objects.requireNonNull(id); + Objects.requireNonNull(prettyName); + Objects.requireNonNull(superGroup); + Objects.requireNonNull(avatarUri); + Objects.requireNonNull(bannerUri); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/app/group/domain/GroupId.java b/app/src/main/java/it/chalmers/gamma/app/group/domain/GroupId.java new file mode 100644 index 000000000..7a928ce8c --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/group/domain/GroupId.java @@ -0,0 +1,25 @@ +package it.chalmers.gamma.app.group.domain; + +import it.chalmers.gamma.app.common.Id; +import java.util.Objects; +import java.util.UUID; + +public record GroupId(UUID value) implements Id { + + public GroupId { + Objects.requireNonNull(value); + } + + public static GroupId generate() { + return new GroupId(UUID.randomUUID()); + } + + public static GroupId valueOf(String value) { + return new GroupId(UUID.fromString(value)); + } + + @Override + public UUID getValue() { + return this.value; + } +} diff --git a/app/src/main/java/it/chalmers/gamma/app/group/domain/GroupMember.java b/app/src/main/java/it/chalmers/gamma/app/group/domain/GroupMember.java new file mode 100644 index 000000000..6b2ba1cad --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/group/domain/GroupMember.java @@ -0,0 +1,17 @@ +package it.chalmers.gamma.app.group.domain; + +import io.soabase.recordbuilder.core.RecordBuilder; +import it.chalmers.gamma.app.post.domain.Post; +import it.chalmers.gamma.app.user.domain.GammaUser; +import java.util.Objects; + +@RecordBuilder +public record GroupMember(Post post, UnofficialPostName unofficialPostName, GammaUser user) + implements GroupMemberBuilder.With { + + public GroupMember { + Objects.requireNonNull(post); + Objects.requireNonNull(unofficialPostName); + Objects.requireNonNull(user); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/app/group/domain/GroupRepository.java b/app/src/main/java/it/chalmers/gamma/app/group/domain/GroupRepository.java new file mode 100644 index 000000000..966063956 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/group/domain/GroupRepository.java @@ -0,0 +1,42 @@ +package it.chalmers.gamma.app.group.domain; + +import it.chalmers.gamma.app.post.domain.PostId; +import it.chalmers.gamma.app.supergroup.domain.SuperGroupId; +import it.chalmers.gamma.app.user.domain.Name; +import it.chalmers.gamma.app.user.domain.UserId; +import it.chalmers.gamma.app.user.domain.UserMembership; +import java.util.List; +import java.util.Optional; + +public interface GroupRepository { + + void save(Group group) + throws GroupNameAlreadyExistsRuntimeException, + SuperGroupNotFoundRuntimeException, + UserNotFoundRuntimeException, + PostNotFoundRuntimeException; + + void delete(GroupId groupId) throws GroupNotFoundException; + + List getAll(); + + List getAllBySuperGroup(SuperGroupId superGroupId); + + List getAllByPost(PostId postId); + + List getAllByUser(UserId userId); + + Optional get(GroupId groupId); + + Optional get(Name name); + + class GroupNotFoundException extends Exception {} + + class GroupNameAlreadyExistsRuntimeException extends RuntimeException {} + + class SuperGroupNotFoundRuntimeException extends RuntimeException {} + + class UserNotFoundRuntimeException extends RuntimeException {} + + class PostNotFoundRuntimeException extends RuntimeException {} +} diff --git a/app/src/main/java/it/chalmers/gamma/app/group/domain/UnofficialPostName.java b/app/src/main/java/it/chalmers/gamma/app/group/domain/UnofficialPostName.java new file mode 100644 index 000000000..275416498 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/group/domain/UnofficialPostName.java @@ -0,0 +1,31 @@ +package it.chalmers.gamma.app.group.domain; + +import static it.chalmers.gamma.app.validation.ValidationHelper.*; +import static it.chalmers.gamma.app.validation.ValidationHelper.MAX_LENGTH; + +import it.chalmers.gamma.app.validation.SuccessfulValidation; +import it.chalmers.gamma.app.validation.ValidationResult; +import it.chalmers.gamma.app.validation.Validator; + +public record UnofficialPostName(String value) { + + public UnofficialPostName { + throwIfFailed(new UnofficialPostNameValidator().validate(value)); + } + + public static UnofficialPostName none() { + return new UnofficialPostName(null); + } + + public static final class UnofficialPostNameValidator implements Validator { + + @Override + public ValidationResult validate(String value) { + if (value != null) { + return withValidators(IS_NOT_EMPTY, SANITIZED_HTML, MAX_LENGTH.apply(50)).validate(value); + } + + return new SuccessfulValidation(); + } + } +} diff --git a/app/src/main/java/it/chalmers/gamma/app/image/ImageFacade.java b/app/src/main/java/it/chalmers/gamma/app/image/ImageFacade.java new file mode 100644 index 000000000..969d40115 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/image/ImageFacade.java @@ -0,0 +1,166 @@ +package it.chalmers.gamma.app.image; + +import static it.chalmers.gamma.app.authentication.AccessGuard.isAdmin; +import static it.chalmers.gamma.app.authentication.AccessGuard.isSignedInUserMemberOfGroup; + +import it.chalmers.gamma.app.Facade; +import it.chalmers.gamma.app.authentication.AccessGuard; +import it.chalmers.gamma.app.group.domain.Group; +import it.chalmers.gamma.app.group.domain.GroupId; +import it.chalmers.gamma.app.group.domain.GroupRepository; +import it.chalmers.gamma.app.image.domain.Image; +import it.chalmers.gamma.app.image.domain.ImageService; +import it.chalmers.gamma.app.image.domain.ImageUri; +import it.chalmers.gamma.app.image.domain.UserAvatarRepository; +import it.chalmers.gamma.app.supergroup.domain.SuperGroupId; +import it.chalmers.gamma.app.user.domain.UserId; +import java.util.List; +import java.util.Optional; +import java.util.UUID; +import java.util.concurrent.ThreadLocalRandom; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; + +@Service +public class ImageFacade extends Facade { + + private static final Logger LOGGER = LoggerFactory.getLogger(ImageFacade.class); + + private final ImageService imageService; + private final GroupRepository groupRepository; + private final UserAvatarRepository userAvatarRepository; + + public ImageFacade( + AccessGuard accessGuard, + ImageService imageService, + GroupRepository groupRepository, + UserAvatarRepository userAvatarRepository) { + super(accessGuard); + this.imageService = imageService; + this.groupRepository = groupRepository; + this.userAvatarRepository = userAvatarRepository; + } + + public void setGroupBanner(UUID groupId, Image image) + throws ImageService.ImageCouldNotBeSavedException { + Group group = this.groupRepository.get(new GroupId(groupId)).orElseThrow(); + accessGuard.requireEither(isAdmin(), isSignedInUserMemberOfGroup(group)); + + ImageUri imageUri = this.imageService.saveImage(image); + this.groupRepository.save(group.withBannerUri(Optional.of(imageUri))); + } + + public ImageDetails getGroupBanner(UUID groupId) { + Group group = this.groupRepository.get(new GroupId(groupId)).orElseThrow(); + return new ImageDetails( + this.imageService.getImage(group.bannerUri().orElse(ImageUri.defaultGroupBanner()))); + } + + public void removeGroupBanner(UUID groupId) { + Group group = this.groupRepository.get(new GroupId(groupId)).orElseThrow(); + accessGuard.requireEither(isAdmin(), isSignedInUserMemberOfGroup(group)); + + ImageUri imageUri = group.bannerUri().orElseThrow(); + + try { + this.groupRepository.save(group.withBannerUri(Optional.empty())); + this.imageService.removeImage(imageUri); + } catch (ImageService.ImageCouldNotBeRemovedException e) { + throw new RuntimeException(e); + } + } + + public void setGroupAvatar(UUID groupId, Image image) + throws ImageService.ImageCouldNotBeSavedException { + Group group = this.groupRepository.get(new GroupId(groupId)).orElseThrow(); + accessGuard.requireEither(isAdmin(), isSignedInUserMemberOfGroup(group)); + + ImageUri imageUri = this.imageService.saveImage(image); + this.groupRepository.save(group.withAvatarUri(Optional.of(imageUri))); + } + + public ImageDetails getGroupAvatar(UUID groupId) { + Group group = this.groupRepository.get(new GroupId(groupId)).orElseThrow(); + return new ImageDetails( + this.imageService.getImage(group.avatarUri().orElse(ImageUri.defaultGroupAvatar()))); + } + + public void removeGroupAvatar(UUID groupId) { + Group group = this.groupRepository.get(new GroupId(groupId)).orElseThrow(); + accessGuard.requireEither(isAdmin(), isSignedInUserMemberOfGroup(group)); + + ImageUri imageUri = group.avatarUri().orElseThrow(); + + try { + this.groupRepository.save(group.withAvatarUri(Optional.empty())); + this.imageService.removeImage(imageUri); + } catch (ImageService.ImageCouldNotBeRemovedException e) { + throw new RuntimeException(e); + } + } + + public ImageDetails getAvatar(UUID userId) { + ImageUri avatarUri = + this.userAvatarRepository + .getAvatarUri(new UserId(userId)) + .orElse(ImageUri.defaultUserAvatar()); + return new ImageDetails(this.imageService.getImage(avatarUri)); + } + + public void removeUserAvatar(UUID userId) { + this.accessGuard.require(isAdmin()); + ImageUri avatarUri = this.userAvatarRepository.getAvatarUri(new UserId(userId)).orElseThrow(); + + try { + this.userAvatarRepository.removeAvatarUri(userId); + this.imageService.removeImage(avatarUri); + } catch (ImageService.ImageCouldNotBeRemovedException e) { + throw new RuntimeException(e); + } + } + + public ImageDetails getSuperGroupAvatar(UUID superGroupId) { + List groupAvatars = + this.groupRepository.getAllBySuperGroup(new SuperGroupId(superGroupId)).stream() + .map(Group::avatarUri) + .filter(Optional::isPresent) + .map(Optional::get) + .toList(); + + ImageUri randomAvatar = null; + if (!groupAvatars.isEmpty()) { + int randomIndex = ThreadLocalRandom.current().nextInt(groupAvatars.size()); + randomAvatar = groupAvatars.get(randomIndex); + } + + ImageUri image = randomAvatar != null ? randomAvatar : ImageUri.defaultGroupAvatar(); + + return new ImageDetails(this.imageService.getImage(image)); + } + + public ImageDetails getSuperGroupBanner(UUID superGroupId) { + List groupBanners = + this.groupRepository.getAllBySuperGroup(new SuperGroupId(superGroupId)).stream() + .map(Group::bannerUri) + .filter(Optional::isPresent) + .map(Optional::get) + .toList(); + + ImageUri randomBanner = null; + if (!groupBanners.isEmpty()) { + int randomIndex = ThreadLocalRandom.current().nextInt(groupBanners.size()); + randomBanner = groupBanners.get(randomIndex); + } + + ImageUri image = randomBanner != null ? randomBanner : ImageUri.defaultGroupBanner(); + + return new ImageDetails(this.imageService.getImage(image)); + } + + public record ImageDetails(byte[] data, String imageType) { + public ImageDetails(ImageService.ImageDetails image) { + this(image.data(), image.type()); + } + } +} diff --git a/app/src/main/java/it/chalmers/gamma/app/image/domain/Image.java b/app/src/main/java/it/chalmers/gamma/app/image/domain/Image.java new file mode 100644 index 000000000..2f7730a9a --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/image/domain/Image.java @@ -0,0 +1,3 @@ +package it.chalmers.gamma.app.image.domain; + +public interface Image {} diff --git a/app/src/main/java/it/chalmers/gamma/app/image/domain/ImageService.java b/app/src/main/java/it/chalmers/gamma/app/image/domain/ImageService.java new file mode 100644 index 000000000..56562aac6 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/image/domain/ImageService.java @@ -0,0 +1,24 @@ +package it.chalmers.gamma.app.image.domain; + +public interface ImageService { + + ImageUri saveImage(Image image) throws ImageCouldNotBeSavedException; + + void removeImage(ImageUri imageUri) throws ImageCouldNotBeRemovedException; + + ImageDetails getImage(ImageUri imageUri); + + record ImageDetails(byte[] data, String type) {} + + class ImageCouldNotBeRemovedException extends Exception {} + + class ImageCouldNotBeSavedException extends Exception { + public ImageCouldNotBeSavedException(String message) { + super(message); + } + + public ImageCouldNotBeSavedException(String message, Throwable cause) { + super(message, cause); + } + } +} diff --git a/app/src/main/java/it/chalmers/gamma/app/image/domain/ImageUri.java b/app/src/main/java/it/chalmers/gamma/app/image/domain/ImageUri.java new file mode 100644 index 000000000..848897429 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/image/domain/ImageUri.java @@ -0,0 +1,29 @@ +package it.chalmers.gamma.app.image.domain; + +import java.io.Serializable; + +public record ImageUri(String value) implements Serializable { + + public ImageUri { + if (value == null) { + throw new NullPointerException("Image Uri cannot be null"); + } else if (!(value.endsWith(".png") + || value.endsWith(".jpg") + || value.endsWith(".gif") + || value.endsWith(".jpeg"))) { + throw new IllegalArgumentException("Image uri must end with .png, .jpg, .jpeg or .gif"); + } + } + + public static ImageUri defaultGroupBanner() { + return new ImageUri("default_group_banner.jpg"); + } + + public static ImageUri defaultGroupAvatar() { + return new ImageUri("default_group_avatar.jpg"); + } + + public static ImageUri defaultUserAvatar() { + return new ImageUri("default_user_avatar.jpg"); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/app/image/domain/UserAvatarRepository.java b/app/src/main/java/it/chalmers/gamma/app/image/domain/UserAvatarRepository.java new file mode 100644 index 000000000..b94537574 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/image/domain/UserAvatarRepository.java @@ -0,0 +1,12 @@ +package it.chalmers.gamma.app.image.domain; + +import it.chalmers.gamma.app.user.domain.UserId; +import java.util.Optional; +import java.util.UUID; + +public interface UserAvatarRepository { + + Optional getAvatarUri(UserId userId); + + void removeAvatarUri(UUID userId); +} diff --git a/app/src/main/java/it/chalmers/gamma/app/mail/domain/MailService.java b/app/src/main/java/it/chalmers/gamma/app/mail/domain/MailService.java new file mode 100644 index 000000000..e423b680f --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/mail/domain/MailService.java @@ -0,0 +1,5 @@ +package it.chalmers.gamma.app.mail.domain; + +public interface MailService { + void sendMail(String email, String subject, String body); +} diff --git a/app/src/main/java/it/chalmers/gamma/app/oauth2/ClaimsMapper.java b/app/src/main/java/it/chalmers/gamma/app/oauth2/ClaimsMapper.java new file mode 100644 index 000000000..64fc8f975 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/oauth2/ClaimsMapper.java @@ -0,0 +1,53 @@ +package it.chalmers.gamma.app.oauth2; + +import it.chalmers.gamma.app.user.domain.GammaUser; +import it.chalmers.gamma.app.user.domain.UserId; +import it.chalmers.gamma.app.user.domain.UserRepository; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class ClaimsMapper { + + private final UserRepository userRepository; + private final String baseUrl; + + private ClaimsMapper( + UserRepository userRepository, @Value("${application.base-url}") String baseUrl) { + this.userRepository = userRepository; + this.baseUrl = baseUrl; + } + + public Map generateClaims(List scopes, UserId userId) { + GammaUser me = this.userRepository.get(userId).orElseThrow(); + + final String PROFILE_SCOPE = "SCOPE_profile"; + final String EMAIL_SCOPE = "SCOPE_email"; + + Map claims = new HashMap<>(); + + for (String scope : scopes) { + if (scope.equals(PROFILE_SCOPE)) { + // https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims + claims.put( + "name", + me.firstName().value() + " '" + me.nick().value() + "' " + me.lastName().value()); + claims.put("given_name", me.firstName().value()); + claims.put("family_name", me.lastName().value()); + claims.put("nickname", me.nick().value()); + claims.put("locale", me.language().toString().toLowerCase()); + claims.put("picture", this.baseUrl + "/images/user/avatar/" + me.id().value()); + + // Non-standard claims. + claims.put("cid", me.cid().value()); + } else if (scope.equals(EMAIL_SCOPE)) { + claims.put("email", me.extended().email().value()); + } + } + + return claims; + } +} diff --git a/app/src/main/java/it/chalmers/gamma/app/oauth2/GammaAuthorizationConsentService.java b/app/src/main/java/it/chalmers/gamma/app/oauth2/GammaAuthorizationConsentService.java new file mode 100644 index 000000000..f590600c2 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/oauth2/GammaAuthorizationConsentService.java @@ -0,0 +1,83 @@ +package it.chalmers.gamma.app.oauth2; + +import it.chalmers.gamma.app.client.domain.Client; +import it.chalmers.gamma.app.client.domain.ClientRepository; +import it.chalmers.gamma.app.client.domain.ClientUid; +import it.chalmers.gamma.app.user.domain.UserId; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsent; +import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsentService; +import org.springframework.stereotype.Component; + +@Component +public class GammaAuthorizationConsentService implements OAuth2AuthorizationConsentService { + + private final Logger LOGGER = LoggerFactory.getLogger(GammaAuthorizationConsentService.class); + private final ClientRepository clientRepository; + + public GammaAuthorizationConsentService(ClientRepository clientRepository) { + this.clientRepository = clientRepository; + } + + @Override + public void save(OAuth2AuthorizationConsent authorizationConsent) { + Client client = + this.clientRepository + .get(ClientUid.valueOf(authorizationConsent.getRegisteredClientId())) + .orElseThrow(); + + List consentedScopes = + authorizationConsent.getScopes().stream().map(String::toLowerCase).sorted().toList(); + + List clientScopes = + new ArrayList<>(client.scopes().stream().map(scope -> scope.name().toLowerCase()).toList()); + clientScopes.add("openid"); + clientScopes.sort(String::compareTo); + + if (consentedScopes.size() != clientScopes.size() || !consentedScopes.equals(clientScopes)) { + throw new IllegalStateException( + "Must have the same scopes for the authorize request and what is on the client." + + "Consent scopes: " + + consentedScopes + + "Client scopes: " + + clientScopes); + } + + this.clientRepository.addClientApproval( + UserId.valueOf(authorizationConsent.getPrincipalName()), + ClientUid.valueOf(authorizationConsent.getRegisteredClientId())); + } + + @Override + public void remove(OAuth2AuthorizationConsent authorizationConsent) { + // Use instead MeFacade.deleteUserApproval + throw new UnsupportedOperationException(); + } + + @Override + public OAuth2AuthorizationConsent findById(String registeredClientId, String principalName) { + if (this.clientRepository.isApprovedByUser( + UserId.valueOf(principalName), ClientUid.valueOf(registeredClientId))) { + Optional maybeClient = + this.clientRepository.get(ClientUid.valueOf(registeredClientId)); + + if (maybeClient.isEmpty()) { + return null; + } + + Client client = maybeClient.get(); + OAuth2AuthorizationConsent.Builder consentBuilder = + OAuth2AuthorizationConsent.withId(registeredClientId, principalName); + client.scopes().forEach(scope -> consentBuilder.scope(scope.name().toLowerCase())); + consentBuilder.scope("openid"); + + return consentBuilder.build(); + } + + return null; + } +} diff --git a/app/src/main/java/it/chalmers/gamma/app/oauth2/GammaAuthorizationService.java b/app/src/main/java/it/chalmers/gamma/app/oauth2/GammaAuthorizationService.java new file mode 100644 index 000000000..8f3be7afb --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/oauth2/GammaAuthorizationService.java @@ -0,0 +1,95 @@ +package it.chalmers.gamma.app.oauth2; + +import it.chalmers.gamma.app.client.domain.Client; +import it.chalmers.gamma.app.client.domain.ClientRepository; +import it.chalmers.gamma.app.client.domain.ClientUid; +import it.chalmers.gamma.app.client.domain.restriction.ClientRestriction; +import it.chalmers.gamma.app.group.domain.GroupRepository; +import it.chalmers.gamma.app.oauth2.domain.GammaAuthorizationRepository; +import it.chalmers.gamma.app.oauth2.domain.GammaAuthorizationToken; +import it.chalmers.gamma.app.supergroup.domain.SuperGroupId; +import it.chalmers.gamma.app.user.domain.UserId; +import it.chalmers.gamma.app.user.domain.UserMembership; +import java.util.List; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.oauth2.server.authorization.OAuth2Authorization; +import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService; +import org.springframework.security.oauth2.server.authorization.OAuth2TokenType; +import org.springframework.stereotype.Component; + +@Component +public class GammaAuthorizationService implements OAuth2AuthorizationService { + + private final Logger LOGGER = LoggerFactory.getLogger(GammaAuthorizationService.class); + private final GammaAuthorizationRepository gammaAuthorizationRepository; + private final ClientRepository clientRepository; + private final GroupRepository groupRepository; + + public GammaAuthorizationService( + GammaAuthorizationRepository gammaAuthorizationRepository, + ClientRepository clientRepository, + GroupRepository groupRepository) { + this.gammaAuthorizationRepository = gammaAuthorizationRepository; + this.clientRepository = clientRepository; + this.groupRepository = groupRepository; + } + + @Override + public void save(OAuth2Authorization authorization) { + UsernamePasswordAuthenticationToken authenticationToken = + authorization.getAttribute("java.security.Principal"); + + if (authenticationToken != null && authenticationToken.getPrincipal() instanceof User user) { + Client client = + this.clientRepository + .get(ClientUid.valueOf(authorization.getRegisteredClientId())) + .orElseThrow(); + + // If the client has no restrictions, then any user can sign in. + if (client.restrictions().isPresent() + && !client.restrictions().get().superGroups().isEmpty() + && !userPassesRestriction(client.restrictions().get(), user)) { + throw new UserNotAllowedRuntimeException(); + } + } + + gammaAuthorizationRepository.save(authorization); + } + + private boolean userPassesRestriction(ClientRestriction restriction, User user) { + UserId userId = UserId.valueOf(user.getUsername()); + + List memberships = this.groupRepository.getAllByUser(userId); + List userSuperGroups = + memberships.stream() + .map(UserMembership::group) + .map(group -> group.superGroup().id()) + .distinct() + .toList(); + + return restriction.superGroups().stream() + .anyMatch(superGroup -> userSuperGroups.contains(superGroup.id())); + } + + @Override + public void remove(OAuth2Authorization authorization) { + gammaAuthorizationRepository.remove(authorization); + } + + @Override + public OAuth2Authorization findById(String id) { + return gammaAuthorizationRepository.findById(id).orElseThrow(); + } + + @Override + public OAuth2Authorization findByToken(String token, OAuth2TokenType tokenType) { + return gammaAuthorizationRepository + .findByToken(GammaAuthorizationToken.valueOf(token, tokenType)) + .orElseThrow(); + } + + public static class UserNotAllowedRuntimeException extends RuntimeException {} +} diff --git a/app/src/main/java/it/chalmers/gamma/app/oauth2/GammaRegisteredClientRepository.java b/app/src/main/java/it/chalmers/gamma/app/oauth2/GammaRegisteredClientRepository.java new file mode 100644 index 000000000..8d87f761c --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/oauth2/GammaRegisteredClientRepository.java @@ -0,0 +1,75 @@ +package it.chalmers.gamma.app.oauth2; + +import it.chalmers.gamma.app.client.domain.*; +import org.springframework.security.oauth2.core.AuthorizationGrantType; +import org.springframework.security.oauth2.core.ClientAuthenticationMethod; +import org.springframework.security.oauth2.server.authorization.client.RegisteredClient; +import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository; +import org.springframework.security.oauth2.server.authorization.settings.ClientSettings; +import org.springframework.stereotype.Component; + +@Component +public class GammaRegisteredClientRepository implements RegisteredClientRepository { + + public static final String IS_OFFICIAL = "_is_official"; + + private final ClientRepository clientRepository; + + public GammaRegisteredClientRepository(ClientRepository clientRepository) { + this.clientRepository = clientRepository; + } + + @Override + public void save(RegisteredClient registeredClient) { + throw new UnsupportedOperationException("Use ClientFacade instead."); + } + + @Override + public RegisteredClient findById(String id) { + try { + return this.clientRepository + .get(ClientUid.valueOf(id)) + .map(this::toRegisteredClient) + .orElse(null); + } catch (IllegalArgumentException e) { + return null; + } + } + + @Override + public RegisteredClient findByClientId(String clientId) { + try { + return this.clientRepository + .get(new ClientId(clientId)) + .map(this::toRegisteredClient) + .orElse(null); + } catch (IllegalArgumentException e) { + return null; + } + } + + private RegisteredClient toRegisteredClient(Client client) { + RegisteredClient.Builder builder = + RegisteredClient.withId(client.clientUid().getValue()) + .clientId(client.clientId().value()) + .clientSecret(client.clientSecret().value()) + .redirectUri(client.clientRedirectUrl().value()) + .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE) + .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC) + .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_POST) + .clientName(client.prettyName().value()) + .clientSettings( + ClientSettings.builder() + .requireAuthorizationConsent(true) + .setting(IS_OFFICIAL, client.owner() instanceof ClientOwnerOfficial) + .build()); + + builder.scope("openid"); + + for (Scope scope : client.scopes()) { + builder.scope(scope.name().toLowerCase()); + } + + return builder.build(); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/app/oauth2/UserInfoMapper.java b/app/src/main/java/it/chalmers/gamma/app/oauth2/UserInfoMapper.java new file mode 100644 index 000000000..3d02b6d55 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/oauth2/UserInfoMapper.java @@ -0,0 +1,36 @@ +package it.chalmers.gamma.app.oauth2; + +import it.chalmers.gamma.app.user.domain.UserId; +import java.util.HashMap; +import java.util.Map; +import java.util.function.Function; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.oauth2.core.oidc.OidcUserInfo; +import org.springframework.security.oauth2.server.authorization.oidc.authentication.OidcUserInfoAuthenticationContext; +import org.springframework.security.oauth2.server.authorization.oidc.authentication.OidcUserInfoAuthenticationToken; +import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken; +import org.springframework.stereotype.Component; + +@Component +public class UserInfoMapper implements Function { + + private final ClaimsMapper claimsMapper; + + public UserInfoMapper(ClaimsMapper claimsMapper) { + this.claimsMapper = claimsMapper; + } + + public OidcUserInfo apply(OidcUserInfoAuthenticationContext context) { + OidcUserInfoAuthenticationToken authentication = context.getAuthentication(); + JwtAuthenticationToken principal = (JwtAuthenticationToken) authentication.getPrincipal(); + + Map claims = new HashMap<>(principal.getToken().getClaims()); + + claims.putAll( + this.claimsMapper.generateClaims( + principal.getAuthorities().stream().map(GrantedAuthority::getAuthority).toList(), + UserId.valueOf(principal.getName()))); + + return new OidcUserInfo(claims); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/app/oauth2/domain/GammaAuthorizationRepository.java b/app/src/main/java/it/chalmers/gamma/app/oauth2/domain/GammaAuthorizationRepository.java new file mode 100644 index 000000000..5f04e4560 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/oauth2/domain/GammaAuthorizationRepository.java @@ -0,0 +1,15 @@ +package it.chalmers.gamma.app.oauth2.domain; + +import java.util.Optional; +import org.springframework.security.oauth2.server.authorization.OAuth2Authorization; + +public interface GammaAuthorizationRepository { + + void save(OAuth2Authorization authorization); + + void remove(OAuth2Authorization authorization); + + Optional findById(String id); + + Optional findByToken(GammaAuthorizationToken token); +} diff --git a/app/src/main/java/it/chalmers/gamma/app/oauth2/domain/GammaAuthorizationToken.java b/app/src/main/java/it/chalmers/gamma/app/oauth2/domain/GammaAuthorizationToken.java new file mode 100644 index 000000000..730679c65 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/oauth2/domain/GammaAuthorizationToken.java @@ -0,0 +1,24 @@ +package it.chalmers.gamma.app.oauth2.domain; + +import org.springframework.security.oauth2.server.authorization.OAuth2TokenType; + +public record GammaAuthorizationToken(String value, Type type) { + + public static GammaAuthorizationToken valueOf(String value, OAuth2TokenType auth2TokenType) { + return switch (auth2TokenType.getValue()) { + case "access_token" -> new GammaAuthorizationToken(value, Type.ACCESS_TOKEN); + case "code" -> new GammaAuthorizationToken(value, Type.CODE); + case "state" -> new GammaAuthorizationToken(value, Type.STATE); + case "oidc" -> new GammaAuthorizationToken(value, Type.OIDC); + default -> + throw new IllegalArgumentException("Invalid rawToken type: " + auth2TokenType.getValue()); + }; + } + + public enum Type { + CODE, + ACCESS_TOKEN, + STATE, + OIDC + } +} diff --git a/app/src/main/java/it/chalmers/gamma/app/post/PostFacade.java b/app/src/main/java/it/chalmers/gamma/app/post/PostFacade.java new file mode 100644 index 000000000..ddd6b0ef1 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/post/PostFacade.java @@ -0,0 +1,140 @@ +package it.chalmers.gamma.app.post; + +import static it.chalmers.gamma.app.authentication.AccessGuard.isAdmin; +import static it.chalmers.gamma.app.authentication.AccessGuard.isSignedIn; + +import it.chalmers.gamma.app.Facade; +import it.chalmers.gamma.app.authentication.AccessGuard; +import it.chalmers.gamma.app.common.Text; +import it.chalmers.gamma.app.group.GroupFacade; +import it.chalmers.gamma.app.group.domain.EmailPrefix; +import it.chalmers.gamma.app.group.domain.GroupRepository; +import it.chalmers.gamma.app.post.domain.Order; +import it.chalmers.gamma.app.post.domain.Post; +import it.chalmers.gamma.app.post.domain.PostId; +import it.chalmers.gamma.app.post.domain.PostRepository; +import jakarta.transaction.Transactional; +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; +import org.springframework.stereotype.Service; + +@Service +public class PostFacade extends Facade { + + private final PostRepository postRepository; + private final GroupRepository groupRepository; + + public PostFacade( + AccessGuard accessGuard, PostRepository postRepository, GroupRepository groupRepository) { + super(accessGuard); + this.postRepository = postRepository; + this.groupRepository = groupRepository; + } + + public UUID create(NewPost newPost) { + accessGuard.require(isAdmin()); + + PostId postId = PostId.generate(); + + if (newPost.svText.isEmpty() || newPost.enText.isEmpty()) { + throw new IllegalArgumentException("Post names must not be empty"); + } + + this.postRepository.save( + new Post( + postId, + 0, + new Text(newPost.svText, newPost.enText), + new EmailPrefix(newPost.emailPrefix), + new Order(this.postRepository.numberOfPosts()))); + + return postId.value(); + } + + public void update(UpdatePost updatePost) throws PostRepository.PostNotFoundException { + accessGuard.require(isAdmin()); + + Post oldPost = this.postRepository.get(new PostId(updatePost.postId)).orElseThrow(); + Post newPost = + oldPost + .with() + .version(updatePost.version) + .name(new Text(updatePost.svText, updatePost.enText)) + .emailPrefix(new EmailPrefix(updatePost.emailPrefix)) + .build(); + + this.postRepository.save(newPost); + } + + public void delete(UUID postId) throws PostRepository.PostNotFoundException { + accessGuard.require(isAdmin()); + + this.postRepository.delete(new PostId(postId)); + } + + public Optional get(UUID postId) { + this.accessGuard.require(isSignedIn()); + + return this.postRepository.get(new PostId(postId)).map(PostDTO::new); + } + + public List getAll() { + this.accessGuard.require(isSignedIn()); + + return this.postRepository.getAll().stream().map(PostDTO::new).toList(); + } + + public List getPostUsages(UUID postId) { + this.accessGuard.require(isSignedIn()); + + return this.groupRepository.getAllByPost(new PostId(postId)).stream() + .map(GroupFacade.GroupWithMembersDTO::new) + .toList(); + } + + @Transactional + public void setOrder(List orderedPosts) { + this.accessGuard.require(isAdmin()); + + Map posts = + this.postRepository.getAll().stream() + .collect(Collectors.toMap(Post::id, Function.identity())); + + boolean anythingChanged = false; + + for (int i = 0; i < orderedPosts.size(); i++) { + UUID orderedPostId = orderedPosts.get(i); + Post post = posts.get(new PostId(orderedPostId)); + if (post == null) { + throw new IllegalArgumentException("Unexpected post id"); + } + + anythingChanged = anythingChanged || post.order().value() != i; + + posts.put(post.id(), post.withOrder(new Order(i))); + } + + if (anythingChanged) { + this.postRepository.saveAll(new ArrayList<>(posts.values())); + } + } + + public record NewPost(String svText, String enText, String emailPrefix) {} + + public record UpdatePost( + UUID postId, int version, String svText, String enText, String emailPrefix) {} + + public record PostDTO( + UUID id, int version, String svName, String enName, String emailPrefix, int order) { + public PostDTO(Post post) { + this( + post.id().value(), + post.version(), + post.name().sv().value(), + post.name().en().value(), + post.emailPrefix().value(), + post.order().value()); + } + } +} diff --git a/app/src/main/java/it/chalmers/gamma/app/post/domain/Order.java b/app/src/main/java/it/chalmers/gamma/app/post/domain/Order.java new file mode 100644 index 000000000..831ebb9bf --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/post/domain/Order.java @@ -0,0 +1,10 @@ +package it.chalmers.gamma.app.post.domain; + +public record Order(int value) { + + public Order { + if (value < 0) { + throw new IllegalArgumentException("order must be >= 0"); + } + } +} diff --git a/app/src/main/java/it/chalmers/gamma/app/post/domain/Post.java b/app/src/main/java/it/chalmers/gamma/app/post/domain/Post.java new file mode 100644 index 000000000..a84662360 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/post/domain/Post.java @@ -0,0 +1,17 @@ +package it.chalmers.gamma.app.post.domain; + +import io.soabase.recordbuilder.core.RecordBuilder; +import it.chalmers.gamma.app.common.Text; +import it.chalmers.gamma.app.group.domain.EmailPrefix; +import java.util.Objects; + +@RecordBuilder +public record Post(PostId id, int version, Text name, EmailPrefix emailPrefix, Order order) + implements PostBuilder.With { + + public Post { + Objects.requireNonNull(id); + Objects.requireNonNull(name); + Objects.requireNonNull(emailPrefix); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/app/post/domain/PostId.java b/app/src/main/java/it/chalmers/gamma/app/post/domain/PostId.java new file mode 100644 index 000000000..866b4db4b --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/post/domain/PostId.java @@ -0,0 +1,25 @@ +package it.chalmers.gamma.app.post.domain; + +import it.chalmers.gamma.app.common.Id; +import java.util.Objects; +import java.util.UUID; + +public record PostId(UUID value) implements Id { + + public PostId { + Objects.requireNonNull(value); + } + + public static PostId generate() { + return new PostId(UUID.randomUUID()); + } + + public static PostId valueOf(String value) { + return new PostId(UUID.fromString(value)); + } + + @Override + public UUID getValue() { + return this.value; + } +} diff --git a/app/src/main/java/it/chalmers/gamma/app/post/domain/PostRepository.java b/app/src/main/java/it/chalmers/gamma/app/post/domain/PostRepository.java new file mode 100644 index 000000000..0aad318ea --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/post/domain/PostRepository.java @@ -0,0 +1,21 @@ +package it.chalmers.gamma.app.post.domain; + +import java.util.List; +import java.util.Optional; + +public interface PostRepository { + + void save(Post post); + + void saveAll(List posts); + + void delete(PostId postId) throws PostNotFoundException; + + List getAll(); + + Optional get(PostId postId); + + int numberOfPosts(); + + class PostNotFoundException extends Exception {} +} diff --git a/app/src/main/java/it/chalmers/gamma/app/supergroup/SuperGroupFacade.java b/app/src/main/java/it/chalmers/gamma/app/supergroup/SuperGroupFacade.java new file mode 100644 index 000000000..e80e20644 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/supergroup/SuperGroupFacade.java @@ -0,0 +1,228 @@ +package it.chalmers.gamma.app.supergroup; + +import static it.chalmers.gamma.app.authentication.AccessGuard.*; + +import it.chalmers.gamma.app.Facade; +import it.chalmers.gamma.app.apikey.domain.ApiKeyType; +import it.chalmers.gamma.app.apikey.domain.settings.ApiKeySettingsRepository; +import it.chalmers.gamma.app.authentication.AccessGuard; +import it.chalmers.gamma.app.common.PrettyName; +import it.chalmers.gamma.app.common.Text; +import it.chalmers.gamma.app.group.GroupFacade; +import it.chalmers.gamma.app.group.domain.Group; +import it.chalmers.gamma.app.group.domain.GroupRepository; +import it.chalmers.gamma.app.supergroup.domain.*; +import it.chalmers.gamma.app.user.domain.Name; +import it.chalmers.gamma.security.authentication.ApiAuthentication; +import it.chalmers.gamma.security.authentication.AuthenticationExtractor; +import java.util.*; +import org.springframework.stereotype.Service; + +@Service +public class SuperGroupFacade extends Facade { + + private final SuperGroupRepository superGroupRepository; + private final SuperGroupTypeRepository superGroupTypeRepository; + private final GroupRepository groupRepository; + private final ApiKeySettingsRepository apiKeySettingsRepository; + + public SuperGroupFacade( + AccessGuard accessGuard, + SuperGroupRepository superGroupRepository, + SuperGroupTypeRepository superGroupTypeRepository, + GroupRepository groupRepository, + ApiKeySettingsRepository apiKeySettingsRepository) { + super(accessGuard); + this.superGroupRepository = superGroupRepository; + this.superGroupTypeRepository = superGroupTypeRepository; + this.groupRepository = groupRepository; + this.apiKeySettingsRepository = apiKeySettingsRepository; + } + + public void addType(String type) + throws SuperGroupTypeRepository.SuperGroupTypeAlreadyExistsException { + accessGuard.require(isAdmin()); + + this.superGroupTypeRepository.add(new SuperGroupType(type)); + } + + public void removeType(String type) + throws SuperGroupTypeRepository.SuperGroupTypeNotFoundException, + SuperGroupTypeRepository.SuperGroupTypeHasUsagesException { + accessGuard.require(isAdmin()); + + this.superGroupTypeRepository.delete(new SuperGroupType(type)); + } + + public List getAllTypes() { + accessGuard.requireEither(isAdmin(), isSignedIn()); + + return this.superGroupTypeRepository.getAll().stream().map(SuperGroupType::value).toList(); + } + + public List getAllTypesWithSuperGroups() { + accessGuard.requireEither(isAdmin(), isApi(ApiKeyType.INFO)); + + List superGroupTypes; + + if (AuthenticationExtractor.getAuthentication() + instanceof ApiAuthentication apiAuthentication) { + superGroupTypes = + this.apiKeySettingsRepository + .getInfoSettings(apiAuthentication.get().id()) + .superGroupTypes(); + } else { + superGroupTypes = this.superGroupTypeRepository.getAll(); + } + + List output = new ArrayList<>(); + + for (SuperGroupType type : superGroupTypes) { + List superGroupsOutput = new ArrayList<>(); + for (SuperGroup superGroup : this.superGroupRepository.getAllByType(type)) { + List groups = this.groupRepository.getAllBySuperGroup(superGroup.id()); + + boolean hasAvatar = + groups.stream() + .map(Group::avatarUri) + .map(Optional::isPresent) + .reduce(false, (a, b) -> a || b); + boolean hasBanner = + groups.stream() + .map(Group::bannerUri) + .map(Optional::isPresent) + .reduce(false, (a, b) -> a || b); + List members = + groups.stream() + .flatMap(group -> group.groupMembers().stream()) + .map(GroupFacade.GroupMemberDTO::new) + .sorted(Comparator.comparingInt(member -> member.post().order())) + .toList(); + + superGroupsOutput.add( + new SuperGroupWithMembersDTO( + new SuperGroupDTO(superGroup), hasBanner, hasAvatar, members)); + } + + output.add(new SuperGroupTypeDTO(type.value(), superGroupsOutput)); + } + + return output; + } + + public record SuperGroupWithMembersDTO( + SuperGroupDTO superGroup, + boolean hasBanner, + boolean hasAvatar, + List members) {} + + public record SuperGroupTypeDTO(String type, List superGroups) {} + + public UUID createSuperGroup(NewSuperGroup newSuperGroup) + throws SuperGroupRepository.SuperGroupAlreadyExistsException { + accessGuard.require(isAdmin()); + + SuperGroupId superGroupId = SuperGroupId.generate(); + + this.superGroupRepository.save( + new SuperGroup( + superGroupId, + 0, + new Name(newSuperGroup.name), + new PrettyName(newSuperGroup.prettyName), + new SuperGroupType(newSuperGroup.superGroupType), + new Text(newSuperGroup.svDescription, newSuperGroup.enDescription))); + + return superGroupId.value(); + } + + public void updateSuperGroup(UpdateSuperGroup updateSuperGroup) + throws SuperGroupRepository.SuperGroupNotFoundException { + accessGuard.require(isAdmin()); + + SuperGroup oldSuperGroup = + this.superGroupRepository.get(new SuperGroupId(updateSuperGroup.id)).orElseThrow(); + SuperGroup newSuperGroup = + SuperGroupBuilder.builder(oldSuperGroup) + .name(new Name(updateSuperGroup.name)) + .prettyName(new PrettyName(updateSuperGroup.prettyName)) + .type(new SuperGroupType(updateSuperGroup.type)) + .description(new Text(updateSuperGroup.svDescription, updateSuperGroup.enDescription)) + .build(); + + this.superGroupRepository.save(newSuperGroup); + } + + public void deleteSuperGroup(UUID superGroupId) + throws SuperGroupIsUsedException, SuperGroupNotFoundException { + accessGuard.require(isAdmin()); + + try { + this.superGroupRepository.delete(new SuperGroupId(superGroupId)); + } catch (SuperGroupRepository.SuperGroupNotFoundException e) { + throw new SuperGroupNotFoundException(); + } catch (SuperGroupRepository.SuperGroupIsUsedException e) { + throw new SuperGroupIsUsedException(); + } + } + + public List getAll() { + accessGuard.requireEither(isAdmin(), isClientApi(), isSignedIn()); + + return this.superGroupRepository.getAll().stream().map(SuperGroupDTO::new).toList(); + } + + public List getAllSuperGroupsByType(String superGroupType) { + accessGuard.require(isAdmin()); + + return this.superGroupRepository.getAllByType(new SuperGroupType(superGroupType)).stream() + .map(SuperGroupDTO::new) + .toList(); + } + + public Optional get(UUID superGroupId) { + accessGuard.require(isSignedIn()); + + return this.superGroupRepository.get(new SuperGroupId(superGroupId)).map(SuperGroupDTO::new); + } + + public record NewSuperGroup( + String name, + String prettyName, + String superGroupType, + String svDescription, + String enDescription) {} + + public record UpdateSuperGroup( + UUID id, + int version, + String name, + String prettyName, + String type, + String svDescription, + String enDescription) {} + + public record SuperGroupDTO( + UUID id, + int version, + String name, + String prettyName, + String type, + String svDescription, + String enDescription) { + public SuperGroupDTO(SuperGroup superGroup) { + this( + superGroup.id().value(), + superGroup.version(), + superGroup.name().value(), + superGroup.prettyName().value(), + superGroup.type().value(), + superGroup.description().sv().value(), + superGroup.description().en().value()); + } + } + + public static class SuperGroupNotFoundException extends Exception {} + + public static class SuperGroupIsUsedException extends Exception {} +} diff --git a/app/src/main/java/it/chalmers/gamma/app/supergroup/domain/SuperGroup.java b/app/src/main/java/it/chalmers/gamma/app/supergroup/domain/SuperGroup.java new file mode 100644 index 000000000..2da419339 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/supergroup/domain/SuperGroup.java @@ -0,0 +1,26 @@ +package it.chalmers.gamma.app.supergroup.domain; + +import io.soabase.recordbuilder.core.RecordBuilder; +import it.chalmers.gamma.app.common.PrettyName; +import it.chalmers.gamma.app.common.Text; +import it.chalmers.gamma.app.user.domain.Name; +import java.util.Objects; + +@RecordBuilder +public record SuperGroup( + SuperGroupId id, + int version, + Name name, + PrettyName prettyName, + SuperGroupType type, + Text description) + implements SuperGroupBuilder.With { + + public SuperGroup { + Objects.requireNonNull(id); + Objects.requireNonNull(name); + Objects.requireNonNull(prettyName); + Objects.requireNonNull(type); + Objects.requireNonNull(description); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/app/supergroup/domain/SuperGroupId.java b/app/src/main/java/it/chalmers/gamma/app/supergroup/domain/SuperGroupId.java new file mode 100644 index 000000000..28349cefe --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/supergroup/domain/SuperGroupId.java @@ -0,0 +1,25 @@ +package it.chalmers.gamma.app.supergroup.domain; + +import it.chalmers.gamma.app.common.Id; +import java.util.Objects; +import java.util.UUID; + +public record SuperGroupId(UUID value) implements Id { + + public SuperGroupId { + Objects.requireNonNull(value); + } + + public static SuperGroupId generate() { + return new SuperGroupId(UUID.randomUUID()); + } + + public static SuperGroupId valueOf(String value) { + return new SuperGroupId(UUID.fromString(value)); + } + + @Override + public UUID getValue() { + return this.value; + } +} diff --git a/app/src/main/java/it/chalmers/gamma/app/supergroup/domain/SuperGroupRepository.java b/app/src/main/java/it/chalmers/gamma/app/supergroup/domain/SuperGroupRepository.java new file mode 100644 index 000000000..5abf01175 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/supergroup/domain/SuperGroupRepository.java @@ -0,0 +1,29 @@ +package it.chalmers.gamma.app.supergroup.domain; + +import java.util.List; +import java.util.Optional; + +public interface SuperGroupRepository { + + void save(SuperGroup superGroup) + throws NameAlreadyExistsRuntimeException, TypeNotFoundRuntimeException; + + void delete(SuperGroupId superGroupId) + throws SuperGroupNotFoundException, SuperGroupIsUsedException; + + List getAll(); + + List getAllByType(SuperGroupType superGroupType); + + Optional get(SuperGroupId superGroupId); + + class SuperGroupAlreadyExistsException extends Exception {} + + class SuperGroupNotFoundException extends Exception {} + + class SuperGroupIsUsedException extends Exception {} + + class NameAlreadyExistsRuntimeException extends RuntimeException {} + + class TypeNotFoundRuntimeException extends RuntimeException {} +} diff --git a/app/src/main/java/it/chalmers/gamma/app/supergroup/domain/SuperGroupType.java b/app/src/main/java/it/chalmers/gamma/app/supergroup/domain/SuperGroupType.java new file mode 100644 index 000000000..bb1776b57 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/supergroup/domain/SuperGroupType.java @@ -0,0 +1,38 @@ +package it.chalmers.gamma.app.supergroup.domain; + +import static it.chalmers.gamma.app.validation.ValidationHelper.*; + +import it.chalmers.gamma.app.common.Id; +import it.chalmers.gamma.app.validation.ValidationResult; +import it.chalmers.gamma.app.validation.Validator; +import java.util.regex.Pattern; + +public record SuperGroupType(String value) implements Id { + + public SuperGroupType { + throwIfFailed(new SuperGroupTypeValidator().validate(value)); + } + + public static SuperGroupType valueOf(String name) { + return new SuperGroupType(name); + } + + @Override + public String getValue() { + return this.value; + } + + public static final class SuperGroupTypeValidator implements Validator { + + private static final Pattern pattern = Pattern.compile("^([a-z]{3,30})$"); + + @Override + public ValidationResult validate(String value) { + return withValidators( + IS_NOT_EMPTY, + MATCHES_REGEX.apply( + new RegexMatcher(pattern, "must be made using a-z, with length between 3-30"))) + .validate(value); + } + } +} diff --git a/app/src/main/java/it/chalmers/gamma/app/supergroup/domain/SuperGroupTypeRepository.java b/app/src/main/java/it/chalmers/gamma/app/supergroup/domain/SuperGroupTypeRepository.java new file mode 100644 index 000000000..1ecbf3ef4 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/supergroup/domain/SuperGroupTypeRepository.java @@ -0,0 +1,23 @@ +package it.chalmers.gamma.app.supergroup.domain; + +import java.util.List; + +public interface SuperGroupTypeRepository { + + void add(SuperGroupType superGroupType) throws SuperGroupTypeAlreadyExistsException; + + void delete(SuperGroupType superGroupType) + throws SuperGroupTypeNotFoundException, SuperGroupTypeHasUsagesException; + + List getAll(); + + class SuperGroupTypeAlreadyExistsException extends Exception { + public SuperGroupTypeAlreadyExistsException(String value) { + super("Super group type: " + value + " already exists"); + } + } + + class SuperGroupTypeNotFoundException extends Exception {} + + class SuperGroupTypeHasUsagesException extends Exception {} +} diff --git a/app/src/main/java/it/chalmers/gamma/app/throttling/ThrottlingManagementFacade.java b/app/src/main/java/it/chalmers/gamma/app/throttling/ThrottlingManagementFacade.java new file mode 100644 index 000000000..9e37f22ef --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/throttling/ThrottlingManagementFacade.java @@ -0,0 +1,48 @@ +package it.chalmers.gamma.app.throttling; + +import static it.chalmers.gamma.app.authentication.AccessGuard.isAdmin; + +import it.chalmers.gamma.app.Facade; +import it.chalmers.gamma.app.authentication.AccessGuard; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Service; + +@Service +public class ThrottlingManagementFacade extends Facade { + + private final StringRedisTemplate redisTemplate; + + public ThrottlingManagementFacade(AccessGuard accessGuard, StringRedisTemplate redisTemplate) { + super(accessGuard); + this.redisTemplate = redisTemplate; + } + + public record KeyValue(String key, String value) {} + + public List getAll() { + super.accessGuard.require(isAdmin()); + + Set keys = redisTemplate.keys("throttle:*"); + List result = new ArrayList<>(); + + if (keys != null) { + for (String key : keys) { + String value = redisTemplate.opsForValue().get(key); + String trimmedKey = key.substring("throttle:".length()); + result.add(new KeyValue(trimmedKey, value)); + } + } + + return result; + } + + public void deleteKey(String key) { + super.accessGuard.require(isAdmin()); + + String prefixedKey = "throttle:" + key; + redisTemplate.delete(prefixedKey); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/app/throttling/ThrottlingService.java b/app/src/main/java/it/chalmers/gamma/app/throttling/ThrottlingService.java new file mode 100644 index 000000000..f11d9d6d2 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/throttling/ThrottlingService.java @@ -0,0 +1,32 @@ +package it.chalmers.gamma.app.throttling; + +import java.util.concurrent.TimeUnit; +import org.springframework.data.redis.RedisConnectionFailureException; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Service; + +@Service +public class ThrottlingService { + + private final StringRedisTemplate redisTemplate; + + public ThrottlingService(StringRedisTemplate redisTemplate) { + this.redisTemplate = redisTemplate; + } + + public boolean canProceed(String key, int maxPerDay) { + String redisKey = "throttle:" + key; + + Long counter = redisTemplate.opsForValue().increment(redisKey, 1); + + if (counter == null) { + throw new RedisConnectionFailureException("count not connect to redis"); + } + + if (counter == 1) { + redisTemplate.expire(redisKey, 24, TimeUnit.HOURS); + } + + return counter <= maxPerDay; + } +} diff --git a/app/src/main/java/it/chalmers/gamma/app/user/MeFacade.java b/app/src/main/java/it/chalmers/gamma/app/user/MeFacade.java new file mode 100644 index 000000000..1e7307e84 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/user/MeFacade.java @@ -0,0 +1,230 @@ +package it.chalmers.gamma.app.user; + +import static it.chalmers.gamma.app.authentication.AccessGuard.isSignedIn; + +import it.chalmers.gamma.app.Facade; +import it.chalmers.gamma.app.authentication.AccessGuard; +import it.chalmers.gamma.app.client.domain.Client; +import it.chalmers.gamma.app.client.domain.ClientRepository; +import it.chalmers.gamma.app.client.domain.ClientUid; +import it.chalmers.gamma.app.common.Email; +import it.chalmers.gamma.app.group.GroupFacade; +import it.chalmers.gamma.app.group.domain.GroupRepository; +import it.chalmers.gamma.app.image.domain.Image; +import it.chalmers.gamma.app.image.domain.ImageService; +import it.chalmers.gamma.app.image.domain.ImageUri; +import it.chalmers.gamma.app.post.PostFacade; +import it.chalmers.gamma.app.user.domain.*; +import it.chalmers.gamma.security.authentication.AuthenticationExtractor; +import it.chalmers.gamma.security.authentication.GammaAuthentication; +import it.chalmers.gamma.security.authentication.UserAuthentication; +import java.util.List; +import java.util.UUID; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; + +@Service +public class MeFacade extends Facade { + + private static final Logger LOGGER = LoggerFactory.getLogger(MeFacade.class); + + private final UserRepository userRepository; + private final ClientRepository clientRepository; + private final GroupRepository groupRepository; + private final ImageService imageService; + + public MeFacade( + AccessGuard accessGuard, + UserRepository userRepository, + ClientRepository clientRepository, + GroupRepository groupRepository, + ImageService imageService) { + super(accessGuard); + this.userRepository = userRepository; + this.clientRepository = clientRepository; + this.groupRepository = groupRepository; + this.imageService = imageService; + } + + public List getSignedInUserApprovals() { + this.accessGuard.require(isSignedIn()); + + if (AuthenticationExtractor.getAuthentication() + instanceof UserAuthentication userAuthentication) { + GammaUser user = userAuthentication.gammaUser(); + return this.clientRepository.getClientsByUserApproved(user.id()).stream() + .map(UserApprovedClientDTO::new) + .toList(); + } else { + return null; + } + } + + public void deleteUserApproval(UUID clientUid) { + this.accessGuard.require(isSignedIn()); + + if (AuthenticationExtractor.getAuthentication() + instanceof UserAuthentication userAuthentication) { + this.clientRepository.deleteUserApproval( + new ClientUid(clientUid), userAuthentication.gammaUser().id()); + } + } + + public MeDTO getMe() { + GammaAuthentication authenticated = AuthenticationExtractor.getAuthentication(); + GammaUser user = null; + boolean isAdmin = false; + + if (authenticated instanceof UserAuthentication userAuthentication) { + user = userAuthentication.gammaUser(); + isAdmin = userAuthentication.isAdmin(); + } + + if (user == null) { + throw new IllegalCallerException("Can only be called by signed in sessions"); + } + + List groups = + this.groupRepository.getAllByUser(user.id()).stream().map(MyMembership::new).toList(); + + return new MeDTO(user, groups, isAdmin); + } + + public void updateMe(UpdateMe updateMe) { + GammaAuthentication authenticated = AuthenticationExtractor.getAuthentication(); + if (authenticated instanceof UserAuthentication userAuthentication) { + GammaUser oldMe = userAuthentication.gammaUser(); + GammaUser newMe = + oldMe + .with() + .nick(new Nick(updateMe.nick)) + .firstName(new FirstName(updateMe.firstName)) + .lastName(new LastName(updateMe.lastName)) + .language(Language.valueOf(updateMe.language)) + .extended(oldMe.extended().with().email(new Email(updateMe.email)).build()) + .build(); + + this.userRepository.save(newMe); + } + } + + public void updatePassword(UpdatePassword updatePassword) + throws NewPasswordNotConfirmedException, PasswordIncorrectException { + GammaAuthentication authenticated = AuthenticationExtractor.getAuthentication(); + if (authenticated instanceof UserAuthentication userAuthentication) { + if (!updatePassword.newPassword.equals(updatePassword.confirmNewPassword)) { + throw new NewPasswordNotConfirmedException(); + } + + GammaUser me = userAuthentication.gammaUser(); + if (this.userRepository.checkPassword( + me.id(), new UnencryptedPassword(updatePassword.oldPassword))) { + this.userRepository.setPassword( + me.id(), new UnencryptedPassword(updatePassword.newPassword)); + } else { + throw new PasswordIncorrectException(); + } + } + } + + public void deleteMe(String password) { + GammaAuthentication authenticated = AuthenticationExtractor.getAuthentication(); + if (authenticated instanceof UserAuthentication userAuthentication) { + GammaUser me = userAuthentication.gammaUser(); + if (this.userRepository.checkPassword(me.id(), new UnencryptedPassword(password))) { + try { + this.userRepository.delete(me.id()); + } catch (UserRepository.UserNotFoundException e) { + throw new IllegalStateException(); + } + } else { + throw new IllegalArgumentException(); + } + } + } + + public void setAvatar(Image image) throws ImageService.ImageCouldNotBeSavedException { + GammaAuthentication authenticated = AuthenticationExtractor.getAuthentication(); + if (authenticated instanceof UserAuthentication userAuthentication) { + GammaUser user = userAuthentication.gammaUser(); + LOGGER.info("Image has been attempted to be uploaded by the user " + user.id().value()); + ImageUri imageUri = this.imageService.saveImage(image); + this.userRepository.save(user.withExtended(user.extended().withAvatarUri(imageUri))); + LOGGER.info("Image was successfully uploaded with the id: " + imageUri.value()); + } else { + throw new ImageService.ImageCouldNotBeSavedException( + "Could not find the authenticated user to upload the image"); + } + } + + public void deleteAvatar() throws ImageService.ImageCouldNotBeRemovedException { + GammaAuthentication authenticated = AuthenticationExtractor.getAuthentication(); + if (authenticated instanceof UserAuthentication userAuthentication) { + GammaUser user = userAuthentication.gammaUser(); + this.userRepository.save(user.withExtended(user.extended().withAvatarUri(null))); + this.imageService.removeImage(user.extended().avatarUri()); + } + } + + public record UserApprovedClientDTO( + UUID clientUid, + String name, + String svDescription, + String enDescription, + List scopes) { + public UserApprovedClientDTO(Client client) { + this( + client.clientUid().value(), + client.prettyName().value(), + client.description().sv().value(), + client.description().en().value(), + client.scopes().stream().map(Enum::name).toList()); + } + } + + public record MyMembership( + PostFacade.PostDTO post, GroupFacade.GroupDTO group, String unofficialPostName) { + public MyMembership(UserMembership userMembership) { + this( + new PostFacade.PostDTO(userMembership.post()), + new GroupFacade.GroupDTO(userMembership.group()), + userMembership.unofficialPostName().value()); + } + } + + public record MeDTO( + String nick, + String firstName, + String lastName, + String cid, + String email, + UUID id, + int acceptanceYear, + List groups, + String language, + boolean isAdmin) { + public MeDTO(GammaUser user, List groups, boolean isAdmin) { + this( + user.nick().value(), + user.firstName().value(), + user.lastName().value(), + user.cid().value(), + user.extended().email().value(), + user.id().value(), + user.acceptanceYear().value(), + groups, + user.language().name(), + isAdmin); + } + } + + public record UpdateMe( + String nick, String firstName, String lastName, String email, String language) {} + + public record UpdatePassword(String oldPassword, String newPassword, String confirmNewPassword) {} + + public static final class NewPasswordNotConfirmedException extends Exception {} + + public static final class PasswordIncorrectException extends Exception {} +} diff --git a/app/src/main/java/it/chalmers/gamma/app/user/UserCreationFacade.java b/app/src/main/java/it/chalmers/gamma/app/user/UserCreationFacade.java new file mode 100644 index 000000000..d6a38b97a --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/user/UserCreationFacade.java @@ -0,0 +1,192 @@ +package it.chalmers.gamma.app.user; + +import static it.chalmers.gamma.app.authentication.AccessGuard.isAdmin; +import static it.chalmers.gamma.app.authentication.AccessGuard.isNotSignedIn; + +import it.chalmers.gamma.app.Facade; +import it.chalmers.gamma.app.authentication.AccessGuard; +import it.chalmers.gamma.app.common.Email; +import it.chalmers.gamma.app.mail.domain.MailService; +import it.chalmers.gamma.app.throttling.ThrottlingService; +import it.chalmers.gamma.app.user.activation.domain.UserActivationRepository; +import it.chalmers.gamma.app.user.activation.domain.UserActivationToken; +import it.chalmers.gamma.app.user.allowlist.AllowListRepository; +import it.chalmers.gamma.app.user.domain.*; +import it.chalmers.gamma.security.TimerBlock; +import jakarta.transaction.Transactional; +import java.util.UUID; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +@Service +public class UserCreationFacade extends Facade { + + private static final String MAIL_POSTFIX = "chalmers.se"; + private static final Logger LOGGER = LoggerFactory.getLogger(UserCreationFacade.class); + private final MailService mailService; + private final UserActivationRepository userActivationRepository; + private final UserRepository userRepository; + private final ThrottlingService throttlingService; + private final AllowListRepository allowListRepository; + private final String baseUrl; + + public UserCreationFacade( + AccessGuard accessGuard, + MailService mailService, + UserActivationRepository userActivationRepository, + UserRepository userRepository, + ThrottlingService throttlingService, + AllowListRepository allowListRepository, + @Value("${application.base-url}") String baseUrl) { + super(accessGuard); + this.mailService = mailService; + this.userActivationRepository = userActivationRepository; + this.userRepository = userRepository; + this.throttlingService = throttlingService; + this.allowListRepository = allowListRepository; + this.baseUrl = baseUrl; + } + + public void tryToActivateUser(String cidRaw) { + accessGuard.require(isNotSignedIn()); + + TimerBlock.minimum(3000) + .execute( + () -> { + Cid cid = new Cid(cidRaw); + try { + if (throttlingService.canProceed(cidRaw + "-activation", 3)) { + UserActivationToken userActivationToken = + this.userActivationRepository.createActivationToken(cid); + sendEmail(cid, userActivationToken); + } else { + LOGGER.info("Throttling an activation and its email..."); + } + LOGGER.info("Cid {} has been activated", cid); + } catch (UserActivationRepository.CidNotAllowedException e) { + LOGGER.info("Someone tried to activate the cid: {}", cid); + } + }); + } + + public UUID createUser(NewUser newUser) throws EmailNotUniqueException, CidNotUniqueException { + this.accessGuard.require(isAdmin()); + + UserId userId = UserId.generate(); + + try { + this.userRepository.create( + new GammaUser( + userId, + new Cid(newUser.cid), + new Nick(newUser.nick), + new FirstName(newUser.firstName), + new LastName(newUser.lastName), + new AcceptanceYear(newUser.acceptanceYear), + Language.valueOf(newUser.language), + new UserExtended(new Email(newUser.email), 0, false, null)), + new UnencryptedPassword(newUser.password)); + + return userId.value(); + } catch (UserRepository.CidAlreadyInUseException e) { + throw new CidNotUniqueException(); + } catch (UserRepository.EmailAlreadyInUseException e) { + throw new EmailNotUniqueException(); + } + } + + @Transactional + public void createUserWithCode( + NewUserByCode data, String token, String confirmPassword, boolean acceptsUserAgreement) { + this.accessGuard.require(isNotSignedIn()); + + if (!data.password.equals(confirmPassword)) { + throw new IllegalArgumentException("Password not confirmed"); + } + + if (!acceptsUserAgreement) { + throw new IllegalArgumentException("Must accept user agreement"); + } + + Cid cid = this.userActivationRepository.useToken(new UserActivationToken(token)); + + try { + this.userRepository.create( + new GammaUser( + UserId.generate(), + cid, + new Nick(data.nick), + new FirstName(data.firstName), + new LastName(data.lastName), + new AcceptanceYear(data.acceptanceYear), + Language.valueOf(data.language), + new UserExtended(new Email(data.email), 0, false, null)), + new UnencryptedPassword(data.password)); + } catch (UserRepository.CidAlreadyInUseException + | UserRepository.EmailAlreadyInUseException e) { + throw new SomePropertyNotUniqueRuntimeException(); + } + + this.userActivationRepository.removeActivation(cid); + this.allowListRepository.remove(cid); + } + + private void sendEmail(Cid cid, UserActivationToken userActivationToken) { + String to = cid.getValue() + "@" + MAIL_POSTFIX; + String resetUrl = baseUrl + "/register?token=" + userActivationToken.value(); + String message = + """ + Follow the link to finish up creating your account. + The link is valid for 15 minutes. + %s + """ + .formatted(resetUrl, resetUrl); + + this.mailService.sendMail(to, "Gamma activation url", message); + } + + public boolean isValidToken(String token) { + this.accessGuard.require(isNotSignedIn()); + + return this.userActivationRepository.isTokenValid(new UserActivationToken(token)); + } + + public record NewUserByCode( + String password, + String nick, + String firstName, + String lastName, + String email, + int acceptanceYear, + String language) {} + + public record NewUser( + String password, + String nick, + String firstName, + String lastName, + String email, + int acceptanceYear, + String cid, + String language) {} + + public static class SomePropertyNotUniqueRuntimeException extends RuntimeException { + public SomePropertyNotUniqueRuntimeException() { + super("Please double check your details"); + } + } + + public static class CidNotUniqueException extends Exception { + public CidNotUniqueException() { + super("Cid is already in use"); + } + } + + public static class EmailNotUniqueException extends Exception { + public EmailNotUniqueException() { + super("Email is already in use"); + } + } +} diff --git a/app/src/main/java/it/chalmers/gamma/app/user/UserFacade.java b/app/src/main/java/it/chalmers/gamma/app/user/UserFacade.java new file mode 100644 index 000000000..8b82eba0c --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/user/UserFacade.java @@ -0,0 +1,186 @@ +package it.chalmers.gamma.app.user; + +import static it.chalmers.gamma.app.authentication.AccessGuard.*; + +import it.chalmers.gamma.app.Facade; +import it.chalmers.gamma.app.apikey.domain.ApiKeyType; +import it.chalmers.gamma.app.authentication.AccessGuard; +import it.chalmers.gamma.app.client.domain.Client; +import it.chalmers.gamma.app.client.domain.approval.ClientApprovalsRepository; +import it.chalmers.gamma.app.common.Email; +import it.chalmers.gamma.app.group.GroupFacade; +import it.chalmers.gamma.app.group.domain.GroupRepository; +import it.chalmers.gamma.app.post.PostFacade; +import it.chalmers.gamma.app.user.domain.*; +import it.chalmers.gamma.security.authentication.ApiAuthentication; +import it.chalmers.gamma.security.authentication.AuthenticationExtractor; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.UUID; +import org.springframework.stereotype.Component; + +@Component +public class UserFacade extends Facade { + + private final UserRepository userRepository; + private final GroupRepository groupRepository; + private final ClientApprovalsRepository clientApprovalsRepository; + + public UserFacade( + AccessGuard accessGuard, + UserRepository userRepository, + GroupRepository groupRepository, + ClientApprovalsRepository clientApprovalsRepository) { + super(accessGuard); + this.userRepository = userRepository; + this.groupRepository = groupRepository; + this.clientApprovalsRepository = clientApprovalsRepository; + } + + public Optional get(UUID id) { + UserId userId = new UserId(id); + accessGuard.requireEither(isSignedIn(), userHasAcceptedClient(userId), isApi(ApiKeyType.INFO)); + + return this.userRepository.get(userId).map(UserDTO::new); + } + + public Optional getWithGroups(UUID id) { + UserId userId = new UserId(id); + accessGuard.requireEither(isSignedIn(), userHasAcceptedClient(userId), isApi(ApiKeyType.INFO)); + + Optional maybeUser = this.userRepository.get(userId).map(UserDTO::new); + return maybeUser.map(userDTO -> new UserWithGroupsDTO(userDTO, getUserGroups(userId))); + } + + private List getUserGroups(UserId userId) { + return this.groupRepository.getAllByUser(userId).stream().map(UserGroupDTO::new).toList(); + } + + public List getAll() { + accessGuard.require(isSignedIn()); + + return this.userRepository.getAll().stream().map(UserDTO::new).toList(); + } + + public List getAllByClientAccepting() { + this.accessGuard.require(isClientApi()); + + if (AuthenticationExtractor.getAuthentication() + instanceof ApiAuthentication apiAuthentication) { + Client client = apiAuthentication.getClient().orElseThrow(); + return clientApprovalsRepository.getAllByClientUid(client.clientUid()).stream() + .map(UserDTO::new) + .toList(); + } + + return Collections.emptyList(); + } + + public void setUserPassword(UUID id, String newPassword) { + accessGuard.require(isAdmin()); + this.userRepository.setPassword(new UserId(id), new UnencryptedPassword(newPassword)); + } + + public void deleteUser(UUID id) { + accessGuard.require(isAdmin()); + + try { + this.userRepository.delete(new UserId(id)); + } catch (UserRepository.UserNotFoundException e) { + e.printStackTrace(); + } + } + + public Optional getAsAdmin(UUID id) { + accessGuard.require(isAdmin()); + + UserId userId = new UserId(id); + + Optional maybeUser = this.userRepository.get(userId).map(UserExtendedDTO::new); + return maybeUser.map( + userExtendedDTO -> new UserExtendedWithGroupsDTO(userExtendedDTO, getUserGroups(userId))); + } + + public void updateUser(UpdateUser updateUser) { + accessGuard.require(isAdmin()); + + GammaUser oldUser = this.userRepository.get(new UserId(updateUser.id)).orElseThrow(); + this.userRepository.save( + oldUser + .with() + .nick(new Nick(updateUser.nick)) + .firstName(new FirstName(updateUser.firstName)) + .lastName(new LastName(updateUser.lastName)) + .language(Language.valueOf(updateUser.language)) + .acceptanceYear(new AcceptanceYear(updateUser.acceptanceYear)) + .extended(oldUser.extended().with().email(new Email(updateUser.email)).build()) + .build()); + } + + public record UserDTO( + String cid, String nick, String firstName, String lastName, UUID id, int acceptanceYear) { + + public UserDTO(GammaUser user) { + this( + user.cid().value(), + user.nick().value(), + user.firstName().value(), + user.lastName().value(), + user.id().value(), + user.acceptanceYear().value()); + } + + public String fullName() { + return firstName + " '" + nick + "' " + lastName; + } + } + + public record UserGroupDTO(GroupFacade.GroupDTO group, PostFacade.PostDTO post) { + public UserGroupDTO(UserMembership userMembership) { + this( + new GroupFacade.GroupDTO(userMembership.group()), + new PostFacade.PostDTO(userMembership.post())); + } + } + + public record UserWithGroupsDTO(UserDTO user, List groups) {} + + public record UserExtendedDTO( + String cid, + String nick, + String firstName, + String lastName, + UUID id, + int version, + int acceptanceYear, + String email, + boolean locked, + String language) { + + public UserExtendedDTO(GammaUser user) { + this( + user.cid().value(), + user.nick().value(), + user.firstName().value(), + user.lastName().value(), + user.id().value(), + user.extended().version(), + user.acceptanceYear().value(), + user.extended().email().value(), + user.extended().locked(), + user.language().name()); + } + } + + public record UserExtendedWithGroupsDTO(UserExtendedDTO user, List groups) {} + + public record UpdateUser( + UUID id, + String nick, + String firstName, + String lastName, + String email, + String language, + int acceptanceYear) {} +} diff --git a/app/src/main/java/it/chalmers/gamma/app/user/UserGdprTrainingFacade.java b/app/src/main/java/it/chalmers/gamma/app/user/UserGdprTrainingFacade.java new file mode 100644 index 000000000..c59b1897d --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/user/UserGdprTrainingFacade.java @@ -0,0 +1,43 @@ +package it.chalmers.gamma.app.user; + +import static it.chalmers.gamma.app.authentication.AccessGuard.isAdmin; +import static it.chalmers.gamma.app.authentication.AccessGuard.isMe; + +import it.chalmers.gamma.app.Facade; +import it.chalmers.gamma.app.authentication.AccessGuard; +import it.chalmers.gamma.app.user.domain.UserId; +import it.chalmers.gamma.app.user.gdpr.GdprTrainedRepository; +import java.util.List; +import java.util.UUID; +import org.springframework.stereotype.Service; + +@Service +public class UserGdprTrainingFacade extends Facade { + + private final GdprTrainedRepository gdprTrainedRepository; + + public UserGdprTrainingFacade( + AccessGuard accessGuard, GdprTrainedRepository gdprTrainedRepository) { + super(accessGuard); + this.gdprTrainedRepository = gdprTrainedRepository; + } + + public List getGdprTrained() { + this.accessGuard.require(isAdmin()); + + return this.gdprTrainedRepository.getAll().stream().map(UserId::value).toList(); + } + + public void updateGdprTrainedStatus(UUID userId, boolean gdprTrained) { + this.accessGuard.require(isAdmin()); + + this.gdprTrainedRepository.setGdprTrainedStatus(new UserId(userId), gdprTrained); + } + + public boolean hasGdprTraining(UUID userId) { + UserId id = new UserId(userId); + this.accessGuard.requireEither(isAdmin(), isMe(id)); + + return this.gdprTrainedRepository.getGdprTrainedStatus(id); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/app/user/activation/ActivationCodeFacade.java b/app/src/main/java/it/chalmers/gamma/app/user/activation/ActivationCodeFacade.java new file mode 100644 index 000000000..28408dcc1 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/user/activation/ActivationCodeFacade.java @@ -0,0 +1,42 @@ +package it.chalmers.gamma.app.user.activation; + +import static it.chalmers.gamma.app.authentication.AccessGuard.isAdmin; + +import it.chalmers.gamma.app.Facade; +import it.chalmers.gamma.app.authentication.AccessGuard; +import it.chalmers.gamma.app.user.activation.domain.UserActivation; +import it.chalmers.gamma.app.user.activation.domain.UserActivationRepository; +import it.chalmers.gamma.app.user.domain.Cid; +import java.time.Instant; +import java.util.List; +import org.springframework.stereotype.Service; + +@Service +public class ActivationCodeFacade extends Facade { + + private final UserActivationRepository userActivationRepository; + + public ActivationCodeFacade( + AccessGuard accessGuard, UserActivationRepository userActivationRepository) { + super(accessGuard); + this.userActivationRepository = userActivationRepository; + } + + public List getAllUserActivations() { + this.accessGuard.require(isAdmin()); + + return this.userActivationRepository.getAll().stream().map(UserActivationDTO::new).toList(); + } + + public void removeUserActivation(String cid) { + this.accessGuard.require(isAdmin()); + + this.userActivationRepository.removeActivation(new Cid(cid)); + } + + public record UserActivationDTO(String cid, Instant createdAt) { + public UserActivationDTO(UserActivation userActivation) { + this(userActivation.cid().value(), userActivation.createdAt()); + } + } +} diff --git a/app/src/main/java/it/chalmers/gamma/app/user/activation/domain/UserActivation.java b/app/src/main/java/it/chalmers/gamma/app/user/activation/domain/UserActivation.java new file mode 100644 index 000000000..f8734e1f6 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/user/activation/domain/UserActivation.java @@ -0,0 +1,14 @@ +package it.chalmers.gamma.app.user.activation.domain; + +import it.chalmers.gamma.app.user.domain.Cid; +import java.time.Instant; +import java.util.Objects; + +public record UserActivation(Cid cid, UserActivationToken token, Instant createdAt) { + + public UserActivation { + Objects.requireNonNull(cid); + Objects.requireNonNull(token); + Objects.requireNonNull(createdAt); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/app/user/activation/domain/UserActivationRepository.java b/app/src/main/java/it/chalmers/gamma/app/user/activation/domain/UserActivationRepository.java new file mode 100644 index 000000000..e99d288dd --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/user/activation/domain/UserActivationRepository.java @@ -0,0 +1,25 @@ +package it.chalmers.gamma.app.user.activation.domain; + +import it.chalmers.gamma.app.user.domain.Cid; +import java.util.List; + +public interface UserActivationRepository { + + UserActivationToken createActivationToken(Cid cid) throws CidNotAllowedException; + + List getAll(); + + boolean isTokenValid(UserActivationToken token); + + Cid useToken(UserActivationToken token); + + void removeActivation(Cid cid) throws CidNotActivatedException; + + int removeInvalidActivationCodes(); + + class TokenNotActivatedRuntimeException extends RuntimeException {} + + class CidNotActivatedException extends RuntimeException {} + + class CidNotAllowedException extends Exception {} +} diff --git a/app/src/main/java/it/chalmers/gamma/app/user/activation/domain/UserActivationToken.java b/app/src/main/java/it/chalmers/gamma/app/user/activation/domain/UserActivationToken.java new file mode 100644 index 000000000..bf3a4893f --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/user/activation/domain/UserActivationToken.java @@ -0,0 +1,17 @@ +package it.chalmers.gamma.app.user.activation.domain; + +import static it.chalmers.gamma.app.Tokens.CharacterTypes.*; + +import it.chalmers.gamma.app.Tokens; +import java.util.Objects; + +public record UserActivationToken(String value) { + + public UserActivationToken { + Objects.requireNonNull(value); + } + + public static UserActivationToken generate() { + return new UserActivationToken(Tokens.generate(100, UPPERCASE, NUMBERS, LOWERCASE)); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/app/user/allowlist/AllowListFacade.java b/app/src/main/java/it/chalmers/gamma/app/user/allowlist/AllowListFacade.java new file mode 100644 index 000000000..48d600700 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/user/allowlist/AllowListFacade.java @@ -0,0 +1,65 @@ +package it.chalmers.gamma.app.user.allowlist; + +import static it.chalmers.gamma.app.authentication.AccessGuard.isAdmin; +import static it.chalmers.gamma.app.authentication.AccessGuard.isApi; + +import it.chalmers.gamma.app.Facade; +import it.chalmers.gamma.app.apikey.domain.ApiKeyType; +import it.chalmers.gamma.app.authentication.AccessGuard; +import it.chalmers.gamma.app.user.domain.Cid; +import it.chalmers.gamma.app.user.domain.UserRepository; +import java.util.List; +import org.springframework.stereotype.Service; + +@Service +public class AllowListFacade extends Facade { + + private final AllowListRepository allowListRepository; + private final UserRepository userRepository; + + public AllowListFacade( + AccessGuard accessGuard, + AllowListRepository allowListRepository, + UserRepository userRepository) { + super(accessGuard); + this.allowListRepository = allowListRepository; + this.userRepository = userRepository; + } + + public List getAllowList() { + this.accessGuard.require(isAdmin()); + + return this.allowListRepository.getAllowList().stream().map(Cid::value).toList(); + } + + public void allow(String cidRaw) + throws AllowListRepository.AlreadyAllowedException, AlreadyAUserException { + Cid cid = new Cid(cidRaw); + + this.accessGuard.requireEither(isAdmin(), isApi(ApiKeyType.ALLOW_LIST)); + + if (this.userRepository.get(cid).isPresent()) { + throw new AlreadyAUserException(); + } + + this.allowListRepository.allow(cid); + } + + public void removeFromAllowList(String cid) throws AllowListRepository.NotOnAllowListException { + this.accessGuard.requireEither(isAdmin(), isApi(ApiKeyType.ALLOW_LIST)); + + this.allowListRepository.remove(new Cid(cid)); + } + + public boolean isAllowed(String cid) { + this.accessGuard.requireEither(isAdmin(), isApi(ApiKeyType.ALLOW_LIST)); + + return this.allowListRepository.isAllowed(new Cid(cid)); + } + + public static final class AlreadyAUserException extends Exception { + public AlreadyAUserException() { + super("Cid is already a user"); + } + } +} diff --git a/app/src/main/java/it/chalmers/gamma/app/user/allowlist/AllowListRepository.java b/app/src/main/java/it/chalmers/gamma/app/user/allowlist/AllowListRepository.java new file mode 100644 index 000000000..f893e6b33 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/user/allowlist/AllowListRepository.java @@ -0,0 +1,23 @@ +package it.chalmers.gamma.app.user.allowlist; + +import it.chalmers.gamma.app.user.domain.Cid; +import java.util.List; + +public interface AllowListRepository { + + void allow(Cid cid) throws AlreadyAllowedException; + + void remove(Cid cid) throws NotOnAllowListException; + + boolean isAllowed(Cid cid); + + List getAllowList(); + + class AlreadyAllowedException extends Exception { + public AlreadyAllowedException() { + super("Cid already allowed"); + } + } + + class NotOnAllowListException extends RuntimeException {} +} diff --git a/app/src/main/java/it/chalmers/gamma/app/user/domain/AcceptanceYear.java b/app/src/main/java/it/chalmers/gamma/app/user/domain/AcceptanceYear.java new file mode 100644 index 000000000..a620aeb8c --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/user/domain/AcceptanceYear.java @@ -0,0 +1,32 @@ +package it.chalmers.gamma.app.user.domain; + +import static it.chalmers.gamma.app.validation.ValidationHelper.result; +import static it.chalmers.gamma.app.validation.ValidationHelper.throwIfFailed; + +import it.chalmers.gamma.app.validation.ValidationResult; +import it.chalmers.gamma.app.validation.Validator; +import java.io.Serializable; + +public record AcceptanceYear(int value) implements Serializable { + + public AcceptanceYear { + throwIfFailed(new AcceptanceYearValidator().validate(value)); + } + + public static final class AcceptanceYearValidator implements Validator { + + @Override + public ValidationResult validate(Integer value) { + if (value == null) { + return result(false, "Value cannot be empty"); + } + + int currentYear = java.time.Year.now().getValue(); + if (value < 2001 || value > currentYear) { + return result(false, "Acceptance year must be between 2001 and current year"); + } + + return result(true, ""); + } + } +} diff --git a/app/src/main/java/it/chalmers/gamma/app/user/domain/Cid.java b/app/src/main/java/it/chalmers/gamma/app/user/domain/Cid.java new file mode 100644 index 000000000..3d0bc82a6 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/user/domain/Cid.java @@ -0,0 +1,41 @@ +package it.chalmers.gamma.app.user.domain; + +import static it.chalmers.gamma.app.validation.ValidationHelper.*; + +import it.chalmers.gamma.app.common.Id; +import it.chalmers.gamma.app.validation.ValidationResult; +import it.chalmers.gamma.app.validation.Validator; +import java.io.Serializable; +import java.util.regex.Pattern; + +public record Cid(String value) implements Id, UserIdentifier, Serializable { + + public Cid { + throwIfFailed(new CidValidator().validate(value)); + } + + public static Cid valueOf(String cid) { + return new Cid(cid); + } + + @Override + public String getValue() { + return this.value; + } + + public static final class CidValidator implements Validator { + + private static final Pattern namePattern = Pattern.compile("^([a-z]{4,12})$"); + + @Override + public ValidationResult validate(String value) { + return withValidators( + IS_NOT_EMPTY, + MATCHES_REGEX.apply( + new RegexMatcher( + namePattern, + "Cid length must be between 4 and 12, and only have letters between a - z"))) + .validate(value); + } + } +} diff --git a/app/src/main/java/it/chalmers/gamma/app/user/domain/FirstName.java b/app/src/main/java/it/chalmers/gamma/app/user/domain/FirstName.java new file mode 100644 index 000000000..b5ead1832 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/user/domain/FirstName.java @@ -0,0 +1,22 @@ +package it.chalmers.gamma.app.user.domain; + +import static it.chalmers.gamma.app.validation.ValidationHelper.*; + +import it.chalmers.gamma.app.validation.ValidationResult; +import it.chalmers.gamma.app.validation.Validator; +import java.io.Serializable; + +public record FirstName(String value) implements Serializable { + + public FirstName { + throwIfFailed(new FirstNameValidator().validate(value)); + } + + public static final class FirstNameValidator implements Validator { + + @Override + public ValidationResult validate(String value) { + return withValidators(IS_NOT_EMPTY, SANITIZED_HTML, MAX_LENGTH.apply(50)).validate(value); + } + } +} diff --git a/app/src/main/java/it/chalmers/gamma/app/user/domain/GammaUser.java b/app/src/main/java/it/chalmers/gamma/app/user/domain/GammaUser.java new file mode 100644 index 000000000..49673de18 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/user/domain/GammaUser.java @@ -0,0 +1,27 @@ +package it.chalmers.gamma.app.user.domain; + +import io.soabase.recordbuilder.core.RecordBuilder; +import java.io.Serializable; +import java.util.Objects; + +@RecordBuilder +public record GammaUser( + UserId id, + Cid cid, + Nick nick, + FirstName firstName, + LastName lastName, + AcceptanceYear acceptanceYear, + Language language, + UserExtended extended) + implements GammaUserBuilder.With, Serializable { + + public GammaUser { + Objects.requireNonNull(id); + Objects.requireNonNull(cid); + Objects.requireNonNull(nick); + Objects.requireNonNull(firstName); + Objects.requireNonNull(lastName); + Objects.requireNonNull(acceptanceYear); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/app/user/domain/Language.java b/app/src/main/java/it/chalmers/gamma/app/user/domain/Language.java new file mode 100644 index 000000000..7fa3fbc84 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/user/domain/Language.java @@ -0,0 +1,6 @@ +package it.chalmers.gamma.app.user.domain; + +public enum Language { + SV, + EN +} diff --git a/app/src/main/java/it/chalmers/gamma/app/user/domain/LastName.java b/app/src/main/java/it/chalmers/gamma/app/user/domain/LastName.java new file mode 100644 index 000000000..ad2a22a08 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/user/domain/LastName.java @@ -0,0 +1,22 @@ +package it.chalmers.gamma.app.user.domain; + +import static it.chalmers.gamma.app.validation.ValidationHelper.*; + +import it.chalmers.gamma.app.validation.ValidationResult; +import it.chalmers.gamma.app.validation.Validator; +import java.io.Serializable; + +public record LastName(String value) implements Serializable { + + public LastName { + throwIfFailed(new LastNameValidator().validate(value)); + } + + public static final class LastNameValidator implements Validator { + + @Override + public ValidationResult validate(String value) { + return withValidators(IS_NOT_EMPTY, SANITIZED_HTML, MAX_LENGTH.apply(50)).validate(value); + } + } +} diff --git a/app/src/main/java/it/chalmers/gamma/app/user/domain/Name.java b/app/src/main/java/it/chalmers/gamma/app/user/domain/Name.java new file mode 100644 index 000000000..9d39a538e --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/user/domain/Name.java @@ -0,0 +1,30 @@ +package it.chalmers.gamma.app.user.domain; + +import static it.chalmers.gamma.app.validation.ValidationHelper.*; + +import it.chalmers.gamma.app.validation.ValidationResult; +import it.chalmers.gamma.app.validation.Validator; +import java.util.regex.Pattern; + +public record Name(String value) { + + public Name { + throwIfFailed(new NameValidator().validate(value)); + } + + public static final class NameValidator implements Validator { + + private static final Pattern namePattern = Pattern.compile("^([0-9a-z\\-]{3,30})$"); + + @Override + public ValidationResult validate(String value) { + return withValidators( + IS_NOT_EMPTY, + MATCHES_REGEX.apply( + new RegexMatcher( + namePattern, + "Must be lowercase letters a - z, '-' and be of length between 3 - 30"))) + .validate(value); + } + } +} diff --git a/app/src/main/java/it/chalmers/gamma/app/user/domain/Nick.java b/app/src/main/java/it/chalmers/gamma/app/user/domain/Nick.java new file mode 100644 index 000000000..ed5fa1d75 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/user/domain/Nick.java @@ -0,0 +1,21 @@ +package it.chalmers.gamma.app.user.domain; + +import static it.chalmers.gamma.app.validation.ValidationHelper.*; + +import it.chalmers.gamma.app.validation.*; +import java.io.Serializable; + +public record Nick(String value) implements Serializable { + + public Nick { + throwIfFailed(new NickValidator().validate(value)); + } + + public static final class NickValidator implements Validator { + + @Override + public ValidationResult validate(String value) { + return withValidators(IS_NOT_EMPTY, SANITIZED_HTML, MAX_LENGTH.apply(50)).validate(value); + } + } +} diff --git a/app/src/main/java/it/chalmers/gamma/app/user/domain/Password.java b/app/src/main/java/it/chalmers/gamma/app/user/domain/Password.java new file mode 100644 index 000000000..dbe51bede --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/user/domain/Password.java @@ -0,0 +1,23 @@ +package it.chalmers.gamma.app.user.domain; + +import java.util.regex.Pattern; + +public record Password(String value) { + + private static final Pattern passwordStartPattern = Pattern.compile("^\\{bcrypt}.+"); + + public Password { + if (value == null) { + throw new IllegalArgumentException(); + } else if (!passwordStartPattern.matcher(value).matches()) { + throw new IllegalArgumentException( + "Password must start with what type the encoding of the value is," + + "such as {bcrypt} or {noop}"); + } + } + + @Override + public String toString() { + return ""; + } +} diff --git a/app/src/main/java/it/chalmers/gamma/app/user/domain/UnencryptedPassword.java b/app/src/main/java/it/chalmers/gamma/app/user/domain/UnencryptedPassword.java new file mode 100644 index 000000000..c6d12c4ec --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/user/domain/UnencryptedPassword.java @@ -0,0 +1,21 @@ +package it.chalmers.gamma.app.user.domain; + +import static it.chalmers.gamma.app.validation.ValidationHelper.*; + +import it.chalmers.gamma.app.validation.ValidationResult; +import it.chalmers.gamma.app.validation.Validator; + +public record UnencryptedPassword(String value) { + + public UnencryptedPassword { + throwIfFailed(new UnencryptedPasswordValidator().validate(value)); + } + + public static class UnencryptedPasswordValidator implements Validator { + + @Override + public ValidationResult validate(String value) { + return withValidators(IS_NOT_EMPTY, MIN_LENGTH.apply(12)).validate(value); + } + } +} diff --git a/app/src/main/java/it/chalmers/gamma/app/user/domain/UserExtended.java b/app/src/main/java/it/chalmers/gamma/app/user/domain/UserExtended.java new file mode 100644 index 000000000..43d39562f --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/user/domain/UserExtended.java @@ -0,0 +1,15 @@ +package it.chalmers.gamma.app.user.domain; + +import io.soabase.recordbuilder.core.RecordBuilder; +import it.chalmers.gamma.app.common.Email; +import it.chalmers.gamma.app.image.domain.ImageUri; + +/** + * Extension of User. Usually, records in Gamma always have to be valid, but UserExtended is an + * exception. To limit the amount of data that can accidentally be leaked, UserExtended can be + * partial complete. For example, account-scaffold api needs to have access to email and + * gdprTrained, but not the rest of the data. + */ +@RecordBuilder +public record UserExtended(Email email, int version, boolean locked, ImageUri avatarUri) + implements UserExtendedBuilder.With {} diff --git a/app/src/main/java/it/chalmers/gamma/app/user/domain/UserId.java b/app/src/main/java/it/chalmers/gamma/app/user/domain/UserId.java new file mode 100644 index 000000000..2ebfa2365 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/user/domain/UserId.java @@ -0,0 +1,25 @@ +package it.chalmers.gamma.app.user.domain; + +import it.chalmers.gamma.app.common.Id; +import java.util.Objects; +import java.util.UUID; + +public record UserId(UUID value) implements Id, UserIdentifier { + + public UserId { + Objects.requireNonNull(value); + } + + public static UserId generate() { + return new UserId(UUID.randomUUID()); + } + + public static UserId valueOf(String value) { + return new UserId(UUID.fromString(value)); + } + + @Override + public UUID getValue() { + return value; + } +} diff --git a/app/src/main/java/it/chalmers/gamma/app/user/domain/UserIdentifier.java b/app/src/main/java/it/chalmers/gamma/app/user/domain/UserIdentifier.java new file mode 100644 index 000000000..717379dcd --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/user/domain/UserIdentifier.java @@ -0,0 +1,3 @@ +package it.chalmers.gamma.app.user.domain; + +public interface UserIdentifier {} diff --git a/app/src/main/java/it/chalmers/gamma/app/user/domain/UserMembership.java b/app/src/main/java/it/chalmers/gamma/app/user/domain/UserMembership.java new file mode 100644 index 000000000..aea8e9464 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/user/domain/UserMembership.java @@ -0,0 +1,14 @@ +package it.chalmers.gamma.app.user.domain; + +import it.chalmers.gamma.app.group.domain.Group; +import it.chalmers.gamma.app.group.domain.UnofficialPostName; +import it.chalmers.gamma.app.post.domain.Post; +import java.util.Objects; + +public record UserMembership(Post post, Group group, UnofficialPostName unofficialPostName) { + public UserMembership { + Objects.requireNonNull(post); + Objects.requireNonNull(group); + Objects.requireNonNull(unofficialPostName); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/app/user/domain/UserRepository.java b/app/src/main/java/it/chalmers/gamma/app/user/domain/UserRepository.java new file mode 100644 index 000000000..14614d70d --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/user/domain/UserRepository.java @@ -0,0 +1,38 @@ +package it.chalmers.gamma.app.user.domain; + +import it.chalmers.gamma.app.common.Email; +import java.util.List; +import java.util.Optional; + +public interface UserRepository { + + void create(GammaUser user, UnencryptedPassword password) + throws UserAlreadyExistsException, CidAlreadyInUseException, EmailAlreadyInUseException; + + void save(GammaUser user); + + void delete(UserId userId) throws UserNotFoundException; + + List getAll(); + + Optional get(UserId userId); + + Optional get(Cid cid); + + Optional get(Email email); + + boolean checkPassword(UserId userId, UnencryptedPassword password) throws UserNotFoundException; + + void setPassword(UserId userId, UnencryptedPassword newPassword) throws UserNotFoundException; + + void acceptUserAgreement(UserId userId) throws UserNotFoundException; + + class UserNotFoundException extends RuntimeException {} + + /** A user with the given id already exists. Use save instead. */ + class UserAlreadyExistsException extends RuntimeException {} + + class CidAlreadyInUseException extends Exception {} + + class EmailAlreadyInUseException extends Exception {} +} diff --git a/app/src/main/java/it/chalmers/gamma/app/user/gdpr/GdprTrainedRepository.java b/app/src/main/java/it/chalmers/gamma/app/user/gdpr/GdprTrainedRepository.java new file mode 100644 index 000000000..79a9a1862 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/user/gdpr/GdprTrainedRepository.java @@ -0,0 +1,13 @@ +package it.chalmers.gamma.app.user.gdpr; + +import it.chalmers.gamma.app.user.domain.UserId; +import java.util.List; + +public interface GdprTrainedRepository { + + void setGdprTrainedStatus(UserId userId, boolean gdprTrained); + + List getAll(); + + boolean getGdprTrainedStatus(UserId userId); +} diff --git a/app/src/main/java/it/chalmers/gamma/app/user/passwordreset/UserResetPasswordFacade.java b/app/src/main/java/it/chalmers/gamma/app/user/passwordreset/UserResetPasswordFacade.java new file mode 100644 index 000000000..a050d18db --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/user/passwordreset/UserResetPasswordFacade.java @@ -0,0 +1,138 @@ +package it.chalmers.gamma.app.user.passwordreset; + +import static it.chalmers.gamma.app.authentication.AccessGuard.isAdmin; +import static it.chalmers.gamma.app.authentication.AccessGuard.isNotSignedIn; + +import it.chalmers.gamma.app.Facade; +import it.chalmers.gamma.app.authentication.AccessGuard; +import it.chalmers.gamma.app.common.Email; +import it.chalmers.gamma.app.mail.domain.MailService; +import it.chalmers.gamma.app.throttling.ThrottlingService; +import it.chalmers.gamma.app.user.domain.Cid; +import it.chalmers.gamma.app.user.domain.UnencryptedPassword; +import it.chalmers.gamma.app.user.domain.UserId; +import it.chalmers.gamma.app.user.domain.UserRepository; +import it.chalmers.gamma.app.user.passwordreset.domain.PasswordResetRepository; +import it.chalmers.gamma.app.user.passwordreset.domain.PasswordResetToken; +import it.chalmers.gamma.app.validation.SuccessfulValidation; +import it.chalmers.gamma.security.TimerBlock; +import java.util.UUID; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +@Service +public class UserResetPasswordFacade extends Facade { + + private static final Logger LOGGER = LoggerFactory.getLogger(UserResetPasswordFacade.class); + private final MailService mailService; + private final UserRepository userRepository; + private final PasswordResetRepository passwordResetRepository; + private final ThrottlingService throttlingService; + private final String baseUrl; + + public UserResetPasswordFacade( + AccessGuard accessGuard, + MailService mailService, + UserRepository userRepository, + PasswordResetRepository passwordResetRepository, + ThrottlingService throttlingService, + @Value("${application.base-url}") String baseUrl) { + super(accessGuard); + this.mailService = mailService; + this.userRepository = userRepository; + this.passwordResetRepository = passwordResetRepository; + this.throttlingService = throttlingService; + this.baseUrl = baseUrl; + } + + public String generatePasswordLink(UUID userId) { + super.accessGuard.require(isAdmin()); + + try { + PasswordResetRepository.PasswordReset passwordReset = + this.passwordResetRepository.createNewToken(new UserId(userId)); + + return generatePasswordResetLink(passwordReset.token()); + } catch (PasswordResetRepository.UserNotFoundException e) { + throw new IllegalStateException(); + } + } + + public void startResetPasswordProcess(String cidOrEmailString) { + this.accessGuard.require(isNotSignedIn()); + + TimerBlock.minimum(3000) + .execute( + () -> { + try { + PasswordResetRepository.PasswordReset passwordReset; + if (new Email.EmailValidator().validate(cidOrEmailString) + instanceof SuccessfulValidation) { + passwordReset = + this.passwordResetRepository.createNewToken(new Email(cidOrEmailString)); + } else if (new Cid.CidValidator().validate(cidOrEmailString.toLowerCase()) + instanceof SuccessfulValidation) { + passwordReset = + this.passwordResetRepository.createNewToken( + new Cid(cidOrEmailString.toLowerCase())); + } else { + throw new IllegalArgumentException("Neither an email nor a cid."); + } + + if (throttlingService.canProceed( + passwordReset.email().value() + "-password-reset", 3)) { + sendPasswordResetTokenMail(passwordReset.email(), passwordReset.token()); + } else { + LOGGER.info("Throttling password reset process triggered."); + } + } catch (PasswordResetRepository.UserNotFoundException e) { + LOGGER.debug( + "Someone tried to reset the password for the email {} that doesn't exist", + cidOrEmailString); + } + }); + } + + public void finishResetPasswordProcess( + String inputToken, String newPassword, String confirmPassword) { + this.accessGuard.require(isNotSignedIn()); + + if (!newPassword.equals(confirmPassword)) { + throw new IllegalArgumentException("Please properly confirm password"); + } + + UnencryptedPassword unencryptedPassword = new UnencryptedPassword(newPassword); + + UserId userId = this.passwordResetRepository.useToken(new PasswordResetToken(inputToken)); + + this.userRepository.setPassword(userId, unencryptedPassword); + } + + private String generatePasswordResetLink(PasswordResetToken token) { + return this.baseUrl + "/forgot-password/finalize?token=" + token.value(); + } + + private void sendPasswordResetTokenMail(Email email, PasswordResetToken token) { + String subject = "Password reset for Account at IT division of Chalmers"; + + String resetUrl = generatePasswordResetLink(token); + + String message = + """ + A password reset have been requested for this account, if you have not requested this mail, feel free to ignore it. + The link is valid for 15 minutes. Click here to reset password: + %s + """ + .formatted(resetUrl); + + this.mailService.sendMail(email.value(), subject, message); + } + + public boolean isValidToken(String token) { + this.accessGuard.require(isNotSignedIn()); + + return this.passwordResetRepository.isTokenValid(new PasswordResetToken(token)); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/app/user/passwordreset/domain/PasswordReset.java b/app/src/main/java/it/chalmers/gamma/app/user/passwordreset/domain/PasswordReset.java new file mode 100644 index 000000000..dd7c07d35 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/user/passwordreset/domain/PasswordReset.java @@ -0,0 +1,14 @@ +package it.chalmers.gamma.app.user.passwordreset.domain; + +import it.chalmers.gamma.app.user.domain.UserId; +import java.time.Instant; +import java.util.Objects; + +public record PasswordReset(UserId userId, PasswordResetToken token, Instant createdAt) { + + public PasswordReset { + Objects.requireNonNull(userId); + Objects.requireNonNull(token); + Objects.requireNonNull(createdAt); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/app/user/passwordreset/domain/PasswordResetRepository.java b/app/src/main/java/it/chalmers/gamma/app/user/passwordreset/domain/PasswordResetRepository.java new file mode 100644 index 000000000..2fc911210 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/user/passwordreset/domain/PasswordResetRepository.java @@ -0,0 +1,26 @@ +package it.chalmers.gamma.app.user.passwordreset.domain; + +import it.chalmers.gamma.app.common.Email; +import it.chalmers.gamma.app.user.domain.Cid; +import it.chalmers.gamma.app.user.domain.UserId; + +public interface PasswordResetRepository { + + record PasswordReset(PasswordResetToken token, Email email) {} + + PasswordReset createNewToken(Email email) throws UserNotFoundException; + + PasswordReset createNewToken(Cid cid) throws UserNotFoundException; + + PasswordReset createNewToken(UserId userId) throws UserNotFoundException; + + boolean isTokenValid(PasswordResetToken token); + + UserId useToken(PasswordResetToken token); + + int removeInvalidPasswordResetTokens(); + + class UserNotFoundException extends Exception {} + + class TokenNotFoundRuntimeException extends RuntimeException {} +} diff --git a/app/src/main/java/it/chalmers/gamma/app/user/passwordreset/domain/PasswordResetToken.java b/app/src/main/java/it/chalmers/gamma/app/user/passwordreset/domain/PasswordResetToken.java new file mode 100644 index 000000000..2a7eb1225 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/user/passwordreset/domain/PasswordResetToken.java @@ -0,0 +1,17 @@ +package it.chalmers.gamma.app.user.passwordreset.domain; + +import static it.chalmers.gamma.app.Tokens.CharacterTypes.*; + +import it.chalmers.gamma.app.Tokens; +import java.util.Objects; + +public record PasswordResetToken(String value) { + + public PasswordResetToken { + Objects.requireNonNull(value); + } + + public static PasswordResetToken generate() { + return new PasswordResetToken(Tokens.generate(100, UPPERCASE, NUMBERS, LOWERCASE)); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/app/validation/FailedValidation.java b/app/src/main/java/it/chalmers/gamma/app/validation/FailedValidation.java new file mode 100644 index 000000000..b2fe2eaac --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/validation/FailedValidation.java @@ -0,0 +1,3 @@ +package it.chalmers.gamma.app.validation; + +public record FailedValidation(String message) implements ValidationResult {} diff --git a/app/src/main/java/it/chalmers/gamma/app/validation/SuccessfulValidation.java b/app/src/main/java/it/chalmers/gamma/app/validation/SuccessfulValidation.java new file mode 100644 index 000000000..0db8d6e73 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/validation/SuccessfulValidation.java @@ -0,0 +1,3 @@ +package it.chalmers.gamma.app.validation; + +public record SuccessfulValidation() implements ValidationResult {} diff --git a/app/src/main/java/it/chalmers/gamma/app/validation/ValidationHelper.java b/app/src/main/java/it/chalmers/gamma/app/validation/ValidationHelper.java new file mode 100644 index 000000000..b5cba6bb2 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/validation/ValidationHelper.java @@ -0,0 +1,66 @@ +package it.chalmers.gamma.app.validation; + +import java.util.function.BiFunction; +import java.util.function.Function; +import java.util.regex.Pattern; +import org.springframework.web.util.HtmlUtils; + +public class ValidationHelper { + + @SafeVarargs + public static Validator withValidators(Validator... validators) { + return value -> { + for (Validator validator : validators) { + if (validator.validate(value) instanceof FailedValidation failedValidation) { + return failedValidation; + } + } + + return new SuccessfulValidation(); + }; + } + + public static Validator IS_NOT_NULL = value -> result(value != null, "Cannot be null"); + + public static Validator IS_NOT_EMPTY = + value -> result(!(value == null || value.isEmpty()), "Cannot be empty"); + + public static Validator SANITIZED_HTML = + value -> + result( + value.equals(HtmlUtils.htmlEscape(value, "UTF-8")), + "Cannot have illegal html characters"); + + public static Function> MAX_LENGTH = + (maxLength) -> + value -> result(value.length() <= maxLength, "Must be between 1 and " + maxLength); + + public static Function> MIN_LENGTH = + (minLength) -> value -> result(value.length() >= minLength, "Must be at least " + minLength); + + public static BiFunction> BETWEEN_LENGTH = + (min, max) -> + value -> + result( + value.length() >= min && value.length() <= max, + "Must be between " + min + " and " + max); + + public record RegexMatcher(Pattern pattern, String message) {} + + public static Function> MATCHES_REGEX = + (r) -> (value) -> result(r.pattern.matcher(value).matches(), r.message); + + public static ValidationResult result(boolean valid, String message) { + if (valid) { + return new SuccessfulValidation(); + } else { + return new FailedValidation(message); + } + } + + public static void throwIfFailed(ValidationResult validationResult) { + if (validationResult instanceof FailedValidation failedValidation) { + throw new IllegalArgumentException(failedValidation.message()); + } + } +} diff --git a/app/src/main/java/it/chalmers/gamma/app/validation/ValidationResult.java b/app/src/main/java/it/chalmers/gamma/app/validation/ValidationResult.java new file mode 100644 index 000000000..f120da60c --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/validation/ValidationResult.java @@ -0,0 +1,3 @@ +package it.chalmers.gamma.app.validation; + +public sealed interface ValidationResult permits FailedValidation, SuccessfulValidation {} diff --git a/app/src/main/java/it/chalmers/gamma/app/validation/Validator.java b/app/src/main/java/it/chalmers/gamma/app/validation/Validator.java new file mode 100644 index 000000000..d5b919023 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/app/validation/Validator.java @@ -0,0 +1,5 @@ +package it.chalmers.gamma.app.validation; + +public interface Validator { + ValidationResult validate(T value); +} diff --git a/app/src/main/java/it/chalmers/gamma/bootstrap/ApiKeyBootstrap.java b/app/src/main/java/it/chalmers/gamma/bootstrap/ApiKeyBootstrap.java new file mode 100644 index 000000000..4b81d9f1d --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/bootstrap/ApiKeyBootstrap.java @@ -0,0 +1,51 @@ +package it.chalmers.gamma.bootstrap; + +import it.chalmers.gamma.app.apikey.ApiKeyFacade; +import it.chalmers.gamma.app.apikey.domain.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +@Component +public class ApiKeyBootstrap { + + private static final Logger LOGGER = LoggerFactory.getLogger(ApiKeyBootstrap.class); + + private final ApiKeyFacade apiKeyFacade; + private final BootstrapSettings bootstrapSettings; + + public ApiKeyBootstrap(BootstrapSettings bootstrapSettings, ApiKeyFacade apiKeyFacade) { + this.apiKeyFacade = apiKeyFacade; + this.bootstrapSettings = bootstrapSettings; + } + + public void ensureApiKeys() { + if (!this.bootstrapSettings.mocking() || !this.apiKeyFacade.getAll().isEmpty()) { + return; + } + + LOGGER.info("========== API BOOTSTRAP =========="); + LOGGER.info("Generating mock api keys..."); + + for (ApiKeyType apiKeyType : ApiKeyType.values()) { + if (apiKeyType != ApiKeyType.CLIENT) { + + var createdApiKey = + this.apiKeyFacade.create( + new ApiKeyFacade.NewApiKey( + apiKeyType.name().toLowerCase() + "-mock", "", "", apiKeyType.name())); + + LOGGER.info( + "Api key of type " + + apiKeyType.name() + + " has been generated with id: " + + createdApiKey.apiKey().id() + + " and code: " + + createdApiKey.token()); + } + } + + LOGGER.info("Add the header: Authorization: pre-shared : to start using the APIs"); + LOGGER.info("========== =========="); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/bootstrap/BootstrapAuthenticated.java b/app/src/main/java/it/chalmers/gamma/bootstrap/BootstrapAuthenticated.java new file mode 100644 index 000000000..d61397796 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/bootstrap/BootstrapAuthenticated.java @@ -0,0 +1,36 @@ +package it.chalmers.gamma.bootstrap; + +import static org.springframework.security.core.authority.AuthorityUtils.NO_AUTHORITIES; + +import it.chalmers.gamma.security.authentication.LocalRunnerAuthentication; +import java.time.Instant; +import org.springframework.security.authentication.AbstractAuthenticationToken; + +public class BootstrapAuthenticated extends AbstractAuthenticationToken { + + private final LocalRunnerAuthentication localRunnerPrincipal; + + public BootstrapAuthenticated() { + super(NO_AUTHORITIES); + setAuthenticated(true); + + final String instantiatedAt = "Local runner instantiated at " + Instant.now(); + localRunnerPrincipal = + new LocalRunnerAuthentication() { + @Override + public String toString() { + return instantiatedAt; + } + }; + } + + @Override + public Object getCredentials() { + return null; + } + + @Override + public Object getPrincipal() { + return localRunnerPrincipal; + } +} diff --git a/app/src/main/java/it/chalmers/gamma/bootstrap/BootstrapSettings.java b/app/src/main/java/it/chalmers/gamma/bootstrap/BootstrapSettings.java new file mode 100644 index 000000000..1a58535db --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/bootstrap/BootstrapSettings.java @@ -0,0 +1,3 @@ +package it.chalmers.gamma.bootstrap; + +public record BootstrapSettings(boolean adminSetup, boolean mocking) {} diff --git a/app/src/main/java/it/chalmers/gamma/bootstrap/EnsureAnAdminUserBootstrap.java b/app/src/main/java/it/chalmers/gamma/bootstrap/EnsureAnAdminUserBootstrap.java new file mode 100644 index 000000000..0e6bd5894 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/bootstrap/EnsureAnAdminUserBootstrap.java @@ -0,0 +1,103 @@ +package it.chalmers.gamma.bootstrap; + +import it.chalmers.gamma.app.Tokens; +import it.chalmers.gamma.app.admin.domain.AdminRepository; +import it.chalmers.gamma.app.common.Email; +import it.chalmers.gamma.app.user.domain.*; +import it.chalmers.gamma.app.user.gdpr.GdprTrainedRepository; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class EnsureAnAdminUserBootstrap { + + private static final Logger LOGGER = LoggerFactory.getLogger(EnsureAnAdminUserBootstrap.class); + + private final UserRepository userRepository; + private final AdminRepository adminRepository; + private final GdprTrainedRepository gdprTrainedRepository; + private final BootstrapSettings bootstrapSettings; + private final boolean production; + + public EnsureAnAdminUserBootstrap( + UserRepository userRepository, + AdminRepository adminRepository, + GdprTrainedRepository gdprTrainedRepository, + BootstrapSettings bootstrapSettings, + @Value("${application.production}") boolean production) { + this.userRepository = userRepository; + this.adminRepository = adminRepository; + this.gdprTrainedRepository = gdprTrainedRepository; + this.bootstrapSettings = bootstrapSettings; + this.production = production; + } + + public void ensureAnAdminUser() { + LOGGER.info("========== ENSURE AN ADMIN BOOTSTRAP =========="); + + if (!this.bootstrapSettings.adminSetup()) { + LOGGER.info("Ensuring admin setup is disabled. I hope you know what you're doing..."); + return; + } + + if (!adminRepository.getAll().isEmpty()) { + LOGGER.info( + "There is already at least one user that is admin. Not creating a new admin user..."); + return; + } + + String admin = "admin"; + + if (this.userRepository.get(new Cid(admin)).isPresent()) { + LOGGER.error( + "There's no user that is admin right now, but there is a user that is named admin. " + + "Note that there are no admin users right now and none will be created."); + return; + } + + String password; + if (!production) { + password = "password1337"; + } else { + password = + Tokens.generate( + 75, + Tokens.CharacterTypes.LOWERCASE, + Tokens.CharacterTypes.UPPERCASE, + Tokens.CharacterTypes.NUMBERS); + } + + UserId adminId = UserId.generate(); + String name = "admin"; + + GammaUser adminUser = + new GammaUser( + adminId, + new Cid(name), + new Nick(name), + new FirstName(name), + new LastName(name), + new AcceptanceYear(2018), + Language.EN, + new UserExtended(new Email(name + "@chalmers.it"), 0, false, null)); + + try { + this.userRepository.create(adminUser, new UnencryptedPassword(password)); + } catch (UserRepository.CidAlreadyInUseException + | UserRepository.EmailAlreadyInUseException e) { + LOGGER.error(e.getMessage()); + return; + } + + this.adminRepository.setAdmin(adminUser.id(), true); + this.gdprTrainedRepository.setGdprTrainedStatus(adminUser.id(), true); + + LOGGER.info("Admin user created!"); + LOGGER.info("cid: " + name); + LOGGER.info("password: " + password); + + LOGGER.info("========== =========="); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/bootstrap/GroupBootstrap.java b/app/src/main/java/it/chalmers/gamma/bootstrap/GroupBootstrap.java new file mode 100644 index 000000000..e5153a620 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/bootstrap/GroupBootstrap.java @@ -0,0 +1,114 @@ +package it.chalmers.gamma.bootstrap; + +import it.chalmers.gamma.app.common.PrettyName; +import it.chalmers.gamma.app.group.domain.*; +import it.chalmers.gamma.app.post.domain.PostId; +import it.chalmers.gamma.app.post.domain.PostRepository; +import it.chalmers.gamma.app.supergroup.domain.SuperGroupId; +import it.chalmers.gamma.app.supergroup.domain.SuperGroupRepository; +import it.chalmers.gamma.app.user.domain.Name; +import it.chalmers.gamma.app.user.domain.UserId; +import it.chalmers.gamma.app.user.domain.UserRepository; +import java.time.Instant; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.time.temporal.ChronoUnit; +import java.util.Calendar; +import java.util.GregorianCalendar; +import java.util.Optional; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +@Component +public class GroupBootstrap { + + private static final Logger LOGGER = LoggerFactory.getLogger(GroupBootstrap.class); + + private final MockData mockData; + private final GroupRepository groupRepository; + private final PostRepository postRepository; + private final UserRepository userRepository; + private final SuperGroupRepository superGroupRepository; + private final BootstrapSettings bootstrapSettings; + + public GroupBootstrap( + MockData mockData, + GroupRepository groupRepository, + PostRepository postRepository, + UserRepository userRepository, + SuperGroupRepository superGroupRepository, + BootstrapSettings bootstrapSettings) { + this.mockData = mockData; + this.groupRepository = groupRepository; + this.postRepository = postRepository; + this.userRepository = userRepository; + this.superGroupRepository = superGroupRepository; + this.bootstrapSettings = bootstrapSettings; + } + + public void createGroups() { + if (!this.bootstrapSettings.mocking() || !this.groupRepository.getAll().isEmpty()) { + return; + } + + LOGGER.info("========== GROUP BOOTSTRAP =========="); + + Calendar activeGroupBecomesActive = toCalendar(Instant.now().minus(1, ChronoUnit.DAYS)); + Calendar inactiveGroupBecomesActive = toCalendar(Instant.now().minus(366, ChronoUnit.DAYS)); + int activeYear = activeGroupBecomesActive.get(Calendar.YEAR); + int inactiveYear = inactiveGroupBecomesActive.get(Calendar.YEAR); + + mockData + .groups() + .forEach( + mockGroup -> { + String type = + mockData.superGroups().stream() + .filter(sg -> sg.id().equals(mockGroup.superGroupId())) + .findFirst() + .orElseThrow() + .type(); + + boolean active = !type.equalsIgnoreCase("alumni"); + int year = active ? activeYear : inactiveYear; + Name name = new Name(mockGroup.name() + year); + PrettyName prettyName = new PrettyName(mockGroup.prettyName() + year); + + Group group = + new Group( + new GroupId(mockGroup.id()), + 0, + name, + prettyName, + superGroupRepository + .get(new SuperGroupId(mockGroup.superGroupId())) + .orElseThrow(), + mockGroup.members().stream() + .map( + mockMembership -> + new GroupMember( + postRepository + .get(new PostId(mockMembership.postId())) + .orElseThrow(), + mockMembership.unofficialPostName() == null + ? UnofficialPostName.none() + : new UnofficialPostName( + mockMembership.unofficialPostName()), + userRepository + .get(new UserId(mockMembership.userId())) + .orElseThrow(IllegalArgumentException::new))) + .toList(), + Optional.empty(), + Optional.empty()); + + this.groupRepository.save(group); + }); + + LOGGER.info("========== =========="); + } + + private Calendar toCalendar(Instant i) { + return GregorianCalendar.from(ZonedDateTime.ofInstant(i, ZoneOffset.UTC)); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/bootstrap/MiscBootstrap.java b/app/src/main/java/it/chalmers/gamma/bootstrap/MiscBootstrap.java new file mode 100644 index 000000000..41f4209d2 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/bootstrap/MiscBootstrap.java @@ -0,0 +1,61 @@ +package it.chalmers.gamma.bootstrap; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.io.Resource; +import org.springframework.stereotype.Component; + +@Component +public class MiscBootstrap { + + private static final Logger LOGGER = LoggerFactory.getLogger(MiscBootstrap.class); + + @Value("classpath:/image/default_user_avatar.jpg") + private Resource defaultUserAvatar; + + @Value("classpath:/image/default_group_banner.jpg") + private Resource defaultGroupBanner; + + @Value("classpath:/image/default_group_avatar.jpg") + private Resource defaultGroupAvatar; + + @Value("${application.files.path}") + private String targetDir; + + public void runImageBootstrap() { + assureFileExistsInUpload(defaultUserAvatar); + assureFileExistsInUpload(defaultGroupAvatar); + assureFileExistsInUpload(defaultGroupBanner); + } + + private void assureFileExistsInUpload(Resource resource) { + File targetFile = new File(String.format("%s/%s", this.targetDir, resource.getFilename())); + if (!targetFile.exists()) { + LOGGER.info( + "default file: " + + resource.getFilename() + + " does not exist in " + + this.targetDir + + ", creating a new one"); + try { + File defaultFile = resource.getFile(); + if (defaultFile.isFile()) { + File targetDirFile = new File(this.targetDir); + if (!targetDirFile.mkdir()) { + LOGGER.warn("Could not create target directory"); + } + Files.copy(defaultFile.toPath(), targetFile.toPath()); + } else { + throw new IOException(); + } + } catch (IOException e) { + LOGGER.warn("Could not copy: " + resource.getFilename()); + LOGGER.error(e.getMessage()); + } + } + } +} diff --git a/app/src/main/java/it/chalmers/gamma/bootstrap/MockBootstrap.java b/app/src/main/java/it/chalmers/gamma/bootstrap/MockBootstrap.java new file mode 100644 index 000000000..acb800c75 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/bootstrap/MockBootstrap.java @@ -0,0 +1,47 @@ +package it.chalmers.gamma.bootstrap; + +import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.IOException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.core.io.Resource; +import org.springframework.core.io.ResourceLoader; +import org.springframework.stereotype.Component; + +@Component +public class MockBootstrap { + + private static final Logger LOGGER = LoggerFactory.getLogger(MockBootstrap.class); + + private final ResourceLoader resourceLoader; + + public MockBootstrap(ResourceLoader resourceLoader) { + this.resourceLoader = resourceLoader; + } + + @Bean + public BootstrapSettings loadBootstrapSettings( + @Value("${application.admin-setup}") boolean adminSetup, + @Value("${application.production}") boolean production) { + return new BootstrapSettings(adminSetup, !production); + } + + @Bean + public MockData mockData(BootstrapSettings bootstrapSettings) { + if (!bootstrapSettings.mocking()) { + LOGGER.info("Not running mock..."); + return MockData.empty(); + } + + Resource resource = this.resourceLoader.getResource("classpath:/mock/mock.json"); + ObjectMapper objectMapper = new ObjectMapper(); + try { + return objectMapper.readValue(resource.getInputStream(), MockData.class); + } catch (IOException e) { + LOGGER.error("Error when trying to read mock.json", e); + return MockData.empty(); + } + } +} diff --git a/app/src/main/java/it/chalmers/gamma/bootstrap/MockData.java b/app/src/main/java/it/chalmers/gamma/bootstrap/MockData.java new file mode 100644 index 000000000..26b3acd5e --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/bootstrap/MockData.java @@ -0,0 +1,41 @@ +package it.chalmers.gamma.bootstrap; + +import java.util.Collections; +import java.util.List; +import java.util.UUID; + +public record MockData( + List users, + List groups, + List superGroups, + List posts) { + + public static MockData empty() { + return new MockData( + Collections.emptyList(), + Collections.emptyList(), + Collections.emptyList(), + Collections.emptyList()); + } + + public record MockGroup( + UUID id, String name, String prettyName, List members, UUID superGroupId) {} + + public record MockMembership(UUID userId, UUID postId, String unofficialPostName) {} + + public record MockText(String sv, String en) {} + + public record MockPost(UUID id, MockText postName) {} + + public record MockSuperGroup( + UUID id, String name, String prettyName, String type, List authorities) {} + + public record MockUser( + UUID id, + String cid, + String nick, + String firstName, + String lastName, + int acceptanceYear, + boolean admin) {} +} diff --git a/app/src/main/java/it/chalmers/gamma/bootstrap/PostBootstrap.java b/app/src/main/java/it/chalmers/gamma/bootstrap/PostBootstrap.java new file mode 100644 index 000000000..59786313e --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/bootstrap/PostBootstrap.java @@ -0,0 +1,50 @@ +package it.chalmers.gamma.bootstrap; + +import it.chalmers.gamma.app.common.Text; +import it.chalmers.gamma.app.group.domain.EmailPrefix; +import it.chalmers.gamma.app.post.domain.Order; +import it.chalmers.gamma.app.post.domain.Post; +import it.chalmers.gamma.app.post.domain.PostId; +import it.chalmers.gamma.app.post.domain.PostRepository; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +@Component +public class PostBootstrap { + + private static final Logger LOGGER = LoggerFactory.getLogger(PostBootstrap.class); + + private final MockData mockData; + private final PostRepository postRepository; + private final BootstrapSettings bootstrapSettings; + + public PostBootstrap( + MockData mockData, PostRepository postRepository, BootstrapSettings bootstrapSettings) { + this.mockData = mockData; + this.postRepository = postRepository; + this.bootstrapSettings = bootstrapSettings; + } + + public void createPosts() { + if (!this.bootstrapSettings.mocking() || !this.postRepository.getAll().isEmpty()) { + return; + } + + LOGGER.info("========== POST BOOTSTRAP =========="); + + int i = 0; + for (MockData.MockPost mockPost : mockData.posts()) { + this.postRepository.save( + new Post( + new PostId(mockPost.id()), + 0, + new Text(mockPost.postName().sv(), mockPost.postName().en()), + EmailPrefix.none(), + new Order(i))); + i++; + } + LOGGER.info("Posts created"); + LOGGER.info("========== =========="); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/bootstrap/SuperGroupBootstrap.java b/app/src/main/java/it/chalmers/gamma/bootstrap/SuperGroupBootstrap.java new file mode 100644 index 000000000..02cf92b3a --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/bootstrap/SuperGroupBootstrap.java @@ -0,0 +1,71 @@ +package it.chalmers.gamma.bootstrap; + +import it.chalmers.gamma.app.common.PrettyName; +import it.chalmers.gamma.app.common.Text; +import it.chalmers.gamma.app.supergroup.domain.*; +import it.chalmers.gamma.app.user.domain.Name; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +@Component +public class SuperGroupBootstrap { + + private static final Logger LOGGER = LoggerFactory.getLogger(SuperGroupBootstrap.class); + + private final MockData mockData; + private final SuperGroupTypeRepository superGroupTypeRepository; + private final SuperGroupRepository superGroupRepository; + private final BootstrapSettings bootstrapSettings; + + public SuperGroupBootstrap( + MockData mockData, + SuperGroupTypeRepository superGroupTypeRepository, + SuperGroupRepository superGroupRepository, + BootstrapSettings bootstrapSettings) { + this.mockData = mockData; + this.superGroupTypeRepository = superGroupTypeRepository; + this.superGroupRepository = superGroupRepository; + this.bootstrapSettings = bootstrapSettings; + } + + public void createSuperGroups() { + if (!this.bootstrapSettings.mocking() || !this.superGroupRepository.getAll().isEmpty()) { + return; + } + + LOGGER.info("========== SUPERGROUP BOOTSTRAP =========="); + + mockData.superGroups().stream() + .map(MockData.MockSuperGroup::type) + .distinct() + .forEach( + type -> { + try { + this.superGroupTypeRepository.add(new SuperGroupType(type.toLowerCase())); + } catch (SuperGroupTypeRepository.SuperGroupTypeAlreadyExistsException e) { + LOGGER.error("Error creating supergroup type: " + type + ";"); + } + }); + + LOGGER.info("Supergroup types created"); + + mockData + .superGroups() + .forEach( + mockSuperGroup -> { + this.superGroupRepository.save( + new SuperGroup( + new SuperGroupId(mockSuperGroup.id()), + 0, + new Name(mockSuperGroup.name()), + new PrettyName(mockSuperGroup.prettyName()), + new SuperGroupType(mockSuperGroup.type().toLowerCase()), + new Text())); + }); + + LOGGER.info("Supergroups created"); + + LOGGER.info("========== =========="); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/bootstrap/UserBootstrap.java b/app/src/main/java/it/chalmers/gamma/bootstrap/UserBootstrap.java new file mode 100644 index 000000000..2e7a78209 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/bootstrap/UserBootstrap.java @@ -0,0 +1,64 @@ +package it.chalmers.gamma.bootstrap; + +import it.chalmers.gamma.app.common.Email; +import it.chalmers.gamma.app.user.domain.*; +import java.util.stream.Collectors; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +@Component +public class UserBootstrap { + + private static final Logger LOGGER = LoggerFactory.getLogger(UserBootstrap.class); + + private final MockData mockData; + private final UserRepository userRepository; + private final BootstrapSettings bootstrapSettings; + + public UserBootstrap( + MockData mockData, UserRepository userRepository, BootstrapSettings bootstrapSettings) { + this.mockData = mockData; + this.userRepository = userRepository; + this.bootstrapSettings = bootstrapSettings; + } + + public void createUsers() { + if (!this.bootstrapSettings.mocking() || this.userRepository.getAll().size() > 1) { + return; + } + + LOGGER.info("========== USER BOOTSTRAP =========="); + + this.mockData + .users() + .forEach( + mockUser -> { + try { + this.userRepository.create( + new GammaUser( + new UserId(mockUser.id()), + new Cid(mockUser.cid()), + new Nick(mockUser.nick()), + new FirstName(mockUser.firstName()), + new LastName(mockUser.lastName()), + new AcceptanceYear(mockUser.acceptanceYear()), + Language.EN, + new UserExtended( + new Email(mockUser.cid() + "@example.org"), 0, false, null)), + new UnencryptedPassword("password1337")); + } catch (UserRepository.CidAlreadyInUseException + | UserRepository.EmailAlreadyInUseException e) { + e.printStackTrace(); + } + }); + + LOGGER.info( + "Generated the users: " + + this.mockData.users().stream() + .map(MockData.MockUser::cid) + .collect(Collectors.joining(", "))); + LOGGER.info("Use a cid from the row above and use the value: value to sign in"); + LOGGER.info("========== =========="); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/security/CookieConfig.java b/app/src/main/java/it/chalmers/gamma/security/CookieConfig.java new file mode 100644 index 000000000..f65b37675 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/security/CookieConfig.java @@ -0,0 +1,28 @@ +package it.chalmers.gamma.security; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.session.web.http.CookieSerializer; +import org.springframework.session.web.http.DefaultCookieSerializer; +import org.springframework.stereotype.Component; + +/** All other cookie config can be found in application.yml */ +@Component +public class CookieConfig { + + @Value("${application.cookie.validity-time}") + private int validityTime; + + @Bean + public CookieSerializer cookieSerializer() { + DefaultCookieSerializer serializer = new DefaultCookieSerializer(); + serializer.setSameSite("LAX"); + serializer.setUseSecureCookie(true); + serializer.setCookieName("gamma"); + serializer.setDomainName(""); + serializer.setUseHttpOnlyCookie(true); + serializer.setCookiePath("/"); + serializer.setCookieMaxAge(this.validityTime); + return serializer; + } +} diff --git a/app/src/main/java/it/chalmers/gamma/security/JWKConfig.java b/app/src/main/java/it/chalmers/gamma/security/JWKConfig.java new file mode 100644 index 000000000..1bc139242 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/security/JWKConfig.java @@ -0,0 +1,41 @@ +package it.chalmers.gamma.security; + +import com.nimbusds.jose.jwk.JWKSet; +import com.nimbusds.jose.jwk.RSAKey; +import com.nimbusds.jose.jwk.source.JWKSource; +import com.nimbusds.jose.proc.SecurityContext; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; +import java.util.UUID; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class JWKConfig { + + private static KeyPair generateRsaKey() throws NoSuchAlgorithmException { + KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); + keyPairGenerator.initialize(2048); + return keyPairGenerator.generateKeyPair(); + } + + @Bean + public JWKSource jwkSource(RSAKey rsaKey) { + JWKSet jwkSet = new JWKSet(rsaKey); + return (jwkSelector, securityContext) -> jwkSelector.select(jwkSet); + } + + @Bean + public RSAKey generateRsa() throws NoSuchAlgorithmException { + KeyPair keyPair = generateRsaKey(); + RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); + RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); + return new RSAKey.Builder(publicKey) + .privateKey(privateKey) + .keyID(UUID.randomUUID().toString()) + .build(); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/security/JWTConfig.java b/app/src/main/java/it/chalmers/gamma/security/JWTConfig.java new file mode 100644 index 000000000..cf98cd235 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/security/JWTConfig.java @@ -0,0 +1,17 @@ +package it.chalmers.gamma.security; + +import com.nimbusds.jose.JOSEException; +import com.nimbusds.jose.jwk.RSAKey; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.oauth2.jwt.JwtDecoder; +import org.springframework.security.oauth2.jwt.NimbusJwtDecoder; + +@Configuration +public class JWTConfig { + + @Bean + public JwtDecoder jwtDecoder(RSAKey rsaKey) throws JOSEException { + return NimbusJwtDecoder.withPublicKey(rsaKey.toRSAPublicKey()).build(); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/security/LoginCustomizer.java b/app/src/main/java/it/chalmers/gamma/security/LoginCustomizer.java new file mode 100644 index 000000000..dbcc1ef39 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/security/LoginCustomizer.java @@ -0,0 +1,13 @@ +package it.chalmers.gamma.security; + +import org.springframework.security.config.Customizer; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configurers.FormLoginConfigurer; + +public class LoginCustomizer implements Customizer> { + + @Override + public void customize(FormLoginConfigurer login) { + login.loginPage("/login").usernameParameter("username").passwordParameter("password"); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/security/LoginThrottlingFilter.java b/app/src/main/java/it/chalmers/gamma/security/LoginThrottlingFilter.java new file mode 100644 index 000000000..06f379542 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/security/LoginThrottlingFilter.java @@ -0,0 +1,36 @@ +package it.chalmers.gamma.security; + +import it.chalmers.gamma.app.throttling.ThrottlingService; +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import java.io.IOException; +import org.springframework.lang.NonNull; +import org.springframework.web.filter.OncePerRequestFilter; + +public class LoginThrottlingFilter extends OncePerRequestFilter { + + private final ThrottlingService throttlingService; + + public LoginThrottlingFilter(ThrottlingService throttlingService) { + this.throttlingService = throttlingService; + } + + @Override + protected void doFilterInternal( + @NonNull HttpServletRequest request, + @NonNull HttpServletResponse response, + @NonNull FilterChain filterChain) + throws ServletException, IOException { + String clientIp = request.getRemoteAddr(); + + if ("POST".equalsIgnoreCase(request.getMethod()) + && "/login".equals(request.getRequestURI()) + && !throttlingService.canProceed("login:" + clientIp, 50)) { + response.sendRedirect("/login?throttle=true"); + } else { + filterChain.doFilter(request, response); + } + } +} diff --git a/app/src/main/java/it/chalmers/gamma/security/LogoutCustomizer.java b/app/src/main/java/it/chalmers/gamma/security/LogoutCustomizer.java new file mode 100644 index 000000000..85e5fbeea --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/security/LogoutCustomizer.java @@ -0,0 +1,17 @@ +package it.chalmers.gamma.security; + +import org.springframework.security.config.Customizer; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configurers.LogoutConfigurer; +import org.springframework.security.web.util.matcher.AntPathRequestMatcher; + +public class LogoutCustomizer implements Customizer> { + + @Override + public void customize(LogoutConfigurer logout) { + logout + .logoutRequestMatcher(new AntPathRequestMatcher("/logout")) + .logoutSuccessUrl("/login") + .deleteCookies("gamma"); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/security/MvcConfig.java b/app/src/main/java/it/chalmers/gamma/security/MvcConfig.java new file mode 100644 index 000000000..40c25ca77 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/security/MvcConfig.java @@ -0,0 +1,38 @@ +package it.chalmers.gamma.security; + +import java.util.List; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.filter.HiddenHttpMethodFilter; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +@Configuration +@EnableWebMvc +public class MvcConfig implements WebMvcConfigurer { + + @Bean + public FilterRegistrationBean hiddenHttpMethodFilter() { + FilterRegistrationBean filterRegistrationBean = + new FilterRegistrationBean<>(new HiddenHttpMethodFilter()); + filterRegistrationBean.setUrlPatterns(List.of("/*")); + return filterRegistrationBean; + } + + @Override + public void addResourceHandlers(ResourceHandlerRegistry registry) { + registry.addResourceHandler("/img/**").addResourceLocations("classpath:/static/img/"); + + registry.addResourceHandler("/css/**").addResourceLocations("classpath:/static/css/"); + + registry.addResourceHandler("/js/**").addResourceLocations("classpath:/static/js/"); + + registry + .addResourceHandler("/webjars/**") + .addResourceLocations("classpath:/META-INF/resources/webjars/"); + + registry.addResourceHandler("/**").addResourceLocations("classpath:/static/txt/"); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/security/RedisConfig.java b/app/src/main/java/it/chalmers/gamma/security/RedisConfig.java new file mode 100644 index 000000000..f35daa44c --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/security/RedisConfig.java @@ -0,0 +1,17 @@ +package it.chalmers.gamma.security; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.core.RedisTemplate; + +@Configuration +public class RedisConfig { + + @Bean + public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) { + RedisTemplate template = new RedisTemplate<>(); + template.setConnectionFactory(redisConnectionFactory); + return template; + } +} diff --git a/app/src/main/java/it/chalmers/gamma/security/SecurityFiltersConfig.java b/app/src/main/java/it/chalmers/gamma/security/SecurityFiltersConfig.java new file mode 100644 index 000000000..2530f675a --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/security/SecurityFiltersConfig.java @@ -0,0 +1,227 @@ +package it.chalmers.gamma.security; + +import static org.springframework.security.web.header.writers.ClearSiteDataHeaderWriter.Directive.CACHE; +import static org.springframework.security.web.header.writers.ClearSiteDataHeaderWriter.Directive.COOKIES; + +import it.chalmers.gamma.adapter.secondary.jpa.user.TrustedUserDetailsRepository; +import it.chalmers.gamma.adapter.secondary.jpa.user.UserJpaRepository; +import it.chalmers.gamma.app.admin.domain.AdminRepository; +import it.chalmers.gamma.app.apikey.domain.ApiKeyRepository; +import it.chalmers.gamma.app.client.domain.ClientRepository; +import it.chalmers.gamma.app.oauth2.ClaimsMapper; +import it.chalmers.gamma.app.oauth2.UserInfoMapper; +import it.chalmers.gamma.app.throttling.ThrottlingService; +import it.chalmers.gamma.app.user.domain.UserId; +import it.chalmers.gamma.security.api.ApiAuthenticationFilter; +import it.chalmers.gamma.security.api.ApiAuthenticationProvider; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.annotation.Order; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.security.authentication.ProviderManager; +import org.springframework.security.authentication.dao.DaoAuthenticationProvider; +import org.springframework.security.config.Customizer; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.oauth2.core.oidc.endpoint.OidcParameterNames; +import org.springframework.security.oauth2.server.authorization.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration; +import org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers.OAuth2AuthorizationServerConfigurer; +import org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings; +import org.springframework.security.oauth2.server.authorization.token.JwtEncodingContext; +import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenCustomizer; +import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.authentication.HttpStatusEntryPoint; +import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; +import org.springframework.security.web.authentication.logout.HeaderWriterLogoutHandler; +import org.springframework.security.web.authentication.www.BasicAuthenticationFilter; +import org.springframework.security.web.csrf.XorCsrfTokenRequestAttributeHandler; +import org.springframework.security.web.header.writers.ClearSiteDataHeaderWriter; +import org.springframework.security.web.savedrequest.HttpSessionRequestCache; +import org.springframework.security.web.util.matcher.MediaTypeRequestMatcher; +import org.springframework.security.web.util.matcher.RegexRequestMatcher; + +@Configuration +public class SecurityFiltersConfig { + + @Order(1) + @Bean + public SecurityFilterChain authorizationServerSecurityFilterChain( + HttpSecurity http, UserInfoMapper userInfoMapper) throws Exception { + OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http); + + http.getConfigurer(OAuth2AuthorizationServerConfigurer.class) + .authorizationEndpoint( + authorizationEndpoint -> authorizationEndpoint.consentPage("/oauth2/consent")) + .oidc( + oidcConfigurer -> + oidcConfigurer.userInfoEndpoint( + userInfo -> userInfo.userInfoMapper(userInfoMapper))); + + http.exceptionHandling( + (exceptions) -> + exceptions.defaultAuthenticationEntryPointFor( + new LoginUrlAuthenticationEntryPoint("/login?authorizing"), + new MediaTypeRequestMatcher(MediaType.TEXT_HTML))) + .oauth2ResourceServer((resourceServer) -> resourceServer.jwt(Customizer.withDefaults())); + + return http.build(); + } + + @Bean + public AuthorizationServerSettings authorizationServerSettings() { + return AuthorizationServerSettings.builder().oidcUserInfoEndpoint("/oauth2/userinfo").build(); + } + + @Bean + public OAuth2TokenCustomizer tokenCustomizer(ClaimsMapper claimsMapper) { + return (context) -> { + if (OidcParameterNames.ID_TOKEN.equals(context.getTokenType().getValue())) { + context + .getClaims() + .claims( + (claims) -> + claims.putAll( + claimsMapper.generateClaims( + context.getAuthorizedScopes().stream() + .map(scope -> "SCOPE_" + scope) + .toList(), + UserId.valueOf(context.getAuthorization().getPrincipalName())))); + } + }; + } + + @Order(2) + @Bean + SecurityFilterChain externalSecurityFilterChain( + HttpSecurity http, + ApiKeyRepository apiKeyRepository, + ClientRepository clientRepository, + PasswordEncoder passwordEncoder) + throws Exception { + + ApiAuthenticationProvider apiAuthenticationProvider = + new ApiAuthenticationProvider(apiKeyRepository, clientRepository, passwordEncoder); + + RegexRequestMatcher regexRequestMatcher = new RegexRequestMatcher("\\/api/.+", null); + http.securityMatcher(regexRequestMatcher) + .addFilterBefore( + new ApiAuthenticationFilter(new ProviderManager(apiAuthenticationProvider)), + BasicAuthenticationFilter.class) + .authorizeHttpRequests(authorization -> authorization.anyRequest().authenticated()) + .sessionManagement( + sessionManagement -> + sessionManagement.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) + // Since only backends will call this + .csrf(csrf -> csrf.disable()) + .exceptionHandling( + config -> + config.authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED))); + return http.build(); + } + + @Order(3) + @Bean + SecurityFilterChain imagesSecurityFilterChain(HttpSecurity http) throws Exception { + http.securityMatcher(new RegexRequestMatcher("\\/images.+", null)) + .authorizeHttpRequests(authorization -> authorization.anyRequest().permitAll()) + .sessionManagement( + sessionManagement -> + sessionManagement.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) + .csrf(csrf -> csrf.disable()); + return http.build(); + } + + /** Sets up the security for web interface */ + @Order(4) + @Bean + SecurityFilterChain webSecurityFilterChain( + HttpSecurity http, + PasswordEncoder passwordEncoder, + UserJpaRepository userJpaRepository, + AdminRepository adminRepository, + ThrottlingService throttlingService) + throws Exception { + + TrustedUserDetailsRepository trustedUserDetails = + new TrustedUserDetailsRepository(userJpaRepository); + + DaoAuthenticationProvider userAuthenticationProvider = new DaoAuthenticationProvider(); + userAuthenticationProvider.setUserDetailsService(trustedUserDetails); + userAuthenticationProvider.setPasswordEncoder(passwordEncoder); + + HttpSessionRequestCache requestCache = new HttpSessionRequestCache(); + requestCache.setMatchingRequestParameterName(null); + + http.addFilterBefore( + new LoginThrottlingFilter(throttlingService), + UsernamePasswordAuthenticationFilter.class) + .addFilterAfter( + new UpdateUserPrincipalFilter(trustedUserDetails, adminRepository), + UsernamePasswordAuthenticationFilter.class) + .authorizeHttpRequests( + authorize -> + authorize + .requestMatchers(HttpMethod.GET, "/img/**") + .permitAll() + .requestMatchers(HttpMethod.GET, "/js/**") + .permitAll() + .requestMatchers(HttpMethod.GET, "/css/**") + .permitAll() + .requestMatchers(HttpMethod.GET, "/webjars/**") + .permitAll() + .requestMatchers(HttpMethod.GET, "/login") + .permitAll() + .requestMatchers(HttpMethod.POST, "/login") + .anonymous() + .requestMatchers(HttpMethod.GET, "/activate-cid") + .anonymous() + .requestMatchers(HttpMethod.POST, "/activate-cid") + .anonymous() + .requestMatchers(HttpMethod.GET, "/email-sent") + .anonymous() + .requestMatchers(HttpMethod.GET, "/register") + .anonymous() + .requestMatchers(HttpMethod.POST, "/register") + .anonymous() + .requestMatchers(HttpMethod.GET, "/forgot-password") + .anonymous() + .requestMatchers(HttpMethod.POST, "/forgot-password") + .anonymous() + .requestMatchers(HttpMethod.GET, "/forgot-password/finalize") + .anonymous() + .requestMatchers(HttpMethod.POST, "/forgot-password/finalize") + .anonymous() + .requestMatchers(HttpMethod.GET, "/robots.txt") + .permitAll() + .anyRequest() + .authenticated()) + .formLogin(new LoginCustomizer()) + .logout( + (logout) -> + logout.addLogoutHandler( + new HeaderWriterLogoutHandler(new ClearSiteDataHeaderWriter(CACHE, COOKIES)))) + .authenticationProvider(userAuthenticationProvider) + .sessionManagement( + sessionManagement -> + sessionManagement.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)) + .cors(Customizer.withDefaults()) + .csrf((csrf) -> csrf.csrfTokenRequestHandler(new XorCsrfTokenRequestAttributeHandler())) + .requestCache(cacheConfig -> cacheConfig.requestCache(requestCache)) + .exceptionHandling( + exceptionConfig -> + exceptionConfig.accessDeniedHandler( + (request, response, accessDeniedException) -> response.sendRedirect("/"))) + .headers( + headers -> + headers.contentSecurityPolicy( + csp -> + csp.policyDirectives( + "default-src 'self'; object-src 'none'; frame-ancestors 'none'; frame-src 'none'; base-uri 'none';"))); + + return http.build(); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/security/SessionConfig.java b/app/src/main/java/it/chalmers/gamma/security/SessionConfig.java new file mode 100644 index 000000000..882ea8ad9 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/security/SessionConfig.java @@ -0,0 +1,32 @@ +package it.chalmers.gamma.security; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.connection.RedisStandaloneConfiguration; +import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; +import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession; + +@Configuration +@EnableRedisHttpSession +public class SessionConfig { + + @Value("${spring.data.redis.host}") + private String redisHost; + + @Value("${spring.data.redis.port}") + private int redisPort; + + @Value("${spring.data.redis.password}") + private String redisPassword; + + @Bean + public LettuceConnectionFactory connectionFactory() { + RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration(); + redisStandaloneConfiguration.setHostName(redisHost); + redisStandaloneConfiguration.setPort(redisPort); + redisStandaloneConfiguration.setPassword(redisPassword); + + return new LettuceConnectionFactory(redisStandaloneConfiguration); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/security/TimerBlock.java b/app/src/main/java/it/chalmers/gamma/security/TimerBlock.java new file mode 100644 index 000000000..895d6c9f7 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/security/TimerBlock.java @@ -0,0 +1,57 @@ +package it.chalmers.gamma.security; + +import java.security.SecureRandom; +import java.util.concurrent.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class TimerBlock { + private static final Logger LOGGER = LoggerFactory.getLogger(TimerBlock.class); + private static final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); + + private final long minExecutionTimeInMillis; + + private TimerBlock(long minExecutionTimeInMillis) { + this.minExecutionTimeInMillis = minExecutionTimeInMillis; + } + + public static TimerBlock minimum(long minExecutionTimeInMillis) { + return new TimerBlock(minExecutionTimeInMillis); + } + + public void execute(Runnable block) { + SecureRandom secureRandom = new SecureRandom(); + long startTime = System.currentTimeMillis(); + RuntimeException blockException = null; + try { + block.run(); + } catch (RuntimeException e) { + blockException = e; + } finally { + long endTime = System.currentTimeMillis(); + long actualExecutionTimeInMillis = endTime - startTime; + + long maxExecutionTime = minExecutionTimeInMillis + (long) (minExecutionTimeInMillis * 0.5); + long randomDelay = + minExecutionTimeInMillis + + secureRandom.nextInt((int) (maxExecutionTime - minExecutionTimeInMillis)); + + if (actualExecutionTimeInMillis < randomDelay) { + try { + long remainingTimeInMillis = randomDelay - actualExecutionTimeInMillis; + scheduler.schedule(() -> {}, remainingTimeInMillis, TimeUnit.MILLISECONDS).get(); + } catch (InterruptedException | ExecutionException e) { + LOGGER.warn("Exception occurred during delay: {}", e.getMessage()); + } + } else { + LOGGER.warn( + "Block execution took longer than expected: {} milliseconds.", + actualExecutionTimeInMillis); + } + } + + if (blockException != null) { + throw blockException; + } + } +} diff --git a/app/src/main/java/it/chalmers/gamma/security/UpdateUserPrincipalFilter.java b/app/src/main/java/it/chalmers/gamma/security/UpdateUserPrincipalFilter.java new file mode 100644 index 000000000..5971b7b6e --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/security/UpdateUserPrincipalFilter.java @@ -0,0 +1,47 @@ +package it.chalmers.gamma.security; + +import it.chalmers.gamma.adapter.secondary.jpa.user.TrustedUserDetailsRepository; +import it.chalmers.gamma.app.admin.domain.AdminRepository; +import it.chalmers.gamma.app.user.domain.GammaUser; +import it.chalmers.gamma.security.authentication.UserAuthentication; +import jakarta.servlet.*; +import java.io.IOException; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.UsernameNotFoundException; + +public class UpdateUserPrincipalFilter implements Filter { + + private final TrustedUserDetailsRepository userDetailsRepository; + private final AdminRepository adminRepository; + + public UpdateUserPrincipalFilter( + TrustedUserDetailsRepository userDetailsRepository, AdminRepository adminRepository) { + this.userDetailsRepository = userDetailsRepository; + this.adminRepository = adminRepository; + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException { + if (SecurityContextHolder.getContext().getAuthentication() + instanceof UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken) { + if (!usernamePasswordAuthenticationToken.isAuthenticated()) { + return; + } + + try { + final GammaUser gammaUser = userDetailsRepository.getGammaUserByUser(); + final boolean isAdmin = adminRepository.isAdmin(gammaUser.id()); + + UserAuthentication userPrincipal = new UserAuthentication(gammaUser, isAdmin); + + usernamePasswordAuthenticationToken.setDetails(userPrincipal); + } catch (UsernameNotFoundException ignored) { + SecurityContextHolder.getContext().setAuthentication(null); + } + } + + chain.doFilter(request, response); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/security/api/ApiAuthenticationConverter.java b/app/src/main/java/it/chalmers/gamma/security/api/ApiAuthenticationConverter.java new file mode 100644 index 000000000..a532a1193 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/security/api/ApiAuthenticationConverter.java @@ -0,0 +1,29 @@ +package it.chalmers.gamma.security.api; + +import jakarta.servlet.http.HttpServletRequest; +import java.util.Optional; +import org.springframework.security.core.Authentication; +import org.springframework.security.web.authentication.AuthenticationConverter; + +public class ApiAuthenticationConverter implements AuthenticationConverter { + + @Override + public Authentication convert(HttpServletRequest request) { + Optional maybeApiKeyToken = resolveToken(request); + return maybeApiKeyToken.map(ApiAuthenticationToken::fromApiKeyToken).orElse(null); + } + + private Optional resolveToken(HttpServletRequest req) { + String basicToken = req.getHeader("Authorization"); + if (basicToken != null && basicToken.startsWith("pre-shared ")) { + basicToken = removePreShared(basicToken); + } else { + basicToken = null; + } + return Optional.ofNullable(basicToken); + } + + private String removePreShared(String token) { + return token.substring(11); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/security/api/ApiAuthenticationFilter.java b/app/src/main/java/it/chalmers/gamma/security/api/ApiAuthenticationFilter.java new file mode 100644 index 000000000..b3085abee --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/security/api/ApiAuthenticationFilter.java @@ -0,0 +1,14 @@ +package it.chalmers.gamma.security.api; + +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.web.authentication.AuthenticationFilter; + +public class ApiAuthenticationFilter extends AuthenticationFilter { + + public ApiAuthenticationFilter(AuthenticationManager authenticationManager) { + super(authenticationManager, new ApiAuthenticationConverter()); + + // Do nothing on successful authentication since we need to authenticate on every request + setSuccessHandler((request, response, authentication) -> {}); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/security/api/ApiAuthenticationProvider.java b/app/src/main/java/it/chalmers/gamma/security/api/ApiAuthenticationProvider.java new file mode 100644 index 000000000..5e1115c60 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/security/api/ApiAuthenticationProvider.java @@ -0,0 +1,69 @@ +package it.chalmers.gamma.security.api; + +import it.chalmers.gamma.app.apikey.domain.ApiKey; +import it.chalmers.gamma.app.apikey.domain.ApiKeyId; +import it.chalmers.gamma.app.apikey.domain.ApiKeyRepository; +import it.chalmers.gamma.app.client.domain.Client; +import it.chalmers.gamma.app.client.domain.ClientRepository; +import it.chalmers.gamma.security.authentication.ApiAuthentication; +import java.util.Optional; +import org.springframework.security.authentication.AuthenticationProvider; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.crypto.password.PasswordEncoder; + +public class ApiAuthenticationProvider implements AuthenticationProvider { + + private final ApiKeyRepository apiKeyRepository; + private final ClientRepository clientRepository; + private final PasswordEncoder passwordEncoder; + + public ApiAuthenticationProvider( + ApiKeyRepository apiKeyRepository, + ClientRepository clientRepository, + PasswordEncoder passwordEncoder) { + this.apiKeyRepository = apiKeyRepository; + this.clientRepository = clientRepository; + this.passwordEncoder = passwordEncoder; + } + + @Override + public Authentication authenticate(Authentication authentication) throws AuthenticationException { + ApiAuthenticationToken apiAuthenticationToken = (ApiAuthenticationToken) authentication; + final ApiKey apiKey = + this.apiKeyRepository + .getById(new ApiKeyId(apiAuthenticationToken.getCredentials().apiKeyId())) + .orElseThrow(ApiAuthenticationException::new); + + if (!passwordEncoder.matches( + apiAuthenticationToken.getCredentials().token(), apiKey.apiKeyToken().value())) { + throw new ApiAuthenticationException(); + } + + final Optional maybeClient = this.clientRepository.getByApiKey(apiKey.apiKeyToken()); + + return ApiAuthenticationToken.fromAuthenticatedApiKey( + new ApiAuthentication() { + @Override + public ApiKey get() { + return apiKey; + } + + @Override + public Optional getClient() { + return maybeClient; + } + }); + } + + @Override + public boolean supports(Class authentication) { + return ApiAuthenticationToken.class.isAssignableFrom(authentication); + } + + public static class ApiAuthenticationException extends AuthenticationException { + public ApiAuthenticationException() { + super("Exception when trying to authenticate api key"); + } + } +} diff --git a/app/src/main/java/it/chalmers/gamma/security/api/ApiAuthenticationToken.java b/app/src/main/java/it/chalmers/gamma/security/api/ApiAuthenticationToken.java new file mode 100644 index 000000000..4dc208bd1 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/security/api/ApiAuthenticationToken.java @@ -0,0 +1,64 @@ +package it.chalmers.gamma.security.api; + +import static org.springframework.security.core.authority.AuthorityUtils.NO_AUTHORITIES; + +import it.chalmers.gamma.security.authentication.ApiAuthentication; +import java.util.UUID; +import org.springframework.security.authentication.AbstractAuthenticationToken; +import org.springframework.security.core.Transient; + +@Transient +public class ApiAuthenticationToken extends AbstractAuthenticationToken { + + private final UUID apiKeyId; + private final String apiKeyToken; + private final ApiAuthentication apiPrincipal; + + private ApiAuthenticationToken(ApiAuthentication apiPrincipal) { + super(NO_AUTHORITIES); + this.apiKeyId = apiPrincipal.get().id().value(); + this.apiKeyToken = null; + this.apiPrincipal = apiPrincipal; + super.setAuthenticated(true); + } + + private ApiAuthenticationToken(UUID apiKeyId, String apiKeyToken) { + super(NO_AUTHORITIES); + this.apiKeyId = apiKeyId; + this.apiKeyToken = apiKeyToken; + this.apiPrincipal = null; + super.setAuthenticated(false); + } + + public static ApiAuthenticationToken fromApiKeyToken(String apiKeyToken) { + try { + String[] parts = apiKeyToken.split(":"); + + return new ApiAuthenticationToken(UUID.fromString(parts[0]), parts[1]); + } catch (Exception e) { + throw new ApiAuthenticationProvider.ApiAuthenticationException(); + } + } + + public static ApiAuthenticationToken fromAuthenticatedApiKey(ApiAuthentication apiPrincipal) { + return new ApiAuthenticationToken(apiPrincipal); + } + + @Override + public void setAuthenticated(boolean authenticated) { + throw new IllegalCallerException( + "You cannot call set authenticated on an already created ApiAuthenticationToken"); + } + + public record Credentials(UUID apiKeyId, String token) {} + + @Override + public Credentials getCredentials() { + return new Credentials(this.apiKeyId, this.apiKeyToken); + } + + @Override + public ApiAuthentication getPrincipal() { + return this.apiPrincipal; + } +} diff --git a/app/src/main/java/it/chalmers/gamma/security/authentication/ApiAuthentication.java b/app/src/main/java/it/chalmers/gamma/security/authentication/ApiAuthentication.java new file mode 100644 index 000000000..ffdbb6dcd --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/security/authentication/ApiAuthentication.java @@ -0,0 +1,12 @@ +package it.chalmers.gamma.security.authentication; + +import it.chalmers.gamma.app.apikey.domain.ApiKey; +import it.chalmers.gamma.app.client.domain.Client; +import java.util.Optional; + +public non-sealed interface ApiAuthentication extends GammaAuthentication { + ApiKey get(); + + /** Api key might be connected to a client. */ + Optional getClient(); +} diff --git a/app/src/main/java/it/chalmers/gamma/security/authentication/AuthenticationExtractor.java b/app/src/main/java/it/chalmers/gamma/security/authentication/AuthenticationExtractor.java new file mode 100644 index 000000000..3c028cf80 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/security/authentication/AuthenticationExtractor.java @@ -0,0 +1,25 @@ +package it.chalmers.gamma.security.authentication; + +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; + +public final class AuthenticationExtractor { + + private AuthenticationExtractor() {} + + public static GammaAuthentication getAuthentication() { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + + if (authentication == null) { + return null; + } + + if (authentication.getPrincipal() instanceof GammaAuthentication gammaAuthentication) { + return gammaAuthentication; + } else if (authentication.getDetails() instanceof GammaAuthentication gammaAuthentication) { + return gammaAuthentication; + } else { + return null; + } + } +} diff --git a/app/src/main/java/it/chalmers/gamma/security/authentication/GammaAuthentication.java b/app/src/main/java/it/chalmers/gamma/security/authentication/GammaAuthentication.java new file mode 100644 index 000000000..92c03a58e --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/security/authentication/GammaAuthentication.java @@ -0,0 +1,5 @@ +package it.chalmers.gamma.security.authentication; + +/** These are the different */ +public sealed interface GammaAuthentication + permits ApiAuthentication, UserAuthentication, LocalRunnerAuthentication {} diff --git a/app/src/main/java/it/chalmers/gamma/security/authentication/LocalRunnerAuthentication.java b/app/src/main/java/it/chalmers/gamma/security/authentication/LocalRunnerAuthentication.java new file mode 100644 index 000000000..3c6a46efa --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/security/authentication/LocalRunnerAuthentication.java @@ -0,0 +1,3 @@ +package it.chalmers.gamma.security.authentication; + +public non-sealed interface LocalRunnerAuthentication extends GammaAuthentication {} diff --git a/app/src/main/java/it/chalmers/gamma/security/authentication/UserAuthentication.java b/app/src/main/java/it/chalmers/gamma/security/authentication/UserAuthentication.java new file mode 100644 index 000000000..c1abcd6ea --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/security/authentication/UserAuthentication.java @@ -0,0 +1,11 @@ +package it.chalmers.gamma.security.authentication; + +import it.chalmers.gamma.app.user.domain.GammaUser; +import java.util.Objects; + +public record UserAuthentication(GammaUser gammaUser, boolean isAdmin) + implements GammaAuthentication { + public UserAuthentication { + Objects.requireNonNull(gammaUser); + } +} diff --git a/app/src/main/java/it/chalmers/gamma/security/user/PasswordConfiguration.java b/app/src/main/java/it/chalmers/gamma/security/user/PasswordConfiguration.java new file mode 100644 index 000000000..d47a27318 --- /dev/null +++ b/app/src/main/java/it/chalmers/gamma/security/user/PasswordConfiguration.java @@ -0,0 +1,14 @@ +package it.chalmers.gamma.security.user; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.crypto.factory.PasswordEncoderFactories; +import org.springframework.security.crypto.password.PasswordEncoder; + +@Configuration +public class PasswordConfiguration { + @Bean + public PasswordEncoder passwordEncoder() { + return PasswordEncoderFactories.createDelegatingPasswordEncoder(); + } +} diff --git a/app/src/main/resources/application.yml b/app/src/main/resources/application.yml new file mode 100644 index 000000000..4a09eceee --- /dev/null +++ b/app/src/main/resources/application.yml @@ -0,0 +1,69 @@ +--- +spring: + datasource: + username: "${DB_USER:postgres}" + password: "${DB_PASSWORD:postgres}" + url: "jdbc:postgresql://${DB_HOST:db}:${DB_PORT:5432}/${DB_NAME:postgres}" + flyway: + baseline-on-migrate: true + locations: "classpath:/db/migration" + output: + ansi: + enabled: "ALWAYS" + jpa: + database-platform: "org.hibernate.dialect.PostgreSQLDialect" + properties: + hibernate: + globally_quoted_identifiers: true + temp: + use_jdbc_metadata_defaults: false + hibernate: + ddl-auto: "validate" + open-in-view: false + servlet: + multipart: + max-file-size: 50MB + data: + redis: + host: "${REDIS_HOST:redis}" + password: "${REDIS_PASSWORD:}" + port: "${REDIS_PORT:6379}" + repositories: + enabled: true + thymeleaf: + cache: "${PRODUCTION:false}" + enabled: true + encoding: "UTF-8" + session: + store-type: "redis" + timeout: "${SESSION_TIMEOUT:43200}" + mvc: + hiddenmethod: + filter: + enabled: true + threads: + virtual: + enabled: true +server: + port: "${SERVER_PORT:8081}" + error: + whitelabel: + enabled: false + path: "/error" + http2: + enabled: true + forward-headers-strategy: "native" +logging: + level: + root: "${ROOT_DEBUG_LEVEL:INFO}" +application: + base-url: "${BASE_URL:http://localhost:8081}" + production: "${PRODUCTION:false}" + files: + path: "${UPLOAD_FOLDER:./uploads/}" + cookie: + validity-time: 2628000 + admin-setup: "${ADMIN_SETUP:true}" + gotify: + key: "${GOTIFY_KEY:123abc}" + url: "${GOTIFY_BASE_URL:http://gotify:80}" diff --git a/app/src/main/resources/db/migration/V1__BASE.sql b/app/src/main/resources/db/migration/V1__BASE.sql new file mode 100644 index 000000000..7b50a143d --- /dev/null +++ b/app/src/main/resources/db/migration/V1__BASE.sql @@ -0,0 +1,240 @@ +-- g_ = gamma prefix to prevent using reserved names +CREATE TABLE g_text +( + text_id UUID PRIMARY KEY, + sv VARCHAR(2048) NOT NULL, + en VARCHAR(2048) NOT NULL, + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE TABLE g_user +( + user_id UUID PRIMARY KEY, + cid VARCHAR(12) NOT NULL UNIQUE, + password VARCHAR(255) CHECK (password IS NULL OR password LIKE '{bcrypt}$%'), + nick VARCHAR(50) NOT NULL, + first_name VARCHAR(50) NOT NULL, + last_name VARCHAR(50) NOT NULL, + email VARCHAR(100) NOT NULL UNIQUE, + LANGUAGE VARCHAR(15) NULL, + user_agreement_accepted TIMESTAMP NOT NULL DEFAULT NOW(), + acceptance_year INTEGER, + version INT, + locked BOOLEAN DEFAULT FALSE, + created_at TIMESTAMP NOT NULL, + updated_at TIMESTAMP NOT NULL +); + +CREATE TABLE g_user_avatar_uri +( + avatar_uri VARCHAR(255) NOT NULL, + version INT, + created_at TIMESTAMP NOT NULL, + updated_at TIMESTAMP NOT NULL, + user_id UUID REFERENCES g_user ON DELETE CASCADE +); + +CREATE TABLE g_admin_user +( + created_at TIMESTAMP NOT NULL, + user_id UUID PRIMARY KEY REFERENCES g_user (user_id) ON DELETE CASCADE +); + +CREATE TABLE g_gdpr_trained +( + created_at TIMESTAMP NOT NULL, + user_id UUID PRIMARY KEY REFERENCES g_user (user_id) ON DELETE CASCADE +); + +CREATE TABLE g_password_reset +( + token VARCHAR(100) UNIQUE, + user_id UUID PRIMARY KEY REFERENCES g_user ON DELETE CASCADE, + created_at TIMESTAMP NOT NULL +); + +CREATE TABLE g_super_group_type +( + super_group_type_name VARCHAR(30) PRIMARY KEY, + created_at TIMESTAMP NOT NULL +); + +CREATE TABLE g_super_group +( + super_group_id UUID PRIMARY KEY, + e_name VARCHAR(50) NOT NULL UNIQUE, + pretty_name VARCHAR(50) NOT NULL, + super_group_type_name VARCHAR(30) NOT NULL REFERENCES g_super_group_type, + created_at TIMESTAMP NOT NULL, + updated_at TIMESTAMP NOT NULL, + description UUID REFERENCES g_text ON DELETE CASCADE, + version INT +); + +CREATE TABLE g_group +( + group_id UUID PRIMARY KEY, + e_name VARCHAR(50) NOT NULL UNIQUE, + pretty_name VARCHAR(50) NOT NULL, + super_group_id UUID NOT NULL REFERENCES g_super_group, + created_at TIMESTAMP NOT NULL, + updated_at TIMESTAMP NOT NULL, + version INT +); + +CREATE TABLE g_post +( + post_id UUID PRIMARY KEY, + post_name UUID NOT NULL REFERENCES g_text ON DELETE CASCADE, + email_prefix VARCHAR(20), + version INT, + created_at TIMESTAMP NOT NULL, + updated_at TIMESTAMP NOT NULL +); + +CREATE TABLE g_membership +( + created_at TIMESTAMP NOT NULL, + user_id UUID REFERENCES g_user ON DELETE CASCADE, + group_id UUID REFERENCES g_group ON DELETE CASCADE, + post_id UUID REFERENCES g_post ON DELETE CASCADE, + unofficial_post_name VARCHAR(50), + PRIMARY KEY (user_id,group_id,post_id) +); + +CREATE TABLE g_allow_list +( + created_at TIMESTAMP NOT NULL, + cid VARCHAR(10) PRIMARY KEY CHECK (LOWER(cid) = cid) +); + +CREATE TABLE g_user_activation +( + cid VARCHAR(10) PRIMARY KEY REFERENCES g_allow_list, + token VARCHAR(10) UNIQUE NOT NULL, + created_at TIMESTAMP NOT NULL +); + +CREATE TABLE g_client +( + client_uid UUID PRIMARY KEY, + client_id VARCHAR(100) UNIQUE, + client_secret VARCHAR(255) NOT NULL CHECK (client_secret LIKE '{bcrypt}$%'), + redirect_uri VARCHAR(256) NOT NULL, + pretty_name VARCHAR(30) NOT NULL, + created_at TIMESTAMP NOT NULL, + description UUID REFERENCES g_text ON DELETE CASCADE, + official BOOLEAN NOT NULL, + created_by UUID REFERENCES g_user (user_id) ON DELETE CASCADE, + CHECK ( + (official = TRUE AND created_by IS NULL) + OR + (official = FALSE AND created_by IS NOT NULL) + ) +); + +CREATE TABLE g_client_scope +( + client_uid UUID REFERENCES g_client, + SCOPE VARCHAR(30) NOT NULL, + created_at TIMESTAMP NOT NULL, + PRIMARY KEY (client_uid,SCOPE) +); + +CREATE TABLE g_user_approval +( + created_at TIMESTAMP NOT NULL, + user_id UUID REFERENCES g_user ON DELETE CASCADE, + client_uid UUID REFERENCES g_client ON DELETE CASCADE, + PRIMARY KEY (user_id,client_uid) +); + +CREATE TABLE g_group_images_uri +( + created_at TIMESTAMP NOT NULL, + updated_at TIMESTAMP NOT NULL, + group_id UUID REFERENCES g_group ON DELETE CASCADE, + avatar_uri VARCHAR(255), + banner_uri VARCHAR(255), + version INT +); + +CREATE TABLE g_api_key +( + api_key_id UUID PRIMARY KEY, + pretty_name VARCHAR(30) NOT NULL, + token VARCHAR(255) NOT NULL CHECK (token LIKE '{bcrypt}$%'), + KEY_TYPE VARCHAR(30) NOT NULL, + created_at TIMESTAMP NOT NULL, + updated_at TIMESTAMP NOT NULL, + version INT, + description UUID REFERENCES g_text ON DELETE CASCADE +); + +CREATE TABLE g_api_key_settings +( + settings_id UUID PRIMARY KEY, + created_at TIMESTAMP NOT NULL, + updated_at TIMESTAMP NOT NULL, + version INT, + api_key_id UUID REFERENCES g_api_key (api_key_id) ON DELETE CASCADE +); + +CREATE TABLE g_api_key_to_super_group_type +( + settings_id UUID REFERENCES g_api_key_settings (settings_id), + created_at TIMESTAMP NOT NULL, + super_group_type_name VARCHAR(30) REFERENCES g_super_group_type, + PRIMARY KEY (settings_id,super_group_type_name) +); + +CREATE TABLE g_client_api_key +( + created_at TIMESTAMP NOT NULL, + client_uid UUID PRIMARY KEY REFERENCES g_client ON DELETE CASCADE, + api_key_id UUID REFERENCES g_api_key ON DELETE CASCADE +); + +CREATE TABLE g_client_authority +( + created_at TIMESTAMP NOT NULL, + client_uid UUID REFERENCES g_client (client_uid) ON DELETE CASCADE, + authority_name VARCHAR(30), + PRIMARY KEY (client_uid,authority_name) +); + +CREATE TABLE g_client_authority_super_group +( + created_at TIMESTAMP NOT NULL, + super_group_id UUID REFERENCES g_super_group, + client_uid UUID, + authority_name VARCHAR(30), + PRIMARY KEY (super_group_id,client_uid,authority_name), + FOREIGN KEY (client_uid,authority_name) REFERENCES g_client_authority (client_uid,authority_name) ON DELETE CASCADE +); + +CREATE TABLE g_client_authority_user +( + created_at TIMESTAMP NOT NULL, + user_id UUID REFERENCES g_user ON DELETE CASCADE, + client_uid UUID, + authority_name VARCHAR(30), + PRIMARY KEY (user_id,client_uid,authority_name), + FOREIGN KEY (client_uid,authority_name) REFERENCES g_client_authority (client_uid,authority_name) ON DELETE CASCADE +); + +CREATE TABLE g_client_restriction +( + created_at TIMESTAMP NOT NULL, + restriction_id UUID, + client_uid UUID REFERENCES g_client ON DELETE CASCADE, + PRIMARY KEY (client_uid) +); + +CREATE TABLE g_client_restriction_super_group +( + created_at TIMESTAMP NOT NULL, + super_group_id UUID REFERENCES g_super_group ON DELETE CASCADE, + restriction_id UUID REFERENCES g_client_restriction ON DELETE CASCADE, + PRIMARY KEY (super_group_id,restriction_id) +); \ No newline at end of file diff --git a/app/src/main/resources/db/migration/V2__TOKENS.sql b/app/src/main/resources/db/migration/V2__TOKENS.sql new file mode 100644 index 000000000..13733f527 --- /dev/null +++ b/app/src/main/resources/db/migration/V2__TOKENS.sql @@ -0,0 +1,2 @@ +ALTER TABLE g_user_activation + ALTER COLUMN token TYPE VARCHAR(100); \ No newline at end of file diff --git a/app/src/main/resources/db/migration/V3__RESTRICT_POST_DELETION.sql b/app/src/main/resources/db/migration/V3__RESTRICT_POST_DELETION.sql new file mode 100644 index 000000000..6a3d6ba99 --- /dev/null +++ b/app/src/main/resources/db/migration/V3__RESTRICT_POST_DELETION.sql @@ -0,0 +1,6 @@ +ALTER TABLE g_membership + DROP CONSTRAINT g_membership_post_id_fkey; + +ALTER TABLE g_membership + ADD CONSTRAINT g_membership_post_id_fkey FOREIGN KEY (post_id) + REFERENCES g_post (post_id) ON DELETE RESTRICT; \ No newline at end of file diff --git a/app/src/main/resources/db/migration/V4__ADD_POST_ORDER.sql b/app/src/main/resources/db/migration/V4__ADD_POST_ORDER.sql new file mode 100644 index 000000000..1d61221ce --- /dev/null +++ b/app/src/main/resources/db/migration/V4__ADD_POST_ORDER.sql @@ -0,0 +1,2 @@ +ALTER TABLE g_post + ADD COLUMN post_order INT DEFAULT 0 CHECK ( post_order >= 0 ); \ No newline at end of file diff --git a/app/src/main/resources/image/default_group_avatar.jpg b/app/src/main/resources/image/default_group_avatar.jpg new file mode 100644 index 000000000..c5abc8af7 Binary files /dev/null and b/app/src/main/resources/image/default_group_avatar.jpg differ diff --git a/app/src/main/resources/image/default_group_banner.jpg b/app/src/main/resources/image/default_group_banner.jpg new file mode 100644 index 000000000..6dd1e1993 Binary files /dev/null and b/app/src/main/resources/image/default_group_banner.jpg differ diff --git a/backend/src/main/resources/image/default.jpg b/app/src/main/resources/image/default_user_avatar.jpg similarity index 100% rename from backend/src/main/resources/image/default.jpg rename to app/src/main/resources/image/default_user_avatar.jpg diff --git a/app/src/main/resources/mock/mock.json b/app/src/main/resources/mock/mock.json new file mode 100644 index 000000000..f2e2610ea --- /dev/null +++ b/app/src/main/resources/mock/mock.json @@ -0,0 +1,337 @@ +{ + "users" : [ { + "id" : "88eec5c2-5ebb-4e13-9a76-fcc4dac9e74f", + "firstName" : "Michael", + "lastName" : "Scott", + "cid" : "mscott", + "nick" : "Boss", + "acceptanceYear" : 2005, + "admin" : true + }, { + "id" : "bc605869-9a4d-46ec-8a29-d00819d4c195", + "firstName" : "Jim", + "lastName" : "Halpert", + "cid" : "jhalpert", + "nick" : "Big Tuna", + "acceptanceYear" : 2002 + }, { + "id" : "ec8987d7-4087-461d-bed5-9365086b6e3b", + "firstName" : "Pam", + "lastName" : "Beesly", + "cid" : "pbeesly", + "nick" : "Pam-Pam", + "acceptanceYear" : 2003 + }, { + "id" : "0c67c90b-dfdf-473a-98e3-b551e2f2f0f1", + "firstName" : "Dwight", + "lastName" : "Schrute", + "cid" : "dschrute", + "nick" : "Assistant Manager", + "acceptanceYear" : 2001 + }, { + "id" : "858e5acc-c289-40d3-9422-d6d317f40299", + "firstName" : "Angela", + "lastName" : "Martin", + "cid" : "amartin", + "nick" : "Pumpkin", + "acceptanceYear" : 2008 + }, { + "id" : "9ad8946d-cfef-4f6f-8b48-cfb536d0c9eb", + "firstName" : "Stanley", + "lastName" : "Hudson", + "cid" : "shudson", + "nick" : "Papa Bear", + "acceptanceYear" : 2002 + }, { + "id" : "4efb340f-540c-4b15-a362-d402aab10195", + "firstName" : "Kevin", + "lastName" : "Malone", + "cid" : "kmalone", + "nick" : "Chili King", + "acceptanceYear" : 2006 + }, { + "id" : "08e4abb5-e4d6-413b-94f2-6e1aa63716e7", + "firstName" : "Oscar", + "lastName" : "Martinez", + "cid" : "omartinez", + "nick" : "C-Span", + "acceptanceYear" : 2008 + }, { + "id" : "43af2838-43b9-4665-b3d7-9c615f5038fb", + "firstName" : "Andy", + "lastName" : "Bernard", + "cid" : "abernard", + "nick" : "Nard Dog", + "acceptanceYear" : 2007 + }, { + "id" : "4542ab3d-7996-4097-ae4a-4fe61eaf2f20", + "firstName" : "Phyllis", + "lastName" : "Vance", + "cid" : "pvance", + "nick" : "Mama Goose", + "acceptanceYear" : 2006 + }, { + "id" : "0a799f6d-c65a-4d20-8588-2ff5375d6cce", + "firstName" : "Meredith", + "lastName" : "Palmer", + "cid" : "mpalmer", + "nick" : "Einstein", + "acceptanceYear" : 2003 + }, { + "id" : "4fcf6566-45d8-4d5d-b7d4-4f6f52bb0ac2", + "firstName" : "Kelly", + "lastName" : "Kapoor", + "cid" : "kkapoor", + "nick" : "Business Woman", + "acceptanceYear" : 2004 + }, { + "id" : "e6a76e6a-3499-4611-ae28-e1281ffa6e80", + "firstName" : "Creed", + "lastName" : "Bratton", + "cid" : "cbratton", + "nick" : "Papa Smurf", + "acceptanceYear" : 2007 + } ], + "groups" : [ { + "id" : "047ac437-a789-4cc5-bb6e-ba50efd7c509", + "name" : "digit", + "prettyName" : "digIT", + "superGroupId" : "364a359a-f9eb-4d81-bb99-25cc5adf176d", + "members" : [ { + "userId" : "bc605869-9a4d-46ec-8a29-d00819d4c195", + "postId" : "7bb1db15-730d-4864-bfc3-99abe7c0ccf8", + "unofficialPostName" : "root" + }, { + "userId" : "ec8987d7-4087-461d-bed5-9365086b6e3b", + "postId" : "844067b3-e95d-4a28-a586-7388f155b8fb", + "unofficialPostName" : "cache-chef" + }, { + "userId" : "0c67c90b-dfdf-473a-98e3-b551e2f2f0f1", + "postId" : "08efcf3a-1805-4b5f-a60e-da6ce0d33f58", + "unofficialPostName" : "dev-ooops" + } ] + }, { + "id" : "2abe2264-fd61-4899-ba46-851279d85229", + "name" : "digit", + "prettyName" : "digIT", + "superGroupId" : "aed27030-ad90-4526-855c-1e909b1dcecb", + "members" : [ { + "userId" : "858e5acc-c289-40d3-9422-d6d317f40299", + "postId" : "7bb1db15-730d-4864-bfc3-99abe7c0ccf8", + "unofficialPostName" : "root" + }, { + "userId" : "9ad8946d-cfef-4f6f-8b48-cfb536d0c9eb", + "postId" : "844067b3-e95d-4a28-a586-7388f155b8fb", + "unofficialPostName" : "cache-chef" + }, { + "userId" : "4efb340f-540c-4b15-a362-d402aab10195", + "postId" : "08efcf3a-1805-4b5f-a60e-da6ce0d33f58", + "unofficialPostName" : "dev-ooops" + } ] + }, { + "id" : "a2f06d3a-7432-4655-a778-69c9142912f1", + "name" : "styrit", + "prettyName" : "styrIT", + "superGroupId" : "30c2ee3b-b761-46d0-9029-215a9b484f7a", + "members" : [ { + "userId" : "9ad8946d-cfef-4f6f-8b48-cfb536d0c9eb", + "postId" : "7bb1db15-730d-4864-bfc3-99abe7c0ccf8", + "unofficialPostName" : "Ordf" + }, { + "userId" : "bc605869-9a4d-46ec-8a29-d00819d4c195", + "postId" : "844067b3-e95d-4a28-a586-7388f155b8fb", + "unofficialPostName" : "Kassör" + }, { + "userId" : "4542ab3d-7996-4097-ae4a-4fe61eaf2f20", + "postId" : "08efcf3a-1805-4b5f-a60e-da6ce0d33f58", + "unofficialPostName" : "IT-ansvarig" + }, { + "userId" : "0a799f6d-c65a-4d20-8588-2ff5375d6cce", + "postId" : "524db9a7-e8be-403e-a07c-a41803ea5ee7", + "unofficialPostName" : "VO" + } ] + }, { + "id" : "834651d1-34c1-4bac-b148-6546368a8454", + "name" : "styrit", + "prettyName" : "styrIT", + "superGroupId" : "2157ee72-04cd-4029-8d57-77142d3ef5fa", + "members" : [ { + "userId" : "4fcf6566-45d8-4d5d-b7d4-4f6f52bb0ac2", + "postId" : "7bb1db15-730d-4864-bfc3-99abe7c0ccf8", + "unofficialPostName" : "Ordf" + }, { + "userId" : "bc605869-9a4d-46ec-8a29-d00819d4c195", + "postId" : "844067b3-e95d-4a28-a586-7388f155b8fb", + "unofficialPostName" : "Kassör" + }, { + "userId" : "ec8987d7-4087-461d-bed5-9365086b6e3b", + "postId" : "08efcf3a-1805-4b5f-a60e-da6ce0d33f58", + "unofficialPostName" : "IT-ansvarig" + }, { + "userId" : "0c67c90b-dfdf-473a-98e3-b551e2f2f0f1", + "postId" : "524db9a7-e8be-403e-a07c-a41803ea5ee7", + "unofficialPostName" : "VO" + } ] + }, { + "id" : "672db849-8afb-4160-9f12-7f8c1d379fcc", + "name" : "drawit", + "prettyName" : "DrawIT", + "superGroupId" : "5a427d4d-adb7-4de7-9c87-a569014c7b58", + "members" : [ { + "userId" : "858e5acc-c289-40d3-9422-d6d317f40299", + "postId" : "7bb1db15-730d-4864-bfc3-99abe7c0ccf8", + "unofficialPostName" : "Ordf" + }, { + "userId" : "9ad8946d-cfef-4f6f-8b48-cfb536d0c9eb", + "postId" : "844067b3-e95d-4a28-a586-7388f155b8fb", + "unofficialPostName" : "Kassör" + }, { + "userId" : "4efb340f-540c-4b15-a362-d402aab10195", + "postId" : "08efcf3a-1805-4b5f-a60e-da6ce0d33f58", + "unofficialPostName" : "Knapansvarig" + } ] + }, { + "id" : "9b239de9-88a3-4992-96d1-b8dea2a637ec", + "name" : "drawit", + "prettyName" : "DrawIT", + "superGroupId" : "b8dbca3a-52e7-4299-9499-e58ec93a0c2c", + "members" : [ { + "userId" : "4542ab3d-7996-4097-ae4a-4fe61eaf2f20", + "postId" : "7bb1db15-730d-4864-bfc3-99abe7c0ccf8", + "unofficialPostName" : "Ordf" + }, { + "userId" : "4542ab3d-7996-4097-ae4a-4fe61eaf2f20", + "postId" : "844067b3-e95d-4a28-a586-7388f155b8fb", + "unofficialPostName" : "Kassör" + }, { + "userId" : "4542ab3d-7996-4097-ae4a-4fe61eaf2f20", + "postId" : "08efcf3a-1805-4b5f-a60e-da6ce0d33f58", + "unofficialPostName" : "Knapansvarig" + } ] + }, { + "id" : "5f26a10c-e668-4ec1-b072-a7dd8f11735c", + "name" : "prit", + "prettyName" : "P.R.I.T.", + "superGroupId" : "326807b4-ae68-4626-8382-919a15a8e23c", + "members" : [ { + "userId" : "0a799f6d-c65a-4d20-8588-2ff5375d6cce", + "postId" : "7bb1db15-730d-4864-bfc3-99abe7c0ccf8", + "unofficialPostName" : "ChefChef" + }, { + "userId" : "e6a76e6a-3499-4611-ae28-e1281ffa6e80", + "postId" : "844067b3-e95d-4a28-a586-7388f155b8fb", + "unofficialPostName" : "Ka$$Chef" + }, { + "userId" : "4542ab3d-7996-4097-ae4a-4fe61eaf2f20", + "postId" : "08efcf3a-1805-4b5f-a60e-da6ce0d33f58", + "unofficialPostName" : "BösChef" + } ] + }, { + "id" : "1ed91274-13c8-4d6d-ab75-37c9d732b51b", + "name" : "prit", + "prettyName" : "P.R.I.T.", + "superGroupId" : "b3bcbbcc-0b93-4c41-a3c7-1792448c6fc1", + "members" : [ { + "userId" : "bc605869-9a4d-46ec-8a29-d00819d4c195", + "postId" : "7bb1db15-730d-4864-bfc3-99abe7c0ccf8", + "unofficialPostName" : "ChefChef" + }, { + "userId" : "ec8987d7-4087-461d-bed5-9365086b6e3b", + "postId" : "844067b3-e95d-4a28-a586-7388f155b8fb", + "unofficialPostName" : "Ka$$Chef" + }, { + "userId" : "0c67c90b-dfdf-473a-98e3-b551e2f2f0f1", + "postId" : "08efcf3a-1805-4b5f-a60e-da6ce0d33f58", + "unofficialPostName" : "BösChef" + } ] + }, { + "id" : "ee4153d5-830d-445f-acb3-ec09c53e7c0c", + "name" : "kandidatmiddagen", + "prettyName" : "Kandidatmiddagen", + "superGroupId" : "712e21f5-f3c6-49fc-a9e7-5b7ec3ff31ab", + "members" : [ { + "userId" : "858e5acc-c289-40d3-9422-d6d317f40299", + "postId" : "7bb1db15-730d-4864-bfc3-99abe7c0ccf8" + }, { + "userId" : "9ad8946d-cfef-4f6f-8b48-cfb536d0c9eb", + "postId" : "08efcf3a-1805-4b5f-a60e-da6ce0d33f58" + }, { + "userId" : "4efb340f-540c-4b15-a362-d402aab10195", + "postId" : "08efcf3a-1805-4b5f-a60e-da6ce0d33f58" + }, { + "userId" : "4542ab3d-7996-4097-ae4a-4fe61eaf2f20", + "postId" : "08efcf3a-1805-4b5f-a60e-da6ce0d33f58" + } ] + } ], + "superGroups" : [ { + "id" : "aed27030-ad90-4526-855c-1e909b1dcecb", + "name" : "digit", + "prettyName" : "digIT", + "type" : "COMMITTEE" + }, { + "id" : "2157ee72-04cd-4029-8d57-77142d3ef5fa", + "name" : "styrit", + "prettyName" : "styrIT", + "type" : "BOARD" + }, { + "id" : "b8dbca3a-52e7-4299-9499-e58ec93a0c2c", + "name" : "drawit", + "prettyName" : "DrawIT", + "type" : "SOCIETY" + }, { + "id" : "b3bcbbcc-0b93-4c41-a3c7-1792448c6fc1", + "name" : "prit", + "prettyName" : "P.R.I.T.", + "type" : "COMMITTEE" + }, { + "id" : "364a359a-f9eb-4d81-bb99-25cc5adf176d", + "name" : "didit", + "prettyName" : "didIT", + "type" : "ALUMNI" + }, { + "id" : "30c2ee3b-b761-46d0-9029-215a9b484f7a", + "name" : "emeritus", + "prettyName" : "EmerITus", + "type" : "ALUMNI" + }, { + "id" : "5a427d4d-adb7-4de7-9c87-a569014c7b58", + "name" : "dragit", + "prettyName" : "DragIT", + "type" : "ALUMNI" + }, { + "id" : "326807b4-ae68-4626-8382-919a15a8e23c", + "name" : "sprit", + "prettyName" : "S.P.R.I.T.", + "type" : "ALUMNI" + }, { + "id" : "712e21f5-f3c6-49fc-a9e7-5b7ec3ff31ab", + "name" : "kandidatmiddagen", + "prettyName" : "Kandidatmiddagen", + "type" : "FUNCTIONARIES" + } ], + "posts" : [ { + "id" : "7bb1db15-730d-4864-bfc3-99abe7c0ccf8", + "postName" : { + "sv" : "Ordförande", + "en" : "Chairman" + } + }, { + "id" : "844067b3-e95d-4a28-a586-7388f155b8fb", + "postName" : { + "sv" : "Kassör", + "en" : "Treasurer" + } + }, { + "id" : "08efcf3a-1805-4b5f-a60e-da6ce0d33f58", + "postName" : { + "sv" : "Ledamot", + "en" : "Member" + } + }, { + "id" : "524db9a7-e8be-403e-a07c-a41803ea5ee7", + "postName" : { + "sv" : "Vice Ordförande", + "en" : "Vice-chairman" + } + } ] +} \ No newline at end of file diff --git a/app/src/main/resources/static/css/login.css b/app/src/main/resources/static/css/login.css new file mode 100644 index 000000000..155be3d8a --- /dev/null +++ b/app/src/main/resources/static/css/login.css @@ -0,0 +1,64 @@ +body { + padding-left: 0 !important; + padding-right: 0 !important; +} + +main { + flex: 1; + display: flex; + flex-direction: column; + align-items: center; + gap: 1rem; + min-height: 100lvh; + + grid-column-start: 1; + grid-column-end: 3; +} + +article { + margin: auto; +} + +article > header > h1 { + margin-top: 1rem; + margin-bottom: 1rem; +} + +form > fieldset { + margin-bottom: 0 !important; +} + +#links { + display: flex; + flex-direction: row; + gap: 1rem; + justify-content: flex-end; + align-items: baseline; +} + +img { + opacity: 0; + z-index: -2; + + left: 0; + top: 0; + right: 0; + bottom: 0; + + width: 100%; + height: 100%; + + position: absolute; + + object-fit: cover; + object-position: center; +} + +form { + display: flex; + flex-direction: column; +} + +form button { + width: 100%; +} \ No newline at end of file diff --git a/app/src/main/resources/static/css/main.css b/app/src/main/resources/static/css/main.css new file mode 100644 index 000000000..a8df6f5de --- /dev/null +++ b/app/src/main/resources/static/css/main.css @@ -0,0 +1,298 @@ +article { + margin-left: auto; + margin-right: auto; + max-width: 600px; +} + +article > footer { + display: flex; + flex-direction: row; + gap: 1rem; + justify-content: flex-end; + align-items: flex-end; +} + +article footer * { + margin-bottom: 0 !important; +} + +div[role='alert'] { + margin-bottom: var(--pico-spacing); + padding: var(--pico-form-element-spacing-vertical) var(--pico-form-element-spacing-horizontal); + border-radius: var(--pico-border-radius); +} + +div[role='alert'].error, div[role='alert'].error * { + background-color: #FAEEEB; + color: #333333; +} + +div[role='alert'].success { + background-color: #D7FBC1; + color: #333333; +} + +#alerts { + position: fixed; + right: 1rem; + bottom: 1rem; + + display: flex; + flex-direction: column; + + max-width: 300px; + + z-index: 10; +} + +p.error { + color: var(--pico-del-color); +} + +form { + display: contents; +} + +header { + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; + position: relative; + max-width: calc(100vw - var(--pico-spacing) * 2); +} + +header div { + display: flex; + flex-direction: row; + gap: 1rem; + align-items: center; +} + +header > div > a > h1 { + margin-bottom: 0; +} + +img.avatar { + display: block; + margin: auto auto var(--pico-spacing); + height: 150px; + object-fit: contain; +} + +ul.tuple { + padding-left: 0; +} + +ul.tuple > li { + display: flex; + flex-direction: row; + gap: 0.5rem; +} + +div.tuple-right-expand > div { + display: flex; + flex-direction: row; + gap: 0.5rem; +} + +div.tuple-right-expand > div > *:nth-child(1) { + text-align: right; + flex: 1; +} + +div.tuple-right-expand > div > *:nth-child(2) { + text-align: left; + flex: 10; + max-width: max-content; +} + +ul.tuple > li > * { + flex: 1; +} + +ul.tuple > li > *:nth-child(1) { + text-align: right; +} + +ul.tuple > li > *:nth-child(2) { + text-align: left; +} + +.form-check-input { + visibility: hidden; +} + +input[type=checkbox], input[type=radio], select { + /* This is currently a workaround, due to Gamma's strict Content Security Policy. */ + appearance: auto; +} + +.td-buttons { + gap: 0.5rem; + display: flex; + flex-direction: column; + text-align: right; +} + +.list-item { + display: flex; + gap: 2rem; + justify-content: space-between; + align-items: center; +} + +body { + display: grid; + grid-template-areas: + "header header" + "nav main"; + grid-template-columns: 200px auto; + + overflow-x: hidden; +} + +header { + grid-area: header; + grid-column: span 2; +} + +nav { + grid-area: nav; +} + +main { + grid-area: main; + overflow-x: auto; + padding-block: 0 !important; +} + +@media only screen and (min-width: 600px) { + #toggle-nav { + display: none; + } +} + +@media only screen and (max-width: 600px) { + body { + grid-template-areas: + "header" + "nav" + "main"; + } + + body.show-nav nav { + display: block; + } + + nav { + display: none; + } + + main { + grid-column: span 2; + } + + header { + align-items: flex-start; + } + + header div { + flex-direction: column; + } + + header > *:nth-child(3) { + flex-direction: column-reverse; + } +} +.image-input-container { + display: flex; + flex-direction: column; + width: 15rem; + margin: auto; + gap: 2rem; +} + +.home-links { + display: flex; + flex-direction: column; + flex-wrap: wrap; + max-height: 6rem; + gap: 0.5rem; +} + +.member-row > p { + margin-bottom: 0.2rem; +} + +.member-row > div { + display: flex; + gap: 0.5rem; + align-items: last baseline; +} + +.member-row > div > button { + height: fit-content; + margin-bottom: 0; +} + +.row { + display: flex; + gap: 1rem; +} + +.table-align-right { + text-align: right; +} + +.m-auto { + display: block; + margin: auto; +} + +code { + overflow-x: scroll; + white-space: nowrap; + max-width: 100%; +} + +.contents { + display: contents; +} + +#loader-container { + position: absolute; + top: -3px; + left: -5px; + width: calc(100% + 8px); +} + +progress { + animation-duration: 5s !important; +} + +[data-loading] { + opacity: 0; +} + +.loading { + opacity: 1; + animation: fadeIn 0.5s linear forwards; +} + +@keyframes fadeIn { + 0% {opacity: 0;} + 100% {opacity: 1;} +} + +.error-message { + color: var(--pico-del-color); +} + +span a { + display: inline-block !important; +} + +#digit18-smurf { + width: 60%; +} \ No newline at end of file diff --git a/app/src/main/resources/static/css/no-nav.css b/app/src/main/resources/static/css/no-nav.css new file mode 100644 index 000000000..87d2cc0e0 --- /dev/null +++ b/app/src/main/resources/static/css/no-nav.css @@ -0,0 +1,19 @@ +body { + grid-template-areas: + "header header" + "main main"; +} + +@media only screen and (max-width: 600px) { + #toggle-nav { + display: none !important; + } + + #login-container { + display: none !important; + } + + #main-header { + justify-content: center !important; + } +} \ No newline at end of file diff --git a/app/src/main/resources/static/img/bg.webp b/app/src/main/resources/static/img/bg.webp new file mode 100644 index 000000000..66faa6fd1 Binary files /dev/null and b/app/src/main/resources/static/img/bg.webp differ diff --git a/app/src/main/resources/static/img/digit18.svg b/app/src/main/resources/static/img/digit18.svg new file mode 100644 index 000000000..fabe13949 --- /dev/null +++ b/app/src/main/resources/static/img/digit18.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/backend/src/main/resources/static/img/itlogo.svg b/app/src/main/resources/static/img/itlogo.svg similarity index 83% rename from backend/src/main/resources/static/img/itlogo.svg rename to app/src/main/resources/static/img/itlogo.svg index 7d0cb5307..7bcc301ba 100644 --- a/backend/src/main/resources/static/img/itlogo.svg +++ b/app/src/main/resources/static/img/itlogo.svg @@ -1,5 +1,6 @@ - + itlogo Created with Sketch. @@ -12,79 +13,146 @@ - - + + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/resources/static/js/posts-sortable.js b/app/src/main/resources/static/js/posts-sortable.js new file mode 100644 index 000000000..6376990e5 --- /dev/null +++ b/app/src/main/resources/static/js/posts-sortable.js @@ -0,0 +1,14 @@ +htmx.onLoad(function(content) { + var sortable = content.querySelector('.sortable'); + + if (sortable != null) { + sortableInstance = new Sortable(sortable, { + animation: 150, + handle: '.sortable-item', + + onEnd: function (evt) { + this.option("disabled", true); + } + }); + } +}); diff --git a/app/src/main/resources/static/js/reorder.js b/app/src/main/resources/static/js/reorder.js new file mode 100644 index 000000000..f92db44a0 --- /dev/null +++ b/app/src/main/resources/static/js/reorder.js @@ -0,0 +1,17 @@ +function updateNames(key, ...queries) { + if(queries.length === 1) { + const inputFields = document.querySelectorAll(queries[0]); + inputFields.forEach(function(input, index) { + input.name = key + '[' + index + ']'; + input.id = key + index; + }); + } else { + for (const query of queries) { + const inputFields = document.querySelectorAll(query); + inputFields.forEach(function(input, index) { + input.name = key + '[' + index + ']' + query; + input.id = key + index; + }); + } + } +} diff --git a/frontend/public/robots.txt b/app/src/main/resources/static/txt/robots.txt similarity index 100% rename from frontend/public/robots.txt rename to app/src/main/resources/static/txt/robots.txt diff --git a/app/src/main/resources/templates/client-details/add-authority-to-client.html b/app/src/main/resources/templates/client-details/add-authority-to-client.html new file mode 100644 index 000000000..6a1520da9 --- /dev/null +++ b/app/src/main/resources/templates/client-details/add-authority-to-client.html @@ -0,0 +1,25 @@ +
+
+ Create client authority +
+
+
+
+

Super groups:

+ +

Users:

+ + +
+ +
+ + diff --git a/app/src/main/resources/templates/client-details/add-super-group-authority-to-client.html b/app/src/main/resources/templates/client-details/add-super-group-authority-to-client.html new file mode 100644 index 000000000..0399ff771 --- /dev/null +++ b/app/src/main/resources/templates/client-details/add-super-group-authority-to-client.html @@ -0,0 +1,3 @@ + diff --git a/app/src/main/resources/templates/client-details/add-user-authority-to-client.html b/app/src/main/resources/templates/client-details/add-user-authority-to-client.html new file mode 100644 index 000000000..0e14efdca --- /dev/null +++ b/app/src/main/resources/templates/client-details/add-user-authority-to-client.html @@ -0,0 +1,3 @@ + diff --git a/app/src/main/resources/templates/client-details/client-credentials.html b/app/src/main/resources/templates/client-details/client-credentials.html new file mode 100644 index 000000000..d1a498c7a --- /dev/null +++ b/app/src/main/resources/templates/client-details/client-credentials.html @@ -0,0 +1,27 @@ +
+
+ Credentials +
+

These are the credentials for your client. They will not be shown again.

+
+
+ Client secret: + +
+
+ Api key: + +
+
+ +

+ Read more here about how to use Client API here:
github.com/cthit/Gamma/wiki/Client-API +

+
+ To authorize when doing API requests, simply add this header: +
+

+ Authorization: pre-shared : +

+
+
\ No newline at end of file diff --git a/app/src/main/resources/templates/client-details/created-client-authority.html b/app/src/main/resources/templates/client-details/created-client-authority.html new file mode 100644 index 000000000..a6291ed76 --- /dev/null +++ b/app/src/main/resources/templates/client-details/created-client-authority.html @@ -0,0 +1,5 @@ +
+
+
+
+
diff --git a/app/src/main/resources/templates/client-details/deleted-client-authority.html b/app/src/main/resources/templates/client-details/deleted-client-authority.html new file mode 100644 index 000000000..8b0948086 --- /dev/null +++ b/app/src/main/resources/templates/client-details/deleted-client-authority.html @@ -0,0 +1 @@ +
diff --git a/app/src/main/resources/templates/client-details/not-found.html b/app/src/main/resources/templates/client-details/not-found.html new file mode 100644 index 000000000..1f831fdaa --- /dev/null +++ b/app/src/main/resources/templates/client-details/not-found.html @@ -0,0 +1,16 @@ +
+
+ +
\ No newline at end of file diff --git a/app/src/main/resources/templates/client-details/page.html b/app/src/main/resources/templates/client-details/page.html new file mode 100644 index 000000000..7aebfc3b9 --- /dev/null +++ b/app/src/main/resources/templates/client-details/page.html @@ -0,0 +1,120 @@ +
+
+ +
+
+
+
+ Client details +
+
    +
  • + Pretty name: + +
  • +
  • + Swedish description: + +
  • +
  • + English description: + +
  • +
  • + Client id: + +
  • +
  • + Redirect: + +
  • +
  • + Super group restrictions: + + + +
  • +
  • + This client has no restrictions. +
  • +
  • + Owned by: + + + +
  • +
+
+
+
+ +
+
+ +
+
+
+ + +
+
+
+
+ + +
+
+
+

+ Super groups: +

+

+ No super groups +

+
    +
  • + +
  • +
+

+ Users: +

+

+ No users +

+
    +
  • + +
  • +
+
+
+
+ + +
+
+
+
+ + + +
+ +
+
+ User approvals +
+

+ No users have approved this client yet +

+
    +
  • + +
  • +
+
+ +
\ No newline at end of file diff --git a/app/src/main/resources/templates/common/alert.html b/app/src/main/resources/templates/common/alert.html new file mode 100644 index 000000000..f307c78b7 --- /dev/null +++ b/app/src/main/resources/templates/common/alert.html @@ -0,0 +1,27 @@ + +
+ +
+
+ + +
+ +
+
diff --git a/app/src/main/resources/templates/common/content-too-large.html b/app/src/main/resources/templates/common/content-too-large.html new file mode 100644 index 000000000..d8e7e45ed --- /dev/null +++ b/app/src/main/resources/templates/common/content-too-large.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/app/views/drawer/elements/gamma-actions/index.js b/app/src/main/resources/templates/common/empty.html similarity index 100% rename from frontend/src/app/views/drawer/elements/gamma-actions/index.js rename to app/src/main/resources/templates/common/empty.html diff --git a/app/src/main/resources/templates/common/error.html b/app/src/main/resources/templates/common/error.html new file mode 100644 index 000000000..499d34c66 --- /dev/null +++ b/app/src/main/resources/templates/common/error.html @@ -0,0 +1,5 @@ + +

+ +

+
\ No newline at end of file diff --git a/app/src/main/resources/templates/common/form-csrf.html b/app/src/main/resources/templates/common/form-csrf.html new file mode 100644 index 000000000..c031e43d6 --- /dev/null +++ b/app/src/main/resources/templates/common/form-csrf.html @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/app/src/main/resources/templates/common/header-without-nav.html b/app/src/main/resources/templates/common/header-without-nav.html new file mode 100644 index 000000000..1af75d0c4 --- /dev/null +++ b/app/src/main/resources/templates/common/header-without-nav.html @@ -0,0 +1,29 @@ +
+
+ +
+ +
+
+ + +
+ +
+
+ +
+
+
+
diff --git a/app/src/main/resources/templates/common/header.html b/app/src/main/resources/templates/common/header.html new file mode 100644 index 000000000..c3191fe6d --- /dev/null +++ b/app/src/main/resources/templates/common/header.html @@ -0,0 +1,96 @@ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+
+
+
+ diff --git a/app/src/main/resources/templates/common/input.html b/app/src/main/resources/templates/common/input.html new file mode 100644 index 000000000..a9b51de03 --- /dev/null +++ b/app/src/main/resources/templates/common/input.html @@ -0,0 +1,94 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/resources/templates/create-api-key/page.html b/app/src/main/resources/templates/create-api-key/page.html new file mode 100644 index 000000000..e1bc5326c --- /dev/null +++ b/app/src/main/resources/templates/create-api-key/page.html @@ -0,0 +1,22 @@ +
+
+
+
+ Create api key +
+
+
+
+
+ +
+
+ +
+
+
\ No newline at end of file diff --git a/app/src/main/resources/templates/create-client/add-restriction-to-client.html b/app/src/main/resources/templates/create-client/add-restriction-to-client.html new file mode 100644 index 000000000..f362e4f6b --- /dev/null +++ b/app/src/main/resources/templates/create-client/add-restriction-to-client.html @@ -0,0 +1,6 @@ +
+ + +
diff --git a/app/src/main/resources/templates/create-client/page.html b/app/src/main/resources/templates/create-client/page.html new file mode 100644 index 000000000..4bf5eb2f5 --- /dev/null +++ b/app/src/main/resources/templates/create-client/page.html @@ -0,0 +1,30 @@ +
+
+
+
+ Create client +
+
+
+
+
+
+ + + +
+
+ +
+
+
\ No newline at end of file diff --git a/app/src/main/resources/templates/create-group/page.html b/app/src/main/resources/templates/create-group/page.html new file mode 100644 index 000000000..908ca1c45 --- /dev/null +++ b/app/src/main/resources/templates/create-group/page.html @@ -0,0 +1,53 @@ +
+
+
+
+
+ Create group +
+ +
+
+ +
+
+ +
+
+ + + + +
+
+
+
+ +
+
+ +
+ +
+
+
+
\ No newline at end of file diff --git a/app/src/main/resources/templates/create-post/page.html b/app/src/main/resources/templates/create-post/page.html new file mode 100644 index 000000000..4dbb7df33 --- /dev/null +++ b/app/src/main/resources/templates/create-post/page.html @@ -0,0 +1,18 @@ +
+
+
+
+
+ Create post +
+
+
+
+
+ +
+
+
+
\ No newline at end of file diff --git a/app/src/main/resources/templates/create-super-group/page.html b/app/src/main/resources/templates/create-super-group/page.html new file mode 100644 index 000000000..0eb946f13 --- /dev/null +++ b/app/src/main/resources/templates/create-super-group/page.html @@ -0,0 +1,23 @@ +
+
+
+
+
+ Create super group +
+
+
+
+
+ +
+ +
+
+
+
\ No newline at end of file diff --git a/app/src/main/resources/templates/create-user/page.html b/app/src/main/resources/templates/create-user/page.html new file mode 100644 index 000000000..3201f37d2 --- /dev/null +++ b/app/src/main/resources/templates/create-user/page.html @@ -0,0 +1,40 @@ +
+
+
+
+ Create user +
+
+
+
+
+
+
+
+ + +
+
+
+ +
+
+
diff --git a/app/src/main/resources/templates/group-details/add-member-to-group.html b/app/src/main/resources/templates/group-details/add-member-to-group.html new file mode 100644 index 000000000..abe9a9c95 --- /dev/null +++ b/app/src/main/resources/templates/group-details/add-member-to-group.html @@ -0,0 +1,24 @@ +
+
+ +
+ + + +
+
\ No newline at end of file diff --git a/app/src/main/resources/templates/group-details/edit-group.html b/app/src/main/resources/templates/group-details/edit-group.html new file mode 100644 index 000000000..8d3a6f767 --- /dev/null +++ b/app/src/main/resources/templates/group-details/edit-group.html @@ -0,0 +1,57 @@ +
+
+ Edit group details +
+
+ +
+
+ +
+
+

+
+ +
+ + + + +
+
+
+
+ +
+
+ +
+
+ + +
+
\ No newline at end of file diff --git a/app/src/main/resources/templates/group-details/failed-to-edit-group-avatar.html b/app/src/main/resources/templates/group-details/failed-to-edit-group-avatar.html new file mode 100644 index 000000000..77e0a5f34 --- /dev/null +++ b/app/src/main/resources/templates/group-details/failed-to-edit-group-avatar.html @@ -0,0 +1 @@ + diff --git a/app/src/main/resources/templates/group-details/failed-to-edit-group-banner.html b/app/src/main/resources/templates/group-details/failed-to-edit-group-banner.html new file mode 100644 index 000000000..7ce4fd9ce --- /dev/null +++ b/app/src/main/resources/templates/group-details/failed-to-edit-group-banner.html @@ -0,0 +1 @@ + diff --git a/app/src/main/resources/templates/group-details/not-found.html b/app/src/main/resources/templates/group-details/not-found.html new file mode 100644 index 000000000..b580e3f24 --- /dev/null +++ b/app/src/main/resources/templates/group-details/not-found.html @@ -0,0 +1,16 @@ +
+
+ +
\ No newline at end of file diff --git a/app/src/main/resources/templates/group-details/page.html b/app/src/main/resources/templates/group-details/page.html new file mode 100644 index 000000000..bf80986e4 --- /dev/null +++ b/app/src/main/resources/templates/group-details/page.html @@ -0,0 +1,115 @@ +
+
+
+
+ Group details +
+
    +
  • + Name: + +
  • +
  • + Pretty name: + +
  • +
  • + Super group: + + + +
  • +
+

+ Members: +

+
    +
  • + + - + +
  • +
+ +
+
+ +
+ +
+
+ +
+
+ Change unofficial post name for your posts +
+

+ Here you are able to update your unofficial post name for . + They are a more fun variant of your post name, since 'Chairman' can be a bit boring. +

+
+ +
+
+
+
+ +
+
+ + +
+
+ Group avatar +
+ Group avatar +
+ Group avatar +
+
+ + +
+
+
+ +
+
+ +
+
+ Group banner +
+ Group banner +
+ Group banner +
+
+ + +
+
+
+ +
+
+
+
\ No newline at end of file diff --git a/app/src/main/resources/templates/groups/page.html b/app/src/main/resources/templates/groups/page.html new file mode 100644 index 000000000..9c0e1b41e --- /dev/null +++ b/app/src/main/resources/templates/groups/page.html @@ -0,0 +1,22 @@ +
+
+ Create group + + + + + + + + + + + + + + + +
NameSuper groupDetails
+ Details +
+
\ No newline at end of file diff --git a/app/src/main/resources/templates/home/edit-me-password.html b/app/src/main/resources/templates/home/edit-me-password.html new file mode 100644 index 000000000..963221c35 --- /dev/null +++ b/app/src/main/resources/templates/home/edit-me-password.html @@ -0,0 +1,16 @@ +
+
+
+ Creating a new password +
+
+ +
+
+
+
+ + +
+
+
\ No newline at end of file diff --git a/app/src/main/resources/templates/home/edit-me.html b/app/src/main/resources/templates/home/edit-me.html new file mode 100644 index 000000000..c571495ad --- /dev/null +++ b/app/src/main/resources/templates/home/edit-me.html @@ -0,0 +1,29 @@ +
+
+
+ Editing your information +
+
+ +
+
+
+
+ +
+
+ + +
+
+
\ No newline at end of file diff --git a/app/src/main/resources/templates/home/edited-me-avatar.html b/app/src/main/resources/templates/home/edited-me-avatar.html new file mode 100644 index 000000000..2bbfe4df9 --- /dev/null +++ b/app/src/main/resources/templates/home/edited-me-avatar.html @@ -0,0 +1,2 @@ +
+
\ No newline at end of file diff --git a/app/src/main/resources/templates/home/edited-me-password.html b/app/src/main/resources/templates/home/edited-me-password.html new file mode 100644 index 000000000..a21c7a60d --- /dev/null +++ b/app/src/main/resources/templates/home/edited-me-password.html @@ -0,0 +1,2 @@ +
+
\ No newline at end of file diff --git a/app/src/main/resources/templates/home/edited-me.html b/app/src/main/resources/templates/home/edited-me.html new file mode 100644 index 000000000..f9a417e3b --- /dev/null +++ b/app/src/main/resources/templates/home/edited-me.html @@ -0,0 +1,2 @@ +
+
\ No newline at end of file diff --git a/app/src/main/resources/templates/home/failed-to-edit-me-avatar.html b/app/src/main/resources/templates/home/failed-to-edit-me-avatar.html new file mode 100644 index 000000000..e1d15672f --- /dev/null +++ b/app/src/main/resources/templates/home/failed-to-edit-me-avatar.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/src/main/resources/templates/home/page.html b/app/src/main/resources/templates/home/page.html new file mode 100644 index 000000000..dc71d50d3 --- /dev/null +++ b/app/src/main/resources/templates/home/page.html @@ -0,0 +1,114 @@ +
+
+
+
+ Urgency for Deletion of This 'Admin' Account +
+

+ The security of your system is paramount. Given that accounts with the "admin" username tend to + attract higher rates of brute-force attack attempts, we strongly advise you to delete this account promptly. +

+
+ +
+
+ Your information +
+
    +
  • + First name: + +
  • +
  • + Last name: + +
  • +
  • + Nick + +
  • +
  • + Email: + +
  • +
  • + Acceptance year: + +
  • +
  • + Cid: + +
  • +
  • + Preferred language: + +
  • +
  • + Have you attended GDPR training? + +
  • +
  • + Is admin? + Yes +
  • +
+
+ + +
+
+
+
+ My groups +
+ + You are not part of any groups + +
    +
  • + +
  • +
+
+
+
+ Your avatar +
+
+ Me avatar +
+
+ + +
+
+
+ +
+
+
+
+ Do you want to delete your account? +
+

+ Here you can delete your account and prevent further access for clients you have accepted. + You have the right to ensure all of your data is removed. + Please email ita@chalmers.it, along with: +

+

+ UserId: +

+

+ Cid: +

+ +
+
diff --git a/app/src/main/resources/templates/index.html b/app/src/main/resources/templates/index.html new file mode 100644 index 000000000..017847269 --- /dev/null +++ b/app/src/main/resources/templates/index.html @@ -0,0 +1,42 @@ + + + + Gamma + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/resources/templates/pages/404.html b/app/src/main/resources/templates/pages/404.html new file mode 100644 index 000000000..44227ebfb --- /dev/null +++ b/app/src/main/resources/templates/pages/404.html @@ -0,0 +1,16 @@ +
+
+ +
\ No newline at end of file diff --git a/app/src/main/resources/templates/pages/activation-codes.html b/app/src/main/resources/templates/pages/activation-codes.html new file mode 100644 index 000000000..fbf402a2e --- /dev/null +++ b/app/src/main/resources/templates/pages/activation-codes.html @@ -0,0 +1,25 @@ +
+
+ + + + + + + + + + + + + + + +
CidCreated at
+
+
+ + +
+
+
\ No newline at end of file diff --git a/app/src/main/resources/templates/pages/admins.html b/app/src/main/resources/templates/pages/admins.html new file mode 100644 index 000000000..c3c964443 --- /dev/null +++ b/app/src/main/resources/templates/pages/admins.html @@ -0,0 +1,30 @@ +
+
+
+ +

+ + + + + + + + + + + + + + + + + +
AdminFirst NameNickLast name
+ +
+
+
\ No newline at end of file diff --git a/app/src/main/resources/templates/pages/allow-list.html b/app/src/main/resources/templates/pages/allow-list.html new file mode 100644 index 000000000..b29b6afb8 --- /dev/null +++ b/app/src/main/resources/templates/pages/allow-list.html @@ -0,0 +1,37 @@ +
+
+
+
+ Allow new cid +
+
+
+
+
+ +
+
+ + + + + + + + + + + + + +
Cid
+ + Has activation code + +
+
+ + +
+
+
\ No newline at end of file diff --git a/app/src/main/resources/templates/pages/api-key-details.html b/app/src/main/resources/templates/pages/api-key-details.html new file mode 100644 index 000000000..ad057ec89 --- /dev/null +++ b/app/src/main/resources/templates/pages/api-key-details.html @@ -0,0 +1,53 @@ +
+
+ +
+
+ +
+
+ Api key details +
+
    +
  • + Pretty name + +
  • +
  • + Type + +
  • +
  • + Swedish description + +
  • +
  • + English description + +
  • +
+ +
+
+
+ +
+
+ +
+ +
+
+
+ +
+
+
\ No newline at end of file diff --git a/app/src/main/resources/templates/pages/api-key-not-found.html b/app/src/main/resources/templates/pages/api-key-not-found.html new file mode 100644 index 000000000..e73fd8103 --- /dev/null +++ b/app/src/main/resources/templates/pages/api-key-not-found.html @@ -0,0 +1,16 @@ +
+
+ +
\ No newline at end of file diff --git a/app/src/main/resources/templates/pages/api-keys.html b/app/src/main/resources/templates/pages/api-keys.html new file mode 100644 index 000000000..9d090b9b2 --- /dev/null +++ b/app/src/main/resources/templates/pages/api-keys.html @@ -0,0 +1,22 @@ +
+
+ Create api key + + + + + + + + + + + + + + + +
NameTypeDetails
+ Details +
+
\ No newline at end of file diff --git a/app/src/main/resources/templates/pages/authorize.html b/app/src/main/resources/templates/pages/authorize.html new file mode 100644 index 000000000..01ac7b065 --- /dev/null +++ b/app/src/main/resources/templates/pages/authorize.html @@ -0,0 +1,43 @@ +
+
+
+
+
+ + +
    +
  • First and last name
  • +
  • Email
  • +
  • Nickname
  • +
  • Preferred language
  • +
  • Cid
  • +
  • Authorities
  • +
  • Groups that you're apart of
  • +
+ +
+ + + + + + +
+
+ + +
+
+
+ diff --git a/app/src/main/resources/templates/pages/client-authorizing-issue.html b/app/src/main/resources/templates/pages/client-authorizing-issue.html new file mode 100644 index 000000000..543a1b594 --- /dev/null +++ b/app/src/main/resources/templates/pages/client-authorizing-issue.html @@ -0,0 +1,13 @@ +
+
+ +
+ diff --git a/app/src/main/resources/templates/pages/create-user-client.html b/app/src/main/resources/templates/pages/create-user-client.html new file mode 100644 index 000000000..019307b38 --- /dev/null +++ b/app/src/main/resources/templates/pages/create-user-client.html @@ -0,0 +1,30 @@ +
+
+
+
+ Create new client +
+

+ This client will be created in your name, and will be shown everytime + a user attempts to authenticate with gamma to your client. +

+
+
+
+
+
+ + +
+
+ +
+
+ +
\ No newline at end of file diff --git a/app/src/main/resources/templates/pages/delete-your-account.html b/app/src/main/resources/templates/pages/delete-your-account.html new file mode 100644 index 000000000..cf7f3038e --- /dev/null +++ b/app/src/main/resources/templates/pages/delete-your-account.html @@ -0,0 +1,19 @@ +
+
+
+
+ Deleting your account +
+

+ Deleting your account can't be reversed. +

+
+
+
+
+ +
+
+
\ No newline at end of file diff --git a/app/src/main/resources/templates/pages/error.html b/app/src/main/resources/templates/pages/error.html new file mode 100644 index 000000000..e962c0132 --- /dev/null +++ b/app/src/main/resources/templates/pages/error.html @@ -0,0 +1,14 @@ +
+
+
+
+ 500 - Internal Server Error +
+

Something went wrong...

+ +
+
\ No newline at end of file diff --git a/app/src/main/resources/templates/pages/finalize-forgot-password.html b/app/src/main/resources/templates/pages/finalize-forgot-password.html new file mode 100644 index 000000000..e945a3d46 --- /dev/null +++ b/app/src/main/resources/templates/pages/finalize-forgot-password.html @@ -0,0 +1,17 @@ +
+
+
+
+
+ Finalize resetting password +
+ +
+
+
+
+ +
+
+
+
\ No newline at end of file diff --git a/app/src/main/resources/templates/pages/forgot-password.html b/app/src/main/resources/templates/pages/forgot-password.html new file mode 100644 index 000000000..aad1e4a08 --- /dev/null +++ b/app/src/main/resources/templates/pages/forgot-password.html @@ -0,0 +1,32 @@ +
+
+
+
+
+ Reset password +
+ +

+ + You should have received an email with a link for resetting your password. + +

+

+ Please check your spam email if you can't find it. You might also have typed your cid/email incorrectly. +

+

+ If you're certain that you've entered your CID or email correctly but still haven't received the password recovery email, + it could be due to a rate limit. If you suspect this to be the case, please reach out to ita@chalmers.it for further assistance. +

+
+
+

+ Please enter your cid or email to begin the reset process. +

+
+
+ +
+
+
+
\ No newline at end of file diff --git a/app/src/main/resources/templates/pages/gdpr.html b/app/src/main/resources/templates/pages/gdpr.html new file mode 100644 index 000000000..abfb82a1d --- /dev/null +++ b/app/src/main/resources/templates/pages/gdpr.html @@ -0,0 +1,29 @@ +
+
+
+ + + + + + + + + + + + + + + + + + +
Gdpr trainedFirst NameNickLast name
+ +
+
+
\ No newline at end of file diff --git a/app/src/main/resources/templates/pages/login.html b/app/src/main/resources/templates/pages/login.html new file mode 100644 index 000000000..d6170c4bf --- /dev/null +++ b/app/src/main/resources/templates/pages/login.html @@ -0,0 +1,54 @@ + +Background image +
+
+
+

+ Gamma +

+
+

+ Before deciding on authorizing the client, please verify your identity +

+
+ + + +
+
+

+ Invalid credentials or locked account due to system migration. Password reset may be needed. +

+ +

+ You have been logged out. +

+ +

+ You have been throttled for attempting to sign in too many times... +

+ +

+ Your account has been deleted. +

+ +

+ Your account has been created. +

+ +

+ Your password was reset. +

+ + + Register + + + + Forgot password + + +
+
+
\ No newline at end of file diff --git a/app/src/main/resources/templates/pages/my-accepted-clients.html b/app/src/main/resources/templates/pages/my-accepted-clients.html new file mode 100644 index 000000000..21361887c --- /dev/null +++ b/app/src/main/resources/templates/pages/my-accepted-clients.html @@ -0,0 +1,30 @@ +
+
+

+ Here are the clients that you have agreed to shared your data from Gamma with. + You have the right to retract that approval at any time. + If you have any questions, please do not hesitate to contact ita@chalmers.it. +

+ + + + + + + + + + + + + + + +
Client nameDescription
+
+
+ + +
+
+
\ No newline at end of file diff --git a/app/src/main/resources/templates/pages/my-clients.html b/app/src/main/resources/templates/pages/my-clients.html new file mode 100644 index 000000000..cbe2cd0aa --- /dev/null +++ b/app/src/main/resources/templates/pages/my-clients.html @@ -0,0 +1,24 @@ +
+
+

+ Here you are able to create your own OAuth2 client to authenticate Gamma with! + Read more about how here:
github.com/cthit/Gamma/wiki/Authenticating-With-Gamma +

+ Create client + + + + + + + + + + + + + +
NameDetails
+ Details +
+
\ No newline at end of file diff --git a/app/src/main/resources/templates/pages/no-access-to-client.html b/app/src/main/resources/templates/pages/no-access-to-client.html new file mode 100644 index 000000000..6b04f0648 --- /dev/null +++ b/app/src/main/resources/templates/pages/no-access-to-client.html @@ -0,0 +1,12 @@ +
+
+
+
+ Missing access to client +
+

+ You are missing access to authorize with this client. Please contact ita@chalmers.it if you have any questions. +

+
+
+ diff --git a/app/src/main/resources/templates/pages/official-clients.html b/app/src/main/resources/templates/pages/official-clients.html new file mode 100644 index 000000000..7ae6c81de --- /dev/null +++ b/app/src/main/resources/templates/pages/official-clients.html @@ -0,0 +1,20 @@ +
+
+ Create client + + + + + + + + + + + + + +
NameDetails
+ Details +
+
\ No newline at end of file diff --git a/app/src/main/resources/templates/pages/password-reset-token-bad.html b/app/src/main/resources/templates/pages/password-reset-token-bad.html new file mode 100644 index 000000000..6fe20604a --- /dev/null +++ b/app/src/main/resources/templates/pages/password-reset-token-bad.html @@ -0,0 +1,17 @@ +
+
+
+
+ Bad token +
+

+ It seems like the reset password link has been expired. + Please request a new token. +

+ +
+
\ No newline at end of file diff --git a/app/src/main/resources/templates/pages/register-account-token-bad.html b/app/src/main/resources/templates/pages/register-account-token-bad.html new file mode 100644 index 000000000..71342f256 --- /dev/null +++ b/app/src/main/resources/templates/pages/register-account-token-bad.html @@ -0,0 +1,17 @@ +
+
+
+
+ Bad token +
+

+ It seems like the register account link has been expired. + Please request a new token. +

+ +
+
\ No newline at end of file diff --git a/app/src/main/resources/templates/pages/super-group-details.html b/app/src/main/resources/templates/pages/super-group-details.html new file mode 100644 index 000000000..0f11c500c --- /dev/null +++ b/app/src/main/resources/templates/pages/super-group-details.html @@ -0,0 +1,68 @@ +
+
+
+
+
+
    +
  • + Name: + +
  • +
  • + Pretty name: + +
  • +
  • + Swedish description: + +
  • +
  • + English description: + +
  • +
  • + Type: + +
  • +
+
+ +
+ +
+
+
+
+
+
+ + + + + + + + + + + + + + + + +
+ Pretty name + + Details +
+ View +
+
+
\ No newline at end of file diff --git a/app/src/main/resources/templates/pages/super-group-not-found.html b/app/src/main/resources/templates/pages/super-group-not-found.html new file mode 100644 index 000000000..60abdd7fc --- /dev/null +++ b/app/src/main/resources/templates/pages/super-group-not-found.html @@ -0,0 +1,16 @@ +
+
+ +
\ No newline at end of file diff --git a/app/src/main/resources/templates/pages/super-groups.html b/app/src/main/resources/templates/pages/super-groups.html new file mode 100644 index 000000000..eb92fdfc0 --- /dev/null +++ b/app/src/main/resources/templates/pages/super-groups.html @@ -0,0 +1,30 @@ +
+
+ Create super group + + + + + + + + + + + + + + + +
+ Pretty name + + Type + + Details +
+ + + Details +
+
\ No newline at end of file diff --git a/app/src/main/resources/templates/pages/types.html b/app/src/main/resources/templates/pages/types.html new file mode 100644 index 000000000..dcd7c426a --- /dev/null +++ b/app/src/main/resources/templates/pages/types.html @@ -0,0 +1,32 @@ +
+
+
+
+ Create new super group type +
+
+
+ +
+
+ + + + + + + + + + + + + +
+ Name + + Details +
+ Details +
+
\ No newline at end of file diff --git a/app/src/main/resources/templates/pages/unauthorized.html b/app/src/main/resources/templates/pages/unauthorized.html new file mode 100644 index 000000000..4de7afa94 --- /dev/null +++ b/app/src/main/resources/templates/pages/unauthorized.html @@ -0,0 +1,14 @@ +
+
+
+
+ 403 - Unauthorized +
+

You are not authorized to view this page.

+ +
+
\ No newline at end of file diff --git a/app/src/main/resources/templates/pages/user-clients.html b/app/src/main/resources/templates/pages/user-clients.html new file mode 100644 index 000000000..bd5678ab9 --- /dev/null +++ b/app/src/main/resources/templates/pages/user-clients.html @@ -0,0 +1,23 @@ +
+
+ + + + + + + + + + + + + + + +
NameCreated byDetails
+ + + Details +
+
\ No newline at end of file diff --git a/app/src/main/resources/templates/partial/api-key-credentials.html b/app/src/main/resources/templates/partial/api-key-credentials.html new file mode 100644 index 000000000..0cb11a1f3 --- /dev/null +++ b/app/src/main/resources/templates/partial/api-key-credentials.html @@ -0,0 +1,23 @@ +
+
+ Credentials +
+

These are the credentials for your api key. They will not be shown again.

+
+
+ Api key: + +
+
+ +

+ Read more here about how to use Client API here:
github.com/cthit/Gamma/wiki/Client-API +

+
+ To authorize when doing API requests, simply add this header: +
+

+ Authorization: pre-shared : +

+
+
\ No newline at end of file diff --git a/app/src/main/resources/templates/partial/api-key-super-group-types.html b/app/src/main/resources/templates/partial/api-key-super-group-types.html new file mode 100644 index 000000000..2e9020248 --- /dev/null +++ b/app/src/main/resources/templates/partial/api-key-super-group-types.html @@ -0,0 +1,33 @@ +
+ + +
+ +
+
> +
+

+
+ + +
+
+ + +
+
+
\ No newline at end of file diff --git a/app/src/main/resources/templates/partial/created-super-group.html b/app/src/main/resources/templates/partial/created-super-group.html new file mode 100644 index 000000000..6bc216e02 --- /dev/null +++ b/app/src/main/resources/templates/partial/created-super-group.html @@ -0,0 +1,2 @@ +
+
\ No newline at end of file diff --git a/app/src/main/resources/templates/partial/deleted-post.html b/app/src/main/resources/templates/partial/deleted-post.html new file mode 100644 index 000000000..668638a20 --- /dev/null +++ b/app/src/main/resources/templates/partial/deleted-post.html @@ -0,0 +1 @@ +
\ No newline at end of file diff --git a/app/src/main/resources/templates/partial/edit-super-group.html b/app/src/main/resources/templates/partial/edit-super-group.html new file mode 100644 index 000000000..5ac4970cd --- /dev/null +++ b/app/src/main/resources/templates/partial/edit-super-group.html @@ -0,0 +1,21 @@ +
+
> +
+
+ + +
+
+
+
+
+ +
+
+ + +
+
+
\ No newline at end of file diff --git a/app/src/main/resources/templates/partial/edited-post.html b/app/src/main/resources/templates/partial/edited-post.html new file mode 100644 index 000000000..685ee15d9 --- /dev/null +++ b/app/src/main/resources/templates/partial/edited-post.html @@ -0,0 +1,2 @@ +
+
\ No newline at end of file diff --git a/app/src/main/resources/templates/partial/new-super-group-type-to-api-settings.html b/app/src/main/resources/templates/partial/new-super-group-type-to-api-settings.html new file mode 100644 index 000000000..d9d857dd2 --- /dev/null +++ b/app/src/main/resources/templates/partial/new-super-group-type-to-api-settings.html @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/app/src/main/resources/templates/partial/retracted-accepted-client.html b/app/src/main/resources/templates/partial/retracted-accepted-client.html new file mode 100644 index 000000000..f36154077 --- /dev/null +++ b/app/src/main/resources/templates/partial/retracted-accepted-client.html @@ -0,0 +1 @@ +
\ No newline at end of file diff --git a/app/src/main/resources/templates/post-details/edit-post.html b/app/src/main/resources/templates/post-details/edit-post.html new file mode 100644 index 000000000..bb6b3ddd9 --- /dev/null +++ b/app/src/main/resources/templates/post-details/edit-post.html @@ -0,0 +1,18 @@ +
+
Post details
+
+
+
+
+ +
+
+ + +
+
\ No newline at end of file diff --git a/app/src/main/resources/templates/post-details/not-found.html b/app/src/main/resources/templates/post-details/not-found.html new file mode 100644 index 000000000..f76ee82c2 --- /dev/null +++ b/app/src/main/resources/templates/post-details/not-found.html @@ -0,0 +1,16 @@ +
+
+ +
\ No newline at end of file diff --git a/app/src/main/resources/templates/post-details/page.html b/app/src/main/resources/templates/post-details/page.html new file mode 100644 index 000000000..8f567c381 --- /dev/null +++ b/app/src/main/resources/templates/post-details/page.html @@ -0,0 +1,72 @@ +
+
+
+
+ Post details +
+
    +
  • + Swedish name: + +
  • +
  • + English name: + +
  • +
  • + Email prefix: + + + This post has no email prefix. + +
  • +
+
+ +
+ +
+
+
+ +
+
+ Post usages +
+

+

+ + + + + + + + + + + + + + + + +
+ Group + + User +
+ Post has no usages. +
+ + + + +
+
+ +
\ No newline at end of file diff --git a/app/src/main/resources/templates/posts/page.html b/app/src/main/resources/templates/posts/page.html new file mode 100644 index 000000000..2855fd39b --- /dev/null +++ b/app/src/main/resources/templates/posts/page.html @@ -0,0 +1,34 @@ +
+
+ Create posts +
+ + + + + + + + + + + + + + + + + + + + +
OrderSwedish nameEnglish nameDetails
+ + + + Details +
+
+
\ No newline at end of file diff --git a/app/src/main/resources/templates/register-account/activate-cid.html b/app/src/main/resources/templates/register-account/activate-cid.html new file mode 100644 index 000000000..0fb73e88c --- /dev/null +++ b/app/src/main/resources/templates/register-account/activate-cid.html @@ -0,0 +1,17 @@ +
+
+
+
+
+ Activate cid +
+

Enter cid to start process of creating an account.

+

If you are an IT student, your cid should be on the allowed list of people who can create an account.

+

+
+
+ +
+
+
+
\ No newline at end of file diff --git a/app/src/main/resources/templates/register-account/email-sent.html b/app/src/main/resources/templates/register-account/email-sent.html new file mode 100644 index 000000000..2b53fdce7 --- /dev/null +++ b/app/src/main/resources/templates/register-account/email-sent.html @@ -0,0 +1,24 @@ +
+
+
+
+ An email should be sent to your student email +
+

+ + You should have received an email with a link to activate your IT account. + +

+

+ If you can't find it, please check your spam folder. There's also a chance that you might have typed your CID incorrectly. +

+

+ If you're certain that you've entered your CID correctly but still haven't received the account activation email, it could be due to a rate limit. If you suspect this to be the case, please contact ita@chalmers.it for further assistance. +

+ +
+
\ No newline at end of file diff --git a/app/src/main/resources/templates/register-account/register-account.html b/app/src/main/resources/templates/register-account/register-account.html new file mode 100644 index 000000000..8a4117a2f --- /dev/null +++ b/app/src/main/resources/templates/register-account/register-account.html @@ -0,0 +1,53 @@ +
+
+
+
+
+ Finish setting up your account +
+ +
+
+
+
+
+
+ + +
+
+
+
+ User agreement +
+ + +
+ +
+
+
+
\ No newline at end of file diff --git a/app/src/main/resources/templates/register-account/user-agreement.html b/app/src/main/resources/templates/register-account/user-agreement.html new file mode 100644 index 000000000..621159a68 --- /dev/null +++ b/app/src/main/resources/templates/register-account/user-agreement.html @@ -0,0 +1,10 @@ +

“IT" refers to the organization with the legal name "Teknologsektionen Informationsteknik" and org. number 857209-9524 based in Sweden.

+

This agreement refers to IT:s user account system Gamma.

+

IT will collect and manage name, nickname, year of admission, CID, phone number, e-mail, commitées and societies you are and have been part of, preferred language and your profile picture. The data is managed in order to authenticate you to IT and third party services. Furthermore, the data is used to create a profile that connects to IT services as well as any third party services you approve. The data is also used if we need to contact you for matters of special interest to you. The data is also handled for statistical purposes.

+

The data is saved until you choose to delete your profile or the IT section decides to delete your data. You will be notified of this at least 30 days prior.

+

Name, Chalmers ID, nickname and year of admission is shared with all users of Gamma. Data may also be shared with third party services with the user’s approval.

+

You have the right to withdraw your consent to the handling and request to have all data that IT has about you. If you have any questions or want to exercise your rights you can contact:

+ \ No newline at end of file diff --git a/app/src/main/resources/templates/throttling/throttling.html b/app/src/main/resources/templates/throttling/throttling.html new file mode 100644 index 000000000..9bb345b70 --- /dev/null +++ b/app/src/main/resources/templates/throttling/throttling.html @@ -0,0 +1,25 @@ +
+
+ + + + + + + + + + + + + + + +
KeyValue
+
+
+ + +
+
+
\ No newline at end of file diff --git a/app/src/main/resources/templates/type-details/not-found.html b/app/src/main/resources/templates/type-details/not-found.html new file mode 100644 index 000000000..17187b4e3 --- /dev/null +++ b/app/src/main/resources/templates/type-details/not-found.html @@ -0,0 +1,16 @@ +
+
+ +
\ No newline at end of file diff --git a/app/src/main/resources/templates/type-details/page.html b/app/src/main/resources/templates/type-details/page.html new file mode 100644 index 000000000..022965ba9 --- /dev/null +++ b/app/src/main/resources/templates/type-details/page.html @@ -0,0 +1,39 @@ +
+
+
+
+
+

+ These are the super group that has as the type. +

+ + + + + + + + + + + + + + + + +
+ Pretty name + + Details +
+ View +
+
+
+ +
+
+
+
\ No newline at end of file diff --git a/app/src/main/resources/templates/user-agreement/page.html b/app/src/main/resources/templates/user-agreement/page.html new file mode 100644 index 000000000..dd276633b --- /dev/null +++ b/app/src/main/resources/templates/user-agreement/page.html @@ -0,0 +1,9 @@ +
+
+
+
+ User agreement +
+ +
+
\ No newline at end of file diff --git a/app/src/main/resources/templates/user-details/edit-user.html b/app/src/main/resources/templates/user-details/edit-user.html new file mode 100644 index 000000000..a1096601f --- /dev/null +++ b/app/src/main/resources/templates/user-details/edit-user.html @@ -0,0 +1,41 @@ +
+
User details
+
+
+ +
+
+
+
+ + +
+
+
+ + +
+
\ No newline at end of file diff --git a/app/src/main/resources/templates/user-details/edited-user.html b/app/src/main/resources/templates/user-details/edited-user.html new file mode 100644 index 000000000..e1033b435 --- /dev/null +++ b/app/src/main/resources/templates/user-details/edited-user.html @@ -0,0 +1,2 @@ +
+
\ No newline at end of file diff --git a/app/src/main/resources/templates/user-details/not-found.html b/app/src/main/resources/templates/user-details/not-found.html new file mode 100644 index 000000000..9d7267ef7 --- /dev/null +++ b/app/src/main/resources/templates/user-details/not-found.html @@ -0,0 +1,16 @@ +
+
+ +
\ No newline at end of file diff --git a/app/src/main/resources/templates/user-details/page.html b/app/src/main/resources/templates/user-details/page.html new file mode 100644 index 000000000..a5c663d6d --- /dev/null +++ b/app/src/main/resources/templates/user-details/page.html @@ -0,0 +1,74 @@ +
+
+
+
User details
+ User avatar +
+
    +
  • + Name: + +
  • +
  • + Cid: + +
  • +
  • + Acceptance year + +
  • +
  • + Email: + +
  • +
  • + Has GDPR training: + +
  • +
  • + Is locked: + +
  • +
+
+
+ +
+ +
+
+
+ +
+
+ Generate reset password link +
+

Password link will appear here

+ +

Link valid for 15 minutes.

+ +
+
+
+
+ +
+
+
+ +
+
+

+ Is not a part of any groups +

+
    +
  • + +
  • +
+
+
\ No newline at end of file diff --git a/app/src/main/resources/templates/users/page.html b/app/src/main/resources/templates/users/page.html new file mode 100644 index 000000000..aa5294edf --- /dev/null +++ b/app/src/main/resources/templates/users/page.html @@ -0,0 +1,26 @@ +
+
+ Create user + + + + + + + + + + + + + + + + + + + +
First nameNickLast nameAcceptance yearDetails
+ Details +
+
\ No newline at end of file diff --git a/backend/.gitignore b/backend/.gitignore deleted file mode 100644 index 0cdbb81ed..000000000 --- a/backend/.gitignore +++ /dev/null @@ -1,33 +0,0 @@ -.gradle/ -/build/ -!gradle/wrapper/gradle-wrapper.jar -/uploads/ - -/src/main/resources/secrets.properties - -### STS ### -.apt_generated -.classpath -.factorypath -.project -.settings -.springBeans -.sts4-cache - -### IntelliJ IDEA ### -.idea -*.iws -*.iml -*.ipr -/out/ -.idea/ - -### NetBeans ### -/nbproject/private/ -/build/ -/nbbuild/ -/dist/ -/nbdist/ -/.nb-gradle/ - -secrets.properties diff --git a/backend/Insomnia_gamma_endpoints.json b/backend/Insomnia_gamma_endpoints.json deleted file mode 100644 index f5c5e1f53..000000000 --- a/backend/Insomnia_gamma_endpoints.json +++ /dev/null @@ -1,3820 +0,0 @@ -{ - "_type": "export", - "__export_format": 3, - "__export_date": "2019-06-02T17:11:42.511Z", - "__export_source": "insomnia.desktop.app:v5.16.6", - "resources": [ - { - "_id": "wrk_e128b6afbd1b4c408f3c249804f82cc7", - "created": 1532433905526, - "description": "", - "modified": 1532433905526, - "name": "Insomnia", - "parentId": null, - "_type": "workspace" - }, - { - "_id": "env_e64dcd68442a4510a1de314cdcb06727", - "color": null, - "created": 1532433905578, - "data": {}, - "isPrivate": false, - "modified": 1532433905578, - "name": "New Environment", - "parentId": "wrk_e128b6afbd1b4c408f3c249804f82cc7", - "_type": "environment" - }, - { - "_id": "jar_c7e865dde67e476aae412e63c7644599", - "cookies": [ - { - "creation": "2018-07-24T12:36:47.828Z", - "domain": "localhost", - "hostOnly": true, - "httpOnly": true, - "id": "4304288510903631", - "key": "adminer_sid", - "lastAccessed": "2018-07-24T12:36:47.828Z", - "path": "/whitelist/activate_cid", - "value": "296b60439fb9c2169d4db9fb75c466e9" - }, - { - "creation": "2018-07-24T12:36:47.828Z", - "domain": "localhost", - "extensions": ["SameSite=lax"], - "hostOnly": true, - "httpOnly": true, - "id": "8642686320025581", - "key": "adminer_key", - "lastAccessed": "2018-07-24T12:36:47.828Z", - "path": "/whitelist/activate_cid", - "value": "814b79680af4e5052928ebf54fd24e5d" - }, - { - "creation": "2018-12-07T18:37:38.071Z", - "domain": "localhost", - "hostOnly": true, - "httpOnly": true, - "id": "7748912179413627", - "key": "JSESSIONID", - "lastAccessed": "2018-12-26T20:36:17.996Z", - "path": "/", - "value": "429882DF8EF38CD6B786F7345B882404" - }, - { - "creation": "2019-01-02T17:23:42.905Z", - "domain": "localhost", - "hostOnly": true, - "httpOnly": true, - "id": "46993308803973965", - "key": "JSESSIONID", - "lastAccessed": "2019-03-03T20:28:26.296Z", - "path": "/api", - "value": "345907FFEE82FCACDE11DFCBD55DF07D" - } - ], - "created": 1532433905652, - "modified": 1551644906297, - "name": "Default Jar", - "parentId": "wrk_e128b6afbd1b4c408f3c249804f82cc7", - "_type": "cookie_jar" - }, - { - "_id": "fld_193320d04baf40e4a046d61def653114", - "created": 1559494924048, - "description": "", - "environment": {}, - "metaSortKey": -1559494924048, - "modified": 1559495087058, - "name": "Gamma", - "parentId": "wrk_e128b6afbd1b4c408f3c249804f82cc7", - "_type": "request_group" - }, - { - "_id": "fld_c846f7fe3dad4f209e047c857d24e546", - "created": 1559495101481, - "description": "", - "environment": {}, - "metaSortKey": -1559494923998, - "modified": 1559495101637, - "name": "Gamma", - "parentId": "wrk_e128b6afbd1b4c408f3c249804f82cc7", - "_type": "request_group" - }, - { - "_id": "env_5d80efc2fc764077a64292db8fd398c5", - "color": "#411bd2", - "created": 1559494872696, - "data": {}, - "isPrivate": false, - "modified": 1559494877392, - "name": "New Environment", - "parentId": "env_e64dcd68442a4510a1de314cdcb06727", - "_type": "environment" - }, - { - "_id": "req_76232166158a415f8a8e141e609586ec", - "authentication": {}, - "body": { - "mimeType": "application/json", - "text": "{\n\t\"cids\":[\n\t\t\"engsmyre\"\n\t\t]\n}" - }, - "created": 1532435453165, - "description": "", - "headers": [ - { - "id": "pair_fd8a2baa477a4c1fbf75f84711306afd", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhZG1pbiIsImlzcyI6IkNUSElUIiwiaWF0IjoxNTQzNjcyMjE2LCJleHAiOjE1NDYyNjQyMTZ9.fJ8zGWLjUF7vjKyH3Lr4vFQPJa6AW5xadZQobh7IUKY" - }, - { - "id": "pair_8be41d4ac33640978efbd8f70d248be2", - "name": "Content-Type", - "value": "application/json" - } - ], - "isPrivate": false, - "metaSortKey": 2296.58203125, - "method": "POST", - "modified": 1559495058374, - "name": "Create Whitelist", - "parameters": [], - "parentId": "fld_193320d04baf40e4a046d61def653114", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/admin/users/whitelist", - "_type": "request" - }, - { - "_id": "req_bab9e19ac73e4220afcc801fcf9be1b9", - "authentication": {}, - "body": { - "mimeType": "application/json", - "text": "{\n\t\"code\":\"UMANATISRR\",\n\t\"password\":\"password123\",\n\t\"nick\":\"coffe\",\n\t\"acceptanceYear\":\"2017\",\n\t\"whitelist\":{\n\t\t\t\"cid\":\"kaffe\"\n\t}\n}" - }, - "created": 1532435474623, - "description": "", - "headers": [ - { - "id": "pair_6e5102b055ee4d7fb9cf13a297ebb353", - "name": "Content-Type", - "value": "application/json" - } - ], - "isPrivate": false, - "metaSortKey": 2296.6796875, - "method": "POST", - "modified": 1559495057037, - "name": "create account", - "parameters": [], - "parentId": "fld_193320d04baf40e4a046d61def653114", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/users/create", - "_type": "request" - }, - { - "_id": "req_932e93b591804c64900799000991a79f", - "authentication": {}, - "body": { - "mimeType": "application/json", - "text": "{\n\t\"cid\":\"engsmyre\"\n}" - }, - "created": 1532435711349, - "description": "", - "headers": [ - { - "id": "pair_ff59990f14e8420aa87642d8c49434ae", - "name": "Content-Type", - "value": "application/json" - } - ], - "isPrivate": false, - "metaSortKey": 2296.484375, - "method": "POST", - "modified": 1559495056007, - "name": "Create Code", - "parameters": [], - "parentId": "fld_193320d04baf40e4a046d61def653114", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/whitelist/activate_cid", - "_type": "request" - }, - { - "_id": "req_e28bd0bdee134bcb84e4d6e4473b7bdb", - "authentication": { - "type": "bearer" - }, - "body": {}, - "created": 1532436221255, - "description": "", - "headers": [ - { - "id": "pair_c9d82714b2394a9f9298797acb9df41a", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODEiLCJleHAiOjE1NTMxOTYzNjcsImF1dGhvcml0aWVzIjpbImFkbWluIl0sImp0aSI6IjA4NzViMDlkLTFjNjAtNDU4NC1hMWM2LWRmOTViY2IxZTI0ZCIsImNsaWVudF9pZCI6IjdoQWRVRXRNbzRNZ0ZuQTdab1o0MW9oVGUxTk5Sb0ptakw2N0dmME5JcnJCbmF1eWhjIn0._UpKccV_CRKJplx0BczDEoKaz8mvN8aS8j5wXojQGLU" - } - ], - "isPrivate": false, - "metaSortKey": 2295.8984375, - "method": "GET", - "modified": 1559495052568, - "name": "get Post", - "parameters": [], - "parentId": "fld_193320d04baf40e4a046d61def653114", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/api/admin/groups/posts", - "_type": "request" - }, - { - "_id": "req_fb405d78eeaa4114a5fedf418995ccfc", - "authentication": {}, - "body": {}, - "created": 1532437807205, - "description": "", - "headers": [ - { - "id": "pair_74be68e6da4b43b998c633f0090eaf3a", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODEiLCJleHAiOjE1NTEwMzUxNTMsImF1dGhvcml0aWVzIjpbImFkbWluIl0sImp0aSI6IjNhNWEyYzMxLTMyODQtNDAyMC05YzZhLWMwOTRlM2YyM2VmYiIsImNsaWVudF9pZCI6IjdoQWRVRXRNbzRNZ0ZuQTdab1o0MW9oVGUxTk5Sb0ptakw2N0dmME5JcnJCbmF1eWhjIn0.mAhpI7plWg2FyNhEz03BvuQ2oxIgzPckz-KHnht1gws" - } - ], - "isPrivate": false, - "metaSortKey": 2295.703125, - "method": "GET", - "modified": 1559495002129, - "name": "get Minified", - "parameters": [], - "parentId": "fld_193320d04baf40e4a046d61def653114", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/api/users/minified", - "_type": "request" - }, - { - "_id": "req_500b0d02fcbe475bb1fdbb940a429377", - "authentication": {}, - "body": { - "mimeType": "application/json", - "text": "{\n\t\"post\":\n\t{\n\t\t\"sv\":\"ledamot\",\n\t\t\"en\":\"ledamot\"\n\t}\n}" - }, - "created": 1532440476321, - "description": "", - "headers": [ - { - "id": "pair_899d7e4fb6984310bd6d2d4a3ed66f28", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODEiLCJleHAiOjE1NTMxOTYzNjcsImF1dGhvcml0aWVzIjpbImFkbWluIl0sImp0aSI6IjA4NzViMDlkLTFjNjAtNDU4NC1hMWM2LWRmOTViY2IxZTI0ZCIsImNsaWVudF9pZCI6IjdoQWRVRXRNbzRNZ0ZuQTdab1o0MW9oVGUxTk5Sb0ptakw2N0dmME5JcnJCbmF1eWhjIn0._UpKccV_CRKJplx0BczDEoKaz8mvN8aS8j5wXojQGLU" - }, - { - "id": "pair_3576d565efe24065815d70b7ed67edbc", - "name": "Content-Type", - "value": "application/json" - } - ], - "isPrivate": false, - "metaSortKey": 2296.09375, - "method": "POST", - "modified": 1559495001213, - "name": "add post", - "parameters": [], - "parentId": "fld_193320d04baf40e4a046d61def653114", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/api/admin/groups/posts", - "_type": "request" - }, - { - "_id": "req_faa2e955ded24265901b0475830108f4", - "authentication": {}, - "body": {}, - "created": 1532442511326, - "description": "", - "headers": [ - { - "id": "pair_8bb4a52708bb49c7abcddc4d18b06932", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODEiLCJleHAiOjE1NDkwNDE3NTQsImF1dGhvcml0aWVzIjpbImFkbWluIl0sImp0aSI6IjFhYjA2NWFhLTYzNmYtNGZkNy05ZTRkLTAwZTdiNDZkYzBkMyIsImNsaWVudF9pZCI6IjdoQWRVRXRNbzRNZ0ZuQTdab1o0MW9oVGUxTk5Sb0ptakw2N0dmME5JcnJCbmF1eWhjIn0.ZlV7JumIzb6LoYlUp4ch8-IxN_vQMOY1RLCPJPKqciA" - } - ], - "isPrivate": false, - "metaSortKey": 2294.53125, - "method": "GET", - "modified": 1559494999724, - "name": "get user", - "parameters": [], - "parentId": "fld_193320d04baf40e4a046d61def653114", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/api/users/4b30f99f-39bd-4197-9089-04ae33c9ae92", - "_type": "request" - }, - { - "_id": "req_4eb5d351abda4183b9f3ad5d14547664", - "authentication": {}, - "body": { - "mimeType": "application/json", - "text": "{\n\t\"name\": \"digit18\",\n\t\"prettyName\":\"ldap\",\n\t\"email\": \"digit@chalmers.it\",\n\t\"superGroup\":\"aa835d66-5a59-47c8-9d57-8b1594b08216\",\n\t\"func\": {\n\t\t\"sv\": \"being gods\",\n\t\t\"en\": \"god\"\n\t},\n\t\"websites\": [\n\t\t{\n\t\t\t\"website\": \"186c262d-e5fd-41c5-b681-bba594919a36\",\n\t\t\t\"url\": \"facebook.com/helloworl\"\n\t\t},\n\t\t{\n\t\t\t\"website\": \"186c262d-e5fd-41c5-b681-bba594919a36\",\n\t\t\t\"url\": \"facebook.com/sdfkl\"\n\t\t}\n\t],\n\t\"type\": \"COMMITTEE\",\n\t\"year\":2018,\n\t\"becomesActive\":\"2018-03-17\",\n\t\"becomesInactive\":\"2019-05-01\"\n}" - }, - "created": 1532443206245, - "description": "", - "headers": [ - { - "id": "pair_a1e5825c515e4287b36a4dc9747bdb55", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODEiLCJleHAiOjE1NTMxOTYzNjcsImF1dGhvcml0aWVzIjpbImFkbWluIl0sImp0aSI6IjA4NzViMDlkLTFjNjAtNDU4NC1hMWM2LWRmOTViY2IxZTI0ZCIsImNsaWVudF9pZCI6IjdoQWRVRXRNbzRNZ0ZuQTdab1o0MW9oVGUxTk5Sb0ptakw2N0dmME5JcnJCbmF1eWhjIn0._UpKccV_CRKJplx0BczDEoKaz8mvN8aS8j5wXojQGLU" - }, - { - "id": "pair_d822b7fe2f42443d899ce8aff9937bf4", - "name": "Content-Type", - "value": "application/json" - } - ], - "isPrivate": false, - "metaSortKey": 2295.3125, - "method": "POST", - "modified": 1559494998862, - "name": "add group", - "parameters": [], - "parentId": "fld_193320d04baf40e4a046d61def653114", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/api/admin/groups", - "_type": "request" - }, - { - "_id": "req_9820b160fa8f4a3bb40257570c953ad4", - "authentication": {}, - "body": { - "mimeType": "application/json", - "text": "{\n\t\"prettyName\":\"leffe\",\n\t\"email\": \"digit@chalmers.it\",\n\t\"function\": {\n\t\t\"sv\": \"rustmästeri\",\n\t\t\"en\": \"\"\n\t},\n\t\"websites\": [\n\t\t{\n\t\t\t\"website\": \"facebook\",\n\t\t\t\"url\": \"2\"\n\t\t}\n],\n\"groupType\": \"COMMITTEE\"\n}" - }, - "created": 1532443450667, - "description": "", - "headers": [ - { - "id": "pair_466cab8cd5c14c0e82dfc58146a76b6a", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJlbmdzbXlyZSIsImlzcyI6ImRpZ0lUIiwiaWF0IjoxNTMyNDM2MzA5LCJleHAiOjE1MzUwMjgzMDl9.mvV65rFj8wFANLJrgQwrUDPq70gW0ulcjCtbjzUfV9E" - }, - { - "id": "pair_5690ed6b8bb7463e91d3e7ed05c70ba5", - "name": "Content-Type", - "value": "application/json" - } - ], - "isPrivate": false, - "metaSortKey": 2296.875, - "method": "PUT", - "modified": 1559494997818, - "name": "edit group", - "parameters": [], - "parentId": "fld_193320d04baf40e4a046d61def653114", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/admin/groups/334d7158-0a99-4e1b-8598-a44d5b6cbfe4", - "_type": "request" - }, - { - "_id": "req_39d0898f349947e8b40ce1ec93cb2d5f", - "authentication": {}, - "body": { - "mimeType": "application/json", - "text": "{\n\t\"websites\": [\n\t\t{\n\t\t\t\"website\": \"facebook\",\n\t\t\t\"url\": \"facebook.com/gustavengsmyre\"\n\t\t},\n\t\t{\n\t\t\t\"website\": \"facebook\",\n\t\t\t\"url\": \"facebook.com/facebook\"\n\t\t},\n\t\t\t\t{\n\t\t\t\"website\": \"facebook\",\n\t\t\t\"url\": \"facebook.com/portalssuger\"\n\t\t}\n\t]\n}" - }, - "created": 1532517838300, - "description": "", - "headers": [ - { - "id": "pair_9b58efc9843e44219001a2c9ad8b8c61", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJlbmdzbXlyZSIsImlzcyI6ImRpZ0lUIiwiaWF0IjoxNTMyNTE3ODQzLCJleHAiOjE1MzUxMDk4NDN9.X4FnNL2QlxkZMSAlRL2uAypU5CEB1iPyVbwKpvdQZG0" - }, - { - "id": "pair_9414e2d6b0a94b9083ae2998d7c4a896", - "name": "Content-Type", - "value": "application/json" - } - ], - "isPrivate": false, - "metaSortKey": 2293.75, - "method": "PUT", - "modified": 1559494996631, - "name": "Edit user", - "parameters": [], - "parentId": "fld_193320d04baf40e4a046d61def653114", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/admin/users/d8f9cb87-760f-4dee-95c5-deaa7ca6c79b", - "_type": "request" - }, - { - "_id": "req_df3500b5da784bcc844d6f75423fe451", - "authentication": {}, - "body": { - "mimeType": "application/json", - "text": "{\n\t\"cid\":\"engsmyre\"\n}" - }, - "created": 1532520384950, - "description": "", - "headers": [ - { - "id": "pair_a01a15041b864f4fba44117515ccdb03", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJlbmdzbXlyZSIsImlzcyI6ImRpZ0lUIiwiaWF0IjoxNTMyNTIwMzYwLCJleHAiOjE1MzUxMTIzNjB9.AcR7JlrE2NJc83OrY9S9eNQPIfRfSFJIpitZEiml1w0" - }, - { - "id": "pair_ffd533bec58f4e8383ad3b1dd81661f9", - "name": "Content-Type", - "value": "application/json" - } - ], - "isPrivate": false, - "metaSortKey": 2287.5, - "method": "PUT", - "modified": 1559494995488, - "name": "edit whitelisted", - "parameters": [], - "parentId": "fld_193320d04baf40e4a046d61def653114", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/admin/users/whitelist/4a141001-78c5-4e6e-9c8e-c125d08beb38", - "_type": "request" - }, - { - "_id": "req_6657c4791d354157bf9fcd78c5d91c05", - "authentication": {}, - "body": {}, - "created": 1532521499241, - "description": "", - "headers": [ - { - "id": "pair_d3a3781902764b9b90eb80c9439edb24", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJlbmdzbXlyZSIsImlzcyI6ImRpZ0lUIiwiaWF0IjoxNTM1NTY1Nzg2LCJleHAiOjE1MzgxNTc3ODZ9.OfAUIFrzHOwtO1m5veAAkAHNoNOtSJYDvYlsYGfkoiw" - }, - { - "id": "pair_0430e809374d4acc8efa95dc0ff73363", - "name": "", - "value": "" - } - ], - "isPrivate": false, - "metaSortKey": 2275, - "method": "GET", - "modified": 1559494994451, - "name": "get whitelist", - "parameters": [], - "parentId": "fld_193320d04baf40e4a046d61def653114", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/admin/users/whitelist", - "_type": "request" - }, - { - "_id": "req_fe16bb8d12db4e5eb67868b4103a40d4", - "authentication": {}, - "body": {}, - "created": 1532523134901, - "description": "", - "headers": [ - { - "id": "pair_63a4b81c74d34492b52c4a3ca549ef30", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJlbmdzbXlyZSIsImlzcyI6ImRpZ0lUIiwiaWF0IjoxNTMyNTIwMzYwLCJleHAiOjE1MzUxMTIzNjB9.AcR7JlrE2NJc83OrY9S9eNQPIfRfSFJIpitZEiml1w0" - } - ], - "isPrivate": false, - "metaSortKey": 2249.609375, - "method": "DELETE", - "modified": 1559494992098, - "name": "delete whitelist", - "parameters": [], - "parentId": "fld_193320d04baf40e4a046d61def653114", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/admin/users/whitelist/4a141001-78c5-4e6e-9c8e-c125d08beb38", - "_type": "request" - }, - { - "_id": "req_4b1990c0db6c4cee9fb404ee4e4b4082", - "authentication": {}, - "body": { - "mimeType": "application/json", - "text": "{\n\t\"post\":{\n\t\"sv\":\"master\"\t\n\t}\n}" - }, - "created": 1532610465817, - "description": "", - "headers": [ - { - "id": "pair_42e9e4511cae48c78ac2e7bbf11cdde9", - "name": "Content-Type", - "value": "application/json" - }, - { - "id": "pair_70555760ea5041ad906da475b6cdeb9a", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJlbmdzbXlyZSIsImlzcyI6ImRpZ0lUIiwiaWF0IjoxNTMyNjEwNTgwLCJleHAiOjE1MzUyMDI1ODB9.hOJPhObU0BQtFv0vnWcKmdpFtijl9-St3fsu5nWd0Vc" - } - ], - "isPrivate": false, - "metaSortKey": 2245.3125, - "method": "PUT", - "modified": 1559494988368, - "name": "Edit post", - "parameters": [], - "parentId": "fld_193320d04baf40e4a046d61def653114", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/admin/groups/posts/88e1708f-2462-435e-a70f-2ff1006b2866", - "_type": "request" - }, - { - "_id": "req_54549cf10bdf455cb0e5bde69399db0e", - "authentication": {}, - "body": { - "mimeType": "application/json", - "text": "{\n\t\"name\":\"facebook\",\n\t\"prettyName\":\"facebook\"\n}" - }, - "created": 1532685378741, - "description": "", - "headers": [ - { - "id": "pair_505a0928654a4dbfade0ba2c8640ea8e", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODEiLCJleHAiOjE1NTMxOTYzNjcsImF1dGhvcml0aWVzIjpbImFkbWluIl0sImp0aSI6IjA4NzViMDlkLTFjNjAtNDU4NC1hMWM2LWRmOTViY2IxZTI0ZCIsImNsaWVudF9pZCI6IjdoQWRVRXRNbzRNZ0ZuQTdab1o0MW9oVGUxTk5Sb0ptakw2N0dmME5JcnJCbmF1eWhjIn0._UpKccV_CRKJplx0BczDEoKaz8mvN8aS8j5wXojQGLU" - }, - { - "id": "pair_5c3eaac167884d72b5d924bb519ba443", - "name": "Content-Type", - "value": "application/json" - } - ], - "isPrivate": false, - "metaSortKey": 2249.21875, - "method": "POST", - "modified": 1559494990917, - "name": "Create Website", - "parameters": [], - "parentId": "fld_193320d04baf40e4a046d61def653114", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/api/admin/websites", - "_type": "request" - }, - { - "_id": "req_63dc9126eff9499791abcbc796b88c97", - "authentication": {}, - "body": {}, - "created": 1532685563113, - "description": "", - "headers": [ - { - "id": "pair_fa5d062cda0a4cad9c7f18cb1e547c61", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODEiLCJleHAiOjE1NTMxOTYzNjcsImF1dGhvcml0aWVzIjpbImFkbWluIl0sImp0aSI6IjA4NzViMDlkLTFjNjAtNDU4NC1hMWM2LWRmOTViY2IxZTI0ZCIsImNsaWVudF9pZCI6IjdoQWRVRXRNbzRNZ0ZuQTdab1o0MW9oVGUxTk5Sb0ptakw2N0dmME5JcnJCbmF1eWhjIn0._UpKccV_CRKJplx0BczDEoKaz8mvN8aS8j5wXojQGLU" - } - ], - "isPrivate": false, - "metaSortKey": 2247.65625, - "method": "GET", - "modified": 1559494990132, - "name": "Get Websites", - "parameters": [], - "parentId": "fld_193320d04baf40e4a046d61def653114", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/api/admin/websites", - "_type": "request" - }, - { - "_id": "req_5e341d1d080c4f8a9a05e9d3bcfa05d3", - "authentication": {}, - "body": {}, - "created": 1532686019481, - "description": "", - "headers": [ - { - "id": "pair_fb9f508e07ae4f569c61eb2e9ea09977", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJrYWZmZSIsImlzcyI6ImRpZ0lUIiwiaWF0IjoxNTM5MTgxNTAzLCJleHAiOjE1NDE3NzM1MDN9.B_Uqy9P3ING6_Ull_kIXgs8WfDByW0GgkaL0NUIkJfw" - } - ], - "isPrivate": false, - "metaSortKey": 2248.4375, - "method": "GET", - "modified": 1559494989223, - "name": "Get Website", - "parameters": [], - "parentId": "fld_193320d04baf40e4a046d61def653114", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/admin/websites/b624d762-754d-4c0b-9e48-6dcb3cdc955a", - "_type": "request" - }, - { - "_id": "req_3e16b098ba8c43c7a16bac91d8af9730", - "authentication": {}, - "body": { - "mimeType": "application/json", - "text": "{\n\t\"website\":\"Facebook\"\n}" - }, - "created": 1532686074313, - "description": "", - "headers": [ - { - "id": "pair_240d8a87af8c491da7b75ee7720f6409", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJlbmdzbXlyZSIsImlzcyI6ImRpZ0lUIiwiaWF0IjoxNTMyNjg1NTIzLCJleHAiOjE1MzUyNzc1MjN9.g4YwfNjoBPhfgZI98zaXn7z3CcJMgxapMu_4HThSilw" - }, - { - "id": "pair_e8c7f441d7c64000812353202e06231f", - "name": "Content-Type", - "value": "application/json" - } - ], - "isPrivate": false, - "metaSortKey": 2246.875, - "method": "PUT", - "modified": 1559494987518, - "name": "Edit Website", - "parameters": [], - "parentId": "fld_193320d04baf40e4a046d61def653114", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/admin/websites/c5ea640a-c566-4dfe-a03d-85a20beaf74c", - "_type": "request" - }, - { - "_id": "req_baab8d025f0d49bd8db49c78724b7880", - "authentication": {}, - "body": { - "mimeType": "application/json", - "text": "" - }, - "created": 1532686118056, - "description": "", - "headers": [ - { - "id": "pair_1bbc30a665ae419fb25f5f69561135f2", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJlbmdzbXlyZSIsImlzcyI6ImRpZ0lUIiwiaWF0IjoxNTMyNjg1NTIzLCJleHAiOjE1MzUyNzc1MjN9.g4YwfNjoBPhfgZI98zaXn7z3CcJMgxapMu_4HThSilw" - }, - { - "id": "pair_93f8c8db9cea4203b3a1e88a7ef3d21e", - "name": "Content-Type", - "value": "application/json" - } - ], - "isPrivate": false, - "metaSortKey": 2243.75, - "method": "DELETE", - "modified": 1559494986844, - "name": "Delete Website", - "parameters": [], - "parentId": "fld_193320d04baf40e4a046d61def653114", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/admin/websites/6b0a83df-830a-4f1a-ad6b-568f7c4171f8", - "_type": "request" - }, - { - "_id": "req_09493e39bb094eda8c86119acef3db99", - "authentication": {}, - "body": {}, - "created": 1532692708671, - "description": "", - "headers": [ - { - "id": "pair_b386cc577c65418589e8d91aa22e6b41", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhZG1pbiIsImlzcyI6IkNUSElUIiwiaWF0IjoxNTQ1NzQ3ODU1LCJleHAiOjE1NDgzMzk4NTV9.emgG3YOaxI3loIlvG3eqi2dmJTsJ0U5oBzz9K5Zc6Po" - } - ], - "isPrivate": false, - "metaSortKey": 2231.25, - "method": "GET", - "modified": 1559494985981, - "name": "Get Group", - "parameters": [], - "parentId": "fld_193320d04baf40e4a046d61def653114", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/groups/334d7158-0a99-4e1b-8598-a44d5b6cbfe4", - "_type": "request" - }, - { - "_id": "req_db996db2fa73406082edd32732a3a597", - "authentication": {}, - "body": {}, - "created": 1532979250841, - "description": "", - "headers": [ - { - "id": "pair_b1b33c1608ab44639d4ead975ef5f5e1", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJlbmdzbXlyZSIsImlzcyI6ImRpZ0lUIiwiaWF0IjoxNTMyNjg1NTIzLCJleHAiOjE1MzUyNzc1MjN9.g4YwfNjoBPhfgZI98zaXn7z3CcJMgxapMu_4HThSilw" - } - ], - "isPrivate": false, - "metaSortKey": 2237.5, - "method": "GET", - "modified": 1559494984756, - "name": "Get Group Minified", - "parameters": [], - "parentId": "fld_193320d04baf40e4a046d61def653114", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/groups/digit/minified", - "_type": "request" - }, - { - "_id": "req_2a76214c4ec34202a03705a3a5f890c5", - "authentication": {}, - "body": { - "mimeType": "application/json", - "text": "{\n\t\"user\":\"466c9e51-8c18-499f-97da-266499e4acdd\",\n\t\"post\":\"e8a25cd7-4dfc-4cbd-b860-b2724aeacee4\",\n\t\"unofficialName\":\"onödig\"\n}" - }, - "created": 1533039178985, - "description": "", - "headers": [ - { - "id": "pair_c70a5b81d88b4d39bec6487eb1657dd0", - "name": "Content-Type", - "value": "application/json" - }, - { - "id": "pair_289e56d5622b49a19315bac43a020029", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODEiLCJleHAiOjE1NTIxNDUxOTcsImF1dGhvcml0aWVzIjpbImFkbWluIl0sImp0aSI6IjNkZDNiYzFkLTk4MWEtNDQwYy05N2FjLWQ5OTJkZjJmYzIwOSIsImNsaWVudF9pZCI6IjdoQWRVRXRNbzRNZ0ZuQTdab1o0MW9oVGUxTk5Sb0ptakw2N0dmME5JcnJCbmF1eWhjIn0.gXILm0CCeLOOa_-yh0_Tw4WaoC_ZcvBvMXeMm578qsk" - } - ], - "isPrivate": false, - "metaSortKey": 2225, - "method": "POST", - "modified": 1559494983777, - "name": "Add User To Group", - "parameters": [], - "parentId": "fld_193320d04baf40e4a046d61def653114", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/api/admin/groups/7aa80b2d-4ed2-465d-ba22-6503b8a396c7/members", - "_type": "request" - }, - { - "_id": "req_f2085663c11d46e5938ddb00c98cee1f", - "authentication": {}, - "body": {}, - "created": 1533039875713, - "description": "", - "headers": [ - { - "id": "pair_eaf2697c85444f2c8910ddb49fa90c53", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODEiLCJleHAiOjE1NDkwNDE3NTQsImF1dGhvcml0aWVzIjpbImFkbWluIl0sImp0aSI6IjFhYjA2NWFhLTYzNmYtNGZkNy05ZTRkLTAwZTdiNDZkYzBkMyIsImNsaWVudF9pZCI6IjdoQWRVRXRNbzRNZ0ZuQTdab1o0MW9oVGUxTk5Sb0ptakw2N0dmME5JcnJCbmF1eWhjIn0.ZlV7JumIzb6LoYlUp4ch8-IxN_vQMOY1RLCPJPKqciA" - } - ], - "isPrivate": false, - "metaSortKey": 2250, - "method": "GET", - "modified": 1559494982685, - "name": "Get Post Usage", - "parameters": [], - "parentId": "fld_193320d04baf40e4a046d61def653114", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/api/admin/groups/posts/9dcb2751-fb4e-43a8-8681-090d1392bc36/usage", - "_type": "request" - }, - { - "_id": "req_c6537bd2974447149ac4736ff48d6965", - "authentication": {}, - "body": { - "mimeType": "application/json", - "text": "{\n\t\"id\":\"d8f9cb87-760f-4dee-95c5-deaa7ca6c79b\"\n}" - }, - "created": 1533129142079, - "description": "", - "headers": [ - { - "id": "pair_db6e908fdcd1489c8f0bce350b889eae", - "name": "Content-Type", - "value": "application/json" - }, - { - "id": "pair_c2995a3c232b4c4ba8b039127f4d9822", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJlbmdzbXlyZSIsImlzcyI6ImRpZ0lUIiwiaWF0IjoxNTMyNjg1NTIzLCJleHAiOjE1MzUyNzc1MjN9.g4YwfNjoBPhfgZI98zaXn7z3CcJMgxapMu_4HThSilw" - } - ], - "isPrivate": false, - "metaSortKey": 2012.5, - "method": "POST", - "modified": 1559494974091, - "name": "Admin Password Reset", - "parameters": [], - "parentId": "fld_193320d04baf40e4a046d61def653114", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/admin/users/reset_password", - "_type": "request" - }, - { - "_id": "req_236d8fbf6afd498eb932347e99945573", - "authentication": {}, - "body": { - "mimeType": "application/json", - "text": "{\n\t\"password\":\"iamapassword\",\n\t\"token\":\"gaK>A]1K$C?BgLl*P([[#IZP.R$]&teYh(#qWK&/eS3ZsNhZDTV]P+55=i[VF7SUTG9UH?>_&Yx&e!dKz8lD&H(7qC,PK=+d]9]8\",\n\t\"cid\":\"engsmyre\"\n}" - }, - "created": 1533130038288, - "description": "", - "headers": [ - { - "id": "pair_6c43e750e2484fffba7b6037693a1862", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJlbmdzbXlyZSIsImlzcyI6ImRpZ0lUIiwiaWF0IjoxNTMyNjg1NTIzLCJleHAiOjE1MzUyNzc1MjN9.g4YwfNjoBPhfgZI98zaXn7z3CcJMgxapMu_4HThSilw" - }, - { - "id": "pair_67d30ea94f1d4818a1d7e2c127c0db58", - "name": "Content-Type", - "value": "application/json" - } - ], - "isPrivate": false, - "metaSortKey": 2075, - "method": "PUT", - "modified": 1559494981636, - "name": "Finish Password Reset", - "parameters": [], - "parentId": "fld_193320d04baf40e4a046d61def653114", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/admin/users/reset_password/finish", - "_type": "request" - }, - { - "_id": "req_bf560fff20a44034ba434656cd589359", - "authentication": {}, - "body": {}, - "created": 1533133637715, - "description": "", - "headers": [ - { - "id": "pair_3a82dc1565ae49cea48d1b1b7fd91608", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODEiLCJleHAiOjE1NTMxOTYzNjcsImF1dGhvcml0aWVzIjpbImFkbWluIl0sImp0aSI6IjA4NzViMDlkLTFjNjAtNDU4NC1hMWM2LWRmOTViY2IxZTI0ZCIsImNsaWVudF9pZCI6IjdoQWRVRXRNbzRNZ0ZuQTdab1o0MW9oVGUxTk5Sb0ptakw2N0dmME5JcnJCbmF1eWhjIn0._UpKccV_CRKJplx0BczDEoKaz8mvN8aS8j5wXojQGLU" - } - ], - "isPrivate": false, - "metaSortKey": 2048.4375, - "method": "DELETE", - "modified": 1559494979562, - "name": "Delete Group", - "parameters": [], - "parentId": "fld_193320d04baf40e4a046d61def653114", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/api/admin/groups/40339f21-221b-4fdf-bb9a-9d957ebbd9b9", - "_type": "request" - }, - { - "_id": "req_0f694ec84f664e3ca9f1f0d97301eb49", - "authentication": { - "accessTokenUrl": "localhost:8081/oauth/token", - "authorizationUrl": "localhost:8081/oauth/authorize", - "clientId": "this_is_a_client_id", - "clientSecret": "{noop}secret", - "grantType": "authorization_code", - "redirectUrl": "http://localhost:3000/login", - "type": "oauth2" - }, - "body": {}, - "created": 1533133858173, - "description": "", - "headers": [ - { - "id": "pair_9834904ea5aa4effbefc509f5e921a17", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODEiLCJleHAiOjE1NTIxNDUxOTcsImF1dGhvcml0aWVzIjpbImFkbWluIl0sImp0aSI6IjNkZDNiYzFkLTk4MWEtNDQwYy05N2FjLWQ5OTJkZjJmYzIwOSIsImNsaWVudF9pZCI6IjdoQWRVRXRNbzRNZ0ZuQTdab1o0MW9oVGUxTk5Sb0ptakw2N0dmME5JcnJCbmF1eWhjIn0.gXILm0CCeLOOa_-yh0_Tw4WaoC_ZcvBvMXeMm578qsk" - } - ], - "isPrivate": false, - "metaSortKey": 2043.75, - "method": "GET", - "modified": 1559494976988, - "name": "Get All Groups", - "parameters": [], - "parentId": "fld_193320d04baf40e4a046d61def653114", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/api/groups", - "_type": "request" - }, - { - "_id": "req_821f6889760048c9b2ca2e5aae36bb49", - "authentication": {}, - "body": { - "mimeType": "application/json", - "text": "{\n\t\"password\":\"iamapassword\"\n}" - }, - "created": 1533135137877, - "description": "", - "headers": [ - { - "id": "pair_fef108d24296411eb539477de430d054", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJrYWZmZSIsImlzcyI6ImRpZ0lUIiwiaWF0IjoxNTQyMTI2MjQ2LCJleHAiOjE1NDQ3MTgyNDZ9.IuBuAZeTyYVHfc0_9pSR0rM76TDxrghyD385F2fqeKo" - }, - { - "id": "pair_89dad1bca6c24b21b3e04f3b1bfc7b0a", - "name": "Content-Type", - "value": "application/json" - } - ], - "isPrivate": false, - "metaSortKey": 2046.875, - "method": "PUT", - "modified": 1559494978281, - "name": "Admin Change Password", - "parameters": [], - "parentId": "fld_193320d04baf40e4a046d61def653114", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/admin/users/f126e2a5-bce2-40f5-aa7e-e5018cc5174e/change_password", - "_type": "request" - }, - { - "_id": "req_53f349ca1aaf4c78a6dc3825d827d10f", - "authentication": {}, - "body": {}, - "created": 1533217911410, - "description": "", - "headers": [ - { - "id": "pair_99ae6a5665ad4feb8e7720a74978b67f", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJlbmdzbXlyZSIsImlzcyI6ImRpZ0lUIiwiaWF0IjoxNTM1NTY1Nzg2LCJleHAiOjE1MzgxNTc3ODZ9.OfAUIFrzHOwtO1m5veAAkAHNoNOtSJYDvYlsYGfkoiw" - } - ], - "isPrivate": false, - "metaSortKey": 2037.5, - "method": "DELETE", - "modified": 1559494975547, - "name": "Delete User", - "parameters": [], - "parentId": "fld_193320d04baf40e4a046d61def653114", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/admin/users/d8f9cb87-760f-4dee-95c5-deaa7ca6c79b", - "_type": "request" - }, - { - "_id": "req_0396511938c04440948ad2265de9408a", - "authentication": {}, - "body": {}, - "created": 1533217939952, - "description": "", - "headers": [ - { - "id": "pair_07859151af8b44a18aecb23d4f8942f1", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODEiLCJleHAiOjE1NTMxOTYzNjcsImF1dGhvcml0aWVzIjpbImFkbWluIl0sImp0aSI6IjA4NzViMDlkLTFjNjAtNDU4NC1hMWM2LWRmOTViY2IxZTI0ZCIsImNsaWVudF9pZCI6IjdoQWRVRXRNbzRNZ0ZuQTdab1o0MW9oVGUxTk5Sb0ptakw2N0dmME5JcnJCbmF1eWhjIn0._UpKccV_CRKJplx0BczDEoKaz8mvN8aS8j5wXojQGLU" - } - ], - "isPrivate": false, - "metaSortKey": 2050, - "method": "GET", - "modified": 1559494971386, - "name": "Get All Users", - "parameters": [], - "parentId": "fld_193320d04baf40e4a046d61def653114", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/api/admin/users", - "_type": "request" - }, - { - "_id": "req_15157609a48a4af495d4d4cff12298f0", - "authentication": {}, - "body": {}, - "created": 1537660262984, - "description": "", - "headers": [ - { - "id": "pair_0b03c72524be4af6839e02ae2d585ef0", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODEiLCJleHAiOjE1NDkwNDE3NTQsImF1dGhvcml0aWVzIjpbImFkbWluIl0sImp0aSI6IjFhYjA2NWFhLTYzNmYtNGZkNy05ZTRkLTAwZTdiNDZkYzBkMyIsImNsaWVudF9pZCI6IjdoQWRVRXRNbzRNZ0ZuQTdab1o0MW9oVGUxTk5Sb0ptakw2N0dmME5JcnJCbmF1eWhjIn0.ZlV7JumIzb6LoYlUp4ch8-IxN_vQMOY1RLCPJPKqciA" - } - ], - "isPrivate": false, - "metaSortKey": 2100, - "method": "GET", - "modified": 1559494969848, - "name": "get users in group", - "parameters": [], - "parentId": "fld_193320d04baf40e4a046d61def653114", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/api/admin/groups/8323b76d-8daf-458b-956c-64ab67a90bbb/members", - "_type": "request" - }, - { - "_id": "req_e120facce79647f7bc5f9d540292dfd4", - "authentication": {}, - "body": { - "mimeType": "application/json", - "text": "{\n\t\"post\":\"e8a25cd7-4dfc-4cbd-b860-b2724aeacee4\",\n\t\"superGroup\":\"aa835d66-5a59-47c8-9d57-8b1594b08216\",\n\t\"authority\":\"9f01ead6-96ac-48ea-ae59-c1f6bf3a3658\"\n}\n" - }, - "created": 1541337434753, - "description": "", - "headers": [ - { - "id": "pair_392cb6ea1aba4a2b8a98ea90301ad038", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODEiLCJleHAiOjE1NTMyMDU4NjMsImF1dGhvcml0aWVzIjpbImFkbWluIl0sImp0aSI6ImE5MGVlZGJmLTFlNmMtNGNiMi1iZDQyLTFjMDFmM2RlMWY2MSIsImNsaWVudF9pZCI6IjdoQWRVRXRNbzRNZ0ZuQTdab1o0MW9oVGUxTk5Sb0ptakw2N0dmME5JcnJCbmF1eWhjIn0.vj3W6BsBHbSAkpD1J7LlfclGd-B2ibA6sxbXHXpQQsI" - }, - { - "id": "pair_2fce5db8ca114326817fff7c238b9933", - "name": "Content-Type", - "value": "application/json" - } - ], - "isPrivate": false, - "metaSortKey": 2025, - "method": "POST", - "modified": 1559494972809, - "name": "add authority", - "parameters": [], - "parentId": "fld_193320d04baf40e4a046d61def653114", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/api/admin/authority", - "_type": "request" - }, - { - "_id": "req_0fb3cb74867c49f69b4b937b2f6d5017", - "authentication": {}, - "body": {}, - "created": 1542128355017, - "description": "", - "headers": [ - { - "id": "pair_e9027d9d32304a3f934f2b68748e618d", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODEiLCJleHAiOjE1NTMyMDU4NjMsImF1dGhvcml0aWVzIjpbImFkbWluIl0sImp0aSI6ImE5MGVlZGJmLTFlNmMtNGNiMi1iZDQyLTFjMDFmM2RlMWY2MSIsImNsaWVudF9pZCI6IjdoQWRVRXRNbzRNZ0ZuQTdab1o0MW9oVGUxTk5Sb0ptakw2N0dmME5JcnJCbmF1eWhjIn0.vj3W6BsBHbSAkpD1J7LlfclGd-B2ibA6sxbXHXpQQsI" - } - ], - "isPrivate": false, - "metaSortKey": 1900, - "method": "GET", - "modified": 1559494969848, - "name": "get authorities", - "parameters": [], - "parentId": "fld_193320d04baf40e4a046d61def653114", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/api/admin/authority", - "_type": "request" - }, - { - "_id": "req_924b5b6af66441909ce0a21871a52416", - "authentication": {}, - "body": { - "mimeType": "application/json", - "text": "{\n\t\"authorityLevel\":\"digit\"\n}" - }, - "created": 1542132503128, - "description": "", - "headers": [ - { - "id": "pair_a532392d8da94145966face42753f047", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODEiLCJleHAiOjE1NTMyMDU4NjMsImF1dGhvcml0aWVzIjpbImFkbWluIl0sImp0aSI6ImE5MGVlZGJmLTFlNmMtNGNiMi1iZDQyLTFjMDFmM2RlMWY2MSIsImNsaWVudF9pZCI6IjdoQWRVRXRNbzRNZ0ZuQTdab1o0MW9oVGUxTk5Sb0ptakw2N0dmME5JcnJCbmF1eWhjIn0.vj3W6BsBHbSAkpD1J7LlfclGd-B2ibA6sxbXHXpQQsI" - }, - { - "id": "pair_a63febe739cf485bb531ffc46cb3f728", - "name": "Content-Type", - "value": "application/json" - } - ], - "isPrivate": false, - "metaSortKey": 1800, - "method": "POST", - "modified": 1559494969848, - "name": "add authority level", - "parameters": [], - "parentId": "fld_193320d04baf40e4a046d61def653114", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/api/admin/authority/level", - "_type": "request" - }, - { - "_id": "req_df4beb14b3c24cebb27289fb6a623e77", - "authentication": {}, - "body": {}, - "created": 1542286896964, - "description": "", - "headers": [ - { - "id": "pair_cc4267a2c0a14eaea4ffba4a8b34522a", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhZG1pbiIsImlzcyI6IkNUSElUIiwiaWF0IjoxNTQ0NzI1ODAzLCJleHAiOjE1NDczMTc4MDN9.jxp8DNGxNbnQtlWv4M9KdblOuYP8tra4azBelBvB57I" - } - ], - "isPrivate": false, - "metaSortKey": 1700, - "method": "GET", - "modified": 1559494969848, - "name": "get users with authority", - "parameters": [], - "parentId": "fld_193320d04baf40e4a046d61def653114", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/api/admin/authority/user_authorities/8b7bf45d-9955-4e8d-8c0b-8cb5758945d1", - "_type": "request" - }, - { - "_id": "req_536117c4f1c04051b30029b053c01c73", - "authentication": {}, - "body": {}, - "created": 1542304676565, - "description": "", - "headers": [ - { - "id": "pair_99de617c02464269ba9a7458b5f5c8dc", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJrYWZmZSIsImlzcyI6ImRpZ0lUIiwiaWF0IjoxNTQyMTI2MjQ2LCJleHAiOjE1NDQ3MTgyNDZ9.IuBuAZeTyYVHfc0_9pSR0rM76TDxrghyD385F2fqeKo" - } - ], - "isPrivate": false, - "metaSortKey": 1600, - "method": "DELETE", - "modified": 1559494969848, - "name": "remove authority level", - "parameters": [], - "parentId": "fld_193320d04baf40e4a046d61def653114", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/admin/authorization/level/b1796a29-748d-4861-864b-554cd65124c6", - "_type": "request" - }, - { - "_id": "req_5be09fd153994b79a6dff54ed8cabe67", - "authentication": {}, - "body": {}, - "created": 1542305876084, - "description": "", - "headers": [ - { - "id": "pair_3ed9f9e1ac34447389846b309a968628", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODEiLCJleHAiOjE1NDkwNDE3NTQsImF1dGhvcml0aWVzIjpbImFkbWluIl0sImp0aSI6IjFhYjA2NWFhLTYzNmYtNGZkNy05ZTRkLTAwZTdiNDZkYzBkMyIsImNsaWVudF9pZCI6IjdoQWRVRXRNbzRNZ0ZuQTdab1o0MW9oVGUxTk5Sb0ptakw2N0dmME5JcnJCbmF1eWhjIn0.ZlV7JumIzb6LoYlUp4ch8-IxN_vQMOY1RLCPJPKqciA" - } - ], - "isPrivate": false, - "metaSortKey": 1500, - "method": "GET", - "modified": 1559494969848, - "name": "get authority", - "parameters": [], - "parentId": "fld_193320d04baf40e4a046d61def653114", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/api/admin/authority/c6113d2c-2198-4474-a8c0-95b7e1ea4809", - "_type": "request" - }, - { - "_id": "req_8c2f7dfebae148e7904f00476cd98bb3", - "authentication": {}, - "body": {}, - "created": 1542316671243, - "description": "", - "headers": [ - { - "id": "pair_fea4e9f6cfc14db4b0d348aed56d4c87", - "name": "Authorization", - "value": "Bearer Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODEiLCJleHAiOjE1NTMyMDU4NjMsImF1dGhvcml0aWVzIjpbImFkbWluIl0sImp0aSI6ImE5MGVlZGJmLTFlNmMtNGNiMi1iZDQyLTFjMDFmM2RlMWY2MSIsImNsaWVudF9pZCI6IjdoQWRVRXRNbzRNZ0ZuQTdab1o0MW9oVGUxTk5Sb0ptakw2N0dmME5JcnJCbmF1eWhjIn0.vj3W6BsBHbSAkpD1J7LlfclGd-B2ibA6sxbXHXpQQsI" - } - ], - "isPrivate": false, - "metaSortKey": 2000, - "method": "GET", - "modified": 1559494969848, - "name": "Get Authority levels", - "parameters": [], - "parentId": "fld_193320d04baf40e4a046d61def653114", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/api/admin/authority/level", - "_type": "request" - }, - { - "_id": "req_0fa4532983794a2bad5c2e9b5d0ec63f", - "authentication": {}, - "body": {}, - "created": 1542372296191, - "description": "", - "headers": [ - { - "id": "pair_14c026d25bf04384a898e8785edc8e66", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJrYWZmZSIsImlzcyI6ImRpZ0lUIiwiaWF0IjoxNTQyMTI2MjQ2LCJleHAiOjE1NDQ3MTgyNDZ9.IuBuAZeTyYVHfc0_9pSR0rM76TDxrghyD385F2fqeKo" - } - ], - "isPrivate": false, - "metaSortKey": 1400, - "method": "DELETE", - "modified": 1559494969848, - "name": "remove authority", - "parameters": [], - "parentId": "fld_193320d04baf40e4a046d61def653114", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/admin/authorization/6c39a0af-53b4-4b57-b66f-df7c857b5fa2", - "_type": "request" - }, - { - "_id": "req_169a7efb913346a08424dcf05ebba0ce", - "authentication": {}, - "body": {}, - "created": 1544134429609, - "description": "", - "headers": [ - { - "id": "pair_3fe9a03d19c24bc3b26ce3b5ede003d2", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODEiLCJleHAiOjE1NTEzNzMzOTAsImF1dGhvcml0aWVzIjpbImFkbWluIl0sImp0aSI6IjEwZjllYWU5LWZjZmUtNDM0Yi1hYTVkLTlkMGRmZTVhNDU4MSIsImNsaWVudF9pZCI6IjdoQWRVRXRNbzRNZ0ZuQTdab1o0MW9oVGUxTk5Sb0ptakw2N0dmME5JcnJCbmF1eWhjIn0.EtpDpAzg9C0bygDhuHTi8dj9iUMYY9WZ6F7S4euJm6M" - } - ], - "isPrivate": false, - "metaSortKey": 1300, - "method": "GET", - "modified": 1559494969848, - "name": "Get All Super Groups", - "parameters": [], - "parentId": "fld_193320d04baf40e4a046d61def653114", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/api/superGroups", - "_type": "request" - }, - { - "_id": "req_9c3350848e754346b141684b42679c7d", - "authentication": { - "accessTokenUrl": "http://localhost:8081/api/oauth/token", - "authorizationUrl": "http://localhost:8081/api/oauth/authorize", - "clientId": "7hAdUEtMo4MgFnA7ZoZ41ohTe1NNRoJmjL67Gf0NIrrBnauyhc", - "clientSecret": "LBoxmzohQOSRCz99uBhS0IjLglxUOaLRXJxIC8iWuHTWYCLLqo", - "grantType": "authorization_code", - "redirectUrl": "http://localhost:3000/login", - "type": "oauth2" - }, - "body": {}, - "created": 1544207798182, - "description": "", - "headers": [ - { - "id": "pair_e7a0fb5fad7844d4bbd1b73ff1691e8f", - "name": "Content-Type", - "value": "application/json" - }, - { - "id": "pair_3573c2467b8a49688e3286f35092845f", - "name": "Authorization", - "value": "Bearer cb1e8cbf-df6e-46b6-b4d0-8075141fb6b7" - } - ], - "isPrivate": false, - "metaSortKey": 1100, - "method": "POST", - "modified": 1559494969848, - "name": "create oauth", - "parameters": [], - "parentId": "fld_193320d04baf40e4a046d61def653114", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/oauth/token", - "_type": "request" - }, - { - "_id": "req_06da1ecd4fd8492ab45f6f0a435e1bc1", - "authentication": { - "disabled": false, - "password": "password", - "type": "basic", - "username": "admin" - }, - "body": { - "mimeType": "", - "text": "" - }, - "created": 1544276623787, - "description": "", - "headers": [ - { - "id": "pair_6ac6bebf4c8a4963afcf2537b0fc8070", - "name": "Authorization", - "value": "Bearer cb1e8cbf-df6e-46b6-b4d0-8075141fb6b7" - } - ], - "isPrivate": false, - "metaSortKey": 1200, - "method": "GET", - "modified": 1559494969848, - "name": "oauth test", - "parameters": [], - "parentId": "fld_193320d04baf40e4a046d61def653114", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "http://localhost:8081/oauth/check_token", - "_type": "request" - }, - { - "_id": "req_fe96a3931fb246268bf4cf946ac776e7", - "authentication": {}, - "body": { - "mimeType": "application/json", - "text": "{\n\t\"name\":\"digit\",\n\t\"prettyName\":\"digIT\",\n\t\"type\":\"COMMITTEE\"\n}" - }, - "created": 1544729176801, - "description": "", - "headers": [ - { - "id": "pair_5aa51c48922e4e50a3d7b7a858c2e4f8", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODEiLCJleHAiOjE1NTMxOTYzNjcsImF1dGhvcml0aWVzIjpbImFkbWluIl0sImp0aSI6IjA4NzViMDlkLTFjNjAtNDU4NC1hMWM2LWRmOTViY2IxZTI0ZCIsImNsaWVudF9pZCI6IjdoQWRVRXRNbzRNZ0ZuQTdab1o0MW9oVGUxTk5Sb0ptakw2N0dmME5JcnJCbmF1eWhjIn0._UpKccV_CRKJplx0BczDEoKaz8mvN8aS8j5wXojQGLU" - }, - { - "id": "pair_c6fd5fe93a8b4409b1e514f89cedc376", - "name": "Content-Type", - "value": "application/json" - } - ], - "isPrivate": false, - "metaSortKey": 1000, - "method": "POST", - "modified": 1559494969848, - "name": "Add Super Group", - "parameters": [], - "parentId": "fld_193320d04baf40e4a046d61def653114", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/api/admin/superGroups", - "_type": "request" - }, - { - "_id": "req_ec2362e3db64455ca2226d2517de8faa", - "authentication": {}, - "body": { - "mimeType": "application/json", - "text": "{\n\t\"cid\":\"engsmre\",\n\t\"password\":\"password\",\n\t\"nick\":\"gurr\",\n\t\"firstName\":\"gustav\",\n\t\"email\":\"engsmyre@stud\",\n\t\"userAgreement\":true,\n\t\"acceptanceYear\":2016\n}" - }, - "created": 1544734651891, - "description": "", - "headers": [ - { - "id": "pair_74d57904834a4b30a72c2303d5f87da3", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODEiLCJleHAiOjE1NTQyMzYzNTgsImF1dGhvcml0aWVzIjpbImFkbWluIl0sImp0aSI6IjYyZjU3ZjA4LTVhOWItNGIzNC05NDM5LTVjNzZjM2Y5YTUzZSIsImNsaWVudF9pZCI6IjdoQWRVRXRNbzRNZ0ZuQTdab1o0MW9oVGUxTk5Sb0ptakw2N0dmME5JcnJCbmF1eWhjIn0.1UTI3W9aHuaHQZBA8EfNZr6HEfny7oHi8yYzoFrMMNE" - }, - { - "id": "pair_af297e80ec2c4d2fa378860180206b2a", - "name": "Content-Type", - "value": "application/json" - } - ], - "isPrivate": false, - "metaSortKey": 800, - "method": "POST", - "modified": 1559494969848, - "name": "Admin Add User", - "parameters": [], - "parentId": "fld_193320d04baf40e4a046d61def653114", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/api/admin/users", - "_type": "request" - }, - { - "_id": "req_72fb1a266d8a4b99871103678843802e", - "authentication": { - "grantType": "authorization_code", - "type": "oauth2" - }, - "body": { - "mimeType": "application/json", - "text": "{\n\t\"url_redirect\":\"http://localhost:8083/ui/login\",\n\t\"name\":\"tesdsfat\",\n\t\"description\":{\n\t\t\"sv\":\"an example application\",\n\t\t\"en\":\"ex\"\n\t}\n}" - }, - "created": 1545077397366, - "description": "", - "headers": [ - { - "id": "pair_3c9b81c64b9b40a0a5650f670d992dda", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODEiLCJleHAiOjE1NTEwMzUxNTMsImF1dGhvcml0aWVzIjpbImFkbWluIl0sImp0aSI6IjNhNWEyYzMxLTMyODQtNDAyMC05YzZhLWMwOTRlM2YyM2VmYiIsImNsaWVudF9pZCI6IjdoQWRVRXRNbzRNZ0ZuQTdab1o0MW9oVGUxTk5Sb0ptakw2N0dmME5JcnJCbmF1eWhjIn0.mAhpI7plWg2FyNhEz03BvuQ2oxIgzPckz-KHnht1gws" - }, - { - "id": "pair_035f8f80ec7d4f209d02028c43c30030", - "name": "Content-Type", - "value": "application/json" - } - ], - "isPrivate": false, - "metaSortKey": 900, - "method": "POST", - "modified": 1559494969848, - "name": "add client", - "parameters": [], - "parentId": "fld_193320d04baf40e4a046d61def653114", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/api/admin/clients", - "_type": "request" - }, - { - "_id": "req_f4afd7994d5448dbb0a2f05ac6e463c2", - "authentication": { - "grantType": "authorization_code", - "type": "oauth2" - }, - "body": {}, - "created": 1545749344611, - "description": "", - "headers": [ - { - "id": "pair_100895883e484e1795996cb39c538252", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODEiLCJleHAiOjE1NDk4Mzc3MjUsInVzZXJfbmFtZSI6ImVuZ3NteXJlIiwianRpIjoiNTI5MGNjNzYtMGY3My00MmYzLTkyNjItMjU2MTgwMmRiY2JjIiwiY2xpZW50X2lkIjoiN2hBZFVFdE1vNE1nRm5BN1pvWjQxb2hUZTFOTlJvSm1qTDY3R2YwTklyckJuYXV5aGMiLCJzY29wZSI6WyJyZWFkIiwid3JpdGUiXX0.ogh3TlB83bqEtqCKw1tMknTCuC2WQzaZPzkpx8AP0vY" - } - ], - "isPrivate": false, - "metaSortKey": 600, - "method": "GET", - "modified": 1559494969847, - "name": "Get Me", - "parameters": [], - "parentId": "fld_193320d04baf40e4a046d61def653114", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/api/users/me", - "_type": "request" - }, - { - "_id": "req_f591204bbed94df6b3be8b4895a80dad", - "authentication": {}, - "body": { - "mimeType": "application/json", - "text": "{\n\t\"unofficialName\":\"DevOps\"\n}" - }, - "created": 1546983675255, - "description": "", - "headers": [ - { - "id": "pair_8a42933965aa4c91a21402523b0981ac", - "name": "Content-Type", - "value": "application/json" - }, - { - "id": "pair_9672c9263cbf40f0bace752aeb8e477e", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODEiLCJleHAiOjE1NDkwNDE3NTQsImF1dGhvcml0aWVzIjpbImFkbWluIl0sImp0aSI6IjFhYjA2NWFhLTYzNmYtNGZkNy05ZTRkLTAwZTdiNDZkYzBkMyIsImNsaWVudF9pZCI6IjdoQWRVRXRNbzRNZ0ZuQTdab1o0MW9oVGUxTk5Sb0ptakw2N0dmME5JcnJCbmF1eWhjIn0.ZlV7JumIzb6LoYlUp4ch8-IxN_vQMOY1RLCPJPKqciA" - } - ], - "isPrivate": false, - "metaSortKey": 2200, - "method": "PUT", - "modified": 1559494969848, - "name": "Edit user in supergroup", - "parameters": [], - "parentId": "fld_193320d04baf40e4a046d61def653114", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/api/admin/groups/8323b76d-8daf-458b-956c-64ab67a90bbb/members/4b30f99f-39bd-4197-9089-04ae33c9ae92", - "_type": "request" - }, - { - "_id": "req_f4137a7f107b412590c52fef17859eca", - "authentication": {}, - "body": {}, - "created": 1546983997838, - "description": "", - "headers": [ - { - "id": "pair_ecf009def3c24dbdbc85cb3b5233685c", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODEiLCJleHAiOjE1NDkwNDE3NTQsImF1dGhvcml0aWVzIjpbImFkbWluIl0sImp0aSI6IjFhYjA2NWFhLTYzNmYtNGZkNy05ZTRkLTAwZTdiNDZkYzBkMyIsImNsaWVudF9pZCI6IjdoQWRVRXRNbzRNZ0ZuQTdab1o0MW9oVGUxTk5Sb0ptakw2N0dmME5JcnJCbmF1eWhjIn0.ZlV7JumIzb6LoYlUp4ch8-IxN_vQMOY1RLCPJPKqciA" - } - ], - "isPrivate": false, - "metaSortKey": 500, - "method": "DELETE", - "modified": 1559494969847, - "name": "Delete User In Group", - "parameters": [], - "parentId": "fld_193320d04baf40e4a046d61def653114", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/api/admin/groups/8323b76d-8daf-458b-956c-64ab67a90bbb/members/4b30f99f-39bd-4197-9089-04ae33c9ae92", - "_type": "request" - }, - { - "_id": "req_dad2f70cb94f437ab2637dac5d6a4ea3", - "authentication": {}, - "body": {}, - "created": 1546994824536, - "description": "", - "headers": [ - { - "id": "pair_ec34a296a8c5485d80982f7dc0f47e42", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODEiLCJleHAiOjE1NDkwNDE3NTQsImF1dGhvcml0aWVzIjpbImFkbWluIl0sImp0aSI6IjFhYjA2NWFhLTYzNmYtNGZkNy05ZTRkLTAwZTdiNDZkYzBkMyIsImNsaWVudF9pZCI6IjdoQWRVRXRNbzRNZ0ZuQTdab1o0MW9oVGUxTk5Sb0ptakw2N0dmME5JcnJCbmF1eWhjIn0.ZlV7JumIzb6LoYlUp4ch8-IxN_vQMOY1RLCPJPKqciA" - } - ], - "isPrivate": false, - "metaSortKey": 700, - "method": "GET", - "modified": 1559494969848, - "name": "Get groups by supergroup", - "parameters": [], - "parentId": "fld_193320d04baf40e4a046d61def653114", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "l§ocalhost:8081/api/admin/superGroups/bfff0a19-3d5f-46af-a5d5-e4bd5949b368/subgroups", - "_type": "request" - }, - { - "_id": "req_5eac49b7a44a45529c14b002e4860729", - "authentication": { - "grantType": "authorization_code", - "type": "oauth2" - }, - "body": { - "mimeType": "application/json", - "text": "{\n\t\"firstName\":\"Big G\"\n}" - }, - "created": 1547245639816, - "description": "", - "headers": [ - { - "id": "pair_10f70e5c56c442ee8b4bebf99b784f32", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODEiLCJleHAiOjE1NDk4Mzc3MjUsInVzZXJfbmFtZSI6ImVuZ3NteXJlIiwianRpIjoiNTI5MGNjNzYtMGY3My00MmYzLTkyNjItMjU2MTgwMmRiY2JjIiwiY2xpZW50X2lkIjoiN2hBZFVFdE1vNE1nRm5BN1pvWjQxb2hUZTFOTlJvSm1qTDY3R2YwTklyckJuYXV5aGMiLCJzY29wZSI6WyJyZWFkIiwid3JpdGUiXX0.ogh3TlB83bqEtqCKw1tMknTCuC2WQzaZPzkpx8AP0vY" - }, - { - "id": "pair_b895185360304a09b86adfdc71a2cd9a", - "name": "Content-Type", - "value": "application/json" - } - ], - "isPrivate": false, - "metaSortKey": 300, - "method": "PUT", - "modified": 1559494969847, - "name": "edit me", - "parameters": [], - "parentId": "fld_193320d04baf40e4a046d61def653114", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/api/users/me", - "_type": "request" - }, - { - "_id": "req_62af0d2bf3c04e9a995867b189e9a8a4", - "authentication": {}, - "body": { - "mimeType": "application/json", - "text": "{\n\t\"description\":\n\t{\n\t\t\"sv\":\"admi\",\n\t\t\"en\":\"admin\"\n\t}\n}" - }, - "created": 1547329280673, - "description": "", - "headers": [ - { - "id": "pair_489b2383773a43a9b7d4c94b1d6f04ca", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJlbmdzbXlyZSIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODEiLCJleHAiOjE1NTMyMTE3OTQsImF1dGhvcml0aWVzIjpbImRpZ2l0Il0sImp0aSI6Ijc5NGZjNzQxLTQ1ZDctNDUyMy1hMzMwLWFjNGMzYTZiNTljMCIsImNsaWVudF9pZCI6IjdoQWRVRXRNbzRNZ0ZuQTdab1o0MW9oVGUxTk5Sb0ptakw2N0dmME5JcnJCbmF1eWhjIn0.32rECcJ-AXC1eclP2z0tvVfvRasrQn0XwcvQwY4PXco" - }, - { - "id": "pair_b014cb2281af4d7dad0c6b3e35b64fa9", - "name": "Content-Type", - "value": "application/json" - } - ], - "isPrivate": false, - "metaSortKey": 2300, - "method": "PUT", - "modified": 1559494969848, - "name": "Edit Group", - "parameters": [], - "parentId": "fld_193320d04baf40e4a046d61def653114", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/api/admin/groups/7aa80b2d-4ed2-465d-ba22-6503b8a396c7", - "_type": "request" - }, - { - "_id": "req_6f7d6424b51b49f3ab52f5e0bb388718", - "authentication": {}, - "body": {}, - "created": 1549534045357, - "description": "", - "headers": [ - { - "id": "pair_924ef95ad9a4466eb86482bb870f72e2", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODEiLCJleHAiOjE1NTIxNDUxOTcsImF1dGhvcml0aWVzIjpbImFkbWluIl0sImp0aSI6IjNkZDNiYzFkLTk4MWEtNDQwYy05N2FjLWQ5OTJkZjJmYzIwOSIsImNsaWVudF9pZCI6IjdoQWRVRXRNbzRNZ0ZuQTdab1o0MW9oVGUxTk5Sb0ptakw2N0dmME5JcnJCbmF1eWhjIn0.gXILm0CCeLOOa_-yh0_Tw4WaoC_ZcvBvMXeMm578qsk" - } - ], - "isPrivate": false, - "metaSortKey": 400, - "method": "GET", - "modified": 1559494969847, - "name": "get active group", - "parameters": [], - "parentId": "fld_193320d04baf40e4a046d61def653114", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/api/superGroups/40180559-e281-46f6-a2d1-3a63ffd18433/active", - "_type": "request" - }, - { - "_id": "req_ee292e3809104fc78160e93907d7aa4e", - "authentication": {}, - "body": {}, - "created": 1549555983662, - "description": "", - "headers": [ - { - "id": "pair_03598fd7b43b43798220e845dcb0636d", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODEiLCJleHAiOjE1NTIxNDUxOTcsImF1dGhvcml0aWVzIjpbImFkbWluIl0sImp0aSI6IjNkZDNiYzFkLTk4MWEtNDQwYy05N2FjLWQ5OTJkZjJmYzIwOSIsImNsaWVudF9pZCI6IjdoQWRVRXRNbzRNZ0ZuQTdab1o0MW9oVGUxTk5Sb0ptakw2N0dmME5JcnJCbmF1eWhjIn0.gXILm0CCeLOOa_-yh0_Tw4WaoC_ZcvBvMXeMm578qsk" - } - ], - "isPrivate": false, - "metaSortKey": 2400, - "method": "GET", - "modified": 1559494969848, - "name": "Get active groups", - "parameters": [], - "parentId": "fld_193320d04baf40e4a046d61def653114", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/api/groups/active", - "_type": "request" - }, - { - "_id": "req_dad584a9d98c4a1c810daba2675bfcf9", - "authentication": {}, - "body": { - "mimeType": "multipart/form-data", - "params": [ - { - "fileName": "/home/gurr/Desktop/images/Arch.png", - "id": "pair_2dea10919523464a8a6a61065e96816e", - "name": "file", - "type": "file", - "value": "" - } - ] - }, - "created": 1550013774953, - "description": "", - "headers": [ - { - "id": "pair_08114df83d314db68758924589affb30", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODEiLCJleHAiOjE1NTIxNDUxOTcsImF1dGhvcml0aWVzIjpbImFkbWluIl0sImp0aSI6IjNkZDNiYzFkLTk4MWEtNDQwYy05N2FjLWQ5OTJkZjJmYzIwOSIsImNsaWVudF9pZCI6IjdoQWRVRXRNbzRNZ0ZuQTdab1o0MW9oVGUxTk5Sb0ptakw2N0dmME5JcnJCbmF1eWhjIn0.gXILm0CCeLOOa_-yh0_Tw4WaoC_ZcvBvMXeMm578qsk" - }, - { - "id": "pair_dd5a31b0aef143e1a166bae7b3c014c8", - "name": "Content-Type", - "value": "multipart/form-data" - } - ], - "isPrivate": false, - "metaSortKey": 200, - "method": "PUT", - "modified": 1559494969847, - "name": "add imaeg", - "parameters": [], - "parentId": "fld_193320d04baf40e4a046d61def653114", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/api/users/me/avatar", - "_type": "request" - }, - { - "_id": "req_01485baed266407e9308c93aa996226d", - "authentication": {}, - "body": { - "mimeType": "multipart/form-data", - "params": [ - { - "fileName": "/home/gurr/trains_fine.png", - "id": "pair_ac79ce95b4264c57b4813d8438c30dc3", - "name": "file", - "type": "file", - "value": "" - } - ] - }, - "created": 1550018598013, - "description": "", - "headers": [ - { - "id": "pair_74cc8db7570e4f4482de102270ec21f8", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODEiLCJleHAiOjE1NTIxNDUxOTcsImF1dGhvcml0aWVzIjpbImFkbWluIl0sImp0aSI6IjNkZDNiYzFkLTk4MWEtNDQwYy05N2FjLWQ5OTJkZjJmYzIwOSIsImNsaWVudF9pZCI6IjdoQWRVRXRNbzRNZ0ZuQTdab1o0MW9oVGUxTk5Sb0ptakw2N0dmME5JcnJCbmF1eWhjIn0.gXILm0CCeLOOa_-yh0_Tw4WaoC_ZcvBvMXeMm578qsk" - }, - { - "id": "pair_e2ee946f065446a4860efd63ffe68ec7", - "name": "Content-Type", - "value": "multipart/form-data" - } - ], - "isPrivate": false, - "metaSortKey": 0, - "method": "PUT", - "modified": 1559494969847, - "name": "add group image", - "parameters": [], - "parentId": "fld_193320d04baf40e4a046d61def653114", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/api/admin/groups/52f5580c-937e-410d-b9e5-6e8e44328d94/avatar", - "_type": "request" - }, - { - "_id": "req_bb058bb09d17460e8edcd108972f80d7", - "authentication": {}, - "body": {}, - "created": 1553943409542, - "description": "", - "headers": [], - "isPrivate": false, - "metaSortKey": 100, - "method": "POST", - "modified": 1559494969847, - "name": "Jwt", - "parameters": [], - "parentId": "fld_193320d04baf40e4a046d61def653114", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "http://localhost:9090/oauth/token", - "_type": "request" - }, - { - "_id": "req_650c624e47dc4d849c69950f2552d1ad", - "authentication": {}, - "body": { - "mimeType": "application/json", - "text": "{\n\t\"cid\":\"engsmyre\",\n\t\"password\":\"password\"\n}" - }, - "created": 1559495029965, - "description": "", - "headers": [ - { - "id": "pair_f1c12844a5584bc2a3e9ab5a71693afc", - "name": "Content-Type", - "value": "application/json" - } - ], - "isPrivate": false, - "metaSortKey": 2295.99609375, - "method": "POST", - "modified": 1559495054467, - "name": "login", - "parameters": [], - "parentId": "fld_193320d04baf40e4a046d61def653114", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/api/users/login", - "_type": "request" - }, - { - "_id": "req_5105de88f4044472b16c44740b835a48", - "authentication": {}, - "body": { - "mimeType": "application/json", - "text": "{\n\t\"cids\":[\n\t\t\"engsmyre\"\n\t\t]\n}" - }, - "created": 1559495101490, - "description": "", - "headers": [ - { - "id": "pair_fd8a2baa477a4c1fbf75f84711306afd", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhZG1pbiIsImlzcyI6IkNUSElUIiwiaWF0IjoxNTQzNjcyMjE2LCJleHAiOjE1NDYyNjQyMTZ9.fJ8zGWLjUF7vjKyH3Lr4vFQPJa6AW5xadZQobh7IUKY" - }, - { - "id": "pair_8be41d4ac33640978efbd8f70d248be2", - "name": "Content-Type", - "value": "application/json" - } - ], - "isPrivate": false, - "metaSortKey": 2296.58203125, - "method": "POST", - "modified": 1559495101490, - "name": "Create Whitelist", - "parameters": [], - "parentId": "fld_c846f7fe3dad4f209e047c857d24e546", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/admin/users/whitelist", - "_type": "request" - }, - { - "_id": "req_86af53f83be5476b8f4df56520c282ba", - "authentication": {}, - "body": { - "mimeType": "application/json", - "text": "{\n\t\"code\":\"UMANATISRR\",\n\t\"password\":\"password123\",\n\t\"nick\":\"coffe\",\n\t\"acceptanceYear\":\"2017\",\n\t\"whitelist\":{\n\t\t\t\"cid\":\"kaffe\"\n\t}\n}" - }, - "created": 1559495101496, - "description": "", - "headers": [ - { - "id": "pair_6e5102b055ee4d7fb9cf13a297ebb353", - "name": "Content-Type", - "value": "application/json" - } - ], - "isPrivate": false, - "metaSortKey": 2296.6796875, - "method": "POST", - "modified": 1559495101496, - "name": "create account", - "parameters": [], - "parentId": "fld_c846f7fe3dad4f209e047c857d24e546", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/users/create", - "_type": "request" - }, - { - "_id": "req_e792e197540845e3af7c5f0af9a3ca0a", - "authentication": {}, - "body": { - "mimeType": "application/json", - "text": "{\n\t\"cid\":\"engsmyre\"\n}" - }, - "created": 1559495101499, - "description": "", - "headers": [ - { - "id": "pair_ff59990f14e8420aa87642d8c49434ae", - "name": "Content-Type", - "value": "application/json" - } - ], - "isPrivate": false, - "metaSortKey": 2296.484375, - "method": "POST", - "modified": 1559495101499, - "name": "Create Code", - "parameters": [], - "parentId": "fld_c846f7fe3dad4f209e047c857d24e546", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/whitelist/activate_cid", - "_type": "request" - }, - { - "_id": "req_9bd062813c9942cba9fac592c2eba336", - "authentication": { - "type": "bearer" - }, - "body": {}, - "created": 1559495101501, - "description": "", - "headers": [ - { - "id": "pair_c9d82714b2394a9f9298797acb9df41a", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODEiLCJleHAiOjE1NTMxOTYzNjcsImF1dGhvcml0aWVzIjpbImFkbWluIl0sImp0aSI6IjA4NzViMDlkLTFjNjAtNDU4NC1hMWM2LWRmOTViY2IxZTI0ZCIsImNsaWVudF9pZCI6IjdoQWRVRXRNbzRNZ0ZuQTdab1o0MW9oVGUxTk5Sb0ptakw2N0dmME5JcnJCbmF1eWhjIn0._UpKccV_CRKJplx0BczDEoKaz8mvN8aS8j5wXojQGLU" - } - ], - "isPrivate": false, - "metaSortKey": 2295.8984375, - "method": "GET", - "modified": 1559495101501, - "name": "get Post", - "parameters": [], - "parentId": "fld_c846f7fe3dad4f209e047c857d24e546", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/api/admin/groups/posts", - "_type": "request" - }, - { - "_id": "req_d8985fb0404d4ec1b929272486de8321", - "authentication": {}, - "body": {}, - "created": 1559495101503, - "description": "", - "headers": [ - { - "id": "pair_74be68e6da4b43b998c633f0090eaf3a", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODEiLCJleHAiOjE1NTEwMzUxNTMsImF1dGhvcml0aWVzIjpbImFkbWluIl0sImp0aSI6IjNhNWEyYzMxLTMyODQtNDAyMC05YzZhLWMwOTRlM2YyM2VmYiIsImNsaWVudF9pZCI6IjdoQWRVRXRNbzRNZ0ZuQTdab1o0MW9oVGUxTk5Sb0ptakw2N0dmME5JcnJCbmF1eWhjIn0.mAhpI7plWg2FyNhEz03BvuQ2oxIgzPckz-KHnht1gws" - } - ], - "isPrivate": false, - "metaSortKey": 2295.703125, - "method": "GET", - "modified": 1559495101503, - "name": "get Minified", - "parameters": [], - "parentId": "fld_c846f7fe3dad4f209e047c857d24e546", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/api/users/minified", - "_type": "request" - }, - { - "_id": "req_e1f3f54f4fa04a0baad4bf27c2cfd715", - "authentication": {}, - "body": { - "mimeType": "application/json", - "text": "{\n\t\"post\":\n\t{\n\t\t\"sv\":\"ledamot\",\n\t\t\"en\":\"ledamot\"\n\t}\n}" - }, - "created": 1559495101507, - "description": "", - "headers": [ - { - "id": "pair_899d7e4fb6984310bd6d2d4a3ed66f28", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODEiLCJleHAiOjE1NTMxOTYzNjcsImF1dGhvcml0aWVzIjpbImFkbWluIl0sImp0aSI6IjA4NzViMDlkLTFjNjAtNDU4NC1hMWM2LWRmOTViY2IxZTI0ZCIsImNsaWVudF9pZCI6IjdoQWRVRXRNbzRNZ0ZuQTdab1o0MW9oVGUxTk5Sb0ptakw2N0dmME5JcnJCbmF1eWhjIn0._UpKccV_CRKJplx0BczDEoKaz8mvN8aS8j5wXojQGLU" - }, - { - "id": "pair_3576d565efe24065815d70b7ed67edbc", - "name": "Content-Type", - "value": "application/json" - } - ], - "isPrivate": false, - "metaSortKey": 2296.09375, - "method": "POST", - "modified": 1559495101507, - "name": "add post", - "parameters": [], - "parentId": "fld_c846f7fe3dad4f209e047c857d24e546", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/api/admin/groups/posts", - "_type": "request" - }, - { - "_id": "req_c53102a021c844f9af07a93f7a576e52", - "authentication": {}, - "body": {}, - "created": 1559495101510, - "description": "", - "headers": [ - { - "id": "pair_8bb4a52708bb49c7abcddc4d18b06932", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODEiLCJleHAiOjE1NDkwNDE3NTQsImF1dGhvcml0aWVzIjpbImFkbWluIl0sImp0aSI6IjFhYjA2NWFhLTYzNmYtNGZkNy05ZTRkLTAwZTdiNDZkYzBkMyIsImNsaWVudF9pZCI6IjdoQWRVRXRNbzRNZ0ZuQTdab1o0MW9oVGUxTk5Sb0ptakw2N0dmME5JcnJCbmF1eWhjIn0.ZlV7JumIzb6LoYlUp4ch8-IxN_vQMOY1RLCPJPKqciA" - } - ], - "isPrivate": false, - "metaSortKey": 2294.53125, - "method": "GET", - "modified": 1559495101510, - "name": "get user", - "parameters": [], - "parentId": "fld_c846f7fe3dad4f209e047c857d24e546", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/api/users/4b30f99f-39bd-4197-9089-04ae33c9ae92", - "_type": "request" - }, - { - "_id": "req_9a6b02a4860f4658a59775ddf0da419f", - "authentication": {}, - "body": { - "mimeType": "application/json", - "text": "{\n\t\"name\": \"digit18\",\n\t\"prettyName\":\"ldap\",\n\t\"email\": \"digit@chalmers.it\",\n\t\"superGroup\":\"aa835d66-5a59-47c8-9d57-8b1594b08216\",\n\t\"func\": {\n\t\t\"sv\": \"being gods\",\n\t\t\"en\": \"god\"\n\t},\n\t\"websites\": [\n\t\t{\n\t\t\t\"website\": \"186c262d-e5fd-41c5-b681-bba594919a36\",\n\t\t\t\"url\": \"facebook.com/helloworl\"\n\t\t},\n\t\t{\n\t\t\t\"website\": \"186c262d-e5fd-41c5-b681-bba594919a36\",\n\t\t\t\"url\": \"facebook.com/sdfkl\"\n\t\t}\n\t],\n\t\"type\": \"COMMITTEE\",\n\t\"year\":2018,\n\t\"becomesActive\":\"2018-03-17\",\n\t\"becomesInactive\":\"2019-05-01\"\n}" - }, - "created": 1559495101514, - "description": "", - "headers": [ - { - "id": "pair_a1e5825c515e4287b36a4dc9747bdb55", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODEiLCJleHAiOjE1NTMxOTYzNjcsImF1dGhvcml0aWVzIjpbImFkbWluIl0sImp0aSI6IjA4NzViMDlkLTFjNjAtNDU4NC1hMWM2LWRmOTViY2IxZTI0ZCIsImNsaWVudF9pZCI6IjdoQWRVRXRNbzRNZ0ZuQTdab1o0MW9oVGUxTk5Sb0ptakw2N0dmME5JcnJCbmF1eWhjIn0._UpKccV_CRKJplx0BczDEoKaz8mvN8aS8j5wXojQGLU" - }, - { - "id": "pair_d822b7fe2f42443d899ce8aff9937bf4", - "name": "Content-Type", - "value": "application/json" - } - ], - "isPrivate": false, - "metaSortKey": 2295.3125, - "method": "POST", - "modified": 1559495101514, - "name": "add group", - "parameters": [], - "parentId": "fld_c846f7fe3dad4f209e047c857d24e546", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/api/admin/groups", - "_type": "request" - }, - { - "_id": "req_85a5f63a020e4e8692a59cceb84dce80", - "authentication": {}, - "body": { - "mimeType": "application/json", - "text": "{\n\t\"prettyName\":\"leffe\",\n\t\"email\": \"digit@chalmers.it\",\n\t\"function\": {\n\t\t\"sv\": \"rustmästeri\",\n\t\t\"en\": \"\"\n\t},\n\t\"websites\": [\n\t\t{\n\t\t\t\"website\": \"facebook\",\n\t\t\t\"url\": \"2\"\n\t\t}\n],\n\"groupType\": \"COMMITTEE\"\n}" - }, - "created": 1559495101517, - "description": "", - "headers": [ - { - "id": "pair_466cab8cd5c14c0e82dfc58146a76b6a", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJlbmdzbXlyZSIsImlzcyI6ImRpZ0lUIiwiaWF0IjoxNTMyNDM2MzA5LCJleHAiOjE1MzUwMjgzMDl9.mvV65rFj8wFANLJrgQwrUDPq70gW0ulcjCtbjzUfV9E" - }, - { - "id": "pair_5690ed6b8bb7463e91d3e7ed05c70ba5", - "name": "Content-Type", - "value": "application/json" - } - ], - "isPrivate": false, - "metaSortKey": 2296.875, - "method": "PUT", - "modified": 1559495101517, - "name": "edit group", - "parameters": [], - "parentId": "fld_c846f7fe3dad4f209e047c857d24e546", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/admin/groups/334d7158-0a99-4e1b-8598-a44d5b6cbfe4", - "_type": "request" - }, - { - "_id": "req_31e16d0eea9f45c3b71fba5335616a5b", - "authentication": {}, - "body": { - "mimeType": "application/json", - "text": "{\n\t\"websites\": [\n\t\t{\n\t\t\t\"website\": \"facebook\",\n\t\t\t\"url\": \"facebook.com/gustavengsmyre\"\n\t\t},\n\t\t{\n\t\t\t\"website\": \"facebook\",\n\t\t\t\"url\": \"facebook.com/facebook\"\n\t\t},\n\t\t\t\t{\n\t\t\t\"website\": \"facebook\",\n\t\t\t\"url\": \"facebook.com/portalssuger\"\n\t\t}\n\t]\n}" - }, - "created": 1559495101519, - "description": "", - "headers": [ - { - "id": "pair_9b58efc9843e44219001a2c9ad8b8c61", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJlbmdzbXlyZSIsImlzcyI6ImRpZ0lUIiwiaWF0IjoxNTMyNTE3ODQzLCJleHAiOjE1MzUxMDk4NDN9.X4FnNL2QlxkZMSAlRL2uAypU5CEB1iPyVbwKpvdQZG0" - }, - { - "id": "pair_9414e2d6b0a94b9083ae2998d7c4a896", - "name": "Content-Type", - "value": "application/json" - } - ], - "isPrivate": false, - "metaSortKey": 2293.75, - "method": "PUT", - "modified": 1559495101519, - "name": "Edit user", - "parameters": [], - "parentId": "fld_c846f7fe3dad4f209e047c857d24e546", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/admin/users/d8f9cb87-760f-4dee-95c5-deaa7ca6c79b", - "_type": "request" - }, - { - "_id": "req_ae21636bf4c04b259ff63c3eaf0dc48d", - "authentication": {}, - "body": { - "mimeType": "application/json", - "text": "{\n\t\"cid\":\"engsmyre\"\n}" - }, - "created": 1559495101526, - "description": "", - "headers": [ - { - "id": "pair_a01a15041b864f4fba44117515ccdb03", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJlbmdzbXlyZSIsImlzcyI6ImRpZ0lUIiwiaWF0IjoxNTMyNTIwMzYwLCJleHAiOjE1MzUxMTIzNjB9.AcR7JlrE2NJc83OrY9S9eNQPIfRfSFJIpitZEiml1w0" - }, - { - "id": "pair_ffd533bec58f4e8383ad3b1dd81661f9", - "name": "Content-Type", - "value": "application/json" - } - ], - "isPrivate": false, - "metaSortKey": 2287.5, - "method": "PUT", - "modified": 1559495101526, - "name": "edit whitelisted", - "parameters": [], - "parentId": "fld_c846f7fe3dad4f209e047c857d24e546", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/admin/users/whitelist/4a141001-78c5-4e6e-9c8e-c125d08beb38", - "_type": "request" - }, - { - "_id": "req_6bd093a60fee4da784de8160420c4565", - "authentication": {}, - "body": {}, - "created": 1559495101529, - "description": "", - "headers": [ - { - "id": "pair_d3a3781902764b9b90eb80c9439edb24", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJlbmdzbXlyZSIsImlzcyI6ImRpZ0lUIiwiaWF0IjoxNTM1NTY1Nzg2LCJleHAiOjE1MzgxNTc3ODZ9.OfAUIFrzHOwtO1m5veAAkAHNoNOtSJYDvYlsYGfkoiw" - }, - { - "id": "pair_0430e809374d4acc8efa95dc0ff73363", - "name": "", - "value": "" - } - ], - "isPrivate": false, - "metaSortKey": 2275, - "method": "GET", - "modified": 1559495101529, - "name": "get whitelist", - "parameters": [], - "parentId": "fld_c846f7fe3dad4f209e047c857d24e546", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/admin/users/whitelist", - "_type": "request" - }, - { - "_id": "req_c08dc7ee49394151bff5c5d6fc4ed366", - "authentication": {}, - "body": {}, - "created": 1559495101531, - "description": "", - "headers": [ - { - "id": "pair_63a4b81c74d34492b52c4a3ca549ef30", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJlbmdzbXlyZSIsImlzcyI6ImRpZ0lUIiwiaWF0IjoxNTMyNTIwMzYwLCJleHAiOjE1MzUxMTIzNjB9.AcR7JlrE2NJc83OrY9S9eNQPIfRfSFJIpitZEiml1w0" - } - ], - "isPrivate": false, - "metaSortKey": 2249.609375, - "method": "DELETE", - "modified": 1559495101531, - "name": "delete whitelist", - "parameters": [], - "parentId": "fld_c846f7fe3dad4f209e047c857d24e546", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/admin/users/whitelist/4a141001-78c5-4e6e-9c8e-c125d08beb38", - "_type": "request" - }, - { - "_id": "req_5a9a919f073842669bc912284cde7264", - "authentication": {}, - "body": { - "mimeType": "application/json", - "text": "{\n\t\"post\":{\n\t\"sv\":\"master\"\t\n\t}\n}" - }, - "created": 1559495101533, - "description": "", - "headers": [ - { - "id": "pair_42e9e4511cae48c78ac2e7bbf11cdde9", - "name": "Content-Type", - "value": "application/json" - }, - { - "id": "pair_70555760ea5041ad906da475b6cdeb9a", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJlbmdzbXlyZSIsImlzcyI6ImRpZ0lUIiwiaWF0IjoxNTMyNjEwNTgwLCJleHAiOjE1MzUyMDI1ODB9.hOJPhObU0BQtFv0vnWcKmdpFtijl9-St3fsu5nWd0Vc" - } - ], - "isPrivate": false, - "metaSortKey": 2245.3125, - "method": "PUT", - "modified": 1559495101533, - "name": "Edit post", - "parameters": [], - "parentId": "fld_c846f7fe3dad4f209e047c857d24e546", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/admin/groups/posts/88e1708f-2462-435e-a70f-2ff1006b2866", - "_type": "request" - }, - { - "_id": "req_c7d7dcbdc9f74a69a38d801d437c8688", - "authentication": {}, - "body": { - "mimeType": "application/json", - "text": "{\n\t\"name\":\"facebook\",\n\t\"prettyName\":\"facebook\"\n}" - }, - "created": 1559495101534, - "description": "", - "headers": [ - { - "id": "pair_505a0928654a4dbfade0ba2c8640ea8e", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODEiLCJleHAiOjE1NTMxOTYzNjcsImF1dGhvcml0aWVzIjpbImFkbWluIl0sImp0aSI6IjA4NzViMDlkLTFjNjAtNDU4NC1hMWM2LWRmOTViY2IxZTI0ZCIsImNsaWVudF9pZCI6IjdoQWRVRXRNbzRNZ0ZuQTdab1o0MW9oVGUxTk5Sb0ptakw2N0dmME5JcnJCbmF1eWhjIn0._UpKccV_CRKJplx0BczDEoKaz8mvN8aS8j5wXojQGLU" - }, - { - "id": "pair_5c3eaac167884d72b5d924bb519ba443", - "name": "Content-Type", - "value": "application/json" - } - ], - "isPrivate": false, - "metaSortKey": 2249.21875, - "method": "POST", - "modified": 1559495101534, - "name": "Create Website", - "parameters": [], - "parentId": "fld_c846f7fe3dad4f209e047c857d24e546", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/api/admin/websites", - "_type": "request" - }, - { - "_id": "req_eea8eaffeccd42a8993fcf4322550de3", - "authentication": {}, - "body": {}, - "created": 1559495101536, - "description": "", - "headers": [ - { - "id": "pair_fa5d062cda0a4cad9c7f18cb1e547c61", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODEiLCJleHAiOjE1NTMxOTYzNjcsImF1dGhvcml0aWVzIjpbImFkbWluIl0sImp0aSI6IjA4NzViMDlkLTFjNjAtNDU4NC1hMWM2LWRmOTViY2IxZTI0ZCIsImNsaWVudF9pZCI6IjdoQWRVRXRNbzRNZ0ZuQTdab1o0MW9oVGUxTk5Sb0ptakw2N0dmME5JcnJCbmF1eWhjIn0._UpKccV_CRKJplx0BczDEoKaz8mvN8aS8j5wXojQGLU" - } - ], - "isPrivate": false, - "metaSortKey": 2247.65625, - "method": "GET", - "modified": 1559495101536, - "name": "Get Websites", - "parameters": [], - "parentId": "fld_c846f7fe3dad4f209e047c857d24e546", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/api/admin/websites", - "_type": "request" - }, - { - "_id": "req_58e3f635381e496f990dd4796b33a509", - "authentication": {}, - "body": {}, - "created": 1559495101540, - "description": "", - "headers": [ - { - "id": "pair_fb9f508e07ae4f569c61eb2e9ea09977", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJrYWZmZSIsImlzcyI6ImRpZ0lUIiwiaWF0IjoxNTM5MTgxNTAzLCJleHAiOjE1NDE3NzM1MDN9.B_Uqy9P3ING6_Ull_kIXgs8WfDByW0GgkaL0NUIkJfw" - } - ], - "isPrivate": false, - "metaSortKey": 2248.4375, - "method": "GET", - "modified": 1559495101540, - "name": "Get Website", - "parameters": [], - "parentId": "fld_c846f7fe3dad4f209e047c857d24e546", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/admin/websites/b624d762-754d-4c0b-9e48-6dcb3cdc955a", - "_type": "request" - }, - { - "_id": "req_7375729b58cc42e6b62e770722e03827", - "authentication": {}, - "body": { - "mimeType": "application/json", - "text": "{\n\t\"website\":\"Facebook\"\n}" - }, - "created": 1559495101543, - "description": "", - "headers": [ - { - "id": "pair_240d8a87af8c491da7b75ee7720f6409", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJlbmdzbXlyZSIsImlzcyI6ImRpZ0lUIiwiaWF0IjoxNTMyNjg1NTIzLCJleHAiOjE1MzUyNzc1MjN9.g4YwfNjoBPhfgZI98zaXn7z3CcJMgxapMu_4HThSilw" - }, - { - "id": "pair_e8c7f441d7c64000812353202e06231f", - "name": "Content-Type", - "value": "application/json" - } - ], - "isPrivate": false, - "metaSortKey": 2246.875, - "method": "PUT", - "modified": 1559495101543, - "name": "Edit Website", - "parameters": [], - "parentId": "fld_c846f7fe3dad4f209e047c857d24e546", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/admin/websites/c5ea640a-c566-4dfe-a03d-85a20beaf74c", - "_type": "request" - }, - { - "_id": "req_a18aac0e9a724245b95587368902a1f1", - "authentication": {}, - "body": { - "mimeType": "application/json", - "text": "" - }, - "created": 1559495101546, - "description": "", - "headers": [ - { - "id": "pair_1bbc30a665ae419fb25f5f69561135f2", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJlbmdzbXlyZSIsImlzcyI6ImRpZ0lUIiwiaWF0IjoxNTMyNjg1NTIzLCJleHAiOjE1MzUyNzc1MjN9.g4YwfNjoBPhfgZI98zaXn7z3CcJMgxapMu_4HThSilw" - }, - { - "id": "pair_93f8c8db9cea4203b3a1e88a7ef3d21e", - "name": "Content-Type", - "value": "application/json" - } - ], - "isPrivate": false, - "metaSortKey": 2243.75, - "method": "DELETE", - "modified": 1559495101546, - "name": "Delete Website", - "parameters": [], - "parentId": "fld_c846f7fe3dad4f209e047c857d24e546", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/admin/websites/6b0a83df-830a-4f1a-ad6b-568f7c4171f8", - "_type": "request" - }, - { - "_id": "req_74d115523e874a5d9a21ec78a1eb2742", - "authentication": {}, - "body": {}, - "created": 1559495101548, - "description": "", - "headers": [ - { - "id": "pair_b386cc577c65418589e8d91aa22e6b41", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhZG1pbiIsImlzcyI6IkNUSElUIiwiaWF0IjoxNTQ1NzQ3ODU1LCJleHAiOjE1NDgzMzk4NTV9.emgG3YOaxI3loIlvG3eqi2dmJTsJ0U5oBzz9K5Zc6Po" - } - ], - "isPrivate": false, - "metaSortKey": 2231.25, - "method": "GET", - "modified": 1559495101548, - "name": "Get Group", - "parameters": [], - "parentId": "fld_c846f7fe3dad4f209e047c857d24e546", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/groups/334d7158-0a99-4e1b-8598-a44d5b6cbfe4", - "_type": "request" - }, - { - "_id": "req_ba99349ca45b4a0387115a372489892f", - "authentication": {}, - "body": {}, - "created": 1559495101549, - "description": "", - "headers": [ - { - "id": "pair_b1b33c1608ab44639d4ead975ef5f5e1", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJlbmdzbXlyZSIsImlzcyI6ImRpZ0lUIiwiaWF0IjoxNTMyNjg1NTIzLCJleHAiOjE1MzUyNzc1MjN9.g4YwfNjoBPhfgZI98zaXn7z3CcJMgxapMu_4HThSilw" - } - ], - "isPrivate": false, - "metaSortKey": 2237.5, - "method": "GET", - "modified": 1559495101549, - "name": "Get Group Minified", - "parameters": [], - "parentId": "fld_c846f7fe3dad4f209e047c857d24e546", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/groups/digit/minified", - "_type": "request" - }, - { - "_id": "req_ca229b981be84b0d9151490614f664b7", - "authentication": {}, - "body": { - "mimeType": "application/json", - "text": "{\n\t\"user\":\"466c9e51-8c18-499f-97da-266499e4acdd\",\n\t\"post\":\"e8a25cd7-4dfc-4cbd-b860-b2724aeacee4\",\n\t\"unofficialName\":\"onödig\"\n}" - }, - "created": 1559495101551, - "description": "", - "headers": [ - { - "id": "pair_c70a5b81d88b4d39bec6487eb1657dd0", - "name": "Content-Type", - "value": "application/json" - }, - { - "id": "pair_289e56d5622b49a19315bac43a020029", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODEiLCJleHAiOjE1NTIxNDUxOTcsImF1dGhvcml0aWVzIjpbImFkbWluIl0sImp0aSI6IjNkZDNiYzFkLTk4MWEtNDQwYy05N2FjLWQ5OTJkZjJmYzIwOSIsImNsaWVudF9pZCI6IjdoQWRVRXRNbzRNZ0ZuQTdab1o0MW9oVGUxTk5Sb0ptakw2N0dmME5JcnJCbmF1eWhjIn0.gXILm0CCeLOOa_-yh0_Tw4WaoC_ZcvBvMXeMm578qsk" - } - ], - "isPrivate": false, - "metaSortKey": 2225, - "method": "POST", - "modified": 1559495101551, - "name": "Add User To Group", - "parameters": [], - "parentId": "fld_c846f7fe3dad4f209e047c857d24e546", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/api/admin/groups/7aa80b2d-4ed2-465d-ba22-6503b8a396c7/members", - "_type": "request" - }, - { - "_id": "req_11618621bb1a444e9e7fbdccaec12066", - "authentication": {}, - "body": {}, - "created": 1559495101556, - "description": "", - "headers": [ - { - "id": "pair_eaf2697c85444f2c8910ddb49fa90c53", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODEiLCJleHAiOjE1NDkwNDE3NTQsImF1dGhvcml0aWVzIjpbImFkbWluIl0sImp0aSI6IjFhYjA2NWFhLTYzNmYtNGZkNy05ZTRkLTAwZTdiNDZkYzBkMyIsImNsaWVudF9pZCI6IjdoQWRVRXRNbzRNZ0ZuQTdab1o0MW9oVGUxTk5Sb0ptakw2N0dmME5JcnJCbmF1eWhjIn0.ZlV7JumIzb6LoYlUp4ch8-IxN_vQMOY1RLCPJPKqciA" - } - ], - "isPrivate": false, - "metaSortKey": 2250, - "method": "GET", - "modified": 1559495101556, - "name": "Get Post Usage", - "parameters": [], - "parentId": "fld_c846f7fe3dad4f209e047c857d24e546", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/api/admin/groups/posts/9dcb2751-fb4e-43a8-8681-090d1392bc36/usage", - "_type": "request" - }, - { - "_id": "req_7506e0e0d5ec496f8f475d2a888ae4b0", - "authentication": {}, - "body": { - "mimeType": "application/json", - "text": "{\n\t\"id\":\"d8f9cb87-760f-4dee-95c5-deaa7ca6c79b\"\n}" - }, - "created": 1559495101560, - "description": "", - "headers": [ - { - "id": "pair_db6e908fdcd1489c8f0bce350b889eae", - "name": "Content-Type", - "value": "application/json" - }, - { - "id": "pair_c2995a3c232b4c4ba8b039127f4d9822", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJlbmdzbXlyZSIsImlzcyI6ImRpZ0lUIiwiaWF0IjoxNTMyNjg1NTIzLCJleHAiOjE1MzUyNzc1MjN9.g4YwfNjoBPhfgZI98zaXn7z3CcJMgxapMu_4HThSilw" - } - ], - "isPrivate": false, - "metaSortKey": 2012.5, - "method": "POST", - "modified": 1559495101560, - "name": "Admin Password Reset", - "parameters": [], - "parentId": "fld_c846f7fe3dad4f209e047c857d24e546", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/admin/users/reset_password", - "_type": "request" - }, - { - "_id": "req_caf693f7c7a24c9c9c0d1b359416f639", - "authentication": {}, - "body": { - "mimeType": "application/json", - "text": "{\n\t\"password\":\"iamapassword\",\n\t\"token\":\"gaK>A]1K$C?BgLl*P([[#IZP.R$]&teYh(#qWK&/eS3ZsNhZDTV]P+55=i[VF7SUTG9UH?>_&Yx&e!dKz8lD&H(7qC,PK=+d]9]8\",\n\t\"cid\":\"engsmyre\"\n}" - }, - "created": 1559495101563, - "description": "", - "headers": [ - { - "id": "pair_6c43e750e2484fffba7b6037693a1862", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJlbmdzbXlyZSIsImlzcyI6ImRpZ0lUIiwiaWF0IjoxNTMyNjg1NTIzLCJleHAiOjE1MzUyNzc1MjN9.g4YwfNjoBPhfgZI98zaXn7z3CcJMgxapMu_4HThSilw" - }, - { - "id": "pair_67d30ea94f1d4818a1d7e2c127c0db58", - "name": "Content-Type", - "value": "application/json" - } - ], - "isPrivate": false, - "metaSortKey": 2075, - "method": "PUT", - "modified": 1559495101563, - "name": "Finish Password Reset", - "parameters": [], - "parentId": "fld_c846f7fe3dad4f209e047c857d24e546", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/admin/users/reset_password/finish", - "_type": "request" - }, - { - "_id": "req_7dcc1331ce6d463a8d154aebf82fbf18", - "authentication": {}, - "body": {}, - "created": 1559495101564, - "description": "", - "headers": [ - { - "id": "pair_3a82dc1565ae49cea48d1b1b7fd91608", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODEiLCJleHAiOjE1NTMxOTYzNjcsImF1dGhvcml0aWVzIjpbImFkbWluIl0sImp0aSI6IjA4NzViMDlkLTFjNjAtNDU4NC1hMWM2LWRmOTViY2IxZTI0ZCIsImNsaWVudF9pZCI6IjdoQWRVRXRNbzRNZ0ZuQTdab1o0MW9oVGUxTk5Sb0ptakw2N0dmME5JcnJCbmF1eWhjIn0._UpKccV_CRKJplx0BczDEoKaz8mvN8aS8j5wXojQGLU" - } - ], - "isPrivate": false, - "metaSortKey": 2048.4375, - "method": "DELETE", - "modified": 1559495101564, - "name": "Delete Group", - "parameters": [], - "parentId": "fld_c846f7fe3dad4f209e047c857d24e546", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/api/admin/groups/40339f21-221b-4fdf-bb9a-9d957ebbd9b9", - "_type": "request" - }, - { - "_id": "req_035f77679ec5426fbe5505fa09e06882", - "authentication": { - "accessTokenUrl": "localhost:8081/oauth/token", - "authorizationUrl": "localhost:8081/oauth/authorize", - "clientId": "this_is_a_client_id", - "clientSecret": "{noop}secret", - "grantType": "authorization_code", - "redirectUrl": "http://localhost:3000/login", - "type": "oauth2" - }, - "body": {}, - "created": 1559495101568, - "description": "", - "headers": [ - { - "id": "pair_9834904ea5aa4effbefc509f5e921a17", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODEiLCJleHAiOjE1NTIxNDUxOTcsImF1dGhvcml0aWVzIjpbImFkbWluIl0sImp0aSI6IjNkZDNiYzFkLTk4MWEtNDQwYy05N2FjLWQ5OTJkZjJmYzIwOSIsImNsaWVudF9pZCI6IjdoQWRVRXRNbzRNZ0ZuQTdab1o0MW9oVGUxTk5Sb0ptakw2N0dmME5JcnJCbmF1eWhjIn0.gXILm0CCeLOOa_-yh0_Tw4WaoC_ZcvBvMXeMm578qsk" - } - ], - "isPrivate": false, - "metaSortKey": 2043.75, - "method": "GET", - "modified": 1559495101568, - "name": "Get All Groups", - "parameters": [], - "parentId": "fld_c846f7fe3dad4f209e047c857d24e546", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/api/groups", - "_type": "request" - }, - { - "_id": "req_f71ad890d08d44bc9628d0d46812c0c2", - "authentication": {}, - "body": { - "mimeType": "application/json", - "text": "{\n\t\"password\":\"iamapassword\"\n}" - }, - "created": 1559495101569, - "description": "", - "headers": [ - { - "id": "pair_fef108d24296411eb539477de430d054", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJrYWZmZSIsImlzcyI6ImRpZ0lUIiwiaWF0IjoxNTQyMTI2MjQ2LCJleHAiOjE1NDQ3MTgyNDZ9.IuBuAZeTyYVHfc0_9pSR0rM76TDxrghyD385F2fqeKo" - }, - { - "id": "pair_89dad1bca6c24b21b3e04f3b1bfc7b0a", - "name": "Content-Type", - "value": "application/json" - } - ], - "isPrivate": false, - "metaSortKey": 2046.875, - "method": "PUT", - "modified": 1559495101569, - "name": "Admin Change Password", - "parameters": [], - "parentId": "fld_c846f7fe3dad4f209e047c857d24e546", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/admin/users/f126e2a5-bce2-40f5-aa7e-e5018cc5174e/change_password", - "_type": "request" - }, - { - "_id": "req_5df3aa187c414b89acae4df39f155cf5", - "authentication": {}, - "body": {}, - "created": 1559495101571, - "description": "", - "headers": [ - { - "id": "pair_99ae6a5665ad4feb8e7720a74978b67f", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJlbmdzbXlyZSIsImlzcyI6ImRpZ0lUIiwiaWF0IjoxNTM1NTY1Nzg2LCJleHAiOjE1MzgxNTc3ODZ9.OfAUIFrzHOwtO1m5veAAkAHNoNOtSJYDvYlsYGfkoiw" - } - ], - "isPrivate": false, - "metaSortKey": 2037.5, - "method": "DELETE", - "modified": 1559495101571, - "name": "Delete User", - "parameters": [], - "parentId": "fld_c846f7fe3dad4f209e047c857d24e546", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/admin/users/d8f9cb87-760f-4dee-95c5-deaa7ca6c79b", - "_type": "request" - }, - { - "_id": "req_163c717f143b45828d50298ac1b5754b", - "authentication": {}, - "body": {}, - "created": 1559495101579, - "description": "", - "headers": [ - { - "id": "pair_07859151af8b44a18aecb23d4f8942f1", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODEiLCJleHAiOjE1NTMxOTYzNjcsImF1dGhvcml0aWVzIjpbImFkbWluIl0sImp0aSI6IjA4NzViMDlkLTFjNjAtNDU4NC1hMWM2LWRmOTViY2IxZTI0ZCIsImNsaWVudF9pZCI6IjdoQWRVRXRNbzRNZ0ZuQTdab1o0MW9oVGUxTk5Sb0ptakw2N0dmME5JcnJCbmF1eWhjIn0._UpKccV_CRKJplx0BczDEoKaz8mvN8aS8j5wXojQGLU" - } - ], - "isPrivate": false, - "metaSortKey": 2050, - "method": "GET", - "modified": 1559495101579, - "name": "Get All Users", - "parameters": [], - "parentId": "fld_c846f7fe3dad4f209e047c857d24e546", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/api/admin/users", - "_type": "request" - }, - { - "_id": "req_d8bd648b12d648dab3cfc0da90143180", - "authentication": {}, - "body": {}, - "created": 1559495101581, - "description": "", - "headers": [ - { - "id": "pair_0b03c72524be4af6839e02ae2d585ef0", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODEiLCJleHAiOjE1NDkwNDE3NTQsImF1dGhvcml0aWVzIjpbImFkbWluIl0sImp0aSI6IjFhYjA2NWFhLTYzNmYtNGZkNy05ZTRkLTAwZTdiNDZkYzBkMyIsImNsaWVudF9pZCI6IjdoQWRVRXRNbzRNZ0ZuQTdab1o0MW9oVGUxTk5Sb0ptakw2N0dmME5JcnJCbmF1eWhjIn0.ZlV7JumIzb6LoYlUp4ch8-IxN_vQMOY1RLCPJPKqciA" - } - ], - "isPrivate": false, - "metaSortKey": 2100, - "method": "GET", - "modified": 1559495101581, - "name": "get users in group", - "parameters": [], - "parentId": "fld_c846f7fe3dad4f209e047c857d24e546", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/api/admin/groups/8323b76d-8daf-458b-956c-64ab67a90bbb/members", - "_type": "request" - }, - { - "_id": "req_496e9eee7bba485a89407a6555f6a63d", - "authentication": {}, - "body": { - "mimeType": "application/json", - "text": "{\n\t\"post\":\"e8a25cd7-4dfc-4cbd-b860-b2724aeacee4\",\n\t\"superGroup\":\"aa835d66-5a59-47c8-9d57-8b1594b08216\",\n\t\"authority\":\"9f01ead6-96ac-48ea-ae59-c1f6bf3a3658\"\n}\n" - }, - "created": 1559495101584, - "description": "", - "headers": [ - { - "id": "pair_392cb6ea1aba4a2b8a98ea90301ad038", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODEiLCJleHAiOjE1NTMyMDU4NjMsImF1dGhvcml0aWVzIjpbImFkbWluIl0sImp0aSI6ImE5MGVlZGJmLTFlNmMtNGNiMi1iZDQyLTFjMDFmM2RlMWY2MSIsImNsaWVudF9pZCI6IjdoQWRVRXRNbzRNZ0ZuQTdab1o0MW9oVGUxTk5Sb0ptakw2N0dmME5JcnJCbmF1eWhjIn0.vj3W6BsBHbSAkpD1J7LlfclGd-B2ibA6sxbXHXpQQsI" - }, - { - "id": "pair_2fce5db8ca114326817fff7c238b9933", - "name": "Content-Type", - "value": "application/json" - } - ], - "isPrivate": false, - "metaSortKey": 2025, - "method": "POST", - "modified": 1559495101584, - "name": "add authority", - "parameters": [], - "parentId": "fld_c846f7fe3dad4f209e047c857d24e546", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/api/admin/authority", - "_type": "request" - }, - { - "_id": "req_d3e7660f5d1b4ef8883bcd9f2eba4b12", - "authentication": {}, - "body": {}, - "created": 1559495101585, - "description": "", - "headers": [ - { - "id": "pair_e9027d9d32304a3f934f2b68748e618d", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODEiLCJleHAiOjE1NTMyMDU4NjMsImF1dGhvcml0aWVzIjpbImFkbWluIl0sImp0aSI6ImE5MGVlZGJmLTFlNmMtNGNiMi1iZDQyLTFjMDFmM2RlMWY2MSIsImNsaWVudF9pZCI6IjdoQWRVRXRNbzRNZ0ZuQTdab1o0MW9oVGUxTk5Sb0ptakw2N0dmME5JcnJCbmF1eWhjIn0.vj3W6BsBHbSAkpD1J7LlfclGd-B2ibA6sxbXHXpQQsI" - } - ], - "isPrivate": false, - "metaSortKey": 1900, - "method": "GET", - "modified": 1559495101585, - "name": "get authorities", - "parameters": [], - "parentId": "fld_c846f7fe3dad4f209e047c857d24e546", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/api/admin/authority", - "_type": "request" - }, - { - "_id": "req_f093007b77dc40a69ccba248c29c0d55", - "authentication": {}, - "body": { - "mimeType": "application/json", - "text": "{\n\t\"authorityLevel\":\"digit\"\n}" - }, - "created": 1559495101586, - "description": "", - "headers": [ - { - "id": "pair_a532392d8da94145966face42753f047", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODEiLCJleHAiOjE1NTMyMDU4NjMsImF1dGhvcml0aWVzIjpbImFkbWluIl0sImp0aSI6ImE5MGVlZGJmLTFlNmMtNGNiMi1iZDQyLTFjMDFmM2RlMWY2MSIsImNsaWVudF9pZCI6IjdoQWRVRXRNbzRNZ0ZuQTdab1o0MW9oVGUxTk5Sb0ptakw2N0dmME5JcnJCbmF1eWhjIn0.vj3W6BsBHbSAkpD1J7LlfclGd-B2ibA6sxbXHXpQQsI" - }, - { - "id": "pair_a63febe739cf485bb531ffc46cb3f728", - "name": "Content-Type", - "value": "application/json" - } - ], - "isPrivate": false, - "metaSortKey": 1800, - "method": "POST", - "modified": 1559495101586, - "name": "add authority level", - "parameters": [], - "parentId": "fld_c846f7fe3dad4f209e047c857d24e546", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/api/admin/authority/level", - "_type": "request" - }, - { - "_id": "req_9214491e509041cfb0d78a6f8cad414c", - "authentication": {}, - "body": {}, - "created": 1559495101589, - "description": "", - "headers": [ - { - "id": "pair_cc4267a2c0a14eaea4ffba4a8b34522a", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhZG1pbiIsImlzcyI6IkNUSElUIiwiaWF0IjoxNTQ0NzI1ODAzLCJleHAiOjE1NDczMTc4MDN9.jxp8DNGxNbnQtlWv4M9KdblOuYP8tra4azBelBvB57I" - } - ], - "isPrivate": false, - "metaSortKey": 1700, - "method": "GET", - "modified": 1559495101589, - "name": "get users with authority", - "parameters": [], - "parentId": "fld_c846f7fe3dad4f209e047c857d24e546", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/api/admin/authority/user_authorities/8b7bf45d-9955-4e8d-8c0b-8cb5758945d1", - "_type": "request" - }, - { - "_id": "req_872a6946652e49fcb67148cb6678f064", - "authentication": {}, - "body": {}, - "created": 1559495101594, - "description": "", - "headers": [ - { - "id": "pair_99de617c02464269ba9a7458b5f5c8dc", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJrYWZmZSIsImlzcyI6ImRpZ0lUIiwiaWF0IjoxNTQyMTI2MjQ2LCJleHAiOjE1NDQ3MTgyNDZ9.IuBuAZeTyYVHfc0_9pSR0rM76TDxrghyD385F2fqeKo" - } - ], - "isPrivate": false, - "metaSortKey": 1600, - "method": "DELETE", - "modified": 1559495101594, - "name": "remove authority level", - "parameters": [], - "parentId": "fld_c846f7fe3dad4f209e047c857d24e546", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/admin/authorization/level/b1796a29-748d-4861-864b-554cd65124c6", - "_type": "request" - }, - { - "_id": "req_ff59445f86224174a93eec1ba8c25e15", - "authentication": {}, - "body": {}, - "created": 1559495101597, - "description": "", - "headers": [ - { - "id": "pair_3ed9f9e1ac34447389846b309a968628", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODEiLCJleHAiOjE1NDkwNDE3NTQsImF1dGhvcml0aWVzIjpbImFkbWluIl0sImp0aSI6IjFhYjA2NWFhLTYzNmYtNGZkNy05ZTRkLTAwZTdiNDZkYzBkMyIsImNsaWVudF9pZCI6IjdoQWRVRXRNbzRNZ0ZuQTdab1o0MW9oVGUxTk5Sb0ptakw2N0dmME5JcnJCbmF1eWhjIn0.ZlV7JumIzb6LoYlUp4ch8-IxN_vQMOY1RLCPJPKqciA" - } - ], - "isPrivate": false, - "metaSortKey": 1500, - "method": "GET", - "modified": 1559495101597, - "name": "get authority", - "parameters": [], - "parentId": "fld_c846f7fe3dad4f209e047c857d24e546", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/api/admin/authority/c6113d2c-2198-4474-a8c0-95b7e1ea4809", - "_type": "request" - }, - { - "_id": "req_18a9c3458de9473da7e57623ea69ea9d", - "authentication": {}, - "body": {}, - "created": 1559495101599, - "description": "", - "headers": [ - { - "id": "pair_fea4e9f6cfc14db4b0d348aed56d4c87", - "name": "Authorization", - "value": "Bearer Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODEiLCJleHAiOjE1NTMyMDU4NjMsImF1dGhvcml0aWVzIjpbImFkbWluIl0sImp0aSI6ImE5MGVlZGJmLTFlNmMtNGNiMi1iZDQyLTFjMDFmM2RlMWY2MSIsImNsaWVudF9pZCI6IjdoQWRVRXRNbzRNZ0ZuQTdab1o0MW9oVGUxTk5Sb0ptakw2N0dmME5JcnJCbmF1eWhjIn0.vj3W6BsBHbSAkpD1J7LlfclGd-B2ibA6sxbXHXpQQsI" - } - ], - "isPrivate": false, - "metaSortKey": 2000, - "method": "GET", - "modified": 1559495101599, - "name": "Get Authority levels", - "parameters": [], - "parentId": "fld_c846f7fe3dad4f209e047c857d24e546", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/api/admin/authority/level", - "_type": "request" - }, - { - "_id": "req_b6f67b524700435ab1ff3f17bd1e1b20", - "authentication": {}, - "body": {}, - "created": 1559495101600, - "description": "", - "headers": [ - { - "id": "pair_14c026d25bf04384a898e8785edc8e66", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJrYWZmZSIsImlzcyI6ImRpZ0lUIiwiaWF0IjoxNTQyMTI2MjQ2LCJleHAiOjE1NDQ3MTgyNDZ9.IuBuAZeTyYVHfc0_9pSR0rM76TDxrghyD385F2fqeKo" - } - ], - "isPrivate": false, - "metaSortKey": 1400, - "method": "DELETE", - "modified": 1559495101600, - "name": "remove authority", - "parameters": [], - "parentId": "fld_c846f7fe3dad4f209e047c857d24e546", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/admin/authorization/6c39a0af-53b4-4b57-b66f-df7c857b5fa2", - "_type": "request" - }, - { - "_id": "req_0bfe572827fe48b39e4f3d22b5ebb199", - "authentication": {}, - "body": {}, - "created": 1559495101602, - "description": "", - "headers": [ - { - "id": "pair_3fe9a03d19c24bc3b26ce3b5ede003d2", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODEiLCJleHAiOjE1NTEzNzMzOTAsImF1dGhvcml0aWVzIjpbImFkbWluIl0sImp0aSI6IjEwZjllYWU5LWZjZmUtNDM0Yi1hYTVkLTlkMGRmZTVhNDU4MSIsImNsaWVudF9pZCI6IjdoQWRVRXRNbzRNZ0ZuQTdab1o0MW9oVGUxTk5Sb0ptakw2N0dmME5JcnJCbmF1eWhjIn0.EtpDpAzg9C0bygDhuHTi8dj9iUMYY9WZ6F7S4euJm6M" - } - ], - "isPrivate": false, - "metaSortKey": 1300, - "method": "GET", - "modified": 1559495101602, - "name": "Get All Super Groups", - "parameters": [], - "parentId": "fld_c846f7fe3dad4f209e047c857d24e546", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/api/superGroups", - "_type": "request" - }, - { - "_id": "req_8823b40937ad4fc295c8e1b5874e8141", - "authentication": { - "accessTokenUrl": "http://localhost:8081/api/oauth/token", - "authorizationUrl": "http://localhost:8081/api/oauth/authorize", - "clientId": "7hAdUEtMo4MgFnA7ZoZ41ohTe1NNRoJmjL67Gf0NIrrBnauyhc", - "clientSecret": "LBoxmzohQOSRCz99uBhS0IjLglxUOaLRXJxIC8iWuHTWYCLLqo", - "grantType": "authorization_code", - "redirectUrl": "http://localhost:3000/login", - "type": "oauth2" - }, - "body": {}, - "created": 1559495101604, - "description": "", - "headers": [ - { - "id": "pair_e7a0fb5fad7844d4bbd1b73ff1691e8f", - "name": "Content-Type", - "value": "application/json" - }, - { - "id": "pair_3573c2467b8a49688e3286f35092845f", - "name": "Authorization", - "value": "Bearer cb1e8cbf-df6e-46b6-b4d0-8075141fb6b7" - } - ], - "isPrivate": false, - "metaSortKey": 1100, - "method": "POST", - "modified": 1559495101604, - "name": "create oauth", - "parameters": [], - "parentId": "fld_c846f7fe3dad4f209e047c857d24e546", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/oauth/token", - "_type": "request" - }, - { - "_id": "req_3e27483274514904bd90fcc91a51bff1", - "authentication": { - "disabled": false, - "password": "password", - "type": "basic", - "username": "admin" - }, - "body": { - "mimeType": "", - "text": "" - }, - "created": 1559495101606, - "description": "", - "headers": [ - { - "id": "pair_6ac6bebf4c8a4963afcf2537b0fc8070", - "name": "Authorization", - "value": "Bearer cb1e8cbf-df6e-46b6-b4d0-8075141fb6b7" - } - ], - "isPrivate": false, - "metaSortKey": 1200, - "method": "GET", - "modified": 1559495101606, - "name": "oauth test", - "parameters": [], - "parentId": "fld_c846f7fe3dad4f209e047c857d24e546", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "http://localhost:8081/oauth/check_token", - "_type": "request" - }, - { - "_id": "req_2f9a4e56703a4ebeaa5c09bea864ed46", - "authentication": {}, - "body": { - "mimeType": "application/json", - "text": "{\n\t\"name\":\"digit\",\n\t\"prettyName\":\"digIT\",\n\t\"type\":\"COMMITTEE\"\n}" - }, - "created": 1559495101607, - "description": "", - "headers": [ - { - "id": "pair_5aa51c48922e4e50a3d7b7a858c2e4f8", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODEiLCJleHAiOjE1NTMxOTYzNjcsImF1dGhvcml0aWVzIjpbImFkbWluIl0sImp0aSI6IjA4NzViMDlkLTFjNjAtNDU4NC1hMWM2LWRmOTViY2IxZTI0ZCIsImNsaWVudF9pZCI6IjdoQWRVRXRNbzRNZ0ZuQTdab1o0MW9oVGUxTk5Sb0ptakw2N0dmME5JcnJCbmF1eWhjIn0._UpKccV_CRKJplx0BczDEoKaz8mvN8aS8j5wXojQGLU" - }, - { - "id": "pair_c6fd5fe93a8b4409b1e514f89cedc376", - "name": "Content-Type", - "value": "application/json" - } - ], - "isPrivate": false, - "metaSortKey": 1000, - "method": "POST", - "modified": 1559495101607, - "name": "Add Super Group", - "parameters": [], - "parentId": "fld_c846f7fe3dad4f209e047c857d24e546", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/api/admin/superGroups", - "_type": "request" - }, - { - "_id": "req_76a98315e0904eb1972043342f356e14", - "authentication": {}, - "body": { - "mimeType": "application/json", - "text": "{\n\t\"cid\":\"engsmre\",\n\t\"password\":\"password\",\n\t\"nick\":\"gurr\",\n\t\"firstName\":\"gustav\",\n\t\"email\":\"engsmyre@stud\",\n\t\"userAgreement\":true,\n\t\"acceptanceYear\":2016\n}" - }, - "created": 1559495101608, - "description": "", - "headers": [ - { - "id": "pair_74d57904834a4b30a72c2303d5f87da3", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODEiLCJleHAiOjE1NTQyMzYzNTgsImF1dGhvcml0aWVzIjpbImFkbWluIl0sImp0aSI6IjYyZjU3ZjA4LTVhOWItNGIzNC05NDM5LTVjNzZjM2Y5YTUzZSIsImNsaWVudF9pZCI6IjdoQWRVRXRNbzRNZ0ZuQTdab1o0MW9oVGUxTk5Sb0ptakw2N0dmME5JcnJCbmF1eWhjIn0.1UTI3W9aHuaHQZBA8EfNZr6HEfny7oHi8yYzoFrMMNE" - }, - { - "id": "pair_af297e80ec2c4d2fa378860180206b2a", - "name": "Content-Type", - "value": "application/json" - } - ], - "isPrivate": false, - "metaSortKey": 800, - "method": "POST", - "modified": 1559495101608, - "name": "Admin Add User", - "parameters": [], - "parentId": "fld_c846f7fe3dad4f209e047c857d24e546", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/api/admin/users", - "_type": "request" - }, - { - "_id": "req_09762a35e64244b2aa2e9a7e05a703f9", - "authentication": { - "grantType": "authorization_code", - "type": "oauth2" - }, - "body": { - "mimeType": "application/json", - "text": "{\n\t\"url_redirect\":\"http://localhost:8083/ui/login\",\n\t\"name\":\"tesdsfat\",\n\t\"description\":{\n\t\t\"sv\":\"an example application\",\n\t\t\"en\":\"ex\"\n\t}\n}" - }, - "created": 1559495101609, - "description": "", - "headers": [ - { - "id": "pair_3c9b81c64b9b40a0a5650f670d992dda", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODEiLCJleHAiOjE1NTEwMzUxNTMsImF1dGhvcml0aWVzIjpbImFkbWluIl0sImp0aSI6IjNhNWEyYzMxLTMyODQtNDAyMC05YzZhLWMwOTRlM2YyM2VmYiIsImNsaWVudF9pZCI6IjdoQWRVRXRNbzRNZ0ZuQTdab1o0MW9oVGUxTk5Sb0ptakw2N0dmME5JcnJCbmF1eWhjIn0.mAhpI7plWg2FyNhEz03BvuQ2oxIgzPckz-KHnht1gws" - }, - { - "id": "pair_035f8f80ec7d4f209d02028c43c30030", - "name": "Content-Type", - "value": "application/json" - } - ], - "isPrivate": false, - "metaSortKey": 900, - "method": "POST", - "modified": 1559495101609, - "name": "add client", - "parameters": [], - "parentId": "fld_c846f7fe3dad4f209e047c857d24e546", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/api/admin/clients", - "_type": "request" - }, - { - "_id": "req_c52ecef916fe48b5b9020e835dc0bfd5", - "authentication": { - "grantType": "authorization_code", - "type": "oauth2" - }, - "body": {}, - "created": 1559495101611, - "description": "", - "headers": [ - { - "id": "pair_100895883e484e1795996cb39c538252", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODEiLCJleHAiOjE1NDk4Mzc3MjUsInVzZXJfbmFtZSI6ImVuZ3NteXJlIiwianRpIjoiNTI5MGNjNzYtMGY3My00MmYzLTkyNjItMjU2MTgwMmRiY2JjIiwiY2xpZW50X2lkIjoiN2hBZFVFdE1vNE1nRm5BN1pvWjQxb2hUZTFOTlJvSm1qTDY3R2YwTklyckJuYXV5aGMiLCJzY29wZSI6WyJyZWFkIiwid3JpdGUiXX0.ogh3TlB83bqEtqCKw1tMknTCuC2WQzaZPzkpx8AP0vY" - } - ], - "isPrivate": false, - "metaSortKey": 600, - "method": "GET", - "modified": 1559495101611, - "name": "Get Me", - "parameters": [], - "parentId": "fld_c846f7fe3dad4f209e047c857d24e546", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/api/users/me", - "_type": "request" - }, - { - "_id": "req_6e86817951d744219846fee69bcaa15c", - "authentication": {}, - "body": { - "mimeType": "application/json", - "text": "{\n\t\"unofficialName\":\"DevOps\"\n}" - }, - "created": 1559495101614, - "description": "", - "headers": [ - { - "id": "pair_8a42933965aa4c91a21402523b0981ac", - "name": "Content-Type", - "value": "application/json" - }, - { - "id": "pair_9672c9263cbf40f0bace752aeb8e477e", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODEiLCJleHAiOjE1NDkwNDE3NTQsImF1dGhvcml0aWVzIjpbImFkbWluIl0sImp0aSI6IjFhYjA2NWFhLTYzNmYtNGZkNy05ZTRkLTAwZTdiNDZkYzBkMyIsImNsaWVudF9pZCI6IjdoQWRVRXRNbzRNZ0ZuQTdab1o0MW9oVGUxTk5Sb0ptakw2N0dmME5JcnJCbmF1eWhjIn0.ZlV7JumIzb6LoYlUp4ch8-IxN_vQMOY1RLCPJPKqciA" - } - ], - "isPrivate": false, - "metaSortKey": 2200, - "method": "PUT", - "modified": 1559495101614, - "name": "Edit user in supergroup", - "parameters": [], - "parentId": "fld_c846f7fe3dad4f209e047c857d24e546", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/api/admin/groups/8323b76d-8daf-458b-956c-64ab67a90bbb/members/4b30f99f-39bd-4197-9089-04ae33c9ae92", - "_type": "request" - }, - { - "_id": "req_10156116c31147bbaed2162e231f1d9f", - "authentication": {}, - "body": {}, - "created": 1559495101615, - "description": "", - "headers": [ - { - "id": "pair_ecf009def3c24dbdbc85cb3b5233685c", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODEiLCJleHAiOjE1NDkwNDE3NTQsImF1dGhvcml0aWVzIjpbImFkbWluIl0sImp0aSI6IjFhYjA2NWFhLTYzNmYtNGZkNy05ZTRkLTAwZTdiNDZkYzBkMyIsImNsaWVudF9pZCI6IjdoQWRVRXRNbzRNZ0ZuQTdab1o0MW9oVGUxTk5Sb0ptakw2N0dmME5JcnJCbmF1eWhjIn0.ZlV7JumIzb6LoYlUp4ch8-IxN_vQMOY1RLCPJPKqciA" - } - ], - "isPrivate": false, - "metaSortKey": 500, - "method": "DELETE", - "modified": 1559495101615, - "name": "Delete User In Group", - "parameters": [], - "parentId": "fld_c846f7fe3dad4f209e047c857d24e546", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/api/admin/groups/8323b76d-8daf-458b-956c-64ab67a90bbb/members/4b30f99f-39bd-4197-9089-04ae33c9ae92", - "_type": "request" - }, - { - "_id": "req_276cf98e2a71425694ed8f8402cf18b9", - "authentication": {}, - "body": {}, - "created": 1559495101617, - "description": "", - "headers": [ - { - "id": "pair_ec34a296a8c5485d80982f7dc0f47e42", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODEiLCJleHAiOjE1NDkwNDE3NTQsImF1dGhvcml0aWVzIjpbImFkbWluIl0sImp0aSI6IjFhYjA2NWFhLTYzNmYtNGZkNy05ZTRkLTAwZTdiNDZkYzBkMyIsImNsaWVudF9pZCI6IjdoQWRVRXRNbzRNZ0ZuQTdab1o0MW9oVGUxTk5Sb0ptakw2N0dmME5JcnJCbmF1eWhjIn0.ZlV7JumIzb6LoYlUp4ch8-IxN_vQMOY1RLCPJPKqciA" - } - ], - "isPrivate": false, - "metaSortKey": 700, - "method": "GET", - "modified": 1559495101617, - "name": "Get groups by supergroup", - "parameters": [], - "parentId": "fld_c846f7fe3dad4f209e047c857d24e546", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "l§ocalhost:8081/api/admin/superGroups/bfff0a19-3d5f-46af-a5d5-e4bd5949b368/subgroups", - "_type": "request" - }, - { - "_id": "req_9636b1b0e8734f469f88cc4a5f691b50", - "authentication": { - "grantType": "authorization_code", - "type": "oauth2" - }, - "body": { - "mimeType": "application/json", - "text": "{\n\t\"firstName\":\"Big G\"\n}" - }, - "created": 1559495101618, - "description": "", - "headers": [ - { - "id": "pair_10f70e5c56c442ee8b4bebf99b784f32", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODEiLCJleHAiOjE1NDk4Mzc3MjUsInVzZXJfbmFtZSI6ImVuZ3NteXJlIiwianRpIjoiNTI5MGNjNzYtMGY3My00MmYzLTkyNjItMjU2MTgwMmRiY2JjIiwiY2xpZW50X2lkIjoiN2hBZFVFdE1vNE1nRm5BN1pvWjQxb2hUZTFOTlJvSm1qTDY3R2YwTklyckJuYXV5aGMiLCJzY29wZSI6WyJyZWFkIiwid3JpdGUiXX0.ogh3TlB83bqEtqCKw1tMknTCuC2WQzaZPzkpx8AP0vY" - }, - { - "id": "pair_b895185360304a09b86adfdc71a2cd9a", - "name": "Content-Type", - "value": "application/json" - } - ], - "isPrivate": false, - "metaSortKey": 300, - "method": "PUT", - "modified": 1559495101618, - "name": "edit me", - "parameters": [], - "parentId": "fld_c846f7fe3dad4f209e047c857d24e546", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/api/users/me", - "_type": "request" - }, - { - "_id": "req_5ea6c88ddfc94daebd8ae15a1b9a1598", - "authentication": {}, - "body": { - "mimeType": "application/json", - "text": "{\n\t\"description\":\n\t{\n\t\t\"sv\":\"admi\",\n\t\t\"en\":\"admin\"\n\t}\n}" - }, - "created": 1559495101620, - "description": "", - "headers": [ - { - "id": "pair_489b2383773a43a9b7d4c94b1d6f04ca", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJlbmdzbXlyZSIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODEiLCJleHAiOjE1NTMyMTE3OTQsImF1dGhvcml0aWVzIjpbImRpZ2l0Il0sImp0aSI6Ijc5NGZjNzQxLTQ1ZDctNDUyMy1hMzMwLWFjNGMzYTZiNTljMCIsImNsaWVudF9pZCI6IjdoQWRVRXRNbzRNZ0ZuQTdab1o0MW9oVGUxTk5Sb0ptakw2N0dmME5JcnJCbmF1eWhjIn0.32rECcJ-AXC1eclP2z0tvVfvRasrQn0XwcvQwY4PXco" - }, - { - "id": "pair_b014cb2281af4d7dad0c6b3e35b64fa9", - "name": "Content-Type", - "value": "application/json" - } - ], - "isPrivate": false, - "metaSortKey": 2300, - "method": "PUT", - "modified": 1559495101620, - "name": "Edit Group", - "parameters": [], - "parentId": "fld_c846f7fe3dad4f209e047c857d24e546", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/api/admin/groups/7aa80b2d-4ed2-465d-ba22-6503b8a396c7", - "_type": "request" - }, - { - "_id": "req_fad22214e8a848f2a9a43fad7ccc54f9", - "authentication": {}, - "body": {}, - "created": 1559495101622, - "description": "", - "headers": [ - { - "id": "pair_924ef95ad9a4466eb86482bb870f72e2", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODEiLCJleHAiOjE1NTIxNDUxOTcsImF1dGhvcml0aWVzIjpbImFkbWluIl0sImp0aSI6IjNkZDNiYzFkLTk4MWEtNDQwYy05N2FjLWQ5OTJkZjJmYzIwOSIsImNsaWVudF9pZCI6IjdoQWRVRXRNbzRNZ0ZuQTdab1o0MW9oVGUxTk5Sb0ptakw2N0dmME5JcnJCbmF1eWhjIn0.gXILm0CCeLOOa_-yh0_Tw4WaoC_ZcvBvMXeMm578qsk" - } - ], - "isPrivate": false, - "metaSortKey": 400, - "method": "GET", - "modified": 1559495101622, - "name": "get active group", - "parameters": [], - "parentId": "fld_c846f7fe3dad4f209e047c857d24e546", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/api/superGroups/40180559-e281-46f6-a2d1-3a63ffd18433/active", - "_type": "request" - }, - { - "_id": "req_5da62f14e4254525a4ed3c40080ab6f8", - "authentication": {}, - "body": {}, - "created": 1559495101623, - "description": "", - "headers": [ - { - "id": "pair_03598fd7b43b43798220e845dcb0636d", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODEiLCJleHAiOjE1NTIxNDUxOTcsImF1dGhvcml0aWVzIjpbImFkbWluIl0sImp0aSI6IjNkZDNiYzFkLTk4MWEtNDQwYy05N2FjLWQ5OTJkZjJmYzIwOSIsImNsaWVudF9pZCI6IjdoQWRVRXRNbzRNZ0ZuQTdab1o0MW9oVGUxTk5Sb0ptakw2N0dmME5JcnJCbmF1eWhjIn0.gXILm0CCeLOOa_-yh0_Tw4WaoC_ZcvBvMXeMm578qsk" - } - ], - "isPrivate": false, - "metaSortKey": 2400, - "method": "GET", - "modified": 1559495101623, - "name": "Get active groups", - "parameters": [], - "parentId": "fld_c846f7fe3dad4f209e047c857d24e546", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/api/groups/active", - "_type": "request" - }, - { - "_id": "req_dc01363810174b418df54abc025574e7", - "authentication": {}, - "body": { - "mimeType": "multipart/form-data", - "params": [ - { - "fileName": "/home/gurr/Desktop/images/Arch.png", - "id": "pair_2dea10919523464a8a6a61065e96816e", - "name": "file", - "type": "file", - "value": "" - } - ] - }, - "created": 1559495101624, - "description": "", - "headers": [ - { - "id": "pair_08114df83d314db68758924589affb30", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODEiLCJleHAiOjE1NTIxNDUxOTcsImF1dGhvcml0aWVzIjpbImFkbWluIl0sImp0aSI6IjNkZDNiYzFkLTk4MWEtNDQwYy05N2FjLWQ5OTJkZjJmYzIwOSIsImNsaWVudF9pZCI6IjdoQWRVRXRNbzRNZ0ZuQTdab1o0MW9oVGUxTk5Sb0ptakw2N0dmME5JcnJCbmF1eWhjIn0.gXILm0CCeLOOa_-yh0_Tw4WaoC_ZcvBvMXeMm578qsk" - }, - { - "id": "pair_dd5a31b0aef143e1a166bae7b3c014c8", - "name": "Content-Type", - "value": "multipart/form-data" - } - ], - "isPrivate": false, - "metaSortKey": 200, - "method": "PUT", - "modified": 1559495101624, - "name": "add imaeg", - "parameters": [], - "parentId": "fld_c846f7fe3dad4f209e047c857d24e546", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/api/users/me/avatar", - "_type": "request" - }, - { - "_id": "req_01d26b0bfa054855afbfe44d996af2f4", - "authentication": {}, - "body": { - "mimeType": "multipart/form-data", - "params": [ - { - "fileName": "/home/gurr/trains_fine.png", - "id": "pair_ac79ce95b4264c57b4813d8438c30dc3", - "name": "file", - "type": "file", - "value": "" - } - ] - }, - "created": 1559495101626, - "description": "", - "headers": [ - { - "id": "pair_74cc8db7570e4f4482de102270ec21f8", - "name": "Authorization", - "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODEiLCJleHAiOjE1NTIxNDUxOTcsImF1dGhvcml0aWVzIjpbImFkbWluIl0sImp0aSI6IjNkZDNiYzFkLTk4MWEtNDQwYy05N2FjLWQ5OTJkZjJmYzIwOSIsImNsaWVudF9pZCI6IjdoQWRVRXRNbzRNZ0ZuQTdab1o0MW9oVGUxTk5Sb0ptakw2N0dmME5JcnJCbmF1eWhjIn0.gXILm0CCeLOOa_-yh0_Tw4WaoC_ZcvBvMXeMm578qsk" - }, - { - "id": "pair_e2ee946f065446a4860efd63ffe68ec7", - "name": "Content-Type", - "value": "multipart/form-data" - } - ], - "isPrivate": false, - "metaSortKey": 0, - "method": "PUT", - "modified": 1559495101626, - "name": "add group image", - "parameters": [], - "parentId": "fld_c846f7fe3dad4f209e047c857d24e546", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/api/admin/groups/52f5580c-937e-410d-b9e5-6e8e44328d94/avatar", - "_type": "request" - }, - { - "_id": "req_1c9902f273e64647b06129d8bc8f6529", - "authentication": {}, - "body": {}, - "created": 1559495101627, - "description": "", - "headers": [], - "isPrivate": false, - "metaSortKey": 100, - "method": "POST", - "modified": 1559495101627, - "name": "Jwt", - "parameters": [], - "parentId": "fld_c846f7fe3dad4f209e047c857d24e546", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "http://localhost:9090/oauth/token", - "_type": "request" - }, - { - "_id": "req_39b6b70f8692452d8048d964dfbd01c8", - "authentication": {}, - "body": { - "mimeType": "application/json", - "text": "{\n\t\"cid\":\"engsmyre\",\n\t\"password\":\"password\"\n}" - }, - "created": 1559495101630, - "description": "", - "headers": [ - { - "id": "pair_f1c12844a5584bc2a3e9ab5a71693afc", - "name": "Content-Type", - "value": "application/json" - } - ], - "isPrivate": false, - "metaSortKey": 2295.99609375, - "method": "POST", - "modified": 1559495101630, - "name": "login", - "parameters": [], - "parentId": "fld_c846f7fe3dad4f209e047c857d24e546", - "settingDisableRenderRequestBody": false, - "settingEncodeUrl": true, - "settingRebuildPath": true, - "settingSendCookies": true, - "settingStoreCookies": true, - "url": "localhost:8081/api/users/login", - "_type": "request" - } - ] -} diff --git a/backend/build.gradle b/backend/build.gradle deleted file mode 100644 index e443729f1..000000000 --- a/backend/build.gradle +++ /dev/null @@ -1,144 +0,0 @@ -buildscript { - ext { - springBootVersion = "2.4.+" - springVersion = "5.3.+" - } - repositories { - mavenCentral() - } - dependencies { - classpath "org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}" - } -} - -plugins { - id "java" - id "eclipse" - id "application" - id "checkstyle" - id "pmd" - id "jacoco" - id "nebula.lint" version "16.7.0" -} - -apply plugin: "org.springframework.boot" -apply plugin: "io.spring.dependency-management" -group = "it.chalmers" -version = "0.9.0-SNAPSHOT" -sourceCompatibility = 11 -mainClassName = "it.chalmers.gamma.GammaApplication" - -repositories { - mavenCentral() -} -jar { - manifest { - attributes "Main-Class": "it.chalmers.GammaApplication" - } - from { - configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } - } -} - -dependencies { - - compileOnly( - "com.github.spotbugs:spotbugs-annotations:3.1.8" - ) - // Are not needed to compile and build, only to configure - runtime( - "org.springframework.security.oauth.boot:spring-security-oauth2-autoconfigure:${springBootVersion}", - "org.springframework.boot:spring-boot-devtools:${springBootVersion}", - "org.postgresql:postgresql:42.2.12", - "org.springframework.boot:spring-boot-starter-data-jpa:${springBootVersion}", - "org.springframework.boot:spring-boot-starter-web:${springBootVersion}", - "org.springframework.boot:spring-boot-starter-data-redis:${springBootVersion}", - "org.springframework.session:spring-session-data-redis:2.2.2.RELEASE", - "org.springframework.boot:spring-boot-starter-thymeleaf:${springBootVersion}", - "org.flywaydb:flyway-core:6.3.3" - - ) - compile( - "org.springframework:spring-tx:${springVersion}", - "org.springframework.security:spring-security-core:${springVersion}", - "org.springframework.security:spring-security-web:${springVersion}", - "org.springframework:spring-beans:${springVersion}", - "org.springframework.data:spring-data-jpa:${springBootVersion}", - "org.springframework:spring-core:${springVersion}", - "org.springframework:spring-web:${springVersion}", - "org.springframework:spring-context:${springVersion}", - "org.springframework:spring-webmvc:${springVersion}", - "org.springframework.security:spring-security-config:${springVersion}", - "org.springframework.security.oauth:spring-security-oauth2:${springBootVersion}", - "org.springframework.boot:spring-boot-autoconfigure:${springBootVersion}", - "org.springframework.session:spring-session-core:${springBootVersion}", - "org.springframework.boot:spring-boot:${springBootVersion}", - "org.hibernate:hibernate-core:5.4.14.Final", - "javax.validation:validation-api:2.0.1.Final", - "org.apache.tomcat.embed:tomcat-embed-core:9.0.34", - "org.jboss.spec.javax.transaction:jboss-transaction-api_1.2_spec:1.1.1.Final", - "org.apache.httpcomponents:httpcore:4.4.13", - "javax.persistence:javax.persistence-api:2.2", - "org.apache.httpcomponents:httpclient:4.5.6", - "javax.transaction:javax.transaction-api:1.3", - "com.fasterxml.jackson.core:jackson-annotations:2.10.3", - "org.slf4j:slf4j-api:1.7.30", - "com.fasterxml.jackson.core:jackson-databind:2.10.3", - "com.googlecode.json-simple:json-simple:1.1.1", - "io.jsonwebtoken:jjwt:0.9.1", - "commons-io:commons-io:2.6", - "org.apache.httpcomponents:httpmime:4.5.12", - "io.springfox:springfox-swagger-ui:2.9.2", - "io.springfox:springfox-swagger2:2.9.2" - ) - - testCompile( - "org.springframework:spring-test:${springVersion}", - "org.springframework.security:spring-security-test:${springVersion}", - "org.springframework.boot:spring-boot-test-autoconfigure:${springBootVersion}", - "org.springframework.boot:spring-boot-test:${springBootVersion}", - "junit:junit:4.13.1", - "org.mockito:mockito-all:1.10.19", - ) - - - testRuntimeOnly( - "com.h2database:h2:1.4.200", - "org.springframework.restdocs:spring-restdocs-mockmvc", - ) -} - -repositories { - mavenCentral() -} - -checkstyle { - toolVersion = "8.11" - ignoreFailures = false - maxWarnings = 0 - configFile = project(":").file("config/checkstyle/checkstyle.xml") - configProperties = ["suppressionFile": project(":").file("config/checkstyle/suppressions.xml")] -} - -pmd { - toolVersion = "6.21.0" - consoleOutput = false - ignoreFailures = false - rulePriority = 5 - ruleSets = [] - ruleSetConfig = resources.text.fromFile("./config/pmd/ruleset.xml") -} - -jacoco { - toolVersion = "0.8.5" -} - -jacocoTestReport { - reports { - html.enabled = true - } -} -// Is not perfect, but gives you an idea of what needs to be changed -gradleLint { - rules = ["dependency-parentheses", "archaic-wrapper"] -} diff --git a/backend/config/checkstyle/checkstyle.xml b/backend/config/checkstyle/checkstyle.xml deleted file mode 100644 index 3f09dd734..000000000 --- a/backend/config/checkstyle/checkstyle.xml +++ /dev/null @@ -1,232 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/backend/config/checkstyle/suppressions.xml b/backend/config/checkstyle/suppressions.xml deleted file mode 100644 index 9b5539341..000000000 --- a/backend/config/checkstyle/suppressions.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - diff --git a/backend/config/pmd/ruleset.xml b/backend/config/pmd/ruleset.xml deleted file mode 100755 index 7672c612f..000000000 --- a/backend/config/pmd/ruleset.xml +++ /dev/null @@ -1,90 +0,0 @@ - - - - - - PMD rule set for Gamma. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/backend/dev.Dockerfile b/backend/dev.Dockerfile deleted file mode 100644 index 431553878..000000000 --- a/backend/dev.Dockerfile +++ /dev/null @@ -1,21 +0,0 @@ -FROM gradle:6.3.0-jdk11 -#Gradle docker has gradle user as default -USER root - - -WORKDIR /app - -#db is used to separate development and production databases - -# Environment variables needed for Gamma to run in Production env, These must be changed!!. -COPY . /app - -RUN mkdir -p /app -RUN chown -R gradle /app - -USER gradle - -RUN gradle :build -x test -x pmdMain -x checkstyleMain -x pmdTest -# This probably should not have a static path, but instead build in a custom path. -CMD sleep 5 && java -jar -Dspring.profiles.active=development build/libs/gamma-0.9.0-SNAPSHOT.jar - diff --git a/backend/dockerfile b/backend/dockerfile deleted file mode 100644 index 59eed412a..000000000 --- a/backend/dockerfile +++ /dev/null @@ -1,23 +0,0 @@ -FROM gradle:6.3.0-jdk11 -#Gradle docker has gradle user as default -USER root - - -WORKDIR /app - -#db is used to separate development and production databases - -# Environment variables needed for Gamma to run in Production env, These must be changed!!. -COPY . /app - -ENV LOGGING_FILE log/production.log - -RUN mkdir -p /app -RUN chown -R gradle /app - -USER gradle - -RUN gradle :build -x test -x pmdMain -x checkstyleMain -x pmdTest -# This probably should not have a static path, but instead build in a custom path. -CMD sleep 5 && java -jar -Dspring.profiles.active=production build/libs/gamma-0.9.0-SNAPSHOT.jar - diff --git a/backend/gradle/wrapper/gradle-wrapper.jar b/backend/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index e708b1c02..000000000 Binary files a/backend/gradle/wrapper/gradle-wrapper.jar and /dev/null differ diff --git a/backend/gradlew b/backend/gradlew deleted file mode 100755 index 4f906e0c8..000000000 --- a/backend/gradlew +++ /dev/null @@ -1,185 +0,0 @@ -#!/usr/bin/env sh - -# -# Copyright 2015 the original author or authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -############################################################################## -## -## Gradle start up script for UN*X -## -############################################################################## - -# Attempt to set APP_HOME -# Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null - -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" - -warn () { - echo "$*" -} - -die () { - echo - echo "$*" - echo - exit 1 -} - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi -fi - -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi - -# For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi - # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" - fi - i=`expr $i + 1` - done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac -fi - -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` - -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" - -exec "$JAVACMD" "$@" diff --git a/backend/settings.gradle b/backend/settings.gradle deleted file mode 100644 index a6a599a2f..000000000 --- a/backend/settings.gradle +++ /dev/null @@ -1 +0,0 @@ -rootProject.name = 'gamma' diff --git a/backend/src/main/java/it/chalmers/gamma/GammaApplication.java b/backend/src/main/java/it/chalmers/gamma/GammaApplication.java deleted file mode 100644 index 84d4f4b6f..000000000 --- a/backend/src/main/java/it/chalmers/gamma/GammaApplication.java +++ /dev/null @@ -1,13 +0,0 @@ -package it.chalmers.gamma; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SuppressWarnings("PMD.UseUtilityClass") -@SpringBootApplication -public class GammaApplication { - - public static void main(String[] args) { - SpringApplication.run(GammaApplication.class, args); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/bootstrap/AdminBootstrap.java b/backend/src/main/java/it/chalmers/gamma/bootstrap/AdminBootstrap.java deleted file mode 100644 index 00ecd24d9..000000000 --- a/backend/src/main/java/it/chalmers/gamma/bootstrap/AdminBootstrap.java +++ /dev/null @@ -1,90 +0,0 @@ -package it.chalmers.gamma.bootstrap; - -import it.chalmers.gamma.db.entity.Text; -import it.chalmers.gamma.domain.GroupType; -import it.chalmers.gamma.domain.dto.authority.AuthorityLevelDTO; -import it.chalmers.gamma.domain.dto.group.FKITGroupDTO; -import it.chalmers.gamma.domain.dto.group.FKITSuperGroupDTO; -import it.chalmers.gamma.domain.dto.post.PostDTO; -import it.chalmers.gamma.domain.dto.user.ITUserDTO; - -import java.time.Year; -import java.util.Calendar; -import java.util.GregorianCalendar; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.stereotype.Component; - -@Component -public class AdminBootstrap { - - private static final Logger LOGGER = LoggerFactory.getLogger(AdminBootstrap.class); - - private final BootstrapConfig config; - - private final BootstrapServiceHelper helper; - - public AdminBootstrap(BootstrapConfig bootstrapConfig, BootstrapServiceHelper bootstrapServiceHelper) { - this.config = bootstrapConfig; - this.helper = bootstrapServiceHelper; - } - - void runAdminBootstrap() { - String admin = "admin"; - if (!this.helper.getUserService().userExists(admin)) { - LOGGER.info("Creating admin user, cid:admin, password: " + this.config.getPassword()); - Text description = new Text(); - String descriptionText = "Super admin group, do not add anything to this group," - + " as it is a way to always keep a privileged user on startup"; - description.setEn(descriptionText); - description.setSv(descriptionText); - Text function = new Text(); - function.setEn(descriptionText); - function.setSv(descriptionText); - String adminMail = "admin@chalmers.it"; - FKITSuperGroupDTO superGroupCreation = - new FKITSuperGroupDTO( - "superadmin", - "super admin", - GroupType.COMMITTEE, - adminMail - ); - Calendar end = new GregorianCalendar(); - end.set(2099, Calendar.DECEMBER, 31); - Calendar start = new GregorianCalendar(); - start.setTimeInMillis(System.currentTimeMillis()); - FKITSuperGroupDTO superGroup = - this.helper.getSuperGroupService().createSuperGroup(superGroupCreation); - FKITGroupDTO group = new FKITGroupDTO( - start, end, description, adminMail, function, - "superadmin", "superAdmin", null, superGroup - ); - group = this.helper.getGroupService().createGroup(group); - Text p = new Text(); - p.setSv(admin); - p.setEn(admin); - PostDTO post = this.helper.getPostService().addPost(p); - ITUserDTO user = this.helper.getUserService().createUser( - admin, - admin, - admin, - admin, - Year.of(2018), - true, - adminMail, - this.config.getPassword() - ); - this.helper.getMembershipService().addUserToGroup( - group, - user, - post, - admin - ); // This might break on a new year - AuthorityLevelDTO authorityLevel = this.helper.getAuthorityLevelService().addAuthorityLevel(admin); - this.helper.getAuthorityService().createAuthority(superGroup, post, authorityLevel); - LOGGER.info("admin user created!"); - } - } - -} diff --git a/backend/src/main/java/it/chalmers/gamma/bootstrap/Bootstrap.java b/backend/src/main/java/it/chalmers/gamma/bootstrap/Bootstrap.java deleted file mode 100644 index de6e7c789..000000000 --- a/backend/src/main/java/it/chalmers/gamma/bootstrap/Bootstrap.java +++ /dev/null @@ -1,63 +0,0 @@ -package it.chalmers.gamma.bootstrap; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.boot.CommandLineRunner; -import org.springframework.stereotype.Component; - - -/** - * This class adds a superadmin on startup if one does not already exist, to make sure one - * always exists, and to make development easier. It also adds mock data from /mock/mock.json - */ -@Component -public class Bootstrap implements CommandLineRunner { - - private static final Logger LOGGER = LoggerFactory.getLogger(Bootstrap.class); - - private final BootstrapConfig config; - - private final BootstrapServiceHelper helper; - - private final AdminBootstrap adminBootstrap; - - private final MockBootstrap mockBootstrap; - - private final TestClientBootstrap testClientBootstrap; - - private final MiscBootstrap miscBootstrap; - - public Bootstrap(BootstrapConfig config, - BootstrapServiceHelper helper, - AdminBootstrap adminBootstrap, - MockBootstrap mockBootstrap, - TestClientBootstrap testClientBootstrap, MiscBootstrap miscBootstrap) { - this.config = config; - this.helper = helper; - this.adminBootstrap = adminBootstrap; - this.mockBootstrap = mockBootstrap; - this.testClientBootstrap = testClientBootstrap; - this.miscBootstrap = miscBootstrap; - } - - @Override - public void run(String... args) { - this.miscBootstrap.runImageBootstrap(); - if (shouldRunBootstrap()) { - LOGGER.info("No admin user, running Bootstrap..."); - this.adminBootstrap.runAdminBootstrap(); - if (this.config.isMocking()) { - LOGGER.info("Mock enabled..."); - this.mockBootstrap.runMockBootstrap(); - this.testClientBootstrap.runOauthClient(); - LOGGER.info("Mock finished!"); - } - LOGGER.info("Bootstrap finished!"); - } - } - - private boolean shouldRunBootstrap() { - return !this.helper.getUserService().userExists("admin"); - } - -} diff --git a/backend/src/main/java/it/chalmers/gamma/bootstrap/BootstrapConfig.java b/backend/src/main/java/it/chalmers/gamma/bootstrap/BootstrapConfig.java deleted file mode 100644 index 371b9012e..000000000 --- a/backend/src/main/java/it/chalmers/gamma/bootstrap/BootstrapConfig.java +++ /dev/null @@ -1,72 +0,0 @@ -package it.chalmers.gamma.bootstrap; - -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Configuration; - -@Configuration -public class BootstrapConfig { - - @Value("${application.standard-admin-account.password}") - private String password; - - @Value("${application.default-oauth2-client.client-name}") - private String oauth2ClientName; - - @Value("${application.default-oauth2-client.client-id}") - private String oauth2ClientId; - - @Value("${application.default-oauth2-client.client-secret}") - private String oauth2ClientSecret; - - @Value("${application.default-oauth2-client.redirect-uri}") - private String oauth2ClientRedirectUri; - - @Value("${application.default-oauth2-client.api-key}") - private String oauth2ClientApiKey; - - @Value("${application.mocking}") - private boolean mocking; - - @Value("${application.auth.accessTokenValidityTime}") // TODO Fix this - private int accessTokenValidityTime; - - @Value("${application.auth.refreshTokenValidityTime}") - private int refreshTokenValidityTime; - - public String getPassword() { - return this.password; - } - - public String getOauth2ClientName() { - return this.oauth2ClientName; - } - - public String getOauth2ClientId() { - return this.oauth2ClientId; - } - - public String getOauth2ClientSecret() { - return this.oauth2ClientSecret; - } - - public String getOauth2ClientRedirectUri() { - return this.oauth2ClientRedirectUri; - } - - public String getOauth2ClientApiKey() { - return this.oauth2ClientApiKey; - } - - public boolean isMocking() { - return this.mocking; - } - - public int getAccessTokenValidityTime() { - return this.accessTokenValidityTime; - } - - public int getRefreshTokenValidityTime() { - return this.refreshTokenValidityTime; - } - -} diff --git a/backend/src/main/java/it/chalmers/gamma/bootstrap/BootstrapServiceHelper.java b/backend/src/main/java/it/chalmers/gamma/bootstrap/BootstrapServiceHelper.java deleted file mode 100644 index cca80733c..000000000 --- a/backend/src/main/java/it/chalmers/gamma/bootstrap/BootstrapServiceHelper.java +++ /dev/null @@ -1,93 +0,0 @@ -package it.chalmers.gamma.bootstrap; - -import it.chalmers.gamma.service.ApiKeyService; -import it.chalmers.gamma.service.AuthorityLevelService; -import it.chalmers.gamma.service.AuthorityService; -import it.chalmers.gamma.service.FKITGroupService; -import it.chalmers.gamma.service.FKITSuperGroupService; -import it.chalmers.gamma.service.ITClientService; -import it.chalmers.gamma.service.ITUserService; -import it.chalmers.gamma.service.MembershipService; -import it.chalmers.gamma.service.PostService; - -import org.springframework.stereotype.Component; - -@SuppressWarnings({"PMD.ExcessiveParameterList"}) -@Component() -public final class BootstrapServiceHelper { - - private final ITUserService userService; - - private final FKITGroupService groupService; - - private final AuthorityLevelService authorityLevelService; - - private final PostService postService; - - private final MembershipService membershipService; - - private final AuthorityService authorityService; - - private final ITClientService itClientService; - - - private final ApiKeyService apiKeyService; - - private final FKITSuperGroupService superGroupService; - - public BootstrapServiceHelper(ITUserService userService, - FKITGroupService groupService, - AuthorityLevelService authorityLevelService, - PostService postService, - MembershipService membershipService, - AuthorityService authorityService, - ITClientService itClientService, - ApiKeyService apiKeyService, - FKITSuperGroupService superGroupService) { - this.userService = userService; - this.groupService = groupService; - this.authorityLevelService = authorityLevelService; - this.postService = postService; - this.membershipService = membershipService; - this.authorityService = authorityService; - this.itClientService = itClientService; - this.apiKeyService = apiKeyService; - this.superGroupService = superGroupService; - } - - public ITUserService getUserService() { - return this.userService; - } - - public FKITGroupService getGroupService() { - return this.groupService; - } - - public AuthorityLevelService getAuthorityLevelService() { - return this.authorityLevelService; - } - - public PostService getPostService() { - return this.postService; - } - - public MembershipService getMembershipService() { - return this.membershipService; - } - - public AuthorityService getAuthorityService() { - return this.authorityService; - } - - public ITClientService getItClientService() { - return this.itClientService; - } - - public ApiKeyService getApiKeyService() { - return this.apiKeyService; - } - - public FKITSuperGroupService getSuperGroupService() { - return this.superGroupService; - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/bootstrap/MiscBootstrap.java b/backend/src/main/java/it/chalmers/gamma/bootstrap/MiscBootstrap.java deleted file mode 100644 index 5a22167b8..000000000 --- a/backend/src/main/java/it/chalmers/gamma/bootstrap/MiscBootstrap.java +++ /dev/null @@ -1,44 +0,0 @@ -package it.chalmers.gamma.bootstrap; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.core.io.Resource; -import org.springframework.stereotype.Component; - -@Component -public class MiscBootstrap { - - @Value("classpath:image/default.jpg") - private Resource defaultResourceFile; - - @Value("${application.files.path}") - private String targetDir; - - private static final Logger LOGGER = LoggerFactory.getLogger(MiscBootstrap.class); - - - public void runImageBootstrap() { - File targetFile = new File(String.format("%s/%s", this.targetDir, "default.jpg")); - if (!targetFile.exists()) { - LOGGER.info("Default Avatar file does not exist, creating a new one"); - try { - File defaultFile = this.defaultResourceFile.getFile(); - if (defaultFile.isFile()) { - File targetDirFile = new File(this.targetDir); - if (!targetDirFile.mkdir()) { - LOGGER.warn("Could not create target directory"); - } - Files.copy(defaultFile.toPath(), targetFile.toPath()); - } else { - throw new IOException(); - } - } catch (IOException e) { - LOGGER.warn("Could not add a default avatar image"); - } - } - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/bootstrap/MockBootstrap.java b/backend/src/main/java/it/chalmers/gamma/bootstrap/MockBootstrap.java deleted file mode 100644 index 24de65c78..000000000 --- a/backend/src/main/java/it/chalmers/gamma/bootstrap/MockBootstrap.java +++ /dev/null @@ -1,204 +0,0 @@ -package it.chalmers.gamma.bootstrap; - -import com.fasterxml.jackson.databind.ObjectMapper; - -import it.chalmers.gamma.domain.dto.group.FKITGroupDTO; -import it.chalmers.gamma.domain.dto.group.FKITSuperGroupDTO; -import it.chalmers.gamma.domain.dto.post.PostDTO; -import it.chalmers.gamma.domain.dto.user.ITUserDTO; -import it.chalmers.gamma.util.mock.MockData; - -import java.io.IOException; -import java.time.Instant; -import java.time.ZoneOffset; -import java.time.ZonedDateTime; -import java.time.temporal.ChronoUnit; -import java.util.Calendar; -import java.util.GregorianCalendar; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.core.io.Resource; -import org.springframework.core.io.ResourceLoader; -import org.springframework.stereotype.Component; - -@Component -public class MockBootstrap { - - private static final Logger LOGGER = LoggerFactory.getLogger(MockBootstrap.class); - - private final BootstrapServiceHelper helper; - - private final ResourceLoader resourceLoader; - - public MockBootstrap(BootstrapServiceHelper helper, ResourceLoader resourceLoader) { - this.helper = helper; - this.resourceLoader = resourceLoader; - } - - void runMockBootstrap() { - LOGGER.info("Running mock..."); - - Resource resource = this.resourceLoader.getResource("classpath:/mock/mock.json"); - ObjectMapper objectMapper = new ObjectMapper(); - MockData mockData = null; - try { - mockData = objectMapper.readValue(resource.getInputStream(), MockData.class); - } catch (IOException e) { - LOGGER.error(e.getMessage()); - LOGGER.error("Error when trying to read mock.json"); - return; - } - - final Map users = createUsers(mockData); - LOGGER.info("Users created"); - - final Map posts = createPosts(mockData); - LOGGER.info("Posts created"); - - final Map superGroups = createSuperGroups(mockData); - LOGGER.info("Super groups created"); - - createGroups(mockData, users, posts, superGroups); - LOGGER.info("Groups created"); - - LOGGER.info("Mock finished"); - } - - private Map createUsers(MockData mockData) { - Map users = new HashMap<>(); - - mockData.getUsers().forEach(mockUser -> { - ITUserDTO user = this.helper.getUserService().createUser( - mockUser.getId(), - mockUser.getNick(), - mockUser.getFirstName(), - mockUser.getLastName(), - mockUser.getCid(), - mockUser.getAcceptanceYear(), - true, - mockUser.getCid() + "@student.chalmers.it", - "password" - ); - - users.put(user.getId(), user); - }); - - return users; - } - - private Map createPosts(MockData mockData) { - Map posts = new HashMap<>(); - - mockData.getPosts().forEach(mockPost -> { - PostDTO post = this.helper.getPostService().addPost( - mockPost.getId(), - mockPost.getPostName(), - "" - ); - - posts.put(post.getId(), post); - }); - - return posts; - } - - private Map createGroups( - MockData mockData, - Map users, - Map posts, - Map superGroups) { - - Calendar activeGroupBecomesActive = toCalendar( - Instant.now().minus(1, ChronoUnit.DAYS) - ); - Calendar activeGroupBecomesInactive = toCalendar( - Instant.now().plus(365, ChronoUnit.DAYS) - ); - - Calendar inactiveGroupBecomesActive = toCalendar( - Instant.now() - .minus(366, ChronoUnit.DAYS) - ); - Calendar inactiveGroupBecomesInactive = toCalendar( - Instant.now().minus(1, ChronoUnit.DAYS) - ); - - int activeYear = activeGroupBecomesActive.get(Calendar.YEAR); - int inactiveYear = inactiveGroupBecomesActive.get(Calendar.YEAR); - - Map groups = new HashMap<>(); - - mockData.getGroups().forEach(mockGroup -> { - int year = mockGroup.isActive() ? activeYear : inactiveYear; - String name = mockGroup.getName() + year; - String prettyName = mockGroup.getPrettyName() + year; - Calendar active = mockGroup.isActive() - ? activeGroupBecomesActive - : inactiveGroupBecomesActive; - Calendar inactive = mockGroup.isActive() - ? activeGroupBecomesInactive - : inactiveGroupBecomesInactive; - - FKITGroupDTO group = new FKITGroupDTO( - mockGroup.getId(), - active, - inactive, - mockGroup.getDescription(), - name + "@chalmers.it", - mockGroup.getFunction(), - name, - prettyName, - null, - superGroups.get(mockGroup.getSuperGroup()) - ); - - groups.put(group.getId(), group); - - this.helper.getGroupService().createGroup(group); - - mockGroup.getMembers().forEach(mockMembership -> { - PostDTO post = posts.get(mockMembership.getPostId()); - ITUserDTO user = users.get(mockMembership.getUserId()); - - this.helper.getMembershipService().addUserToGroup( - group, - user, - post, - mockMembership.getUnofficialPostName() - ); - }); - }); - - return groups; - } - - private Map createSuperGroups(MockData mockData) { - Map superGroupDTOMap = new HashMap<>(); - mockData.getSuperGroups().forEach(mockSuperGroup -> { - FKITSuperGroupDTO superGroup = new FKITSuperGroupDTO( - mockSuperGroup.getId(), - mockSuperGroup.getName(), - mockSuperGroup.getPrettyName(), - mockSuperGroup.getType(), - mockSuperGroup.getName() + "@chalmers.it" - ); - - superGroupDTOMap.put(superGroup.getId(), this.helper.getSuperGroupService().createSuperGroup(superGroup)); - }); - return superGroupDTOMap; - } - - private Calendar toCalendar(Instant i) { - return GregorianCalendar.from( - ZonedDateTime.ofInstant( - i, - ZoneOffset.UTC - ) - ); - } - -} diff --git a/backend/src/main/java/it/chalmers/gamma/bootstrap/TestClientBootstrap.java b/backend/src/main/java/it/chalmers/gamma/bootstrap/TestClientBootstrap.java deleted file mode 100644 index 49874ecd0..000000000 --- a/backend/src/main/java/it/chalmers/gamma/bootstrap/TestClientBootstrap.java +++ /dev/null @@ -1,55 +0,0 @@ -package it.chalmers.gamma.bootstrap; - -import it.chalmers.gamma.db.entity.ITClient; -import it.chalmers.gamma.db.entity.Text; - -import java.time.Instant; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.stereotype.Component; - -@Component -class TestClientBootstrap { - - private static final Logger LOGGER = LoggerFactory.getLogger(TestClientBootstrap.class); - - private final BootstrapConfig config; - - private final BootstrapServiceHelper helper; - - public TestClientBootstrap(BootstrapConfig bootstrapConfig, BootstrapServiceHelper bootstrapServiceHelper) { - this.config = bootstrapConfig; - this.helper = bootstrapServiceHelper; - } - - void runOauthClient() { - if (!this.helper.getItClientService().clientExists(this.config.getOauth2ClientId())) { - LOGGER.info("Creating test client..."); - ITClient client = new ITClient(); - client.setName(this.config.getOauth2ClientName()); - Text description = new Text(); - description.setEn("Client for mocking " + this.config.getOauth2ClientName()); - description.setSv("Klient för att mocka " + this.config.getOauth2ClientName()); - client.setDescription(description); - client.setWebServerRedirectUri(this.config.getOauth2ClientRedirectUri()); - client.setCreatedAt(Instant.now()); - client.setLastModifiedAt(Instant.now()); - client.setAccessTokenValidity(this.config.getAccessTokenValidityTime()); - client.setAutoApprove(true); - client.setRefreshTokenValidity(this.config.getRefreshTokenValidityTime()); - client.setClientId(this.config.getOauth2ClientId()); - client.setClientSecret("{noop}" + this.config.getOauth2ClientSecret()); - this.helper.getItClientService().addITClient(client); - Text apiDescription = new Text(); - apiDescription.setSv("API key"); - apiDescription.setEn("API key"); - this.helper.getApiKeyService().addApiKey( - this.config.getOauth2ClientName(), - this.config.getOauth2ClientApiKey(), - apiDescription - ); - LOGGER.info("Test client created!"); - } - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/config/CookieConfig.java b/backend/src/main/java/it/chalmers/gamma/config/CookieConfig.java deleted file mode 100644 index e2302cf6e..000000000 --- a/backend/src/main/java/it/chalmers/gamma/config/CookieConfig.java +++ /dev/null @@ -1,41 +0,0 @@ -package it.chalmers.gamma.config; - -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; -import org.springframework.session.web.http.CookieSerializer; -import org.springframework.session.web.http.DefaultCookieSerializer; -import org.springframework.stereotype.Component; - -/** - * All other cookie config can be found in application.yml and application-production.yml - */ -@Component -public class CookieConfig { - - @Value("${application.production}") - private boolean production; - - @Value("${application.cookie.domain}") - private String domain; - - @Value("${application.cookie.path}") - private String path; - - @Value("${application.cookie.validity-time}") - private int validityTime; - - //Remember Me functionality is in WebSecurityConfig - @Bean - public CookieSerializer cookieSerializer() { - DefaultCookieSerializer serializer = new DefaultCookieSerializer(); - serializer.setSameSite("STRICT"); - serializer.setUseSecureCookie(this.production); - serializer.setCookieName("gamma"); - serializer.setDomainName(this.domain); - serializer.setUseHttpOnlyCookie(true); - serializer.setCookiePath(this.path); - serializer.setCookieMaxAge(this.validityTime); - return serializer; - } - -} diff --git a/backend/src/main/java/it/chalmers/gamma/config/CustomPasswordEncoder.java b/backend/src/main/java/it/chalmers/gamma/config/CustomPasswordEncoder.java deleted file mode 100644 index 7a860c7d0..000000000 --- a/backend/src/main/java/it/chalmers/gamma/config/CustomPasswordEncoder.java +++ /dev/null @@ -1,14 +0,0 @@ -package it.chalmers.gamma.config; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.security.crypto.factory.PasswordEncoderFactories; -import org.springframework.security.crypto.password.PasswordEncoder; - -@Configuration -public class CustomPasswordEncoder { - @Bean - public PasswordEncoder passwordEncoder() { - return PasswordEncoderFactories.createDelegatingPasswordEncoder(); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/config/MvcConfig.java b/backend/src/main/java/it/chalmers/gamma/config/MvcConfig.java deleted file mode 100644 index 055af6f50..000000000 --- a/backend/src/main/java/it/chalmers/gamma/config/MvcConfig.java +++ /dev/null @@ -1,31 +0,0 @@ -package it.chalmers.gamma.config; - -import org.springframework.context.annotation.Configuration; -import org.springframework.web.servlet.config.annotation.EnableWebMvc; -import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; - -@Configuration -@EnableWebMvc -public class MvcConfig implements WebMvcConfigurer { - - @Override - public void addResourceHandlers(ResourceHandlerRegistry registry) { - registry.addResourceHandler("/css/**") - .addResourceLocations("classpath:/static/css/"); - - registry.addResourceHandler("/js/**") - .addResourceLocations("classpath:/static/js/"); - - registry.addResourceHandler("/img/**") - .addResourceLocations("classpath:/static/img/"); - - registry.addResourceHandler("swagger-ui.html") - .addResourceLocations("classpath:/META-INF/resources/"); - - registry.addResourceHandler("/webjars/**") - .addResourceLocations("classpath:/META-INF/resources/webjars/"); - } - - -} diff --git a/backend/src/main/java/it/chalmers/gamma/config/OAuth2Config.java b/backend/src/main/java/it/chalmers/gamma/config/OAuth2Config.java deleted file mode 100644 index f47aada8c..000000000 --- a/backend/src/main/java/it/chalmers/gamma/config/OAuth2Config.java +++ /dev/null @@ -1,133 +0,0 @@ -package it.chalmers.gamma.config; - -import it.chalmers.gamma.service.ITClientService; -import it.chalmers.gamma.service.ITUserApprovalService; -import it.chalmers.gamma.service.ITUserService; - -import java.net.MalformedURLException; -import java.net.URL; -import java.util.Arrays; -import java.util.Date; -import java.util.HashMap; -import java.util.Map; - -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Primary; -import org.springframework.security.authentication.AuthenticationManager; -import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken; -import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer; -import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter; -import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer; -import org.springframework.security.oauth2.config.annotation.web.configuration.EnableOAuth2Client; -import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer; -import org.springframework.security.oauth2.provider.token.DefaultTokenServices; -import org.springframework.security.oauth2.provider.token.TokenEnhancer; -import org.springframework.security.oauth2.provider.token.TokenEnhancerChain; -import org.springframework.security.oauth2.provider.token.TokenStore; -import org.springframework.security.oauth2.provider.token.store.IssuerClaimVerifier; -import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter; -import org.springframework.security.oauth2.provider.token.store.JwtClaimsSetVerifier; -import org.springframework.security.oauth2.provider.token.store.JwtTokenStore; - -@Configuration -@EnableAuthorizationServer -@EnableOAuth2Client -public class OAuth2Config extends AuthorizationServerConfigurerAdapter { - - @Qualifier("userDetailsService") - private final ITUserService userDetailsService; - - @Qualifier("authenticationManagerBean") - private final AuthenticationManager authenticationManager; - - @Qualifier("clientDetailsService") - private final ITClientService clientDetailsService; - - private final ITUserApprovalService itUserApprovalService; - - @Value("${security.jwt.token.secret-key}") - private String signingKey; - - @Value("${security.jwt.token.issuer}") - private String issuer; - - //@Value("${security.jwt.token.audience}") - //private String audience; - - @Value("${security.jwt.token.expire-length}") - private long expiration; - - public OAuth2Config(ITUserService userDetailsService, AuthenticationManager authenticationManager, - ITClientService clientDetailsService, ITUserApprovalService itUserApprovalService) { - this.userDetailsService = userDetailsService; - this.authenticationManager = authenticationManager; - this.clientDetailsService = clientDetailsService; - this.itUserApprovalService = itUserApprovalService; - } - - - @Override - public void configure(AuthorizationServerEndpointsConfigurer configurer) { - TokenEnhancerChain enhancerChain = new TokenEnhancerChain(); - enhancerChain.setTokenEnhancers(Arrays.asList(issuerTokenEnhancer(), accessTokenConverter())); - configurer.tokenEnhancer(enhancerChain) - .accessTokenConverter(accessTokenConverter()) - .authenticationManager(this.authenticationManager) - .userDetailsService(this.userDetailsService) - .approvalStore(this.itUserApprovalService); - } - - @Override - public void configure(ClientDetailsServiceConfigurer clients) throws Exception { - clients.withClientDetails(this.clientDetailsService); - } - - @Bean - public TokenEnhancer issuerTokenEnhancer() { - return (accessToken, authentication) -> { - - Map additionalInfo = new HashMap<>(); - additionalInfo.put("iss", this.issuer); - // additionalInfo.put("aud", this.audience); - ((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo); - ((DefaultOAuth2AccessToken) accessToken).setExpiration( - new Date(System.currentTimeMillis() + this.expiration * 1000)); - return accessToken; - }; - } - - - @Bean - @Primary - public DefaultTokenServices tokenServices() { - final DefaultTokenServices defaultTokenServices = new DefaultTokenServices(); - defaultTokenServices.setTokenStore(tokenStore()); - defaultTokenServices.setSupportRefreshToken(true); - return defaultTokenServices; - } - - @Bean - public TokenStore tokenStore() { - return new JwtTokenStore(accessTokenConverter()); - } - - @Bean - public JwtAccessTokenConverter accessTokenConverter() { - final JwtAccessTokenConverter converter = new JwtAccessTokenConverter(); - converter.setSigningKey(this.signingKey); - return converter; - } - - @Bean - public JwtClaimsSetVerifier issuerClaimVerifier() { - try { - return new IssuerClaimVerifier(new URL(this.issuer)); - } catch (MalformedURLException e) { - throw new RuntimeException(e); - } - } - -} diff --git a/backend/src/main/java/it/chalmers/gamma/config/SpringFoxConfig.java b/backend/src/main/java/it/chalmers/gamma/config/SpringFoxConfig.java deleted file mode 100644 index 3680c2b1c..000000000 --- a/backend/src/main/java/it/chalmers/gamma/config/SpringFoxConfig.java +++ /dev/null @@ -1,22 +0,0 @@ -package it.chalmers.gamma.config; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import springfox.documentation.builders.PathSelectors; -import springfox.documentation.builders.RequestHandlerSelectors; -import springfox.documentation.spi.DocumentationType; -import springfox.documentation.spring.web.plugins.Docket; -import springfox.documentation.swagger2.annotations.EnableSwagger2; - -@Configuration -@EnableSwagger2 -public class SpringFoxConfig { - @Bean - public Docket api() { - return new Docket(DocumentationType.SWAGGER_2) - .select() - .apis(RequestHandlerSelectors.any()) - .paths(PathSelectors.any()) - .build(); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/config/WebSecurityConfig.java b/backend/src/main/java/it/chalmers/gamma/config/WebSecurityConfig.java deleted file mode 100644 index 0078d13ea..000000000 --- a/backend/src/main/java/it/chalmers/gamma/config/WebSecurityConfig.java +++ /dev/null @@ -1,250 +0,0 @@ -package it.chalmers.gamma.config; - -import it.chalmers.gamma.domain.dto.group.FKITGroupDTO; -import it.chalmers.gamma.filter.AuthenticationFilterConfigurer; -import it.chalmers.gamma.filter.OauthRedirectFilter; -import it.chalmers.gamma.handlers.LoginRedirectHandler; -import it.chalmers.gamma.service.ApiKeyService; -import it.chalmers.gamma.service.AuthorityService; -import it.chalmers.gamma.service.FKITGroupService; -import it.chalmers.gamma.service.ITUserService; - -import it.chalmers.gamma.service.PasswordResetService; -import java.util.List; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.core.annotation.Order; -import org.springframework.http.HttpStatus; -import org.springframework.security.authentication.AuthenticationManager; -import org.springframework.security.authentication.dao.DaoAuthenticationProvider; -import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; -import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; -import org.springframework.security.config.http.SessionCreationPolicy; -import org.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer; -import org.springframework.security.web.authentication.HttpStatusEntryPoint; -import org.springframework.security.web.authentication.www.BasicAuthenticationFilter; -import org.springframework.security.web.util.matcher.AntPathRequestMatcher; - -@Configuration -@EnableResourceServer -@Order(2) -public class WebSecurityConfig extends WebSecurityConfigurerAdapter { - - @Value("${security.jwt.token.secret-key}") - private String secretKey; - - @Value("${security.jwt.token.issuer}") - private String issuer; - - //@Value("${application.production}") - //private boolean inProduction; - - private final ITUserService itUserService; - private final AuthorityService authorityService; - private final ApiKeyService apiKeyService; - private final PasswordResetService passwordResetService; - private final PasswordEncoder passwordEncoder; - private final FKITGroupService fkitGroupService; - @Value("${application.frontend-client-details.successful-login-uri}") - private String baseFrontendUrl; - private final LoginRedirectHandler loginRedirectHandler; - - private static final Logger LOGGER = LoggerFactory.getLogger(WebSecurityConfig.class); - - public WebSecurityConfig(ITUserService itUserService, AuthorityService authorityService, - ApiKeyService apiKeyService, - PasswordResetService passwordResetService, - PasswordEncoder passwordEncoder, - FKITGroupService fkitGroupService, - LoginRedirectHandler loginRedirectHandler) { - this.itUserService = itUserService; - this.authorityService = authorityService; - this.apiKeyService = apiKeyService; - this.passwordResetService = passwordResetService; - this.passwordEncoder = passwordEncoder; - this.fkitGroupService = fkitGroupService; - this.loginRedirectHandler = loginRedirectHandler; - } - - @Override - protected void configure(HttpSecurity http) { - //if (!this.inProduction) { - disableCsrf(http); - // } - setSessionManagementToIfRequired(http); - addAuthenticationFilter(http); - addFormLogin(http); - setPermittedPaths(http); - setAdminPaths(http); - setTheRestOfPathsToAuthenticatedOnly(http); - addRedirectFilter(http); - } - - - @Override - protected void configure(AuthenticationManagerBuilder auth) throws Exception { - auth.authenticationProvider(authProvider()); - } - - @Bean - @Override - public AuthenticationManager authenticationManagerBean() throws Exception { - return super.authenticationManagerBean(); - } - - @Bean - public DaoAuthenticationProvider authProvider() { - DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider(); - authProvider.setUserDetailsService(this.itUserService); - authProvider.setPasswordEncoder(this.passwordEncoder); - return authProvider; - } - - private void disableCsrf(HttpSecurity http) { - try { - http - .csrf().disable(); - } catch (Exception e) { - LOGGER.error("Something went wrong when disabling csrf"); - LOGGER.error(e.getMessage()); - } - } - - private void addRedirectFilter(HttpSecurity http) { - try { - OauthRedirectFilter oauthRedirectFilter = new OauthRedirectFilter(); - http.addFilterBefore(oauthRedirectFilter, BasicAuthenticationFilter.class); - } catch (Exception e) { - LOGGER.error("Something went wrong when adding redirects"); - LOGGER.error(e.getMessage()); - } - } - - private void setSessionManagementToIfRequired(HttpSecurity http) { - try { - http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED); - } catch (Exception e) { - LOGGER.error("Something went wrong when setting SessionManagement to 'if required'"); - LOGGER.error(e.getMessage()); - } - } - - private void addAuthenticationFilter(HttpSecurity http) { - try { - http.apply( - new AuthenticationFilterConfigurer( - this.itUserService, - this.secretKey, - this.issuer, - this.apiKeyService, - this.passwordResetService, - this.baseFrontendUrl - ) - ); - } catch (Exception e) { - LOGGER.error("Something went wrong when adding JwtAuthenticationFilter"); - LOGGER.error(e.getMessage()); - } - } - - private void addFormLogin(HttpSecurity http) { - try { - http - .formLogin() - .loginPage("/login") - .successHandler(this.loginRedirectHandler) - .permitAll() - .and() - .logout() - .logoutRequestMatcher(new AntPathRequestMatcher("/logout")) - .logoutSuccessUrl("/login") - .and() - .httpBasic(); - - - } catch (Exception e) { - LOGGER.error("Something went wrong when adding form login"); - LOGGER.error(e.getMessage()); - } - } - - private void setPermittedPaths(HttpSecurity http) { - try { - - String[] permittedPaths = { - "/login", - "/oauth/authorize", - "/oauth/token", - "/users/create", - "/whitelist/activate_cid", - "/users/reset_password", - "/users/reset_password/finish", - "/css/**", - "/js/**", - "/auth/valid_token", - "/img/**", - "/uploads/**" - }; - - - http - .authorizeRequests() - .antMatchers(permittedPaths).permitAll(); - } catch (Exception e) { - LOGGER.error("Something went wrong when setting"); - LOGGER.error(e.getMessage()); - } - } - - private void setAdminPaths(HttpSecurity http) { - try { - List groups = this.fkitGroupService.getGroups(); - for (FKITGroupDTO group : groups) { - addPathRole(http, group); - } - http.authorizeRequests().antMatchers("/admin/gdpr/**") - .hasAnyAuthority("gdpr", "admin").and().authorizeRequests().antMatchers("/admin/**") - .hasAuthority("admin"); - } catch (Exception e) { - LOGGER.error("something went wrong when setting admin paths"); - LOGGER.error(e.getMessage()); - } - } - - private void addPathRole(HttpSecurity http, FKITGroupDTO group) { - this.authorityService.getAllAuthorities().forEach(a -> { - if (a.getSuperGroup().getId().equals(group.getSuperGroup().getId())) { - try { - http.authorizeRequests().antMatchers("/admin/groups/" - + group.getId() + "/**") - .hasAuthority(a.getAuthorityLevel().getAuthority()); - } catch (Exception e) { - LOGGER.error("Something went wrong when setting authorized paths"); - LOGGER.error(e.getMessage()); - } - } - }); - } - - private void setTheRestOfPathsToAuthenticatedOnly(HttpSecurity http) { - try { - http - .authorizeRequests() - .anyRequest() - .authenticated() - .and() - .exceptionHandling() - .authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED)) - ; - } catch (Exception e) { - LOGGER.error("Something went wrong when setting paths to authenticated only."); - LOGGER.error(e.getMessage()); - } - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/controller/AuthController.java b/backend/src/main/java/it/chalmers/gamma/controller/AuthController.java deleted file mode 100644 index f28dd6b60..000000000 --- a/backend/src/main/java/it/chalmers/gamma/controller/AuthController.java +++ /dev/null @@ -1,62 +0,0 @@ -package it.chalmers.gamma.controller; - -import io.jsonwebtoken.Claims; -import io.jsonwebtoken.Jws; -import io.jsonwebtoken.Jwts; -import io.jsonwebtoken.MalformedJwtException; -import io.jsonwebtoken.SignatureException; -import it.chalmers.gamma.response.InvalidJWTTokenResponse; -import it.chalmers.gamma.response.ValidJwtResponse; - -import java.nio.charset.StandardCharsets; -import java.util.Base64; -import java.util.Date; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - - -@RestController -@RequestMapping("/auth") -public class AuthController { - - @Value("${security.jwt.token.secret-key}") - private String secretKey; - @Value("${security.jwt.token.issuer}") - private String issuer; - private static final Logger LOGGER = LoggerFactory.getLogger(AuthController.class); - - - @GetMapping("/valid_token") - public ValidJwtResponse validJWT(@RequestParam("token") String token) { - try { - Jws claim = decodeToken(token); - if (claim.getBody().getExpiration().before(new Date())) { - throw new InvalidJWTTokenResponse(); - } - return new ValidJwtResponse(true); - } catch (InvalidJWTTokenResponse | IllegalArgumentException e) { - return new ValidJwtResponse(false); - } - - } - - private Jws decodeToken(String token) { - try { - return Jwts.parser() - .requireIssuer(this.issuer) - .setSigningKey(Base64.getEncoder().encodeToString( - this.secretKey.getBytes(StandardCharsets.UTF_8)) - ) - .parseClaimsJws(token); - } catch (MalformedJwtException | SignatureException e) { - LOGGER.warn(e.getMessage()); - throw new InvalidJWTTokenResponse(); - } - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/controller/CustomErrorController.java b/backend/src/main/java/it/chalmers/gamma/controller/CustomErrorController.java deleted file mode 100644 index 797519a5a..000000000 --- a/backend/src/main/java/it/chalmers/gamma/controller/CustomErrorController.java +++ /dev/null @@ -1,41 +0,0 @@ -package it.chalmers.gamma.controller; - -import javax.servlet.RequestDispatcher; -import javax.servlet.http.HttpServletRequest; - -import org.springframework.boot.web.servlet.error.ErrorController; -import org.springframework.http.HttpStatus; -import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -import org.springframework.web.bind.annotation.GetMapping; - -@Controller -public class CustomErrorController implements ErrorController { - - @GetMapping("/error") - public String displayError(HttpServletRequest request, Model model) { - Object statusCodeString = request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE); - int statusCode = Integer.parseInt(statusCodeString.toString()); - if (HttpStatus.NOT_FOUND.value() == statusCode) { - model.addAttribute("original_page", - request.getAttribute(RequestDispatcher.FORWARD_REQUEST_URI)); - return "error-404"; - } - if (HttpStatus.valueOf(statusCode).is5xxServerError()) { - return "error-5xx"; - } - if (HttpStatus.UNPROCESSABLE_ENTITY.value() == statusCode) { - model.addAttribute("error_message", request.getAttribute(RequestDispatcher.ERROR_MESSAGE)); - return "error-422"; - } - model.addAttribute("error_code", request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE)); - model.addAttribute("error_message", request.getAttribute(RequestDispatcher.ERROR_MESSAGE)); - model.addAttribute("origin_url", request.getAttribute(RequestDispatcher.FORWARD_REQUEST_URI)); - return "common-error"; - } - - @Override - public String getErrorPath() { - return "/error"; - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/controller/FKITGroupController.java b/backend/src/main/java/it/chalmers/gamma/controller/FKITGroupController.java deleted file mode 100644 index 36a2730c9..000000000 --- a/backend/src/main/java/it/chalmers/gamma/controller/FKITGroupController.java +++ /dev/null @@ -1,107 +0,0 @@ -package it.chalmers.gamma.controller; - -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import it.chalmers.gamma.domain.dto.group.FKITGroupDTO; -import it.chalmers.gamma.domain.dto.membership.MembershipDTO; -import it.chalmers.gamma.domain.dto.membership.NoAccountMembershipDTO; -import it.chalmers.gamma.domain.dto.membership.RestrictedMembershipDTO; -import it.chalmers.gamma.response.group.GetActiveFKITGroupsResponse; -import it.chalmers.gamma.response.group.GetActiveFKITGroupsResponse.GetActiveFKITGroupResponseObject; -import it.chalmers.gamma.response.group.GetAllFKITGroupsMinifiedResponse; -import it.chalmers.gamma.response.group.GetAllFKITGroupsMinifiedResponse.GetAllFKITGroupsMinifiedResponseObject; -import it.chalmers.gamma.response.group.GetAllFKITGroupsResponse; -import it.chalmers.gamma.response.group.GetFKITGroupMinifiedResponse; -import it.chalmers.gamma.response.group.GetFKITGroupMinifiedResponse.GetFKITGroupMinifiedResponseObject; -import it.chalmers.gamma.response.group.GetFKITGroupResponse; -import it.chalmers.gamma.response.group.GetFKITGroupResponse.GetFKITGroupResponseObject; -import it.chalmers.gamma.service.FKITGroupService; -import it.chalmers.gamma.service.MembershipService; - -import java.util.List; -import java.util.stream.Collectors; - -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -@SuppressFBWarnings(justification = "I don't know", value = "UC_USELESS_OBJECT") -@SuppressWarnings("PMD.ExcessiveImports") -@RestController -@RequestMapping("/groups") -public final class FKITGroupController { - - //TODO add groupmembers to serialize method call once that has been solved. - - private final FKITGroupService fkitGroupService; - private final MembershipService membershipService; - - public FKITGroupController( - FKITGroupService fkitGroupService, - MembershipService membershipService) { - this.fkitGroupService = fkitGroupService; - this.membershipService = membershipService; - } - - @GetMapping("/{id}") - public GetFKITGroupResponseObject getGroup(@PathVariable("id") String id) { - final FKITGroupDTO group = this.fkitGroupService.getGroup(id); - List minifiedMembers = this.membershipService.getMembershipsInGroup(group); - List noAccountMemberships = this.membershipService.getNoAccountMembership(group); - //List websites = this.getWebsiteDTO(group); - return new GetFKITGroupResponse( - group, - toRestrictedMembershipDTO(minifiedMembers), - noAccountMemberships, - null) - .toResponseObject(); - } - - @GetMapping("/minified") - public GetAllFKITGroupsMinifiedResponseObject getGroupsMinified() { - List responses = this.fkitGroupService.getGroups() - .stream().map(g -> new GetFKITGroupMinifiedResponse(g.toMinifiedDTO())).collect(Collectors.toList()); - return new GetAllFKITGroupsMinifiedResponse(responses).toResponseObject(); - } - - @GetMapping("/{id}/minified") - public GetFKITGroupMinifiedResponseObject getGroupMinified(@PathVariable("id") String id) { - return new GetFKITGroupMinifiedResponse(this.fkitGroupService.getGroup(id) - .toMinifiedDTO()).toResponseObject(); - } - - @GetMapping() - public GetAllFKITGroupsResponse getGroups() { - List responses = this.fkitGroupService.getGroups() - .stream().map(g -> new GetFKITGroupResponse( - g, - toRestrictedMembershipDTO(this.membershipService.getMembershipsInGroup(g)), - this.membershipService.getNoAccountMembership(g), - null - )).collect(Collectors.toList()); - - return new GetAllFKITGroupsResponse(responses); - } - - @GetMapping("/active") - public GetActiveFKITGroupResponseObject getActiveGroups() { - List groups = this.fkitGroupService.getGroups().stream() - .filter(FKITGroupDTO::isActive).collect(Collectors.toList()); - - List groupResponses = groups.stream().map(g -> new GetFKITGroupResponse( - g, - toRestrictedMembershipDTO(this.membershipService.getMembershipsInGroup(g)), - this.membershipService.getNoAccountMembership(g), - null - )).collect(Collectors.toList()); - return new GetActiveFKITGroupsResponse(groupResponses).toResponseObject(); - } - - private List toRestrictedMembershipDTO(List membershipList) { - return membershipList - .stream() - .map(RestrictedMembershipDTO::new) - .collect(Collectors.toList()); - } - -} diff --git a/backend/src/main/java/it/chalmers/gamma/controller/FileController.java b/backend/src/main/java/it/chalmers/gamma/controller/FileController.java deleted file mode 100644 index 8d6f33a2e..000000000 --- a/backend/src/main/java/it/chalmers/gamma/controller/FileController.java +++ /dev/null @@ -1,27 +0,0 @@ -package it.chalmers.gamma.controller; - -import it.chalmers.gamma.response.FileNotFoundResponse; -import it.chalmers.gamma.response.GetFileResponse; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Paths; -import org.springframework.util.StreamUtils; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -@RestController -@RequestMapping("/uploads") -public class FileController { - @GetMapping("/{id}.{type}") - public GetFileResponse getFile(@PathVariable("id") String fileName, @PathVariable("type") String type) { - String filePath = String.format("uploads/%s.%s", fileName, type); - try { - byte[] data = StreamUtils.copyToByteArray(Files.newInputStream(Paths.get(filePath))); - return new GetFileResponse(data); - } catch (IOException e) { - throw new FileNotFoundResponse(); - } - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/controller/GroupMemberController.java b/backend/src/main/java/it/chalmers/gamma/controller/GroupMemberController.java deleted file mode 100644 index 2f44b1123..000000000 --- a/backend/src/main/java/it/chalmers/gamma/controller/GroupMemberController.java +++ /dev/null @@ -1,41 +0,0 @@ -package it.chalmers.gamma.controller; - -import it.chalmers.gamma.domain.dto.group.FKITGroupDTO; -import it.chalmers.gamma.domain.dto.membership.MembershipDTO; -import it.chalmers.gamma.domain.dto.membership.RestrictedMembershipDTO; -import it.chalmers.gamma.response.group.GetMembershipResponse; -import it.chalmers.gamma.response.group.GetMembershipResponse.GetMembershipResponseObject; -import it.chalmers.gamma.service.FKITGroupService; -import it.chalmers.gamma.service.MembershipService; -import java.util.List; -import java.util.stream.Collectors; - -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -@RestController -@RequestMapping("/groups") -public class GroupMemberController { - - private final FKITGroupService fkitGroupService; - private final MembershipService membershipService; - - public GroupMemberController(FKITGroupService fkitGroupService, MembershipService membershipService) { - this.fkitGroupService = fkitGroupService; - this.membershipService = membershipService; - } - - @GetMapping("/{id}/members") - public GetMembershipResponseObject getUsersInGroup(@PathVariable("id") String id) { - FKITGroupDTO group = this.fkitGroupService.getGroup(id); - List members = this.membershipService.getMembershipsInGroup(group); - return new GetMembershipResponse( - members - .stream() - .map(RestrictedMembershipDTO::new) - .collect(Collectors.toList()) - ).toResponseObject(); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/controller/GroupPostController.java b/backend/src/main/java/it/chalmers/gamma/controller/GroupPostController.java deleted file mode 100644 index 70566b5c1..000000000 --- a/backend/src/main/java/it/chalmers/gamma/controller/GroupPostController.java +++ /dev/null @@ -1,43 +0,0 @@ -package it.chalmers.gamma.controller; - -import it.chalmers.gamma.domain.dto.post.PostDTO; -import it.chalmers.gamma.response.post.GetMultiplePostsResponse; -import it.chalmers.gamma.response.post.GetMultiplePostsResponse.GetMultiplePostsResponseObject; -import it.chalmers.gamma.response.post.GetPostResponse; -import it.chalmers.gamma.response.post.GetPostResponse.GetPostResponseObject; -import it.chalmers.gamma.service.PostService; -import java.util.stream.Collectors; - -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -@RestController -@RequestMapping("/groups/posts") -public class GroupPostController { - - private final PostService postService; - - public GroupPostController(PostService postService) { - this.postService = postService; - } - - @GetMapping("/{id}") - public GetPostResponseObject getPost(@PathVariable("id") String id) { - PostDTO post = this.postService.getPostDTO(id); - return new GetPostResponse(post).toResponseObject(); - } - - - /** - * gets all posts in the system. - * - * @return all posts currently in the system - */ - @GetMapping() - public GetMultiplePostsResponseObject getPosts() { - return new GetMultiplePostsResponse(this.postService.getAllPosts().stream() - .map(GetPostResponse::new).collect(Collectors.toList())).toResponseObject(); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/controller/ITUserApprovalController.java b/backend/src/main/java/it/chalmers/gamma/controller/ITUserApprovalController.java deleted file mode 100644 index 57ed9a5b9..000000000 --- a/backend/src/main/java/it/chalmers/gamma/controller/ITUserApprovalController.java +++ /dev/null @@ -1,36 +0,0 @@ -package it.chalmers.gamma.controller; - -import it.chalmers.gamma.domain.dto.access.ITClientUserAccessDTO; -import it.chalmers.gamma.response.client.ApprovedITClientsResponse; -import it.chalmers.gamma.service.ITUserApprovalService; - -import java.security.Principal; -import java.util.stream.Collectors; - -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -@RestController -@RequestMapping("/users/approval") -public class ITUserApprovalController { - - private final ITUserApprovalService itUserApprovalService; - - public ITUserApprovalController(ITUserApprovalService itUserApprovalService) { - this.itUserApprovalService = itUserApprovalService; - } - - @GetMapping() - public ApprovedITClientsResponse getApprovedClientsByUser(Principal principal) { - String cid = principal.getName(); - - return new ApprovedITClientsResponse( - this.itUserApprovalService.getApprovalsByCid(cid) - .stream() - .map(itUserApprovalDTO -> new ITClientUserAccessDTO(itUserApprovalDTO.getClient())) - .collect(Collectors.toList()) - ); - } - -} diff --git a/backend/src/main/java/it/chalmers/gamma/controller/ITUserController.java b/backend/src/main/java/it/chalmers/gamma/controller/ITUserController.java deleted file mode 100644 index a4cbf45f8..000000000 --- a/backend/src/main/java/it/chalmers/gamma/controller/ITUserController.java +++ /dev/null @@ -1,232 +0,0 @@ -package it.chalmers.gamma.controller; - -import it.chalmers.gamma.domain.dto.group.FKITGroupDTO; -import it.chalmers.gamma.domain.dto.membership.MembershipDTO; -import it.chalmers.gamma.domain.dto.user.ITUserDTO; -import it.chalmers.gamma.domain.dto.user.ITUserRestrictedDTO; -import it.chalmers.gamma.domain.dto.user.WhitelistDTO; -import it.chalmers.gamma.filter.JwtAuthenticationFilter; -import it.chalmers.gamma.requests.ChangeUserPassword; -import it.chalmers.gamma.requests.CreateITUserRequest; -import it.chalmers.gamma.requests.DeleteMeRequest; -import it.chalmers.gamma.requests.EditITUserRequest; -import it.chalmers.gamma.response.CodeOrCidIsWrongResponse; -import it.chalmers.gamma.response.InputValidationFailedResponse; -import it.chalmers.gamma.response.user.EditedProfilePictureResponse; -import it.chalmers.gamma.response.user.GetAllITUsersMinifiedResponse; -import it.chalmers.gamma.response.user.GetAllITUsersMinifiedResponse.GetAllITUsersMinifiedResponseObject; -import it.chalmers.gamma.response.user.GetITUserMinifiedResponse; -import it.chalmers.gamma.response.user.GetITUserResponse; -import it.chalmers.gamma.response.user.GetITUserResponse.GetITUserResponseObject; -import it.chalmers.gamma.response.user.GetITUserRestrictedResponse; -import it.chalmers.gamma.response.user.IncorrectCidOrPasswordResponse; -import it.chalmers.gamma.response.user.PasswordChangedResponse; -import it.chalmers.gamma.response.user.PasswordTooShortResponse; -import it.chalmers.gamma.response.user.UserAlreadyExistsResponse; -import it.chalmers.gamma.response.user.UserCreatedResponse; -import it.chalmers.gamma.response.user.UserDeletedResponse; -import it.chalmers.gamma.response.user.UserEditedResponse; -import it.chalmers.gamma.response.user.UserNotFoundResponse; -import it.chalmers.gamma.response.whitelist.WhitelistDoesNotExistsException; -import it.chalmers.gamma.service.ActivationCodeService; -import it.chalmers.gamma.service.ITUserService; -import it.chalmers.gamma.service.MembershipService; -import it.chalmers.gamma.service.UserWebsiteService; -import it.chalmers.gamma.service.WhitelistService; -import it.chalmers.gamma.util.InputValidationUtils; - -import java.io.IOException; -import java.security.Principal; -import java.time.Year; -import java.util.List; -import java.util.stream.Collectors; - -import javax.servlet.http.HttpServletResponse; -import javax.validation.Valid; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.validation.BindingResult; -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.RequestParam; -import org.springframework.web.bind.annotation.ResponseBody; -import org.springframework.web.bind.annotation.RestController; -import org.springframework.web.multipart.MultipartFile; - -@SuppressWarnings("PMD.ExcessiveImports") -@RestController -@RequestMapping("/users") -public final class ITUserController { - - private final ITUserService itUserService; - private final ActivationCodeService activationCodeService; - private final WhitelistService whitelistService; - private final UserWebsiteService userWebsiteService; - private final MembershipService membershipService; - private static final Logger LOGGER = LoggerFactory.getLogger(JwtAuthenticationFilter.class); - - public ITUserController(ITUserService itUserService, - ActivationCodeService activationCodeService, - WhitelistService whitelistService, - UserWebsiteService userWebsiteService, - MembershipService membershipService) { - this.itUserService = itUserService; - this.activationCodeService = activationCodeService; - this.whitelistService = whitelistService; - this.userWebsiteService = userWebsiteService; - this.membershipService = membershipService; - } - - @PostMapping("/create") - @ResponseBody - @SuppressWarnings("PMD.CyclomaticComplexity") - // TODO, move checks to service, and return only if checks failed or passed - public UserCreatedResponse createUser(@Valid @RequestBody CreateITUserRequest createITUserRequest, - BindingResult result) { - try { - if (result.hasErrors()) { - throw new InputValidationFailedResponse(InputValidationUtils.getErrorMessages(result.getAllErrors())); - } - WhitelistDTO user = this.whitelistService.getWhitelist(createITUserRequest.getWhitelist().getCid()); - - if (this.itUserService.userExists(user.getCid())) { - throw new UserAlreadyExistsResponse(); - } - if (!this.activationCodeService.codeMatches(createITUserRequest.getCode(), user.getCid())) { - throw new CodeOrCidIsWrongResponse(); - } - int minPassLength = 8; - - if (createITUserRequest.getPassword().length() < minPassLength) { - throw new PasswordTooShortResponse(); - } else { - this.itUserService.createUser( - createITUserRequest.getNick(), - createITUserRequest.getFirstName(), - createITUserRequest.getLastName(), - createITUserRequest.getWhitelist().getCid(), - Year.of(createITUserRequest.getAcceptanceYear()), - createITUserRequest.isUserAgreement(), - createITUserRequest.getEmail(), - - createITUserRequest.getPassword()); - this.whitelistService.removeWhiteListedCID(createITUserRequest.getWhitelist().getCid()); - return new UserCreatedResponse(); - } - } catch (WhitelistDoesNotExistsException e) { - LOGGER.warn(String.format("user %s entered non-valid code", createITUserRequest.getNick())); - return new UserCreatedResponse(); - } - } - - @GetMapping("/me") - public GetITUserResponseObject getMe(Principal principal) { - String cid = principal.getName(); - ITUserDTO user = this.itUserService.loadUser(cid); - // List websites = - // this.userWebsiteService.getWebsitesOrdered( - // this.userWebsiteService.getWebsites(user) - // ); - List groups = this.membershipService.getMembershipsByUser(user) - .stream().map(MembershipDTO::getFkitGroupDTO).collect(Collectors.toList()); - return new GetITUserResponse(user, groups, null).toResponseObject(); - } - - @GetMapping("/minified") - public GetAllITUsersMinifiedResponseObject getAllUserMini() { - List itUsers = this.itUserService - .loadAllUsers() - .stream() - .map(ITUserRestrictedDTO::new) - .map(GetITUserMinifiedResponse::new) - .collect(Collectors.toList()); - return new GetAllITUsersMinifiedResponse(itUsers).toResponseObject(); - } - - /** - * First tries to get user using id, if not found gets it using the cid. - */ - @GetMapping("/{id}") - public GetITUserRestrictedResponse.GetITUserRestrictedResponseObject getUser(@PathVariable("id") String id) { - ITUserDTO user = this.itUserService.getITUser(id); - List groups = this.membershipService.getUsersGroupDTO(user); - return new GetITUserRestrictedResponse(new ITUserRestrictedDTO(user), groups, null) - .toResponseObject(); - } - - @GetMapping("/{id}/avatar") - public void getUserAvatar(@PathVariable("id") String id, HttpServletResponse response) throws IOException { - ITUserDTO user = this.itUserService.getITUser(id); - response.sendRedirect(user.getAvatarUrl()); - } - - @PutMapping("/me") - public UserEditedResponse editMe(Principal principal, @RequestBody EditITUserRequest request) { - String cid = principal.getName(); - ITUserDTO user = this.itUserService.loadUser(cid); - this.itUserService.editUser(user.getId(), request.getNick(), request.getFirstName(), request.getLastName(), - request.getEmail(), request.getPhone(), request.getLanguage(), request.getAcceptanceYear()); - // List websiteURLs = new ArrayList<>(); - // List userWebsite = new ArrayList<>( - // this.userWebsiteService.getWebsites(user) - // ); - // this.userWebsiteService.addWebsiteToUser(user, websiteURLs); - return new UserEditedResponse(); - } - - @PutMapping("/me/avatar") - public EditedProfilePictureResponse editProfileImage(Principal principal, @RequestParam MultipartFile file) { - String cid = principal.getName(); - ITUserDTO user = this.itUserService.loadUser(cid); - if (user == null) { - throw new UserNotFoundResponse(); - } else { - this.itUserService.editProfilePicture(user, file); - return new EditedProfilePictureResponse(); - } - - } - - @PutMapping("/me/change_password") - public PasswordChangedResponse changePassword(Principal principal, @Valid @RequestBody ChangeUserPassword request, - BindingResult result) { - if (result.hasErrors()) { - throw new InputValidationFailedResponse(InputValidationUtils.getErrorMessages(result.getAllErrors())); - } - ITUserDTO user = this.extractUser(principal); - if (!this.itUserService.passwordMatches(user, request.getOldPassword())) { - throw new IncorrectCidOrPasswordResponse(); - } - this.itUserService.setPassword(user, request.getPassword()); - return new PasswordChangedResponse(); - } - - @DeleteMapping("/me") - public UserDeletedResponse deleteMe(Principal principal, @Valid @RequestBody DeleteMeRequest request, - BindingResult result) { - if (result.hasErrors()) { - throw new InputValidationFailedResponse(InputValidationUtils.getErrorMessages(result.getAllErrors())); - } - ITUserDTO user = this.extractUser(principal); - if (!this.itUserService.passwordMatches(user, request.getPassword())) { - throw new IncorrectCidOrPasswordResponse(); - } - this.userWebsiteService.deleteWebsitesConnectedToUser( - this.itUserService.getITUser(user.getId().toString()) - ); - this.membershipService.removeAllMemberships(user); - this.itUserService.removeUser(user.getId()); - return new UserDeletedResponse(); - } - - private ITUserDTO extractUser(Principal principal) { - return this.itUserService.loadUser(principal.getName()); - } - -} diff --git a/backend/src/main/java/it/chalmers/gamma/controller/LoginController.java b/backend/src/main/java/it/chalmers/gamma/controller/LoginController.java deleted file mode 100644 index cb7718a77..000000000 --- a/backend/src/main/java/it/chalmers/gamma/controller/LoginController.java +++ /dev/null @@ -1,26 +0,0 @@ -package it.chalmers.gamma.controller; - -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestParam; - -@Controller -public class LoginController { - @Value("${application.frontend-client-details.successful-login-uri}") - private String baseFrontendUrl; - - @GetMapping("/login") - public String getLogin(@RequestParam(value = "error", required = false) String error, - @RequestParam(value = "logout", required = false) String logout, - Model model) { - model.addAttribute("createAccountUrl", this.baseFrontendUrl + "/create-account"); - model.addAttribute("forgotPasswordUrl", this.baseFrontendUrl + "/reset-password"); - model.addAttribute("error", error); - model.addAttribute("logout", logout); - - return "login"; - } - -} diff --git a/backend/src/main/java/it/chalmers/gamma/controller/OAuth2AuthorizeController.java b/backend/src/main/java/it/chalmers/gamma/controller/OAuth2AuthorizeController.java deleted file mode 100644 index 04577b8c1..000000000 --- a/backend/src/main/java/it/chalmers/gamma/controller/OAuth2AuthorizeController.java +++ /dev/null @@ -1,31 +0,0 @@ -package it.chalmers.gamma.controller; - -import it.chalmers.gamma.domain.dto.access.ITClientDTO; -import it.chalmers.gamma.service.ITClientService; - -import org.springframework.security.oauth2.provider.AuthorizationRequest; -import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.ModelAttribute; -import org.springframework.web.bind.annotation.SessionAttributes; - -@Controller -@SessionAttributes(types = AuthorizationRequest.class) -public class OAuth2AuthorizeController { - - private final ITClientService clientService; - - public OAuth2AuthorizeController(ITClientService clientService) { - this.clientService = clientService; - } - - @GetMapping("/oauth/confirm_access") - public String getConfirmAccess(@ModelAttribute AuthorizationRequest clientAuth, Model model) { - ITClientDTO client = this.clientService.getITClientById(clientAuth.getClientId()).orElseThrow(); - model.addAttribute("clientName", client.getName()); - return "authorize"; - } - -} - diff --git a/backend/src/main/java/it/chalmers/gamma/controller/SuperGroupController.java b/backend/src/main/java/it/chalmers/gamma/controller/SuperGroupController.java deleted file mode 100644 index abd1ef1ca..000000000 --- a/backend/src/main/java/it/chalmers/gamma/controller/SuperGroupController.java +++ /dev/null @@ -1,79 +0,0 @@ -package it.chalmers.gamma.controller; - -import it.chalmers.gamma.domain.dto.group.FKITSuperGroupDTO; -import it.chalmers.gamma.domain.dto.membership.RestrictedMembershipDTO; -import it.chalmers.gamma.response.group.GetActiveFKITGroupsResponse; -import it.chalmers.gamma.response.group.GetActiveFKITGroupsResponse.GetActiveFKITGroupResponseObject; -import it.chalmers.gamma.response.group.GetAllFKITGroupsMinifiedResponse; -import it.chalmers.gamma.response.group.GetAllFKITGroupsMinifiedResponse.GetAllFKITGroupsMinifiedResponseObject; -import it.chalmers.gamma.response.group.GetFKITGroupMinifiedResponse; -import it.chalmers.gamma.response.group.GetFKITGroupResponse; -import it.chalmers.gamma.response.group.GroupDoesNotExistResponse; -import it.chalmers.gamma.response.supergroup.GetAllSuperGroupsResponse; -import it.chalmers.gamma.response.supergroup.GetAllSuperGroupsResponse.GetAllSuperGroupsResponseObject; -import it.chalmers.gamma.response.supergroup.GetSuperGroupResponse; -import it.chalmers.gamma.service.FKITGroupService; -import it.chalmers.gamma.service.FKITSuperGroupService; -import it.chalmers.gamma.service.MembershipService; - -import java.util.List; - -import java.util.stream.Collectors; - -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -@RestController -@RequestMapping("/superGroups") -public class SuperGroupController { - - private final FKITSuperGroupService fkitSuperGroupService; - private final MembershipService membershipService; - private final FKITGroupService fkitGroupService; - - public SuperGroupController(FKITSuperGroupService fkitSuperGroupService, - MembershipService membershipService, FKITGroupService fkitGroupService) { - this.fkitSuperGroupService = fkitSuperGroupService; - this.membershipService = membershipService; - this.fkitGroupService = fkitGroupService; - } - - @GetMapping("/{id}/subgroups") - public GetAllFKITGroupsMinifiedResponseObject getAllSubGroups(@PathVariable("id") String id) { - FKITSuperGroupDTO superGroup = this.fkitSuperGroupService.getGroupDTO(id); - return new GetAllFKITGroupsMinifiedResponse( - this.fkitGroupService.getAllGroupsWithSuperGroup(superGroup).stream() - .map(g -> new GetFKITGroupMinifiedResponse(g.toMinifiedDTO())) - .collect(Collectors.toList())).toResponseObject(); - } - - @GetMapping() - public GetAllSuperGroupsResponseObject getAllSuperGroups() { - return new GetAllSuperGroupsResponse(this.fkitSuperGroupService.getAllGroups() - .stream().map(GetSuperGroupResponse::new).collect(Collectors.toList())).toResponseObject(); - } - - @GetMapping("/{id}") - public GetSuperGroupResponse getSuperGroup(@PathVariable("id") String id) { - if (!this.fkitSuperGroupService.groupExists(id)) { - throw new GroupDoesNotExistResponse(); - } - return new GetSuperGroupResponse(this.fkitSuperGroupService.getGroupDTO(id)); - } - - @GetMapping("/{id}/active") - public GetActiveFKITGroupResponseObject getActiveGroup(@PathVariable("id") String id) { - FKITSuperGroupDTO superGroup = this.fkitSuperGroupService.getGroupDTO(id); - List groups = this.fkitGroupService.getActiveGroups(superGroup) - .stream().map(g -> new GetFKITGroupResponse( - g, - this.membershipService.getMembershipsInGroup(g) - .stream() - .map(RestrictedMembershipDTO::new) - .collect(Collectors.toList()) - )).collect(Collectors.toList()); - return new GetActiveFKITGroupsResponse(groups).toResponseObject(); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/controller/UserPasswordResetController.java b/backend/src/main/java/it/chalmers/gamma/controller/UserPasswordResetController.java deleted file mode 100644 index 2892a59c7..000000000 --- a/backend/src/main/java/it/chalmers/gamma/controller/UserPasswordResetController.java +++ /dev/null @@ -1,67 +0,0 @@ -package it.chalmers.gamma.controller; - -import it.chalmers.gamma.domain.dto.user.ITUserDTO; -import it.chalmers.gamma.requests.ResetPasswordFinishRequest; -import it.chalmers.gamma.requests.ResetPasswordRequest; -import it.chalmers.gamma.response.CodeOrCidIsWrongResponse; -import it.chalmers.gamma.response.InputValidationFailedResponse; -import it.chalmers.gamma.response.user.PasswordChangedResponse; -import it.chalmers.gamma.response.user.PasswordResetResponse; -import it.chalmers.gamma.service.ITUserService; -import it.chalmers.gamma.service.PasswordResetService; -import it.chalmers.gamma.util.InputValidationUtils; - -import javax.validation.Valid; - -import org.springframework.validation.BindingResult; -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; - - - -@RestController -@RequestMapping("/users/reset_password") -public class UserPasswordResetController { - - private final ITUserService itUserService; - private final PasswordResetService passwordResetService; - - public UserPasswordResetController( - ITUserService itUserService, - PasswordResetService passwordResetService) { - this.itUserService = itUserService; - this.passwordResetService = passwordResetService; - } - - @PostMapping() - public PasswordResetResponse resetPasswordRequest( - @Valid @RequestBody ResetPasswordRequest request, BindingResult result) { - if (result.hasErrors()) { - throw new InputValidationFailedResponse(InputValidationUtils.getErrorMessages(result.getAllErrors())); - } - String userCredentials = request.getCid(); // CID can either be CID or email. - ITUserDTO user = this.itUserService.getITUser(userCredentials); - this.passwordResetService.handlePasswordReset(user); - return new PasswordResetResponse(); - } - - @PutMapping("/finish") - public PasswordChangedResponse resetPassword( - @Valid @RequestBody ResetPasswordFinishRequest request, BindingResult result) { - if (result.hasErrors()) { - throw new InputValidationFailedResponse(InputValidationUtils.getErrorMessages(result.getAllErrors())); - } - ITUserDTO user = this.itUserService.getITUser(request.getCid()); - if (!this.passwordResetService.userHasActiveReset(user) - || !this.passwordResetService.tokenMatchesUser(user, request.getToken())) { - throw new CodeOrCidIsWrongResponse(); - } - this.itUserService.setPassword(user, request.getPassword()); - this.passwordResetService.removeToken(user); - return new PasswordChangedResponse(); - } - -} diff --git a/backend/src/main/java/it/chalmers/gamma/controller/WebsiteController.java b/backend/src/main/java/it/chalmers/gamma/controller/WebsiteController.java deleted file mode 100644 index 585563d2e..000000000 --- a/backend/src/main/java/it/chalmers/gamma/controller/WebsiteController.java +++ /dev/null @@ -1,39 +0,0 @@ -package it.chalmers.gamma.controller; - -import it.chalmers.gamma.domain.dto.website.WebsiteDTO; -import it.chalmers.gamma.response.website.GetAllWebsitesResponse; -import it.chalmers.gamma.response.website.GetAllWebsitesResponse.GetAllWebsitesResponseObject; -import it.chalmers.gamma.response.website.GetWebsiteResponse; -import it.chalmers.gamma.service.WebsiteService; - -import java.util.stream.Collectors; - -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - - -@RestController -@RequestMapping("/websites") -public class WebsiteController { - - private final WebsiteService websiteService; - - public WebsiteController(WebsiteService websiteService) { - this.websiteService = websiteService; - } - - - @GetMapping("/{id}") - public GetWebsiteResponse getWebsite(@PathVariable("id") String id) { - WebsiteDTO website = this.websiteService.getWebsite(id); - return new GetWebsiteResponse(website); - } - - @GetMapping() - public GetAllWebsitesResponseObject getAllWebsites() { - return new GetAllWebsitesResponse(this.websiteService.getAllWebsites().stream().map(GetWebsiteResponse::new) - .collect(Collectors.toList())).toResponseObject(); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/controller/WhitelistController.java b/backend/src/main/java/it/chalmers/gamma/controller/WhitelistController.java deleted file mode 100644 index 8ee77f06d..000000000 --- a/backend/src/main/java/it/chalmers/gamma/controller/WhitelistController.java +++ /dev/null @@ -1,75 +0,0 @@ -package it.chalmers.gamma.controller; - -import it.chalmers.gamma.domain.dto.user.ActivationCodeDTO; -import it.chalmers.gamma.domain.dto.user.WhitelistDTO; -import it.chalmers.gamma.requests.WhitelistCodeRequest; -import it.chalmers.gamma.response.InputValidationFailedResponse; -import it.chalmers.gamma.response.activationcode.ActivationCodeAddedResonse; -import it.chalmers.gamma.response.whitelist.WhitelistDoesNotExistsException; -import it.chalmers.gamma.service.ActivationCodeService; -import it.chalmers.gamma.service.MailSenderService; -import it.chalmers.gamma.service.WhitelistService; - -import it.chalmers.gamma.util.InputValidationUtils; - -import javax.validation.Valid; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.http.MediaType; -import org.springframework.validation.BindingResult; -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; - -@RestController -@RequestMapping(value = "/whitelist", produces = MediaType.APPLICATION_JSON_UTF8_VALUE) -public final class WhitelistController { - - private final WhitelistService whitelistService; - private final ActivationCodeService activationCodeService; - private final MailSenderService mailSenderService; - private static final Logger LOGGER = LoggerFactory.getLogger(WhitelistController.class); - @Value("${mail.receiver.standard-postfix}") - private static final String MAIL_POSTFIX = "student.chalmers.se"; - - public WhitelistController( - WhitelistService whitelistService, - ActivationCodeService activationCodeService, - MailSenderService mailSenderService) { - this.whitelistService = whitelistService; - this.activationCodeService = activationCodeService; - this.mailSenderService = mailSenderService; - } - - @PostMapping("/activate_cid") - public ActivationCodeAddedResonse createActivationCode(@Valid @RequestBody WhitelistCodeRequest cid, - BindingResult result) { - try { - if (result.hasErrors()) { - throw new InputValidationFailedResponse(InputValidationUtils.getErrorMessages(result.getAllErrors())); - } - if (this.whitelistService.isCIDWhiteListed(cid.getCid())) { - WhitelistDTO whitelist = this.whitelistService.getWhitelist(cid.getCid()); - ActivationCodeDTO activationCode = this.activationCodeService.saveActivationCode(whitelist); - sendEmail(activationCode); - } else { - String nonWhitelistWarning = "Non Whitelisted User: %s Tried to Create Account"; - LOGGER.warn(String.format(nonWhitelistWarning, cid.getCid())); - } - return new ActivationCodeAddedResonse(); // For security reasons - } catch (WhitelistDoesNotExistsException e) { // This should never happen. - return new ActivationCodeAddedResonse(); - } - } - - private void sendEmail(ActivationCodeDTO activationCode) { - String code = activationCode.getCode(); - String to = activationCode.getWhitelistDTO().getCid() + "@" + MAIL_POSTFIX; - String message = "Your code to Gamma is: " + code; - this.mailSenderService.trySendingMail(to, "Chalmers activation code", message); - } -} - diff --git a/backend/src/main/java/it/chalmers/gamma/controller/admin/ApiKeyAdminController.java b/backend/src/main/java/it/chalmers/gamma/controller/admin/ApiKeyAdminController.java deleted file mode 100644 index 7b168936b..000000000 --- a/backend/src/main/java/it/chalmers/gamma/controller/admin/ApiKeyAdminController.java +++ /dev/null @@ -1,77 +0,0 @@ -package it.chalmers.gamma.controller.admin; - -import it.chalmers.gamma.domain.dto.access.ApiKeyDTO; -import it.chalmers.gamma.requests.CreateApiKeyRequest; -import it.chalmers.gamma.response.InputValidationFailedResponse; -import it.chalmers.gamma.response.apikey.ApiKeyDeletedResponse; -import it.chalmers.gamma.response.apikey.ApiKeyDoesNotExistResponse; -import it.chalmers.gamma.response.apikey.GetAllAPIKeysResponse; -import it.chalmers.gamma.response.apikey.GetAllAPIKeysResponse.GetAllAPIKeysResponseObject; -import it.chalmers.gamma.response.apikey.GetApiKeyResponse; -import it.chalmers.gamma.response.apikey.GetApiKeyResponse.GetApiKeyResponseObject; -import it.chalmers.gamma.response.apikey.GetApiKeySecretResponse; -import it.chalmers.gamma.response.apikey.GetApiKeySecretResponse.GetApiKeySecretResponseObject; -import it.chalmers.gamma.service.ApiKeyService; -import it.chalmers.gamma.util.InputValidationUtils; - -import java.util.List; -import java.util.UUID; -import javax.validation.Valid; - -import org.springframework.validation.BindingResult; -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.RestController; - -@RestController -@RequestMapping("/admin/api_keys") -public class ApiKeyAdminController { - private final ApiKeyService apiKeyService; - public ApiKeyAdminController(ApiKeyService apiKeyService) { - this.apiKeyService = apiKeyService; - } - - @PostMapping() - public GetApiKeySecretResponseObject createApiKey( - @Valid @RequestBody CreateApiKeyRequest request, - BindingResult result) { - if (result.hasErrors()) { - throw new InputValidationFailedResponse(InputValidationUtils.getErrorMessages(result.getAllErrors())); - } - ApiKeyDTO apiKeyDTO = this.apiKeyService.createApiKey(requestToDTO(request)); - return new GetApiKeySecretResponse(apiKeyDTO.getKey()).toResponseObject(); - } - - @GetMapping() - public GetAllAPIKeysResponseObject getAllApiKeys() { - List apiKeys = this.apiKeyService.getAllApiKeys(); - return new GetAllAPIKeysResponse(apiKeys).toResponseObject(); - } - - @GetMapping("/{id}") - public GetApiKeyResponseObject getApiKey(@PathVariable("id") String id) { - ApiKeyDTO apiKey = this.apiKeyService.getApiKeyDetails(id); - return new GetApiKeyResponse(apiKey).toResponseObject(); - } - - @DeleteMapping("/{id}") - public ApiKeyDeletedResponse deleteApiKeyDetails(@PathVariable("id") String idString) { - UUID id = UUID.fromString(idString); - if (!this.apiKeyService.apiKeyExists(id)) { - throw new ApiKeyDoesNotExistResponse(); - } - this.apiKeyService.deleteApiKey(id); - return new ApiKeyDeletedResponse(); - } - - private ApiKeyDTO requestToDTO(CreateApiKeyRequest request) { - return new ApiKeyDTO( - request.getName(), request.getDescription() - ); - } - -} diff --git a/backend/src/main/java/it/chalmers/gamma/controller/admin/AuthorityAdminController.java b/backend/src/main/java/it/chalmers/gamma/controller/admin/AuthorityAdminController.java deleted file mode 100644 index cf720a440..000000000 --- a/backend/src/main/java/it/chalmers/gamma/controller/admin/AuthorityAdminController.java +++ /dev/null @@ -1,135 +0,0 @@ -package it.chalmers.gamma.controller.admin; - -import it.chalmers.gamma.domain.dto.authority.AuthorityDTO; -import it.chalmers.gamma.domain.dto.authority.AuthorityLevelDTO; -import it.chalmers.gamma.domain.dto.group.FKITSuperGroupDTO; -import it.chalmers.gamma.domain.dto.post.PostDTO; -import it.chalmers.gamma.requests.AddAuthorityLevelRequest; -import it.chalmers.gamma.requests.AddAuthorityRequest; -import it.chalmers.gamma.response.InputValidationFailedResponse; -import it.chalmers.gamma.response.authority.AuthorityAddedResponse; -import it.chalmers.gamma.response.authority.AuthorityDoesNotExistResponse; -import it.chalmers.gamma.response.authority.AuthorityLevelAddedResponse; -import it.chalmers.gamma.response.authority.AuthorityLevelAlreadyExists; -import it.chalmers.gamma.response.authority.AuthorityLevelRemovedResponse; -import it.chalmers.gamma.response.authority.AuthorityRemovedResponse; -import it.chalmers.gamma.response.authority.GetAllAuthoritiesForLevelResponse; -import it.chalmers.gamma.response.authority.GetAllAuthoritiesResponse; -import it.chalmers.gamma.response.authority.GetAllAuthorityLevelsResponse; -import it.chalmers.gamma.response.authority.GetAllAuthorityLevelsResponse.GetAllAuthorityLevelsResponseObject; -import it.chalmers.gamma.response.authority.GetAuthorityResponse; -import it.chalmers.gamma.response.authority.GetAuthorityResponse.GetAuthorityResponseObject; -import it.chalmers.gamma.service.AuthorityLevelService; -import it.chalmers.gamma.service.AuthorityService; -import it.chalmers.gamma.service.FKITSuperGroupService; -import it.chalmers.gamma.service.PostService; -import it.chalmers.gamma.util.InputValidationUtils; - -import java.util.List; -import java.util.UUID; - -import javax.validation.Valid; - -import org.springframework.validation.BindingResult; -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.RestController; - -@SuppressWarnings({"PMD.ExcessiveImports", "PMD.AvoidDuplicateLiterals"}) -@RestController -@RequestMapping("/admin/authority") -public final class AuthorityAdminController { - - private final AuthorityService authorityService; - private final PostService postService; - private final AuthorityLevelService authorityLevelService; - private final FKITSuperGroupService fkitSuperGroupService; - - public AuthorityAdminController(AuthorityService authorityService, - PostService postService, - AuthorityLevelService authorityLevelService, - FKITSuperGroupService fkitSuperGroupService) { - this.authorityService = authorityService; - this.postService = postService; - this.authorityLevelService = authorityLevelService; - this.fkitSuperGroupService = fkitSuperGroupService; - } - - @PostMapping() - public AuthorityAddedResponse addAuthority(@Valid @RequestBody AddAuthorityRequest request, BindingResult result) { - if (result.hasErrors()) { - throw new InputValidationFailedResponse(InputValidationUtils.getErrorMessages(result.getAllErrors())); - } - PostDTO post = this.postService.getPostDTO(request.getPost()); - FKITSuperGroupDTO group = this.fkitSuperGroupService.getGroupDTO(request.getSuperGroup()); - AuthorityLevelDTO level = this.authorityLevelService.getAuthorityLevelDTO(request.getAuthority()); - this.authorityService.createAuthority(group, post, level); - return new AuthorityAddedResponse(); - } - - @DeleteMapping("/{id}") - public AuthorityRemovedResponse removeAuthority(@PathVariable("id") String id) { - if (!this.authorityService.authorityExists(id)) { - throw new AuthorityDoesNotExistResponse(); - } - this.authorityService.removeAuthority(UUID.fromString(id)); // TODO move check to service? - return new AuthorityRemovedResponse(); - } - - @GetMapping() - public GetAllAuthoritiesResponse getAllAuthorities() { - List authorities = this.authorityService.getAllAuthorities(); - return new GetAllAuthoritiesResponse(authorities); - } - - // BELOW THIS SHOULD MAYBE BE MOVED TO A DIFFERENT FILE - @PostMapping("/level") - public AuthorityLevelAddedResponse addAuthorityLevel(@Valid @RequestBody AddAuthorityLevelRequest request, - BindingResult result) { - if (result.hasErrors()) { - throw new InputValidationFailedResponse(InputValidationUtils.getErrorMessages(result.getAllErrors())); - } - if (this.authorityLevelService.authorityLevelExists(request.getAuthorityLevel())) { - throw new AuthorityLevelAlreadyExists(); - } - this.authorityLevelService.addAuthorityLevel(request.getAuthorityLevel()); //TODO Move check to service? - return new AuthorityLevelAddedResponse(); - } - - @GetMapping("/level") - public GetAllAuthorityLevelsResponseObject getAllAuthorityLevels() { - List authorityLevels = this.authorityLevelService.getAllAuthorityLevels(); - return new GetAllAuthorityLevelsResponse(authorityLevels).toResponseObject(); - } - - @DeleteMapping("/level/{id}") - public AuthorityLevelRemovedResponse removeAuthorityLevel(@PathVariable("id") String id) { - if (!this.authorityLevelService.authorityLevelExists(id)) { - throw new AuthorityDoesNotExistResponse(); - } - AuthorityLevelDTO authorityLevel = this.authorityLevelService.getAuthorityLevelDTO(id); - this.authorityService.removeAllAuthoritiesWithAuthorityLevel(authorityLevel); - this.authorityLevelService.removeAuthorityLevel(UUID.fromString(id)); // TODO Move check to service? - return new AuthorityLevelRemovedResponse(); - } - - @GetMapping("/level/{id}") - public GetAllAuthoritiesForLevelResponse.GetAllAuthoritiesForLevelResponseObject getAuthoritiesWithLevel( - @PathVariable("id") String id) { - List authorities = this.authorityService.getAuthoritiesWithLevel(UUID.fromString(id)); - AuthorityLevelDTO authorityLevel = this.authorityLevelService.getAuthorityLevelDTO(id); - return new GetAllAuthoritiesForLevelResponse(authorities, authorityLevel.getAuthority()).toResponseObject(); - } - - @GetMapping("/{id}") - public GetAuthorityResponseObject getAuthority(@PathVariable("id") String id) { - AuthorityDTO authority = this.authorityService.getAuthority(UUID.fromString(id)); - return new GetAuthorityResponse(authority).toResponseObject(); - } - -} - diff --git a/backend/src/main/java/it/chalmers/gamma/controller/admin/GDPRAdminController.java b/backend/src/main/java/it/chalmers/gamma/controller/admin/GDPRAdminController.java deleted file mode 100644 index 2c847da65..000000000 --- a/backend/src/main/java/it/chalmers/gamma/controller/admin/GDPRAdminController.java +++ /dev/null @@ -1,56 +0,0 @@ -package it.chalmers.gamma.controller.admin; - -import it.chalmers.gamma.requests.ChangeGDPRStatusRequest; -import it.chalmers.gamma.response.InputValidationFailedResponse; -import it.chalmers.gamma.response.user.GDPRStatusEditedResponse; -import it.chalmers.gamma.response.user.GetAllITUsersResponse; -import it.chalmers.gamma.response.user.GetITUserResponse; -import it.chalmers.gamma.response.user.UserNotFoundResponse; -import it.chalmers.gamma.service.ITUserService; -import it.chalmers.gamma.util.InputValidationUtils; - -import java.util.List; -import java.util.UUID; - -import java.util.stream.Collectors; -import javax.validation.Valid; - -import org.springframework.validation.BindingResult; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -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; - -@RestController() -@RequestMapping("/admin/gdpr") -public class GDPRAdminController { - - private final ITUserService itUserService; - - public GDPRAdminController(ITUserService itUserService) { - this.itUserService = itUserService; - } - - @PutMapping("/{id}") - public GDPRStatusEditedResponse editGDPRStatus(@PathVariable("id") String id, - @Valid @RequestBody ChangeGDPRStatusRequest request, - BindingResult result) { - if (result.hasErrors()) { - throw new InputValidationFailedResponse(InputValidationUtils.getErrorMessages(result.getAllErrors())); - } - if (!this.itUserService.userExists(UUID.fromString(id))) { - throw new UserNotFoundResponse(); - } - this.itUserService.editGdpr(UUID.fromString(id), request.isGdpr()); - return new GDPRStatusEditedResponse(); - } - - @GetMapping("/minified") - public GetAllITUsersResponse getAllUserMini() { - List userResponses = this.itUserService.loadAllUsers() - .stream().map(GetITUserResponse::new).collect(Collectors.toList()); - return new GetAllITUsersResponse(userResponses); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/controller/admin/GoldappsController.java b/backend/src/main/java/it/chalmers/gamma/controller/admin/GoldappsController.java deleted file mode 100644 index 1926c15e6..000000000 --- a/backend/src/main/java/it/chalmers/gamma/controller/admin/GoldappsController.java +++ /dev/null @@ -1,162 +0,0 @@ -package it.chalmers.gamma.controller.admin; - -import it.chalmers.gamma.db.serializers.GoldappsGroupSerializer; -import it.chalmers.gamma.db.serializers.GoldappsUserSerializer; -import it.chalmers.gamma.domain.GroupType; -import it.chalmers.gamma.domain.dto.group.FKITGroupDTO; -import it.chalmers.gamma.domain.dto.group.FKITSuperGroupDTO; -import it.chalmers.gamma.domain.dto.post.PostDTO; -import it.chalmers.gamma.domain.dto.user.ITUserDTO; -import it.chalmers.gamma.response.GoldappsReponse; -import it.chalmers.gamma.service.FKITGroupService; -import it.chalmers.gamma.service.FKITSuperGroupService; -import it.chalmers.gamma.service.MembershipService; -import it.chalmers.gamma.service.PostService; -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Collectors; - -import org.json.simple.JSONObject; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -@RestController -@RequestMapping("/admin/goldapps") -public class GoldappsController { - - private final FKITSuperGroupService fkitSuperGroupService; - private final FKITGroupService fkitGroupService; - private final MembershipService membershipService; - private final PostService postService; - - public GoldappsController(FKITSuperGroupService fkitSuperGroupService, - FKITGroupService fkitGroupService, - MembershipService membershipService, - PostService postService) { - this.fkitSuperGroupService = fkitSuperGroupService; - this.fkitGroupService = fkitGroupService; - this.membershipService = membershipService; - this.postService = postService; - } - - @GetMapping() - public ResponseEntity getGoldappsData() { - List groupsJSON = new ArrayList<>(); - List usersJSON = new ArrayList<>(); - - // Fetch all Committees - List committees = this.fkitSuperGroupService.getAllGroups().stream() - .filter(g -> g.getType().equals(GroupType.COMMITTEE)).collect(Collectors.toList()); - - List groups = committees.stream() - .flatMap(g -> this.fkitGroupService.getAllGroupsWithSuperGroup(g).stream()) - .collect(Collectors.toList()); - - GoldappsUserSerializer goldappsUserSerializer = new GoldappsUserSerializer(); - GoldappsGroupSerializer goldappsGroupSerializer = new GoldappsGroupSerializer(); - - // Go through all groups and serialize them and their users. - groups.stream().filter(FKITGroupDTO::isActive).forEach(g -> { - usersJSON.addAll( - this.membershipService.getMembershipsInGroup(g).stream() - .map(m -> goldappsUserSerializer.serialize(m.getUser())) - .collect(Collectors.toList())); - }); - groups = this.fkitSuperGroupService.getAllGroups() // Really ugly solution, should be refactored - .stream() - .filter(g -> !g.getType().equals(GroupType.ADMIN)) - .flatMap(g -> this.fkitGroupService.getAllGroupsWithSuperGroup(g).stream()) - .distinct() - .collect(Collectors.toList()); - - groups.forEach(g -> groupsJSON.add( - goldappsGroupSerializer.serialize(g.getEmail(), - this.membershipService.getMembershipsInGroup(g).stream() - .map(m -> this.getCorrectEmail(m.getUser(), g)).collect(Collectors.toList())))); - // Construct and send the payload - - List activeGroups = this.fkitGroupService.getAllActiveGroups(); - groupsJSON.addAll(activeGroups.stream() - .map(g -> - goldappsGroupSerializer.serialize(g.getSuperGroup().getEmail(), - this.fkitGroupService.getAllGroupsWithSuperGroup(g.getSuperGroup()).stream() - .map(FKITGroupDTO::getEmail).collect(Collectors.toList()))) - .collect(Collectors.toList())); - JSONObject payload = new JSONObject(); - List groupsJSONWithCustom = addCustomGroups(groupsJSON, goldappsGroupSerializer); - groupsJSONWithCustom = addAliases(groupsJSON, goldappsGroupSerializer); - - List usersJSONFiltered = usersJSON.stream().distinct().collect(Collectors.toList()); - payload.put("groups", groupsJSONWithCustom); - payload.put("users", usersJSONFiltered); - - return new GoldappsReponse(payload); - } - - private List addCustomGroups(List groupsJSON, - GoldappsGroupSerializer goldappsGroupSerializer) { - - groupsJSON.add(goldappsGroupSerializer.serialize("fkit@chalmers.it", - this.fkitSuperGroupService.getAllGroups().stream().filter(group -> - group.getType().equals(GroupType.COMMITTEE) || group.getType().equals(GroupType.SOCIETY)) - .map(FKITSuperGroupDTO::getEmail).collect(Collectors.toList()))); - this.postService.getAllPosts().stream().filter(post -> !post.getPostName().getSv().equals("medlem")) - .forEach(post -> this.membershipService.getMembershipsByPost(post) - .forEach(membership -> { - groupsJSON.add(goldappsGroupSerializer.serialize( - post.getEmailPrefix() + "." + membership - // This works out a technicality, should be rewritten - .getId().getFKITGroup().getSuperGroup().getEmail(), - List.of(this.getCorrectEmail(membership.getId().getITUser().toDTO(), - membership.getId().getFKITGroup().toDTO())))); - })); - groupsJSON.add(goldappsGroupSerializer.serialize("kit@chalmers.it", - this.fkitSuperGroupService.getAllGroups().stream() - .filter(g -> g.getType().equals(GroupType.COMMITTEE)) - .map(FKITSuperGroupDTO::getEmail).collect(Collectors.toList()))); - return groupsJSON; - } - - private List addAliases(List groupsJson, GoldappsGroupSerializer goldappsGroupSerializer) { - PostDTO kassor = this.postService.getPostDTO("kassör"); - - List groups = this.fkitSuperGroupService.getAllGroups() - .stream().filter(g -> g.getType().equals(GroupType.COMMITTEE)) - .collect(Collectors.toList()); - - this.addAliasToJson(goldappsGroupSerializer, groupsJson, groups, - kassor, "kassorer.kommitteer@chalmers.it"); - - PostDTO ordf = this.postService.getPostDTO("ordförande"); - this.addAliasToJson(goldappsGroupSerializer, groupsJson, groups, - ordf, "ordforanden.kommitteer@chalmers.it"); - - List committeeGroups = this.fkitSuperGroupService - .getAllGroups().stream().filter(g -> g.getType().equals(GroupType.COMMITTEE)) - .collect(Collectors.toList()); - - this.addAliasToJson(goldappsGroupSerializer, groupsJson, committeeGroups, ordf, "kassorer@chalmers.it"); - - this.addAliasToJson(goldappsGroupSerializer, groupsJson, committeeGroups, ordf, "ordforanden@chalmers.it"); - - return groupsJson; - } - - private List addAliasToJson(GoldappsGroupSerializer goldappsGroupSerializer, - List groupsJson, - List groups, - PostDTO post, - String mail - ) { - groupsJson.add(goldappsGroupSerializer.serialize(mail, - groups.stream().map(group -> post.getEmailPrefix() + "." - + group.getEmail()).collect(Collectors.toList()))); - return groupsJson; - } - - private String getCorrectEmail(ITUserDTO user, FKITGroupDTO group) { - return this.membershipService.groupIsActiveCommittee(group) ? user.getCid() + "@chalmers.it" : user.getEmail(); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/controller/admin/GroupAdminController.java b/backend/src/main/java/it/chalmers/gamma/controller/admin/GroupAdminController.java deleted file mode 100644 index dbe54010c..000000000 --- a/backend/src/main/java/it/chalmers/gamma/controller/admin/GroupAdminController.java +++ /dev/null @@ -1,172 +0,0 @@ -package it.chalmers.gamma.controller.admin; - -import it.chalmers.gamma.domain.dto.group.FKITGroupDTO; -import it.chalmers.gamma.domain.dto.group.FKITSuperGroupDTO; -import it.chalmers.gamma.domain.dto.website.WebsiteDTO; -import it.chalmers.gamma.domain.dto.website.WebsiteUrlDTO; -import it.chalmers.gamma.requests.CreateGroupRequest; -import it.chalmers.gamma.response.FileNotFoundResponse; -import it.chalmers.gamma.response.FileNotSavedException; -import it.chalmers.gamma.response.InputValidationFailedResponse; -import it.chalmers.gamma.response.group.GroupAlreadyExistsResponse; -import it.chalmers.gamma.response.group.GroupCreatedResponse; -import it.chalmers.gamma.response.group.GroupDeletedResponse; -import it.chalmers.gamma.response.group.GroupDoesNotExistResponse; -import it.chalmers.gamma.response.group.GroupEditedResponse; -import it.chalmers.gamma.service.AuthorityLevelService; -import it.chalmers.gamma.service.FKITGroupService; -import it.chalmers.gamma.service.FKITSuperGroupService; -import it.chalmers.gamma.service.GroupWebsiteService; - -import it.chalmers.gamma.service.MembershipService; -import it.chalmers.gamma.service.WebsiteService; - -import it.chalmers.gamma.util.ImageUtils; -import it.chalmers.gamma.util.InputValidationUtils; - -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; - -import javax.validation.Valid; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.dao.DataIntegrityViolationException; -import org.springframework.validation.BindingResult; -import org.springframework.web.bind.annotation.DeleteMapping; -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.RequestParam; -import org.springframework.web.bind.annotation.RestController; -import org.springframework.web.multipart.MultipartFile; - -@SuppressWarnings({"PMD.ExcessiveImports", "PMD.AvoidDuplicateLiterals"}) -@RestController -@RequestMapping("/admin/groups") -public final class GroupAdminController { - - private final FKITGroupService fkitGroupService; - private final WebsiteService websiteService; - private final GroupWebsiteService groupWebsiteService; - private final FKITSuperGroupService fkitSuperGroupService; - private static final Logger LOGGER = LoggerFactory.getLogger(GroupAdminController.class); - private final MembershipService membershipService; - private final AuthorityLevelService authorityLevelService; - - public GroupAdminController( - FKITGroupService fkitGroupService, - WebsiteService websiteService, - GroupWebsiteService groupWebsiteService, - FKITSuperGroupService fkitSuperGroupService, - MembershipService membershipService, - AuthorityLevelService authorityLevelService) { - this.fkitGroupService = fkitGroupService; - this.websiteService = websiteService; - this.groupWebsiteService = groupWebsiteService; - this.fkitSuperGroupService = fkitSuperGroupService; - this.membershipService = membershipService; - this.authorityLevelService = authorityLevelService; - } - - @SuppressWarnings("PMD.CyclomaticComplexity") - @PostMapping() - public GroupCreatedResponse addNewGroup(@Valid @RequestBody CreateGroupRequest createGroupRequest, - BindingResult result) { - if (result.hasErrors()) { - throw new InputValidationFailedResponse(InputValidationUtils.getErrorMessages(result.getAllErrors())); - } - if (this.fkitGroupService.groupExists(createGroupRequest.getName())) { // TODO Move check to service? - throw new GroupAlreadyExistsResponse(); - } - - FKITGroupDTO group = this.fkitGroupService.createGroup(requestToDTO(createGroupRequest)); - - List websites = createGroupRequest.getWebsites(); // TODO move to service? - if (websites != null && !websites.isEmpty()) { - List websiteURLs = new ArrayList<>(); - for (CreateGroupRequest.WebsiteInfo websiteInfo : websites) { - WebsiteDTO website = this.websiteService.getWebsite(websiteInfo.getWebsite()); - WebsiteUrlDTO websiteURL = new WebsiteUrlDTO(websiteInfo.getUrl(), website); - websiteURLs.add(websiteURL); - } - try { - this.groupWebsiteService.addGroupWebsites(group, websiteURLs); - } catch (DataIntegrityViolationException e) { - LOGGER.warn(e.getMessage()); - LOGGER.warn("Warning was non-fatal, continuing without adding websites"); - } - } - if (createGroupRequest.getSuperGroup() != null) { // TODO move to service? - FKITSuperGroupDTO superGroup = this.fkitSuperGroupService.getGroupDTO(createGroupRequest.getSuperGroup()); - if (superGroup == null) { - throw new GroupDoesNotExistResponse(); - } - } - this.authorityLevelService.addAuthorityLevel(group.getName()); - return new GroupCreatedResponse(); - } - - @PutMapping("/{id}") - public GroupEditedResponse editGroup( - @RequestBody CreateGroupRequest request, - @PathVariable("id") String id) { - if (!this.fkitGroupService.groupExists(id)) { // TODO move to service? - throw new GroupDoesNotExistResponse(); - } - this.fkitGroupService.editGroup(id, requestToDTO(request)); - //FKITGroupDTO group = this.fkitGroupService.getDTOGroup(id); - /* List websiteUrlDTOS = request.getWebsites() - .stream().map(w -> new WebsiteUrlDTO( - w.getUrl(), - this.websiteService.getWebsite(w.getWebsite()))).collect(Collectors.toList()); - this.groupWebsiteService.addGroupWebsites(group, websiteUrlDTOS);*/ - return new GroupEditedResponse(); - } - - @DeleteMapping("/{id}") - public GroupDeletedResponse deleteGroup(@PathVariable("id") String id) { - if (!this.fkitGroupService.groupExists(id)) { // TODO Move to service? - throw new GroupDoesNotExistResponse(); - } - this.groupWebsiteService.deleteWebsitesConnectedToGroup( - this.fkitGroupService.getGroup(id) - ); - this.membershipService.removeAllUsersFromGroup(this.fkitGroupService.getGroup(id)); - this.fkitGroupService.removeGroup(UUID.fromString(id)); - return new GroupDeletedResponse(); - } - - @PutMapping("/{id}/avatar") - public GroupEditedResponse editAvatar(@PathVariable("id") String id, @RequestParam MultipartFile file) { - FKITGroupDTO group = this.fkitGroupService.getGroup(id); - if (group == null) { - throw new GroupDoesNotExistResponse(); - } - try { - String url = ImageUtils.saveImage(file, file.getName()); - this.fkitGroupService.editGroupAvatar(group, url); - } catch (FileNotFoundResponse e) { - throw new FileNotSavedException(); - } - return new GroupEditedResponse(); - } - - private FKITGroupDTO requestToDTO(CreateGroupRequest request) { - return new FKITGroupDTO( - request.getBecomesActive(), - request.getBecomesInactive(), - request.getDescription(), - request.getEmail(), - request.getFunction(), - request.getName(), - request.getPrettyName(), - request.getAvatarURL(), - this.fkitSuperGroupService.getGroupDTO(request.getSuperGroup()) - ); - } - -} diff --git a/backend/src/main/java/it/chalmers/gamma/controller/admin/GroupMemberAdminController.java b/backend/src/main/java/it/chalmers/gamma/controller/admin/GroupMemberAdminController.java deleted file mode 100644 index 42009b753..000000000 --- a/backend/src/main/java/it/chalmers/gamma/controller/admin/GroupMemberAdminController.java +++ /dev/null @@ -1,90 +0,0 @@ -package it.chalmers.gamma.controller.admin; - -import it.chalmers.gamma.domain.dto.group.FKITGroupDTO; -import it.chalmers.gamma.domain.dto.membership.MembershipDTO; -import it.chalmers.gamma.domain.dto.post.PostDTO; -import it.chalmers.gamma.domain.dto.user.ITUserDTO; -import it.chalmers.gamma.requests.AddUserGroupRequest; -import it.chalmers.gamma.requests.EditMembershipRequest; - -import it.chalmers.gamma.response.InputValidationFailedResponse; -import it.chalmers.gamma.response.membership.EditedMembershipResponse; -import it.chalmers.gamma.response.membership.MemberAddedToGroupResponse; -import it.chalmers.gamma.response.membership.MemberRemovedFromGroupResponse; - -import it.chalmers.gamma.service.FKITGroupService; -import it.chalmers.gamma.service.ITUserService; -import it.chalmers.gamma.service.MembershipService; -import it.chalmers.gamma.service.PostService; -import it.chalmers.gamma.util.InputValidationUtils; - -import javax.validation.Valid; - -import org.springframework.validation.BindingResult; -import org.springframework.web.bind.annotation.DeleteMapping; -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; - -@SuppressWarnings({"PMD.ExcessiveImports", "PMD.AvoidDuplicateLiterals"}) -@RestController -@RequestMapping("/admin/groups") -public final class GroupMemberAdminController { - private final ITUserService itUserService; - private final PostService postService; - private final FKITGroupService fkitGroupService; - private final MembershipService membershipService; - - public GroupMemberAdminController( - ITUserService itUserService, - PostService postService, - FKITGroupService fkitGroupService, - MembershipService membershipService) { - this.itUserService = itUserService; - this.postService = postService; - this.fkitGroupService = fkitGroupService; - this.membershipService = membershipService; - } - - @PostMapping("/{id}/members") - public MemberAddedToGroupResponse addUserToGroup( - @Valid @RequestBody AddUserGroupRequest request, BindingResult result, - @PathVariable("id") String id) { - if (result.hasErrors()) { - throw new InputValidationFailedResponse(InputValidationUtils.getErrorMessages(result.getAllErrors())); - } - ITUserDTO user = this.itUserService.getITUser(request.getUserId()); - FKITGroupDTO fkitGroup = this.fkitGroupService.getGroup(id); - PostDTO post = this.postService.getPostDTO(request.getPost()); - this.membershipService.addUserToGroup(fkitGroup, user, post, request.getUnofficialName()); - return new MemberAddedToGroupResponse(); - } - - @DeleteMapping("/{id}/members/{user}") - public MemberRemovedFromGroupResponse deleteUserFromGroup(@PathVariable("id") String id, - @PathVariable("user") String userId) { - FKITGroupDTO group = this.fkitGroupService.getGroup(id); - ITUserDTO user = this.itUserService.getITUser(userId); - this.membershipService.removeUserFromGroup(group, user); - return new MemberRemovedFromGroupResponse(); - } - - @PutMapping("/{id}/members/{user}") - public EditedMembershipResponse editUserInGroup(@PathVariable("id") String groupId, - @PathVariable("user") String userId, - @Valid @RequestBody EditMembershipRequest request, - BindingResult result) { - if (result.hasErrors()) { - throw new InputValidationFailedResponse(InputValidationUtils.getErrorMessages(result.getAllErrors())); - } - FKITGroupDTO group = this.fkitGroupService.getGroup(groupId); - ITUserDTO user = this.itUserService.getITUser(userId); - MembershipDTO membership = this.membershipService.getMembershipByUserAndGroup(user, group); - PostDTO post = this.postService.getPostDTO(request.getPost()); - this.membershipService.editMembership(membership, request.getUnofficialName(), post); - return new EditedMembershipResponse(); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/controller/admin/GroupPostAdminController.java b/backend/src/main/java/it/chalmers/gamma/controller/admin/GroupPostAdminController.java deleted file mode 100644 index 7aff82bd6..000000000 --- a/backend/src/main/java/it/chalmers/gamma/controller/admin/GroupPostAdminController.java +++ /dev/null @@ -1,118 +0,0 @@ -package it.chalmers.gamma.controller.admin; - -import it.chalmers.gamma.domain.dto.group.FKITGroupDTO; -import it.chalmers.gamma.domain.dto.membership.RestrictedMembershipDTO; -import it.chalmers.gamma.domain.dto.post.PostDTO; -import it.chalmers.gamma.requests.AddPostRequest; -import it.chalmers.gamma.response.InputValidationFailedResponse; -import it.chalmers.gamma.response.group.GetFKITGroupResponse; -import it.chalmers.gamma.response.post.GetPostUsagesResponse; -import it.chalmers.gamma.response.post.GetPostUsagesResponse.GetPostUsagesResponseObject; -import it.chalmers.gamma.response.post.PostAlreadyExistsResponse; -import it.chalmers.gamma.response.post.PostCreatedResponse; -import it.chalmers.gamma.response.post.PostDeletedResponse; -import it.chalmers.gamma.response.post.PostEditedResponse; -import it.chalmers.gamma.response.post.PostIsInUseResponse; -import it.chalmers.gamma.service.MembershipService; -import it.chalmers.gamma.service.PostService; -import it.chalmers.gamma.util.InputValidationUtils; - -import java.util.List; -import java.util.UUID; - -import java.util.stream.Collectors; -import javax.validation.Valid; - -import org.springframework.validation.BindingResult; -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; - -@SuppressWarnings({"PMD.ExcessiveImports", "PMD.AvoidDuplicateLiterals"}) -@RestController -@RequestMapping("/admin/groups/posts") -public final class GroupPostAdminController { - - private final PostService postService; - private final MembershipService membershipService; - - public GroupPostAdminController( - PostService postService, - MembershipService membershipService) { - this.postService = postService; - this.membershipService = membershipService; - } - - /** - * Adds a new post, eg ordförande or ledamot. - * - * @param request the name of the new post - * @return what the result of trying to create the post was. - */ - @PostMapping() - public PostCreatedResponse addOfficialPost(@Valid @RequestBody AddPostRequest request, BindingResult result) { - if (result.hasErrors()) { - throw new InputValidationFailedResponse(InputValidationUtils.getErrorMessages(result.getAllErrors())); - } - if (this.postService.postExists(request.getPost().getSv())) { - throw new PostAlreadyExistsResponse(); - } - this.postService.addPost(request.getPost(), request.getEmailPrefix()); - return new PostCreatedResponse(); - } - - /** - * Attempts to edit the name of a already created post. - * - * @param request the new name of the post - * @param id the id of the post - * @return the result of creating the post - */ - @PutMapping("/{id}") - public PostEditedResponse editPost( - @RequestBody AddPostRequest request, - @PathVariable("id") String id) { - PostDTO post = this.postService.getPostDTO(id); - this.postService.editPost(post, request.getPost(), request.getEmailPrefix()); - return new PostEditedResponse(); - } - - - @DeleteMapping("/{id}") - public PostDeletedResponse deletePost(@PathVariable("id") String id) { - UUID uuid = UUID.fromString(id); - if (this.membershipService.isPostUsed(uuid)) { - throw new PostIsInUseResponse(); - } - - this.postService.deletePost(uuid); - return new PostDeletedResponse(); - } - - - /** - * gets all places where a post is used, meaning which groups have the post and who currently is assigned that post. - * - * @param id the GROUP_ID of the post - * @return a list of groups that has the post and who in the group currently is assigned that post - */ - @GetMapping("/{id}/usage") - public GetPostUsagesResponseObject getPostUsages(@PathVariable("id") String id) { - PostDTO post = this.postService.getPostDTO(id); - List groups = this.membershipService.getGroupsWithPost(post); - List groupResponses = groups.stream() - .map(g -> new GetFKITGroupResponse(g, - this.membershipService.getUserDTOByGroupAndPost(g, post) - .stream() - .map(RestrictedMembershipDTO::new) - .collect(Collectors.toList()) - )) - .collect(Collectors.toList()); - return new GetPostUsagesResponse(groupResponses).toResponseObject(); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/controller/admin/ITClientAdminController.java b/backend/src/main/java/it/chalmers/gamma/controller/admin/ITClientAdminController.java deleted file mode 100644 index feaa908ef..000000000 --- a/backend/src/main/java/it/chalmers/gamma/controller/admin/ITClientAdminController.java +++ /dev/null @@ -1,86 +0,0 @@ -package it.chalmers.gamma.controller.admin; - -import it.chalmers.gamma.domain.dto.access.ITClientDTO; -import it.chalmers.gamma.requests.AddITClientRequest; -import it.chalmers.gamma.response.client.ClientAddedResponse; -import it.chalmers.gamma.response.client.ClientAddedResponse.ClientAddedResponseObject; -import it.chalmers.gamma.response.client.ClientEditedResponse; -import it.chalmers.gamma.response.client.GetAllClientsResponse; -import it.chalmers.gamma.response.client.GetAllClientsResponse.GetAllClientResponseObject; -import it.chalmers.gamma.response.client.GetITClientResponse; -import it.chalmers.gamma.response.client.GetITClientResponse.GetITClientResponseObject; -import it.chalmers.gamma.response.client.ITClientDoesNotExistException; -import it.chalmers.gamma.response.client.ITClientRemovedResponse; -import it.chalmers.gamma.service.ITClientService; - -import java.util.UUID; - -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; - -@RestController -@RequestMapping("/admin/clients") -public class ITClientAdminController { - - private final ITClientService itClientService; - - public ITClientAdminController(ITClientService itClientService) { - this.itClientService = itClientService; - } - - @PostMapping() - public ClientAddedResponseObject addITClient(@RequestBody AddITClientRequest request) { - return new ClientAddedResponse(this.itClientService.createITClient( - request.getName(), - request.getDescription(), - request.getWebServerRedirectUri(), - request.isAutoApprove() - ) - .getClientSecret()).toResponseObject(); - } - - @GetMapping() - public GetAllClientResponseObject getAllOauthClients() { - return new GetAllClientsResponse(this.itClientService.getAllClients()).toResponseObject(); - } - - @GetMapping("/{id}") - public GetITClientResponseObject getClient(@PathVariable("id") String id) { - ITClientDTO client = this.itClientService.getITClient(UUID.fromString(id)); - return new GetITClientResponse(client).toResponseObject(); - } - - @DeleteMapping("/{id}") - public ITClientRemovedResponse removeClient(@PathVariable("id") String id) { - if (!this.itClientService.clientExists(id)) { - throw new ITClientDoesNotExistException(); - } - this.itClientService.removeITClient(UUID.fromString(id)); - return new ITClientRemovedResponse(); - } - - @PutMapping("/{id}") - public ClientEditedResponse editClient( - @PathVariable("id") String id, @RequestBody AddITClientRequest request) { - if (this.itClientService.clientExists(id)) { - throw new ITClientDoesNotExistException(); - } - this.itClientService.editClient(UUID.fromString(id), responseToDTO(request)); - return new ClientEditedResponse(); - } - - private ITClientDTO responseToDTO(AddITClientRequest request) { - return new ITClientDTO( - request.getWebServerRedirectUri(), - request.getName(), - request.getDescription(), - request.isAutoApprove() - ); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/controller/admin/ITUserApprovalAdminController.java b/backend/src/main/java/it/chalmers/gamma/controller/admin/ITUserApprovalAdminController.java deleted file mode 100644 index d370d8c3a..000000000 --- a/backend/src/main/java/it/chalmers/gamma/controller/admin/ITUserApprovalAdminController.java +++ /dev/null @@ -1,42 +0,0 @@ -package it.chalmers.gamma.controller.admin; - -import it.chalmers.gamma.domain.dto.user.ITUserRestrictedDTO; -import it.chalmers.gamma.response.approval.GetAllITUserApprovalResponse; -import it.chalmers.gamma.response.client.ITClientDoesNotExistException; -import it.chalmers.gamma.service.ITClientService; -import it.chalmers.gamma.service.ITUserApprovalService; - -import java.util.stream.Collectors; - -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -@RestController -@RequestMapping("/admin/users/approval") -public class ITUserApprovalAdminController { - - private final ITUserApprovalService itUserApprovalService; - private final ITClientService itClientService; - - public ITUserApprovalAdminController(ITUserApprovalService itUserApprovalService, ITClientService itClientService) { - this.itUserApprovalService = itUserApprovalService; - this.itClientService = itClientService; - } - - @GetMapping("/{clientId}") - public GetAllITUserApprovalResponse getApprovalsByClientId(@PathVariable("clientId") String clientId) { - if (!this.itClientService.clientExists(clientId)) { - throw new ITClientDoesNotExistException(); - } - - return new GetAllITUserApprovalResponse( - this.itUserApprovalService.getApprovalsByClientId(clientId) - .stream() - .map(itUserApprovalDTO -> new ITUserRestrictedDTO(itUserApprovalDTO.getUser())) - .collect(Collectors.toList()) - ); - } - -} diff --git a/backend/src/main/java/it/chalmers/gamma/controller/admin/SuperGroupAdminController.java b/backend/src/main/java/it/chalmers/gamma/controller/admin/SuperGroupAdminController.java deleted file mode 100644 index 9f8dea2b1..000000000 --- a/backend/src/main/java/it/chalmers/gamma/controller/admin/SuperGroupAdminController.java +++ /dev/null @@ -1,88 +0,0 @@ -package it.chalmers.gamma.controller.admin; - -import it.chalmers.gamma.domain.dto.group.FKITSuperGroupDTO; -import it.chalmers.gamma.requests.CreateSuperGroupRequest; -import it.chalmers.gamma.response.InputValidationFailedResponse; -import it.chalmers.gamma.response.group.GroupAlreadyExistsResponse; -import it.chalmers.gamma.response.group.GroupDeletedResponse; -import it.chalmers.gamma.response.group.GroupDoesNotExistResponse; -import it.chalmers.gamma.response.group.GroupEditedResponse; -import it.chalmers.gamma.response.supergroup.GetSuperGroupResponse; -import it.chalmers.gamma.response.supergroup.GetSuperGroupResponse.GetSuperGroupResponseObject; -import it.chalmers.gamma.response.supergroup.RemoveSubGroupsBeforeRemovingSuperGroupResponse; -import it.chalmers.gamma.service.FKITGroupService; -import it.chalmers.gamma.service.FKITSuperGroupService; -import it.chalmers.gamma.util.InputValidationUtils; - -import java.util.UUID; - -import javax.validation.Valid; - -import org.springframework.validation.BindingResult; -import org.springframework.web.bind.annotation.DeleteMapping; -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; - -@RestController -@RequestMapping("/admin/superGroups") // What should this URL be? -public class SuperGroupAdminController { - private final FKITSuperGroupService fkitSuperGroupService; - private final FKITGroupService fkitGroupService; - - - public SuperGroupAdminController(FKITSuperGroupService fkitSuperGroupService, FKITGroupService fkitGroupService) { - this.fkitSuperGroupService = fkitSuperGroupService; - this.fkitGroupService = fkitGroupService; - } - - @PostMapping() - public GetSuperGroupResponseObject createSuperGroup(@Valid @RequestBody CreateSuperGroupRequest request, - BindingResult result) { - if (result.hasErrors()) { - throw new InputValidationFailedResponse(InputValidationUtils.getErrorMessages(result.getAllErrors())); - } - if (this.fkitSuperGroupService.groupExists(request.getName())) { - throw new GroupAlreadyExistsResponse(); - } - FKITSuperGroupDTO group = this.fkitSuperGroupService.createSuperGroup(requestToDTO(request)); - return new GetSuperGroupResponse(group).toResponseObject(); - } - - - - @DeleteMapping("/{id}") - public GroupDeletedResponse removeSuperGroup(@PathVariable("id") String id) { - if (!this.fkitSuperGroupService.groupExists(id)) { - throw new GroupDoesNotExistResponse(); - } - FKITSuperGroupDTO superGroup = this.fkitSuperGroupService.getGroupDTO(id); - if (!this.fkitGroupService.getAllGroupsWithSuperGroup(superGroup).isEmpty()) { - throw new RemoveSubGroupsBeforeRemovingSuperGroupResponse(); - } - this.fkitSuperGroupService.removeGroup(UUID.fromString(id)); - return new GroupDeletedResponse(); - } - - @PutMapping("/{id}") - public GroupEditedResponse updateSuperGroup(@PathVariable("id") String id, - @RequestBody CreateSuperGroupRequest request) { - if (!this.fkitSuperGroupService.groupExists(id)) { - throw new GroupDoesNotExistResponse(); - } - this.fkitSuperGroupService.updateSuperGroup(UUID.fromString(id), requestToDTO(request)); - return new GroupEditedResponse(); - } - - private FKITSuperGroupDTO requestToDTO(CreateSuperGroupRequest request) { - return new FKITSuperGroupDTO( - request.getName(), - request.getPrettyName(), - request.getType(), - request.getEmail()); - } - -} diff --git a/backend/src/main/java/it/chalmers/gamma/controller/admin/UserActivationCodeAdminController.java b/backend/src/main/java/it/chalmers/gamma/controller/admin/UserActivationCodeAdminController.java deleted file mode 100644 index 6487053a0..000000000 --- a/backend/src/main/java/it/chalmers/gamma/controller/admin/UserActivationCodeAdminController.java +++ /dev/null @@ -1,53 +0,0 @@ -package it.chalmers.gamma.controller.admin; - -import it.chalmers.gamma.response.activationcode.ActivationCodeDeletedResponse; -import it.chalmers.gamma.response.activationcode.ActivationCodeDoesNotExistResponse; -import it.chalmers.gamma.response.activationcode.GetActivationCodeResponse; -import it.chalmers.gamma.response.activationcode.GetActivationCodeResponse.GetActivationCodeResponseObject; -import it.chalmers.gamma.response.activationcode.GetAllActivationCodesResponse; -import it.chalmers.gamma.response.activationcode.GetAllActivationCodesResponse.GetAllActivationCodesResponseObject; -import it.chalmers.gamma.service.ActivationCodeService; - -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.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -@RestController -@RequestMapping("/admin/activation_codes") -public final class UserActivationCodeAdminController { - - private final ActivationCodeService activationCodeService; - - public UserActivationCodeAdminController(ActivationCodeService activationCodeService) { - this.activationCodeService = activationCodeService; - } - - @GetMapping() - public GetAllActivationCodesResponseObject getAllActivationCodes() { - return new GetAllActivationCodesResponse( - this.activationCodeService.getAllActivationCodes()).toResponseObject(); - } - - @GetMapping("/{activationCode}") - public GetActivationCodeResponseObject getActivationCode( - @PathVariable("activationCode") String activationCode) { - if (!this.activationCodeService.codeExists(activationCode)) { - throw new ActivationCodeDoesNotExistResponse(); - } - return new GetActivationCodeResponse( - this.activationCodeService.getActivationCodeDTO(activationCode)).toResponseObject(); - } - - @DeleteMapping("/{activationCode}") - public ActivationCodeDeletedResponse removeActivationCode(@PathVariable("activationCode") String activationCode) { - if (!this.activationCodeService.codeExists(activationCode)) { - throw new ActivationCodeDoesNotExistResponse(); - } - if (!this.activationCodeService.deleteCode(activationCode)) { - throw new ActivationCodeDoesNotExistResponse(); - } - return new ActivationCodeDeletedResponse(); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/controller/admin/UsersAdminController.java b/backend/src/main/java/it/chalmers/gamma/controller/admin/UsersAdminController.java deleted file mode 100644 index 616a5fe01..000000000 --- a/backend/src/main/java/it/chalmers/gamma/controller/admin/UsersAdminController.java +++ /dev/null @@ -1,152 +0,0 @@ -package it.chalmers.gamma.controller.admin; - -import it.chalmers.gamma.domain.dto.group.FKITGroupDTO; -import it.chalmers.gamma.domain.dto.user.ITUserDTO; -import it.chalmers.gamma.domain.dto.website.WebsiteUrlDTO; -import it.chalmers.gamma.requests.AdminChangePasswordRequest; -import it.chalmers.gamma.requests.AdminViewCreateITUserRequest; -import it.chalmers.gamma.requests.EditITUserRequest; -import it.chalmers.gamma.response.InputValidationFailedResponse; -import it.chalmers.gamma.response.user.GetAllITUsersResponse; -import it.chalmers.gamma.response.user.GetAllITUsersResponse.GetAllITUsersResponseObject; -import it.chalmers.gamma.response.user.GetITUserResponse; -import it.chalmers.gamma.response.user.GetITUserResponse.GetITUserResponseObject; -import it.chalmers.gamma.response.user.PasswordChangedResponse; -import it.chalmers.gamma.response.user.UserAlreadyExistsResponse; -import it.chalmers.gamma.response.user.UserCreatedResponse; -import it.chalmers.gamma.response.user.UserDeletedResponse; -import it.chalmers.gamma.response.user.UserEditedResponse; -import it.chalmers.gamma.response.user.UserNotFoundResponse; -import it.chalmers.gamma.service.ITUserService; -import it.chalmers.gamma.service.MembershipService; -import it.chalmers.gamma.service.UserWebsiteService; -import it.chalmers.gamma.util.InputValidationUtils; - -import java.time.Year; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; - -import java.util.stream.Collectors; -import javax.validation.Valid; - -import org.springframework.validation.BindingResult; -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; - -@SuppressWarnings({"PMD.AvoidDuplicateLiterals", "PMD.ExcessiveImports"}) -@RestController -@RequestMapping("/admin/users") -public final class UsersAdminController { - - private final ITUserService itUserService; - private final UserWebsiteService userWebsiteService; - - - private final MembershipService membershipService; - - public UsersAdminController( - ITUserService itUserService, - UserWebsiteService userWebsiteService, - MembershipService membershipService) { - this.itUserService = itUserService; - this.userWebsiteService = userWebsiteService; - this.membershipService = membershipService; - } - - @PutMapping("/{id}/change_password") - public PasswordChangedResponse changePassword( - @PathVariable("id") String id, - @Valid @RequestBody AdminChangePasswordRequest request, BindingResult result) { - if (result.hasErrors()) { - throw new InputValidationFailedResponse(InputValidationUtils.getErrorMessages(result.getAllErrors())); - } - ITUserDTO user = this.itUserService.getITUser(id); - this.itUserService.setPassword(user, request.getPassword()); - return new PasswordChangedResponse(); - } - - //TODO Make sure that the code to add websites to users actually works - @PutMapping("/{id}") - public UserEditedResponse editUser(@PathVariable("id") String id, - @RequestBody EditITUserRequest request) { - if (!this.itUserService.userExists(UUID.fromString(id))) { - throw new UserNotFoundResponse(); - } - this.itUserService.editUser( - UUID.fromString(id), - request.getNick(), - request.getFirstName(), - request.getLastName(), - request.getEmail(), - request.getPhone(), - request.getLanguage(), - request.getAcceptanceYear() - ); - // Below handles adding websites. - ITUserDTO user = this.itUserService.getITUser(id); - List websiteURLs = new ArrayList<>(); - this.userWebsiteService.addWebsiteToUser(user, websiteURLs); - return new UserEditedResponse(); - } - - @DeleteMapping("/{id}") - public UserDeletedResponse deleteUser(@PathVariable("id") String id) { - ITUserDTO user = this.itUserService.getITUser(id); - this.userWebsiteService.deleteWebsitesConnectedToUser(user); - this.membershipService.removeAllMemberships(user); - this.itUserService.removeUser(user.getId()); - return new UserDeletedResponse(); - } - - @GetMapping("/{id}") - public GetITUserResponseObject getUser(@PathVariable("id") String id) { - ITUserDTO user = this.itUserService.getITUser(id); - // List websites = this.userWebsiteService.getWebsitesOrdered( - // this.userWebsiteService.getWebsites(user)); - List groups = this.membershipService.getUsersGroupDTO(user); - return new GetITUserResponse(user, groups, null).toResponseObject(); - } - - @GetMapping() - public GetAllITUsersResponseObject getAllUsers() { - - List users = this.itUserService.loadAllUsers(); - List userResponses = users.stream() - .map(u -> new GetITUserResponse(u, this.membershipService.getUsersGroupDTO(u), - null)) - .collect(Collectors.toList()); - return new GetAllITUsersResponse(userResponses).toResponseObject(); - } - - /** - * Administrative function that can add user without need for user to add it personally. - */ - @PostMapping() - public UserCreatedResponse addUser( - @Valid @RequestBody AdminViewCreateITUserRequest createITUserRequest, BindingResult result) { - if (result.hasErrors()) { - throw new InputValidationFailedResponse(InputValidationUtils.getErrorMessages(result.getAllErrors())); - } - if (this.itUserService.userExists(createITUserRequest.getCid())) { - throw new UserAlreadyExistsResponse(); - } - this.itUserService.createUser( - createITUserRequest.getNick(), - createITUserRequest.getFirstName(), - createITUserRequest.getLastName(), - createITUserRequest.getCid(), - Year.of(createITUserRequest.getAcceptanceYear()), - createITUserRequest.isUserAgreement(), - createITUserRequest.getEmail(), - createITUserRequest.getPassword() - ); - return new UserCreatedResponse(); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/controller/admin/UsersWhitelistAdminController.java b/backend/src/main/java/it/chalmers/gamma/controller/admin/UsersWhitelistAdminController.java deleted file mode 100644 index 16386cc3a..000000000 --- a/backend/src/main/java/it/chalmers/gamma/controller/admin/UsersWhitelistAdminController.java +++ /dev/null @@ -1,142 +0,0 @@ -package it.chalmers.gamma.controller.admin; - -import it.chalmers.gamma.domain.dto.user.WhitelistDTO; -import it.chalmers.gamma.requests.AddListOfWhitelistedRequest; -import it.chalmers.gamma.requests.WhitelistCodeRequest; - -import it.chalmers.gamma.response.InputValidationFailedResponse; -import it.chalmers.gamma.response.user.UserAlreadyExistsResponse; -import it.chalmers.gamma.response.user.UserDeletedResponse; -import it.chalmers.gamma.response.user.UserNotFoundResponse; -import it.chalmers.gamma.response.whitelist.EditedWhitelistResponse; -import it.chalmers.gamma.response.whitelist.GetAllWhitelistResponse; -import it.chalmers.gamma.response.whitelist.GetAllWhitelistResponse.GetAllWhitelistResponseObject; -import it.chalmers.gamma.response.whitelist.GetWhitelistResponse; -import it.chalmers.gamma.response.whitelist.GetWhitelistResponse.GetWhitelistResponseObject; - -import it.chalmers.gamma.response.whitelist.WhitelistAddedResponse; -import it.chalmers.gamma.response.whitelist.WhitelistAlreadyAddedException; -import it.chalmers.gamma.response.whitelist.WhitelistIsValidResponse; -import it.chalmers.gamma.response.whitelist.WhitelistIsValidResponse.WhitelistIsValidResponseObject; -import it.chalmers.gamma.service.ITUserService; -import it.chalmers.gamma.service.WhitelistService; -import it.chalmers.gamma.util.InputValidationUtils; - -import java.util.List; -import java.util.stream.Collectors; -import javax.validation.Valid; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.validation.BindingResult; -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; - -@SuppressWarnings({"PMD.AvoidDuplicateLiterals","PMD.CyclomaticComplexity", "PMD.ExcessiveImports"}) -@RestController -@RequestMapping("/admin/users/whitelist") -public final class UsersWhitelistAdminController { - - private final WhitelistService whitelistService; - private final ITUserService itUserService; - - private static final Logger LOGGER = LoggerFactory.getLogger(UsersWhitelistAdminController.class); - - public UsersWhitelistAdminController(WhitelistService whitelistService, - ITUserService itUserService) { - this.whitelistService = whitelistService; - this.itUserService = itUserService; - } - - @PostMapping() - public WhitelistAddedResponse addWhitelistedUsers( - @Valid @RequestBody AddListOfWhitelistedRequest request, BindingResult result) { - if (result.hasErrors()) { - throw new InputValidationFailedResponse(InputValidationUtils.getErrorMessages(result.getAllErrors())); - } - List cids = request.getCids(); - int numNotAdded = 0; - - for (String cid : cids) { // TODO move this to service - try { - if (this.whitelistService.isCIDWhiteListed(cid)) { - throw new WhitelistAlreadyAddedException(); - } - if (this.itUserService.userExists(cid)) { - throw new UserAlreadyExistsResponse(); - } - this.whitelistService.addWhiteListedCID(cid); - LOGGER.info("Added user " + cid + " to whitelist"); - } catch (UserAlreadyExistsResponse | WhitelistAlreadyAddedException e) { - LOGGER.info("Did not add user " + cid + " message: " + e.getMessage()); - numNotAdded++; - } - } - int numAdded = cids.size() - numNotAdded; - if (numAdded == 0) { - throw new UserAlreadyExistsResponse(); - } - return new WhitelistAddedResponse(numAdded, numNotAdded); - } - - /** - * /whitelist/valid will be able to return whether or not a - * user is whitelist, without doing anything to modify the data. - * - * @return true if the user is whitelisted false otherwise - */ - @GetMapping("/{id}/valid") // Should this be changed to a Pathvar? - public WhitelistIsValidResponseObject validCid(@PathVariable("id") String id) { - - return new WhitelistIsValidResponse(this.whitelistService.isCIDWhiteListed(id)).toResponseObject(); - } - - @PutMapping("/{id}") - public EditedWhitelistResponse editWhitelist( - @Valid @RequestBody WhitelistCodeRequest request, - @PathVariable("id") String id, - BindingResult result) { - if (result.hasErrors()) { - throw new InputValidationFailedResponse(InputValidationUtils.getErrorMessages(result.getAllErrors())); - } - WhitelistDTO oldWhitelist = this.whitelistService.getWhitelist(id); - if (!this.whitelistService.isCIDWhiteListed(oldWhitelist.getCid())) { - throw new UserNotFoundResponse(); - } - if (this.whitelistService.isCIDWhiteListed(request.getCid())) { - throw new WhitelistAlreadyAddedException(); - } - this.whitelistService.editWhitelist(oldWhitelist, request.getCid()); - return new EditedWhitelistResponse(); - } - - @DeleteMapping("/{id}") - public UserDeletedResponse removeWhitelist(@PathVariable("id") String id) { - if (!this.whitelistService.isCIDWhiteListed(id)) { - throw new UserNotFoundResponse(); - } - this.whitelistService.removeWhiteListedCID(id); - return new UserDeletedResponse(); - } - - @GetMapping() - public GetAllWhitelistResponseObject getAllWhiteList() { - List whitelistResponses = this.whitelistService.getAllWhitelist() - .stream().map(GetWhitelistResponse::new).collect(Collectors.toList()); - return new GetAllWhitelistResponse(whitelistResponses).toResponseObject(); - } - - @GetMapping("/{id}") - public GetWhitelistResponseObject getWhitelist(@PathVariable("id") String id) { - return new GetWhitelistResponse(this.whitelistService.getWhitelist(id)).toResponseObject(); - } - - - -} diff --git a/backend/src/main/java/it/chalmers/gamma/controller/admin/WebsiteAdminController.java b/backend/src/main/java/it/chalmers/gamma/controller/admin/WebsiteAdminController.java deleted file mode 100644 index 8fa3dacc1..000000000 --- a/backend/src/main/java/it/chalmers/gamma/controller/admin/WebsiteAdminController.java +++ /dev/null @@ -1,72 +0,0 @@ -package it.chalmers.gamma.controller.admin; - -import it.chalmers.gamma.domain.dto.website.WebsiteDTO; -import it.chalmers.gamma.requests.CreateWebsiteRequest; -import it.chalmers.gamma.response.InputValidationFailedResponse; -import it.chalmers.gamma.response.website.EditedWebsiteResponse; -import it.chalmers.gamma.response.website.WebsiteAddedResponse; -import it.chalmers.gamma.response.website.WebsiteDeletedResponse; -import it.chalmers.gamma.service.GroupWebsiteService; -import it.chalmers.gamma.service.UserWebsiteService; -import it.chalmers.gamma.service.WebsiteService; -import it.chalmers.gamma.util.InputValidationUtils; - -import javax.validation.Valid; - -import org.springframework.validation.BindingResult; -import org.springframework.web.bind.annotation.DeleteMapping; -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; - -@SuppressWarnings("PMD.AvoidDuplicateLiterals") -@RestController -@RequestMapping("/admin/websites") -public final class WebsiteAdminController { - - private final WebsiteService websiteService; - private final GroupWebsiteService groupWebsiteService; - private final UserWebsiteService userWebsiteService; - - public WebsiteAdminController( - WebsiteService websiteService, - GroupWebsiteService groupWebsiteService, - UserWebsiteService userWebsiteService) { - this.websiteService = websiteService; - this.groupWebsiteService = groupWebsiteService; - this.userWebsiteService = userWebsiteService; - } - - - @PostMapping() - public WebsiteAddedResponse addWebsite(@Valid @RequestBody CreateWebsiteRequest request, BindingResult result) { - if (result.hasErrors()) { - throw new InputValidationFailedResponse(InputValidationUtils.getErrorMessages(result.getAllErrors())); - } - this.websiteService.addPossibleWebsite(request.getName(), request.getPrettyName()); - return new WebsiteAddedResponse(); - } - - @PutMapping("/{id}") - public EditedWebsiteResponse editWebsite( - @PathVariable("id") String id, - @RequestBody CreateWebsiteRequest request) { - WebsiteDTO website = this.websiteService.getWebsite(id); - this.websiteService.editWebsite(website, request.getName(), request.getPrettyName()); - return new EditedWebsiteResponse(); - } - - @DeleteMapping("/{id}") - public WebsiteDeletedResponse deleteWebsite(@PathVariable("id") String id) { - WebsiteDTO website = this.websiteService.getWebsite(id); - this.groupWebsiteService.deleteGroupWebsiteByWebsite(website); - this.userWebsiteService.deleteUserWebsiteByWebsite(website); - this.websiteService.deleteWebsite(id); - return new WebsiteDeletedResponse(); - } - - -} diff --git a/backend/src/main/java/it/chalmers/gamma/db/entity/ActivationCode.java b/backend/src/main/java/it/chalmers/gamma/db/entity/ActivationCode.java deleted file mode 100644 index 1547bc869..000000000 --- a/backend/src/main/java/it/chalmers/gamma/db/entity/ActivationCode.java +++ /dev/null @@ -1,130 +0,0 @@ -package it.chalmers.gamma.db.entity; - -import it.chalmers.gamma.domain.dto.user.ActivationCodeDTO; -import java.time.Duration; -import java.time.Instant; -import java.util.Objects; -import java.util.UUID; - -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.OneToOne; -import javax.persistence.Table; -import javax.persistence.Transient; -import org.springframework.beans.factory.annotation.Value; - -@Entity -@Table(name = "activation_code") -public class ActivationCode { - - @Id - @Column(updatable = false) - private UUID id; - - @JoinColumn(name = "cid", insertable = true, updatable = false, unique = true) - @OneToOne(fetch = FetchType.EAGER) - private Whitelist cid; // Has a foreign key referencing the Whitelist GROUP_ID - - @Column(name = "code", length = 30) - private String code; - - @Column(name = "created_at") - private Instant createdAt; - - @Transient - @Value("${password-expiration-time}") - private static final int PASSWORD_EXPIRATION_TIME = 3600; - - public Instant getCreatedAt() { - return this.createdAt; - } - - protected ActivationCode() { - this.id = UUID.randomUUID(); - } - - public ActivationCode(Whitelist cid) { - this.id = UUID.randomUUID(); - this.createdAt = Instant.now(); - this.cid = cid; - } - - public UUID getId() { - return this.id; - } - - public void setId(UUID id) { - this.id = id; - } - - public String getCid() { - return this.cid.getCid(); - } - - public Whitelist getWhitelist() { - return this.cid; - } - - public void setCreatedAt(Instant createdAt) { - this.createdAt = createdAt; - } - - public void setWhitelist(Whitelist cid) { - this.cid = cid; - } - - public void setCid(Whitelist cid) { - this.cid = cid; - } - - public String getCode() { - return this.code; - } - - public void setCode(String code) { - this.code = code; - } - - public boolean isValid() { - return Instant.now().isBefore(this.createdAt.plus(Duration.ofSeconds(PASSWORD_EXPIRATION_TIME))); - } - - public ActivationCodeDTO toDTO() { - return new ActivationCodeDTO(this.id, - this.cid.toDTO(), - this.code, - this.createdAt, - PASSWORD_EXPIRATION_TIME); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - ActivationCode that = (ActivationCode) o; - return Objects.equals(this.id, that.id) - && Objects.equals(this.cid, that.cid) - && Objects.equals(this.code, that.code); - } - - @Override - public int hashCode() { - return Objects.hash(this.id, this.cid, this.code); - } - - @Override - public String toString() { - return "ActivationCode{" - + "id=" + this.id - + ", whitelistedCid=" + this.cid - + ", code='" + this.code + '\'' - + '}'; - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/db/entity/ApiKey.java b/backend/src/main/java/it/chalmers/gamma/db/entity/ApiKey.java deleted file mode 100644 index 727202760..000000000 --- a/backend/src/main/java/it/chalmers/gamma/db/entity/ApiKey.java +++ /dev/null @@ -1,147 +0,0 @@ -package it.chalmers.gamma.db.entity; - -import it.chalmers.gamma.domain.dto.access.ApiKeyDTO; -import java.time.Instant; -import java.util.Objects; -import java.util.UUID; -import javax.persistence.CascadeType; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.OneToOne; -import javax.persistence.Table; - -import org.hibernate.annotations.ColumnDefault; - -@Entity -@Table(name = "apikey") -public class ApiKey { - @Id - @Column(updatable = false) - private UUID id; - - @Column(name = "name", length = 30, nullable = false) - private String name; - - @JoinColumn(name = "description") - @OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true) - private Text description; - - @Column(name = "key", length = 150, nullable = false) - private String key; - - @Column(name = "created_at", nullable = false) - @ColumnDefault("current_timestamp") - private Instant createdAt; - - @Column(name = "last_modified_at", nullable = false) - @ColumnDefault("current_timestamp") - private Instant lastModifiedAt; - - public ApiKey() { - this.id = UUID.randomUUID(); - this.createdAt = Instant.now(); - this.lastModifiedAt = Instant.now(); - } - - public ApiKey(String name, String key, Text description) { - this(); - this.name = name; - this.key = key; - this.description = description; - } - - public UUID getId() { - return this.id; - } - - public void setId(UUID id) { - this.id = id; - } - - public String getName() { - return this.name; - } - - public void setName(String name) { - this.name = name; - } - - public Text getDescription() { - return this.description; - } - - public void setDescription(Text description) { - this.description = description; - } - - public String getKey() { - return this.key; - } - - public void setKey(String key) { - this.key = key; - } - - public Instant getCreatedAt() { - return this.createdAt; - } - - public void setCreatedAt(Instant createdAt) { - this.createdAt = createdAt; - } - - public Instant getLastModifiedAt() { - return this.lastModifiedAt; - } - - public void setLastModifiedAt(Instant lastModifiedAt) { - this.lastModifiedAt = lastModifiedAt; - } - - public ApiKeyDTO toDTO() { - return new ApiKeyDTO(this.id, this.name, this.description, this.createdAt, this.lastModifiedAt, this.key); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - ApiKey apiKey = (ApiKey) o; - return Objects.equals(this.id, apiKey.id) - && Objects.equals(this.name, apiKey.name) - && Objects.equals(this.description, apiKey.description) - && Objects.equals(this.key, apiKey.key) - && Objects.equals(this.createdAt, apiKey.createdAt) - && Objects.equals(this.lastModifiedAt, apiKey.lastModifiedAt); - } - - @Override - public int hashCode() { - return Objects.hash( - this.id, - this.name, - this.description, - this.key, - this.createdAt, - this.lastModifiedAt); - } - - @Override - public String toString() { - return "ApiKey{" - + "id=" + this.id - + ", name='" + this.name + '\'' - + ", description=" + this.description - + ", key='" + this.key + '\'' - + ", createdAt=" + this.createdAt - + ", lastModifiedAt=" + this.lastModifiedAt - + '}'; - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/db/entity/Authority.java b/backend/src/main/java/it/chalmers/gamma/db/entity/Authority.java deleted file mode 100644 index d46b9f3b8..000000000 --- a/backend/src/main/java/it/chalmers/gamma/db/entity/Authority.java +++ /dev/null @@ -1,96 +0,0 @@ -package it.chalmers.gamma.db.entity; - -import it.chalmers.gamma.db.entity.pk.AuthorityPK; - -import it.chalmers.gamma.domain.dto.authority.AuthorityDTO; -import java.util.Objects; -import java.util.UUID; - -import javax.persistence.Column; -import javax.persistence.EmbeddedId; -import javax.persistence.Entity; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.Table; - -import org.hibernate.annotations.Target; - -@Entity -@Table(name = "authority") -public class Authority { - - @Target(AuthorityPK.class) - @EmbeddedId - private AuthorityPK id; - - @Column(name = "id") - private UUID internalId; - - @JoinColumn(name = "authority_level") - @ManyToOne - private AuthorityLevel authorityLevel; - - public AuthorityPK getId() { - return this.id; - } - - public void setId(AuthorityPK id) { - this.id = id; - } - - public AuthorityLevel getAuthorityLevel() { - return this.authorityLevel; - } - - public void setAuthorityLevel(AuthorityLevel authorityLevel) { - this.authorityLevel = authorityLevel; - } - - public UUID getInternalID() { - return this.internalId; - } - - public void setInternalID(UUID internalID) { - this.internalId = internalID; - } - - public Authority() { - this.internalId = UUID.randomUUID(); - } - - public AuthorityDTO toDTO() { - return new AuthorityDTO( - this.id.getFkitSuperGroup().toDTO(), - this.id.getPost().toDTO(), - this.internalId, - this.authorityLevel.toDTO() - ); - } - - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - Authority authority = (Authority) o; - return Objects.equals(this.id, authority.id) - && Objects.equals(this.authorityLevel, authority.authorityLevel); - } - - @Override - public int hashCode() { - return Objects.hash(this.id, this.authorityLevel); - } - - @Override - public String toString() { - return "Authority{" - + "id=" + this.id - + ", authorityLevel=" + this.authorityLevel - + '}'; - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/db/entity/AuthorityLevel.java b/backend/src/main/java/it/chalmers/gamma/db/entity/AuthorityLevel.java deleted file mode 100644 index cc7706bc3..000000000 --- a/backend/src/main/java/it/chalmers/gamma/db/entity/AuthorityLevel.java +++ /dev/null @@ -1,78 +0,0 @@ -package it.chalmers.gamma.db.entity; - -import it.chalmers.gamma.domain.dto.authority.AuthorityLevelDTO; -import java.util.Objects; -import java.util.UUID; - -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.Id; -import javax.persistence.Table; - -import org.springframework.security.core.GrantedAuthority; - -@Entity -@Table(name = "authority_level") -@SuppressWarnings({"PMD.AvoidDuplicateLiterals", "PMD.AvoidDuplicateLiterals", "PMD.AvoidFieldNameMatchingTypeName"}) -public class AuthorityLevel implements GrantedAuthority { - - @Id - @Column(updatable = false) - private UUID id; - - @Column(name = "authority_level") - private String authorityLevel; - - public AuthorityLevel() { - this.id = UUID.randomUUID(); - } - - public UUID getId() { - return this.id; - } - - public void setId(UUID id) { - this.id = id; - } - - @Override - public String getAuthority() { - return this.authorityLevel; - } - - public void setAuthorityLevel(String authorityLevel) { - this.authorityLevel = authorityLevel.toLowerCase(); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - AuthorityLevel that = (AuthorityLevel) o; - return Objects.equals(this.id, that.id) - && Objects.equals(this.authorityLevel, that.authorityLevel); - } - - public AuthorityLevelDTO toDTO() { - return new AuthorityLevelDTO(this.id, this.authorityLevel); - } - - @Override - public int hashCode() { - return Objects.hash(this.id, this.authorityLevel); - } - - @Override - public String toString() { - return "AuthorityLevel{" - + "id=" + this.id - + ", authorityLevel='" - + this.authorityLevel + '\'' - + '}'; - } - -} diff --git a/backend/src/main/java/it/chalmers/gamma/db/entity/FKITGroup.java b/backend/src/main/java/it/chalmers/gamma/db/entity/FKITGroup.java deleted file mode 100644 index 8013c70f0..000000000 --- a/backend/src/main/java/it/chalmers/gamma/db/entity/FKITGroup.java +++ /dev/null @@ -1,170 +0,0 @@ -package it.chalmers.gamma.db.entity; - -import it.chalmers.gamma.domain.dto.group.FKITGroupDTO; - -import java.util.Calendar; -import java.util.UUID; - -import javax.persistence.CascadeType; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.OneToOne; -import javax.persistence.Table; - -@Entity -@Table(name = "fkit_group") -public class FKITGroup { - - @Id - @Column(updatable = false) - private UUID id; - - @Column(name = "avatar_url") - private String avatarURL; - - @Column(name = "name", length = 50, nullable = false) - private String name; - - @Column(name = "pretty_name", length = 50, nullable = false) - private String prettyName; - - @JoinColumn(name = "description") - @OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true) - private Text description; - - @JoinColumn(name = "function", nullable = false) - @OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true) - private Text function; - - @Column(name = "becomes_active") - private Calendar becomesActive; - - @Column(name = "becomes_inactive") - private Calendar becomesInactive; - - @Column(name = "email") - private String email; - - @JoinColumn(name = "fkit_super_group") - @ManyToOne(fetch = FetchType.EAGER) - private FKITSuperGroup superGroup; - - public FKITGroup() { - this.id = UUID.randomUUID(); - } - - public FKITGroupDTO toDTO() { - return new FKITGroupDTO( - this.id, - this.becomesActive, - this.becomesInactive, - this.description, - this.email, - this.function, - this.name, - this.prettyName, - this.avatarURL, - this.superGroup.toDTO()); - } - - public UUID getId() { - return this.id; - } - - public void setId(UUID id) { - this.id = id; - } - - public String getName() { - return this.name; - } - - public void setName(String name) { - this.name = name.toLowerCase(); - } - - public Text getDescription() { - return this.description; - } - - public void setDescription(Text description) { - this.description = description; - } - - public String getAvatarURL() { - return this.avatarURL; - } - - public void setAvatarURL(String avatarURL) { - this.avatarURL = avatarURL; - } - - public Text getFunction() { - return this.function; - } - - public void setFunction(Text function) { - this.function = function; - } - - public String getPrettyName() { - return this.prettyName; - } - - public void setPrettyName(String prettyName) { - this.prettyName = prettyName; - } - - public Calendar getBecomesActive() { - return this.becomesActive; - } - - public void setBecomesActive(Calendar becomesActive) { - this.becomesActive = becomesActive; - } - - public Calendar getBecomesInactive() { - return this.becomesInactive; - } - - public void setBecomesInactive(Calendar becomesInactive) { - this.becomesInactive = becomesInactive; - } - - public String getEmail() { - return this.email; - } - - public void setEmail(String email) { - this.email = email.toLowerCase(); - } - - public FKITSuperGroup getSuperGroup() { - return this.superGroup; - } - - public void setSuperGroup(FKITSuperGroup superGroup) { - this.superGroup = superGroup; - } - - @Override - public String toString() { - return "FKITGroup{" - + "id=" + this.id - + ", avatarURL='" + this.avatarURL + '\'' - + ", name='" + this.name + '\'' - + ", prettyName='" + this.prettyName + '\'' - + ", description=" + this.description - + ", func=" + this.function - + ", becomesActive=" + this.becomesActive - + ", becomesInactive=" + this.becomesInactive - + ", email=" + this.email + '\'' - + ", superGroup='" + this.superGroup - + '}'; - } - -} \ No newline at end of file diff --git a/backend/src/main/java/it/chalmers/gamma/db/entity/FKITSuperGroup.java b/backend/src/main/java/it/chalmers/gamma/db/entity/FKITSuperGroup.java deleted file mode 100644 index c019cfbae..000000000 --- a/backend/src/main/java/it/chalmers/gamma/db/entity/FKITSuperGroup.java +++ /dev/null @@ -1,102 +0,0 @@ -package it.chalmers.gamma.db.entity; - -import it.chalmers.gamma.domain.GroupType; -import it.chalmers.gamma.domain.dto.group.FKITSuperGroupDTO; - -import java.util.UUID; - -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.EnumType; -import javax.persistence.Enumerated; -import javax.persistence.Id; -import javax.persistence.Table; - - -@Entity -@Table(name = "fkit_super_group") - -public class FKITSuperGroup { - - @Column(name = "id", updatable = false) - @Id - private UUID id; - - @Column(name = "name") - private String name; - - @Column(name = "pretty_name") - private String prettyName; - - @Column(name = "type") - @Enumerated(EnumType.STRING) - private GroupType type; - - @Column(name = "email") - private String email; - - public FKITSuperGroup() { - this.id = UUID.randomUUID(); - } - - public FKITSuperGroup(UUID id) { - this.id = id; - } - - public void setId(UUID id) { - this.id = id; - } - - public UUID getId() { - return this.id; - } - - public String getName() { - return this.name; - } - - public void setName(String name) { - this.name = name.toLowerCase(); - } - - public String getPrettyName() { - return this.prettyName; - } - - public void setPrettyName(String prettyName) { - this.prettyName = prettyName; - } - - public GroupType getType() { - return this.type; - } - - public void setType(GroupType type) { - this.type = type; - } - - public String getEmail() { - return this.email; - } - - public void setEmail(String email) { - this.email = email.toLowerCase(); - } - - public FKITSuperGroupDTO toDTO() { - return new FKITSuperGroupDTO( - this.id, this.name, this.prettyName, this.type, this.email - ); - } - - @Override - public String toString() { - return "FKITSuperGroup{" - + "id=" + this.id - + ", name='" + this.name + '\'' - + ", prettyName='" + this.prettyName + '\'' - + ", type=" + this.type - + ", email='" + this.email + '\'' - + '}'; - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/db/entity/GroupWebsite.java b/backend/src/main/java/it/chalmers/gamma/db/entity/GroupWebsite.java deleted file mode 100644 index 7c96edb37..000000000 --- a/backend/src/main/java/it/chalmers/gamma/db/entity/GroupWebsite.java +++ /dev/null @@ -1,90 +0,0 @@ -package it.chalmers.gamma.db.entity; - -import com.fasterxml.jackson.annotation.JsonIgnore; - -import it.chalmers.gamma.domain.dto.website.GroupWebsiteDTO; -import java.util.Objects; -import java.util.UUID; - -import javax.persistence.CascadeType; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.OneToOne; -import javax.persistence.Table; - -@Entity -@Table(name = "fkit_group_website") -public class GroupWebsite implements WebsiteInterface { - @Id - @JsonIgnore - private final UUID id; - - @JoinColumn(name = "website") - @OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true) - private WebsiteURL website; - - @OneToOne - @JoinColumn(name = "fkit_group") - @JsonIgnore - private FKITGroup group; - - public GroupWebsite() { - this.id = UUID.randomUUID(); - } - - public UUID getId() { - return this.id; - } - - @Override - public WebsiteURL getWebsite() { - return this.website; - } - - public void setWebsite(WebsiteURL website) { - this.website = website; - } - - public FKITGroup getGroup() { - return this.group; - } - - public void setGroup(FKITGroup group) { - this.group = group; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - GroupWebsite that = (GroupWebsite) o; - return Objects.equals(this.id, that.id) - && Objects.equals(this.website, that.website) - && Objects.equals(this.group, that.group); - } - - public GroupWebsiteDTO toDTO() { - return new GroupWebsiteDTO(this.id, this.website.toDTO(), this.group.toDTO()); - } - - @Override - public int hashCode() { - return Objects.hash(this.id, this.website, this.group); - } - - @Override - public String toString() { - return "GroupWebsite{" - + "id=" + this.id - + ", website=" + this.website - + ", group=" + this.group - + '}'; - } - -} diff --git a/backend/src/main/java/it/chalmers/gamma/db/entity/ITClient.java b/backend/src/main/java/it/chalmers/gamma/db/entity/ITClient.java deleted file mode 100644 index 8f5fc65f9..000000000 --- a/backend/src/main/java/it/chalmers/gamma/db/entity/ITClient.java +++ /dev/null @@ -1,213 +0,0 @@ -package it.chalmers.gamma.db.entity; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonInclude; - -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; - -import it.chalmers.gamma.domain.dto.access.ITClientDTO; -import java.time.Instant; -import java.util.Objects; -import java.util.UUID; - -import javax.persistence.CascadeType; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.OneToOne; -import javax.persistence.Table; - -@Entity -@Table(name = "itclient") -@JsonInclude(JsonInclude.Include.NON_EMPTY) -public class ITClient { - - @Id - @Column(updatable = false) - private final UUID id; - - @Column(name = "client_id", length = 256, nullable = false) - private String clientId; - - @Column(name = "client_secret", length = 256, nullable = false) - @JsonIgnore - private String clientSecret; - - @Column(name = "web_server_redirect_uri", length = 256, nullable = false) - private String webServerRedirectUri; - - @Column(name = "access_token_validity", nullable = false) - private int accessTokenValidity; - - @Column(name = "refresh_token_validity", nullable = false) - private int refreshTokenValidity; - - @Column(name = "auto_approve", nullable = false) - private boolean autoApprove; - - @Column(name = "name", nullable = false) - private String name; - - @SuppressFBWarnings(value = "SE_BAD_FIELD", justification = "is serializable by Jackson") - @JoinColumn(name = "description", nullable = false) - @OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true) - private Text description; - - @Column(name = "created_at", nullable = false) - private Instant createdAt; - - @Column(name = "last_modified_at", nullable = false) - private Instant lastModifiedAt; - - public ITClient() { - this.id = UUID.randomUUID(); - } - - public UUID getId() { - return this.id; - } - - public void setClientId(String clientId) { - this.clientId = clientId; - } - - public void setClientSecret(String clientSecret) { - this.clientSecret = clientSecret; - } - - public String getWebServerRedirectUri() { - return this.webServerRedirectUri; - } - - public void setWebServerRedirectUri(String webServerRedirectUri) { - this.webServerRedirectUri = webServerRedirectUri; - } - - public int getAccessTokenValidity() { - return this.accessTokenValidity; - } - - public void setAccessTokenValidity(int accessTokenValidity) { - this.accessTokenValidity = accessTokenValidity; - } - - public int getRefreshTokenValidity() { - return this.refreshTokenValidity; - } - - public void setRefreshTokenValidity(int refreshTokenValidity) { - this.refreshTokenValidity = refreshTokenValidity; - } - - public void setAutoApprove(boolean autoApprove) { - this.autoApprove = autoApprove; - } - - public String getName() { - return this.name; - } - - public void setName(String name) { - this.name = name; - } - - public Text getDescription() { - return this.description; - } - - public void setDescription(Text description) { - this.description = description; - } - - public Instant getCreatedAt() { - return this.createdAt; - } - - public void setCreatedAt(Instant createdAt) { - this.createdAt = createdAt; - } - - public Instant getLastModifiedAt() { - return this.lastModifiedAt; - } - - public void setLastModifiedAt(Instant lastModifiedAt) { - this.lastModifiedAt = lastModifiedAt; - } - - public ITClientDTO toDTO() { - return new ITClientDTO( - this.id, - this.clientId, - this.clientSecret, - this.webServerRedirectUri, - this.accessTokenValidity, - this.refreshTokenValidity, - this.autoApprove, - this.name, - this.description, - this.createdAt, - this.lastModifiedAt - ); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - - if (o == null || getClass() != o.getClass()) { - return false; - } - - ITClient itClient = (ITClient) o; - return this.accessTokenValidity == itClient.accessTokenValidity - && this.refreshTokenValidity == itClient.refreshTokenValidity - && this.autoApprove == itClient.autoApprove - && Objects.equals(this.id, itClient.id) - && Objects.equals(this.clientId, itClient.clientId) - && Objects.equals(this.clientSecret, itClient.clientSecret) - && Objects.equals(this.webServerRedirectUri, itClient.webServerRedirectUri) - && Objects.equals(this.name, itClient.name) - && Objects.equals(this.description, itClient.description) - && Objects.equals(this.createdAt, itClient.createdAt) - && Objects.equals(this.lastModifiedAt, itClient.lastModifiedAt); - } - - @Override - public int hashCode() { - return Objects.hash( - this.id, - this.clientId, - this.clientSecret, - this.webServerRedirectUri, - this.accessTokenValidity, - this.refreshTokenValidity, - this.autoApprove, - this.name, - this.description, - this.createdAt, - this.lastModifiedAt - ); - } - - @Override - public String toString() { - return "ITClient{" - + "id=" + this.id - + ", clientId='" + this.clientId + '\'' - + ", clientSecret={redacted}'\''" - + ", webServerRedirectUri='" + this.webServerRedirectUri + '\'' - + ", accessTokenValidity=" + this.accessTokenValidity - + ", refreshTokenValidity=" + this.refreshTokenValidity - + ", autoApprove=" + this.autoApprove - + ", name='" + this.name + '\'' - + ", description='" + this.description + '\'' - + ", createdAt=" + this.createdAt - + ", lastModifiedAt=" + this.lastModifiedAt - + '}'; - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/db/entity/ITUser.java b/backend/src/main/java/it/chalmers/gamma/db/entity/ITUser.java deleted file mode 100644 index c9cb2f93a..000000000 --- a/backend/src/main/java/it/chalmers/gamma/db/entity/ITUser.java +++ /dev/null @@ -1,340 +0,0 @@ -package it.chalmers.gamma.db.entity; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonInclude; - -import it.chalmers.gamma.domain.Language; -import it.chalmers.gamma.domain.dto.user.ITUserDTO; - -import java.time.Instant; -import java.time.Year; -import java.util.List; -import java.util.Objects; -import java.util.UUID; - -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.EnumType; -import javax.persistence.Enumerated; -import javax.persistence.Id; -import javax.persistence.Table; - -import org.hibernate.annotations.ColumnDefault; -import org.springframework.security.core.GrantedAuthority; - -@Entity -@Table(name = "ituser") -@JsonInclude(JsonInclude.Include.NON_EMPTY) -@SuppressWarnings({"PMD.TooManyFields"}) -public class ITUser { - - @Id - @Column(updatable = false) - @JsonIgnore - private UUID id; - - @Column(name = "cid", length = 10, nullable = false, unique = true) - private String cid; - - @JsonIgnore - @Column(name = "password", length = 255, nullable = false) - private String password; - - @Column(name = "nick", length = 50) - private String nick; - - @Column(name = "first_name", length = 50) - private String firstName; - - @Column(name = "last_name", length = 50) - private String lastName; - - @Column(name = "email", length = 100) - private String email; - - @Column(name = "phone", length = 15) - private String phone; - - @Column(name = "language", length = 15, nullable = false) - @Enumerated(EnumType.STRING) - private Language language; - - @Column(name = "avatar_url", length = 255, nullable = false) - @ColumnDefault("default.jpg") - private String avatarUrl; - - @Column(name = "gdpr", nullable = false) - @ColumnDefault("false") - private boolean gdpr; - - @Column(name = "user_agreement", nullable = false) - @ColumnDefault("false") - private boolean userAgreement; - - @Column(name = "account_locked", nullable = false) - @ColumnDefault("false") - private boolean accountLocked; - - @Column(name = "activated", nullable = false) - private boolean activated; - - @Column(name = "acceptance_year", nullable = false) - private int acceptanceYear; - - @Column(name = "created_at", nullable = false) - @ColumnDefault("current_timestamp") - private Instant createdAt; - - @Column(name = "last_modified_at", nullable = false) - @ColumnDefault("current_timestamp") - private Instant lastModifiedAt; - - public ITUser() { - this.id = UUID.randomUUID(); - this.createdAt = Instant.now(); - this.lastModifiedAt = Instant.now(); - this.activated = true; - this.avatarUrl = "default.jpg"; - } - - public ITUserDTO toDTO() { - return new ITUserDTO( - this.id, - this.cid, - this.nick, - this.firstName, - this.lastName, - this.email, - this.phone, - this.language, - this.avatarUrl, - this.gdpr, - this.userAgreement, - this.accountLocked, - Year.of(this.acceptanceYear), - this.activated - ); - } - - public ITUserDTO toUserDetailsDTO(List authorities) { - return new ITUserDTO( - this.id, - this.cid, - this.nick, - this.firstName, - this.lastName, - this.email, - this.phone, - this.language, - this.avatarUrl, - this.gdpr, - this.userAgreement, - this.accountLocked, - Year.of(this.acceptanceYear), - authorities, - this.password, - this.activated - ); - } - - public UUID getId() { - return this.id; - } - - public void setId(UUID id) { - this.id = id; - } - - public String getCid() { - return this.cid; - } - - public void setCid(String cid) { - this.cid = cid.toLowerCase(); - } - - public void setPassword(String password) { - this.password = password; - } - - public String getNick() { - return this.nick; - } - - public void setNick(String nick) { - this.nick = nick; - } - - public String getFirstName() { - return this.firstName; - } - - public void setFirstName(String firstName) { - this.firstName = firstName; - } - - public String getLastName() { - return this.lastName; - } - - public void setLastName(String lastName) { - this.lastName = lastName; - } - - public String getEmail() { - return this.email; - } - - public void setEmail(String email) { - this.email = email; - } - - public String getPhone() { - return this.phone; - } - - public void setPhone(String phone) { - this.phone = phone; - } - - public Language getLanguage() { - return this.language; - } - - public void setLanguage(Language language) { - this.language = language; - } - - public String getAvatarUrl() { - return this.avatarUrl; - } - - public void setAvatarUrl(String avatarUrl) { - this.avatarUrl = avatarUrl; - } - - public boolean isGdpr() { - return this.gdpr; - } - - public void setGdpr(boolean gdpr) { - this.gdpr = gdpr; - } - - public boolean isUserAgreement() { - return this.userAgreement; - } - - public void setUserAgreement(boolean userAgreement) { - this.userAgreement = userAgreement; - } - - public Year getAcceptanceYear() { - return Year.of(this.acceptanceYear); - } - - public void setAcceptanceYear(Year acceptanceYear) { - this.acceptanceYear = acceptanceYear.getValue(); - } - - public Instant getCreatedAt() { - return this.createdAt; - } - - public void setCreatedAt(Instant createdAt) { - this.createdAt = createdAt; - } - - public Instant getLastModifiedAt() { - return this.lastModifiedAt; - } - - public void setLastModifiedAt(Instant lastModifiedAt) { - this.lastModifiedAt = lastModifiedAt; - } - - public boolean isAccountLocked() { - return this.accountLocked; - } - - public void setAccountLocked(boolean accountLocked) { - this.accountLocked = accountLocked; - } - - public boolean isActivated() { - return this.activated; - } - - public void setActivated(boolean activated) { - this.activated = activated; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - ITUser itUser = (ITUser) o; - return this.gdpr == itUser.gdpr - && this.userAgreement == itUser.userAgreement - && Objects.equals(this.id, itUser.id) - && Objects.equals(this.cid, itUser.cid) - && Objects.equals(this.nick, itUser.nick) - && Objects.equals(this.password, itUser.password) - && Objects.equals(this.firstName, itUser.firstName) - && Objects.equals(this.lastName, itUser.lastName) - && Objects.equals(this.email, itUser.email) - && Objects.equals(this.phone, itUser.phone) - && Objects.equals(this.language, itUser.language) - && Objects.equals(this.avatarUrl, itUser.avatarUrl) - && Objects.equals(this.acceptanceYear, itUser.acceptanceYear) - && Objects.equals(this.createdAt, itUser.createdAt) - && Objects.equals(this.lastModifiedAt, itUser.lastModifiedAt); - } - - @Override - public int hashCode() { - return Objects.hash( - this.id, - this.cid, - this.password, - this.nick, - this.firstName, - this.lastName, - this.email, - this.phone, - this.language, - this.avatarUrl, - this.gdpr, - this.userAgreement, - this.acceptanceYear, - this.createdAt, - this.lastModifiedAt); - } - - @Override - public String toString() { - return "ITUser{" - + "id=" + id - + ", cid='" + cid + '\'' - + ", password='" + "" + '\'' - + ", nick='" + nick + '\'' - + ", firstName='" + firstName + '\'' - + ", lastName='" + lastName + '\'' - + ", email='" + email + '\'' - + ", phone='" + phone + '\'' - + ", language=" + language - + ", avatarUrl='" + avatarUrl + '\'' - + ", gdpr=" + gdpr - + ", userAgreement=" + userAgreement - + ", accountLocked=" + accountLocked - + ", acceptanceYear=" + acceptanceYear - + ", createdAt=" + createdAt - + ", lastModifiedAt=" + lastModifiedAt - + '}'; - } - -} diff --git a/backend/src/main/java/it/chalmers/gamma/db/entity/ITUserApproval.java b/backend/src/main/java/it/chalmers/gamma/db/entity/ITUserApproval.java deleted file mode 100644 index f8446dc0b..000000000 --- a/backend/src/main/java/it/chalmers/gamma/db/entity/ITUserApproval.java +++ /dev/null @@ -1,55 +0,0 @@ -package it.chalmers.gamma.db.entity; - -import it.chalmers.gamma.db.entity.pk.ITUserApprovalPK; -import it.chalmers.gamma.domain.dto.user.ITUserApprovalDTO; - -import java.util.Objects; - -import javax.persistence.EmbeddedId; -import javax.persistence.Entity; -import javax.persistence.Table; - -@Entity -@Table(name = "it_user_approval") -public class ITUserApproval { - - @EmbeddedId - private ITUserApprovalPK id; - - public ITUserApprovalPK getId() { - return this.id; - } - - public void setId(ITUserApprovalPK id) { - this.id = id; - } - - public ITUserApprovalDTO toDTO() { - return new ITUserApprovalDTO(this.id.getItUser().toDTO(), this.id.getItClient().toDTO()); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - ITUserApproval that = (ITUserApproval) o; - return Objects.equals(this.id, that.id); - } - - @Override - public int hashCode() { - return Objects.hash(this.id); - } - - @Override - public String toString() { - return "ITUserApproval{" - + "id=" + this.id - + '}'; - } -} - diff --git a/backend/src/main/java/it/chalmers/gamma/db/entity/Membership.java b/backend/src/main/java/it/chalmers/gamma/db/entity/Membership.java deleted file mode 100644 index e4f5a84fe..000000000 --- a/backend/src/main/java/it/chalmers/gamma/db/entity/Membership.java +++ /dev/null @@ -1,73 +0,0 @@ -package it.chalmers.gamma.db.entity; - -import it.chalmers.gamma.db.entity.pk.MembershipPK; -import it.chalmers.gamma.domain.dto.membership.MembershipDTO; - -import java.util.Objects; - -import javax.persistence.Column; -import javax.persistence.EmbeddedId; -import javax.persistence.Entity; -import javax.persistence.Table; - -@Entity -@Table(name = "membership") -public class Membership { - - @EmbeddedId - private MembershipPK id; - - @Column(name = "unofficial_post_name", length = 100) - private String unofficialPostName; - - public MembershipPK getId() { - return this.id; - } - - public void setId(MembershipPK id) { - this.id = id; - } - - public String getUnofficialPostName() { - return this.unofficialPostName; - } - - public void setUnofficialPostName(String unofficialPostName) { - this.unofficialPostName = unofficialPostName; - } - - public MembershipDTO toDTO() { - return new MembershipDTO( - this.id.getPost().toDTO(), - this.id.getFKITGroup().toDTO(), - this.unofficialPostName, - this.id.getITUser().toDTO()); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - Membership that = (Membership) o; - return Objects.equals(this.id, that.id) - && Objects.equals(this.unofficialPostName, that.unofficialPostName); - } - - @Override - public int hashCode() { - return Objects.hash(this.id, this.unofficialPostName); - } - - @Override - public String toString() { - return "Membership{" - + "id=" + this.id - + ", unofficialPostName='" + this.unofficialPostName + '\'' - + '}'; - } - -} diff --git a/backend/src/main/java/it/chalmers/gamma/db/entity/NoAccountMembership.java b/backend/src/main/java/it/chalmers/gamma/db/entity/NoAccountMembership.java deleted file mode 100644 index 78a69952d..000000000 --- a/backend/src/main/java/it/chalmers/gamma/db/entity/NoAccountMembership.java +++ /dev/null @@ -1,92 +0,0 @@ -package it.chalmers.gamma.db.entity; - -import it.chalmers.gamma.db.entity.pk.NoAccountMembershipPK; - -import it.chalmers.gamma.domain.dto.membership.NoAccountMembershipDTO; -import java.util.Objects; - -import javax.persistence.Column; -import javax.persistence.EmbeddedId; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.Table; - - -@Entity -@Table(name = "no_account_membership") -public class NoAccountMembership { - - @EmbeddedId - private NoAccountMembershipPK id; - - @ManyToOne(fetch = FetchType.EAGER) - @JoinColumn(name = "post_id") - private Post post; - - @Column(name = "unofficial_post_name", length = 100) - private String unofficialPostName; - - public NoAccountMembershipPK getId() { - return this.id; - } - - public void setId(NoAccountMembershipPK id) { - this.id = id; - } - - public Post getPost() { - return this.post; - } - - public void setPost(Post post) { - this.post = post; - } - - public String getUnofficialPostName() { - return this.unofficialPostName; - } - - public void setUnofficialPostName(String unofficialPostName) { - this.unofficialPostName = unofficialPostName; - } - - public NoAccountMembershipDTO toDTO() { - return new NoAccountMembershipDTO( - this.id.getITUser(), - this.id.getFKITGroup(), - this.post, - this.unofficialPostName - ); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - NoAccountMembership that = (NoAccountMembership) o; - return Objects.equals(this.id, that.id) - && Objects.equals(this.post, that.post) - && Objects.equals(this.unofficialPostName, that.unofficialPostName); - } - - @Override - public int hashCode() { - - return Objects.hash(this.id, this.post, this.unofficialPostName); - } - - @Override - public String toString() { - return "NoAccountMembership{" - + "id=" + this.id - + ", post=" + this.post - + ", unofficialPostName='" + this.unofficialPostName + '\'' - + '}'; - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/db/entity/PasswordResetToken.java b/backend/src/main/java/it/chalmers/gamma/db/entity/PasswordResetToken.java deleted file mode 100644 index 46ad7cce5..000000000 --- a/backend/src/main/java/it/chalmers/gamma/db/entity/PasswordResetToken.java +++ /dev/null @@ -1,88 +0,0 @@ -package it.chalmers.gamma.db.entity; - -import it.chalmers.gamma.domain.dto.user.PasswordResetTokenDTO; -import java.util.Objects; -import java.util.UUID; - -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.OneToOne; -import javax.persistence.Table; - -@Entity -@Table(name = "password_reset_token") -@SuppressWarnings("PMD.ExcessiveParameterList") -public class PasswordResetToken { - @Id - private UUID id; - - @Column(name = "token") - private String token; - - @JoinColumn(name = "ituser") - @OneToOne - private ITUser itUser; - - - public PasswordResetToken() { - this.id = UUID.randomUUID(); - } - - public UUID getId() { - return this.id; - } - - public void setId(UUID id) { - this.id = id; - } - - public String getToken() { - return this.token; - } - - public void setToken(String token) { - this.token = token; - } - - public ITUser getItUser() { - return this.itUser; - } - - public void setItUser(ITUser itUser) { - this.itUser = itUser; - } - - @Override - public String toString() { - return "PasswordResetToken{" - + "id=" + this.id - + ", token='" + this.token + '\'' - + ", itUser=" + this.itUser - + '}'; - } - - public PasswordResetTokenDTO toDTO() { - return new PasswordResetTokenDTO(this.id, this.token, this.itUser.toDTO()); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - PasswordResetToken that = (PasswordResetToken) o; - return Objects.equals(this.id, that.id) - && Objects.equals(this.token, that.token) - && Objects.equals(this.itUser, that.itUser); - } - - @Override - public int hashCode() { - return Objects.hash(this.id, this.token, this.itUser); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/db/entity/Post.java b/backend/src/main/java/it/chalmers/gamma/db/entity/Post.java deleted file mode 100644 index 8c62e4479..000000000 --- a/backend/src/main/java/it/chalmers/gamma/db/entity/Post.java +++ /dev/null @@ -1,109 +0,0 @@ -package it.chalmers.gamma.db.entity; - -import com.fasterxml.jackson.annotation.JsonProperty; - -import it.chalmers.gamma.domain.dto.post.PostDTO; -import java.util.Objects; -import java.util.UUID; - -import javax.persistence.CascadeType; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.OneToOne; -import javax.persistence.Table; - -@Entity -@Table(name = "post") -public class Post { - - @Id - @Column(updatable = false) - private UUID id; - - @JoinColumn(name = "post_name") - @OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL) - private final Text postName; - - @Column(name = "email_prefix") - private String emailPrefix; - - public Post() { - this.postName = new Text(); - this.emailPrefix = ""; - } - - public Post(Text postName, String emailPrefix) { - this.postName = postName; - this.id = UUID.randomUUID(); - this.emailPrefix = emailPrefix; - } - - public UUID getId() { - return this.id; - } - - public void setId(UUID id) { - this.id = id; - } - - @JsonProperty("sv") - public void setSVPostName(String postName) { - this.postName.setSv(postName); - } - - @JsonProperty("en") - public void setENPostName(String postName) { - this.postName.setEn(postName); - } - - public String getSVPostName() { - return this.postName.getSv(); - } - - public String getENPostName() { - return this.postName.getEn(); - } - - public String getEmailPrefix() { - return this.emailPrefix; - } - - public void setEmailPrefix(String emailPrefix) { - this.emailPrefix = emailPrefix == null ? null : emailPrefix.toLowerCase(); - } - - public PostDTO toDTO() { - return new PostDTO(this.id, this.postName, this.emailPrefix); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - Post post = (Post) o; - return Objects.equals(this.id, post.id) - && Objects.equals(this.postName, post.postName) - && Objects.equals(this.emailPrefix, post.emailPrefix); - } - - @Override - public int hashCode() { - return Objects.hash(this.id, this.postName, this.emailPrefix); - } - - @Override - public String toString() { - return "Post{" - + "id=" + this.id - + ", postName=" + this.postName - + ", emailPrefix='" + this.emailPrefix + '\'' - + '}'; - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/db/entity/Text.java b/backend/src/main/java/it/chalmers/gamma/db/entity/Text.java deleted file mode 100644 index 266d5df36..000000000 --- a/backend/src/main/java/it/chalmers/gamma/db/entity/Text.java +++ /dev/null @@ -1,87 +0,0 @@ -package it.chalmers.gamma.db.entity; - -import com.fasterxml.jackson.annotation.JsonIgnore; - -import java.util.Objects; -import java.util.UUID; - -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.Id; -import javax.persistence.Table; - -@Entity -@Table(name = "internal_text") -public class Text { - - @Id - @Column(updatable = false) - @JsonIgnore - private final UUID id; - - @Column(name = "sv") - private String sv; - - @Column(name = "en") - private String en; - - public Text(String sv, String en) { - this.sv = sv; - this.en = en; - this.id = UUID.randomUUID(); - } - - public Text() { - this.sv = ""; - this.en = ""; - this.id = UUID.randomUUID(); - } - - public UUID getId() { - return this.id; - } - - public String getSv() { - return this.sv; - } - - public void setSv(String sv) { - this.sv = sv; - } - - public String getEn() { - return this.en; - } - - public void setEn(String en) { - this.en = en; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - Text text = (Text) o; - return Objects.equals(this.id, text.id) - && Objects.equals(this.sv, text.sv) - && Objects.equals(this.en, text.en); - } - - @Override - public String toString() { - return "Text{" - + "id=" + this.id - + ", sv='" + this.sv + '\'' - + ", en='" + this.en + '\'' - + '}'; - } - - @Override - public int hashCode() { - return Objects.hash(this.id, this.sv, this.en); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/db/entity/UserWebsite.java b/backend/src/main/java/it/chalmers/gamma/db/entity/UserWebsite.java deleted file mode 100644 index 3ac8b694c..000000000 --- a/backend/src/main/java/it/chalmers/gamma/db/entity/UserWebsite.java +++ /dev/null @@ -1,92 +0,0 @@ -package it.chalmers.gamma.db.entity; - -import it.chalmers.gamma.domain.dto.website.UserWebsiteDTO; -import java.util.Objects; -import java.util.UUID; - -import javax.persistence.CascadeType; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.OneToOne; -import javax.persistence.Table; - -@Entity -@Table(name = "ituser_website") -public class UserWebsite implements WebsiteInterface { - - @Id - @Column(updatable = false) - private UUID id; - - @OneToOne - @JoinColumn(name = "ituser") - private ITUser itUser; - - @JoinColumn(name = "website") - @OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true) - private WebsiteURL website; - - public UserWebsite() { - this.id = UUID.randomUUID(); - } - - public UUID getId() { - return this.id; - } - - public void setId(UUID id) { - this.id = id; - } - - public ITUser getItUser() { - return this.itUser; - } - - public void setItUser(ITUser itUser) { - this.itUser = itUser; - } - - @Override - public WebsiteURL getWebsite() { - return this.website; - } - - public void setWebsite(WebsiteURL website) { - this.website = website; - } - - public UserWebsiteDTO toDTO() { - return new UserWebsiteDTO(this.id, this.itUser.toDTO(), this.website.toDTO()); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - UserWebsite that = (UserWebsite) o; - return Objects.equals(this.id, that.id) - && Objects.equals(this.itUser, that.itUser) - && Objects.equals(this.website, that.website); - } - - @Override - public int hashCode() { - return Objects.hash(this.id, this.itUser, this.website); - } - - @Override - public String toString() { - return "UserWebsite{" - + "id=" + this.id - + ", itUser=" + this.itUser - + ", website=" + this.website - + '}'; - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/db/entity/Website.java b/backend/src/main/java/it/chalmers/gamma/db/entity/Website.java deleted file mode 100644 index 7ec45899f..000000000 --- a/backend/src/main/java/it/chalmers/gamma/db/entity/Website.java +++ /dev/null @@ -1,84 +0,0 @@ -package it.chalmers.gamma.db.entity; - -import it.chalmers.gamma.domain.dto.website.WebsiteDTO; -import java.util.Objects; -import java.util.UUID; - -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.Id; -import javax.persistence.Table; - -@Entity -@Table(name = "website") -public class Website { - @Id - @Column(updatable = false) - private UUID id; - @Column(name = "name", unique = true) - private String name; - @Column(name = "pretty_name") - private String prettyName; - - public Website() { - this.id = UUID.randomUUID(); - } - - public Website(String name) { - this.name = name; - } - - public UUID getId() { - return this.id; - } - - public void setId(UUID id) { - this.id = id; - } - - public String getName() { - return this.name; - } - - public void setName(String name) { - this.name = name.toLowerCase(); - } - - public String getPrettyName() { - return this.prettyName; - } - - public void setPrettyName(String prettyName) { - this.prettyName = prettyName; - } - - public WebsiteDTO toDTO() { - return new WebsiteDTO(this.id, this.name, this.prettyName); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - Website website = (Website) o; - return Objects.equals(this.id, website.id) - && Objects.equals(this.name, website.name); - } - - @Override - public int hashCode() { - return Objects.hash(this.id, this.name); - } - - @Override - public String toString() { - return "Website{" - + "id=" + this.id - + ", name='" + this.name + '\'' - + '}'; - } -} \ No newline at end of file diff --git a/backend/src/main/java/it/chalmers/gamma/db/entity/WebsiteInterface.java b/backend/src/main/java/it/chalmers/gamma/db/entity/WebsiteInterface.java deleted file mode 100644 index 74ed8e948..000000000 --- a/backend/src/main/java/it/chalmers/gamma/db/entity/WebsiteInterface.java +++ /dev/null @@ -1,5 +0,0 @@ -package it.chalmers.gamma.db.entity; - -public interface WebsiteInterface { - WebsiteURL getWebsite(); -} diff --git a/backend/src/main/java/it/chalmers/gamma/db/entity/WebsiteURL.java b/backend/src/main/java/it/chalmers/gamma/db/entity/WebsiteURL.java deleted file mode 100644 index f6a995738..000000000 --- a/backend/src/main/java/it/chalmers/gamma/db/entity/WebsiteURL.java +++ /dev/null @@ -1,98 +0,0 @@ -package it.chalmers.gamma.db.entity; - -import com.fasterxml.jackson.annotation.JsonIgnore; - -import it.chalmers.gamma.domain.dto.website.WebsiteUrlDTO; -import java.util.Objects; -import java.util.UUID; - -import javax.persistence.CascadeType; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.OneToOne; -import javax.persistence.Table; - -@Entity -@Table(name = "website_url") -public class WebsiteURL { - @Id - @Column(name = "id", updatable = false) - @JsonIgnore - private UUID id; - - @JoinColumn(name = "website", nullable = false) - @OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.DETACH) - private Website website; - - @Column(name = "url") - private String url; - - - public WebsiteURL() { - this.id = UUID.randomUUID(); - } - - public UUID getId() { - return this.id; - } - - public void setId(UUID id) { - this.id = id; - } - - @JsonIgnore - public Website getWebsite() { - return this.website; - } - - public String getWebsiteName() { - return this.website.getName(); - } - - public void setWebsite(Website website) { - this.website = website; - } - - public String getUrl() { - return this.url; - } - - public void setUrl(String url) { - this.url = url; - } - - public WebsiteUrlDTO toDTO() { - return new WebsiteUrlDTO(this.id, this.url, this.website.toDTO()); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - WebsiteURL that = (WebsiteURL) o; - return Objects.equals(this.id, that.id) - && Objects.equals(this.website, that.website) - && Objects.equals(this.url, that.url); - } - - @Override - public int hashCode() { - return Objects.hash(this.id, this.website, this.url); - } - - @Override - public String toString() { - return "WebsiteURL{" - + "id=" + this.id - + ", website=" + this.website - + ", url='" + this.url + '\'' - + '}'; - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/db/entity/Whitelist.java b/backend/src/main/java/it/chalmers/gamma/db/entity/Whitelist.java deleted file mode 100644 index 2ebca555b..000000000 --- a/backend/src/main/java/it/chalmers/gamma/db/entity/Whitelist.java +++ /dev/null @@ -1,77 +0,0 @@ -package it.chalmers.gamma.db.entity; - -import it.chalmers.gamma.domain.dto.user.WhitelistDTO; - -import java.util.Objects; -import java.util.UUID; - -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.Id; -import javax.persistence.Table; - -@Entity -@Table(name = "whitelist") -public class Whitelist { - @Id - @Column(updatable = false, unique = true) - private UUID id; - - @Column(name = "cid", unique = true, length = 10, nullable = false) - private String cid; - - protected Whitelist() { - this.id = UUID.randomUUID(); - } - - public Whitelist(String cid) { - this.id = UUID.randomUUID(); - this.cid = cid; - } - - public UUID getId() { - return this.id; - } - - public void setId(UUID id) { - this.id = id; - } - - public String getCid() { - return this.cid; - } - - public void setCid(String cid) { - this.cid = cid.toLowerCase(); - } - - public WhitelistDTO toDTO() { - return new WhitelistDTO(this.id, this.cid); - } - - @Override - public String toString() { - return "Whitelist{" - + "id=" + this.id - + ", cid='" + this.cid + '\'' - + '}'; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - Whitelist whitelist = (Whitelist) o; - return Objects.equals(this.id, whitelist.id) - && Objects.equals(this.cid, whitelist.cid); - } - - @Override - public int hashCode() { - return Objects.hash(this.id, this.cid); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/db/entity/pk/AuthorityPK.java b/backend/src/main/java/it/chalmers/gamma/db/entity/pk/AuthorityPK.java deleted file mode 100644 index a907897c5..000000000 --- a/backend/src/main/java/it/chalmers/gamma/db/entity/pk/AuthorityPK.java +++ /dev/null @@ -1,68 +0,0 @@ -package it.chalmers.gamma.db.entity.pk; - -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import it.chalmers.gamma.db.entity.FKITSuperGroup; -import it.chalmers.gamma.db.entity.Post; -import java.io.Serializable; -import java.util.Objects; -import javax.persistence.Embeddable; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; - -@Embeddable -@SuppressFBWarnings(justification = "Fields should be serializable", value = "SE_BAD_FIELD") -public class AuthorityPK implements Serializable { - - @ManyToOne - @JoinColumn(name = "fkit_group_id") - private FKITSuperGroup fkitSuperGroup; - - @ManyToOne - @JoinColumn(name = "post_id") - private Post post; - - private static final long serialVersionUID = 3085451407319206L; - - - public FKITSuperGroup getFkitSuperGroup() { - return this.fkitSuperGroup; - } - - public void setFkitGroup(FKITSuperGroup fkitSuperGroup) { - this.fkitSuperGroup = fkitSuperGroup; - } - - public Post getPost() { - return this.post; - } - - public void setPost(Post post) { - this.post = post; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - AuthorityPK that = (AuthorityPK) o; - return Objects.equals(this.fkitSuperGroup, that.fkitSuperGroup) - && Objects.equals(this.post, that.post); - } - - @Override - public int hashCode() { - return Objects.hash(this.fkitSuperGroup, this.post); - } - - @Override - public String toString() { - return "AuthorityPK{" - + "fkitGroup=" + this.fkitSuperGroup - + ", post=" + this.post - + '}'; - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/db/entity/pk/FKITGroupToSuperGroupPK.java b/backend/src/main/java/it/chalmers/gamma/db/entity/pk/FKITGroupToSuperGroupPK.java deleted file mode 100644 index f5bba64d7..000000000 --- a/backend/src/main/java/it/chalmers/gamma/db/entity/pk/FKITGroupToSuperGroupPK.java +++ /dev/null @@ -1,76 +0,0 @@ -package it.chalmers.gamma.db.entity.pk; - -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; - -import it.chalmers.gamma.db.entity.FKITGroup; -import it.chalmers.gamma.db.entity.FKITSuperGroup; - -import java.io.Serializable; -import java.util.Objects; - -import javax.persistence.Embeddable; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; - -@Embeddable -@SuppressFBWarnings(justification = "Fields should be serializable", value = "SE_BAD_FIELD") -public class FKITGroupToSuperGroupPK implements Serializable { - @ManyToOne - @JoinColumn(name = "fkit_super_group_id") - private FKITSuperGroup superGroup; - - @ManyToOne - @JoinColumn(name = "fkit_group_id") - private FKITGroup group; - - public FKITGroupToSuperGroupPK(FKITSuperGroup superGroup, FKITGroup group) { - this.superGroup = superGroup; - this.group = group; - } - - public FKITGroupToSuperGroupPK() { - //Used by hibernate - } - - public FKITSuperGroup getSuperGroup() { - return this.superGroup; - } - - public void setSuperGroup(FKITSuperGroup superGroup) { - this.superGroup = superGroup; - } - - public FKITGroup getGroup() { - return this.group; - } - - public void setGroup(FKITGroup group) { - this.group = group; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - FKITGroupToSuperGroupPK that = (FKITGroupToSuperGroupPK) o; - return Objects.equals(this.superGroup, that.superGroup) - && Objects.equals(this.group, that.group); - } - - @Override - public int hashCode() { - return Objects.hash(this.superGroup, this.group); - } - - @Override - public String toString() { - return "FKITGroupToSuperGroupPK{" - + "superGroup=" + this.superGroup - + ", group=" + this. group - + '}'; - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/db/entity/pk/ITUserApprovalPK.java b/backend/src/main/java/it/chalmers/gamma/db/entity/pk/ITUserApprovalPK.java deleted file mode 100644 index 9f54b5fa4..000000000 --- a/backend/src/main/java/it/chalmers/gamma/db/entity/pk/ITUserApprovalPK.java +++ /dev/null @@ -1,68 +0,0 @@ -package it.chalmers.gamma.db.entity.pk; - -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; - -import it.chalmers.gamma.db.entity.ITClient; -import it.chalmers.gamma.db.entity.ITUser; - -import java.io.Serializable; -import java.util.Objects; - -import javax.persistence.Embeddable; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; - -@Embeddable -@SuppressFBWarnings(justification = "Fields should be serializable", value = "SE_BAD_FIELD") -public class ITUserApprovalPK implements Serializable { - - @ManyToOne - @JoinColumn(name = "ituser_id") - private ITUser itUser; - - @ManyToOne - @JoinColumn(name = "itclient_id") - private ITClient itClient; - - public ITUser getItUser() { - return this.itUser; - } - - public void setItUser(ITUser itUser) { - this.itUser = itUser; - } - - public ITClient getItClient() { - return this.itClient; - } - - public void setItClient(ITClient itClient) { - this.itClient = itClient; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - ITUserApprovalPK that = (ITUserApprovalPK) o; - return Objects.equals(this.itUser, that.itUser) - && Objects.equals(this.itClient, that.itClient); - } - - @Override - public int hashCode() { - return Objects.hash(this.itUser, this.itClient); - } - - @Override - public String toString() { - return "ITUserApprovalPK{" - + "itUser=" + this.itUser - + ", itClient=" + this.itClient - + '}'; - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/db/entity/pk/MembershipPK.java b/backend/src/main/java/it/chalmers/gamma/db/entity/pk/MembershipPK.java deleted file mode 100644 index 2ecc23a75..000000000 --- a/backend/src/main/java/it/chalmers/gamma/db/entity/pk/MembershipPK.java +++ /dev/null @@ -1,85 +0,0 @@ -package it.chalmers.gamma.db.entity.pk; - -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import it.chalmers.gamma.db.entity.FKITGroup; -import it.chalmers.gamma.db.entity.ITUser; -import it.chalmers.gamma.db.entity.Post; - -import java.io.Serializable; -import java.util.Objects; -import javax.persistence.Embeddable; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; - -@Embeddable -@SuppressFBWarnings(justification = "Fields should be serializable", value = "SE_BAD_FIELD") -public class MembershipPK implements Serializable { - - @ManyToOne - @JoinColumn(name = "ituser_id") - private ITUser itUser; - - @ManyToOne - @JoinColumn(name = "fkit_group_id") - private FKITGroup fkitGroup; - - @ManyToOne - private Post post; - - private static final long serialVersionUID = 6624119509779427L; - - - public ITUser getITUser() { - return this.itUser; - } - - public void setITUser(ITUser ituserId) { - this.itUser = ituserId; - } - - public FKITGroup getFKITGroup() { - return this.fkitGroup; - } - - public void setFKITGroup(FKITGroup fkitGroupId) { - this.fkitGroup = fkitGroupId; - } - - public Post getPost() { - return this.post; - } - - public void setPost(Post post) { - this.post = post; - } - - @Override - public String toString() { - return "MembershipPK{" - + "itUser=" + this.itUser - + ", fkitGroup=" + this.fkitGroup - + ", post=" + this.post - + '}'; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - MembershipPK that = (MembershipPK) o; - return Objects.equals(this.itUser, that.itUser) - && Objects.equals(this.fkitGroup, that.fkitGroup) - && Objects.equals(this.post, that.post); - } - - @Override - public int hashCode() { - return Objects.hash(this.itUser, this.fkitGroup, this.post); - } - - -} diff --git a/backend/src/main/java/it/chalmers/gamma/db/entity/pk/NoAccountMembershipPK.java b/backend/src/main/java/it/chalmers/gamma/db/entity/pk/NoAccountMembershipPK.java deleted file mode 100644 index 2da98d729..000000000 --- a/backend/src/main/java/it/chalmers/gamma/db/entity/pk/NoAccountMembershipPK.java +++ /dev/null @@ -1,67 +0,0 @@ -package it.chalmers.gamma.db.entity.pk; - -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import it.chalmers.gamma.db.entity.FKITGroup; - -import java.io.Serializable; -import java.util.Objects; - -import javax.persistence.Column; -import javax.persistence.Embeddable; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; - -@Embeddable -@SuppressFBWarnings(justification = "Fields should be serializable", value = "SE_BAD_FIELD") -public class NoAccountMembershipPK implements Serializable { - - private static final long serialVersionUID = 6624119509779427L; - @Column(name = "user_name") - private String itUser; - @ManyToOne - @JoinColumn(name = "fkit_group_id") - private FKITGroup fkitGroup; - - public String getITUser() { - return this.itUser; - } - - public void setITUser(String ituserId) { - this.itUser = ituserId; - } - - public FKITGroup getFKITGroup() { - return this.fkitGroup; - } - - public void setFKITGroup(FKITGroup fkitGroupId) { - this.fkitGroup = fkitGroupId; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - NoAccountMembershipPK that = (NoAccountMembershipPK) o; - return Objects.equals(this.itUser, that.itUser) - && Objects.equals(this.fkitGroup, that.fkitGroup); - } - - @Override - public int hashCode() { - - return Objects.hash(this.itUser, this.fkitGroup); - } - - @Override - public String toString() { - return "NoAccountMembershipPK{" - + "itUser='" + this.itUser + '\'' - + ", fkitGroup=" + this.fkitGroup - + '}'; - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/db/repository/ActivationCodeRepository.java b/backend/src/main/java/it/chalmers/gamma/db/repository/ActivationCodeRepository.java deleted file mode 100644 index b2dd906ee..000000000 --- a/backend/src/main/java/it/chalmers/gamma/db/repository/ActivationCodeRepository.java +++ /dev/null @@ -1,15 +0,0 @@ -package it.chalmers.gamma.db.repository; - -import it.chalmers.gamma.db.entity.ActivationCode; - -import java.util.Optional; -import java.util.UUID; - -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -@Repository -public interface ActivationCodeRepository extends JpaRepository { - Optional findByCid_Cid(String cid); - boolean existsActivationCodeByCid_Cid(String cid); -} diff --git a/backend/src/main/java/it/chalmers/gamma/db/repository/ApiKeyRepository.java b/backend/src/main/java/it/chalmers/gamma/db/repository/ApiKeyRepository.java deleted file mode 100644 index a20758cc7..000000000 --- a/backend/src/main/java/it/chalmers/gamma/db/repository/ApiKeyRepository.java +++ /dev/null @@ -1,16 +0,0 @@ -package it.chalmers.gamma.db.repository; - -import it.chalmers.gamma.db.entity.ApiKey; - -import java.util.Optional; -import java.util.UUID; - -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -@Repository -public interface ApiKeyRepository extends JpaRepository { - boolean existsByKey(String apiKey); - - Optional findByName(String apiKey); -} diff --git a/backend/src/main/java/it/chalmers/gamma/db/repository/AuthorityLevelRepository.java b/backend/src/main/java/it/chalmers/gamma/db/repository/AuthorityLevelRepository.java deleted file mode 100644 index 63c63d4cc..000000000 --- a/backend/src/main/java/it/chalmers/gamma/db/repository/AuthorityLevelRepository.java +++ /dev/null @@ -1,15 +0,0 @@ -package it.chalmers.gamma.db.repository; - -import it.chalmers.gamma.db.entity.AuthorityLevel; - -import java.util.Optional; -import java.util.UUID; - -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -@Repository -public interface AuthorityLevelRepository extends JpaRepository { - Optional findByAuthorityLevel(String authorityLevel); - Boolean existsByAuthorityLevel(String authorityLevel); -} diff --git a/backend/src/main/java/it/chalmers/gamma/db/repository/AuthorityRepository.java b/backend/src/main/java/it/chalmers/gamma/db/repository/AuthorityRepository.java deleted file mode 100644 index 324e5bd50..000000000 --- a/backend/src/main/java/it/chalmers/gamma/db/repository/AuthorityRepository.java +++ /dev/null @@ -1,26 +0,0 @@ -package it.chalmers.gamma.db.repository; - -import it.chalmers.gamma.db.entity.Authority; -import it.chalmers.gamma.db.entity.AuthorityLevel; -import it.chalmers.gamma.db.entity.FKITSuperGroup; -import it.chalmers.gamma.db.entity.Post; - -import java.util.List; -import java.util.Optional; -import java.util.UUID; - -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -@Repository -public interface AuthorityRepository extends JpaRepository { - Optional findById_FkitSuperGroupAndId_Post(FKITSuperGroup superGroup, Post post); - - List findAllByAuthorityLevel(AuthorityLevel authorityLevel); - - Optional findByInternalId(UUID id); - - boolean existsByInternalId(UUID id); - - void deleteByInternalId(UUID id); -} diff --git a/backend/src/main/java/it/chalmers/gamma/db/repository/FKITGroupRepository.java b/backend/src/main/java/it/chalmers/gamma/db/repository/FKITGroupRepository.java deleted file mode 100644 index 681da7888..000000000 --- a/backend/src/main/java/it/chalmers/gamma/db/repository/FKITGroupRepository.java +++ /dev/null @@ -1,19 +0,0 @@ -package it.chalmers.gamma.db.repository; - -import it.chalmers.gamma.db.entity.FKITGroup; - -import it.chalmers.gamma.db.entity.FKITSuperGroup; -import java.util.List; -import java.util.Optional; -import java.util.UUID; - -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -@Repository -public interface FKITGroupRepository extends JpaRepository { - boolean existsFKITGroupByName(String name); - Optional findByName(String name); - void deleteByName(String name); - List findAllBySuperGroup(FKITSuperGroup group); -} diff --git a/backend/src/main/java/it/chalmers/gamma/db/repository/FKITSuperGroupRepository.java b/backend/src/main/java/it/chalmers/gamma/db/repository/FKITSuperGroupRepository.java deleted file mode 100644 index 5cce2c1d5..000000000 --- a/backend/src/main/java/it/chalmers/gamma/db/repository/FKITSuperGroupRepository.java +++ /dev/null @@ -1,13 +0,0 @@ -package it.chalmers.gamma.db.repository; - -import it.chalmers.gamma.db.entity.FKITSuperGroup; -import java.util.Optional; -import java.util.UUID; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -@Repository -public interface FKITSuperGroupRepository extends JpaRepository { - Optional findByName(String name); - boolean existsByName(String name); -} diff --git a/backend/src/main/java/it/chalmers/gamma/db/repository/GroupWebsiteRepository.java b/backend/src/main/java/it/chalmers/gamma/db/repository/GroupWebsiteRepository.java deleted file mode 100644 index b4ff447ac..000000000 --- a/backend/src/main/java/it/chalmers/gamma/db/repository/GroupWebsiteRepository.java +++ /dev/null @@ -1,22 +0,0 @@ -package it.chalmers.gamma.db.repository; - -import it.chalmers.gamma.db.entity.FKITGroup; -import it.chalmers.gamma.db.entity.GroupWebsite; -import it.chalmers.gamma.db.entity.Website; - -import java.util.List; -import java.util.UUID; - -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -@Repository -public interface GroupWebsiteRepository extends JpaRepository { - List findAllByGroup(FKITGroup group); - - GroupWebsite findByWebsite_Website(Website website); - - void deleteAllByGroup(FKITGroup group); - - void deleteAllByWebsite_Website(Website website); -} diff --git a/backend/src/main/java/it/chalmers/gamma/db/repository/ITClientRepository.java b/backend/src/main/java/it/chalmers/gamma/db/repository/ITClientRepository.java deleted file mode 100644 index 3643f8fd9..000000000 --- a/backend/src/main/java/it/chalmers/gamma/db/repository/ITClientRepository.java +++ /dev/null @@ -1,17 +0,0 @@ -package it.chalmers.gamma.db.repository; - -import it.chalmers.gamma.db.entity.ITClient; - -import java.util.Optional; -import java.util.UUID; - -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -@Repository -public interface ITClientRepository extends JpaRepository { - - Optional findByClientId(String clientId); - - boolean existsITClientByClientId(String clientId); -} diff --git a/backend/src/main/java/it/chalmers/gamma/db/repository/ITUserApprovalRepository.java b/backend/src/main/java/it/chalmers/gamma/db/repository/ITUserApprovalRepository.java deleted file mode 100644 index 75d054f23..000000000 --- a/backend/src/main/java/it/chalmers/gamma/db/repository/ITUserApprovalRepository.java +++ /dev/null @@ -1,16 +0,0 @@ -package it.chalmers.gamma.db.repository; - -import it.chalmers.gamma.db.entity.ITUserApproval; - -import java.util.List; -import java.util.UUID; - -import org.springframework.data.jpa.repository.JpaRepository; - -public interface ITUserApprovalRepository extends JpaRepository { - - ITUserApproval findById_ItUserCidContainingAndId_ItClient_ClientIdContaining(String cid, String clientId); - List findAllById_ItClient_ClientIdContaining(String clientId); - List findAllById_ItUser_CidContaining(String cid); - -} diff --git a/backend/src/main/java/it/chalmers/gamma/db/repository/ITUserRepository.java b/backend/src/main/java/it/chalmers/gamma/db/repository/ITUserRepository.java deleted file mode 100644 index fe5cd31c2..000000000 --- a/backend/src/main/java/it/chalmers/gamma/db/repository/ITUserRepository.java +++ /dev/null @@ -1,20 +0,0 @@ -package it.chalmers.gamma.db.repository; - -import it.chalmers.gamma.db.entity.ITUser; - -import java.util.Optional; -import java.util.UUID; - -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -@Repository -public interface ITUserRepository extends JpaRepository { - - Optional findByCid(String cid); - - Optional findByEmail(String email); - - boolean existsByCid(String cid); - -} diff --git a/backend/src/main/java/it/chalmers/gamma/db/repository/MembershipRepository.java b/backend/src/main/java/it/chalmers/gamma/db/repository/MembershipRepository.java deleted file mode 100644 index 43d7fb9a9..000000000 --- a/backend/src/main/java/it/chalmers/gamma/db/repository/MembershipRepository.java +++ /dev/null @@ -1,24 +0,0 @@ -package it.chalmers.gamma.db.repository; - -import it.chalmers.gamma.db.entity.FKITGroup; -import it.chalmers.gamma.db.entity.ITUser; -import it.chalmers.gamma.db.entity.Membership; -import it.chalmers.gamma.db.entity.Post; - -import java.util.List; -import java.util.Optional; -import java.util.UUID; - -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -@Repository -public interface MembershipRepository extends JpaRepository { - List findAllById_Post(Post post); - List findAllById_PostId(UUID id); - List findAllById_ItUser(ITUser itUser); - Optional findById_ItUserAndId_Post(ITUser user, Post post); - List findAllById_FkitGroupAndId_Post(FKITGroup group, Post post); - List findAllById_FkitGroup(FKITGroup group); - Optional findById_ItUserAndId_FkitGroup(ITUser user, FKITGroup group); -} diff --git a/backend/src/main/java/it/chalmers/gamma/db/repository/NoAccountMembershipRepository.java b/backend/src/main/java/it/chalmers/gamma/db/repository/NoAccountMembershipRepository.java deleted file mode 100644 index c4562f7b6..000000000 --- a/backend/src/main/java/it/chalmers/gamma/db/repository/NoAccountMembershipRepository.java +++ /dev/null @@ -1,13 +0,0 @@ -package it.chalmers.gamma.db.repository; - -import it.chalmers.gamma.db.entity.FKITGroup; -import it.chalmers.gamma.db.entity.NoAccountMembership; -import java.util.List; -import java.util.UUID; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -@Repository -public interface NoAccountMembershipRepository extends JpaRepository { - List findAllById_FkitGroup(FKITGroup group); -} diff --git a/backend/src/main/java/it/chalmers/gamma/db/repository/PasswordResetTokenRepository.java b/backend/src/main/java/it/chalmers/gamma/db/repository/PasswordResetTokenRepository.java deleted file mode 100644 index 523efa84f..000000000 --- a/backend/src/main/java/it/chalmers/gamma/db/repository/PasswordResetTokenRepository.java +++ /dev/null @@ -1,17 +0,0 @@ -package it.chalmers.gamma.db.repository; - -import it.chalmers.gamma.db.entity.ITUser; -import it.chalmers.gamma.db.entity.PasswordResetToken; - -import java.util.Optional; -import java.util.UUID; - -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -@Repository -public interface PasswordResetTokenRepository extends JpaRepository { - Optional findByItUser(ITUser user); - - boolean existsByItUser(ITUser user); -} diff --git a/backend/src/main/java/it/chalmers/gamma/db/repository/PostRepository.java b/backend/src/main/java/it/chalmers/gamma/db/repository/PostRepository.java deleted file mode 100644 index 4ee6e6e23..000000000 --- a/backend/src/main/java/it/chalmers/gamma/db/repository/PostRepository.java +++ /dev/null @@ -1,15 +0,0 @@ -package it.chalmers.gamma.db.repository; - -import it.chalmers.gamma.db.entity.Post; - -import java.util.Optional; -import java.util.UUID; - -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -@Repository -public interface PostRepository extends JpaRepository { - Optional findByPostName_Sv(String post); - Boolean existsByPostName_Sv(String post); -} diff --git a/backend/src/main/java/it/chalmers/gamma/db/repository/TextRepository.java b/backend/src/main/java/it/chalmers/gamma/db/repository/TextRepository.java deleted file mode 100644 index 0c764acf1..000000000 --- a/backend/src/main/java/it/chalmers/gamma/db/repository/TextRepository.java +++ /dev/null @@ -1,13 +0,0 @@ -package it.chalmers.gamma.db.repository; - -import it.chalmers.gamma.db.entity.Text; - -import java.util.UUID; - -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -@Repository -public interface TextRepository extends JpaRepository { - Text findBySv(String sv); -} diff --git a/backend/src/main/java/it/chalmers/gamma/db/repository/UserWebsiteRepository.java b/backend/src/main/java/it/chalmers/gamma/db/repository/UserWebsiteRepository.java deleted file mode 100644 index 08514669c..000000000 --- a/backend/src/main/java/it/chalmers/gamma/db/repository/UserWebsiteRepository.java +++ /dev/null @@ -1,23 +0,0 @@ -package it.chalmers.gamma.db.repository; - -import it.chalmers.gamma.db.entity.ITUser; -import it.chalmers.gamma.db.entity.UserWebsite; -import it.chalmers.gamma.db.entity.Website; - -import java.util.List; -import java.util.Optional; -import java.util.UUID; - -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -@Repository -public interface UserWebsiteRepository extends JpaRepository { - List findAllByItUser(ITUser user); - - Optional findByWebsite(Website website); - - void deleteAllByItUser(ITUser user); - - void deleteAllByWebsite_Website(Website website); -} diff --git a/backend/src/main/java/it/chalmers/gamma/db/repository/WebsiteRepository.java b/backend/src/main/java/it/chalmers/gamma/db/repository/WebsiteRepository.java deleted file mode 100644 index 404dff1fe..000000000 --- a/backend/src/main/java/it/chalmers/gamma/db/repository/WebsiteRepository.java +++ /dev/null @@ -1,14 +0,0 @@ -package it.chalmers.gamma.db.repository; - -import it.chalmers.gamma.db.entity.Website; - -import java.util.Optional; -import java.util.UUID; - -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -@Repository -public interface WebsiteRepository extends JpaRepository { - Optional findByName(String name); -} diff --git a/backend/src/main/java/it/chalmers/gamma/db/repository/WebsiteURLRepository.java b/backend/src/main/java/it/chalmers/gamma/db/repository/WebsiteURLRepository.java deleted file mode 100644 index 31b415fde..000000000 --- a/backend/src/main/java/it/chalmers/gamma/db/repository/WebsiteURLRepository.java +++ /dev/null @@ -1,14 +0,0 @@ -package it.chalmers.gamma.db.repository; - -import it.chalmers.gamma.db.entity.Website; -import it.chalmers.gamma.db.entity.WebsiteURL; - -import java.util.UUID; - -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -@Repository -public interface WebsiteURLRepository extends JpaRepository { - void deleteAllByWebsite(Website website); -} diff --git a/backend/src/main/java/it/chalmers/gamma/db/repository/WhitelistRepository.java b/backend/src/main/java/it/chalmers/gamma/db/repository/WhitelistRepository.java deleted file mode 100644 index ea38e14fe..000000000 --- a/backend/src/main/java/it/chalmers/gamma/db/repository/WhitelistRepository.java +++ /dev/null @@ -1,15 +0,0 @@ -package it.chalmers.gamma.db.repository; - -import it.chalmers.gamma.db.entity.Whitelist; - -import java.util.Optional; -import java.util.UUID; - -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -@Repository -public interface WhitelistRepository extends JpaRepository { - Optional findByCid(String cid); - Boolean existsByCid(String cid); -} diff --git a/backend/src/main/java/it/chalmers/gamma/db/serializers/GoldappsGroupSerializer.java b/backend/src/main/java/it/chalmers/gamma/db/serializers/GoldappsGroupSerializer.java deleted file mode 100644 index 5ab1bd7e9..000000000 --- a/backend/src/main/java/it/chalmers/gamma/db/serializers/GoldappsGroupSerializer.java +++ /dev/null @@ -1,58 +0,0 @@ -package it.chalmers.gamma.db.serializers; - -import java.util.ArrayList; -import java.util.List; - -import org.json.simple.JSONObject; - -public class GoldappsGroupSerializer { - - public JSONObject serialize(String value, - List groupMembers) { - List values = new ArrayList<>(); - values.add(new SerializerValue(true, value, "email")); - values.add(new SerializerValue(true, groupMembers, "members")); - values.add(new SerializerValue(true, null, "aliases")); - return SerializerUtils.serialize(values, true); - } - - private static class SerializerValue { - - private final boolean enabled; - private final Object value; - private final String name; - - private SerializerValue(boolean enabled, Object value, String name) { - this.enabled = enabled; - this.value = value; - this.name = name; - } - - public boolean isEnabled() { - return this.enabled; - } - - public Object getValue() { - return this.value; - } - - public String getName() { - return this.name; - } - } - - - private static class SerializerUtils { - - - private static JSONObject serialize(List values, boolean includeNullFields) { - JSONObject json = new JSONObject(); - for (SerializerValue value : values) { - if (value.isEnabled() && !(!includeNullFields && value.getValue() == null)) { - json.put(value.getName(), value.getValue()); - } - } - return json; - } - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/db/serializers/GoldappsUserSerializer.java b/backend/src/main/java/it/chalmers/gamma/db/serializers/GoldappsUserSerializer.java deleted file mode 100644 index 4e01ae3f4..000000000 --- a/backend/src/main/java/it/chalmers/gamma/db/serializers/GoldappsUserSerializer.java +++ /dev/null @@ -1,60 +0,0 @@ -package it.chalmers.gamma.db.serializers; - -import it.chalmers.gamma.domain.dto.user.ITUserDTO; -import java.util.ArrayList; -import java.util.List; -import org.json.simple.JSONObject; - -public class GoldappsUserSerializer { - - public JSONObject serialize(ITUserDTO value) { - List values = new ArrayList<>(); - values.add(new SerializerValue(true, value.getCid(), "cid")); - values.add(new SerializerValue(true, value.getFirstName(), "first_name")); - values.add(new SerializerValue(true, value.getLastName(), "second_name")); - values.add(new SerializerValue(true, value.getNick(), "nick")); - values.add(new SerializerValue(true, value.getEmail(), "mail")); - values.add(new SerializerValue(true, value.isGdpr(), "gdpr_education")); - return SerializerUtils.serialize(values, false); - } - private static class SerializerValue { - - private final boolean enabled; - private final Object value; - private final String name; - - private SerializerValue(boolean enabled, Object value, String name) { - this.enabled = enabled; - this.value = value; - this.name = name; - } - - public boolean isEnabled() { - return this.enabled; - } - - public Object getValue() { - return this.value; - } - - public String getName() { - return this.name; - } - } - - private static class SerializerUtils { - - private static JSONObject serialize(List values, boolean includeNullFields) { - JSONObject json = new JSONObject(); - for (SerializerValue value : values) { - if (value.isEnabled() && !(!includeNullFields && value.getValue() == null)) { - json.put(value.getName(), value.getValue()); - } - } - return json; - } - - - } -} - diff --git a/backend/src/main/java/it/chalmers/gamma/domain/GroupType.java b/backend/src/main/java/it/chalmers/gamma/domain/GroupType.java deleted file mode 100644 index f52e45f9f..000000000 --- a/backend/src/main/java/it/chalmers/gamma/domain/GroupType.java +++ /dev/null @@ -1,10 +0,0 @@ -package it.chalmers.gamma.domain; - -public enum GroupType { - ADMIN, - SOCIETY, - COMMITTEE, - BOARD, - ALUMNI, - FUNCTIONARIES -} diff --git a/backend/src/main/java/it/chalmers/gamma/domain/Language.java b/backend/src/main/java/it/chalmers/gamma/domain/Language.java deleted file mode 100644 index 289bd4b5d..000000000 --- a/backend/src/main/java/it/chalmers/gamma/domain/Language.java +++ /dev/null @@ -1,8 +0,0 @@ -package it.chalmers.gamma.domain; - -//Since frontend likes it lowercase. Might need to be changed in the future, but would be breaking. -@SuppressWarnings("PMD.FieldNamingConventions") -public enum Language { - sv, - en -} diff --git a/backend/src/main/java/it/chalmers/gamma/domain/dto/access/ApiKeyDTO.java b/backend/src/main/java/it/chalmers/gamma/domain/dto/access/ApiKeyDTO.java deleted file mode 100644 index e6cfae4e2..000000000 --- a/backend/src/main/java/it/chalmers/gamma/domain/dto/access/ApiKeyDTO.java +++ /dev/null @@ -1,93 +0,0 @@ -package it.chalmers.gamma.domain.dto.access; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import it.chalmers.gamma.db.entity.Text; -import java.time.Instant; -import java.util.Objects; -import java.util.UUID; - -public class ApiKeyDTO { - private final UUID id; - private final String name; - private final Text description; - private final Instant createdAt; - private final Instant lastModifiedAt; - @JsonIgnore - private final String key; - - public ApiKeyDTO(UUID id, String name, Text description, Instant createdAt, Instant lastModifiedAt, String key) { - this.id = id; - this.name = name; - this.description = description; - this.createdAt = createdAt; - this.lastModifiedAt = lastModifiedAt; - this.key = key; - } - - public ApiKeyDTO(String name, Text description) { - this(null, name, description, null, null, ""); - } - - public UUID getId() { - return this.id; - } - - public String getName() { - return this.name; - } - - public Text getDescription() { - return this.description; - } - - public Instant getCreatedAt() { - return this.createdAt; - } - - public Instant getLastModifiedAt() { - return this.lastModifiedAt; - } - - @JsonIgnore - public String getKey() { - return this.key; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - ApiKeyDTO apiKeyDTO = (ApiKeyDTO) o; - return Objects.equals(this.id, apiKeyDTO.id) - && Objects.equals(this.name, apiKeyDTO.name) - && Objects.equals(this.description, apiKeyDTO.description) - && Objects.equals(this.createdAt, apiKeyDTO.createdAt) - && Objects.equals(this.lastModifiedAt, apiKeyDTO.lastModifiedAt); - } - - @Override - public int hashCode() { - return Objects.hash( - this.id, - this.name, - this.description, - this.createdAt, - this.lastModifiedAt); - } - - @Override - public String toString() { - return "ApiKeyDTO{" - + "id=" + this.id - + ", name='" + this.name + '\'' - + ", description=" + this.description - + ", createdAt=" + this.createdAt - + ", lastModifiedAt=" + this.lastModifiedAt - + ", key={secret}" - + '}'; - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/domain/dto/access/ITClientDTO.java b/backend/src/main/java/it/chalmers/gamma/domain/dto/access/ITClientDTO.java deleted file mode 100644 index e2c59b534..000000000 --- a/backend/src/main/java/it/chalmers/gamma/domain/dto/access/ITClientDTO.java +++ /dev/null @@ -1,241 +0,0 @@ -package it.chalmers.gamma.domain.dto.access; - -import com.fasterxml.jackson.annotation.JsonIgnore; - -import it.chalmers.gamma.db.entity.Text; -import java.time.Instant; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.UUID; - -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.authority.SimpleGrantedAuthority; -import org.springframework.security.oauth2.provider.ClientDetails; - -@SuppressWarnings("PMD.ExcessiveParameterList") -public class ITClientDTO implements ClientDetails { - private final UUID id; - private final String clientId; - @JsonIgnore - private final String clientSecret; - private final String webServerRedirectUri; - @JsonIgnore - private final int accessTokenValidity; - @JsonIgnore - private final int refreshTokenValidity; - private final boolean autoApprove; - private final String name; - private final Text description; - @JsonIgnore - private final Instant createdAt; - @JsonIgnore - private final Instant lastModifiedAt; - - - public ITClientDTO(UUID id, - String clientId, - String clientSecret, - String webServerRedirectUri, - Integer accessTokenValidity, - Integer refreshTokenValidity, - boolean autoApprove, - String name, - Text description, - Instant createdAt, - Instant lastModifiedAt) { - this.id = id; - this.clientId = clientId; - this.clientSecret = clientSecret; - this.webServerRedirectUri = webServerRedirectUri; - this.accessTokenValidity = accessTokenValidity; - this.refreshTokenValidity = refreshTokenValidity; - this.autoApprove = autoApprove; - this.name = name; - this.description = description; - this.createdAt = createdAt; - this.lastModifiedAt = lastModifiedAt; - } - - public ITClientDTO(String webServerRedirectUri, String name, Text description, boolean autoApprove) { - this(null, null, null, webServerRedirectUri, Integer.MAX_VALUE, Integer.MAX_VALUE, - autoApprove, name, description, null, null); - } - - public UUID getId() { - return this.id; - } - - public String getWebServerRedirectUri() { - return this.webServerRedirectUri; - } - - public int getAccessTokenValidity() { - return this.accessTokenValidity; - } - - public int getRefreshTokenValidity() { - return this.refreshTokenValidity; - } - - public String getName() { - return this.name; - } - - public Text getDescription() { - return this.description; - } - - public Instant getCreatedAt() { - return this.createdAt; - } - - public Instant getLastModifiedAt() { - return this.lastModifiedAt; - } - - @Override - public String getClientId() { - return this.clientId; - } - - public boolean isAutoApprove() { - return this.autoApprove; - } - - @Override - public boolean isAutoApprove(String scope) { - return isAutoApprove(); - } - - @Override - @JsonIgnore - public Set getResourceIds() { - return null; - } - - @Override - public boolean isSecretRequired() { - return true; - } - - @Override - @JsonIgnore - public String getClientSecret() { - return this.clientSecret; - } - - @Override - public boolean isScoped() { - return false; - } - - @Override - public Set getScope() { - Set scopes = new HashSet<>(); - scopes.add("access"); - return scopes; - } - - @Override - public Set getAuthorizedGrantTypes() { - Set authorized = new HashSet<>(); - authorized.add("authorization_code"); - return authorized; - } - - @Override - public Set getRegisteredRedirectUri() { - Set authorized = new HashSet<>(); - authorized.add(this.webServerRedirectUri); - return authorized; - } - - @Override - @JsonIgnore - public Collection getAuthorities() { - Set authorities = new HashSet<>(); - authorities.add(new SimpleGrantedAuthority("ROLE_CLIENT")); - return authorities; - } - - @Override - public Integer getAccessTokenValiditySeconds() { - return this.accessTokenValidity; - } - - @Override - public Integer getRefreshTokenValiditySeconds() { - return this.refreshTokenValidity; - } - - @Override - public Map getAdditionalInformation() { - Map additionalInformation = new HashMap<>(); - additionalInformation.put("name", this.name); - additionalInformation.put("description", this.description); - - return additionalInformation; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - - if (o == null || getClass() != o.getClass()) { - return false; - } - - ITClientDTO itClient = (ITClientDTO) o; - return this.accessTokenValidity == itClient.accessTokenValidity - && this.refreshTokenValidity == itClient.refreshTokenValidity - && this.autoApprove == itClient.autoApprove - && Objects.equals(this.id, itClient.id) - && Objects.equals(this.clientId, itClient.clientId) - && Objects.equals(this.clientSecret, itClient.clientSecret) - && Objects.equals(this.webServerRedirectUri, itClient.webServerRedirectUri) - && Objects.equals(this.name, itClient.name) - && Objects.equals(this.description, itClient.description) - && Objects.equals(this.createdAt, itClient.createdAt) - && Objects.equals(this.lastModifiedAt, itClient.lastModifiedAt); - } - - @Override - public int hashCode() { - return Objects.hash( - this.id, - this.clientId, - this.clientSecret, - this.webServerRedirectUri, - this.accessTokenValidity, - this.refreshTokenValidity, - this.autoApprove, - this.name, - this.description, - this.createdAt, - this.lastModifiedAt - ); - } - - @Override - public String toString() { - return "ITClient{" - + "id=" + this.id - + ", clientId='" + this.clientId + '\'' - + ", clientSecret={redacted}'\''" - + ", webServerRedirectUri='" + this.webServerRedirectUri + '\'' - + ", accessTokenValidity=" + this.accessTokenValidity - + ", refreshTokenValidity=" + this.refreshTokenValidity - + ", autoApprove=" + this.autoApprove - + ", name='" + this.name + '\'' - + ", description='" + this.description + '\'' - + ", createdAt=" + this.createdAt - + ", lastModifiedAt=" + this.lastModifiedAt - + '}'; - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/domain/dto/access/ITClientUserAccessDTO.java b/backend/src/main/java/it/chalmers/gamma/domain/dto/access/ITClientUserAccessDTO.java deleted file mode 100644 index 5f3136b56..000000000 --- a/backend/src/main/java/it/chalmers/gamma/domain/dto/access/ITClientUserAccessDTO.java +++ /dev/null @@ -1,50 +0,0 @@ -package it.chalmers.gamma.domain.dto.access; - -import it.chalmers.gamma.db.entity.Text; - -import java.util.Objects; - -public class ITClientUserAccessDTO { - - private final String name; - private final Text description; - - public ITClientUserAccessDTO(ITClientDTO itClientDTO) { - this.name = itClientDTO.getName(); - this.description = itClientDTO.getDescription(); - } - - public String getName() { - return this.name; - } - - public Text getDescription() { - return this.description; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - ITClientUserAccessDTO that = (ITClientUserAccessDTO) o; - return Objects.equals(this.name, that.name) - && Objects.equals(this.description, that.description); - } - - @Override - public int hashCode() { - return Objects.hash(this.name, this.description); - } - - @Override - public String toString() { - return "ITClientUserAccessDTO{" - + "name='" + this.name + '\'' - + ", description=" + this.description - + '}'; - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/domain/dto/authority/AuthorityDTO.java b/backend/src/main/java/it/chalmers/gamma/domain/dto/authority/AuthorityDTO.java deleted file mode 100644 index 02c827fd5..000000000 --- a/backend/src/main/java/it/chalmers/gamma/domain/dto/authority/AuthorityDTO.java +++ /dev/null @@ -1,67 +0,0 @@ -package it.chalmers.gamma.domain.dto.authority; - -import it.chalmers.gamma.domain.dto.group.FKITSuperGroupDTO; -import it.chalmers.gamma.domain.dto.post.PostDTO; -import java.util.Objects; -import java.util.UUID; - -public class AuthorityDTO { - private final FKITSuperGroupDTO superGroup; - private final PostDTO post; - private final UUID id; - private final AuthorityLevelDTO authorityLevel; - - public AuthorityDTO(FKITSuperGroupDTO superGroup, PostDTO post, - UUID internalID, AuthorityLevelDTO authorityLevel) { - this.superGroup = superGroup; - this.post = post; - this.id = internalID; - this.authorityLevel = authorityLevel; - } - - public FKITSuperGroupDTO getSuperGroup() { - return this.superGroup; - } - - public PostDTO getPost() { - return this.post; - } - - public UUID getId() { - return this.id; - } - - public AuthorityLevelDTO getAuthorityLevel() { - return this.authorityLevel; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - AuthorityDTO that = (AuthorityDTO) o; - return Objects.equals(this.superGroup, that.superGroup) - && Objects.equals(this.post, that.post) - && Objects.equals(this.id, that.id) - && Objects.equals(this.authorityLevel, that.authorityLevel); - } - - @Override - public int hashCode() { - return Objects.hash(this.superGroup, this.post, this.id, this.authorityLevel); - } - - @Override - public String toString() { - return "AuthorityDTO{" - + "superGroup=" + this.superGroup - + ", post=" + this.post - + ", internalID=" + this.id - + ", authorityLevel=" + this.authorityLevel - + '}'; - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/domain/dto/authority/AuthorityLevelDTO.java b/backend/src/main/java/it/chalmers/gamma/domain/dto/authority/AuthorityLevelDTO.java deleted file mode 100644 index 936dae3b9..000000000 --- a/backend/src/main/java/it/chalmers/gamma/domain/dto/authority/AuthorityLevelDTO.java +++ /dev/null @@ -1,51 +0,0 @@ -package it.chalmers.gamma.domain.dto.authority; - -import java.util.Objects; -import java.util.UUID; -import org.springframework.security.core.GrantedAuthority; - -public class AuthorityLevelDTO implements GrantedAuthority { - private final UUID id; - private final String authorityLevel; - - public AuthorityLevelDTO(UUID id, String authorityLevel) { - this.id = id; - this.authorityLevel = authorityLevel; - } - - public UUID getId() { - return this.id; - } - - @Override - public String getAuthority() { - return this.authorityLevel; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - AuthorityLevelDTO that = (AuthorityLevelDTO) o; - return Objects.equals(this.id, that.id) - && Objects.equals(this.authorityLevel, that.authorityLevel); - - } - - @Override - public int hashCode() { - return Objects.hash(this.id, this.authorityLevel); - } - - @Override - public String toString() { - return "AuthorityLevelDTO{" - + "id=" + id - + ", authorityLevel='" + authorityLevel + '\'' - + '}'; - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/domain/dto/group/FKITGroupDTO.java b/backend/src/main/java/it/chalmers/gamma/domain/dto/group/FKITGroupDTO.java deleted file mode 100644 index 0c04e8ed1..000000000 --- a/backend/src/main/java/it/chalmers/gamma/domain/dto/group/FKITGroupDTO.java +++ /dev/null @@ -1,171 +0,0 @@ -package it.chalmers.gamma.domain.dto.group; - -import it.chalmers.gamma.db.entity.Text; - -import java.util.Calendar; -import java.util.GregorianCalendar; -import java.util.Objects; -import java.util.UUID; - -@SuppressWarnings("PMD.ExcessiveParameterList") -public class FKITGroupDTO { - - private final UUID id; - private final Calendar becomesActive; - private final Calendar becomesInactive; - private final Text description; - private final String email; - private final Text function; - private final String name; - private final String prettyName; - private final String avatarURL; - private final FKITSuperGroupDTO superGroup; - - public FKITGroupDTO(UUID id, - Calendar becomesActive, - Calendar becomesInactive, - Text description, - String email, - Text function, - String name, - String prettyName, - String avatarURL, - FKITSuperGroupDTO superGroup) { - this.id = id; - this.becomesActive = becomesActive; - this.becomesInactive = becomesInactive; - this.description = description; - this.email = email; - this.function = function; - this.name = name; - this.prettyName = prettyName; - this.avatarURL = avatarURL; - this.superGroup = superGroup; - } - - public FKITGroupDTO(Calendar becomesActive, - Calendar becomesInactive, - Text description, - String email, - Text function, - String name, - String prettyName, - String avatarURL, - FKITSuperGroupDTO superGroup) { - this(null, - becomesActive, - becomesInactive, - description, - email, - function, - name, - prettyName, - avatarURL, - superGroup); - - } - - public UUID getId() { - return this.id; - } - - public Calendar getBecomesActive() { - return this.becomesActive; - } - - public Calendar getBecomesInactive() { - return this.becomesInactive; - } - - public Text getDescription() { - return this.description; - } - - public String getEmail() { - return this.email; - } - - public Text getFunction() { - return this.function; - } - - public boolean isActive() { - Calendar now = new GregorianCalendar(); - return now.after(this.becomesActive) && now.before(this.becomesInactive); - } - - public String getName() { - return this.name; - } - - public String getPrettyName() { - return this.prettyName; - } - - public String getAvatarURL() { - return this.avatarURL; - } - - public FKITSuperGroupDTO getSuperGroup() { - return this.superGroup; - } - - public FKITMinifiedGroupDTO toMinifiedDTO() { - return new FKITMinifiedGroupDTO( - this.name, this.function, this.email, this.description, this.id, this.prettyName - ); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - FKITGroupDTO groupDTO = (FKITGroupDTO) o; - return Objects.equals(this.id, groupDTO.id) - && Objects.equals(this.becomesActive, groupDTO.becomesActive) - && Objects.equals(this.becomesInactive, groupDTO.becomesInactive) - && Objects.equals(this.description, groupDTO.description) - && Objects.equals(this.email, groupDTO.email) - && Objects.equals(this.function, groupDTO.function) - && Objects.equals(this.name, groupDTO.name) - && Objects.equals(this.prettyName, groupDTO.prettyName) - && Objects.equals(this.avatarURL, groupDTO.avatarURL) - && Objects.equals(this.superGroup, groupDTO.superGroup); - } - - @Override - public int hashCode() { - return Objects.hash( - this.id, - this.becomesActive, - this.becomesInactive, - this.description, - this.email, - this.function, - this.name, - this.prettyName, - this.avatarURL, - this.superGroup); - - } - - @Override - public String toString() { - return "FKITGroupDTO{" - + "id=" + this.id - + ", becomesActive=" + this.becomesActive - + ", becomesInactive=" + this.becomesInactive - + ", description=" + this.description - + ", email='" + this.email + '\'' - + ", function=" + this.function - + ", name='" + this.name + '\'' - + ", prettyName='" + this.prettyName + '\'' - + ", avatarURL='" + this.avatarURL + '\'' - + ", superGroup=" + this.superGroup - + '}'; - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/domain/dto/group/FKITMinifiedGroupDTO.java b/backend/src/main/java/it/chalmers/gamma/domain/dto/group/FKITMinifiedGroupDTO.java deleted file mode 100644 index 0039f40d2..000000000 --- a/backend/src/main/java/it/chalmers/gamma/domain/dto/group/FKITMinifiedGroupDTO.java +++ /dev/null @@ -1,49 +0,0 @@ -package it.chalmers.gamma.domain.dto.group; - -import it.chalmers.gamma.db.entity.Text; - -import java.util.UUID; - -public class FKITMinifiedGroupDTO { - - private final String name; - private final Text function; - private final String email; - private final Text description; - private final UUID id; - private final String prettyName; - - public FKITMinifiedGroupDTO(String name, Text function, - String email, Text description, UUID id, String prettyName) { - this.name = name; - this.function = function; - this.email = email; - this.description = description; - this.id = id; - this.prettyName = prettyName; - } - - public String getName() { - return this.name; - } - - public Text getFunction() { - return this.function; - } - - public String getEmail() { - return this.email; - } - - public Text getDescription() { - return this.description; - } - - public UUID getId() { - return this.id; - } - - public String getPrettyName() { - return this.prettyName; - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/domain/dto/group/FKITSuperGroupDTO.java b/backend/src/main/java/it/chalmers/gamma/domain/dto/group/FKITSuperGroupDTO.java deleted file mode 100644 index eb7e5d49c..000000000 --- a/backend/src/main/java/it/chalmers/gamma/domain/dto/group/FKITSuperGroupDTO.java +++ /dev/null @@ -1,79 +0,0 @@ -package it.chalmers.gamma.domain.dto.group; - -import it.chalmers.gamma.domain.GroupType; - -import java.util.Objects; -import java.util.UUID; - -public class FKITSuperGroupDTO { - - private final UUID id; - private final String name; - private final String prettyName; - private final GroupType type; - private final String email; - - public FKITSuperGroupDTO(UUID id, String name, String prettyName, GroupType type, String email) { - this.id = id; - this.name = name; - this.prettyName = prettyName; - this.type = type; - this.email = email; - } - - public FKITSuperGroupDTO(String name, String prettyName, GroupType type, String email) { - this(null, name, prettyName, type, email); - } - - public UUID getId() { - return this.id; - } - - public String getName() { - return this.name; - } - - public String getPrettyName() { - return this.prettyName; - } - - public GroupType getType() { - return this.type; - } - - public String getEmail() { - return this.email; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - FKITSuperGroupDTO that = (FKITSuperGroupDTO) o; - return Objects.equals(this.id, that.id) - && Objects.equals(this.name, that.name) - && Objects.equals(this.prettyName, that.prettyName) - && this.type == that.type - && Objects.equals(this.email, that.email); - } - - @Override - public int hashCode() { - return Objects.hash(this.id, this.name, this.prettyName, this.type, this.email); - } - - @Override - public String toString() { - return "FKITSuperGroupDTO{" - + "id=" + this.id - + ", name='" + this.name + '\'' - + ", prettyName='" + this.prettyName + '\'' - + ", type=" + this.type - + ", email='" + this.email + '\'' - + '}'; - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/domain/dto/membership/MembershipDTO.java b/backend/src/main/java/it/chalmers/gamma/domain/dto/membership/MembershipDTO.java deleted file mode 100644 index 8f681316f..000000000 --- a/backend/src/main/java/it/chalmers/gamma/domain/dto/membership/MembershipDTO.java +++ /dev/null @@ -1,75 +0,0 @@ -package it.chalmers.gamma.domain.dto.membership; - -import com.fasterxml.jackson.annotation.JsonUnwrapped; - -import it.chalmers.gamma.domain.dto.group.FKITGroupDTO; -import it.chalmers.gamma.domain.dto.post.PostDTO; -import it.chalmers.gamma.domain.dto.user.ITUserDTO; -import java.util.Objects; - -public class MembershipDTO { - private final PostDTO post; - private final FKITGroupDTO fkitGroupDTO; - private final String unofficialPostName; - @JsonUnwrapped - private final ITUserDTO user; - - - public MembershipDTO(PostDTO post, - FKITGroupDTO fkitGroupDTO, String unofficialPostName, - ITUserDTO user) { - this.post = post; - this.fkitGroupDTO = fkitGroupDTO; - this.unofficialPostName = unofficialPostName; - this.user = user; - } - - public PostDTO getPost() { - return this.post; - } - - public String getUnofficialPostName() { - return this.unofficialPostName; - } - - public ITUserDTO getUser() { - return this.user; - } - - public FKITGroupDTO getFkitGroupDTO() { - return this.fkitGroupDTO; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - MembershipDTO that = (MembershipDTO) o; - return Objects.equals(this.post, that.post) - && Objects.equals(this.unofficialPostName, that.unofficialPostName) - && Objects.equals(this.user, that.user) - && Objects.equals(this.fkitGroupDTO, that.fkitGroupDTO); - } - - @Override - public int hashCode() { - return Objects.hash(this.post, - this.unofficialPostName, - this.user, - this.fkitGroupDTO); - } - - @Override - public String toString() { - return "MembershipDTO{" - + "post=" + this.post - + ", fkitGroupDTO='" + this.fkitGroupDTO + '\'' - + ", unofficialPostName='" + this.unofficialPostName + '\'' - + ", user='" + this.user + '\'' - + '}'; - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/domain/dto/membership/NoAccountMembershipDTO.java b/backend/src/main/java/it/chalmers/gamma/domain/dto/membership/NoAccountMembershipDTO.java deleted file mode 100644 index 0a1f88524..000000000 --- a/backend/src/main/java/it/chalmers/gamma/domain/dto/membership/NoAccountMembershipDTO.java +++ /dev/null @@ -1,66 +0,0 @@ -package it.chalmers.gamma.domain.dto.membership; - -import it.chalmers.gamma.db.entity.FKITGroup; -import it.chalmers.gamma.db.entity.Post; -import java.util.Objects; - -public class NoAccountMembershipDTO { - private final String cid; - private final FKITGroup group; - private final Post post; - private final String unofficialPostName; - - - public NoAccountMembershipDTO(String cid, FKITGroup group, Post post, String unofficialPostName) { - this.cid = cid; - this.group = group; - this.post = post; - this.unofficialPostName = unofficialPostName; - } - - public String getCid() { - return this.cid; - } - - public FKITGroup getGroup() { - return this.group; - } - - public Post getPost() { - return this.post; - } - - public String getUnofficialPostName() { - return this.unofficialPostName; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - NoAccountMembershipDTO that = (NoAccountMembershipDTO) o; - return Objects.equals(this.cid, that.cid) - && Objects.equals(this.group, that.group) - && Objects.equals(this.post, that.post) - && Objects.equals(this.unofficialPostName, that.unofficialPostName); - } - - @Override - public int hashCode() { - return Objects.hash(this.cid, this.group, this.post, this.unofficialPostName); - } - - @Override - public String toString() { - return "NoAccountMembershipDTO{" - + "cid='" + this.cid + '\'' - + ", group=" + this.group - + ", post=" + this.post - + ", unofficialPostName='" + this.unofficialPostName + '\'' - + '}'; - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/domain/dto/membership/RestrictedMembershipDTO.java b/backend/src/main/java/it/chalmers/gamma/domain/dto/membership/RestrictedMembershipDTO.java deleted file mode 100644 index 8f18d2607..000000000 --- a/backend/src/main/java/it/chalmers/gamma/domain/dto/membership/RestrictedMembershipDTO.java +++ /dev/null @@ -1,71 +0,0 @@ -package it.chalmers.gamma.domain.dto.membership; - -import com.fasterxml.jackson.annotation.JsonUnwrapped; - -import it.chalmers.gamma.domain.dto.group.FKITGroupDTO; -import it.chalmers.gamma.domain.dto.post.PostDTO; -import it.chalmers.gamma.domain.dto.user.ITUserRestrictedDTO; - -import java.util.Objects; - -public class RestrictedMembershipDTO { - - private final PostDTO post; - private final FKITGroupDTO fkitGroupDTO; - private final String unofficialPostName; - @JsonUnwrapped - private final ITUserRestrictedDTO user; - - public RestrictedMembershipDTO(MembershipDTO membership) { - this.post = membership.getPost(); - this.fkitGroupDTO = membership.getFkitGroupDTO(); - this.unofficialPostName = membership.getUnofficialPostName(); - this.user = new ITUserRestrictedDTO(membership.getUser()); - } - - public PostDTO getPost() { - return this.post; - } - - public FKITGroupDTO getFkitGroupDTO() { - return this.fkitGroupDTO; - } - - public String getUnofficialPostName() { - return this.unofficialPostName; - } - - public ITUserRestrictedDTO getUser() { - return this.user; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - RestrictedMembershipDTO that = (RestrictedMembershipDTO) o; - return Objects.equals(this.post, that.post) - && Objects.equals(this.fkitGroupDTO, that.fkitGroupDTO) - && Objects.equals(this.unofficialPostName, that.unofficialPostName) - && Objects.equals(this.user, that.user); - } - - @Override - public int hashCode() { - return Objects.hash(this.post, this.fkitGroupDTO, this.unofficialPostName, this.user); - } - - @Override - public String toString() { - return "RestrictedMembershipDTO{" - + "post=" + this.post - + ", fkitGroupDTO=" + this.fkitGroupDTO - + ", unofficialPostName='" + this.unofficialPostName + '\'' - + ", user=" + this.user - + '}'; - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/domain/dto/post/PostDTO.java b/backend/src/main/java/it/chalmers/gamma/domain/dto/post/PostDTO.java deleted file mode 100644 index cb35c8abe..000000000 --- a/backend/src/main/java/it/chalmers/gamma/domain/dto/post/PostDTO.java +++ /dev/null @@ -1,63 +0,0 @@ -package it.chalmers.gamma.domain.dto.post; - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonUnwrapped; -import it.chalmers.gamma.db.entity.Text; -import java.util.Objects; -import java.util.UUID; - -@JsonInclude(JsonInclude.Include.NON_NULL) -public class PostDTO { - private final UUID id; - @JsonUnwrapped - private final Text postName; - private final String emailPrefix; - - public PostDTO(UUID id, Text postName, String emailPrefix) { - this.id = id; - this.postName = postName; - this.emailPrefix = emailPrefix; - } - - public UUID getId() { - return this.id; - } - - public Text getPostName() { - return this.postName; - } - - - public String getEmailPrefix() { - return this.emailPrefix; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - PostDTO postDTO = (PostDTO) o; - return Objects.equals(this.id, postDTO.id) - && Objects.equals(this.postName, postDTO.postName) - && Objects.equals(this.emailPrefix, postDTO.emailPrefix); - } - - @Override - public int hashCode() { - return Objects.hash(this.id, this.postName, this.emailPrefix); - } - - @Override - public String toString() { - return "PostDTO{" - + "id=" + this.id - + ", postName=" + this.postName - + ", emailPrefix=" + this.emailPrefix - + '}'; - } - -} diff --git a/backend/src/main/java/it/chalmers/gamma/domain/dto/user/ActivationCodeDTO.java b/backend/src/main/java/it/chalmers/gamma/domain/dto/user/ActivationCodeDTO.java deleted file mode 100644 index 715ef23a6..000000000 --- a/backend/src/main/java/it/chalmers/gamma/domain/dto/user/ActivationCodeDTO.java +++ /dev/null @@ -1,89 +0,0 @@ -package it.chalmers.gamma.domain.dto.user; - -import com.fasterxml.jackson.annotation.JsonIgnore; - -import java.time.Duration; -import java.time.Instant; -import java.util.Objects; -import java.util.UUID; - -public class ActivationCodeDTO { - private final UUID id; - private final WhitelistDTO whitelistDTO; - private final String code; - private final Instant createdAt; - private final int passwordExpirationTime; - - public ActivationCodeDTO(UUID id, - WhitelistDTO whitelistDTO, - String code, - Instant createdAt, - int passwordExpirationTime) { - this.id = id; - this.whitelistDTO = whitelistDTO; - this.code = code; - this.createdAt = createdAt; - this.passwordExpirationTime = passwordExpirationTime; - } - - public UUID getId() { - return this.id; - } - - @JsonIgnore - public WhitelistDTO getWhitelistDTO() { - return this.whitelistDTO; - } - - public String getCid() { - return this.whitelistDTO.getCid(); - } - - public String getCode() { - return this.code; - } - - public Instant getCreatedAt() { - return this.createdAt; - } - - public boolean isValid() { - return Instant.now().isBefore(this.createdAt.plus(Duration.ofSeconds(this.passwordExpirationTime))); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - ActivationCodeDTO that = (ActivationCodeDTO) o; - return Objects.equals(this.id, that.id) - && Objects.equals(this.whitelistDTO, that.whitelistDTO) - && Objects.equals(this.code, that.code) - && Objects.equals(this.createdAt, that.createdAt); - } - - @Override - public int hashCode() { - - return Objects.hash( - this.id, - this.whitelistDTO, - this.code, - this.createdAt); - } - - @Override - public String toString() { - return "ActivationCodeDTO{" - + "id=" + this.id - + ", whitelistDTO=" + this.whitelistDTO - + ", code='" + this.code + '\'' - + ", createdAt=" + this.createdAt - + ", passwordExpirationTime=" + this.passwordExpirationTime - + '}'; - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/domain/dto/user/ITUserApprovalDTO.java b/backend/src/main/java/it/chalmers/gamma/domain/dto/user/ITUserApprovalDTO.java deleted file mode 100644 index 06dcf8f8b..000000000 --- a/backend/src/main/java/it/chalmers/gamma/domain/dto/user/ITUserApprovalDTO.java +++ /dev/null @@ -1,50 +0,0 @@ -package it.chalmers.gamma.domain.dto.user; - -import it.chalmers.gamma.domain.dto.access.ITClientDTO; - -import java.util.Objects; - -public class ITUserApprovalDTO { - - private final ITUserDTO user; - private final ITClientDTO client; - - public ITUserApprovalDTO(ITUserDTO user, ITClientDTO client) { - this.user = user; - this.client = client; - } - - public ITUserDTO getUser() { - return this.user; - } - - public ITClientDTO getClient() { - return this.client; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - ITUserApprovalDTO that = (ITUserApprovalDTO) o; - return Objects.equals(this.user, that.user) - && Objects.equals(this.client, that.client); - } - - @Override - public int hashCode() { - return Objects.hash(this.user, this.client); - } - - @Override - public String toString() { - return "ITUserApprovalDTO{" - + "user=" + user - + ", client=" + client - + '}'; - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/domain/dto/user/ITUserDTO.java b/backend/src/main/java/it/chalmers/gamma/domain/dto/user/ITUserDTO.java deleted file mode 100644 index 74897ce73..000000000 --- a/backend/src/main/java/it/chalmers/gamma/domain/dto/user/ITUserDTO.java +++ /dev/null @@ -1,250 +0,0 @@ -package it.chalmers.gamma.domain.dto.user; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import it.chalmers.gamma.domain.Language; -import it.chalmers.gamma.util.ImageUtils; -import java.time.Year; -import java.util.List; -import java.util.Objects; -import java.util.UUID; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.userdetails.UserDetails; - -@SuppressWarnings({"PMD.ExcessiveParameterList", "PMD.TooManyFields"}) -public class ITUserDTO implements UserDetails { - private final UUID id; - private final String cid; - private final String nick; - private final String firstName; - private final String lastName; - private final String email; - private final String phone; - private final Language language; - private final String avatarUrl; - private final boolean gdpr; - private final boolean userAgreement; - private final boolean accountLocked; - private final Year acceptanceYear; - private final List authorities; - @JsonIgnore - private final String password; - private final boolean activated; - - public ITUserDTO(UUID id, - String cid, - String nick, - String firstName, - String lastName, - String email, - String phone, - Language language, - String avatarUrl, - boolean gdpr, - boolean userAgreement, - boolean accountLocked, - Year acceptanceYear, - boolean activated) { - this.id = id; - this.cid = cid; - this.nick = nick; - this.firstName = firstName; - this.lastName = lastName; - this.email = email; - this.phone = phone; - this.language = language; - this.avatarUrl = avatarUrl; - this.gdpr = gdpr; - this.userAgreement = userAgreement; - this.accountLocked = accountLocked; - this.acceptanceYear = acceptanceYear; - this.authorities = null; - this.password = null; - this.activated = activated; - } - - public ITUserDTO(UUID id, - String cid, - String nick, - String firstName, - String lastName, - String email, - String phone, - Language language, - String avatarUrl, - boolean gdpr, - boolean userAgreement, - boolean accountLocked, - Year acceptanceYear, - List authorities, - String password, - boolean activated) { - this.id = id; - this.cid = cid; - this.nick = nick; - this.firstName = firstName; - this.lastName = lastName; - this.email = email; - this.phone = phone; - this.language = language; - this.avatarUrl = avatarUrl; - this.gdpr = gdpr; - this.userAgreement = userAgreement; - this.accountLocked = accountLocked; - this.acceptanceYear = acceptanceYear; - this.authorities = authorities; - this.password = password; - this.activated = activated; - } - - public UUID getId() { - return this.id; - } - - public String getCid() { - return this.cid; - } - - public String getNick() { - return this.nick; - } - - public String getFirstName() { - return this.firstName; - } - - public String getLastName() { - return this.lastName; - } - - public String getEmail() { - return this.email; - } - - public String getPhone() { - return this.phone; - } - - public Language getLanguage() { - return this.language; - } - - public String getAvatarUrl() { - return ImageUtils.getAbsolutePath(this.avatarUrl); - } - - public boolean isGdpr() { - return this.gdpr; - } - - public boolean isUserAgreement() { - return this.userAgreement; - } - - public boolean isAccountLocked() { - return this.accountLocked; - } - - public Year getAcceptanceYear() { - return this.acceptanceYear; - } - - @Override - public List getAuthorities() { - return this.authorities; - } - - @Override - public String getPassword() { - return this.password; - } - - @Override - public String getUsername() { - return this.cid; - } - - @Override - public boolean isAccountNonExpired() { - return true; - } - - @Override - public boolean isAccountNonLocked() { - return !this.accountLocked; - } - - @Override - public boolean isCredentialsNonExpired() { - return true; - } - - @Override - public boolean isEnabled() { - return true; - } - - public boolean isActivated() { - return this.activated; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - ITUserDTO that = (ITUserDTO) o; - return this.gdpr == that.gdpr - && this.userAgreement == that.userAgreement - && this.accountLocked == that.accountLocked - && Objects.equals(this.id, that.id) - && Objects.equals(this.cid, that.cid) - && Objects.equals(this.nick, that.nick) - && Objects.equals(this.firstName, that.firstName) - && Objects.equals(this.lastName, that.lastName) - && Objects.equals(this.email, that.email) - && Objects.equals(this.phone, that.phone) - && this.language == that.language - && Objects.equals(this.avatarUrl, that.avatarUrl) - && Objects.equals(this.acceptanceYear, that.acceptanceYear); - } - - @Override - public int hashCode() { - return Objects.hash(this.id, - this.cid, - this.nick, - this.firstName, - this.lastName, - this.email, - this.phone, - this.language, - this.avatarUrl, - this.gdpr, - this.userAgreement, - this.accountLocked, - this.acceptanceYear); - } - - @Override - public String toString() { - return "ITUserDTO{" - + "id=" + this.id - + ", cid='" + this.cid + '\'' - + ", nick='" + this.nick + '\'' - + ", firstName='" + this.firstName + '\'' - + ", lastName='" + this.lastName + '\'' - + ", email='" + this.email + '\'' - + ", phone='" + this.phone + '\'' - + ", language=" + this.language - + ", avatarUrl='" + this.avatarUrl + '\'' - + ", gdpr=" + this.gdpr - + ", userAgreement=" + this.userAgreement - + ", accountLocked=" + this.accountLocked - + ", acceptanceYear=" + this.acceptanceYear - + '}'; - } - -} diff --git a/backend/src/main/java/it/chalmers/gamma/domain/dto/user/ITUserRestrictedDTO.java b/backend/src/main/java/it/chalmers/gamma/domain/dto/user/ITUserRestrictedDTO.java deleted file mode 100644 index 77d1a0f36..000000000 --- a/backend/src/main/java/it/chalmers/gamma/domain/dto/user/ITUserRestrictedDTO.java +++ /dev/null @@ -1,97 +0,0 @@ -package it.chalmers.gamma.domain.dto.user; - -import java.time.Year; -import java.util.Objects; -import java.util.UUID; - -public class ITUserRestrictedDTO { - private final UUID id; - private final String cid; - private final String nick; - private final String firstName; - private final String lastName; - private final String avatarUrl; - private final Year acceptanceYear; - - public ITUserRestrictedDTO(ITUserDTO userDTO) { - this.id = userDTO.getId(); - this.cid = userDTO.getCid(); - this.nick = userDTO.getNick(); - this.firstName = userDTO.getFirstName(); - this.lastName = userDTO.getLastName(); - this.avatarUrl = userDTO.getAvatarUrl(); - this.acceptanceYear = userDTO.getAcceptanceYear(); - } - - public UUID getId() { - return this.id; - } - - public String getCid() { - return this.cid; - } - - public String getNick() { - return this.nick; - } - - public String getFirstName() { - return this.firstName; - } - - public String getLastName() { - return this.lastName; - } - - public String getAvatarUrl() { - return this.avatarUrl; - } - - public Year getAcceptanceYear() { - return this.acceptanceYear; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - ITUserRestrictedDTO that = (ITUserRestrictedDTO) o; - return Objects.equals(this.id, that.id) - && Objects.equals(this.cid, that.cid) - && Objects.equals(this.nick, that.nick) - && Objects.equals(this.firstName, that.firstName) - && Objects.equals(this.lastName, that.lastName) - && Objects.equals(this.avatarUrl, that.avatarUrl) - && Objects.equals(this.acceptanceYear, that.acceptanceYear); - } - - @Override - public int hashCode() { - return Objects.hash( - this.id, - this.cid, - this.nick, - this.firstName, - this.lastName, - this.avatarUrl, - this.acceptanceYear - ); - } - - @Override - public String toString() { - return "ITUserRestrictedDTO{" - + "id=" + this.id - + ", cid='" + this.cid + '\'' - + ", nick='" + this.nick + '\'' - + ", firstName='" + this.firstName + '\'' - + ", lastName='" + this.lastName + '\'' - + ", avatarUrl='" + this.avatarUrl + '\'' - + ", acceptanceYear=" + this.acceptanceYear + '\'' - + '}'; - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/domain/dto/user/PasswordResetTokenDTO.java b/backend/src/main/java/it/chalmers/gamma/domain/dto/user/PasswordResetTokenDTO.java deleted file mode 100644 index 926155786..000000000 --- a/backend/src/main/java/it/chalmers/gamma/domain/dto/user/PasswordResetTokenDTO.java +++ /dev/null @@ -1,56 +0,0 @@ -package it.chalmers.gamma.domain.dto.user; - -import java.util.Objects; -import java.util.UUID; - -public class PasswordResetTokenDTO { - private final UUID id; - private final String token; - private final ITUserDTO itUserDTO; - - public PasswordResetTokenDTO(UUID id, String token, ITUserDTO itUserDTO) { - this.id = id; - this.token = token; - this.itUserDTO = itUserDTO; - } - - public UUID getId() { - return this.id; - } - - public String getToken() { - return this.token; - } - - public ITUserDTO getItUserDTO() { - return this.itUserDTO; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - PasswordResetTokenDTO that = (PasswordResetTokenDTO) o; - return Objects.equals(this.id, that.id) - && Objects.equals(this.token, that.token) - && Objects.equals(this.itUserDTO, that.itUserDTO); - } - - @Override - public int hashCode() { - return Objects.hash(this.id, this.token, this.itUserDTO); - } - - @Override - public String toString() { - return "PasswordResetTokenDTO{" - + "id=" + this.id - + ", token='" + this.token + '\'' - + ", itUserDTO=" + this.itUserDTO - + '}'; - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/domain/dto/user/WhitelistDTO.java b/backend/src/main/java/it/chalmers/gamma/domain/dto/user/WhitelistDTO.java deleted file mode 100644 index 4d3d48c08..000000000 --- a/backend/src/main/java/it/chalmers/gamma/domain/dto/user/WhitelistDTO.java +++ /dev/null @@ -1,53 +0,0 @@ -package it.chalmers.gamma.domain.dto.user; - -import java.util.Objects; -import java.util.UUID; - -public class WhitelistDTO { - private UUID id; - private String cid; - - public WhitelistDTO() { - // Needed for Jackson serialization - } - - public WhitelistDTO(UUID id, String cid) { - this.id = id; - this.cid = cid; - } - - public UUID getId() { - return this.id; - } - - public String getCid() { - return this.cid; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - WhitelistDTO that = (WhitelistDTO) o; - return Objects.equals(this.id, that.id) - && Objects.equals(this.cid, that.cid); - } - - @Override - public int hashCode() { - - return Objects.hash(this.id, this.cid); - } - - @Override - public String toString() { - return "WhitelistDTO{" - + "id=" + this.id - + ", cid='" + this.cid + '\'' - + '}'; - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/domain/dto/website/GroupWebsiteDTO.java b/backend/src/main/java/it/chalmers/gamma/domain/dto/website/GroupWebsiteDTO.java deleted file mode 100644 index 40f79c8c0..000000000 --- a/backend/src/main/java/it/chalmers/gamma/domain/dto/website/GroupWebsiteDTO.java +++ /dev/null @@ -1,59 +0,0 @@ -package it.chalmers.gamma.domain.dto.website; - -import it.chalmers.gamma.domain.dto.group.FKITGroupDTO; -import java.util.Objects; -import java.util.UUID; - -public class GroupWebsiteDTO implements WebsiteInterfaceDTO { - private final UUID id; - private final WebsiteUrlDTO website; - private final FKITGroupDTO groupDTO; - - - public GroupWebsiteDTO(UUID id, WebsiteUrlDTO website, FKITGroupDTO groupDTO) { - this.id = id; - this.website = website; - this.groupDTO = groupDTO; - } - - public UUID getId() { - return this.id; - } - - @Override - public WebsiteUrlDTO getWebsiteURL() { - return this.website; - } - - public FKITGroupDTO getGroupDTO() { - return this.groupDTO; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - GroupWebsiteDTO that = (GroupWebsiteDTO) o; - return Objects.equals(this.id, that.id) - && Objects.equals(this.website, that.website) - && Objects.equals(this.groupDTO, that.groupDTO); - } - - @Override - public int hashCode() { - return Objects.hash(this.id, this.website, this.groupDTO); - } - - @Override - public String toString() { - return "GroupWebsiteDTO{" - + "id=" + this.id - + ", website=" + this.website - + ", groupDTO=" + this.groupDTO - + '}'; - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/domain/dto/website/UserWebsiteDTO.java b/backend/src/main/java/it/chalmers/gamma/domain/dto/website/UserWebsiteDTO.java deleted file mode 100644 index a0d680575..000000000 --- a/backend/src/main/java/it/chalmers/gamma/domain/dto/website/UserWebsiteDTO.java +++ /dev/null @@ -1,57 +0,0 @@ -package it.chalmers.gamma.domain.dto.website; - -import it.chalmers.gamma.domain.dto.user.ITUserDTO; -import java.util.Objects; -import java.util.UUID; - -public class UserWebsiteDTO implements WebsiteInterfaceDTO { - private final UUID id; - private final ITUserDTO itUserDTO; - private final WebsiteUrlDTO websiteUrlDTO; - - public UserWebsiteDTO(UUID id, ITUserDTO itUserDTO, WebsiteUrlDTO websiteUrlDTO) { - this.id = id; - this.itUserDTO = itUserDTO; - this.websiteUrlDTO = websiteUrlDTO; - } - - public UUID getId() { - return this.id; - } - - public ITUserDTO getItUserDTO() { - return this.itUserDTO; - } - @Override - public WebsiteUrlDTO getWebsiteURL() { - return this.websiteUrlDTO; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - UserWebsiteDTO that = (UserWebsiteDTO) o; - return Objects.equals(this.id, that.id) - && Objects.equals(this.itUserDTO, that.itUserDTO) - && Objects.equals(this.websiteUrlDTO, that.websiteUrlDTO); - } - - @Override - public int hashCode() { - return Objects.hash(this.id, this.itUserDTO, this.websiteUrlDTO); - } - - @Override - public String toString() { - return "UserWebsiteDTO{" - + "id=" + this.id - + ", itUserDTO=" + this.itUserDTO - + ", websiteUrlDTO=" + this.websiteUrlDTO - + '}'; - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/domain/dto/website/WebsiteDTO.java b/backend/src/main/java/it/chalmers/gamma/domain/dto/website/WebsiteDTO.java deleted file mode 100644 index 9d44be613..000000000 --- a/backend/src/main/java/it/chalmers/gamma/domain/dto/website/WebsiteDTO.java +++ /dev/null @@ -1,56 +0,0 @@ -package it.chalmers.gamma.domain.dto.website; - -import java.util.Objects; -import java.util.UUID; - -public class WebsiteDTO { - private final UUID id; - private final String name; - private final String prettyName; - - public WebsiteDTO(UUID id, String name, String prettyName) { - this.id = id; - this.name = name; - this.prettyName = prettyName; - } - - public UUID getId() { - return this.id; - } - - public String getName() { - return this.name; - } - - public String getPrettyName() { - return this.prettyName; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - WebsiteDTO that = (WebsiteDTO) o; - return Objects.equals(this.id, that.id) - && Objects.equals(this.name, that.name) - && Objects.equals(this.prettyName, that.prettyName); - } - - @Override - public int hashCode() { - return Objects.hash(this.id, this.name, this.prettyName); - } - - @Override - public String toString() { - return "WebsiteDTO{" - + "id=" + this.id - + ", name='" + this.name + '\'' - + ", prettyName='" + this.prettyName + '\'' - + '}'; - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/domain/dto/website/WebsiteInterfaceDTO.java b/backend/src/main/java/it/chalmers/gamma/domain/dto/website/WebsiteInterfaceDTO.java deleted file mode 100644 index a422620cd..000000000 --- a/backend/src/main/java/it/chalmers/gamma/domain/dto/website/WebsiteInterfaceDTO.java +++ /dev/null @@ -1,5 +0,0 @@ -package it.chalmers.gamma.domain.dto.website; - -public interface WebsiteInterfaceDTO { - WebsiteUrlDTO getWebsiteURL(); -} diff --git a/backend/src/main/java/it/chalmers/gamma/domain/dto/website/WebsiteUrlDTO.java b/backend/src/main/java/it/chalmers/gamma/domain/dto/website/WebsiteUrlDTO.java deleted file mode 100644 index 7f654f179..000000000 --- a/backend/src/main/java/it/chalmers/gamma/domain/dto/website/WebsiteUrlDTO.java +++ /dev/null @@ -1,60 +0,0 @@ -package it.chalmers.gamma.domain.dto.website; - -import java.util.Objects; -import java.util.UUID; - -public class WebsiteUrlDTO { - private final UUID id; - private final String url; - private final WebsiteDTO websiteDTO; - - public WebsiteUrlDTO(UUID id, String url, WebsiteDTO websiteDTO) { - this.id = id; - this.url = url; - this.websiteDTO = websiteDTO; - } - - public WebsiteUrlDTO(String url, WebsiteDTO websiteDTO) { - this(null, url, websiteDTO); - } - - public UUID getId() { - return this.id; - } - - public String getUrl() { - return this.url; - } - - public WebsiteDTO getWebsiteDTO() { - return this.websiteDTO; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - WebsiteUrlDTO that = (WebsiteUrlDTO) o; - return Objects.equals(this.id, that.id) - && Objects.equals(this.url, that.url) - && Objects.equals(this.websiteDTO, that.websiteDTO); - } - - @Override - public int hashCode() { - return Objects.hash(this.id, this.url, this.websiteDTO); - } - - @Override - public String toString() { - return "WebsiteUrlDTO{" - + "id=" + this.id - + ", url='" + this.url + '\'' - + ", websiteDTO=" + this.websiteDTO - + '}'; - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/filter/ApiKeyAuthenticationFilter.java b/backend/src/main/java/it/chalmers/gamma/filter/ApiKeyAuthenticationFilter.java deleted file mode 100644 index bce67e5f9..000000000 --- a/backend/src/main/java/it/chalmers/gamma/filter/ApiKeyAuthenticationFilter.java +++ /dev/null @@ -1,64 +0,0 @@ -package it.chalmers.gamma.filter; - -import it.chalmers.gamma.service.ApiKeyService; -import it.chalmers.gamma.service.ITUserService; - -import java.io.IOException; -import javax.servlet.FilterChain; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.web.filter.OncePerRequestFilter; - - - -public class ApiKeyAuthenticationFilter extends OncePerRequestFilter { - - private final ApiKeyService apiKeyService; - private final ITUserService itUserService; - - public ApiKeyAuthenticationFilter(ApiKeyService apiKeyService, ITUserService itUserService) { - this.apiKeyService = apiKeyService; - this.itUserService = itUserService; - } - - /* - Authentication using API keys are not supported natively, so once a recognized API key is sent, the Server - authenticates the session by giving the request the Principal and Authorities of the Admin user. - */ - @Override - protected void doFilterInternal( - HttpServletRequest request, - HttpServletResponse response, - FilterChain filterChain) throws ServletException, IOException { - String token = resolveToken(request); - if (this.apiKeyService.isValidApiKey(token)) { - Authentication auth = getAdminAuthentication(); - SecurityContextHolder.getContext().setAuthentication(auth); - } - filterChain.doFilter(request, response); - } - - private String resolveToken(HttpServletRequest req) { - String basicToken = req.getHeader("Authorization"); - if (basicToken != null && basicToken.startsWith("pre-shared ")) { - return removeBasic(basicToken); - } - return null; - } - // THIS IS SOOOOOOO UGLY - // Can't figure out another, less hacky way to do it... - private Authentication getAdminAuthentication() { - UserDetails userDetails = this.itUserService.loadUserByUsername("admin"); - return new UsernamePasswordAuthenticationToken(userDetails.getUsername(), null, userDetails.getAuthorities()); - } - - private String removeBasic(String token) { - return token.substring(11); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/filter/AuthenticationFilterConfigurer.java b/backend/src/main/java/it/chalmers/gamma/filter/AuthenticationFilterConfigurer.java deleted file mode 100644 index 6cb1d317f..000000000 --- a/backend/src/main/java/it/chalmers/gamma/filter/AuthenticationFilterConfigurer.java +++ /dev/null @@ -1,58 +0,0 @@ -package it.chalmers.gamma.filter; - -import it.chalmers.gamma.service.ApiKeyService; -import it.chalmers.gamma.service.ITUserService; - -import it.chalmers.gamma.service.PasswordResetService; -import org.springframework.security.config.annotation.SecurityConfigurerAdapter; -import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.web.DefaultSecurityFilterChain; -import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; -import org.springframework.security.web.authentication.www.BasicAuthenticationFilter; - -public class AuthenticationFilterConfigurer extends SecurityConfigurerAdapter - { - - private final String secretKey; - private final String baseFrontendUrl; - private final String issuer; - private final ITUserService itUserService; - private final ApiKeyService apiKeyService; - private final PasswordResetService passwordResetService; - - public AuthenticationFilterConfigurer( - ITUserService itUserService, - String secretKey, - String issuer, - ApiKeyService apiKeyService, - PasswordResetService passwordResetService, - String baseFrontendUrl) { - this.itUserService = itUserService; - this.secretKey = secretKey; - this.issuer = issuer; - this.apiKeyService = apiKeyService; - this.passwordResetService = passwordResetService; - this.baseFrontendUrl = baseFrontendUrl; - } - - @Override - public void configure(HttpSecurity builder) { - JwtAuthenticationFilter customFilter = new JwtAuthenticationFilter( - this.itUserService, - this.secretKey, - this.issuer - ); - ApiKeyAuthenticationFilter apiKeyAuthenticationFilter = new ApiKeyAuthenticationFilter( - this.apiKeyService, - this.itUserService - ); - ResetNonActivatedAccountFilter c = new ResetNonActivatedAccountFilter( - this.itUserService, - this.passwordResetService, - this.baseFrontendUrl); - builder.addFilterBefore(c, UsernamePasswordAuthenticationFilter.class); - builder.addFilterBefore(customFilter, UsernamePasswordAuthenticationFilter.class); - builder.addFilterBefore(apiKeyAuthenticationFilter, BasicAuthenticationFilter.class); - - } -} \ No newline at end of file diff --git a/backend/src/main/java/it/chalmers/gamma/filter/CorsFilter.java b/backend/src/main/java/it/chalmers/gamma/filter/CorsFilter.java deleted file mode 100644 index 67a01d732..000000000 --- a/backend/src/main/java/it/chalmers/gamma/filter/CorsFilter.java +++ /dev/null @@ -1,62 +0,0 @@ -package it.chalmers.gamma.filter; - -import java.io.IOException; - -import javax.servlet.Filter; -import javax.servlet.FilterChain; -import javax.servlet.FilterConfig; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.springframework.beans.factory.annotation.Value; -import org.springframework.core.Ordered; -import org.springframework.core.annotation.Order; -import org.springframework.stereotype.Component; - -@Component -@Order(Ordered.HIGHEST_PRECEDENCE) -public class CorsFilter implements Filter { - - @Value("${application.production}") - private boolean inProduction; - - @Value("${application.allowed-origin}") - private String configAllowedOrigin; - - @Override - public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) - throws IOException, ServletException { - HttpServletResponse response = (HttpServletResponse) res; - String allowedOrigin = this.inProduction ? this.configAllowedOrigin : "*"; - response.setHeader("Access-Control-Allow-Origin", allowedOrigin); - response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PUT"); - response.setHeader("Access-Control-Max-Age", "3600"); - response.setHeader( - "Access-Control-Allow-Headers", - "x-requested-with, " - + "authorization, " - + "Content-Type, " - + "Authorization, " - + "credential, " - + "X-XSRF-TOKEN" - ); - - HttpServletRequest request = (HttpServletRequest) req; - if ("OPTIONS".equalsIgnoreCase(request.getMethod())) { - response.setStatus(HttpServletResponse.SC_OK); - } else { - chain.doFilter(req, res); - } - } - - @Override - public void destroy() { - } - - @Override - public void init(FilterConfig config) throws ServletException { - } -} \ No newline at end of file diff --git a/backend/src/main/java/it/chalmers/gamma/filter/JSONSentObjectFilter.java b/backend/src/main/java/it/chalmers/gamma/filter/JSONSentObjectFilter.java deleted file mode 100644 index e4ad54827..000000000 --- a/backend/src/main/java/it/chalmers/gamma/filter/JSONSentObjectFilter.java +++ /dev/null @@ -1,36 +0,0 @@ -package it.chalmers.gamma.filter; - -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import javax.servlet.Filter; -import javax.servlet.FilterChain; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.core.annotation.Order; -import org.springframework.stereotype.Component; -import org.springframework.web.util.ContentCachingResponseWrapper; - -@Component -@Order() -public class JSONSentObjectFilter implements Filter { - private static final Logger LOGGER = LoggerFactory.getLogger(JSONSentObjectFilter.class); - - @Override - public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) - throws IOException, ServletException { - ContentCachingResponseWrapper resWrapper = new ContentCachingResponseWrapper((HttpServletResponse) response); - chain.doFilter(request, resWrapper); - String payload = new String(resWrapper.getContentAsByteArray(), StandardCharsets.UTF_8); - String url = ((HttpServletRequest)request).getRequestURL().toString(); - if (resWrapper.getContentType() != null && resWrapper.getContentType().startsWith("application/json")) { - LOGGER.debug("Response from server was: {} {}", payload, url); - } - resWrapper.copyBodyToResponse(); - } - -} diff --git a/backend/src/main/java/it/chalmers/gamma/filter/JwtAuthenticationFilter.java b/backend/src/main/java/it/chalmers/gamma/filter/JwtAuthenticationFilter.java deleted file mode 100644 index 285f6981d..000000000 --- a/backend/src/main/java/it/chalmers/gamma/filter/JwtAuthenticationFilter.java +++ /dev/null @@ -1,110 +0,0 @@ -package it.chalmers.gamma.filter; - -import io.jsonwebtoken.Claims; -import io.jsonwebtoken.Jws; -import io.jsonwebtoken.Jwts; -import io.jsonwebtoken.MalformedJwtException; -import io.jsonwebtoken.SignatureException; - -import it.chalmers.gamma.response.InvalidJWTTokenResponse; -import it.chalmers.gamma.service.ITUserService; - -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.util.Base64; - -import javax.servlet.FilterChain; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.security.core.userdetails.UsernameNotFoundException; -import org.springframework.web.filter.OncePerRequestFilter; - -public class JwtAuthenticationFilter extends OncePerRequestFilter { - - private final String secretKey; - private final String issuer; - private final ITUserService itUserService; - - private static final Logger LOGGER = LoggerFactory.getLogger(JwtAuthenticationFilter.class); - - public JwtAuthenticationFilter(ITUserService itUserService, String secretKey, String issuer) { - this.itUserService = itUserService; - this.secretKey = secretKey; - this.issuer = issuer; - } - - //TODO This function might cause some problems if sent wrong info. - @Override - protected void doFilterInternal( - HttpServletRequest request, - HttpServletResponse response, - FilterChain chain) throws ServletException, IOException { - String encodedToken = resolveToken(request); - if (encodedToken != null) { - try { - Jws claim = decodeToken(encodedToken); - String token = null; - if (claim != null) { - token = (String) claim.getBody().get("user_name"); - } - if (token != null) { - Authentication auth = getAuthentication(token); - SecurityContextHolder.getContext().setAuthentication(auth); - } - } catch (SignatureException e) { - response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); - return; - } - } - chain.doFilter(request, response); - } - - private Authentication getAuthentication(String cid) { - UserDetails userDetails; - try { - userDetails = this.itUserService.loadUserByUsername(cid); - } catch (UsernameNotFoundException e) { - throw new InvalidJWTTokenResponse(); - } - return new UsernamePasswordAuthenticationToken(userDetails.getUsername(), - null, userDetails.getAuthorities()); - } - - /* - * If this doesn't crash, then the JWT token is valid. - */ - private Jws decodeToken(String token) { - try { - return Jwts.parser() - .requireIssuer(this.issuer) - .setSigningKey(Base64.getEncoder().encodeToString( - this.secretKey.getBytes(StandardCharsets.UTF_8)) - ) - .parseClaimsJws(token); - } catch (MalformedJwtException | SignatureException e) { - LOGGER.warn(e.getMessage()); - throw new SignatureException(e.getMessage()); - } - } - - private String resolveToken(HttpServletRequest req) { - String bearerToken = req.getHeader("Authorization"); - if (bearerToken != null && bearerToken.startsWith("Bearer ")) { - return removeBearer(bearerToken); - } - return null; - } - - private String removeBearer(String token) { - return token.substring(7); - } - -} \ No newline at end of file diff --git a/backend/src/main/java/it/chalmers/gamma/filter/OauthRedirectFilter.java b/backend/src/main/java/it/chalmers/gamma/filter/OauthRedirectFilter.java deleted file mode 100644 index 7dd3a1f20..000000000 --- a/backend/src/main/java/it/chalmers/gamma/filter/OauthRedirectFilter.java +++ /dev/null @@ -1,34 +0,0 @@ -package it.chalmers.gamma.filter; - -import java.io.IOException; -import javax.servlet.Filter; -import javax.servlet.FilterChain; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import org.springframework.security.core.context.SecurityContext; -import org.springframework.security.core.context.SecurityContextHolder; - -public class OauthRedirectFilter implements Filter { - - @Override - public void doFilter(ServletRequest request, - ServletResponse response, - FilterChain chain) throws IOException, ServletException { - HttpServletRequest httpServletRequest = (HttpServletRequest) request; - HttpServletResponse httpServletResponse = (HttpServletResponse) response; - String requestURI = httpServletRequest.getRequestURI(); - SecurityContext context = SecurityContextHolder.getContext(); - String prefix = ((HttpServletRequest) request).getContextPath(); - if (requestURI.startsWith(prefix + "/oauth") - && (context.getAuthentication() == null || !context.getAuthentication().isAuthenticated())) { - ((HttpServletRequest) request).getSession().setAttribute("redirect", requestURI - + "?" + httpServletRequest.getQueryString()); - httpServletResponse.sendRedirect(String.format("%s/login", httpServletRequest.getContextPath())); - } else { - chain.doFilter(request, response); - } - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/filter/ResetNonActivatedAccountFilter.java b/backend/src/main/java/it/chalmers/gamma/filter/ResetNonActivatedAccountFilter.java deleted file mode 100644 index 20beb4ca9..000000000 --- a/backend/src/main/java/it/chalmers/gamma/filter/ResetNonActivatedAccountFilter.java +++ /dev/null @@ -1,52 +0,0 @@ -package it.chalmers.gamma.filter; - -import it.chalmers.gamma.domain.dto.user.ITUserDTO; -import it.chalmers.gamma.response.user.UserNotFoundResponse; -import it.chalmers.gamma.service.ITUserService; -import it.chalmers.gamma.service.PasswordResetService; -import java.io.IOException; -import javax.servlet.FilterChain; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.web.filter.OncePerRequestFilter; - -public class ResetNonActivatedAccountFilter extends OncePerRequestFilter { - - private final String baseFrontendUrl; - private static final String USERNAME_PARAMETER = "username"; - private final ITUserService itUserService; - private static final Logger LOGGER = LoggerFactory.getLogger(ResetNonActivatedAccountFilter.class); - private final PasswordResetService passwordResetService; - - public ResetNonActivatedAccountFilter(ITUserService itUserService, - PasswordResetService passwordResetService, - String baseFrontendUrl) { - this.itUserService = itUserService; - this.passwordResetService = passwordResetService; - this.baseFrontendUrl = baseFrontendUrl; - } - - @Override - protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) - throws ServletException, IOException { - String username = request.getParameter(USERNAME_PARAMETER); - if (username != null) { - try { - ITUserDTO userDTO = this.itUserService.getITUser(username); - if (!userDTO.isActivated()) { - this.passwordResetService.handlePasswordReset(userDTO); - String params = "accountLocked=true"; - response.sendRedirect(String.format("%s/reset-password/finish?%s", this.baseFrontendUrl, params)); - return; - } - } catch (UserNotFoundResponse e) { - LOGGER.info(String.format("User %s tried logging in, but no such user exists", username)); - } - } - filterChain.doFilter(request, response); - - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/handlers/LoginRedirectHandler.java b/backend/src/main/java/it/chalmers/gamma/handlers/LoginRedirectHandler.java deleted file mode 100644 index 209636784..000000000 --- a/backend/src/main/java/it/chalmers/gamma/handlers/LoginRedirectHandler.java +++ /dev/null @@ -1,36 +0,0 @@ -package it.chalmers.gamma.handlers; - -import java.io.IOException; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.security.core.Authentication; -import org.springframework.security.web.authentication.AuthenticationSuccessHandler; -import org.springframework.stereotype.Component; - -@Component -public class LoginRedirectHandler implements AuthenticationSuccessHandler { - - - @Value("${application.frontend-client-details.successful-login-uri}") - private String frontendUrl; - - private static final Logger LOGGER = LoggerFactory.getLogger(LoginRedirectHandler.class); - - @Override - public void onAuthenticationSuccess(HttpServletRequest request, - HttpServletResponse response, - Authentication authentication) throws IOException, ServletException { - if (response.isCommitted()) { - LOGGER.warn("Response already committed, cannot redirect "); - } - response.sendRedirect(redirectUrl(request)); - } - private String redirectUrl(HttpServletRequest request) { - String setRedirect = (String) request.getSession().getAttribute("redirect"); - return setRedirect == null ? frontendUrl : setRedirect; - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/handlers/MultipartExceptionHandler.java b/backend/src/main/java/it/chalmers/gamma/handlers/MultipartExceptionHandler.java deleted file mode 100644 index ba8d18e0e..000000000 --- a/backend/src/main/java/it/chalmers/gamma/handlers/MultipartExceptionHandler.java +++ /dev/null @@ -1,23 +0,0 @@ -package it.chalmers.gamma.handlers; - -import it.chalmers.gamma.response.FileTooLargeResponse; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.web.bind.annotation.ControllerAdvice; -import org.springframework.web.bind.annotation.ExceptionHandler; -import org.springframework.web.bind.annotation.RestController; -import org.springframework.web.multipart.MaxUploadSizeExceededException; - -@ControllerAdvice -@RestController -public class MultipartExceptionHandler { - - private static final Logger LOGGER = LoggerFactory.getLogger(MultipartExceptionHandler.class); - - - @ExceptionHandler({MaxUploadSizeExceededException.class}) - public FileTooLargeResponse handleUploadSizeException() { - LOGGER.info("Too large file upload was attempted"); - return new FileTooLargeResponse(); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/requests/AddAuthorityLevelRequest.java b/backend/src/main/java/it/chalmers/gamma/requests/AddAuthorityLevelRequest.java deleted file mode 100644 index d4d5fbbcf..000000000 --- a/backend/src/main/java/it/chalmers/gamma/requests/AddAuthorityLevelRequest.java +++ /dev/null @@ -1,41 +0,0 @@ -package it.chalmers.gamma.requests; - -import java.util.Objects; -import javax.validation.constraints.NotEmpty; - -public class AddAuthorityLevelRequest { - @NotEmpty(message = "AUTHORITY_LEVEL_MUST_BE_PROVIDED") - private String authorityLevel; - - public String getAuthorityLevel() { - return this.authorityLevel; - } - - public void setAuthorityLevel(String authorityLevel) { - this.authorityLevel = authorityLevel; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - AddAuthorityLevelRequest that = (AddAuthorityLevelRequest) o; - return Objects.equals(this.authorityLevel, that.authorityLevel); - } - - @Override - public int hashCode() { - return Objects.hash(this.authorityLevel); - } - - @Override - public String toString() { - return "AuthorizationLevelRequest{" - + "AuthorityLevel='" + this.authorityLevel + '\'' - + '}'; - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/requests/AddAuthorityRequest.java b/backend/src/main/java/it/chalmers/gamma/requests/AddAuthorityRequest.java deleted file mode 100644 index 24f73d8ad..000000000 --- a/backend/src/main/java/it/chalmers/gamma/requests/AddAuthorityRequest.java +++ /dev/null @@ -1,65 +0,0 @@ -package it.chalmers.gamma.requests; - -import java.util.Objects; -import javax.validation.constraints.NotNull; - -public class AddAuthorityRequest { - @NotNull(message = "POST_MUST_BE_PROVIDED") - private String post; - @NotNull(message = "SUPER_GROUP_MUST_BE_PROVIDED") - private String superGroup; - @NotNull(message = "AUTHORITY_MUST_BE_PROVIDED") - private String authority; - - public String getAuthority() { - return this.authority; - } - - public void setAuthority(String authorization) { - this.authority = authorization; - } - - public String getPost() { - return this.post; - } - - public void setPost(String post) { - this.post = post; - } - - public String getSuperGroup() { - return this.superGroup; - } - - public void setSuperGroup(String superGroup) { - this.superGroup = superGroup; - } - - @Override - public String toString() { - return "AuthorizationRequest{" - + "post='" + this.post + '\'' - + ", superGroup='" + this.superGroup + '\'' - + ", authority'" + this.authority + '\'' - + '}'; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - AddAuthorityRequest that = (AddAuthorityRequest) o; - return Objects.equals(this.post, that.post) - && Objects.equals(this.superGroup, that.superGroup) - && Objects.equals(this.authority, that.authority); - } - - @Override - public int hashCode() { - return Objects.hash(this.post, this.superGroup, this.authority); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/requests/AddITClientRequest.java b/backend/src/main/java/it/chalmers/gamma/requests/AddITClientRequest.java deleted file mode 100644 index 8723624ac..000000000 --- a/backend/src/main/java/it/chalmers/gamma/requests/AddITClientRequest.java +++ /dev/null @@ -1,83 +0,0 @@ -package it.chalmers.gamma.requests; - -import it.chalmers.gamma.db.entity.Text; - -import java.util.Objects; - -import javax.validation.constraints.NotNull; - -public class AddITClientRequest { - - @NotNull - private String webServerRedirectUri; - - @NotNull - private String name; - - @NotNull - private boolean autoApprove; - - private Text description; - - public String getWebServerRedirectUri() { - return this.webServerRedirectUri; - } - - public void setWebServerRedirectUri(String webServerRedirectUri) { - this.webServerRedirectUri = webServerRedirectUri; - } - - public String getName() { - return this.name; - } - - public void setName(String name) { - this.name = name; - } - - public Text getDescription() { - return this.description; - } - - public void setDescription(Text description) { - this.description = description; - } - - public boolean isAutoApprove() { - return this.autoApprove; - } - - public void setAutoApprove(boolean autoApprove) { - this.autoApprove = autoApprove; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - AddITClientRequest that = (AddITClientRequest) o; - return this.autoApprove == that.autoApprove - && Objects.equals(this.webServerRedirectUri, that.webServerRedirectUri) - && Objects.equals(this.name, that.name) - && Objects.equals(this.description, that.description); - } - - @Override - public int hashCode() { - return Objects.hash(this.webServerRedirectUri, this.name, this.autoApprove, this.description); - } - - @Override - public String toString() { - return "AddITClientRequest{" - + "webServerRedirectUri='" + this.webServerRedirectUri + '\'' - + ", name='" + this.name + '\'' - + ", autoApprove=" + this.autoApprove - + ", description=" + this.description - + '}'; - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/requests/AddListOfWhitelistedRequest.java b/backend/src/main/java/it/chalmers/gamma/requests/AddListOfWhitelistedRequest.java deleted file mode 100644 index 2daa2318f..000000000 --- a/backend/src/main/java/it/chalmers/gamma/requests/AddListOfWhitelistedRequest.java +++ /dev/null @@ -1,43 +0,0 @@ -package it.chalmers.gamma.requests; - -import java.util.List; -import java.util.Objects; -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.Size; - -public class AddListOfWhitelistedRequest { - @NotEmpty(message = "NO_CID_IN_REQUEST") - private List<@Size(min = 4, max = 12, message = "CIDS_MUST_BE_BETWEEN_4_AND_12_CHARACTERS") String> cids; - - public List getCids() { - return this.cids; - } - - public void setCids(List cid) { - this.cids = cid; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - AddListOfWhitelistedRequest that = (AddListOfWhitelistedRequest) o; - return this.cids.equals(that.cids); - } - - @Override - public int hashCode() { - return Objects.hash(this.cids); - } - - @Override - public String toString() { - return "AddListOfWhitelistedRequest{" - + "cids=" + this.cids - + '}'; - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/requests/AddPostRequest.java b/backend/src/main/java/it/chalmers/gamma/requests/AddPostRequest.java deleted file mode 100644 index 450226490..000000000 --- a/backend/src/main/java/it/chalmers/gamma/requests/AddPostRequest.java +++ /dev/null @@ -1,55 +0,0 @@ -package it.chalmers.gamma.requests; - -import it.chalmers.gamma.db.entity.Text; -import java.util.Objects; -import javax.validation.constraints.NotNull; - - -public class AddPostRequest { - @NotNull(message = "POST_CANNOT_BE_NULL") - private Text post; - - private String emailPrefix; - - public Text getPost() { - return this.post; - } - - public void setPost(Text post) { - this.post = post; - } - - public String getEmailPrefix() { - return this.emailPrefix; - } - - public void setEmailPrefix(String emailPrefix) { - this.emailPrefix = emailPrefix; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - AddPostRequest that = (AddPostRequest) o; - return Objects.equals(this.post, that.post) - && Objects.equals(this.emailPrefix, that.emailPrefix); - } - - @Override - public int hashCode() { - return Objects.hash(this.post, this.emailPrefix); - } - - @Override - public String toString() { - return "AddPostRequest{" - + "post=" + this.post - + ", emailPrefix='" + this.emailPrefix + '\'' - + '}'; - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/requests/AddUserGroupRequest.java b/backend/src/main/java/it/chalmers/gamma/requests/AddUserGroupRequest.java deleted file mode 100644 index 89a9e0257..000000000 --- a/backend/src/main/java/it/chalmers/gamma/requests/AddUserGroupRequest.java +++ /dev/null @@ -1,66 +0,0 @@ -package it.chalmers.gamma.requests; - -import java.util.Objects; -import javax.validation.constraints.NotEmpty; - -public class AddUserGroupRequest { - - @NotEmpty(message = "USER_MUST_BE_PROVIDED") - private String userId; - - @NotEmpty(message = "POST_MUST_BE_PROVIDED") - private String post; - private String unofficialName; - - public String getUserId() { - return this.userId; - } - - public void setUserId(String userId) { - this.userId = userId; - } - - public String getPost() { - return this.post; - } - - public void setPost(String post) { - this.post = post; - } - - public String getUnofficialName() { - return this.unofficialName; - } - - public void setUnofficialName(String unofficialName) { - this.unofficialName = unofficialName; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - AddUserGroupRequest that = (AddUserGroupRequest) o; - return this.userId.equals(that.userId) - && this.post.equals(that.post) - && this.unofficialName.equals(that.unofficialName); - } - - @Override - public int hashCode() { - return Objects.hash(this.userId, this.post, this.unofficialName); - } - - @Override - public String toString() { - return "AddUserGroupRequest{" - + "userId='" + this.userId + '\'' - + ", post='" + this.post + '\'' - + ", unofficialName='" + this.unofficialName + '\'' - + '}'; - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/requests/AdminChangePasswordRequest.java b/backend/src/main/java/it/chalmers/gamma/requests/AdminChangePasswordRequest.java deleted file mode 100644 index 7de18124b..000000000 --- a/backend/src/main/java/it/chalmers/gamma/requests/AdminChangePasswordRequest.java +++ /dev/null @@ -1,41 +0,0 @@ -package it.chalmers.gamma.requests; - -import java.util.Objects; -import javax.validation.constraints.Size; - -public class AdminChangePasswordRequest { - @Size(min = 8, message = "PASSWORD_MUST_BE_MORE_THAN_8_CHARACTERS") - private String password; - - public String getPassword() { - return this.password; - } - - public void setPassword(String password) { - this.password = password; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - AdminChangePasswordRequest that = (AdminChangePasswordRequest) o; - return this.password.equals(that.password); - } - - @Override - public int hashCode() { - return Objects.hash(this.password); - } - - @Override - public String toString() { - return "AdminChangePasswordRequest{" - + "password='" + '\'' - + '}'; - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/requests/AdminViewCreateITUserRequest.java b/backend/src/main/java/it/chalmers/gamma/requests/AdminViewCreateITUserRequest.java deleted file mode 100644 index 175646148..000000000 --- a/backend/src/main/java/it/chalmers/gamma/requests/AdminViewCreateITUserRequest.java +++ /dev/null @@ -1,146 +0,0 @@ -package it.chalmers.gamma.requests; - -import it.chalmers.gamma.domain.Language; - -import java.util.Objects; -import javax.validation.constraints.AssertTrue; -import javax.validation.constraints.Email; -import javax.validation.constraints.Min; -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.Size; - -public class AdminViewCreateITUserRequest { - - @NotEmpty(message = "CID_MUST_BE_PROVIDED") - @Size(min = 4, max = 12, message = "CIDS_MUST_BE_BETWEEN_4_AND_12_CHARACTERS") - private String cid; - - @Size(min = 8, message = "PASSWORD_MUST_BE_MORE_THAN_8_CHARACTERS") - private String password; - - @NotEmpty(message = "NICK_MUST_BE_PROVIDED") - private String nick; - - @NotEmpty(message = "FIRST_NAME_MUST_BE_PROVIDED") - private String firstName; - - @NotEmpty(message = "LAST_NAME_MUST_BE_PROVIDED") - private String lastName; - - @NotEmpty(message = "EMAIL_NAME_MUST_BE_PROVIDED") - @Email(message = "NOT_A_VALID_EMAIL") - private String email; - - @AssertTrue(message = "USER_AGREEMENT_MUST_BE_ACCEPTED") - private boolean userAgreement; - - @Min(value = 2001, message = "ACCEPTANCE_YEAR_MUST_BE_AFTER_2001") - private int acceptanceYear; - - private Language language = Language.sv; - - public String getCid() { - return this.cid; - } - - public void setCid(String cid) { - this.cid = cid; - } - - public String getPassword() { - return this.password; - } - - public void setPassword(String password) { - this.password = password; - } - - public String getNick() { - return this.nick; - } - - public void setNick(String nick) { - this.nick = nick; - } - - public String getFirstName() { - return this.firstName; - } - - public void setFirstName(String firstName) { - this.firstName = firstName; - } - - public String getLastName() { - return this.lastName; - } - - public void setLastName(String lastName) { - this.lastName = lastName; - } - - public String getEmail() { - return this.email; - } - - public void setEmail(String email) { - this.email = email; - } - - public boolean isUserAgreement() { - return this.userAgreement; - } - - public void setUserAgreement(boolean userAgreement) { - this.userAgreement = userAgreement; - } - - public int getAcceptanceYear() { - return this.acceptanceYear; - } - - public void setAcceptanceYear(int acceptanceYear) { - this.acceptanceYear = acceptanceYear; - } - - public Language getLanguage() { - return this.language; - } - - public void setLanguage(Language language) { - this.language = language; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - AdminViewCreateITUserRequest that = (AdminViewCreateITUserRequest) o; - return this.userAgreement == that.userAgreement - && this.acceptanceYear == that.acceptanceYear - && Objects.equals(this.cid, that.cid) - && Objects.equals(this.password, that.password) - && Objects.equals(this.nick, that.nick) - && Objects.equals(this.firstName, that.firstName) - && Objects.equals(this.lastName, that.lastName) - && Objects.equals(this.email, that.email) - && this.language == that.language; - } - - @Override - public int hashCode() { - return Objects.hash(this.cid, - this.password, - this.nick, - this.firstName, - this.lastName, - this.email, - this.userAgreement, - this.acceptanceYear, - this.language); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/requests/ChangeGDPRStatusRequest.java b/backend/src/main/java/it/chalmers/gamma/requests/ChangeGDPRStatusRequest.java deleted file mode 100644 index ef41aab99..000000000 --- a/backend/src/main/java/it/chalmers/gamma/requests/ChangeGDPRStatusRequest.java +++ /dev/null @@ -1,39 +0,0 @@ -package it.chalmers.gamma.requests; - -import java.util.Objects; - -public class ChangeGDPRStatusRequest { - private boolean gdpr; - - public boolean isGdpr() { - return this.gdpr; - } - - public void setGdpr(boolean gdpr) { - this.gdpr = gdpr; - } - - @Override - public String toString() { - return "ChangeGDPRStatusRequest{" - + "gdpr=" + this.gdpr - + '}'; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - ChangeGDPRStatusRequest that = (ChangeGDPRStatusRequest) o; - return this.gdpr == that.gdpr; - } - - @Override - public int hashCode() { - return Objects.hash(this.gdpr); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/requests/ChangeUserPassword.java b/backend/src/main/java/it/chalmers/gamma/requests/ChangeUserPassword.java deleted file mode 100644 index 22bb61a9a..000000000 --- a/backend/src/main/java/it/chalmers/gamma/requests/ChangeUserPassword.java +++ /dev/null @@ -1,58 +0,0 @@ -package it.chalmers.gamma.requests; - -import java.util.Objects; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; - -public class ChangeUserPassword { - - @Size(min = 8, message = "OLD_PASSWORD_TOO_SHORT") - @NotNull(message = "OLD_PASSWORD_MUST_NOT_BE_NULL") - private String oldPassword; - - @Size(min = 8, message = "NEW_PASSWORD_TOO_SHORT") - @NotNull(message = "PASSWORD_MUST_NOT_BE_NULL") - private String password; - - public String getOldPassword() { - return this.oldPassword; - } - - public void setOldPassword(String oldPassword) { - this.oldPassword = oldPassword; - } - - public String getPassword() { - return this.password; - } - - public void setPassword(String password) { - this.password = password; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - ChangeUserPassword that = (ChangeUserPassword) o; - return Objects.equals(this.oldPassword, that.oldPassword) - && Objects.equals(this.password, that.password); - } - - @Override - public int hashCode() { - return Objects.hash(this.oldPassword, this.password); - } - - @Override - public String toString() { - return "ChangeUserPassword{" - + "oldPassword='" + this.oldPassword + '\'' - + ", password='" + this.password + '\'' - + '}'; - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/requests/CidPasswordRequest.java b/backend/src/main/java/it/chalmers/gamma/requests/CidPasswordRequest.java deleted file mode 100644 index f87547102..000000000 --- a/backend/src/main/java/it/chalmers/gamma/requests/CidPasswordRequest.java +++ /dev/null @@ -1,54 +0,0 @@ -package it.chalmers.gamma.requests; - -import java.util.Objects; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; - -public class CidPasswordRequest { - @NotNull(message = "CID_MUST_BE_PROVIDED") - private String cid; - @Size(min = 8, message = "PASSWORD_TOO_SHORT") - private String password; - - public String getCid() { - return this.cid; - } - - public void setCid(String cid) { - this.cid = cid; - } - - public String getPassword() { - return this.password; - } - - public void setPassword(String password) { - this.password = password; - } - - @Override - public String toString() { - return "CidPasswordRequest{" - + "cid='" + cid + '\'' - + ", password='[REDACTED]'" - + '}'; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - CidPasswordRequest that = (CidPasswordRequest) o; - return Objects.equals(this.cid, that.cid) - && Objects.equals(this.password, that.password); - } - - @Override - public int hashCode() { - return Objects.hash(this.cid, this.password); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/requests/CreateApiKeyRequest.java b/backend/src/main/java/it/chalmers/gamma/requests/CreateApiKeyRequest.java deleted file mode 100644 index 526de5439..000000000 --- a/backend/src/main/java/it/chalmers/gamma/requests/CreateApiKeyRequest.java +++ /dev/null @@ -1,57 +0,0 @@ -package it.chalmers.gamma.requests; - -import it.chalmers.gamma.db.entity.Text; - -import java.util.Objects; - -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; - -public class CreateApiKeyRequest { - @NotNull - @Size(min = 1, max = 30, message = "NAME_MUST_BE_BETWEEN_1_AND_30_CHARACTERS") - private String name; - private Text description; - - public String getName() { - return this.name; - } - - public void setName(String name) { - this.name = name; - } - - public Text getDescription() { - return this.description; - } - - public void setDescription(Text description) { - this.description = description; - } - - @Override - public String toString() { - return "CreateApiKeyRequest{" - + "name='" + this.name + '\'' - + ", description='" + this.description.toString() + '\'' - + '}'; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - CreateApiKeyRequest that = (CreateApiKeyRequest) o; - return Objects.equals(this.name, that.name) - && Objects.equals(this.description, that.description); - } - - @Override - public int hashCode() { - return Objects.hash(this.name, this.description); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/requests/CreateGroupRequest.java b/backend/src/main/java/it/chalmers/gamma/requests/CreateGroupRequest.java deleted file mode 100644 index 471dc1916..000000000 --- a/backend/src/main/java/it/chalmers/gamma/requests/CreateGroupRequest.java +++ /dev/null @@ -1,217 +0,0 @@ -package it.chalmers.gamma.requests; - -import it.chalmers.gamma.db.entity.Text; - -import java.util.Calendar; -import java.util.List; -import java.util.Objects; - -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; - -@SuppressWarnings("PMD.ExcessiveParameterList") -public class CreateGroupRequest { - - @NotNull(message = "NAME_MUST_BE_PROVIDED") - @Size(max = 50, message = "NAME_TOO_LONG") - private String name; - - @Size(max = 50, message = "PRETTY_NAME_TOO_LONG") - private String prettyName; - - private Text description; - - @NotNull(message = "A_FUNCTION_MUST_BE_PROVIDED") - private Text function; - private String avatarURL; - private List websites; - - @NotNull(message = "BECOMES_ACTIVE_MUST_BE_PROVIDED") // MORE SPECIFIC CHECK - private Calendar becomesActive; - - @NotNull(message = "BECOMES_INACTIVE_MUST_BE_PROVIDED") // MORE SPECIFIC CHECK - private Calendar becomesInactive; - - private String superGroup; - - private String email; - - public List getWebsites() { - return this.websites; - } - - public String getSuperGroup() { - return this.superGroup; - } - - public void setSuperGroup(String superGroup) { - this.superGroup = superGroup; - } - - public void setWebsites(List websites) { - this.websites = websites; - } - - public void setDescription(Text description) { - this.description = description; - } - - public Text getDescription() { - return this.description; - } - - public Text getFunction() { - return this.function; - } - - public void setFunction(Text function) { - this.function = function; - } - - public String getAvatarURL() { - return this.avatarURL; - } - - public void setAvatarURL(String avatarURL) { - this.avatarURL = avatarURL; - } - - public String getName() { - return this.name; - } - - public void setName(String name) { - this.name = name; - } - - public String getPrettyName() { - return this.prettyName; - } - - public void setPrettyName(String prettyName) { - this.prettyName = prettyName; - } - - public Calendar getBecomesActive() { - return this.becomesActive; - } - - public void setBecomesActive(Calendar becomesActive) { - this.becomesActive = becomesActive; - } - - public Calendar getBecomesInactive() { - return this.becomesInactive; - } - - public void setBecomesInactive(Calendar becomesInactive) { - this.becomesInactive = becomesInactive; - } - - public String getEmail() { - return this.email; - } - - public void setEmail(String email) { - this.email = email; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - CreateGroupRequest that = (CreateGroupRequest) o; - return Objects.equals(this.name, that.name) - && Objects.equals(this.prettyName, that.prettyName) - && Objects.equals(this.description, that.description) - && Objects.equals(this.function, that.function) - && Objects.equals(this.avatarURL, that.avatarURL) - && Objects.equals(this.websites, that.websites) - && Objects.equals(this.becomesActive, that.becomesActive) - && Objects.equals(this.becomesInactive, that.becomesInactive) - && Objects.equals(this.superGroup, that.superGroup) - && Objects.equals(this.email, that.email); - } - - @Override - public int hashCode() { - return Objects.hash(this.name, - this.prettyName, - this.description, - this.function, - this.avatarURL, - this.websites, - this.becomesActive, - this.becomesInactive, - this.superGroup, - this.email); - - } - - @Override - public String toString() { - return "CreateGroupRequest{" - + "name='" + this.name + '\'' - + ", prettyName='" + this.prettyName + '\'' - + ", description=" + this.description - + ", function=" + this.function - + ", avatarURL='" + this.avatarURL + '\'' - + ", websites=" + this.websites - + ", becomesActive=" + this.becomesActive - + ", becomesInactive=" + this.becomesInactive - + ", superGroup='" + this.superGroup + '\'' - + ", email='" + this.email + '\'' - + '}'; - } - - public static class WebsiteInfo { - String website; - String url; - - public String getWebsite() { - return this.website; - } - - public void setWebsite(String website) { - this.website = website; - } - - public String getUrl() { - return this.url; - } - - public void setUrl(String url) { - this.url = url; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - WebsiteInfo that = (WebsiteInfo) o; - return this.website.equals(that.website) - && this.url.equals(that.url); - } - - @Override - public int hashCode() { - return Objects.hash(this.website, this.url); - } - - @Override - public String toString() { - return "WebsiteInfo{" - + "website='" + this.website + '\'' - + ", url='" + this.url + '\'' - + '}'; - } - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/requests/CreateITUserRequest.java b/backend/src/main/java/it/chalmers/gamma/requests/CreateITUserRequest.java deleted file mode 100644 index 433de3c2a..000000000 --- a/backend/src/main/java/it/chalmers/gamma/requests/CreateITUserRequest.java +++ /dev/null @@ -1,180 +0,0 @@ -package it.chalmers.gamma.requests; - -import it.chalmers.gamma.domain.Language; - -import it.chalmers.gamma.domain.dto.user.WhitelistDTO; -import java.util.Objects; - -import javax.validation.constraints.AssertTrue; -import javax.validation.constraints.Email; -import javax.validation.constraints.Min; -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Pattern; -import javax.validation.constraints.Size; - - -public class CreateITUserRequest { - @NotEmpty(message = "CODE_MUST_BE_PROVIDED") - // TODO SPECIFY MINIMUM AND MAXIMUM LENGTH OF CODE - private String code; - - @NotEmpty(message = "PASSWORD_MUST_BE_PROVIDED") - @Size(min = 8, message = "PASSWORD_MUST_BE_MORE_THAN_8_CHARACTERS") - private String password; - - @NotEmpty(message = "NICK_MUST_BE_PROVIDED") - private String nick; - - @NotEmpty(message = "FIRST_NAME_MUST_BE_PROVIDED") - private String firstName; - - @NotEmpty(message = "EMAIL_REQUIRED") - @Email(message = "NON_EMAIL_ENTERED") - @Pattern(regexp = "^((?!@student.chalmers.se).)*$", message = "STUDENT_MAIL_ENTERED") - private String email; - - @NotEmpty(message = "LAST_NAME_MUST_BE_PROVIDED") - private String lastName; - - @AssertTrue(message = "USER_AGREEMENT_MUST_BE_ACCEPTED") - private boolean userAgreement; - - @Min(value = 2001, message = "ACCEPTANCE_YEAR_MUST_BE_AFTER_2001") - private int acceptanceYear; - - @NotNull(message = "WHITELIST_MUST_BE_PROVIDED") - private WhitelistDTO whitelist; - - private Language language = Language.sv; - - public WhitelistDTO getWhitelist() { - return this.whitelist; - } - - public void setWhitelist(WhitelistDTO whitelist) { - this.whitelist = whitelist; - } - - public String getCode() { - return this.code; - } - - public void setCode(String code) { - this.code = code; - } - - public String getPassword() { - return this.password; - } - - public void setPassword(String password) { - this.password = password; - } - - public String getNick() { - return this.nick; - } - - public void setNick(String nick) { - this.nick = nick; - } - - public String getFirstName() { - return this.firstName; - } - - public void setFirstName(String firstName) { - this.firstName = firstName; - } - - public String getLastName() { - return this.lastName; - } - - public void setLastName(String lastName) { - this.lastName = lastName; - } - - public boolean isUserAgreement() { - return this.userAgreement; - } - - public void setUserAgreement(boolean userAgreement) { - this.userAgreement = userAgreement; - } - - public int getAcceptanceYear() { - return this.acceptanceYear; - } - - public void setAcceptanceYear(int acceptanceYear) { - this.acceptanceYear = acceptanceYear; - } - - public Language getLanguage() { - return this.language; - } - - public void setLanguage(Language language) { - this.language = language; - } - - public String getEmail() { - return this.email; - } - - public void setEmail(String email) { - this.email = email; - } - - @Override - public String toString() { - return "CreateITUserRequest{" - + "code='" + this.code + '\'' - + ", password='" + this.password + '\'' - + ", nick='" + this.nick + '\'' - + ", firstName='" + this.firstName + '\'' - + ", lastName='" + this.lastName + '\'' - + ", userAgreement=" + this.userAgreement - + ", acceptanceYear=" + this.acceptanceYear - + ", whitelist=" + this.whitelist - + ", language=" + this.language - + '}'; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - CreateITUserRequest that = (CreateITUserRequest) o; - return this.userAgreement == that.userAgreement - && this.acceptanceYear == that.acceptanceYear - && Objects.equals(this.code, that.code) - && Objects.equals(this.password, that.password) - && Objects.equals(this.nick, that.nick) - && Objects.equals(this.firstName, that.firstName) - && Objects.equals(this.lastName, that.lastName) - && Objects.equals(this.whitelist, that.whitelist) - && this.language == that.language; - } - - @Override - public int hashCode() { - return Objects.hash(this.code, - this.password, - this.nick, - this.firstName, - this.lastName, - this.userAgreement, - this.acceptanceYear, - this.whitelist, - this.language); - } - - -} diff --git a/backend/src/main/java/it/chalmers/gamma/requests/CreateSuperGroupRequest.java b/backend/src/main/java/it/chalmers/gamma/requests/CreateSuperGroupRequest.java deleted file mode 100644 index e2a74e888..000000000 --- a/backend/src/main/java/it/chalmers/gamma/requests/CreateSuperGroupRequest.java +++ /dev/null @@ -1,91 +0,0 @@ -package it.chalmers.gamma.requests; - -import it.chalmers.gamma.domain.GroupType; - -import java.util.Objects; - -import javax.validation.constraints.Email; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; - - -public class CreateSuperGroupRequest { - - @NotNull(message = "NAME_MUST_BE_PROVIDED") - @Size(min = 2, max = 50, message = "NAME_MUST_BE_BETWEEN_2_AND_50_CHARACTERS") - private String name; - - @Size(max = 50, message = "PRETTY_NAME_TOO_LONG") - private String prettyName; - - @NotNull(message = "TYPE_MUST_BE_PROVIDED") - private GroupType type; - - @NotNull(message = "EMAIL_MUST_BE_PROVIDED") - @Email(message = "FIELD_EMAIL_DOES_NOT_MATCH_EMAIL_ADDRESS") - private String email; - - - public String getName() { - return this.name; - } - - public void setName(String name) { - this.name = name; - } - - public String getPrettyName() { - return this.prettyName; - } - - public void setPrettyName(String prettyName) { - this.prettyName = prettyName; - } - - public GroupType getType() { - return this.type; - } - - public void setType(GroupType type) { - this.type = type; - } - - public String getEmail() { - return this.email; - } - - public void setEmail(String email) { - this.email = email; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - CreateSuperGroupRequest that = (CreateSuperGroupRequest) o; - return Objects.equals(this.name, that.name) - && Objects.equals(this.prettyName, that.prettyName) - && this.type == that.type - && Objects.equals(this.email, that.email); - } - - @Override - public int hashCode() { - return Objects.hash(this.name, this.prettyName, this.type, this.email); - } - - @Override - public String toString() { - return "CreateSuperGroupRequest{" - + "name='" + this.name + '\'' - + ", prettyName='" + this.prettyName + '\'' - + ", type=" + this.type - + ", email='" + this.email + '\'' - + '}'; - } - -} diff --git a/backend/src/main/java/it/chalmers/gamma/requests/CreateWebsiteRequest.java b/backend/src/main/java/it/chalmers/gamma/requests/CreateWebsiteRequest.java deleted file mode 100644 index d4dd7ed2c..000000000 --- a/backend/src/main/java/it/chalmers/gamma/requests/CreateWebsiteRequest.java +++ /dev/null @@ -1,54 +0,0 @@ -package it.chalmers.gamma.requests; -import java.util.Objects; -import javax.validation.constraints.NotNull; - -public class CreateWebsiteRequest { - - @NotNull(message = "NAME_MUST_BE_PROVIDED") - private String name; - - @NotNull(message = "PRETTY_NAME_MUST_BE_PROVIDED") - private String prettyName; - - public void setName(String name) { - this.name = name; - } - - public void setPrettyName(String prettyName) { - this.prettyName = prettyName; - } - - public String getPrettyName() { - return this.prettyName; - } - - public String getName() { - return this.name; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - CreateWebsiteRequest that = (CreateWebsiteRequest) o; - return this.name.equals(that.name) - && this.prettyName.equals(that.prettyName); - } - - @Override - public int hashCode() { - return Objects.hash(this.name, this.prettyName); - } - - @Override - public String toString() { - return "CreateWebsiteRequest{" - + "name='" + this.name + '\'' - + ", prettyName='" + this.prettyName + '\'' - + '}'; - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/requests/DeleteGroupRequest.java b/backend/src/main/java/it/chalmers/gamma/requests/DeleteGroupRequest.java deleted file mode 100644 index 3bdb47fe7..000000000 --- a/backend/src/main/java/it/chalmers/gamma/requests/DeleteGroupRequest.java +++ /dev/null @@ -1,66 +0,0 @@ -package it.chalmers.gamma.requests; - -import java.util.Objects; -import javax.validation.constraints.NotNull; - -public class DeleteGroupRequest { // Unsure about this one - - @NotNull(message = "GROUP_MUST_BE_PROVIDED") - private String group; - - @NotNull(message = "NAME_MUST_BE_PROVIDED") - private String adminUser; - private String adminPassword; - - public String getGroup() { - return this.group; - } - - public void setGroup(String group) { - this.group = group; - } - - public String getAdminUser() { - return this.adminUser; - } - - public void setAdminUser(String adminUser) { - this.adminUser = adminUser; - } - - public String getAdminPassword() { - return this.adminPassword; - } - - public void setAdminPassword(String adminPassword) { - this.adminPassword = adminPassword; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - DeleteGroupRequest that = (DeleteGroupRequest) o; - return this.group.equals(that.group) - && this.adminUser.equals(that.adminUser) - && this.adminPassword.equals(that.adminPassword); - } - - @Override - public int hashCode() { - return Objects.hash(this.group, this.adminUser, this.adminPassword); - } - - @Override - public String toString() { - return "DeleteGroupRequest{" - + "group='" + this.group + '\'' - + ", adminUser='" + this.adminUser + '\'' - + ", adminPassword='" + this.adminPassword + '\'' - + '}'; - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/requests/DeleteMeRequest.java b/backend/src/main/java/it/chalmers/gamma/requests/DeleteMeRequest.java deleted file mode 100644 index 557434159..000000000 --- a/backend/src/main/java/it/chalmers/gamma/requests/DeleteMeRequest.java +++ /dev/null @@ -1,43 +0,0 @@ -package it.chalmers.gamma.requests; - -import java.util.Objects; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; - -public class DeleteMeRequest { - @NotNull(message = "PASSWORD_MUST_NOT_BE_NULL") - @Size(min = 8, message = "PASSWORD_TOO_SHORT") - private String password; - - public String getPassword() { - return this.password; - } - - public void setPassword(String password) { - this.password = password; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - DeleteMeRequest that = (DeleteMeRequest) o; - return Objects.equals(this.password, that.password); - } - - @Override - public int hashCode() { - return Objects.hash(this.password); - } - - @Override - public String toString() { - return "DeleteMeRequest{" - + "password='" + this.password + '\'' - + '}'; - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/requests/EditITUserRequest.java b/backend/src/main/java/it/chalmers/gamma/requests/EditITUserRequest.java deleted file mode 100644 index cf9691757..000000000 --- a/backend/src/main/java/it/chalmers/gamma/requests/EditITUserRequest.java +++ /dev/null @@ -1,117 +0,0 @@ -package it.chalmers.gamma.requests; - -import it.chalmers.gamma.domain.Language; -import java.util.List; -import java.util.Objects; - -public class EditITUserRequest { - private String nick; - private String firstName; - private String lastName; - private String email; - private String phone; - private Language language; - private int acceptanceYear; - private List websites; - - public void setNick(String nick) { - this.nick = nick; - } - - public void setFirstName(String firstName) { - this.firstName = firstName; - } - - public void setLastName(String lastName) { - this.lastName = lastName; - } - - public void setEmail(String email) { - this.email = email; - } - - public void setPhone(String phone) { - this.phone = phone; - } - - public void setLanguage(Language language) { - this.language = language; - } - - public List getWebsites() { - return this.websites; - } - - public void setWebsites(List websites) { - this.websites = websites; - } - - public void setAcceptanceYear(int acceptanceYear) { - this.acceptanceYear = acceptanceYear; - } - - public int getAcceptanceYear() { - return this.acceptanceYear; - } - - public String getNick() { - return this.nick; - } - - public String getFirstName() { - return this.firstName; - } - - public String getLastName() { - return this.lastName; - } - - public String getEmail() { - return this.email; - } - - public String getPhone() { - return this.phone; - } - - public Language getLanguage() { - return this.language; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - EditITUserRequest that = (EditITUserRequest) o; - return this.nick.equals(that.nick) - && this.firstName.equals(that.firstName) - && this.lastName.equals(that.lastName) - && this.email.equals(that.email) - && this.phone.equals(that.phone) - && this.language == that.language - && this.websites.equals(that.websites); - } - - @Override - public int hashCode() { - return Objects.hash(this.nick, this.firstName, this.lastName, this.email, - this.phone, this.language, this.websites); - } - - @Override - public String toString() { - return "EditITUserRequest{" - + "nick='" + this.nick + '\'' - + ", firstName='" + this.firstName + '\'' - + ", lastName='" + this.lastName + '\'' - + ", email='" + this.email + '\'' - + ", phone='" + this.phone + '\'' - + ", language=" + this.language - + ", websites=" + this.websites - + '}'; - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/requests/EditMembershipRequest.java b/backend/src/main/java/it/chalmers/gamma/requests/EditMembershipRequest.java deleted file mode 100644 index e627334d0..000000000 --- a/backend/src/main/java/it/chalmers/gamma/requests/EditMembershipRequest.java +++ /dev/null @@ -1,50 +0,0 @@ -package it.chalmers.gamma.requests; - -import java.util.Objects; - -public class EditMembershipRequest { - - private String post; - private String unofficialName; - - public String getPost() { - return this.post; - } - - public void setPost(String post) { - this.post = post; - } - - public String getUnofficialName() { - return this.unofficialName; - } - - public void setUnofficialName(String unofficialName) { - this.unofficialName = unofficialName; - } - - @Override - public String toString() { - return "EditMembershipRequest{" - + "unofficialName='" + this.unofficialName + '\'' - + "post='" + this.post + '\'' - + '}'; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - EditMembershipRequest that = (EditMembershipRequest) o; - return Objects.equals(this.unofficialName, that.unofficialName) && Objects.equals(this.post, that.post); - } - - @Override - public int hashCode() { - return Objects.hash(this.unofficialName, this.post); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/requests/ResetPasswordFinishRequest.java b/backend/src/main/java/it/chalmers/gamma/requests/ResetPasswordFinishRequest.java deleted file mode 100644 index 091cff37e..000000000 --- a/backend/src/main/java/it/chalmers/gamma/requests/ResetPasswordFinishRequest.java +++ /dev/null @@ -1,39 +0,0 @@ -package it.chalmers.gamma.requests; - -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; - -public class ResetPasswordFinishRequest { - @Size(min = 8, message = "NEW_PASSWORD_TOO_SHORT") - @NotNull(message = "NEW_PASSWORD_MUST_BE_PROVIDED") - private String password; - @NotEmpty(message = "CID_MUST_BE_PROVIDED") - private String cid; - @NotEmpty(message = "A_TOKEN_MUST_BE_PROVIDED") - private String token; - - public String getPassword() { - return this.password; - } - - public void setPassword(String password) { - this.password = password; - } - - public String getCid() { - return this.cid; - } - - public void setCid(String cid) { - this.cid = cid; - } - - public String getToken() { - return this.token; - } - - public void setToken(String token) { - this.token = token; - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/requests/ResetPasswordRequest.java b/backend/src/main/java/it/chalmers/gamma/requests/ResetPasswordRequest.java deleted file mode 100644 index 65c6ccc36..000000000 --- a/backend/src/main/java/it/chalmers/gamma/requests/ResetPasswordRequest.java +++ /dev/null @@ -1,39 +0,0 @@ -package it.chalmers.gamma.requests; - -import java.util.Objects; - -public class ResetPasswordRequest { - private String cid; - - public String getCid() { - return this.cid; - } - - public void setCid(String cid) { - this.cid = cid; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - ResetPasswordRequest that = (ResetPasswordRequest) o; - return this.cid.equals(that.cid); - } - - @Override - public int hashCode() { - return Objects.hash(this.cid); - } - - @Override - public String toString() { - return "ResetPasswordRequest{" - + "cid='" + this.cid + '\'' - + '}'; - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/requests/ValidateJwtRequest.java b/backend/src/main/java/it/chalmers/gamma/requests/ValidateJwtRequest.java deleted file mode 100644 index 88ba542be..000000000 --- a/backend/src/main/java/it/chalmers/gamma/requests/ValidateJwtRequest.java +++ /dev/null @@ -1,41 +0,0 @@ -package it.chalmers.gamma.requests; - -import java.util.Objects; -import javax.validation.constraints.NotEmpty; - -public class ValidateJwtRequest { - @NotEmpty(message = "JWT_MUST_BE_PROVIDED") - private String jwt; - - public String getJwt() { - return this.jwt; - } - - public void setJwt(String jwt) { - this.jwt = jwt; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - ValidateJwtRequest that = (ValidateJwtRequest) o; - return this.jwt.equals(that.jwt); - } - - @Override - public int hashCode() { - return Objects.hash(this.jwt); - } - - @Override - public String toString() { - return "ValidateJwtRequest{" - + "jwt='" + this.jwt + '\'' - + '}'; - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/requests/WhitelistCodeRequest.java b/backend/src/main/java/it/chalmers/gamma/requests/WhitelistCodeRequest.java deleted file mode 100644 index 959e97235..000000000 --- a/backend/src/main/java/it/chalmers/gamma/requests/WhitelistCodeRequest.java +++ /dev/null @@ -1,41 +0,0 @@ -package it.chalmers.gamma.requests; - -import java.util.Objects; -import javax.validation.constraints.NotEmpty; - -public class WhitelistCodeRequest { - @NotEmpty(message = "CID_MUST_BE_PROVIDED") - private String cid; - - public String getCid() { - return this.cid; - } - - public void setCid(String cid) { - this.cid = cid; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - WhitelistCodeRequest that = (WhitelistCodeRequest) o; - return this.cid.equals(that.cid); - } - - @Override - public int hashCode() { - return Objects.hash(this.cid); - } - - @Override - public String toString() { - return "WhitelistCodeRequest{" - + "cid='" + this.cid + '\'' - + '}'; - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/CodeExpiredResponse.java b/backend/src/main/java/it/chalmers/gamma/response/CodeExpiredResponse.java deleted file mode 100644 index 34e512b64..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/CodeExpiredResponse.java +++ /dev/null @@ -1,9 +0,0 @@ -package it.chalmers.gamma.response; - -import org.springframework.http.HttpStatus; - -public class CodeExpiredResponse extends CustomResponseStatusException { - public CodeExpiredResponse() { - super(HttpStatus.UNPROCESSABLE_ENTITY, "CODE_EXPIRED"); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/CodeOrCidIsWrongResponse.java b/backend/src/main/java/it/chalmers/gamma/response/CodeOrCidIsWrongResponse.java deleted file mode 100644 index 86588f676..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/CodeOrCidIsWrongResponse.java +++ /dev/null @@ -1,16 +0,0 @@ -package it.chalmers.gamma.response; - -import org.springframework.http.HttpStatus; -import org.springframework.web.server.ResponseStatusException; - -public class CodeOrCidIsWrongResponse extends ResponseStatusException { - @Override - public synchronized Throwable fillInStackTrace() { - return null; - } - - public CodeOrCidIsWrongResponse() { - super(HttpStatus.UNPROCESSABLE_ENTITY, "CODE_OR_CID_IS_WRONG"); - } - -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/CustomResponseStatusException.java b/backend/src/main/java/it/chalmers/gamma/response/CustomResponseStatusException.java deleted file mode 100644 index 442f0e856..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/CustomResponseStatusException.java +++ /dev/null @@ -1,30 +0,0 @@ -package it.chalmers.gamma.response; - -import java.util.Arrays; -import java.util.stream.Collectors; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.http.HttpStatus; -import org.springframework.web.server.ResponseStatusException; - -public class CustomResponseStatusException extends ResponseStatusException { - - private static final Logger LOGGER = LoggerFactory.getLogger(CustomResponseStatusException.class); - - public CustomResponseStatusException(HttpStatus status, String reason) { - super(status, reason); - LOGGER.error(String.format( - "An exception was thrown in the application: \n status: %d, \n Reason: %s", - status.value(), - reason)); - LOGGER.debug(String.format("Stacktrace: \n %s:", Arrays.stream(super.fillInStackTrace().getStackTrace()) - .map(StackTraceElement::toString).collect(Collectors.joining("\n ")))); - // Prints the stacktrace to debug - } - - @Override - public synchronized Throwable fillInStackTrace() { - return null; - } - -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/FileNotFoundResponse.java b/backend/src/main/java/it/chalmers/gamma/response/FileNotFoundResponse.java deleted file mode 100644 index e40e80579..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/FileNotFoundResponse.java +++ /dev/null @@ -1,9 +0,0 @@ -package it.chalmers.gamma.response; - -import org.springframework.http.HttpStatus; - -public class FileNotFoundResponse extends CustomResponseStatusException { - public FileNotFoundResponse() { - super(HttpStatus.NOT_FOUND, "FILE_NOT_FOUND"); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/FileNotSavedException.java b/backend/src/main/java/it/chalmers/gamma/response/FileNotSavedException.java deleted file mode 100644 index ec7d09ce7..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/FileNotSavedException.java +++ /dev/null @@ -1,9 +0,0 @@ -package it.chalmers.gamma.response; - -import org.springframework.http.HttpStatus; - -public class FileNotSavedException extends CustomResponseStatusException { - public FileNotSavedException() { - super(HttpStatus.UNPROCESSABLE_ENTITY, "FILE_COULD_NOT_BE_SAVED"); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/FileTooLargeResponse.java b/backend/src/main/java/it/chalmers/gamma/response/FileTooLargeResponse.java deleted file mode 100644 index 1d1dd3ad9..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/FileTooLargeResponse.java +++ /dev/null @@ -1,10 +0,0 @@ -package it.chalmers.gamma.response; - -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -public class FileTooLargeResponse extends ResponseEntity { - public FileTooLargeResponse() { - super("FILE_UPLOAD_TOO_LARGE", HttpStatus.PAYLOAD_TOO_LARGE); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/GetFileResponse.java b/backend/src/main/java/it/chalmers/gamma/response/GetFileResponse.java deleted file mode 100644 index 6def50a7c..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/GetFileResponse.java +++ /dev/null @@ -1,10 +0,0 @@ -package it.chalmers.gamma.response; - -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -public class GetFileResponse extends ResponseEntity { - public GetFileResponse(byte[] file) { - super(file, HttpStatus.OK); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/GoldappsReponse.java b/backend/src/main/java/it/chalmers/gamma/response/GoldappsReponse.java deleted file mode 100644 index aaf75d3b7..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/GoldappsReponse.java +++ /dev/null @@ -1,11 +0,0 @@ -package it.chalmers.gamma.response; - -import org.json.simple.JSONObject; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -public class GoldappsReponse extends ResponseEntity { - public GoldappsReponse(JSONObject body) { - super(body, HttpStatus.ACCEPTED); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/InputValidationFailedResponse.java b/backend/src/main/java/it/chalmers/gamma/response/InputValidationFailedResponse.java deleted file mode 100644 index 6b54af8c4..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/InputValidationFailedResponse.java +++ /dev/null @@ -1,10 +0,0 @@ -package it.chalmers.gamma.response; - -import org.springframework.http.HttpStatus; - -public class InputValidationFailedResponse extends CustomResponseStatusException { - - public InputValidationFailedResponse(String errors) { - super(HttpStatus.UNPROCESSABLE_ENTITY, errors); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/InvalidFileTypeResponse.java b/backend/src/main/java/it/chalmers/gamma/response/InvalidFileTypeResponse.java deleted file mode 100644 index 879b29875..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/InvalidFileTypeResponse.java +++ /dev/null @@ -1,9 +0,0 @@ -package it.chalmers.gamma.response; - -import org.springframework.http.HttpStatus; - -public class InvalidFileTypeResponse extends CustomResponseStatusException { - public InvalidFileTypeResponse() { - super(HttpStatus.UNSUPPORTED_MEDIA_TYPE, "INVALID_FILE_TYPE"); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/InvalidJWTTokenResponse.java b/backend/src/main/java/it/chalmers/gamma/response/InvalidJWTTokenResponse.java deleted file mode 100644 index 2ad225322..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/InvalidJWTTokenResponse.java +++ /dev/null @@ -1,11 +0,0 @@ -package it.chalmers.gamma.response; - -import org.springframework.http.HttpStatus; - -public class InvalidJWTTokenResponse extends CustomResponseStatusException { - - public InvalidJWTTokenResponse() { - super(HttpStatus.INTERNAL_SERVER_ERROR, "INVALID_JWT_TOKEN"); - } - -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/MissingRequiredFieldResponse.java b/backend/src/main/java/it/chalmers/gamma/response/MissingRequiredFieldResponse.java deleted file mode 100644 index a9b4475f5..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/MissingRequiredFieldResponse.java +++ /dev/null @@ -1,9 +0,0 @@ -package it.chalmers.gamma.response; - -import org.springframework.http.HttpStatus; - -public class MissingRequiredFieldResponse extends CustomResponseStatusException { - public MissingRequiredFieldResponse(String missingField) { - super(HttpStatus.UNPROCESSABLE_ENTITY, "MISSING_FIELD: " + missingField); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/ValidJwtResponse.java b/backend/src/main/java/it/chalmers/gamma/response/ValidJwtResponse.java deleted file mode 100644 index 656ab392d..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/ValidJwtResponse.java +++ /dev/null @@ -1,10 +0,0 @@ -package it.chalmers.gamma.response; - -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -public class ValidJwtResponse extends ResponseEntity { - public ValidJwtResponse(boolean isValid) { - super(isValid, HttpStatus.ACCEPTED); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/activationcode/ActivationCodeAddedResonse.java b/backend/src/main/java/it/chalmers/gamma/response/activationcode/ActivationCodeAddedResonse.java deleted file mode 100644 index 9275e7ec9..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/activationcode/ActivationCodeAddedResonse.java +++ /dev/null @@ -1,10 +0,0 @@ -package it.chalmers.gamma.response.activationcode; - -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -public class ActivationCodeAddedResonse extends ResponseEntity { - public ActivationCodeAddedResonse() { - super("ACTIVATION_CODE_ADDED", HttpStatus.ACCEPTED); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/activationcode/ActivationCodeDeletedResponse.java b/backend/src/main/java/it/chalmers/gamma/response/activationcode/ActivationCodeDeletedResponse.java deleted file mode 100644 index 4d8db89a8..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/activationcode/ActivationCodeDeletedResponse.java +++ /dev/null @@ -1,10 +0,0 @@ -package it.chalmers.gamma.response.activationcode; - -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -public class ActivationCodeDeletedResponse extends ResponseEntity { - public ActivationCodeDeletedResponse() { - super("ACTIVATION_CODE_DELETED", HttpStatus.ACCEPTED); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/activationcode/ActivationCodeDoesNotExistResponse.java b/backend/src/main/java/it/chalmers/gamma/response/activationcode/ActivationCodeDoesNotExistResponse.java deleted file mode 100644 index 3f69a239e..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/activationcode/ActivationCodeDoesNotExistResponse.java +++ /dev/null @@ -1,11 +0,0 @@ -package it.chalmers.gamma.response.activationcode; - -import it.chalmers.gamma.response.CustomResponseStatusException; -import org.springframework.http.HttpStatus; - -public class ActivationCodeDoesNotExistResponse extends CustomResponseStatusException { - - public ActivationCodeDoesNotExistResponse() { - super(HttpStatus.UNPROCESSABLE_ENTITY, "ACTIVATION_CODE_DOES_NOT_EXIST"); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/activationcode/GetActivationCodeResponse.java b/backend/src/main/java/it/chalmers/gamma/response/activationcode/GetActivationCodeResponse.java deleted file mode 100644 index 66776fe2f..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/activationcode/GetActivationCodeResponse.java +++ /dev/null @@ -1,29 +0,0 @@ -package it.chalmers.gamma.response.activationcode; - -import com.fasterxml.jackson.annotation.JsonUnwrapped; -import it.chalmers.gamma.domain.dto.user.ActivationCodeDTO; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -public class GetActivationCodeResponse { - @JsonUnwrapped - private final ActivationCodeDTO activationCode; - - public GetActivationCodeResponse(ActivationCodeDTO activationCode) { - this.activationCode = activationCode; - } - - public ActivationCodeDTO getActivationCode() { - return this.activationCode; - } - - public GetActivationCodeResponseObject toResponseObject() { - return new GetActivationCodeResponseObject(this); - } - - public static class GetActivationCodeResponseObject extends ResponseEntity { - GetActivationCodeResponseObject(GetActivationCodeResponse body) { - super(body, HttpStatus.OK); - } - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/activationcode/GetAllActivationCodesResponse.java b/backend/src/main/java/it/chalmers/gamma/response/activationcode/GetAllActivationCodesResponse.java deleted file mode 100644 index 262c0954c..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/activationcode/GetAllActivationCodesResponse.java +++ /dev/null @@ -1,30 +0,0 @@ -package it.chalmers.gamma.response.activationcode; - -import com.fasterxml.jackson.annotation.JsonValue; -import it.chalmers.gamma.domain.dto.user.ActivationCodeDTO; -import java.util.List; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -public class GetAllActivationCodesResponse { - @JsonValue - private final List activationCodes; - - public GetAllActivationCodesResponse(List activationCodes) { - this.activationCodes = activationCodes; - } - - public List getActivationCodes() { - return this.activationCodes; - } - - public GetAllActivationCodesResponseObject toResponseObject() { - return new GetAllActivationCodesResponseObject(this); - } - - public static class GetAllActivationCodesResponseObject extends ResponseEntity { - GetAllActivationCodesResponseObject(GetAllActivationCodesResponse body) { - super(body, HttpStatus.OK); - } - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/apikey/ApiKeyDeletedResponse.java b/backend/src/main/java/it/chalmers/gamma/response/apikey/ApiKeyDeletedResponse.java deleted file mode 100644 index 74e3e8218..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/apikey/ApiKeyDeletedResponse.java +++ /dev/null @@ -1,11 +0,0 @@ -package it.chalmers.gamma.response.apikey; - -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -public class ApiKeyDeletedResponse extends ResponseEntity { - - public ApiKeyDeletedResponse() { - super("API_KEY_DELETED", HttpStatus.ACCEPTED); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/apikey/ApiKeyDoesNotExistResponse.java b/backend/src/main/java/it/chalmers/gamma/response/apikey/ApiKeyDoesNotExistResponse.java deleted file mode 100644 index 011092c8a..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/apikey/ApiKeyDoesNotExistResponse.java +++ /dev/null @@ -1,11 +0,0 @@ -package it.chalmers.gamma.response.apikey; - -import it.chalmers.gamma.response.CustomResponseStatusException; -import org.springframework.http.HttpStatus; - -public class ApiKeyDoesNotExistResponse extends CustomResponseStatusException { - - public ApiKeyDoesNotExistResponse() { - super(HttpStatus.UNPROCESSABLE_ENTITY, "API_KEY_DOES_NOT_EXIST"); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/apikey/GetAllAPIKeysResponse.java b/backend/src/main/java/it/chalmers/gamma/response/apikey/GetAllAPIKeysResponse.java deleted file mode 100644 index 90f472f29..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/apikey/GetAllAPIKeysResponse.java +++ /dev/null @@ -1,33 +0,0 @@ -package it.chalmers.gamma.response.apikey; - -import com.fasterxml.jackson.annotation.JsonValue; -import it.chalmers.gamma.domain.dto.access.ApiKeyDTO; -import java.util.List; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - - -public class GetAllAPIKeysResponse { - @JsonValue - private final List apiKeys; - - - public GetAllAPIKeysResponse(List apiKeys) { - this.apiKeys = apiKeys; - } - - public List getApiKeys() { - return this.apiKeys; - } - - public GetAllAPIKeysResponseObject toResponseObject() { - return new GetAllAPIKeysResponseObject(this); - } - - public static class GetAllAPIKeysResponseObject extends ResponseEntity { - - GetAllAPIKeysResponseObject(GetAllAPIKeysResponse body) { - super(body, HttpStatus.OK); - } - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/apikey/GetApiKeyResponse.java b/backend/src/main/java/it/chalmers/gamma/response/apikey/GetApiKeyResponse.java deleted file mode 100644 index b1c75c935..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/apikey/GetApiKeyResponse.java +++ /dev/null @@ -1,31 +0,0 @@ -package it.chalmers.gamma.response.apikey; - -import com.fasterxml.jackson.annotation.JsonUnwrapped; -import it.chalmers.gamma.domain.dto.access.ApiKeyDTO; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -public class GetApiKeyResponse { - @JsonUnwrapped - private final ApiKeyDTO apiKey; - - - public GetApiKeyResponse(ApiKeyDTO apiKey) { - this.apiKey = apiKey; - } - - public ApiKeyDTO getApiKey() { - return this.apiKey; - } - - public GetApiKeyResponseObject toResponseObject() { - return new GetApiKeyResponseObject(this); - } - - public static class GetApiKeyResponseObject extends ResponseEntity { - - GetApiKeyResponseObject(GetApiKeyResponse response) { - super(response, HttpStatus.OK); - } - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/apikey/GetApiKeySecretResponse.java b/backend/src/main/java/it/chalmers/gamma/response/apikey/GetApiKeySecretResponse.java deleted file mode 100644 index 088eb1f56..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/apikey/GetApiKeySecretResponse.java +++ /dev/null @@ -1,31 +0,0 @@ -package it.chalmers.gamma.response.apikey; - -import com.fasterxml.jackson.annotation.JsonUnwrapped; - -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -public class GetApiKeySecretResponse { - - @JsonUnwrapped - private final String secret; - - public GetApiKeySecretResponse(String secret) { - this.secret = secret; - } - - public String getSecret() { - return this.secret; - } - - public GetApiKeySecretResponseObject toResponseObject() { - return new GetApiKeySecretResponseObject(this); - } - - public static class GetApiKeySecretResponseObject extends ResponseEntity { - GetApiKeySecretResponseObject(GetApiKeySecretResponse response) { - super(response, HttpStatus.OK); - } - } - -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/approval/GetAllITUserApprovalResponse.java b/backend/src/main/java/it/chalmers/gamma/response/approval/GetAllITUserApprovalResponse.java deleted file mode 100644 index cfd0f71d7..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/approval/GetAllITUserApprovalResponse.java +++ /dev/null @@ -1,35 +0,0 @@ -package it.chalmers.gamma.response.approval; - -import com.fasterxml.jackson.annotation.JsonValue; - -import it.chalmers.gamma.domain.dto.user.ITUserRestrictedDTO; - -import java.util.List; - -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -public class GetAllITUserApprovalResponse { - - @JsonValue - private final List users; - - public List getUsers() { - return this.users; - } - - public GetAllITUserApprovalResponse(List users) { - this.users = users; - } - - public GetAllITUserApprovalResponseObject toResponseObject() { - return new GetAllITUserApprovalResponseObject(this); - } - - public static class GetAllITUserApprovalResponseObject extends ResponseEntity { - GetAllITUserApprovalResponseObject(GetAllITUserApprovalResponse body) { - super(body, HttpStatus.OK); - } - } - -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/authority/AuthorityAddedResponse.java b/backend/src/main/java/it/chalmers/gamma/response/authority/AuthorityAddedResponse.java deleted file mode 100644 index 40e49857d..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/authority/AuthorityAddedResponse.java +++ /dev/null @@ -1,10 +0,0 @@ -package it.chalmers.gamma.response.authority; - -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -public class AuthorityAddedResponse extends ResponseEntity { - public AuthorityAddedResponse() { - super("AUTHORITY_ADDED", HttpStatus.ACCEPTED); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/authority/AuthorityDoesNotExistResponse.java b/backend/src/main/java/it/chalmers/gamma/response/authority/AuthorityDoesNotExistResponse.java deleted file mode 100644 index d8e47235c..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/authority/AuthorityDoesNotExistResponse.java +++ /dev/null @@ -1,11 +0,0 @@ -package it.chalmers.gamma.response.authority; - -import it.chalmers.gamma.response.CustomResponseStatusException; -import org.springframework.http.HttpStatus; - -public class AuthorityDoesNotExistResponse extends CustomResponseStatusException { - public AuthorityDoesNotExistResponse() { - super(HttpStatus.NOT_FOUND, - "AUTHORITY_DOES_NOT_EXIST"); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/authority/AuthorityLevelAddedResponse.java b/backend/src/main/java/it/chalmers/gamma/response/authority/AuthorityLevelAddedResponse.java deleted file mode 100644 index 9163ff5d2..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/authority/AuthorityLevelAddedResponse.java +++ /dev/null @@ -1,10 +0,0 @@ -package it.chalmers.gamma.response.authority; - -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -public class AuthorityLevelAddedResponse extends ResponseEntity { - public AuthorityLevelAddedResponse() { - super("AUTHORITY_LEVEL_ADDED", HttpStatus.ACCEPTED); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/authority/AuthorityLevelAlreadyExists.java b/backend/src/main/java/it/chalmers/gamma/response/authority/AuthorityLevelAlreadyExists.java deleted file mode 100644 index 69b973d0e..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/authority/AuthorityLevelAlreadyExists.java +++ /dev/null @@ -1,10 +0,0 @@ -package it.chalmers.gamma.response.authority; - -import it.chalmers.gamma.response.CustomResponseStatusException; -import org.springframework.http.HttpStatus; - -public class AuthorityLevelAlreadyExists extends CustomResponseStatusException { - public AuthorityLevelAlreadyExists() { - super(HttpStatus.UNPROCESSABLE_ENTITY, "AUTHORITY_LEVEL_ALREADY_EXISTS"); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/authority/AuthorityLevelDoesNotExistException.java b/backend/src/main/java/it/chalmers/gamma/response/authority/AuthorityLevelDoesNotExistException.java deleted file mode 100644 index 590ae6dd7..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/authority/AuthorityLevelDoesNotExistException.java +++ /dev/null @@ -1,10 +0,0 @@ -package it.chalmers.gamma.response.authority; - -import it.chalmers.gamma.response.CustomResponseStatusException; -import org.springframework.http.HttpStatus; - -public class AuthorityLevelDoesNotExistException extends CustomResponseStatusException { - public AuthorityLevelDoesNotExistException() { - super(HttpStatus.UNPROCESSABLE_ENTITY, "AUTHORITY_LEVEL_NOT_FOUND"); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/authority/AuthorityLevelRemovedResponse.java b/backend/src/main/java/it/chalmers/gamma/response/authority/AuthorityLevelRemovedResponse.java deleted file mode 100644 index fcc120e44..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/authority/AuthorityLevelRemovedResponse.java +++ /dev/null @@ -1,10 +0,0 @@ -package it.chalmers.gamma.response.authority; - -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -public class AuthorityLevelRemovedResponse extends ResponseEntity { - public AuthorityLevelRemovedResponse() { - super("AUTHORITY_LEVEL_REMOVED", HttpStatus.ACCEPTED); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/authority/AuthorityRemovedResponse.java b/backend/src/main/java/it/chalmers/gamma/response/authority/AuthorityRemovedResponse.java deleted file mode 100644 index 3115dea21..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/authority/AuthorityRemovedResponse.java +++ /dev/null @@ -1,11 +0,0 @@ -package it.chalmers.gamma.response.authority; - -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -public class AuthorityRemovedResponse extends ResponseEntity { - - public AuthorityRemovedResponse() { - super("REMOVED_AUTHORITY", HttpStatus.ACCEPTED); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/authority/GetAllAuthoritiesForLevelResponse.java b/backend/src/main/java/it/chalmers/gamma/response/authority/GetAllAuthoritiesForLevelResponse.java deleted file mode 100644 index 2133ba406..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/authority/GetAllAuthoritiesForLevelResponse.java +++ /dev/null @@ -1,38 +0,0 @@ -package it.chalmers.gamma.response.authority; - -import it.chalmers.gamma.domain.dto.authority.AuthorityDTO; - -import java.util.List; - -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -public class GetAllAuthoritiesForLevelResponse { - - private final List authorities; - private final String authorityLevel; - - public GetAllAuthoritiesForLevelResponse(List authorities, String authorityLevel) { - this.authorities = authorities; - this.authorityLevel = authorityLevel; - } - - public List getAuthorities() { - return this.authorities; - } - - public String getAuthorityLevel() { - return this.authorityLevel; - } - - public GetAllAuthoritiesForLevelResponseObject toResponseObject() { - return new GetAllAuthoritiesForLevelResponseObject(this); - } - - public static class GetAllAuthoritiesForLevelResponseObject - extends ResponseEntity { - GetAllAuthoritiesForLevelResponseObject(GetAllAuthoritiesForLevelResponse body) { - super(body, HttpStatus.ACCEPTED); - } - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/authority/GetAllAuthoritiesResponse.java b/backend/src/main/java/it/chalmers/gamma/response/authority/GetAllAuthoritiesResponse.java deleted file mode 100644 index 074a591a8..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/authority/GetAllAuthoritiesResponse.java +++ /dev/null @@ -1,30 +0,0 @@ -package it.chalmers.gamma.response.authority; - -import it.chalmers.gamma.domain.dto.authority.AuthorityDTO; -import java.util.List; - -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -public class GetAllAuthoritiesResponse { - - private final List authorities; - - public GetAllAuthoritiesResponse(List authorities) { - this.authorities = authorities; - } - - public List getAuthorities() { - return this.authorities; - } - - public GetAllAuthoritiesResponseObject toResponseObject() { - return new GetAllAuthoritiesResponseObject(this); - } - - public static class GetAllAuthoritiesResponseObject extends ResponseEntity { - GetAllAuthoritiesResponseObject(GetAllAuthoritiesResponse body) { - super(body, HttpStatus.ACCEPTED); - } - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/authority/GetAllAuthorityLevelsResponse.java b/backend/src/main/java/it/chalmers/gamma/response/authority/GetAllAuthorityLevelsResponse.java deleted file mode 100644 index bf37be0e5..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/authority/GetAllAuthorityLevelsResponse.java +++ /dev/null @@ -1,29 +0,0 @@ -package it.chalmers.gamma.response.authority; - -import it.chalmers.gamma.domain.dto.authority.AuthorityLevelDTO; - -import java.util.List; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -public class GetAllAuthorityLevelsResponse { - private final List authorityLevels; - - public GetAllAuthorityLevelsResponse(List authorityLevels) { - this.authorityLevels = authorityLevels; - } - - public List getAuthorityLevels() { - return this.authorityLevels; - } - - public GetAllAuthorityLevelsResponseObject toResponseObject() { - return new GetAllAuthorityLevelsResponseObject(this); - } - - public static class GetAllAuthorityLevelsResponseObject extends ResponseEntity { - GetAllAuthorityLevelsResponseObject(GetAllAuthorityLevelsResponse body) { - super(body, HttpStatus.OK); - } - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/authority/GetAuthorityResponse.java b/backend/src/main/java/it/chalmers/gamma/response/authority/GetAuthorityResponse.java deleted file mode 100644 index 64d63f945..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/authority/GetAuthorityResponse.java +++ /dev/null @@ -1,28 +0,0 @@ -package it.chalmers.gamma.response.authority; - -import it.chalmers.gamma.domain.dto.authority.AuthorityDTO; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -public class GetAuthorityResponse { - private final AuthorityDTO authority; - - - public GetAuthorityResponse(AuthorityDTO authority) { - this.authority = authority; - } - - public AuthorityDTO getAuthority() { - return this.authority; - } - - public GetAuthorityResponseObject toResponseObject() { - return new GetAuthorityResponseObject(this); - } - - public static class GetAuthorityResponseObject extends ResponseEntity { - GetAuthorityResponseObject(GetAuthorityResponse body) { - super(body, HttpStatus.OK); - } - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/client/ApprovedITClientsResponse.java b/backend/src/main/java/it/chalmers/gamma/response/client/ApprovedITClientsResponse.java deleted file mode 100644 index 9c6714d50..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/client/ApprovedITClientsResponse.java +++ /dev/null @@ -1,34 +0,0 @@ -package it.chalmers.gamma.response.client; - -import com.fasterxml.jackson.annotation.JsonValue; - -import it.chalmers.gamma.domain.dto.access.ITClientUserAccessDTO; - -import java.util.List; - -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -public class ApprovedITClientsResponse { - - @JsonValue - private final List clients; - - public ApprovedITClientsResponse(List clients) { - this.clients = clients; - } - - public List getClients() { - return this.clients; - } - - public ApprovedITClientsResponseObject toResponseObject() { - return new ApprovedITClientsResponseObject(this); - } - - public static class ApprovedITClientsResponseObject extends ResponseEntity { - ApprovedITClientsResponseObject(ApprovedITClientsResponse body) { - super(body, HttpStatus.OK); - } - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/client/ClientAddedResponse.java b/backend/src/main/java/it/chalmers/gamma/response/client/ClientAddedResponse.java deleted file mode 100644 index d4029d20d..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/client/ClientAddedResponse.java +++ /dev/null @@ -1,26 +0,0 @@ -package it.chalmers.gamma.response.client; - -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -public class ClientAddedResponse { - private final String clientSecret; - - public ClientAddedResponse(String secret) { - this.clientSecret = secret; - } - - public String getClientSecret() { - return this.clientSecret; - } - - public ClientAddedResponseObject toResponseObject() { - return new ClientAddedResponseObject(this); - } - - public static class ClientAddedResponseObject extends ResponseEntity { - ClientAddedResponseObject(ClientAddedResponse body) { - super(body, HttpStatus.ACCEPTED); - } - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/client/ClientEditedResponse.java b/backend/src/main/java/it/chalmers/gamma/response/client/ClientEditedResponse.java deleted file mode 100644 index 3788ef171..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/client/ClientEditedResponse.java +++ /dev/null @@ -1,11 +0,0 @@ -package it.chalmers.gamma.response.client; - -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -public class ClientEditedResponse extends ResponseEntity { - - public ClientEditedResponse() { - super("EDITED_CLIENT_RESPONSE", HttpStatus.ACCEPTED); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/client/GetAllClientsResponse.java b/backend/src/main/java/it/chalmers/gamma/response/client/GetAllClientsResponse.java deleted file mode 100644 index 74c26cbe7..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/client/GetAllClientsResponse.java +++ /dev/null @@ -1,30 +0,0 @@ -package it.chalmers.gamma.response.client; - -import com.fasterxml.jackson.annotation.JsonValue; -import it.chalmers.gamma.domain.dto.access.ITClientDTO; -import java.util.List; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -public class GetAllClientsResponse { - @JsonValue - private final List clients; - - public GetAllClientsResponse(List clients) { - this.clients = clients; - } - - public List getClients() { - return this.clients; - } - - public GetAllClientResponseObject toResponseObject() { - return new GetAllClientResponseObject(this); - } - - public static class GetAllClientResponseObject extends ResponseEntity { - GetAllClientResponseObject(GetAllClientsResponse body) { - super(body, HttpStatus.OK); - } - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/client/GetITClientResponse.java b/backend/src/main/java/it/chalmers/gamma/response/client/GetITClientResponse.java deleted file mode 100644 index be9a0c20f..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/client/GetITClientResponse.java +++ /dev/null @@ -1,29 +0,0 @@ -package it.chalmers.gamma.response.client; - -import com.fasterxml.jackson.annotation.JsonUnwrapped; -import it.chalmers.gamma.domain.dto.access.ITClientDTO; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -public class GetITClientResponse { - @JsonUnwrapped - private final ITClientDTO itClient; - - public GetITClientResponse(ITClientDTO itClient) { - this.itClient = itClient; - } - - public ITClientDTO getItClient() { - return this.itClient; - } - - public GetITClientResponseObject toResponseObject() { - return new GetITClientResponseObject(this); - } - - public static class GetITClientResponseObject extends ResponseEntity { - GetITClientResponseObject(GetITClientResponse body) { - super(body, HttpStatus.OK); - } - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/client/ITClientDoesNotExistException.java b/backend/src/main/java/it/chalmers/gamma/response/client/ITClientDoesNotExistException.java deleted file mode 100644 index 3847c73bb..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/client/ITClientDoesNotExistException.java +++ /dev/null @@ -1,10 +0,0 @@ -package it.chalmers.gamma.response.client; - -import it.chalmers.gamma.response.CustomResponseStatusException; -import org.springframework.http.HttpStatus; - -public class ITClientDoesNotExistException extends CustomResponseStatusException { - public ITClientDoesNotExistException() { - super(HttpStatus.UNPROCESSABLE_ENTITY, "NO_SUCH_CLIENT_EXISTS"); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/client/ITClientRemovedResponse.java b/backend/src/main/java/it/chalmers/gamma/response/client/ITClientRemovedResponse.java deleted file mode 100644 index e62fac882..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/client/ITClientRemovedResponse.java +++ /dev/null @@ -1,10 +0,0 @@ -package it.chalmers.gamma.response.client; - -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -public class ITClientRemovedResponse extends ResponseEntity { - public ITClientRemovedResponse() { - super("REMOVED_CLIENT", HttpStatus.OK); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/group/GetActiveFKITGroupsResponse.java b/backend/src/main/java/it/chalmers/gamma/response/group/GetActiveFKITGroupsResponse.java deleted file mode 100644 index a05f18b3d..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/group/GetActiveFKITGroupsResponse.java +++ /dev/null @@ -1,28 +0,0 @@ -package it.chalmers.gamma.response.group; - -import java.util.List; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -public class GetActiveFKITGroupsResponse { - private final List getFKITGroupResponse; - - public GetActiveFKITGroupsResponse(List getFKITGroupResponse) { - this.getFKITGroupResponse = getFKITGroupResponse; - } - - public List getGetFKITGroupResponse() { - return this.getFKITGroupResponse; - } - - public GetActiveFKITGroupResponseObject toResponseObject() { - return new GetActiveFKITGroupResponseObject(this); - } - - public static class GetActiveFKITGroupResponseObject extends ResponseEntity { - GetActiveFKITGroupResponseObject(GetActiveFKITGroupsResponse body) { - super(body, HttpStatus.OK); - } - } - -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/group/GetAllFKITGroupsMinifiedResponse.java b/backend/src/main/java/it/chalmers/gamma/response/group/GetAllFKITGroupsMinifiedResponse.java deleted file mode 100644 index d5ce30482..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/group/GetAllFKITGroupsMinifiedResponse.java +++ /dev/null @@ -1,30 +0,0 @@ -package it.chalmers.gamma.response.group; - -import com.fasterxml.jackson.annotation.JsonValue; -import java.util.List; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -public class GetAllFKITGroupsMinifiedResponse { - - private final List groups; - - public GetAllFKITGroupsMinifiedResponse(List groups) { - this.groups = groups; - } - @JsonValue - public List getGroups() { - return this.groups; - } - - public GetAllFKITGroupsMinifiedResponseObject toResponseObject() { - return new GetAllFKITGroupsMinifiedResponseObject(this); - } - - public static class GetAllFKITGroupsMinifiedResponseObject - extends ResponseEntity { - GetAllFKITGroupsMinifiedResponseObject(GetAllFKITGroupsMinifiedResponse body) { - super(body, HttpStatus.OK); - } - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/group/GetAllFKITGroupsResponse.java b/backend/src/main/java/it/chalmers/gamma/response/group/GetAllFKITGroupsResponse.java deleted file mode 100644 index 77f83beaf..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/group/GetAllFKITGroupsResponse.java +++ /dev/null @@ -1,29 +0,0 @@ -package it.chalmers.gamma.response.group; - -import com.fasterxml.jackson.annotation.JsonUnwrapped; -import java.util.List; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -public class GetAllFKITGroupsResponse { - @JsonUnwrapped - private final List groups; - - public GetAllFKITGroupsResponse(List groups) { - this.groups = groups; - } - - public List getGroups() { - return this.groups; - } - - public GetAllFKITGroupsResponseObject toResponseObject() { - return new GetAllFKITGroupsResponseObject(this); - } - - public static class GetAllFKITGroupsResponseObject extends ResponseEntity { - GetAllFKITGroupsResponseObject(GetAllFKITGroupsResponse body) { - super(body, HttpStatus.OK); - } - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/group/GetFKITGroupMinifiedResponse.java b/backend/src/main/java/it/chalmers/gamma/response/group/GetFKITGroupMinifiedResponse.java deleted file mode 100644 index 152e0f9b1..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/group/GetFKITGroupMinifiedResponse.java +++ /dev/null @@ -1,29 +0,0 @@ -package it.chalmers.gamma.response.group; - -import com.fasterxml.jackson.annotation.JsonUnwrapped; -import it.chalmers.gamma.domain.dto.group.FKITMinifiedGroupDTO; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -public class GetFKITGroupMinifiedResponse { - @JsonUnwrapped - private final FKITMinifiedGroupDTO group; - - public GetFKITGroupMinifiedResponse(FKITMinifiedGroupDTO group) { - this.group = group; - } - - public FKITMinifiedGroupDTO getGroup() { - return this.group; - } - - public GetFKITGroupMinifiedResponseObject toResponseObject() { - return new GetFKITGroupMinifiedResponseObject(this); - } - - public static class GetFKITGroupMinifiedResponseObject extends ResponseEntity { - GetFKITGroupMinifiedResponseObject(GetFKITGroupMinifiedResponse body) { - super(body, HttpStatus.OK); - } - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/group/GetFKITGroupResponse.java b/backend/src/main/java/it/chalmers/gamma/response/group/GetFKITGroupResponse.java deleted file mode 100644 index 07b58ee1b..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/group/GetFKITGroupResponse.java +++ /dev/null @@ -1,61 +0,0 @@ -package it.chalmers.gamma.response.group; - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonUnwrapped; -import it.chalmers.gamma.domain.dto.group.FKITGroupDTO; - -import it.chalmers.gamma.domain.dto.membership.NoAccountMembershipDTO; -import it.chalmers.gamma.domain.dto.membership.RestrictedMembershipDTO; -import it.chalmers.gamma.domain.dto.website.WebsiteUrlDTO; -import java.util.List; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -@JsonInclude(JsonInclude.Include.NON_NULL) -public class GetFKITGroupResponse { - @JsonUnwrapped - private final FKITGroupDTO group; - private final List groupMembers; - private final List noAccountMembers; - private final List websites; - - public GetFKITGroupResponse(FKITGroupDTO group, - List groupMembers, - List noAccountMembers, - List websites) { - this.group = group; - this.groupMembers = groupMembers; - this.noAccountMembers = noAccountMembers; - this.websites = websites; - } - - public GetFKITGroupResponse(FKITGroupDTO group, List groupMembers) { - this(group, groupMembers, null, null); - } - - public FKITGroupDTO getGroup() { - return this.group; - } - - public List getGroupMembers() { - return this.groupMembers; - } - - public List getNoAccountMembers() { - return this.noAccountMembers; - } - - public List getWebsites() { - return this.websites; - } - - public GetFKITGroupResponseObject toResponseObject() { - return new GetFKITGroupResponseObject(this); - } - - public static class GetFKITGroupResponseObject extends ResponseEntity { - public GetFKITGroupResponseObject(GetFKITGroupResponse body) { - super(body, HttpStatus.OK); - } - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/group/GetMembershipResponse.java b/backend/src/main/java/it/chalmers/gamma/response/group/GetMembershipResponse.java deleted file mode 100644 index dacf70451..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/group/GetMembershipResponse.java +++ /dev/null @@ -1,29 +0,0 @@ -package it.chalmers.gamma.response.group; - -import it.chalmers.gamma.domain.dto.membership.RestrictedMembershipDTO; - -import java.util.List; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -public class GetMembershipResponse { - public final List members; - - public GetMembershipResponse(List members) { - this.members = members; - } - - public List getMembers() { - return this.members; - } - - public GetMembershipResponseObject toResponseObject() { - return new GetMembershipResponseObject(this); - } - - public static class GetMembershipResponseObject extends ResponseEntity { - public GetMembershipResponseObject(GetMembershipResponse body) { - super(body, HttpStatus.OK); - } - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/group/GroupAlreadyExistsResponse.java b/backend/src/main/java/it/chalmers/gamma/response/group/GroupAlreadyExistsResponse.java deleted file mode 100644 index 0bbb0f30a..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/group/GroupAlreadyExistsResponse.java +++ /dev/null @@ -1,10 +0,0 @@ -package it.chalmers.gamma.response.group; - -import it.chalmers.gamma.response.CustomResponseStatusException; -import org.springframework.http.HttpStatus; - -public class GroupAlreadyExistsResponse extends CustomResponseStatusException { - public GroupAlreadyExistsResponse() { - super(HttpStatus.UNPROCESSABLE_ENTITY, "GROUP_ALREADY_EXISTS"); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/group/GroupCreatedResponse.java b/backend/src/main/java/it/chalmers/gamma/response/group/GroupCreatedResponse.java deleted file mode 100644 index 25db7aeba..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/group/GroupCreatedResponse.java +++ /dev/null @@ -1,11 +0,0 @@ -package it.chalmers.gamma.response.group; - -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -public class GroupCreatedResponse extends ResponseEntity { - - public GroupCreatedResponse() { - super("GROUP_CREATED", HttpStatus.ACCEPTED); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/group/GroupDeletedResponse.java b/backend/src/main/java/it/chalmers/gamma/response/group/GroupDeletedResponse.java deleted file mode 100644 index 904135495..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/group/GroupDeletedResponse.java +++ /dev/null @@ -1,10 +0,0 @@ -package it.chalmers.gamma.response.group; - -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -public class GroupDeletedResponse extends ResponseEntity { - public GroupDeletedResponse() { - super("DELETED_GROUP", HttpStatus.ACCEPTED); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/group/GroupDoesNotExistResponse.java b/backend/src/main/java/it/chalmers/gamma/response/group/GroupDoesNotExistResponse.java deleted file mode 100644 index 422805c31..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/group/GroupDoesNotExistResponse.java +++ /dev/null @@ -1,10 +0,0 @@ -package it.chalmers.gamma.response.group; - -import it.chalmers.gamma.response.CustomResponseStatusException; -import org.springframework.http.HttpStatus; - -public class GroupDoesNotExistResponse extends CustomResponseStatusException { - public GroupDoesNotExistResponse() { - super(HttpStatus.NOT_FOUND, "NO_SUCH_GROUP_EXISTS"); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/group/GroupEditedResponse.java b/backend/src/main/java/it/chalmers/gamma/response/group/GroupEditedResponse.java deleted file mode 100644 index 524ab2593..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/group/GroupEditedResponse.java +++ /dev/null @@ -1,10 +0,0 @@ -package it.chalmers.gamma.response.group; - -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -public class GroupEditedResponse extends ResponseEntity { - public GroupEditedResponse() { - super("GROUP_EDITED", HttpStatus.ACCEPTED); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/membership/EditedMembershipResponse.java b/backend/src/main/java/it/chalmers/gamma/response/membership/EditedMembershipResponse.java deleted file mode 100644 index 9af92093a..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/membership/EditedMembershipResponse.java +++ /dev/null @@ -1,10 +0,0 @@ -package it.chalmers.gamma.response.membership; - -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -public class EditedMembershipResponse extends ResponseEntity { - public EditedMembershipResponse() { - super("EDITED_MEMBERSHIP", HttpStatus.ACCEPTED); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/membership/MemberAddedToGroupResponse.java b/backend/src/main/java/it/chalmers/gamma/response/membership/MemberAddedToGroupResponse.java deleted file mode 100644 index 92d2b79cd..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/membership/MemberAddedToGroupResponse.java +++ /dev/null @@ -1,10 +0,0 @@ -package it.chalmers.gamma.response.membership; - -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -public class MemberAddedToGroupResponse extends ResponseEntity { - public MemberAddedToGroupResponse() { - super("USER_WAS_ADDED_TO_GROUP", HttpStatus.ACCEPTED); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/membership/MemberRemovedFromGroupResponse.java b/backend/src/main/java/it/chalmers/gamma/response/membership/MemberRemovedFromGroupResponse.java deleted file mode 100644 index 267356599..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/membership/MemberRemovedFromGroupResponse.java +++ /dev/null @@ -1,11 +0,0 @@ -package it.chalmers.gamma.response.membership; - -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -public class MemberRemovedFromGroupResponse extends ResponseEntity { - - public MemberRemovedFromGroupResponse() { - super("USER_REMOVED_FROM_GROUP", HttpStatus.OK); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/membership/MembershipDoesNotExistResponse.java b/backend/src/main/java/it/chalmers/gamma/response/membership/MembershipDoesNotExistResponse.java deleted file mode 100644 index 1bde3ebc2..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/membership/MembershipDoesNotExistResponse.java +++ /dev/null @@ -1,10 +0,0 @@ -package it.chalmers.gamma.response.membership; - -import it.chalmers.gamma.response.CustomResponseStatusException; -import org.springframework.http.HttpStatus; - -public class MembershipDoesNotExistResponse extends CustomResponseStatusException { - public MembershipDoesNotExistResponse() { - super(HttpStatus.UNPROCESSABLE_ENTITY, "MEMBERSHIP_DOES_NOT_EXIST"); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/post/GetMultiplePostsResponse.java b/backend/src/main/java/it/chalmers/gamma/response/post/GetMultiplePostsResponse.java deleted file mode 100644 index 66ba34a2d..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/post/GetMultiplePostsResponse.java +++ /dev/null @@ -1,31 +0,0 @@ -package it.chalmers.gamma.response.post; - -import com.fasterxml.jackson.annotation.JsonValue; -import java.util.List; - -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -public class GetMultiplePostsResponse { - @JsonValue - private final List getPostResponse; - - public GetMultiplePostsResponse(List getPostResponses) { - this.getPostResponse = getPostResponses; - } - - public List getGetPostResponse() { - return this.getPostResponse; - } - - public GetMultiplePostsResponseObject toResponseObject() { - return new GetMultiplePostsResponseObject(this); - } - - public static class GetMultiplePostsResponseObject extends ResponseEntity { - GetMultiplePostsResponseObject(GetMultiplePostsResponse body) { - super(body, HttpStatus.OK); - } - } -} - diff --git a/backend/src/main/java/it/chalmers/gamma/response/post/GetPostResponse.java b/backend/src/main/java/it/chalmers/gamma/response/post/GetPostResponse.java deleted file mode 100644 index df495e219..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/post/GetPostResponse.java +++ /dev/null @@ -1,29 +0,0 @@ -package it.chalmers.gamma.response.post; - -import com.fasterxml.jackson.annotation.JsonUnwrapped; -import it.chalmers.gamma.domain.dto.post.PostDTO; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -public class GetPostResponse { - @JsonUnwrapped - private final PostDTO post; - - public GetPostResponse(PostDTO post) { - this.post = post; - } - - public PostDTO getPost() { - return this.post; - } - - public GetPostResponseObject toResponseObject() { - return new GetPostResponseObject(this); - } - - public static class GetPostResponseObject extends ResponseEntity { - GetPostResponseObject(GetPostResponse body) { - super(body, HttpStatus.OK); - } - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/post/GetPostUsagesResponse.java b/backend/src/main/java/it/chalmers/gamma/response/post/GetPostUsagesResponse.java deleted file mode 100644 index 4da73276b..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/post/GetPostUsagesResponse.java +++ /dev/null @@ -1,30 +0,0 @@ -package it.chalmers.gamma.response.post; - -import com.fasterxml.jackson.annotation.JsonValue; -import it.chalmers.gamma.response.group.GetFKITGroupResponse; -import java.util.List; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -public class GetPostUsagesResponse { - @JsonValue - private final List fkitGroupResponses; - - public GetPostUsagesResponse(List fkitGroupResponses) { - this.fkitGroupResponses = fkitGroupResponses; - } - - public List getFkitGroupResponses() { - return this.fkitGroupResponses; - } - - public GetPostUsagesResponseObject toResponseObject() { - return new GetPostUsagesResponseObject(this); - } - - public static class GetPostUsagesResponseObject extends ResponseEntity { - GetPostUsagesResponseObject(GetPostUsagesResponse body) { - super(body, HttpStatus.OK); - } - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/post/PostAlreadyExistsResponse.java b/backend/src/main/java/it/chalmers/gamma/response/post/PostAlreadyExistsResponse.java deleted file mode 100644 index 5a2401b45..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/post/PostAlreadyExistsResponse.java +++ /dev/null @@ -1,11 +0,0 @@ -package it.chalmers.gamma.response.post; - -import it.chalmers.gamma.response.CustomResponseStatusException; -import org.springframework.http.HttpStatus; - -public class PostAlreadyExistsResponse extends CustomResponseStatusException { - - public PostAlreadyExistsResponse() { - super(HttpStatus.UNPROCESSABLE_ENTITY, "POST_ALREADY_EXISTS"); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/post/PostCreatedResponse.java b/backend/src/main/java/it/chalmers/gamma/response/post/PostCreatedResponse.java deleted file mode 100644 index 9c1f0409c..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/post/PostCreatedResponse.java +++ /dev/null @@ -1,10 +0,0 @@ -package it.chalmers.gamma.response.post; - -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -public class PostCreatedResponse extends ResponseEntity { - public PostCreatedResponse() { - super("POST_CREATED", HttpStatus.ACCEPTED); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/post/PostDeletedResponse.java b/backend/src/main/java/it/chalmers/gamma/response/post/PostDeletedResponse.java deleted file mode 100644 index 08b6892b5..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/post/PostDeletedResponse.java +++ /dev/null @@ -1,11 +0,0 @@ -package it.chalmers.gamma.response.post; - -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -public class PostDeletedResponse extends ResponseEntity { - - public PostDeletedResponse() { - super("POST_DELETED", HttpStatus.OK); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/post/PostDoesNotExistResponse.java b/backend/src/main/java/it/chalmers/gamma/response/post/PostDoesNotExistResponse.java deleted file mode 100644 index d3aea42e4..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/post/PostDoesNotExistResponse.java +++ /dev/null @@ -1,10 +0,0 @@ -package it.chalmers.gamma.response.post; - -import it.chalmers.gamma.response.CustomResponseStatusException; -import org.springframework.http.HttpStatus; - -public class PostDoesNotExistResponse extends CustomResponseStatusException { - public PostDoesNotExistResponse() { - super(HttpStatus.NOT_FOUND, "POST_DOES_NOT_EXIST"); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/post/PostEditedResponse.java b/backend/src/main/java/it/chalmers/gamma/response/post/PostEditedResponse.java deleted file mode 100644 index ef9e7761c..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/post/PostEditedResponse.java +++ /dev/null @@ -1,10 +0,0 @@ -package it.chalmers.gamma.response.post; - -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -public class PostEditedResponse extends ResponseEntity { - public PostEditedResponse() { - super("POST_EDITED", HttpStatus.ACCEPTED); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/post/PostIsInUseResponse.java b/backend/src/main/java/it/chalmers/gamma/response/post/PostIsInUseResponse.java deleted file mode 100644 index 601020090..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/post/PostIsInUseResponse.java +++ /dev/null @@ -1,10 +0,0 @@ -package it.chalmers.gamma.response.post; - -import it.chalmers.gamma.response.CustomResponseStatusException; -import org.springframework.http.HttpStatus; - -public class PostIsInUseResponse extends CustomResponseStatusException { - public PostIsInUseResponse() { - super(HttpStatus.NOT_ACCEPTABLE, "POST_IS_IN_USE"); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/supergroup/FKITSuperGroupCreatedResponse.java b/backend/src/main/java/it/chalmers/gamma/response/supergroup/FKITSuperGroupCreatedResponse.java deleted file mode 100644 index 97ae26b5c..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/supergroup/FKITSuperGroupCreatedResponse.java +++ /dev/null @@ -1,12 +0,0 @@ -package it.chalmers.gamma.response.supergroup; - -import it.chalmers.gamma.db.entity.FKITSuperGroup; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -public class FKITSuperGroupCreatedResponse extends ResponseEntity { - - public FKITSuperGroupCreatedResponse(FKITSuperGroup group) { - super(group, HttpStatus.ACCEPTED); - } -} \ No newline at end of file diff --git a/backend/src/main/java/it/chalmers/gamma/response/supergroup/GetAllSuperGroupsResponse.java b/backend/src/main/java/it/chalmers/gamma/response/supergroup/GetAllSuperGroupsResponse.java deleted file mode 100644 index 96eaf3a8a..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/supergroup/GetAllSuperGroupsResponse.java +++ /dev/null @@ -1,29 +0,0 @@ -package it.chalmers.gamma.response.supergroup; - -import com.fasterxml.jackson.annotation.JsonValue; -import java.util.List; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -public class GetAllSuperGroupsResponse { - @JsonValue - private final List superGroups; - - public GetAllSuperGroupsResponse(List superGroups) { - this.superGroups = superGroups; - } - - public List getSuperGroups() { - return this.superGroups; - } - - public GetAllSuperGroupsResponseObject toResponseObject() { - return new GetAllSuperGroupsResponseObject(this); - } - - public static class GetAllSuperGroupsResponseObject extends ResponseEntity { - GetAllSuperGroupsResponseObject(GetAllSuperGroupsResponse body) { - super(body, HttpStatus.OK); - } - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/supergroup/GetSuperGroupResponse.java b/backend/src/main/java/it/chalmers/gamma/response/supergroup/GetSuperGroupResponse.java deleted file mode 100644 index 2e3f8b167..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/supergroup/GetSuperGroupResponse.java +++ /dev/null @@ -1,30 +0,0 @@ -package it.chalmers.gamma.response.supergroup; - -import com.fasterxml.jackson.annotation.JsonUnwrapped; -import it.chalmers.gamma.domain.dto.group.FKITSuperGroupDTO; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -public class GetSuperGroupResponse { - @JsonUnwrapped - private final FKITSuperGroupDTO fkitSuperGroup; - - public GetSuperGroupResponse(FKITSuperGroupDTO fkitSuperGroup) { - this.fkitSuperGroup = fkitSuperGroup; - } - - public FKITSuperGroupDTO getFkitSuperGroup() { - return this.fkitSuperGroup; - } - - public GetSuperGroupResponseObject toResponseObject() { - return new GetSuperGroupResponseObject(this); - } - - public static class GetSuperGroupResponseObject extends ResponseEntity { - GetSuperGroupResponseObject(GetSuperGroupResponse body) { - super(body, HttpStatus.OK); - } - } -} - diff --git a/backend/src/main/java/it/chalmers/gamma/response/supergroup/RemoveSubGroupsBeforeRemovingSuperGroupResponse.java b/backend/src/main/java/it/chalmers/gamma/response/supergroup/RemoveSubGroupsBeforeRemovingSuperGroupResponse.java deleted file mode 100644 index c7ea6bd19..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/supergroup/RemoveSubGroupsBeforeRemovingSuperGroupResponse.java +++ /dev/null @@ -1,10 +0,0 @@ -package it.chalmers.gamma.response.supergroup; - -import it.chalmers.gamma.response.CustomResponseStatusException; -import org.springframework.http.HttpStatus; - -public class RemoveSubGroupsBeforeRemovingSuperGroupResponse extends CustomResponseStatusException { - public RemoveSubGroupsBeforeRemovingSuperGroupResponse() { - super(HttpStatus.EXPECTATION_FAILED, "REMOVE_SUB_GROUPS_BEFORE_REMOVING_SUPER_GROUP"); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/supergroup/SuperGroupDoesNotExistResponse.java b/backend/src/main/java/it/chalmers/gamma/response/supergroup/SuperGroupDoesNotExistResponse.java deleted file mode 100644 index 892e8bf8a..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/supergroup/SuperGroupDoesNotExistResponse.java +++ /dev/null @@ -1,10 +0,0 @@ -package it.chalmers.gamma.response.supergroup; - -import it.chalmers.gamma.response.CustomResponseStatusException; -import org.springframework.http.HttpStatus; - -public class SuperGroupDoesNotExistResponse extends CustomResponseStatusException { - public SuperGroupDoesNotExistResponse() { - super(HttpStatus.UNPROCESSABLE_ENTITY, "SUPER_GROUP_DOES_NOT_EXIST"); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/user/EditedProfilePictureResponse.java b/backend/src/main/java/it/chalmers/gamma/response/user/EditedProfilePictureResponse.java deleted file mode 100644 index 287df182f..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/user/EditedProfilePictureResponse.java +++ /dev/null @@ -1,10 +0,0 @@ -package it.chalmers.gamma.response.user; - -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -public class EditedProfilePictureResponse extends ResponseEntity { - public EditedProfilePictureResponse() { - super("EDITED_PROFILE_PICTURE", HttpStatus.ACCEPTED); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/user/GDPRStatusEditedResponse.java b/backend/src/main/java/it/chalmers/gamma/response/user/GDPRStatusEditedResponse.java deleted file mode 100644 index 0e95e8219..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/user/GDPRStatusEditedResponse.java +++ /dev/null @@ -1,11 +0,0 @@ -package it.chalmers.gamma.response.user; - -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -public class GDPRStatusEditedResponse extends ResponseEntity { - - public GDPRStatusEditedResponse() { - super("GDPREdited", HttpStatus.ACCEPTED); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/user/GetAllITUsersMinifiedResponse.java b/backend/src/main/java/it/chalmers/gamma/response/user/GetAllITUsersMinifiedResponse.java deleted file mode 100644 index 63a4eacda..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/user/GetAllITUsersMinifiedResponse.java +++ /dev/null @@ -1,30 +0,0 @@ -package it.chalmers.gamma.response.user; - -import com.fasterxml.jackson.annotation.JsonValue; -import java.util.List; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -public class GetAllITUsersMinifiedResponse { - - private final List users; - - public GetAllITUsersMinifiedResponse(List users) { - this.users = users; - } - - @JsonValue - public List getUsers() { - return this.users; - } - - public GetAllITUsersMinifiedResponseObject toResponseObject() { - return new GetAllITUsersMinifiedResponseObject(this); - } - - public static class GetAllITUsersMinifiedResponseObject extends ResponseEntity { - GetAllITUsersMinifiedResponseObject(GetAllITUsersMinifiedResponse body) { - super(body, HttpStatus.OK); - } - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/user/GetAllITUsersResponse.java b/backend/src/main/java/it/chalmers/gamma/response/user/GetAllITUsersResponse.java deleted file mode 100644 index 89a027de2..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/user/GetAllITUsersResponse.java +++ /dev/null @@ -1,29 +0,0 @@ -package it.chalmers.gamma.response.user; - -import com.fasterxml.jackson.annotation.JsonValue; -import java.util.List; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -public class GetAllITUsersResponse { - @JsonValue - private final List users; - - public GetAllITUsersResponse(List users) { - this.users = users; - } - - public List getUsers() { - return this.users; - } - - public GetAllITUsersResponseObject toResponseObject() { - return new GetAllITUsersResponseObject(this); - } - - public static class GetAllITUsersResponseObject extends ResponseEntity { - GetAllITUsersResponseObject(GetAllITUsersResponse body) { - super(body, HttpStatus.OK); - } - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/user/GetITUserMinifiedResponse.java b/backend/src/main/java/it/chalmers/gamma/response/user/GetITUserMinifiedResponse.java deleted file mode 100644 index 709ce9b27..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/user/GetITUserMinifiedResponse.java +++ /dev/null @@ -1,33 +0,0 @@ -package it.chalmers.gamma.response.user; - -import com.fasterxml.jackson.annotation.JsonUnwrapped; - -import it.chalmers.gamma.domain.dto.user.ITUserRestrictedDTO; - -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -public class GetITUserMinifiedResponse { - - @JsonUnwrapped - private final ITUserRestrictedDTO user; - - public GetITUserMinifiedResponse(ITUserRestrictedDTO user) { - this.user = user; - } - - @JsonUnwrapped - public ITUserRestrictedDTO getUser() { - return this.user; - } - - public GetITUserMinifiedResponseObject toResponseObject() { - return new GetITUserMinifiedResponseObject(this); - } - - public static class GetITUserMinifiedResponseObject extends ResponseEntity { - GetITUserMinifiedResponseObject(GetITUserMinifiedResponse body) { - super(body, HttpStatus.OK); - } - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/user/GetITUserResponse.java b/backend/src/main/java/it/chalmers/gamma/response/user/GetITUserResponse.java deleted file mode 100644 index 6a40eb48b..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/user/GetITUserResponse.java +++ /dev/null @@ -1,56 +0,0 @@ -package it.chalmers.gamma.response.user; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonUnwrapped; - -import it.chalmers.gamma.domain.dto.group.FKITGroupDTO; -import it.chalmers.gamma.domain.dto.user.ITUserDTO; -import it.chalmers.gamma.domain.dto.website.WebsiteUrlDTO; -import java.util.List; - -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -public class GetITUserResponse { - - @JsonUnwrapped - private final ITUserDTO user; - private final List groups; - private final List websiteURLs; - - public GetITUserResponse(ITUserDTO user, - List groups, - List websiteURLs) { - this.user = user; - this.groups = groups; - this.websiteURLs = websiteURLs; - } - - public GetITUserResponse(ITUserDTO user) { - this(user, null, null); - } - - @JsonUnwrapped - public ITUserDTO getUser() { - return this.user; - } - - public List getGroups() { - return this.groups; - } - - public List getWebsiteURLs() { - return this.websiteURLs; - } - - @JsonIgnore - public GetITUserResponseObject toResponseObject() { - return new GetITUserResponseObject(this); - } - - public static class GetITUserResponseObject extends ResponseEntity { - GetITUserResponseObject(GetITUserResponse body) { - super(body, HttpStatus.OK); - } - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/user/GetITUserRestrictedResponse.java b/backend/src/main/java/it/chalmers/gamma/response/user/GetITUserRestrictedResponse.java deleted file mode 100644 index 70034715e..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/user/GetITUserRestrictedResponse.java +++ /dev/null @@ -1,53 +0,0 @@ -package it.chalmers.gamma.response.user; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonUnwrapped; - -import it.chalmers.gamma.domain.dto.group.FKITGroupDTO; -import it.chalmers.gamma.domain.dto.user.ITUserRestrictedDTO; -import it.chalmers.gamma.domain.dto.website.WebsiteUrlDTO; - -import java.util.List; - -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -public class GetITUserRestrictedResponse { - - @JsonUnwrapped - private final ITUserRestrictedDTO user; - private final List groups; - private final List websiteURLs; - - public GetITUserRestrictedResponse( - ITUserRestrictedDTO user, - List groups, - List websiteURLs) { - this.user = user; - this.groups = groups; - this.websiteURLs = websiteURLs; - } - - public ITUserRestrictedDTO getUser() { - return this.user; - } - - public List getGroups() { - return this.groups; - } - - public List getWebsiteURLs() { - return this.websiteURLs; - } - - @JsonIgnore - public GetITUserRestrictedResponseObject toResponseObject() { - return new GetITUserRestrictedResponseObject(this); - } - - public static class GetITUserRestrictedResponseObject extends ResponseEntity { - GetITUserRestrictedResponseObject(GetITUserRestrictedResponse body) { - super(body, HttpStatus.OK); - } - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/user/IncorrectCidOrPasswordResponse.java b/backend/src/main/java/it/chalmers/gamma/response/user/IncorrectCidOrPasswordResponse.java deleted file mode 100644 index f690d9150..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/user/IncorrectCidOrPasswordResponse.java +++ /dev/null @@ -1,11 +0,0 @@ -package it.chalmers.gamma.response.user; - -import it.chalmers.gamma.response.CustomResponseStatusException; -import org.springframework.http.HttpStatus; - -public class IncorrectCidOrPasswordResponse extends CustomResponseStatusException { - public IncorrectCidOrPasswordResponse() { - super(HttpStatus.UNPROCESSABLE_ENTITY, "INCORRECT_CID_OR_PASSWORD"); - } - -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/user/PasswordChangedResponse.java b/backend/src/main/java/it/chalmers/gamma/response/user/PasswordChangedResponse.java deleted file mode 100644 index 4565b0a1a..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/user/PasswordChangedResponse.java +++ /dev/null @@ -1,10 +0,0 @@ -package it.chalmers.gamma.response.user; - -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -public class PasswordChangedResponse extends ResponseEntity { - public PasswordChangedResponse() { - super("PASSWORD_CHANGED", HttpStatus.ACCEPTED); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/user/PasswordResetResponse.java b/backend/src/main/java/it/chalmers/gamma/response/user/PasswordResetResponse.java deleted file mode 100644 index 4367be2be..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/user/PasswordResetResponse.java +++ /dev/null @@ -1,11 +0,0 @@ -package it.chalmers.gamma.response.user; - -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -public class PasswordResetResponse extends ResponseEntity { - - public PasswordResetResponse() { - super("PASSWORD_RESET_LINK_SENT", HttpStatus.ACCEPTED); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/user/PasswordTooShortResponse.java b/backend/src/main/java/it/chalmers/gamma/response/user/PasswordTooShortResponse.java deleted file mode 100644 index 1edd97362..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/user/PasswordTooShortResponse.java +++ /dev/null @@ -1,10 +0,0 @@ -package it.chalmers.gamma.response.user; - -import it.chalmers.gamma.response.CustomResponseStatusException; -import org.springframework.http.HttpStatus; - -public class PasswordTooShortResponse extends CustomResponseStatusException { - public PasswordTooShortResponse() { - super(HttpStatus.UNPROCESSABLE_ENTITY, "TOO_SHORT_PASSWORD"); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/user/UserAlreadyExistsResponse.java b/backend/src/main/java/it/chalmers/gamma/response/user/UserAlreadyExistsResponse.java deleted file mode 100644 index b4414c6f3..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/user/UserAlreadyExistsResponse.java +++ /dev/null @@ -1,10 +0,0 @@ -package it.chalmers.gamma.response.user; - -import it.chalmers.gamma.response.CustomResponseStatusException; -import org.springframework.http.HttpStatus; - -public class UserAlreadyExistsResponse extends CustomResponseStatusException { - public UserAlreadyExistsResponse() { - super(HttpStatus.UNPROCESSABLE_ENTITY, "USER_ALREADY_REGISTERED"); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/user/UserCreatedResponse.java b/backend/src/main/java/it/chalmers/gamma/response/user/UserCreatedResponse.java deleted file mode 100644 index 9dc542158..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/user/UserCreatedResponse.java +++ /dev/null @@ -1,12 +0,0 @@ -package it.chalmers.gamma.response.user; - -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -public class UserCreatedResponse extends ResponseEntity { - - public UserCreatedResponse() { - super("USER_CREATED", HttpStatus.ACCEPTED); - } - -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/user/UserDeletedResponse.java b/backend/src/main/java/it/chalmers/gamma/response/user/UserDeletedResponse.java deleted file mode 100644 index ad8d896ba..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/user/UserDeletedResponse.java +++ /dev/null @@ -1,10 +0,0 @@ -package it.chalmers.gamma.response.user; - -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -public class UserDeletedResponse extends ResponseEntity { - public UserDeletedResponse() { - super("USER_DELETED", HttpStatus.OK); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/user/UserEditedResponse.java b/backend/src/main/java/it/chalmers/gamma/response/user/UserEditedResponse.java deleted file mode 100644 index 404d937ea..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/user/UserEditedResponse.java +++ /dev/null @@ -1,10 +0,0 @@ -package it.chalmers.gamma.response.user; - -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -public class UserEditedResponse extends ResponseEntity { - public UserEditedResponse() { - super("USER_EDITED", HttpStatus.ACCEPTED); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/user/UserNotFoundResponse.java b/backend/src/main/java/it/chalmers/gamma/response/user/UserNotFoundResponse.java deleted file mode 100644 index 64f6fbc03..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/user/UserNotFoundResponse.java +++ /dev/null @@ -1,10 +0,0 @@ -package it.chalmers.gamma.response.user; - -import it.chalmers.gamma.response.CustomResponseStatusException; -import org.springframework.http.HttpStatus; - -public class UserNotFoundResponse extends CustomResponseStatusException { - public UserNotFoundResponse() { - super(HttpStatus.NOT_FOUND, "NO_USER_FOUND"); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/website/EditedWebsiteResponse.java b/backend/src/main/java/it/chalmers/gamma/response/website/EditedWebsiteResponse.java deleted file mode 100644 index 15b63799b..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/website/EditedWebsiteResponse.java +++ /dev/null @@ -1,10 +0,0 @@ -package it.chalmers.gamma.response.website; - -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -public class EditedWebsiteResponse extends ResponseEntity { - public EditedWebsiteResponse() { - super("EDITED_WEBSITE", HttpStatus.ACCEPTED); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/website/GetAllWebsitesResponse.java b/backend/src/main/java/it/chalmers/gamma/response/website/GetAllWebsitesResponse.java deleted file mode 100644 index a84a33904..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/website/GetAllWebsitesResponse.java +++ /dev/null @@ -1,30 +0,0 @@ -package it.chalmers.gamma.response.website; - -import com.fasterxml.jackson.annotation.JsonValue; - -import java.util.List; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -public class GetAllWebsitesResponse { - private final List websites; - - public GetAllWebsitesResponse(List websites) { - this.websites = websites; - } - - @JsonValue - public List getWebsites() { - return this.websites; - } - - public GetAllWebsitesResponseObject toResponseObject() { - return new GetAllWebsitesResponseObject(this); - } - - public static class GetAllWebsitesResponseObject extends ResponseEntity { - GetAllWebsitesResponseObject(GetAllWebsitesResponse body) { - super(body, HttpStatus.OK); - } - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/website/GetWebsiteResponse.java b/backend/src/main/java/it/chalmers/gamma/response/website/GetWebsiteResponse.java deleted file mode 100644 index 904a729cd..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/website/GetWebsiteResponse.java +++ /dev/null @@ -1,31 +0,0 @@ -package it.chalmers.gamma.response.website; - -import com.fasterxml.jackson.annotation.JsonUnwrapped; - -import it.chalmers.gamma.domain.dto.website.WebsiteDTO; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -public class GetWebsiteResponse { - - @JsonUnwrapped - private final WebsiteDTO website; - - public GetWebsiteResponse(WebsiteDTO website) { - this.website = website; - } - - public WebsiteDTO getWebsite() { - return this.website; - } - - public GetWebsiteResponseObject toResponseObject() { - return new GetWebsiteResponseObject(this); - } - - public static class GetWebsiteResponseObject extends ResponseEntity { - GetWebsiteResponseObject(GetWebsiteResponse body) { - super(body, HttpStatus.OK); - } - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/website/WebsiteAddedResponse.java b/backend/src/main/java/it/chalmers/gamma/response/website/WebsiteAddedResponse.java deleted file mode 100644 index 88685c760..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/website/WebsiteAddedResponse.java +++ /dev/null @@ -1,10 +0,0 @@ -package it.chalmers.gamma.response.website; - -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -public class WebsiteAddedResponse extends ResponseEntity { - public WebsiteAddedResponse() { - super("WEBSITE_ADDED", HttpStatus.ACCEPTED); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/website/WebsiteDeletedResponse.java b/backend/src/main/java/it/chalmers/gamma/response/website/WebsiteDeletedResponse.java deleted file mode 100644 index 556d445a4..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/website/WebsiteDeletedResponse.java +++ /dev/null @@ -1,10 +0,0 @@ -package it.chalmers.gamma.response.website; - -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -public class WebsiteDeletedResponse extends ResponseEntity { - public WebsiteDeletedResponse() { - super("DELETED_WEBSITE", HttpStatus.ACCEPTED); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/website/WebsiteNotFoundResponse.java b/backend/src/main/java/it/chalmers/gamma/response/website/WebsiteNotFoundResponse.java deleted file mode 100644 index 5652091b1..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/website/WebsiteNotFoundResponse.java +++ /dev/null @@ -1,11 +0,0 @@ -package it.chalmers.gamma.response.website; - -import it.chalmers.gamma.response.CustomResponseStatusException; -import org.springframework.http.HttpStatus; - -public class WebsiteNotFoundResponse extends CustomResponseStatusException { - - public WebsiteNotFoundResponse() { - super(HttpStatus.NOT_FOUND, "WEBSITE_NOT_FOUND"); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/whitelist/EditedWhitelistResponse.java b/backend/src/main/java/it/chalmers/gamma/response/whitelist/EditedWhitelistResponse.java deleted file mode 100644 index 2fdc72d14..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/whitelist/EditedWhitelistResponse.java +++ /dev/null @@ -1,10 +0,0 @@ -package it.chalmers.gamma.response.whitelist; - -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -public class EditedWhitelistResponse extends ResponseEntity { - public EditedWhitelistResponse() { - super("WHITELIST_EDITED", HttpStatus.ACCEPTED); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/whitelist/GetAllWhitelistResponse.java b/backend/src/main/java/it/chalmers/gamma/response/whitelist/GetAllWhitelistResponse.java deleted file mode 100644 index e38a717ec..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/whitelist/GetAllWhitelistResponse.java +++ /dev/null @@ -1,29 +0,0 @@ -package it.chalmers.gamma.response.whitelist; - -import com.fasterxml.jackson.annotation.JsonValue; -import java.util.List; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -public class GetAllWhitelistResponse { - @JsonValue - private final List whitelistResponses; - - public GetAllWhitelistResponse(List whitelistResponses) { - this.whitelistResponses = whitelistResponses; - } - - public List getWhitelistResponses() { - return this.whitelistResponses; - } - - public GetAllWhitelistResponseObject toResponseObject() { - return new GetAllWhitelistResponseObject(this); - } - - public static class GetAllWhitelistResponseObject extends ResponseEntity { - GetAllWhitelistResponseObject(GetAllWhitelistResponse body) { - super(body, HttpStatus.OK); - } - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/whitelist/GetWhitelistResponse.java b/backend/src/main/java/it/chalmers/gamma/response/whitelist/GetWhitelistResponse.java deleted file mode 100644 index f1bcf75a3..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/whitelist/GetWhitelistResponse.java +++ /dev/null @@ -1,29 +0,0 @@ -package it.chalmers.gamma.response.whitelist; - -import com.fasterxml.jackson.annotation.JsonUnwrapped; -import it.chalmers.gamma.domain.dto.user.WhitelistDTO; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -public class GetWhitelistResponse { - @JsonUnwrapped - private final WhitelistDTO whitelist; - - public GetWhitelistResponse(WhitelistDTO whitelist) { - this.whitelist = whitelist; - } - - public WhitelistDTO getWhitelist() { - return this.whitelist; - } - - public GetWhitelistResponseObject toResponseObject() { - return new GetWhitelistResponseObject(this); - } - - public static class GetWhitelistResponseObject extends ResponseEntity { - GetWhitelistResponseObject(GetWhitelistResponse body) { - super(body, HttpStatus.OK); - } - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/whitelist/WhitelistAddedResponse.java b/backend/src/main/java/it/chalmers/gamma/response/whitelist/WhitelistAddedResponse.java deleted file mode 100644 index ac524726b..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/whitelist/WhitelistAddedResponse.java +++ /dev/null @@ -1,12 +0,0 @@ -package it.chalmers.gamma.response.whitelist; - -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -public class WhitelistAddedResponse extends ResponseEntity { - - public WhitelistAddedResponse(int numAdded, int numTotal) { - super("Added" + numAdded + "of requested" + numTotal, HttpStatus.ACCEPTED); - } - -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/whitelist/WhitelistAlreadyAddedException.java b/backend/src/main/java/it/chalmers/gamma/response/whitelist/WhitelistAlreadyAddedException.java deleted file mode 100644 index 2267b974a..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/whitelist/WhitelistAlreadyAddedException.java +++ /dev/null @@ -1,11 +0,0 @@ -package it.chalmers.gamma.response.whitelist; - -import it.chalmers.gamma.response.CustomResponseStatusException; -import org.springframework.http.HttpStatus; - -public class WhitelistAlreadyAddedException extends CustomResponseStatusException { - - public WhitelistAlreadyAddedException() { - super(HttpStatus.UNPROCESSABLE_ENTITY, "CID_ALREADY_ADDED_TO_WHITELIST"); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/whitelist/WhitelistDoesNotExistsException.java b/backend/src/main/java/it/chalmers/gamma/response/whitelist/WhitelistDoesNotExistsException.java deleted file mode 100644 index 36e40a846..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/whitelist/WhitelistDoesNotExistsException.java +++ /dev/null @@ -1,10 +0,0 @@ -package it.chalmers.gamma.response.whitelist; - -import it.chalmers.gamma.response.CustomResponseStatusException; -import org.springframework.http.HttpStatus; - -public class WhitelistDoesNotExistsException extends CustomResponseStatusException { - public WhitelistDoesNotExistsException() { - super(HttpStatus.UNPROCESSABLE_ENTITY, "WHITELIST_DOES_NOT_EXIST"); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/response/whitelist/WhitelistIsValidResponse.java b/backend/src/main/java/it/chalmers/gamma/response/whitelist/WhitelistIsValidResponse.java deleted file mode 100644 index 4ac6ac92c..000000000 --- a/backend/src/main/java/it/chalmers/gamma/response/whitelist/WhitelistIsValidResponse.java +++ /dev/null @@ -1,26 +0,0 @@ -package it.chalmers.gamma.response.whitelist; - -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -public class WhitelistIsValidResponse { - private final Boolean valid; - - public WhitelistIsValidResponse(Boolean valid) { - this.valid = valid; - } - - public Boolean getValid() { - return this.valid; - } - - public WhitelistIsValidResponseObject toResponseObject() { - return new WhitelistIsValidResponseObject(this); - } - - public static class WhitelistIsValidResponseObject extends ResponseEntity { - WhitelistIsValidResponseObject(WhitelistIsValidResponse body) { - super(body, HttpStatus.OK); - } - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/service/ActivationCodeService.java b/backend/src/main/java/it/chalmers/gamma/service/ActivationCodeService.java deleted file mode 100644 index c757321eb..000000000 --- a/backend/src/main/java/it/chalmers/gamma/service/ActivationCodeService.java +++ /dev/null @@ -1,99 +0,0 @@ -package it.chalmers.gamma.service; - -import it.chalmers.gamma.db.entity.ActivationCode; -import it.chalmers.gamma.db.entity.Whitelist; -import it.chalmers.gamma.db.repository.ActivationCodeRepository; -import it.chalmers.gamma.domain.dto.user.ActivationCodeDTO; -import it.chalmers.gamma.domain.dto.user.WhitelistDTO; - -import it.chalmers.gamma.response.activationcode.ActivationCodeDoesNotExistResponse; -import it.chalmers.gamma.util.TokenUtils; -import it.chalmers.gamma.util.UUIDUtil; -import java.util.List; -import java.util.UUID; - -import java.util.stream.Collectors; -import javax.transaction.Transactional; -import org.springframework.stereotype.Service; - -@Service -@SuppressWarnings({"TooManyMethods"}) -public class ActivationCodeService { - - private final ActivationCodeRepository activationCodeRepository; - private final DTOToEntityService dtoToEntityService; - - public ActivationCodeService(ActivationCodeRepository activationCodeRepository, - DTOToEntityService dtoToEntityService) { - this.activationCodeRepository = activationCodeRepository; - this.dtoToEntityService = dtoToEntityService; - } - - /** - * connects and places a whitelisted user and a code in the database. - * - * @param whitelistDTO the information regarding the whitelistDTO - * @return a copy of the ActivationCode object added to the database - */ - public ActivationCodeDTO saveActivationCode(WhitelistDTO whitelistDTO) { - if (this.activationCodeRepository.existsActivationCodeByCid_Cid(whitelistDTO.getCid())) { - this.deleteCode(whitelistDTO.getCid()); - } - Whitelist whitelist = this.dtoToEntityService.fromDTO(whitelistDTO); - ActivationCode activationCode = new ActivationCode(whitelist); - activationCode.setCode(TokenUtils.generateToken(8, TokenUtils.CharacterTypes.NUMBERS)); - this.activationCodeRepository.save(activationCode); - return activationCode.toDTO(); - } - - public boolean codeMatches(String code, String user) { - ActivationCode activationCode = this.activationCodeRepository.findByCid_Cid(user) - .orElse(null); - if (activationCode == null) { - return false; - } - if (!activationCode.isValid()) { - deleteCode(activationCode.getId().toString()); - return false; - } - return activationCode.getCode().equals(code); - } - - @Transactional - public boolean deleteCode(String id) { - try { - ActivationCode activationCode = this.fromDTO(this.getActivationCodeDTO(id)); - this.activationCodeRepository.delete(activationCode); - return true; - } catch (ActivationCodeDoesNotExistResponse e) { - return false; - } - } - - public boolean codeExists(String id) { - if (UUIDUtil.validUUID(id)) { - return this.activationCodeRepository.existsById(UUID.fromString(id)); - } - return this.activationCodeRepository.existsActivationCodeByCid_Cid(id); - } - - public List getAllActivationCodes() { - return this.activationCodeRepository.findAll().stream() - .map(ActivationCode::toDTO).collect(Collectors.toList()); - } - - public ActivationCodeDTO getActivationCodeDTO(String id) { - if (UUIDUtil.validUUID(id)) { - return this.activationCodeRepository.findById(UUID.fromString(id)) - .map(ActivationCode::toDTO).orElse(null); - } else { - return this.activationCodeRepository.findByCid_Cid(id) - .map(ActivationCode::toDTO).orElseThrow(ActivationCodeDoesNotExistResponse::new); - } - } - - protected ActivationCode fromDTO(ActivationCodeDTO activationCodeDTO) { - return this.activationCodeRepository.findById(activationCodeDTO.getId()) - .orElseThrow(ActivationCodeDoesNotExistResponse::new); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/service/ApiKeyService.java b/backend/src/main/java/it/chalmers/gamma/service/ApiKeyService.java deleted file mode 100644 index d4a56eece..000000000 --- a/backend/src/main/java/it/chalmers/gamma/service/ApiKeyService.java +++ /dev/null @@ -1,68 +0,0 @@ -package it.chalmers.gamma.service; - -import it.chalmers.gamma.db.entity.ApiKey; -import it.chalmers.gamma.db.entity.Text; -import it.chalmers.gamma.db.repository.ApiKeyRepository; -import it.chalmers.gamma.domain.dto.access.ApiKeyDTO; -import it.chalmers.gamma.response.apikey.ApiKeyDoesNotExistResponse; -import it.chalmers.gamma.util.TokenUtils; - -import it.chalmers.gamma.util.UUIDUtil; -import java.util.List; -import java.util.UUID; - -import java.util.stream.Collectors; -import org.springframework.stereotype.Service; - -@Service -public class ApiKeyService { - - private final ApiKeyRepository apiKeyRepository; - - public ApiKeyService(ApiKeyRepository apiKeyRepository) { - this.apiKeyRepository = apiKeyRepository; - } - public boolean isValidApiKey(String apiKey) { - return this.apiKeyRepository.existsByKey(apiKey); - } - - public ApiKeyDTO createApiKey(ApiKeyDTO request) { - ApiKey apiKey = new ApiKey(); - Text description = new Text(); - description.setEn(request.getDescription().getEn()); - description.setSv(request.getDescription().getSv()); - apiKey.setName(request.getName()); - apiKey.setDescription(description); - String key = TokenUtils.generateToken(50, TokenUtils.CharacterTypes.LOWERCASE, - TokenUtils.CharacterTypes.UPPERCASE, - TokenUtils.CharacterTypes.NUMBERS); - apiKey.setKey(key); - return this.apiKeyRepository.save(apiKey).toDTO(); - } - - public void addApiKey(String clientName, String clientApiKey, Text description) { - ApiKey apiKey = new ApiKey(clientName, clientApiKey, description); - this.apiKeyRepository.save(apiKey); - } - - public ApiKeyDTO getApiKeyDetails(String name) { - if (UUIDUtil.validUUID(name)) { - return this.apiKeyRepository.findById(UUID.fromString(name)) - .orElseThrow(ApiKeyDoesNotExistResponse::new).toDTO(); - } - return this.apiKeyRepository.findByName(name) - .orElseThrow(ApiKeyDoesNotExistResponse::new).toDTO(); - } - - public void deleteApiKey(UUID id) { - this.apiKeyRepository.deleteById(id); - } - - public List getAllApiKeys() { - return this.apiKeyRepository.findAll().stream().map(ApiKey::toDTO).collect(Collectors.toList()); - } - - public boolean apiKeyExists(UUID id) { - return this.apiKeyRepository.existsById(id); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/service/AuthorityLevelService.java b/backend/src/main/java/it/chalmers/gamma/service/AuthorityLevelService.java deleted file mode 100644 index 105013925..000000000 --- a/backend/src/main/java/it/chalmers/gamma/service/AuthorityLevelService.java +++ /dev/null @@ -1,62 +0,0 @@ -package it.chalmers.gamma.service; - -import it.chalmers.gamma.db.entity.AuthorityLevel; -import it.chalmers.gamma.db.repository.AuthorityLevelRepository; - -import it.chalmers.gamma.domain.dto.authority.AuthorityLevelDTO; -import it.chalmers.gamma.response.authority.AuthorityLevelDoesNotExistException; -import it.chalmers.gamma.util.UUIDUtil; -import java.util.List; -import java.util.UUID; - -import java.util.stream.Collectors; -import javax.transaction.Transactional; -import org.springframework.stereotype.Service; - -@Service -public class AuthorityLevelService { - private final AuthorityLevelRepository authorityLevelRepository; - - public AuthorityLevelService(AuthorityLevelRepository authorityLevelRepository) { - this.authorityLevelRepository = authorityLevelRepository; - } - - public AuthorityLevelDTO addAuthorityLevel(String level) { - AuthorityLevel authorityLevel = new AuthorityLevel(); - authorityLevel.setAuthorityLevel(level); - this.authorityLevelRepository.save(authorityLevel); - return authorityLevel.toDTO(); - } - - public boolean authorityLevelExists(String authorityLevel) { - if (this.authorityLevelRepository.existsByAuthorityLevel(authorityLevel)) { - return true; - } - - return UUIDUtil.validUUID(authorityLevel) - && this.authorityLevelRepository.existsById(UUID.fromString(authorityLevel)); - } - - public AuthorityLevelDTO getAuthorityLevelDTO(String authorityLevel) { - if (UUIDUtil.validUUID(authorityLevel)) { - return this.authorityLevelRepository.findById(UUID.fromString(authorityLevel)) - .orElseThrow(AuthorityLevelDoesNotExistException::new).toDTO(); - } - return this.authorityLevelRepository.findByAuthorityLevel(authorityLevel.toLowerCase()) - .orElseThrow(AuthorityLevelDoesNotExistException::new).toDTO(); - } - - - public List getAllAuthorityLevels() { - return this.authorityLevelRepository.findAll().stream().map(AuthorityLevel::toDTO).collect(Collectors.toList()); - } - - @Transactional - public void removeAuthorityLevel(UUID id) { - this.authorityLevelRepository.deleteById(id); - } - - protected AuthorityLevel getAuthorityLevel(AuthorityLevelDTO authorityLevelDTO) { - return this.authorityLevelRepository.findById(authorityLevelDTO.getId()).orElse(null); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/service/AuthorityService.java b/backend/src/main/java/it/chalmers/gamma/service/AuthorityService.java deleted file mode 100644 index 268deedd7..000000000 --- a/backend/src/main/java/it/chalmers/gamma/service/AuthorityService.java +++ /dev/null @@ -1,161 +0,0 @@ -package it.chalmers.gamma.service; - -import it.chalmers.gamma.db.entity.Authority; -import it.chalmers.gamma.db.entity.AuthorityLevel; -import it.chalmers.gamma.db.entity.FKITSuperGroup; -import it.chalmers.gamma.db.entity.Post; -import it.chalmers.gamma.db.entity.pk.AuthorityPK; -import it.chalmers.gamma.db.repository.AuthorityRepository; -import it.chalmers.gamma.domain.dto.authority.AuthorityDTO; -import it.chalmers.gamma.domain.dto.authority.AuthorityLevelDTO; -import it.chalmers.gamma.domain.dto.group.FKITSuperGroupDTO; -import it.chalmers.gamma.domain.dto.membership.MembershipDTO; - -import it.chalmers.gamma.domain.dto.post.PostDTO; -import it.chalmers.gamma.domain.dto.user.ITUserDTO; -import it.chalmers.gamma.response.authority.AuthorityDoesNotExistResponse; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.List; -import java.util.UUID; - -import java.util.stream.Collectors; -import javax.transaction.Transactional; - -import org.springframework.security.core.GrantedAuthority; -import org.springframework.stereotype.Service; - -@Service -public class AuthorityService { - - private final AuthorityRepository authorityRepository; - private final FKITSuperGroupService fkitSuperGroupService; - private final PostService postService; - private final AuthorityLevelService authorityLevelService; - private final MembershipService membershipService; - - public AuthorityService(AuthorityRepository authorityRepository, - FKITSuperGroupService fkitSuperGroupService, - PostService postService, - AuthorityLevelService authorityLevelService, MembershipService membershipService) { - this.authorityRepository = authorityRepository; - this.fkitSuperGroupService = fkitSuperGroupService; - this.postService = postService; - this.authorityLevelService = authorityLevelService; - this.membershipService = membershipService; - } - - public AuthorityDTO createAuthority( - FKITSuperGroupDTO groupDTO, - PostDTO postDTO, - AuthorityLevelDTO authorityLevelDTO) { - - Post post = this.postService.getPost(postDTO); - FKITSuperGroup group = this.fkitSuperGroupService.getGroup(groupDTO); - AuthorityLevel authorityLevel = this.authorityLevelService.getAuthorityLevel(authorityLevelDTO); - Authority authority = this.authorityRepository.findById_FkitSuperGroupAndId_Post( - group, - post - ).orElseGet(() -> { - Authority auth = new Authority(); - AuthorityPK pk = new AuthorityPK(); - pk.setFkitGroup(group); - pk.setPost(post); - auth.setId(pk); - return auth; - }); - authority.setAuthorityLevel(authorityLevel); - return this.authorityRepository.save(authority).toDTO(); - } - protected List getGrantedAuthorities(ITUserDTO details) { - List memberships = this.membershipService.getMembershipsByUser(details); - // for (MembershipDTO membership : memberships) { - // AuthorityLevel authorityLevel = this.authorityLevelService - // .getAuthorityLevel(this.authorityLevelService.getAuthorityLevel( - // membership.getFkitGroupDTO().getId().toString())); - // if (authorityLevel != null) { - // authorities.add(authorityLevel); - // } - // } - return new ArrayList<>(this.getAuthorities(memberships)); - } - - - // TODO Check for name? - public boolean authorityExists(String id) { - return this.authorityRepository.existsByInternalId(UUID.fromString(id)); - } - - public AuthorityDTO getAuthorityLevel(FKITSuperGroupDTO groupDTO, PostDTO postDTO) { - FKITSuperGroup group = this.fkitSuperGroupService.getGroup(groupDTO); - Post post = this.postService.getPost(postDTO); - Authority authority = this.authorityRepository.findById_FkitSuperGroupAndId_Post(group, post) - .orElse(null); - if (authority != null) { - return authority.toDTO(); - } - return null; - } - - public void removeAuthority(FKITSuperGroupDTO groupDTO, PostDTO postDTO) { - FKITSuperGroup group = this.fkitSuperGroupService.getGroup(groupDTO); - Post post = this.postService.getPost(postDTO); - Authority authority = this.authorityRepository.findById_FkitSuperGroupAndId_Post(group, post) - .orElseThrow(AuthorityDoesNotExistResponse::new); - this.authorityRepository.delete(authority); - } - - @Transactional - public void removeAuthority(UUID id) { - this.authorityRepository.deleteByInternalId(id); - } - - public List getAuthorities(List memberships) { - List authorityLevels = new ArrayList<>(); - for (MembershipDTO membership : memberships) { - AuthorityDTO authority = this.getAuthorityLevel( - membership.getFkitGroupDTO().getSuperGroup(), - membership.getPost() - ); - - if (authority != null) { - Calendar start = membership.getFkitGroupDTO().getBecomesActive(); - Calendar end = membership.getFkitGroupDTO().getBecomesInactive(); - Calendar now = Calendar.getInstance(); - if (now.after(start) && now.before(end)) { - authorityLevels.add(authority.getAuthorityLevel()); - } - } - } - return authorityLevels; - } - - public List getAllAuthorities() { - return this.authorityRepository.findAll().stream().map(Authority::toDTO).collect(Collectors.toList()); - } - - public List getAllAuthoritiesWithAuthorityLevel(AuthorityLevelDTO authorityLevelDTO) { - AuthorityLevel authorityLevel = this.authorityLevelService.getAuthorityLevel(authorityLevelDTO); - return this.authorityRepository.findAllByAuthorityLevel(authorityLevel) - .stream().map(Authority::toDTO).collect(Collectors.toList()); - } - - public List getAuthoritiesWithLevel(UUID id) { - return this.authorityRepository.findAllByAuthorityLevel( - this.authorityLevelService.getAuthorityLevel( - this.authorityLevelService.getAuthorityLevelDTO(id.toString()))).stream() - .map(Authority::toDTO) - .collect(Collectors.toList()); - } - - public AuthorityDTO getAuthority(UUID id) { - return this.authorityRepository.findByInternalId(id) - .orElseThrow(AuthorityDoesNotExistResponse::new).toDTO(); - } - - @Transactional - public void removeAllAuthoritiesWithAuthorityLevel(AuthorityLevelDTO authorityLevelDTO) { - List authorities = this.getAllAuthoritiesWithAuthorityLevel(authorityLevelDTO); - authorities.forEach(a -> this.removeAuthority(a.getId())); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/service/DTOToEntityService.java b/backend/src/main/java/it/chalmers/gamma/service/DTOToEntityService.java deleted file mode 100644 index 859b12285..000000000 --- a/backend/src/main/java/it/chalmers/gamma/service/DTOToEntityService.java +++ /dev/null @@ -1,33 +0,0 @@ -package it.chalmers.gamma.service; - -import it.chalmers.gamma.db.entity.ITUser; -import it.chalmers.gamma.db.entity.Whitelist; -import it.chalmers.gamma.db.repository.ITUserRepository; -import it.chalmers.gamma.db.repository.WhitelistRepository; -import it.chalmers.gamma.domain.dto.user.ITUserDTO; -import it.chalmers.gamma.domain.dto.user.WhitelistDTO; -import it.chalmers.gamma.response.user.UserNotFoundResponse; -import it.chalmers.gamma.response.whitelist.WhitelistDoesNotExistsException; -import org.springframework.stereotype.Service; - -@Service -public class DTOToEntityService { - private final ITUserRepository itUserRepository; - private final WhitelistRepository whitelistRepository; - - public DTOToEntityService(ITUserRepository itUserRepository, WhitelistRepository whitelistRepository) { - this.itUserRepository = itUserRepository; - this.whitelistRepository = whitelistRepository; - } - - - protected ITUser fromDTO(ITUserDTO itUserDTO) { - return this.itUserRepository.findById(itUserDTO.getId()) - .orElseThrow(UserNotFoundResponse::new); - } - - protected Whitelist fromDTO(WhitelistDTO whitelistDTO) { - return this.whitelistRepository.findById(whitelistDTO.getId()) - .orElseThrow(WhitelistDoesNotExistsException::new); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/service/EntityWebsiteService.java b/backend/src/main/java/it/chalmers/gamma/service/EntityWebsiteService.java deleted file mode 100644 index 757bd483b..000000000 --- a/backend/src/main/java/it/chalmers/gamma/service/EntityWebsiteService.java +++ /dev/null @@ -1,60 +0,0 @@ -package it.chalmers.gamma.service; - -import org.springframework.stereotype.Service; - -@Service - -@SuppressWarnings({"PMD.UnusedPrivateField", "PMD.SingularField", "PMD.CommentSize"}) -public class EntityWebsiteService { - - private final WebsiteService websiteService; - - protected EntityWebsiteService(WebsiteService websiteService) { - this.websiteService = websiteService; - } - - /** - * gets all websites ordered after type I.E all facebook pages are subpages of type facebook - * - * @param websites a list of websites to be ordered - * @return a list of websites in an ordered fashion - */ - - // TODO I DONT THINK THIS FUNCTION ACCTUALLY DOES ANYTHING USEFULL - // Began rewriting it, but I'm unsure why I created it, leaving it for now. - /* public List getWebsitesOrdered(List websites) { - List groupedWebsites = new ArrayList<>(); - // gets a list of all websiteTypes that an entity has - List websiteTypes = websites.stream().map(w -> w.getWebsiteURL() - .getWebsiteDTO()).distinct().collect(Collectors.toList()); - - //loops through all websites added to group. - for (WebsiteInterfaceDTO website : websites) { - boolean websiteFound = false; - - //loops through all added website types. - for (int y = 0; y < websiteTypes.size(); y++) { - - // checks if the website has been added to found types. - if (websiteTypes.get(y).equals(website.getWebsiteURL())) { - - // if website has been found before the url - // is added to a list of websites connected to that. - groupedWebsites.get(y).getUrl().add(website.getWebsiteURL().getUrl()); - websiteFound = true; - } - } - if (!websiteFound) { - - // if the websitetype is not found, it is added. - websiteTypes.add(website.getWebsiteURL().getWebsite()); - WebsiteDTO newGroup = new WebsiteDTO(website.getWebsiteURL().getWebsite()); - newGroup.setUrl(new ArrayList<>()); - newGroup.getUrl().add(website.getWebsiteURL().getUrl()); - groupedWebsites.add(newGroup); - } - } - return groupedWebsites; - } -*/ -} diff --git a/backend/src/main/java/it/chalmers/gamma/service/FKITGroupService.java b/backend/src/main/java/it/chalmers/gamma/service/FKITGroupService.java deleted file mode 100644 index c173ad837..000000000 --- a/backend/src/main/java/it/chalmers/gamma/service/FKITGroupService.java +++ /dev/null @@ -1,137 +0,0 @@ -package it.chalmers.gamma.service; - -import it.chalmers.gamma.db.entity.FKITGroup; -import it.chalmers.gamma.db.repository.FKITGroupRepository; -import it.chalmers.gamma.domain.dto.group.FKITGroupDTO; - -import it.chalmers.gamma.domain.dto.group.FKITSuperGroupDTO; -import it.chalmers.gamma.response.group.GroupDoesNotExistResponse; -import it.chalmers.gamma.util.UUIDUtil; -import java.util.Calendar; -import java.util.List; -import java.util.UUID; -import java.util.stream.Collectors; - -import org.springframework.stereotype.Service; - -@Service -public class FKITGroupService { - - private final FKITGroupRepository repo; - - private final FKITSuperGroupService superGroupService; - - public FKITGroupService(FKITGroupRepository repo, FKITSuperGroupService superGroupService) { - - this.repo = repo; - this.superGroupService = superGroupService; - } - - - public FKITGroupDTO createGroup(FKITGroupDTO fkitGroupDTO) { - FKITGroup fkitGroup = new FKITGroup(); - UUID id = fkitGroupDTO.getId(); - if (id == null) { - id = UUID.randomUUID(); - } - fkitGroup.setId(id); - fkitGroup.setName(fkitGroupDTO.getName()); - fkitGroup.setFunction(fkitGroupDTO.getFunction()); - fkitGroup.setDescription(fkitGroupDTO.getDescription()); - return saveGroup(fkitGroup, - fkitGroup.getPrettyName() == null ? fkitGroupDTO.getName() : fkitGroupDTO.getPrettyName(), - fkitGroupDTO.getBecomesActive(), fkitGroupDTO.getBecomesInactive(), - fkitGroupDTO.getEmail(), fkitGroupDTO.getAvatarURL(), fkitGroupDTO.getSuperGroup()); - } - - public FKITGroupDTO editGroup(String id, FKITGroupDTO fkitGroupDTO) { - FKITGroup group = this.fromDTO(this.getGroup(id)); - if (group == null) { - return null; - } - group.getFunction().setSv(fkitGroupDTO.getFunction() == null - ? group.getFunction().getSv() : fkitGroupDTO.getFunction().getSv()); - - group.getFunction().setEn(fkitGroupDTO.getFunction() == null - ? group.getFunction().getEn() : fkitGroupDTO.getFunction().getEn()); - - if (fkitGroupDTO.getDescription() != null && group.getDescription() != null) { - group.getDescription().setSv(fkitGroupDTO.getDescription().getSv()); - group.getDescription().setEn(fkitGroupDTO.getDescription().getEn()); - } - return saveGroup(group, fkitGroupDTO.getPrettyName(), fkitGroupDTO.getBecomesActive(), - fkitGroupDTO.getBecomesInactive(), - fkitGroupDTO.getEmail(), fkitGroupDTO.getAvatarURL(), fkitGroupDTO.getSuperGroup()); - } - - private FKITGroupDTO saveGroup(FKITGroup group, String prettyName, - Calendar becomesActive, Calendar becomesInactive, - String email, String avatarURL, FKITSuperGroupDTO superGroup) { - group.setPrettyName(prettyName == null ? group.getPrettyName() : prettyName); - group.setEmail(email == null ? group.getEmail() : email); - group.setAvatarURL(avatarURL == null ? group.getAvatarURL() : avatarURL); - group.setBecomesActive(becomesActive == null ? group.getBecomesActive() : becomesActive); - group.setBecomesInactive(becomesInactive == null ? group.getBecomesInactive() : becomesInactive); - group.setSuperGroup(superGroup == null ? group.getSuperGroup() : this.superGroupService.getGroup(superGroup)); - return this.repo.save(group).toDTO(); - } - - public List getAllGroupsWithSuperGroup(FKITSuperGroupDTO superGroupDTO) { - return this.repo.findAllBySuperGroup(this.superGroupService.getGroup(superGroupDTO)).stream() - .map(FKITGroup::toDTO) - .collect(Collectors.toList()); - } - - public List getAllActiveGroups() { - return this.getGroups().stream().filter(FKITGroupDTO::isActive).collect(Collectors.toList()); - } - - public List getActiveGroups(FKITSuperGroupDTO superGroup) { - return this.getAllGroupsWithSuperGroup(superGroup).stream() - .filter(FKITGroupDTO::isActive) - .collect(Collectors.toList()); - } - - public boolean groupExists(String name) { - if (UUIDUtil.validUUID(name)) { - return this.repo.existsById(UUID.fromString(name)); - } - return this.repo.existsFKITGroupByName(name); - } - - public void removeGroup(String name) { - this.repo.deleteByName(name); - } - - public void removeGroup(UUID groupId) { - this.repo.deleteById(groupId); - } - - public List getGroups() { - return this.repo.findAll().stream().map(FKITGroup::toDTO).collect(Collectors.toList()); - } - - public FKITGroupDTO getGroup(String name) { - if (UUIDUtil.validUUID(name)) { - return this.repo.findById(UUID.fromString(name)) - .orElseThrow(GroupDoesNotExistResponse::new).toDTO(); - } - return this.repo.findByName(name.toLowerCase()) - .orElseThrow(GroupDoesNotExistResponse::new) - .toDTO(); - } - - public void editGroupAvatar(FKITGroupDTO groupDTO, String url) { - FKITGroup group = this.fromDTO(groupDTO); - if (group == null) { - throw new GroupDoesNotExistResponse(); - } - group.setAvatarURL(url); - this.repo.save(group); - } - - protected FKITGroup fromDTO(FKITGroupDTO group) { - return this.repo.findById(group.getId()).orElse(null); - } - -} diff --git a/backend/src/main/java/it/chalmers/gamma/service/FKITSuperGroupService.java b/backend/src/main/java/it/chalmers/gamma/service/FKITSuperGroupService.java deleted file mode 100644 index 6e7819c61..000000000 --- a/backend/src/main/java/it/chalmers/gamma/service/FKITSuperGroupService.java +++ /dev/null @@ -1,79 +0,0 @@ -package it.chalmers.gamma.service; - -import it.chalmers.gamma.db.entity.FKITSuperGroup; -import it.chalmers.gamma.db.repository.FKITSuperGroupRepository; -import it.chalmers.gamma.domain.GroupType; -import it.chalmers.gamma.domain.dto.group.FKITSuperGroupDTO; - -import it.chalmers.gamma.response.supergroup.SuperGroupDoesNotExistResponse; -import it.chalmers.gamma.util.UUIDUtil; -import java.util.List; -import java.util.Optional; -import java.util.UUID; -import java.util.stream.Collectors; - -import org.springframework.stereotype.Service; - -@Service -public class FKITSuperGroupService { - private final FKITSuperGroupRepository repository; - - public FKITSuperGroupService(FKITSuperGroupRepository repository) { - this.repository = repository; - } - - public FKITSuperGroupDTO createSuperGroup(FKITSuperGroupDTO superGroupDTO) { - FKITSuperGroup group = new FKITSuperGroup(); - UUID id = superGroupDTO.getId(); - if (id == null) { - id = UUID.randomUUID(); - } - group.setId(id); - group.setName(superGroupDTO.getName()); - group.setPrettyName(superGroupDTO.getPrettyName() == null - ? superGroupDTO.getName() : superGroupDTO.getPrettyName()); - group.setType(superGroupDTO.getType()); - group.setEmail(superGroupDTO.getEmail()); - return this.repository.save(group).toDTO(); - } - - public FKITSuperGroupDTO getGroupDTO(String id) { - if (UUIDUtil.validUUID(id)) { - return this.repository.findById(UUID.fromString(id)) - .orElseThrow(SuperGroupDoesNotExistResponse::new).toDTO(); - } - return this.repository.findByName(id.toLowerCase()) - .orElseThrow(SuperGroupDoesNotExistResponse::new).toDTO(); - } - - public boolean groupExists(String name) { - return this.repository.existsByName(name.toLowerCase()) - || UUIDUtil.validUUID(name) && this.repository.existsById(UUID.fromString(name)); - } - - public void removeGroup(UUID id) { - this.repository.deleteById(id); - } - - public List getAllGroups() { - return Optional.of(this.repository.findAll().stream() - .filter(g -> !g.getType().equals(GroupType.ADMIN)) - .map(FKITSuperGroup::toDTO) - .collect(Collectors.toList())).orElseThrow(); - } - - public void updateSuperGroup(UUID id, FKITSuperGroupDTO superGroupDTO) { - FKITSuperGroup group = this.getGroup(this.getGroupDTO(id.toString())); - group.setType(superGroupDTO.getType() == null ? group.getType() : superGroupDTO.getType()); - group.setName(superGroupDTO.getName() == null ? group.getName() : superGroupDTO.getName()); - group.setPrettyName(superGroupDTO.getPrettyName() == null - ? group.getPrettyName() : superGroupDTO.getPrettyName()); - group.setEmail(superGroupDTO.getEmail() == null ? group.getEmail() : superGroupDTO.getEmail()); - this.repository.save(group); - } - - protected FKITSuperGroup getGroup(FKITSuperGroupDTO group) { - return this.repository.findById(group.getId()) - .orElse(null); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/service/GroupWebsiteService.java b/backend/src/main/java/it/chalmers/gamma/service/GroupWebsiteService.java deleted file mode 100644 index 19a036758..000000000 --- a/backend/src/main/java/it/chalmers/gamma/service/GroupWebsiteService.java +++ /dev/null @@ -1,105 +0,0 @@ -package it.chalmers.gamma.service; - -import it.chalmers.gamma.db.entity.FKITGroup; -import it.chalmers.gamma.db.entity.GroupWebsite; -import it.chalmers.gamma.db.entity.Website; -import it.chalmers.gamma.db.entity.WebsiteURL; -import it.chalmers.gamma.db.repository.GroupWebsiteRepository; -import it.chalmers.gamma.domain.dto.group.FKITGroupDTO; - -import it.chalmers.gamma.domain.dto.website.GroupWebsiteDTO; -import it.chalmers.gamma.domain.dto.website.WebsiteDTO; -import it.chalmers.gamma.domain.dto.website.WebsiteInterfaceDTO; -import it.chalmers.gamma.domain.dto.website.WebsiteUrlDTO; -import java.util.List; -import java.util.UUID; - -import java.util.stream.Collectors; -import javax.transaction.Transactional; - -import org.springframework.dao.DataIntegrityViolationException; -import org.springframework.stereotype.Service; - -/* - * @ł€®®þþ←↓→œþªßðđŋħ̡ĸłøæ«»©“”nµ̣ΩŁ¢®Þ¥↑↑ıŒÞ§ÐªŊĦ̛&ŁØ<>©‘’Nº - * Type this in the url for a secret.... If I don't forget.... in that case f me. right - * Nobody will ever know this is here cause no-one will ever look at this code. - */ - -@Service -public class GroupWebsiteService extends EntityWebsiteService { - - private final GroupWebsiteRepository repository; - private final FKITGroupService fkitGroupService; - private final WebsiteURLService websiteURLService; - private final WebsiteService websiteService; - - public GroupWebsiteService(GroupWebsiteRepository repository, - WebsiteService websiteService, FKITGroupService fkitGroupService, - WebsiteURLService websiteURLService, WebsiteService websiteService1) { - super(websiteService); - this.repository = repository; - this.fkitGroupService = fkitGroupService; - this.websiteURLService = websiteURLService; - this.websiteService = websiteService1; - } - - public void addGroupWebsites(FKITGroupDTO groupDTO, List websiteUrlDTOS) { - if (websiteUrlDTOS == null || groupDTO == null) { - return; - } - boolean error = false; - for (WebsiteUrlDTO websiteUrlDTO : websiteUrlDTOS) { - if (websiteUrlDTO.getWebsiteDTO() == null || websiteUrlDTO.getUrl() == null) { - error = true; - continue; - } - FKITGroup group = this.fkitGroupService.fromDTO(groupDTO); - WebsiteURL websiteURL = this.websiteURLService.getWebsiteURL(websiteUrlDTO); - GroupWebsite groupWebsite = new GroupWebsite(); - groupWebsite.setGroup(group); - groupWebsite.setWebsite(websiteURL); - this.repository.save(groupWebsite); - } - if (error) { - throw new DataIntegrityViolationException("A SQL Constraint was violated"); - } - } - - @Transactional - public void deleteGroupWebsiteByWebsite(WebsiteDTO websiteDTO) { - Website website = this.websiteService.getWebsite(websiteDTO); - this.repository.deleteAllByWebsite_Website(website); - } - - public List getAllGroupWebsites() { - return this.repository.findAll().stream().map(GroupWebsite::toDTO).collect(Collectors.toList()); - } - - public GroupWebsiteDTO getGroupWebsiteById(String id) { - return this.repository.findById(UUID.fromString(id)).map(GroupWebsite::toDTO).orElse(null); - } - - public void deleteGroupWebsite(String id) { - - } - - public List getWebsites(FKITGroupDTO group) { - return this.repository.findAllByGroup(this.fkitGroupService.fromDTO(group)).stream() - .map(GroupWebsite::toDTO).collect(Collectors.toList()); - } - - public GroupWebsiteDTO getGroupWebsiteByWebsite(WebsiteDTO websiteDTO) { - return this.repository.findByWebsite_Website(this.websiteService.getWebsite(websiteDTO)).toDTO(); - } - - @Transactional - public void deleteWebsitesConnectedToGroup(FKITGroupDTO group) { - this.repository.deleteAllByGroup(this.fkitGroupService.fromDTO(group)); - } - - protected GroupWebsiteDTO getGroupWebsite(GroupWebsiteDTO websiteDTO) { - return this.repository.findById(websiteDTO.getId()).map(GroupWebsite::toDTO).orElse(null); - } - -} diff --git a/backend/src/main/java/it/chalmers/gamma/service/ITClientService.java b/backend/src/main/java/it/chalmers/gamma/service/ITClientService.java deleted file mode 100644 index cdfa23541..000000000 --- a/backend/src/main/java/it/chalmers/gamma/service/ITClientService.java +++ /dev/null @@ -1,103 +0,0 @@ -package it.chalmers.gamma.service; - -import it.chalmers.gamma.db.entity.ITClient; -import it.chalmers.gamma.db.entity.Text; -import it.chalmers.gamma.db.repository.ITClientRepository; -import it.chalmers.gamma.domain.dto.access.ITClientDTO; -import it.chalmers.gamma.response.client.ITClientDoesNotExistException; -import it.chalmers.gamma.util.TokenUtils; - -import it.chalmers.gamma.util.UUIDUtil; -import java.time.Instant; -import java.util.List; -import java.util.Optional; -import java.util.UUID; - -import java.util.stream.Collectors; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.security.oauth2.provider.ClientDetails; -import org.springframework.security.oauth2.provider.ClientDetailsService; -import org.springframework.stereotype.Service; - -@Service -public class ITClientService implements ClientDetailsService { - - @Value("${application.auth.accessTokenValidityTime}") // TODO Fix this - private int accessTokenValidityTime; - - @Value("${application.auth.refreshTokenValidityTime}") - private int refreshTokenValidityTime; - - private final ITClientRepository itClientRepository; - - public ITClientService(ITClientRepository itClientRepository) { - this.itClientRepository = itClientRepository; - } - - @Override - public ClientDetails loadClientByClientId(String clientId) { - return this.itClientRepository.findByClientId(clientId).orElseThrow(ITClientDoesNotExistException::new) - .toDTO(); - } - - public ITClientDTO createITClient(String name, Text description, String redirect, boolean autoApprove) { - ITClient client = new ITClient(); - client.setName(name); - client.setDescription(description == null ? new Text() : description); - client.setWebServerRedirectUri(redirect); - client.setCreatedAt(Instant.now()); - client.setLastModifiedAt(Instant.now()); - client.setAccessTokenValidity(this.accessTokenValidityTime); - client.setAutoApprove(autoApprove); - client.setRefreshTokenValidity(this.refreshTokenValidityTime); - client.setClientId(TokenUtils.generateToken(75, TokenUtils.CharacterTypes.LOWERCASE, - TokenUtils.CharacterTypes.UPPERCASE, - TokenUtils.CharacterTypes.NUMBERS) - ); - String clientSecret = TokenUtils.generateToken(75, TokenUtils.CharacterTypes.LOWERCASE, - TokenUtils.CharacterTypes.UPPERCASE, - TokenUtils.CharacterTypes.NUMBERS); - client.setClientSecret("{noop}" + clientSecret); - return this.itClientRepository.save(client).toDTO(); - } - - public List getAllClients() { - return this.itClientRepository.findAll().stream().map(ITClient::toDTO).collect(Collectors.toList()); - } - - public ITClientDTO getITClient(UUID id) { - return this.itClientRepository.findById(id).map(ITClient::toDTO).orElseThrow(); - } - - protected ITClient getITClient(ITClientDTO clientDTO) { - return this.itClientRepository.findById(clientDTO.getId()).orElse(null); - } - - public void removeITClient(UUID id) { - this.itClientRepository.deleteById(id); - } - - public void editClient(UUID id, ITClientDTO clientDTO) { - ITClient client = this.itClientRepository.findById(id).orElseThrow(); - client.setLastModifiedAt(Instant.now()); - client.setName(clientDTO.getName() == null ? client.getName() : clientDTO.getName()); - client.setDescription(clientDTO.getDescription() == null - ? client.getDescription() : clientDTO.getDescription()); - client.setWebServerRedirectUri(clientDTO.getWebServerRedirectUri() == null - ? client.getWebServerRedirectUri() : clientDTO.getWebServerRedirectUri()); - } - - public boolean clientExists(String id) { - return UUIDUtil.validUUID(id) && this.itClientRepository.existsById(UUID.fromString(id)) - || this.itClientRepository.existsITClientByClientId(id); - } - - - public void addITClient(ITClient itClient) { - this.itClientRepository.save(itClient); - } - - public Optional getITClientById(String clientId) { - return this.itClientRepository.findByClientId(clientId).map(ITClient::toDTO); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/service/ITUserApprovalService.java b/backend/src/main/java/it/chalmers/gamma/service/ITUserApprovalService.java deleted file mode 100644 index 843bfffa4..000000000 --- a/backend/src/main/java/it/chalmers/gamma/service/ITUserApprovalService.java +++ /dev/null @@ -1,104 +0,0 @@ -package it.chalmers.gamma.service; - -import it.chalmers.gamma.db.entity.ITUserApproval; -import it.chalmers.gamma.db.entity.pk.ITUserApprovalPK; -import it.chalmers.gamma.db.repository.ITUserApprovalRepository; -import it.chalmers.gamma.domain.dto.user.ITUserApprovalDTO; - -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Objects; -import java.util.Optional; -import java.util.stream.Collectors; - -import org.springframework.security.oauth2.provider.approval.Approval; -import org.springframework.security.oauth2.provider.approval.ApprovalStore; -import org.springframework.stereotype.Service; - -@Service("itUserApprovalService") -public class ITUserApprovalService implements ApprovalStore { - - private final ITUserApprovalRepository itUserApprovalRepository; - private final ITClientService itClientService; - private final ITUserService itUserService; - - public ITUserApprovalService( - ITUserApprovalRepository itUserApprovalRepository, - ITClientService itClientService, - ITUserService itUserService) { - this.itUserApprovalRepository = itUserApprovalRepository; - this.itClientService = itClientService; - this.itUserService = itUserService; - } - - @Override - public boolean addApprovals(Collection approvals) { - Optional accessApproval = approvals - .stream() - .filter(approval -> approval.getScope().equals("access")) - .findFirst(); - - accessApproval.ifPresent(this::saveApproval); - - return true; - } - - @Override - public boolean revokeApprovals(Collection approvals) { - //TODO - return false; - } - - @Override - public Collection getApprovals(String cid, String clientId) { - ITUserApproval itUserApproval = this.itUserApprovalRepository - .findById_ItUserCidContainingAndId_ItClient_ClientIdContaining(cid, clientId); - return itUserApproval == null - ? Collections.emptyList() - : Collections.singleton( - new Approval( - cid, - clientId, - "access", - Integer.MAX_VALUE, - Approval.ApprovalStatus.APPROVED - ) - ); - } - - public void saveApproval(String cid, String clientId) { - ITUserApprovalPK itUserApprovalPK = new ITUserApprovalPK(); - itUserApprovalPK.setItUser(this.itUserService.getITUser(this.itUserService.getITUser(cid))); - itUserApprovalPK.setItClient(this.itClientService.getITClient( - Objects.requireNonNull(this.itClientService.getITClientById(clientId).orElse(null))) - ); - - ITUserApproval itUserApproval = new ITUserApproval(); - itUserApproval.setId(itUserApprovalPK); - - this.itUserApprovalRepository.save(itUserApproval); - } - - private void saveApproval(Approval approval) { - String cid = approval.getUserId(); - String clientId = approval.getClientId(); - - saveApproval(cid, clientId); - } - - public List getApprovalsByClientId(String clientId) { - return this.itUserApprovalRepository.findAllById_ItClient_ClientIdContaining(clientId) - .stream() - .map(ITUserApproval::toDTO) - .collect(Collectors.toList()); - } - - public List getApprovalsByCid(String cid) { - return this.itUserApprovalRepository.findAllById_ItUser_CidContaining(cid) - .stream() - .map(ITUserApproval::toDTO) - .collect(Collectors.toList()); - } - -} diff --git a/backend/src/main/java/it/chalmers/gamma/service/ITUserService.java b/backend/src/main/java/it/chalmers/gamma/service/ITUserService.java deleted file mode 100644 index a70eb8ea2..000000000 --- a/backend/src/main/java/it/chalmers/gamma/service/ITUserService.java +++ /dev/null @@ -1,213 +0,0 @@ -package it.chalmers.gamma.service; - -import it.chalmers.gamma.db.entity.ITUser; -import it.chalmers.gamma.db.repository.ITUserRepository; -import it.chalmers.gamma.domain.Language; -import it.chalmers.gamma.domain.dto.user.ITUserDTO; - -import it.chalmers.gamma.response.FileNotFoundResponse; -import it.chalmers.gamma.response.FileNotSavedException; -import it.chalmers.gamma.response.InvalidFileTypeResponse; -import it.chalmers.gamma.response.user.UserNotFoundResponse; -import it.chalmers.gamma.util.ImageUtils; -import it.chalmers.gamma.util.UUIDUtil; - -import java.time.Instant; -import java.time.Year; -import java.util.List; -import java.util.UUID; -import java.util.stream.Collectors; - -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.security.core.userdetails.UserDetailsService; -import org.springframework.security.core.userdetails.UsernameNotFoundException; -import org.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.stereotype.Service; -import org.springframework.web.multipart.MultipartFile; - -@SuppressWarnings({"PMD.TooManyMethods", "PMD.UseObjectForClearerAPI"}) -@Service("userDetailsService") -public class ITUserService implements UserDetailsService { - - private final ITUserRepository itUserRepository; - - private final PasswordEncoder passwordEncoder; - - private final AuthorityService authorityService; - - private static final String USER_ERROR_MSG = "User could not be found"; - - /* - * These dependencies are needed for the authentication system to work, - * since that does not go through the controller layer. - * Can be fixed later, and probably should, to minimize dependencies between services. - */ - public ITUserService(ITUserRepository itUserRepository, AuthorityService authorityService, - PasswordEncoder passwordEncoder) { - this.itUserRepository = itUserRepository; - this.authorityService = authorityService; - this.passwordEncoder = passwordEncoder; - } - - @Override - public UserDetails loadUserByUsername(String cidOrEmail) { - String cidOrEmailLowerCase = cidOrEmail.toLowerCase(); - ITUser user = this.itUserRepository.findByEmail(cidOrEmailLowerCase) - .orElseGet(() -> this.itUserRepository.findByCid(cidOrEmailLowerCase) - .orElseThrow(() -> new UsernameNotFoundException(USER_ERROR_MSG))); - return user.toUserDetailsDTO(this.authorityService.getGrantedAuthorities(user.toDTO())); - - } - - public ITUserDTO loadUser(String cid) { - String cidLowerCase = cid.toLowerCase(); - return this.itUserRepository.findByCid(cidLowerCase) - .map(u -> u.toUserDetailsDTO(this.authorityService.getGrantedAuthorities(u.toDTO()))) - .orElseThrow(() -> new UsernameNotFoundException(USER_ERROR_MSG)); - } - - - public List loadAllUsers() { - return this.itUserRepository.findAll().stream().map(ITUser::toDTO).collect(Collectors.toList()); - } - - public boolean userExists(String cid) { - return this.itUserRepository.existsByCid(cid); - } - - public boolean userExists(UUID id) { - return this.itUserRepository.existsById(id); - } - - public ITUserDTO createUser(UUID id, - String nick, - String firstName, - String lastName, - String cid, - Year year, - boolean userAgreement, - String email, - String password) { - ITUser itUser = new ITUser(); - itUser.setNick(nick); - itUser.setFirstName(firstName); - itUser.setLastName(lastName); - itUser.setCid(cid); - itUser.setAcceptanceYear(year); - itUser.setUserAgreement(userAgreement); - itUser.setGdpr(false); - itUser.setAccountLocked(false); - itUser.setLanguage(Language.sv); - itUser.setEmail(email == null ? itUser.getCid() + "@student.chalmers.se" : email); - itUser.setPassword(this.passwordEncoder.encode(password)); - - if (id != null) { - itUser.setId(id); - } - - this.itUserRepository.save(itUser); - return itUser.toDTO(); - } - - public ITUserDTO createUser(String nick, - String firstName, - String lastName, - String cid, - Year year, - boolean userAgreement, - String email, - String password) { - return createUser(null, nick, firstName, lastName, cid, year, userAgreement, email, password); - } - - public void removeUser(UUID id) { - this.itUserRepository.deleteById(id); - } - - public void editUser(UUID user, String nick, String firstName, String lastName, - String email, String phone, Language language, int acceptanceYear) { - ITUser itUser = this.itUserRepository.findById(user) - .orElseThrow(() -> new UsernameNotFoundException(USER_ERROR_MSG)); - - itUser.setNick(nick == null ? itUser.getNick() : nick); - itUser.setFirstName(firstName == null ? itUser.getFirstName() : firstName); - itUser.setLastName(lastName == null ? itUser.getLastName() : lastName); - itUser.setEmail(email == null ? itUser.getEmail() : email); - itUser.setPhone(phone == null ? itUser.getPhone() : phone); - itUser.setLanguage(language == null ? itUser.getLanguage() : language); - itUser.setAcceptanceYear(Year.of(acceptanceYear)); - itUser.setLastModifiedAt(Instant.now()); - this.itUserRepository.save(itUser); - } - - public ITUserDTO getITUser(String idCidOrEmail) { - ITUser user; - String idCidOrEmailLowerCase = idCidOrEmail.toLowerCase(); - if (UUIDUtil.validUUID(idCidOrEmail)) { - user = this.itUserRepository.findById(UUID.fromString(idCidOrEmail)) - .orElseThrow(UserNotFoundResponse::new); - } else { - user = this.itUserRepository.findByEmail(idCidOrEmailLowerCase) - .orElseGet(() -> this.itUserRepository.findByCid(idCidOrEmailLowerCase) - .orElseThrow(UserNotFoundResponse::new)); - } - return user.toUserDetailsDTO(this.authorityService.getGrantedAuthorities(user.toDTO())); - } - - ITUser getITUser(ITUserDTO userDTO) { - return this.itUserRepository.findById(userDTO.getId()) - .orElseThrow(() -> new UsernameNotFoundException(USER_ERROR_MSG)); - } - - public ITUserDTO getUserByEmail(String email) { - return this.itUserRepository.findByCid(email) - .map(u -> u.toUserDetailsDTO(this.authorityService.getGrantedAuthorities(u.toDTO()))) - .orElseThrow(() -> new UsernameNotFoundException(USER_ERROR_MSG)); - } - - public void setPassword(ITUserDTO userDTO, String password) { - ITUser user = this.getITUser(userDTO); - user.setPassword(this.passwordEncoder.encode(password)); - user.setActivated(true); - this.itUserRepository.save(user); - } - - public void editGdpr(UUID id, boolean gdpr) { - ITUser user = this.itUserRepository.findById(id) - .orElseThrow(() -> new UsernameNotFoundException(USER_ERROR_MSG)); - user.setGdpr(gdpr); - this.itUserRepository.save(user); - } - - public void editProfilePicture(ITUserDTO userDTO, MultipartFile file) { - ITUser user = this.getITUser(userDTO); - if (user == null) { - throw new UserNotFoundResponse(); - } - if (ImageUtils.isImageOrGif(file)) { - try { - if (!user.getAvatarUrl().equals("default.jpg")) { - ImageUtils.removeImage(user.getAvatarUrl()); - } - String fileUrl = ImageUtils.saveImage(file, user.getCid()); - user.setAvatarUrl(fileUrl); - this.itUserRepository.save(user); - } catch (FileNotFoundResponse e) { - throw new FileNotSavedException(); - } - } else { - throw new InvalidFileTypeResponse(); - } - } - - public void setAccountActivated(ITUserDTO userDTO, boolean activated) { - ITUser user = this.getITUser(userDTO); - user.setActivated(activated); - this.itUserRepository.save(user).toDTO(); - } - - public boolean passwordMatches(ITUserDTO user, String password) { - return this.passwordEncoder.matches(password, user.getPassword()); - } - -} diff --git a/backend/src/main/java/it/chalmers/gamma/service/MailSenderService.java b/backend/src/main/java/it/chalmers/gamma/service/MailSenderService.java deleted file mode 100644 index 5aa4a4c98..000000000 --- a/backend/src/main/java/it/chalmers/gamma/service/MailSenderService.java +++ /dev/null @@ -1,63 +0,0 @@ -package it.chalmers.gamma.service; - -import org.json.simple.JSONObject; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.MediaType; -import org.springframework.http.ResponseEntity; -import org.springframework.stereotype.Service; -import org.springframework.web.client.RestTemplate; - -@Service -public class MailSenderService { - - @Value("${application.gotify.key}") - private String gotifyApiKey; - - @Value("${application.gotify.url}") - private String gotifyURL; - - @Value("${application.production}") - private boolean production; - - private static final Logger LOGGER = LoggerFactory.getLogger(MailSenderService.class); - - public boolean trySendingMail(String email, String subject, String body) { - if (this.production) { - return sendMail(email, subject, body); - - } else { - LOGGER.warn("Not in production environment, printing mail: \n " - + "to: " + email + "\n" - + "subject: " + subject + "\n" - + "body: " + body); - return false; - } - } - - /** - * Sends mail using Gotify Rest API, see https://github.com/cthit/gotify - * - * @return true if message was successfully sent false if not - */ - public boolean sendMail(String email, String subject, String body) { - HttpHeaders headers = new HttpHeaders(); - headers.add(HttpHeaders.AUTHORIZATION, "pre-shared: " + this.gotifyApiKey); - headers.setContentType(MediaType.APPLICATION_JSON); - JSONObject object = new JSONObject(); - object.put("to", email); - object.put("from", "no-reply@chalmers.it"); - object.put("subject", subject); - object.put("body", body); - - HttpEntity entity = new HttpEntity<>(object, headers); - RestTemplate restTemplate = new RestTemplate(); - ResponseEntity response = restTemplate.postForEntity(this.gotifyURL, entity, String.class); - LOGGER.info("Gotify responded with " + response.getHeaders() + response.getBody()); - return true; - } - -} diff --git a/backend/src/main/java/it/chalmers/gamma/service/MembershipService.java b/backend/src/main/java/it/chalmers/gamma/service/MembershipService.java deleted file mode 100644 index 769dbbf3e..000000000 --- a/backend/src/main/java/it/chalmers/gamma/service/MembershipService.java +++ /dev/null @@ -1,204 +0,0 @@ -package it.chalmers.gamma.service; - -import it.chalmers.gamma.db.entity.FKITGroup; -import it.chalmers.gamma.db.entity.Membership; -import it.chalmers.gamma.db.entity.NoAccountMembership; -import it.chalmers.gamma.db.entity.pk.MembershipPK; -import it.chalmers.gamma.db.repository.MembershipRepository; -import it.chalmers.gamma.db.repository.NoAccountMembershipRepository; -import it.chalmers.gamma.domain.dto.group.FKITGroupDTO; -import it.chalmers.gamma.domain.dto.membership.MembershipDTO; -import it.chalmers.gamma.domain.dto.membership.NoAccountMembershipDTO; -import it.chalmers.gamma.domain.dto.post.PostDTO; -import it.chalmers.gamma.domain.dto.user.ITUserDTO; - -import it.chalmers.gamma.response.membership.MembershipDoesNotExistResponse; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; -import java.util.stream.Collectors; - -import javax.transaction.Transactional; - -import org.springframework.stereotype.Service; - -@Service -public class MembershipService { - - private final MembershipRepository membershipRepository; - private final FKITGroupService fkitGroupService; - private final DTOToEntityService dtoToEntityService; - private final PostService postService; - private final NoAccountMembershipRepository noAccountMembershipRepository; - - public MembershipService(MembershipRepository membershipRepository, - FKITGroupService fkitGroupService, - DTOToEntityService dtoToEntityService, - PostService postService, NoAccountMembershipRepository noAccountMembershipRepository) { - this.membershipRepository = membershipRepository; - this.fkitGroupService = fkitGroupService; - this.dtoToEntityService = dtoToEntityService; - this.postService = postService; - this.noAccountMembershipRepository = noAccountMembershipRepository; - } - - - //TODO check which methods should be left in this class, - // many are probably never going to be used. - - /** - * adds a userDTO to the groupDTO. - * - * @param groupDTO groupDTO the userDTO should be added to - * @param userDTO which userDTO is added - * @param postDTO what post the userDTO has in groupDTO - * @param postname what the unoficial-post name is - */ - public MembershipDTO addUserToGroup(FKITGroupDTO groupDTO, ITUserDTO userDTO, PostDTO postDTO, String postname) { - MembershipPK pk = new MembershipPK(); - pk.setFKITGroup(this.fkitGroupService.fromDTO(groupDTO)); - pk.setITUser(this.dtoToEntityService.fromDTO(userDTO)); - pk.setPost(this.postService.getPost(postDTO)); - Membership membership = new Membership(); - membership.setId(pk); - membership.setUnofficialPostName(postname); - return this.membershipRepository.save(membership).toDTO(); - } - - /** - * finds all users that has a specific post. - * - * @param postDTO which post that should be looked for - * @return the users UUID, the identifier for the user - */ - public List getPostHoldersDTO(PostDTO postDTO) { - List memberships = this.membershipRepository.findAllById_Post(this.postService.getPost(postDTO)); - List usersId = new ArrayList<>(); - for (Membership membership : memberships) { - usersId.add(membership.getId().getITUser().toDTO()); - } - return usersId; - } - - public List getMembershipsInGroup(FKITGroupDTO group) { - return this.membershipRepository - .findAllById_FkitGroup(this.fkitGroupService.fromDTO(group)) - .stream() - .map(Membership::toDTO) - .collect(Collectors.toList()); - } - public List getMembershipsByPost(PostDTO post) { - return this.membershipRepository.findAllById_Post(this.postService.getPost(post)); - } - - - /** - * gets which groups a user is a part of. - * - * @param user which user which group membersships should be queried - * @return The UUIDs of the groups the user is a part of - */ - public List getUsersGroupDTO(ITUserDTO user) { - List memberships = this.membershipRepository.findAllById_ItUser(this.dtoToEntityService - .fromDTO(user)); - return memberships.stream() - .map(m -> m.getId().getFKITGroup().toDTO()).collect(Collectors.toList()); - } - - /** - * finds which group the userDTO has a specific postDTO in. - */ - public FKITGroupDTO getGroupDTOIdByUserAndPost(ITUserDTO userDTO, PostDTO postDTO) { - Membership membership = this.membershipRepository - .findById_ItUserAndId_Post( - this.dtoToEntityService.fromDTO(userDTO), - this.postService.getPost(postDTO)).orElseThrow(MembershipDoesNotExistResponse::new); - return membership.getId().getFKITGroup().toDTO(); - } - - public List getUserDTOByGroupAndPost(FKITGroupDTO group, PostDTO post) { - return this.membershipRepository.findAllById_FkitGroupAndId_Post( - this.fkitGroupService.fromDTO(group), - this.postService.getPost(post)).stream().map(Membership::toDTO).collect(Collectors.toList()); - } - - public List getGroupsWithPost(PostDTO postDTO) { - List memberships = this.membershipRepository - .findAllById_Post(this.postService.getPost(postDTO)); - List groups = new ArrayList<>(); - for (Membership membership : memberships) { - if (!groups.contains(membership.getId().getFKITGroup().toDTO())) { - groups.add(membership.getId().getFKITGroup().toDTO()); - } - } - return groups; - } - - public List getMembershipsByUser(ITUserDTO userDTO) { - List memberships = this.membershipRepository - .findAllById_ItUser(this.dtoToEntityService.fromDTO(userDTO)); - return memberships.stream().map(Membership::toDTO).collect(Collectors.toList()); - } - - public MembershipDTO getMembershipByUserAndGroup(ITUserDTO userDTO, FKITGroupDTO groupDTO) { - return this.membershipRepository - .findById_ItUserAndId_FkitGroup( - this.dtoToEntityService.fromDTO(userDTO), - this.fkitGroupService.fromDTO(groupDTO)).orElseThrow(MembershipDoesNotExistResponse::new) - .toDTO(); - } - - public void removeUserFromGroup(FKITGroupDTO group, ITUserDTO user) { - MembershipDTO membershipDTO = getMembershipByUserAndGroup(user, group); - this.membershipRepository.delete(this.getMembership(membershipDTO)); - } - - @Transactional - public void editMembership(MembershipDTO membershipDTO, String unofficialName, PostDTO post) { - this.removeUserFromGroup(membershipDTO.getFkitGroupDTO(), membershipDTO.getUser()); - this.addUserToGroup(membershipDTO.getFkitGroupDTO(), - membershipDTO.getUser(), post, - unofficialName); - this.membershipRepository.save(this.getMembership(membershipDTO)); - } - - public void removeAllUsersFromGroup(FKITGroupDTO group) { - List users = this.getMembershipsInGroup(group).stream() - .map(MembershipDTO::getUser).collect(Collectors.toList()); - for (ITUserDTO user : users) { - this.membershipRepository.delete( - this.getMembership(this.getMembershipByUserAndGroup(user, group))); - } - } - - public void removeAllMemberships(ITUserDTO user) { - List memberships = this.membershipRepository - .findAllById_ItUser(this.dtoToEntityService.fromDTO(user)); - memberships.forEach(this.membershipRepository::delete); - } - - /** - * This is a Legacy function, only to keep track of which users have been in different committees long ago. - * @param fkitGroupDTO the group which to fetch users with no account for. - * @return A list of NoAccountMemberships corresponding to members of that group. - */ - public List getNoAccountMembership(FKITGroupDTO fkitGroupDTO) { - FKITGroup group = this.fkitGroupService.fromDTO(fkitGroupDTO); - return this.noAccountMembershipRepository.findAllById_FkitGroup(group).stream() - .map(NoAccountMembership::toDTO).collect(Collectors.toList()); - } - - public boolean groupIsActiveCommittee(FKITGroupDTO group) { - return group.isActive(); - } - - private Membership getMembership(MembershipDTO membershipDTO) { - return this.membershipRepository.findById_ItUserAndId_FkitGroup( - this.dtoToEntityService.fromDTO(membershipDTO.getUser()), - this.fkitGroupService.fromDTO(membershipDTO.getFkitGroupDTO())).orElse(null); - } - - public boolean isPostUsed(UUID id) { - return !this.membershipRepository.findAllById_PostId(id).isEmpty(); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/service/PasswordResetService.java b/backend/src/main/java/it/chalmers/gamma/service/PasswordResetService.java deleted file mode 100644 index dd76f5043..000000000 --- a/backend/src/main/java/it/chalmers/gamma/service/PasswordResetService.java +++ /dev/null @@ -1,93 +0,0 @@ -package it.chalmers.gamma.service; - -import it.chalmers.gamma.db.entity.ITUser; -import it.chalmers.gamma.db.entity.PasswordResetToken; -import it.chalmers.gamma.db.repository.PasswordResetTokenRepository; - -import it.chalmers.gamma.domain.dto.user.ITUserDTO; -import it.chalmers.gamma.domain.dto.user.PasswordResetTokenDTO; -import it.chalmers.gamma.util.TokenUtils; -import java.util.Objects; -import org.springframework.stereotype.Service; - -@Service -public class PasswordResetService { - private final PasswordResetTokenRepository repository; - private final DTOToEntityService dtoToEntityService; - private final MailSenderService mailSenderService; - - public PasswordResetService(PasswordResetTokenRepository repository, DTOToEntityService dtoToEntityService, - MailSenderService mailSenderService) { - this.repository = repository; - this.dtoToEntityService = dtoToEntityService; - this.mailSenderService = mailSenderService; - } - - - public void handlePasswordReset(ITUserDTO user) { - - String token = TokenUtils.generateToken(10, - TokenUtils.CharacterTypes.UPPERCASE, - TokenUtils.CharacterTypes.NUMBERS); - if (this.userHasActiveReset(user)) { - this.editToken(user, token); - } else { - this.addToken(user, token); - } - this.sendMail(user, token); - } - - - public void addToken(ITUserDTO user, String token) { - setToken(new PasswordResetToken(), user, token); - - } - - /** - * adds or edits a token that associated with a user wanting to do a password reset. - * - * @param passwordResetToken the token object used to create a new association - * @param userDTO the user that attempted a password reset - * @param token the token word that is associated with the password reset - */ - private void setToken(PasswordResetToken passwordResetToken, ITUserDTO userDTO, String token) { - ITUser user = this.dtoToEntityService.fromDTO(userDTO); - passwordResetToken.setItUser(user); - passwordResetToken.setToken(token); - this.repository.save(passwordResetToken); - } - - public void editToken(ITUserDTO userDTO, String token) { - ITUser user = this.dtoToEntityService.fromDTO(userDTO); - setToken(Objects.requireNonNull(this.repository.findByItUser(user).orElse(null)), user.toDTO(), token); - } - - public boolean userHasActiveReset(ITUserDTO user) { - return this.repository.existsByItUser(this.dtoToEntityService.fromDTO(user)); - } - - public boolean tokenMatchesUser(ITUserDTO user, String token) { - PasswordResetToken storedToken = this.repository.findByItUser(this.dtoToEntityService.fromDTO(user)) - .orElse(null); - return storedToken != null && storedToken.getToken().equals(token); - } - - public void removeToken(ITUserDTO user) { - this.repository.delete(Objects.requireNonNull( - this.repository.findByItUser(this.dtoToEntityService.fromDTO(user)).orElse(null))); - } - - - // TODO Make sure that an URL is added to the email - private void sendMail(ITUserDTO user, String token) { - String subject = "Password reset for Account at IT division of Chalmers"; - String message = "A password reset have been requested for this account, if you have not requested " - + "this mail, feel free to ignore it. \n Your reset code : " + token; - this.mailSenderService.trySendingMail(user.getEmail(), subject, message); - } - - protected PasswordResetToken getPasswordResetToken(PasswordResetTokenDTO passwordResetTokenDTO) { - return this.repository.findById(passwordResetTokenDTO.getId()).orElse(null); - } - -} \ No newline at end of file diff --git a/backend/src/main/java/it/chalmers/gamma/service/PostService.java b/backend/src/main/java/it/chalmers/gamma/service/PostService.java deleted file mode 100644 index 8c743ccb6..000000000 --- a/backend/src/main/java/it/chalmers/gamma/service/PostService.java +++ /dev/null @@ -1,91 +0,0 @@ -package it.chalmers.gamma.service; - -import it.chalmers.gamma.db.entity.Post; -import it.chalmers.gamma.db.entity.Text; -import it.chalmers.gamma.db.repository.PostRepository; - -import it.chalmers.gamma.domain.dto.post.PostDTO; -import it.chalmers.gamma.response.post.PostDoesNotExistResponse; -import it.chalmers.gamma.util.UUIDUtil; -import java.util.List; -import java.util.UUID; - -import java.util.stream.Collectors; -import org.springframework.stereotype.Service; - - -/** - * A class to handle all database access to memberships between users and groups in the system. - */ -@Service -public class PostService { - - private final PostRepository repository; - - public PostService(PostRepository repository) { - this.repository = repository; - } - - public PostDTO addPost(Text postName) { - return this.repository.save(new Post(postName, null)).toDTO(); - } - - public PostDTO addPost(Text postName, String emailPrefix) { - return this.repository.save(new Post(postName, emailPrefix)).toDTO(); - } - - public PostDTO addPost(UUID id, Text postName, String emailPrefix) { - Post post = new Post(postName, emailPrefix); - post.setId(id); - return this.repository.save(post).toDTO(); - } - - public PostDTO editPost(PostDTO postDTO, Text postName) { - Post post = this.getPost(postDTO); - post.setSVPostName(postName.getSv()); - post.setENPostName(postName.getEn()); - post.setEmailPrefix(""); - return this.repository.save(post).toDTO(); - } - - public PostDTO editPost(PostDTO postDTO, Text postName, String emailPrefix) { - Post post = this.getPost(postDTO); - post.setSVPostName(postName.getSv()); - post.setENPostName(postName.getEn()); - post.setEmailPrefix(emailPrefix); - return this.repository.save(post).toDTO(); - } - - public boolean postExists(String id) { - if (UUIDUtil.validUUID(id)) { - return this.repository.existsById(UUID.fromString(id)); - } - return this.repository.existsByPostName_Sv(id); - } - - public List getAllPosts() { - return this.repository.findAll().stream().map(Post::toDTO).collect(Collectors.toList()); - } - - public PostDTO getPostDTO(String post) { - if (UUIDUtil.validUUID(post)) { - return this.repository.findById(UUID.fromString(post)) - .orElseThrow(PostDoesNotExistResponse::new).toDTO(); - } - return this.repository.findByPostName_Sv(post.toLowerCase()) - .orElseThrow(PostDoesNotExistResponse::new).toDTO(); - } - - public void deletePost(UUID id) { - if (!this.postExists(id.toString())) { - throw new PostDoesNotExistResponse(); - } - - this.repository.deleteById(id); - } - - protected Post getPost(PostDTO postDTO) { - return this.repository.findById(postDTO.getId()).orElse(null); - } - -} diff --git a/backend/src/main/java/it/chalmers/gamma/service/UserWebsiteService.java b/backend/src/main/java/it/chalmers/gamma/service/UserWebsiteService.java deleted file mode 100644 index 3a9893673..000000000 --- a/backend/src/main/java/it/chalmers/gamma/service/UserWebsiteService.java +++ /dev/null @@ -1,103 +0,0 @@ -package it.chalmers.gamma.service; - -import it.chalmers.gamma.db.entity.UserWebsite; -import it.chalmers.gamma.db.repository.UserWebsiteRepository; - -import it.chalmers.gamma.domain.dto.user.ITUserDTO; -import it.chalmers.gamma.domain.dto.website.UserWebsiteDTO; -import it.chalmers.gamma.domain.dto.website.WebsiteDTO; -import it.chalmers.gamma.domain.dto.website.WebsiteInterfaceDTO; -import it.chalmers.gamma.domain.dto.website.WebsiteUrlDTO; -import java.util.List; -import java.util.UUID; - -import java.util.stream.Collectors; -import javax.transaction.Transactional; - -import org.springframework.stereotype.Service; - -@Service -public class UserWebsiteService extends EntityWebsiteService { - - private final UserWebsiteRepository repository; - private final DTOToEntityService dtoToEntityService; - private final WebsiteURLService websiteURLService; - private final WebsiteService websiteService; - - public UserWebsiteService(UserWebsiteRepository repository, - WebsiteService websiteService, - DTOToEntityService dtoToEntityService, - WebsiteURLService websiteURLService) { - super(websiteService); - this.repository = repository; - this.dtoToEntityService = dtoToEntityService; - this.websiteURLService = websiteURLService; - this.websiteService = websiteService; - } - - /** - * adds an associated websiteurl to a user. - * - * @param user the ITUser to handle - * @param websites all websites that should be added to the user - */ - public void addWebsiteToUser(ITUserDTO user, List websites) { - for (WebsiteUrlDTO website : websites) { - UserWebsite userWebsite = new UserWebsite(); - userWebsite.setItUser(this.dtoToEntityService.fromDTO(user)); - userWebsite.setWebsite(this.websiteURLService.getWebsiteURL(website)); - this.repository.save(userWebsite); - } - } - - public List getAllUserWebsites() { - return this.repository.findAll().stream().map(UserWebsite::toDTO).collect(Collectors.toList()); - } - - public UserWebsiteDTO getUserWebsiteById(String id) { - return this.repository.findById(UUID.fromString(id)).map(UserWebsite::toDTO).orElse(null); - } - - //TODO function bellow - public void deleteUserWebsite(String id) { - - } - - /** - * gets all websites connected to a user. - * - * @param user the user to search for connected websites - * @return all websites connected to a user - */ - public List getWebsites(ITUserDTO user) { - return this.repository.findAllByItUser(this.dtoToEntityService.fromDTO(user)) - .stream().map(UserWebsite::toDTO).collect(Collectors.toList()); - } - - public UserWebsiteDTO getUserWebsiteByWebsite(WebsiteDTO website) { - return this.repository.findByWebsite(this.websiteService.getWebsite(website)).map(UserWebsite::toDTO) - .orElse(null); - } - - /** - * deletes all websites connected to a user, - * IE done before deleting a user to not have dangling tables. - * - * @param user the user - */ - @Transactional - public void deleteWebsitesConnectedToUser(ITUserDTO user) { - this.repository.deleteAllByItUser(this.dtoToEntityService.fromDTO(user)); - } - - /** - * Deletes all websites of a specific type. - * - * @param website the type of website to delete - */ - @Transactional - public void deleteUserWebsiteByWebsite(WebsiteDTO website) { - this.repository.deleteAllByWebsite_Website(this.websiteService.getWebsite(website)); - } - -} diff --git a/backend/src/main/java/it/chalmers/gamma/service/WebsiteService.java b/backend/src/main/java/it/chalmers/gamma/service/WebsiteService.java deleted file mode 100644 index a28eb8de4..000000000 --- a/backend/src/main/java/it/chalmers/gamma/service/WebsiteService.java +++ /dev/null @@ -1,69 +0,0 @@ -package it.chalmers.gamma.service; - -import it.chalmers.gamma.db.entity.Website; -import it.chalmers.gamma.db.repository.WebsiteRepository; - -import it.chalmers.gamma.domain.dto.website.WebsiteDTO; -import it.chalmers.gamma.response.website.WebsiteNotFoundResponse; -import it.chalmers.gamma.util.UUIDUtil; -import java.util.List; -import java.util.UUID; - -import java.util.stream.Collectors; -import org.springframework.stereotype.Service; - -@Service -public class WebsiteService { - - private final WebsiteRepository repository; - - public WebsiteService(WebsiteRepository repository) { - this.repository = repository; - } - - /** - * adds a possible website to the database. - * - * @param name the name of the website - * @param prettyName the display-name of the website - */ - public WebsiteDTO addPossibleWebsite(String name, String prettyName) { - Website website = new Website(); - website.setPrettyName(prettyName == null ? name.toLowerCase() : prettyName); - website.setName(name); - return this.repository.save(website).toDTO(); - } - - public WebsiteDTO getWebsite(String websiteName) { - if (UUIDUtil.validUUID(websiteName)) { - return this.repository.findById(UUID.fromString(websiteName)) - .orElseThrow(WebsiteNotFoundResponse::new).toDTO(); - } - return this.repository.findByName(websiteName.toLowerCase()) - .orElseThrow(WebsiteNotFoundResponse::new).toDTO(); - } - - protected Website getWebsite(WebsiteDTO websiteDTO) { - return this.repository.findById(websiteDTO.getId()).orElse(null); - } - - public void editWebsite(WebsiteDTO websiteDTO, String name, String prettyName) { - Website website = this.getWebsite(websiteDTO); - website.setName(name.toLowerCase()); - website.setPrettyName(prettyName == null ? name.toLowerCase() : prettyName); - this.repository.save(website); - } - - public void deleteWebsite(String id) { - this.repository.deleteById(UUID.fromString(id)); - } - - - public boolean websiteExists(UUID id) { - return this.repository.existsById(id); - } - - public List getAllWebsites() { - return this.repository.findAll().stream().map(Website::toDTO).collect(Collectors.toList()); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/service/WebsiteURLService.java b/backend/src/main/java/it/chalmers/gamma/service/WebsiteURLService.java deleted file mode 100644 index 7c667b954..000000000 --- a/backend/src/main/java/it/chalmers/gamma/service/WebsiteURLService.java +++ /dev/null @@ -1,64 +0,0 @@ -package it.chalmers.gamma.service; - -import it.chalmers.gamma.db.entity.WebsiteURL; -import it.chalmers.gamma.db.repository.WebsiteURLRepository; - -import it.chalmers.gamma.domain.dto.website.WebsiteDTO; -import it.chalmers.gamma.domain.dto.website.WebsiteUrlDTO; -import java.util.List; -import java.util.UUID; - -import java.util.stream.Collectors; -import javax.transaction.Transactional; - -import org.springframework.stereotype.Service; - -//TODO this class might be unnecessary because of changes in how websites work -@SuppressWarnings("PMD.UnusedPrivateMethod") -@Service -public class WebsiteURLService { - - private final WebsiteURLRepository repository; - private final WebsiteService websiteService; - - public WebsiteURLService(WebsiteURLRepository repository, WebsiteService websiteService) { - this.repository = repository; - this.websiteService = websiteService; - } - - private void addWebsite(WebsiteDTO websiteDTO, String url) { - WebsiteURL websiteURL = new WebsiteURL(); - websiteURL.setWebsite(this.websiteService.getWebsite(websiteDTO)); - websiteURL.setUrl(url); - this.repository.save(websiteURL); - } - - public List getAllWebsites() { - return this.repository.findAll().stream().map(WebsiteURL::toDTO).collect(Collectors.toList()); - } - - public WebsiteUrlDTO getWebsiteURLById(String id) { - return this.repository.findById(UUID.fromString(id)).map(WebsiteURL::toDTO).orElse(null); - } - - public void deleteWebsite(String id) { - this.repository.deleteById(UUID.fromString(id)); - } - - public void editWebsite(WebsiteUrlDTO websiteUrlDTO, WebsiteDTO websiteDTO, String url) { - WebsiteURL websiteURL = this.getWebsiteURL(websiteUrlDTO); - websiteURL.setWebsite(this.websiteService.getWebsite(websiteDTO)); - websiteURL.setUrl(url); - this.repository.save(websiteURL); - } - - @Transactional - public void deleteAllWebsites(WebsiteDTO website) { - this.repository.deleteAllByWebsite(this.websiteService.getWebsite(website)); - } - - protected WebsiteURL getWebsiteURL(WebsiteUrlDTO websiteUrlDTO) { - return this.repository.findById(websiteUrlDTO.getId()).orElse(null); - } - -} diff --git a/backend/src/main/java/it/chalmers/gamma/service/WhitelistService.java b/backend/src/main/java/it/chalmers/gamma/service/WhitelistService.java deleted file mode 100644 index ab6a6c795..000000000 --- a/backend/src/main/java/it/chalmers/gamma/service/WhitelistService.java +++ /dev/null @@ -1,103 +0,0 @@ -package it.chalmers.gamma.service; - -import it.chalmers.gamma.db.entity.Whitelist; -import it.chalmers.gamma.db.repository.WhitelistRepository; -import it.chalmers.gamma.domain.dto.user.WhitelistDTO; -import it.chalmers.gamma.response.whitelist.WhitelistAlreadyAddedException; -import it.chalmers.gamma.response.whitelist.WhitelistDoesNotExistsException; -import it.chalmers.gamma.util.UUIDUtil; - -import java.util.List; -import java.util.Objects; -import java.util.UUID; -import java.util.stream.Collectors; - -import javax.transaction.Transactional; -import org.springframework.stereotype.Service; - -@Service -public class WhitelistService { - - private final WhitelistRepository whitelistRepository; - - private final ActivationCodeService activationCodeService; - - public WhitelistService(WhitelistRepository whitelistRepository, - ActivationCodeService activationCodeService) { - this.whitelistRepository = whitelistRepository; - this.activationCodeService = activationCodeService; - } - - /** - * adds a cid that can create a account. - * - * @param cid the cid that is added to the whitelisted database - * @return a copy of the whitelist object that is created - */ - public WhitelistDTO addWhiteListedCID(String cid) { - if (this.whitelistRepository.existsByCid(cid)) { - throw new WhitelistAlreadyAddedException(); - } - Whitelist whitelistedCID = new Whitelist(cid); - return this.whitelistRepository.save(whitelistedCID).toDTO(); - } - - @Transactional - public void removeWhiteListedCID(String id) { - WhitelistDTO whitelistDTO = this.getWhitelist(id); - this.activationCodeService.deleteCode(whitelistDTO.getCid()); - this.whitelistRepository.delete(this.fromDTO(whitelistDTO)); - } - - protected Whitelist fromDTO(WhitelistDTO whitelistDTO) { - return this.whitelistRepository.findById(whitelistDTO.getId()) - .orElseThrow(WhitelistDoesNotExistsException::new); - } - - /** - * gets whitelist object by id. - * - * @param id the GROUP_ID of the whitelist object to get - * @return the whitelist object that has corresponding GROUP_ID - */ - public WhitelistDTO getWhitelist(String id) { - if (UUIDUtil.validUUID(id)) { - return this.whitelistRepository.findById(UUID.fromString(id)) - .orElseThrow(WhitelistDoesNotExistsException::new).toDTO(); - } else { - return this.whitelistRepository.findByCid(id) - .orElseThrow(WhitelistAlreadyAddedException::new).toDTO(); - } - } - - /** - * checks if cid has been whitelisted. - * - * @param cid the cid check if whitelisted - * @return true if exists in the database, false otherwise - */ - public boolean isCIDWhiteListed(String cid) { - return this.whitelistRepository.existsByCid(cid.toLowerCase()) - || UUIDUtil.validUUID(cid) && this.whitelistRepository.existsById(UUID.fromString(cid)); - } // Above works because java only checks right if left is correct. - - public List getAllWhitelist() { - return this.whitelistRepository.findAll() - .stream().map(Whitelist::toDTO).collect(Collectors.toList()); - } - - - /** - * edits the cid of a already whitelisted object. - * - * @param whitelistDTO the old whitelist object that should be edited - * @param newCid the new cid that will replace the old whitelisted cid - */ - public void editWhitelist(WhitelistDTO whitelistDTO, String newCid) { - Whitelist whitelist = this.whitelistRepository.findById(whitelistDTO.getId()).orElse(null); - Objects.requireNonNull(whitelist).setCid(newCid); - this.whitelistRepository.save(whitelist); - } - - -} diff --git a/backend/src/main/java/it/chalmers/gamma/util/ImageUtils.java b/backend/src/main/java/it/chalmers/gamma/util/ImageUtils.java deleted file mode 100644 index 84b0df054..000000000 --- a/backend/src/main/java/it/chalmers/gamma/util/ImageUtils.java +++ /dev/null @@ -1,104 +0,0 @@ -package it.chalmers.gamma.util; - -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; - -import it.chalmers.gamma.response.FileNotSavedException; -import java.io.File; -import java.io.IOException; -import java.io.OutputStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.List; -import org.apache.commons.io.FilenameUtils; -import org.apache.http.entity.ContentType; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Component; -import org.springframework.web.multipart.MultipartFile; - - -@Component -@SuppressFBWarnings(justification = "Needed for Spring to inject value, This is not in issue, FB is projecting", - value = {"ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD", "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE"}) -@SuppressWarnings("PMD.CyclomaticComplexity") -public class ImageUtils { - - private static final Logger LOGGER = LoggerFactory.getLogger(ImageUtils.class); - private static String relativePath; - private static String absoluteBasePath; - - public static String saveImage(MultipartFile file, String name) { - File f; - try { - f = saveToDisk(file, name); - if (f != null) { - return f.getName(); - } - throw new FileNotSavedException(); - } catch (IOException e) { - throw new FileNotSavedException(); - } - } - - private static File saveToDisk(MultipartFile file, String name) throws IOException { - File f = new File(relativePath + name + "." + FilenameUtils.getExtension(file.getOriginalFilename())); - File dir = new File(f.getParent()); - if (dir.mkdir()) { - LOGGER.info("no uploads directory exists, creating a new one"); - } - if (f.createNewFile()) { - OutputStream fos = null; - try { - fos = Files.newOutputStream(Path.of(f.getPath())); - fos.write(file.getBytes()); - } finally { - if (fos != null) { - fos.close(); - } - } - return f; - } - return null; - } - - public static boolean removeImage(String path) { - File f = new File(relativePath + path); - if (f.delete()) { - return true; - } else { - LOGGER.warn(String.format("could not remove file with path %s", path)); - return false; - } - - } - - /** - * It's pronounced Gif. - * - * @return true if file is image or gif, false otherwise - */ - public static boolean isImageOrGif(MultipartFile file) { - String contentType = file.getContentType(); - return List.of( - ContentType.IMAGE_GIF.toString(), - ContentType.IMAGE_PNG.toString(), - ContentType.IMAGE_JPEG.toString()) - .contains(contentType); - } - - public static String getAbsolutePath(String imageName) { - return absoluteBasePath + relativePath + imageName; - } - - @Value("${application.base-uri}") - public void setAbsoluteBasePath(String absolutePath) { - ImageUtils.absoluteBasePath = absolutePath; - } - - // Needed to inject into static field - @Value("${application.files.path}") - public void setRelativePath(String relativePath) { - ImageUtils.relativePath = relativePath; - } -} \ No newline at end of file diff --git a/backend/src/main/java/it/chalmers/gamma/util/InputValidationUtils.java b/backend/src/main/java/it/chalmers/gamma/util/InputValidationUtils.java deleted file mode 100644 index fef50b22f..000000000 --- a/backend/src/main/java/it/chalmers/gamma/util/InputValidationUtils.java +++ /dev/null @@ -1,18 +0,0 @@ -package it.chalmers.gamma.util; - -import java.util.List; -import org.springframework.validation.ObjectError; - -public final class InputValidationUtils { - private InputValidationUtils() { - - } - - public static String getErrorMessages(List errors) { - StringBuilder errorMessages = new StringBuilder(); - for (ObjectError error : errors) { - errorMessages.append(error.getDefaultMessage()); - } - return errorMessages.toString(); - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/util/TokenUtils.java b/backend/src/main/java/it/chalmers/gamma/util/TokenUtils.java deleted file mode 100644 index e6cdf7332..000000000 --- a/backend/src/main/java/it/chalmers/gamma/util/TokenUtils.java +++ /dev/null @@ -1,59 +0,0 @@ -package it.chalmers.gamma.util; - -import java.util.Arrays; -import java.util.Random; -import java.util.stream.Collectors; - -public final class TokenUtils { - - public enum CharacterTypes { - UPPERCASE("ABCDEFGHIJKLMNOPQRSTUVWXYZ"), - LOWERCASE("abcdefghijklmnopqrstuvwxyz"), - NUMBERS("123456789"), - SPECIALS("!@#$%&()+=[]|/?><"); - - private String characters; - - CharacterTypes(String characters) { - this.characters = characters; - } - - public String getCharacters() { - return this.characters; - } - - public static CharacterTypes[] allValues() { - return new CharacterTypes[]{ - UPPERCASE, LOWERCASE, NUMBERS, SPECIALS - }; - } - } - - private TokenUtils() { - - } - - public static String generateToken() { - CharacterTypes[] types = { - CharacterTypes.UPPERCASE, - CharacterTypes.LOWERCASE, - CharacterTypes.NUMBERS, - CharacterTypes.SPECIALS}; - - return generateToken(100, types); - } - - - public static String generateToken(int length, CharacterTypes...types) { - String characters = Arrays.stream(types) - .map(CharacterTypes::getCharacters) - .collect(Collectors.joining()); - Random rand = new Random(); - StringBuilder code = new StringBuilder(); - for (int i = 0; i < length; i++) { - code.append(characters.charAt(rand.nextInt(characters.length() - 1))); - } - return code.toString(); - } - -} diff --git a/backend/src/main/java/it/chalmers/gamma/util/UUIDUtil.java b/backend/src/main/java/it/chalmers/gamma/util/UUIDUtil.java deleted file mode 100644 index b8e7b8b43..000000000 --- a/backend/src/main/java/it/chalmers/gamma/util/UUIDUtil.java +++ /dev/null @@ -1,18 +0,0 @@ -package it.chalmers.gamma.util; - -import java.util.regex.Pattern; - -public final class UUIDUtil { - - private static final String PATTERN = - "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"; - - public static boolean validUUID(String id) { - Pattern p = Pattern.compile(PATTERN); - return p.matcher(id).find(); - } - - private UUIDUtil() { - - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/util/mock/MockData.java b/backend/src/main/java/it/chalmers/gamma/util/mock/MockData.java deleted file mode 100644 index 29b888ab1..000000000 --- a/backend/src/main/java/it/chalmers/gamma/util/mock/MockData.java +++ /dev/null @@ -1,43 +0,0 @@ -package it.chalmers.gamma.util.mock; - -import java.util.List; - -public class MockData { - - private List users; - private List groups; - private List superGroups; - private List posts; - - public List getUsers() { - return this.users; - } - - public void setUsers(List users) { - this.users = users; - } - - public List getGroups() { - return this.groups; - } - - public void setGroups(List groups) { - this.groups = groups; - } - - public List getSuperGroups() { - return this.superGroups; - } - - public void setSuperGroups(List superGroups) { - this.superGroups = superGroups; - } - - public List getPosts() { - return this.posts; - } - - public void setPosts(List posts) { - this.posts = posts; - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/util/mock/MockFKITGroup.java b/backend/src/main/java/it/chalmers/gamma/util/mock/MockFKITGroup.java deleted file mode 100644 index f972da72e..000000000 --- a/backend/src/main/java/it/chalmers/gamma/util/mock/MockFKITGroup.java +++ /dev/null @@ -1,88 +0,0 @@ -package it.chalmers.gamma.util.mock; - -import it.chalmers.gamma.db.entity.Text; - -import java.util.List; -import java.util.Objects; -import java.util.UUID; - -public class MockFKITGroup { - - private UUID id; - private String name; - private String prettyName; - private Text description; - private Text function; - private List members; - private UUID superGroup; - - /** - * If true, then this group will be active from today until a year forward. - * If false, then this group was active a year ago to yesterday. - */ - private boolean active; - - public UUID getId() { - return this.id; - } - - public void setId(UUID id) { - this.id = id; - } - - public String getName() { - return this.name; - } - - public void setName(String name) { - this.name = name; - } - - public String getPrettyName() { - return this.prettyName; - } - - public void setPrettyName(String prettyName) { - this.prettyName = prettyName; - } - - public Text getDescription() { - return Objects.requireNonNullElseGet(this.description, Text::new); - } - - public void setDescription(Text description) { - this.description = description; - } - - public Text getFunction() { - return Objects.requireNonNullElseGet(this.function, Text::new); - } - - public void setFunction(Text function) { - this.function = function; - } - - public List getMembers() { - return this.members; - } - - public void setMembers(List members) { - this.members = members; - } - - public boolean isActive() { - return this.active; - } - - public void setActive(boolean active) { - this.active = active; - } - - public UUID getSuperGroup() { - return this.superGroup; - } - - public void setSuperGroup(UUID superGroup) { - this.superGroup = superGroup; - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/util/mock/MockFKITSuperGroup.java b/backend/src/main/java/it/chalmers/gamma/util/mock/MockFKITSuperGroup.java deleted file mode 100644 index 62e71f1ac..000000000 --- a/backend/src/main/java/it/chalmers/gamma/util/mock/MockFKITSuperGroup.java +++ /dev/null @@ -1,55 +0,0 @@ -package it.chalmers.gamma.util.mock; - -import it.chalmers.gamma.domain.GroupType; - -import java.util.List; -import java.util.UUID; - -public class MockFKITSuperGroup { - - private UUID id; - private String name; - private String prettyName; - private GroupType type; - private List groups; - - public UUID getId() { - return this.id; - } - - public void setId(UUID id) { - this.id = id; - } - - public String getName() { - return this.name; - } - - public void setName(String name) { - this.name = name; - } - - public String getPrettyName() { - return this.prettyName; - } - - public void setPrettyName(String prettyName) { - this.prettyName = prettyName; - } - - public GroupType getType() { - return this.type; - } - - public void setType(GroupType type) { - this.type = type; - } - - public List getGroups() { - return this.groups; - } - - public void setGroups(List groups) { - this.groups = groups; - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/util/mock/MockITUser.java b/backend/src/main/java/it/chalmers/gamma/util/mock/MockITUser.java deleted file mode 100644 index 718c04312..000000000 --- a/backend/src/main/java/it/chalmers/gamma/util/mock/MockITUser.java +++ /dev/null @@ -1,62 +0,0 @@ -package it.chalmers.gamma.util.mock; - -import java.time.Year; -import java.util.UUID; - -public class MockITUser { - - private UUID id; - private String cid; - private String nick; - private String firstName; - private String lastName; - private Year acceptanceYear; - - public UUID getId() { - return this.id; - } - - public void setId(UUID id) { - this.id = id; - } - - public String getCid() { - return this.cid; - } - - public void setCid(String cid) { - this.cid = cid; - } - - public String getNick() { - return this.nick; - } - - public void setNick(String nick) { - this.nick = nick; - } - - public String getFirstName() { - return this.firstName; - } - - public void setFirstName(String firstName) { - this.firstName = firstName; - } - - public String getLastName() { - return this.lastName; - } - - public void setLastName(String lastName) { - this.lastName = lastName; - } - - public Year getAcceptanceYear() { - return this.acceptanceYear; - } - - public void setAcceptanceYear(Year acceptanceYear) { - this.acceptanceYear = acceptanceYear; - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/util/mock/MockMembership.java b/backend/src/main/java/it/chalmers/gamma/util/mock/MockMembership.java deleted file mode 100644 index 415adf4ab..000000000 --- a/backend/src/main/java/it/chalmers/gamma/util/mock/MockMembership.java +++ /dev/null @@ -1,34 +0,0 @@ -package it.chalmers.gamma.util.mock; - -import java.util.UUID; - -public class MockMembership { - - private UUID userId; - private UUID postId; - private String unofficialPostName; - - public UUID getUserId() { - return this.userId; - } - - public void setUserId(UUID userId) { - this.userId = userId; - } - - public UUID getPostId() { - return this.postId; - } - - public void setPostId(UUID postId) { - this.postId = postId; - } - - public String getUnofficialPostName() { - return this.unofficialPostName; - } - - public void setUnofficialPostName(String unofficialPostName) { - this.unofficialPostName = unofficialPostName; - } -} diff --git a/backend/src/main/java/it/chalmers/gamma/util/mock/MockPost.java b/backend/src/main/java/it/chalmers/gamma/util/mock/MockPost.java deleted file mode 100644 index 9ca298eca..000000000 --- a/backend/src/main/java/it/chalmers/gamma/util/mock/MockPost.java +++ /dev/null @@ -1,27 +0,0 @@ -package it.chalmers.gamma.util.mock; - -import it.chalmers.gamma.db.entity.Text; - -import java.util.UUID; - -public class MockPost { - - private UUID id; - private Text postName; - - public UUID getId() { - return this.id; - } - - public void setId(UUID id) { - this.id = id; - } - - public Text getPostName() { - return this.postName; - } - - public void setPostName(Text postName) { - this.postName = postName; - } -} diff --git a/backend/src/main/resources/application-production.yml b/backend/src/main/resources/application-production.yml deleted file mode 100644 index 6c574db0e..000000000 --- a/backend/src/main/resources/application-production.yml +++ /dev/null @@ -1,83 +0,0 @@ -spring: - datasource: - username: ${DB_USER:user} - password: ${DB_PASSWORD:password} - url: jdbc:postgresql://${DB_HOST:db}:${DB_PORT:5432}/${DB_NAME:postgres} - output: - ansi: - enabled: ALWAYS - flyway: - baseline-on-migrate: true - locations: classpath:/db/migration - jpa: - database-platform: org.hibernate.dialect.PostgreSQL9Dialect - properties: - hibernate: - temp: - #http://vkuzel.blogspot.se/2016/03/spring-boot-jpa-hibernate-atomikos.html - use_jdbc_metadata_defaults: false - session: - store-type: redis - - redis: - host: ${REDIS_HOST:localhost} - password: ${REDIS_PASSWORD:password} - port: ${REDIS_PORT:6379} - -server: - port: ${SERVER_PORT:9090} - servlet: - context-path: /api - session: - timeout: ${SESSION_TIMEOUT:-1} - - - -logging: - file: ${LOGGING_FILE:production.log} - level: - root: ${ROOT_DEBUG_LEVEL:WARN} - org: - springframework: - web: ${WEB_DEBUG_LEVEL:WARN} - hibernate: ${HIBERNATE_DEBUG_LEVEL:ERROR} - -security: - jwt: - token: - secret-key: ${JWT_SECRET_KEY:jwtkey} # This is only for Development, should also be a secret one for Production - expire-length: ${JWT_EXPIRE_LENGTH:25200} #7 Hours. Subject to change. - issuer: ${JWT_ISSUER:http://localhost:9090} - audience: ${JWT_AUDIENCE:http://localhost:3000} - - - -application: - base-uri: ${BACKEND_URI:http://localhost:9090/api} - production: ${PRODUCTION:true} - cookie: - domain: ${COOKIE_DOMAIN:https://gamma.chalmers.it} - path: ${COOKIE_PATH:/} - validity-time: 31536000 # One year - password-expiration-time: 3600 - frontend-client-details: - client-id: ${FRONTEND_CLIENT_ID:7hAdUEtMo4MgFnA7ZoZ41ohTe1NNRoJmjL67Gf0NIrrBnauyhc} - client-secret: ${FRONTEND_CLIENT_SECRET:LBoxmzohQOSRCz99uBhS0IjLglxUOaLRXJxIC8iWuHTWYCLLqo} - redirect-uri: ${FRONTEND_REDIRECT_URI:http://localhost:8080/login} - successful-login-uri: ${SUCCESSFUL_LOGIN:http://localhost:8080} - standard-admin-account: - password: ${ADMIN_PASSWORD:password} - mocking: ${IS_MOCKING:false} - default-oauth2-client: - client-name: ${DEFAULT_CLIENT_NAME:name} - client-id: ${DEFAULT_CLIENT_ID:id} - client-secret: ${DEFAULT_CLIENT_SECRET:secret} - redirect-uri: ${DEFAULT_REDIRECT_URI:http://localhost:3001/auth/callback} - api-key: ${DEFAULT_API_KEY:key} - gotify: - key: ${GOTIFY_KEY:key} - url: ${GOTIFY_URL:https://gotify.chalmers.it} - allowed-origin: ${CORS_ALLOWED_ORIGIN:https://gamma.chalmers.it} - auth: - accessTokenValidityTime: ${AUTH_ACCESS_TOKEN_VALIDITY:3600} - refreshTokenValidityTime: ${AUTH_REFRESH_TOKEN_VALIDITY:500000000} diff --git a/backend/src/main/resources/application.yml b/backend/src/main/resources/application.yml deleted file mode 100644 index a3f32669e..000000000 --- a/backend/src/main/resources/application.yml +++ /dev/null @@ -1,98 +0,0 @@ -spring: - datasource: - username: ${DB_USER:postgres} - password: ${DB_PASSWORD:example} - url: jdbc:postgresql://${DB_HOST:localhost}:${DB_PORT:5432}/${DB_NAME:postgres} - flyway: - baseline-on-migrate: true - locations: classpath:/db/migration - output: - ansi: - enabled: ALWAYS - jpa: - database-platform: org.hibernate.dialect.PostgreSQL9Dialect - properties: - hibernate: - temp: - use_jdbc_metadata_defaults: false - hibernate: - ddl-auto: none - servlet: - multipart: - max-file-size: 2MB - max-request-size: 2MB - - thymeleaf: - cache: false - check-template: true - check-template-location: true - enabled: true - encoding: UTF-8 - mode: HTML - prefix: classpath:/templates/ - suffix: .html - servlet: - content-type: text/html - - session: - store-type: redis - - redis: - host: ${REDIS_HOST:0.0.0.0} - password: ${REDIS_PASSWORD:} - port: ${REDIS_PORT:6379} - -server: - port: ${SERVER_PORT:8081} - error: - whitelabel: - enabled: false - servlet: - context-path: /api - - - -logging: - level: - root: ${ROOT_DEBUG_LEVEL:INFO} - org: - springframework: - web: ${WEB_DEBUG_LEVEL:INFO} - hibernate: ${HIBERNATE_DEBUG_LEVEL:INFO} - -security: - jwt: - token: - secret-key: xJqKgDuIikgjkvOXI71j8LKkBlKg3bdr7/WYN6Q0uDs= # This is only for Development, should also be a secret one for Production - expire-length: 2629746 #One Month. Subject to change. - issuer: http://localhost:8081 - audience: http://localhost:3000 - -application: - base-uri: http://localhost:8081/api/ - production: false - files: - path: uploads/ - cookie: - domain: ${COOKIE_DOMAIN:localhost} - path: ${COOKIE_PATH:/} - validity-time: 31536000 - pre-populate-database: true - frontend-client-details: - successful-login-uri: ${SUCCESSFUL_LOGIN:http://localhost:3000} - standard-admin-account: - password: ${ADMIN_PASSWORD:password} - mocking: ${IS_MOCKING:true} - default-oauth2-client: - client-name: ${DEFAULT_CLIENT_NAME:name} - client-id: ${DEFAULT_CLIENT_ID:id} - client-secret: ${DEFAULT_CLIENT_SECRET:secret} - redirect-uri: ${DEFAULT_REDIRECT_URI:http://localhost:3001/auth/account/callback} - api-key: ${DEFAULT_API_KEY:key} - gotify: - key: "key" # This is not needed, but application crashes since it looks for these values. - url: "https://gotify.chalmers.it" - allowed-origin: ${CORS_ALLOWED_ORIGIN:http://localhost:3000} - auth: - accessTokenValidityTime: 3600 - refreshTokenValidityTime: 500000000 diff --git a/backend/src/main/resources/db/migration/README.md b/backend/src/main/resources/db/migration/README.md deleted file mode 100644 index f89e48ea6..000000000 --- a/backend/src/main/resources/db/migration/README.md +++ /dev/null @@ -1,23 +0,0 @@ -# How to write migrations - -Create a sql file with a V that is +1 of the last one. - -Here's some examples with an sql file named `V99__website-changes.sql`: - -```sql - --- Add column -ALTER TABLE website - ADD test_column varchar(100) not null; - --- Rename column -ALTER TABLE website - RENAME COLUMN name TO name_new; - --- Modify column -ALTER TABLE website - ALTER COLUMN pretty_name TYPE varchar(200); - -``` - -More examples here, check for PostgresSQL: https://www.postgresql.org/docs/9.4/ddl-alter.html diff --git a/backend/src/main/resources/db/migration/V1.1__post_email_prefix.sql b/backend/src/main/resources/db/migration/V1.1__post_email_prefix.sql deleted file mode 100644 index 3c78478df..000000000 --- a/backend/src/main/resources/db/migration/V1.1__post_email_prefix.sql +++ /dev/null @@ -1,2 +0,0 @@ -ALTER TABLE post -ADD email_prefix VARCHAR(20) NOT NULL DEFAULT '' \ No newline at end of file diff --git a/backend/src/main/resources/db/migration/V1.2__user_activated_account.sql b/backend/src/main/resources/db/migration/V1.2__user_activated_account.sql deleted file mode 100644 index 53f7b570b..000000000 --- a/backend/src/main/resources/db/migration/V1.2__user_activated_account.sql +++ /dev/null @@ -1,2 +0,0 @@ -ALTER TABLE ituser -ADD activated BOOLEAN DEFAULT FALSE \ No newline at end of file diff --git a/backend/src/main/resources/db/migration/V1.3__post_email_prefix_nullable.sql b/backend/src/main/resources/db/migration/V1.3__post_email_prefix_nullable.sql deleted file mode 100644 index 2b0f7cda8..000000000 --- a/backend/src/main/resources/db/migration/V1.3__post_email_prefix_nullable.sql +++ /dev/null @@ -1,3 +0,0 @@ -alter table post alter column email_prefix drop not null; - -alter table post alter column email_prefix drop default; diff --git a/backend/src/main/resources/db/migration/V1.4__it_user_approval.sql b/backend/src/main/resources/db/migration/V1.4__it_user_approval.sql deleted file mode 100644 index 2f56344b3..000000000 --- a/backend/src/main/resources/db/migration/V1.4__it_user_approval.sql +++ /dev/null @@ -1,5 +0,0 @@ -CREATE TABLE it_user_approval ( - ituser_id UUID REFERENCES ituser(id), - itclient_id UUID REFERENCES itclient(id), - CONSTRAINT it_user_approval_pk PRIMARY KEY(ituser_id, itclient_id) -); diff --git a/backend/src/main/resources/db/migration/V1__BASE.sql b/backend/src/main/resources/db/migration/V1__BASE.sql deleted file mode 100644 index dc2d1ff76..000000000 --- a/backend/src/main/resources/db/migration/V1__BASE.sql +++ /dev/null @@ -1,148 +0,0 @@ -create table internal_text ( - id uuid constraint text_pk primary key, - sv text not null, - en text -); - -create table website ( - id uuid constraint websites_pk primary key, - name varchar(100) not null constraint website_name unique, - pretty_name varchar(100) not null -); - -create table website_url ( - id uuid constraint websites_url_pk primary key, - website uuid not null references website, - url varchar(2000) not null -); - -create table ituser ( - id uuid constraint ituser_pk primary key, - cid varchar(10) not null constraint ituser_cid_unique unique, - password varchar(255) not null, - nick varchar(50) not null, - first_name varchar(50) null, - last_name varchar(50) null, - email varchar(100) not null constraint ituser_email_unique unique, - phone varchar(15) null, - language varchar(15) null, - avatar_url varchar(255) default 'default.jpg', - gdpr boolean not null default false, - user_agreement boolean not null default false, - account_locked boolean not null default false, - acceptance_year integer constraint ituser_valid_year check (acceptance_year >= 2001), - created_at timestamp not null default current_timestamp, - last_modified_at timestamp not null default current_timestamp -); - -create table ituser_website ( - id uuid constraint ituser_website_pk primary key, - ituser uuid not null references ituser, - website uuid not null references website_url -); - -create table authority_level ( - id uuid constraint authority_level_pk primary key, - authority_level varchar(30) -); - -create table password_reset_token( - id uuid constraint password_reset_token_pk primary key, - token varchar(100) not null, - ituser uuid references ituser -); - -create table fkit_super_group ( - id uuid constraint fkit_super_group_pk primary key, - name varchar(50) not null constraint fkit_super_group_name_unique unique, - pretty_name varchar(50) not null constraint fkit_super_group_pretty_name_unique unique, - email varchar(100) not null, - type varchar(30) not null -); - -create table fkit_group ( - id uuid constraint fkit_group_pk primary key, - name varchar(50) not null constraint fkit_group_name_unique unique, - pretty_name varchar(50) not null, - description uuid null references internal_text, - function uuid not null references internal_text, - becomes_active date not null, - becomes_inactive date not null, constraint inactive_after_inactive check (becomes_active < becomes_inactive), - fkit_super_group uuid not null references fkit_super_group, - email varchar(100) null, - avatar_url varchar(255) null -); - -create table post ( - id uuid constraint post_pk primary key, - post_name uuid not null references internal_text - -); - -create table authority ( - id uuid constraint authority_unique unique, - fkit_group_id uuid constraint authority_fkit_super_group_fk references fkit_super_group, - post_id uuid constraint authority_post references post, - authority_level uuid constraint authority_authority_level references authority_level, - constraint authority_pk primary key (post_id, fkit_group_id) -); - -create table fkit_group_website( - id uuid constraint fkit_group_website_pk primary key, - fkit_group uuid not null references fkit_group, - website uuid not null references website_url -); - - - -create table membership ( -- Should this be rebuilt to look like all other tables? probably - ituser_id uuid constraint membership_ituser_fk references ituser, - fkit_group_id uuid constraint membership_fkit_group_fk references fkit_group, - post_id uuid constraint membership_post_fk references post, - unofficial_post_name varchar(100) null, - constraint membership_pk primary key (ituser_id, fkit_group_id, post_id) -); - -create table no_account_membership ( - user_name varchar(20) not null, - fkit_group_id uuid constraint no_account_membership_fkit_group_fk references fkit_group, - post_id uuid not null constraint no_account_membership_post_fk references post, - unofficial_post_name varchar(100) null, - constraint no_account_membership_pk primary key (user_name, fkit_group_id) -); - -create table whitelist ( - id uuid constraint whitelist_pk primary key, - cid varchar(10) not null constraint whitelist_cid_unique unique -); - -create table activation_code ( - id uuid constraint activation_code_pk primary key, - cid uuid unique not null references whitelist, - code varchar(30) not null, - created_at timestamp not null default current_timestamp -); - -create table itclient ( - id uuid constraint itclient_pk primary key, - client_id varchar(256) not null, - client_secret varchar(256) not null, - web_server_redirect_uri varchar(256) not null, - --authorities varchar(256) not null, - access_token_validity integer not null, - refresh_token_validity integer not null, - auto_approve boolean default false not null, - name varchar(30) not null, - description uuid references internal_text, - created_at timestamp not null default current_timestamp, - last_modified_at timestamp not null default current_timestamp -); - -create table apikey ( - id uuid constraint apikey_pk primary key, - name varchar(30) not null, - description uuid references internal_text, - key varchar(150) not null, - created_at timestamp not null default current_timestamp, - last_modified_at timestamp not null default current_timestamp -) \ No newline at end of file diff --git a/backend/src/main/resources/mock/README.md b/backend/src/main/resources/mock/README.md deleted file mode 100644 index 19da7b3f1..000000000 --- a/backend/src/main/resources/mock/README.md +++ /dev/null @@ -1,81 +0,0 @@ -# Gamma Mocking -Using mock.json, or providing your .json file is an easy way to create users, groups, posts, and supergroups for usage when creating mock data in your application that uses gamma. By always providing the same ID:s, you can easily, for example, create a booking with a given user id that will be the same for everyone who tries to develop on your application and tries to use your mock data. - -Note that this file will only run if there's no admin user, i.e. the database is empty. - -The json document represents an object of `MockData.java`. `DbInitalizer.java` has the logic to actually insert the mock data into the database. But here's a quick overview of the different props that can be used: - -## `groups` - -Creates `FKITGroup`:s. Each object in the array is represented in code by `MockFKITGroup.java`. The available props are: - -* `id`: UUID -* `name`: String -* `prettyName`: String -* `active`: boolean -* `superGroup`: Object -* `members`: Array -* `function`: Object | null -* `description`: Object | null - -###`active` - -If `active` is false, then the `becomesActive` date will be a year ago, and `becomesInactive` will be yesterday. If `active` is true, then `becomesActive` will be yesterday and `becomesInactive` will be a year from now. - -### `members` - -An array of `MockMembership.java`. Props are: - -* `userId`: UUID -* `postId`: UUID -* `unofficialPostName`: String | null - -### `function` and `description` - -Are `Text.java` objects which means they take in an object that has the properties `sv` and `en`. The value for them are strings. - -### Other notes - -`email` will be `name` + @chalmers.it. - -##`users` - -Creates `ITUser.java`. Each object in the array is represented in code by `MockITUser.java`. The available props are: - -* `id`: UUID -* `cid`: String -* `nick`: String -* `firstName`: String -* `lastName`: String -* `acceptanceYear`: Year - -`acceptanceYear` can be a value between 2001 - current year. - -## `posts` - -Create `Post.java`. Each object in the array is represented in code by `MockPost.java`. The available props are: - -* `id`: UUID -* `postName`: Object - -### `postName` - -As with `function` and `description` in groups, `postName` is represented by the `Text.java` class. - -## `superGroups` - -Creates `FKITSuperGroup.java`. Each object in the array is represented in code by `MockFKITSuperGroup.java`. The available props are: - -* `id`: UUID -* `name`: String -* `prettyName`: String -* `type`: GroupType -* `groups`: Array - -### `type` - -An enum where the possible values are: `ADMIN`, `SOCIETY`, `COMMITTEE`, `BOARD`, `ALUMNI` and `FUNCTIONARIES`. - -### `groups` - -Only an array of UUID that represents a `FKITGroup`. \ No newline at end of file diff --git a/backend/src/main/resources/mock/mock.json b/backend/src/main/resources/mock/mock.json deleted file mode 100644 index 4f7abc34d..000000000 --- a/backend/src/main/resources/mock/mock.json +++ /dev/null @@ -1,432 +0,0 @@ -{ - "users": [ - { - "id": "88eec5c2-5ebb-4e13-9a76-fcc4dac9e74f", - "firstName": "Wyatt", - "lastName": "MacMakin", - "cid": "wmacmak", - "nick": "Chokladkaka", - "acceptanceYear": 2014 - }, - { - "id": "bc605869-9a4d-46ec-8a29-d00819d4c195", - "firstName": "Mellie", - "lastName": "Juorio", - "cid": "mjuorio", - "nick": "Kladdkaka", - "acceptanceYear": 2016 - }, - { - "id": "ec8987d7-4087-461d-bed5-9365086b6e3b", - "firstName": "Lane", - "lastName": "Twell", - "cid": "tltwell", - "nick": "Mylta", - "acceptanceYear": 2012 - }, - { - "id": "0c67c90b-dfdf-473a-98e3-b551e2f2f0f1", - "firstName": "Hy", - "lastName": "Borg-Bartolo", - "cid": "hborgba", - "nick": "Strössel", - "acceptanceYear": 2017 - }, - { - "id": "858e5acc-c289-40d3-9422-d6d317f40299", - "firstName": "Sorcha", - "lastName": "Vanni", - "cid": "svanni", - "nick": "Våffla", - "acceptanceYear": 2016 - }, - { - "id": "9ad8946d-cfef-4f6f-8b48-cfb536d0c9eb", - "firstName": "Hobey", - "lastName": "Spaarritt", - "cid": "hsparritt", - "nick": "Fruktsallad", - "acceptanceYear": 2007 - }, - { - "id": "4efb340f-540c-4b15-a362-d402aab10195", - "firstName": "Wolfy", - "lastName": "Bulloch", - "cid": "wbulloch", - "nick": "Crème brûlée", - "acceptanceYear": 2018 - }, - { - "id": "4542ab3d-7996-4097-ae4a-4fe61eaf2f20", - "firstName": "Dolly", - "lastName": "Mathy", - "cid": "dmathy", - "nick": "Glassbomb", - "acceptanceYear": 2017 - }, - { - "id": "4542ab3d-7996-4097-ae4a-4fe61eaf2f20", - "firstName": "Matelda", - "lastName": "Novotne", - "cid": "mnovotne", - "nick": "Chokladpudding", - "acceptanceYear": 2011 - }, - { - "id": "4542ab3d-7996-4097-ae4a-4fe61eaf2f20", - "firstName": "Farra", - "lastName": "Longshaw", - "cid": "flongshaw", - "nick": "Äppelmos", - "acceptanceYear": 2013 - }, - { - "id": "0a799f6d-c65a-4d20-8588-2ff5375d6cce", - "firstName": "Dorri", - "lastName": "Barneville", - "cid": "dbarnevi", - "nick": "Chokladtryffel", - "acceptanceYear": 2002 - }, - { - "id": "4fcf6566-45d8-4d5d-b7d4-4f6f52bb0ac2", - "firstName": "Alberik", - "lastName": "Nunson", - "cid": "anunson", - "nick": "O’hoj", - "acceptanceYear": 2004 - }, - { - "id": "e6a76e6a-3499-4611-ae28-e1281ffa6e80", - "firstName": "Joyce", - "lastName": "Hanhard", - "cid": "jhanhard", - "nick": "Marängsviss", - "acceptanceYear": 2016 - } - ], - "groups": [ - { - "id": "047ac437-a789-4cc5-bb6e-ba50efd7c509", - "name": "digit", - "prettyName": "digIT", - "active": false, - "superGroup": "364a359a-f9eb-4d81-bb99-25cc5adf176d", - "members": [ - { - "userId": "bc605869-9a4d-46ec-8a29-d00819d4c195", - "postId": "7bb1db15-730d-4864-bfc3-99abe7c0ccf8", - "unofficialPostName": "root" - }, - { - "userId": "ec8987d7-4087-461d-bed5-9365086b6e3b", - "postId": "844067b3-e95d-4a28-a586-7388f155b8fb", - "unofficialPostName": "cache-chef" - }, - { - "userId": "0c67c90b-dfdf-473a-98e3-b551e2f2f0f1", - "postId": "08efcf3a-1805-4b5f-a60e-da6ce0d33f58", - "unofficialPostName": "dev-ooops" - } - ] - }, - { - "id": "2abe2264-fd61-4899-ba46-851279d85229", - "name": "digit", - "prettyName": "digIT", - "active": true, - "superGroup": "aed27030-ad90-4526-855c-1e909b1dcecb", - "members": [ - { - "userId": "858e5acc-c289-40d3-9422-d6d317f40299", - "postId": "7bb1db15-730d-4864-bfc3-99abe7c0ccf8", - "unofficialPostName": "root" - }, - { - "userId": "9ad8946d-cfef-4f6f-8b48-cfb536d0c9eb", - "postId": "844067b3-e95d-4a28-a586-7388f155b8fb", - "unofficialPostName": "cache-chef" - }, - { - "userId": "4efb340f-540c-4b15-a362-d402aab10195", - "postId": "08efcf3a-1805-4b5f-a60e-da6ce0d33f58", - "unofficialPostName": "dev-ooops" - } - ] - }, - { - "id": "a2f06d3a-7432-4655-a778-69c9142912f1", - "name": "styrit", - "prettyName": "styrIT", - "active": false, - "superGroup": "30c2ee3b-b761-46d0-9029-215a9b484f7a", - "members": [ - { - "userId": "9ad8946d-cfef-4f6f-8b48-cfb536d0c9eb", - "postId": "7bb1db15-730d-4864-bfc3-99abe7c0ccf8", - "unofficialPostName": "Ordf" - }, - { - "userId": "bc605869-9a4d-46ec-8a29-d00819d4c195", - "postId": "844067b3-e95d-4a28-a586-7388f155b8fb", - "unofficialPostName": "Kassör" - }, - { - "userId": "4542ab3d-7996-4097-ae4a-4fe61eaf2f20", - "postId": "08efcf3a-1805-4b5f-a60e-da6ce0d33f58", - "unofficialPostName": "IT-ansvarig" - }, - { - "userId": "0a799f6d-c65a-4d20-8588-2ff5375d6cce", - "postId": "524db9a7-e8be-403e-a07c-a41803ea5ee7", - "unofficialPostName": "VO" - } - ] - }, - { - "id": "834651d1-34c1-4bac-b148-6546368a8454", - "name": "styrit", - "prettyName": "styrIT", - "active": true, - "superGroup": "2157ee72-04cd-4029-8d57-77142d3ef5fa", - "members": [ - { - "userId": "4fcf6566-45d8-4d5d-b7d4-4f6f52bb0ac2", - "postId": "7bb1db15-730d-4864-bfc3-99abe7c0ccf8", - "unofficialPostName": "Ordf" - }, - { - "userId": "bc605869-9a4d-46ec-8a29-d00819d4c195", - "postId": "844067b3-e95d-4a28-a586-7388f155b8fb", - "unofficialPostName": "Kassör" - }, - { - "userId": "ec8987d7-4087-461d-bed5-9365086b6e3b", - "postId": "08efcf3a-1805-4b5f-a60e-da6ce0d33f58", - "unofficialPostName": "IT-ansvarig" - }, - { - "userId": "0c67c90b-dfdf-473a-98e3-b551e2f2f0f1", - "postId": "524db9a7-e8be-403e-a07c-a41803ea5ee7", - "unofficialPostName": "VO" - } - ] - }, - { - "id": "672db849-8afb-4160-9f12-7f8c1d379fcc", - "name": "drawit", - "prettyName": "DrawIT", - "active": false, - "superGroup": "5a427d4d-adb7-4de7-9c87-a569014c7b58", - "members": [ - { - "userId": "858e5acc-c289-40d3-9422-d6d317f40299", - "postId": "7bb1db15-730d-4864-bfc3-99abe7c0ccf8", - "unofficialPostName": "Ordf" - }, - { - "userId": "9ad8946d-cfef-4f6f-8b48-cfb536d0c9eb", - "postId": "844067b3-e95d-4a28-a586-7388f155b8fb", - "unofficialPostName": "Kassör" - }, - { - "userId": "4efb340f-540c-4b15-a362-d402aab10195", - "postId": "08efcf3a-1805-4b5f-a60e-da6ce0d33f58", - "unofficialPostName": "Knapansvarig" - } - ] - }, - { - "id": "9b239de9-88a3-4992-96d1-b8dea2a637ec", - "name": "drawit", - "prettyName": "DrawIT", - "active": true, - "superGroup": "b8dbca3a-52e7-4299-9499-e58ec93a0c2c", - "members": [ - { - "userId": "4542ab3d-7996-4097-ae4a-4fe61eaf2f20", - "postId": "7bb1db15-730d-4864-bfc3-99abe7c0ccf8", - "unofficialPostName": "Ordf" - }, - { - "userId": "4542ab3d-7996-4097-ae4a-4fe61eaf2f20", - "postId": "844067b3-e95d-4a28-a586-7388f155b8fb", - "unofficialPostName": "Kassör" - }, - { - "userId": "4542ab3d-7996-4097-ae4a-4fe61eaf2f20", - "postId": "08efcf3a-1805-4b5f-a60e-da6ce0d33f58", - "unofficialPostName": "Knapansvarig" - } - ] - }, - { - "id": "5f26a10c-e668-4ec1-b072-a7dd8f11735c", - "name": "prit", - "prettyName": "P.R.I.T.", - "active": false, - "superGroup": "326807b4-ae68-4626-8382-919a15a8e23c", - "members": [ - { - "userId": "0a799f6d-c65a-4d20-8588-2ff5375d6cce", - "postId": "7bb1db15-730d-4864-bfc3-99abe7c0ccf8", - "unofficialPostName": "ChefChef" - }, - { - "userId": "e6a76e6a-3499-4611-ae28-e1281ffa6e80", - "postId": "844067b3-e95d-4a28-a586-7388f155b8fb", - "unofficialPostName": "Ka$$Chef" - }, - { - "userId": "4542ab3d-7996-4097-ae4a-4fe61eaf2f20", - "postId": "08efcf3a-1805-4b5f-a60e-da6ce0d33f58", - "unofficialPostName": "BösChef" - } - ] - }, - { - "id": "1ed91274-13c8-4d6d-ab75-37c9d732b51b", - "name": "prit", - "prettyName": "P.R.I.T.", - "active": true, - "superGroup": "b3bcbbcc-0b93-4c41-a3c7-1792448c6fc1", - "members": [ - { - "userId": "bc605869-9a4d-46ec-8a29-d00819d4c195", - "postId": "7bb1db15-730d-4864-bfc3-99abe7c0ccf8", - "unofficialPostName": "ChefChef" - }, - { - "userId": "ec8987d7-4087-461d-bed5-9365086b6e3b", - "postId": "844067b3-e95d-4a28-a586-7388f155b8fb", - "unofficialPostName": "Ka$$Chef" - }, - { - "userId": "0c67c90b-dfdf-473a-98e3-b551e2f2f0f1", - "postId": "08efcf3a-1805-4b5f-a60e-da6ce0d33f58", - "unofficialPostName": "BösChef" - } - ] - }, - { - "id": "ee4153d5-830d-445f-acb3-ec09c53e7c0c", - "name": "kandidatmiddagen", - "prettyName": "Kandidatmiddagen", - "active": true, - "superGroup": "712e21f5-f3c6-49fc-a9e7-5b7ec3ff31ab", - "members": [ - { - "userId": "858e5acc-c289-40d3-9422-d6d317f40299", - "postId": "7bb1db15-730d-4864-bfc3-99abe7c0ccf8" - }, - { - "userId": "9ad8946d-cfef-4f6f-8b48-cfb536d0c9eb", - "postId": "08efcf3a-1805-4b5f-a60e-da6ce0d33f58" - }, - { - "userId": "4efb340f-540c-4b15-a362-d402aab10195", - "postId": "08efcf3a-1805-4b5f-a60e-da6ce0d33f58" - }, - { - "userId": "4542ab3d-7996-4097-ae4a-4fe61eaf2f20", - "postId": "08efcf3a-1805-4b5f-a60e-da6ce0d33f58" - } - ] - } - ], - "superGroups": [ - { - "id": "aed27030-ad90-4526-855c-1e909b1dcecb", - "name": "digit", - "prettyName": "digIT", - "type": "COMMITTEE", - "groups": ["2abe2264-fd61-4899-ba46-851279d85229"] - }, - { - "id": "2157ee72-04cd-4029-8d57-77142d3ef5fa", - "name": "styrit", - "prettyName": "styrIT", - "type": "BOARD", - "groups": ["834651d1-34c1-4bac-b148-6546368a8454"] - }, - { - "id": "b8dbca3a-52e7-4299-9499-e58ec93a0c2c", - "name": "drawit", - "prettyName": "DrawIT", - "type": "SOCIETY", - "groups": ["9b239de9-88a3-4992-96d1-b8dea2a637ec"] - }, - { - "id": "b3bcbbcc-0b93-4c41-a3c7-1792448c6fc1", - "name": "prit", - "prettyName": "P.R.I.T.", - "type": "COMMITTEE", - "groups": ["1ed91274-13c8-4d6d-ab75-37c9d732b51b"] - }, - { - "id": "364a359a-f9eb-4d81-bb99-25cc5adf176d", - "name": "didit", - "prettyName": "didIT", - "type": "ALUMNI", - "groups": ["047ac437-a789-4cc5-bb6e-ba50efd7c509"] - }, - { - "id": "30c2ee3b-b761-46d0-9029-215a9b484f7a", - "name": "emeritus", - "prettyName": "EmerITus", - "type": "ALUMNI", - "groups": ["a2f06d3a-7432-4655-a778-69c9142912f1"] - }, - { - "id": "5a427d4d-adb7-4de7-9c87-a569014c7b58", - "name": "dragit", - "prettyName": "DragIT", - "type": "ALUMNI", - "groups": ["672db849-8afb-4160-9f12-7f8c1d379fcc"] - }, - { - "id": "326807b4-ae68-4626-8382-919a15a8e23c", - "name": "sprit", - "prettyName": "S.P.R.I.T.", - "type": "ALUMNI", - "groups": ["5f26a10c-e668-4ec1-b072-a7dd8f11735c"] - }, - { - "id": "712e21f5-f3c6-49fc-a9e7-5b7ec3ff31ab", - "name": "kandidatmiddagen", - "prettyName": "Kandidatmiddagen", - "type": "FUNCTIONARIES", - "groups": ["ee4153d5-830d-445f-acb3-ec09c53e7c0c"] - } - ], - "posts": [ - { - "id": "7bb1db15-730d-4864-bfc3-99abe7c0ccf8", - "postName": { - "sv": "Ordförande", - "en": "Chairman" - } - }, - { - "id": "844067b3-e95d-4a28-a586-7388f155b8fb", - "postName": { - "sv": "Kassör", - "en": "Treasurer" - } - }, - { - "id": "08efcf3a-1805-4b5f-a60e-da6ce0d33f58", - "postName": { - "sv": "Ledamot", - "en": "Member" - } - }, - { - "id": "524db9a7-e8be-403e-a07c-a41803ea5ee7", - "postName": { - "sv": "Vice Ordförande", - "en": "Vice-chairman" - } - } - ] -} diff --git a/backend/src/main/resources/static/css/main.css b/backend/src/main/resources/static/css/main.css deleted file mode 100644 index 02f5cf5d9..000000000 --- a/backend/src/main/resources/static/css/main.css +++ /dev/null @@ -1,152 +0,0 @@ - -*{ - --mdc-theme-primary: #2196F3; - --mdc-theme-secondary: #2196F3; -} - -.mdc-text-field--focused:not(.mdc-text-field--disabled) .mdc-floating-label { - color: var(--mdc-theme-primary) !important; -} - -body { - margin: 0; - height: 100vh; -} - -canvas { - position: absolute; - z-index: 1; -} - -body { - background: black; - margin: 0; -} - -.fadeInBackground { - width: 100vw; - height: 100vh; - position: absolute; - - animation-name: fadeIn; - animation-iteration-count: 1; - animation-timing-function: ease-in-out; - animation-duration: 0.5s; - animation-fill-mode:forwards; - - object-fit: cover; - object-position: center; -} - -@keyframes fadeIn { - 0% { - opacity: 0; - } - 100% { - opacity: 1; - } -} - -footer { - text-align: center; - color: white; - - position: absolute; - bottom: 8px; - width: 100%; -} - -#it-logo{ - width:50px; - height:50px; -} - -.text{ - font-size: 16px; - font-weight: normal; - margin: 0px; -} - -.center-vertical{ - display:block; - margin-top: auto; - margin-bottom: auto; -} - -.text--large{ - font-size: 23px; - font-weight: 900; -} - -.text--small{ - font-size: 13px !important; -} - -.text--roboto{ - font-family: "Roboto", serif; -} - -.card{ - margin: auto; - - display: flex; - flex-direction: column; - - max-width: 280px; - min-width: 250px; - - padding: 16px; - - background-color: white; -} - -.padding{ - display: block; - width: 16px; - height: 16px; -} - -.row{ - display: flex; - flex-direction: row; -} - -.row--space-between{ - justify-content: space-between; -} - -.black-color{ - color: black !important; -} - -hr{ - display: block; - height: 1px; - border: 0; - border-top: 1px solid #bbb; - margin: 0px; - margin-top: 8px; - padding: 0; -} - -.centerCard { - position: absolute; - z-index: 2; - width: 100%; - height: 100%; - - flex-grow: 1; - flex-shrink: 1; - - display: grid; - grid-template-columns: auto; - grid-template-rows: auto; - justify-content: center; - align-content: center; -} - -footer { - z-index: 2; - position: absolute; - bottom: 16px; -} \ No newline at end of file diff --git a/backend/src/main/resources/static/css/mcw.min.css b/backend/src/main/resources/static/css/mcw.min.css deleted file mode 100644 index 6056e53ea..000000000 --- a/backend/src/main/resources/static/css/mcw.min.css +++ /dev/null @@ -1,10 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://github.com/material-components/material-components-web/blob/master/LICENSE - */ -.mdc-touch-target-wrapper{display:inline}.mdc-elevation-overlay{position:absolute;border-radius:inherit;opacity:0;pointer-events:none;transition:opacity 280ms cubic-bezier(0.4, 0, 0.2, 1);background-color:#fff}.mdc-button{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-button-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:.875rem;font-size:var(--mdc-typography-button-font-size, 0.875rem);line-height:2.25rem;line-height:var(--mdc-typography-button-line-height, 2.25rem);font-weight:500;font-weight:var(--mdc-typography-button-font-weight, 500);letter-spacing:.0892857143em;letter-spacing:var(--mdc-typography-button-letter-spacing, 0.0892857143em);text-decoration:none;-webkit-text-decoration:var(--mdc-typography-button-text-decoration, none);text-decoration:var(--mdc-typography-button-text-decoration, none);text-transform:uppercase;text-transform:var(--mdc-typography-button-text-transform, uppercase);padding:0 8px 0 8px;position:relative;display:inline-flex;align-items:center;justify-content:center;box-sizing:border-box;min-width:64px;border:none;outline:none;line-height:inherit;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-appearance:none;overflow:visible;vertical-align:middle;border-radius:4px}.mdc-button .mdc-elevation-overlay{width:100%;height:100%;top:0;left:0}.mdc-button::-moz-focus-inner{padding:0;border:0}.mdc-button:active{outline:none}.mdc-button:hover{cursor:pointer}.mdc-button:disabled{cursor:default;pointer-events:none}.mdc-button .mdc-button__ripple{border-radius:4px}.mdc-button:not(:disabled){background-color:transparent}.mdc-button:disabled{background-color:transparent}.mdc-button .mdc-button__icon{margin-left:0;margin-right:8px;display:inline-block;width:18px;height:18px;font-size:18px;vertical-align:top}[dir=rtl] .mdc-button .mdc-button__icon,.mdc-button .mdc-button__icon[dir=rtl]{margin-left:8px;margin-right:0}.mdc-button .mdc-button__touch{position:absolute;top:50%;right:0;height:48px;left:0;-webkit-transform:translateY(-50%);transform:translateY(-50%)}.mdc-button:not(:disabled){color:#6200ee;color:var(--mdc-theme-primary, #6200ee)}.mdc-button:disabled{color:rgba(0,0,0,.38)}.mdc-button__label+.mdc-button__icon{margin-left:8px;margin-right:0}[dir=rtl] .mdc-button__label+.mdc-button__icon,.mdc-button__label+.mdc-button__icon[dir=rtl]{margin-left:0;margin-right:8px}svg.mdc-button__icon{fill:currentColor}.mdc-button--raised .mdc-button__icon,.mdc-button--unelevated .mdc-button__icon,.mdc-button--outlined .mdc-button__icon{margin-left:-4px;margin-right:8px}[dir=rtl] .mdc-button--raised .mdc-button__icon,.mdc-button--raised .mdc-button__icon[dir=rtl],[dir=rtl] .mdc-button--unelevated .mdc-button__icon,.mdc-button--unelevated .mdc-button__icon[dir=rtl],[dir=rtl] .mdc-button--outlined .mdc-button__icon,.mdc-button--outlined .mdc-button__icon[dir=rtl]{margin-left:8px;margin-right:-4px}.mdc-button--raised .mdc-button__label+.mdc-button__icon,.mdc-button--unelevated .mdc-button__label+.mdc-button__icon,.mdc-button--outlined .mdc-button__label+.mdc-button__icon{margin-left:8px;margin-right:-4px}[dir=rtl] .mdc-button--raised .mdc-button__label+.mdc-button__icon,.mdc-button--raised .mdc-button__label+.mdc-button__icon[dir=rtl],[dir=rtl] .mdc-button--unelevated .mdc-button__label+.mdc-button__icon,.mdc-button--unelevated .mdc-button__label+.mdc-button__icon[dir=rtl],[dir=rtl] .mdc-button--outlined .mdc-button__label+.mdc-button__icon,.mdc-button--outlined .mdc-button__label+.mdc-button__icon[dir=rtl]{margin-left:-4px;margin-right:8px}.mdc-button--raised,.mdc-button--unelevated{padding:0 16px 0 16px}.mdc-button--raised:not(:disabled),.mdc-button--unelevated:not(:disabled){background-color:#6200ee;background-color:var(--mdc-theme-primary, #6200ee)}.mdc-button--raised:not(:disabled),.mdc-button--unelevated:not(:disabled){color:#fff;color:var(--mdc-theme-on-primary, #fff)}.mdc-button--raised:disabled,.mdc-button--unelevated:disabled{background-color:rgba(0,0,0,.12)}.mdc-button--raised:disabled,.mdc-button--unelevated:disabled{color:rgba(0,0,0,.38)}.mdc-button--raised{box-shadow:0px 3px 1px -2px rgba(0, 0, 0, 0.2),0px 2px 2px 0px rgba(0, 0, 0, 0.14),0px 1px 5px 0px rgba(0,0,0,.12);transition:box-shadow 280ms cubic-bezier(0.4, 0, 0.2, 1)}.mdc-button--raised:hover,.mdc-button--raised:focus{box-shadow:0px 2px 4px -1px rgba(0, 0, 0, 0.2),0px 4px 5px 0px rgba(0, 0, 0, 0.14),0px 1px 10px 0px rgba(0,0,0,.12)}.mdc-button--raised:active{box-shadow:0px 5px 5px -3px rgba(0, 0, 0, 0.2),0px 8px 10px 1px rgba(0, 0, 0, 0.14),0px 3px 14px 2px rgba(0,0,0,.12)}.mdc-button--raised:disabled{box-shadow:0px 0px 0px 0px rgba(0, 0, 0, 0.2),0px 0px 0px 0px rgba(0, 0, 0, 0.14),0px 0px 0px 0px rgba(0,0,0,.12)}.mdc-button--outlined{padding:0 15px 0 15px;border-width:1px;border-style:solid}.mdc-button--outlined .mdc-button__ripple{top:-1px;left:-1px;border:1px solid transparent}.mdc-button--outlined .mdc-button__touch{left:-1px;width:calc(100% + 2 * 1px)}.mdc-button--outlined:not(:disabled){border-color:rgba(0,0,0,.12)}.mdc-button--outlined:disabled{border-color:rgba(0,0,0,.12)}.mdc-button--touch{margin-top:6px;margin-bottom:6px}@-webkit-keyframes mdc-ripple-fg-radius-in{from{-webkit-animation-timing-function:cubic-bezier(0.4, 0, 0.2, 1);animation-timing-function:cubic-bezier(0.4, 0, 0.2, 1);-webkit-transform:translate(var(--mdc-ripple-fg-translate-start, 0)) scale(1);transform:translate(var(--mdc-ripple-fg-translate-start, 0)) scale(1)}to{-webkit-transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1))}}@keyframes mdc-ripple-fg-radius-in{from{-webkit-animation-timing-function:cubic-bezier(0.4, 0, 0.2, 1);animation-timing-function:cubic-bezier(0.4, 0, 0.2, 1);-webkit-transform:translate(var(--mdc-ripple-fg-translate-start, 0)) scale(1);transform:translate(var(--mdc-ripple-fg-translate-start, 0)) scale(1)}to{-webkit-transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1))}}@-webkit-keyframes mdc-ripple-fg-opacity-in{from{-webkit-animation-timing-function:linear;animation-timing-function:linear;opacity:0}to{opacity:var(--mdc-ripple-fg-opacity, 0)}}@keyframes mdc-ripple-fg-opacity-in{from{-webkit-animation-timing-function:linear;animation-timing-function:linear;opacity:0}to{opacity:var(--mdc-ripple-fg-opacity, 0)}}@-webkit-keyframes mdc-ripple-fg-opacity-out{from{-webkit-animation-timing-function:linear;animation-timing-function:linear;opacity:var(--mdc-ripple-fg-opacity, 0)}to{opacity:0}}@keyframes mdc-ripple-fg-opacity-out{from{-webkit-animation-timing-function:linear;animation-timing-function:linear;opacity:var(--mdc-ripple-fg-opacity, 0)}to{opacity:0}}.mdc-button{--mdc-ripple-fg-size: 0;--mdc-ripple-left: 0;--mdc-ripple-top: 0;--mdc-ripple-fg-scale: 1;--mdc-ripple-fg-translate-end: 0;--mdc-ripple-fg-translate-start: 0;-webkit-tap-highlight-color:rgba(0,0,0,0)}.mdc-button .mdc-button__ripple::before,.mdc-button .mdc-button__ripple::after{position:absolute;border-radius:50%;opacity:0;pointer-events:none;content:""}.mdc-button .mdc-button__ripple::before{transition:opacity 15ms linear,background-color 15ms linear;z-index:1}.mdc-button.mdc-ripple-upgraded .mdc-button__ripple::before{-webkit-transform:scale(var(--mdc-ripple-fg-scale, 1));transform:scale(var(--mdc-ripple-fg-scale, 1))}.mdc-button.mdc-ripple-upgraded .mdc-button__ripple::after{top:0;left:0;-webkit-transform:scale(0);transform:scale(0);-webkit-transform-origin:center center;transform-origin:center center}.mdc-button.mdc-ripple-upgraded--unbounded .mdc-button__ripple::after{top:var(--mdc-ripple-top, 0);left:var(--mdc-ripple-left, 0)}.mdc-button.mdc-ripple-upgraded--foreground-activation .mdc-button__ripple::after{-webkit-animation:mdc-ripple-fg-radius-in 225ms forwards,mdc-ripple-fg-opacity-in 75ms forwards;animation:mdc-ripple-fg-radius-in 225ms forwards,mdc-ripple-fg-opacity-in 75ms forwards}.mdc-button.mdc-ripple-upgraded--foreground-deactivation .mdc-button__ripple::after{-webkit-animation:mdc-ripple-fg-opacity-out 150ms;animation:mdc-ripple-fg-opacity-out 150ms;-webkit-transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1))}.mdc-button .mdc-button__ripple::before,.mdc-button .mdc-button__ripple::after{top:calc(50% - 100%);left:calc(50% - 100%);width:200%;height:200%}.mdc-button.mdc-ripple-upgraded .mdc-button__ripple::after{width:var(--mdc-ripple-fg-size, 100%);height:var(--mdc-ripple-fg-size, 100%)}.mdc-button .mdc-button__ripple::before,.mdc-button .mdc-button__ripple::after{background-color:#6200ee;background-color:var(--mdc-theme-primary, #6200ee)}.mdc-button:hover .mdc-button__ripple::before{opacity:.04}.mdc-button.mdc-ripple-upgraded--background-focused .mdc-button__ripple::before,.mdc-button:not(.mdc-ripple-upgraded):focus .mdc-button__ripple::before{transition-duration:75ms;opacity:.12}.mdc-button:not(.mdc-ripple-upgraded) .mdc-button__ripple::after{transition:opacity 150ms linear}.mdc-button:not(.mdc-ripple-upgraded):active .mdc-button__ripple::after{transition-duration:75ms;opacity:.12}.mdc-button.mdc-ripple-upgraded{--mdc-ripple-fg-opacity: 0.12}.mdc-button .mdc-button__ripple{position:absolute;box-sizing:content-box;width:100%;height:100%;overflow:hidden}.mdc-button:not(.mdc-button--outlined) .mdc-button__ripple{top:0;left:0}.mdc-button--raised .mdc-button__ripple::before,.mdc-button--raised .mdc-button__ripple::after,.mdc-button--unelevated .mdc-button__ripple::before,.mdc-button--unelevated .mdc-button__ripple::after{background-color:#fff;background-color:var(--mdc-theme-on-primary, #fff)}.mdc-button--raised:hover .mdc-button__ripple::before,.mdc-button--unelevated:hover .mdc-button__ripple::before{opacity:.08}.mdc-button--raised.mdc-ripple-upgraded--background-focused .mdc-button__ripple::before,.mdc-button--raised:not(.mdc-ripple-upgraded):focus .mdc-button__ripple::before,.mdc-button--unelevated.mdc-ripple-upgraded--background-focused .mdc-button__ripple::before,.mdc-button--unelevated:not(.mdc-ripple-upgraded):focus .mdc-button__ripple::before{transition-duration:75ms;opacity:.24}.mdc-button--raised:not(.mdc-ripple-upgraded) .mdc-button__ripple::after,.mdc-button--unelevated:not(.mdc-ripple-upgraded) .mdc-button__ripple::after{transition:opacity 150ms linear}.mdc-button--raised:not(.mdc-ripple-upgraded):active .mdc-button__ripple::after,.mdc-button--unelevated:not(.mdc-ripple-upgraded):active .mdc-button__ripple::after{transition-duration:75ms;opacity:.24}.mdc-button--raised.mdc-ripple-upgraded,.mdc-button--unelevated.mdc-ripple-upgraded{--mdc-ripple-fg-opacity: 0.24}.mdc-button{height:36px}.mdc-card{border-radius:4px;background-color:#fff;background-color:var(--mdc-theme-surface, #fff);position:relative;box-shadow:0px 2px 1px -1px rgba(0, 0, 0, 0.2),0px 1px 1px 0px rgba(0, 0, 0, 0.14),0px 1px 3px 0px rgba(0,0,0,.12);display:flex;flex-direction:column;box-sizing:border-box}.mdc-card .mdc-elevation-overlay{width:100%;height:100%;top:0;left:0}.mdc-card--outlined{box-shadow:0px 0px 0px 0px rgba(0, 0, 0, 0.2),0px 0px 0px 0px rgba(0, 0, 0, 0.14),0px 0px 0px 0px rgba(0,0,0,.12);border-width:1px;border-style:solid;border-color:#e0e0e0}.mdc-card__media{position:relative;box-sizing:border-box;background-repeat:no-repeat;background-position:center;background-size:cover}.mdc-card__media::before{display:block;content:""}.mdc-card__media:first-child{border-top-left-radius:inherit;border-top-right-radius:inherit}.mdc-card__media:last-child{border-bottom-left-radius:inherit;border-bottom-right-radius:inherit}.mdc-card__media--square::before{margin-top:100%}.mdc-card__media--16-9::before{margin-top:56.25%}.mdc-card__media-content{position:absolute;top:0;right:0;bottom:0;left:0;box-sizing:border-box}.mdc-card__primary-action{display:flex;flex-direction:column;box-sizing:border-box;position:relative;outline:none;color:inherit;text-decoration:none;cursor:pointer;overflow:hidden}.mdc-card__primary-action:first-child{border-top-left-radius:inherit;border-top-right-radius:inherit}.mdc-card__primary-action:last-child{border-bottom-left-radius:inherit;border-bottom-right-radius:inherit}.mdc-card__actions{display:flex;flex-direction:row;align-items:center;box-sizing:border-box;min-height:52px;padding:8px}.mdc-card__actions--full-bleed{padding:0}.mdc-card__action-buttons,.mdc-card__action-icons{display:flex;flex-direction:row;align-items:center;box-sizing:border-box}.mdc-card__action-icons{color:rgba(0,0,0,.6);flex-grow:1;justify-content:flex-end}.mdc-card__action-buttons+.mdc-card__action-icons{margin-left:16px;margin-right:0}[dir=rtl] .mdc-card__action-buttons+.mdc-card__action-icons,.mdc-card__action-buttons+.mdc-card__action-icons[dir=rtl]{margin-left:0;margin-right:16px}.mdc-card__action{display:inline-flex;flex-direction:row;align-items:center;box-sizing:border-box;justify-content:center;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.mdc-card__action:focus{outline:none}.mdc-card__action--button{margin-left:0;margin-right:8px;padding:0 8px}[dir=rtl] .mdc-card__action--button,.mdc-card__action--button[dir=rtl]{margin-left:8px;margin-right:0}.mdc-card__action--button:last-child{margin-left:0;margin-right:0}[dir=rtl] .mdc-card__action--button:last-child,.mdc-card__action--button:last-child[dir=rtl]{margin-left:0;margin-right:0}.mdc-card__actions--full-bleed .mdc-card__action--button{justify-content:space-between;width:100%;height:auto;max-height:none;margin:0;padding:8px 16px;text-align:left}[dir=rtl] .mdc-card__actions--full-bleed .mdc-card__action--button,.mdc-card__actions--full-bleed .mdc-card__action--button[dir=rtl]{text-align:right}.mdc-card__action--icon{margin:-6px 0;padding:12px}.mdc-card__action--icon:not(:disabled){color:rgba(0,0,0,.6)}.mdc-card__primary-action{--mdc-ripple-fg-size: 0;--mdc-ripple-left: 0;--mdc-ripple-top: 0;--mdc-ripple-fg-scale: 1;--mdc-ripple-fg-translate-end: 0;--mdc-ripple-fg-translate-start: 0;-webkit-tap-highlight-color:rgba(0,0,0,0)}.mdc-card__primary-action::before,.mdc-card__primary-action::after{position:absolute;border-radius:50%;opacity:0;pointer-events:none;content:""}.mdc-card__primary-action::before{transition:opacity 15ms linear,background-color 15ms linear;z-index:1}.mdc-card__primary-action.mdc-ripple-upgraded::before{-webkit-transform:scale(var(--mdc-ripple-fg-scale, 1));transform:scale(var(--mdc-ripple-fg-scale, 1))}.mdc-card__primary-action.mdc-ripple-upgraded::after{top:0;left:0;-webkit-transform:scale(0);transform:scale(0);-webkit-transform-origin:center center;transform-origin:center center}.mdc-card__primary-action.mdc-ripple-upgraded--unbounded::after{top:var(--mdc-ripple-top, 0);left:var(--mdc-ripple-left, 0)}.mdc-card__primary-action.mdc-ripple-upgraded--foreground-activation::after{-webkit-animation:mdc-ripple-fg-radius-in 225ms forwards,mdc-ripple-fg-opacity-in 75ms forwards;animation:mdc-ripple-fg-radius-in 225ms forwards,mdc-ripple-fg-opacity-in 75ms forwards}.mdc-card__primary-action.mdc-ripple-upgraded--foreground-deactivation::after{-webkit-animation:mdc-ripple-fg-opacity-out 150ms;animation:mdc-ripple-fg-opacity-out 150ms;-webkit-transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1))}.mdc-card__primary-action::before,.mdc-card__primary-action::after{top:calc(50% - 100%);left:calc(50% - 100%);width:200%;height:200%}.mdc-card__primary-action.mdc-ripple-upgraded::after{width:var(--mdc-ripple-fg-size, 100%);height:var(--mdc-ripple-fg-size, 100%)}.mdc-card__primary-action::before,.mdc-card__primary-action::after{background-color:#000}.mdc-card__primary-action:hover::before{opacity:.04}.mdc-card__primary-action.mdc-ripple-upgraded--background-focused::before,.mdc-card__primary-action:not(.mdc-ripple-upgraded):focus::before{transition-duration:75ms;opacity:.12}.mdc-card__primary-action:not(.mdc-ripple-upgraded)::after{transition:opacity 150ms linear}.mdc-card__primary-action:not(.mdc-ripple-upgraded):active::after{transition-duration:75ms;opacity:.12}.mdc-card__primary-action.mdc-ripple-upgraded{--mdc-ripple-fg-opacity: 0.12}@-webkit-keyframes mdc-checkbox-unchecked-checked-checkmark-path{0%,50%{stroke-dashoffset:29.7833385}50%{-webkit-animation-timing-function:cubic-bezier(0, 0, 0.2, 1);animation-timing-function:cubic-bezier(0, 0, 0.2, 1)}100%{stroke-dashoffset:0}}@keyframes mdc-checkbox-unchecked-checked-checkmark-path{0%,50%{stroke-dashoffset:29.7833385}50%{-webkit-animation-timing-function:cubic-bezier(0, 0, 0.2, 1);animation-timing-function:cubic-bezier(0, 0, 0.2, 1)}100%{stroke-dashoffset:0}}@-webkit-keyframes mdc-checkbox-unchecked-indeterminate-mixedmark{0%,68.2%{-webkit-transform:scaleX(0);transform:scaleX(0)}68.2%{-webkit-animation-timing-function:cubic-bezier(0, 0, 0, 1);animation-timing-function:cubic-bezier(0, 0, 0, 1)}100%{-webkit-transform:scaleX(1);transform:scaleX(1)}}@keyframes mdc-checkbox-unchecked-indeterminate-mixedmark{0%,68.2%{-webkit-transform:scaleX(0);transform:scaleX(0)}68.2%{-webkit-animation-timing-function:cubic-bezier(0, 0, 0, 1);animation-timing-function:cubic-bezier(0, 0, 0, 1)}100%{-webkit-transform:scaleX(1);transform:scaleX(1)}}@-webkit-keyframes mdc-checkbox-checked-unchecked-checkmark-path{from{-webkit-animation-timing-function:cubic-bezier(0.4, 0, 1, 1);animation-timing-function:cubic-bezier(0.4, 0, 1, 1);opacity:1;stroke-dashoffset:0}to{opacity:0;stroke-dashoffset:-29.7833385}}@keyframes mdc-checkbox-checked-unchecked-checkmark-path{from{-webkit-animation-timing-function:cubic-bezier(0.4, 0, 1, 1);animation-timing-function:cubic-bezier(0.4, 0, 1, 1);opacity:1;stroke-dashoffset:0}to{opacity:0;stroke-dashoffset:-29.7833385}}@-webkit-keyframes mdc-checkbox-checked-indeterminate-checkmark{from{-webkit-animation-timing-function:cubic-bezier(0, 0, 0.2, 1);animation-timing-function:cubic-bezier(0, 0, 0.2, 1);-webkit-transform:rotate(0deg);transform:rotate(0deg);opacity:1}to{-webkit-transform:rotate(45deg);transform:rotate(45deg);opacity:0}}@keyframes mdc-checkbox-checked-indeterminate-checkmark{from{-webkit-animation-timing-function:cubic-bezier(0, 0, 0.2, 1);animation-timing-function:cubic-bezier(0, 0, 0.2, 1);-webkit-transform:rotate(0deg);transform:rotate(0deg);opacity:1}to{-webkit-transform:rotate(45deg);transform:rotate(45deg);opacity:0}}@-webkit-keyframes mdc-checkbox-indeterminate-checked-checkmark{from{-webkit-animation-timing-function:cubic-bezier(0.14, 0, 0, 1);animation-timing-function:cubic-bezier(0.14, 0, 0, 1);-webkit-transform:rotate(45deg);transform:rotate(45deg);opacity:0}to{-webkit-transform:rotate(360deg);transform:rotate(360deg);opacity:1}}@keyframes mdc-checkbox-indeterminate-checked-checkmark{from{-webkit-animation-timing-function:cubic-bezier(0.14, 0, 0, 1);animation-timing-function:cubic-bezier(0.14, 0, 0, 1);-webkit-transform:rotate(45deg);transform:rotate(45deg);opacity:0}to{-webkit-transform:rotate(360deg);transform:rotate(360deg);opacity:1}}@-webkit-keyframes mdc-checkbox-checked-indeterminate-mixedmark{from{-webkit-animation-timing-function:mdc-animation-deceleration-curve-timing-function;animation-timing-function:mdc-animation-deceleration-curve-timing-function;-webkit-transform:rotate(-45deg);transform:rotate(-45deg);opacity:0}to{-webkit-transform:rotate(0deg);transform:rotate(0deg);opacity:1}}@keyframes mdc-checkbox-checked-indeterminate-mixedmark{from{-webkit-animation-timing-function:mdc-animation-deceleration-curve-timing-function;animation-timing-function:mdc-animation-deceleration-curve-timing-function;-webkit-transform:rotate(-45deg);transform:rotate(-45deg);opacity:0}to{-webkit-transform:rotate(0deg);transform:rotate(0deg);opacity:1}}@-webkit-keyframes mdc-checkbox-indeterminate-checked-mixedmark{from{-webkit-animation-timing-function:cubic-bezier(0.14, 0, 0, 1);animation-timing-function:cubic-bezier(0.14, 0, 0, 1);-webkit-transform:rotate(0deg);transform:rotate(0deg);opacity:1}to{-webkit-transform:rotate(315deg);transform:rotate(315deg);opacity:0}}@keyframes mdc-checkbox-indeterminate-checked-mixedmark{from{-webkit-animation-timing-function:cubic-bezier(0.14, 0, 0, 1);animation-timing-function:cubic-bezier(0.14, 0, 0, 1);-webkit-transform:rotate(0deg);transform:rotate(0deg);opacity:1}to{-webkit-transform:rotate(315deg);transform:rotate(315deg);opacity:0}}@-webkit-keyframes mdc-checkbox-indeterminate-unchecked-mixedmark{0%{-webkit-animation-timing-function:linear;animation-timing-function:linear;-webkit-transform:scaleX(1);transform:scaleX(1);opacity:1}32.8%,100%{-webkit-transform:scaleX(0);transform:scaleX(0);opacity:0}}@keyframes mdc-checkbox-indeterminate-unchecked-mixedmark{0%{-webkit-animation-timing-function:linear;animation-timing-function:linear;-webkit-transform:scaleX(1);transform:scaleX(1);opacity:1}32.8%,100%{-webkit-transform:scaleX(0);transform:scaleX(0);opacity:0}}.mdc-checkbox{display:inline-block;position:relative;flex:0 0 18px;box-sizing:content-box;width:18px;height:18px;line-height:0;white-space:nowrap;cursor:pointer;vertical-align:bottom;padding:11px}.mdc-checkbox .mdc-checkbox__native-control:checked~.mdc-checkbox__background::before,.mdc-checkbox .mdc-checkbox__native-control:indeterminate~.mdc-checkbox__background::before,.mdc-checkbox .mdc-checkbox__native-control[data-indeterminate=true]~.mdc-checkbox__background::before{background-color:#018786;background-color:var(--mdc-theme-secondary, #018786)}.mdc-checkbox.mdc-checkbox--selected .mdc-checkbox__ripple::before,.mdc-checkbox.mdc-checkbox--selected .mdc-checkbox__ripple::after{background-color:#018786;background-color:var(--mdc-theme-secondary, #018786)}.mdc-checkbox.mdc-checkbox--selected:hover .mdc-checkbox__ripple::before{opacity:.04}.mdc-checkbox.mdc-checkbox--selected.mdc-ripple-upgraded--background-focused .mdc-checkbox__ripple::before,.mdc-checkbox.mdc-checkbox--selected:not(.mdc-ripple-upgraded):focus .mdc-checkbox__ripple::before{transition-duration:75ms;opacity:.12}.mdc-checkbox.mdc-checkbox--selected:not(.mdc-ripple-upgraded) .mdc-checkbox__ripple::after{transition:opacity 150ms linear}.mdc-checkbox.mdc-checkbox--selected:not(.mdc-ripple-upgraded):active .mdc-checkbox__ripple::after{transition-duration:75ms;opacity:.12}.mdc-checkbox.mdc-checkbox--selected.mdc-ripple-upgraded{--mdc-ripple-fg-opacity: 0.12}.mdc-checkbox.mdc-ripple-upgraded--background-focused.mdc-checkbox--selected .mdc-checkbox__ripple::before,.mdc-checkbox.mdc-ripple-upgraded--background-focused.mdc-checkbox--selected .mdc-checkbox__ripple::after{background-color:#018786;background-color:var(--mdc-theme-secondary, #018786)}.mdc-checkbox .mdc-checkbox__background{top:11px;left:11px}.mdc-checkbox .mdc-checkbox__background::before{top:-13px;left:-13px;width:40px;height:40px}.mdc-checkbox .mdc-checkbox__native-control{top:0px;right:0px;left:0px;width:40px;height:40px}.mdc-checkbox__native-control:enabled:not(:checked):not(:indeterminate):not([data-indeterminate=true])~.mdc-checkbox__background{border-color:rgba(0,0,0,.54);background-color:transparent}.mdc-checkbox__native-control:enabled:checked~.mdc-checkbox__background,.mdc-checkbox__native-control:enabled:indeterminate~.mdc-checkbox__background,.mdc-checkbox__native-control[data-indeterminate=true]:enabled~.mdc-checkbox__background{border-color:#018786;border-color:var(--mdc-theme-secondary, #018786);background-color:#018786;background-color:var(--mdc-theme-secondary, #018786)}@-webkit-keyframes mdc-checkbox-fade-in-background-8A000000secondary00000000secondary{0%{border-color:rgba(0,0,0,.54);background-color:transparent}50%{border-color:#018786;border-color:var(--mdc-theme-secondary, #018786);background-color:#018786;background-color:var(--mdc-theme-secondary, #018786)}}@keyframes mdc-checkbox-fade-in-background-8A000000secondary00000000secondary{0%{border-color:rgba(0,0,0,.54);background-color:transparent}50%{border-color:#018786;border-color:var(--mdc-theme-secondary, #018786);background-color:#018786;background-color:var(--mdc-theme-secondary, #018786)}}@-webkit-keyframes mdc-checkbox-fade-out-background-8A000000secondary00000000secondary{0%,80%{border-color:#018786;border-color:var(--mdc-theme-secondary, #018786);background-color:#018786;background-color:var(--mdc-theme-secondary, #018786)}100%{border-color:rgba(0,0,0,.54);background-color:transparent}}@keyframes mdc-checkbox-fade-out-background-8A000000secondary00000000secondary{0%,80%{border-color:#018786;border-color:var(--mdc-theme-secondary, #018786);background-color:#018786;background-color:var(--mdc-theme-secondary, #018786)}100%{border-color:rgba(0,0,0,.54);background-color:transparent}}.mdc-checkbox--anim-unchecked-checked .mdc-checkbox__native-control:enabled~.mdc-checkbox__background,.mdc-checkbox--anim-unchecked-indeterminate .mdc-checkbox__native-control:enabled~.mdc-checkbox__background{-webkit-animation-name:mdc-checkbox-fade-in-background-8A000000secondary00000000secondary;animation-name:mdc-checkbox-fade-in-background-8A000000secondary00000000secondary}.mdc-checkbox--anim-checked-unchecked .mdc-checkbox__native-control:enabled~.mdc-checkbox__background,.mdc-checkbox--anim-indeterminate-unchecked .mdc-checkbox__native-control:enabled~.mdc-checkbox__background{-webkit-animation-name:mdc-checkbox-fade-out-background-8A000000secondary00000000secondary;animation-name:mdc-checkbox-fade-out-background-8A000000secondary00000000secondary}.mdc-checkbox__native-control[disabled]:not(:checked):not(:indeterminate):not([data-indeterminate=true])~.mdc-checkbox__background{border-color:rgba(0,0,0,.38);background-color:transparent}.mdc-checkbox__native-control[disabled]:checked~.mdc-checkbox__background,.mdc-checkbox__native-control[disabled]:indeterminate~.mdc-checkbox__background,.mdc-checkbox__native-control[data-indeterminate=true][disabled]~.mdc-checkbox__background{border-color:transparent;background-color:rgba(0,0,0,.38)}.mdc-checkbox__native-control:enabled~.mdc-checkbox__background .mdc-checkbox__checkmark{color:#fff}.mdc-checkbox__native-control:enabled~.mdc-checkbox__background .mdc-checkbox__mixedmark{border-color:#fff}.mdc-checkbox__native-control:disabled~.mdc-checkbox__background .mdc-checkbox__checkmark{color:#fff}.mdc-checkbox__native-control:disabled~.mdc-checkbox__background .mdc-checkbox__mixedmark{border-color:#fff}@media screen and (-ms-high-contrast: active){.mdc-checkbox__native-control[disabled]:not(:checked):not(:indeterminate):not([data-indeterminate=true])~.mdc-checkbox__background{border-color:GrayText;background-color:transparent}.mdc-checkbox__native-control[disabled]:checked~.mdc-checkbox__background,.mdc-checkbox__native-control[disabled]:indeterminate~.mdc-checkbox__background,.mdc-checkbox__native-control[data-indeterminate=true][disabled]~.mdc-checkbox__background{border-color:GrayText;background-color:transparent}.mdc-checkbox__native-control:disabled~.mdc-checkbox__background .mdc-checkbox__checkmark{color:GrayText}.mdc-checkbox__native-control:disabled~.mdc-checkbox__background .mdc-checkbox__mixedmark{border-color:GrayText}.mdc-checkbox__mixedmark{margin:0 1px}}.mdc-checkbox--disabled{cursor:default;pointer-events:none}.mdc-checkbox__background{display:inline-flex;position:absolute;align-items:center;justify-content:center;box-sizing:border-box;width:18px;height:18px;border:2px solid currentColor;border-radius:2px;background-color:transparent;pointer-events:none;will-change:background-color,border-color;transition:background-color 90ms 0ms cubic-bezier(0.4, 0, 0.6, 1),border-color 90ms 0ms cubic-bezier(0.4, 0, 0.6, 1)}.mdc-checkbox__background .mdc-checkbox__background::before{background-color:#000;background-color:var(--mdc-theme-on-surface, #000)}.mdc-checkbox__checkmark{position:absolute;top:0;right:0;bottom:0;left:0;width:100%;opacity:0;transition:opacity 180ms 0ms cubic-bezier(0.4, 0, 0.6, 1)}.mdc-checkbox--upgraded .mdc-checkbox__checkmark{opacity:1}.mdc-checkbox__checkmark-path{transition:stroke-dashoffset 180ms 0ms cubic-bezier(0.4, 0, 0.6, 1);stroke:currentColor;stroke-width:3.12px;stroke-dashoffset:29.7833385;stroke-dasharray:29.7833385}.mdc-checkbox__mixedmark{width:100%;height:0;-webkit-transform:scaleX(0) rotate(0deg);transform:scaleX(0) rotate(0deg);border-width:1px;border-style:solid;opacity:0;transition:opacity 90ms 0ms cubic-bezier(0.4, 0, 0.6, 1),-webkit-transform 90ms 0ms cubic-bezier(0.4, 0, 0.6, 1);transition:opacity 90ms 0ms cubic-bezier(0.4, 0, 0.6, 1),transform 90ms 0ms cubic-bezier(0.4, 0, 0.6, 1);transition:opacity 90ms 0ms cubic-bezier(0.4, 0, 0.6, 1),transform 90ms 0ms cubic-bezier(0.4, 0, 0.6, 1),-webkit-transform 90ms 0ms cubic-bezier(0.4, 0, 0.6, 1)}.mdc-checkbox--upgraded .mdc-checkbox__background,.mdc-checkbox--upgraded .mdc-checkbox__checkmark,.mdc-checkbox--upgraded .mdc-checkbox__checkmark-path,.mdc-checkbox--upgraded .mdc-checkbox__mixedmark{transition:none !important}.mdc-checkbox--anim-unchecked-checked .mdc-checkbox__background,.mdc-checkbox--anim-unchecked-indeterminate .mdc-checkbox__background,.mdc-checkbox--anim-checked-unchecked .mdc-checkbox__background,.mdc-checkbox--anim-indeterminate-unchecked .mdc-checkbox__background{-webkit-animation-duration:180ms;animation-duration:180ms;-webkit-animation-timing-function:linear;animation-timing-function:linear}.mdc-checkbox--anim-unchecked-checked .mdc-checkbox__checkmark-path{-webkit-animation:mdc-checkbox-unchecked-checked-checkmark-path 180ms linear 0s;animation:mdc-checkbox-unchecked-checked-checkmark-path 180ms linear 0s;transition:none}.mdc-checkbox--anim-unchecked-indeterminate .mdc-checkbox__mixedmark{-webkit-animation:mdc-checkbox-unchecked-indeterminate-mixedmark 90ms linear 0s;animation:mdc-checkbox-unchecked-indeterminate-mixedmark 90ms linear 0s;transition:none}.mdc-checkbox--anim-checked-unchecked .mdc-checkbox__checkmark-path{-webkit-animation:mdc-checkbox-checked-unchecked-checkmark-path 90ms linear 0s;animation:mdc-checkbox-checked-unchecked-checkmark-path 90ms linear 0s;transition:none}.mdc-checkbox--anim-checked-indeterminate .mdc-checkbox__checkmark{-webkit-animation:mdc-checkbox-checked-indeterminate-checkmark 90ms linear 0s;animation:mdc-checkbox-checked-indeterminate-checkmark 90ms linear 0s;transition:none}.mdc-checkbox--anim-checked-indeterminate .mdc-checkbox__mixedmark{-webkit-animation:mdc-checkbox-checked-indeterminate-mixedmark 90ms linear 0s;animation:mdc-checkbox-checked-indeterminate-mixedmark 90ms linear 0s;transition:none}.mdc-checkbox--anim-indeterminate-checked .mdc-checkbox__checkmark{-webkit-animation:mdc-checkbox-indeterminate-checked-checkmark 500ms linear 0s;animation:mdc-checkbox-indeterminate-checked-checkmark 500ms linear 0s;transition:none}.mdc-checkbox--anim-indeterminate-checked .mdc-checkbox__mixedmark{-webkit-animation:mdc-checkbox-indeterminate-checked-mixedmark 500ms linear 0s;animation:mdc-checkbox-indeterminate-checked-mixedmark 500ms linear 0s;transition:none}.mdc-checkbox--anim-indeterminate-unchecked .mdc-checkbox__mixedmark{-webkit-animation:mdc-checkbox-indeterminate-unchecked-mixedmark 300ms linear 0s;animation:mdc-checkbox-indeterminate-unchecked-mixedmark 300ms linear 0s;transition:none}.mdc-checkbox__native-control:checked~.mdc-checkbox__background,.mdc-checkbox__native-control:indeterminate~.mdc-checkbox__background,.mdc-checkbox__native-control[data-indeterminate=true]~.mdc-checkbox__background{transition:border-color 90ms 0ms cubic-bezier(0, 0, 0.2, 1),background-color 90ms 0ms cubic-bezier(0, 0, 0.2, 1)}.mdc-checkbox__native-control:checked~.mdc-checkbox__background .mdc-checkbox__checkmark-path,.mdc-checkbox__native-control:indeterminate~.mdc-checkbox__background .mdc-checkbox__checkmark-path,.mdc-checkbox__native-control[data-indeterminate=true]~.mdc-checkbox__background .mdc-checkbox__checkmark-path{stroke-dashoffset:0}.mdc-checkbox__background::before{position:absolute;-webkit-transform:scale(0, 0);transform:scale(0, 0);border-radius:50%;opacity:0;pointer-events:none;content:"";will-change:opacity,transform;transition:opacity 90ms 0ms cubic-bezier(0.4, 0, 0.6, 1),-webkit-transform 90ms 0ms cubic-bezier(0.4, 0, 0.6, 1);transition:opacity 90ms 0ms cubic-bezier(0.4, 0, 0.6, 1),transform 90ms 0ms cubic-bezier(0.4, 0, 0.6, 1);transition:opacity 90ms 0ms cubic-bezier(0.4, 0, 0.6, 1),transform 90ms 0ms cubic-bezier(0.4, 0, 0.6, 1),-webkit-transform 90ms 0ms cubic-bezier(0.4, 0, 0.6, 1)}.mdc-checkbox__native-control:focus~.mdc-checkbox__background::before{-webkit-transform:scale(1);transform:scale(1);opacity:.12;transition:opacity 80ms 0ms cubic-bezier(0, 0, 0.2, 1),-webkit-transform 80ms 0ms cubic-bezier(0, 0, 0.2, 1);transition:opacity 80ms 0ms cubic-bezier(0, 0, 0.2, 1),transform 80ms 0ms cubic-bezier(0, 0, 0.2, 1);transition:opacity 80ms 0ms cubic-bezier(0, 0, 0.2, 1),transform 80ms 0ms cubic-bezier(0, 0, 0.2, 1),-webkit-transform 80ms 0ms cubic-bezier(0, 0, 0.2, 1)}.mdc-checkbox__native-control{position:absolute;margin:0;padding:0;opacity:0;cursor:inherit}.mdc-checkbox__native-control:disabled{cursor:default;pointer-events:none}.mdc-checkbox--touch{margin-top:4px;margin-bottom:4px;margin-right:4px;margin-left:4px}.mdc-checkbox--touch .mdc-checkbox__native-control{top:-4px;right:-4px;left:-4px;width:48px;height:48px}.mdc-checkbox__native-control:checked~.mdc-checkbox__background .mdc-checkbox__checkmark{transition:opacity 180ms 0ms cubic-bezier(0, 0, 0.2, 1),-webkit-transform 180ms 0ms cubic-bezier(0, 0, 0.2, 1);transition:opacity 180ms 0ms cubic-bezier(0, 0, 0.2, 1),transform 180ms 0ms cubic-bezier(0, 0, 0.2, 1);transition:opacity 180ms 0ms cubic-bezier(0, 0, 0.2, 1),transform 180ms 0ms cubic-bezier(0, 0, 0.2, 1),-webkit-transform 180ms 0ms cubic-bezier(0, 0, 0.2, 1);opacity:1}.mdc-checkbox__native-control:checked~.mdc-checkbox__background .mdc-checkbox__mixedmark{-webkit-transform:scaleX(1) rotate(-45deg);transform:scaleX(1) rotate(-45deg)}.mdc-checkbox__native-control:indeterminate~.mdc-checkbox__background .mdc-checkbox__checkmark,.mdc-checkbox__native-control[data-indeterminate=true]~.mdc-checkbox__background .mdc-checkbox__checkmark{-webkit-transform:rotate(45deg);transform:rotate(45deg);opacity:0;transition:opacity 90ms 0ms cubic-bezier(0.4, 0, 0.6, 1),-webkit-transform 90ms 0ms cubic-bezier(0.4, 0, 0.6, 1);transition:opacity 90ms 0ms cubic-bezier(0.4, 0, 0.6, 1),transform 90ms 0ms cubic-bezier(0.4, 0, 0.6, 1);transition:opacity 90ms 0ms cubic-bezier(0.4, 0, 0.6, 1),transform 90ms 0ms cubic-bezier(0.4, 0, 0.6, 1),-webkit-transform 90ms 0ms cubic-bezier(0.4, 0, 0.6, 1)}.mdc-checkbox__native-control:indeterminate~.mdc-checkbox__background .mdc-checkbox__mixedmark,.mdc-checkbox__native-control[data-indeterminate=true]~.mdc-checkbox__background .mdc-checkbox__mixedmark{-webkit-transform:scaleX(1) rotate(0deg);transform:scaleX(1) rotate(0deg);opacity:1}.mdc-checkbox{--mdc-ripple-fg-size: 0;--mdc-ripple-left: 0;--mdc-ripple-top: 0;--mdc-ripple-fg-scale: 1;--mdc-ripple-fg-translate-end: 0;--mdc-ripple-fg-translate-start: 0;-webkit-tap-highlight-color:rgba(0,0,0,0)}.mdc-checkbox .mdc-checkbox__ripple::before,.mdc-checkbox .mdc-checkbox__ripple::after{position:absolute;border-radius:50%;opacity:0;pointer-events:none;content:""}.mdc-checkbox .mdc-checkbox__ripple::before{transition:opacity 15ms linear,background-color 15ms linear;z-index:1}.mdc-checkbox.mdc-ripple-upgraded .mdc-checkbox__ripple::before{-webkit-transform:scale(var(--mdc-ripple-fg-scale, 1));transform:scale(var(--mdc-ripple-fg-scale, 1))}.mdc-checkbox.mdc-ripple-upgraded .mdc-checkbox__ripple::after{top:0;left:0;-webkit-transform:scale(0);transform:scale(0);-webkit-transform-origin:center center;transform-origin:center center}.mdc-checkbox.mdc-ripple-upgraded--unbounded .mdc-checkbox__ripple::after{top:var(--mdc-ripple-top, 0);left:var(--mdc-ripple-left, 0)}.mdc-checkbox.mdc-ripple-upgraded--foreground-activation .mdc-checkbox__ripple::after{-webkit-animation:mdc-ripple-fg-radius-in 225ms forwards,mdc-ripple-fg-opacity-in 75ms forwards;animation:mdc-ripple-fg-radius-in 225ms forwards,mdc-ripple-fg-opacity-in 75ms forwards}.mdc-checkbox.mdc-ripple-upgraded--foreground-deactivation .mdc-checkbox__ripple::after{-webkit-animation:mdc-ripple-fg-opacity-out 150ms;animation:mdc-ripple-fg-opacity-out 150ms;-webkit-transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1))}.mdc-checkbox .mdc-checkbox__ripple::before,.mdc-checkbox .mdc-checkbox__ripple::after{background-color:#000;background-color:var(--mdc-theme-on-surface, #000)}.mdc-checkbox:hover .mdc-checkbox__ripple::before{opacity:.04}.mdc-checkbox.mdc-ripple-upgraded--background-focused .mdc-checkbox__ripple::before,.mdc-checkbox:not(.mdc-ripple-upgraded):focus .mdc-checkbox__ripple::before{transition-duration:75ms;opacity:.12}.mdc-checkbox:not(.mdc-ripple-upgraded) .mdc-checkbox__ripple::after{transition:opacity 150ms linear}.mdc-checkbox:not(.mdc-ripple-upgraded):active .mdc-checkbox__ripple::after{transition-duration:75ms;opacity:.12}.mdc-checkbox.mdc-ripple-upgraded{--mdc-ripple-fg-opacity: 0.12}.mdc-checkbox .mdc-checkbox__ripple::before,.mdc-checkbox .mdc-checkbox__ripple::after{top:calc(50% - 50%);left:calc(50% - 50%);width:100%;height:100%}.mdc-checkbox.mdc-ripple-upgraded .mdc-checkbox__ripple::before,.mdc-checkbox.mdc-ripple-upgraded .mdc-checkbox__ripple::after{top:var(--mdc-ripple-top, calc(50% - 50%));left:var(--mdc-ripple-left, calc(50% - 50%));width:var(--mdc-ripple-fg-size, 100%);height:var(--mdc-ripple-fg-size, 100%)}.mdc-checkbox.mdc-ripple-upgraded .mdc-checkbox__ripple::after{width:var(--mdc-ripple-fg-size, 100%);height:var(--mdc-ripple-fg-size, 100%)}.mdc-checkbox__ripple{position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none}.mdc-ripple-upgraded--background-focused .mdc-checkbox__background::before{content:none}.mdc-chip-trailing-action__touch{width:26px}.mdc-chip-trailing-action__touch{position:absolute;top:50%;right:0;height:48px;left:50%;width:48px;-webkit-transform:translate(-50%, -50%);transform:translate(-50%, -50%)}.mdc-chip-trailing-action{border:none;display:inline-flex;position:relative;align-items:center;justify-content:center;box-sizing:border-box;padding:0;outline:none;cursor:pointer;-webkit-appearance:none;background:none}.mdc-chip-trailing-action .mdc-chip-trailing-action__icon{height:18px;width:18px;font-size:18px}.mdc-chip-trailing-action .mdc-chip-trailing-action{color:#000;color:var(--mdc-theme-on-surface, #000)}.mdc-chip-trailing-action .mdc-chip-trailing-action__icon{fill:currentColor;color:inherit}.mdc-chip-trailing-action{--mdc-ripple-fg-size: 0;--mdc-ripple-left: 0;--mdc-ripple-top: 0;--mdc-ripple-fg-scale: 1;--mdc-ripple-fg-translate-end: 0;--mdc-ripple-fg-translate-start: 0;-webkit-tap-highlight-color:rgba(0,0,0,0)}.mdc-chip-trailing-action .mdc-chip-trailing-action__ripple::before,.mdc-chip-trailing-action .mdc-chip-trailing-action__ripple::after{position:absolute;border-radius:50%;opacity:0;pointer-events:none;content:""}.mdc-chip-trailing-action .mdc-chip-trailing-action__ripple::before{transition:opacity 15ms linear,background-color 15ms linear;z-index:1}.mdc-chip-trailing-action.mdc-ripple-upgraded .mdc-chip-trailing-action__ripple::before{-webkit-transform:scale(var(--mdc-ripple-fg-scale, 1));transform:scale(var(--mdc-ripple-fg-scale, 1))}.mdc-chip-trailing-action.mdc-ripple-upgraded .mdc-chip-trailing-action__ripple::after{top:0;left:0;-webkit-transform:scale(0);transform:scale(0);-webkit-transform-origin:center center;transform-origin:center center}.mdc-chip-trailing-action.mdc-ripple-upgraded--unbounded .mdc-chip-trailing-action__ripple::after{top:var(--mdc-ripple-top, 0);left:var(--mdc-ripple-left, 0)}.mdc-chip-trailing-action.mdc-ripple-upgraded--foreground-activation .mdc-chip-trailing-action__ripple::after{-webkit-animation:mdc-ripple-fg-radius-in 225ms forwards,mdc-ripple-fg-opacity-in 75ms forwards;animation:mdc-ripple-fg-radius-in 225ms forwards,mdc-ripple-fg-opacity-in 75ms forwards}.mdc-chip-trailing-action.mdc-ripple-upgraded--foreground-deactivation .mdc-chip-trailing-action__ripple::after{-webkit-animation:mdc-ripple-fg-opacity-out 150ms;animation:mdc-ripple-fg-opacity-out 150ms;-webkit-transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1))}.mdc-chip-trailing-action .mdc-chip-trailing-action__ripple::before,.mdc-chip-trailing-action .mdc-chip-trailing-action__ripple::after{top:calc(50% - 50%);left:calc(50% - 50%);width:100%;height:100%}.mdc-chip-trailing-action.mdc-ripple-upgraded .mdc-chip-trailing-action__ripple::before,.mdc-chip-trailing-action.mdc-ripple-upgraded .mdc-chip-trailing-action__ripple::after{top:var(--mdc-ripple-top, calc(50% - 50%));left:var(--mdc-ripple-left, calc(50% - 50%));width:var(--mdc-ripple-fg-size, 100%);height:var(--mdc-ripple-fg-size, 100%)}.mdc-chip-trailing-action.mdc-ripple-upgraded .mdc-chip-trailing-action__ripple::after{width:var(--mdc-ripple-fg-size, 100%);height:var(--mdc-ripple-fg-size, 100%)}.mdc-chip-trailing-action .mdc-chip-trailing-action__ripple::before,.mdc-chip-trailing-action .mdc-chip-trailing-action__ripple::after{background-color:#000;background-color:var(--mdc-theme-on-surface, #000)}.mdc-chip-trailing-action:hover .mdc-chip-trailing-action__ripple::before{opacity:.04}.mdc-chip-trailing-action.mdc-ripple-upgraded--background-focused .mdc-chip-trailing-action__ripple::before,.mdc-chip-trailing-action:not(.mdc-ripple-upgraded):focus .mdc-chip-trailing-action__ripple::before{transition-duration:75ms;opacity:.12}.mdc-chip-trailing-action:not(.mdc-ripple-upgraded) .mdc-chip-trailing-action__ripple::after{transition:opacity 150ms linear}.mdc-chip-trailing-action:not(.mdc-ripple-upgraded):active .mdc-chip-trailing-action__ripple::after{transition-duration:75ms;opacity:.12}.mdc-chip-trailing-action.mdc-ripple-upgraded{--mdc-ripple-fg-opacity: 0.12}.mdc-chip-trailing-action .mdc-chip-trailing-action__ripple{position:absolute;box-sizing:content-box;width:100%;height:100%;overflow:hidden}.mdc-chip__icon--leading{color:rgba(0,0,0,.54)}.mdc-chip-trailing-action{color:#000}.mdc-chip__icon--trailing{color:rgba(0,0,0,.54)}.mdc-chip__icon--trailing:hover{color:rgba(0,0,0,.62)}.mdc-chip__icon--trailing:focus{color:rgba(0,0,0,.87)}.mdc-chip__icon.mdc-chip__icon--leading:not(.mdc-chip__icon--leading-hidden){width:20px;height:20px;font-size:20px}.mdc-chip-trailing-action__icon{height:18px;width:18px;font-size:18px}.mdc-chip__icon.mdc-chip__icon--trailing{width:18px;height:18px;font-size:18px}.mdc-chip-trailing-action{margin-left:4px;margin-right:-4px}[dir=rtl] .mdc-chip-trailing-action,.mdc-chip-trailing-action[dir=rtl]{margin-left:-4px;margin-right:4px}.mdc-chip__icon--trailing{margin-left:4px;margin-right:-4px}[dir=rtl] .mdc-chip__icon--trailing,.mdc-chip__icon--trailing[dir=rtl]{margin-left:-4px;margin-right:4px}.mdc-chip{border-radius:16px;background-color:#e0e0e0;color:rgba(0,0,0,.87);-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-body2-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:.875rem;font-size:var(--mdc-typography-body2-font-size, 0.875rem);line-height:1.25rem;line-height:var(--mdc-typography-body2-line-height, 1.25rem);font-weight:400;font-weight:var(--mdc-typography-body2-font-weight, 400);letter-spacing:.0178571429em;letter-spacing:var(--mdc-typography-body2-letter-spacing, 0.0178571429em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-body2-text-decoration, inherit);text-decoration:var(--mdc-typography-body2-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-body2-text-transform, inherit);height:32px;position:relative;display:inline-flex;align-items:center;box-sizing:border-box;padding:0 12px;border-width:0;outline:none;cursor:pointer;-webkit-appearance:none}.mdc-chip .mdc-chip__ripple{border-radius:16px}.mdc-chip:hover{color:rgba(0,0,0,.87)}.mdc-chip.mdc-chip--selected .mdc-chip__checkmark,.mdc-chip .mdc-chip__icon--leading:not(.mdc-chip__icon--leading-hidden){margin-left:-4px;margin-right:4px}[dir=rtl] .mdc-chip.mdc-chip--selected .mdc-chip__checkmark,.mdc-chip.mdc-chip--selected .mdc-chip__checkmark[dir=rtl],[dir=rtl] .mdc-chip .mdc-chip__icon--leading:not(.mdc-chip__icon--leading-hidden),.mdc-chip .mdc-chip__icon--leading:not(.mdc-chip__icon--leading-hidden)[dir=rtl]{margin-left:4px;margin-right:-4px}.mdc-chip .mdc-elevation-overlay{width:100%;height:100%;top:0;left:0}.mdc-chip::-moz-focus-inner{padding:0;border:0}.mdc-chip:hover{color:#000;color:var(--mdc-theme-on-surface, #000)}.mdc-chip .mdc-chip__touch{position:absolute;top:50%;right:0;height:48px;left:0;-webkit-transform:translateY(-50%);transform:translateY(-50%)}.mdc-chip--exit{transition:opacity 75ms cubic-bezier(0.4, 0, 0.2, 1),width 150ms cubic-bezier(0, 0, 0.2, 1),padding 100ms linear,margin 100ms linear;opacity:0}.mdc-chip__text{white-space:nowrap}.mdc-chip__icon{border-radius:50%;outline:none;vertical-align:middle}.mdc-chip__checkmark{height:20px}.mdc-chip__checkmark-path{transition:stroke-dashoffset 150ms 50ms cubic-bezier(0.4, 0, 0.6, 1);stroke-width:2px;stroke-dashoffset:29.7833385;stroke-dasharray:29.7833385}.mdc-chip__primary-action:focus{outline:none}.mdc-chip--selected .mdc-chip__checkmark-path{stroke-dashoffset:0}.mdc-chip__icon--leading,.mdc-chip__icon--trailing{position:relative}.mdc-chip-set--choice .mdc-chip.mdc-chip--selected{color:#6200ee;color:var(--mdc-theme-primary, #6200ee)}.mdc-chip-set--choice .mdc-chip.mdc-chip--selected .mdc-chip__icon--leading{color:rgba(98,0,238,.54)}.mdc-chip-set--choice .mdc-chip.mdc-chip--selected:hover{color:#6200ee;color:var(--mdc-theme-primary, #6200ee)}.mdc-chip-set--choice .mdc-chip .mdc-chip__checkmark-path{stroke:#6200ee;stroke:var(--mdc-theme-primary, #6200ee)}.mdc-chip-set--choice .mdc-chip--selected{background-color:#fff;background-color:var(--mdc-theme-surface, #fff)}.mdc-chip__checkmark-svg{width:0;height:20px;transition:width 150ms cubic-bezier(0.4, 0, 0.2, 1)}.mdc-chip--selected .mdc-chip__checkmark-svg{width:20px}.mdc-chip-set--filter .mdc-chip__icon--leading{transition:opacity 75ms linear;transition-delay:-50ms;opacity:1}.mdc-chip-set--filter .mdc-chip__icon--leading+.mdc-chip__checkmark{transition:opacity 75ms linear;transition-delay:80ms;opacity:0}.mdc-chip-set--filter .mdc-chip__icon--leading+.mdc-chip__checkmark .mdc-chip__checkmark-svg{transition:width 0ms}.mdc-chip-set--filter .mdc-chip--selected .mdc-chip__icon--leading{opacity:0}.mdc-chip-set--filter .mdc-chip--selected .mdc-chip__icon--leading+.mdc-chip__checkmark{width:0;opacity:1}.mdc-chip-set--filter .mdc-chip__icon--leading-hidden.mdc-chip__icon--leading{width:0;opacity:0}.mdc-chip-set--filter .mdc-chip__icon--leading-hidden.mdc-chip__icon--leading+.mdc-chip__checkmark{width:20px}.mdc-chip{--mdc-ripple-fg-size: 0;--mdc-ripple-left: 0;--mdc-ripple-top: 0;--mdc-ripple-fg-scale: 1;--mdc-ripple-fg-translate-end: 0;--mdc-ripple-fg-translate-start: 0;-webkit-tap-highlight-color:rgba(0,0,0,0)}.mdc-chip .mdc-chip__ripple::before,.mdc-chip .mdc-chip__ripple::after{position:absolute;border-radius:50%;opacity:0;pointer-events:none;content:""}.mdc-chip .mdc-chip__ripple::before{transition:opacity 15ms linear,background-color 15ms linear;z-index:1}.mdc-chip.mdc-ripple-upgraded .mdc-chip__ripple::before{-webkit-transform:scale(var(--mdc-ripple-fg-scale, 1));transform:scale(var(--mdc-ripple-fg-scale, 1))}.mdc-chip.mdc-ripple-upgraded .mdc-chip__ripple::after{top:0;left:0;-webkit-transform:scale(0);transform:scale(0);-webkit-transform-origin:center center;transform-origin:center center}.mdc-chip.mdc-ripple-upgraded--unbounded .mdc-chip__ripple::after{top:var(--mdc-ripple-top, 0);left:var(--mdc-ripple-left, 0)}.mdc-chip.mdc-ripple-upgraded--foreground-activation .mdc-chip__ripple::after{-webkit-animation:mdc-ripple-fg-radius-in 225ms forwards,mdc-ripple-fg-opacity-in 75ms forwards;animation:mdc-ripple-fg-radius-in 225ms forwards,mdc-ripple-fg-opacity-in 75ms forwards}.mdc-chip.mdc-ripple-upgraded--foreground-deactivation .mdc-chip__ripple::after{-webkit-animation:mdc-ripple-fg-opacity-out 150ms;animation:mdc-ripple-fg-opacity-out 150ms;-webkit-transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1))}.mdc-chip .mdc-chip__ripple::before,.mdc-chip .mdc-chip__ripple::after{top:calc(50% - 100%);left:calc(50% - 100%);width:200%;height:200%}.mdc-chip.mdc-ripple-upgraded .mdc-chip__ripple::after{width:var(--mdc-ripple-fg-size, 100%);height:var(--mdc-ripple-fg-size, 100%)}.mdc-chip .mdc-chip__ripple::before,.mdc-chip .mdc-chip__ripple::after{background-color:rgba(0,0,0,.87)}.mdc-chip:hover .mdc-chip__ripple::before{opacity:.04}.mdc-chip.mdc-ripple-upgraded--background-focused .mdc-chip__ripple::before,.mdc-chip.mdc-ripple-upgraded:focus-within .mdc-chip__ripple::before,.mdc-chip:not(.mdc-ripple-upgraded):focus .mdc-chip__ripple::before,.mdc-chip:not(.mdc-ripple-upgraded):focus-within .mdc-chip__ripple::before{transition-duration:75ms;opacity:.12}.mdc-chip:not(.mdc-ripple-upgraded) .mdc-chip__ripple::after{transition:opacity 150ms linear}.mdc-chip:not(.mdc-ripple-upgraded):active .mdc-chip__ripple::after{transition-duration:75ms;opacity:.12}.mdc-chip.mdc-ripple-upgraded{--mdc-ripple-fg-opacity: 0.12}.mdc-chip .mdc-chip__ripple{position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none;overflow:hidden}.mdc-chip-set--choice .mdc-chip.mdc-chip--selected .mdc-chip__ripple::before{opacity:.08}.mdc-chip-set--choice .mdc-chip.mdc-chip--selected .mdc-chip__ripple::before,.mdc-chip-set--choice .mdc-chip.mdc-chip--selected .mdc-chip__ripple::after{background-color:#6200ee;background-color:var(--mdc-theme-primary, #6200ee)}.mdc-chip-set--choice .mdc-chip.mdc-chip--selected:hover .mdc-chip__ripple::before{opacity:.12}.mdc-chip-set--choice .mdc-chip.mdc-chip--selected.mdc-ripple-upgraded--background-focused .mdc-chip__ripple::before,.mdc-chip-set--choice .mdc-chip.mdc-chip--selected.mdc-ripple-upgraded:focus-within .mdc-chip__ripple::before,.mdc-chip-set--choice .mdc-chip.mdc-chip--selected:not(.mdc-ripple-upgraded):focus .mdc-chip__ripple::before,.mdc-chip-set--choice .mdc-chip.mdc-chip--selected:not(.mdc-ripple-upgraded):focus-within .mdc-chip__ripple::before{transition-duration:75ms;opacity:.2}.mdc-chip-set--choice .mdc-chip.mdc-chip--selected:not(.mdc-ripple-upgraded) .mdc-chip__ripple::after{transition:opacity 150ms linear}.mdc-chip-set--choice .mdc-chip.mdc-chip--selected:not(.mdc-ripple-upgraded):active .mdc-chip__ripple::after{transition-duration:75ms;opacity:.2}.mdc-chip-set--choice .mdc-chip.mdc-chip--selected.mdc-ripple-upgraded{--mdc-ripple-fg-opacity: 0.2}@-webkit-keyframes mdc-chip-entry{from{-webkit-transform:scale(0.8);transform:scale(0.8);opacity:.4}to{-webkit-transform:scale(1);transform:scale(1);opacity:1}}@keyframes mdc-chip-entry{from{-webkit-transform:scale(0.8);transform:scale(0.8);opacity:.4}to{-webkit-transform:scale(1);transform:scale(1);opacity:1}}.mdc-chip-set{padding:4px;display:flex;flex-wrap:wrap;box-sizing:border-box}.mdc-chip-set .mdc-chip{margin:4px}.mdc-chip-set .mdc-chip--touch{margin-top:8px;margin-bottom:8px}.mdc-chip-set--input .mdc-chip{-webkit-animation:mdc-chip-entry 100ms cubic-bezier(0, 0, 0.2, 1);animation:mdc-chip-entry 100ms cubic-bezier(0, 0, 0.2, 1)}.mdc-circular-progress__determinate-circle,.mdc-circular-progress__indeterminate-circle-graphic{stroke:#6200ee;stroke:var(--mdc-theme-primary, #6200ee)}@-webkit-keyframes mdc-circular-progress-container-rotate{to{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes mdc-circular-progress-container-rotate{to{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@-webkit-keyframes mdc-circular-progress-spinner-layer-rotate{12.5%{-webkit-transform:rotate(135deg);transform:rotate(135deg)}25%{-webkit-transform:rotate(270deg);transform:rotate(270deg)}37.5%{-webkit-transform:rotate(405deg);transform:rotate(405deg)}50%{-webkit-transform:rotate(540deg);transform:rotate(540deg)}62.5%{-webkit-transform:rotate(675deg);transform:rotate(675deg)}75%{-webkit-transform:rotate(810deg);transform:rotate(810deg)}87.5%{-webkit-transform:rotate(945deg);transform:rotate(945deg)}100%{-webkit-transform:rotate(1080deg);transform:rotate(1080deg)}}@keyframes mdc-circular-progress-spinner-layer-rotate{12.5%{-webkit-transform:rotate(135deg);transform:rotate(135deg)}25%{-webkit-transform:rotate(270deg);transform:rotate(270deg)}37.5%{-webkit-transform:rotate(405deg);transform:rotate(405deg)}50%{-webkit-transform:rotate(540deg);transform:rotate(540deg)}62.5%{-webkit-transform:rotate(675deg);transform:rotate(675deg)}75%{-webkit-transform:rotate(810deg);transform:rotate(810deg)}87.5%{-webkit-transform:rotate(945deg);transform:rotate(945deg)}100%{-webkit-transform:rotate(1080deg);transform:rotate(1080deg)}}@-webkit-keyframes mdc-circular-progress-color-1-fade-in-out{from{opacity:.99}25%{opacity:.99}26%{opacity:0}89%{opacity:0}90%{opacity:.99}to{opacity:.99}}@keyframes mdc-circular-progress-color-1-fade-in-out{from{opacity:.99}25%{opacity:.99}26%{opacity:0}89%{opacity:0}90%{opacity:.99}to{opacity:.99}}@-webkit-keyframes mdc-circular-progress-color-2-fade-in-out{from{opacity:0}15%{opacity:0}25%{opacity:.99}50%{opacity:.99}51%{opacity:0}to{opacity:0}}@keyframes mdc-circular-progress-color-2-fade-in-out{from{opacity:0}15%{opacity:0}25%{opacity:.99}50%{opacity:.99}51%{opacity:0}to{opacity:0}}@-webkit-keyframes mdc-circular-progress-color-3-fade-in-out{from{opacity:0}40%{opacity:0}50%{opacity:.99}75%{opacity:.99}76%{opacity:0}to{opacity:0}}@keyframes mdc-circular-progress-color-3-fade-in-out{from{opacity:0}40%{opacity:0}50%{opacity:.99}75%{opacity:.99}76%{opacity:0}to{opacity:0}}@-webkit-keyframes mdc-circular-progress-color-4-fade-in-out{from{opacity:0}65%{opacity:0}75%{opacity:.99}90%{opacity:.99}to{opacity:0}}@keyframes mdc-circular-progress-color-4-fade-in-out{from{opacity:0}65%{opacity:0}75%{opacity:.99}90%{opacity:.99}to{opacity:0}}@-webkit-keyframes mdc-circular-progress-left-spin{from{-webkit-transform:rotate(265deg);transform:rotate(265deg)}50%{-webkit-transform:rotate(130deg);transform:rotate(130deg)}to{-webkit-transform:rotate(265deg);transform:rotate(265deg)}}@keyframes mdc-circular-progress-left-spin{from{-webkit-transform:rotate(265deg);transform:rotate(265deg)}50%{-webkit-transform:rotate(130deg);transform:rotate(130deg)}to{-webkit-transform:rotate(265deg);transform:rotate(265deg)}}@-webkit-keyframes mdc-circular-progress-right-spin{from{-webkit-transform:rotate(-265deg);transform:rotate(-265deg)}50%{-webkit-transform:rotate(-130deg);transform:rotate(-130deg)}to{-webkit-transform:rotate(-265deg);transform:rotate(-265deg)}}@keyframes mdc-circular-progress-right-spin{from{-webkit-transform:rotate(-265deg);transform:rotate(-265deg)}50%{-webkit-transform:rotate(-130deg);transform:rotate(-130deg)}to{-webkit-transform:rotate(-265deg);transform:rotate(-265deg)}}.mdc-circular-progress{width:48px;height:48px;display:inline-block;position:relative;direction:ltr;transition:opacity 250ms 0ms cubic-bezier(0.4, 0, 0.6, 1)}.mdc-circular-progress .mdc-circular-progress__determinate-circle-graphic,.mdc-circular-progress .mdc-circular-progress__indeterminate-circle-graphic{stroke-width:4px}.mdc-circular-progress .mdc-circular-progress__gap-patch .mdc-circular-progress__indeterminate-circle-graphic{stroke-width:3.2px}.mdc-circular-progress--small{width:24px;height:24px}.mdc-circular-progress--small .mdc-circular-progress__determinate-circle-graphic,.mdc-circular-progress--small .mdc-circular-progress__indeterminate-circle-graphic{stroke-width:2.5px}.mdc-circular-progress--small .mdc-circular-progress__gap-patch .mdc-circular-progress__indeterminate-circle-graphic{stroke-width:2px}.mdc-circular-progress--medium{width:36px;height:36px}.mdc-circular-progress--medium .mdc-circular-progress__determinate-circle-graphic,.mdc-circular-progress--medium .mdc-circular-progress__indeterminate-circle-graphic{stroke-width:3px}.mdc-circular-progress--medium .mdc-circular-progress__gap-patch .mdc-circular-progress__indeterminate-circle-graphic{stroke-width:2.4px}.mdc-circular-progress--large{width:48px;height:48px}.mdc-circular-progress--large .mdc-circular-progress__determinate-circle-graphic,.mdc-circular-progress--large .mdc-circular-progress__indeterminate-circle-graphic{stroke-width:4px}.mdc-circular-progress--large .mdc-circular-progress__gap-patch .mdc-circular-progress__indeterminate-circle-graphic{stroke-width:3.2px}.mdc-circular-progress__determinate-container,.mdc-circular-progress__indeterminate-circle-graphic,.mdc-circular-progress__indeterminate-container,.mdc-circular-progress__spinner-layer{position:absolute;width:100%;height:100%}.mdc-circular-progress__determinate-container{-webkit-transform:rotate(-90deg);transform:rotate(-90deg)}.mdc-circular-progress__indeterminate-container{opacity:0}.mdc-circular-progress__determinate-circle-graphic,.mdc-circular-progress__indeterminate-circle-graphic{fill:transparent}.mdc-circular-progress__determinate-circle{transition:stroke-dashoffset 500ms 0ms cubic-bezier(0, 0, 0.2, 1)}.mdc-circular-progress__gap-patch{position:absolute;top:0;left:47.5%;box-sizing:border-box;width:5%;height:100%;overflow:hidden}.mdc-circular-progress__gap-patch .mdc-circular-progress__indeterminate-circle-graphic{left:-900%;width:2000%;-webkit-transform:rotate(180deg);transform:rotate(180deg)}.mdc-circular-progress__circle-clipper{display:inline-block;position:relative;width:50%;height:100%;overflow:hidden}.mdc-circular-progress__circle-clipper .mdc-circular-progress__indeterminate-circle-graphic{width:200%}.mdc-circular-progress__circle-right .mdc-circular-progress__indeterminate-circle-graphic{left:-100%}.mdc-circular-progress--indeterminate .mdc-circular-progress__determinate-container{opacity:0}.mdc-circular-progress--indeterminate .mdc-circular-progress__indeterminate-container{opacity:1}.mdc-circular-progress--indeterminate .mdc-circular-progress__indeterminate-container{-webkit-animation:mdc-circular-progress-container-rotate 1568.2352941176ms linear infinite;animation:mdc-circular-progress-container-rotate 1568.2352941176ms linear infinite}.mdc-circular-progress--indeterminate .mdc-circular-progress__spinner-layer{-webkit-animation:mdc-circular-progress-spinner-layer-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;animation:mdc-circular-progress-spinner-layer-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both}.mdc-circular-progress--indeterminate .mdc-circular-progress__color-1{-webkit-animation:mdc-circular-progress-spinner-layer-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both,mdc-circular-progress-color-1-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;animation:mdc-circular-progress-spinner-layer-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both,mdc-circular-progress-color-1-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both}.mdc-circular-progress--indeterminate .mdc-circular-progress__color-2{-webkit-animation:mdc-circular-progress-spinner-layer-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both,mdc-circular-progress-color-2-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;animation:mdc-circular-progress-spinner-layer-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both,mdc-circular-progress-color-2-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both}.mdc-circular-progress--indeterminate .mdc-circular-progress__color-3{-webkit-animation:mdc-circular-progress-spinner-layer-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both,mdc-circular-progress-color-3-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;animation:mdc-circular-progress-spinner-layer-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both,mdc-circular-progress-color-3-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both}.mdc-circular-progress--indeterminate .mdc-circular-progress__color-4{-webkit-animation:mdc-circular-progress-spinner-layer-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both,mdc-circular-progress-color-4-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;animation:mdc-circular-progress-spinner-layer-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both,mdc-circular-progress-color-4-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both}.mdc-circular-progress--indeterminate .mdc-circular-progress__circle-left .mdc-circular-progress__indeterminate-circle-graphic{-webkit-animation:mdc-circular-progress-left-spin 1333ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;animation:mdc-circular-progress-left-spin 1333ms cubic-bezier(0.4, 0, 0.2, 1) infinite both}.mdc-circular-progress--indeterminate .mdc-circular-progress__circle-right .mdc-circular-progress__indeterminate-circle-graphic{-webkit-animation:mdc-circular-progress-right-spin 1333ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;animation:mdc-circular-progress-right-spin 1333ms cubic-bezier(0.4, 0, 0.2, 1) infinite both}.mdc-circular-progress--closed{opacity:0}.mdc-data-table__content{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-body2-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:.875rem;font-size:var(--mdc-typography-body2-font-size, 0.875rem);line-height:1.25rem;line-height:var(--mdc-typography-body2-line-height, 1.25rem);font-weight:400;font-weight:var(--mdc-typography-body2-font-weight, 400);letter-spacing:.0178571429em;letter-spacing:var(--mdc-typography-body2-letter-spacing, 0.0178571429em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-body2-text-decoration, inherit);text-decoration:var(--mdc-typography-body2-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-body2-text-transform, inherit)}.mdc-data-table{background-color:#fff;background-color:var(--mdc-theme-surface, #fff);border-radius:4px;border-width:1px;border-style:solid;border-color:rgba(0,0,0,.12);-webkit-overflow-scrolling:touch;display:inline-flex;flex-direction:column;box-sizing:border-box;overflow-x:auto;position:relative}.mdc-data-table__row{background-color:inherit}.mdc-data-table__header-row{background-color:inherit}.mdc-data-table__row--selected{background-color:rgba(98,0,238,.04)}.mdc-data-table__row,.mdc-data-table__pagination{border-top-color:rgba(0,0,0,.12)}.mdc-data-table__row,.mdc-data-table__pagination{border-top-width:1px;border-top-style:solid}.mdc-data-table__row:not(.mdc-data-table__row--selected):hover{background-color:rgba(0,0,0,.04)}.mdc-data-table__header-cell{color:rgba(0,0,0,.87)}.mdc-data-table__cell{color:rgba(0,0,0,.87)}.mdc-data-table__cell,.mdc-data-table__pagination{height:52px}.mdc-data-table__header-cell{height:56px}.mdc-data-table__cell,.mdc-data-table__header-cell{padding-right:16px;padding-left:16px}.mdc-data-table__header-cell--checkbox,.mdc-data-table__cell--checkbox{padding-left:16px;padding-right:0}[dir=rtl] .mdc-data-table__header-cell--checkbox,.mdc-data-table__header-cell--checkbox[dir=rtl],[dir=rtl] .mdc-data-table__cell--checkbox,.mdc-data-table__cell--checkbox[dir=rtl]{padding-left:0;padding-right:16px}.mdc-data-table__sort-icon-button{color:rgba(0,0,0,.6)}.mdc-data-table__sort-icon-button::before,.mdc-data-table__sort-icon-button::after{background-color:rgba(0,0,0,.6)}.mdc-data-table__sort-icon-button:hover::before{opacity:.04}.mdc-data-table__sort-icon-button.mdc-ripple-upgraded--background-focused::before,.mdc-data-table__sort-icon-button:not(.mdc-ripple-upgraded):focus::before{transition-duration:75ms;opacity:.12}.mdc-data-table__sort-icon-button:not(.mdc-ripple-upgraded)::after{transition:opacity 150ms linear}.mdc-data-table__sort-icon-button:not(.mdc-ripple-upgraded):active::after{transition-duration:75ms;opacity:.12}.mdc-data-table__sort-icon-button.mdc-ripple-upgraded{--mdc-ripple-fg-opacity: 0.12}.mdc-data-table__header-cell--sorted .mdc-data-table__sort-icon-button{color:rgba(0,0,0,.87)}.mdc-data-table__header-cell--sorted .mdc-data-table__sort-icon-button::before,.mdc-data-table__header-cell--sorted .mdc-data-table__sort-icon-button::after{background-color:rgba(0,0,0,.87)}.mdc-data-table__header-cell--sorted .mdc-data-table__sort-icon-button:hover::before{opacity:.04}.mdc-data-table__header-cell--sorted .mdc-data-table__sort-icon-button.mdc-ripple-upgraded--background-focused::before,.mdc-data-table__header-cell--sorted .mdc-data-table__sort-icon-button:not(.mdc-ripple-upgraded):focus::before{transition-duration:75ms;opacity:.12}.mdc-data-table__header-cell--sorted .mdc-data-table__sort-icon-button:not(.mdc-ripple-upgraded)::after{transition:opacity 150ms linear}.mdc-data-table__header-cell--sorted .mdc-data-table__sort-icon-button:not(.mdc-ripple-upgraded):active::after{transition-duration:75ms;opacity:.12}.mdc-data-table__header-cell--sorted .mdc-data-table__sort-icon-button.mdc-ripple-upgraded{--mdc-ripple-fg-opacity: 0.12}.mdc-data-table__table{min-width:100%;border:0;white-space:nowrap;border-collapse:collapse;table-layout:fixed}.mdc-data-table__cell{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-body2-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:.875rem;font-size:var(--mdc-typography-body2-font-size, 0.875rem);line-height:1.25rem;line-height:var(--mdc-typography-body2-line-height, 1.25rem);font-weight:400;font-weight:var(--mdc-typography-body2-font-weight, 400);letter-spacing:.0178571429em;letter-spacing:var(--mdc-typography-body2-letter-spacing, 0.0178571429em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-body2-text-decoration, inherit);text-decoration:var(--mdc-typography-body2-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-body2-text-transform, inherit);box-sizing:border-box;text-overflow:ellipsis;overflow:hidden}.mdc-data-table__cell--numeric{text-align:right}[dir=rtl] .mdc-data-table__cell--numeric,.mdc-data-table__cell--numeric[dir=rtl]{text-align:left}.mdc-data-table__header-cell{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-subtitle2-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:.875rem;font-size:var(--mdc-typography-subtitle2-font-size, 0.875rem);line-height:1.375rem;line-height:var(--mdc-typography-subtitle2-line-height, 1.375rem);font-weight:500;font-weight:var(--mdc-typography-subtitle2-font-weight, 500);letter-spacing:.0071428571em;letter-spacing:var(--mdc-typography-subtitle2-letter-spacing, 0.0071428571em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-subtitle2-text-decoration, inherit);text-decoration:var(--mdc-typography-subtitle2-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-subtitle2-text-transform, inherit);box-sizing:border-box;text-align:left;text-overflow:ellipsis;overflow:hidden;outline:none}[dir=rtl] .mdc-data-table__header-cell,.mdc-data-table__header-cell[dir=rtl]{text-align:right}.mdc-data-table__header-cell--numeric{text-align:right}[dir=rtl] .mdc-data-table__header-cell--numeric,.mdc-data-table__header-cell--numeric[dir=rtl]{text-align:left}.mdc-data-table__sort-icon-button{width:28px;height:28px;padding:2px;margin-left:4px;margin-right:0;transition:-webkit-transform 150ms 0ms cubic-bezier(0.4, 0, 0.2, 1);transition:transform 150ms 0ms cubic-bezier(0.4, 0, 0.2, 1);transition:transform 150ms 0ms cubic-bezier(0.4, 0, 0.2, 1), -webkit-transform 150ms 0ms cubic-bezier(0.4, 0, 0.2, 1);opacity:0}[dir=rtl] .mdc-data-table__sort-icon-button,.mdc-data-table__sort-icon-button[dir=rtl]{margin-left:0;margin-right:4px}.mdc-data-table__header-cell--numeric .mdc-data-table__sort-icon-button{margin-left:0;margin-right:4px}[dir=rtl] .mdc-data-table__header-cell--numeric .mdc-data-table__sort-icon-button,.mdc-data-table__header-cell--numeric .mdc-data-table__sort-icon-button[dir=rtl]{margin-left:4px;margin-right:0}.mdc-data-table__header-cell--sorted-descending .mdc-data-table__sort-icon-button{-webkit-transform:rotate(-180deg);transform:rotate(-180deg)}.mdc-data-table__sort-icon-button:focus,.mdc-data-table__header-cell:hover .mdc-data-table__sort-icon-button,.mdc-data-table__header-cell--sorted .mdc-data-table__sort-icon-button{opacity:1}.mdc-data-table__header-cell-wrapper{display:inline-flex;align-items:center}.mdc-data-table__header-cell--with-sort{cursor:pointer}.mdc-data-table__progress-indicator{display:none;position:absolute;width:100%}.mdc-data-table--in-progress .mdc-data-table__progress-indicator{display:block}.mdc-data-table__scrim{background-color:#fff;background-color:var(--mdc-theme-surface, #fff);height:100%;opacity:.32;position:absolute;top:0;width:100%}.mdc-data-table__pagination{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-body2-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:.875rem;font-size:var(--mdc-typography-body2-font-size, 0.875rem);line-height:1.25rem;line-height:var(--mdc-typography-body2-line-height, 1.25rem);font-weight:400;font-weight:var(--mdc-typography-body2-font-weight, 400);letter-spacing:.0178571429em;letter-spacing:var(--mdc-typography-body2-letter-spacing, 0.0178571429em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-body2-text-decoration, inherit);text-decoration:var(--mdc-typography-body2-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-body2-text-transform, inherit);box-sizing:border-box;display:flex;justify-content:flex-end}.mdc-data-table__pagination-trailing{margin-left:4px;margin-right:0;align-items:center;display:flex}[dir=rtl] .mdc-data-table__pagination-trailing,.mdc-data-table__pagination-trailing[dir=rtl]{margin-left:0;margin-right:4px}.mdc-data-table__pagination-button{margin-left:0;margin-right:4px}[dir=rtl] .mdc-data-table__pagination-button .mdc-button__icon,.mdc-data-table__pagination-button .mdc-button__icon[dir=rtl]{-webkit-transform:rotate(180deg);transform:rotate(180deg)}[dir=rtl] .mdc-data-table__pagination-button,.mdc-data-table__pagination-button[dir=rtl]{margin-left:4px;margin-right:0}.mdc-data-table__pagination-total{margin-left:0;margin-right:36px;white-space:nowrap}[dir=rtl] .mdc-data-table__pagination-total,.mdc-data-table__pagination-total[dir=rtl]{margin-left:36px;margin-right:0}.mdc-data-table__header-row-checkbox .mdc-checkbox__native-control:checked~.mdc-checkbox__background::before,.mdc-data-table__header-row-checkbox .mdc-checkbox__native-control:indeterminate~.mdc-checkbox__background::before,.mdc-data-table__header-row-checkbox .mdc-checkbox__native-control[data-indeterminate=true]~.mdc-checkbox__background::before,.mdc-data-table__row-checkbox .mdc-checkbox__native-control:checked~.mdc-checkbox__background::before,.mdc-data-table__row-checkbox .mdc-checkbox__native-control:indeterminate~.mdc-checkbox__background::before,.mdc-data-table__row-checkbox .mdc-checkbox__native-control[data-indeterminate=true]~.mdc-checkbox__background::before{background-color:#6200ee;background-color:var(--mdc-theme-primary, #6200ee)}.mdc-data-table__header-row-checkbox.mdc-checkbox--selected .mdc-checkbox__ripple::before,.mdc-data-table__header-row-checkbox.mdc-checkbox--selected .mdc-checkbox__ripple::after,.mdc-data-table__row-checkbox.mdc-checkbox--selected .mdc-checkbox__ripple::before,.mdc-data-table__row-checkbox.mdc-checkbox--selected .mdc-checkbox__ripple::after{background-color:#6200ee;background-color:var(--mdc-theme-primary, #6200ee)}.mdc-data-table__header-row-checkbox.mdc-checkbox--selected:hover .mdc-checkbox__ripple::before,.mdc-data-table__row-checkbox.mdc-checkbox--selected:hover .mdc-checkbox__ripple::before{opacity:.04}.mdc-data-table__header-row-checkbox.mdc-checkbox--selected.mdc-ripple-upgraded--background-focused .mdc-checkbox__ripple::before,.mdc-data-table__header-row-checkbox.mdc-checkbox--selected:not(.mdc-ripple-upgraded):focus .mdc-checkbox__ripple::before,.mdc-data-table__row-checkbox.mdc-checkbox--selected.mdc-ripple-upgraded--background-focused .mdc-checkbox__ripple::before,.mdc-data-table__row-checkbox.mdc-checkbox--selected:not(.mdc-ripple-upgraded):focus .mdc-checkbox__ripple::before{transition-duration:75ms;opacity:.12}.mdc-data-table__header-row-checkbox.mdc-checkbox--selected:not(.mdc-ripple-upgraded) .mdc-checkbox__ripple::after,.mdc-data-table__row-checkbox.mdc-checkbox--selected:not(.mdc-ripple-upgraded) .mdc-checkbox__ripple::after{transition:opacity 150ms linear}.mdc-data-table__header-row-checkbox.mdc-checkbox--selected:not(.mdc-ripple-upgraded):active .mdc-checkbox__ripple::after,.mdc-data-table__row-checkbox.mdc-checkbox--selected:not(.mdc-ripple-upgraded):active .mdc-checkbox__ripple::after{transition-duration:75ms;opacity:.12}.mdc-data-table__header-row-checkbox.mdc-checkbox--selected.mdc-ripple-upgraded,.mdc-data-table__row-checkbox.mdc-checkbox--selected.mdc-ripple-upgraded{--mdc-ripple-fg-opacity: 0.12}.mdc-data-table__header-row-checkbox.mdc-ripple-upgraded--background-focused.mdc-checkbox--selected .mdc-checkbox__ripple::before,.mdc-data-table__header-row-checkbox.mdc-ripple-upgraded--background-focused.mdc-checkbox--selected .mdc-checkbox__ripple::after,.mdc-data-table__row-checkbox.mdc-ripple-upgraded--background-focused.mdc-checkbox--selected .mdc-checkbox__ripple::before,.mdc-data-table__row-checkbox.mdc-ripple-upgraded--background-focused.mdc-checkbox--selected .mdc-checkbox__ripple::after{background-color:#6200ee;background-color:var(--mdc-theme-primary, #6200ee)}.mdc-data-table__header-row-checkbox .mdc-checkbox__native-control:enabled:not(:checked):not(:indeterminate):not([data-indeterminate=true])~.mdc-checkbox__background,.mdc-data-table__row-checkbox .mdc-checkbox__native-control:enabled:not(:checked):not(:indeterminate):not([data-indeterminate=true])~.mdc-checkbox__background{border-color:rgba(0,0,0,.54);background-color:transparent}.mdc-data-table__header-row-checkbox .mdc-checkbox__native-control:enabled:checked~.mdc-checkbox__background,.mdc-data-table__header-row-checkbox .mdc-checkbox__native-control:enabled:indeterminate~.mdc-checkbox__background,.mdc-data-table__header-row-checkbox .mdc-checkbox__native-control[data-indeterminate=true]:enabled~.mdc-checkbox__background,.mdc-data-table__row-checkbox .mdc-checkbox__native-control:enabled:checked~.mdc-checkbox__background,.mdc-data-table__row-checkbox .mdc-checkbox__native-control:enabled:indeterminate~.mdc-checkbox__background,.mdc-data-table__row-checkbox .mdc-checkbox__native-control[data-indeterminate=true]:enabled~.mdc-checkbox__background{border-color:#6200ee;border-color:var(--mdc-theme-primary, #6200ee);background-color:#6200ee;background-color:var(--mdc-theme-primary, #6200ee)}@-webkit-keyframes mdc-checkbox-fade-in-background-8A000000primary00000000primary{0%{border-color:rgba(0,0,0,.54);background-color:transparent}50%{border-color:#6200ee;border-color:var(--mdc-theme-primary, #6200ee);background-color:#6200ee;background-color:var(--mdc-theme-primary, #6200ee)}}@keyframes mdc-checkbox-fade-in-background-8A000000primary00000000primary{0%{border-color:rgba(0,0,0,.54);background-color:transparent}50%{border-color:#6200ee;border-color:var(--mdc-theme-primary, #6200ee);background-color:#6200ee;background-color:var(--mdc-theme-primary, #6200ee)}}@-webkit-keyframes mdc-checkbox-fade-out-background-8A000000primary00000000primary{0%,80%{border-color:#6200ee;border-color:var(--mdc-theme-primary, #6200ee);background-color:#6200ee;background-color:var(--mdc-theme-primary, #6200ee)}100%{border-color:rgba(0,0,0,.54);background-color:transparent}}@keyframes mdc-checkbox-fade-out-background-8A000000primary00000000primary{0%,80%{border-color:#6200ee;border-color:var(--mdc-theme-primary, #6200ee);background-color:#6200ee;background-color:var(--mdc-theme-primary, #6200ee)}100%{border-color:rgba(0,0,0,.54);background-color:transparent}}.mdc-data-table__header-row-checkbox.mdc-checkbox--anim-unchecked-checked .mdc-checkbox__native-control:enabled~.mdc-checkbox__background,.mdc-data-table__header-row-checkbox.mdc-checkbox--anim-unchecked-indeterminate .mdc-checkbox__native-control:enabled~.mdc-checkbox__background,.mdc-data-table__row-checkbox.mdc-checkbox--anim-unchecked-checked .mdc-checkbox__native-control:enabled~.mdc-checkbox__background,.mdc-data-table__row-checkbox.mdc-checkbox--anim-unchecked-indeterminate .mdc-checkbox__native-control:enabled~.mdc-checkbox__background{-webkit-animation-name:mdc-checkbox-fade-in-background-8A000000primary00000000primary;animation-name:mdc-checkbox-fade-in-background-8A000000primary00000000primary}.mdc-data-table__header-row-checkbox.mdc-checkbox--anim-checked-unchecked .mdc-checkbox__native-control:enabled~.mdc-checkbox__background,.mdc-data-table__header-row-checkbox.mdc-checkbox--anim-indeterminate-unchecked .mdc-checkbox__native-control:enabled~.mdc-checkbox__background,.mdc-data-table__row-checkbox.mdc-checkbox--anim-checked-unchecked .mdc-checkbox__native-control:enabled~.mdc-checkbox__background,.mdc-data-table__row-checkbox.mdc-checkbox--anim-indeterminate-unchecked .mdc-checkbox__native-control:enabled~.mdc-checkbox__background{-webkit-animation-name:mdc-checkbox-fade-out-background-8A000000primary00000000primary;animation-name:mdc-checkbox-fade-out-background-8A000000primary00000000primary}.mdc-dialog,.mdc-dialog__scrim{position:fixed;top:0;left:0;align-items:center;justify-content:center;box-sizing:border-box;width:100%;height:100%}.mdc-dialog{display:none;z-index:7}.mdc-dialog .mdc-dialog__surface{background-color:#fff;background-color:var(--mdc-theme-surface, #fff)}.mdc-dialog .mdc-dialog__scrim{background-color:rgba(0,0,0,.32)}.mdc-dialog .mdc-dialog__title{color:rgba(0,0,0,.87)}.mdc-dialog .mdc-dialog__content{color:rgba(0,0,0,.6)}.mdc-dialog.mdc-dialog--scrollable .mdc-dialog__title,.mdc-dialog.mdc-dialog--scrollable .mdc-dialog__actions{border-color:rgba(0,0,0,.12)}.mdc-dialog .mdc-dialog__surface{min-width:280px}@media(max-width: 592px){.mdc-dialog .mdc-dialog__surface{max-width:calc(100vw - 32px)}}@media(min-width: 592px){.mdc-dialog .mdc-dialog__surface{max-width:560px}}.mdc-dialog .mdc-dialog__surface{max-height:calc(100% - 32px)}.mdc-dialog .mdc-dialog__surface{border-radius:4px}.mdc-dialog__scrim{opacity:0;z-index:-1}.mdc-dialog__container{display:flex;flex-direction:row;align-items:center;justify-content:space-around;box-sizing:border-box;height:100%;-webkit-transform:scale(0.8);transform:scale(0.8);opacity:0;pointer-events:none}.mdc-dialog__surface{position:relative;box-shadow:0px 11px 15px -7px rgba(0, 0, 0, 0.2),0px 24px 38px 3px rgba(0, 0, 0, 0.14),0px 9px 46px 8px rgba(0,0,0,.12);display:flex;flex-direction:column;flex-grow:0;flex-shrink:0;box-sizing:border-box;max-width:100%;max-height:100%;pointer-events:auto;overflow-y:auto}.mdc-dialog__surface .mdc-elevation-overlay{width:100%;height:100%;top:0;left:0}.mdc-dialog[dir=rtl] .mdc-dialog__surface,[dir=rtl] .mdc-dialog .mdc-dialog__surface{text-align:right}.mdc-dialog__title{display:block;margin-top:0;line-height:normal;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-headline6-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:1.25rem;font-size:var(--mdc-typography-headline6-font-size, 1.25rem);line-height:2rem;line-height:var(--mdc-typography-headline6-line-height, 2rem);font-weight:500;font-weight:var(--mdc-typography-headline6-font-weight, 500);letter-spacing:.0125em;letter-spacing:var(--mdc-typography-headline6-letter-spacing, 0.0125em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-headline6-text-decoration, inherit);text-decoration:var(--mdc-typography-headline6-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-headline6-text-transform, inherit);position:relative;flex-shrink:0;box-sizing:border-box;margin:0;padding:0 24px 9px;border-bottom:1px solid transparent}.mdc-dialog__title::before{display:inline-block;width:0;height:40px;content:"";vertical-align:0}.mdc-dialog[dir=rtl] .mdc-dialog__title,[dir=rtl] .mdc-dialog .mdc-dialog__title{text-align:right}.mdc-dialog--scrollable .mdc-dialog__title{padding-bottom:15px}.mdc-dialog__content{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-body1-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:1rem;font-size:var(--mdc-typography-body1-font-size, 1rem);line-height:1.5rem;line-height:var(--mdc-typography-body1-line-height, 1.5rem);font-weight:400;font-weight:var(--mdc-typography-body1-font-weight, 400);letter-spacing:.03125em;letter-spacing:var(--mdc-typography-body1-letter-spacing, 0.03125em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-body1-text-decoration, inherit);text-decoration:var(--mdc-typography-body1-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-body1-text-transform, inherit);flex-grow:1;box-sizing:border-box;margin:0;padding:20px 24px;overflow:auto;-webkit-overflow-scrolling:touch}.mdc-dialog__content>:first-child{margin-top:0}.mdc-dialog__content>:last-child{margin-bottom:0}.mdc-dialog__title+.mdc-dialog__content{padding-top:0}.mdc-dialog--scrollable .mdc-dialog__content{padding-top:8px;padding-bottom:8px}.mdc-dialog__content .mdc-list:first-child:last-child{padding:6px 0 0}.mdc-dialog--scrollable .mdc-dialog__content .mdc-list:first-child:last-child{padding:0}.mdc-dialog__actions{display:flex;position:relative;flex-shrink:0;flex-wrap:wrap;align-items:center;justify-content:flex-end;box-sizing:border-box;min-height:52px;margin:0;padding:8px;border-top:1px solid transparent}.mdc-dialog--stacked .mdc-dialog__actions{flex-direction:column;align-items:flex-end}.mdc-dialog__button{margin-left:8px;margin-right:0;max-width:100%;text-align:right}[dir=rtl] .mdc-dialog__button,.mdc-dialog__button[dir=rtl]{margin-left:0;margin-right:8px}.mdc-dialog__button:first-child{margin-left:0;margin-right:0}[dir=rtl] .mdc-dialog__button:first-child,.mdc-dialog__button:first-child[dir=rtl]{margin-left:0;margin-right:0}.mdc-dialog[dir=rtl] .mdc-dialog__button,[dir=rtl] .mdc-dialog .mdc-dialog__button{text-align:left}.mdc-dialog--stacked .mdc-dialog__button:not(:first-child){margin-top:12px}.mdc-dialog--open,.mdc-dialog--opening,.mdc-dialog--closing{display:flex}.mdc-dialog--opening .mdc-dialog__scrim{transition:opacity 150ms linear}.mdc-dialog--opening .mdc-dialog__container{transition:opacity 75ms linear,-webkit-transform 150ms 0ms cubic-bezier(0, 0, 0.2, 1);transition:opacity 75ms linear,transform 150ms 0ms cubic-bezier(0, 0, 0.2, 1);transition:opacity 75ms linear,transform 150ms 0ms cubic-bezier(0, 0, 0.2, 1),-webkit-transform 150ms 0ms cubic-bezier(0, 0, 0.2, 1)}.mdc-dialog--closing .mdc-dialog__scrim,.mdc-dialog--closing .mdc-dialog__container{transition:opacity 75ms linear}.mdc-dialog--closing .mdc-dialog__container{-webkit-transform:scale(1);transform:scale(1)}.mdc-dialog--open .mdc-dialog__scrim{opacity:1}.mdc-dialog--open .mdc-dialog__container{-webkit-transform:scale(1);transform:scale(1);opacity:1}.mdc-dialog-scroll-lock{overflow:hidden}.mdc-drawer{border-color:rgba(0,0,0,.12);background-color:#fff;border-radius:0 0 0 0;z-index:6;width:256px;display:flex;flex-direction:column;flex-shrink:0;box-sizing:border-box;height:100%;border-right-width:1px;border-right-style:solid;overflow:hidden;transition-property:-webkit-transform;transition-property:transform;transition-property:transform, -webkit-transform;transition-timing-function:cubic-bezier(0.4, 0, 0.2, 1)}.mdc-drawer .mdc-drawer__title{color:rgba(0,0,0,.87)}.mdc-drawer .mdc-list-group__subheader{color:rgba(0,0,0,.6)}.mdc-drawer .mdc-drawer__subtitle{color:rgba(0,0,0,.6)}.mdc-drawer .mdc-list-item__graphic{color:rgba(0,0,0,.6)}.mdc-drawer .mdc-list-item{color:rgba(0,0,0,.87)}.mdc-drawer .mdc-list-item--activated .mdc-list-item__graphic{color:#6200ee}.mdc-drawer .mdc-list-item--activated{color:rgba(98,0,238,.87)}[dir=rtl] .mdc-drawer,.mdc-drawer[dir=rtl]{border-radius:0 0 0 0}.mdc-drawer .mdc-list-item{border-radius:4px}.mdc-drawer.mdc-drawer--open:not(.mdc-drawer--closing)+.mdc-drawer-app-content{margin-left:256px;margin-right:0}[dir=rtl] .mdc-drawer.mdc-drawer--open:not(.mdc-drawer--closing)+.mdc-drawer-app-content,.mdc-drawer.mdc-drawer--open:not(.mdc-drawer--closing)+.mdc-drawer-app-content[dir=rtl]{margin-left:0;margin-right:256px}[dir=rtl] .mdc-drawer,.mdc-drawer[dir=rtl]{border-right-width:0;border-left-width:1px;border-right-style:none;border-left-style:solid}.mdc-drawer .mdc-list-item{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-subtitle2-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:.875rem;font-size:var(--mdc-typography-subtitle2-font-size, 0.875rem);line-height:1.375rem;line-height:var(--mdc-typography-subtitle2-line-height, 1.375rem);font-weight:500;font-weight:var(--mdc-typography-subtitle2-font-weight, 500);letter-spacing:.0071428571em;letter-spacing:var(--mdc-typography-subtitle2-letter-spacing, 0.0071428571em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-subtitle2-text-decoration, inherit);text-decoration:var(--mdc-typography-subtitle2-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-subtitle2-text-transform, inherit);height:calc(48px - 2 * 4px);margin:8px 8px;padding:0 8px}.mdc-drawer .mdc-list-item:nth-child(1){margin-top:2px}.mdc-drawer .mdc-list-item:nth-last-child(1){margin-bottom:0}.mdc-drawer .mdc-list-group__subheader{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-body2-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:.875rem;font-size:var(--mdc-typography-body2-font-size, 0.875rem);line-height:1.25rem;line-height:var(--mdc-typography-body2-line-height, 1.25rem);font-weight:400;font-weight:var(--mdc-typography-body2-font-weight, 400);letter-spacing:.0178571429em;letter-spacing:var(--mdc-typography-body2-letter-spacing, 0.0178571429em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-body2-text-decoration, inherit);text-decoration:var(--mdc-typography-body2-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-body2-text-transform, inherit);display:block;margin-top:0;line-height:normal;margin:0;padding:0 16px}.mdc-drawer .mdc-list-group__subheader::before{display:inline-block;width:0;height:24px;content:"";vertical-align:0}.mdc-drawer .mdc-list-divider{margin:3px 0 4px}.mdc-drawer .mdc-list-item__text,.mdc-drawer .mdc-list-item__graphic{pointer-events:none}.mdc-drawer--animate{-webkit-transform:translateX(-100%);transform:translateX(-100%)}[dir=rtl] .mdc-drawer--animate,.mdc-drawer--animate[dir=rtl]{-webkit-transform:translateX(100%);transform:translateX(100%)}.mdc-drawer--opening{-webkit-transform:translateX(0);transform:translateX(0);transition-duration:250ms}[dir=rtl] .mdc-drawer--opening,.mdc-drawer--opening[dir=rtl]{-webkit-transform:translateX(0);transform:translateX(0)}.mdc-drawer--closing{-webkit-transform:translateX(-100%);transform:translateX(-100%);transition-duration:200ms}[dir=rtl] .mdc-drawer--closing,.mdc-drawer--closing[dir=rtl]{-webkit-transform:translateX(100%);transform:translateX(100%)}.mdc-drawer__header{flex-shrink:0;box-sizing:border-box;min-height:64px;padding:0 16px 4px}.mdc-drawer__title{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-headline6-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:1.25rem;font-size:var(--mdc-typography-headline6-font-size, 1.25rem);line-height:2rem;line-height:var(--mdc-typography-headline6-line-height, 2rem);font-weight:500;font-weight:var(--mdc-typography-headline6-font-weight, 500);letter-spacing:.0125em;letter-spacing:var(--mdc-typography-headline6-letter-spacing, 0.0125em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-headline6-text-decoration, inherit);text-decoration:var(--mdc-typography-headline6-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-headline6-text-transform, inherit);display:block;margin-top:0;line-height:normal;margin-bottom:-20px}.mdc-drawer__title::before{display:inline-block;width:0;height:36px;content:"";vertical-align:0}.mdc-drawer__title::after{display:inline-block;width:0;height:20px;content:"";vertical-align:-20px}.mdc-drawer__subtitle{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-body2-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:.875rem;font-size:var(--mdc-typography-body2-font-size, 0.875rem);line-height:1.25rem;line-height:var(--mdc-typography-body2-line-height, 1.25rem);font-weight:400;font-weight:var(--mdc-typography-body2-font-weight, 400);letter-spacing:.0178571429em;letter-spacing:var(--mdc-typography-body2-letter-spacing, 0.0178571429em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-body2-text-decoration, inherit);text-decoration:var(--mdc-typography-body2-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-body2-text-transform, inherit);display:block;margin-top:0;line-height:normal;margin-bottom:0}.mdc-drawer__subtitle::before{display:inline-block;width:0;height:20px;content:"";vertical-align:0}.mdc-drawer__content{height:100%;overflow-y:auto;-webkit-overflow-scrolling:touch}.mdc-drawer--dismissible{left:0;right:initial;display:none;position:absolute}[dir=rtl] .mdc-drawer--dismissible,.mdc-drawer--dismissible[dir=rtl]{left:initial;right:0}.mdc-drawer--dismissible.mdc-drawer--open{display:flex}.mdc-drawer-app-content{margin-left:0;margin-right:0;position:relative}[dir=rtl] .mdc-drawer-app-content,.mdc-drawer-app-content[dir=rtl]{margin-left:0;margin-right:0}.mdc-drawer--modal{box-shadow:0px 8px 10px -5px rgba(0, 0, 0, 0.2),0px 16px 24px 2px rgba(0, 0, 0, 0.14),0px 6px 30px 5px rgba(0,0,0,.12);left:0;right:initial;display:none;position:fixed}.mdc-drawer--modal+.mdc-drawer-scrim{background-color:rgba(0,0,0,.32)}[dir=rtl] .mdc-drawer--modal,.mdc-drawer--modal[dir=rtl]{left:initial;right:0}.mdc-drawer--modal.mdc-drawer--open{display:flex}.mdc-drawer-scrim{display:none;position:fixed;top:0;left:0;width:100%;height:100%;z-index:5;transition-property:opacity;transition-timing-function:cubic-bezier(0.4, 0, 0.2, 1)}.mdc-drawer--open+.mdc-drawer-scrim{display:block}.mdc-drawer--animate+.mdc-drawer-scrim{opacity:0}.mdc-drawer--opening+.mdc-drawer-scrim{transition-duration:250ms;opacity:1}.mdc-drawer--closing+.mdc-drawer-scrim{transition-duration:200ms;opacity:0}.mdc-elevation--z0{box-shadow:0px 0px 0px 0px rgba(0, 0, 0, 0.2),0px 0px 0px 0px rgba(0, 0, 0, 0.14),0px 0px 0px 0px rgba(0,0,0,.12)}.mdc-elevation--z1{box-shadow:0px 2px 1px -1px rgba(0, 0, 0, 0.2),0px 1px 1px 0px rgba(0, 0, 0, 0.14),0px 1px 3px 0px rgba(0,0,0,.12)}.mdc-elevation--z2{box-shadow:0px 3px 1px -2px rgba(0, 0, 0, 0.2),0px 2px 2px 0px rgba(0, 0, 0, 0.14),0px 1px 5px 0px rgba(0,0,0,.12)}.mdc-elevation--z3{box-shadow:0px 3px 3px -2px rgba(0, 0, 0, 0.2),0px 3px 4px 0px rgba(0, 0, 0, 0.14),0px 1px 8px 0px rgba(0,0,0,.12)}.mdc-elevation--z4{box-shadow:0px 2px 4px -1px rgba(0, 0, 0, 0.2),0px 4px 5px 0px rgba(0, 0, 0, 0.14),0px 1px 10px 0px rgba(0,0,0,.12)}.mdc-elevation--z5{box-shadow:0px 3px 5px -1px rgba(0, 0, 0, 0.2),0px 5px 8px 0px rgba(0, 0, 0, 0.14),0px 1px 14px 0px rgba(0,0,0,.12)}.mdc-elevation--z6{box-shadow:0px 3px 5px -1px rgba(0, 0, 0, 0.2),0px 6px 10px 0px rgba(0, 0, 0, 0.14),0px 1px 18px 0px rgba(0,0,0,.12)}.mdc-elevation--z7{box-shadow:0px 4px 5px -2px rgba(0, 0, 0, 0.2),0px 7px 10px 1px rgba(0, 0, 0, 0.14),0px 2px 16px 1px rgba(0,0,0,.12)}.mdc-elevation--z8{box-shadow:0px 5px 5px -3px rgba(0, 0, 0, 0.2),0px 8px 10px 1px rgba(0, 0, 0, 0.14),0px 3px 14px 2px rgba(0,0,0,.12)}.mdc-elevation--z9{box-shadow:0px 5px 6px -3px rgba(0, 0, 0, 0.2),0px 9px 12px 1px rgba(0, 0, 0, 0.14),0px 3px 16px 2px rgba(0,0,0,.12)}.mdc-elevation--z10{box-shadow:0px 6px 6px -3px rgba(0, 0, 0, 0.2),0px 10px 14px 1px rgba(0, 0, 0, 0.14),0px 4px 18px 3px rgba(0,0,0,.12)}.mdc-elevation--z11{box-shadow:0px 6px 7px -4px rgba(0, 0, 0, 0.2),0px 11px 15px 1px rgba(0, 0, 0, 0.14),0px 4px 20px 3px rgba(0,0,0,.12)}.mdc-elevation--z12{box-shadow:0px 7px 8px -4px rgba(0, 0, 0, 0.2),0px 12px 17px 2px rgba(0, 0, 0, 0.14),0px 5px 22px 4px rgba(0,0,0,.12)}.mdc-elevation--z13{box-shadow:0px 7px 8px -4px rgba(0, 0, 0, 0.2),0px 13px 19px 2px rgba(0, 0, 0, 0.14),0px 5px 24px 4px rgba(0,0,0,.12)}.mdc-elevation--z14{box-shadow:0px 7px 9px -4px rgba(0, 0, 0, 0.2),0px 14px 21px 2px rgba(0, 0, 0, 0.14),0px 5px 26px 4px rgba(0,0,0,.12)}.mdc-elevation--z15{box-shadow:0px 8px 9px -5px rgba(0, 0, 0, 0.2),0px 15px 22px 2px rgba(0, 0, 0, 0.14),0px 6px 28px 5px rgba(0,0,0,.12)}.mdc-elevation--z16{box-shadow:0px 8px 10px -5px rgba(0, 0, 0, 0.2),0px 16px 24px 2px rgba(0, 0, 0, 0.14),0px 6px 30px 5px rgba(0,0,0,.12)}.mdc-elevation--z17{box-shadow:0px 8px 11px -5px rgba(0, 0, 0, 0.2),0px 17px 26px 2px rgba(0, 0, 0, 0.14),0px 6px 32px 5px rgba(0,0,0,.12)}.mdc-elevation--z18{box-shadow:0px 9px 11px -5px rgba(0, 0, 0, 0.2),0px 18px 28px 2px rgba(0, 0, 0, 0.14),0px 7px 34px 6px rgba(0,0,0,.12)}.mdc-elevation--z19{box-shadow:0px 9px 12px -6px rgba(0, 0, 0, 0.2),0px 19px 29px 2px rgba(0, 0, 0, 0.14),0px 7px 36px 6px rgba(0,0,0,.12)}.mdc-elevation--z20{box-shadow:0px 10px 13px -6px rgba(0, 0, 0, 0.2),0px 20px 31px 3px rgba(0, 0, 0, 0.14),0px 8px 38px 7px rgba(0,0,0,.12)}.mdc-elevation--z21{box-shadow:0px 10px 13px -6px rgba(0, 0, 0, 0.2),0px 21px 33px 3px rgba(0, 0, 0, 0.14),0px 8px 40px 7px rgba(0,0,0,.12)}.mdc-elevation--z22{box-shadow:0px 10px 14px -6px rgba(0, 0, 0, 0.2),0px 22px 35px 3px rgba(0, 0, 0, 0.14),0px 8px 42px 7px rgba(0,0,0,.12)}.mdc-elevation--z23{box-shadow:0px 11px 14px -7px rgba(0, 0, 0, 0.2),0px 23px 36px 3px rgba(0, 0, 0, 0.14),0px 9px 44px 8px rgba(0,0,0,.12)}.mdc-elevation--z24{box-shadow:0px 11px 15px -7px rgba(0, 0, 0, 0.2),0px 24px 38px 3px rgba(0, 0, 0, 0.14),0px 9px 46px 8px rgba(0,0,0,.12)}.mdc-elevation-transition{transition:box-shadow 280ms cubic-bezier(0.4, 0, 0.2, 1);will-change:box-shadow}.mdc-fab{position:relative;box-shadow:0px 3px 5px -1px rgba(0, 0, 0, 0.2),0px 6px 10px 0px rgba(0, 0, 0, 0.14),0px 1px 18px 0px rgba(0,0,0,.12);display:inline-flex;position:relative;align-items:center;justify-content:center;box-sizing:border-box;width:56px;height:56px;padding:0;border:none;fill:currentColor;text-decoration:none;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-moz-appearance:none;-webkit-appearance:none;overflow:visible;transition:box-shadow 280ms cubic-bezier(0.4, 0, 0.2, 1),opacity 15ms linear 30ms,-webkit-transform 270ms 0ms cubic-bezier(0, 0, 0.2, 1);transition:box-shadow 280ms cubic-bezier(0.4, 0, 0.2, 1),opacity 15ms linear 30ms,transform 270ms 0ms cubic-bezier(0, 0, 0.2, 1);transition:box-shadow 280ms cubic-bezier(0.4, 0, 0.2, 1),opacity 15ms linear 30ms,transform 270ms 0ms cubic-bezier(0, 0, 0.2, 1),-webkit-transform 270ms 0ms cubic-bezier(0, 0, 0.2, 1);background-color:#018786;background-color:var(--mdc-theme-secondary, #018786);color:#fff;color:var(--mdc-theme-on-secondary, #fff)}.mdc-fab .mdc-elevation-overlay{width:100%;height:100%;top:0;left:0}.mdc-fab:not(.mdc-fab--extended){border-radius:50%}.mdc-fab:not(.mdc-fab--extended) .mdc-fab__ripple{border-radius:50%}.mdc-fab::-moz-focus-inner{padding:0;border:0}.mdc-fab:hover,.mdc-fab:focus{box-shadow:0px 5px 5px -3px rgba(0, 0, 0, 0.2),0px 8px 10px 1px rgba(0, 0, 0, 0.14),0px 3px 14px 2px rgba(0,0,0,.12)}.mdc-fab:active{box-shadow:0px 7px 8px -4px rgba(0, 0, 0, 0.2),0px 12px 17px 2px rgba(0, 0, 0, 0.14),0px 5px 22px 4px rgba(0,0,0,.12)}.mdc-fab:active,.mdc-fab:focus{outline:none}.mdc-fab:hover{cursor:pointer}.mdc-fab>svg{width:100%}.mdc-fab .mdc-fab__icon{width:24px;height:24px;font-size:24px}.mdc-fab--mini{width:40px;height:40px}.mdc-fab--extended{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-button-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:.875rem;font-size:var(--mdc-typography-button-font-size, 0.875rem);line-height:2.25rem;line-height:var(--mdc-typography-button-line-height, 2.25rem);font-weight:500;font-weight:var(--mdc-typography-button-font-weight, 500);letter-spacing:.0892857143em;letter-spacing:var(--mdc-typography-button-letter-spacing, 0.0892857143em);text-decoration:none;-webkit-text-decoration:var(--mdc-typography-button-text-decoration, none);text-decoration:var(--mdc-typography-button-text-decoration, none);text-transform:uppercase;text-transform:var(--mdc-typography-button-text-transform, uppercase);border-radius:24px;padding:0 20px;width:auto;max-width:100%;height:48px;line-height:normal}.mdc-fab--extended .mdc-fab__ripple{border-radius:24px}.mdc-fab--extended .mdc-fab__icon{margin-left:-8px;margin-right:12px}[dir=rtl] .mdc-fab--extended .mdc-fab__icon,.mdc-fab--extended .mdc-fab__icon[dir=rtl]{margin-left:12px;margin-right:-8px}.mdc-fab--extended .mdc-fab__label+.mdc-fab__icon{margin-left:12px;margin-right:-8px}[dir=rtl] .mdc-fab--extended .mdc-fab__label+.mdc-fab__icon,.mdc-fab--extended .mdc-fab__label+.mdc-fab__icon[dir=rtl]{margin-left:-8px;margin-right:12px}.mdc-fab--touch{margin-top:4px;margin-bottom:4px;margin-right:4px;margin-left:4px}.mdc-fab--touch .mdc-fab__touch{position:absolute;top:50%;right:0;height:48px;left:50%;width:48px;-webkit-transform:translate(-50%, -50%);transform:translate(-50%, -50%)}.mdc-fab::before{position:absolute;box-sizing:border-box;width:100%;height:100%;top:0;left:0;border:1px solid transparent;border-radius:inherit;content:""}.mdc-fab__label{justify-content:flex-start;text-overflow:ellipsis;white-space:nowrap;overflow-x:hidden;overflow-y:visible}.mdc-fab__icon{transition:-webkit-transform 180ms 90ms cubic-bezier(0, 0, 0.2, 1);transition:transform 180ms 90ms cubic-bezier(0, 0, 0.2, 1);transition:transform 180ms 90ms cubic-bezier(0, 0, 0.2, 1), -webkit-transform 180ms 90ms cubic-bezier(0, 0, 0.2, 1);fill:currentColor;will-change:transform}.mdc-fab .mdc-fab__icon{display:inline-flex;align-items:center;justify-content:center}.mdc-fab--exited{-webkit-transform:scale(0);transform:scale(0);opacity:0;transition:opacity 15ms linear 150ms,-webkit-transform 180ms 0ms cubic-bezier(0.4, 0, 1, 1);transition:opacity 15ms linear 150ms,transform 180ms 0ms cubic-bezier(0.4, 0, 1, 1);transition:opacity 15ms linear 150ms,transform 180ms 0ms cubic-bezier(0.4, 0, 1, 1),-webkit-transform 180ms 0ms cubic-bezier(0.4, 0, 1, 1)}.mdc-fab--exited .mdc-fab__icon{-webkit-transform:scale(0);transform:scale(0);transition:-webkit-transform 135ms 0ms cubic-bezier(0.4, 0, 1, 1);transition:transform 135ms 0ms cubic-bezier(0.4, 0, 1, 1);transition:transform 135ms 0ms cubic-bezier(0.4, 0, 1, 1), -webkit-transform 135ms 0ms cubic-bezier(0.4, 0, 1, 1)}.mdc-fab{--mdc-ripple-fg-size: 0;--mdc-ripple-left: 0;--mdc-ripple-top: 0;--mdc-ripple-fg-scale: 1;--mdc-ripple-fg-translate-end: 0;--mdc-ripple-fg-translate-start: 0;-webkit-tap-highlight-color:rgba(0,0,0,0)}.mdc-fab .mdc-fab__ripple::before,.mdc-fab .mdc-fab__ripple::after{position:absolute;border-radius:50%;opacity:0;pointer-events:none;content:""}.mdc-fab .mdc-fab__ripple::before{transition:opacity 15ms linear,background-color 15ms linear;z-index:1}.mdc-fab.mdc-ripple-upgraded .mdc-fab__ripple::before{-webkit-transform:scale(var(--mdc-ripple-fg-scale, 1));transform:scale(var(--mdc-ripple-fg-scale, 1))}.mdc-fab.mdc-ripple-upgraded .mdc-fab__ripple::after{top:0;left:0;-webkit-transform:scale(0);transform:scale(0);-webkit-transform-origin:center center;transform-origin:center center}.mdc-fab.mdc-ripple-upgraded--unbounded .mdc-fab__ripple::after{top:var(--mdc-ripple-top, 0);left:var(--mdc-ripple-left, 0)}.mdc-fab.mdc-ripple-upgraded--foreground-activation .mdc-fab__ripple::after{-webkit-animation:mdc-ripple-fg-radius-in 225ms forwards,mdc-ripple-fg-opacity-in 75ms forwards;animation:mdc-ripple-fg-radius-in 225ms forwards,mdc-ripple-fg-opacity-in 75ms forwards}.mdc-fab.mdc-ripple-upgraded--foreground-deactivation .mdc-fab__ripple::after{-webkit-animation:mdc-ripple-fg-opacity-out 150ms;animation:mdc-ripple-fg-opacity-out 150ms;-webkit-transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1))}.mdc-fab .mdc-fab__ripple::before,.mdc-fab .mdc-fab__ripple::after{top:calc(50% - 100%);left:calc(50% - 100%);width:200%;height:200%}.mdc-fab.mdc-ripple-upgraded .mdc-fab__ripple::after{width:var(--mdc-ripple-fg-size, 100%);height:var(--mdc-ripple-fg-size, 100%)}.mdc-fab .mdc-fab__ripple::before,.mdc-fab .mdc-fab__ripple::after{background-color:#fff;background-color:var(--mdc-theme-on-secondary, #fff)}.mdc-fab:hover .mdc-fab__ripple::before{opacity:.08}.mdc-fab.mdc-ripple-upgraded--background-focused .mdc-fab__ripple::before,.mdc-fab:not(.mdc-ripple-upgraded):focus .mdc-fab__ripple::before{transition-duration:75ms;opacity:.24}.mdc-fab:not(.mdc-ripple-upgraded) .mdc-fab__ripple::after{transition:opacity 150ms linear}.mdc-fab:not(.mdc-ripple-upgraded):active .mdc-fab__ripple::after{transition-duration:75ms;opacity:.24}.mdc-fab.mdc-ripple-upgraded{--mdc-ripple-fg-opacity: 0.24}.mdc-fab .mdc-fab__ripple{position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none;overflow:hidden}.mdc-floating-label{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-subtitle1-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:1rem;font-size:var(--mdc-typography-subtitle1-font-size, 1rem);font-weight:400;font-weight:var(--mdc-typography-subtitle1-font-weight, 400);letter-spacing:.009375em;letter-spacing:var(--mdc-typography-subtitle1-letter-spacing, 0.009375em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-subtitle1-text-decoration, inherit);text-decoration:var(--mdc-typography-subtitle1-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-subtitle1-text-transform, inherit);position:absolute;left:0;-webkit-transform-origin:left top;transform-origin:left top;line-height:1.15rem;text-align:left;text-overflow:ellipsis;white-space:nowrap;cursor:text;overflow:hidden;will-change:transform;transition:color 150ms cubic-bezier(0.4, 0, 0.2, 1),-webkit-transform 150ms cubic-bezier(0.4, 0, 0.2, 1);transition:transform 150ms cubic-bezier(0.4, 0, 0.2, 1),color 150ms cubic-bezier(0.4, 0, 0.2, 1);transition:transform 150ms cubic-bezier(0.4, 0, 0.2, 1),color 150ms cubic-bezier(0.4, 0, 0.2, 1),-webkit-transform 150ms cubic-bezier(0.4, 0, 0.2, 1)}[dir=rtl] .mdc-floating-label,.mdc-floating-label[dir=rtl]{right:0;left:auto;-webkit-transform-origin:right top;transform-origin:right top;text-align:right}.mdc-floating-label--float-above{cursor:auto}.mdc-floating-label--float-above{-webkit-transform:translateY(-106%) scale(0.75);transform:translateY(-106%) scale(0.75)}.mdc-floating-label--shake{-webkit-animation:mdc-floating-label-shake-float-above-standard 250ms 1;animation:mdc-floating-label-shake-float-above-standard 250ms 1}@-webkit-keyframes mdc-floating-label-shake-float-above-standard{0%{-webkit-transform:translateX(calc(0 - 0%)) translateY(-106%) scale(0.75);transform:translateX(calc(0 - 0%)) translateY(-106%) scale(0.75)}33%{-webkit-animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);-webkit-transform:translateX(calc(4% - 0%)) translateY(-106%) scale(0.75);transform:translateX(calc(4% - 0%)) translateY(-106%) scale(0.75)}66%{-webkit-animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);-webkit-transform:translateX(calc(-4% - 0%)) translateY(-106%) scale(0.75);transform:translateX(calc(-4% - 0%)) translateY(-106%) scale(0.75)}100%{-webkit-transform:translateX(calc(0 - 0%)) translateY(-106%) scale(0.75);transform:translateX(calc(0 - 0%)) translateY(-106%) scale(0.75)}}@keyframes mdc-floating-label-shake-float-above-standard{0%{-webkit-transform:translateX(calc(0 - 0%)) translateY(-106%) scale(0.75);transform:translateX(calc(0 - 0%)) translateY(-106%) scale(0.75)}33%{-webkit-animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);-webkit-transform:translateX(calc(4% - 0%)) translateY(-106%) scale(0.75);transform:translateX(calc(4% - 0%)) translateY(-106%) scale(0.75)}66%{-webkit-animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);-webkit-transform:translateX(calc(-4% - 0%)) translateY(-106%) scale(0.75);transform:translateX(calc(-4% - 0%)) translateY(-106%) scale(0.75)}100%{-webkit-transform:translateX(calc(0 - 0%)) translateY(-106%) scale(0.75);transform:translateX(calc(0 - 0%)) translateY(-106%) scale(0.75)}}.mdc-form-field{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-body2-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:.875rem;font-size:var(--mdc-typography-body2-font-size, 0.875rem);line-height:1.25rem;line-height:var(--mdc-typography-body2-line-height, 1.25rem);font-weight:400;font-weight:var(--mdc-typography-body2-font-weight, 400);letter-spacing:.0178571429em;letter-spacing:var(--mdc-typography-body2-letter-spacing, 0.0178571429em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-body2-text-decoration, inherit);text-decoration:var(--mdc-typography-body2-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-body2-text-transform, inherit);color:rgba(0,0,0,.87);color:var(--mdc-theme-text-primary-on-background, rgba(0, 0, 0, 0.87));display:inline-flex;align-items:center;vertical-align:middle}.mdc-form-field>label{margin-left:0;margin-right:auto;padding-left:4px;padding-right:0;order:0}[dir=rtl] .mdc-form-field>label,.mdc-form-field>label[dir=rtl]{margin-left:auto;margin-right:0}[dir=rtl] .mdc-form-field>label,.mdc-form-field>label[dir=rtl]{padding-left:0;padding-right:4px}.mdc-form-field--nowrap>label{text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.mdc-form-field--align-end>label{margin-left:auto;margin-right:0;padding-left:0;padding-right:4px;order:-1}[dir=rtl] .mdc-form-field--align-end>label,.mdc-form-field--align-end>label[dir=rtl]{margin-left:0;margin-right:auto}[dir=rtl] .mdc-form-field--align-end>label,.mdc-form-field--align-end>label[dir=rtl]{padding-left:4px;padding-right:0}.mdc-form-field--space-between{justify-content:space-between}.mdc-form-field--space-between>label{margin:0}[dir=rtl] .mdc-form-field--space-between>label,.mdc-form-field--space-between>label[dir=rtl]{margin:0}.mdc-icon-button{display:inline-block;position:relative;box-sizing:border-box;border:none;outline:none;background-color:transparent;fill:currentColor;color:inherit;font-size:24px;text-decoration:none;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;width:48px;height:48px;padding:12px}.mdc-icon-button svg,.mdc-icon-button img{width:24px;height:24px}.mdc-icon-button:disabled{color:rgba(0,0,0,.38);color:var(--mdc-theme-text-disabled-on-light, rgba(0, 0, 0, 0.38))}.mdc-icon-button:disabled{cursor:default;pointer-events:none}.mdc-icon-button__icon{display:inline-block}.mdc-icon-button__icon.mdc-icon-button__icon--on{display:none}.mdc-icon-button--on .mdc-icon-button__icon{display:none}.mdc-icon-button--on .mdc-icon-button__icon.mdc-icon-button__icon--on{display:inline-block}.mdc-icon-button{--mdc-ripple-fg-size: 0;--mdc-ripple-left: 0;--mdc-ripple-top: 0;--mdc-ripple-fg-scale: 1;--mdc-ripple-fg-translate-end: 0;--mdc-ripple-fg-translate-start: 0;-webkit-tap-highlight-color:rgba(0,0,0,0)}.mdc-icon-button::before,.mdc-icon-button::after{position:absolute;border-radius:50%;opacity:0;pointer-events:none;content:""}.mdc-icon-button::before{transition:opacity 15ms linear,background-color 15ms linear;z-index:1}.mdc-icon-button.mdc-ripple-upgraded::before{-webkit-transform:scale(var(--mdc-ripple-fg-scale, 1));transform:scale(var(--mdc-ripple-fg-scale, 1))}.mdc-icon-button.mdc-ripple-upgraded::after{top:0;left:0;-webkit-transform:scale(0);transform:scale(0);-webkit-transform-origin:center center;transform-origin:center center}.mdc-icon-button.mdc-ripple-upgraded--unbounded::after{top:var(--mdc-ripple-top, 0);left:var(--mdc-ripple-left, 0)}.mdc-icon-button.mdc-ripple-upgraded--foreground-activation::after{-webkit-animation:mdc-ripple-fg-radius-in 225ms forwards,mdc-ripple-fg-opacity-in 75ms forwards;animation:mdc-ripple-fg-radius-in 225ms forwards,mdc-ripple-fg-opacity-in 75ms forwards}.mdc-icon-button.mdc-ripple-upgraded--foreground-deactivation::after{-webkit-animation:mdc-ripple-fg-opacity-out 150ms;animation:mdc-ripple-fg-opacity-out 150ms;-webkit-transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1))}.mdc-icon-button::before,.mdc-icon-button::after{top:calc(50% - 50%);left:calc(50% - 50%);width:100%;height:100%}.mdc-icon-button.mdc-ripple-upgraded::before,.mdc-icon-button.mdc-ripple-upgraded::after{top:var(--mdc-ripple-top, calc(50% - 50%));left:var(--mdc-ripple-left, calc(50% - 50%));width:var(--mdc-ripple-fg-size, 100%);height:var(--mdc-ripple-fg-size, 100%)}.mdc-icon-button.mdc-ripple-upgraded::after{width:var(--mdc-ripple-fg-size, 100%);height:var(--mdc-ripple-fg-size, 100%)}.mdc-icon-button::before,.mdc-icon-button::after{background-color:#000}.mdc-icon-button:hover::before{opacity:.04}.mdc-icon-button.mdc-ripple-upgraded--background-focused::before,.mdc-icon-button:not(.mdc-ripple-upgraded):focus::before{transition-duration:75ms;opacity:.12}.mdc-icon-button:not(.mdc-ripple-upgraded)::after{transition:opacity 150ms linear}.mdc-icon-button:not(.mdc-ripple-upgraded):active::after{transition-duration:75ms;opacity:.12}.mdc-icon-button.mdc-ripple-upgraded{--mdc-ripple-fg-opacity: 0.12}.mdc-image-list{display:flex;flex-wrap:wrap;margin:0 auto;padding:0}.mdc-image-list__item,.mdc-image-list__image-aspect-container{position:relative;box-sizing:border-box}.mdc-image-list__item{list-style-type:none}.mdc-image-list__image{width:100%}.mdc-image-list__image-aspect-container .mdc-image-list__image{position:absolute;top:0;right:0;bottom:0;left:0;height:100%;background-repeat:no-repeat;background-position:center;background-size:cover}.mdc-image-list__image-aspect-container{padding-bottom:calc(100% / 1)}.mdc-image-list__image{border-radius:0}.mdc-image-list--with-text-protection .mdc-image-list__supporting{border-radius:0 0 0 0}.mdc-image-list__supporting{color:rgba(0,0,0,.87);color:var(--mdc-theme-text-primary-on-background, rgba(0, 0, 0, 0.87));display:flex;align-items:center;justify-content:space-between;box-sizing:border-box;padding:8px 0;line-height:24px}.mdc-image-list__label{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-subtitle1-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:1rem;font-size:var(--mdc-typography-subtitle1-font-size, 1rem);line-height:1.75rem;line-height:var(--mdc-typography-subtitle1-line-height, 1.75rem);font-weight:400;font-weight:var(--mdc-typography-subtitle1-font-weight, 400);letter-spacing:.009375em;letter-spacing:var(--mdc-typography-subtitle1-letter-spacing, 0.009375em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-subtitle1-text-decoration, inherit);text-decoration:var(--mdc-typography-subtitle1-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-subtitle1-text-transform, inherit);text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.mdc-image-list--with-text-protection .mdc-image-list__supporting{position:absolute;bottom:0;width:100%;height:48px;padding:0 16px;background:rgba(0,0,0,.6);color:#fff}.mdc-image-list--masonry{display:block}.mdc-image-list--masonry .mdc-image-list__item{-webkit-column-break-inside:avoid;break-inside:avoid-column}.mdc-image-list--masonry .mdc-image-list__image{display:block;height:auto}:root{--mdc-layout-grid-margin-desktop: 24px;--mdc-layout-grid-gutter-desktop: 24px;--mdc-layout-grid-column-width-desktop: 72px;--mdc-layout-grid-margin-tablet: 16px;--mdc-layout-grid-gutter-tablet: 16px;--mdc-layout-grid-column-width-tablet: 72px;--mdc-layout-grid-margin-phone: 16px;--mdc-layout-grid-gutter-phone: 16px;--mdc-layout-grid-column-width-phone: 72px}@media(min-width: 840px){.mdc-layout-grid{box-sizing:border-box;margin:0 auto;padding:24px;padding:var(--mdc-layout-grid-margin-desktop, 24px)}}@media(min-width: 600px)and (max-width: 839px){.mdc-layout-grid{box-sizing:border-box;margin:0 auto;padding:16px;padding:var(--mdc-layout-grid-margin-tablet, 16px)}}@media(max-width: 599px){.mdc-layout-grid{box-sizing:border-box;margin:0 auto;padding:16px;padding:var(--mdc-layout-grid-margin-phone, 16px)}}@media(min-width: 840px){.mdc-layout-grid__inner{display:flex;flex-flow:row wrap;align-items:stretch;margin:-12px;margin:calc(var(--mdc-layout-grid-gutter-desktop, 24px) / 2 * -1)}@supports(display: grid){.mdc-layout-grid__inner{display:grid;margin:0;grid-gap:24px;grid-gap:var(--mdc-layout-grid-gutter-desktop, 24px);grid-template-columns:repeat(12, minmax(0, 1fr))}}}@media(min-width: 600px)and (max-width: 839px){.mdc-layout-grid__inner{display:flex;flex-flow:row wrap;align-items:stretch;margin:-8px;margin:calc(var(--mdc-layout-grid-gutter-tablet, 16px) / 2 * -1)}@supports(display: grid){.mdc-layout-grid__inner{display:grid;margin:0;grid-gap:16px;grid-gap:var(--mdc-layout-grid-gutter-tablet, 16px);grid-template-columns:repeat(8, minmax(0, 1fr))}}}@media(max-width: 599px){.mdc-layout-grid__inner{display:flex;flex-flow:row wrap;align-items:stretch;margin:-8px;margin:calc(var(--mdc-layout-grid-gutter-phone, 16px) / 2 * -1)}@supports(display: grid){.mdc-layout-grid__inner{display:grid;margin:0;grid-gap:16px;grid-gap:var(--mdc-layout-grid-gutter-phone, 16px);grid-template-columns:repeat(4, minmax(0, 1fr))}}}@media(min-width: 840px){.mdc-layout-grid__cell{width:calc(33.3333333333% - 24px);width:calc(33.3333333333% - var(--mdc-layout-grid-gutter-desktop, 24px));box-sizing:border-box;margin:12px;margin:calc(var(--mdc-layout-grid-gutter-desktop, 24px) / 2)}@supports(display: grid){.mdc-layout-grid__cell{width:auto;grid-column-end:span 4}}@supports(display: grid){.mdc-layout-grid__cell{margin:0}}.mdc-layout-grid__cell--span-1,.mdc-layout-grid__cell--span-1-desktop{width:calc(8.3333333333% - 24px);width:calc(8.3333333333% - var(--mdc-layout-grid-gutter-desktop, 24px))}@supports(display: grid){.mdc-layout-grid__cell--span-1,.mdc-layout-grid__cell--span-1-desktop{width:auto;grid-column-end:span 1}}.mdc-layout-grid__cell--span-2,.mdc-layout-grid__cell--span-2-desktop{width:calc(16.6666666667% - 24px);width:calc(16.6666666667% - var(--mdc-layout-grid-gutter-desktop, 24px))}@supports(display: grid){.mdc-layout-grid__cell--span-2,.mdc-layout-grid__cell--span-2-desktop{width:auto;grid-column-end:span 2}}.mdc-layout-grid__cell--span-3,.mdc-layout-grid__cell--span-3-desktop{width:calc(25% - 24px);width:calc(25% - var(--mdc-layout-grid-gutter-desktop, 24px))}@supports(display: grid){.mdc-layout-grid__cell--span-3,.mdc-layout-grid__cell--span-3-desktop{width:auto;grid-column-end:span 3}}.mdc-layout-grid__cell--span-4,.mdc-layout-grid__cell--span-4-desktop{width:calc(33.3333333333% - 24px);width:calc(33.3333333333% - var(--mdc-layout-grid-gutter-desktop, 24px))}@supports(display: grid){.mdc-layout-grid__cell--span-4,.mdc-layout-grid__cell--span-4-desktop{width:auto;grid-column-end:span 4}}.mdc-layout-grid__cell--span-5,.mdc-layout-grid__cell--span-5-desktop{width:calc(41.6666666667% - 24px);width:calc(41.6666666667% - var(--mdc-layout-grid-gutter-desktop, 24px))}@supports(display: grid){.mdc-layout-grid__cell--span-5,.mdc-layout-grid__cell--span-5-desktop{width:auto;grid-column-end:span 5}}.mdc-layout-grid__cell--span-6,.mdc-layout-grid__cell--span-6-desktop{width:calc(50% - 24px);width:calc(50% - var(--mdc-layout-grid-gutter-desktop, 24px))}@supports(display: grid){.mdc-layout-grid__cell--span-6,.mdc-layout-grid__cell--span-6-desktop{width:auto;grid-column-end:span 6}}.mdc-layout-grid__cell--span-7,.mdc-layout-grid__cell--span-7-desktop{width:calc(58.3333333333% - 24px);width:calc(58.3333333333% - var(--mdc-layout-grid-gutter-desktop, 24px))}@supports(display: grid){.mdc-layout-grid__cell--span-7,.mdc-layout-grid__cell--span-7-desktop{width:auto;grid-column-end:span 7}}.mdc-layout-grid__cell--span-8,.mdc-layout-grid__cell--span-8-desktop{width:calc(66.6666666667% - 24px);width:calc(66.6666666667% - var(--mdc-layout-grid-gutter-desktop, 24px))}@supports(display: grid){.mdc-layout-grid__cell--span-8,.mdc-layout-grid__cell--span-8-desktop{width:auto;grid-column-end:span 8}}.mdc-layout-grid__cell--span-9,.mdc-layout-grid__cell--span-9-desktop{width:calc(75% - 24px);width:calc(75% - var(--mdc-layout-grid-gutter-desktop, 24px))}@supports(display: grid){.mdc-layout-grid__cell--span-9,.mdc-layout-grid__cell--span-9-desktop{width:auto;grid-column-end:span 9}}.mdc-layout-grid__cell--span-10,.mdc-layout-grid__cell--span-10-desktop{width:calc(83.3333333333% - 24px);width:calc(83.3333333333% - var(--mdc-layout-grid-gutter-desktop, 24px))}@supports(display: grid){.mdc-layout-grid__cell--span-10,.mdc-layout-grid__cell--span-10-desktop{width:auto;grid-column-end:span 10}}.mdc-layout-grid__cell--span-11,.mdc-layout-grid__cell--span-11-desktop{width:calc(91.6666666667% - 24px);width:calc(91.6666666667% - var(--mdc-layout-grid-gutter-desktop, 24px))}@supports(display: grid){.mdc-layout-grid__cell--span-11,.mdc-layout-grid__cell--span-11-desktop{width:auto;grid-column-end:span 11}}.mdc-layout-grid__cell--span-12,.mdc-layout-grid__cell--span-12-desktop{width:calc(100% - 24px);width:calc(100% - var(--mdc-layout-grid-gutter-desktop, 24px))}@supports(display: grid){.mdc-layout-grid__cell--span-12,.mdc-layout-grid__cell--span-12-desktop{width:auto;grid-column-end:span 12}}}@media(min-width: 600px)and (max-width: 839px){.mdc-layout-grid__cell{width:calc(50% - 16px);width:calc(50% - var(--mdc-layout-grid-gutter-tablet, 16px));box-sizing:border-box;margin:8px;margin:calc(var(--mdc-layout-grid-gutter-tablet, 16px) / 2)}@supports(display: grid){.mdc-layout-grid__cell{width:auto;grid-column-end:span 4}}@supports(display: grid){.mdc-layout-grid__cell{margin:0}}.mdc-layout-grid__cell--span-1,.mdc-layout-grid__cell--span-1-tablet{width:calc(12.5% - 16px);width:calc(12.5% - var(--mdc-layout-grid-gutter-tablet, 16px))}@supports(display: grid){.mdc-layout-grid__cell--span-1,.mdc-layout-grid__cell--span-1-tablet{width:auto;grid-column-end:span 1}}.mdc-layout-grid__cell--span-2,.mdc-layout-grid__cell--span-2-tablet{width:calc(25% - 16px);width:calc(25% - var(--mdc-layout-grid-gutter-tablet, 16px))}@supports(display: grid){.mdc-layout-grid__cell--span-2,.mdc-layout-grid__cell--span-2-tablet{width:auto;grid-column-end:span 2}}.mdc-layout-grid__cell--span-3,.mdc-layout-grid__cell--span-3-tablet{width:calc(37.5% - 16px);width:calc(37.5% - var(--mdc-layout-grid-gutter-tablet, 16px))}@supports(display: grid){.mdc-layout-grid__cell--span-3,.mdc-layout-grid__cell--span-3-tablet{width:auto;grid-column-end:span 3}}.mdc-layout-grid__cell--span-4,.mdc-layout-grid__cell--span-4-tablet{width:calc(50% - 16px);width:calc(50% - var(--mdc-layout-grid-gutter-tablet, 16px))}@supports(display: grid){.mdc-layout-grid__cell--span-4,.mdc-layout-grid__cell--span-4-tablet{width:auto;grid-column-end:span 4}}.mdc-layout-grid__cell--span-5,.mdc-layout-grid__cell--span-5-tablet{width:calc(62.5% - 16px);width:calc(62.5% - var(--mdc-layout-grid-gutter-tablet, 16px))}@supports(display: grid){.mdc-layout-grid__cell--span-5,.mdc-layout-grid__cell--span-5-tablet{width:auto;grid-column-end:span 5}}.mdc-layout-grid__cell--span-6,.mdc-layout-grid__cell--span-6-tablet{width:calc(75% - 16px);width:calc(75% - var(--mdc-layout-grid-gutter-tablet, 16px))}@supports(display: grid){.mdc-layout-grid__cell--span-6,.mdc-layout-grid__cell--span-6-tablet{width:auto;grid-column-end:span 6}}.mdc-layout-grid__cell--span-7,.mdc-layout-grid__cell--span-7-tablet{width:calc(87.5% - 16px);width:calc(87.5% - var(--mdc-layout-grid-gutter-tablet, 16px))}@supports(display: grid){.mdc-layout-grid__cell--span-7,.mdc-layout-grid__cell--span-7-tablet{width:auto;grid-column-end:span 7}}.mdc-layout-grid__cell--span-8,.mdc-layout-grid__cell--span-8-tablet{width:calc(100% - 16px);width:calc(100% - var(--mdc-layout-grid-gutter-tablet, 16px))}@supports(display: grid){.mdc-layout-grid__cell--span-8,.mdc-layout-grid__cell--span-8-tablet{width:auto;grid-column-end:span 8}}.mdc-layout-grid__cell--span-9,.mdc-layout-grid__cell--span-9-tablet{width:calc(100% - 16px);width:calc(100% - var(--mdc-layout-grid-gutter-tablet, 16px))}@supports(display: grid){.mdc-layout-grid__cell--span-9,.mdc-layout-grid__cell--span-9-tablet{width:auto;grid-column-end:span 8}}.mdc-layout-grid__cell--span-10,.mdc-layout-grid__cell--span-10-tablet{width:calc(100% - 16px);width:calc(100% - var(--mdc-layout-grid-gutter-tablet, 16px))}@supports(display: grid){.mdc-layout-grid__cell--span-10,.mdc-layout-grid__cell--span-10-tablet{width:auto;grid-column-end:span 8}}.mdc-layout-grid__cell--span-11,.mdc-layout-grid__cell--span-11-tablet{width:calc(100% - 16px);width:calc(100% - var(--mdc-layout-grid-gutter-tablet, 16px))}@supports(display: grid){.mdc-layout-grid__cell--span-11,.mdc-layout-grid__cell--span-11-tablet{width:auto;grid-column-end:span 8}}.mdc-layout-grid__cell--span-12,.mdc-layout-grid__cell--span-12-tablet{width:calc(100% - 16px);width:calc(100% - var(--mdc-layout-grid-gutter-tablet, 16px))}@supports(display: grid){.mdc-layout-grid__cell--span-12,.mdc-layout-grid__cell--span-12-tablet{width:auto;grid-column-end:span 8}}}@media(max-width: 599px){.mdc-layout-grid__cell{width:calc(100% - 16px);width:calc(100% - var(--mdc-layout-grid-gutter-phone, 16px));box-sizing:border-box;margin:8px;margin:calc(var(--mdc-layout-grid-gutter-phone, 16px) / 2)}@supports(display: grid){.mdc-layout-grid__cell{width:auto;grid-column-end:span 4}}@supports(display: grid){.mdc-layout-grid__cell{margin:0}}.mdc-layout-grid__cell--span-1,.mdc-layout-grid__cell--span-1-phone{width:calc(25% - 16px);width:calc(25% - var(--mdc-layout-grid-gutter-phone, 16px))}@supports(display: grid){.mdc-layout-grid__cell--span-1,.mdc-layout-grid__cell--span-1-phone{width:auto;grid-column-end:span 1}}.mdc-layout-grid__cell--span-2,.mdc-layout-grid__cell--span-2-phone{width:calc(50% - 16px);width:calc(50% - var(--mdc-layout-grid-gutter-phone, 16px))}@supports(display: grid){.mdc-layout-grid__cell--span-2,.mdc-layout-grid__cell--span-2-phone{width:auto;grid-column-end:span 2}}.mdc-layout-grid__cell--span-3,.mdc-layout-grid__cell--span-3-phone{width:calc(75% - 16px);width:calc(75% - var(--mdc-layout-grid-gutter-phone, 16px))}@supports(display: grid){.mdc-layout-grid__cell--span-3,.mdc-layout-grid__cell--span-3-phone{width:auto;grid-column-end:span 3}}.mdc-layout-grid__cell--span-4,.mdc-layout-grid__cell--span-4-phone{width:calc(100% - 16px);width:calc(100% - var(--mdc-layout-grid-gutter-phone, 16px))}@supports(display: grid){.mdc-layout-grid__cell--span-4,.mdc-layout-grid__cell--span-4-phone{width:auto;grid-column-end:span 4}}.mdc-layout-grid__cell--span-5,.mdc-layout-grid__cell--span-5-phone{width:calc(100% - 16px);width:calc(100% - var(--mdc-layout-grid-gutter-phone, 16px))}@supports(display: grid){.mdc-layout-grid__cell--span-5,.mdc-layout-grid__cell--span-5-phone{width:auto;grid-column-end:span 4}}.mdc-layout-grid__cell--span-6,.mdc-layout-grid__cell--span-6-phone{width:calc(100% - 16px);width:calc(100% - var(--mdc-layout-grid-gutter-phone, 16px))}@supports(display: grid){.mdc-layout-grid__cell--span-6,.mdc-layout-grid__cell--span-6-phone{width:auto;grid-column-end:span 4}}.mdc-layout-grid__cell--span-7,.mdc-layout-grid__cell--span-7-phone{width:calc(100% - 16px);width:calc(100% - var(--mdc-layout-grid-gutter-phone, 16px))}@supports(display: grid){.mdc-layout-grid__cell--span-7,.mdc-layout-grid__cell--span-7-phone{width:auto;grid-column-end:span 4}}.mdc-layout-grid__cell--span-8,.mdc-layout-grid__cell--span-8-phone{width:calc(100% - 16px);width:calc(100% - var(--mdc-layout-grid-gutter-phone, 16px))}@supports(display: grid){.mdc-layout-grid__cell--span-8,.mdc-layout-grid__cell--span-8-phone{width:auto;grid-column-end:span 4}}.mdc-layout-grid__cell--span-9,.mdc-layout-grid__cell--span-9-phone{width:calc(100% - 16px);width:calc(100% - var(--mdc-layout-grid-gutter-phone, 16px))}@supports(display: grid){.mdc-layout-grid__cell--span-9,.mdc-layout-grid__cell--span-9-phone{width:auto;grid-column-end:span 4}}.mdc-layout-grid__cell--span-10,.mdc-layout-grid__cell--span-10-phone{width:calc(100% - 16px);width:calc(100% - var(--mdc-layout-grid-gutter-phone, 16px))}@supports(display: grid){.mdc-layout-grid__cell--span-10,.mdc-layout-grid__cell--span-10-phone{width:auto;grid-column-end:span 4}}.mdc-layout-grid__cell--span-11,.mdc-layout-grid__cell--span-11-phone{width:calc(100% - 16px);width:calc(100% - var(--mdc-layout-grid-gutter-phone, 16px))}@supports(display: grid){.mdc-layout-grid__cell--span-11,.mdc-layout-grid__cell--span-11-phone{width:auto;grid-column-end:span 4}}.mdc-layout-grid__cell--span-12,.mdc-layout-grid__cell--span-12-phone{width:calc(100% - 16px);width:calc(100% - var(--mdc-layout-grid-gutter-phone, 16px))}@supports(display: grid){.mdc-layout-grid__cell--span-12,.mdc-layout-grid__cell--span-12-phone{width:auto;grid-column-end:span 4}}}.mdc-layout-grid__cell--order-1{order:1}.mdc-layout-grid__cell--order-2{order:2}.mdc-layout-grid__cell--order-3{order:3}.mdc-layout-grid__cell--order-4{order:4}.mdc-layout-grid__cell--order-5{order:5}.mdc-layout-grid__cell--order-6{order:6}.mdc-layout-grid__cell--order-7{order:7}.mdc-layout-grid__cell--order-8{order:8}.mdc-layout-grid__cell--order-9{order:9}.mdc-layout-grid__cell--order-10{order:10}.mdc-layout-grid__cell--order-11{order:11}.mdc-layout-grid__cell--order-12{order:12}.mdc-layout-grid__cell--align-top{align-self:flex-start}@supports(display: grid){.mdc-layout-grid__cell--align-top{align-self:start}}.mdc-layout-grid__cell--align-middle{align-self:center}.mdc-layout-grid__cell--align-bottom{align-self:flex-end}@supports(display: grid){.mdc-layout-grid__cell--align-bottom{align-self:end}}@media(min-width: 840px){.mdc-layout-grid--fixed-column-width{width:1176px;width:calc( var(--mdc-layout-grid-column-width-desktop, 72px) * 12 + var(--mdc-layout-grid-gutter-desktop, 24px) * 11 + var(--mdc-layout-grid-margin-desktop, 24px) * 2 )}}@media(min-width: 600px)and (max-width: 839px){.mdc-layout-grid--fixed-column-width{width:720px;width:calc( var(--mdc-layout-grid-column-width-tablet, 72px) * 8 + var(--mdc-layout-grid-gutter-tablet, 16px) * 7 + var(--mdc-layout-grid-margin-tablet, 16px) * 2 )}}@media(max-width: 599px){.mdc-layout-grid--fixed-column-width{width:368px;width:calc( var(--mdc-layout-grid-column-width-phone, 72px) * 4 + var(--mdc-layout-grid-gutter-phone, 16px) * 3 + var(--mdc-layout-grid-margin-phone, 16px) * 2 )}}.mdc-layout-grid--align-left{margin-right:auto;margin-left:0}.mdc-layout-grid--align-right{margin-right:0;margin-left:auto}.mdc-line-ripple::before,.mdc-line-ripple::after{position:absolute;bottom:0;left:0;width:100%;border-bottom-style:solid;content:""}.mdc-line-ripple::before{border-bottom-width:1px;z-index:1}.mdc-line-ripple::after{-webkit-transform:scaleX(0);transform:scaleX(0);border-bottom-width:2px;opacity:0;z-index:2}.mdc-line-ripple::after{transition:opacity 180ms cubic-bezier(0.4, 0, 0.2, 1),-webkit-transform 180ms cubic-bezier(0.4, 0, 0.2, 1);transition:transform 180ms cubic-bezier(0.4, 0, 0.2, 1),opacity 180ms cubic-bezier(0.4, 0, 0.2, 1);transition:transform 180ms cubic-bezier(0.4, 0, 0.2, 1),opacity 180ms cubic-bezier(0.4, 0, 0.2, 1),-webkit-transform 180ms cubic-bezier(0.4, 0, 0.2, 1)}.mdc-line-ripple--active::after{-webkit-transform:scaleX(1);transform:scaleX(1);opacity:1}.mdc-line-ripple--deactivating::after{opacity:0}@-webkit-keyframes mdc-linear-progress-primary-indeterminate-translate{0%{-webkit-transform:translateX(0);transform:translateX(0)}20%{-webkit-animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);-webkit-transform:translateX(0);transform:translateX(0)}59.15%{-webkit-animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);-webkit-transform:translateX(83.67142%);transform:translateX(83.67142%)}100%{-webkit-transform:translateX(200.611057%);transform:translateX(200.611057%)}}@keyframes mdc-linear-progress-primary-indeterminate-translate{0%{-webkit-transform:translateX(0);transform:translateX(0)}20%{-webkit-animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);-webkit-transform:translateX(0);transform:translateX(0)}59.15%{-webkit-animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);-webkit-transform:translateX(83.67142%);transform:translateX(83.67142%)}100%{-webkit-transform:translateX(200.611057%);transform:translateX(200.611057%)}}@-webkit-keyframes mdc-linear-progress-primary-indeterminate-scale{0%{-webkit-transform:scaleX(0.08);transform:scaleX(0.08)}36.65%{-webkit-animation-timing-function:cubic-bezier(0.334731, 0.12482, 0.785844, 1);animation-timing-function:cubic-bezier(0.334731, 0.12482, 0.785844, 1);-webkit-transform:scaleX(0.08);transform:scaleX(0.08)}69.15%{-webkit-animation-timing-function:cubic-bezier(0.06, 0.11, 0.6, 1);animation-timing-function:cubic-bezier(0.06, 0.11, 0.6, 1);-webkit-transform:scaleX(0.661479);transform:scaleX(0.661479)}100%{-webkit-transform:scaleX(0.08);transform:scaleX(0.08)}}@keyframes mdc-linear-progress-primary-indeterminate-scale{0%{-webkit-transform:scaleX(0.08);transform:scaleX(0.08)}36.65%{-webkit-animation-timing-function:cubic-bezier(0.334731, 0.12482, 0.785844, 1);animation-timing-function:cubic-bezier(0.334731, 0.12482, 0.785844, 1);-webkit-transform:scaleX(0.08);transform:scaleX(0.08)}69.15%{-webkit-animation-timing-function:cubic-bezier(0.06, 0.11, 0.6, 1);animation-timing-function:cubic-bezier(0.06, 0.11, 0.6, 1);-webkit-transform:scaleX(0.661479);transform:scaleX(0.661479)}100%{-webkit-transform:scaleX(0.08);transform:scaleX(0.08)}}@-webkit-keyframes mdc-linear-progress-secondary-indeterminate-translate{0%{-webkit-animation-timing-function:cubic-bezier(0.15, 0, 0.515058, 0.409685);animation-timing-function:cubic-bezier(0.15, 0, 0.515058, 0.409685);-webkit-transform:translateX(0);transform:translateX(0)}25%{-webkit-animation-timing-function:cubic-bezier(0.31033, 0.284058, 0.8, 0.733712);animation-timing-function:cubic-bezier(0.31033, 0.284058, 0.8, 0.733712);-webkit-transform:translateX(37.651913%);transform:translateX(37.651913%)}48.35%{-webkit-animation-timing-function:cubic-bezier(0.4, 0.627035, 0.6, 0.902026);animation-timing-function:cubic-bezier(0.4, 0.627035, 0.6, 0.902026);-webkit-transform:translateX(84.386165%);transform:translateX(84.386165%)}100%{-webkit-transform:translateX(160.277782%);transform:translateX(160.277782%)}}@keyframes mdc-linear-progress-secondary-indeterminate-translate{0%{-webkit-animation-timing-function:cubic-bezier(0.15, 0, 0.515058, 0.409685);animation-timing-function:cubic-bezier(0.15, 0, 0.515058, 0.409685);-webkit-transform:translateX(0);transform:translateX(0)}25%{-webkit-animation-timing-function:cubic-bezier(0.31033, 0.284058, 0.8, 0.733712);animation-timing-function:cubic-bezier(0.31033, 0.284058, 0.8, 0.733712);-webkit-transform:translateX(37.651913%);transform:translateX(37.651913%)}48.35%{-webkit-animation-timing-function:cubic-bezier(0.4, 0.627035, 0.6, 0.902026);animation-timing-function:cubic-bezier(0.4, 0.627035, 0.6, 0.902026);-webkit-transform:translateX(84.386165%);transform:translateX(84.386165%)}100%{-webkit-transform:translateX(160.277782%);transform:translateX(160.277782%)}}@-webkit-keyframes mdc-linear-progress-secondary-indeterminate-scale{0%{-webkit-animation-timing-function:cubic-bezier(0.205028, 0.057051, 0.57661, 0.453971);animation-timing-function:cubic-bezier(0.205028, 0.057051, 0.57661, 0.453971);-webkit-transform:scaleX(0.08);transform:scaleX(0.08)}19.15%{-webkit-animation-timing-function:cubic-bezier(0.152313, 0.196432, 0.648374, 1.004315);animation-timing-function:cubic-bezier(0.152313, 0.196432, 0.648374, 1.004315);-webkit-transform:scaleX(0.457104);transform:scaleX(0.457104)}44.15%{-webkit-animation-timing-function:cubic-bezier(0.257759, -0.003163, 0.211762, 1.38179);animation-timing-function:cubic-bezier(0.257759, -0.003163, 0.211762, 1.38179);-webkit-transform:scaleX(0.72796);transform:scaleX(0.72796)}100%{-webkit-transform:scaleX(0.08);transform:scaleX(0.08)}}@keyframes mdc-linear-progress-secondary-indeterminate-scale{0%{-webkit-animation-timing-function:cubic-bezier(0.205028, 0.057051, 0.57661, 0.453971);animation-timing-function:cubic-bezier(0.205028, 0.057051, 0.57661, 0.453971);-webkit-transform:scaleX(0.08);transform:scaleX(0.08)}19.15%{-webkit-animation-timing-function:cubic-bezier(0.152313, 0.196432, 0.648374, 1.004315);animation-timing-function:cubic-bezier(0.152313, 0.196432, 0.648374, 1.004315);-webkit-transform:scaleX(0.457104);transform:scaleX(0.457104)}44.15%{-webkit-animation-timing-function:cubic-bezier(0.257759, -0.003163, 0.211762, 1.38179);animation-timing-function:cubic-bezier(0.257759, -0.003163, 0.211762, 1.38179);-webkit-transform:scaleX(0.72796);transform:scaleX(0.72796)}100%{-webkit-transform:scaleX(0.08);transform:scaleX(0.08)}}@-webkit-keyframes mdc-linear-progress-buffering{from{-webkit-transform:rotate(180deg) translateX(-10px);transform:rotate(180deg) translateX(-10px)}}@keyframes mdc-linear-progress-buffering{from{-webkit-transform:rotate(180deg) translateX(-10px);transform:rotate(180deg) translateX(-10px)}}@-webkit-keyframes mdc-linear-progress-primary-indeterminate-translate-reverse{0%{-webkit-transform:translateX(0);transform:translateX(0)}20%{-webkit-animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);-webkit-transform:translateX(0);transform:translateX(0)}59.15%{-webkit-animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);-webkit-transform:translateX(-83.67142%);transform:translateX(-83.67142%)}100%{-webkit-transform:translateX(-200.611057%);transform:translateX(-200.611057%)}}@keyframes mdc-linear-progress-primary-indeterminate-translate-reverse{0%{-webkit-transform:translateX(0);transform:translateX(0)}20%{-webkit-animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);-webkit-transform:translateX(0);transform:translateX(0)}59.15%{-webkit-animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);-webkit-transform:translateX(-83.67142%);transform:translateX(-83.67142%)}100%{-webkit-transform:translateX(-200.611057%);transform:translateX(-200.611057%)}}@-webkit-keyframes mdc-linear-progress-secondary-indeterminate-translate-reverse{0%{-webkit-animation-timing-function:cubic-bezier(0.15, 0, 0.515058, 0.409685);animation-timing-function:cubic-bezier(0.15, 0, 0.515058, 0.409685);-webkit-transform:translateX(0);transform:translateX(0)}25%{-webkit-animation-timing-function:cubic-bezier(0.31033, 0.284058, 0.8, 0.733712);animation-timing-function:cubic-bezier(0.31033, 0.284058, 0.8, 0.733712);-webkit-transform:translateX(-37.651913%);transform:translateX(-37.651913%)}48.35%{-webkit-animation-timing-function:cubic-bezier(0.4, 0.627035, 0.6, 0.902026);animation-timing-function:cubic-bezier(0.4, 0.627035, 0.6, 0.902026);-webkit-transform:translateX(-84.386165%);transform:translateX(-84.386165%)}100%{-webkit-transform:translateX(-160.277782%);transform:translateX(-160.277782%)}}@keyframes mdc-linear-progress-secondary-indeterminate-translate-reverse{0%{-webkit-animation-timing-function:cubic-bezier(0.15, 0, 0.515058, 0.409685);animation-timing-function:cubic-bezier(0.15, 0, 0.515058, 0.409685);-webkit-transform:translateX(0);transform:translateX(0)}25%{-webkit-animation-timing-function:cubic-bezier(0.31033, 0.284058, 0.8, 0.733712);animation-timing-function:cubic-bezier(0.31033, 0.284058, 0.8, 0.733712);-webkit-transform:translateX(-37.651913%);transform:translateX(-37.651913%)}48.35%{-webkit-animation-timing-function:cubic-bezier(0.4, 0.627035, 0.6, 0.902026);animation-timing-function:cubic-bezier(0.4, 0.627035, 0.6, 0.902026);-webkit-transform:translateX(-84.386165%);transform:translateX(-84.386165%)}100%{-webkit-transform:translateX(-160.277782%);transform:translateX(-160.277782%)}}@-webkit-keyframes mdc-linear-progress-buffering-reverse{from{-webkit-transform:translateX(-10px);transform:translateX(-10px)}}@keyframes mdc-linear-progress-buffering-reverse{from{-webkit-transform:translateX(-10px);transform:translateX(-10px)}}.mdc-linear-progress{position:relative;width:100%;height:4px;-webkit-transform:translateZ(0);transform:translateZ(0);outline:1px solid transparent;overflow:hidden;transition:opacity 250ms 0ms cubic-bezier(0.4, 0, 0.6, 1)}.mdc-linear-progress__bar{position:absolute;width:100%;height:100%;-webkit-animation:none;animation:none;-webkit-transform-origin:top left;transform-origin:top left;transition:-webkit-transform 250ms 0ms cubic-bezier(0.4, 0, 0.6, 1);transition:transform 250ms 0ms cubic-bezier(0.4, 0, 0.6, 1);transition:transform 250ms 0ms cubic-bezier(0.4, 0, 0.6, 1), -webkit-transform 250ms 0ms cubic-bezier(0.4, 0, 0.6, 1)}.mdc-linear-progress__bar-inner{display:inline-block;position:absolute;width:100%;-webkit-animation:none;animation:none;border-top:4px solid}.mdc-linear-progress__buffer{display:flex;position:absolute;width:100%;height:100%}.mdc-linear-progress__buffer-dots{background-repeat:repeat-x;background-size:10px 4px;flex:auto;-webkit-transform:rotate(180deg);transform:rotate(180deg);-webkit-animation:mdc-linear-progress-buffering 250ms infinite linear;animation:mdc-linear-progress-buffering 250ms infinite linear}.mdc-linear-progress__buffer-bar{flex:0 1 100%;transition:flex-basis 250ms 0ms cubic-bezier(0.4, 0, 0.6, 1)}.mdc-linear-progress__primary-bar{-webkit-transform:scaleX(0);transform:scaleX(0)}.mdc-linear-progress__secondary-bar{visibility:hidden}.mdc-linear-progress--indeterminate .mdc-linear-progress__bar{transition:none}.mdc-linear-progress--indeterminate .mdc-linear-progress__primary-bar{left:-145.166611%;-webkit-animation:mdc-linear-progress-primary-indeterminate-translate 2s infinite linear;animation:mdc-linear-progress-primary-indeterminate-translate 2s infinite linear}.mdc-linear-progress--indeterminate .mdc-linear-progress__primary-bar>.mdc-linear-progress__bar-inner{-webkit-animation:mdc-linear-progress-primary-indeterminate-scale 2s infinite linear;animation:mdc-linear-progress-primary-indeterminate-scale 2s infinite linear}.mdc-linear-progress--indeterminate .mdc-linear-progress__secondary-bar{left:-54.888891%;visibility:visible;-webkit-animation:mdc-linear-progress-secondary-indeterminate-translate 2s infinite linear;animation:mdc-linear-progress-secondary-indeterminate-translate 2s infinite linear}.mdc-linear-progress--indeterminate .mdc-linear-progress__secondary-bar>.mdc-linear-progress__bar-inner{-webkit-animation:mdc-linear-progress-secondary-indeterminate-scale 2s infinite linear;animation:mdc-linear-progress-secondary-indeterminate-scale 2s infinite linear}.mdc-linear-progress--reversed .mdc-linear-progress__bar{right:0;-webkit-transform-origin:center right;transform-origin:center right}.mdc-linear-progress--reversed .mdc-linear-progress__primary-bar{-webkit-animation-name:mdc-linear-progress-primary-indeterminate-translate-reverse;animation-name:mdc-linear-progress-primary-indeterminate-translate-reverse}.mdc-linear-progress--reversed .mdc-linear-progress__secondary-bar{-webkit-animation-name:mdc-linear-progress-secondary-indeterminate-translate-reverse;animation-name:mdc-linear-progress-secondary-indeterminate-translate-reverse}.mdc-linear-progress--reversed .mdc-linear-progress__buffer-dots{-webkit-animation:mdc-linear-progress-buffering-reverse 250ms infinite linear;animation:mdc-linear-progress-buffering-reverse 250ms infinite linear;order:0;-webkit-transform:rotate(0);transform:rotate(0)}.mdc-linear-progress--reversed .mdc-linear-progress__buffer-bar{order:1}.mdc-linear-progress--closed{opacity:0;-webkit-animation:none;animation:none}.mdc-linear-progress__bar-inner{border-color:#6200ee;border-color:var(--mdc-theme-primary, #6200ee)}.mdc-linear-progress__buffer-dots{background-image:url("data:image/svg+xml,%3Csvg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' enable-background='new 0 0 5 2' xml:space='preserve' viewBox='0 0 5 2' preserveAspectRatio='none slice'%3E%3Ccircle cx='1' cy='1' r='1' fill='%23e6e6e6'/%3E%3C/svg%3E")}.mdc-linear-progress__buffer-bar{background-color:#e6e6e6}.mdc-linear-progress--indeterminate.mdc-linear-progress--reversed .mdc-linear-progress__primary-bar{right:-145.166611%;left:auto}.mdc-linear-progress--indeterminate.mdc-linear-progress--reversed .mdc-linear-progress__secondary-bar{right:-54.888891%;left:auto}.mdc-list{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-subtitle1-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:1rem;font-size:var(--mdc-typography-subtitle1-font-size, 1rem);line-height:1.75rem;line-height:var(--mdc-typography-subtitle1-line-height, 1.75rem);font-weight:400;font-weight:var(--mdc-typography-subtitle1-font-weight, 400);letter-spacing:.009375em;letter-spacing:var(--mdc-typography-subtitle1-letter-spacing, 0.009375em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-subtitle1-text-decoration, inherit);text-decoration:var(--mdc-typography-subtitle1-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-subtitle1-text-transform, inherit);line-height:1.5rem;margin:0;padding:8px 0;list-style-type:none;color:rgba(0,0,0,.87);color:var(--mdc-theme-text-primary-on-background, rgba(0, 0, 0, 0.87))}.mdc-list:focus{outline:none}.mdc-list-item{height:48px}.mdc-list-item__secondary-text{color:rgba(0,0,0,.54);color:var(--mdc-theme-text-secondary-on-background, rgba(0, 0, 0, 0.54))}.mdc-list-item__graphic{background-color:transparent}.mdc-list-item__graphic{color:rgba(0,0,0,.38);color:var(--mdc-theme-text-icon-on-background, rgba(0, 0, 0, 0.38))}.mdc-list-item__meta{color:rgba(0,0,0,.38);color:var(--mdc-theme-text-hint-on-background, rgba(0, 0, 0, 0.38))}.mdc-list-group__subheader{color:rgba(0,0,0,.87);color:var(--mdc-theme-text-primary-on-background, rgba(0, 0, 0, 0.87))}.mdc-list-item--disabled .mdc-list-item__text{opacity:.38}.mdc-list-item--disabled .mdc-list-item__text,.mdc-list-item--disabled .mdc-list-item__primary-text,.mdc-list-item--disabled .mdc-list-item__secondary-text{color:#000;color:var(--mdc-theme-on-surface, #000)}.mdc-list--dense{padding-top:4px;padding-bottom:4px;font-size:.812rem}.mdc-list-item{display:flex;position:relative;align-items:center;justify-content:flex-start;padding:0 16px;overflow:hidden}.mdc-list-item:focus{outline:none}.mdc-list-item--selected,.mdc-list-item--activated{color:#6200ee;color:var(--mdc-theme-primary, #6200ee)}.mdc-list-item--selected .mdc-list-item__graphic,.mdc-list-item--activated .mdc-list-item__graphic{color:#6200ee;color:var(--mdc-theme-primary, #6200ee)}.mdc-list-item__graphic{margin-left:0;margin-right:32px;width:24px;height:24px;flex-shrink:0;align-items:center;justify-content:center;fill:currentColor}.mdc-list-item[dir=rtl] .mdc-list-item__graphic,[dir=rtl] .mdc-list-item .mdc-list-item__graphic{margin-left:32px;margin-right:0}.mdc-list .mdc-list-item__graphic{display:inline-flex}.mdc-list-item__meta{margin-left:auto;margin-right:0}.mdc-list-item__meta:not(.material-icons){-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-caption-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:.75rem;font-size:var(--mdc-typography-caption-font-size, 0.75rem);line-height:1.25rem;line-height:var(--mdc-typography-caption-line-height, 1.25rem);font-weight:400;font-weight:var(--mdc-typography-caption-font-weight, 400);letter-spacing:.0333333333em;letter-spacing:var(--mdc-typography-caption-letter-spacing, 0.0333333333em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-caption-text-decoration, inherit);text-decoration:var(--mdc-typography-caption-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-caption-text-transform, inherit)}.mdc-list-item[dir=rtl] .mdc-list-item__meta,[dir=rtl] .mdc-list-item .mdc-list-item__meta{margin-left:0;margin-right:auto}.mdc-list-item__text{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.mdc-list-item__text[for]{pointer-events:none}.mdc-list-item__primary-text{text-overflow:ellipsis;white-space:nowrap;overflow:hidden;display:block;margin-top:0;line-height:normal;margin-bottom:-20px}.mdc-list-item__primary-text::before{display:inline-block;width:0;height:32px;content:"";vertical-align:0}.mdc-list-item__primary-text::after{display:inline-block;width:0;height:20px;content:"";vertical-align:-20px}.mdc-list--dense .mdc-list-item__primary-text{display:block;margin-top:0;line-height:normal;margin-bottom:-20px}.mdc-list--dense .mdc-list-item__primary-text::before{display:inline-block;width:0;height:24px;content:"";vertical-align:0}.mdc-list--dense .mdc-list-item__primary-text::after{display:inline-block;width:0;height:20px;content:"";vertical-align:-20px}.mdc-list-item__secondary-text{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-body2-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:.875rem;font-size:var(--mdc-typography-body2-font-size, 0.875rem);line-height:1.25rem;line-height:var(--mdc-typography-body2-line-height, 1.25rem);font-weight:400;font-weight:var(--mdc-typography-body2-font-weight, 400);letter-spacing:.0178571429em;letter-spacing:var(--mdc-typography-body2-letter-spacing, 0.0178571429em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-body2-text-decoration, inherit);text-decoration:var(--mdc-typography-body2-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-body2-text-transform, inherit);text-overflow:ellipsis;white-space:nowrap;overflow:hidden;display:block;margin-top:0;line-height:normal}.mdc-list-item__secondary-text::before{display:inline-block;width:0;height:20px;content:"";vertical-align:0}.mdc-list--dense .mdc-list-item__secondary-text{font-size:inherit}.mdc-list--dense .mdc-list-item{height:40px}.mdc-list--dense .mdc-list-item__graphic{margin-left:0;margin-right:36px;width:20px;height:20px}.mdc-list-item[dir=rtl] .mdc-list--dense .mdc-list-item__graphic,[dir=rtl] .mdc-list-item .mdc-list--dense .mdc-list-item__graphic{margin-left:36px;margin-right:0}.mdc-list--avatar-list .mdc-list-item{height:56px}.mdc-list--avatar-list .mdc-list-item__graphic{margin-left:0;margin-right:16px;width:40px;height:40px;border-radius:50%}.mdc-list-item[dir=rtl] .mdc-list--avatar-list .mdc-list-item__graphic,[dir=rtl] .mdc-list-item .mdc-list--avatar-list .mdc-list-item__graphic{margin-left:16px;margin-right:0}.mdc-list--two-line .mdc-list-item__text{align-self:flex-start}.mdc-list--two-line .mdc-list-item{height:72px}.mdc-list--two-line.mdc-list--dense .mdc-list-item,.mdc-list--avatar-list.mdc-list--dense .mdc-list-item{height:60px}.mdc-list--avatar-list.mdc-list--dense .mdc-list-item__graphic{margin-left:0;margin-right:20px;width:36px;height:36px}.mdc-list-item[dir=rtl] .mdc-list--avatar-list.mdc-list--dense .mdc-list-item__graphic,[dir=rtl] .mdc-list-item .mdc-list--avatar-list.mdc-list--dense .mdc-list-item__graphic{margin-left:20px;margin-right:0}:not(.mdc-list--non-interactive)>:not(.mdc-list-item--disabled).mdc-list-item{cursor:pointer}a.mdc-list-item{color:inherit;text-decoration:none}.mdc-list-divider{height:0;margin:0;border:none;border-bottom-width:1px;border-bottom-style:solid}.mdc-list-divider{border-bottom-color:rgba(0,0,0,.12)}.mdc-list-divider--padded{margin:0 16px}.mdc-list-divider--inset{margin-left:72px;margin-right:0;width:calc(100% - 72px)}.mdc-list-group[dir=rtl] .mdc-list-divider--inset,[dir=rtl] .mdc-list-group .mdc-list-divider--inset{margin-left:0;margin-right:72px}.mdc-list-divider--inset.mdc-list-divider--padded{width:calc(100% - 72px - 16px)}.mdc-list-group .mdc-list{padding:0}.mdc-list-group__subheader{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-subtitle1-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:1rem;font-size:var(--mdc-typography-subtitle1-font-size, 1rem);line-height:1.75rem;line-height:var(--mdc-typography-subtitle1-line-height, 1.75rem);font-weight:400;font-weight:var(--mdc-typography-subtitle1-font-weight, 400);letter-spacing:.009375em;letter-spacing:var(--mdc-typography-subtitle1-letter-spacing, 0.009375em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-subtitle1-text-decoration, inherit);text-decoration:var(--mdc-typography-subtitle1-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-subtitle1-text-transform, inherit);margin:calc((3rem - 1.5rem) / 2) 16px}:not(.mdc-list--non-interactive)>:not(.mdc-list-item--disabled).mdc-list-item{--mdc-ripple-fg-size: 0;--mdc-ripple-left: 0;--mdc-ripple-top: 0;--mdc-ripple-fg-scale: 1;--mdc-ripple-fg-translate-end: 0;--mdc-ripple-fg-translate-start: 0;-webkit-tap-highlight-color:rgba(0,0,0,0)}:not(.mdc-list--non-interactive)>:not(.mdc-list-item--disabled).mdc-list-item::before,:not(.mdc-list--non-interactive)>:not(.mdc-list-item--disabled).mdc-list-item::after{position:absolute;border-radius:50%;opacity:0;pointer-events:none;content:""}:not(.mdc-list--non-interactive)>:not(.mdc-list-item--disabled).mdc-list-item::before{transition:opacity 15ms linear,background-color 15ms linear;z-index:1}:not(.mdc-list--non-interactive)>:not(.mdc-list-item--disabled).mdc-list-item.mdc-ripple-upgraded::before{-webkit-transform:scale(var(--mdc-ripple-fg-scale, 1));transform:scale(var(--mdc-ripple-fg-scale, 1))}:not(.mdc-list--non-interactive)>:not(.mdc-list-item--disabled).mdc-list-item.mdc-ripple-upgraded::after{top:0;left:0;-webkit-transform:scale(0);transform:scale(0);-webkit-transform-origin:center center;transform-origin:center center}:not(.mdc-list--non-interactive)>:not(.mdc-list-item--disabled).mdc-list-item.mdc-ripple-upgraded--unbounded::after{top:var(--mdc-ripple-top, 0);left:var(--mdc-ripple-left, 0)}:not(.mdc-list--non-interactive)>:not(.mdc-list-item--disabled).mdc-list-item.mdc-ripple-upgraded--foreground-activation::after{-webkit-animation:mdc-ripple-fg-radius-in 225ms forwards,mdc-ripple-fg-opacity-in 75ms forwards;animation:mdc-ripple-fg-radius-in 225ms forwards,mdc-ripple-fg-opacity-in 75ms forwards}:not(.mdc-list--non-interactive)>:not(.mdc-list-item--disabled).mdc-list-item.mdc-ripple-upgraded--foreground-deactivation::after{-webkit-animation:mdc-ripple-fg-opacity-out 150ms;animation:mdc-ripple-fg-opacity-out 150ms;-webkit-transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1))}:not(.mdc-list--non-interactive)>:not(.mdc-list-item--disabled).mdc-list-item::before,:not(.mdc-list--non-interactive)>:not(.mdc-list-item--disabled).mdc-list-item::after{top:calc(50% - 100%);left:calc(50% - 100%);width:200%;height:200%}:not(.mdc-list--non-interactive)>:not(.mdc-list-item--disabled).mdc-list-item.mdc-ripple-upgraded::after{width:var(--mdc-ripple-fg-size, 100%);height:var(--mdc-ripple-fg-size, 100%)}:not(.mdc-list--non-interactive)>:not(.mdc-list-item--disabled).mdc-list-item::before,:not(.mdc-list--non-interactive)>:not(.mdc-list-item--disabled).mdc-list-item::after{background-color:#000}:not(.mdc-list--non-interactive)>:not(.mdc-list-item--disabled).mdc-list-item:hover::before{opacity:.04}:not(.mdc-list--non-interactive)>:not(.mdc-list-item--disabled).mdc-list-item.mdc-ripple-upgraded--background-focused::before,:not(.mdc-list--non-interactive)>:not(.mdc-list-item--disabled).mdc-list-item:not(.mdc-ripple-upgraded):focus::before{transition-duration:75ms;opacity:.12}:not(.mdc-list--non-interactive)>:not(.mdc-list-item--disabled).mdc-list-item:not(.mdc-ripple-upgraded)::after{transition:opacity 150ms linear}:not(.mdc-list--non-interactive)>:not(.mdc-list-item--disabled).mdc-list-item:not(.mdc-ripple-upgraded):active::after{transition-duration:75ms;opacity:.12}:not(.mdc-list--non-interactive)>:not(.mdc-list-item--disabled).mdc-list-item.mdc-ripple-upgraded{--mdc-ripple-fg-opacity: 0.12}:not(.mdc-list--non-interactive)>:not(.mdc-list-item--disabled).mdc-list-item--activated::before{opacity:.12}:not(.mdc-list--non-interactive)>:not(.mdc-list-item--disabled).mdc-list-item--activated::before,:not(.mdc-list--non-interactive)>:not(.mdc-list-item--disabled).mdc-list-item--activated::after{background-color:#6200ee;background-color:var(--mdc-theme-primary, #6200ee)}:not(.mdc-list--non-interactive)>:not(.mdc-list-item--disabled).mdc-list-item--activated:hover::before{opacity:.16}:not(.mdc-list--non-interactive)>:not(.mdc-list-item--disabled).mdc-list-item--activated.mdc-ripple-upgraded--background-focused::before,:not(.mdc-list--non-interactive)>:not(.mdc-list-item--disabled).mdc-list-item--activated:not(.mdc-ripple-upgraded):focus::before{transition-duration:75ms;opacity:.24}:not(.mdc-list--non-interactive)>:not(.mdc-list-item--disabled).mdc-list-item--activated:not(.mdc-ripple-upgraded)::after{transition:opacity 150ms linear}:not(.mdc-list--non-interactive)>:not(.mdc-list-item--disabled).mdc-list-item--activated:not(.mdc-ripple-upgraded):active::after{transition-duration:75ms;opacity:.24}:not(.mdc-list--non-interactive)>:not(.mdc-list-item--disabled).mdc-list-item--activated.mdc-ripple-upgraded{--mdc-ripple-fg-opacity: 0.24}:not(.mdc-list--non-interactive)>:not(.mdc-list-item--disabled).mdc-list-item--selected::before{opacity:.08}:not(.mdc-list--non-interactive)>:not(.mdc-list-item--disabled).mdc-list-item--selected::before,:not(.mdc-list--non-interactive)>:not(.mdc-list-item--disabled).mdc-list-item--selected::after{background-color:#6200ee;background-color:var(--mdc-theme-primary, #6200ee)}:not(.mdc-list--non-interactive)>:not(.mdc-list-item--disabled).mdc-list-item--selected:hover::before{opacity:.12}:not(.mdc-list--non-interactive)>:not(.mdc-list-item--disabled).mdc-list-item--selected.mdc-ripple-upgraded--background-focused::before,:not(.mdc-list--non-interactive)>:not(.mdc-list-item--disabled).mdc-list-item--selected:not(.mdc-ripple-upgraded):focus::before{transition-duration:75ms;opacity:.2}:not(.mdc-list--non-interactive)>:not(.mdc-list-item--disabled).mdc-list-item--selected:not(.mdc-ripple-upgraded)::after{transition:opacity 150ms linear}:not(.mdc-list--non-interactive)>:not(.mdc-list-item--disabled).mdc-list-item--selected:not(.mdc-ripple-upgraded):active::after{transition-duration:75ms;opacity:.2}:not(.mdc-list--non-interactive)>:not(.mdc-list-item--disabled).mdc-list-item--selected.mdc-ripple-upgraded{--mdc-ripple-fg-opacity: 0.2}:not(.mdc-list--non-interactive)>.mdc-list-item--disabled{--mdc-ripple-fg-size: 0;--mdc-ripple-left: 0;--mdc-ripple-top: 0;--mdc-ripple-fg-scale: 1;--mdc-ripple-fg-translate-end: 0;--mdc-ripple-fg-translate-start: 0;-webkit-tap-highlight-color:rgba(0,0,0,0)}:not(.mdc-list--non-interactive)>.mdc-list-item--disabled::before,:not(.mdc-list--non-interactive)>.mdc-list-item--disabled::after{position:absolute;border-radius:50%;opacity:0;pointer-events:none;content:""}:not(.mdc-list--non-interactive)>.mdc-list-item--disabled::before{transition:opacity 15ms linear,background-color 15ms linear;z-index:1}:not(.mdc-list--non-interactive)>.mdc-list-item--disabled.mdc-ripple-upgraded::before{-webkit-transform:scale(var(--mdc-ripple-fg-scale, 1));transform:scale(var(--mdc-ripple-fg-scale, 1))}:not(.mdc-list--non-interactive)>.mdc-list-item--disabled.mdc-ripple-upgraded::after{top:0;left:0;-webkit-transform:scale(0);transform:scale(0);-webkit-transform-origin:center center;transform-origin:center center}:not(.mdc-list--non-interactive)>.mdc-list-item--disabled.mdc-ripple-upgraded--unbounded::after{top:var(--mdc-ripple-top, 0);left:var(--mdc-ripple-left, 0)}:not(.mdc-list--non-interactive)>.mdc-list-item--disabled.mdc-ripple-upgraded--foreground-activation::after{-webkit-animation:mdc-ripple-fg-radius-in 225ms forwards,mdc-ripple-fg-opacity-in 75ms forwards;animation:mdc-ripple-fg-radius-in 225ms forwards,mdc-ripple-fg-opacity-in 75ms forwards}:not(.mdc-list--non-interactive)>.mdc-list-item--disabled.mdc-ripple-upgraded--foreground-deactivation::after{-webkit-animation:mdc-ripple-fg-opacity-out 150ms;animation:mdc-ripple-fg-opacity-out 150ms;-webkit-transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1))}:not(.mdc-list--non-interactive)>.mdc-list-item--disabled::before,:not(.mdc-list--non-interactive)>.mdc-list-item--disabled::after{top:calc(50% - 100%);left:calc(50% - 100%);width:200%;height:200%}:not(.mdc-list--non-interactive)>.mdc-list-item--disabled.mdc-ripple-upgraded::after{width:var(--mdc-ripple-fg-size, 100%);height:var(--mdc-ripple-fg-size, 100%)}:not(.mdc-list--non-interactive)>.mdc-list-item--disabled::before,:not(.mdc-list--non-interactive)>.mdc-list-item--disabled::after{background-color:#000}:not(.mdc-list--non-interactive)>.mdc-list-item--disabled.mdc-ripple-upgraded--background-focused::before,:not(.mdc-list--non-interactive)>.mdc-list-item--disabled:not(.mdc-ripple-upgraded):focus::before{transition-duration:75ms;opacity:.12}.mdc-menu{min-width:112px}.mdc-menu .mdc-list-item__meta{color:rgba(0,0,0,.87)}.mdc-menu .mdc-list-item__graphic{color:rgba(0,0,0,.87)}.mdc-menu .mdc-list{color:rgba(0,0,0,.87);position:relative}.mdc-menu .mdc-list .mdc-elevation-overlay{width:100%;height:100%;top:0;left:0}.mdc-menu .mdc-list-divider{margin:8px 0}.mdc-menu .mdc-list-item{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.mdc-menu .mdc-list-item--disabled{cursor:auto}.mdc-menu a.mdc-list-item .mdc-list-item__text,.mdc-menu a.mdc-list-item .mdc-list-item__graphic{pointer-events:none}.mdc-menu__selection-group{padding:0;fill:currentColor}.mdc-menu__selection-group .mdc-list-item{padding-left:56px;padding-right:16px}[dir=rtl] .mdc-menu__selection-group .mdc-list-item,.mdc-menu__selection-group .mdc-list-item[dir=rtl]{padding-left:16px;padding-right:56px}.mdc-menu__selection-group .mdc-menu__selection-group-icon{left:16px;right:initial;display:none;position:absolute;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%)}[dir=rtl] .mdc-menu__selection-group .mdc-menu__selection-group-icon,.mdc-menu__selection-group .mdc-menu__selection-group-icon[dir=rtl]{left:initial;right:16px}.mdc-menu-item--selected .mdc-menu__selection-group-icon{display:inline}.mdc-menu-surface{display:none;position:absolute;box-sizing:border-box;max-width:calc(100vw - 32px);max-height:calc(100vh - 32px);margin:0;padding:0;-webkit-transform:scale(1);transform:scale(1);-webkit-transform-origin:top left;transform-origin:top left;opacity:0;overflow:auto;will-change:transform,opacity;z-index:8;transition:opacity .03s linear,-webkit-transform .12s cubic-bezier(0, 0, 0.2, 1);transition:opacity .03s linear,transform .12s cubic-bezier(0, 0, 0.2, 1);transition:opacity .03s linear,transform .12s cubic-bezier(0, 0, 0.2, 1),-webkit-transform .12s cubic-bezier(0, 0, 0.2, 1);box-shadow:0px 5px 5px -3px rgba(0, 0, 0, 0.2),0px 8px 10px 1px rgba(0, 0, 0, 0.14),0px 3px 14px 2px rgba(0,0,0,.12);background-color:#fff;background-color:var(--mdc-theme-surface, #fff);color:#000;color:var(--mdc-theme-on-surface, #000);border-radius:4px;transform-origin-left:top left;transform-origin-right:top right}.mdc-menu-surface:focus{outline:none}.mdc-menu-surface--open{display:inline-block;-webkit-transform:scale(1);transform:scale(1);opacity:1}.mdc-menu-surface--animating-open{display:inline-block;-webkit-transform:scale(0.8);transform:scale(0.8);opacity:0}.mdc-menu-surface--animating-closed{display:inline-block;opacity:0;transition:opacity .075s linear}[dir=rtl] .mdc-menu-surface,.mdc-menu-surface[dir=rtl]{transform-origin-left:top right;transform-origin-right:top left}.mdc-menu-surface--anchor{position:relative;overflow:visible}.mdc-menu-surface--fixed{position:fixed}.mdc-notched-outline{display:flex;position:absolute;top:0;right:0;left:0;box-sizing:border-box;width:100%;max-width:100%;height:100%;text-align:left;pointer-events:none}[dir=rtl] .mdc-notched-outline,.mdc-notched-outline[dir=rtl]{text-align:right}.mdc-notched-outline__leading,.mdc-notched-outline__notch,.mdc-notched-outline__trailing{box-sizing:border-box;height:100%;border-top:1px solid;border-bottom:1px solid;pointer-events:none}.mdc-notched-outline__leading{border-left:1px solid;border-right:none;width:12px}[dir=rtl] .mdc-notched-outline__leading,.mdc-notched-outline__leading[dir=rtl]{border-left:none;border-right:1px solid}.mdc-notched-outline__trailing{border-left:none;border-right:1px solid;flex-grow:1}[dir=rtl] .mdc-notched-outline__trailing,.mdc-notched-outline__trailing[dir=rtl]{border-left:1px solid;border-right:none}.mdc-notched-outline__notch{flex:0 0 auto;width:auto;max-width:calc(100% - 12px * 2)}.mdc-notched-outline .mdc-floating-label{display:inline-block;position:relative;max-width:100%}.mdc-notched-outline .mdc-floating-label--float-above{text-overflow:clip}.mdc-notched-outline--upgraded .mdc-floating-label--float-above{max-width:calc(100% / .75)}.mdc-notched-outline--notched .mdc-notched-outline__notch{padding-left:0;padding-right:8px;border-top:none}[dir=rtl] .mdc-notched-outline--notched .mdc-notched-outline__notch,.mdc-notched-outline--notched .mdc-notched-outline__notch[dir=rtl]{padding-left:8px;padding-right:0}.mdc-notched-outline--no-label .mdc-notched-outline__notch{padding:0}.mdc-radio{padding:10px;display:inline-block;position:relative;flex:0 0 auto;box-sizing:content-box;width:20px;height:20px;cursor:pointer;will-change:opacity,transform,border-color,color}.mdc-radio .mdc-radio__native-control:enabled:not(:checked)+.mdc-radio__background .mdc-radio__outer-circle{border-color:rgba(0,0,0,.54)}.mdc-radio .mdc-radio__native-control:enabled:checked+.mdc-radio__background .mdc-radio__outer-circle{border-color:#018786;border-color:var(--mdc-theme-secondary, #018786)}.mdc-radio .mdc-radio__native-control:enabled+.mdc-radio__background .mdc-radio__inner-circle{border-color:#018786;border-color:var(--mdc-theme-secondary, #018786)}.mdc-radio [aria-disabled=true] .mdc-radio__native-control:not(:checked)+.mdc-radio__background .mdc-radio__outer-circle,.mdc-radio .mdc-radio__native-control:disabled:not(:checked)+.mdc-radio__background .mdc-radio__outer-circle{border-color:rgba(0,0,0,.38)}.mdc-radio [aria-disabled=true] .mdc-radio__native-control:checked+.mdc-radio__background .mdc-radio__outer-circle,.mdc-radio .mdc-radio__native-control:disabled:checked+.mdc-radio__background .mdc-radio__outer-circle{border-color:rgba(0,0,0,.38)}.mdc-radio [aria-disabled=true] .mdc-radio__native-control+.mdc-radio__background .mdc-radio__inner-circle,.mdc-radio .mdc-radio__native-control:disabled+.mdc-radio__background .mdc-radio__inner-circle{border-color:rgba(0,0,0,.38)}.mdc-radio .mdc-radio__background::before{background-color:#018786;background-color:var(--mdc-theme-secondary, #018786)}.mdc-radio .mdc-radio__background::before{top:-10px;left:-10px;width:40px;height:40px}.mdc-radio .mdc-radio__native-control{top:0px;right:0px;left:0px;width:40px;height:40px}.mdc-radio__background{display:inline-block;position:relative;box-sizing:border-box;width:20px;height:20px}.mdc-radio__background::before{position:absolute;-webkit-transform:scale(0, 0);transform:scale(0, 0);border-radius:50%;opacity:0;pointer-events:none;content:"";transition:opacity 120ms 0ms cubic-bezier(0.4, 0, 0.6, 1),-webkit-transform 120ms 0ms cubic-bezier(0.4, 0, 0.6, 1);transition:opacity 120ms 0ms cubic-bezier(0.4, 0, 0.6, 1),transform 120ms 0ms cubic-bezier(0.4, 0, 0.6, 1);transition:opacity 120ms 0ms cubic-bezier(0.4, 0, 0.6, 1),transform 120ms 0ms cubic-bezier(0.4, 0, 0.6, 1),-webkit-transform 120ms 0ms cubic-bezier(0.4, 0, 0.6, 1)}.mdc-radio__outer-circle{position:absolute;top:0;left:0;box-sizing:border-box;width:100%;height:100%;border-width:2px;border-style:solid;border-radius:50%;transition:border-color 120ms 0ms cubic-bezier(0.4, 0, 0.6, 1)}.mdc-radio__inner-circle{position:absolute;top:0;left:0;box-sizing:border-box;width:100%;height:100%;-webkit-transform:scale(0, 0);transform:scale(0, 0);border-width:10px;border-style:solid;border-radius:50%;transition:border-color 120ms 0ms cubic-bezier(0.4, 0, 0.6, 1),-webkit-transform 120ms 0ms cubic-bezier(0.4, 0, 0.6, 1);transition:transform 120ms 0ms cubic-bezier(0.4, 0, 0.6, 1),border-color 120ms 0ms cubic-bezier(0.4, 0, 0.6, 1);transition:transform 120ms 0ms cubic-bezier(0.4, 0, 0.6, 1),border-color 120ms 0ms cubic-bezier(0.4, 0, 0.6, 1),-webkit-transform 120ms 0ms cubic-bezier(0.4, 0, 0.6, 1)}.mdc-radio__native-control{position:absolute;margin:0;padding:0;opacity:0;cursor:inherit;z-index:1}.mdc-radio--touch{margin-top:4px;margin-bottom:4px;margin-right:4px;margin-left:4px}.mdc-radio--touch .mdc-radio__native-control{top:-4px;right:-4px;left:-4px;width:48px;height:48px}.mdc-radio__native-control:checked+.mdc-radio__background,.mdc-radio__native-control:disabled+.mdc-radio__background{transition:opacity 120ms 0ms cubic-bezier(0, 0, 0.2, 1),-webkit-transform 120ms 0ms cubic-bezier(0, 0, 0.2, 1);transition:opacity 120ms 0ms cubic-bezier(0, 0, 0.2, 1),transform 120ms 0ms cubic-bezier(0, 0, 0.2, 1);transition:opacity 120ms 0ms cubic-bezier(0, 0, 0.2, 1),transform 120ms 0ms cubic-bezier(0, 0, 0.2, 1),-webkit-transform 120ms 0ms cubic-bezier(0, 0, 0.2, 1)}.mdc-radio__native-control:checked+.mdc-radio__background .mdc-radio__outer-circle,.mdc-radio__native-control:disabled+.mdc-radio__background .mdc-radio__outer-circle{transition:border-color 120ms 0ms cubic-bezier(0, 0, 0.2, 1)}.mdc-radio__native-control:checked+.mdc-radio__background .mdc-radio__inner-circle,.mdc-radio__native-control:disabled+.mdc-radio__background .mdc-radio__inner-circle{transition:border-color 120ms 0ms cubic-bezier(0, 0, 0.2, 1),-webkit-transform 120ms 0ms cubic-bezier(0, 0, 0.2, 1);transition:transform 120ms 0ms cubic-bezier(0, 0, 0.2, 1),border-color 120ms 0ms cubic-bezier(0, 0, 0.2, 1);transition:transform 120ms 0ms cubic-bezier(0, 0, 0.2, 1),border-color 120ms 0ms cubic-bezier(0, 0, 0.2, 1),-webkit-transform 120ms 0ms cubic-bezier(0, 0, 0.2, 1)}.mdc-radio--disabled{cursor:default;pointer-events:none}.mdc-radio__native-control:checked+.mdc-radio__background .mdc-radio__inner-circle{-webkit-transform:scale(0.5);transform:scale(0.5);transition:border-color 120ms 0ms cubic-bezier(0, 0, 0.2, 1),-webkit-transform 120ms 0ms cubic-bezier(0, 0, 0.2, 1);transition:transform 120ms 0ms cubic-bezier(0, 0, 0.2, 1),border-color 120ms 0ms cubic-bezier(0, 0, 0.2, 1);transition:transform 120ms 0ms cubic-bezier(0, 0, 0.2, 1),border-color 120ms 0ms cubic-bezier(0, 0, 0.2, 1),-webkit-transform 120ms 0ms cubic-bezier(0, 0, 0.2, 1)}.mdc-radio__native-control:disabled+.mdc-radio__background,[aria-disabled=true] .mdc-radio__native-control+.mdc-radio__background{cursor:default}.mdc-radio__native-control:focus+.mdc-radio__background::before{-webkit-transform:scale(1);transform:scale(1);opacity:.12;transition:opacity 120ms 0ms cubic-bezier(0, 0, 0.2, 1),-webkit-transform 120ms 0ms cubic-bezier(0, 0, 0.2, 1);transition:opacity 120ms 0ms cubic-bezier(0, 0, 0.2, 1),transform 120ms 0ms cubic-bezier(0, 0, 0.2, 1);transition:opacity 120ms 0ms cubic-bezier(0, 0, 0.2, 1),transform 120ms 0ms cubic-bezier(0, 0, 0.2, 1),-webkit-transform 120ms 0ms cubic-bezier(0, 0, 0.2, 1)}.mdc-radio{--mdc-ripple-fg-size: 0;--mdc-ripple-left: 0;--mdc-ripple-top: 0;--mdc-ripple-fg-scale: 1;--mdc-ripple-fg-translate-end: 0;--mdc-ripple-fg-translate-start: 0;-webkit-tap-highlight-color:rgba(0,0,0,0)}.mdc-radio .mdc-radio__ripple::before,.mdc-radio .mdc-radio__ripple::after{position:absolute;border-radius:50%;opacity:0;pointer-events:none;content:""}.mdc-radio .mdc-radio__ripple::before{transition:opacity 15ms linear,background-color 15ms linear;z-index:1}.mdc-radio.mdc-ripple-upgraded .mdc-radio__ripple::before{-webkit-transform:scale(var(--mdc-ripple-fg-scale, 1));transform:scale(var(--mdc-ripple-fg-scale, 1))}.mdc-radio.mdc-ripple-upgraded .mdc-radio__ripple::after{top:0;left:0;-webkit-transform:scale(0);transform:scale(0);-webkit-transform-origin:center center;transform-origin:center center}.mdc-radio.mdc-ripple-upgraded--unbounded .mdc-radio__ripple::after{top:var(--mdc-ripple-top, 0);left:var(--mdc-ripple-left, 0)}.mdc-radio.mdc-ripple-upgraded--foreground-activation .mdc-radio__ripple::after{-webkit-animation:mdc-ripple-fg-radius-in 225ms forwards,mdc-ripple-fg-opacity-in 75ms forwards;animation:mdc-ripple-fg-radius-in 225ms forwards,mdc-ripple-fg-opacity-in 75ms forwards}.mdc-radio.mdc-ripple-upgraded--foreground-deactivation .mdc-radio__ripple::after{-webkit-animation:mdc-ripple-fg-opacity-out 150ms;animation:mdc-ripple-fg-opacity-out 150ms;-webkit-transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1))}.mdc-radio .mdc-radio__ripple::before,.mdc-radio .mdc-radio__ripple::after{top:calc(50% - 50%);left:calc(50% - 50%);width:100%;height:100%}.mdc-radio.mdc-ripple-upgraded .mdc-radio__ripple::before,.mdc-radio.mdc-ripple-upgraded .mdc-radio__ripple::after{top:var(--mdc-ripple-top, calc(50% - 50%));left:var(--mdc-ripple-left, calc(50% - 50%));width:var(--mdc-ripple-fg-size, 100%);height:var(--mdc-ripple-fg-size, 100%)}.mdc-radio.mdc-ripple-upgraded .mdc-radio__ripple::after{width:var(--mdc-ripple-fg-size, 100%);height:var(--mdc-ripple-fg-size, 100%)}.mdc-radio .mdc-radio__ripple::before,.mdc-radio .mdc-radio__ripple::after{background-color:#018786;background-color:var(--mdc-theme-secondary, #018786)}.mdc-radio:hover .mdc-radio__ripple::before{opacity:.04}.mdc-radio.mdc-ripple-upgraded--background-focused .mdc-radio__ripple::before,.mdc-radio:not(.mdc-ripple-upgraded):focus .mdc-radio__ripple::before{transition-duration:75ms;opacity:.12}.mdc-radio:not(.mdc-ripple-upgraded) .mdc-radio__ripple::after{transition:opacity 150ms linear}.mdc-radio:not(.mdc-ripple-upgraded):active .mdc-radio__ripple::after{transition-duration:75ms;opacity:.12}.mdc-radio.mdc-ripple-upgraded{--mdc-ripple-fg-opacity: 0.12}.mdc-radio.mdc-ripple-upgraded--background-focused .mdc-radio__background::before{content:none}.mdc-radio__ripple{position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none}.mdc-ripple-surface{--mdc-ripple-fg-size: 0;--mdc-ripple-left: 0;--mdc-ripple-top: 0;--mdc-ripple-fg-scale: 1;--mdc-ripple-fg-translate-end: 0;--mdc-ripple-fg-translate-start: 0;-webkit-tap-highlight-color:rgba(0,0,0,0);position:relative;outline:none;overflow:hidden}.mdc-ripple-surface::before,.mdc-ripple-surface::after{position:absolute;border-radius:50%;opacity:0;pointer-events:none;content:""}.mdc-ripple-surface::before{transition:opacity 15ms linear,background-color 15ms linear;z-index:1}.mdc-ripple-surface.mdc-ripple-upgraded::before{-webkit-transform:scale(var(--mdc-ripple-fg-scale, 1));transform:scale(var(--mdc-ripple-fg-scale, 1))}.mdc-ripple-surface.mdc-ripple-upgraded::after{top:0;left:0;-webkit-transform:scale(0);transform:scale(0);-webkit-transform-origin:center center;transform-origin:center center}.mdc-ripple-surface.mdc-ripple-upgraded--unbounded::after{top:var(--mdc-ripple-top, 0);left:var(--mdc-ripple-left, 0)}.mdc-ripple-surface.mdc-ripple-upgraded--foreground-activation::after{-webkit-animation:mdc-ripple-fg-radius-in 225ms forwards,mdc-ripple-fg-opacity-in 75ms forwards;animation:mdc-ripple-fg-radius-in 225ms forwards,mdc-ripple-fg-opacity-in 75ms forwards}.mdc-ripple-surface.mdc-ripple-upgraded--foreground-deactivation::after{-webkit-animation:mdc-ripple-fg-opacity-out 150ms;animation:mdc-ripple-fg-opacity-out 150ms;-webkit-transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1))}.mdc-ripple-surface::before,.mdc-ripple-surface::after{background-color:#000}.mdc-ripple-surface:hover::before{opacity:.04}.mdc-ripple-surface.mdc-ripple-upgraded--background-focused::before,.mdc-ripple-surface:not(.mdc-ripple-upgraded):focus::before{transition-duration:75ms;opacity:.12}.mdc-ripple-surface:not(.mdc-ripple-upgraded)::after{transition:opacity 150ms linear}.mdc-ripple-surface:not(.mdc-ripple-upgraded):active::after{transition-duration:75ms;opacity:.12}.mdc-ripple-surface.mdc-ripple-upgraded{--mdc-ripple-fg-opacity: 0.12}.mdc-ripple-surface::before,.mdc-ripple-surface::after{top:calc(50% - 100%);left:calc(50% - 100%);width:200%;height:200%}.mdc-ripple-surface.mdc-ripple-upgraded::after{width:var(--mdc-ripple-fg-size, 100%);height:var(--mdc-ripple-fg-size, 100%)}.mdc-ripple-surface[data-mdc-ripple-is-unbounded]{overflow:visible}.mdc-ripple-surface[data-mdc-ripple-is-unbounded]::before,.mdc-ripple-surface[data-mdc-ripple-is-unbounded]::after{top:calc(50% - 50%);left:calc(50% - 50%);width:100%;height:100%}.mdc-ripple-surface[data-mdc-ripple-is-unbounded].mdc-ripple-upgraded::before,.mdc-ripple-surface[data-mdc-ripple-is-unbounded].mdc-ripple-upgraded::after{top:var(--mdc-ripple-top, calc(50% - 50%));left:var(--mdc-ripple-left, calc(50% - 50%));width:var(--mdc-ripple-fg-size, 100%);height:var(--mdc-ripple-fg-size, 100%)}.mdc-ripple-surface[data-mdc-ripple-is-unbounded].mdc-ripple-upgraded::after{width:var(--mdc-ripple-fg-size, 100%);height:var(--mdc-ripple-fg-size, 100%)}.mdc-ripple-surface--primary::before,.mdc-ripple-surface--primary::after{background-color:#6200ee;background-color:var(--mdc-theme-primary, #6200ee)}.mdc-ripple-surface--primary:hover::before{opacity:.04}.mdc-ripple-surface--primary.mdc-ripple-upgraded--background-focused::before,.mdc-ripple-surface--primary:not(.mdc-ripple-upgraded):focus::before{transition-duration:75ms;opacity:.12}.mdc-ripple-surface--primary:not(.mdc-ripple-upgraded)::after{transition:opacity 150ms linear}.mdc-ripple-surface--primary:not(.mdc-ripple-upgraded):active::after{transition-duration:75ms;opacity:.12}.mdc-ripple-surface--primary.mdc-ripple-upgraded{--mdc-ripple-fg-opacity: 0.12}.mdc-ripple-surface--accent::before,.mdc-ripple-surface--accent::after{background-color:#018786;background-color:var(--mdc-theme-secondary, #018786)}.mdc-ripple-surface--accent:hover::before{opacity:.04}.mdc-ripple-surface--accent.mdc-ripple-upgraded--background-focused::before,.mdc-ripple-surface--accent:not(.mdc-ripple-upgraded):focus::before{transition-duration:75ms;opacity:.12}.mdc-ripple-surface--accent:not(.mdc-ripple-upgraded)::after{transition:opacity 150ms linear}.mdc-ripple-surface--accent:not(.mdc-ripple-upgraded):active::after{transition-duration:75ms;opacity:.12}.mdc-ripple-surface--accent.mdc-ripple-upgraded{--mdc-ripple-fg-opacity: 0.12}.mdc-select-helper-text{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-caption-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:.75rem;font-size:var(--mdc-typography-caption-font-size, 0.75rem);line-height:1.25rem;line-height:var(--mdc-typography-caption-line-height, 1.25rem);font-weight:400;font-weight:var(--mdc-typography-caption-font-weight, 400);letter-spacing:.0333333333em;letter-spacing:var(--mdc-typography-caption-letter-spacing, 0.0333333333em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-caption-text-decoration, inherit);text-decoration:var(--mdc-typography-caption-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-caption-text-transform, inherit);display:block;margin-top:0;line-height:normal;margin:0;opacity:0;will-change:opacity;transition:opacity 180ms cubic-bezier(0.4, 0, 0.2, 1)}.mdc-select-helper-text::before{display:inline-block;width:0;height:16px;content:"";vertical-align:0}.mdc-select-helper-text--persistent{transition:none;opacity:1;will-change:initial}.mdc-select--with-leading-icon .mdc-select__icon{display:inline-block;box-sizing:border-box;width:24px;height:24px;border:none;opacity:.54;text-decoration:none;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;flex-shrink:0;align-self:center;background-color:transparent;fill:currentColor}.mdc-select--with-leading-icon .mdc-select__icon{margin-left:12px;margin-right:12px}[dir=rtl] .mdc-select--with-leading-icon .mdc-select__icon,.mdc-select--with-leading-icon .mdc-select__icon[dir=rtl]{margin-left:12px;margin-right:12px}.mdc-select--with-leading-icon:not(.mdc-select--disabled) .mdc-select__icon{color:#000;color:var(--mdc-theme-on-surface, #000)}.mdc-select__icon:not([tabindex]),.mdc-select__icon[tabindex="-1"]{cursor:default;pointer-events:none}.mdc-select__anchor{--mdc-ripple-fg-size: 0;--mdc-ripple-left: 0;--mdc-ripple-top: 0;--mdc-ripple-fg-scale: 1;--mdc-ripple-fg-translate-end: 0;--mdc-ripple-fg-translate-start: 0;-webkit-tap-highlight-color:rgba(0,0,0,0)}.mdc-select__anchor .mdc-select__ripple::before,.mdc-select__anchor .mdc-select__ripple::after{position:absolute;border-radius:50%;opacity:0;pointer-events:none;content:""}.mdc-select__anchor .mdc-select__ripple::before{transition:opacity 15ms linear,background-color 15ms linear;z-index:1}.mdc-select__anchor.mdc-ripple-upgraded .mdc-select__ripple::before{-webkit-transform:scale(var(--mdc-ripple-fg-scale, 1));transform:scale(var(--mdc-ripple-fg-scale, 1))}.mdc-select__anchor.mdc-ripple-upgraded .mdc-select__ripple::after{top:0;left:0;-webkit-transform:scale(0);transform:scale(0);-webkit-transform-origin:center center;transform-origin:center center}.mdc-select__anchor.mdc-ripple-upgraded--unbounded .mdc-select__ripple::after{top:var(--mdc-ripple-top, 0);left:var(--mdc-ripple-left, 0)}.mdc-select__anchor.mdc-ripple-upgraded--foreground-activation .mdc-select__ripple::after{-webkit-animation:mdc-ripple-fg-radius-in 225ms forwards,mdc-ripple-fg-opacity-in 75ms forwards;animation:mdc-ripple-fg-radius-in 225ms forwards,mdc-ripple-fg-opacity-in 75ms forwards}.mdc-select__anchor.mdc-ripple-upgraded--foreground-deactivation .mdc-select__ripple::after{-webkit-animation:mdc-ripple-fg-opacity-out 150ms;animation:mdc-ripple-fg-opacity-out 150ms;-webkit-transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1))}.mdc-select__anchor .mdc-select__ripple::before,.mdc-select__anchor .mdc-select__ripple::after{top:calc(50% - 100%);left:calc(50% - 100%);width:200%;height:200%}.mdc-select__anchor.mdc-ripple-upgraded .mdc-select__ripple::after{width:var(--mdc-ripple-fg-size, 100%);height:var(--mdc-ripple-fg-size, 100%)}.mdc-select__anchor .mdc-select__ripple::before,.mdc-select__anchor .mdc-select__ripple::after{background-color:rgba(0,0,0,.87)}.mdc-select__anchor:hover .mdc-select__ripple::before{opacity:.04}.mdc-select__anchor.mdc-ripple-upgraded--background-focused .mdc-select__ripple::before,.mdc-select__anchor:not(.mdc-ripple-upgraded):focus .mdc-select__ripple::before{transition-duration:75ms;opacity:.12}.mdc-select__anchor .mdc-select__ripple{position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none}.mdc-select__menu .mdc-list .mdc-list-item--selected::before,.mdc-select__menu .mdc-list .mdc-list-item--selected::after{background-color:#000;background-color:var(--mdc-theme-on-surface, #000)}.mdc-select__menu .mdc-list .mdc-list-item--selected:hover::before{opacity:.04}.mdc-select__menu .mdc-list .mdc-list-item--selected.mdc-ripple-upgraded--background-focused::before,.mdc-select__menu .mdc-list .mdc-list-item--selected:not(.mdc-ripple-upgraded):focus::before{transition-duration:75ms;opacity:.12}.mdc-select__menu .mdc-list .mdc-list-item--selected:not(.mdc-ripple-upgraded)::after{transition:opacity 150ms linear}.mdc-select__menu .mdc-list .mdc-list-item--selected:not(.mdc-ripple-upgraded):active::after{transition-duration:75ms;opacity:.12}.mdc-select__menu .mdc-list .mdc-list-item--selected.mdc-ripple-upgraded{--mdc-ripple-fg-opacity: 0.12}.mdc-select{position:relative}.mdc-select:not(.mdc-select--disabled) .mdc-select__anchor{background-color:#f5f5f5}.mdc-select:not(.mdc-select--disabled) .mdc-select__selected-text{color:rgba(0,0,0,.87)}.mdc-select:not(.mdc-select--disabled) .mdc-floating-label{color:rgba(0,0,0,.6)}.mdc-select:not(.mdc-select--disabled) .mdc-line-ripple::before{border-bottom-color:rgba(0,0,0,.42)}.mdc-select:not(.mdc-select--disabled) .mdc-select__anchor+.mdc-select-helper-text{color:rgba(0,0,0,.6)}.mdc-select:not(.mdc-select--disabled).mdc-select--focused .mdc-line-ripple::after{border-bottom-color:#6200ee;border-bottom-color:var(--mdc-theme-primary, #6200ee)}.mdc-select:not(.mdc-select--disabled).mdc-select--focused .mdc-floating-label{color:rgba(98,0,238,.87)}.mdc-select:not(.mdc-select--disabled):hover .mdc-line-ripple::before{border-bottom-color:rgba(0,0,0,.87)}.mdc-select .mdc-floating-label{left:16px;right:initial;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%);pointer-events:none}[dir=rtl] .mdc-select .mdc-floating-label,.mdc-select .mdc-floating-label[dir=rtl]{left:initial;right:16px}.mdc-select.mdc-select--outlined .mdc-floating-label{left:4px;right:initial}[dir=rtl] .mdc-select.mdc-select--outlined .mdc-floating-label,.mdc-select.mdc-select--outlined .mdc-floating-label[dir=rtl]{left:initial;right:4px}.mdc-select .mdc-select__anchor{border-radius:4px 4px 0 0}.mdc-select .mdc-select__anchor{padding-left:16px;padding-right:0}[dir=rtl] .mdc-select .mdc-select__anchor,.mdc-select .mdc-select__anchor[dir=rtl]{padding-left:0;padding-right:16px}.mdc-select.mdc-select--with-leading-icon .mdc-select__anchor{padding-left:0;padding-right:0}[dir=rtl] .mdc-select.mdc-select--with-leading-icon .mdc-select__anchor,.mdc-select.mdc-select--with-leading-icon .mdc-select__anchor[dir=rtl]{padding-left:0;padding-right:0}.mdc-select__dropdown-icon{background:url("data:image/svg+xml,%3Csvg%20width%3D%2210px%22%20height%3D%225px%22%20viewBox%3D%227%2010%2010%205%22%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%3E%0A%20%20%20%20%3Cpolygon%20id%3D%22Shape%22%20stroke%3D%22none%22%20fill%3D%22%23000%22%20fill-rule%3D%22evenodd%22%20opacity%3D%220.54%22%20points%3D%227%2010%2012%2015%2017%2010%22%3E%3C%2Fpolygon%3E%0A%3C%2Fsvg%3E") no-repeat center;margin-left:12px;margin-right:12px;width:24px;height:24px;align-self:center;flex-shrink:0;pointer-events:none;transition:-webkit-transform 150ms cubic-bezier(0.4, 0, 0.2, 1);transition:transform 150ms cubic-bezier(0.4, 0, 0.2, 1);transition:transform 150ms cubic-bezier(0.4, 0, 0.2, 1), -webkit-transform 150ms cubic-bezier(0.4, 0, 0.2, 1)}[dir=rtl] .mdc-select__dropdown-icon,.mdc-select__dropdown-icon[dir=rtl]{margin-left:12px;margin-right:12px}.mdc-select--focused .mdc-select__dropdown-icon{background:url("data:image/svg+xml,%3Csvg%20width%3D%2210px%22%20height%3D%225px%22%20viewBox%3D%227%2010%2010%205%22%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%3E%0A%20%20%20%20%3Cpolygon%20id%3D%22Shape%22%20stroke%3D%22none%22%20fill%3D%22%236200ee%22%20fill-rule%3D%22evenodd%22%20opacity%3D%221%22%20points%3D%227%2010%2012%2015%2017%2010%22%3E%3C%2Fpolygon%3E%0A%3C%2Fsvg%3E") no-repeat center}.mdc-select--activated .mdc-select__dropdown-icon{-webkit-transform:rotate(180deg) translateY(-5px);transform:rotate(180deg) translateY(-5px);transition:-webkit-transform 150ms cubic-bezier(0.4, 0, 0.2, 1);transition:transform 150ms cubic-bezier(0.4, 0, 0.2, 1);transition:transform 150ms cubic-bezier(0.4, 0, 0.2, 1), -webkit-transform 150ms cubic-bezier(0.4, 0, 0.2, 1)}.mdc-select__anchor{height:56px;display:inline-flex;align-items:baseline;display:inline-flex;position:relative;box-sizing:border-box;overflow:hidden;outline:none;cursor:pointer;min-width:200px}.mdc-select__anchor::before{display:inline-block;width:0;height:40px;content:"";vertical-align:0}.mdc-select--outlined .mdc-select__anchor .mdc-select__selected-text,.mdc-select--no-label .mdc-select__anchor .mdc-select__selected-text{height:100%}.mdc-select--outlined .mdc-select__anchor::before,.mdc-select--no-label .mdc-select__anchor::before{display:none}.mdc-select__anchor .mdc-floating-label--float-above{-webkit-transform:translateY(-106%) scale(0.75);transform:translateY(-106%) scale(0.75)}.mdc-select__anchor.mdc-select--focused .mdc-line-ripple::after{-webkit-transform:scale(1, 2);transform:scale(1, 2);opacity:1}.mdc-select__anchor+.mdc-select-helper-text{margin-right:16px;margin-left:16px}.mdc-select--focused .mdc-select__anchor+.mdc-select-helper-text:not(.mdc-select-helper-text--validation-msg){opacity:1}.mdc-select__selected-text{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-subtitle1-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:1rem;font-size:var(--mdc-typography-subtitle1-font-size, 1rem);line-height:1.75rem;line-height:var(--mdc-typography-subtitle1-line-height, 1.75rem);font-weight:400;font-weight:var(--mdc-typography-subtitle1-font-weight, 400);letter-spacing:.009375em;letter-spacing:var(--mdc-typography-subtitle1-letter-spacing, 0.009375em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-subtitle1-text-decoration, inherit);text-decoration:var(--mdc-typography-subtitle1-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-subtitle1-text-transform, inherit);box-sizing:border-box;width:0;flex-grow:1;height:28px;border:none;outline:none;padding:0;white-space:nowrap;-webkit-appearance:none;-moz-appearance:none;appearance:none;pointer-events:none;text-overflow:ellipsis;background-color:transparent;color:inherit}.mdc-select__selected-text::-ms-expand{display:none}.mdc-select__selected-text::-ms-value{background-color:transparent;color:inherit}.mdc-select--outlined{border:none}.mdc-select--outlined:not(.mdc-select--disabled) .mdc-select__anchor{background-color:transparent}.mdc-select--outlined:not(.mdc-select--disabled) .mdc-notched-outline__leading,.mdc-select--outlined:not(.mdc-select--disabled) .mdc-notched-outline__notch,.mdc-select--outlined:not(.mdc-select--disabled) .mdc-notched-outline__trailing{border-color:rgba(0,0,0,.38)}.mdc-select--outlined:not(.mdc-select--disabled):not(.mdc-select--focused) .mdc-select__anchor:hover .mdc-notched-outline .mdc-notched-outline__leading,.mdc-select--outlined:not(.mdc-select--disabled):not(.mdc-select--focused) .mdc-select__anchor:hover .mdc-notched-outline .mdc-notched-outline__notch,.mdc-select--outlined:not(.mdc-select--disabled):not(.mdc-select--focused) .mdc-select__anchor:hover .mdc-notched-outline .mdc-notched-outline__trailing{border-color:rgba(0,0,0,.87)}.mdc-select--outlined:not(.mdc-select--disabled).mdc-select--focused .mdc-notched-outline .mdc-notched-outline__leading,.mdc-select--outlined:not(.mdc-select--disabled).mdc-select--focused .mdc-notched-outline .mdc-notched-outline__notch,.mdc-select--outlined:not(.mdc-select--disabled).mdc-select--focused .mdc-notched-outline .mdc-notched-outline__trailing{border-width:2px}.mdc-select--outlined:not(.mdc-select--disabled).mdc-select--focused .mdc-notched-outline .mdc-notched-outline__leading,.mdc-select--outlined:not(.mdc-select--disabled).mdc-select--focused .mdc-notched-outline .mdc-notched-outline__notch,.mdc-select--outlined:not(.mdc-select--disabled).mdc-select--focused .mdc-notched-outline .mdc-notched-outline__trailing{border-color:#6200ee;border-color:var(--mdc-theme-primary, #6200ee)}.mdc-select--outlined .mdc-notched-outline .mdc-notched-outline__leading{border-radius:4px 0 0 4px}[dir=rtl] .mdc-select--outlined .mdc-notched-outline .mdc-notched-outline__leading,.mdc-select--outlined .mdc-notched-outline .mdc-notched-outline__leading[dir=rtl]{border-radius:0 4px 4px 0}.mdc-select--outlined .mdc-notched-outline .mdc-notched-outline__trailing{border-radius:0 4px 4px 0}[dir=rtl] .mdc-select--outlined .mdc-notched-outline .mdc-notched-outline__trailing,.mdc-select--outlined .mdc-notched-outline .mdc-notched-outline__trailing[dir=rtl]{border-radius:4px 0 0 4px}.mdc-select--outlined .mdc-select__selected-text{border-radius:4px}.mdc-select--outlined:not(.mdc-select--disabled) .mdc-select__anchor{background-color:transparent}.mdc-select--outlined .mdc-select__anchor{overflow:visible}.mdc-select--outlined .mdc-select__anchor .mdc-floating-label--shake{-webkit-animation:mdc-floating-label-shake-float-above-select-outlined 250ms 1;animation:mdc-floating-label-shake-float-above-select-outlined 250ms 1}.mdc-select--outlined .mdc-select__anchor .mdc-floating-label--float-above{-webkit-transform:translateY(-37.25px) scale(1);transform:translateY(-37.25px) scale(1)}.mdc-select--outlined .mdc-select__anchor .mdc-floating-label--float-above{font-size:.75rem}.mdc-select--outlined .mdc-select__anchor.mdc-notched-outline--upgraded .mdc-floating-label--float-above,.mdc-select--outlined .mdc-select__anchor .mdc-notched-outline--upgraded .mdc-floating-label--float-above{-webkit-transform:translateY(-34.75px) scale(0.75);transform:translateY(-34.75px) scale(0.75)}.mdc-select--outlined .mdc-select__anchor.mdc-notched-outline--upgraded .mdc-floating-label--float-above,.mdc-select--outlined .mdc-select__anchor .mdc-notched-outline--upgraded .mdc-floating-label--float-above{font-size:1rem}.mdc-select--outlined .mdc-select__anchor .mdc-notched-outline--notched .mdc-notched-outline__notch{padding-top:1px}.mdc-select--outlined .mdc-select__selected-text{display:flex;border:none;z-index:1;background-color:transparent}.mdc-select--outlined .mdc-select__icon{z-index:2}.mdc-select--outlined .mdc-floating-label{line-height:1.15rem;pointer-events:auto}.mdc-select--outlined.mdc-select--focused .mdc-notched-outline--notched .mdc-notched-outline__notch{padding-top:2px}.mdc-select--invalid:not(.mdc-select--disabled) .mdc-floating-label{color:#b00020;color:var(--mdc-theme-error, #b00020)}.mdc-select--invalid:not(.mdc-select--disabled) .mdc-line-ripple::before{border-bottom-color:#b00020;border-bottom-color:var(--mdc-theme-error, #b00020)}.mdc-select--invalid:not(.mdc-select--disabled).mdc-select--focused .mdc-line-ripple::after{border-bottom-color:#b00020;border-bottom-color:var(--mdc-theme-error, #b00020)}.mdc-select--invalid:not(.mdc-select--disabled).mdc-select--focused .mdc-floating-label{color:#b00020}.mdc-select--invalid:not(.mdc-select--disabled).mdc-select--invalid .mdc-select__anchor+.mdc-select-helper-text--validation-msg{color:#b00020;color:var(--mdc-theme-error, #b00020)}.mdc-select--invalid:not(.mdc-select--disabled):hover .mdc-line-ripple::before{border-bottom-color:#b00020;border-bottom-color:var(--mdc-theme-error, #b00020)}.mdc-select--invalid.mdc-select--outlined:not(.mdc-select--disabled) .mdc-notched-outline__leading,.mdc-select--invalid.mdc-select--outlined:not(.mdc-select--disabled) .mdc-notched-outline__notch,.mdc-select--invalid.mdc-select--outlined:not(.mdc-select--disabled) .mdc-notched-outline__trailing{border-color:#b00020;border-color:var(--mdc-theme-error, #b00020)}.mdc-select--invalid.mdc-select--outlined:not(.mdc-select--disabled):not(.mdc-select--focused) .mdc-select__anchor:hover .mdc-notched-outline .mdc-notched-outline__leading,.mdc-select--invalid.mdc-select--outlined:not(.mdc-select--disabled):not(.mdc-select--focused) .mdc-select__anchor:hover .mdc-notched-outline .mdc-notched-outline__notch,.mdc-select--invalid.mdc-select--outlined:not(.mdc-select--disabled):not(.mdc-select--focused) .mdc-select__anchor:hover .mdc-notched-outline .mdc-notched-outline__trailing{border-color:#b00020;border-color:var(--mdc-theme-error, #b00020)}.mdc-select--invalid.mdc-select--outlined:not(.mdc-select--disabled).mdc-select--focused .mdc-notched-outline .mdc-notched-outline__leading,.mdc-select--invalid.mdc-select--outlined:not(.mdc-select--disabled).mdc-select--focused .mdc-notched-outline .mdc-notched-outline__notch,.mdc-select--invalid.mdc-select--outlined:not(.mdc-select--disabled).mdc-select--focused .mdc-notched-outline .mdc-notched-outline__trailing{border-width:2px}.mdc-select--invalid.mdc-select--outlined:not(.mdc-select--disabled).mdc-select--focused .mdc-notched-outline .mdc-notched-outline__leading,.mdc-select--invalid.mdc-select--outlined:not(.mdc-select--disabled).mdc-select--focused .mdc-notched-outline .mdc-notched-outline__notch,.mdc-select--invalid.mdc-select--outlined:not(.mdc-select--disabled).mdc-select--focused .mdc-notched-outline .mdc-notched-outline__trailing{border-color:#b00020;border-color:var(--mdc-theme-error, #b00020)}.mdc-select--invalid .mdc-select__dropdown-icon{background:url("data:image/svg+xml,%3Csvg%20width%3D%2210px%22%20height%3D%225px%22%20viewBox%3D%227%2010%2010%205%22%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%3E%0A%20%20%20%20%3Cpolygon%20id%3D%22Shape%22%20stroke%3D%22none%22%20fill%3D%22%23b00020%22%20fill-rule%3D%22evenodd%22%20opacity%3D%221%22%20points%3D%227%2010%2012%2015%2017%2010%22%3E%3C%2Fpolygon%3E%0A%3C%2Fsvg%3E") no-repeat center}.mdc-select--invalid+.mdc-select-helper-text--validation-msg{opacity:1}.mdc-select--required .mdc-floating-label::after{content:"*"}.mdc-select--disabled{cursor:default;pointer-events:none}.mdc-select--disabled .mdc-select__anchor{background-color:#fafafa}.mdc-select--disabled .mdc-floating-label{color:rgba(0,0,0,.38)}.mdc-select--disabled .mdc-select__dropdown-icon{background:url("data:image/svg+xml,%3Csvg%20width%3D%2210px%22%20height%3D%225px%22%20viewBox%3D%227%2010%2010%205%22%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%3E%0A%20%20%20%20%3Cpolygon%20id%3D%22Shape%22%20stroke%3D%22none%22%20fill%3D%22%23000%22%20fill-rule%3D%22evenodd%22%20opacity%3D%220.38%22%20points%3D%227%2010%2012%2015%2017%2010%22%3E%3C%2Fpolygon%3E%0A%3C%2Fsvg%3E") no-repeat center}.mdc-select--disabled .mdc-line-ripple::before{border-bottom-color:rgba(0,0,0,.38)}.mdc-select--disabled .mdc-line-ripple::before{border-bottom-style:dotted}.mdc-select--disabled .mdc-select__icon{color:rgba(0,0,0,.38)}.mdc-select--disabled .mdc-select__selected-text{color:rgba(0,0,0,.38);pointer-events:none}.mdc-select--disabled.mdc-select--outlined .mdc-select__anchor{background-color:transparent}.mdc-select--disabled.mdc-select--outlined .mdc-notched-outline__leading,.mdc-select--disabled.mdc-select--outlined .mdc-notched-outline__notch,.mdc-select--disabled.mdc-select--outlined .mdc-notched-outline__trailing{border-color:rgba(0,0,0,.16)}.mdc-select--with-leading-icon .mdc-floating-label{left:48px;right:initial}[dir=rtl] .mdc-select--with-leading-icon .mdc-floating-label,.mdc-select--with-leading-icon .mdc-floating-label[dir=rtl]{left:initial;right:48px}.mdc-select--with-leading-icon.mdc-select--outlined .mdc-floating-label{left:36px;right:initial}[dir=rtl] .mdc-select--with-leading-icon.mdc-select--outlined .mdc-floating-label,.mdc-select--with-leading-icon.mdc-select--outlined .mdc-floating-label[dir=rtl]{left:initial;right:36px}.mdc-select--with-leading-icon.mdc-select--outlined .mdc-floating-label--float-above{left:36px;right:initial}[dir=rtl] .mdc-select--with-leading-icon.mdc-select--outlined .mdc-floating-label--float-above,.mdc-select--with-leading-icon.mdc-select--outlined .mdc-floating-label--float-above[dir=rtl]{left:initial;right:36px}.mdc-select--with-leading-icon.mdc-select--outlined .mdc-floating-label--float-above{-webkit-transform:translateY(-37.25px) translateX(-32px) scale(1);transform:translateY(-37.25px) translateX(-32px) scale(1)}[dir=rtl] .mdc-select--with-leading-icon.mdc-select--outlined .mdc-floating-label--float-above,.mdc-select--with-leading-icon.mdc-select--outlined .mdc-floating-label--float-above[dir=rtl]{-webkit-transform:translateY(-37.25px) translateX(32px) scale(1);transform:translateY(-37.25px) translateX(32px) scale(1)}.mdc-select--with-leading-icon.mdc-select--outlined .mdc-floating-label--float-above{font-size:.75rem}.mdc-select--with-leading-icon.mdc-select--outlined.mdc-notched-outline--upgraded .mdc-floating-label--float-above,.mdc-select--with-leading-icon.mdc-select--outlined .mdc-notched-outline--upgraded .mdc-floating-label--float-above{-webkit-transform:translateY(-34.75px) translateX(-32px) scale(0.75);transform:translateY(-34.75px) translateX(-32px) scale(0.75)}[dir=rtl] .mdc-select--with-leading-icon.mdc-select--outlined.mdc-notched-outline--upgraded .mdc-floating-label--float-above,.mdc-select--with-leading-icon.mdc-select--outlined.mdc-notched-outline--upgraded .mdc-floating-label--float-above[dir=rtl],[dir=rtl] .mdc-select--with-leading-icon.mdc-select--outlined .mdc-notched-outline--upgraded .mdc-floating-label--float-above,.mdc-select--with-leading-icon.mdc-select--outlined .mdc-notched-outline--upgraded .mdc-floating-label--float-above[dir=rtl]{-webkit-transform:translateY(-34.75px) translateX(32px) scale(0.75);transform:translateY(-34.75px) translateX(32px) scale(0.75)}.mdc-select--with-leading-icon.mdc-select--outlined.mdc-notched-outline--upgraded .mdc-floating-label--float-above,.mdc-select--with-leading-icon.mdc-select--outlined .mdc-notched-outline--upgraded .mdc-floating-label--float-above{font-size:1rem}.mdc-select--with-leading-icon.mdc-select--outlined .mdc-floating-label--shake{-webkit-animation:mdc-floating-label-shake-float-above-select-outlined-leading-icon 250ms 1;animation:mdc-floating-label-shake-float-above-select-outlined-leading-icon 250ms 1}[dir=rtl] .mdc-select--with-leading-icon.mdc-select--outlined .mdc-floating-label--shake,.mdc-select--with-leading-icon.mdc-select--outlined[dir=rtl] .mdc-floating-label--shake{-webkit-animation:mdc-floating-label-shake-float-above-select-outlined-leading-icon-rtl 250ms 1;animation:mdc-floating-label-shake-float-above-select-outlined-leading-icon-rtl 250ms 1}.mdc-select--with-leading-icon.mdc-select__menu .mdc-list-item__text{padding-left:32px;padding-right:32px}[dir=rtl] .mdc-select--with-leading-icon.mdc-select__menu .mdc-list-item__text,.mdc-select--with-leading-icon.mdc-select__menu .mdc-list-item__text[dir=rtl]{padding-left:32px;padding-right:32px}.mdc-select__menu .mdc-list .mdc-list-item--selected{color:#000;color:var(--mdc-theme-on-surface, #000)}@-webkit-keyframes mdc-floating-label-shake-float-above-select-outlined-leading-icon{0%{-webkit-transform:translateX(calc(0 - 32px)) translateY(-34.75px) scale(0.75);transform:translateX(calc(0 - 32px)) translateY(-34.75px) scale(0.75)}33%{-webkit-animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);-webkit-transform:translateX(calc(4% - 32px)) translateY(-34.75px) scale(0.75);transform:translateX(calc(4% - 32px)) translateY(-34.75px) scale(0.75)}66%{-webkit-animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);-webkit-transform:translateX(calc(-4% - 32px)) translateY(-34.75px) scale(0.75);transform:translateX(calc(-4% - 32px)) translateY(-34.75px) scale(0.75)}100%{-webkit-transform:translateX(calc(0 - 32px)) translateY(-34.75px) scale(0.75);transform:translateX(calc(0 - 32px)) translateY(-34.75px) scale(0.75)}}@keyframes mdc-floating-label-shake-float-above-select-outlined-leading-icon{0%{-webkit-transform:translateX(calc(0 - 32px)) translateY(-34.75px) scale(0.75);transform:translateX(calc(0 - 32px)) translateY(-34.75px) scale(0.75)}33%{-webkit-animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);-webkit-transform:translateX(calc(4% - 32px)) translateY(-34.75px) scale(0.75);transform:translateX(calc(4% - 32px)) translateY(-34.75px) scale(0.75)}66%{-webkit-animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);-webkit-transform:translateX(calc(-4% - 32px)) translateY(-34.75px) scale(0.75);transform:translateX(calc(-4% - 32px)) translateY(-34.75px) scale(0.75)}100%{-webkit-transform:translateX(calc(0 - 32px)) translateY(-34.75px) scale(0.75);transform:translateX(calc(0 - 32px)) translateY(-34.75px) scale(0.75)}}@-webkit-keyframes mdc-floating-label-shake-float-above-select-outlined-leading-icon-rtl{0%{-webkit-transform:translateX(calc(0 - -32px)) translateY(-34.75px) scale(0.75);transform:translateX(calc(0 - -32px)) translateY(-34.75px) scale(0.75)}33%{-webkit-animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);-webkit-transform:translateX(calc(4% - -32px)) translateY(-34.75px) scale(0.75);transform:translateX(calc(4% - -32px)) translateY(-34.75px) scale(0.75)}66%{-webkit-animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);-webkit-transform:translateX(calc(-4% - -32px)) translateY(-34.75px) scale(0.75);transform:translateX(calc(-4% - -32px)) translateY(-34.75px) scale(0.75)}100%{-webkit-transform:translateX(calc(0 - -32px)) translateY(-34.75px) scale(0.75);transform:translateX(calc(0 - -32px)) translateY(-34.75px) scale(0.75)}}@keyframes mdc-floating-label-shake-float-above-select-outlined-leading-icon-rtl{0%{-webkit-transform:translateX(calc(0 - -32px)) translateY(-34.75px) scale(0.75);transform:translateX(calc(0 - -32px)) translateY(-34.75px) scale(0.75)}33%{-webkit-animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);-webkit-transform:translateX(calc(4% - -32px)) translateY(-34.75px) scale(0.75);transform:translateX(calc(4% - -32px)) translateY(-34.75px) scale(0.75)}66%{-webkit-animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);-webkit-transform:translateX(calc(-4% - -32px)) translateY(-34.75px) scale(0.75);transform:translateX(calc(-4% - -32px)) translateY(-34.75px) scale(0.75)}100%{-webkit-transform:translateX(calc(0 - -32px)) translateY(-34.75px) scale(0.75);transform:translateX(calc(0 - -32px)) translateY(-34.75px) scale(0.75)}}@-webkit-keyframes mdc-slider-emphasize{0%{-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}50%{-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in;-webkit-transform:scale(0.85);transform:scale(0.85)}100%{-webkit-transform:scale(0.571);transform:scale(0.571)}}@keyframes mdc-slider-emphasize{0%{-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}50%{-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in;-webkit-transform:scale(0.85);transform:scale(0.85)}100%{-webkit-transform:scale(0.571);transform:scale(0.571)}}.mdc-slider{position:relative;width:100%;height:48px;cursor:pointer;touch-action:pan-x;-webkit-tap-highlight-color:rgba(0,0,0,0)}.mdc-slider:not(.mdc-slider--disabled) .mdc-slider__track{background-color:#018786;background-color:var(--mdc-theme-secondary, #018786)}.mdc-slider:not(.mdc-slider--disabled) .mdc-slider__track-container::after{background-color:#018786;background-color:var(--mdc-theme-secondary, #018786);opacity:.26}.mdc-slider:not(.mdc-slider--disabled) .mdc-slider__track-marker-container{background-color:#018786;background-color:var(--mdc-theme-secondary, #018786)}.mdc-slider:not(.mdc-slider--disabled) .mdc-slider__thumb{fill:#018786;fill:var(--mdc-theme-secondary, #018786);stroke:#018786;stroke:var(--mdc-theme-secondary, #018786)}.mdc-slider:not(.mdc-slider--disabled) .mdc-slider__focus-ring{background-color:#018786;background-color:var(--mdc-theme-secondary, #018786)}.mdc-slider:not(.mdc-slider--disabled) .mdc-slider__pin{background-color:#018786;background-color:var(--mdc-theme-secondary, #018786)}.mdc-slider:not(.mdc-slider--disabled) .mdc-slider__pin{color:#fff;color:var(--mdc-theme-text-primary-on-dark, white)}.mdc-slider--disabled{cursor:auto}.mdc-slider--disabled .mdc-slider__track{background-color:#9a9a9a}.mdc-slider--disabled .mdc-slider__track-container::after{background-color:#9a9a9a;opacity:.26}.mdc-slider--disabled .mdc-slider__track-marker-container{background-color:#9a9a9a}.mdc-slider--disabled .mdc-slider__thumb{fill:#9a9a9a;stroke:#9a9a9a}.mdc-slider--disabled .mdc-slider__thumb{stroke:#fff;stroke:var(--mdc-slider-bg-color-behind-component, white)}.mdc-slider:focus{outline:none}.mdc-slider__track-container{position:absolute;top:50%;width:100%;height:2px;overflow:hidden}.mdc-slider__track-container::after{position:absolute;top:0;left:0;display:block;width:100%;height:100%;content:""}.mdc-slider__track{position:absolute;width:100%;height:100%;-webkit-transform-origin:left top;transform-origin:left top;will-change:transform}.mdc-slider[dir=rtl] .mdc-slider__track,[dir=rtl] .mdc-slider .mdc-slider__track{-webkit-transform-origin:right top;transform-origin:right top}.mdc-slider__track-marker-container{display:flex;margin-right:0;margin-left:-1px;visibility:hidden}.mdc-slider[dir=rtl] .mdc-slider__track-marker-container,[dir=rtl] .mdc-slider .mdc-slider__track-marker-container{margin-right:-1px;margin-left:0}.mdc-slider__track-marker-container::after{display:block;width:2px;height:2px;content:""}.mdc-slider__track-marker{flex:1}.mdc-slider__track-marker::after{display:block;width:2px;height:2px;content:""}.mdc-slider__track-marker:first-child::after{width:3px}.mdc-slider__thumb-container{position:absolute;top:15px;left:0;width:21px;height:100%;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;will-change:transform}.mdc-slider__thumb{position:absolute;top:0;left:0;-webkit-transform:scale(0.571);transform:scale(0.571);stroke-width:3.5;transition:fill 100ms ease-out,stroke 100ms ease-out,-webkit-transform 100ms ease-out;transition:transform 100ms ease-out,fill 100ms ease-out,stroke 100ms ease-out;transition:transform 100ms ease-out,fill 100ms ease-out,stroke 100ms ease-out,-webkit-transform 100ms ease-out}.mdc-slider__focus-ring{width:21px;height:21px;border-radius:50%;opacity:0;transition:opacity 266.67ms ease-out,background-color 266.67ms ease-out,-webkit-transform 266.67ms ease-out;transition:transform 266.67ms ease-out,opacity 266.67ms ease-out,background-color 266.67ms ease-out;transition:transform 266.67ms ease-out,opacity 266.67ms ease-out,background-color 266.67ms ease-out,-webkit-transform 266.67ms ease-out}.mdc-slider__pin{display:flex;position:absolute;top:0;left:0;align-items:center;justify-content:center;width:26px;height:26px;margin-top:-2px;margin-left:-2px;-webkit-transform:rotate(-45deg) scale(0) translate(0, 0);transform:rotate(-45deg) scale(0) translate(0, 0);border-radius:50% 50% 50% 0%;z-index:1;transition:-webkit-transform 100ms ease-out;transition:transform 100ms ease-out;transition:transform 100ms ease-out, -webkit-transform 100ms ease-out}.mdc-slider__pin-value-marker{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-body2-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:.875rem;font-size:var(--mdc-typography-body2-font-size, 0.875rem);line-height:1.25rem;line-height:var(--mdc-typography-body2-line-height, 1.25rem);font-weight:400;font-weight:var(--mdc-typography-body2-font-weight, 400);letter-spacing:.0178571429em;letter-spacing:var(--mdc-typography-body2-letter-spacing, 0.0178571429em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-body2-text-decoration, inherit);text-decoration:var(--mdc-typography-body2-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-body2-text-transform, inherit);-webkit-transform:rotate(45deg);transform:rotate(45deg)}.mdc-slider--active .mdc-slider__thumb{-webkit-transform:scale3d(1, 1, 1);transform:scale3d(1, 1, 1)}.mdc-slider--focus .mdc-slider__thumb{-webkit-animation:mdc-slider-emphasize 266.67ms linear;animation:mdc-slider-emphasize 266.67ms linear}.mdc-slider--focus .mdc-slider__focus-ring{-webkit-transform:scale3d(1.55, 1.55, 1.55);transform:scale3d(1.55, 1.55, 1.55);opacity:.25}.mdc-slider--in-transit .mdc-slider__thumb{transition-delay:140ms}.mdc-slider--in-transit .mdc-slider__thumb-container,.mdc-slider--in-transit .mdc-slider__track,.mdc-slider:focus:not(.mdc-slider--active) .mdc-slider__thumb-container,.mdc-slider:focus:not(.mdc-slider--active) .mdc-slider__track{transition:-webkit-transform 80ms ease;transition:transform 80ms ease;transition:transform 80ms ease, -webkit-transform 80ms ease}.mdc-slider--discrete.mdc-slider--active .mdc-slider__thumb{-webkit-transform:scale(calc(12 / 21));transform:scale(calc(12 / 21))}.mdc-slider--discrete.mdc-slider--active .mdc-slider__pin{-webkit-transform:rotate(-45deg) scale(1) translate(19px, -20px);transform:rotate(-45deg) scale(1) translate(19px, -20px)}.mdc-slider--discrete.mdc-slider--focus .mdc-slider__thumb{-webkit-animation:none;animation:none}.mdc-slider--discrete.mdc-slider--display-markers .mdc-slider__track-marker-container{visibility:visible}.mdc-snackbar{z-index:8;margin:8px;display:none;position:fixed;right:0;bottom:0;left:0;align-items:center;justify-content:center;box-sizing:border-box;pointer-events:none;-webkit-tap-highlight-color:rgba(0,0,0,0)}.mdc-snackbar__surface{background-color:#333}.mdc-snackbar__label{color:rgba(255,255,255,.87)}.mdc-snackbar__surface{min-width:344px}@media(max-width: 480px),(max-width: 344px){.mdc-snackbar__surface{min-width:100%}}.mdc-snackbar__surface{max-width:672px}.mdc-snackbar__surface{box-shadow:0px 3px 5px -1px rgba(0, 0, 0, 0.2),0px 6px 10px 0px rgba(0, 0, 0, 0.14),0px 1px 18px 0px rgba(0,0,0,.12)}.mdc-snackbar__surface{border-radius:4px}.mdc-snackbar--opening,.mdc-snackbar--open,.mdc-snackbar--closing{display:flex}.mdc-snackbar--leading{justify-content:flex-start}.mdc-snackbar--stacked .mdc-snackbar__label{padding-left:16px;padding-right:0;padding-bottom:12px}[dir=rtl] .mdc-snackbar--stacked .mdc-snackbar__label,.mdc-snackbar--stacked .mdc-snackbar__label[dir=rtl]{padding-left:0;padding-right:16px}.mdc-snackbar--stacked .mdc-snackbar__surface{flex-direction:column;align-items:flex-start}.mdc-snackbar--stacked .mdc-snackbar__actions{align-self:flex-end;margin-bottom:8px}.mdc-snackbar__surface{padding-left:0;padding-right:8px;display:flex;align-items:center;justify-content:flex-start;box-sizing:border-box;-webkit-transform:scale(0.8);transform:scale(0.8);opacity:0}[dir=rtl] .mdc-snackbar__surface,.mdc-snackbar__surface[dir=rtl]{padding-left:8px;padding-right:0}.mdc-snackbar--open .mdc-snackbar__surface{-webkit-transform:scale(1);transform:scale(1);opacity:1;pointer-events:auto;transition:opacity 150ms 0ms cubic-bezier(0, 0, 0.2, 1),-webkit-transform 150ms 0ms cubic-bezier(0, 0, 0.2, 1);transition:opacity 150ms 0ms cubic-bezier(0, 0, 0.2, 1),transform 150ms 0ms cubic-bezier(0, 0, 0.2, 1);transition:opacity 150ms 0ms cubic-bezier(0, 0, 0.2, 1),transform 150ms 0ms cubic-bezier(0, 0, 0.2, 1),-webkit-transform 150ms 0ms cubic-bezier(0, 0, 0.2, 1)}.mdc-snackbar--closing .mdc-snackbar__surface{-webkit-transform:scale(1);transform:scale(1);transition:opacity 75ms 0ms cubic-bezier(0.4, 0, 1, 1)}.mdc-snackbar__label{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-body2-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:.875rem;font-size:var(--mdc-typography-body2-font-size, 0.875rem);line-height:1.25rem;line-height:var(--mdc-typography-body2-line-height, 1.25rem);font-weight:400;font-weight:var(--mdc-typography-body2-font-weight, 400);letter-spacing:.0178571429em;letter-spacing:var(--mdc-typography-body2-letter-spacing, 0.0178571429em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-body2-text-decoration, inherit);text-decoration:var(--mdc-typography-body2-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-body2-text-transform, inherit);padding-left:16px;padding-right:8px;width:100%;flex-grow:1;box-sizing:border-box;margin:0;padding-top:14px;padding-bottom:14px}[dir=rtl] .mdc-snackbar__label,.mdc-snackbar__label[dir=rtl]{padding-left:8px;padding-right:16px}.mdc-snackbar__label::before{display:inline;content:attr(data-mdc-snackbar-label-text)}.mdc-snackbar__actions{display:flex;flex-shrink:0;align-items:center;box-sizing:border-box}.mdc-snackbar__action:not(:disabled){color:#bb86fc}.mdc-snackbar__action::before,.mdc-snackbar__action::after{background-color:#bb86fc}.mdc-snackbar__action:hover::before{opacity:.08}.mdc-snackbar__action.mdc-ripple-upgraded--background-focused::before,.mdc-snackbar__action:not(.mdc-ripple-upgraded):focus::before{transition-duration:75ms;opacity:.24}.mdc-snackbar__action:not(.mdc-ripple-upgraded)::after{transition:opacity 150ms linear}.mdc-snackbar__action:not(.mdc-ripple-upgraded):active::after{transition-duration:75ms;opacity:.24}.mdc-snackbar__action.mdc-ripple-upgraded{--mdc-ripple-fg-opacity: 0.24}.mdc-snackbar__dismiss{color:rgba(255,255,255,.87)}.mdc-snackbar__dismiss::before,.mdc-snackbar__dismiss::after{background-color:rgba(255,255,255,.87)}.mdc-snackbar__dismiss:hover::before{opacity:.08}.mdc-snackbar__dismiss.mdc-ripple-upgraded--background-focused::before,.mdc-snackbar__dismiss:not(.mdc-ripple-upgraded):focus::before{transition-duration:75ms;opacity:.24}.mdc-snackbar__dismiss:not(.mdc-ripple-upgraded)::after{transition:opacity 150ms linear}.mdc-snackbar__dismiss:not(.mdc-ripple-upgraded):active::after{transition-duration:75ms;opacity:.24}.mdc-snackbar__dismiss.mdc-ripple-upgraded{--mdc-ripple-fg-opacity: 0.24}.mdc-snackbar__dismiss.mdc-snackbar__dismiss{width:36px;height:36px;padding:9px;font-size:18px}.mdc-snackbar__dismiss.mdc-snackbar__dismiss svg,.mdc-snackbar__dismiss.mdc-snackbar__dismiss img{width:18px;height:18px}.mdc-snackbar__action+.mdc-snackbar__dismiss{margin-left:8px;margin-right:0}[dir=rtl] .mdc-snackbar__action+.mdc-snackbar__dismiss,.mdc-snackbar__action+.mdc-snackbar__dismiss[dir=rtl]{margin-left:0;margin-right:8px}.mdc-switch__thumb-underlay{left:-18px;right:initial;top:-17px;width:48px;height:48px}[dir=rtl] .mdc-switch__thumb-underlay,.mdc-switch__thumb-underlay[dir=rtl]{left:initial;right:-18px}.mdc-switch__native-control{width:68px;height:48px}.mdc-switch{display:inline-block;position:relative;outline:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.mdc-switch.mdc-switch--checked .mdc-switch__track{background-color:#018786;background-color:var(--mdc-theme-secondary, #018786)}.mdc-switch.mdc-switch--checked .mdc-switch__thumb{background-color:#018786;background-color:var(--mdc-theme-secondary, #018786);border-color:#018786;border-color:var(--mdc-theme-secondary, #018786)}.mdc-switch:not(.mdc-switch--checked) .mdc-switch__track{background-color:#000;background-color:var(--mdc-theme-on-surface, #000)}.mdc-switch:not(.mdc-switch--checked) .mdc-switch__thumb{background-color:#fff;background-color:var(--mdc-theme-surface, #fff);border-color:#fff;border-color:var(--mdc-theme-surface, #fff)}.mdc-switch__native-control{left:0;right:initial;position:absolute;top:0;margin:0;opacity:0;cursor:pointer;pointer-events:auto;transition:-webkit-transform 90ms cubic-bezier(0.4, 0, 0.2, 1);transition:transform 90ms cubic-bezier(0.4, 0, 0.2, 1);transition:transform 90ms cubic-bezier(0.4, 0, 0.2, 1), -webkit-transform 90ms cubic-bezier(0.4, 0, 0.2, 1)}[dir=rtl] .mdc-switch__native-control,.mdc-switch__native-control[dir=rtl]{left:initial;right:0}.mdc-switch__track{box-sizing:border-box;width:32px;height:14px;border:1px solid transparent;border-radius:7px;opacity:.38;transition:opacity 90ms cubic-bezier(0.4, 0, 0.2, 1),background-color 90ms cubic-bezier(0.4, 0, 0.2, 1),border-color 90ms cubic-bezier(0.4, 0, 0.2, 1)}.mdc-switch__thumb-underlay{display:flex;position:absolute;align-items:center;justify-content:center;-webkit-transform:translateX(0);transform:translateX(0);transition:background-color 90ms cubic-bezier(0.4, 0, 0.2, 1),border-color 90ms cubic-bezier(0.4, 0, 0.2, 1),-webkit-transform 90ms cubic-bezier(0.4, 0, 0.2, 1);transition:transform 90ms cubic-bezier(0.4, 0, 0.2, 1),background-color 90ms cubic-bezier(0.4, 0, 0.2, 1),border-color 90ms cubic-bezier(0.4, 0, 0.2, 1);transition:transform 90ms cubic-bezier(0.4, 0, 0.2, 1),background-color 90ms cubic-bezier(0.4, 0, 0.2, 1),border-color 90ms cubic-bezier(0.4, 0, 0.2, 1),-webkit-transform 90ms cubic-bezier(0.4, 0, 0.2, 1)}.mdc-switch__thumb{box-shadow:0px 3px 1px -2px rgba(0, 0, 0, 0.2),0px 2px 2px 0px rgba(0, 0, 0, 0.14),0px 1px 5px 0px rgba(0,0,0,.12);box-sizing:border-box;width:20px;height:20px;border:10px solid;border-radius:50%;pointer-events:none;z-index:1}.mdc-switch--checked .mdc-switch__track{opacity:.54}.mdc-switch--checked .mdc-switch__thumb-underlay{-webkit-transform:translateX(20px);transform:translateX(20px)}[dir=rtl] .mdc-switch--checked .mdc-switch__thumb-underlay,.mdc-switch--checked .mdc-switch__thumb-underlay[dir=rtl]{-webkit-transform:translateX(-20px);transform:translateX(-20px)}.mdc-switch--checked .mdc-switch__native-control{-webkit-transform:translateX(-20px);transform:translateX(-20px)}[dir=rtl] .mdc-switch--checked .mdc-switch__native-control,.mdc-switch--checked .mdc-switch__native-control[dir=rtl]{-webkit-transform:translateX(20px);transform:translateX(20px)}.mdc-switch--disabled{opacity:.38;pointer-events:none}.mdc-switch--disabled .mdc-switch__thumb{border-width:1px}.mdc-switch--disabled .mdc-switch__native-control{cursor:default;pointer-events:none}.mdc-switch:not(.mdc-switch--checked) .mdc-switch__thumb-underlay::before,.mdc-switch:not(.mdc-switch--checked) .mdc-switch__thumb-underlay::after{background-color:#9e9e9e}.mdc-switch:not(.mdc-switch--checked) .mdc-switch__thumb-underlay:hover::before{opacity:.08}.mdc-switch:not(.mdc-switch--checked) .mdc-switch__thumb-underlay.mdc-ripple-upgraded--background-focused::before,.mdc-switch:not(.mdc-switch--checked) .mdc-switch__thumb-underlay:not(.mdc-ripple-upgraded):focus::before{transition-duration:75ms;opacity:.24}.mdc-switch:not(.mdc-switch--checked) .mdc-switch__thumb-underlay:not(.mdc-ripple-upgraded)::after{transition:opacity 150ms linear}.mdc-switch:not(.mdc-switch--checked) .mdc-switch__thumb-underlay:not(.mdc-ripple-upgraded):active::after{transition-duration:75ms;opacity:.24}.mdc-switch:not(.mdc-switch--checked) .mdc-switch__thumb-underlay.mdc-ripple-upgraded{--mdc-ripple-fg-opacity: 0.24}.mdc-switch__thumb-underlay{--mdc-ripple-fg-size: 0;--mdc-ripple-left: 0;--mdc-ripple-top: 0;--mdc-ripple-fg-scale: 1;--mdc-ripple-fg-translate-end: 0;--mdc-ripple-fg-translate-start: 0;-webkit-tap-highlight-color:rgba(0,0,0,0)}.mdc-switch__thumb-underlay::before,.mdc-switch__thumb-underlay::after{position:absolute;border-radius:50%;opacity:0;pointer-events:none;content:""}.mdc-switch__thumb-underlay::before{transition:opacity 15ms linear,background-color 15ms linear;z-index:1}.mdc-switch__thumb-underlay.mdc-ripple-upgraded::before{-webkit-transform:scale(var(--mdc-ripple-fg-scale, 1));transform:scale(var(--mdc-ripple-fg-scale, 1))}.mdc-switch__thumb-underlay.mdc-ripple-upgraded::after{top:0;left:0;-webkit-transform:scale(0);transform:scale(0);-webkit-transform-origin:center center;transform-origin:center center}.mdc-switch__thumb-underlay.mdc-ripple-upgraded--unbounded::after{top:var(--mdc-ripple-top, 0);left:var(--mdc-ripple-left, 0)}.mdc-switch__thumb-underlay.mdc-ripple-upgraded--foreground-activation::after{-webkit-animation:mdc-ripple-fg-radius-in 225ms forwards,mdc-ripple-fg-opacity-in 75ms forwards;animation:mdc-ripple-fg-radius-in 225ms forwards,mdc-ripple-fg-opacity-in 75ms forwards}.mdc-switch__thumb-underlay.mdc-ripple-upgraded--foreground-deactivation::after{-webkit-animation:mdc-ripple-fg-opacity-out 150ms;animation:mdc-ripple-fg-opacity-out 150ms;-webkit-transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1))}.mdc-switch__thumb-underlay::before,.mdc-switch__thumb-underlay::after{top:calc(50% - 50%);left:calc(50% - 50%);width:100%;height:100%}.mdc-switch__thumb-underlay.mdc-ripple-upgraded::before,.mdc-switch__thumb-underlay.mdc-ripple-upgraded::after{top:var(--mdc-ripple-top, calc(50% - 50%));left:var(--mdc-ripple-left, calc(50% - 50%));width:var(--mdc-ripple-fg-size, 100%);height:var(--mdc-ripple-fg-size, 100%)}.mdc-switch__thumb-underlay.mdc-ripple-upgraded::after{width:var(--mdc-ripple-fg-size, 100%);height:var(--mdc-ripple-fg-size, 100%)}.mdc-switch__thumb-underlay::before,.mdc-switch__thumb-underlay::after{background-color:#018786;background-color:var(--mdc-theme-secondary, #018786)}.mdc-switch__thumb-underlay:hover::before{opacity:.04}.mdc-switch__thumb-underlay.mdc-ripple-upgraded--background-focused::before,.mdc-switch__thumb-underlay:not(.mdc-ripple-upgraded):focus::before{transition-duration:75ms;opacity:.12}.mdc-switch__thumb-underlay:not(.mdc-ripple-upgraded)::after{transition:opacity 150ms linear}.mdc-switch__thumb-underlay:not(.mdc-ripple-upgraded):active::after{transition-duration:75ms;opacity:.12}.mdc-switch__thumb-underlay.mdc-ripple-upgraded{--mdc-ripple-fg-opacity: 0.12}.mdc-tab{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-button-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:.875rem;font-size:var(--mdc-typography-button-font-size, 0.875rem);line-height:2.25rem;line-height:var(--mdc-typography-button-line-height, 2.25rem);font-weight:500;font-weight:var(--mdc-typography-button-font-weight, 500);letter-spacing:.0892857143em;letter-spacing:var(--mdc-typography-button-letter-spacing, 0.0892857143em);text-decoration:none;-webkit-text-decoration:var(--mdc-typography-button-text-decoration, none);text-decoration:var(--mdc-typography-button-text-decoration, none);text-transform:uppercase;text-transform:var(--mdc-typography-button-text-transform, uppercase);padding-right:24px;padding-left:24px;position:relative;display:flex;flex:1 0 auto;justify-content:center;box-sizing:border-box;margin:0;padding-top:0;padding-bottom:0;border:none;outline:none;background:none;text-align:center;white-space:nowrap;cursor:pointer;-webkit-appearance:none;z-index:1}.mdc-tab .mdc-tab__text-label{color:rgba(0,0,0,.6)}.mdc-tab .mdc-tab__icon{color:rgba(0,0,0,.54);fill:currentColor}.mdc-tab::-moz-focus-inner{padding:0;border:0}.mdc-tab--min-width{flex:0 1 auto}.mdc-tab__content{position:relative;display:flex;align-items:center;justify-content:center;height:inherit;pointer-events:none}.mdc-tab__text-label{transition:150ms color linear;display:inline-block;line-height:1;z-index:2}.mdc-tab__icon{transition:150ms color linear;width:24px;height:24px;font-size:24px;z-index:2}.mdc-tab--stacked .mdc-tab__content{flex-direction:column;align-items:center;justify-content:center}.mdc-tab--stacked .mdc-tab__text-label{padding-top:6px;padding-bottom:4px}.mdc-tab--active .mdc-tab__text-label{color:#6200ee;color:var(--mdc-theme-primary, #6200ee)}.mdc-tab--active .mdc-tab__icon{color:#6200ee;color:var(--mdc-theme-primary, #6200ee);fill:currentColor}.mdc-tab--active .mdc-tab__text-label,.mdc-tab--active .mdc-tab__icon{transition-delay:100ms}.mdc-tab:not(.mdc-tab--stacked) .mdc-tab__icon+.mdc-tab__text-label{padding-left:8px;padding-right:0}[dir=rtl] .mdc-tab:not(.mdc-tab--stacked) .mdc-tab__icon+.mdc-tab__text-label,.mdc-tab:not(.mdc-tab--stacked) .mdc-tab__icon+.mdc-tab__text-label[dir=rtl]{padding-left:0;padding-right:8px}.mdc-tab__ripple{--mdc-ripple-fg-size: 0;--mdc-ripple-left: 0;--mdc-ripple-top: 0;--mdc-ripple-fg-scale: 1;--mdc-ripple-fg-translate-end: 0;--mdc-ripple-fg-translate-start: 0;-webkit-tap-highlight-color:rgba(0,0,0,0);position:absolute;top:0;left:0;width:100%;height:100%;overflow:hidden}.mdc-tab__ripple::before,.mdc-tab__ripple::after{position:absolute;border-radius:50%;opacity:0;pointer-events:none;content:""}.mdc-tab__ripple::before{transition:opacity 15ms linear,background-color 15ms linear;z-index:1}.mdc-tab__ripple.mdc-ripple-upgraded::before{-webkit-transform:scale(var(--mdc-ripple-fg-scale, 1));transform:scale(var(--mdc-ripple-fg-scale, 1))}.mdc-tab__ripple.mdc-ripple-upgraded::after{top:0;left:0;-webkit-transform:scale(0);transform:scale(0);-webkit-transform-origin:center center;transform-origin:center center}.mdc-tab__ripple.mdc-ripple-upgraded--unbounded::after{top:var(--mdc-ripple-top, 0);left:var(--mdc-ripple-left, 0)}.mdc-tab__ripple.mdc-ripple-upgraded--foreground-activation::after{-webkit-animation:mdc-ripple-fg-radius-in 225ms forwards,mdc-ripple-fg-opacity-in 75ms forwards;animation:mdc-ripple-fg-radius-in 225ms forwards,mdc-ripple-fg-opacity-in 75ms forwards}.mdc-tab__ripple.mdc-ripple-upgraded--foreground-deactivation::after{-webkit-animation:mdc-ripple-fg-opacity-out 150ms;animation:mdc-ripple-fg-opacity-out 150ms;-webkit-transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1))}.mdc-tab__ripple::before,.mdc-tab__ripple::after{top:calc(50% - 100%);left:calc(50% - 100%);width:200%;height:200%}.mdc-tab__ripple.mdc-ripple-upgraded::after{width:var(--mdc-ripple-fg-size, 100%);height:var(--mdc-ripple-fg-size, 100%)}.mdc-tab__ripple::before,.mdc-tab__ripple::after{background-color:#6200ee;background-color:var(--mdc-theme-primary, #6200ee)}.mdc-tab__ripple:hover::before{opacity:.04}.mdc-tab__ripple.mdc-ripple-upgraded--background-focused::before,.mdc-tab__ripple:not(.mdc-ripple-upgraded):focus::before{transition-duration:75ms;opacity:.12}.mdc-tab__ripple:not(.mdc-ripple-upgraded)::after{transition:opacity 150ms linear}.mdc-tab__ripple:not(.mdc-ripple-upgraded):active::after{transition-duration:75ms;opacity:.12}.mdc-tab__ripple.mdc-ripple-upgraded{--mdc-ripple-fg-opacity: 0.12}.mdc-tab-bar{width:100%}.mdc-tab{height:48px}.mdc-tab--stacked{height:72px}.mdc-tab-indicator{display:flex;position:absolute;top:0;left:0;justify-content:center;width:100%;height:100%;pointer-events:none;z-index:1}.mdc-tab-indicator .mdc-tab-indicator__content--underline{border-color:#6200ee;border-color:var(--mdc-theme-primary, #6200ee)}.mdc-tab-indicator .mdc-tab-indicator__content--icon{color:#018786;color:var(--mdc-theme-secondary, #018786)}.mdc-tab-indicator .mdc-tab-indicator__content--underline{border-top-width:2px}.mdc-tab-indicator .mdc-tab-indicator__content--icon{height:34px;font-size:34px}.mdc-tab-indicator__content{-webkit-transform-origin:left;transform-origin:left;opacity:0}.mdc-tab-indicator__content--underline{align-self:flex-end;box-sizing:border-box;width:100%;border-top-style:solid}.mdc-tab-indicator__content--icon{align-self:center;margin:0 auto}.mdc-tab-indicator--active .mdc-tab-indicator__content{opacity:1}.mdc-tab-indicator .mdc-tab-indicator__content{transition:250ms -webkit-transform cubic-bezier(0.4, 0, 0.2, 1);transition:250ms transform cubic-bezier(0.4, 0, 0.2, 1);transition:250ms transform cubic-bezier(0.4, 0, 0.2, 1), 250ms -webkit-transform cubic-bezier(0.4, 0, 0.2, 1)}.mdc-tab-indicator--no-transition .mdc-tab-indicator__content{transition:none}.mdc-tab-indicator--fade .mdc-tab-indicator__content{transition:150ms opacity linear}.mdc-tab-indicator--active.mdc-tab-indicator--fade .mdc-tab-indicator__content{transition-delay:100ms}.mdc-tab-scroller{overflow-y:hidden}.mdc-tab-scroller.mdc-tab-scroller--animating .mdc-tab-scroller__scroll-content{transition:250ms -webkit-transform cubic-bezier(0.4, 0, 0.2, 1);transition:250ms transform cubic-bezier(0.4, 0, 0.2, 1);transition:250ms transform cubic-bezier(0.4, 0, 0.2, 1), 250ms -webkit-transform cubic-bezier(0.4, 0, 0.2, 1)}.mdc-tab-scroller__test{position:absolute;top:-9999px;width:100px;height:100px;overflow-x:scroll}.mdc-tab-scroller__scroll-area{-webkit-overflow-scrolling:touch;display:flex;overflow-x:hidden}.mdc-tab-scroller__scroll-area::-webkit-scrollbar,.mdc-tab-scroller__test::-webkit-scrollbar{display:none}.mdc-tab-scroller__scroll-area--scroll{overflow-x:scroll}.mdc-tab-scroller__scroll-content{position:relative;display:flex;flex:1 0 auto;-webkit-transform:none;transform:none;will-change:transform}.mdc-tab-scroller--align-start .mdc-tab-scroller__scroll-content{justify-content:flex-start}.mdc-tab-scroller--align-end .mdc-tab-scroller__scroll-content{justify-content:flex-end}.mdc-tab-scroller--align-center .mdc-tab-scroller__scroll-content{justify-content:center}.mdc-tab-scroller--animating .mdc-tab-scroller__scroll-area{-webkit-overflow-scrolling:auto}.mdc-text-field-helper-text{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-caption-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:.75rem;font-size:var(--mdc-typography-caption-font-size, 0.75rem);line-height:1.25rem;line-height:var(--mdc-typography-caption-line-height, 1.25rem);font-weight:400;font-weight:var(--mdc-typography-caption-font-weight, 400);letter-spacing:.0333333333em;letter-spacing:var(--mdc-typography-caption-letter-spacing, 0.0333333333em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-caption-text-decoration, inherit);text-decoration:var(--mdc-typography-caption-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-caption-text-transform, inherit);display:block;margin-top:0;line-height:normal;margin:0;opacity:0;will-change:opacity;transition:opacity 150ms cubic-bezier(0.4, 0, 0.2, 1)}.mdc-text-field-helper-text::before{display:inline-block;width:0;height:16px;content:"";vertical-align:0}.mdc-text-field-helper-text--persistent{transition:none;opacity:1;will-change:initial}.mdc-text-field-character-counter{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-caption-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:.75rem;font-size:var(--mdc-typography-caption-font-size, 0.75rem);line-height:1.25rem;line-height:var(--mdc-typography-caption-line-height, 1.25rem);font-weight:400;font-weight:var(--mdc-typography-caption-font-weight, 400);letter-spacing:.0333333333em;letter-spacing:var(--mdc-typography-caption-letter-spacing, 0.0333333333em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-caption-text-decoration, inherit);text-decoration:var(--mdc-typography-caption-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-caption-text-transform, inherit);display:block;margin-top:0;line-height:normal;margin-left:auto;margin-right:0;padding-left:16px;padding-right:0;white-space:nowrap}.mdc-text-field-character-counter::before{display:inline-block;width:0;height:16px;content:"";vertical-align:0}[dir=rtl] .mdc-text-field-character-counter,.mdc-text-field-character-counter[dir=rtl]{margin-left:0;margin-right:auto}[dir=rtl] .mdc-text-field-character-counter,.mdc-text-field-character-counter[dir=rtl]{padding-left:0;padding-right:16px}.mdc-text-field__icon{align-self:center;cursor:pointer}.mdc-text-field__icon:not([tabindex]),.mdc-text-field__icon[tabindex="-1"]{cursor:default;pointer-events:none}.mdc-text-field__icon--leading{margin-left:16px;margin-right:8px}[dir=rtl] .mdc-text-field__icon--leading,.mdc-text-field__icon--leading[dir=rtl]{margin-left:8px;margin-right:16px}.mdc-text-field__icon--trailing{margin-left:12px;margin-right:12px}[dir=rtl] .mdc-text-field__icon--trailing,.mdc-text-field__icon--trailing[dir=rtl]{margin-left:12px;margin-right:12px}.mdc-text-field--filled{--mdc-ripple-fg-size: 0;--mdc-ripple-left: 0;--mdc-ripple-top: 0;--mdc-ripple-fg-scale: 1;--mdc-ripple-fg-translate-end: 0;--mdc-ripple-fg-translate-start: 0;-webkit-tap-highlight-color:rgba(0,0,0,0)}.mdc-text-field--filled .mdc-text-field__ripple::before,.mdc-text-field--filled .mdc-text-field__ripple::after{position:absolute;border-radius:50%;opacity:0;pointer-events:none;content:""}.mdc-text-field--filled .mdc-text-field__ripple::before{transition:opacity 15ms linear,background-color 15ms linear;z-index:1}.mdc-text-field--filled.mdc-ripple-upgraded .mdc-text-field__ripple::before{-webkit-transform:scale(var(--mdc-ripple-fg-scale, 1));transform:scale(var(--mdc-ripple-fg-scale, 1))}.mdc-text-field--filled.mdc-ripple-upgraded .mdc-text-field__ripple::after{top:0;left:0;-webkit-transform:scale(0);transform:scale(0);-webkit-transform-origin:center center;transform-origin:center center}.mdc-text-field--filled.mdc-ripple-upgraded--unbounded .mdc-text-field__ripple::after{top:var(--mdc-ripple-top, 0);left:var(--mdc-ripple-left, 0)}.mdc-text-field--filled.mdc-ripple-upgraded--foreground-activation .mdc-text-field__ripple::after{-webkit-animation:mdc-ripple-fg-radius-in 225ms forwards,mdc-ripple-fg-opacity-in 75ms forwards;animation:mdc-ripple-fg-radius-in 225ms forwards,mdc-ripple-fg-opacity-in 75ms forwards}.mdc-text-field--filled.mdc-ripple-upgraded--foreground-deactivation .mdc-text-field__ripple::after{-webkit-animation:mdc-ripple-fg-opacity-out 150ms;animation:mdc-ripple-fg-opacity-out 150ms;-webkit-transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1))}.mdc-text-field--filled .mdc-text-field__ripple::before,.mdc-text-field--filled .mdc-text-field__ripple::after{top:calc(50% - 100%);left:calc(50% - 100%);width:200%;height:200%}.mdc-text-field--filled.mdc-ripple-upgraded .mdc-text-field__ripple::after{width:var(--mdc-ripple-fg-size, 100%);height:var(--mdc-ripple-fg-size, 100%)}.mdc-text-field__ripple{position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none}.mdc-text-field{border-radius:4px 4px 0 0;padding:0 16px;display:inline-flex;align-items:baseline;position:relative;box-sizing:border-box;overflow:hidden;will-change:opacity,transform,color}.mdc-text-field:not(.mdc-text-field--disabled) .mdc-floating-label{color:rgba(0,0,0,.6)}.mdc-text-field:not(.mdc-text-field--disabled) .mdc-text-field__input{color:rgba(0,0,0,.87)}@media all{.mdc-text-field:not(.mdc-text-field--disabled) .mdc-text-field__input::-webkit-input-placeholder{color:rgba(0,0,0,.54)}.mdc-text-field:not(.mdc-text-field--disabled) .mdc-text-field__input:-ms-input-placeholder{color:rgba(0,0,0,.54)}.mdc-text-field:not(.mdc-text-field--disabled) .mdc-text-field__input::-ms-input-placeholder{color:rgba(0,0,0,.54)}.mdc-text-field:not(.mdc-text-field--disabled) .mdc-text-field__input::placeholder{color:rgba(0,0,0,.54)}}@media all{.mdc-text-field:not(.mdc-text-field--disabled) .mdc-text-field__input:-ms-input-placeholder{color:rgba(0,0,0,.54)}}.mdc-text-field .mdc-text-field__input{caret-color:#6200ee;caret-color:var(--mdc-theme-primary, #6200ee)}.mdc-text-field:not(.mdc-text-field--disabled)+.mdc-text-field-helper-line .mdc-text-field-helper-text{color:rgba(0,0,0,.6)}.mdc-text-field:not(.mdc-text-field--disabled) .mdc-text-field-character-counter,.mdc-text-field:not(.mdc-text-field--disabled)+.mdc-text-field-helper-line .mdc-text-field-character-counter{color:rgba(0,0,0,.6)}.mdc-text-field:not(.mdc-text-field--disabled) .mdc-text-field__icon--leading{color:rgba(0,0,0,.54)}.mdc-text-field:not(.mdc-text-field--disabled) .mdc-text-field__icon--trailing{color:rgba(0,0,0,.54)}.mdc-text-field:not(.mdc-text-field--disabled) .mdc-text-field__affix--prefix{color:rgba(0,0,0,.6)}.mdc-text-field:not(.mdc-text-field--disabled) .mdc-text-field__affix--suffix{color:rgba(0,0,0,.6)}.mdc-text-field .mdc-floating-label{top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%);pointer-events:none}.mdc-text-field.mdc-text-field--with-leading-icon{padding-left:0;padding-right:16px}[dir=rtl] .mdc-text-field.mdc-text-field--with-leading-icon,.mdc-text-field.mdc-text-field--with-leading-icon[dir=rtl]{padding-left:16px;padding-right:0}.mdc-text-field.mdc-text-field--with-trailing-icon{padding-left:16px;padding-right:0}[dir=rtl] .mdc-text-field.mdc-text-field--with-trailing-icon,.mdc-text-field.mdc-text-field--with-trailing-icon[dir=rtl]{padding-left:0;padding-right:16px}.mdc-text-field.mdc-text-field--with-leading-icon.mdc-text-field--with-trailing-icon{padding-left:0;padding-right:0}[dir=rtl] .mdc-text-field.mdc-text-field--with-leading-icon.mdc-text-field--with-trailing-icon,.mdc-text-field.mdc-text-field--with-leading-icon.mdc-text-field--with-trailing-icon[dir=rtl]{padding-left:0;padding-right:0}.mdc-text-field__input{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-subtitle1-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:1rem;font-size:var(--mdc-typography-subtitle1-font-size, 1rem);font-weight:400;font-weight:var(--mdc-typography-subtitle1-font-weight, 400);letter-spacing:.009375em;letter-spacing:var(--mdc-typography-subtitle1-letter-spacing, 0.009375em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-subtitle1-text-decoration, inherit);text-decoration:var(--mdc-typography-subtitle1-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-subtitle1-text-transform, inherit);height:28px;transition:opacity 150ms cubic-bezier(0.4, 0, 0.2, 1);width:100%;min-width:0;border:none;border-radius:0;background:none;-webkit-appearance:none;-moz-appearance:none;appearance:none;padding:0}.mdc-text-field__input::-ms-clear{display:none}.mdc-text-field__input:focus{outline:none}.mdc-text-field__input:invalid{box-shadow:none}.mdc-text-field__input:-webkit-autofill{z-index:auto !important}@media all{.mdc-text-field__input::-webkit-input-placeholder{transition:opacity 67ms cubic-bezier(0.4, 0, 0.2, 1);opacity:0}.mdc-text-field__input:-ms-input-placeholder{transition:opacity 67ms cubic-bezier(0.4, 0, 0.2, 1);opacity:0}.mdc-text-field__input::-ms-input-placeholder{transition:opacity 67ms cubic-bezier(0.4, 0, 0.2, 1);opacity:0}.mdc-text-field__input::placeholder{transition:opacity 67ms cubic-bezier(0.4, 0, 0.2, 1);opacity:0}}@media all{.mdc-text-field__input:-ms-input-placeholder{transition:opacity 67ms cubic-bezier(0.4, 0, 0.2, 1);opacity:0}}@media all{.mdc-text-field--fullwidth .mdc-text-field__input::-webkit-input-placeholder,.mdc-text-field--no-label .mdc-text-field__input::-webkit-input-placeholder,.mdc-text-field--focused .mdc-text-field__input::-webkit-input-placeholder{transition-delay:40ms;transition-duration:110ms;opacity:1}.mdc-text-field--fullwidth .mdc-text-field__input:-ms-input-placeholder,.mdc-text-field--no-label .mdc-text-field__input:-ms-input-placeholder,.mdc-text-field--focused .mdc-text-field__input:-ms-input-placeholder{transition-delay:40ms;transition-duration:110ms;opacity:1}.mdc-text-field--fullwidth .mdc-text-field__input::-ms-input-placeholder,.mdc-text-field--no-label .mdc-text-field__input::-ms-input-placeholder,.mdc-text-field--focused .mdc-text-field__input::-ms-input-placeholder{transition-delay:40ms;transition-duration:110ms;opacity:1}.mdc-text-field--fullwidth .mdc-text-field__input::placeholder,.mdc-text-field--no-label .mdc-text-field__input::placeholder,.mdc-text-field--focused .mdc-text-field__input::placeholder{transition-delay:40ms;transition-duration:110ms;opacity:1}}@media all{.mdc-text-field--fullwidth .mdc-text-field__input:-ms-input-placeholder,.mdc-text-field--no-label .mdc-text-field__input:-ms-input-placeholder,.mdc-text-field--focused .mdc-text-field__input:-ms-input-placeholder{transition-delay:40ms;transition-duration:110ms;opacity:1}}.mdc-text-field__affix{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-subtitle1-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:1rem;font-size:var(--mdc-typography-subtitle1-font-size, 1rem);font-weight:400;font-weight:var(--mdc-typography-subtitle1-font-weight, 400);letter-spacing:.009375em;letter-spacing:var(--mdc-typography-subtitle1-letter-spacing, 0.009375em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-subtitle1-text-decoration, inherit);text-decoration:var(--mdc-typography-subtitle1-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-subtitle1-text-transform, inherit);height:28px;transition:opacity 150ms cubic-bezier(0.4, 0, 0.2, 1);opacity:0;white-space:nowrap}.mdc-text-field--label-floating .mdc-text-field__affix,.mdc-text-field--no-label .mdc-text-field__affix{opacity:1}.mdc-text-field__affix--prefix{padding-left:0;padding-right:2px}[dir=rtl] .mdc-text-field__affix--prefix,.mdc-text-field__affix--prefix[dir=rtl]{padding-left:2px;padding-right:0}.mdc-text-field--end-aligned .mdc-text-field__affix--prefix{padding-left:0;padding-right:12px}[dir=rtl] .mdc-text-field--end-aligned .mdc-text-field__affix--prefix,.mdc-text-field--end-aligned .mdc-text-field__affix--prefix[dir=rtl]{padding-left:12px;padding-right:0}.mdc-text-field__affix--suffix{padding-left:12px;padding-right:0}[dir=rtl] .mdc-text-field__affix--suffix,.mdc-text-field__affix--suffix[dir=rtl]{padding-left:0;padding-right:12px}.mdc-text-field--end-aligned .mdc-text-field__affix--suffix{padding-left:2px;padding-right:0}[dir=rtl] .mdc-text-field--end-aligned .mdc-text-field__affix--suffix,.mdc-text-field--end-aligned .mdc-text-field__affix--suffix[dir=rtl]{padding-left:0;padding-right:2px}.mdc-text-field__input:-webkit-autofill+.mdc-floating-label{-webkit-transform:translateY(-50%) scale(0.75);transform:translateY(-50%) scale(0.75);cursor:auto}.mdc-text-field--filled{height:56px}.mdc-text-field--filled .mdc-text-field__ripple::before,.mdc-text-field--filled .mdc-text-field__ripple::after{background-color:rgba(0,0,0,.87)}.mdc-text-field--filled:hover .mdc-text-field__ripple::before{opacity:.04}.mdc-text-field--filled.mdc-ripple-upgraded--background-focused .mdc-text-field__ripple::before,.mdc-text-field--filled:not(.mdc-ripple-upgraded):focus .mdc-text-field__ripple::before{transition-duration:75ms;opacity:.12}.mdc-text-field--filled::before{display:inline-block;width:0;height:40px;content:"";vertical-align:0}.mdc-text-field--filled:not(.mdc-text-field--disabled){background-color:#f5f5f5}.mdc-text-field--filled:not(.mdc-text-field--disabled) .mdc-line-ripple::before{border-bottom-color:rgba(0,0,0,.42)}.mdc-text-field--filled:not(.mdc-text-field--disabled):hover .mdc-line-ripple::before{border-bottom-color:rgba(0,0,0,.87)}.mdc-text-field--filled .mdc-line-ripple::after{border-bottom-color:#6200ee;border-bottom-color:var(--mdc-theme-primary, #6200ee)}.mdc-text-field--filled .mdc-floating-label{left:16px;right:initial}[dir=rtl] .mdc-text-field--filled .mdc-floating-label,.mdc-text-field--filled .mdc-floating-label[dir=rtl]{left:initial;right:16px}.mdc-text-field--filled .mdc-floating-label--float-above{-webkit-transform:translateY(-106%) scale(0.75);transform:translateY(-106%) scale(0.75)}.mdc-text-field--filled.mdc-text-field--no-label .mdc-text-field__input{height:100%}.mdc-text-field--filled.mdc-text-field--no-label .mdc-floating-label{display:none}.mdc-text-field--filled.mdc-text-field--no-label::before{display:none}.mdc-text-field--outlined{height:56px;overflow:visible}.mdc-text-field--outlined .mdc-floating-label--float-above{-webkit-transform:translateY(-37.25px) scale(1);transform:translateY(-37.25px) scale(1)}.mdc-text-field--outlined .mdc-floating-label--float-above{font-size:.75rem}.mdc-text-field--outlined.mdc-notched-outline--upgraded .mdc-floating-label--float-above,.mdc-text-field--outlined .mdc-notched-outline--upgraded .mdc-floating-label--float-above{-webkit-transform:translateY(-34.75px) scale(0.75);transform:translateY(-34.75px) scale(0.75)}.mdc-text-field--outlined.mdc-notched-outline--upgraded .mdc-floating-label--float-above,.mdc-text-field--outlined .mdc-notched-outline--upgraded .mdc-floating-label--float-above{font-size:1rem}.mdc-text-field--outlined .mdc-floating-label--shake{-webkit-animation:mdc-floating-label-shake-float-above-text-field-outlined 250ms 1;animation:mdc-floating-label-shake-float-above-text-field-outlined 250ms 1}@-webkit-keyframes mdc-floating-label-shake-float-above-text-field-outlined{0%{-webkit-transform:translateX(calc(0 - 0%)) translateY(-34.75px) scale(0.75);transform:translateX(calc(0 - 0%)) translateY(-34.75px) scale(0.75)}33%{-webkit-animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);-webkit-transform:translateX(calc(4% - 0%)) translateY(-34.75px) scale(0.75);transform:translateX(calc(4% - 0%)) translateY(-34.75px) scale(0.75)}66%{-webkit-animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);-webkit-transform:translateX(calc(-4% - 0%)) translateY(-34.75px) scale(0.75);transform:translateX(calc(-4% - 0%)) translateY(-34.75px) scale(0.75)}100%{-webkit-transform:translateX(calc(0 - 0%)) translateY(-34.75px) scale(0.75);transform:translateX(calc(0 - 0%)) translateY(-34.75px) scale(0.75)}}@keyframes mdc-floating-label-shake-float-above-text-field-outlined{0%{-webkit-transform:translateX(calc(0 - 0%)) translateY(-34.75px) scale(0.75);transform:translateX(calc(0 - 0%)) translateY(-34.75px) scale(0.75)}33%{-webkit-animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);-webkit-transform:translateX(calc(4% - 0%)) translateY(-34.75px) scale(0.75);transform:translateX(calc(4% - 0%)) translateY(-34.75px) scale(0.75)}66%{-webkit-animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);-webkit-transform:translateX(calc(-4% - 0%)) translateY(-34.75px) scale(0.75);transform:translateX(calc(-4% - 0%)) translateY(-34.75px) scale(0.75)}100%{-webkit-transform:translateX(calc(0 - 0%)) translateY(-34.75px) scale(0.75);transform:translateX(calc(0 - 0%)) translateY(-34.75px) scale(0.75)}}.mdc-text-field--outlined .mdc-text-field__input{height:100%}.mdc-text-field--outlined:not(.mdc-text-field--disabled) .mdc-notched-outline__leading,.mdc-text-field--outlined:not(.mdc-text-field--disabled) .mdc-notched-outline__notch,.mdc-text-field--outlined:not(.mdc-text-field--disabled) .mdc-notched-outline__trailing{border-color:rgba(0,0,0,.38)}.mdc-text-field--outlined:not(.mdc-text-field--disabled):not(.mdc-text-field--focused):hover .mdc-notched-outline .mdc-notched-outline__leading,.mdc-text-field--outlined:not(.mdc-text-field--disabled):not(.mdc-text-field--focused):hover .mdc-notched-outline .mdc-notched-outline__notch,.mdc-text-field--outlined:not(.mdc-text-field--disabled):not(.mdc-text-field--focused):hover .mdc-notched-outline .mdc-notched-outline__trailing{border-color:rgba(0,0,0,.87)}.mdc-text-field--outlined:not(.mdc-text-field--disabled).mdc-text-field--focused .mdc-notched-outline__leading,.mdc-text-field--outlined:not(.mdc-text-field--disabled).mdc-text-field--focused .mdc-notched-outline__notch,.mdc-text-field--outlined:not(.mdc-text-field--disabled).mdc-text-field--focused .mdc-notched-outline__trailing{border-color:#6200ee;border-color:var(--mdc-theme-primary, #6200ee)}.mdc-text-field--outlined .mdc-notched-outline .mdc-notched-outline__leading{border-radius:4px 0 0 4px}[dir=rtl] .mdc-text-field--outlined .mdc-notched-outline .mdc-notched-outline__leading,.mdc-text-field--outlined .mdc-notched-outline .mdc-notched-outline__leading[dir=rtl]{border-radius:0 4px 4px 0}.mdc-text-field--outlined .mdc-notched-outline .mdc-notched-outline__trailing{border-radius:0 4px 4px 0}[dir=rtl] .mdc-text-field--outlined .mdc-notched-outline .mdc-notched-outline__trailing,.mdc-text-field--outlined .mdc-notched-outline .mdc-notched-outline__trailing[dir=rtl]{border-radius:4px 0 0 4px}.mdc-text-field--outlined .mdc-notched-outline--notched .mdc-notched-outline__notch{padding-top:1px}.mdc-text-field--outlined .mdc-text-field__ripple::before,.mdc-text-field--outlined .mdc-text-field__ripple::after{content:none}.mdc-text-field--outlined .mdc-floating-label{left:4px;right:initial}[dir=rtl] .mdc-text-field--outlined .mdc-floating-label,.mdc-text-field--outlined .mdc-floating-label[dir=rtl]{left:initial;right:4px}.mdc-text-field--outlined .mdc-text-field__input{display:flex;border:none !important;background-color:transparent;z-index:1}.mdc-text-field--outlined .mdc-text-field__icon{z-index:2}.mdc-text-field--outlined.mdc-text-field--focused .mdc-notched-outline--notched .mdc-notched-outline__notch{padding-top:2px}.mdc-text-field--textarea{align-items:center;width:auto;height:auto;padding:0;overflow:visible;transition:none}.mdc-text-field--textarea:not(.mdc-text-field--disabled) .mdc-notched-outline__leading,.mdc-text-field--textarea:not(.mdc-text-field--disabled) .mdc-notched-outline__notch,.mdc-text-field--textarea:not(.mdc-text-field--disabled) .mdc-notched-outline__trailing{border-color:rgba(0,0,0,.38)}.mdc-text-field--textarea:not(.mdc-text-field--disabled):not(.mdc-text-field--focused):hover .mdc-notched-outline .mdc-notched-outline__leading,.mdc-text-field--textarea:not(.mdc-text-field--disabled):not(.mdc-text-field--focused):hover .mdc-notched-outline .mdc-notched-outline__notch,.mdc-text-field--textarea:not(.mdc-text-field--disabled):not(.mdc-text-field--focused):hover .mdc-notched-outline .mdc-notched-outline__trailing{border-color:rgba(0,0,0,.87)}.mdc-text-field--textarea:not(.mdc-text-field--disabled).mdc-text-field--focused .mdc-notched-outline__leading,.mdc-text-field--textarea:not(.mdc-text-field--disabled).mdc-text-field--focused .mdc-notched-outline__notch,.mdc-text-field--textarea:not(.mdc-text-field--disabled).mdc-text-field--focused .mdc-notched-outline__trailing{border-color:#6200ee;border-color:var(--mdc-theme-primary, #6200ee)}.mdc-text-field--textarea .mdc-notched-outline .mdc-notched-outline__leading{border-radius:4px 0 0 4px}[dir=rtl] .mdc-text-field--textarea .mdc-notched-outline .mdc-notched-outline__leading,.mdc-text-field--textarea .mdc-notched-outline .mdc-notched-outline__leading[dir=rtl]{border-radius:0 4px 4px 0}.mdc-text-field--textarea .mdc-notched-outline .mdc-notched-outline__trailing{border-radius:0 4px 4px 0}[dir=rtl] .mdc-text-field--textarea .mdc-notched-outline .mdc-notched-outline__trailing,.mdc-text-field--textarea .mdc-notched-outline .mdc-notched-outline__trailing[dir=rtl]{border-radius:4px 0 0 4px}.mdc-text-field--textarea .mdc-text-field__ripple::before,.mdc-text-field--textarea .mdc-text-field__ripple::after{content:none}.mdc-text-field--textarea:not(.mdc-text-field--disabled){background-color:transparent}.mdc-text-field--textarea .mdc-text-field-character-counter{left:initial;right:16px;position:absolute;bottom:13px}[dir=rtl] .mdc-text-field--textarea .mdc-text-field-character-counter,.mdc-text-field--textarea .mdc-text-field-character-counter[dir=rtl]{left:16px;right:initial}.mdc-text-field--textarea .mdc-floating-label{left:4px;right:initial;top:17px;width:auto}[dir=rtl] .mdc-text-field--textarea .mdc-floating-label,.mdc-text-field--textarea .mdc-floating-label[dir=rtl]{left:initial;right:4px}.mdc-text-field--textarea .mdc-floating-label:not(.mdc-floating-label--float-above){-webkit-transform:none;transform:none}.mdc-text-field--textarea .mdc-floating-label--float-above{-webkit-transform:translateY(-144%) scale(1);transform:translateY(-144%) scale(1)}.mdc-text-field--textarea .mdc-floating-label--float-above{font-size:.75rem}.mdc-text-field--textarea.mdc-notched-outline--upgraded .mdc-floating-label--float-above,.mdc-text-field--textarea .mdc-notched-outline--upgraded .mdc-floating-label--float-above{-webkit-transform:translateY(-130%) scale(0.75);transform:translateY(-130%) scale(0.75)}.mdc-text-field--textarea.mdc-notched-outline--upgraded .mdc-floating-label--float-above,.mdc-text-field--textarea .mdc-notched-outline--upgraded .mdc-floating-label--float-above{font-size:1rem}.mdc-text-field--textarea .mdc-floating-label--shake{-webkit-animation:mdc-floating-label-shake-float-above-textarea 250ms 1;animation:mdc-floating-label-shake-float-above-textarea 250ms 1}@-webkit-keyframes mdc-floating-label-shake-float-above-textarea{0%{-webkit-transform:translateX(calc(0 - 0%)) translateY(-130%) scale(0.75);transform:translateX(calc(0 - 0%)) translateY(-130%) scale(0.75)}33%{-webkit-animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);-webkit-transform:translateX(calc(4% - 0%)) translateY(-130%) scale(0.75);transform:translateX(calc(4% - 0%)) translateY(-130%) scale(0.75)}66%{-webkit-animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);-webkit-transform:translateX(calc(-4% - 0%)) translateY(-130%) scale(0.75);transform:translateX(calc(-4% - 0%)) translateY(-130%) scale(0.75)}100%{-webkit-transform:translateX(calc(0 - 0%)) translateY(-130%) scale(0.75);transform:translateX(calc(0 - 0%)) translateY(-130%) scale(0.75)}}@keyframes mdc-floating-label-shake-float-above-textarea{0%{-webkit-transform:translateX(calc(0 - 0%)) translateY(-130%) scale(0.75);transform:translateX(calc(0 - 0%)) translateY(-130%) scale(0.75)}33%{-webkit-animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);-webkit-transform:translateX(calc(4% - 0%)) translateY(-130%) scale(0.75);transform:translateX(calc(4% - 0%)) translateY(-130%) scale(0.75)}66%{-webkit-animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);-webkit-transform:translateX(calc(-4% - 0%)) translateY(-130%) scale(0.75);transform:translateX(calc(-4% - 0%)) translateY(-130%) scale(0.75)}100%{-webkit-transform:translateX(calc(0 - 0%)) translateY(-130%) scale(0.75);transform:translateX(calc(0 - 0%)) translateY(-130%) scale(0.75)}}.mdc-text-field--textarea .mdc-text-field__input{height:auto;align-self:stretch;box-sizing:border-box;margin-top:8px;margin-bottom:1px;margin-left:0;margin-right:1px;padding:0 16px 16px;line-height:1.75rem}[dir=rtl] .mdc-text-field--textarea .mdc-text-field__input,.mdc-text-field--textarea .mdc-text-field__input[dir=rtl]{margin-left:1px;margin-right:0}.mdc-text-field--textarea .mdc-text-field-character-counter+.mdc-text-field__input{margin-bottom:28px;padding-bottom:0}.mdc-text-field--fullwidth{padding:0;width:100%}.mdc-text-field--fullwidth:not(.mdc-text-field--disabled) .mdc-line-ripple::before{border-bottom-color:rgba(0,0,0,.42)}.mdc-text-field--fullwidth.mdc-text-field--disabled .mdc-line-ripple::before{border-bottom-color:rgba(0,0,0,.42)}.mdc-text-field--fullwidth:not(.mdc-text-field--textarea){display:flex}.mdc-text-field--fullwidth:not(.mdc-text-field--textarea) .mdc-text-field__input{height:100%}.mdc-text-field--fullwidth:not(.mdc-text-field--textarea) .mdc-floating-label{display:none}.mdc-text-field--fullwidth:not(.mdc-text-field--textarea)::before{display:none}.mdc-text-field--fullwidth:not(.mdc-text-field--textarea) .mdc-text-field__ripple::before,.mdc-text-field--fullwidth:not(.mdc-text-field--textarea) .mdc-text-field__ripple::after{content:none}.mdc-text-field--fullwidth:not(.mdc-text-field--textarea):not(.mdc-text-field--disabled){background-color:transparent}.mdc-text-field--fullwidth.mdc-text-field--textarea .mdc-text-field__input{resize:vertical}.mdc-text-field--with-leading-icon.mdc-text-field--filled .mdc-floating-label{max-width:calc(100% - 48px);left:48px;right:initial}[dir=rtl] .mdc-text-field--with-leading-icon.mdc-text-field--filled .mdc-floating-label,.mdc-text-field--with-leading-icon.mdc-text-field--filled .mdc-floating-label[dir=rtl]{left:initial;right:48px}.mdc-text-field--with-leading-icon.mdc-text-field--filled .mdc-floating-label--float-above{max-width:calc(100% / 0.75 - 64px / 0.75)}.mdc-text-field--with-leading-icon.mdc-text-field--outlined .mdc-floating-label{left:36px;right:initial}[dir=rtl] .mdc-text-field--with-leading-icon.mdc-text-field--outlined .mdc-floating-label,.mdc-text-field--with-leading-icon.mdc-text-field--outlined .mdc-floating-label[dir=rtl]{left:initial;right:36px}.mdc-text-field--with-leading-icon.mdc-text-field--outlined :not(.mdc-notched-outline--notched) .mdc-notched-outline__notch{max-width:calc(100% - 60px)}.mdc-text-field--with-leading-icon.mdc-text-field--outlined .mdc-floating-label--float-above{-webkit-transform:translateY(-37.25px) translateX(-32px) scale(1);transform:translateY(-37.25px) translateX(-32px) scale(1)}[dir=rtl] .mdc-text-field--with-leading-icon.mdc-text-field--outlined .mdc-floating-label--float-above,.mdc-text-field--with-leading-icon.mdc-text-field--outlined .mdc-floating-label--float-above[dir=rtl]{-webkit-transform:translateY(-37.25px) translateX(32px) scale(1);transform:translateY(-37.25px) translateX(32px) scale(1)}.mdc-text-field--with-leading-icon.mdc-text-field--outlined .mdc-floating-label--float-above{font-size:.75rem}.mdc-text-field--with-leading-icon.mdc-text-field--outlined.mdc-notched-outline--upgraded .mdc-floating-label--float-above,.mdc-text-field--with-leading-icon.mdc-text-field--outlined .mdc-notched-outline--upgraded .mdc-floating-label--float-above{-webkit-transform:translateY(-34.75px) translateX(-32px) scale(0.75);transform:translateY(-34.75px) translateX(-32px) scale(0.75)}[dir=rtl] .mdc-text-field--with-leading-icon.mdc-text-field--outlined.mdc-notched-outline--upgraded .mdc-floating-label--float-above,.mdc-text-field--with-leading-icon.mdc-text-field--outlined.mdc-notched-outline--upgraded .mdc-floating-label--float-above[dir=rtl],[dir=rtl] .mdc-text-field--with-leading-icon.mdc-text-field--outlined .mdc-notched-outline--upgraded .mdc-floating-label--float-above,.mdc-text-field--with-leading-icon.mdc-text-field--outlined .mdc-notched-outline--upgraded .mdc-floating-label--float-above[dir=rtl]{-webkit-transform:translateY(-34.75px) translateX(32px) scale(0.75);transform:translateY(-34.75px) translateX(32px) scale(0.75)}.mdc-text-field--with-leading-icon.mdc-text-field--outlined.mdc-notched-outline--upgraded .mdc-floating-label--float-above,.mdc-text-field--with-leading-icon.mdc-text-field--outlined .mdc-notched-outline--upgraded .mdc-floating-label--float-above{font-size:1rem}.mdc-text-field--with-leading-icon.mdc-text-field--outlined .mdc-floating-label--shake{-webkit-animation:mdc-floating-label-shake-float-above-text-field-outlined-leading-icon 250ms 1;animation:mdc-floating-label-shake-float-above-text-field-outlined-leading-icon 250ms 1}@-webkit-keyframes mdc-floating-label-shake-float-above-text-field-outlined-leading-icon{0%{-webkit-transform:translateX(calc(0 - 32px)) translateY(-34.75px) scale(0.75);transform:translateX(calc(0 - 32px)) translateY(-34.75px) scale(0.75)}33%{-webkit-animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);-webkit-transform:translateX(calc(4% - 32px)) translateY(-34.75px) scale(0.75);transform:translateX(calc(4% - 32px)) translateY(-34.75px) scale(0.75)}66%{-webkit-animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);-webkit-transform:translateX(calc(-4% - 32px)) translateY(-34.75px) scale(0.75);transform:translateX(calc(-4% - 32px)) translateY(-34.75px) scale(0.75)}100%{-webkit-transform:translateX(calc(0 - 32px)) translateY(-34.75px) scale(0.75);transform:translateX(calc(0 - 32px)) translateY(-34.75px) scale(0.75)}}@keyframes mdc-floating-label-shake-float-above-text-field-outlined-leading-icon{0%{-webkit-transform:translateX(calc(0 - 32px)) translateY(-34.75px) scale(0.75);transform:translateX(calc(0 - 32px)) translateY(-34.75px) scale(0.75)}33%{-webkit-animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);-webkit-transform:translateX(calc(4% - 32px)) translateY(-34.75px) scale(0.75);transform:translateX(calc(4% - 32px)) translateY(-34.75px) scale(0.75)}66%{-webkit-animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);-webkit-transform:translateX(calc(-4% - 32px)) translateY(-34.75px) scale(0.75);transform:translateX(calc(-4% - 32px)) translateY(-34.75px) scale(0.75)}100%{-webkit-transform:translateX(calc(0 - 32px)) translateY(-34.75px) scale(0.75);transform:translateX(calc(0 - 32px)) translateY(-34.75px) scale(0.75)}}[dir=rtl] .mdc-text-field--with-leading-icon.mdc-text-field--outlined .mdc-floating-label--shake,.mdc-text-field--with-leading-icon.mdc-text-field--outlined[dir=rtl] .mdc-floating-label--shake{-webkit-animation:mdc-floating-label-shake-float-above-text-field-outlined-leading-icon 250ms 1;animation:mdc-floating-label-shake-float-above-text-field-outlined-leading-icon 250ms 1}@-webkit-keyframes mdc-floating-label-shake-float-above-text-field-outlined-leading-icon-rtl{0%{-webkit-transform:translateX(calc(0 - -32px)) translateY(-34.75px) scale(0.75);transform:translateX(calc(0 - -32px)) translateY(-34.75px) scale(0.75)}33%{-webkit-animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);-webkit-transform:translateX(calc(4% - -32px)) translateY(-34.75px) scale(0.75);transform:translateX(calc(4% - -32px)) translateY(-34.75px) scale(0.75)}66%{-webkit-animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);-webkit-transform:translateX(calc(-4% - -32px)) translateY(-34.75px) scale(0.75);transform:translateX(calc(-4% - -32px)) translateY(-34.75px) scale(0.75)}100%{-webkit-transform:translateX(calc(0 - -32px)) translateY(-34.75px) scale(0.75);transform:translateX(calc(0 - -32px)) translateY(-34.75px) scale(0.75)}}@keyframes mdc-floating-label-shake-float-above-text-field-outlined-leading-icon-rtl{0%{-webkit-transform:translateX(calc(0 - -32px)) translateY(-34.75px) scale(0.75);transform:translateX(calc(0 - -32px)) translateY(-34.75px) scale(0.75)}33%{-webkit-animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);-webkit-transform:translateX(calc(4% - -32px)) translateY(-34.75px) scale(0.75);transform:translateX(calc(4% - -32px)) translateY(-34.75px) scale(0.75)}66%{-webkit-animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);-webkit-transform:translateX(calc(-4% - -32px)) translateY(-34.75px) scale(0.75);transform:translateX(calc(-4% - -32px)) translateY(-34.75px) scale(0.75)}100%{-webkit-transform:translateX(calc(0 - -32px)) translateY(-34.75px) scale(0.75);transform:translateX(calc(0 - -32px)) translateY(-34.75px) scale(0.75)}}.mdc-text-field--with-trailing-icon.mdc-text-field--filled .mdc-floating-label{max-width:calc(100% - 64px)}.mdc-text-field--with-trailing-icon.mdc-text-field--filled .mdc-floating-label--float-above{max-width:calc(100% / 0.75 - 64px / 0.75)}.mdc-text-field--with-trailing-icon.mdc-text-field--outlined :not(.mdc-notched-outline--notched) .mdc-notched-outline__notch{max-width:calc(100% - 60px)}.mdc-text-field--with-leading-icon.mdc-text-field--with-trailing-icon.mdc-text-field--filled .mdc-floating-label{max-width:calc(100% - 96px)}.mdc-text-field--with-leading-icon.mdc-text-field--with-trailing-icon.mdc-text-field--filled .mdc-floating-label--float-above{max-width:calc(100% / 0.75 - 96px / 0.75)}.mdc-text-field__input:required~.mdc-floating-label::after,.mdc-text-field__input:required~.mdc-notched-outline .mdc-floating-label::after{margin-left:1px;content:"*"}.mdc-text-field-helper-line{display:flex;justify-content:space-between;box-sizing:border-box}.mdc-text-field+.mdc-text-field-helper-line{padding-right:16px;padding-left:16px}.mdc-form-field>.mdc-text-field+label{align-self:flex-start}.mdc-text-field--focused:not(.mdc-text-field--disabled) .mdc-floating-label{color:rgba(98,0,238,.87)}.mdc-text-field--focused .mdc-notched-outline__leading,.mdc-text-field--focused .mdc-notched-outline__notch,.mdc-text-field--focused .mdc-notched-outline__trailing{border-width:2px}.mdc-text-field--focused+.mdc-text-field-helper-line .mdc-text-field-helper-text:not(.mdc-text-field-helper-text--validation-msg){opacity:1}.mdc-text-field--invalid:not(.mdc-text-field--disabled):hover .mdc-line-ripple::before{border-bottom-color:#b00020;border-bottom-color:var(--mdc-theme-error, #b00020)}.mdc-text-field--invalid:not(.mdc-text-field--disabled) .mdc-line-ripple::after{border-bottom-color:#b00020;border-bottom-color:var(--mdc-theme-error, #b00020)}.mdc-text-field--invalid:not(.mdc-text-field--disabled) .mdc-floating-label{color:#b00020;color:var(--mdc-theme-error, #b00020)}.mdc-text-field--invalid:not(.mdc-text-field--disabled).mdc-text-field--invalid+.mdc-text-field-helper-line .mdc-text-field-helper-text--validation-msg{color:#b00020;color:var(--mdc-theme-error, #b00020)}.mdc-text-field--invalid .mdc-text-field__input{caret-color:#b00020;caret-color:var(--mdc-theme-error, #b00020)}.mdc-text-field--invalid:not(.mdc-text-field--disabled) .mdc-text-field__icon--trailing{color:#b00020;color:var(--mdc-theme-error, #b00020)}.mdc-text-field--invalid:not(.mdc-text-field--disabled) .mdc-line-ripple::before{border-bottom-color:#b00020;border-bottom-color:var(--mdc-theme-error, #b00020)}.mdc-text-field--invalid:not(.mdc-text-field--disabled) .mdc-notched-outline__leading,.mdc-text-field--invalid:not(.mdc-text-field--disabled) .mdc-notched-outline__notch,.mdc-text-field--invalid:not(.mdc-text-field--disabled) .mdc-notched-outline__trailing{border-color:#b00020;border-color:var(--mdc-theme-error, #b00020)}.mdc-text-field--invalid:not(.mdc-text-field--disabled):not(.mdc-text-field--focused):hover .mdc-notched-outline .mdc-notched-outline__leading,.mdc-text-field--invalid:not(.mdc-text-field--disabled):not(.mdc-text-field--focused):hover .mdc-notched-outline .mdc-notched-outline__notch,.mdc-text-field--invalid:not(.mdc-text-field--disabled):not(.mdc-text-field--focused):hover .mdc-notched-outline .mdc-notched-outline__trailing{border-color:#b00020;border-color:var(--mdc-theme-error, #b00020)}.mdc-text-field--invalid:not(.mdc-text-field--disabled).mdc-text-field--focused .mdc-notched-outline__leading,.mdc-text-field--invalid:not(.mdc-text-field--disabled).mdc-text-field--focused .mdc-notched-outline__notch,.mdc-text-field--invalid:not(.mdc-text-field--disabled).mdc-text-field--focused .mdc-notched-outline__trailing{border-color:#b00020;border-color:var(--mdc-theme-error, #b00020)}.mdc-text-field--invalid+.mdc-text-field-helper-line .mdc-text-field-helper-text--validation-msg{opacity:1}.mdc-text-field--disabled{pointer-events:none}.mdc-text-field--disabled .mdc-text-field__input{color:rgba(0,0,0,.38)}@media all{.mdc-text-field--disabled .mdc-text-field__input::-webkit-input-placeholder{color:rgba(0,0,0,.38)}.mdc-text-field--disabled .mdc-text-field__input:-ms-input-placeholder{color:rgba(0,0,0,.38)}.mdc-text-field--disabled .mdc-text-field__input::-ms-input-placeholder{color:rgba(0,0,0,.38)}.mdc-text-field--disabled .mdc-text-field__input::placeholder{color:rgba(0,0,0,.38)}}@media all{.mdc-text-field--disabled .mdc-text-field__input:-ms-input-placeholder{color:rgba(0,0,0,.38)}}.mdc-text-field--disabled .mdc-floating-label{color:rgba(0,0,0,.38)}.mdc-text-field--disabled+.mdc-text-field-helper-line .mdc-text-field-helper-text{color:rgba(0,0,0,.38)}.mdc-text-field--disabled .mdc-text-field-character-counter,.mdc-text-field--disabled+.mdc-text-field-helper-line .mdc-text-field-character-counter{color:rgba(0,0,0,.38)}.mdc-text-field--disabled .mdc-text-field__icon--leading{color:rgba(0,0,0,.3)}.mdc-text-field--disabled .mdc-text-field__icon--trailing{color:rgba(0,0,0,.3)}.mdc-text-field--disabled .mdc-text-field__affix--prefix{color:rgba(0,0,0,.38)}.mdc-text-field--disabled .mdc-text-field__affix--suffix{color:rgba(0,0,0,.38)}.mdc-text-field--disabled .mdc-line-ripple::before{border-bottom-color:rgba(0,0,0,.06)}.mdc-text-field--disabled .mdc-notched-outline__leading,.mdc-text-field--disabled .mdc-notched-outline__notch,.mdc-text-field--disabled .mdc-notched-outline__trailing{border-color:rgba(0,0,0,.06)}@media screen and (-ms-high-contrast: active){.mdc-text-field--disabled .mdc-text-field__input::-webkit-input-placeholder{color:GrayText}.mdc-text-field--disabled .mdc-text-field__input:-ms-input-placeholder{color:GrayText}.mdc-text-field--disabled .mdc-text-field__input::-ms-input-placeholder{color:GrayText}.mdc-text-field--disabled .mdc-text-field__input::placeholder{color:GrayText}}@media screen and (-ms-high-contrast: active){.mdc-text-field--disabled .mdc-text-field__input:-ms-input-placeholder{color:GrayText}}@media screen and (-ms-high-contrast: active){.mdc-text-field--disabled .mdc-floating-label{color:GrayText}}@media screen and (-ms-high-contrast: active){.mdc-text-field--disabled+.mdc-text-field-helper-line .mdc-text-field-helper-text{color:GrayText}}@media screen and (-ms-high-contrast: active){.mdc-text-field--disabled .mdc-text-field-character-counter,.mdc-text-field--disabled+.mdc-text-field-helper-line .mdc-text-field-character-counter{color:GrayText}}@media screen and (-ms-high-contrast: active){.mdc-text-field--disabled .mdc-text-field__icon--leading{color:GrayText}}@media screen and (-ms-high-contrast: active){.mdc-text-field--disabled .mdc-text-field__icon--trailing{color:GrayText}}@media screen and (-ms-high-contrast: active){.mdc-text-field--disabled .mdc-text-field__affix--prefix{color:GrayText}}@media screen and (-ms-high-contrast: active){.mdc-text-field--disabled .mdc-text-field__affix--suffix{color:GrayText}}@media screen and (-ms-high-contrast: active){.mdc-text-field--disabled .mdc-line-ripple::before{border-bottom-color:GrayText}}@media screen and (-ms-high-contrast: active){.mdc-text-field--disabled .mdc-notched-outline__leading,.mdc-text-field--disabled .mdc-notched-outline__notch,.mdc-text-field--disabled .mdc-notched-outline__trailing{border-color:GrayText}}.mdc-text-field--disabled .mdc-floating-label{cursor:default}.mdc-text-field--disabled.mdc-text-field--filled{background-color:#fafafa}.mdc-text-field--end-aligned .mdc-text-field__input{text-align:right}[dir=rtl] .mdc-text-field--end-aligned .mdc-text-field__input,.mdc-text-field--end-aligned .mdc-text-field__input[dir=rtl]{text-align:left}[dir=rtl] .mdc-text-field--ltr-text .mdc-text-field__input,[dir=rtl] .mdc-text-field--ltr-text .mdc-text-field__affix,.mdc-text-field--ltr-text[dir=rtl] .mdc-text-field__input,.mdc-text-field--ltr-text[dir=rtl] .mdc-text-field__affix{direction:ltr}[dir=rtl] .mdc-text-field--ltr-text .mdc-text-field__affix--prefix,.mdc-text-field--ltr-text[dir=rtl] .mdc-text-field__affix--prefix{padding-left:0;padding-right:2px}[dir=rtl] .mdc-text-field--ltr-text .mdc-text-field__affix--suffix,.mdc-text-field--ltr-text[dir=rtl] .mdc-text-field__affix--suffix{padding-left:12px;padding-right:0}[dir=rtl] .mdc-text-field--ltr-text .mdc-text-field__icon--leading,.mdc-text-field--ltr-text[dir=rtl] .mdc-text-field__icon--leading{order:1}[dir=rtl] .mdc-text-field--ltr-text .mdc-text-field__affix--suffix,.mdc-text-field--ltr-text[dir=rtl] .mdc-text-field__affix--suffix{order:2}[dir=rtl] .mdc-text-field--ltr-text .mdc-text-field__input,.mdc-text-field--ltr-text[dir=rtl] .mdc-text-field__input{order:3}[dir=rtl] .mdc-text-field--ltr-text .mdc-text-field__affix--prefix,.mdc-text-field--ltr-text[dir=rtl] .mdc-text-field__affix--prefix{order:4}[dir=rtl] .mdc-text-field--ltr-text .mdc-text-field__icon--trailing,.mdc-text-field--ltr-text[dir=rtl] .mdc-text-field__icon--trailing{order:5}[dir=rtl] .mdc-text-field--ltr-text.mdc-text-field--end-aligned .mdc-text-field__input,.mdc-text-field--ltr-text.mdc-text-field--end-aligned[dir=rtl] .mdc-text-field__input{text-align:right}[dir=rtl] .mdc-text-field--ltr-text.mdc-text-field--end-aligned .mdc-text-field__affix--prefix,.mdc-text-field--ltr-text.mdc-text-field--end-aligned[dir=rtl] .mdc-text-field__affix--prefix{padding-right:12px}[dir=rtl] .mdc-text-field--ltr-text.mdc-text-field--end-aligned .mdc-text-field__affix--suffix,.mdc-text-field--ltr-text.mdc-text-field--end-aligned[dir=rtl] .mdc-text-field__affix--suffix{padding-left:2px}:root{--mdc-theme-primary: #6200ee;--mdc-theme-secondary: #018786;--mdc-theme-background: #fff;--mdc-theme-surface: #fff;--mdc-theme-error: #b00020;--mdc-theme-on-primary: #fff;--mdc-theme-on-secondary: #fff;--mdc-theme-on-surface: #000;--mdc-theme-on-error: #fff;--mdc-theme-text-primary-on-background: rgba(0, 0, 0, 0.87);--mdc-theme-text-secondary-on-background: rgba(0, 0, 0, 0.54);--mdc-theme-text-hint-on-background: rgba(0, 0, 0, 0.38);--mdc-theme-text-disabled-on-background: rgba(0, 0, 0, 0.38);--mdc-theme-text-icon-on-background: rgba(0, 0, 0, 0.38);--mdc-theme-text-primary-on-light: rgba(0, 0, 0, 0.87);--mdc-theme-text-secondary-on-light: rgba(0, 0, 0, 0.54);--mdc-theme-text-hint-on-light: rgba(0, 0, 0, 0.38);--mdc-theme-text-disabled-on-light: rgba(0, 0, 0, 0.38);--mdc-theme-text-icon-on-light: rgba(0, 0, 0, 0.38);--mdc-theme-text-primary-on-dark: white;--mdc-theme-text-secondary-on-dark: rgba(255, 255, 255, 0.7);--mdc-theme-text-hint-on-dark: rgba(255, 255, 255, 0.5);--mdc-theme-text-disabled-on-dark: rgba(255, 255, 255, 0.5);--mdc-theme-text-icon-on-dark: rgba(255, 255, 255, 0.5)}.mdc-theme--primary{color:#6200ee !important;color:var(--mdc-theme-primary, #6200ee) !important}.mdc-theme--secondary{color:#018786 !important;color:var(--mdc-theme-secondary, #018786) !important}.mdc-theme--background{background-color:#fff;background-color:var(--mdc-theme-background, #fff)}.mdc-theme--surface{background-color:#fff;background-color:var(--mdc-theme-surface, #fff)}.mdc-theme--error{color:#b00020 !important;color:var(--mdc-theme-error, #b00020) !important}.mdc-theme--on-primary{color:#fff !important;color:var(--mdc-theme-on-primary, #fff) !important}.mdc-theme--on-secondary{color:#fff !important;color:var(--mdc-theme-on-secondary, #fff) !important}.mdc-theme--on-surface{color:#000 !important;color:var(--mdc-theme-on-surface, #000) !important}.mdc-theme--on-error{color:#fff !important;color:var(--mdc-theme-on-error, #fff) !important}.mdc-theme--text-primary-on-background{color:rgba(0,0,0,.87) !important;color:var(--mdc-theme-text-primary-on-background, rgba(0, 0, 0, 0.87)) !important}.mdc-theme--text-secondary-on-background{color:rgba(0,0,0,.54) !important;color:var(--mdc-theme-text-secondary-on-background, rgba(0, 0, 0, 0.54)) !important}.mdc-theme--text-hint-on-background{color:rgba(0,0,0,.38) !important;color:var(--mdc-theme-text-hint-on-background, rgba(0, 0, 0, 0.38)) !important}.mdc-theme--text-disabled-on-background{color:rgba(0,0,0,.38) !important;color:var(--mdc-theme-text-disabled-on-background, rgba(0, 0, 0, 0.38)) !important}.mdc-theme--text-icon-on-background{color:rgba(0,0,0,.38) !important;color:var(--mdc-theme-text-icon-on-background, rgba(0, 0, 0, 0.38)) !important}.mdc-theme--text-primary-on-light{color:rgba(0,0,0,.87) !important;color:var(--mdc-theme-text-primary-on-light, rgba(0, 0, 0, 0.87)) !important}.mdc-theme--text-secondary-on-light{color:rgba(0,0,0,.54) !important;color:var(--mdc-theme-text-secondary-on-light, rgba(0, 0, 0, 0.54)) !important}.mdc-theme--text-hint-on-light{color:rgba(0,0,0,.38) !important;color:var(--mdc-theme-text-hint-on-light, rgba(0, 0, 0, 0.38)) !important}.mdc-theme--text-disabled-on-light{color:rgba(0,0,0,.38) !important;color:var(--mdc-theme-text-disabled-on-light, rgba(0, 0, 0, 0.38)) !important}.mdc-theme--text-icon-on-light{color:rgba(0,0,0,.38) !important;color:var(--mdc-theme-text-icon-on-light, rgba(0, 0, 0, 0.38)) !important}.mdc-theme--text-primary-on-dark{color:#fff !important;color:var(--mdc-theme-text-primary-on-dark, white) !important}.mdc-theme--text-secondary-on-dark{color:rgba(255,255,255,.7) !important;color:var(--mdc-theme-text-secondary-on-dark, rgba(255, 255, 255, 0.7)) !important}.mdc-theme--text-hint-on-dark{color:rgba(255,255,255,.5) !important;color:var(--mdc-theme-text-hint-on-dark, rgba(255, 255, 255, 0.5)) !important}.mdc-theme--text-disabled-on-dark{color:rgba(255,255,255,.5) !important;color:var(--mdc-theme-text-disabled-on-dark, rgba(255, 255, 255, 0.5)) !important}.mdc-theme--text-icon-on-dark{color:rgba(255,255,255,.5) !important;color:var(--mdc-theme-text-icon-on-dark, rgba(255, 255, 255, 0.5)) !important}.mdc-theme--primary-bg{background-color:#6200ee !important;background-color:var(--mdc-theme-primary, #6200ee) !important}.mdc-theme--secondary-bg{background-color:#018786 !important;background-color:var(--mdc-theme-secondary, #018786) !important}.mdc-top-app-bar{background-color:#6200ee;background-color:var(--mdc-theme-primary, #6200ee);color:#fff;display:flex;position:fixed;flex-direction:column;justify-content:space-between;box-sizing:border-box;width:100%;z-index:4}.mdc-top-app-bar .mdc-top-app-bar__action-item,.mdc-top-app-bar .mdc-top-app-bar__navigation-icon{color:#fff;color:var(--mdc-theme-on-primary, #fff)}.mdc-top-app-bar .mdc-top-app-bar__action-item::before,.mdc-top-app-bar .mdc-top-app-bar__action-item::after,.mdc-top-app-bar .mdc-top-app-bar__navigation-icon::before,.mdc-top-app-bar .mdc-top-app-bar__navigation-icon::after{background-color:#fff;background-color:var(--mdc-theme-on-primary, #fff)}.mdc-top-app-bar .mdc-top-app-bar__action-item:hover::before,.mdc-top-app-bar .mdc-top-app-bar__navigation-icon:hover::before{opacity:.08}.mdc-top-app-bar .mdc-top-app-bar__action-item.mdc-ripple-upgraded--background-focused::before,.mdc-top-app-bar .mdc-top-app-bar__action-item:not(.mdc-ripple-upgraded):focus::before,.mdc-top-app-bar .mdc-top-app-bar__navigation-icon.mdc-ripple-upgraded--background-focused::before,.mdc-top-app-bar .mdc-top-app-bar__navigation-icon:not(.mdc-ripple-upgraded):focus::before{transition-duration:75ms;opacity:.24}.mdc-top-app-bar .mdc-top-app-bar__action-item:not(.mdc-ripple-upgraded)::after,.mdc-top-app-bar .mdc-top-app-bar__navigation-icon:not(.mdc-ripple-upgraded)::after{transition:opacity 150ms linear}.mdc-top-app-bar .mdc-top-app-bar__action-item:not(.mdc-ripple-upgraded):active::after,.mdc-top-app-bar .mdc-top-app-bar__navigation-icon:not(.mdc-ripple-upgraded):active::after{transition-duration:75ms;opacity:.24}.mdc-top-app-bar .mdc-top-app-bar__action-item.mdc-ripple-upgraded,.mdc-top-app-bar .mdc-top-app-bar__navigation-icon.mdc-ripple-upgraded{--mdc-ripple-fg-opacity: 0.24}.mdc-top-app-bar__row{display:flex;position:relative;box-sizing:border-box;width:100%;height:64px}.mdc-top-app-bar__section{display:inline-flex;flex:1 1 auto;align-items:center;min-width:0;padding:8px 12px;z-index:1}.mdc-top-app-bar__section--align-start{justify-content:flex-start;order:-1}.mdc-top-app-bar__section--align-end{justify-content:flex-end;order:1}.mdc-top-app-bar__title{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-headline6-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:1.25rem;font-size:var(--mdc-typography-headline6-font-size, 1.25rem);line-height:2rem;line-height:var(--mdc-typography-headline6-line-height, 2rem);font-weight:500;font-weight:var(--mdc-typography-headline6-font-weight, 500);letter-spacing:.0125em;letter-spacing:var(--mdc-typography-headline6-letter-spacing, 0.0125em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-headline6-text-decoration, inherit);text-decoration:var(--mdc-typography-headline6-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-headline6-text-transform, inherit);padding-left:20px;padding-right:0;text-overflow:ellipsis;white-space:nowrap;overflow:hidden;z-index:1}[dir=rtl] .mdc-top-app-bar__title,.mdc-top-app-bar__title[dir=rtl]{padding-left:0;padding-right:20px}.mdc-top-app-bar--short-collapsed{border-radius:0 0 24px 0}[dir=rtl] .mdc-top-app-bar--short-collapsed,.mdc-top-app-bar--short-collapsed[dir=rtl]{border-radius:0 0 0 24px}.mdc-top-app-bar--short{top:0;right:auto;left:0;width:100%;transition:width 250ms cubic-bezier(0.4, 0, 0.2, 1)}[dir=rtl] .mdc-top-app-bar--short,.mdc-top-app-bar--short[dir=rtl]{right:0;left:auto}.mdc-top-app-bar--short .mdc-top-app-bar__row{height:56px}.mdc-top-app-bar--short .mdc-top-app-bar__section{padding:4px}.mdc-top-app-bar--short .mdc-top-app-bar__title{transition:opacity 200ms cubic-bezier(0.4, 0, 0.2, 1);opacity:1}.mdc-top-app-bar--short-collapsed{box-shadow:0px 2px 4px -1px rgba(0, 0, 0, 0.2),0px 4px 5px 0px rgba(0, 0, 0, 0.14),0px 1px 10px 0px rgba(0,0,0,.12);width:56px;transition:width 300ms cubic-bezier(0.4, 0, 0.2, 1)}.mdc-top-app-bar--short-collapsed .mdc-top-app-bar__title{display:none}.mdc-top-app-bar--short-collapsed .mdc-top-app-bar__action-item{transition:padding 150ms cubic-bezier(0.4, 0, 0.2, 1)}.mdc-top-app-bar--short-collapsed.mdc-top-app-bar--short-has-action-item{width:112px}.mdc-top-app-bar--short-collapsed.mdc-top-app-bar--short-has-action-item .mdc-top-app-bar__section--align-end{padding-left:0;padding-right:12px}[dir=rtl] .mdc-top-app-bar--short-collapsed.mdc-top-app-bar--short-has-action-item .mdc-top-app-bar__section--align-end,.mdc-top-app-bar--short-collapsed.mdc-top-app-bar--short-has-action-item .mdc-top-app-bar__section--align-end[dir=rtl]{padding-left:12px;padding-right:0}.mdc-top-app-bar--dense .mdc-top-app-bar__row{height:48px}.mdc-top-app-bar--dense .mdc-top-app-bar__section{padding:0 4px}.mdc-top-app-bar--dense .mdc-top-app-bar__title{padding-left:12px;padding-right:0}[dir=rtl] .mdc-top-app-bar--dense .mdc-top-app-bar__title,.mdc-top-app-bar--dense .mdc-top-app-bar__title[dir=rtl]{padding-left:0;padding-right:12px}.mdc-top-app-bar--prominent .mdc-top-app-bar__row{height:128px}.mdc-top-app-bar--prominent .mdc-top-app-bar__title{align-self:flex-end;padding-bottom:2px}.mdc-top-app-bar--prominent .mdc-top-app-bar__action-item,.mdc-top-app-bar--prominent .mdc-top-app-bar__navigation-icon{align-self:flex-start}.mdc-top-app-bar--fixed{transition:box-shadow 200ms linear}.mdc-top-app-bar--fixed-scrolled{box-shadow:0px 2px 4px -1px rgba(0, 0, 0, 0.2),0px 4px 5px 0px rgba(0, 0, 0, 0.14),0px 1px 10px 0px rgba(0,0,0,.12);transition:box-shadow 200ms linear}.mdc-top-app-bar--dense.mdc-top-app-bar--prominent .mdc-top-app-bar__row{height:96px}.mdc-top-app-bar--dense.mdc-top-app-bar--prominent .mdc-top-app-bar__section{padding:0 12px}.mdc-top-app-bar--dense.mdc-top-app-bar--prominent .mdc-top-app-bar__title{padding-left:20px;padding-right:0;padding-bottom:9px}[dir=rtl] .mdc-top-app-bar--dense.mdc-top-app-bar--prominent .mdc-top-app-bar__title,.mdc-top-app-bar--dense.mdc-top-app-bar--prominent .mdc-top-app-bar__title[dir=rtl]{padding-left:0;padding-right:20px}.mdc-top-app-bar--fixed-adjust{padding-top:64px}.mdc-top-app-bar--dense-fixed-adjust{padding-top:48px}.mdc-top-app-bar--short-fixed-adjust{padding-top:56px}.mdc-top-app-bar--prominent-fixed-adjust{padding-top:128px}.mdc-top-app-bar--dense-prominent-fixed-adjust{padding-top:96px}@media(max-width: 599px){.mdc-top-app-bar__row{height:56px}.mdc-top-app-bar__section{padding:4px}.mdc-top-app-bar--short{transition:width 200ms cubic-bezier(0.4, 0, 0.2, 1)}.mdc-top-app-bar--short-collapsed{transition:width 250ms cubic-bezier(0.4, 0, 0.2, 1)}.mdc-top-app-bar--short-collapsed .mdc-top-app-bar__section--align-end{padding-left:0;padding-right:12px}[dir=rtl] .mdc-top-app-bar--short-collapsed .mdc-top-app-bar__section--align-end,.mdc-top-app-bar--short-collapsed .mdc-top-app-bar__section--align-end[dir=rtl]{padding-left:12px;padding-right:0}.mdc-top-app-bar--prominent .mdc-top-app-bar__title{padding-bottom:6px}.mdc-top-app-bar--fixed-adjust{padding-top:56px}}.mdc-typography{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-font-family, Roboto, sans-serif)}.mdc-typography--headline1{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-headline1-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:6rem;font-size:var(--mdc-typography-headline1-font-size, 6rem);line-height:6rem;line-height:var(--mdc-typography-headline1-line-height, 6rem);font-weight:300;font-weight:var(--mdc-typography-headline1-font-weight, 300);letter-spacing:-0.015625em;letter-spacing:var(--mdc-typography-headline1-letter-spacing, -0.015625em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-headline1-text-decoration, inherit);text-decoration:var(--mdc-typography-headline1-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-headline1-text-transform, inherit)}.mdc-typography--headline2{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-headline2-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:3.75rem;font-size:var(--mdc-typography-headline2-font-size, 3.75rem);line-height:3.75rem;line-height:var(--mdc-typography-headline2-line-height, 3.75rem);font-weight:300;font-weight:var(--mdc-typography-headline2-font-weight, 300);letter-spacing:-0.0083333333em;letter-spacing:var(--mdc-typography-headline2-letter-spacing, -0.0083333333em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-headline2-text-decoration, inherit);text-decoration:var(--mdc-typography-headline2-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-headline2-text-transform, inherit)}.mdc-typography--headline3{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-headline3-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:3rem;font-size:var(--mdc-typography-headline3-font-size, 3rem);line-height:3.125rem;line-height:var(--mdc-typography-headline3-line-height, 3.125rem);font-weight:400;font-weight:var(--mdc-typography-headline3-font-weight, 400);letter-spacing:normal;letter-spacing:var(--mdc-typography-headline3-letter-spacing, normal);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-headline3-text-decoration, inherit);text-decoration:var(--mdc-typography-headline3-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-headline3-text-transform, inherit)}.mdc-typography--headline4{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-headline4-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:2.125rem;font-size:var(--mdc-typography-headline4-font-size, 2.125rem);line-height:2.5rem;line-height:var(--mdc-typography-headline4-line-height, 2.5rem);font-weight:400;font-weight:var(--mdc-typography-headline4-font-weight, 400);letter-spacing:.0073529412em;letter-spacing:var(--mdc-typography-headline4-letter-spacing, 0.0073529412em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-headline4-text-decoration, inherit);text-decoration:var(--mdc-typography-headline4-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-headline4-text-transform, inherit)}.mdc-typography--headline5{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-headline5-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:1.5rem;font-size:var(--mdc-typography-headline5-font-size, 1.5rem);line-height:2rem;line-height:var(--mdc-typography-headline5-line-height, 2rem);font-weight:400;font-weight:var(--mdc-typography-headline5-font-weight, 400);letter-spacing:normal;letter-spacing:var(--mdc-typography-headline5-letter-spacing, normal);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-headline5-text-decoration, inherit);text-decoration:var(--mdc-typography-headline5-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-headline5-text-transform, inherit)}.mdc-typography--headline6{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-headline6-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:1.25rem;font-size:var(--mdc-typography-headline6-font-size, 1.25rem);line-height:2rem;line-height:var(--mdc-typography-headline6-line-height, 2rem);font-weight:500;font-weight:var(--mdc-typography-headline6-font-weight, 500);letter-spacing:.0125em;letter-spacing:var(--mdc-typography-headline6-letter-spacing, 0.0125em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-headline6-text-decoration, inherit);text-decoration:var(--mdc-typography-headline6-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-headline6-text-transform, inherit)}.mdc-typography--subtitle1{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-subtitle1-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:1rem;font-size:var(--mdc-typography-subtitle1-font-size, 1rem);line-height:1.75rem;line-height:var(--mdc-typography-subtitle1-line-height, 1.75rem);font-weight:400;font-weight:var(--mdc-typography-subtitle1-font-weight, 400);letter-spacing:.009375em;letter-spacing:var(--mdc-typography-subtitle1-letter-spacing, 0.009375em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-subtitle1-text-decoration, inherit);text-decoration:var(--mdc-typography-subtitle1-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-subtitle1-text-transform, inherit)}.mdc-typography--subtitle2{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-subtitle2-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:.875rem;font-size:var(--mdc-typography-subtitle2-font-size, 0.875rem);line-height:1.375rem;line-height:var(--mdc-typography-subtitle2-line-height, 1.375rem);font-weight:500;font-weight:var(--mdc-typography-subtitle2-font-weight, 500);letter-spacing:.0071428571em;letter-spacing:var(--mdc-typography-subtitle2-letter-spacing, 0.0071428571em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-subtitle2-text-decoration, inherit);text-decoration:var(--mdc-typography-subtitle2-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-subtitle2-text-transform, inherit)}.mdc-typography--body1{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-body1-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:1rem;font-size:var(--mdc-typography-body1-font-size, 1rem);line-height:1.5rem;line-height:var(--mdc-typography-body1-line-height, 1.5rem);font-weight:400;font-weight:var(--mdc-typography-body1-font-weight, 400);letter-spacing:.03125em;letter-spacing:var(--mdc-typography-body1-letter-spacing, 0.03125em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-body1-text-decoration, inherit);text-decoration:var(--mdc-typography-body1-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-body1-text-transform, inherit)}.mdc-typography--body2{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-body2-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:.875rem;font-size:var(--mdc-typography-body2-font-size, 0.875rem);line-height:1.25rem;line-height:var(--mdc-typography-body2-line-height, 1.25rem);font-weight:400;font-weight:var(--mdc-typography-body2-font-weight, 400);letter-spacing:.0178571429em;letter-spacing:var(--mdc-typography-body2-letter-spacing, 0.0178571429em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-body2-text-decoration, inherit);text-decoration:var(--mdc-typography-body2-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-body2-text-transform, inherit)}.mdc-typography--caption{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-caption-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:.75rem;font-size:var(--mdc-typography-caption-font-size, 0.75rem);line-height:1.25rem;line-height:var(--mdc-typography-caption-line-height, 1.25rem);font-weight:400;font-weight:var(--mdc-typography-caption-font-weight, 400);letter-spacing:.0333333333em;letter-spacing:var(--mdc-typography-caption-letter-spacing, 0.0333333333em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-caption-text-decoration, inherit);text-decoration:var(--mdc-typography-caption-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-caption-text-transform, inherit)}.mdc-typography--button{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-button-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:.875rem;font-size:var(--mdc-typography-button-font-size, 0.875rem);line-height:2.25rem;line-height:var(--mdc-typography-button-line-height, 2.25rem);font-weight:500;font-weight:var(--mdc-typography-button-font-weight, 500);letter-spacing:.0892857143em;letter-spacing:var(--mdc-typography-button-letter-spacing, 0.0892857143em);text-decoration:none;-webkit-text-decoration:var(--mdc-typography-button-text-decoration, none);text-decoration:var(--mdc-typography-button-text-decoration, none);text-transform:uppercase;text-transform:var(--mdc-typography-button-text-transform, uppercase)}.mdc-typography--overline{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-overline-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:.75rem;font-size:var(--mdc-typography-overline-font-size, 0.75rem);line-height:2rem;line-height:var(--mdc-typography-overline-line-height, 2rem);font-weight:500;font-weight:var(--mdc-typography-overline-font-weight, 500);letter-spacing:.1666666667em;letter-spacing:var(--mdc-typography-overline-letter-spacing, 0.1666666667em);text-decoration:none;-webkit-text-decoration:var(--mdc-typography-overline-text-decoration, none);text-decoration:var(--mdc-typography-overline-text-decoration, none);text-transform:uppercase;text-transform:var(--mdc-typography-overline-text-transform, uppercase)} - -/*# sourceMappingURL=material-components-web.min.css.map*/ \ No newline at end of file diff --git a/backend/src/main/resources/static/img/404.jpg b/backend/src/main/resources/static/img/404.jpg deleted file mode 100644 index ab668e872..000000000 Binary files a/backend/src/main/resources/static/img/404.jpg and /dev/null differ diff --git a/backend/src/main/resources/static/img/500.gif b/backend/src/main/resources/static/img/500.gif deleted file mode 100644 index bd74b3418..000000000 Binary files a/backend/src/main/resources/static/img/500.gif and /dev/null differ diff --git a/backend/src/main/resources/static/img/GitHub_Logo.png b/backend/src/main/resources/static/img/GitHub_Logo.png deleted file mode 100644 index e03d8dd8b..000000000 Binary files a/backend/src/main/resources/static/img/GitHub_Logo.png and /dev/null differ diff --git a/backend/src/main/resources/static/img/enbarsskar.jpg b/backend/src/main/resources/static/img/enbarsskar.jpg deleted file mode 100644 index 2a9892329..000000000 Binary files a/backend/src/main/resources/static/img/enbarsskar.jpg and /dev/null differ diff --git a/backend/src/main/resources/static/img/favicon.ico b/backend/src/main/resources/static/img/favicon.ico deleted file mode 100644 index c873e6a04..000000000 Binary files a/backend/src/main/resources/static/img/favicon.ico and /dev/null differ diff --git a/backend/src/main/resources/static/js/mcw.min.js b/backend/src/main/resources/static/js/mcw.min.js deleted file mode 100644 index 4d870d86a..000000000 --- a/backend/src/main/resources/static/js/mcw.min.js +++ /dev/null @@ -1,15878 +0,0 @@ -!(function(t, e) { - "object" == typeof exports && "object" == typeof module - ? (module.exports = e()) - : "function" == typeof define && define.amd - ? define([], e) - : "object" == typeof exports - ? (exports.mdc = e()) - : (t.mdc = e()); -})(this, function() { - return ( - (i = {}), - (r.m = n = [ - function(t, e, n) { - "use strict"; - Object.defineProperty(e, "__esModule", { value: !0 }); - var i = - (Object.defineProperty(r, "cssClasses", { - get: function() { - return {}; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(r, "strings", { - get: function() { - return {}; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(r, "numbers", { - get: function() { - return {}; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(r, "defaultAdapter", { - get: function() { - return {}; - }, - enumerable: !0, - configurable: !0 - }), - (r.prototype.init = function() {}), - (r.prototype.destroy = function() {}), - r); - function r(t) { - void 0 === t && (t = {}), (this.adapter_ = t); - } - (e.MDCFoundation = i), (e.default = i); - }, - function(t, e, n) { - "use strict"; - var i = - (this && this.__read) || - function(t, e) { - var n = "function" == typeof Symbol && t[Symbol.iterator]; - if (!n) return t; - var i, - r, - o = n.call(t), - s = []; - try { - for (; (void 0 === e || 0 < e--) && !(i = o.next()).done; ) - s.push(i.value); - } catch (t) { - r = { error: t }; - } finally { - try { - i && !i.done && (n = o.return) && n.call(o); - } finally { - if (r) throw r.error; - } - } - return s; - }, - r = - (this && this.__spread) || - function() { - for (var t = [], e = 0; e < arguments.length; e++) - t = t.concat(i(arguments[e])); - return t; - }; - Object.defineProperty(e, "__esModule", { value: !0 }); - var o = n(0), - s = - ((a.attachTo = function(t) { - return new a(t, new o.MDCFoundation({})); - }), - (a.prototype.initialize = function() { - for (var t = [], e = 0; e < arguments.length; e++) - t[e] = arguments[e]; - }), - (a.prototype.getDefaultFoundation = function() { - throw new Error( - "Subclasses must override getDefaultFoundation to return a properly configured foundation class" - ); - }), - (a.prototype.initialSyncWithDOM = function() {}), - (a.prototype.destroy = function() { - this.foundation_.destroy(); - }), - (a.prototype.listen = function(t, e, n) { - this.root_.addEventListener(t, e, n); - }), - (a.prototype.unlisten = function(t, e, n) { - this.root_.removeEventListener(t, e, n); - }), - (a.prototype.emit = function(t, e, n) { - var i; - void 0 === n && (n = !1), - "function" == typeof CustomEvent - ? (i = new CustomEvent(t, { bubbles: n, detail: e })) - : (i = document.createEvent("CustomEvent")).initCustomEvent( - t, - n, - !1, - e - ), - this.root_.dispatchEvent(i); - }), - a); - function a(t, e) { - for (var n = [], i = 2; i < arguments.length; i++) - n[i - 2] = arguments[i]; - (this.root_ = t), - this.initialize.apply(this, r(n)), - (this.foundation_ = void 0 === e ? this.getDefaultFoundation() : e), - this.foundation_.init(), - this.initialSyncWithDOM(); - } - (e.MDCComponent = s), (e.default = s); - }, - function(t, e, n) { - "use strict"; - function i(t, e) { - return ( - t.matches || - t.webkitMatchesSelector || - t.msMatchesSelector - ).call(t, e); - } - Object.defineProperty(e, "__esModule", { value: !0 }), - (e.closest = function(t, e) { - if (t.closest) return t.closest(e); - for (var n = t; n; ) { - if (i(n, e)) return n; - n = n.parentElement; - } - return null; - }), - (e.matches = i), - (e.estimateScrollWidth = function(t) { - var e = t; - if (null !== e.offsetParent) return e.scrollWidth; - var n = e.cloneNode(!0); - n.style.setProperty("position", "absolute"), - n.style.setProperty("transform", "translate(-9999px, -9999px)"), - document.documentElement.appendChild(n); - var i = n.scrollWidth; - return document.documentElement.removeChild(n), i; - }); - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }), - o = - (this && this.__importStar) || - function(t) { - if (t && t.__esModule) return t; - var e = {}; - if (null != t) - for (var n in t) - Object.hasOwnProperty.call(t, n) && (e[n] = t[n]); - return (e.default = t), e; - }; - Object.defineProperty(e, "__esModule", { value: !0 }); - var s, - a = n(1), - c = n(5), - u = n(2), - l = n(4), - d = o(n(16)), - p = - ((s = a.MDCComponent), - r(_, s), - (_.attachTo = function(t, e) { - void 0 === e && (e = { isUnbounded: void 0 }); - var n = new _(t); - return ( - void 0 !== e.isUnbounded && (n.unbounded = e.isUnbounded), n - ); - }), - (_.createAdapter = function(n) { - return { - addClass: function(t) { - return n.root_.classList.add(t); - }, - browserSupportsCssVars: function() { - return d.supportsCssVariables(window); - }, - computeBoundingRect: function() { - return n.root_.getBoundingClientRect(); - }, - containsEventTarget: function(t) { - return n.root_.contains(t); - }, - deregisterDocumentInteractionHandler: function(t, e) { - return document.documentElement.removeEventListener( - t, - e, - c.applyPassive() - ); - }, - deregisterInteractionHandler: function(t, e) { - return n.root_.removeEventListener(t, e, c.applyPassive()); - }, - deregisterResizeHandler: function(t) { - return window.removeEventListener("resize", t); - }, - getWindowPageOffset: function() { - return { x: window.pageXOffset, y: window.pageYOffset }; - }, - isSurfaceActive: function() { - return u.matches(n.root_, ":active"); - }, - isSurfaceDisabled: function() { - return Boolean(n.disabled); - }, - isUnbounded: function() { - return Boolean(n.unbounded); - }, - registerDocumentInteractionHandler: function(t, e) { - return document.documentElement.addEventListener( - t, - e, - c.applyPassive() - ); - }, - registerInteractionHandler: function(t, e) { - return n.root_.addEventListener(t, e, c.applyPassive()); - }, - registerResizeHandler: function(t) { - return window.addEventListener("resize", t); - }, - removeClass: function(t) { - return n.root_.classList.remove(t); - }, - updateCssVariable: function(t, e) { - return n.root_.style.setProperty(t, e); - } - }; - }), - Object.defineProperty(_.prototype, "unbounded", { - get: function() { - return Boolean(this.unbounded_); - }, - set: function(t) { - (this.unbounded_ = Boolean(t)), this.setUnbounded_(); - }, - enumerable: !0, - configurable: !0 - }), - (_.prototype.activate = function() { - this.foundation_.activate(); - }), - (_.prototype.deactivate = function() { - this.foundation_.deactivate(); - }), - (_.prototype.layout = function() { - this.foundation_.layout(); - }), - (_.prototype.getDefaultFoundation = function() { - return new l.MDCRippleFoundation(_.createAdapter(this)); - }), - (_.prototype.initialSyncWithDOM = function() { - var t = this.root_; - this.unbounded = "mdcRippleIsUnbounded" in t.dataset; - }), - (_.prototype.setUnbounded_ = function() { - this.foundation_.setUnbounded(Boolean(this.unbounded_)); - }), - _); - function _() { - var t = (null !== s && s.apply(this, arguments)) || this; - return (t.disabled = !1), t; - } - e.MDCRipple = p; - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }), - o = - (this && this.__assign) || - function() { - return (o = - Object.assign || - function(t) { - for (var e, n = 1, i = arguments.length; n < i; n++) - for (var r in (e = arguments[n])) - Object.prototype.hasOwnProperty.call(e, r) && - (t[r] = e[r]); - return t; - }).apply(this, arguments); - }; - Object.defineProperty(e, "__esModule", { value: !0 }); - var s, - a = n(0), - c = n(40), - u = n(16), - l = ["touchstart", "pointerdown", "mousedown", "keydown"], - d = ["touchend", "pointerup", "mouseup", "contextmenu"], - p = [], - _ = - ((s = a.MDCFoundation), - r(f, s), - Object.defineProperty(f, "cssClasses", { - get: function() { - return c.cssClasses; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(f, "strings", { - get: function() { - return c.strings; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(f, "numbers", { - get: function() { - return c.numbers; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(f, "defaultAdapter", { - get: function() { - return { - addClass: function() {}, - browserSupportsCssVars: function() { - return !0; - }, - computeBoundingRect: function() { - return { - top: 0, - right: 0, - bottom: 0, - left: 0, - width: 0, - height: 0 - }; - }, - containsEventTarget: function() { - return !0; - }, - deregisterDocumentInteractionHandler: function() {}, - deregisterInteractionHandler: function() {}, - deregisterResizeHandler: function() {}, - getWindowPageOffset: function() { - return { x: 0, y: 0 }; - }, - isSurfaceActive: function() { - return !0; - }, - isSurfaceDisabled: function() { - return !0; - }, - isUnbounded: function() { - return !0; - }, - registerDocumentInteractionHandler: function() {}, - registerInteractionHandler: function() {}, - registerResizeHandler: function() {}, - removeClass: function() {}, - updateCssVariable: function() {} - }; - }, - enumerable: !0, - configurable: !0 - }), - (f.prototype.init = function() { - var t = this, - e = this.supportsPressRipple_(); - if ((this.registerRootHandlers_(e), e)) { - var n = f.cssClasses, - i = n.ROOT, - r = n.UNBOUNDED; - requestAnimationFrame(function() { - t.adapter_.addClass(i), - t.adapter_.isUnbounded() && - (t.adapter_.addClass(r), t.layoutInternal_()); - }); - } - }), - (f.prototype.destroy = function() { - var t = this; - if (this.supportsPressRipple_()) { - this.activationTimer_ && - (clearTimeout(this.activationTimer_), - (this.activationTimer_ = 0), - this.adapter_.removeClass(f.cssClasses.FG_ACTIVATION)), - this.fgDeactivationRemovalTimer_ && - (clearTimeout(this.fgDeactivationRemovalTimer_), - (this.fgDeactivationRemovalTimer_ = 0), - this.adapter_.removeClass(f.cssClasses.FG_DEACTIVATION)); - var e = f.cssClasses, - n = e.ROOT, - i = e.UNBOUNDED; - requestAnimationFrame(function() { - t.adapter_.removeClass(n), - t.adapter_.removeClass(i), - t.removeCssVars_(); - }); - } - this.deregisterRootHandlers_(), - this.deregisterDeactivationHandlers_(); - }), - (f.prototype.activate = function(t) { - this.activate_(t); - }), - (f.prototype.deactivate = function() { - this.deactivate_(); - }), - (f.prototype.layout = function() { - var t = this; - this.layoutFrame_ && cancelAnimationFrame(this.layoutFrame_), - (this.layoutFrame_ = requestAnimationFrame(function() { - t.layoutInternal_(), (t.layoutFrame_ = 0); - })); - }), - (f.prototype.setUnbounded = function(t) { - var e = f.cssClasses.UNBOUNDED; - t ? this.adapter_.addClass(e) : this.adapter_.removeClass(e); - }), - (f.prototype.handleFocus = function() { - var t = this; - requestAnimationFrame(function() { - return t.adapter_.addClass(f.cssClasses.BG_FOCUSED); - }); - }), - (f.prototype.handleBlur = function() { - var t = this; - requestAnimationFrame(function() { - return t.adapter_.removeClass(f.cssClasses.BG_FOCUSED); - }); - }), - (f.prototype.supportsPressRipple_ = function() { - return this.adapter_.browserSupportsCssVars(); - }), - (f.prototype.defaultActivationState_ = function() { - return { - activationEvent: void 0, - hasDeactivationUXRun: !1, - isActivated: !1, - isProgrammatic: !1, - wasActivatedByPointer: !1, - wasElementMadeActive: !1 - }; - }), - (f.prototype.registerRootHandlers_ = function(t) { - var e = this; - t && - (l.forEach(function(t) { - e.adapter_.registerInteractionHandler(t, e.activateHandler_); - }), - this.adapter_.isUnbounded() && - this.adapter_.registerResizeHandler(this.resizeHandler_)), - this.adapter_.registerInteractionHandler( - "focus", - this.focusHandler_ - ), - this.adapter_.registerInteractionHandler( - "blur", - this.blurHandler_ - ); - }), - (f.prototype.registerDeactivationHandlers_ = function(t) { - var e = this; - "keydown" === t.type - ? this.adapter_.registerInteractionHandler( - "keyup", - this.deactivateHandler_ - ) - : d.forEach(function(t) { - e.adapter_.registerDocumentInteractionHandler( - t, - e.deactivateHandler_ - ); - }); - }), - (f.prototype.deregisterRootHandlers_ = function() { - var e = this; - l.forEach(function(t) { - e.adapter_.deregisterInteractionHandler(t, e.activateHandler_); - }), - this.adapter_.deregisterInteractionHandler( - "focus", - this.focusHandler_ - ), - this.adapter_.deregisterInteractionHandler( - "blur", - this.blurHandler_ - ), - this.adapter_.isUnbounded() && - this.adapter_.deregisterResizeHandler(this.resizeHandler_); - }), - (f.prototype.deregisterDeactivationHandlers_ = function() { - var e = this; - this.adapter_.deregisterInteractionHandler( - "keyup", - this.deactivateHandler_ - ), - d.forEach(function(t) { - e.adapter_.deregisterDocumentInteractionHandler( - t, - e.deactivateHandler_ - ); - }); - }), - (f.prototype.removeCssVars_ = function() { - var e = this, - n = f.strings; - Object.keys(n).forEach(function(t) { - 0 === t.indexOf("VAR_") && - e.adapter_.updateCssVariable(n[t], null); - }); - }), - (f.prototype.activate_ = function(t) { - var e = this; - if (!this.adapter_.isSurfaceDisabled()) { - var n = this.activationState_; - if (!n.isActivated) { - var i = this.previousActivationEvent_; - (i && void 0 !== t && i.type !== t.type) || - ((n.isActivated = !0), - (n.isProgrammatic = void 0 === t), - (n.activationEvent = t), - (n.wasActivatedByPointer = - !n.isProgrammatic && - void 0 !== t && - ("mousedown" === t.type || - "touchstart" === t.type || - "pointerdown" === t.type)), - void 0 !== t && - 0 < p.length && - p.some(function(t) { - return e.adapter_.containsEventTarget(t); - }) - ? this.resetActivationState_() - : (void 0 !== t && - (p.push(t.target), - this.registerDeactivationHandlers_(t)), - (n.wasElementMadeActive = this.checkElementMadeActive_( - t - )), - n.wasElementMadeActive && this.animateActivation_(), - requestAnimationFrame(function() { - (p = []), - n.wasElementMadeActive || - void 0 === t || - (" " !== t.key && 32 !== t.keyCode) || - ((n.wasElementMadeActive = e.checkElementMadeActive_( - t - )), - n.wasElementMadeActive && e.animateActivation_()), - n.wasElementMadeActive || - (e.activationState_ = e.defaultActivationState_()); - }))); - } - } - }), - (f.prototype.checkElementMadeActive_ = function(t) { - return ( - void 0 === t || - "keydown" !== t.type || - this.adapter_.isSurfaceActive() - ); - }), - (f.prototype.animateActivation_ = function() { - var t = this, - e = f.strings, - n = e.VAR_FG_TRANSLATE_START, - i = e.VAR_FG_TRANSLATE_END, - r = f.cssClasses, - o = r.FG_DEACTIVATION, - s = r.FG_ACTIVATION, - a = f.numbers.DEACTIVATION_TIMEOUT_MS; - this.layoutInternal_(); - var c = "", - u = ""; - if (!this.adapter_.isUnbounded()) { - var l = this.getFgTranslationCoordinates_(), - d = l.startPoint, - p = l.endPoint; - (c = d.x + "px, " + d.y + "px"), - (u = p.x + "px, " + p.y + "px"); - } - this.adapter_.updateCssVariable(n, c), - this.adapter_.updateCssVariable(i, u), - clearTimeout(this.activationTimer_), - clearTimeout(this.fgDeactivationRemovalTimer_), - this.rmBoundedActivationClasses_(), - this.adapter_.removeClass(o), - this.adapter_.computeBoundingRect(), - this.adapter_.addClass(s), - (this.activationTimer_ = setTimeout(function() { - return t.activationTimerCallback_(); - }, a)); - }), - (f.prototype.getFgTranslationCoordinates_ = function() { - var t, - e = this.activationState_, - n = e.activationEvent; - return { - startPoint: (t = { - x: - (t = e.wasActivatedByPointer - ? u.getNormalizedEventCoords( - n, - this.adapter_.getWindowPageOffset(), - this.adapter_.computeBoundingRect() - ) - : { x: this.frame_.width / 2, y: this.frame_.height / 2 }) - .x - - this.initialSize_ / 2, - y: t.y - this.initialSize_ / 2 - }), - endPoint: { - x: this.frame_.width / 2 - this.initialSize_ / 2, - y: this.frame_.height / 2 - this.initialSize_ / 2 - } - }; - }), - (f.prototype.runDeactivationUXLogicIfReady_ = function() { - var t = this, - e = f.cssClasses.FG_DEACTIVATION, - n = this.activationState_, - i = n.hasDeactivationUXRun, - r = n.isActivated; - (!i && r) || - !this.activationAnimationHasEnded_ || - (this.rmBoundedActivationClasses_(), - this.adapter_.addClass(e), - (this.fgDeactivationRemovalTimer_ = setTimeout(function() { - t.adapter_.removeClass(e); - }, c.numbers.FG_DEACTIVATION_MS))); - }), - (f.prototype.rmBoundedActivationClasses_ = function() { - var t = f.cssClasses.FG_ACTIVATION; - this.adapter_.removeClass(t), - (this.activationAnimationHasEnded_ = !1), - this.adapter_.computeBoundingRect(); - }), - (f.prototype.resetActivationState_ = function() { - var t = this; - (this.previousActivationEvent_ = this.activationState_.activationEvent), - (this.activationState_ = this.defaultActivationState_()), - setTimeout(function() { - return (t.previousActivationEvent_ = void 0); - }, f.numbers.TAP_DELAY_MS); - }), - (f.prototype.deactivate_ = function() { - var t = this, - e = this.activationState_; - if (e.isActivated) { - var n = o({}, e); - e.isProgrammatic - ? (requestAnimationFrame(function() { - return t.animateDeactivation_(n); - }), - this.resetActivationState_()) - : (this.deregisterDeactivationHandlers_(), - requestAnimationFrame(function() { - (t.activationState_.hasDeactivationUXRun = !0), - t.animateDeactivation_(n), - t.resetActivationState_(); - })); - } - }), - (f.prototype.animateDeactivation_ = function(t) { - var e = t.wasActivatedByPointer, - n = t.wasElementMadeActive; - (e || n) && this.runDeactivationUXLogicIfReady_(); - }), - (f.prototype.layoutInternal_ = function() { - var t = this; - this.frame_ = this.adapter_.computeBoundingRect(); - var e = Math.max(this.frame_.height, this.frame_.width); - this.maxRadius_ = this.adapter_.isUnbounded() - ? e - : Math.sqrt( - Math.pow(t.frame_.width, 2) + Math.pow(t.frame_.height, 2) - ) + f.numbers.PADDING; - var n = Math.floor(e * f.numbers.INITIAL_ORIGIN_SCALE); - this.adapter_.isUnbounded() && n % 2 != 0 - ? (this.initialSize_ = n - 1) - : (this.initialSize_ = n), - (this.fgScale_ = "" + this.maxRadius_ / this.initialSize_), - this.updateLayoutCssVars_(); - }), - (f.prototype.updateLayoutCssVars_ = function() { - var t = f.strings, - e = t.VAR_FG_SIZE, - n = t.VAR_LEFT, - i = t.VAR_TOP, - r = t.VAR_FG_SCALE; - this.adapter_.updateCssVariable(e, this.initialSize_ + "px"), - this.adapter_.updateCssVariable(r, this.fgScale_), - this.adapter_.isUnbounded() && - ((this.unboundedCoords_ = { - left: Math.round( - this.frame_.width / 2 - this.initialSize_ / 2 - ), - top: Math.round( - this.frame_.height / 2 - this.initialSize_ / 2 - ) - }), - this.adapter_.updateCssVariable( - n, - this.unboundedCoords_.left + "px" - ), - this.adapter_.updateCssVariable( - i, - this.unboundedCoords_.top + "px" - )); - }), - f); - function f(t) { - var e = s.call(this, o(o({}, f.defaultAdapter), t)) || this; - return ( - (e.activationAnimationHasEnded_ = !1), - (e.activationTimer_ = 0), - (e.fgDeactivationRemovalTimer_ = 0), - (e.fgScale_ = "0"), - (e.frame_ = { width: 0, height: 0 }), - (e.initialSize_ = 0), - (e.layoutFrame_ = 0), - (e.maxRadius_ = 0), - (e.unboundedCoords_ = { left: 0, top: 0 }), - (e.activationState_ = e.defaultActivationState_()), - (e.activationTimerCallback_ = function() { - (e.activationAnimationHasEnded_ = !0), - e.runDeactivationUXLogicIfReady_(); - }), - (e.activateHandler_ = function(t) { - return e.activate_(t); - }), - (e.deactivateHandler_ = function() { - return e.deactivate_(); - }), - (e.focusHandler_ = function() { - return e.handleFocus(); - }), - (e.blurHandler_ = function() { - return e.handleBlur(); - }), - (e.resizeHandler_ = function() { - return e.layout(); - }), - e - ); - } - (e.MDCRippleFoundation = _), (e.default = _); - }, - function(t, e, n) { - "use strict"; - Object.defineProperty(e, "__esModule", { value: !0 }), - (e.applyPassive = function(t) { - return ( - void 0 === t && (t = window), - !!(function(t) { - void 0 === t && (t = window); - var e = !1; - try { - var n = { - get passive() { - return !(e = !0); - } - }, - i = function() {}; - t.document.addEventListener("test", i, n), - t.document.removeEventListener("test", i, n); - } catch (t) { - e = !1; - } - return e; - })(t) && { passive: !0 } - ); - }); - }, - function(t, e, n) { - "use strict"; - Object.defineProperty(e, "__esModule", { value: !0 }); - e.cssClasses = { - ANCHOR: "mdc-menu-surface--anchor", - ANIMATING_CLOSED: "mdc-menu-surface--animating-closed", - ANIMATING_OPEN: "mdc-menu-surface--animating-open", - FIXED: "mdc-menu-surface--fixed", - IS_OPEN_BELOW: "mdc-menu-surface--is-open-below", - OPEN: "mdc-menu-surface--open", - ROOT: "mdc-menu-surface" - }; - var i = { - CLOSED_EVENT: "MDCMenuSurface:closed", - OPENED_EVENT: "MDCMenuSurface:opened", - FOCUSABLE_ELEMENTS: [ - "button:not(:disabled)", - '[href]:not([aria-disabled="true"])', - "input:not(:disabled)", - "select:not(:disabled)", - "textarea:not(:disabled)", - '[tabindex]:not([tabindex="-1"]):not([aria-disabled="true"])' - ].join(", ") - }; - e.strings = i; - var r, o, s, a; - (e.numbers = { - TRANSITION_OPEN_DURATION: 120, - TRANSITION_CLOSE_DURATION: 75, - MARGIN_TO_EDGE: 32, - ANCHOR_TO_MENU_SURFACE_WIDTH_RATIO: 0.67 - }), - ((o = r = r || {})[(o.BOTTOM = 1)] = "BOTTOM"), - (o[(o.CENTER = 2)] = "CENTER"), - (o[(o.RIGHT = 4)] = "RIGHT"), - (o[(o.FLIP_RTL = 8)] = "FLIP_RTL"), - (e.CornerBit = r), - ((a = s = s || {})[(a.TOP_LEFT = 0)] = "TOP_LEFT"), - (a[(a.TOP_RIGHT = 4)] = "TOP_RIGHT"), - (a[(a.BOTTOM_LEFT = 1)] = "BOTTOM_LEFT"), - (a[(a.BOTTOM_RIGHT = 5)] = "BOTTOM_RIGHT"), - (a[(a.TOP_START = 8)] = "TOP_START"), - (a[(a.TOP_END = 12)] = "TOP_END"), - (a[(a.BOTTOM_START = 9)] = "BOTTOM_START"), - (a[(a.BOTTOM_END = 13)] = "BOTTOM_END"), - (e.Corner = s); - }, - function(t, e, n) { - "use strict"; - Object.defineProperty(e, "__esModule", { value: !0 }); - e.cssClasses = { - FIXED_CLASS: "mdc-top-app-bar--fixed", - FIXED_SCROLLED_CLASS: "mdc-top-app-bar--fixed-scrolled", - SHORT_CLASS: "mdc-top-app-bar--short", - SHORT_COLLAPSED_CLASS: "mdc-top-app-bar--short-collapsed", - SHORT_HAS_ACTION_ITEM_CLASS: "mdc-top-app-bar--short-has-action-item" - }; - e.numbers = { - DEBOUNCE_THROTTLE_RESIZE_TIME_MS: 100, - MAX_TOP_APP_BAR_HEIGHT: 128 - }; - e.strings = { - ACTION_ITEM_SELECTOR: ".mdc-top-app-bar__action-item", - NAVIGATION_EVENT: "MDCTopAppBar:nav", - NAVIGATION_ICON_SELECTOR: ".mdc-top-app-bar__navigation-icon", - ROOT_SELECTOR: ".mdc-top-app-bar", - TITLE_SELECTOR: ".mdc-top-app-bar__title" - }; - }, - function(t, e, n) { - "use strict"; - var i, r; - Object.defineProperty(e, "__esModule", { value: !0 }), - ((i = e.Direction || (e.Direction = {}))[(i.RIGHT = 0)] = "RIGHT"), - (i[(i.LEFT = 1)] = "LEFT"), - ((r = e.EventSource || (e.EventSource = {}))[(r.PRIMARY = 0)] = - "PRIMARY"), - (r[(r.TRAILING = 1)] = "TRAILING"), - (r[(r.NONE = 2)] = "NONE"), - (e.strings = { - ADDED_ANNOUNCEMENT_ATTRIBUTE: "data-mdc-chip-added-announcement", - ARIA_CHECKED: "aria-checked", - ARROW_DOWN_KEY: "ArrowDown", - ARROW_LEFT_KEY: "ArrowLeft", - ARROW_RIGHT_KEY: "ArrowRight", - ARROW_UP_KEY: "ArrowUp", - BACKSPACE_KEY: "Backspace", - CHECKMARK_SELECTOR: ".mdc-chip__checkmark", - DELETE_KEY: "Delete", - END_KEY: "End", - ENTER_KEY: "Enter", - ENTRY_ANIMATION_NAME: "mdc-chip-entry", - HOME_KEY: "Home", - IE_ARROW_DOWN_KEY: "Down", - IE_ARROW_LEFT_KEY: "Left", - IE_ARROW_RIGHT_KEY: "Right", - IE_ARROW_UP_KEY: "Up", - IE_DELETE_KEY: "Del", - INTERACTION_EVENT: "MDCChip:interaction", - LEADING_ICON_SELECTOR: ".mdc-chip__icon--leading", - NAVIGATION_EVENT: "MDCChip:navigation", - PRIMARY_ACTION_SELECTOR: ".mdc-chip__primary-action", - REMOVED_ANNOUNCEMENT_ATTRIBUTE: - "data-mdc-chip-removed-announcement", - REMOVAL_EVENT: "MDCChip:removal", - SELECTION_EVENT: "MDCChip:selection", - SPACEBAR_KEY: " ", - TAB_INDEX: "tabindex", - TRAILING_ACTION_SELECTOR: ".mdc-chip__trailing-action", - TRAILING_ICON_INTERACTION_EVENT: "MDCChip:trailingIconInteraction", - TRAILING_ICON_SELECTOR: ".mdc-chip__icon--trailing" - }), - (e.cssClasses = { - CHECKMARK: "mdc-chip__checkmark", - CHIP_EXIT: "mdc-chip--exit", - DELETABLE: "mdc-chip--deletable", - HIDDEN_LEADING_ICON: "mdc-chip__icon--leading-hidden", - LEADING_ICON: "mdc-chip__icon--leading", - PRIMARY_ACTION: "mdc-chip__primary-action", - PRIMARY_ACTION_FOCUSED: "mdc-chip--primary-action-focused", - SELECTED: "mdc-chip--selected", - TEXT: "mdc-chip__text", - TRAILING_ACTION: "mdc-chip__trailing-action", - TRAILING_ICON: "mdc-chip__icon--trailing" - }), - (e.navigationKeys = new Set()), - e.navigationKeys.add(e.strings.ARROW_LEFT_KEY), - e.navigationKeys.add(e.strings.ARROW_RIGHT_KEY), - e.navigationKeys.add(e.strings.ARROW_DOWN_KEY), - e.navigationKeys.add(e.strings.ARROW_UP_KEY), - e.navigationKeys.add(e.strings.END_KEY), - e.navigationKeys.add(e.strings.HOME_KEY), - e.navigationKeys.add(e.strings.IE_ARROW_LEFT_KEY), - e.navigationKeys.add(e.strings.IE_ARROW_RIGHT_KEY), - e.navigationKeys.add(e.strings.IE_ARROW_DOWN_KEY), - e.navigationKeys.add(e.strings.IE_ARROW_UP_KEY), - (e.jumpChipKeys = new Set()), - e.jumpChipKeys.add(e.strings.ARROW_UP_KEY), - e.jumpChipKeys.add(e.strings.ARROW_DOWN_KEY), - e.jumpChipKeys.add(e.strings.HOME_KEY), - e.jumpChipKeys.add(e.strings.END_KEY), - e.jumpChipKeys.add(e.strings.IE_ARROW_UP_KEY), - e.jumpChipKeys.add(e.strings.IE_ARROW_DOWN_KEY); - }, - function(t, e, n) { - "use strict"; - Object.defineProperty(e, "__esModule", { value: !0 }); - var i = { - LIST_ITEM_ACTIVATED_CLASS: "mdc-list-item--activated", - LIST_ITEM_CLASS: "mdc-list-item", - LIST_ITEM_DISABLED_CLASS: "mdc-list-item--disabled", - LIST_ITEM_SELECTED_CLASS: "mdc-list-item--selected", - ROOT: "mdc-list" - }, - r = { - ACTION_EVENT: "MDCList:action", - ARIA_CHECKED: "aria-checked", - ARIA_CHECKED_CHECKBOX_SELECTOR: - '[role="checkbox"][aria-checked="true"]', - ARIA_CHECKED_RADIO_SELECTOR: '[role="radio"][aria-checked="true"]', - ARIA_CURRENT: "aria-current", - ARIA_DISABLED: "aria-disabled", - ARIA_ORIENTATION: "aria-orientation", - ARIA_ORIENTATION_HORIZONTAL: "horizontal", - ARIA_ROLE_CHECKBOX_SELECTOR: '[role="checkbox"]', - ARIA_SELECTED: "aria-selected", - CHECKBOX_RADIO_SELECTOR: - 'input[type="checkbox"], input[type="radio"]', - CHECKBOX_SELECTOR: 'input[type="checkbox"]', - CHILD_ELEMENTS_TO_TOGGLE_TABINDEX: - "\n ." + - (e.cssClasses = i).LIST_ITEM_CLASS + - " button:not(:disabled),\n ." + - i.LIST_ITEM_CLASS + - " a\n ", - FOCUSABLE_CHILD_ELEMENTS: - "\n ." + - i.LIST_ITEM_CLASS + - " button:not(:disabled),\n ." + - i.LIST_ITEM_CLASS + - " a,\n ." + - i.LIST_ITEM_CLASS + - ' input[type="radio"]:not(:disabled),\n .' + - i.LIST_ITEM_CLASS + - ' input[type="checkbox"]:not(:disabled)\n ', - RADIO_SELECTOR: 'input[type="radio"]' - }; - e.strings = r; - e.numbers = { UNSET_INDEX: -1 }; - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }), - o = - (this && this.__assign) || - function() { - return (o = - Object.assign || - function(t) { - for (var e, n = 1, i = arguments.length; n < i; n++) - for (var r in (e = arguments[n])) - Object.prototype.hasOwnProperty.call(e, r) && - (t[r] = e[r]); - return t; - }).apply(this, arguments); - }; - Object.defineProperty(e, "__esModule", { value: !0 }); - var s = n(0), - f = n(9), - a = ["input", "button", "textarea", "select"]; - var c, - u = - ((c = s.MDCFoundation), - r(l, c), - Object.defineProperty(l, "strings", { - get: function() { - return f.strings; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(l, "cssClasses", { - get: function() { - return f.cssClasses; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(l, "numbers", { - get: function() { - return f.numbers; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(l, "defaultAdapter", { - get: function() { - return { - addClassForElementIndex: function() {}, - focusItemAtIndex: function() {}, - getAttributeForElementIndex: function() { - return null; - }, - getFocusedElementIndex: function() { - return 0; - }, - getListItemCount: function() { - return 0; - }, - hasCheckboxAtIndex: function() { - return !1; - }, - hasRadioAtIndex: function() { - return !1; - }, - isCheckboxCheckedAtIndex: function() { - return !1; - }, - isFocusInsideList: function() { - return !1; - }, - isRootFocused: function() { - return !1; - }, - listItemAtIndexHasClass: function() { - return !1; - }, - notifyAction: function() {}, - removeClassForElementIndex: function() {}, - setAttributeForElementIndex: function() {}, - setCheckedCheckboxOrRadioAtIndex: function() {}, - setTabIndexForListItemChildren: function() {} - }; - }, - enumerable: !0, - configurable: !0 - }), - (l.prototype.layout = function() { - 0 !== this.adapter_.getListItemCount() && - (this.adapter_.hasCheckboxAtIndex(0) - ? (this.isCheckboxList_ = !0) - : this.adapter_.hasRadioAtIndex(0) && - (this.isRadioList_ = !0)); - }), - (l.prototype.setWrapFocus = function(t) { - this.wrapFocus_ = t; - }), - (l.prototype.setVerticalOrientation = function(t) { - this.isVertical_ = t; - }), - (l.prototype.setSingleSelection = function(t) { - this.isSingleSelectionList_ = t; - }), - (l.prototype.setUseActivatedClass = function(t) { - this.useActivatedClass_ = t; - }), - (l.prototype.getSelectedIndex = function() { - return this.selectedIndex_; - }), - (l.prototype.setSelectedIndex = function(t) { - this.isIndexValid_(t) && - (this.isCheckboxList_ - ? this.setCheckboxAtIndex_(t) - : this.isRadioList_ - ? this.setRadioAtIndex_(t) - : this.setSingleSelectionAtIndex_(t)); - }), - (l.prototype.handleFocusIn = function(t, e) { - 0 <= e && this.adapter_.setTabIndexForListItemChildren(e, "0"); - }), - (l.prototype.handleFocusOut = function(t, e) { - var n = this; - 0 <= e && this.adapter_.setTabIndexForListItemChildren(e, "-1"), - setTimeout(function() { - n.adapter_.isFocusInsideList() || - n.setTabindexToFirstSelectedItem_(); - }, 0); - }), - (l.prototype.handleKeydown = function(t, e, n) { - var i = "ArrowLeft" === t.key || 37 === t.keyCode, - r = "ArrowUp" === t.key || 38 === t.keyCode, - o = "ArrowRight" === t.key || 39 === t.keyCode, - s = "ArrowDown" === t.key || 40 === t.keyCode, - a = "Home" === t.key || 36 === t.keyCode, - c = "End" === t.key || 35 === t.keyCode, - u = "Enter" === t.key || 13 === t.keyCode, - l = "Space" === t.key || 32 === t.keyCode; - if (this.adapter_.isRootFocused()) - r || c - ? (t.preventDefault(), this.focusLastElement()) - : (s || a) && (t.preventDefault(), this.focusFirstElement()); - else { - var d = this.adapter_.getFocusedElementIndex(); - if (!(-1 === d && (d = n) < 0)) { - var p; - if ((this.isVertical_ && s) || (!this.isVertical_ && o)) - this.preventDefaultEvent_(t), - (p = this.focusNextElement(d)); - else if ((this.isVertical_ && r) || (!this.isVertical_ && i)) - this.preventDefaultEvent_(t), - (p = this.focusPrevElement(d)); - else if (a) - this.preventDefaultEvent_(t), - (p = this.focusFirstElement()); - else if (c) - this.preventDefaultEvent_(t), (p = this.focusLastElement()); - else if ((u || l) && e) { - var _ = t.target; - if (_ && "A" === _.tagName && u) return; - if ( - (this.preventDefaultEvent_(t), - this.adapter_.listItemAtIndexHasClass( - d, - f.cssClasses.LIST_ITEM_DISABLED_CLASS - )) - ) - return; - this.isSelectableList_() && - this.setSelectedIndexOnAction_(d), - this.adapter_.notifyAction(d); - } - (this.focusedItemIndex_ = d), - void 0 !== p && - (this.setTabindexAtIndex_(p), - (this.focusedItemIndex_ = p)); - } - } - }), - (l.prototype.handleClick = function(t, e) { - t !== f.numbers.UNSET_INDEX && - (this.setTabindexAtIndex_(t), - (this.focusedItemIndex_ = t), - this.adapter_.listItemAtIndexHasClass( - t, - f.cssClasses.LIST_ITEM_DISABLED_CLASS - ) || - (this.isSelectableList_() && - this.setSelectedIndexOnAction_(t, e), - this.adapter_.notifyAction(t))); - }), - (l.prototype.focusNextElement = function(t) { - var e = t + 1; - if (this.adapter_.getListItemCount() <= e) { - if (!this.wrapFocus_) return t; - e = 0; - } - return this.adapter_.focusItemAtIndex(e), e; - }), - (l.prototype.focusPrevElement = function(t) { - var e = t - 1; - if (e < 0) { - if (!this.wrapFocus_) return t; - e = this.adapter_.getListItemCount() - 1; - } - return this.adapter_.focusItemAtIndex(e), e; - }), - (l.prototype.focusFirstElement = function() { - return this.adapter_.focusItemAtIndex(0), 0; - }), - (l.prototype.focusLastElement = function() { - var t = this.adapter_.getListItemCount() - 1; - return this.adapter_.focusItemAtIndex(t), t; - }), - (l.prototype.setEnabled = function(t, e) { - this.isIndexValid_(t) && - (e - ? (this.adapter_.removeClassForElementIndex( - t, - f.cssClasses.LIST_ITEM_DISABLED_CLASS - ), - this.adapter_.setAttributeForElementIndex( - t, - f.strings.ARIA_DISABLED, - "false" - )) - : (this.adapter_.addClassForElementIndex( - t, - f.cssClasses.LIST_ITEM_DISABLED_CLASS - ), - this.adapter_.setAttributeForElementIndex( - t, - f.strings.ARIA_DISABLED, - "true" - ))); - }), - (l.prototype.preventDefaultEvent_ = function(t) { - var e = ("" + t.target.tagName).toLowerCase(); - -1 === a.indexOf(e) && t.preventDefault(); - }), - (l.prototype.setSingleSelectionAtIndex_ = function(t) { - if (this.selectedIndex_ !== t) { - var e = f.cssClasses.LIST_ITEM_SELECTED_CLASS; - this.useActivatedClass_ && - (e = f.cssClasses.LIST_ITEM_ACTIVATED_CLASS), - this.selectedIndex_ !== f.numbers.UNSET_INDEX && - this.adapter_.removeClassForElementIndex( - this.selectedIndex_, - e - ), - this.adapter_.addClassForElementIndex(t, e), - this.setAriaForSingleSelectionAtIndex_(t), - (this.selectedIndex_ = t); - } - }), - (l.prototype.setAriaForSingleSelectionAtIndex_ = function(t) { - this.selectedIndex_ === f.numbers.UNSET_INDEX && - (this.ariaCurrentAttrValue_ = this.adapter_.getAttributeForElementIndex( - t, - f.strings.ARIA_CURRENT - )); - var e = null !== this.ariaCurrentAttrValue_, - n = e ? f.strings.ARIA_CURRENT : f.strings.ARIA_SELECTED; - this.selectedIndex_ !== f.numbers.UNSET_INDEX && - this.adapter_.setAttributeForElementIndex( - this.selectedIndex_, - n, - "false" - ); - var i = e ? this.ariaCurrentAttrValue_ : "true"; - this.adapter_.setAttributeForElementIndex(t, n, i); - }), - (l.prototype.setRadioAtIndex_ = function(t) { - this.adapter_.setCheckedCheckboxOrRadioAtIndex(t, !0), - this.selectedIndex_ !== f.numbers.UNSET_INDEX && - this.adapter_.setAttributeForElementIndex( - this.selectedIndex_, - f.strings.ARIA_CHECKED, - "false" - ), - this.adapter_.setAttributeForElementIndex( - t, - f.strings.ARIA_CHECKED, - "true" - ), - (this.selectedIndex_ = t); - }), - (l.prototype.setCheckboxAtIndex_ = function(t) { - for (var e = 0; e < this.adapter_.getListItemCount(); e++) { - var n = !1; - 0 <= t.indexOf(e) && (n = !0), - this.adapter_.setCheckedCheckboxOrRadioAtIndex(e, n), - this.adapter_.setAttributeForElementIndex( - e, - f.strings.ARIA_CHECKED, - n ? "true" : "false" - ); - } - this.selectedIndex_ = t; - }), - (l.prototype.setTabindexAtIndex_ = function(t) { - this.focusedItemIndex_ === f.numbers.UNSET_INDEX && 0 !== t - ? this.adapter_.setAttributeForElementIndex(0, "tabindex", "-1") - : 0 <= this.focusedItemIndex_ && - this.focusedItemIndex_ !== t && - this.adapter_.setAttributeForElementIndex( - this.focusedItemIndex_, - "tabindex", - "-1" - ), - this.adapter_.setAttributeForElementIndex(t, "tabindex", "0"); - }), - (l.prototype.isSelectableList_ = function() { - return ( - this.isSingleSelectionList_ || - this.isCheckboxList_ || - this.isRadioList_ - ); - }), - (l.prototype.setTabindexToFirstSelectedItem_ = function() { - var t = 0; - this.isSelectableList_() && - ("number" == typeof this.selectedIndex_ && - this.selectedIndex_ !== f.numbers.UNSET_INDEX - ? (t = this.selectedIndex_) - : (function(t) { - return t instanceof Array; - })(this.selectedIndex_) && - 0 < this.selectedIndex_.length && - (t = this.selectedIndex_.reduce(function(t, e) { - return Math.min(t, e); - }))), - this.setTabindexAtIndex_(t); - }), - (l.prototype.isIndexValid_ = function(t) { - var e = this; - if (t instanceof Array) { - if (!this.isCheckboxList_) - throw new Error( - "MDCListFoundation: Array of index is only supported for checkbox based list" - ); - return ( - 0 === t.length || - t.some(function(t) { - return e.isIndexInRange_(t); - }) - ); - } - if ("number" != typeof t) return !1; - if (this.isCheckboxList_) - throw new Error( - "MDCListFoundation: Expected array of index for checkbox based list but got number: " + - t - ); - return this.isIndexInRange_(t); - }), - (l.prototype.isIndexInRange_ = function(t) { - var e = this.adapter_.getListItemCount(); - return 0 <= t && t < e; - }), - (l.prototype.setSelectedIndexOnAction_ = function(t, e) { - void 0 === e && (e = !0), - this.isCheckboxList_ - ? this.toggleCheckboxAtIndex_(t, e) - : this.setSelectedIndex(t); - }), - (l.prototype.toggleCheckboxAtIndex_ = function(e, t) { - var n = this.adapter_.isCheckboxCheckedAtIndex(e); - t && - ((n = !n), - this.adapter_.setCheckedCheckboxOrRadioAtIndex(e, n)), - this.adapter_.setAttributeForElementIndex( - e, - f.strings.ARIA_CHECKED, - n ? "true" : "false" - ); - var i = - this.selectedIndex_ === f.numbers.UNSET_INDEX - ? [] - : this.selectedIndex_.slice(); - n - ? i.push(e) - : (i = i.filter(function(t) { - return t !== e; - })), - (this.selectedIndex_ = i); - }), - l); - function l(t) { - var e = c.call(this, o(o({}, l.defaultAdapter), t)) || this; - return ( - (e.wrapFocus_ = !1), - (e.isVertical_ = !0), - (e.isSingleSelectionList_ = !1), - (e.selectedIndex_ = f.numbers.UNSET_INDEX), - (e.focusedItemIndex_ = f.numbers.UNSET_INDEX), - (e.useActivatedClass_ = !1), - (e.ariaCurrentAttrValue_ = null), - (e.isCheckboxList_ = !1), - (e.isRadioList_ = !1), - e - ); - } - (e.MDCListFoundation = u), (e.default = u); - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }), - o = - (this && this.__assign) || - function() { - return (o = - Object.assign || - function(t) { - for (var e, n = 1, i = arguments.length; n < i; n++) - for (var r in (e = arguments[n])) - Object.prototype.hasOwnProperty.call(e, r) && - (t[r] = e[r]); - return t; - }).apply(this, arguments); - }, - d = - (this && this.__values) || - function(t) { - var e = "function" == typeof Symbol && Symbol.iterator, - n = e && t[e], - i = 0; - if (n) return n.call(t); - if (t && "number" == typeof t.length) - return { - next: function() { - return ( - t && i >= t.length && (t = void 0), - { value: t && t[i++], done: !t } - ); - } - }; - throw new TypeError( - e - ? "Object is not iterable." - : "Symbol.iterator is not defined." - ); - }; - Object.defineProperty(e, "__esModule", { value: !0 }); - var s, - a = n(0), - y = n(6), - c = - ((s = a.MDCFoundation), - r(E, s), - Object.defineProperty(E, "cssClasses", { - get: function() { - return y.cssClasses; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(E, "strings", { - get: function() { - return y.strings; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(E, "numbers", { - get: function() { - return y.numbers; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(E, "Corner", { - get: function() { - return y.Corner; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(E, "defaultAdapter", { - get: function() { - return { - addClass: function() {}, - removeClass: function() {}, - hasClass: function() { - return !1; - }, - hasAnchor: function() { - return !1; - }, - isElementInContainer: function() { - return !1; - }, - isFocused: function() { - return !1; - }, - isRtl: function() { - return !1; - }, - getInnerDimensions: function() { - return { height: 0, width: 0 }; - }, - getAnchorDimensions: function() { - return null; - }, - getWindowDimensions: function() { - return { height: 0, width: 0 }; - }, - getBodyDimensions: function() { - return { height: 0, width: 0 }; - }, - getWindowScroll: function() { - return { x: 0, y: 0 }; - }, - setPosition: function() {}, - setMaxHeight: function() {}, - setTransformOrigin: function() {}, - saveFocus: function() {}, - restoreFocus: function() {}, - notifyClose: function() {}, - notifyOpen: function() {} - }; - }, - enumerable: !0, - configurable: !0 - }), - (E.prototype.init = function() { - var t = E.cssClasses, - e = t.ROOT, - n = t.OPEN; - if (!this.adapter_.hasClass(e)) - throw new Error(e + " class required in root element."); - this.adapter_.hasClass(n) && (this.isOpen_ = !0); - }), - (E.prototype.destroy = function() { - clearTimeout(this.openAnimationEndTimerId_), - clearTimeout(this.closeAnimationEndTimerId_), - cancelAnimationFrame(this.animationRequestId_); - }), - (E.prototype.setAnchorCorner = function(t) { - this.anchorCorner_ = t; - }), - (E.prototype.flipCornerHorizontally = function() { - this.originCorner_ = this.originCorner_ ^ y.CornerBit.RIGHT; - }), - (E.prototype.setAnchorMargin = function(t) { - (this.anchorMargin_.top = t.top || 0), - (this.anchorMargin_.right = t.right || 0), - (this.anchorMargin_.bottom = t.bottom || 0), - (this.anchorMargin_.left = t.left || 0); - }), - (E.prototype.setIsHoisted = function(t) { - this.isHoistedElement_ = t; - }), - (E.prototype.setFixedPosition = function(t) { - this.isFixedPosition_ = t; - }), - (E.prototype.setAbsolutePosition = function(t, e) { - (this.position_.x = this.isFinite_(t) ? t : 0), - (this.position_.y = this.isFinite_(e) ? e : 0); - }), - (E.prototype.setQuickOpen = function(t) { - this.isQuickOpen_ = t; - }), - (E.prototype.isOpen = function() { - return this.isOpen_; - }), - (E.prototype.open = function() { - var t = this; - this.isOpen_ || - (this.adapter_.saveFocus(), - this.isQuickOpen_ - ? ((this.isOpen_ = !0), - this.adapter_.addClass(E.cssClasses.OPEN), - (this.dimensions_ = this.adapter_.getInnerDimensions()), - this.autoPosition_(), - this.adapter_.notifyOpen()) - : (this.adapter_.addClass(E.cssClasses.ANIMATING_OPEN), - (this.animationRequestId_ = requestAnimationFrame( - function() { - t.adapter_.addClass(E.cssClasses.OPEN), - (t.dimensions_ = t.adapter_.getInnerDimensions()), - t.autoPosition_(), - (t.openAnimationEndTimerId_ = setTimeout(function() { - (t.openAnimationEndTimerId_ = 0), - t.adapter_.removeClass( - E.cssClasses.ANIMATING_OPEN - ), - t.adapter_.notifyOpen(); - }, y.numbers.TRANSITION_OPEN_DURATION)); - } - )), - (this.isOpen_ = !0))); - }), - (E.prototype.close = function(t) { - var e = this; - void 0 === t && (t = !1), - this.isOpen_ && - (this.isQuickOpen_ - ? ((this.isOpen_ = !1), - t || this.maybeRestoreFocus_(), - this.adapter_.removeClass(E.cssClasses.OPEN), - this.adapter_.removeClass(E.cssClasses.IS_OPEN_BELOW), - this.adapter_.notifyClose()) - : (this.adapter_.addClass(E.cssClasses.ANIMATING_CLOSED), - requestAnimationFrame(function() { - e.adapter_.removeClass(E.cssClasses.OPEN), - e.adapter_.removeClass(E.cssClasses.IS_OPEN_BELOW), - (e.closeAnimationEndTimerId_ = setTimeout(function() { - (e.closeAnimationEndTimerId_ = 0), - e.adapter_.removeClass( - E.cssClasses.ANIMATING_CLOSED - ), - e.adapter_.notifyClose(); - }, y.numbers.TRANSITION_CLOSE_DURATION)); - }), - (this.isOpen_ = !1), - t || this.maybeRestoreFocus_())); - }), - (E.prototype.handleBodyClick = function(t) { - var e = t.target; - this.adapter_.isElementInContainer(e) || this.close(); - }), - (E.prototype.handleKeydown = function(t) { - var e = t.keyCode; - ("Escape" !== t.key && 27 !== e) || this.close(); - }), - (E.prototype.autoPosition_ = function() { - var t; - this.measurements_ = this.getAutoLayoutMeasurements_(); - var e = this.getOriginCorner_(), - n = this.getMenuSurfaceMaxHeight_(e), - i = this.hasBit_(e, y.CornerBit.BOTTOM) ? "bottom" : "top", - r = this.hasBit_(e, y.CornerBit.RIGHT) ? "right" : "left", - o = this.getHorizontalOriginOffset_(e), - s = this.getVerticalOriginOffset_(e), - a = this.measurements_, - c = a.anchorSize, - u = a.surfaceSize, - l = (((t = {})[r] = o), (t[i] = s), t); - c.width / u.width > - y.numbers.ANCHOR_TO_MENU_SURFACE_WIDTH_RATIO && (r = "center"), - (this.isHoistedElement_ || this.isFixedPosition_) && - this.adjustPositionForHoistedElement_(l), - this.adapter_.setTransformOrigin(r + " " + i), - this.adapter_.setPosition(l), - this.adapter_.setMaxHeight(n ? n + "px" : ""), - this.hasBit_(e, y.CornerBit.BOTTOM) || - this.adapter_.addClass(E.cssClasses.IS_OPEN_BELOW); - }), - (E.prototype.getAutoLayoutMeasurements_ = function() { - var t = this.adapter_.getAnchorDimensions(), - e = this.adapter_.getBodyDimensions(), - n = this.adapter_.getWindowDimensions(), - i = this.adapter_.getWindowScroll(); - return { - anchorSize: (t = t || { - top: this.position_.y, - right: this.position_.x, - bottom: this.position_.y, - left: this.position_.x, - width: 0, - height: 0 - }), - bodySize: e, - surfaceSize: this.dimensions_, - viewportDistance: { - top: t.top, - right: n.width - t.right, - bottom: n.height - t.bottom, - left: t.left - }, - viewportSize: n, - windowScroll: i - }; - }), - (E.prototype.getOriginCorner_ = function() { - var t, - e, - n = this.originCorner_, - i = this.measurements_, - r = i.viewportDistance, - o = i.anchorSize, - s = i.surfaceSize, - a = E.numbers.MARGIN_TO_EDGE; - !( - 0 < - (e = this.hasBit_(this.anchorCorner_, y.CornerBit.BOTTOM) - ? ((t = r.top - a + o.height + this.anchorMargin_.bottom), - r.bottom - a - this.anchorMargin_.bottom) - : ((t = r.top - a + this.anchorMargin_.top), - r.bottom - a + o.height - this.anchorMargin_.top)) - - s.height - ) && - e <= t && - (n = this.setBit_(n, y.CornerBit.BOTTOM)); - var c, - u, - l = this.adapter_.isRtl(), - d = this.hasBit_(this.anchorCorner_, y.CornerBit.FLIP_RTL), - p = this.hasBit_(this.anchorCorner_, y.CornerBit.RIGHT), - _ = !1; - u = (_ = l && d ? !p : p) - ? ((c = r.left + o.width + this.anchorMargin_.right), - r.right - this.anchorMargin_.right) - : ((c = r.left + this.anchorMargin_.left), - r.right + o.width - this.anchorMargin_.left); - var f = 0 < c - s.width, - h = 0 < u - s.width, - C = - this.hasBit_(n, y.CornerBit.FLIP_RTL) && - this.hasBit_(n, y.CornerBit.RIGHT); - return ( - (h && C && l) || (!f && C) - ? (n = this.unsetBit_(n, y.CornerBit.RIGHT)) - : ((f && _ && l) || (f && !_ && p) || (!h && u <= c)) && - (n = this.setBit_(n, y.CornerBit.RIGHT)), - n - ); - }), - (E.prototype.getMenuSurfaceMaxHeight_ = function(t) { - var e = this.measurements_.viewportDistance, - n = 0, - i = this.hasBit_(t, y.CornerBit.BOTTOM), - r = this.hasBit_(this.anchorCorner_, y.CornerBit.BOTTOM), - o = E.numbers.MARGIN_TO_EDGE; - return ( - i - ? ((n = e.top + this.anchorMargin_.top - o), - r || (n += this.measurements_.anchorSize.height)) - : ((n = - e.bottom - - this.anchorMargin_.bottom + - this.measurements_.anchorSize.height - - o), - r && (n -= this.measurements_.anchorSize.height)), - n - ); - }), - (E.prototype.getHorizontalOriginOffset_ = function(t) { - var e = this.measurements_.anchorSize, - n = this.hasBit_(t, y.CornerBit.RIGHT), - i = this.hasBit_(this.anchorCorner_, y.CornerBit.RIGHT); - if (n) { - var r = i - ? e.width - this.anchorMargin_.left - : this.anchorMargin_.right; - return this.isHoistedElement_ || this.isFixedPosition_ - ? r - - (this.measurements_.viewportSize.width - - this.measurements_.bodySize.width) - : r; - } - return i - ? e.width - this.anchorMargin_.right - : this.anchorMargin_.left; - }), - (E.prototype.getVerticalOriginOffset_ = function(t) { - var e = this.measurements_.anchorSize, - n = this.hasBit_(t, y.CornerBit.BOTTOM), - i = this.hasBit_(this.anchorCorner_, y.CornerBit.BOTTOM); - return n - ? i - ? e.height - this.anchorMargin_.top - : -this.anchorMargin_.bottom - : i - ? e.height + this.anchorMargin_.bottom - : this.anchorMargin_.top; - }), - (E.prototype.adjustPositionForHoistedElement_ = function(t) { - var e, - n, - i = this.measurements_, - r = i.windowScroll, - o = i.viewportDistance, - s = Object.keys(t); - try { - for (var a = d(s), c = a.next(); !c.done; c = a.next()) { - var u = c.value, - l = t[u] || 0; - (l += o[u]), - this.isFixedPosition_ || - ("top" === u - ? (l += r.y) - : "bottom" === u - ? (l -= r.y) - : "left" === u - ? (l += r.x) - : (l -= r.x)), - (t[u] = l); - } - } catch (t) { - e = { error: t }; - } finally { - try { - c && !c.done && (n = a.return) && n.call(a); - } finally { - if (e) throw e.error; - } - } - }), - (E.prototype.maybeRestoreFocus_ = function() { - var t = this.adapter_.isFocused(), - e = - document.activeElement && - this.adapter_.isElementInContainer(document.activeElement); - (t || e) && this.adapter_.restoreFocus(); - }), - (E.prototype.hasBit_ = function(t, e) { - return Boolean(t & e); - }), - (E.prototype.setBit_ = function(t, e) { - return t | e; - }), - (E.prototype.unsetBit_ = function(t, e) { - return t ^ e; - }), - (E.prototype.isFinite_ = function(t) { - return "number" == typeof t && isFinite(t); - }), - E); - function E(t) { - var e = s.call(this, o(o({}, E.defaultAdapter), t)) || this; - return ( - (e.isOpen_ = !1), - (e.isQuickOpen_ = !1), - (e.isHoistedElement_ = !1), - (e.isFixedPosition_ = !1), - (e.openAnimationEndTimerId_ = 0), - (e.closeAnimationEndTimerId_ = 0), - (e.animationRequestId_ = 0), - (e.anchorCorner_ = y.Corner.TOP_START), - (e.originCorner_ = y.Corner.TOP_START), - (e.anchorMargin_ = { top: 0, right: 0, bottom: 0, left: 0 }), - (e.position_ = { x: 0, y: 0 }), - e - ); - } - (e.MDCMenuSurfaceFoundation = c), (e.default = c); - }, - function(t, e, n) { - "use strict"; - Object.defineProperty(e, "__esModule", { value: !0 }); - e.cssClasses = { - MENU_SELECTED_LIST_ITEM: "mdc-menu-item--selected", - MENU_SELECTION_GROUP: "mdc-menu__selection-group", - ROOT: "mdc-menu" - }; - e.strings = { - ARIA_CHECKED_ATTR: "aria-checked", - ARIA_DISABLED_ATTR: "aria-disabled", - CHECKBOX_SELECTOR: 'input[type="checkbox"]', - LIST_SELECTOR: ".mdc-list", - SELECTED_EVENT: "MDCMenu:selected" - }; - var i, r; - (e.numbers = { FOCUS_ROOT_INDEX: -1 }), - ((r = i = i || {})[(r.NONE = 0)] = "NONE"), - (r[(r.LIST_ROOT = 1)] = "LIST_ROOT"), - (r[(r.FIRST_ITEM = 2)] = "FIRST_ITEM"), - (r[(r.LAST_ITEM = 3)] = "LAST_ITEM"), - (e.DefaultFocusState = i); - }, - function(t, e, n) { - "use strict"; - Object.defineProperty(e, "__esModule", { value: !0 }); - e.cssClasses = { - CLOSING: "mdc-snackbar--closing", - OPEN: "mdc-snackbar--open", - OPENING: "mdc-snackbar--opening" - }; - e.strings = { - ACTION_SELECTOR: ".mdc-snackbar__action", - ARIA_LIVE_LABEL_TEXT_ATTR: "data-mdc-snackbar-label-text", - CLOSED_EVENT: "MDCSnackbar:closed", - CLOSING_EVENT: "MDCSnackbar:closing", - DISMISS_SELECTOR: ".mdc-snackbar__dismiss", - LABEL_SELECTOR: ".mdc-snackbar__label", - OPENED_EVENT: "MDCSnackbar:opened", - OPENING_EVENT: "MDCSnackbar:opening", - REASON_ACTION: "action", - REASON_DISMISS: "dismiss", - SURFACE_SELECTOR: ".mdc-snackbar__surface" - }; - e.numbers = { - DEFAULT_AUTO_DISMISS_TIMEOUT_MS: 5e3, - INDETERMINATE: -1, - MAX_AUTO_DISMISS_TIMEOUT_MS: 1e4, - MIN_AUTO_DISMISS_TIMEOUT_MS: 4e3, - SNACKBAR_ANIMATION_CLOSE_TIME_MS: 75, - SNACKBAR_ANIMATION_OPEN_TIME_MS: 150, - ARIA_LIVE_DELAY_MS: 1e3 - }; - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }), - o = - (this && this.__assign) || - function() { - return (o = - Object.assign || - function(t) { - for (var e, n = 1, i = arguments.length; n < i; n++) - for (var r in (e = arguments[n])) - Object.prototype.hasOwnProperty.call(e, r) && - (t[r] = e[r]); - return t; - }).apply(this, arguments); - }; - Object.defineProperty(e, "__esModule", { value: !0 }); - var s, - a = n(0), - c = n(90), - u = - ((s = a.MDCFoundation), - r(l, s), - Object.defineProperty(l, "cssClasses", { - get: function() { - return c.cssClasses; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(l, "strings", { - get: function() { - return c.strings; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(l, "defaultAdapter", { - get: function() { - return { - addClass: function() {}, - removeClass: function() {}, - computeContentClientRect: function() { - return { - top: 0, - right: 0, - bottom: 0, - left: 0, - width: 0, - height: 0 - }; - }, - setContentStyleProperty: function() {} - }; - }, - enumerable: !0, - configurable: !0 - }), - (l.prototype.computeContentClientRect = function() { - return this.adapter_.computeContentClientRect(); - }), - l); - function l(t) { - return s.call(this, o(o({}, l.defaultAdapter), t)) || this; - } - (e.MDCTabIndicatorFoundation = u), (e.default = u); - }, - function(t, e, n) { - "use strict"; - Object.defineProperty(e, "__esModule", { value: !0 }); - var s = { - animation: { prefixed: "-webkit-animation", standard: "animation" }, - transform: { prefixed: "-webkit-transform", standard: "transform" }, - transition: { - prefixed: "-webkit-transition", - standard: "transition" - } - }, - a = { - animationend: { - cssProperty: "animation", - prefixed: "webkitAnimationEnd", - standard: "animationend" - }, - animationiteration: { - cssProperty: "animation", - prefixed: "webkitAnimationIteration", - standard: "animationiteration" - }, - animationstart: { - cssProperty: "animation", - prefixed: "webkitAnimationStart", - standard: "animationstart" - }, - transitionend: { - cssProperty: "transition", - prefixed: "webkitTransitionEnd", - standard: "transitionend" - } - }; - function c(t) { - return ( - Boolean(t.document) && "function" == typeof t.document.createElement - ); - } - (e.getCorrectPropertyName = function(t, e) { - if (c(t) && e in s) { - var n = t.document.createElement("div"), - i = s[e], - r = i.standard, - o = i.prefixed; - return r in n.style ? r : o; - } - return e; - }), - (e.getCorrectEventName = function(t, e) { - if (c(t) && e in a) { - var n = t.document.createElement("div"), - i = a[e], - r = i.standard, - o = i.prefixed; - return i.cssProperty in n.style ? r : o; - } - return e; - }); - }, - function(t, e, n) { - "use strict"; - var s; - Object.defineProperty(e, "__esModule", { value: !0 }), - (e.supportsCssVariables = function(t, e) { - void 0 === e && (e = !1); - var n, - i = t.CSS; - if ("boolean" == typeof s && !e) return s; - if (!(i && "function" == typeof i.supports)) return !1; - var r = i.supports("--css-vars", "yes"), - o = - i.supports("(--css-vars: yes)") && - i.supports("color", "#00000000"); - return (n = r || o), e || (s = n), n; - }), - (e.getNormalizedEventCoords = function(t, e, n) { - if (!t) return { x: 0, y: 0 }; - var i, - r, - o = e.x, - s = e.y, - a = o + n.left, - c = s + n.top; - if ("touchstart" === t.type) { - var u = t; - (i = u.changedTouches[0].pageX - a), - (r = u.changedTouches[0].pageY - c); - } else { - var l = t; - (i = l.pageX - a), (r = l.pageY - c); - } - return { x: i, y: r }; - }); - }, - function(t, e, n) { - "use strict"; - Object.defineProperty(e, "__esModule", { value: !0 }), - (e.cssClasses = { - ANIM_CHECKED_INDETERMINATE: - "mdc-checkbox--anim-checked-indeterminate", - ANIM_CHECKED_UNCHECKED: "mdc-checkbox--anim-checked-unchecked", - ANIM_INDETERMINATE_CHECKED: - "mdc-checkbox--anim-indeterminate-checked", - ANIM_INDETERMINATE_UNCHECKED: - "mdc-checkbox--anim-indeterminate-unchecked", - ANIM_UNCHECKED_CHECKED: "mdc-checkbox--anim-unchecked-checked", - ANIM_UNCHECKED_INDETERMINATE: - "mdc-checkbox--anim-unchecked-indeterminate", - BACKGROUND: "mdc-checkbox__background", - CHECKED: "mdc-checkbox--checked", - CHECKMARK: "mdc-checkbox__checkmark", - CHECKMARK_PATH: "mdc-checkbox__checkmark-path", - DISABLED: "mdc-checkbox--disabled", - INDETERMINATE: "mdc-checkbox--indeterminate", - MIXEDMARK: "mdc-checkbox__mixedmark", - NATIVE_CONTROL: "mdc-checkbox__native-control", - ROOT: "mdc-checkbox", - SELECTED: "mdc-checkbox--selected", - UPGRADED: "mdc-checkbox--upgraded" - }), - (e.strings = { - ARIA_CHECKED_ATTR: "aria-checked", - ARIA_CHECKED_INDETERMINATE_VALUE: "mixed", - DATA_INDETERMINATE_ATTR: "data-indeterminate", - NATIVE_CONTROL_SELECTOR: ".mdc-checkbox__native-control", - TRANSITION_STATE_CHECKED: "checked", - TRANSITION_STATE_INDETERMINATE: "indeterminate", - TRANSITION_STATE_INIT: "init", - TRANSITION_STATE_UNCHECKED: "unchecked" - }), - (e.numbers = { ANIM_END_LATCH_MS: 250 }); - }, - function(t, e, n) { - "use strict"; - var i; - Object.defineProperty(e, "__esModule", { value: !0 }), - ((i = e.InteractionTrigger || (e.InteractionTrigger = {}))[ - (i.UNSPECIFIED = 0) - ] = "UNSPECIFIED"), - (i[(i.CLICK = 1)] = "CLICK"), - (i[(i.BACKSPACE_KEY = 2)] = "BACKSPACE_KEY"), - (i[(i.DELETE_KEY = 3)] = "DELETE_KEY"), - (i[(i.SPACEBAR_KEY = 4)] = "SPACEBAR_KEY"), - (i[(i.ENTER_KEY = 5)] = "ENTER_KEY"), - (e.strings = { - ARIA_HIDDEN: "aria-hidden", - INTERACTION_EVENT: "MDCChipTrailingAction:interaction", - NAVIGATION_EVENT: "MDCChipTrailingAction:navigation", - TAB_INDEX: "tabindex" - }); - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }), - o = - (this && this.__assign) || - function() { - return (o = - Object.assign || - function(t) { - for (var e, n = 1, i = arguments.length; n < i; n++) - for (var r in (e = arguments[n])) - Object.prototype.hasOwnProperty.call(e, r) && - (t[r] = e[r]); - return t; - }).apply(this, arguments); - }; - Object.defineProperty(e, "__esModule", { value: !0 }); - var s, - a = n(0), - u = n(8), - c = { bottom: 0, height: 0, left: 0, right: 0, top: 0, width: 0 }, - l = - ((s = a.MDCFoundation), - r(d, s), - Object.defineProperty(d, "strings", { - get: function() { - return u.strings; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(d, "cssClasses", { - get: function() { - return u.cssClasses; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(d, "defaultAdapter", { - get: function() { - return { - addClass: function() {}, - addClassToLeadingIcon: function() {}, - eventTargetHasClass: function() { - return !1; - }, - focusPrimaryAction: function() {}, - focusTrailingAction: function() {}, - getAttribute: function() { - return null; - }, - getCheckmarkBoundingClientRect: function() { - return c; - }, - getComputedStyleValue: function() { - return ""; - }, - getRootBoundingClientRect: function() { - return c; - }, - hasClass: function() { - return !1; - }, - hasLeadingIcon: function() { - return !1; - }, - hasTrailingAction: function() { - return !1; - }, - isRTL: function() { - return !1; - }, - notifyInteraction: function() {}, - notifyNavigation: function() {}, - notifyRemoval: function() {}, - notifySelection: function() {}, - notifyTrailingIconInteraction: function() {}, - removeClass: function() {}, - removeClassFromLeadingIcon: function() {}, - setPrimaryActionAttr: function() {}, - setStyleProperty: function() {}, - setTrailingActionAttr: function() {} - }; - }, - enumerable: !0, - configurable: !0 - }), - (d.prototype.isSelected = function() { - return this.adapter_.hasClass(u.cssClasses.SELECTED); - }), - (d.prototype.setSelected = function(t) { - this.setSelected_(t), this.notifySelection_(t); - }), - (d.prototype.setSelectedFromChipSet = function(t, e) { - this.setSelected_(t), e && this.notifyIgnoredSelection_(t); - }), - (d.prototype.getShouldRemoveOnTrailingIconClick = function() { - return this.shouldRemoveOnTrailingIconClick_; - }), - (d.prototype.setShouldRemoveOnTrailingIconClick = function(t) { - this.shouldRemoveOnTrailingIconClick_ = t; - }), - (d.prototype.getDimensions = function() { - function t() { - return e.adapter_.getRootBoundingClientRect(); - } - var e = this; - if (!this.adapter_.hasLeadingIcon()) { - var n = e.adapter_.getCheckmarkBoundingClientRect(); - if (n) { - var i = t(); - return { - bottom: i.bottom, - height: i.height, - left: i.left, - right: i.right, - top: i.top, - width: i.width + n.height - }; - } - } - return t(); - }), - (d.prototype.beginExit = function() { - this.adapter_.addClass(u.cssClasses.CHIP_EXIT); - }), - (d.prototype.handleInteraction = function(t) { - this.shouldHandleInteraction_(t) && - (this.adapter_.notifyInteraction(), this.focusPrimaryAction_()); - }), - (d.prototype.handleTransitionEnd = function(t) { - var e = this, - n = this.adapter_.eventTargetHasClass( - t.target, - u.cssClasses.CHIP_EXIT - ), - i = "width" === t.propertyName, - r = "opacity" === t.propertyName; - if (n && r) { - var o = this.adapter_.getComputedStyleValue("width"); - requestAnimationFrame(function() { - e.adapter_.setStyleProperty("width", o), - e.adapter_.setStyleProperty("padding", "0"), - e.adapter_.setStyleProperty("margin", "0"), - requestAnimationFrame(function() { - e.adapter_.setStyleProperty("width", "0"); - }); - }); - } else { - if (n && i) { - this.removeFocus_(); - var s = this.adapter_.getAttribute( - u.strings.REMOVED_ANNOUNCEMENT_ATTRIBUTE - ); - this.adapter_.notifyRemoval(s); - } - if (r) { - var a = - this.adapter_.eventTargetHasClass( - t.target, - u.cssClasses.LEADING_ICON - ) && this.adapter_.hasClass(u.cssClasses.SELECTED), - c = - this.adapter_.eventTargetHasClass( - t.target, - u.cssClasses.CHECKMARK - ) && !this.adapter_.hasClass(u.cssClasses.SELECTED); - return a - ? this.adapter_.addClassToLeadingIcon( - u.cssClasses.HIDDEN_LEADING_ICON - ) - : c - ? this.adapter_.removeClassFromLeadingIcon( - u.cssClasses.HIDDEN_LEADING_ICON - ) - : void 0; - } - } - }), - (d.prototype.handleFocusIn = function(t) { - this.eventFromPrimaryAction_(t) && - this.adapter_.addClass(u.cssClasses.PRIMARY_ACTION_FOCUSED); - }), - (d.prototype.handleFocusOut = function(t) { - this.eventFromPrimaryAction_(t) && - this.adapter_.removeClass(u.cssClasses.PRIMARY_ACTION_FOCUSED); - }), - (d.prototype.handleTrailingIconInteraction = function(t) { - this.shouldHandleInteraction_(t) && - (this.adapter_.notifyTrailingIconInteraction(), - this.removeChip_(t)); - }), - (d.prototype.handleKeydown = function(t) { - if (this.shouldRemoveChip_(t)) return this.removeChip_(t); - var e = t.key; - u.navigationKeys.has(e) && - (t.preventDefault(), this.focusNextAction_(t)); - }), - (d.prototype.removeFocus = function() { - this.adapter_.setPrimaryActionAttr(u.strings.TAB_INDEX, "-1"), - this.adapter_.setTrailingActionAttr(u.strings.TAB_INDEX, "-1"); - }), - (d.prototype.focusPrimaryAction = function() { - this.focusPrimaryAction_(); - }), - (d.prototype.focusTrailingAction = function() { - if (!this.adapter_.hasTrailingAction()) - return this.focusPrimaryAction_(); - this.focusTrailingAction_(); - }), - (d.prototype.focusNextAction_ = function(t) { - var e = t.key, - n = this.adapter_.hasTrailingAction(), - i = this.getDirection_(e), - r = this.getEvtSource_(t); - if (!u.jumpChipKeys.has(e) && n) - return r === u.EventSource.PRIMARY && i === u.Direction.RIGHT - ? this.focusTrailingAction_() - : r === u.EventSource.TRAILING && i === u.Direction.LEFT - ? this.focusPrimaryAction_() - : void this.adapter_.notifyNavigation(e, u.EventSource.NONE); - this.adapter_.notifyNavigation(e, r); - }), - (d.prototype.getEvtSource_ = function(t) { - return this.adapter_.eventTargetHasClass( - t.target, - u.cssClasses.PRIMARY_ACTION - ) - ? u.EventSource.PRIMARY - : this.adapter_.eventTargetHasClass( - t.target, - u.cssClasses.TRAILING_ACTION - ) - ? u.EventSource.TRAILING - : u.EventSource.NONE; - }), - (d.prototype.getDirection_ = function(t) { - var e = this.adapter_.isRTL(), - n = - t === u.strings.ARROW_LEFT_KEY || - t === u.strings.IE_ARROW_LEFT_KEY, - i = - t === u.strings.ARROW_RIGHT_KEY || - t === u.strings.IE_ARROW_RIGHT_KEY; - return (!e && n) || (e && i) - ? u.Direction.LEFT - : u.Direction.RIGHT; - }), - (d.prototype.focusPrimaryAction_ = function() { - this.adapter_.setPrimaryActionAttr(u.strings.TAB_INDEX, "0"), - this.adapter_.focusPrimaryAction(), - this.adapter_.setTrailingActionAttr(u.strings.TAB_INDEX, "-1"); - }), - (d.prototype.focusTrailingAction_ = function() { - this.adapter_.setTrailingActionAttr(u.strings.TAB_INDEX, "0"), - this.adapter_.focusTrailingAction(), - this.adapter_.setPrimaryActionAttr(u.strings.TAB_INDEX, "-1"); - }), - (d.prototype.removeFocus_ = function() { - this.adapter_.setTrailingActionAttr(u.strings.TAB_INDEX, "-1"), - this.adapter_.setPrimaryActionAttr(u.strings.TAB_INDEX, "-1"); - }), - (d.prototype.removeChip_ = function(t) { - t.stopPropagation(), - t.preventDefault(), - this.shouldRemoveOnTrailingIconClick_ && this.beginExit(); - }), - (d.prototype.shouldHandleInteraction_ = function(t) { - if ("click" === t.type) return !0; - var e = t; - return ( - e.key === u.strings.ENTER_KEY || - e.key === u.strings.SPACEBAR_KEY - ); - }), - (d.prototype.shouldRemoveChip_ = function(t) { - return ( - this.adapter_.hasClass(u.cssClasses.DELETABLE) && - (t.key === u.strings.BACKSPACE_KEY || - t.key === u.strings.DELETE_KEY || - t.key === u.strings.IE_DELETE_KEY) - ); - }), - (d.prototype.setSelected_ = function(t) { - t - ? (this.adapter_.addClass(u.cssClasses.SELECTED), - this.adapter_.setPrimaryActionAttr( - u.strings.ARIA_CHECKED, - "true" - )) - : (this.adapter_.removeClass(u.cssClasses.SELECTED), - this.adapter_.setPrimaryActionAttr( - u.strings.ARIA_CHECKED, - "false" - )); - }), - (d.prototype.notifySelection_ = function(t) { - this.adapter_.notifySelection(t, !1); - }), - (d.prototype.notifyIgnoredSelection_ = function(t) { - this.adapter_.notifySelection(t, !0); - }), - (d.prototype.eventFromPrimaryAction_ = function(t) { - return this.adapter_.eventTargetHasClass( - t.target, - u.cssClasses.PRIMARY_ACTION - ); - }), - d); - function d(t) { - var e = s.call(this, o(o({}, d.defaultAdapter), t)) || this; - return (e.shouldRemoveOnTrailingIconClick_ = !0), e; - } - (e.MDCChipFoundation = l), (e.default = l); - }, - function(t, e, n) { - "use strict"; - var i; - Object.defineProperty(e, "__esModule", { value: !0 }), - (e.cssClasses = { - CELL: "mdc-data-table__cell", - CELL_NUMERIC: "mdc-data-table__cell--numeric", - CONTENT: "mdc-data-table__content", - HEADER_CELL_SORTED: "mdc-data-table__header-cell--sorted", - HEADER_CELL_SORTED_DESCENDING: - "mdc-data-table__header-cell--sorted-descending", - HEADER_CELL_WITH_SORT: "mdc-data-table__header-cell--with-sort", - HEADER_ROW: "mdc-data-table__header-row", - HEADER_ROW_CHECKBOX: "mdc-data-table__header-row-checkbox", - IN_PROGRESS: "mdc-data-table--in-progress", - ROOT: "mdc-data-table", - ROW: "mdc-data-table__row", - ROW_CHECKBOX: "mdc-data-table__row-checkbox", - ROW_SELECTED: "mdc-data-table__row--selected", - SORT_ICON_BUTTON: "mdc-data-table__sort-icon-button" - }), - (e.dataAttributes = { - ROW_ID: "data-row-id", - COLUMND_ID: "data-columnd-id" - }), - (e.strings = { - ARIA_SELECTED: "aria-selected", - ARIA_SORT: "aria-sort", - DATA_ROW_ID_ATTR: e.dataAttributes.ROW_ID, - HEADER_ROW_CHECKBOX_SELECTOR: - "." + e.cssClasses.HEADER_ROW_CHECKBOX, - ROW_CHECKBOX_SELECTOR: "." + e.cssClasses.ROW_CHECKBOX, - ROW_SELECTED_SELECTOR: "." + e.cssClasses.ROW_SELECTED, - ROW_SELECTOR: "." + e.cssClasses.ROW - }), - ((i = e.SortValue || (e.SortValue = {})).ASCENDING = "ascending"), - (i.DESCENDING = "descending"), - (i.NONE = "none"), - (i.OTHER = "other"), - (e.events = { - ROW_SELECTION_CHANGED: "MDCDataTable:rowSelectionChanged", - SELECTED_ALL: "MDCDataTable:selectedAll", - UNSELECTED_ALL: "MDCDataTable:unselectedAll", - SORTED: "MDCDataTable:sorted" - }); - }, - function(t, e, n) { - "use strict"; - Object.defineProperty(e, "__esModule", { value: !0 }); - var o = "mdc-dom-focus-sentinel", - i = - ((r.prototype.trapFocus = function() { - var t = this.getFocusableElements(this.root); - if (0 === t.length) - throw new Error( - "FocusTrap: Element must have at least one focusable child." - ); - (this.elFocusedBeforeTrapFocus = - document.activeElement instanceof HTMLElement - ? document.activeElement - : null), - this.wrapTabFocus(this.root, t), - this.options.skipInitialFocus || - this.focusInitialElement(t, this.options.initialFocusEl); - }), - (r.prototype.releaseFocus = function() { - [].slice - .call(this.root.querySelectorAll("." + o)) - .forEach(function(t) { - t.parentElement.removeChild(t); - }), - this.elFocusedBeforeTrapFocus && - this.elFocusedBeforeTrapFocus.focus(); - }), - (r.prototype.wrapTabFocus = function(t, e) { - var n = this.createSentinel(), - i = this.createSentinel(); - n.addEventListener("focus", function() { - 0 < e.length && e[e.length - 1].focus(); - }), - i.addEventListener("focus", function() { - 0 < e.length && e[0].focus(); - }), - t.insertBefore(n, t.children[0]), - t.appendChild(i); - }), - (r.prototype.focusInitialElement = function(t, e) { - var n = 0; - e && (n = Math.max(t.indexOf(e), 0)), t[n].focus(); - }), - (r.prototype.getFocusableElements = function(t) { - return [].slice - .call( - t.querySelectorAll( - "[autofocus], [tabindex], a, input, textarea, select, button" - ) - ) - .filter(function(t) { - var e = - "true" === t.getAttribute("aria-disabled") || - null != t.getAttribute("disabled") || - null != t.getAttribute("hidden") || - "true" === t.getAttribute("aria-hidden"), - n = - 0 <= t.tabIndex && - 0 < t.getBoundingClientRect().width && - !t.classList.contains(o) && - !e, - i = !1; - if (n) { - var r = getComputedStyle(t); - i = "none" === r.display || "hidden" === r.visibility; - } - return n && !i; - }); - }), - (r.prototype.createSentinel = function() { - var t = document.createElement("div"); - return ( - t.setAttribute("tabindex", "0"), - t.setAttribute("aria-hidden", "true"), - t.classList.add(o), - t - ); - }), - r); - function r(t, e) { - void 0 === e && (e = {}), - (this.root = t), - (this.options = e), - (this.elFocusedBeforeTrapFocus = null); - } - e.FocusTrap = i; - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }); - Object.defineProperty(e, "__esModule", { value: !0 }); - var o, - s = n(1), - a = n(2), - c = n(9), - u = n(10), - l = - ((o = s.MDCComponent), - r(d, o), - Object.defineProperty(d.prototype, "vertical", { - set: function(t) { - this.foundation_.setVerticalOrientation(t); - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(d.prototype, "listElements", { - get: function() { - return [].slice.call( - this.root_.querySelectorAll( - "." + c.cssClasses.LIST_ITEM_CLASS - ) - ); - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(d.prototype, "wrapFocus", { - set: function(t) { - this.foundation_.setWrapFocus(t); - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(d.prototype, "singleSelection", { - set: function(t) { - this.foundation_.setSingleSelection(t); - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(d.prototype, "selectedIndex", { - get: function() { - return this.foundation_.getSelectedIndex(); - }, - set: function(t) { - this.foundation_.setSelectedIndex(t); - }, - enumerable: !0, - configurable: !0 - }), - (d.attachTo = function(t) { - return new d(t); - }), - (d.prototype.initialSyncWithDOM = function() { - (this.handleClick_ = this.handleClickEvent_.bind(this)), - (this.handleKeydown_ = this.handleKeydownEvent_.bind(this)), - (this.focusInEventListener_ = this.handleFocusInEvent_.bind( - this - )), - (this.focusOutEventListener_ = this.handleFocusOutEvent_.bind( - this - )), - this.listen("keydown", this.handleKeydown_), - this.listen("click", this.handleClick_), - this.listen("focusin", this.focusInEventListener_), - this.listen("focusout", this.focusOutEventListener_), - this.layout(), - this.initializeListType(); - }), - (d.prototype.destroy = function() { - this.unlisten("keydown", this.handleKeydown_), - this.unlisten("click", this.handleClick_), - this.unlisten("focusin", this.focusInEventListener_), - this.unlisten("focusout", this.focusOutEventListener_); - }), - (d.prototype.layout = function() { - var t = this.root_.getAttribute(c.strings.ARIA_ORIENTATION); - (this.vertical = t !== c.strings.ARIA_ORIENTATION_HORIZONTAL), - [].slice - .call( - this.root_.querySelectorAll( - ".mdc-list-item:not([tabindex])" - ) - ) - .forEach(function(t) { - t.setAttribute("tabindex", "-1"); - }), - [].slice - .call( - this.root_.querySelectorAll( - c.strings.FOCUSABLE_CHILD_ELEMENTS - ) - ) - .forEach(function(t) { - return t.setAttribute("tabindex", "-1"); - }), - this.foundation_.layout(); - }), - (d.prototype.initializeListType = function() { - var e = this, - t = this.root_.querySelectorAll( - c.strings.ARIA_ROLE_CHECKBOX_SELECTOR - ), - n = this.root_.querySelector( - "\n ." + - c.cssClasses.LIST_ITEM_ACTIVATED_CLASS + - ",\n ." + - c.cssClasses.LIST_ITEM_SELECTED_CLASS + - "\n " - ), - i = this.root_.querySelector( - c.strings.ARIA_CHECKED_RADIO_SELECTOR - ); - if (t.length) { - var r = this.root_.querySelectorAll( - c.strings.ARIA_CHECKED_CHECKBOX_SELECTOR - ); - this.selectedIndex = [].map.call(r, function(t) { - return e.listElements.indexOf(t); - }); - } else - n - ? (n.classList.contains( - c.cssClasses.LIST_ITEM_ACTIVATED_CLASS - ) && this.foundation_.setUseActivatedClass(!0), - (this.singleSelection = !0), - (this.selectedIndex = this.listElements.indexOf(n))) - : i && (this.selectedIndex = this.listElements.indexOf(i)); - }), - (d.prototype.setEnabled = function(t, e) { - this.foundation_.setEnabled(t, e); - }), - (d.prototype.getDefaultFoundation = function() { - var r = this, - t = { - addClassForElementIndex: function(t, e) { - var n = r.listElements[t]; - n && n.classList.add(e); - }, - focusItemAtIndex: function(t) { - var e = r.listElements[t]; - e && e.focus(); - }, - getAttributeForElementIndex: function(t, e) { - return r.listElements[t].getAttribute(e); - }, - getFocusedElementIndex: function() { - return r.listElements.indexOf(document.activeElement); - }, - getListItemCount: function() { - return r.listElements.length; - }, - hasCheckboxAtIndex: function(t) { - return !!r.listElements[t].querySelector( - c.strings.CHECKBOX_SELECTOR - ); - }, - hasRadioAtIndex: function(t) { - return !!r.listElements[t].querySelector( - c.strings.RADIO_SELECTOR - ); - }, - isCheckboxCheckedAtIndex: function(t) { - return r.listElements[t].querySelector( - c.strings.CHECKBOX_SELECTOR - ).checked; - }, - isFocusInsideList: function() { - return r.root_.contains(document.activeElement); - }, - isRootFocused: function() { - return document.activeElement === r.root_; - }, - listItemAtIndexHasClass: function(t, e) { - return r.listElements[t].classList.contains(e); - }, - notifyAction: function(t) { - r.emit(c.strings.ACTION_EVENT, { index: t }, !0); - }, - removeClassForElementIndex: function(t, e) { - var n = r.listElements[t]; - n && n.classList.remove(e); - }, - setAttributeForElementIndex: function(t, e, n) { - var i = r.listElements[t]; - i && i.setAttribute(e, n); - }, - setCheckedCheckboxOrRadioAtIndex: function(t, e) { - var n = r.listElements[t].querySelector( - c.strings.CHECKBOX_RADIO_SELECTOR - ); - n.checked = e; - var i = document.createEvent("Event"); - i.initEvent("change", !0, !0), n.dispatchEvent(i); - }, - setTabIndexForListItemChildren: function(t, e) { - var n = r.listElements[t]; - [].slice - .call( - n.querySelectorAll( - c.strings.CHILD_ELEMENTS_TO_TOGGLE_TABINDEX - ) - ) - .forEach(function(t) { - return t.setAttribute("tabindex", e); - }); - } - }; - return new u.MDCListFoundation(t); - }), - (d.prototype.getListItemIndex_ = function(t) { - var e = t.target, - n = a.closest( - e, - "." + c.cssClasses.LIST_ITEM_CLASS + ", ." + c.cssClasses.ROOT - ); - return n && a.matches(n, "." + c.cssClasses.LIST_ITEM_CLASS) - ? this.listElements.indexOf(n) - : -1; - }), - (d.prototype.handleFocusInEvent_ = function(t) { - var e = this.getListItemIndex_(t); - this.foundation_.handleFocusIn(t, e); - }), - (d.prototype.handleFocusOutEvent_ = function(t) { - var e = this.getListItemIndex_(t); - this.foundation_.handleFocusOut(t, e); - }), - (d.prototype.handleKeydownEvent_ = function(t) { - var e = this.getListItemIndex_(t), - n = t.target; - this.foundation_.handleKeydown( - t, - n.classList.contains(c.cssClasses.LIST_ITEM_CLASS), - e - ); - }), - (d.prototype.handleClickEvent_ = function(t) { - var e = this.getListItemIndex_(t), - n = t.target, - i = !a.matches(n, c.strings.CHECKBOX_RADIO_SELECTOR); - this.foundation_.handleClick(e, i); - }), - d); - function d() { - return (null !== o && o.apply(this, arguments)) || this; - } - e.MDCList = l; - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }), - o = - (this && this.__assign) || - function() { - return (o = - Object.assign || - function(t) { - for (var e, n = 1, i = arguments.length; n < i; n++) - for (var r in (e = arguments[n])) - Object.prototype.hasOwnProperty.call(e, r) && - (t[r] = e[r]); - return t; - }).apply(this, arguments); - }; - Object.defineProperty(e, "__esModule", { value: !0 }); - var s, - a = n(0), - c = n(54), - u = - ((s = a.MDCFoundation), - r(l, s), - Object.defineProperty(l, "strings", { - get: function() { - return c.strings; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(l, "cssClasses", { - get: function() { - return c.cssClasses; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(l, "defaultAdapter", { - get: function() { - return { - addClass: function() {}, - removeClass: function() {}, - hasClass: function() { - return !1; - }, - elementHasClass: function() { - return !1; - }, - notifyClose: function() {}, - notifyOpen: function() {}, - saveFocus: function() {}, - restoreFocus: function() {}, - focusActiveNavigationItem: function() {}, - trapFocus: function() {}, - releaseFocus: function() {} - }; - }, - enumerable: !0, - configurable: !0 - }), - (l.prototype.destroy = function() { - this.animationFrame_ && - cancelAnimationFrame(this.animationFrame_), - this.animationTimer_ && clearTimeout(this.animationTimer_); - }), - (l.prototype.open = function() { - var t = this; - this.isOpen() || - this.isOpening() || - this.isClosing() || - (this.adapter_.addClass(c.cssClasses.OPEN), - this.adapter_.addClass(c.cssClasses.ANIMATE), - this.runNextAnimationFrame_(function() { - t.adapter_.addClass(c.cssClasses.OPENING); - }), - this.adapter_.saveFocus()); - }), - (l.prototype.close = function() { - !this.isOpen() || - this.isOpening() || - this.isClosing() || - this.adapter_.addClass(c.cssClasses.CLOSING); - }), - (l.prototype.isOpen = function() { - return this.adapter_.hasClass(c.cssClasses.OPEN); - }), - (l.prototype.isOpening = function() { - return ( - this.adapter_.hasClass(c.cssClasses.OPENING) || - this.adapter_.hasClass(c.cssClasses.ANIMATE) - ); - }), - (l.prototype.isClosing = function() { - return this.adapter_.hasClass(c.cssClasses.CLOSING); - }), - (l.prototype.handleKeydown = function(t) { - var e = t.keyCode; - ("Escape" !== t.key && 27 !== e) || this.close(); - }), - (l.prototype.handleTransitionEnd = function(t) { - var e = c.cssClasses.OPENING, - n = c.cssClasses.CLOSING, - i = c.cssClasses.OPEN, - r = c.cssClasses.ANIMATE, - o = c.cssClasses.ROOT; - this.isElement_(t.target) && - this.adapter_.elementHasClass(t.target, o) && - (this.isClosing() - ? (this.adapter_.removeClass(i), - this.closed_(), - this.adapter_.restoreFocus(), - this.adapter_.notifyClose()) - : (this.adapter_.focusActiveNavigationItem(), - this.opened_(), - this.adapter_.notifyOpen()), - this.adapter_.removeClass(r), - this.adapter_.removeClass(e), - this.adapter_.removeClass(n)); - }), - (l.prototype.opened_ = function() {}), - (l.prototype.closed_ = function() {}), - (l.prototype.runNextAnimationFrame_ = function(t) { - var e = this; - cancelAnimationFrame(this.animationFrame_), - (this.animationFrame_ = requestAnimationFrame(function() { - (e.animationFrame_ = 0), - clearTimeout(e.animationTimer_), - (e.animationTimer_ = setTimeout(t, 0)); - })); - }), - (l.prototype.isElement_ = function(t) { - return Boolean(t.classList); - }), - l); - function l(t) { - var e = s.call(this, o(o({}, l.defaultAdapter), t)) || this; - return (e.animationFrame_ = 0), (e.animationTimer_ = 0), e; - } - (e.MDCDismissibleDrawerFoundation = u), (e.default = u); - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }); - Object.defineProperty(e, "__esModule", { value: !0 }); - var o, - s = n(1), - a = n(2), - c = n(25), - u = - ((o = s.MDCComponent), - r(l, o), - (l.attachTo = function(t) { - return new l(t); - }), - (l.prototype.shake = function(t) { - this.foundation_.shake(t); - }), - (l.prototype.float = function(t) { - this.foundation_.float(t); - }), - (l.prototype.getWidth = function() { - return this.foundation_.getWidth(); - }), - (l.prototype.getDefaultFoundation = function() { - var n = this, - t = { - addClass: function(t) { - return n.root_.classList.add(t); - }, - removeClass: function(t) { - return n.root_.classList.remove(t); - }, - getWidth: function() { - return a.estimateScrollWidth(n.root_); - }, - registerInteractionHandler: function(t, e) { - return n.listen(t, e); - }, - deregisterInteractionHandler: function(t, e) { - return n.unlisten(t, e); - } - }; - return new c.MDCFloatingLabelFoundation(t); - }), - l); - function l() { - return (null !== o && o.apply(this, arguments)) || this; - } - e.MDCFloatingLabel = u; - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }), - o = - (this && this.__assign) || - function() { - return (o = - Object.assign || - function(t) { - for (var e, n = 1, i = arguments.length; n < i; n++) - for (var r in (e = arguments[n])) - Object.prototype.hasOwnProperty.call(e, r) && - (t[r] = e[r]); - return t; - }).apply(this, arguments); - }; - Object.defineProperty(e, "__esModule", { value: !0 }); - var s, - a = n(0), - c = n(56), - u = - ((s = a.MDCFoundation), - r(l, s), - Object.defineProperty(l, "cssClasses", { - get: function() { - return c.cssClasses; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(l, "defaultAdapter", { - get: function() { - return { - addClass: function() {}, - removeClass: function() {}, - getWidth: function() { - return 0; - }, - registerInteractionHandler: function() {}, - deregisterInteractionHandler: function() {} - }; - }, - enumerable: !0, - configurable: !0 - }), - (l.prototype.init = function() { - this.adapter_.registerInteractionHandler( - "animationend", - this.shakeAnimationEndHandler_ - ); - }), - (l.prototype.destroy = function() { - this.adapter_.deregisterInteractionHandler( - "animationend", - this.shakeAnimationEndHandler_ - ); - }), - (l.prototype.getWidth = function() { - return this.adapter_.getWidth(); - }), - (l.prototype.shake = function(t) { - var e = l.cssClasses.LABEL_SHAKE; - t ? this.adapter_.addClass(e) : this.adapter_.removeClass(e); - }), - (l.prototype.float = function(t) { - var e = l.cssClasses, - n = e.LABEL_FLOAT_ABOVE, - i = e.LABEL_SHAKE; - t - ? this.adapter_.addClass(n) - : (this.adapter_.removeClass(n), this.adapter_.removeClass(i)); - }), - (l.prototype.handleShakeAnimationEnd_ = function() { - var t = l.cssClasses.LABEL_SHAKE; - this.adapter_.removeClass(t); - }), - l); - function l(t) { - var e = s.call(this, o(o({}, l.defaultAdapter), t)) || this; - return ( - (e.shakeAnimationEndHandler_ = function() { - return e.handleShakeAnimationEnd_(); - }), - e - ); - } - (e.MDCFloatingLabelFoundation = u), (e.default = u); - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }); - Object.defineProperty(e, "__esModule", { value: !0 }); - var o, - s = n(1), - a = n(61), - c = - ((o = s.MDCComponent), - r(u, o), - (u.attachTo = function(t) { - return new u(t); - }), - (u.prototype.activate = function() { - this.foundation_.activate(); - }), - (u.prototype.deactivate = function() { - this.foundation_.deactivate(); - }), - (u.prototype.setRippleCenter = function(t) { - this.foundation_.setRippleCenter(t); - }), - (u.prototype.getDefaultFoundation = function() { - var n = this, - t = { - addClass: function(t) { - return n.root_.classList.add(t); - }, - removeClass: function(t) { - return n.root_.classList.remove(t); - }, - hasClass: function(t) { - return n.root_.classList.contains(t); - }, - setStyle: function(t, e) { - return n.root_.style.setProperty(t, e); - }, - registerEventHandler: function(t, e) { - return n.listen(t, e); - }, - deregisterEventHandler: function(t, e) { - return n.unlisten(t, e); - } - }; - return new a.MDCLineRippleFoundation(t); - }), - u); - function u() { - return (null !== o && o.apply(this, arguments)) || this; - } - e.MDCLineRipple = c; - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }); - Object.defineProperty(e, "__esModule", { value: !0 }); - var o, - s = n(1), - a = n(25), - c = n(28), - u = n(69), - l = - ((o = s.MDCComponent), - r(d, o), - (d.attachTo = function(t) { - return new d(t); - }), - (d.prototype.initialSyncWithDOM = function() { - this.notchElement_ = this.root_.querySelector( - c.strings.NOTCH_ELEMENT_SELECTOR - ); - var t = this.root_.querySelector( - "." + a.MDCFloatingLabelFoundation.cssClasses.ROOT - ); - t - ? ((t.style.transitionDuration = "0s"), - this.root_.classList.add(c.cssClasses.OUTLINE_UPGRADED), - requestAnimationFrame(function() { - t.style.transitionDuration = ""; - })) - : this.root_.classList.add(c.cssClasses.NO_LABEL); - }), - (d.prototype.notch = function(t) { - this.foundation_.notch(t); - }), - (d.prototype.closeNotch = function() { - this.foundation_.closeNotch(); - }), - (d.prototype.getDefaultFoundation = function() { - var e = this, - t = { - addClass: function(t) { - return e.root_.classList.add(t); - }, - removeClass: function(t) { - return e.root_.classList.remove(t); - }, - setNotchWidthProperty: function(t) { - return e.notchElement_.style.setProperty("width", t + "px"); - }, - removeNotchWidthProperty: function() { - return e.notchElement_.style.removeProperty("width"); - } - }; - return new u.MDCNotchedOutlineFoundation(t); - }), - d); - function d() { - return (null !== o && o.apply(this, arguments)) || this; - } - e.MDCNotchedOutline = l; - }, - function(t, e, n) { - "use strict"; - Object.defineProperty(e, "__esModule", { value: !0 }); - e.strings = { NOTCH_ELEMENT_SELECTOR: ".mdc-notched-outline__notch" }; - e.numbers = { NOTCH_ELEMENT_PADDING: 8 }; - e.cssClasses = { - NO_LABEL: "mdc-notched-outline--no-label", - OUTLINE_NOTCHED: "mdc-notched-outline--notched", - OUTLINE_UPGRADED: "mdc-notched-outline--upgraded" - }; - }, - function(t, e, n) { - "use strict"; - Object.defineProperty(e, "__esModule", { value: !0 }); - var i = { - ACTIVATED: "mdc-select--activated", - DISABLED: "mdc-select--disabled", - FOCUSED: "mdc-select--focused", - INVALID: "mdc-select--invalid", - OUTLINED: "mdc-select--outlined", - REQUIRED: "mdc-select--required", - ROOT: "mdc-select", - SELECTED_ITEM_CLASS: "mdc-list-item--selected", - WITH_LEADING_ICON: "mdc-select--with-leading-icon" - }, - r = { - ARIA_CONTROLS: "aria-controls", - ARIA_SELECTED_ATTR: "aria-selected", - CHANGE_EVENT: "MDCSelect:change", - LABEL_SELECTOR: ".mdc-floating-label", - LEADING_ICON_SELECTOR: ".mdc-select__icon", - LINE_RIPPLE_SELECTOR: ".mdc-line-ripple", - MENU_SELECTOR: ".mdc-select__menu", - OUTLINE_SELECTOR: ".mdc-notched-outline", - SELECTED_ITEM_SELECTOR: - "." + (e.cssClasses = i).SELECTED_ITEM_CLASS, - SELECTED_TEXT_SELECTOR: ".mdc-select__selected-text", - SELECT_ANCHOR_SELECTOR: ".mdc-select__anchor", - VALUE_ATTR: "data-value" - }; - e.strings = r; - e.numbers = { LABEL_SCALE: 0.75, UNSET_INDEX: -1 }; - }, - function(t, e, n) { - "use strict"; - Object.defineProperty(e, "__esModule", { value: !0 }); - e.cssClasses = { - ACTIVE: "mdc-slider--active", - DISABLED: "mdc-slider--disabled", - DISCRETE: "mdc-slider--discrete", - FOCUS: "mdc-slider--focus", - HAS_TRACK_MARKER: "mdc-slider--display-markers", - IN_TRANSIT: "mdc-slider--in-transit", - IS_DISCRETE: "mdc-slider--discrete" - }; - e.strings = { - ARIA_DISABLED: "aria-disabled", - ARIA_VALUEMAX: "aria-valuemax", - ARIA_VALUEMIN: "aria-valuemin", - ARIA_VALUENOW: "aria-valuenow", - CHANGE_EVENT: "MDCSlider:change", - INPUT_EVENT: "MDCSlider:input", - PIN_VALUE_MARKER_SELECTOR: ".mdc-slider__pin-value-marker", - STEP_DATA_ATTR: "data-step", - THUMB_CONTAINER_SELECTOR: ".mdc-slider__thumb-container", - TRACK_MARKER_CONTAINER_SELECTOR: - ".mdc-slider__track-marker-container", - TRACK_SELECTOR: ".mdc-slider__track" - }; - e.numbers = { PAGE_FACTOR: 4 }; - }, - function(t, e, n) { - "use strict"; - Object.defineProperty(e, "__esModule", { value: !0 }); - e.cssClasses = { - ANIMATING: "mdc-tab-scroller--animating", - SCROLL_AREA_SCROLL: "mdc-tab-scroller__scroll-area--scroll", - SCROLL_TEST: "mdc-tab-scroller__test" - }; - e.strings = { - AREA_SELECTOR: ".mdc-tab-scroller__scroll-area", - CONTENT_SELECTOR: ".mdc-tab-scroller__scroll-content" - }; - }, - function(t, e, n) { - "use strict"; - Object.defineProperty(e, "__esModule", { value: !0 }); - function i(t) { - this.adapter_ = t; - } - (e.MDCTabScrollerRTL = i), (e.default = i); - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }), - o = - (this && this.__assign) || - function() { - return (o = - Object.assign || - function(t) { - for (var e, n = 1, i = arguments.length; n < i; n++) - for (var r in (e = arguments[n])) - Object.prototype.hasOwnProperty.call(e, r) && - (t[r] = e[r]); - return t; - }).apply(this, arguments); - }; - Object.defineProperty(e, "__esModule", { value: !0 }); - var s, - a = n(0), - c = n(92), - u = - ((s = a.MDCFoundation), - r(l, s), - Object.defineProperty(l, "cssClasses", { - get: function() { - return c.cssClasses; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(l, "strings", { - get: function() { - return c.strings; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(l, "defaultAdapter", { - get: function() { - return { - addClass: function() {}, - removeClass: function() {}, - hasClass: function() { - return !1; - }, - setAttr: function() {}, - activateIndicator: function() {}, - deactivateIndicator: function() {}, - notifyInteracted: function() {}, - getOffsetLeft: function() { - return 0; - }, - getOffsetWidth: function() { - return 0; - }, - getContentOffsetLeft: function() { - return 0; - }, - getContentOffsetWidth: function() { - return 0; - }, - focus: function() {} - }; - }, - enumerable: !0, - configurable: !0 - }), - (l.prototype.handleClick = function() { - this.adapter_.notifyInteracted(); - }), - (l.prototype.isActive = function() { - return this.adapter_.hasClass(c.cssClasses.ACTIVE); - }), - (l.prototype.setFocusOnActivate = function(t) { - this.focusOnActivate_ = t; - }), - (l.prototype.activate = function(t) { - this.adapter_.addClass(c.cssClasses.ACTIVE), - this.adapter_.setAttr(c.strings.ARIA_SELECTED, "true"), - this.adapter_.setAttr(c.strings.TABINDEX, "0"), - this.adapter_.activateIndicator(t), - this.focusOnActivate_ && this.adapter_.focus(); - }), - (l.prototype.deactivate = function() { - this.isActive() && - (this.adapter_.removeClass(c.cssClasses.ACTIVE), - this.adapter_.setAttr(c.strings.ARIA_SELECTED, "false"), - this.adapter_.setAttr(c.strings.TABINDEX, "-1"), - this.adapter_.deactivateIndicator()); - }), - (l.prototype.computeDimensions = function() { - var t = this.adapter_.getOffsetWidth(), - e = this.adapter_.getOffsetLeft(), - n = this.adapter_.getContentOffsetWidth(), - i = this.adapter_.getContentOffsetLeft(); - return { - contentLeft: e + i, - contentRight: e + i + n, - rootLeft: e, - rootRight: e + t - }; - }), - l); - function l(t) { - var e = s.call(this, o(o({}, l.defaultAdapter), t)) || this; - return (e.focusOnActivate_ = !0), e; - } - (e.MDCTabFoundation = u), (e.default = u); - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }), - o = - (this && this.__assign) || - function() { - return (o = - Object.assign || - function(t) { - for (var e, n = 1, i = arguments.length; n < i; n++) - for (var r in (e = arguments[n])) - Object.prototype.hasOwnProperty.call(e, r) && - (t[r] = e[r]); - return t; - }).apply(this, arguments); - }; - Object.defineProperty(e, "__esModule", { value: !0 }); - var s, - a = n(0), - c = n(96), - u = - ((s = a.MDCFoundation), - r(l, s), - Object.defineProperty(l, "cssClasses", { - get: function() { - return c.cssClasses; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(l, "strings", { - get: function() { - return c.strings; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(l, "defaultAdapter", { - get: function() { - return { setContent: function() {} }; - }, - enumerable: !0, - configurable: !0 - }), - (l.prototype.setCounterValue = function(t, e) { - (t = Math.min(t, e)), this.adapter_.setContent(t + " / " + e); - }), - l); - function l(t) { - return s.call(this, o(o({}, l.defaultAdapter), t)) || this; - } - (e.MDCTextFieldCharacterCounterFoundation = u), (e.default = u); - }, - function(t, e, n) { - "use strict"; - Object.defineProperty(e, "__esModule", { value: !0 }); - e.strings = { - ARIA_CONTROLS: "aria-controls", - INPUT_SELECTOR: ".mdc-text-field__input", - LABEL_SELECTOR: ".mdc-floating-label", - LEADING_ICON_SELECTOR: ".mdc-text-field__icon--leading", - LINE_RIPPLE_SELECTOR: ".mdc-line-ripple", - OUTLINE_SELECTOR: ".mdc-notched-outline", - PREFIX_SELECTOR: ".mdc-text-field__affix--prefix", - SUFFIX_SELECTOR: ".mdc-text-field__affix--suffix", - TRAILING_ICON_SELECTOR: ".mdc-text-field__icon--trailing" - }; - e.cssClasses = { - DISABLED: "mdc-text-field--disabled", - FOCUSED: "mdc-text-field--focused", - FULLWIDTH: "mdc-text-field--fullwidth", - HELPER_LINE: "mdc-text-field-helper-line", - INVALID: "mdc-text-field--invalid", - LABEL_FLOATING: "mdc-text-field--label-floating", - NO_LABEL: "mdc-text-field--no-label", - OUTLINED: "mdc-text-field--outlined", - ROOT: "mdc-text-field", - TEXTAREA: "mdc-text-field--textarea", - WITH_LEADING_ICON: "mdc-text-field--with-leading-icon", - WITH_TRAILING_ICON: "mdc-text-field--with-trailing-icon" - }; - e.numbers = { LABEL_SCALE: 0.75 }; - e.VALIDATION_ATTR_WHITELIST = [ - "pattern", - "min", - "max", - "required", - "step", - "minlength", - "maxlength" - ]; - e.ALWAYS_FLOAT_TYPES = [ - "color", - "date", - "datetime-local", - "month", - "range", - "time", - "week" - ]; - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }), - o = - (this && this.__assign) || - function() { - return (o = - Object.assign || - function(t) { - for (var e, n = 1, i = arguments.length; n < i; n++) - for (var r in (e = arguments[n])) - Object.prototype.hasOwnProperty.call(e, r) && - (t[r] = e[r]); - return t; - }).apply(this, arguments); - }; - Object.defineProperty(e, "__esModule", { value: !0 }); - var s, - a = n(0), - c = n(99), - u = - ((s = a.MDCFoundation), - r(l, s), - Object.defineProperty(l, "cssClasses", { - get: function() { - return c.cssClasses; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(l, "strings", { - get: function() { - return c.strings; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(l, "defaultAdapter", { - get: function() { - return { - addClass: function() {}, - removeClass: function() {}, - hasClass: function() { - return !1; - }, - setAttr: function() {}, - removeAttr: function() {}, - setContent: function() {} - }; - }, - enumerable: !0, - configurable: !0 - }), - (l.prototype.setContent = function(t) { - this.adapter_.setContent(t); - }), - (l.prototype.setPersistent = function(t) { - t - ? this.adapter_.addClass(c.cssClasses.HELPER_TEXT_PERSISTENT) - : this.adapter_.removeClass( - c.cssClasses.HELPER_TEXT_PERSISTENT - ); - }), - (l.prototype.setValidation = function(t) { - t - ? this.adapter_.addClass( - c.cssClasses.HELPER_TEXT_VALIDATION_MSG - ) - : this.adapter_.removeClass( - c.cssClasses.HELPER_TEXT_VALIDATION_MSG - ); - }), - (l.prototype.showToScreenReader = function() { - this.adapter_.removeAttr(c.strings.ARIA_HIDDEN); - }), - (l.prototype.setValidity = function(t) { - var e = this.adapter_.hasClass( - c.cssClasses.HELPER_TEXT_PERSISTENT - ), - n = - this.adapter_.hasClass( - c.cssClasses.HELPER_TEXT_VALIDATION_MSG - ) && !t; - n - ? this.adapter_.setAttr(c.strings.ROLE, "alert") - : this.adapter_.removeAttr(c.strings.ROLE), - e || n || this.hide_(); - }), - (l.prototype.hide_ = function() { - this.adapter_.setAttr(c.strings.ARIA_HIDDEN, "true"); - }), - l); - function l(t) { - return s.call(this, o(o({}, l.defaultAdapter), t)) || this; - } - (e.MDCTextFieldHelperTextFoundation = u), (e.default = u); - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }); - Object.defineProperty(e, "__esModule", { value: !0 }); - var o, - s = n(7), - a = n(38), - c = - ((o = a.MDCTopAppBarBaseFoundation), - r(u, o), - (u.prototype.destroy = function() { - o.prototype.destroy.call(this), this.adapter_.setStyle("top", ""); - }), - (u.prototype.handleTargetScroll = function() { - var t = Math.max(this.adapter_.getViewportScrollY(), 0), - e = t - this.lastScrollPosition_; - (this.lastScrollPosition_ = t), - this.isCurrentlyBeingResized_ || - ((this.currentAppBarOffsetTop_ -= e), - 0 < this.currentAppBarOffsetTop_ - ? (this.currentAppBarOffsetTop_ = 0) - : Math.abs(this.currentAppBarOffsetTop_) > - this.topAppBarHeight_ && - (this.currentAppBarOffsetTop_ = -this.topAppBarHeight_), - this.moveTopAppBar_()); - }), - (u.prototype.handleWindowResize = function() { - var t = this; - this.resizeThrottleId_ || - (this.resizeThrottleId_ = setTimeout(function() { - (t.resizeThrottleId_ = 0), t.throttledResizeHandler_(); - }, s.numbers.DEBOUNCE_THROTTLE_RESIZE_TIME_MS)), - (this.isCurrentlyBeingResized_ = !0), - this.resizeDebounceId_ && clearTimeout(this.resizeDebounceId_), - (this.resizeDebounceId_ = setTimeout(function() { - t.handleTargetScroll(), - (t.isCurrentlyBeingResized_ = !1), - (t.resizeDebounceId_ = 0); - }, s.numbers.DEBOUNCE_THROTTLE_RESIZE_TIME_MS)); - }), - (u.prototype.checkForUpdate_ = function() { - var t = -this.topAppBarHeight_, - e = this.currentAppBarOffsetTop_ < 0, - n = this.currentAppBarOffsetTop_ > t, - i = e && n; - if (i) this.wasDocked_ = !1; - else { - if (!this.wasDocked_) return (this.wasDocked_ = !0); - if (this.isDockedShowing_ !== n) - return (this.isDockedShowing_ = n), !0; - } - return i; - }), - (u.prototype.moveTopAppBar_ = function() { - if (this.checkForUpdate_()) { - var t = this.currentAppBarOffsetTop_; - Math.abs(t) >= this.topAppBarHeight_ && - (t = -s.numbers.MAX_TOP_APP_BAR_HEIGHT), - this.adapter_.setStyle("top", t + "px"); - } - }), - (u.prototype.throttledResizeHandler_ = function() { - var t = this.adapter_.getTopAppBarHeight(); - this.topAppBarHeight_ !== t && - ((this.wasDocked_ = !1), - (this.currentAppBarOffsetTop_ -= this.topAppBarHeight_ - t), - (this.topAppBarHeight_ = t)), - this.handleTargetScroll(); - }), - u); - function u(t) { - var e = o.call(this, t) || this; - return ( - (e.wasDocked_ = !0), - (e.isDockedShowing_ = !0), - (e.currentAppBarOffsetTop_ = 0), - (e.isCurrentlyBeingResized_ = !1), - (e.resizeThrottleId_ = 0), - (e.resizeDebounceId_ = 0), - (e.lastScrollPosition_ = e.adapter_.getViewportScrollY()), - (e.topAppBarHeight_ = e.adapter_.getTopAppBarHeight()), - e - ); - } - (e.MDCTopAppBarFoundation = c), (e.default = c); - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }), - o = - (this && this.__assign) || - function() { - return (o = - Object.assign || - function(t) { - for (var e, n = 1, i = arguments.length; n < i; n++) - for (var r in (e = arguments[n])) - Object.prototype.hasOwnProperty.call(e, r) && - (t[r] = e[r]); - return t; - }).apply(this, arguments); - }; - Object.defineProperty(e, "__esModule", { value: !0 }); - var s, - a = n(0), - c = n(7), - u = - ((s = a.MDCFoundation), - r(l, s), - Object.defineProperty(l, "strings", { - get: function() { - return c.strings; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(l, "cssClasses", { - get: function() { - return c.cssClasses; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(l, "numbers", { - get: function() { - return c.numbers; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(l, "defaultAdapter", { - get: function() { - return { - addClass: function() {}, - removeClass: function() {}, - hasClass: function() { - return !1; - }, - setStyle: function() {}, - getTopAppBarHeight: function() { - return 0; - }, - notifyNavigationIconClicked: function() {}, - getViewportScrollY: function() { - return 0; - }, - getTotalActionItems: function() { - return 0; - } - }; - }, - enumerable: !0, - configurable: !0 - }), - (l.prototype.handleTargetScroll = function() {}), - (l.prototype.handleWindowResize = function() {}), - (l.prototype.handleNavigationClick = function() { - this.adapter_.notifyNavigationIconClicked(); - }), - l); - function l(t) { - return s.call(this, o(o({}, l.defaultAdapter), t)) || this; - } - (e.MDCTopAppBarBaseFoundation = u), (e.default = u); - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }), - o = - (this && this.__assign) || - function() { - return (o = - Object.assign || - function(t) { - for (var e, n = 1, i = arguments.length; n < i; n++) - for (var r in (e = arguments[n])) - Object.prototype.hasOwnProperty.call(e, r) && - (t[r] = e[r]); - return t; - }).apply(this, arguments); - }; - Object.defineProperty(e, "__esModule", { value: !0 }); - var s, - a = n(15), - c = n(1), - u = n(5), - l = n(2), - d = n(3), - p = n(4), - _ = n(17), - f = n(41), - h = ["checked", "indeterminate"], - C = - ((s = c.MDCComponent), - r(y, s), - (y.attachTo = function(t) { - return new y(t); - }), - Object.defineProperty(y.prototype, "ripple", { - get: function() { - return this.ripple_; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(y.prototype, "checked", { - get: function() { - return this.nativeControl_.checked; - }, - set: function(t) { - this.nativeControl_.checked = t; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(y.prototype, "indeterminate", { - get: function() { - return this.nativeControl_.indeterminate; - }, - set: function(t) { - this.nativeControl_.indeterminate = t; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(y.prototype, "disabled", { - get: function() { - return this.nativeControl_.disabled; - }, - set: function(t) { - this.foundation_.setDisabled(t); - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(y.prototype, "value", { - get: function() { - return this.nativeControl_.value; - }, - set: function(t) { - this.nativeControl_.value = t; - }, - enumerable: !0, - configurable: !0 - }), - (y.prototype.initialize = function() { - var t = _.strings.DATA_INDETERMINATE_ATTR; - (this.nativeControl_.indeterminate = - "true" === this.nativeControl_.getAttribute(t)), - this.nativeControl_.removeAttribute(t); - }), - (y.prototype.initialSyncWithDOM = function() { - var t = this; - (this.handleChange_ = function() { - return t.foundation_.handleChange(); - }), - (this.handleAnimationEnd_ = function() { - return t.foundation_.handleAnimationEnd(); - }), - this.nativeControl_.addEventListener( - "change", - this.handleChange_ - ), - this.listen( - a.getCorrectEventName(window, "animationend"), - this.handleAnimationEnd_ - ), - this.installPropertyChangeHooks_(); - }), - (y.prototype.destroy = function() { - this.ripple_.destroy(), - this.nativeControl_.removeEventListener( - "change", - this.handleChange_ - ), - this.unlisten( - a.getCorrectEventName(window, "animationend"), - this.handleAnimationEnd_ - ), - this.uninstallPropertyChangeHooks_(), - s.prototype.destroy.call(this); - }), - (y.prototype.getDefaultFoundation = function() { - var n = this, - t = { - addClass: function(t) { - return n.root_.classList.add(t); - }, - forceLayout: function() { - return n.root_.offsetWidth; - }, - hasNativeControl: function() { - return !!n.nativeControl_; - }, - isAttachedToDOM: function() { - return Boolean(n.root_.parentNode); - }, - isChecked: function() { - return n.checked; - }, - isIndeterminate: function() { - return n.indeterminate; - }, - removeClass: function(t) { - n.root_.classList.remove(t); - }, - removeNativeControlAttr: function(t) { - n.nativeControl_.removeAttribute(t); - }, - setNativeControlAttr: function(t, e) { - n.nativeControl_.setAttribute(t, e); - }, - setNativeControlDisabled: function(t) { - n.nativeControl_.disabled = t; - } - }; - return new f.MDCCheckboxFoundation(t); - }), - (y.prototype.createRipple_ = function() { - var n = this, - t = o(o({}, d.MDCRipple.createAdapter(this)), { - deregisterInteractionHandler: function(t, e) { - return n.nativeControl_.removeEventListener( - t, - e, - u.applyPassive() - ); - }, - isSurfaceActive: function() { - return l.matches(n.nativeControl_, ":active"); - }, - isUnbounded: function() { - return !0; - }, - registerInteractionHandler: function(t, e) { - return n.nativeControl_.addEventListener( - t, - e, - u.applyPassive() - ); - } - }); - return new d.MDCRipple(this.root_, new p.MDCRippleFoundation(t)); - }), - (y.prototype.installPropertyChangeHooks_ = function() { - var r = this, - o = this.nativeControl_, - s = Object.getPrototypeOf(o); - h.forEach(function(t) { - var e = Object.getOwnPropertyDescriptor(s, t); - if (E(e)) { - var n = e.get, - i = { - configurable: e.configurable, - enumerable: e.enumerable, - get: n, - set: function(t) { - e.set.call(o, t), r.foundation_.handleChange(); - } - }; - Object.defineProperty(o, t, i); - } - }); - }), - (y.prototype.uninstallPropertyChangeHooks_ = function() { - var n = this.nativeControl_, - i = Object.getPrototypeOf(n); - h.forEach(function(t) { - var e = Object.getOwnPropertyDescriptor(i, t); - E(e) && Object.defineProperty(n, t, e); - }); - }), - Object.defineProperty(y.prototype, "nativeControl_", { - get: function() { - var t = _.strings.NATIVE_CONTROL_SELECTOR, - e = this.root_.querySelector(t); - if (!e) - throw new Error( - "Checkbox component requires a " + t + " element" - ); - return e; - }, - enumerable: !0, - configurable: !0 - }), - y); - function y() { - var t = (null !== s && s.apply(this, arguments)) || this; - return (t.ripple_ = t.createRipple_()), t; - } - function E(t) { - return !!t && "function" == typeof t.set; - } - e.MDCCheckbox = C; - }, - function(t, e, n) { - "use strict"; - Object.defineProperty(e, "__esModule", { value: !0 }), - (e.cssClasses = { - BG_FOCUSED: "mdc-ripple-upgraded--background-focused", - FG_ACTIVATION: "mdc-ripple-upgraded--foreground-activation", - FG_DEACTIVATION: "mdc-ripple-upgraded--foreground-deactivation", - ROOT: "mdc-ripple-upgraded", - UNBOUNDED: "mdc-ripple-upgraded--unbounded" - }), - (e.strings = { - VAR_FG_SCALE: "--mdc-ripple-fg-scale", - VAR_FG_SIZE: "--mdc-ripple-fg-size", - VAR_FG_TRANSLATE_END: "--mdc-ripple-fg-translate-end", - VAR_FG_TRANSLATE_START: "--mdc-ripple-fg-translate-start", - VAR_LEFT: "--mdc-ripple-left", - VAR_TOP: "--mdc-ripple-top" - }), - (e.numbers = { - DEACTIVATION_TIMEOUT_MS: 225, - FG_DEACTIVATION_MS: 150, - INITIAL_ORIGIN_SCALE: 0.6, - PADDING: 10, - TAP_DELAY_MS: 300 - }); - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }), - o = - (this && this.__assign) || - function() { - return (o = - Object.assign || - function(t) { - for (var e, n = 1, i = arguments.length; n < i; n++) - for (var r in (e = arguments[n])) - Object.prototype.hasOwnProperty.call(e, r) && - (t[r] = e[r]); - return t; - }).apply(this, arguments); - }; - Object.defineProperty(e, "__esModule", { value: !0 }); - var s, - a = n(0), - p = n(17), - c = - ((s = a.MDCFoundation), - r(_, s), - Object.defineProperty(_, "cssClasses", { - get: function() { - return p.cssClasses; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(_, "strings", { - get: function() { - return p.strings; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(_, "numbers", { - get: function() { - return p.numbers; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(_, "defaultAdapter", { - get: function() { - return { - addClass: function() {}, - forceLayout: function() {}, - hasNativeControl: function() { - return !1; - }, - isAttachedToDOM: function() { - return !1; - }, - isChecked: function() { - return !1; - }, - isIndeterminate: function() { - return !1; - }, - removeClass: function() {}, - removeNativeControlAttr: function() {}, - setNativeControlAttr: function() {}, - setNativeControlDisabled: function() {} - }; - }, - enumerable: !0, - configurable: !0 - }), - (_.prototype.init = function() { - (this.currentCheckState_ = this.determineCheckState_()), - this.updateAriaChecked_(), - this.adapter_.addClass(p.cssClasses.UPGRADED); - }), - (_.prototype.destroy = function() { - clearTimeout(this.animEndLatchTimer_); - }), - (_.prototype.setDisabled = function(t) { - this.adapter_.setNativeControlDisabled(t), - t - ? this.adapter_.addClass(p.cssClasses.DISABLED) - : this.adapter_.removeClass(p.cssClasses.DISABLED); - }), - (_.prototype.handleAnimationEnd = function() { - var t = this; - this.enableAnimationEndHandler_ && - (clearTimeout(this.animEndLatchTimer_), - (this.animEndLatchTimer_ = setTimeout(function() { - t.adapter_.removeClass(t.currentAnimationClass_), - (t.enableAnimationEndHandler_ = !1); - }, p.numbers.ANIM_END_LATCH_MS))); - }), - (_.prototype.handleChange = function() { - this.transitionCheckState_(); - }), - (_.prototype.transitionCheckState_ = function() { - if (this.adapter_.hasNativeControl()) { - var t = this.currentCheckState_, - e = this.determineCheckState_(); - if (t !== e) { - this.updateAriaChecked_(); - var n = p.strings.TRANSITION_STATE_UNCHECKED, - i = p.cssClasses.SELECTED; - e === n - ? this.adapter_.removeClass(i) - : this.adapter_.addClass(i), - 0 < this.currentAnimationClass_.length && - (clearTimeout(this.animEndLatchTimer_), - this.adapter_.forceLayout(), - this.adapter_.removeClass(this.currentAnimationClass_)), - (this.currentAnimationClass_ = this.getTransitionAnimationClass_( - t, - e - )), - (this.currentCheckState_ = e), - this.adapter_.isAttachedToDOM() && - 0 < this.currentAnimationClass_.length && - (this.adapter_.addClass(this.currentAnimationClass_), - (this.enableAnimationEndHandler_ = !0)); - } - } - }), - (_.prototype.determineCheckState_ = function() { - var t = p.strings.TRANSITION_STATE_INDETERMINATE, - e = p.strings.TRANSITION_STATE_CHECKED, - n = p.strings.TRANSITION_STATE_UNCHECKED; - return this.adapter_.isIndeterminate() - ? t - : this.adapter_.isChecked() - ? e - : n; - }), - (_.prototype.getTransitionAnimationClass_ = function(t, e) { - var n = p.strings.TRANSITION_STATE_INIT, - i = p.strings.TRANSITION_STATE_CHECKED, - r = p.strings.TRANSITION_STATE_UNCHECKED, - o = _.cssClasses, - s = o.ANIM_UNCHECKED_CHECKED, - a = o.ANIM_UNCHECKED_INDETERMINATE, - c = o.ANIM_CHECKED_UNCHECKED, - u = o.ANIM_CHECKED_INDETERMINATE, - l = o.ANIM_INDETERMINATE_CHECKED, - d = o.ANIM_INDETERMINATE_UNCHECKED; - switch (t) { - case n: - return e === r ? "" : e === i ? l : d; - case r: - return e === i ? s : a; - case i: - return e === r ? c : u; - default: - return e === i ? l : d; - } - }), - (_.prototype.updateAriaChecked_ = function() { - this.adapter_.isIndeterminate() - ? this.adapter_.setNativeControlAttr( - p.strings.ARIA_CHECKED_ATTR, - p.strings.ARIA_CHECKED_INDETERMINATE_VALUE - ) - : this.adapter_.removeNativeControlAttr( - p.strings.ARIA_CHECKED_ATTR - ); - }), - _); - function _(t) { - var e = s.call(this, o(o({}, _.defaultAdapter), t)) || this; - return ( - (e.currentCheckState_ = p.strings.TRANSITION_STATE_INIT), - (e.currentAnimationClass_ = ""), - (e.animEndLatchTimer_ = 0), - (e.enableAnimationEndHandler_ = !1), - e - ); - } - (e.MDCCheckboxFoundation = c), (e.default = c); - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }), - o = - (this && this.__assign) || - function() { - return (o = - Object.assign || - function(t) { - for (var e, n = 1, i = arguments.length; n < i; n++) - for (var r in (e = arguments[n])) - Object.prototype.hasOwnProperty.call(e, r) && - (t[r] = e[r]); - return t; - }).apply(this, arguments); - }; - Object.defineProperty(e, "__esModule", { value: !0 }); - var s, - a = n(0), - c = n(43), - u = n(18), - l = - ((s = a.MDCFoundation), - r(d, s), - Object.defineProperty(d, "strings", { - get: function() { - return u.strings; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(d, "defaultAdapter", { - get: function() { - return { - focus: function() {}, - getAttribute: function() { - return null; - }, - setAttribute: function() {}, - notifyInteraction: function() {}, - notifyNavigation: function() {} - }; - }, - enumerable: !0, - configurable: !0 - }), - (d.prototype.handleClick = function(t) { - t.stopPropagation(), - this.adapter_.notifyInteraction(u.InteractionTrigger.CLICK); - }), - (d.prototype.handleKeydown = function(t) { - t.stopPropagation(); - var e = c.normalizeKey(t); - if (this.shouldNotifyInteractionFromKey_(e)) { - var n = this.getTriggerFromKey_(e); - this.adapter_.notifyInteraction(n); - } else - c.isNavigationEvent(t) && this.adapter_.notifyNavigation(e); - }), - (d.prototype.removeFocus = function() { - this.adapter_.setAttribute(u.strings.TAB_INDEX, "-1"); - }), - (d.prototype.focus = function() { - this.adapter_.setAttribute(u.strings.TAB_INDEX, "0"), - this.adapter_.focus(); - }), - (d.prototype.isNavigable = function() { - return ( - "true" !== this.adapter_.getAttribute(u.strings.ARIA_HIDDEN) - ); - }), - (d.prototype.shouldNotifyInteractionFromKey_ = function(t) { - var e = t === c.KEY.ENTER || t === c.KEY.SPACEBAR, - n = t === c.KEY.BACKSPACE || t === c.KEY.DELETE; - return e || n; - }), - (d.prototype.getTriggerFromKey_ = function(t) { - return t === c.KEY.SPACEBAR - ? u.InteractionTrigger.SPACEBAR_KEY - : t === c.KEY.ENTER - ? u.InteractionTrigger.ENTER_KEY - : t === c.KEY.DELETE - ? u.InteractionTrigger.DELETE_KEY - : t === c.KEY.BACKSPACE - ? u.InteractionTrigger.BACKSPACE_KEY - : u.InteractionTrigger.UNSPECIFIED; - }), - d); - function d(t) { - return s.call(this, o(o({}, d.defaultAdapter), t)) || this; - } - (e.MDCChipTrailingActionFoundation = l), (e.default = l); - }, - function(t, i, e) { - "use strict"; - Object.defineProperty(i, "__esModule", { value: !0 }), - (i.KEY = { - UNKNOWN: "Unknown", - BACKSPACE: "Backspace", - ENTER: "Enter", - SPACEBAR: "Spacebar", - PAGE_UP: "PageUp", - PAGE_DOWN: "PageDown", - END: "End", - HOME: "Home", - ARROW_LEFT: "ArrowLeft", - ARROW_UP: "ArrowUp", - ARROW_RIGHT: "ArrowRight", - ARROW_DOWN: "ArrowDown", - DELETE: "Delete" - }); - var r = new Set(); - r.add(i.KEY.BACKSPACE), - r.add(i.KEY.ENTER), - r.add(i.KEY.SPACEBAR), - r.add(i.KEY.PAGE_UP), - r.add(i.KEY.PAGE_DOWN), - r.add(i.KEY.END), - r.add(i.KEY.HOME), - r.add(i.KEY.ARROW_LEFT), - r.add(i.KEY.ARROW_UP), - r.add(i.KEY.ARROW_RIGHT), - r.add(i.KEY.ARROW_DOWN), - r.add(i.KEY.DELETE); - var n = 8, - o = 13, - s = 32, - a = 33, - c = 34, - u = 35, - l = 36, - d = 37, - p = 38, - _ = 39, - f = 40, - h = 46, - C = new Map(); - C.set(n, i.KEY.BACKSPACE), - C.set(o, i.KEY.ENTER), - C.set(s, i.KEY.SPACEBAR), - C.set(a, i.KEY.PAGE_UP), - C.set(c, i.KEY.PAGE_DOWN), - C.set(u, i.KEY.END), - C.set(l, i.KEY.HOME), - C.set(d, i.KEY.ARROW_LEFT), - C.set(p, i.KEY.ARROW_UP), - C.set(_, i.KEY.ARROW_RIGHT), - C.set(f, i.KEY.ARROW_DOWN), - C.set(h, i.KEY.DELETE); - var y = new Set(); - function E(t) { - var e = t.key; - if (r.has(e)) return e; - var n = C.get(t.keyCode); - return n || i.KEY.UNKNOWN; - } - y.add(i.KEY.PAGE_UP), - y.add(i.KEY.PAGE_DOWN), - y.add(i.KEY.END), - y.add(i.KEY.HOME), - y.add(i.KEY.ARROW_LEFT), - y.add(i.KEY.ARROW_UP), - y.add(i.KEY.ARROW_RIGHT), - y.add(i.KEY.ARROW_DOWN), - (i.normalizeKey = E), - (i.isNavigationEvent = function(t) { - return y.has(E(t)); - }); - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }), - o = - (this && this.__assign) || - function() { - return (o = - Object.assign || - function(t) { - for (var e, n = 1, i = arguments.length; n < i; n++) - for (var r in (e = arguments[n])) - Object.prototype.hasOwnProperty.call(e, r) && - (t[r] = e[r]); - return t; - }).apply(this, arguments); - }; - Object.defineProperty(e, "__esModule", { value: !0 }); - var s, - a = n(1), - c = n(3), - u = n(4), - l = n(8), - d = n(19), - p = ["click", "keydown"], - _ = - ((s = a.MDCComponent), - r(f, s), - Object.defineProperty(f.prototype, "selected", { - get: function() { - return this.foundation_.isSelected(); - }, - set: function(t) { - this.foundation_.setSelected(t); - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty( - f.prototype, - "shouldRemoveOnTrailingIconClick", - { - get: function() { - return this.foundation_.getShouldRemoveOnTrailingIconClick(); - }, - set: function(t) { - this.foundation_.setShouldRemoveOnTrailingIconClick(t); - }, - enumerable: !0, - configurable: !0 - } - ), - Object.defineProperty(f.prototype, "ripple", { - get: function() { - return this.ripple_; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(f.prototype, "id", { - get: function() { - return this.root_.id; - }, - enumerable: !0, - configurable: !0 - }), - (f.attachTo = function(t) { - return new f(t); - }), - (f.prototype.initialize = function(t) { - var e = this; - void 0 === t && - (t = function(t, e) { - return new c.MDCRipple(t, e); - }), - (this.leadingIcon_ = this.root_.querySelector( - l.strings.LEADING_ICON_SELECTOR - )), - (this.trailingIcon_ = this.root_.querySelector( - l.strings.TRAILING_ICON_SELECTOR - )), - (this.checkmark_ = this.root_.querySelector( - l.strings.CHECKMARK_SELECTOR - )), - (this.primaryAction_ = this.root_.querySelector( - l.strings.PRIMARY_ACTION_SELECTOR - )), - (this.trailingAction_ = this.root_.querySelector( - l.strings.TRAILING_ACTION_SELECTOR - )); - var n = o(o({}, c.MDCRipple.createAdapter(this)), { - computeBoundingRect: function() { - return e.foundation_.getDimensions(); - } - }); - this.ripple_ = t(this.root_, new u.MDCRippleFoundation(n)); - }), - (f.prototype.initialSyncWithDOM = function() { - var e = this; - (this.handleInteraction_ = function(t) { - return e.foundation_.handleInteraction(t); - }), - (this.handleTransitionEnd_ = function(t) { - return e.foundation_.handleTransitionEnd(t); - }), - (this.handleTrailingIconInteraction_ = function(t) { - return e.foundation_.handleTrailingIconInteraction(t); - }), - (this.handleKeydown_ = function(t) { - return e.foundation_.handleKeydown(t); - }), - (this.handleFocusIn_ = function(t) { - e.foundation_.handleFocusIn(t); - }), - (this.handleFocusOut_ = function(t) { - e.foundation_.handleFocusOut(t); - }), - p.forEach(function(t) { - e.listen(t, e.handleInteraction_); - }), - this.listen("transitionend", this.handleTransitionEnd_), - this.listen("keydown", this.handleKeydown_), - this.listen("focusin", this.handleFocusIn_), - this.listen("focusout", this.handleFocusOut_), - this.trailingIcon_ && - p.forEach(function(t) { - e.trailingIcon_.addEventListener( - t, - e.handleTrailingIconInteraction_ - ); - }); - }), - (f.prototype.destroy = function() { - var e = this; - this.ripple_.destroy(), - p.forEach(function(t) { - e.unlisten(t, e.handleInteraction_); - }), - this.unlisten("transitionend", this.handleTransitionEnd_), - this.unlisten("keydown", this.handleKeydown_), - this.unlisten("focusin", this.handleFocusIn_), - this.unlisten("focusout", this.handleFocusOut_), - this.trailingIcon_ && - p.forEach(function(t) { - e.trailingIcon_.removeEventListener( - t, - e.handleTrailingIconInteraction_ - ); - }), - s.prototype.destroy.call(this); - }), - (f.prototype.beginExit = function() { - this.foundation_.beginExit(); - }), - (f.prototype.getDefaultFoundation = function() { - var n = this, - t = { - addClass: function(t) { - return n.root_.classList.add(t); - }, - addClassToLeadingIcon: function(t) { - n.leadingIcon_ && n.leadingIcon_.classList.add(t); - }, - eventTargetHasClass: function(t, e) { - return !!t && t.classList.contains(e); - }, - focusPrimaryAction: function() { - n.primaryAction_ && n.primaryAction_.focus(); - }, - focusTrailingAction: function() { - n.trailingAction_ && n.trailingAction_.focus(); - }, - getAttribute: function(t) { - return n.root_.getAttribute(t); - }, - getCheckmarkBoundingClientRect: function() { - return n.checkmark_ - ? n.checkmark_.getBoundingClientRect() - : null; - }, - getComputedStyleValue: function(t) { - return window.getComputedStyle(n.root_).getPropertyValue(t); - }, - getRootBoundingClientRect: function() { - return n.root_.getBoundingClientRect(); - }, - hasClass: function(t) { - return n.root_.classList.contains(t); - }, - hasLeadingIcon: function() { - return !!n.leadingIcon_; - }, - hasTrailingAction: function() { - return !!n.trailingAction_; - }, - isRTL: function() { - return ( - "rtl" === - window - .getComputedStyle(n.root_) - .getPropertyValue("direction") - ); - }, - notifyInteraction: function() { - return n.emit( - l.strings.INTERACTION_EVENT, - { chipId: n.id }, - !0 - ); - }, - notifyNavigation: function(t, e) { - return n.emit( - l.strings.NAVIGATION_EVENT, - { chipId: n.id, key: t, source: e }, - !0 - ); - }, - notifyRemoval: function(t) { - n.emit( - l.strings.REMOVAL_EVENT, - { chipId: n.id, removedAnnouncement: t }, - !0 - ); - }, - notifySelection: function(t, e) { - return n.emit( - l.strings.SELECTION_EVENT, - { chipId: n.id, selected: t, shouldIgnore: e }, - !0 - ); - }, - notifyTrailingIconInteraction: function() { - return n.emit( - l.strings.TRAILING_ICON_INTERACTION_EVENT, - { chipId: n.id }, - !0 - ); - }, - removeClass: function(t) { - return n.root_.classList.remove(t); - }, - removeClassFromLeadingIcon: function(t) { - n.leadingIcon_ && n.leadingIcon_.classList.remove(t); - }, - setPrimaryActionAttr: function(t, e) { - n.primaryAction_ && n.primaryAction_.setAttribute(t, e); - }, - setStyleProperty: function(t, e) { - return n.root_.style.setProperty(t, e); - }, - setTrailingActionAttr: function(t, e) { - n.trailingAction_ && n.trailingAction_.setAttribute(t, e); - } - }; - return new d.MDCChipFoundation(t); - }), - (f.prototype.setSelectedFromChipSet = function(t, e) { - this.foundation_.setSelectedFromChipSet(t, e); - }), - (f.prototype.focusPrimaryAction = function() { - this.foundation_.focusPrimaryAction(); - }), - (f.prototype.focusTrailingAction = function() { - this.foundation_.focusTrailingAction(); - }), - (f.prototype.removeFocus = function() { - this.foundation_.removeFocus(); - }), - (f.prototype.remove = function() { - var t = this.root_.parentNode; - null !== t && t.removeChild(this.root_); - }), - f); - function f() { - return (null !== s && s.apply(this, arguments)) || this; - } - e.MDCChip = _; - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }), - o = - (this && this.__assign) || - function() { - return (o = - Object.assign || - function(t) { - for (var e, n = 1, i = arguments.length; n < i; n++) - for (var r in (e = arguments[n])) - Object.prototype.hasOwnProperty.call(e, r) && - (t[r] = e[r]); - return t; - }).apply(this, arguments); - }; - Object.defineProperty(e, "__esModule", { value: !0 }); - var s, - a = n(0), - _ = n(8), - c = n(46), - u = - ((s = a.MDCFoundation), - r(l, s), - Object.defineProperty(l, "strings", { - get: function() { - return c.strings; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(l, "cssClasses", { - get: function() { - return c.cssClasses; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(l, "defaultAdapter", { - get: function() { - return { - announceMessage: function() {}, - focusChipPrimaryActionAtIndex: function() {}, - focusChipTrailingActionAtIndex: function() {}, - getChipListCount: function() { - return -1; - }, - getIndexOfChipById: function() { - return -1; - }, - hasClass: function() { - return !1; - }, - isRTL: function() { - return !1; - }, - removeChipAtIndex: function() {}, - removeFocusFromChipAtIndex: function() {}, - selectChipAtIndex: function() {} - }; - }, - enumerable: !0, - configurable: !0 - }), - (l.prototype.getSelectedChipIds = function() { - return this.selectedChipIds_.slice(); - }), - (l.prototype.select = function(t) { - this.select_(t, !1); - }), - (l.prototype.handleChipInteraction = function(t) { - var e = t.chipId, - n = this.adapter_.getIndexOfChipById(e); - this.removeFocusFromChipsExcept_(n), - (this.adapter_.hasClass(c.cssClasses.CHOICE) || - this.adapter_.hasClass(c.cssClasses.FILTER)) && - this.toggleSelect_(e); - }), - (l.prototype.handleChipSelection = function(t) { - var e = t.chipId, - n = t.selected; - if (!t.shouldIgnore) { - var i = 0 <= this.selectedChipIds_.indexOf(e); - n && !i ? this.select(e) : !n && i && this.deselect_(e); - } - }), - (l.prototype.handleChipRemoval = function(t) { - var e = t.chipId, - n = t.removedAnnouncement; - n && this.adapter_.announceMessage(n); - var i = this.adapter_.getIndexOfChipById(e); - this.deselectAndNotifyClients_(e), - this.adapter_.removeChipAtIndex(i); - var r = this.adapter_.getChipListCount() - 1, - o = Math.min(i, r); - this.removeFocusFromChipsExcept_(o), - this.adapter_.focusChipTrailingActionAtIndex(o); - }), - (l.prototype.handleChipNavigation = function(t) { - var e = t.chipId, - n = t.key, - i = t.source, - r = this.adapter_.getChipListCount() - 1, - o = this.adapter_.getIndexOfChipById(e); - if (-1 !== o && _.navigationKeys.has(n)) { - var s = this.adapter_.isRTL(), - a = - n === _.strings.ARROW_LEFT_KEY || - n === _.strings.IE_ARROW_LEFT_KEY, - c = - n === _.strings.ARROW_RIGHT_KEY || - n === _.strings.IE_ARROW_RIGHT_KEY, - u = - n === _.strings.ARROW_DOWN_KEY || - n === _.strings.IE_ARROW_DOWN_KEY, - l = (!s && c) || (s && a) || u, - d = n === _.strings.HOME_KEY, - p = n === _.strings.END_KEY; - l ? o++ : d ? (o = 0) : p ? (o = r) : o--, - o < 0 || - r < o || - (this.removeFocusFromChipsExcept_(o), - this.focusChipAction_(o, n, i)); - } - }), - (l.prototype.focusChipAction_ = function(t, e, n) { - var i = _.jumpChipKeys.has(e); - if (i && n === _.EventSource.PRIMARY) - return this.adapter_.focusChipPrimaryActionAtIndex(t); - if (i && n === _.EventSource.TRAILING) - return this.adapter_.focusChipTrailingActionAtIndex(t); - var r = this.getDirection_(e); - return r === _.Direction.LEFT - ? this.adapter_.focusChipTrailingActionAtIndex(t) - : r === _.Direction.RIGHT - ? this.adapter_.focusChipPrimaryActionAtIndex(t) - : void 0; - }), - (l.prototype.getDirection_ = function(t) { - var e = this.adapter_.isRTL(), - n = - t === _.strings.ARROW_LEFT_KEY || - t === _.strings.IE_ARROW_LEFT_KEY, - i = - t === _.strings.ARROW_RIGHT_KEY || - t === _.strings.IE_ARROW_RIGHT_KEY; - return (!e && n) || (e && i) - ? _.Direction.LEFT - : _.Direction.RIGHT; - }), - (l.prototype.deselect_ = function(t, e) { - void 0 === e && (e = !1); - var n = this.selectedChipIds_.indexOf(t); - if (0 <= n) { - this.selectedChipIds_.splice(n, 1); - var i = this.adapter_.getIndexOfChipById(t); - this.adapter_.selectChipAtIndex(i, !1, e); - } - }), - (l.prototype.deselectAndNotifyClients_ = function(t) { - this.deselect_(t, !0); - }), - (l.prototype.toggleSelect_ = function(t) { - 0 <= this.selectedChipIds_.indexOf(t) - ? this.deselectAndNotifyClients_(t) - : this.selectAndNotifyClients_(t); - }), - (l.prototype.removeFocusFromChipsExcept_ = function(t) { - for (var e = this.adapter_.getChipListCount(), n = 0; n < e; n++) - n !== t && this.adapter_.removeFocusFromChipAtIndex(n); - }), - (l.prototype.selectAndNotifyClients_ = function(t) { - this.select_(t, !0); - }), - (l.prototype.select_ = function(t, e) { - if (!(0 <= this.selectedChipIds_.indexOf(t))) { - if ( - this.adapter_.hasClass(c.cssClasses.CHOICE) && - 0 < this.selectedChipIds_.length - ) { - var n = this.selectedChipIds_[0], - i = this.adapter_.getIndexOfChipById(n); - (this.selectedChipIds_ = []), - this.adapter_.selectChipAtIndex(i, !1, e); - } - this.selectedChipIds_.push(t); - var r = this.adapter_.getIndexOfChipById(t); - this.adapter_.selectChipAtIndex(r, !0, e); - } - }), - l); - function l(t) { - var e = s.call(this, o(o({}, l.defaultAdapter), t)) || this; - return (e.selectedChipIds_ = []), e; - } - (e.MDCChipSetFoundation = u), (e.default = u); - }, - function(t, e, n) { - "use strict"; - Object.defineProperty(e, "__esModule", { value: !0 }), - (e.strings = { CHIP_SELECTOR: ".mdc-chip" }), - (e.cssClasses = { - CHOICE: "mdc-chip-set--choice", - FILTER: "mdc-chip-set--filter" - }); - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }), - o = - (this && this.__assign) || - function() { - return (o = - Object.assign || - function(t) { - for (var e, n = 1, i = arguments.length; n < i; n++) - for (var r in (e = arguments[n])) - Object.prototype.hasOwnProperty.call(e, r) && - (t[r] = e[r]); - return t; - }).apply(this, arguments); - }; - Object.defineProperty(e, "__esModule", { value: !0 }); - var s, - a = n(0), - c = n(48), - u = - ((s = a.MDCFoundation), - r(l, s), - Object.defineProperty(l, "cssClasses", { - get: function() { - return c.cssClasses; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(l, "strings", { - get: function() { - return c.strings; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(l, "defaultAdapter", { - get: function() { - return { - addClass: function() {}, - getDeterminateCircleAttribute: function() { - return null; - }, - hasClass: function() { - return !1; - }, - removeClass: function() {}, - removeAttribute: function() {}, - setAttribute: function() {}, - setDeterminateCircleAttribute: function() {} - }; - }, - enumerable: !0, - configurable: !0 - }), - (l.prototype.init = function() { - (this.isClosed_ = this.adapter_.hasClass( - c.cssClasses.CLOSED_CLASS - )), - (this.isDeterminate_ = !this.adapter_.hasClass( - c.cssClasses.INDETERMINATE_CLASS - )), - (this.progress_ = 0), - this.isDeterminate_ && - this.adapter_.setAttribute( - c.strings.ARIA_VALUENOW, - this.progress_.toString() - ), - (this.radius_ = Number( - this.adapter_.getDeterminateCircleAttribute(c.strings.RADIUS) - )); - }), - (l.prototype.isDeterminate = function() { - return this.isDeterminate_; - }), - (l.prototype.getProgress = function() { - return this.progress_; - }), - (l.prototype.isClosed = function() { - return this.isClosed_; - }), - (l.prototype.setDeterminate = function(t) { - (this.isDeterminate_ = t), - this.isDeterminate_ - ? (this.adapter_.removeClass( - c.cssClasses.INDETERMINATE_CLASS - ), - this.setProgress(this.progress_)) - : (this.adapter_.addClass(c.cssClasses.INDETERMINATE_CLASS), - this.adapter_.removeAttribute(c.strings.ARIA_VALUENOW)); - }), - (l.prototype.setProgress = function(t) { - if (((this.progress_ = t), this.isDeterminate_)) { - var e = (1 - this.progress_) * (2 * Math.PI * this.radius_); - this.adapter_.setDeterminateCircleAttribute( - c.strings.STROKE_DASHOFFSET, - "" + e - ), - this.adapter_.setAttribute( - c.strings.ARIA_VALUENOW, - this.progress_.toString() - ); - } - }), - (l.prototype.open = function() { - (this.isClosed_ = !1), - this.adapter_.removeClass(c.cssClasses.CLOSED_CLASS); - }), - (l.prototype.close = function() { - (this.isClosed_ = !0), - this.adapter_.addClass(c.cssClasses.CLOSED_CLASS); - }), - l); - function l(t) { - return s.call(this, o(o({}, l.defaultAdapter), t)) || this; - } - (e.MDCCircularProgressFoundation = u), (e.default = u); - }, - function(t, e, n) { - "use strict"; - Object.defineProperty(e, "__esModule", { value: !0 }), - (e.cssClasses = { - INDETERMINATE_CLASS: "mdc-circular-progress--indeterminate", - CLOSED_CLASS: "mdc-circular-progress--closed" - }), - (e.strings = { - DETERMINATE_CIRCLE_SELECTOR: - ".mdc-circular-progress__determinate-circle", - ARIA_VALUENOW: "aria-valuenow", - RADIUS: "r", - STROKE_DASHOFFSET: "stroke-dashoffset" - }); - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }), - o = - (this && this.__assign) || - function() { - return (o = - Object.assign || - function(t) { - for (var e, n = 1, i = arguments.length; n < i; n++) - for (var r in (e = arguments[n])) - Object.prototype.hasOwnProperty.call(e, r) && - (t[r] = e[r]); - return t; - }).apply(this, arguments); - }, - s = - (this && this.__awaiter) || - function(t, s, a, c) { - return new (a = a || Promise)(function(e, n) { - function i(t) { - try { - o(c.next(t)); - } catch (t) { - n(t); - } - } - function r(t) { - try { - o(c.throw(t)); - } catch (t) { - n(t); - } - } - function o(t) { - t.done - ? e(t.value) - : (function(e) { - return e instanceof a - ? e - : new a(function(t) { - t(e); - }); - })(t.value).then(i, r); - } - o((c = c.apply(t, s || [])).next()); - }); - }, - a = - (this && this.__generator) || - function(n, i) { - var r, - o, - s, - t, - a = { - label: 0, - sent: function() { - if (1 & s[0]) throw s[1]; - return s[1]; - }, - trys: [], - ops: [] - }; - return ( - (t = { next: e(0), throw: e(1), return: e(2) }), - "function" == typeof Symbol && - (t[Symbol.iterator] = function() { - return this; - }), - t - ); - function e(e) { - return function(t) { - return (function(e) { - if (r) - throw new TypeError("Generator is already executing."); - for (; a; ) - try { - if ( - ((r = 1), - o && - (s = - 2 & e[0] - ? o.return - : e[0] - ? o.throw || ((s = o.return) && s.call(o), 0) - : o.next) && - !(s = s.call(o, e[1])).done) - ) - return s; - switch ( - ((o = 0), s && (e = [2 & e[0], s.value]), e[0]) - ) { - case 0: - case 1: - s = e; - break; - case 4: - return a.label++, { value: e[1], done: !1 }; - case 5: - a.label++, (o = e[1]), (e = [0]); - continue; - case 7: - (e = a.ops.pop()), a.trys.pop(); - continue; - default: - if ( - !(s = - 0 < (s = a.trys).length && s[s.length - 1]) && - (6 === e[0] || 2 === e[0]) - ) { - a = 0; - continue; - } - if ( - 3 === e[0] && - (!s || (e[1] > s[0] && e[1] < s[3])) - ) { - a.label = e[1]; - break; - } - if (6 === e[0] && a.label < s[1]) { - (a.label = s[1]), (s = e); - break; - } - if (s && a.label < s[2]) { - (a.label = s[2]), a.ops.push(e); - break; - } - s[2] && a.ops.pop(), a.trys.pop(); - continue; - } - e = i.call(n, a); - } catch (t) { - (e = [6, t]), (o = 0); - } finally { - r = s = 0; - } - if (5 & e[0]) throw e[1]; - return { value: e[0] ? e[1] : void 0, done: !0 }; - })([e, t]); - }; - } - }; - Object.defineProperty(e, "__esModule", { value: !0 }); - var c, - u = n(0), - l = n(20), - d = - ((c = u.MDCFoundation), - r(p, c), - Object.defineProperty(p, "defaultAdapter", { - get: function() { - return { - addClass: function() {}, - addClassAtRowIndex: function() {}, - getAttributeByHeaderCellIndex: function() { - return ""; - }, - getHeaderCellCount: function() { - return 0; - }, - getHeaderCellElements: function() { - return []; - }, - getRowCount: function() { - return 0; - }, - getRowElements: function() { - return []; - }, - getRowIdAtIndex: function() { - return ""; - }, - getRowIndexByChildElement: function() { - return 0; - }, - getSelectedRowCount: function() { - return 0; - }, - getTableBodyHeight: function() { - return ""; - }, - getTableHeaderHeight: function() { - return ""; - }, - isCheckboxAtRowIndexChecked: function() { - return !1; - }, - isHeaderRowCheckboxChecked: function() { - return !1; - }, - isRowsSelectable: function() { - return !1; - }, - notifyRowSelectionChanged: function() {}, - notifySelectedAll: function() {}, - notifySortAction: function() {}, - notifyUnselectedAll: function() {}, - registerHeaderRowCheckbox: function() {}, - registerRowCheckboxes: function() {}, - removeClass: function() {}, - removeClassAtRowIndex: function() {}, - removeClassNameByHeaderCellIndex: function() {}, - setAttributeAtRowIndex: function() {}, - setAttributeByHeaderCellIndex: function() {}, - setClassNameByHeaderCellIndex: function() {}, - setHeaderRowCheckboxChecked: function() {}, - setHeaderRowCheckboxIndeterminate: function() {}, - setProgressIndicatorStyles: function() {}, - setRowCheckboxCheckedAtIndex: function() {} - }; - }, - enumerable: !0, - configurable: !0 - }), - (p.prototype.layout = function() { - this.adapter_.isRowsSelectable() && - (this.adapter_.registerHeaderRowCheckbox(), - this.adapter_.registerRowCheckboxes(), - this.setHeaderRowCheckboxState_()); - }), - (p.prototype.layoutAsync = function() { - return s(this, void 0, void 0, function() { - return a(this, function(t) { - switch (t.label) { - case 0: - return this.adapter_.isRowsSelectable() - ? [4, this.adapter_.registerHeaderRowCheckbox()] - : [3, 3]; - case 1: - return ( - t.sent(), [4, this.adapter_.registerRowCheckboxes()] - ); - case 2: - t.sent(), - this.setHeaderRowCheckboxState_(), - (t.label = 3); - case 3: - return [2]; - } - }); - }); - }), - (p.prototype.getRows = function() { - return this.adapter_.getRowElements(); - }), - (p.prototype.getHeaderCells = function() { - return this.adapter_.getHeaderCellElements(); - }), - (p.prototype.setSelectedRowIds = function(t) { - for (var e = 0; e < this.adapter_.getRowCount(); e++) { - var n = this.adapter_.getRowIdAtIndex(e), - i = !1; - n && 0 <= t.indexOf(n) && (i = !0), - this.adapter_.setRowCheckboxCheckedAtIndex(e, i), - this.selectRowAtIndex_(e, i); - } - this.setHeaderRowCheckboxState_(); - }), - (p.prototype.getRowIds = function() { - for (var t = [], e = 0; e < this.adapter_.getRowCount(); e++) - t.push(this.adapter_.getRowIdAtIndex(e)); - return t; - }), - (p.prototype.getSelectedRowIds = function() { - for (var t = [], e = 0; e < this.adapter_.getRowCount(); e++) - this.adapter_.isCheckboxAtRowIndexChecked(e) && - t.push(this.adapter_.getRowIdAtIndex(e)); - return t; - }), - (p.prototype.handleHeaderRowCheckboxChange = function() { - for ( - var t = this.adapter_.isHeaderRowCheckboxChecked(), e = 0; - e < this.adapter_.getRowCount(); - e++ - ) - this.adapter_.setRowCheckboxCheckedAtIndex(e, t), - this.selectRowAtIndex_(e, t); - t - ? this.adapter_.notifySelectedAll() - : this.adapter_.notifyUnselectedAll(); - }), - (p.prototype.handleRowCheckboxChange = function(t) { - var e = this.adapter_.getRowIndexByChildElement(t.target); - if (-1 !== e) { - var n = this.adapter_.isCheckboxAtRowIndexChecked(e); - this.selectRowAtIndex_(e, n), this.setHeaderRowCheckboxState_(); - var i = this.adapter_.getRowIdAtIndex(e); - this.adapter_.notifyRowSelectionChanged({ - rowId: i, - rowIndex: e, - selected: n - }); - } - }), - (p.prototype.handleSortAction = function(t) { - for ( - var e = t.columnId, n = t.columnIndex, i = t.headerCell, r = 0; - r < this.adapter_.getHeaderCellCount(); - r++ - ) - r !== n && - (this.adapter_.removeClassNameByHeaderCellIndex( - r, - l.cssClasses.HEADER_CELL_SORTED - ), - this.adapter_.removeClassNameByHeaderCellIndex( - r, - l.cssClasses.HEADER_CELL_SORTED_DESCENDING - ), - this.adapter_.setAttributeByHeaderCellIndex( - r, - l.strings.ARIA_SORT, - l.SortValue.NONE - )); - this.adapter_.setClassNameByHeaderCellIndex( - n, - l.cssClasses.HEADER_CELL_SORTED - ); - var o = this.adapter_.getAttributeByHeaderCellIndex( - n, - l.strings.ARIA_SORT - ), - s = l.SortValue.NONE; - (s = - o === l.SortValue.ASCENDING - ? (this.adapter_.setClassNameByHeaderCellIndex( - n, - l.cssClasses.HEADER_CELL_SORTED_DESCENDING - ), - this.adapter_.setAttributeByHeaderCellIndex( - n, - l.strings.ARIA_SORT, - l.SortValue.DESCENDING - ), - l.SortValue.DESCENDING) - : (o === l.SortValue.DESCENDING && - this.adapter_.removeClassNameByHeaderCellIndex( - n, - l.cssClasses.HEADER_CELL_SORTED_DESCENDING - ), - this.adapter_.setAttributeByHeaderCellIndex( - n, - l.strings.ARIA_SORT, - l.SortValue.ASCENDING - ), - l.SortValue.ASCENDING)), - this.adapter_.notifySortAction({ - columnId: e, - columnIndex: n, - headerCell: i, - sortValue: s - }); - }), - (p.prototype.showProgress = function() { - var t = this.adapter_.getTableBodyHeight(), - e = this.adapter_.getTableHeaderHeight(); - this.adapter_.setProgressIndicatorStyles({ height: t, top: e }), - this.adapter_.addClass(l.cssClasses.IN_PROGRESS); - }), - (p.prototype.hideProgress = function() { - this.adapter_.removeClass(l.cssClasses.IN_PROGRESS); - }), - (p.prototype.setHeaderRowCheckboxState_ = function() { - this.adapter_.getSelectedRowCount() === - this.adapter_.getRowCount() - ? (this.adapter_.setHeaderRowCheckboxChecked(!0), - this.adapter_.setHeaderRowCheckboxIndeterminate(!1)) - : (0 === this.adapter_.getSelectedRowCount() - ? this.adapter_.setHeaderRowCheckboxIndeterminate(!1) - : this.adapter_.setHeaderRowCheckboxIndeterminate(!0), - this.adapter_.setHeaderRowCheckboxChecked(!1)); - }), - (p.prototype.selectRowAtIndex_ = function(t, e) { - e - ? (this.adapter_.addClassAtRowIndex( - t, - l.cssClasses.ROW_SELECTED - ), - this.adapter_.setAttributeAtRowIndex( - t, - l.strings.ARIA_SELECTED, - "true" - )) - : (this.adapter_.removeClassAtRowIndex( - t, - l.cssClasses.ROW_SELECTED - ), - this.adapter_.setAttributeAtRowIndex( - t, - l.strings.ARIA_SELECTED, - "false" - )); - }), - p); - function p(t) { - return c.call(this, o(o({}, p.defaultAdapter), t)) || this; - } - e.MDCDataTableFoundation = d; - }, - function(t, e, n) { - "use strict"; - Object.defineProperty(e, "__esModule", { value: !0 }), - (e.createFocusTrapInstance = function(t, e, n) { - return e(t, { initialFocusEl: n }); - }), - (e.isScrollable = function(t) { - return !!t && t.scrollHeight > t.offsetHeight; - }), - (e.areTopsMisaligned = function(t) { - var e = new Set(); - return ( - [].forEach.call(t, function(t) { - return e.add(t.offsetTop); - }), - 1 < e.size - ); - }); - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }), - o = - (this && this.__assign) || - function() { - return (o = - Object.assign || - function(t) { - for (var e, n = 1, i = arguments.length; n < i; n++) - for (var r in (e = arguments[n])) - Object.prototype.hasOwnProperty.call(e, r) && - (t[r] = e[r]); - return t; - }).apply(this, arguments); - }; - Object.defineProperty(e, "__esModule", { value: !0 }); - var s, - a = n(0), - c = n(52), - u = - ((s = a.MDCFoundation), - r(l, s), - Object.defineProperty(l, "cssClasses", { - get: function() { - return c.cssClasses; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(l, "strings", { - get: function() { - return c.strings; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(l, "numbers", { - get: function() { - return c.numbers; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(l, "defaultAdapter", { - get: function() { - return { - addBodyClass: function() {}, - addClass: function() {}, - areButtonsStacked: function() { - return !1; - }, - clickDefaultButton: function() {}, - eventTargetMatches: function() { - return !1; - }, - getActionFromEvent: function() { - return ""; - }, - getInitialFocusEl: function() { - return null; - }, - hasClass: function() { - return !1; - }, - isContentScrollable: function() { - return !1; - }, - notifyClosed: function() {}, - notifyClosing: function() {}, - notifyOpened: function() {}, - notifyOpening: function() {}, - releaseFocus: function() {}, - removeBodyClass: function() {}, - removeClass: function() {}, - reverseButtons: function() {}, - trapFocus: function() {} - }; - }, - enumerable: !0, - configurable: !0 - }), - (l.prototype.init = function() { - this.adapter_.hasClass(c.cssClasses.STACKED) && - this.setAutoStackButtons(!1); - }), - (l.prototype.destroy = function() { - this.isOpen_ && this.close(c.strings.DESTROY_ACTION), - this.animationTimer_ && - (clearTimeout(this.animationTimer_), - this.handleAnimationTimerEnd_()), - this.layoutFrame_ && - (cancelAnimationFrame(this.layoutFrame_), - (this.layoutFrame_ = 0)); - }), - (l.prototype.open = function() { - var t = this; - (this.isOpen_ = !0), - this.adapter_.notifyOpening(), - this.adapter_.addClass(c.cssClasses.OPENING), - this.runNextAnimationFrame_(function() { - t.adapter_.addClass(c.cssClasses.OPEN), - t.adapter_.addBodyClass(c.cssClasses.SCROLL_LOCK), - t.layout(), - (t.animationTimer_ = setTimeout(function() { - t.handleAnimationTimerEnd_(), - t.adapter_.trapFocus(t.adapter_.getInitialFocusEl()), - t.adapter_.notifyOpened(); - }, c.numbers.DIALOG_ANIMATION_OPEN_TIME_MS)); - }); - }), - (l.prototype.close = function(t) { - var e = this; - void 0 === t && (t = ""), - this.isOpen_ && - ((this.isOpen_ = !1), - this.adapter_.notifyClosing(t), - this.adapter_.addClass(c.cssClasses.CLOSING), - this.adapter_.removeClass(c.cssClasses.OPEN), - this.adapter_.removeBodyClass(c.cssClasses.SCROLL_LOCK), - cancelAnimationFrame(this.animationFrame_), - (this.animationFrame_ = 0), - clearTimeout(this.animationTimer_), - (this.animationTimer_ = setTimeout(function() { - e.adapter_.releaseFocus(), - e.handleAnimationTimerEnd_(), - e.adapter_.notifyClosed(t); - }, c.numbers.DIALOG_ANIMATION_CLOSE_TIME_MS))); - }), - (l.prototype.isOpen = function() { - return this.isOpen_; - }), - (l.prototype.getEscapeKeyAction = function() { - return this.escapeKeyAction_; - }), - (l.prototype.setEscapeKeyAction = function(t) { - this.escapeKeyAction_ = t; - }), - (l.prototype.getScrimClickAction = function() { - return this.scrimClickAction_; - }), - (l.prototype.setScrimClickAction = function(t) { - this.scrimClickAction_ = t; - }), - (l.prototype.getAutoStackButtons = function() { - return this.autoStackButtons_; - }), - (l.prototype.setAutoStackButtons = function(t) { - this.autoStackButtons_ = t; - }), - (l.prototype.layout = function() { - var t = this; - this.layoutFrame_ && cancelAnimationFrame(this.layoutFrame_), - (this.layoutFrame_ = requestAnimationFrame(function() { - t.layoutInternal_(), (t.layoutFrame_ = 0); - })); - }), - (l.prototype.handleClick = function(t) { - if ( - this.adapter_.eventTargetMatches( - t.target, - c.strings.SCRIM_SELECTOR - ) && - "" !== this.scrimClickAction_ - ) - this.close(this.scrimClickAction_); - else { - var e = this.adapter_.getActionFromEvent(t); - e && this.close(e); - } - }), - (l.prototype.handleKeydown = function(t) { - var e = "Enter" === t.key || 13 === t.keyCode; - if (e && !this.adapter_.getActionFromEvent(t)) { - var n = !this.adapter_.eventTargetMatches( - t.target, - c.strings.SUPPRESS_DEFAULT_PRESS_SELECTOR - ); - e && n && this.adapter_.clickDefaultButton(); - } - }), - (l.prototype.handleDocumentKeydown = function(t) { - ("Escape" !== t.key && 27 !== t.keyCode) || - "" === this.escapeKeyAction_ || - this.close(this.escapeKeyAction_); - }), - (l.prototype.layoutInternal_ = function() { - this.autoStackButtons_ && this.detectStackedButtons_(), - this.detectScrollableContent_(); - }), - (l.prototype.handleAnimationTimerEnd_ = function() { - (this.animationTimer_ = 0), - this.adapter_.removeClass(c.cssClasses.OPENING), - this.adapter_.removeClass(c.cssClasses.CLOSING); - }), - (l.prototype.runNextAnimationFrame_ = function(t) { - var e = this; - cancelAnimationFrame(this.animationFrame_), - (this.animationFrame_ = requestAnimationFrame(function() { - (e.animationFrame_ = 0), - clearTimeout(e.animationTimer_), - (e.animationTimer_ = setTimeout(t, 0)); - })); - }), - (l.prototype.detectStackedButtons_ = function() { - this.adapter_.removeClass(c.cssClasses.STACKED); - var t = this.adapter_.areButtonsStacked(); - t && this.adapter_.addClass(c.cssClasses.STACKED), - t !== this.areButtonsStacked_ && - (this.adapter_.reverseButtons(), - (this.areButtonsStacked_ = t)); - }), - (l.prototype.detectScrollableContent_ = function() { - this.adapter_.removeClass(c.cssClasses.SCROLLABLE), - this.adapter_.isContentScrollable() && - this.adapter_.addClass(c.cssClasses.SCROLLABLE); - }), - l); - function l(t) { - var e = s.call(this, o(o({}, l.defaultAdapter), t)) || this; - return ( - (e.isOpen_ = !1), - (e.animationFrame_ = 0), - (e.animationTimer_ = 0), - (e.layoutFrame_ = 0), - (e.escapeKeyAction_ = c.strings.CLOSE_ACTION), - (e.scrimClickAction_ = c.strings.CLOSE_ACTION), - (e.autoStackButtons_ = !0), - (e.areButtonsStacked_ = !1), - e - ); - } - (e.MDCDialogFoundation = u), (e.default = u); - }, - function(t, e, n) { - "use strict"; - Object.defineProperty(e, "__esModule", { value: !0 }), - (e.cssClasses = { - CLOSING: "mdc-dialog--closing", - OPEN: "mdc-dialog--open", - OPENING: "mdc-dialog--opening", - SCROLLABLE: "mdc-dialog--scrollable", - SCROLL_LOCK: "mdc-dialog-scroll-lock", - STACKED: "mdc-dialog--stacked" - }), - (e.strings = { - ACTION_ATTRIBUTE: "data-mdc-dialog-action", - BUTTON_DEFAULT_ATTRIBUTE: "data-mdc-dialog-button-default", - BUTTON_SELECTOR: ".mdc-dialog__button", - CLOSED_EVENT: "MDCDialog:closed", - CLOSE_ACTION: "close", - CLOSING_EVENT: "MDCDialog:closing", - CONTAINER_SELECTOR: ".mdc-dialog__container", - CONTENT_SELECTOR: ".mdc-dialog__content", - DESTROY_ACTION: "destroy", - INITIAL_FOCUS_ATTRIBUTE: "data-mdc-dialog-initial-focus", - OPENED_EVENT: "MDCDialog:opened", - OPENING_EVENT: "MDCDialog:opening", - SCRIM_SELECTOR: ".mdc-dialog__scrim", - SUPPRESS_DEFAULT_PRESS_SELECTOR: [ - "textarea", - ".mdc-menu .mdc-list-item" - ].join(", "), - SURFACE_SELECTOR: ".mdc-dialog__surface" - }), - (e.numbers = { - DIALOG_ANIMATION_CLOSE_TIME_MS: 75, - DIALOG_ANIMATION_OPEN_TIME_MS: 150 - }); - }, - function(t, e, n) { - "use strict"; - Object.defineProperty(e, "__esModule", { value: !0 }), - (e.createFocusTrapInstance = function(t, e) { - return e(t, { skipInitialFocus: !0 }); - }); - }, - function(t, e, n) { - "use strict"; - Object.defineProperty(e, "__esModule", { value: !0 }); - e.cssClasses = { - ANIMATE: "mdc-drawer--animate", - CLOSING: "mdc-drawer--closing", - DISMISSIBLE: "mdc-drawer--dismissible", - MODAL: "mdc-drawer--modal", - OPEN: "mdc-drawer--open", - OPENING: "mdc-drawer--opening", - ROOT: "mdc-drawer" - }; - e.strings = { - APP_CONTENT_SELECTOR: ".mdc-drawer-app-content", - CLOSE_EVENT: "MDCDrawer:closed", - OPEN_EVENT: "MDCDrawer:opened", - SCRIM_SELECTOR: ".mdc-drawer-scrim" - }; - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }); - Object.defineProperty(e, "__esModule", { value: !0 }); - var o, - s = n(23), - a = - ((o = s.MDCDismissibleDrawerFoundation), - r(c, o), - (c.prototype.handleScrimClick = function() { - this.close(); - }), - (c.prototype.opened_ = function() { - this.adapter_.trapFocus(); - }), - (c.prototype.closed_ = function() { - this.adapter_.releaseFocus(); - }), - c); - function c() { - return (null !== o && o.apply(this, arguments)) || this; - } - (e.MDCModalDrawerFoundation = a), (e.default = a); - }, - function(t, e, n) { - "use strict"; - Object.defineProperty(e, "__esModule", { value: !0 }), - (e.cssClasses = { - LABEL_FLOAT_ABOVE: "mdc-floating-label--float-above", - LABEL_SHAKE: "mdc-floating-label--shake", - ROOT: "mdc-floating-label" - }); - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }), - o = - (this && this.__assign) || - function() { - return (o = - Object.assign || - function(t) { - for (var e, n = 1, i = arguments.length; n < i; n++) - for (var r in (e = arguments[n])) - Object.prototype.hasOwnProperty.call(e, r) && - (t[r] = e[r]); - return t; - }).apply(this, arguments); - }; - Object.defineProperty(e, "__esModule", { value: !0 }); - var s, - a = n(0), - c = n(58), - u = - ((s = a.MDCFoundation), - r(l, s), - Object.defineProperty(l, "cssClasses", { - get: function() { - return c.cssClasses; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(l, "strings", { - get: function() { - return c.strings; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(l, "defaultAdapter", { - get: function() { - return { - activateInputRipple: function() {}, - deactivateInputRipple: function() {}, - deregisterInteractionHandler: function() {}, - registerInteractionHandler: function() {} - }; - }, - enumerable: !0, - configurable: !0 - }), - (l.prototype.init = function() { - this.adapter_.registerInteractionHandler( - "click", - this.clickHandler_ - ); - }), - (l.prototype.destroy = function() { - this.adapter_.deregisterInteractionHandler( - "click", - this.clickHandler_ - ); - }), - (l.prototype.handleClick_ = function() { - var t = this; - this.adapter_.activateInputRipple(), - requestAnimationFrame(function() { - return t.adapter_.deactivateInputRipple(); - }); - }), - l); - function l(t) { - var e = s.call(this, o(o({}, l.defaultAdapter), t)) || this; - return ( - (e.clickHandler_ = function() { - return e.handleClick_(); - }), - e - ); - } - (e.MDCFormFieldFoundation = u), (e.default = u); - }, - function(t, e, n) { - "use strict"; - Object.defineProperty(e, "__esModule", { value: !0 }), - (e.cssClasses = { ROOT: "mdc-form-field" }), - (e.strings = { LABEL_SELECTOR: ".mdc-form-field > label" }); - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }), - o = - (this && this.__assign) || - function() { - return (o = - Object.assign || - function(t) { - for (var e, n = 1, i = arguments.length; n < i; n++) - for (var r in (e = arguments[n])) - Object.prototype.hasOwnProperty.call(e, r) && - (t[r] = e[r]); - return t; - }).apply(this, arguments); - }; - Object.defineProperty(e, "__esModule", { value: !0 }); - var s, - a = n(0), - c = n(60), - u = - ((s = a.MDCFoundation), - r(l, s), - Object.defineProperty(l, "cssClasses", { - get: function() { - return c.cssClasses; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(l, "strings", { - get: function() { - return c.strings; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(l, "defaultAdapter", { - get: function() { - return { - addClass: function() {}, - hasClass: function() { - return !1; - }, - notifyChange: function() {}, - removeClass: function() {}, - getAttr: function() { - return null; - }, - setAttr: function() {} - }; - }, - enumerable: !0, - configurable: !0 - }), - (l.prototype.init = function() { - var t = this.adapter_.getAttr(c.strings.DATA_ARIA_LABEL_ON), - e = this.adapter_.getAttr(c.strings.DATA_ARIA_LABEL_OFF); - if (t && e) { - if (null !== this.adapter_.getAttr(c.strings.ARIA_PRESSED)) - throw new Error( - "MDCIconButtonToggleFoundation: Button should not set `aria-pressed` if it has a toggled aria label." - ); - this.hasToggledAriaLabel = !0; - } else - this.adapter_.setAttr( - c.strings.ARIA_PRESSED, - String(this.isOn()) - ); - }), - (l.prototype.handleClick = function() { - this.toggle(), this.adapter_.notifyChange({ isOn: this.isOn() }); - }), - (l.prototype.isOn = function() { - return this.adapter_.hasClass(c.cssClasses.ICON_BUTTON_ON); - }), - (l.prototype.toggle = function(t) { - if ( - (void 0 === t && (t = !this.isOn()), - t - ? this.adapter_.addClass(c.cssClasses.ICON_BUTTON_ON) - : this.adapter_.removeClass(c.cssClasses.ICON_BUTTON_ON), - this.hasToggledAriaLabel) - ) { - var e = t - ? this.adapter_.getAttr(c.strings.DATA_ARIA_LABEL_ON) - : this.adapter_.getAttr(c.strings.DATA_ARIA_LABEL_OFF); - this.adapter_.setAttr(c.strings.ARIA_LABEL, e || ""); - } else this.adapter_.setAttr(c.strings.ARIA_PRESSED, "" + t); - }), - l); - function l(t) { - var e = s.call(this, o(o({}, l.defaultAdapter), t)) || this; - return (e.hasToggledAriaLabel = !1), e; - } - (e.MDCIconButtonToggleFoundation = u), (e.default = u); - }, - function(t, e, n) { - "use strict"; - Object.defineProperty(e, "__esModule", { value: !0 }), - (e.cssClasses = { - ICON_BUTTON_ON: "mdc-icon-button--on", - ROOT: "mdc-icon-button" - }), - (e.strings = { - ARIA_LABEL: "aria-label", - ARIA_PRESSED: "aria-pressed", - DATA_ARIA_LABEL_OFF: "data-aria-label-off", - DATA_ARIA_LABEL_ON: "data-aria-label-on", - CHANGE_EVENT: "MDCIconButtonToggle:change" - }); - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }), - o = - (this && this.__assign) || - function() { - return (o = - Object.assign || - function(t) { - for (var e, n = 1, i = arguments.length; n < i; n++) - for (var r in (e = arguments[n])) - Object.prototype.hasOwnProperty.call(e, r) && - (t[r] = e[r]); - return t; - }).apply(this, arguments); - }; - Object.defineProperty(e, "__esModule", { value: !0 }); - var s, - a = n(0), - c = n(62), - u = - ((s = a.MDCFoundation), - r(l, s), - Object.defineProperty(l, "cssClasses", { - get: function() { - return c.cssClasses; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(l, "defaultAdapter", { - get: function() { - return { - addClass: function() {}, - removeClass: function() {}, - hasClass: function() { - return !1; - }, - setStyle: function() {}, - registerEventHandler: function() {}, - deregisterEventHandler: function() {} - }; - }, - enumerable: !0, - configurable: !0 - }), - (l.prototype.init = function() { - this.adapter_.registerEventHandler( - "transitionend", - this.transitionEndHandler_ - ); - }), - (l.prototype.destroy = function() { - this.adapter_.deregisterEventHandler( - "transitionend", - this.transitionEndHandler_ - ); - }), - (l.prototype.activate = function() { - this.adapter_.removeClass(c.cssClasses.LINE_RIPPLE_DEACTIVATING), - this.adapter_.addClass(c.cssClasses.LINE_RIPPLE_ACTIVE); - }), - (l.prototype.setRippleCenter = function(t) { - this.adapter_.setStyle("transform-origin", t + "px center"); - }), - (l.prototype.deactivate = function() { - this.adapter_.addClass(c.cssClasses.LINE_RIPPLE_DEACTIVATING); - }), - (l.prototype.handleTransitionEnd = function(t) { - var e = this.adapter_.hasClass( - c.cssClasses.LINE_RIPPLE_DEACTIVATING - ); - "opacity" === t.propertyName && - e && - (this.adapter_.removeClass(c.cssClasses.LINE_RIPPLE_ACTIVE), - this.adapter_.removeClass( - c.cssClasses.LINE_RIPPLE_DEACTIVATING - )); - }), - l); - function l(t) { - var e = s.call(this, o(o({}, l.defaultAdapter), t)) || this; - return ( - (e.transitionEndHandler_ = function(t) { - return e.handleTransitionEnd(t); - }), - e - ); - } - (e.MDCLineRippleFoundation = u), (e.default = u); - }, - function(t, e, n) { - "use strict"; - Object.defineProperty(e, "__esModule", { value: !0 }); - e.cssClasses = { - LINE_RIPPLE_ACTIVE: "mdc-line-ripple--active", - LINE_RIPPLE_DEACTIVATING: "mdc-line-ripple--deactivating" - }; - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }), - o = - (this && this.__assign) || - function() { - return (o = - Object.assign || - function(t) { - for (var e, n = 1, i = arguments.length; n < i; n++) - for (var r in (e = arguments[n])) - Object.prototype.hasOwnProperty.call(e, r) && - (t[r] = e[r]); - return t; - }).apply(this, arguments); - }; - Object.defineProperty(e, "__esModule", { value: !0 }); - var s, - a = n(15), - c = n(0), - u = n(64), - l = - ((s = c.MDCFoundation), - r(d, s), - Object.defineProperty(d, "cssClasses", { - get: function() { - return u.cssClasses; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(d, "strings", { - get: function() { - return u.strings; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(d, "defaultAdapter", { - get: function() { - return { - addClass: function() {}, - forceLayout: function() {}, - setBufferBarStyle: function() { - return null; - }, - setPrimaryBarStyle: function() { - return null; - }, - hasClass: function() { - return !1; - }, - removeAttribute: function() {}, - removeClass: function() {}, - setAttribute: function() {} - }; - }, - enumerable: !0, - configurable: !0 - }), - (d.prototype.init = function() { - (this.isDeterminate_ = !this.adapter_.hasClass( - u.cssClasses.INDETERMINATE_CLASS - )), - (this.isReversed_ = this.adapter_.hasClass( - u.cssClasses.REVERSED_CLASS - )), - (this.progress_ = 0), - (this.buffer_ = 1); - }), - (d.prototype.setDeterminate = function(t) { - if (((this.isDeterminate_ = t), this.isDeterminate_)) - return ( - this.adapter_.removeClass(u.cssClasses.INDETERMINATE_CLASS), - this.adapter_.setAttribute( - u.strings.ARIA_VALUENOW, - this.progress_.toString() - ), - this.setPrimaryBarProgress_(this.progress_), - void this.setBufferBarProgress_(this.buffer_) - ); - this.isReversed_ && - (this.adapter_.removeClass(u.cssClasses.REVERSED_CLASS), - this.adapter_.forceLayout(), - this.adapter_.addClass(u.cssClasses.REVERSED_CLASS)), - this.adapter_.addClass(u.cssClasses.INDETERMINATE_CLASS), - this.adapter_.removeAttribute(u.strings.ARIA_VALUENOW), - this.setPrimaryBarProgress_(1), - this.setBufferBarProgress_(1); - }), - (d.prototype.isDeterminate = function() { - return this.isDeterminate_; - }), - (d.prototype.setProgress = function(t) { - (this.progress_ = t), - this.isDeterminate_ && - (this.setPrimaryBarProgress_(t), - this.adapter_.setAttribute( - u.strings.ARIA_VALUENOW, - t.toString() - )); - }), - (d.prototype.getProgress = function() { - return this.progress_; - }), - (d.prototype.setBuffer = function(t) { - (this.buffer_ = t), - this.isDeterminate_ && this.setBufferBarProgress_(t); - }), - (d.prototype.setReverse = function(t) { - (this.isReversed_ = t), - this.isDeterminate_ || - (this.adapter_.removeClass(u.cssClasses.INDETERMINATE_CLASS), - this.adapter_.forceLayout(), - this.adapter_.addClass(u.cssClasses.INDETERMINATE_CLASS)), - this.isReversed_ - ? this.adapter_.addClass(u.cssClasses.REVERSED_CLASS) - : this.adapter_.removeClass(u.cssClasses.REVERSED_CLASS); - }), - (d.prototype.open = function() { - this.adapter_.removeClass(u.cssClasses.CLOSED_CLASS); - }), - (d.prototype.close = function() { - this.adapter_.addClass(u.cssClasses.CLOSED_CLASS); - }), - (d.prototype.setPrimaryBarProgress_ = function(t) { - var e = "scaleX(" + t + ")", - n = - "undefined" != typeof window - ? a.getCorrectPropertyName(window, "transform") - : "transform"; - this.adapter_.setPrimaryBarStyle(n, e); - }), - (d.prototype.setBufferBarProgress_ = function(t) { - var e = 100 * t + "%"; - this.adapter_.setBufferBarStyle(u.strings.FLEX_BASIS, e); - }), - d); - function d(t) { - return s.call(this, o(o({}, d.defaultAdapter), t)) || this; - } - (e.MDCLinearProgressFoundation = l), (e.default = l); - }, - function(t, e, n) { - "use strict"; - Object.defineProperty(e, "__esModule", { value: !0 }), - (e.cssClasses = { - CLOSED_CLASS: "mdc-linear-progress--closed", - INDETERMINATE_CLASS: "mdc-linear-progress--indeterminate", - REVERSED_CLASS: "mdc-linear-progress--reversed" - }), - (e.strings = { - ARIA_VALUENOW: "aria-valuenow", - BUFFER_BAR_SELECTOR: ".mdc-linear-progress__buffer-bar", - FLEX_BASIS: "flex-basis", - PRIMARY_BAR_SELECTOR: ".mdc-linear-progress__primary-bar" - }); - }, - function(t, e, n) { - "use strict"; - var i; - Object.defineProperty(e, "__esModule", { value: !0 }), - (e.getTransformPropertyName = function(t, e) { - if ((void 0 === e && (e = !1), void 0 === i || e)) { - var n = t.document.createElement("div"); - i = "transform" in n.style ? "transform" : "webkitTransform"; - } - return i; - }); - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }), - o = - (this && this.__importStar) || - function(t) { - if (t && t.__esModule) return t; - var e = {}; - if (null != t) - for (var n in t) - Object.hasOwnProperty.call(t, n) && (e[n] = t[n]); - return (e.default = t), e; - }; - Object.defineProperty(e, "__esModule", { value: !0 }); - var s, - a = n(1), - c = n(6), - u = n(11), - l = o(n(65)), - d = - ((s = a.MDCComponent), - r(p, s), - (p.attachTo = function(t) { - return new p(t); - }), - (p.prototype.initialSyncWithDOM = function() { - var e = this, - t = this.root_.parentElement; - (this.anchorElement = - t && t.classList.contains(c.cssClasses.ANCHOR) ? t : null), - this.root_.classList.contains(c.cssClasses.FIXED) && - this.setFixedPosition(!0), - (this.handleKeydown_ = function(t) { - return e.foundation_.handleKeydown(t); - }), - (this.handleBodyClick_ = function(t) { - return e.foundation_.handleBodyClick(t); - }), - (this.registerBodyClickListener_ = function() { - return document.body.addEventListener( - "click", - e.handleBodyClick_, - { capture: !0 } - ); - }), - (this.deregisterBodyClickListener_ = function() { - return document.body.removeEventListener( - "click", - e.handleBodyClick_ - ); - }), - this.listen("keydown", this.handleKeydown_), - this.listen( - c.strings.OPENED_EVENT, - this.registerBodyClickListener_ - ), - this.listen( - c.strings.CLOSED_EVENT, - this.deregisterBodyClickListener_ - ); - }), - (p.prototype.destroy = function() { - this.unlisten("keydown", this.handleKeydown_), - this.unlisten( - c.strings.OPENED_EVENT, - this.registerBodyClickListener_ - ), - this.unlisten( - c.strings.CLOSED_EVENT, - this.deregisterBodyClickListener_ - ), - s.prototype.destroy.call(this); - }), - (p.prototype.isOpen = function() { - return this.foundation_.isOpen(); - }), - (p.prototype.open = function() { - this.foundation_.open(); - }), - (p.prototype.close = function(t) { - void 0 === t && (t = !1), this.foundation_.close(t); - }), - Object.defineProperty(p.prototype, "quickOpen", { - set: function(t) { - this.foundation_.setQuickOpen(t); - }, - enumerable: !0, - configurable: !0 - }), - (p.prototype.setIsHoisted = function(t) { - this.foundation_.setIsHoisted(t); - }), - (p.prototype.setMenuSurfaceAnchorElement = function(t) { - this.anchorElement = t; - }), - (p.prototype.setFixedPosition = function(t) { - t - ? this.root_.classList.add(c.cssClasses.FIXED) - : this.root_.classList.remove(c.cssClasses.FIXED), - this.foundation_.setFixedPosition(t); - }), - (p.prototype.setAbsolutePosition = function(t, e) { - this.foundation_.setAbsolutePosition(t, e), this.setIsHoisted(!0); - }), - (p.prototype.setAnchorCorner = function(t) { - this.foundation_.setAnchorCorner(t); - }), - (p.prototype.setAnchorMargin = function(t) { - this.foundation_.setAnchorMargin(t); - }), - (p.prototype.getDefaultFoundation = function() { - var n = this, - t = { - addClass: function(t) { - return n.root_.classList.add(t); - }, - removeClass: function(t) { - return n.root_.classList.remove(t); - }, - hasClass: function(t) { - return n.root_.classList.contains(t); - }, - hasAnchor: function() { - return !!n.anchorElement; - }, - notifyClose: function() { - return n.emit( - u.MDCMenuSurfaceFoundation.strings.CLOSED_EVENT, - {} - ); - }, - notifyOpen: function() { - return n.emit( - u.MDCMenuSurfaceFoundation.strings.OPENED_EVENT, - {} - ); - }, - isElementInContainer: function(t) { - return n.root_.contains(t); - }, - isRtl: function() { - return ( - "rtl" === - getComputedStyle(n.root_).getPropertyValue("direction") - ); - }, - setTransformOrigin: function(t) { - var e = l.getTransformPropertyName(window) + "-origin"; - n.root_.style.setProperty(e, t); - }, - isFocused: function() { - return document.activeElement === n.root_; - }, - saveFocus: function() { - n.previousFocus_ = document.activeElement; - }, - restoreFocus: function() { - n.root_.contains(document.activeElement) && - n.previousFocus_ && - n.previousFocus_.focus && - n.previousFocus_.focus(); - }, - getInnerDimensions: function() { - return { - width: n.root_.offsetWidth, - height: n.root_.offsetHeight - }; - }, - getAnchorDimensions: function() { - return n.anchorElement - ? n.anchorElement.getBoundingClientRect() - : null; - }, - getWindowDimensions: function() { - return { - width: window.innerWidth, - height: window.innerHeight - }; - }, - getBodyDimensions: function() { - return { - width: document.body.clientWidth, - height: document.body.clientHeight - }; - }, - getWindowScroll: function() { - return { x: window.pageXOffset, y: window.pageYOffset }; - }, - setPosition: function(t) { - (n.root_.style.left = "left" in t ? t.left + "px" : ""), - (n.root_.style.right = - "right" in t ? t.right + "px" : ""), - (n.root_.style.top = "top" in t ? t.top + "px" : ""), - (n.root_.style.bottom = - "bottom" in t ? t.bottom + "px" : ""); - }, - setMaxHeight: function(t) { - n.root_.style.maxHeight = t; - } - }; - return new u.MDCMenuSurfaceFoundation(t); - }), - p); - function p() { - return (null !== s && s.apply(this, arguments)) || this; - } - e.MDCMenuSurface = d; - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }); - Object.defineProperty(e, "__esModule", { value: !0 }); - var o, - s = n(1), - a = n(2), - c = n(22), - u = n(10), - l = n(66), - d = n(11), - p = n(12), - _ = n(68), - f = - ((o = s.MDCComponent), - r(h, o), - (h.attachTo = function(t) { - return new h(t); - }), - (h.prototype.initialize = function(t, e) { - void 0 === t && - (t = function(t) { - return new l.MDCMenuSurface(t); - }), - void 0 === e && - (e = function(t) { - return new c.MDCList(t); - }), - (this.menuSurfaceFactory_ = t), - (this.listFactory_ = e); - }), - (h.prototype.initialSyncWithDOM = function() { - var e = this; - this.menuSurface_ = this.menuSurfaceFactory_(this.root_); - var t = this.root_.querySelector(p.strings.LIST_SELECTOR); - t - ? ((this.list_ = this.listFactory_(t)), - (this.list_.wrapFocus = !0)) - : (this.list_ = null), - (this.handleKeydown_ = function(t) { - return e.foundation_.handleKeydown(t); - }), - (this.handleItemAction_ = function(t) { - return e.foundation_.handleItemAction( - e.items[t.detail.index] - ); - }), - (this.handleMenuSurfaceOpened_ = function() { - return e.foundation_.handleMenuSurfaceOpened(); - }), - this.menuSurface_.listen( - d.MDCMenuSurfaceFoundation.strings.OPENED_EVENT, - this.handleMenuSurfaceOpened_ - ), - this.listen("keydown", this.handleKeydown_), - this.listen( - u.MDCListFoundation.strings.ACTION_EVENT, - this.handleItemAction_ - ); - }), - (h.prototype.destroy = function() { - this.list_ && this.list_.destroy(), - this.menuSurface_.destroy(), - this.menuSurface_.unlisten( - d.MDCMenuSurfaceFoundation.strings.OPENED_EVENT, - this.handleMenuSurfaceOpened_ - ), - this.unlisten("keydown", this.handleKeydown_), - this.unlisten( - u.MDCListFoundation.strings.ACTION_EVENT, - this.handleItemAction_ - ), - o.prototype.destroy.call(this); - }), - Object.defineProperty(h.prototype, "open", { - get: function() { - return this.menuSurface_.isOpen(); - }, - set: function(t) { - t ? this.menuSurface_.open() : this.menuSurface_.close(); - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(h.prototype, "wrapFocus", { - get: function() { - return !!this.list_ && this.list_.wrapFocus; - }, - set: function(t) { - this.list_ && (this.list_.wrapFocus = t); - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(h.prototype, "items", { - get: function() { - return this.list_ ? this.list_.listElements : []; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(h.prototype, "quickOpen", { - set: function(t) { - this.menuSurface_.quickOpen = t; - }, - enumerable: !0, - configurable: !0 - }), - (h.prototype.setDefaultFocusState = function(t) { - this.foundation_.setDefaultFocusState(t); - }), - (h.prototype.setAnchorCorner = function(t) { - this.menuSurface_.setAnchorCorner(t); - }), - (h.prototype.setAnchorMargin = function(t) { - this.menuSurface_.setAnchorMargin(t); - }), - (h.prototype.setSelectedIndex = function(t) { - this.foundation_.setSelectedIndex(t); - }), - (h.prototype.setEnabled = function(t, e) { - this.foundation_.setEnabled(t, e); - }), - (h.prototype.getOptionByIndex = function(t) { - return t < this.items.length ? this.items[t] : null; - }), - (h.prototype.setFixedPosition = function(t) { - this.menuSurface_.setFixedPosition(t); - }), - (h.prototype.setIsHoisted = function(t) { - this.menuSurface_.setIsHoisted(t); - }), - (h.prototype.setAbsolutePosition = function(t, e) { - this.menuSurface_.setAbsolutePosition(t, e); - }), - (h.prototype.setAnchorElement = function(t) { - this.menuSurface_.anchorElement = t; - }), - (h.prototype.getDefaultFoundation = function() { - var i = this, - t = { - addClassToElementAtIndex: function(t, e) { - i.items[t].classList.add(e); - }, - removeClassFromElementAtIndex: function(t, e) { - i.items[t].classList.remove(e); - }, - addAttributeToElementAtIndex: function(t, e, n) { - i.items[t].setAttribute(e, n); - }, - removeAttributeFromElementAtIndex: function(t, e) { - i.items[t].removeAttribute(e); - }, - elementContainsClass: function(t, e) { - return t.classList.contains(e); - }, - closeSurface: function(t) { - return i.menuSurface_.close(t); - }, - getElementIndex: function(t) { - return i.items.indexOf(t); - }, - notifySelected: function(t) { - return i.emit(p.strings.SELECTED_EVENT, { - index: t.index, - item: i.items[t.index] - }); - }, - getMenuItemCount: function() { - return i.items.length; - }, - focusItemAtIndex: function(t) { - return i.items[t].focus(); - }, - focusListRoot: function() { - return i.root_ - .querySelector(p.strings.LIST_SELECTOR) - .focus(); - }, - isSelectableItemAtIndex: function(t) { - return !!a.closest( - i.items[t], - "." + p.cssClasses.MENU_SELECTION_GROUP - ); - }, - getSelectedSiblingOfItemAtIndex: function(t) { - var e = a - .closest( - i.items[t], - "." + p.cssClasses.MENU_SELECTION_GROUP - ) - .querySelector( - "." + p.cssClasses.MENU_SELECTED_LIST_ITEM - ); - return e ? i.items.indexOf(e) : -1; - } - }; - return new _.MDCMenuFoundation(t); - }), - h); - function h() { - return (null !== o && o.apply(this, arguments)) || this; - } - e.MDCMenu = f; - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }), - o = - (this && this.__assign) || - function() { - return (o = - Object.assign || - function(t) { - for (var e, n = 1, i = arguments.length; n < i; n++) - for (var r in (e = arguments[n])) - Object.prototype.hasOwnProperty.call(e, r) && - (t[r] = e[r]); - return t; - }).apply(this, arguments); - }; - Object.defineProperty(e, "__esModule", { value: !0 }); - var s, - a = n(0), - c = n(9), - u = n(11), - l = n(12), - d = - ((s = a.MDCFoundation), - r(p, s), - Object.defineProperty(p, "cssClasses", { - get: function() { - return l.cssClasses; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(p, "strings", { - get: function() { - return l.strings; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(p, "numbers", { - get: function() { - return l.numbers; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(p, "defaultAdapter", { - get: function() { - return { - addClassToElementAtIndex: function() {}, - removeClassFromElementAtIndex: function() {}, - addAttributeToElementAtIndex: function() {}, - removeAttributeFromElementAtIndex: function() {}, - elementContainsClass: function() { - return !1; - }, - closeSurface: function() {}, - getElementIndex: function() { - return -1; - }, - notifySelected: function() {}, - getMenuItemCount: function() { - return 0; - }, - focusItemAtIndex: function() {}, - focusListRoot: function() {}, - getSelectedSiblingOfItemAtIndex: function() { - return -1; - }, - isSelectableItemAtIndex: function() { - return !1; - } - }; - }, - enumerable: !0, - configurable: !0 - }), - (p.prototype.destroy = function() { - this.closeAnimationEndTimerId_ && - clearTimeout(this.closeAnimationEndTimerId_), - this.adapter_.closeSurface(); - }), - (p.prototype.handleKeydown = function(t) { - var e = t.key, - n = t.keyCode; - ("Tab" !== e && 9 !== n) || this.adapter_.closeSurface(!0); - }), - (p.prototype.handleItemAction = function(e) { - var n = this, - t = this.adapter_.getElementIndex(e); - t < 0 || - (this.adapter_.notifySelected({ index: t }), - this.adapter_.closeSurface(), - (this.closeAnimationEndTimerId_ = setTimeout(function() { - var t = n.adapter_.getElementIndex(e); - n.adapter_.isSelectableItemAtIndex(t) && - n.setSelectedIndex(t); - }, u - .MDCMenuSurfaceFoundation.numbers.TRANSITION_CLOSE_DURATION))); - }), - (p.prototype.handleMenuSurfaceOpened = function() { - switch (this.defaultFocusState_) { - case l.DefaultFocusState.FIRST_ITEM: - this.adapter_.focusItemAtIndex(0); - break; - case l.DefaultFocusState.LAST_ITEM: - this.adapter_.focusItemAtIndex( - this.adapter_.getMenuItemCount() - 1 - ); - break; - case l.DefaultFocusState.NONE: - break; - default: - this.adapter_.focusListRoot(); - } - }), - (p.prototype.setDefaultFocusState = function(t) { - this.defaultFocusState_ = t; - }), - (p.prototype.setSelectedIndex = function(t) { - if ( - (this.validatedIndex_(t), - !this.adapter_.isSelectableItemAtIndex(t)) - ) - throw new Error( - "MDCMenuFoundation: No selection group at specified index." - ); - var e = this.adapter_.getSelectedSiblingOfItemAtIndex(t); - 0 <= e && - (this.adapter_.removeAttributeFromElementAtIndex( - e, - l.strings.ARIA_CHECKED_ATTR - ), - this.adapter_.removeClassFromElementAtIndex( - e, - l.cssClasses.MENU_SELECTED_LIST_ITEM - )), - this.adapter_.addClassToElementAtIndex( - t, - l.cssClasses.MENU_SELECTED_LIST_ITEM - ), - this.adapter_.addAttributeToElementAtIndex( - t, - l.strings.ARIA_CHECKED_ATTR, - "true" - ); - }), - (p.prototype.setEnabled = function(t, e) { - this.validatedIndex_(t), - e - ? (this.adapter_.removeClassFromElementAtIndex( - t, - c.cssClasses.LIST_ITEM_DISABLED_CLASS - ), - this.adapter_.addAttributeToElementAtIndex( - t, - l.strings.ARIA_DISABLED_ATTR, - "false" - )) - : (this.adapter_.addClassToElementAtIndex( - t, - c.cssClasses.LIST_ITEM_DISABLED_CLASS - ), - this.adapter_.addAttributeToElementAtIndex( - t, - l.strings.ARIA_DISABLED_ATTR, - "true" - )); - }), - (p.prototype.validatedIndex_ = function(t) { - var e = this.adapter_.getMenuItemCount(); - if (!(0 <= t && t < e)) - throw new Error( - "MDCMenuFoundation: No list item at specified index." - ); - }), - p); - function p(t) { - var e = s.call(this, o(o({}, p.defaultAdapter), t)) || this; - return ( - (e.closeAnimationEndTimerId_ = 0), - (e.defaultFocusState_ = l.DefaultFocusState.LIST_ROOT), - e - ); - } - (e.MDCMenuFoundation = d), (e.default = d); - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }), - o = - (this && this.__assign) || - function() { - return (o = - Object.assign || - function(t) { - for (var e, n = 1, i = arguments.length; n < i; n++) - for (var r in (e = arguments[n])) - Object.prototype.hasOwnProperty.call(e, r) && - (t[r] = e[r]); - return t; - }).apply(this, arguments); - }; - Object.defineProperty(e, "__esModule", { value: !0 }); - var s, - a = n(0), - c = n(28), - u = - ((s = a.MDCFoundation), - r(l, s), - Object.defineProperty(l, "strings", { - get: function() { - return c.strings; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(l, "cssClasses", { - get: function() { - return c.cssClasses; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(l, "numbers", { - get: function() { - return c.numbers; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(l, "defaultAdapter", { - get: function() { - return { - addClass: function() {}, - removeClass: function() {}, - setNotchWidthProperty: function() {}, - removeNotchWidthProperty: function() {} - }; - }, - enumerable: !0, - configurable: !0 - }), - (l.prototype.notch = function(t) { - var e = l.cssClasses.OUTLINE_NOTCHED; - 0 < t && (t += c.numbers.NOTCH_ELEMENT_PADDING), - this.adapter_.setNotchWidthProperty(t), - this.adapter_.addClass(e); - }), - (l.prototype.closeNotch = function() { - var t = l.cssClasses.OUTLINE_NOTCHED; - this.adapter_.removeClass(t), - this.adapter_.removeNotchWidthProperty(); - }), - l); - function l(t) { - return s.call(this, o(o({}, l.defaultAdapter), t)) || this; - } - (e.MDCNotchedOutlineFoundation = u), (e.default = u); - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }), - o = - (this && this.__assign) || - function() { - return (o = - Object.assign || - function(t) { - for (var e, n = 1, i = arguments.length; n < i; n++) - for (var r in (e = arguments[n])) - Object.prototype.hasOwnProperty.call(e, r) && - (t[r] = e[r]); - return t; - }).apply(this, arguments); - }; - Object.defineProperty(e, "__esModule", { value: !0 }); - var s, - a = n(0), - c = n(71), - u = - ((s = a.MDCFoundation), - r(l, s), - Object.defineProperty(l, "cssClasses", { - get: function() { - return c.cssClasses; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(l, "strings", { - get: function() { - return c.strings; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(l, "defaultAdapter", { - get: function() { - return { - addClass: function() {}, - removeClass: function() {}, - setNativeControlDisabled: function() {} - }; - }, - enumerable: !0, - configurable: !0 - }), - (l.prototype.setDisabled = function(t) { - var e = l.cssClasses.DISABLED; - this.adapter_.setNativeControlDisabled(t), - t ? this.adapter_.addClass(e) : this.adapter_.removeClass(e); - }), - l); - function l(t) { - return s.call(this, o(o({}, l.defaultAdapter), t)) || this; - } - (e.MDCRadioFoundation = u), (e.default = u); - }, - function(t, e, n) { - "use strict"; - Object.defineProperty(e, "__esModule", { value: !0 }); - e.strings = { NATIVE_CONTROL_SELECTOR: ".mdc-radio__native-control" }; - e.cssClasses = { DISABLED: "mdc-radio--disabled", ROOT: "mdc-radio" }; - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }), - o = - (this && this.__assign) || - function() { - return (o = - Object.assign || - function(t) { - for (var e, n = 1, i = arguments.length; n < i; n++) - for (var r in (e = arguments[n])) - Object.prototype.hasOwnProperty.call(e, r) && - (t[r] = e[r]); - return t; - }).apply(this, arguments); - }; - Object.defineProperty(e, "__esModule", { value: !0 }); - var s, - a = n(0), - c = n(6), - u = n(29), - l = - ((s = a.MDCFoundation), - r(d, s), - Object.defineProperty(d, "cssClasses", { - get: function() { - return u.cssClasses; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(d, "numbers", { - get: function() { - return u.numbers; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(d, "strings", { - get: function() { - return u.strings; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(d, "defaultAdapter", { - get: function() { - return { - addClass: function() {}, - removeClass: function() {}, - hasClass: function() { - return !1; - }, - activateBottomLine: function() {}, - deactivateBottomLine: function() {}, - getSelectedMenuItem: function() { - return null; - }, - hasLabel: function() { - return !1; - }, - floatLabel: function() {}, - getLabelWidth: function() { - return 0; - }, - hasOutline: function() { - return !1; - }, - notchOutline: function() {}, - closeOutline: function() {}, - setRippleCenter: function() {}, - notifyChange: function() {}, - setSelectedText: function() {}, - isSelectAnchorFocused: function() { - return !1; - }, - getSelectAnchorAttr: function() { - return ""; - }, - setSelectAnchorAttr: function() {}, - openMenu: function() {}, - closeMenu: function() {}, - getAnchorElement: function() { - return null; - }, - setMenuAnchorElement: function() {}, - setMenuAnchorCorner: function() {}, - setMenuWrapFocus: function() {}, - setAttributeAtIndex: function() {}, - removeAttributeAtIndex: function() {}, - focusMenuItemAtIndex: function() {}, - getMenuItemCount: function() { - return 0; - }, - getMenuItemValues: function() { - return []; - }, - getMenuItemTextAtIndex: function() { - return ""; - }, - getMenuItemAttr: function() { - return ""; - }, - addClassAtIndex: function() {}, - removeClassAtIndex: function() {} - }; - }, - enumerable: !0, - configurable: !0 - }), - (d.prototype.getSelectedIndex = function() { - return this.selectedIndex; - }), - (d.prototype.setSelectedIndex = function(t, e) { - if ( - (void 0 === e && (e = !1), - !(t >= this.adapter_.getMenuItemCount())) - ) { - var n = this.selectedIndex; - (this.selectedIndex = t), - this.selectedIndex === u.numbers.UNSET_INDEX - ? this.adapter_.setSelectedText("") - : this.adapter_.setSelectedText( - this.adapter_ - .getMenuItemTextAtIndex(this.selectedIndex) - .trim() - ), - n !== u.numbers.UNSET_INDEX && - (this.adapter_.removeClassAtIndex( - n, - u.cssClasses.SELECTED_ITEM_CLASS - ), - this.adapter_.removeAttributeAtIndex( - n, - u.strings.ARIA_SELECTED_ATTR - )), - this.selectedIndex !== u.numbers.UNSET_INDEX && - (this.adapter_.addClassAtIndex( - this.selectedIndex, - u.cssClasses.SELECTED_ITEM_CLASS - ), - this.adapter_.setAttributeAtIndex( - this.selectedIndex, - u.strings.ARIA_SELECTED_ATTR, - "true" - )), - this.layout(), - e && this.adapter_.closeMenu(), - this.handleChange(); - } - }), - (d.prototype.setValue = function(t) { - var e = this.menuItemValues.indexOf(t); - this.setSelectedIndex(e); - }), - (d.prototype.getValue = function() { - var t = this.adapter_.getSelectedMenuItem(); - return ( - (t && this.adapter_.getMenuItemAttr(t, u.strings.VALUE_ATTR)) || - "" - ); - }), - (d.prototype.getDisabled = function() { - return this.disabled; - }), - (d.prototype.setDisabled = function(t) { - (this.disabled = t), - this.disabled - ? (this.adapter_.addClass(u.cssClasses.DISABLED), - this.adapter_.closeMenu()) - : this.adapter_.removeClass(u.cssClasses.DISABLED), - this.leadingIcon && this.leadingIcon.setDisabled(this.disabled), - this.adapter_.setSelectAnchorAttr( - "tabindex", - this.disabled ? "-1" : "0" - ), - this.adapter_.setSelectAnchorAttr( - "aria-disabled", - this.disabled.toString() - ); - }), - (d.prototype.setHelperTextContent = function(t) { - this.helperText && this.helperText.setContent(t); - }), - (d.prototype.layout = function() { - if (this.adapter_.hasLabel()) { - var t = 0 < this.getValue().length; - this.notchOutline(t); - } - }), - (d.prototype.handleMenuOpened = function() { - if (0 !== this.adapter_.getMenuItemValues().length) { - this.adapter_.addClass(u.cssClasses.ACTIVATED); - var t = 0 <= this.selectedIndex ? this.selectedIndex : 0; - this.adapter_.focusMenuItemAtIndex(t); - } - }), - (d.prototype.handleMenuClosed = function() { - this.adapter_.removeClass(u.cssClasses.ACTIVATED), - (this.isMenuOpen = !1), - this.adapter_.setSelectAnchorAttr("aria-expanded", "false"), - this.adapter_.isSelectAnchorFocused() || this.blur(); - }), - (d.prototype.handleChange = function() { - this.updateLabel(), - this.adapter_.notifyChange(this.getValue()), - this.adapter_.hasClass(u.cssClasses.REQUIRED) && - (this.setValid(this.isValid()), - this.helperText && - this.helperText.setValidity(this.isValid())); - }), - (d.prototype.handleMenuItemAction = function(t) { - this.setSelectedIndex(t, !0); - }), - (d.prototype.handleFocus = function() { - this.adapter_.addClass(u.cssClasses.FOCUSED), - this.adapter_.hasLabel() && - (this.notchOutline(!0), this.adapter_.floatLabel(!0)), - this.adapter_.activateBottomLine(), - this.helperText && this.helperText.showToScreenReader(); - }), - (d.prototype.handleBlur = function() { - this.isMenuOpen || this.blur(); - }), - (d.prototype.handleClick = function(t) { - this.isMenuOpen || - (this.adapter_.setRippleCenter(t), - this.adapter_.openMenu(), - (this.isMenuOpen = !0), - this.adapter_.setSelectAnchorAttr("aria-expanded", "true")); - }), - (d.prototype.handleKeydown = function(t) { - if (!this.isMenuOpen) { - var e = "Enter" === t.key || 13 === t.keyCode, - n = "Space" === t.key || 32 === t.keyCode, - i = "ArrowUp" === t.key || 38 === t.keyCode, - r = "ArrowDown" === t.key || 40 === t.keyCode; - this.adapter_.hasClass(u.cssClasses.FOCUSED) && - (e || n || i || r) && - (this.adapter_.openMenu(), - (this.isMenuOpen = !0), - this.adapter_.setSelectAnchorAttr("aria-expanded", "true"), - t.preventDefault()); - } - }), - (d.prototype.notchOutline = function(t) { - if (this.adapter_.hasOutline()) { - var e = this.adapter_.hasClass(u.cssClasses.FOCUSED); - if (t) { - var n = u.numbers.LABEL_SCALE, - i = this.adapter_.getLabelWidth() * n; - this.adapter_.notchOutline(i); - } else e || this.adapter_.closeOutline(); - } - }), - (d.prototype.setLeadingIconAriaLabel = function(t) { - this.leadingIcon && this.leadingIcon.setAriaLabel(t); - }), - (d.prototype.setLeadingIconContent = function(t) { - this.leadingIcon && this.leadingIcon.setContent(t); - }), - (d.prototype.setValid = function(t) { - this.adapter_.setSelectAnchorAttr( - "aria-invalid", - (!t).toString() - ), - t - ? this.adapter_.removeClass(u.cssClasses.INVALID) - : this.adapter_.addClass(u.cssClasses.INVALID); - }), - (d.prototype.isValid = function() { - return ( - !( - this.adapter_.hasClass(u.cssClasses.REQUIRED) && - !this.adapter_.hasClass(u.cssClasses.DISABLED) - ) || - (this.selectedIndex !== u.numbers.UNSET_INDEX && - (0 !== this.selectedIndex || Boolean(this.getValue()))) - ); - }), - (d.prototype.setRequired = function(t) { - t - ? this.adapter_.addClass(u.cssClasses.REQUIRED) - : this.adapter_.removeClass(u.cssClasses.REQUIRED), - this.adapter_.setSelectAnchorAttr( - "aria-required", - t.toString() - ); - }), - (d.prototype.getRequired = function() { - return ( - "true" === this.adapter_.getSelectAnchorAttr("aria-required") - ); - }), - (d.prototype.init = function() { - var t = this.adapter_.getAnchorElement(); - t && - (this.adapter_.setMenuAnchorElement(t), - this.adapter_.setMenuAnchorCorner(c.Corner.BOTTOM_START)), - this.adapter_.setMenuWrapFocus(!1); - var e = this.getValue(); - e && this.setValue(e), this.updateLabel(); - }), - (d.prototype.updateLabel = function() { - var t = 0 < this.getValue().length; - this.adapter_.hasLabel() && - (this.notchOutline(t), - this.adapter_.hasClass(u.cssClasses.FOCUSED) || - this.adapter_.floatLabel(t)); - }), - (d.prototype.blur = function() { - this.adapter_.removeClass(u.cssClasses.FOCUSED), - this.updateLabel(), - this.adapter_.deactivateBottomLine(), - this.adapter_.hasClass(u.cssClasses.REQUIRED) && - (this.setValid(this.isValid()), - this.helperText && - this.helperText.setValidity(this.isValid())); - }), - d); - function d(t, e) { - void 0 === e && (e = {}); - var n = s.call(this, o(o({}, d.defaultAdapter), t)) || this; - return ( - (n.selectedIndex = u.numbers.UNSET_INDEX), - (n.disabled = !1), - (n.isMenuOpen = !1), - (n.leadingIcon = e.leadingIcon), - (n.helperText = e.helperText), - (n.menuItemValues = n.adapter_.getMenuItemValues()), - n.setDisabled(n.adapter_.hasClass(u.cssClasses.DISABLED)), - n - ); - } - (e.MDCSelectFoundation = l), (e.default = l); - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }); - Object.defineProperty(e, "__esModule", { value: !0 }); - var o, - s = n(1), - a = n(74), - c = - ((o = s.MDCComponent), - r(u, o), - (u.attachTo = function(t) { - return new u(t); - }), - Object.defineProperty(u.prototype, "foundation", { - get: function() { - return this.foundation_; - }, - enumerable: !0, - configurable: !0 - }), - (u.prototype.getDefaultFoundation = function() { - var n = this, - t = { - addClass: function(t) { - return n.root_.classList.add(t); - }, - removeClass: function(t) { - return n.root_.classList.remove(t); - }, - hasClass: function(t) { - return n.root_.classList.contains(t); - }, - setAttr: function(t, e) { - return n.root_.setAttribute(t, e); - }, - removeAttr: function(t) { - return n.root_.removeAttribute(t); - }, - setContent: function(t) { - n.root_.textContent = t; - } - }; - return new a.MDCSelectHelperTextFoundation(t); - }), - u); - function u() { - return (null !== o && o.apply(this, arguments)) || this; - } - e.MDCSelectHelperText = c; - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }), - o = - (this && this.__assign) || - function() { - return (o = - Object.assign || - function(t) { - for (var e, n = 1, i = arguments.length; n < i; n++) - for (var r in (e = arguments[n])) - Object.prototype.hasOwnProperty.call(e, r) && - (t[r] = e[r]); - return t; - }).apply(this, arguments); - }; - Object.defineProperty(e, "__esModule", { value: !0 }); - var s, - a = n(0), - c = n(75), - u = - ((s = a.MDCFoundation), - r(l, s), - Object.defineProperty(l, "cssClasses", { - get: function() { - return c.cssClasses; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(l, "strings", { - get: function() { - return c.strings; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(l, "defaultAdapter", { - get: function() { - return { - addClass: function() {}, - removeClass: function() {}, - hasClass: function() { - return !1; - }, - setAttr: function() {}, - removeAttr: function() {}, - setContent: function() {} - }; - }, - enumerable: !0, - configurable: !0 - }), - (l.prototype.setContent = function(t) { - this.adapter_.setContent(t); - }), - (l.prototype.setPersistent = function(t) { - t - ? this.adapter_.addClass(c.cssClasses.HELPER_TEXT_PERSISTENT) - : this.adapter_.removeClass( - c.cssClasses.HELPER_TEXT_PERSISTENT - ); - }), - (l.prototype.setValidation = function(t) { - t - ? this.adapter_.addClass( - c.cssClasses.HELPER_TEXT_VALIDATION_MSG - ) - : this.adapter_.removeClass( - c.cssClasses.HELPER_TEXT_VALIDATION_MSG - ); - }), - (l.prototype.showToScreenReader = function() { - this.adapter_.removeAttr(c.strings.ARIA_HIDDEN); - }), - (l.prototype.setValidity = function(t) { - var e = this.adapter_.hasClass( - c.cssClasses.HELPER_TEXT_PERSISTENT - ), - n = - this.adapter_.hasClass( - c.cssClasses.HELPER_TEXT_VALIDATION_MSG - ) && !t; - n - ? this.adapter_.setAttr(c.strings.ROLE, "alert") - : this.adapter_.removeAttr(c.strings.ROLE), - e || n || this.hide_(); - }), - (l.prototype.hide_ = function() { - this.adapter_.setAttr(c.strings.ARIA_HIDDEN, "true"); - }), - l); - function l(t) { - return s.call(this, o(o({}, l.defaultAdapter), t)) || this; - } - (e.MDCSelectHelperTextFoundation = u), (e.default = u); - }, - function(t, e, n) { - "use strict"; - Object.defineProperty(e, "__esModule", { value: !0 }); - e.strings = { ARIA_HIDDEN: "aria-hidden", ROLE: "role" }; - e.cssClasses = { - HELPER_TEXT_PERSISTENT: "mdc-select-helper-text--persistent", - HELPER_TEXT_VALIDATION_MSG: "mdc-select-helper-text--validation-msg" - }; - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }); - Object.defineProperty(e, "__esModule", { value: !0 }); - var o, - s = n(1), - a = n(77), - c = - ((o = s.MDCComponent), - r(u, o), - (u.attachTo = function(t) { - return new u(t); - }), - Object.defineProperty(u.prototype, "foundation", { - get: function() { - return this.foundation_; - }, - enumerable: !0, - configurable: !0 - }), - (u.prototype.getDefaultFoundation = function() { - var n = this, - t = { - getAttr: function(t) { - return n.root_.getAttribute(t); - }, - setAttr: function(t, e) { - return n.root_.setAttribute(t, e); - }, - removeAttr: function(t) { - return n.root_.removeAttribute(t); - }, - setContent: function(t) { - n.root_.textContent = t; - }, - registerInteractionHandler: function(t, e) { - return n.listen(t, e); - }, - deregisterInteractionHandler: function(t, e) { - return n.unlisten(t, e); - }, - notifyIconAction: function() { - return n.emit( - a.MDCSelectIconFoundation.strings.ICON_EVENT, - {}, - !0 - ); - } - }; - return new a.MDCSelectIconFoundation(t); - }), - u); - function u() { - return (null !== o && o.apply(this, arguments)) || this; - } - e.MDCSelectIcon = c; - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }), - o = - (this && this.__assign) || - function() { - return (o = - Object.assign || - function(t) { - for (var e, n = 1, i = arguments.length; n < i; n++) - for (var r in (e = arguments[n])) - Object.prototype.hasOwnProperty.call(e, r) && - (t[r] = e[r]); - return t; - }).apply(this, arguments); - }; - Object.defineProperty(e, "__esModule", { value: !0 }); - var s, - a = n(0), - c = n(78), - u = ["click", "keydown"], - l = - ((s = a.MDCFoundation), - r(d, s), - Object.defineProperty(d, "strings", { - get: function() { - return c.strings; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(d, "defaultAdapter", { - get: function() { - return { - getAttr: function() { - return null; - }, - setAttr: function() {}, - removeAttr: function() {}, - setContent: function() {}, - registerInteractionHandler: function() {}, - deregisterInteractionHandler: function() {}, - notifyIconAction: function() {} - }; - }, - enumerable: !0, - configurable: !0 - }), - (d.prototype.init = function() { - var e = this; - (this.savedTabIndex_ = this.adapter_.getAttr("tabindex")), - u.forEach(function(t) { - e.adapter_.registerInteractionHandler( - t, - e.interactionHandler_ - ); - }); - }), - (d.prototype.destroy = function() { - var e = this; - u.forEach(function(t) { - e.adapter_.deregisterInteractionHandler( - t, - e.interactionHandler_ - ); - }); - }), - (d.prototype.setDisabled = function(t) { - this.savedTabIndex_ && - (t - ? (this.adapter_.setAttr("tabindex", "-1"), - this.adapter_.removeAttr("role")) - : (this.adapter_.setAttr("tabindex", this.savedTabIndex_), - this.adapter_.setAttr("role", c.strings.ICON_ROLE))); - }), - (d.prototype.setAriaLabel = function(t) { - this.adapter_.setAttr("aria-label", t); - }), - (d.prototype.setContent = function(t) { - this.adapter_.setContent(t); - }), - (d.prototype.handleInteraction = function(t) { - var e = "Enter" === t.key || 13 === t.keyCode; - ("click" !== t.type && !e) || this.adapter_.notifyIconAction(); - }), - d); - function d(t) { - var e = s.call(this, o(o({}, d.defaultAdapter), t)) || this; - return ( - (e.savedTabIndex_ = null), - (e.interactionHandler_ = function(t) { - return e.handleInteraction(t); - }), - e - ); - } - (e.MDCSelectIconFoundation = l), (e.default = l); - }, - function(t, e, n) { - "use strict"; - Object.defineProperty(e, "__esModule", { value: !0 }); - e.strings = { ICON_EVENT: "MDCSelect:icon", ICON_ROLE: "button" }; - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }), - o = - (this && this.__assign) || - function() { - return (o = - Object.assign || - function(t) { - for (var e, n = 1, i = arguments.length; n < i; n++) - for (var r in (e = arguments[n])) - Object.prototype.hasOwnProperty.call(e, r) && - (t[r] = e[r]); - return t; - }).apply(this, arguments); - }; - Object.defineProperty(e, "__esModule", { value: !0 }); - var s, - c = n(15), - a = n(0), - u = n(30), - l = !!window.PointerEvent, - d = l ? ["pointerdown"] : ["mousedown", "touchstart"], - p = l ? ["pointerup"] : ["mouseup", "touchend"], - _ = { - mousedown: "mousemove", - pointerdown: "pointermove", - touchstart: "touchmove" - }, - f = "ArrowDown", - h = "ArrowLeft", - C = "ArrowRight", - y = "ArrowUp", - E = "End", - g = "Home", - m = "PageDown", - A = "PageUp", - v = - ((s = a.MDCFoundation), - r(b, s), - Object.defineProperty(b, "cssClasses", { - get: function() { - return u.cssClasses; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(b, "strings", { - get: function() { - return u.strings; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(b, "numbers", { - get: function() { - return u.numbers; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(b, "defaultAdapter", { - get: function() { - return { - hasClass: function() { - return !1; - }, - addClass: function() {}, - removeClass: function() {}, - getAttribute: function() { - return null; - }, - setAttribute: function() {}, - removeAttribute: function() {}, - computeBoundingRect: function() { - return { - top: 0, - right: 0, - bottom: 0, - left: 0, - width: 0, - height: 0 - }; - }, - getTabIndex: function() { - return 0; - }, - registerInteractionHandler: function() {}, - deregisterInteractionHandler: function() {}, - registerThumbContainerInteractionHandler: function() {}, - deregisterThumbContainerInteractionHandler: function() {}, - registerBodyInteractionHandler: function() {}, - deregisterBodyInteractionHandler: function() {}, - registerResizeHandler: function() {}, - deregisterResizeHandler: function() {}, - notifyInput: function() {}, - notifyChange: function() {}, - setThumbContainerStyleProperty: function() {}, - setTrackStyleProperty: function() {}, - setMarkerValue: function() {}, - setTrackMarkers: function() {}, - isRTL: function() { - return !1; - } - }; - }, - enumerable: !0, - configurable: !0 - }), - (b.prototype.init = function() { - var e = this; - (this.isDiscrete_ = this.adapter_.hasClass( - u.cssClasses.IS_DISCRETE - )), - (this.hasTrackMarker_ = this.adapter_.hasClass( - u.cssClasses.HAS_TRACK_MARKER - )), - d.forEach(function(t) { - e.adapter_.registerInteractionHandler( - t, - e.interactionStartHandler_ - ), - e.adapter_.registerThumbContainerInteractionHandler( - t, - e.thumbContainerPointerHandler_ - ); - }), - this.adapter_.registerInteractionHandler( - "keydown", - this.keydownHandler_ - ), - this.adapter_.registerInteractionHandler( - "focus", - this.focusHandler_ - ), - this.adapter_.registerInteractionHandler( - "blur", - this.blurHandler_ - ), - this.adapter_.registerResizeHandler(this.resizeHandler_), - this.layout(), - this.isDiscrete_ && 0 === this.getStep() && (this.step_ = 1); - }), - (b.prototype.destroy = function() { - var e = this; - d.forEach(function(t) { - e.adapter_.deregisterInteractionHandler( - t, - e.interactionStartHandler_ - ), - e.adapter_.deregisterThumbContainerInteractionHandler( - t, - e.thumbContainerPointerHandler_ - ); - }), - this.adapter_.deregisterInteractionHandler( - "keydown", - this.keydownHandler_ - ), - this.adapter_.deregisterInteractionHandler( - "focus", - this.focusHandler_ - ), - this.adapter_.deregisterInteractionHandler( - "blur", - this.blurHandler_ - ), - this.adapter_.deregisterResizeHandler(this.resizeHandler_); - }), - (b.prototype.setupTrackMarker = function() { - this.isDiscrete_ && - this.hasTrackMarker_ && - 0 !== this.getStep() && - this.adapter_.setTrackMarkers( - this.getStep(), - this.getMax(), - this.getMin() - ); - }), - (b.prototype.layout = function() { - (this.rect_ = this.adapter_.computeBoundingRect()), - this.updateUIForCurrentValue_(); - }), - (b.prototype.getValue = function() { - return this.value_; - }), - (b.prototype.setValue = function(t) { - this.setValue_(t, !1); - }), - (b.prototype.getMax = function() { - return this.max_; - }), - (b.prototype.setMax = function(t) { - if (t < this.min_) - throw new Error( - "Cannot set max to be less than the slider's minimum value" - ); - (this.max_ = t), - this.setValue_(this.value_, !1, !0), - this.adapter_.setAttribute( - u.strings.ARIA_VALUEMAX, - String(this.max_) - ), - this.setupTrackMarker(); - }), - (b.prototype.getMin = function() { - return this.min_; - }), - (b.prototype.setMin = function(t) { - if (t > this.max_) - throw new Error( - "Cannot set min to be greater than the slider's maximum value" - ); - (this.min_ = t), - this.setValue_(this.value_, !1, !0), - this.adapter_.setAttribute( - u.strings.ARIA_VALUEMIN, - String(this.min_) - ), - this.setupTrackMarker(); - }), - (b.prototype.getStep = function() { - return this.step_; - }), - (b.prototype.setStep = function(t) { - if (t < 0) - throw new Error("Step cannot be set to a negative number"); - this.isDiscrete_ && ("number" != typeof t || t < 1) && (t = 1), - (this.step_ = t), - this.setValue_(this.value_, !1, !0), - this.setupTrackMarker(); - }), - (b.prototype.isDisabled = function() { - return this.disabled_; - }), - (b.prototype.setDisabled = function(t) { - (this.disabled_ = t), - this.toggleClass_(u.cssClasses.DISABLED, this.disabled_), - this.disabled_ - ? ((this.savedTabIndex_ = this.adapter_.getTabIndex()), - this.adapter_.setAttribute(u.strings.ARIA_DISABLED, "true"), - this.adapter_.removeAttribute("tabindex")) - : (this.adapter_.removeAttribute(u.strings.ARIA_DISABLED), - isNaN(this.savedTabIndex_) || - this.adapter_.setAttribute( - "tabindex", - String(this.savedTabIndex_) - )); - }), - (b.prototype.handleDown_ = function(t) { - var n = this; - if (!this.disabled_) { - (this.preventFocusState_ = !0), - this.setInTransit_(!this.handlingThumbTargetEvt_), - (this.handlingThumbTargetEvt_ = !1), - this.setActive_(!0); - var i = function(t) { - n.handleMove_(t); - }, - r = _[t.type], - e = function e() { - n.handleUp_(), - n.adapter_.deregisterBodyInteractionHandler(r, i), - p.forEach(function(t) { - return n.adapter_.deregisterBodyInteractionHandler( - t, - e - ); - }); - }; - this.adapter_.registerBodyInteractionHandler(r, i), - p.forEach(function(t) { - return n.adapter_.registerBodyInteractionHandler(t, e); - }), - this.setValueFromEvt_(t); - } - }), - (b.prototype.handleMove_ = function(t) { - t.preventDefault(), this.setValueFromEvt_(t); - }), - (b.prototype.handleUp_ = function() { - this.setActive_(!1), this.adapter_.notifyChange(); - }), - (b.prototype.getClientX_ = function(t) { - return t.targetTouches && 0 < t.targetTouches.length - ? t.targetTouches[0].clientX - : t.clientX; - }), - (b.prototype.setValueFromEvt_ = function(t) { - var e = this.getClientX_(t), - n = this.computeValueFromClientX_(e); - this.setValue_(n, !0); - }), - (b.prototype.computeValueFromClientX_ = function(t) { - var e = this.max_, - n = this.min_, - i = (t - this.rect_.left) / this.rect_.width; - return this.adapter_.isRTL() && (i = 1 - i), n + i * (e - n); - }), - (b.prototype.handleKeydown_ = function(t) { - var e = this.getKeyId_(t), - n = this.getValueForKeyId_(e); - isNaN(n) || - (t.preventDefault(), - this.adapter_.addClass(u.cssClasses.FOCUS), - this.setValue_(n, !0), - this.adapter_.notifyChange()); - }), - (b.prototype.getKeyId_ = function(t) { - return t.key === h || 37 === t.keyCode - ? h - : t.key === C || 39 === t.keyCode - ? C - : t.key === y || 38 === t.keyCode - ? y - : t.key === f || 40 === t.keyCode - ? f - : t.key === g || 36 === t.keyCode - ? g - : t.key === E || 35 === t.keyCode - ? E - : t.key === A || 33 === t.keyCode - ? A - : t.key === m || 34 === t.keyCode - ? m - : ""; - }), - (b.prototype.getValueForKeyId_ = function(t) { - var e = this.max_, - n = this.min_, - i = this.step_ || (e - n) / 100; - switch ( - (!this.adapter_.isRTL() || (t !== h && t !== C) || (i = -i), t) - ) { - case h: - case f: - return this.value_ - i; - case C: - case y: - return this.value_ + i; - case g: - return this.min_; - case E: - return this.max_; - case A: - return this.value_ + i * u.numbers.PAGE_FACTOR; - case m: - return this.value_ - i * u.numbers.PAGE_FACTOR; - default: - return NaN; - } - }), - (b.prototype.handleFocus_ = function() { - this.preventFocusState_ || - this.adapter_.addClass(u.cssClasses.FOCUS); - }), - (b.prototype.handleBlur_ = function() { - (this.preventFocusState_ = !1), - this.adapter_.removeClass(u.cssClasses.FOCUS); - }), - (b.prototype.setValue_ = function(t, e, n) { - if ((void 0 === n && (n = !1), t !== this.value_ || n)) { - var i = this.min_, - r = this.max_, - o = t === i || t === r; - this.step_ && !o && (t = this.quantize_(t)), - t < i ? (t = i) : r < t && (t = r), - (t = t || 0), - (this.value_ = t), - this.adapter_.setAttribute( - u.strings.ARIA_VALUENOW, - String(this.value_) - ), - this.updateUIForCurrentValue_(), - e && - (this.adapter_.notifyInput(), - this.isDiscrete_ && this.adapter_.setMarkerValue(t)); - } - }), - (b.prototype.quantize_ = function(t) { - return Math.round(t / this.step_) * this.step_; - }), - (b.prototype.updateUIForCurrentValue_ = function() { - var e = this, - t = this.max_, - n = this.min_, - i = (this.value_ - n) / (t - n), - r = i * this.rect_.width; - this.adapter_.isRTL() && (r = this.rect_.width - r); - var o = "undefined" != typeof window, - s = o - ? c.getCorrectPropertyName(window, "transform") - : "transform", - a = o - ? c.getCorrectEventName(window, "transitionend") - : "transitionend"; - this.inTransit_ && - this.adapter_.registerThumbContainerInteractionHandler( - a, - function t() { - e.setInTransit_(!1), - e.adapter_.deregisterThumbContainerInteractionHandler( - a, - t - ); - } - ), - requestAnimationFrame(function() { - e.adapter_.setThumbContainerStyleProperty( - s, - "translateX(" + r + "px) translateX(-50%)" - ), - e.adapter_.setTrackStyleProperty(s, "scaleX(" + i + ")"); - }); - }), - (b.prototype.setActive_ = function(t) { - (this.active_ = t), - this.toggleClass_(u.cssClasses.ACTIVE, this.active_); - }), - (b.prototype.setInTransit_ = function(t) { - (this.inTransit_ = t), - this.toggleClass_(u.cssClasses.IN_TRANSIT, this.inTransit_); - }), - (b.prototype.toggleClass_ = function(t, e) { - e ? this.adapter_.addClass(t) : this.adapter_.removeClass(t); - }), - b); - function b(t) { - var e = s.call(this, o(o({}, b.defaultAdapter), t)) || this; - return ( - (e.savedTabIndex_ = NaN), - (e.active_ = !1), - (e.inTransit_ = !1), - (e.isDiscrete_ = !1), - (e.hasTrackMarker_ = !1), - (e.handlingThumbTargetEvt_ = !1), - (e.min_ = 0), - (e.max_ = 100), - (e.step_ = 0), - (e.value_ = 0), - (e.disabled_ = !1), - (e.preventFocusState_ = !1), - (e.thumbContainerPointerHandler_ = function() { - return (e.handlingThumbTargetEvt_ = !0); - }), - (e.interactionStartHandler_ = function(t) { - return e.handleDown_(t); - }), - (e.keydownHandler_ = function(t) { - return e.handleKeydown_(t); - }), - (e.focusHandler_ = function() { - return e.handleFocus_(); - }), - (e.blurHandler_ = function() { - return e.handleBlur_(); - }), - (e.resizeHandler_ = function() { - return e.layout(); - }), - e - ); - } - (e.MDCSliderFoundation = v), (e.default = v); - }, - function(t, e, n) { - "use strict"; - Object.defineProperty(e, "__esModule", { value: !0 }); - var i = n(13), - r = i.numbers.ARIA_LIVE_DELAY_MS, - o = i.strings.ARIA_LIVE_LABEL_TEXT_ATTR; - e.announce = function(t, e) { - void 0 === e && (e = t); - var n = t.getAttribute("aria-live"), - i = e.textContent.trim(); - i && - n && - (t.setAttribute("aria-live", "off"), - (e.textContent = ""), - (e.innerHTML = - ' '), - e.setAttribute(o, i), - setTimeout(function() { - t.setAttribute("aria-live", n), - e.removeAttribute(o), - (e.textContent = i); - }, r)); - }; - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }), - o = - (this && this.__assign) || - function() { - return (o = - Object.assign || - function(t) { - for (var e, n = 1, i = arguments.length; n < i; n++) - for (var r in (e = arguments[n])) - Object.prototype.hasOwnProperty.call(e, r) && - (t[r] = e[r]); - return t; - }).apply(this, arguments); - }; - Object.defineProperty(e, "__esModule", { value: !0 }); - var s, - a = n(0), - c = n(13), - u = c.cssClasses.OPENING, - l = c.cssClasses.OPEN, - d = c.cssClasses.CLOSING, - p = c.strings.REASON_ACTION, - _ = c.strings.REASON_DISMISS, - f = - ((s = a.MDCFoundation), - r(h, s), - Object.defineProperty(h, "cssClasses", { - get: function() { - return c.cssClasses; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(h, "strings", { - get: function() { - return c.strings; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(h, "numbers", { - get: function() { - return c.numbers; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(h, "defaultAdapter", { - get: function() { - return { - addClass: function() {}, - announce: function() {}, - notifyClosed: function() {}, - notifyClosing: function() {}, - notifyOpened: function() {}, - notifyOpening: function() {}, - removeClass: function() {} - }; - }, - enumerable: !0, - configurable: !0 - }), - (h.prototype.destroy = function() { - this.clearAutoDismissTimer_(), - cancelAnimationFrame(this.animationFrame_), - (this.animationFrame_ = 0), - clearTimeout(this.animationTimer_), - (this.animationTimer_ = 0), - this.adapter_.removeClass(u), - this.adapter_.removeClass(l), - this.adapter_.removeClass(d); - }), - (h.prototype.open = function() { - var e = this; - this.clearAutoDismissTimer_(), - (this.isOpen_ = !0), - this.adapter_.notifyOpening(), - this.adapter_.removeClass(d), - this.adapter_.addClass(u), - this.adapter_.announce(), - this.runNextAnimationFrame_(function() { - e.adapter_.addClass(l), - (e.animationTimer_ = setTimeout(function() { - var t = e.getTimeoutMs(); - e.handleAnimationTimerEnd_(), - e.adapter_.notifyOpened(), - t !== c.numbers.INDETERMINATE && - (e.autoDismissTimer_ = setTimeout(function() { - e.close(_); - }, t)); - }, c.numbers.SNACKBAR_ANIMATION_OPEN_TIME_MS)); - }); - }), - (h.prototype.close = function(t) { - var e = this; - void 0 === t && (t = ""), - this.isOpen_ && - (cancelAnimationFrame(this.animationFrame_), - (this.animationFrame_ = 0), - this.clearAutoDismissTimer_(), - (this.isOpen_ = !1), - this.adapter_.notifyClosing(t), - this.adapter_.addClass(c.cssClasses.CLOSING), - this.adapter_.removeClass(c.cssClasses.OPEN), - this.adapter_.removeClass(c.cssClasses.OPENING), - clearTimeout(this.animationTimer_), - (this.animationTimer_ = setTimeout(function() { - e.handleAnimationTimerEnd_(), e.adapter_.notifyClosed(t); - }, c.numbers.SNACKBAR_ANIMATION_CLOSE_TIME_MS))); - }), - (h.prototype.isOpen = function() { - return this.isOpen_; - }), - (h.prototype.getTimeoutMs = function() { - return this.autoDismissTimeoutMs_; - }), - (h.prototype.setTimeoutMs = function(t) { - var e = c.numbers.MIN_AUTO_DISMISS_TIMEOUT_MS, - n = c.numbers.MAX_AUTO_DISMISS_TIMEOUT_MS, - i = c.numbers.INDETERMINATE; - if (!(t === c.numbers.INDETERMINATE || (t <= n && e <= t))) - throw new Error( - "\n timeoutMs must be an integer in the range " + - e + - "–" + - n + - "\n (or " + - i + - " to disable), but got '" + - t + - "'" - ); - this.autoDismissTimeoutMs_ = t; - }), - (h.prototype.getCloseOnEscape = function() { - return this.closeOnEscape_; - }), - (h.prototype.setCloseOnEscape = function(t) { - this.closeOnEscape_ = t; - }), - (h.prototype.handleKeyDown = function(t) { - ("Escape" !== t.key && 27 !== t.keyCode) || - !this.getCloseOnEscape() || - this.close(_); - }), - (h.prototype.handleActionButtonClick = function(t) { - this.close(p); - }), - (h.prototype.handleActionIconClick = function(t) { - this.close(_); - }), - (h.prototype.clearAutoDismissTimer_ = function() { - clearTimeout(this.autoDismissTimer_), - (this.autoDismissTimer_ = 0); - }), - (h.prototype.handleAnimationTimerEnd_ = function() { - (this.animationTimer_ = 0), - this.adapter_.removeClass(c.cssClasses.OPENING), - this.adapter_.removeClass(c.cssClasses.CLOSING); - }), - (h.prototype.runNextAnimationFrame_ = function(t) { - var e = this; - cancelAnimationFrame(this.animationFrame_), - (this.animationFrame_ = requestAnimationFrame(function() { - (e.animationFrame_ = 0), - clearTimeout(e.animationTimer_), - (e.animationTimer_ = setTimeout(t, 0)); - })); - }), - h); - function h(t) { - var e = s.call(this, o(o({}, h.defaultAdapter), t)) || this; - return ( - (e.isOpen_ = !1), - (e.animationFrame_ = 0), - (e.animationTimer_ = 0), - (e.autoDismissTimer_ = 0), - (e.autoDismissTimeoutMs_ = - c.numbers.DEFAULT_AUTO_DISMISS_TIMEOUT_MS), - (e.closeOnEscape_ = !0), - e - ); - } - (e.MDCSnackbarFoundation = f), (e.default = f); - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }), - o = - (this && this.__assign) || - function() { - return (o = - Object.assign || - function(t) { - for (var e, n = 1, i = arguments.length; n < i; n++) - for (var r in (e = arguments[n])) - Object.prototype.hasOwnProperty.call(e, r) && - (t[r] = e[r]); - return t; - }).apply(this, arguments); - }; - Object.defineProperty(e, "__esModule", { value: !0 }); - var s, - a = n(0), - c = n(83), - u = - ((s = a.MDCFoundation), - r(l, s), - Object.defineProperty(l, "strings", { - get: function() { - return c.strings; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(l, "cssClasses", { - get: function() { - return c.cssClasses; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(l, "defaultAdapter", { - get: function() { - return { - addClass: function() {}, - removeClass: function() {}, - setNativeControlChecked: function() {}, - setNativeControlDisabled: function() {}, - setNativeControlAttr: function() {} - }; - }, - enumerable: !0, - configurable: !0 - }), - (l.prototype.setChecked = function(t) { - this.adapter_.setNativeControlChecked(t), - this.updateAriaChecked_(t), - this.updateCheckedStyling_(t); - }), - (l.prototype.setDisabled = function(t) { - this.adapter_.setNativeControlDisabled(t), - t - ? this.adapter_.addClass(c.cssClasses.DISABLED) - : this.adapter_.removeClass(c.cssClasses.DISABLED); - }), - (l.prototype.handleChange = function(t) { - var e = t.target; - this.updateAriaChecked_(e.checked), - this.updateCheckedStyling_(e.checked); - }), - (l.prototype.updateCheckedStyling_ = function(t) { - t - ? this.adapter_.addClass(c.cssClasses.CHECKED) - : this.adapter_.removeClass(c.cssClasses.CHECKED); - }), - (l.prototype.updateAriaChecked_ = function(t) { - this.adapter_.setNativeControlAttr( - c.strings.ARIA_CHECKED_ATTR, - "" + !!t - ); - }), - l); - function l(t) { - return s.call(this, o(o({}, l.defaultAdapter), t)) || this; - } - (e.MDCSwitchFoundation = u), (e.default = u); - }, - function(t, e, n) { - "use strict"; - Object.defineProperty(e, "__esModule", { value: !0 }); - e.cssClasses = { - CHECKED: "mdc-switch--checked", - DISABLED: "mdc-switch--disabled" - }; - e.strings = { - ARIA_CHECKED_ATTR: "aria-checked", - NATIVE_CONTROL_SELECTOR: ".mdc-switch__native-control", - RIPPLE_SURFACE_SELECTOR: ".mdc-switch__thumb-underlay" - }; - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }), - o = - (this && this.__importStar) || - function(t) { - if (t && t.__esModule) return t; - var e = {}; - if (null != t) - for (var n in t) - Object.hasOwnProperty.call(t, n) && (e[n] = t[n]); - return (e.default = t), e; - }; - Object.defineProperty(e, "__esModule", { value: !0 }); - var s, - a = n(1), - c = n(5), - u = n(2), - l = n(85), - d = o(n(86)), - p = - ((s = a.MDCComponent), - r(_, s), - (_.attachTo = function(t) { - return new _(t); - }), - (_.prototype.initialize = function() { - (this.area_ = this.root_.querySelector( - l.MDCTabScrollerFoundation.strings.AREA_SELECTOR - )), - (this.content_ = this.root_.querySelector( - l.MDCTabScrollerFoundation.strings.CONTENT_SELECTOR - )); - }), - (_.prototype.initialSyncWithDOM = function() { - var e = this; - (this.handleInteraction_ = function() { - return e.foundation_.handleInteraction(); - }), - (this.handleTransitionEnd_ = function(t) { - return e.foundation_.handleTransitionEnd(t); - }), - this.area_.addEventListener( - "wheel", - this.handleInteraction_, - c.applyPassive() - ), - this.area_.addEventListener( - "touchstart", - this.handleInteraction_, - c.applyPassive() - ), - this.area_.addEventListener( - "pointerdown", - this.handleInteraction_, - c.applyPassive() - ), - this.area_.addEventListener( - "mousedown", - this.handleInteraction_, - c.applyPassive() - ), - this.area_.addEventListener( - "keydown", - this.handleInteraction_, - c.applyPassive() - ), - this.content_.addEventListener( - "transitionend", - this.handleTransitionEnd_ - ); - }), - (_.prototype.destroy = function() { - s.prototype.destroy.call(this), - this.area_.removeEventListener( - "wheel", - this.handleInteraction_, - c.applyPassive() - ), - this.area_.removeEventListener( - "touchstart", - this.handleInteraction_, - c.applyPassive() - ), - this.area_.removeEventListener( - "pointerdown", - this.handleInteraction_, - c.applyPassive() - ), - this.area_.removeEventListener( - "mousedown", - this.handleInteraction_, - c.applyPassive() - ), - this.area_.removeEventListener( - "keydown", - this.handleInteraction_, - c.applyPassive() - ), - this.content_.removeEventListener( - "transitionend", - this.handleTransitionEnd_ - ); - }), - (_.prototype.getDefaultFoundation = function() { - var n = this, - t = { - eventTargetMatchesSelector: function(t, e) { - return u.matches(t, e); - }, - addClass: function(t) { - return n.root_.classList.add(t); - }, - removeClass: function(t) { - return n.root_.classList.remove(t); - }, - addScrollAreaClass: function(t) { - return n.area_.classList.add(t); - }, - setScrollAreaStyleProperty: function(t, e) { - return n.area_.style.setProperty(t, e); - }, - setScrollContentStyleProperty: function(t, e) { - return n.content_.style.setProperty(t, e); - }, - getScrollContentStyleValue: function(t) { - return window - .getComputedStyle(n.content_) - .getPropertyValue(t); - }, - setScrollAreaScrollLeft: function(t) { - return (n.area_.scrollLeft = t); - }, - getScrollAreaScrollLeft: function() { - return n.area_.scrollLeft; - }, - getScrollContentOffsetWidth: function() { - return n.content_.offsetWidth; - }, - getScrollAreaOffsetWidth: function() { - return n.area_.offsetWidth; - }, - computeScrollAreaClientRect: function() { - return n.area_.getBoundingClientRect(); - }, - computeScrollContentClientRect: function() { - return n.content_.getBoundingClientRect(); - }, - computeHorizontalScrollbarHeight: function() { - return d.computeHorizontalScrollbarHeight(document); - } - }; - return new l.MDCTabScrollerFoundation(t); - }), - (_.prototype.getScrollPosition = function() { - return this.foundation_.getScrollPosition(); - }), - (_.prototype.getScrollContentWidth = function() { - return this.content_.offsetWidth; - }), - (_.prototype.incrementScroll = function(t) { - this.foundation_.incrementScroll(t); - }), - (_.prototype.scrollTo = function(t) { - this.foundation_.scrollTo(t); - }), - _); - function _() { - return (null !== s && s.apply(this, arguments)) || this; - } - e.MDCTabScroller = p; - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }), - o = - (this && this.__assign) || - function() { - return (o = - Object.assign || - function(t) { - for (var e, n = 1, i = arguments.length; n < i; n++) - for (var r in (e = arguments[n])) - Object.prototype.hasOwnProperty.call(e, r) && - (t[r] = e[r]); - return t; - }).apply(this, arguments); - }, - s = - (this && this.__read) || - function(t, e) { - var n = "function" == typeof Symbol && t[Symbol.iterator]; - if (!n) return t; - var i, - r, - o = n.call(t), - s = []; - try { - for (; (void 0 === e || 0 < e--) && !(i = o.next()).done; ) - s.push(i.value); - } catch (t) { - r = { error: t }; - } finally { - try { - i && !i.done && (n = o.return) && n.call(o); - } finally { - if (r) throw r.error; - } - } - return s; - }; - Object.defineProperty(e, "__esModule", { value: !0 }); - var a, - c = n(0), - u = n(31), - l = n(153), - d = n(154), - p = n(155), - _ = - ((a = c.MDCFoundation), - r(f, a), - Object.defineProperty(f, "cssClasses", { - get: function() { - return u.cssClasses; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(f, "strings", { - get: function() { - return u.strings; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(f, "defaultAdapter", { - get: function() { - return { - eventTargetMatchesSelector: function() { - return !1; - }, - addClass: function() {}, - removeClass: function() {}, - addScrollAreaClass: function() {}, - setScrollAreaStyleProperty: function() {}, - setScrollContentStyleProperty: function() {}, - getScrollContentStyleValue: function() { - return ""; - }, - setScrollAreaScrollLeft: function() {}, - getScrollAreaScrollLeft: function() { - return 0; - }, - getScrollContentOffsetWidth: function() { - return 0; - }, - getScrollAreaOffsetWidth: function() { - return 0; - }, - computeScrollAreaClientRect: function() { - return { - top: 0, - right: 0, - bottom: 0, - left: 0, - width: 0, - height: 0 - }; - }, - computeScrollContentClientRect: function() { - return { - top: 0, - right: 0, - bottom: 0, - left: 0, - width: 0, - height: 0 - }; - }, - computeHorizontalScrollbarHeight: function() { - return 0; - } - }; - }, - enumerable: !0, - configurable: !0 - }), - (f.prototype.init = function() { - var t = this.adapter_.computeHorizontalScrollbarHeight(); - this.adapter_.setScrollAreaStyleProperty( - "margin-bottom", - -t + "px" - ), - this.adapter_.addScrollAreaClass( - f.cssClasses.SCROLL_AREA_SCROLL - ); - }), - (f.prototype.getScrollPosition = function() { - if (this.isRTL_()) return this.computeCurrentScrollPositionRTL_(); - var t = this.calculateCurrentTranslateX_(); - return this.adapter_.getScrollAreaScrollLeft() - t; - }), - (f.prototype.handleInteraction = function() { - this.isAnimating_ && this.stopScrollAnimation_(); - }), - (f.prototype.handleTransitionEnd = function(t) { - var e = t.target; - this.isAnimating_ && - this.adapter_.eventTargetMatchesSelector( - e, - f.strings.CONTENT_SELECTOR - ) && - ((this.isAnimating_ = !1), - this.adapter_.removeClass(f.cssClasses.ANIMATING)); - }), - (f.prototype.incrementScroll = function(t) { - 0 !== t && this.animate_(this.getIncrementScrollOperation_(t)); - }), - (f.prototype.incrementScrollImmediate = function(t) { - if (0 !== t) { - var e = this.getIncrementScrollOperation_(t); - 0 !== e.scrollDelta && - (this.stopScrollAnimation_(), - this.adapter_.setScrollAreaScrollLeft(e.finalScrollPosition)); - } - }), - (f.prototype.scrollTo = function(t) { - if (this.isRTL_()) return this.scrollToRTL_(t); - this.scrollTo_(t); - }), - (f.prototype.getRTLScroller = function() { - return ( - this.rtlScrollerInstance_ || - (this.rtlScrollerInstance_ = this.rtlScrollerFactory_()), - this.rtlScrollerInstance_ - ); - }), - (f.prototype.calculateCurrentTranslateX_ = function() { - var t = this.adapter_.getScrollContentStyleValue("transform"); - if ("none" === t) return 0; - var e = /\((.+?)\)/.exec(t); - if (!e) return 0; - var n = e[1], - i = s(n.split(","), 6), - r = (i[0], i[1], i[2], i[3], i[4]); - return i[5], parseFloat(r); - }), - (f.prototype.clampScrollValue_ = function(t) { - var e = this.calculateScrollEdges_(); - return Math.min(Math.max(e.left, t), e.right); - }), - (f.prototype.computeCurrentScrollPositionRTL_ = function() { - var t = this.calculateCurrentTranslateX_(); - return this.getRTLScroller().getScrollPositionRTL(t); - }), - (f.prototype.calculateScrollEdges_ = function() { - return { - left: 0, - right: - this.adapter_.getScrollContentOffsetWidth() - - this.adapter_.getScrollAreaOffsetWidth() - }; - }), - (f.prototype.scrollTo_ = function(t) { - var e = this.getScrollPosition(), - n = this.clampScrollValue_(t), - i = n - e; - this.animate_({ finalScrollPosition: n, scrollDelta: i }); - }), - (f.prototype.scrollToRTL_ = function(t) { - var e = this.getRTLScroller().scrollToRTL(t); - this.animate_(e); - }), - (f.prototype.getIncrementScrollOperation_ = function(t) { - if (this.isRTL_()) - return this.getRTLScroller().incrementScrollRTL(t); - var e = this.getScrollPosition(), - n = t + e, - i = this.clampScrollValue_(n); - return { finalScrollPosition: i, scrollDelta: i - e }; - }), - (f.prototype.animate_ = function(t) { - var e = this; - 0 !== t.scrollDelta && - (this.stopScrollAnimation_(), - this.adapter_.setScrollAreaScrollLeft(t.finalScrollPosition), - this.adapter_.setScrollContentStyleProperty( - "transform", - "translateX(" + t.scrollDelta + "px)" - ), - this.adapter_.computeScrollAreaClientRect(), - requestAnimationFrame(function() { - e.adapter_.addClass(f.cssClasses.ANIMATING), - e.adapter_.setScrollContentStyleProperty( - "transform", - "none" - ); - }), - (this.isAnimating_ = !0)); - }), - (f.prototype.stopScrollAnimation_ = function() { - this.isAnimating_ = !1; - var t = this.getAnimatingScrollPosition_(); - this.adapter_.removeClass(f.cssClasses.ANIMATING), - this.adapter_.setScrollContentStyleProperty( - "transform", - "translateX(0px)" - ), - this.adapter_.setScrollAreaScrollLeft(t); - }), - (f.prototype.getAnimatingScrollPosition_ = function() { - var t = this.calculateCurrentTranslateX_(), - e = this.adapter_.getScrollAreaScrollLeft(); - return this.isRTL_() - ? this.getRTLScroller().getAnimatingScrollPosition(e, t) - : e - t; - }), - (f.prototype.rtlScrollerFactory_ = function() { - var t = this.adapter_.getScrollAreaScrollLeft(); - this.adapter_.setScrollAreaScrollLeft(t - 1); - var e = this.adapter_.getScrollAreaScrollLeft(); - if (e < 0) - return ( - this.adapter_.setScrollAreaScrollLeft(t), - new d.MDCTabScrollerRTLNegative(this.adapter_) - ); - var n = this.adapter_.computeScrollAreaClientRect(), - i = this.adapter_.computeScrollContentClientRect(), - r = Math.round(i.right - n.right); - return ( - this.adapter_.setScrollAreaScrollLeft(t), - r === e - ? new p.MDCTabScrollerRTLReverse(this.adapter_) - : new l.MDCTabScrollerRTLDefault(this.adapter_) - ); - }), - (f.prototype.isRTL_ = function() { - return ( - "rtl" === this.adapter_.getScrollContentStyleValue("direction") - ); - }), - f); - function f(t) { - var e = a.call(this, o(o({}, f.defaultAdapter), t)) || this; - return (e.isAnimating_ = !1), e; - } - (e.MDCTabScrollerFoundation = _), (e.default = _); - }, - function(t, e, n) { - "use strict"; - Object.defineProperty(e, "__esModule", { value: !0 }); - var r, - o = n(31); - e.computeHorizontalScrollbarHeight = function(t, e) { - if ((void 0 === e && (e = !0), e && void 0 !== r)) return r; - var n = t.createElement("div"); - n.classList.add(o.cssClasses.SCROLL_TEST), t.body.appendChild(n); - var i = n.offsetHeight - n.clientHeight; - return t.body.removeChild(n), e && (r = i), i; - }; - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }), - s = - (this && this.__assign) || - function() { - return (s = - Object.assign || - function(t) { - for (var e, n = 1, i = arguments.length; n < i; n++) - for (var r in (e = arguments[n])) - Object.prototype.hasOwnProperty.call(e, r) && - (t[r] = e[r]); - return t; - }).apply(this, arguments); - }; - Object.defineProperty(e, "__esModule", { value: !0 }); - var o, - a = n(1), - c = n(3), - u = n(4), - l = n(88), - d = n(33), - p = - ((o = a.MDCComponent), - r(_, o), - (_.attachTo = function(t) { - return new _(t); - }), - (_.prototype.initialize = function(t, e) { - void 0 === t && - (t = function(t, e) { - return new c.MDCRipple(t, e); - }), - void 0 === e && - (e = function(t) { - return new l.MDCTabIndicator(t); - }), - (this.id = this.root_.id); - var n = this.root_.querySelector( - d.MDCTabFoundation.strings.RIPPLE_SELECTOR - ), - i = s(s({}, c.MDCRipple.createAdapter(this)), { - addClass: function(t) { - return n.classList.add(t); - }, - removeClass: function(t) { - return n.classList.remove(t); - }, - updateCssVariable: function(t, e) { - return n.style.setProperty(t, e); - } - }), - r = new u.MDCRippleFoundation(i); - this.ripple_ = t(this.root_, r); - var o = this.root_.querySelector( - d.MDCTabFoundation.strings.TAB_INDICATOR_SELECTOR - ); - (this.tabIndicator_ = e(o)), - (this.content_ = this.root_.querySelector( - d.MDCTabFoundation.strings.CONTENT_SELECTOR - )); - }), - (_.prototype.initialSyncWithDOM = function() { - var t = this; - (this.handleClick_ = function() { - return t.foundation_.handleClick(); - }), - this.listen("click", this.handleClick_); - }), - (_.prototype.destroy = function() { - this.unlisten("click", this.handleClick_), - this.ripple_.destroy(), - o.prototype.destroy.call(this); - }), - (_.prototype.getDefaultFoundation = function() { - var n = this, - t = { - setAttr: function(t, e) { - return n.root_.setAttribute(t, e); - }, - addClass: function(t) { - return n.root_.classList.add(t); - }, - removeClass: function(t) { - return n.root_.classList.remove(t); - }, - hasClass: function(t) { - return n.root_.classList.contains(t); - }, - activateIndicator: function(t) { - return n.tabIndicator_.activate(t); - }, - deactivateIndicator: function() { - return n.tabIndicator_.deactivate(); - }, - notifyInteracted: function() { - return n.emit( - d.MDCTabFoundation.strings.INTERACTED_EVENT, - { tabId: n.id }, - !0 - ); - }, - getOffsetLeft: function() { - return n.root_.offsetLeft; - }, - getOffsetWidth: function() { - return n.root_.offsetWidth; - }, - getContentOffsetLeft: function() { - return n.content_.offsetLeft; - }, - getContentOffsetWidth: function() { - return n.content_.offsetWidth; - }, - focus: function() { - return n.root_.focus(); - } - }; - return new d.MDCTabFoundation(t); - }), - Object.defineProperty(_.prototype, "active", { - get: function() { - return this.foundation_.isActive(); - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(_.prototype, "focusOnActivate", { - set: function(t) { - this.foundation_.setFocusOnActivate(t); - }, - enumerable: !0, - configurable: !0 - }), - (_.prototype.activate = function(t) { - this.foundation_.activate(t); - }), - (_.prototype.deactivate = function() { - this.foundation_.deactivate(); - }), - (_.prototype.computeIndicatorClientRect = function() { - return this.tabIndicator_.computeContentClientRect(); - }), - (_.prototype.computeDimensions = function() { - return this.foundation_.computeDimensions(); - }), - (_.prototype.focus = function() { - this.root_.focus(); - }), - _); - function _() { - return (null !== o && o.apply(this, arguments)) || this; - } - e.MDCTab = p; - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }); - Object.defineProperty(e, "__esModule", { value: !0 }); - var o, - s = n(1), - a = n(89), - c = n(14), - u = n(91), - l = - ((o = s.MDCComponent), - r(d, o), - (d.attachTo = function(t) { - return new d(t); - }), - (d.prototype.initialize = function() { - this.content_ = this.root_.querySelector( - c.MDCTabIndicatorFoundation.strings.CONTENT_SELECTOR - ); - }), - (d.prototype.computeContentClientRect = function() { - return this.foundation_.computeContentClientRect(); - }), - (d.prototype.getDefaultFoundation = function() { - var n = this, - t = { - addClass: function(t) { - return n.root_.classList.add(t); - }, - removeClass: function(t) { - return n.root_.classList.remove(t); - }, - computeContentClientRect: function() { - return n.content_.getBoundingClientRect(); - }, - setContentStyleProperty: function(t, e) { - return n.content_.style.setProperty(t, e); - } - }; - return this.root_.classList.contains( - c.MDCTabIndicatorFoundation.cssClasses.FADE - ) - ? new a.MDCFadingTabIndicatorFoundation(t) - : new u.MDCSlidingTabIndicatorFoundation(t); - }), - (d.prototype.activate = function(t) { - this.foundation_.activate(t); - }), - (d.prototype.deactivate = function() { - this.foundation_.deactivate(); - }), - d); - function d() { - return (null !== o && o.apply(this, arguments)) || this; - } - e.MDCTabIndicator = l; - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }); - Object.defineProperty(e, "__esModule", { value: !0 }); - var o, - s = n(14), - a = - ((o = s.MDCTabIndicatorFoundation), - r(c, o), - (c.prototype.activate = function() { - this.adapter_.addClass( - s.MDCTabIndicatorFoundation.cssClasses.ACTIVE - ); - }), - (c.prototype.deactivate = function() { - this.adapter_.removeClass( - s.MDCTabIndicatorFoundation.cssClasses.ACTIVE - ); - }), - c); - function c() { - return (null !== o && o.apply(this, arguments)) || this; - } - (e.MDCFadingTabIndicatorFoundation = a), (e.default = a); - }, - function(t, e, n) { - "use strict"; - Object.defineProperty(e, "__esModule", { value: !0 }); - e.cssClasses = { - ACTIVE: "mdc-tab-indicator--active", - FADE: "mdc-tab-indicator--fade", - NO_TRANSITION: "mdc-tab-indicator--no-transition" - }; - e.strings = { CONTENT_SELECTOR: ".mdc-tab-indicator__content" }; - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }); - Object.defineProperty(e, "__esModule", { value: !0 }); - var o, - s = n(14), - a = - ((o = s.MDCTabIndicatorFoundation), - r(c, o), - (c.prototype.activate = function(t) { - if (t) { - var e = this.computeContentClientRect(), - n = t.width / e.width, - i = t.left - e.left; - this.adapter_.addClass( - s.MDCTabIndicatorFoundation.cssClasses.NO_TRANSITION - ), - this.adapter_.setContentStyleProperty( - "transform", - "translateX(" + i + "px) scaleX(" + n + ")" - ), - this.computeContentClientRect(), - this.adapter_.removeClass( - s.MDCTabIndicatorFoundation.cssClasses.NO_TRANSITION - ), - this.adapter_.addClass( - s.MDCTabIndicatorFoundation.cssClasses.ACTIVE - ), - this.adapter_.setContentStyleProperty("transform", ""); - } else - this.adapter_.addClass( - s.MDCTabIndicatorFoundation.cssClasses.ACTIVE - ); - }), - (c.prototype.deactivate = function() { - this.adapter_.removeClass( - s.MDCTabIndicatorFoundation.cssClasses.ACTIVE - ); - }), - c); - function c() { - return (null !== o && o.apply(this, arguments)) || this; - } - (e.MDCSlidingTabIndicatorFoundation = a), (e.default = a); - }, - function(t, e, n) { - "use strict"; - Object.defineProperty(e, "__esModule", { value: !0 }); - e.cssClasses = { ACTIVE: "mdc-tab--active" }; - e.strings = { - ARIA_SELECTED: "aria-selected", - CONTENT_SELECTOR: ".mdc-tab__content", - INTERACTED_EVENT: "MDCTab:interacted", - RIPPLE_SELECTOR: ".mdc-tab__ripple", - TABINDEX: "tabIndex", - TAB_INDICATOR_SELECTOR: ".mdc-tab-indicator" - }; - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }), - o = - (this && this.__assign) || - function() { - return (o = - Object.assign || - function(t) { - for (var e, n = 1, i = arguments.length; n < i; n++) - for (var r in (e = arguments[n])) - Object.prototype.hasOwnProperty.call(e, r) && - (t[r] = e[r]); - return t; - }).apply(this, arguments); - }; - Object.defineProperty(e, "__esModule", { value: !0 }); - var s = n(0), - u = n(94), - a = new Set(); - a.add(u.strings.ARROW_LEFT_KEY), - a.add(u.strings.ARROW_RIGHT_KEY), - a.add(u.strings.END_KEY), - a.add(u.strings.HOME_KEY), - a.add(u.strings.ENTER_KEY), - a.add(u.strings.SPACE_KEY); - var c = new Map(); - c.set(u.numbers.ARROW_LEFT_KEYCODE, u.strings.ARROW_LEFT_KEY), - c.set(u.numbers.ARROW_RIGHT_KEYCODE, u.strings.ARROW_RIGHT_KEY), - c.set(u.numbers.END_KEYCODE, u.strings.END_KEY), - c.set(u.numbers.HOME_KEYCODE, u.strings.HOME_KEY), - c.set(u.numbers.ENTER_KEYCODE, u.strings.ENTER_KEY), - c.set(u.numbers.SPACE_KEYCODE, u.strings.SPACE_KEY); - var l, - d = - ((l = s.MDCFoundation), - r(p, l), - Object.defineProperty(p, "strings", { - get: function() { - return u.strings; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(p, "numbers", { - get: function() { - return u.numbers; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(p, "defaultAdapter", { - get: function() { - return { - scrollTo: function() {}, - incrementScroll: function() {}, - getScrollPosition: function() { - return 0; - }, - getScrollContentWidth: function() { - return 0; - }, - getOffsetWidth: function() { - return 0; - }, - isRTL: function() { - return !1; - }, - setActiveTab: function() {}, - activateTabAtIndex: function() {}, - deactivateTabAtIndex: function() {}, - focusTabAtIndex: function() {}, - getTabIndicatorClientRectAtIndex: function() { - return { - top: 0, - right: 0, - bottom: 0, - left: 0, - width: 0, - height: 0 - }; - }, - getTabDimensionsAtIndex: function() { - return { - rootLeft: 0, - rootRight: 0, - contentLeft: 0, - contentRight: 0 - }; - }, - getPreviousActiveTabIndex: function() { - return -1; - }, - getFocusedTabIndex: function() { - return -1; - }, - getIndexOfTabById: function() { - return -1; - }, - getTabListLength: function() { - return 0; - }, - notifyTabActivated: function() {} - }; - }, - enumerable: !0, - configurable: !0 - }), - (p.prototype.setUseAutomaticActivation = function(t) { - this.useAutomaticActivation_ = t; - }), - (p.prototype.activateTab = function(t) { - var e, - n = this.adapter_.getPreviousActiveTabIndex(); - this.indexIsInRange_(t) && - t !== n && - (-1 !== n && - (this.adapter_.deactivateTabAtIndex(n), - (e = this.adapter_.getTabIndicatorClientRectAtIndex(n))), - this.adapter_.activateTabAtIndex(t, e), - this.scrollIntoView(t), - this.adapter_.notifyTabActivated(t)); - }), - (p.prototype.handleKeyDown = function(t) { - var e = this.getKeyFromEvent_(t); - if (void 0 !== e) - if ( - (this.isActivationKey_(e) || t.preventDefault(), - this.useAutomaticActivation_) - ) { - if (this.isActivationKey_(e)) return; - var n = this.determineTargetFromKey_( - this.adapter_.getPreviousActiveTabIndex(), - e - ); - this.adapter_.setActiveTab(n), this.scrollIntoView(n); - } else { - var i = this.adapter_.getFocusedTabIndex(); - this.isActivationKey_(e) - ? this.adapter_.setActiveTab(i) - : ((n = this.determineTargetFromKey_(i, e)), - this.adapter_.focusTabAtIndex(n), - this.scrollIntoView(n)); - } - }), - (p.prototype.handleTabInteraction = function(t) { - this.adapter_.setActiveTab( - this.adapter_.getIndexOfTabById(t.detail.tabId) - ); - }), - (p.prototype.scrollIntoView = function(t) { - if (this.indexIsInRange_(t)) - return 0 === t - ? this.adapter_.scrollTo(0) - : t === this.adapter_.getTabListLength() - 1 - ? this.adapter_.scrollTo( - this.adapter_.getScrollContentWidth() - ) - : this.isRTL_() - ? this.scrollIntoViewRTL_(t) - : void this.scrollIntoView_(t); - }), - (p.prototype.determineTargetFromKey_ = function(t, e) { - var n = this.isRTL_(), - i = this.adapter_.getTabListLength() - 1, - r = e === u.strings.END_KEY, - o = - (e === u.strings.ARROW_LEFT_KEY && !n) || - (e === u.strings.ARROW_RIGHT_KEY && n), - s = - (e === u.strings.ARROW_RIGHT_KEY && !n) || - (e === u.strings.ARROW_LEFT_KEY && n), - a = t; - return ( - r ? (a = i) : o ? (a -= 1) : s ? (a += 1) : (a = 0), - a < 0 ? (a = i) : i < a && (a = 0), - a - ); - }), - (p.prototype.calculateScrollIncrement_ = function(t, e, n, i) { - var r = this.adapter_.getTabDimensionsAtIndex(e), - o = r.contentLeft - n - i, - s = r.contentRight - n - u.numbers.EXTRA_SCROLL_AMOUNT, - a = o + u.numbers.EXTRA_SCROLL_AMOUNT; - return e < t ? Math.min(s, 0) : Math.max(a, 0); - }), - (p.prototype.calculateScrollIncrementRTL_ = function( - t, - e, - n, - i, - r - ) { - var o = this.adapter_.getTabDimensionsAtIndex(e), - s = r - o.contentLeft - n, - a = r - o.contentRight - n - i + u.numbers.EXTRA_SCROLL_AMOUNT, - c = s - u.numbers.EXTRA_SCROLL_AMOUNT; - return t < e ? Math.max(a, 0) : Math.min(c, 0); - }), - (p.prototype.findAdjacentTabIndexClosestToEdge_ = function( - t, - e, - n, - i - ) { - var r = e.rootLeft - n, - o = e.rootRight - n - i, - s = r + o; - return r < 0 || s < 0 ? t - 1 : 0 < o || 0 < s ? t + 1 : -1; - }), - (p.prototype.findAdjacentTabIndexClosestToEdgeRTL_ = function( - t, - e, - n, - i, - r - ) { - var o = r - e.rootLeft - i - n, - s = r - e.rootRight - n, - a = o + s; - return 0 < o || 0 < a ? t + 1 : s < 0 || a < 0 ? t - 1 : -1; - }), - (p.prototype.getKeyFromEvent_ = function(t) { - return a.has(t.key) ? t.key : c.get(t.keyCode); - }), - (p.prototype.isActivationKey_ = function(t) { - return t === u.strings.SPACE_KEY || t === u.strings.ENTER_KEY; - }), - (p.prototype.indexIsInRange_ = function(t) { - return 0 <= t && t < this.adapter_.getTabListLength(); - }), - (p.prototype.isRTL_ = function() { - return this.adapter_.isRTL(); - }), - (p.prototype.scrollIntoView_ = function(t) { - var e = this.adapter_.getScrollPosition(), - n = this.adapter_.getOffsetWidth(), - i = this.adapter_.getTabDimensionsAtIndex(t), - r = this.findAdjacentTabIndexClosestToEdge_(t, i, e, n); - if (this.indexIsInRange_(r)) { - var o = this.calculateScrollIncrement_(t, r, e, n); - this.adapter_.incrementScroll(o); - } - }), - (p.prototype.scrollIntoViewRTL_ = function(t) { - var e = this.adapter_.getScrollPosition(), - n = this.adapter_.getOffsetWidth(), - i = this.adapter_.getTabDimensionsAtIndex(t), - r = this.adapter_.getScrollContentWidth(), - o = this.findAdjacentTabIndexClosestToEdgeRTL_(t, i, e, n, r); - if (this.indexIsInRange_(o)) { - var s = this.calculateScrollIncrementRTL_(t, o, e, n, r); - this.adapter_.incrementScroll(s); - } - }), - p); - function p(t) { - var e = l.call(this, o(o({}, p.defaultAdapter), t)) || this; - return (e.useAutomaticActivation_ = !1), e; - } - (e.MDCTabBarFoundation = d), (e.default = d); - }, - function(t, e, n) { - "use strict"; - Object.defineProperty(e, "__esModule", { value: !0 }); - e.strings = { - ARROW_LEFT_KEY: "ArrowLeft", - ARROW_RIGHT_KEY: "ArrowRight", - END_KEY: "End", - ENTER_KEY: "Enter", - HOME_KEY: "Home", - SPACE_KEY: "Space", - TAB_ACTIVATED_EVENT: "MDCTabBar:activated", - TAB_SCROLLER_SELECTOR: ".mdc-tab-scroller", - TAB_SELECTOR: ".mdc-tab" - }; - e.numbers = { - ARROW_LEFT_KEYCODE: 37, - ARROW_RIGHT_KEYCODE: 39, - END_KEYCODE: 35, - ENTER_KEYCODE: 13, - EXTRA_SCROLL_AMOUNT: 20, - HOME_KEYCODE: 36, - SPACE_KEYCODE: 32 - }; - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }); - Object.defineProperty(e, "__esModule", { value: !0 }); - var o, - s = n(1), - a = n(34), - c = - ((o = s.MDCComponent), - r(u, o), - (u.attachTo = function(t) { - return new u(t); - }), - Object.defineProperty(u.prototype, "foundation", { - get: function() { - return this.foundation_; - }, - enumerable: !0, - configurable: !0 - }), - (u.prototype.getDefaultFoundation = function() { - var e = this, - t = { - setContent: function(t) { - e.root_.textContent = t; - } - }; - return new a.MDCTextFieldCharacterCounterFoundation(t); - }), - u); - function u() { - return (null !== o && o.apply(this, arguments)) || this; - } - e.MDCTextFieldCharacterCounter = c; - }, - function(t, e, n) { - "use strict"; - Object.defineProperty(e, "__esModule", { value: !0 }); - var i = { ROOT: "mdc-text-field-character-counter" }, - r = { ROOT_SELECTOR: "." + (e.cssClasses = i).ROOT }; - e.strings = r; - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }), - o = - (this && this.__assign) || - function() { - return (o = - Object.assign || - function(t) { - for (var e, n = 1, i = arguments.length; n < i; n++) - for (var r in (e = arguments[n])) - Object.prototype.hasOwnProperty.call(e, r) && - (t[r] = e[r]); - return t; - }).apply(this, arguments); - }; - Object.defineProperty(e, "__esModule", { value: !0 }); - var s, - a = n(0), - c = n(35), - u = ["mousedown", "touchstart"], - l = ["click", "keydown"], - d = - ((s = a.MDCFoundation), - r(p, s), - Object.defineProperty(p, "cssClasses", { - get: function() { - return c.cssClasses; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(p, "strings", { - get: function() { - return c.strings; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(p, "numbers", { - get: function() { - return c.numbers; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(p.prototype, "shouldAlwaysFloat_", { - get: function() { - var t = this.getNativeInput_().type; - return 0 <= c.ALWAYS_FLOAT_TYPES.indexOf(t); - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(p.prototype, "shouldFloat", { - get: function() { - return ( - this.shouldAlwaysFloat_ || - this.isFocused_ || - !!this.getValue() || - this.isBadInput_() - ); - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(p.prototype, "shouldShake", { - get: function() { - return !this.isFocused_ && !this.isValid() && !!this.getValue(); - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(p, "defaultAdapter", { - get: function() { - return { - addClass: function() {}, - removeClass: function() {}, - hasClass: function() { - return !0; - }, - registerTextFieldInteractionHandler: function() {}, - deregisterTextFieldInteractionHandler: function() {}, - registerInputInteractionHandler: function() {}, - deregisterInputInteractionHandler: function() {}, - registerValidationAttributeChangeHandler: function() { - return new MutationObserver(function() {}); - }, - deregisterValidationAttributeChangeHandler: function() {}, - getNativeInput: function() { - return null; - }, - isFocused: function() { - return !1; - }, - activateLineRipple: function() {}, - deactivateLineRipple: function() {}, - setLineRippleTransformOrigin: function() {}, - shakeLabel: function() {}, - floatLabel: function() {}, - hasLabel: function() { - return !1; - }, - getLabelWidth: function() { - return 0; - }, - hasOutline: function() { - return !1; - }, - notchOutline: function() {}, - closeOutline: function() {} - }; - }, - enumerable: !0, - configurable: !0 - }), - (p.prototype.init = function() { - var e = this; - this.adapter_.isFocused() - ? this.inputFocusHandler_() - : this.adapter_.hasLabel() && - this.shouldFloat && - (this.notchOutline(!0), - this.adapter_.floatLabel(!0), - this.styleFloating_(!0)), - this.adapter_.registerInputInteractionHandler( - "focus", - this.inputFocusHandler_ - ), - this.adapter_.registerInputInteractionHandler( - "blur", - this.inputBlurHandler_ - ), - this.adapter_.registerInputInteractionHandler( - "input", - this.inputInputHandler_ - ), - u.forEach(function(t) { - e.adapter_.registerInputInteractionHandler( - t, - e.setPointerXOffset_ - ); - }), - l.forEach(function(t) { - e.adapter_.registerTextFieldInteractionHandler( - t, - e.textFieldInteractionHandler_ - ); - }), - (this.validationObserver_ = this.adapter_.registerValidationAttributeChangeHandler( - this.validationAttributeChangeHandler_ - )), - this.setCharacterCounter_(this.getValue().length); - }), - (p.prototype.destroy = function() { - var e = this; - this.adapter_.deregisterInputInteractionHandler( - "focus", - this.inputFocusHandler_ - ), - this.adapter_.deregisterInputInteractionHandler( - "blur", - this.inputBlurHandler_ - ), - this.adapter_.deregisterInputInteractionHandler( - "input", - this.inputInputHandler_ - ), - u.forEach(function(t) { - e.adapter_.deregisterInputInteractionHandler( - t, - e.setPointerXOffset_ - ); - }), - l.forEach(function(t) { - e.adapter_.deregisterTextFieldInteractionHandler( - t, - e.textFieldInteractionHandler_ - ); - }), - this.adapter_.deregisterValidationAttributeChangeHandler( - this.validationObserver_ - ); - }), - (p.prototype.handleTextFieldInteraction = function() { - var t = this.adapter_.getNativeInput(); - (t && t.disabled) || (this.receivedUserInput_ = !0); - }), - (p.prototype.handleValidationAttributeChange = function(t) { - var e = this; - t.some(function(t) { - return ( - -1 < c.VALIDATION_ATTR_WHITELIST.indexOf(t) && - (e.styleValidity_(!0), !0) - ); - }), - -1 < t.indexOf("maxlength") && - this.setCharacterCounter_(this.getValue().length); - }), - (p.prototype.notchOutline = function(t) { - if (this.adapter_.hasOutline()) - if (t) { - var e = this.adapter_.getLabelWidth() * c.numbers.LABEL_SCALE; - this.adapter_.notchOutline(e); - } else this.adapter_.closeOutline(); - }), - (p.prototype.activateFocus = function() { - (this.isFocused_ = !0), - this.styleFocused_(this.isFocused_), - this.adapter_.activateLineRipple(), - this.adapter_.hasLabel() && - (this.notchOutline(this.shouldFloat), - this.adapter_.floatLabel(this.shouldFloat), - this.styleFloating_(this.shouldFloat), - this.adapter_.shakeLabel(this.shouldShake)), - this.helperText_ && this.helperText_.showToScreenReader(); - }), - (p.prototype.setTransformOrigin = function(t) { - var e = t.touches, - n = e ? e[0] : t, - i = n.target.getBoundingClientRect(), - r = n.clientX - i.left; - this.adapter_.setLineRippleTransformOrigin(r); - }), - (p.prototype.handleInput = function() { - this.autoCompleteFocus(), - this.setCharacterCounter_(this.getValue().length); - }), - (p.prototype.autoCompleteFocus = function() { - this.receivedUserInput_ || this.activateFocus(); - }), - (p.prototype.deactivateFocus = function() { - (this.isFocused_ = !1), this.adapter_.deactivateLineRipple(); - var t = this.isValid(); - this.styleValidity_(t), - this.styleFocused_(this.isFocused_), - this.adapter_.hasLabel() && - (this.notchOutline(this.shouldFloat), - this.adapter_.floatLabel(this.shouldFloat), - this.styleFloating_(this.shouldFloat), - this.adapter_.shakeLabel(this.shouldShake)), - this.shouldFloat || (this.receivedUserInput_ = !1); - }), - (p.prototype.getValue = function() { - return this.getNativeInput_().value; - }), - (p.prototype.setValue = function(t) { - this.getValue() !== t && (this.getNativeInput_().value = t), - this.setCharacterCounter_(t.length); - var e = this.isValid(); - this.styleValidity_(e), - this.adapter_.hasLabel() && - (this.notchOutline(this.shouldFloat), - this.adapter_.floatLabel(this.shouldFloat), - this.styleFloating_(this.shouldFloat), - this.adapter_.shakeLabel(this.shouldShake)); - }), - (p.prototype.isValid = function() { - return this.useNativeValidation_ - ? this.isNativeInputValid_() - : this.isValid_; - }), - (p.prototype.setValid = function(t) { - (this.isValid_ = t), this.styleValidity_(t); - var e = !t && !this.isFocused_ && !!this.getValue(); - this.adapter_.hasLabel() && this.adapter_.shakeLabel(e); - }), - (p.prototype.setUseNativeValidation = function(t) { - this.useNativeValidation_ = t; - }), - (p.prototype.isDisabled = function() { - return this.getNativeInput_().disabled; - }), - (p.prototype.setDisabled = function(t) { - (this.getNativeInput_().disabled = t), this.styleDisabled_(t); - }), - (p.prototype.setHelperTextContent = function(t) { - this.helperText_ && this.helperText_.setContent(t); - }), - (p.prototype.setLeadingIconAriaLabel = function(t) { - this.leadingIcon_ && this.leadingIcon_.setAriaLabel(t); - }), - (p.prototype.setLeadingIconContent = function(t) { - this.leadingIcon_ && this.leadingIcon_.setContent(t); - }), - (p.prototype.setTrailingIconAriaLabel = function(t) { - this.trailingIcon_ && this.trailingIcon_.setAriaLabel(t); - }), - (p.prototype.setTrailingIconContent = function(t) { - this.trailingIcon_ && this.trailingIcon_.setContent(t); - }), - (p.prototype.setCharacterCounter_ = function(t) { - if (this.characterCounter_) { - var e = this.getNativeInput_().maxLength; - if (-1 === e) - throw new Error( - "MDCTextFieldFoundation: Expected maxlength html property on text input or textarea." - ); - this.characterCounter_.setCounterValue(t, e); - } - }), - (p.prototype.isBadInput_ = function() { - return this.getNativeInput_().validity.badInput || !1; - }), - (p.prototype.isNativeInputValid_ = function() { - return this.getNativeInput_().validity.valid; - }), - (p.prototype.styleValidity_ = function(t) { - var e = p.cssClasses.INVALID; - t ? this.adapter_.removeClass(e) : this.adapter_.addClass(e), - this.helperText_ && this.helperText_.setValidity(t); - }), - (p.prototype.styleFocused_ = function(t) { - var e = p.cssClasses.FOCUSED; - t ? this.adapter_.addClass(e) : this.adapter_.removeClass(e); - }), - (p.prototype.styleDisabled_ = function(t) { - var e = p.cssClasses, - n = e.DISABLED, - i = e.INVALID; - t - ? (this.adapter_.addClass(n), this.adapter_.removeClass(i)) - : this.adapter_.removeClass(n), - this.leadingIcon_ && this.leadingIcon_.setDisabled(t), - this.trailingIcon_ && this.trailingIcon_.setDisabled(t); - }), - (p.prototype.styleFloating_ = function(t) { - var e = p.cssClasses.LABEL_FLOATING; - t ? this.adapter_.addClass(e) : this.adapter_.removeClass(e); - }), - (p.prototype.getNativeInput_ = function() { - return ( - (this.adapter_ ? this.adapter_.getNativeInput() : null) || { - disabled: !1, - maxLength: -1, - type: "input", - validity: { badInput: !1, valid: !0 }, - value: "" - } - ); - }), - p); - function p(t, e) { - void 0 === e && (e = {}); - var n = s.call(this, o(o({}, p.defaultAdapter), t)) || this; - return ( - (n.isFocused_ = !1), - (n.receivedUserInput_ = !1), - (n.isValid_ = !0), - (n.useNativeValidation_ = !0), - (n.helperText_ = e.helperText), - (n.characterCounter_ = e.characterCounter), - (n.leadingIcon_ = e.leadingIcon), - (n.trailingIcon_ = e.trailingIcon), - (n.inputFocusHandler_ = function() { - return n.activateFocus(); - }), - (n.inputBlurHandler_ = function() { - return n.deactivateFocus(); - }), - (n.inputInputHandler_ = function() { - return n.handleInput(); - }), - (n.setPointerXOffset_ = function(t) { - return n.setTransformOrigin(t); - }), - (n.textFieldInteractionHandler_ = function() { - return n.handleTextFieldInteraction(); - }), - (n.validationAttributeChangeHandler_ = function(t) { - return n.handleValidationAttributeChange(t); - }), - n - ); - } - (e.MDCTextFieldFoundation = d), (e.default = d); - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }); - Object.defineProperty(e, "__esModule", { value: !0 }); - var o, - s = n(1), - a = n(36), - c = - ((o = s.MDCComponent), - r(u, o), - (u.attachTo = function(t) { - return new u(t); - }), - Object.defineProperty(u.prototype, "foundation", { - get: function() { - return this.foundation_; - }, - enumerable: !0, - configurable: !0 - }), - (u.prototype.getDefaultFoundation = function() { - var n = this, - t = { - addClass: function(t) { - return n.root_.classList.add(t); - }, - removeClass: function(t) { - return n.root_.classList.remove(t); - }, - hasClass: function(t) { - return n.root_.classList.contains(t); - }, - setAttr: function(t, e) { - return n.root_.setAttribute(t, e); - }, - removeAttr: function(t) { - return n.root_.removeAttribute(t); - }, - setContent: function(t) { - n.root_.textContent = t; - } - }; - return new a.MDCTextFieldHelperTextFoundation(t); - }), - u); - function u() { - return (null !== o && o.apply(this, arguments)) || this; - } - e.MDCTextFieldHelperText = c; - }, - function(t, e, n) { - "use strict"; - Object.defineProperty(e, "__esModule", { value: !0 }); - var i = { - HELPER_TEXT_PERSISTENT: "mdc-text-field-helper-text--persistent", - HELPER_TEXT_VALIDATION_MSG: - "mdc-text-field-helper-text--validation-msg", - ROOT: "mdc-text-field-helper-text" - }, - r = { - ARIA_HIDDEN: "aria-hidden", - ROLE: "role", - ROOT_SELECTOR: "." + (e.cssClasses = i).ROOT - }; - e.strings = r; - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }); - Object.defineProperty(e, "__esModule", { value: !0 }); - var o, - s = n(1), - a = n(101), - c = - ((o = s.MDCComponent), - r(u, o), - (u.attachTo = function(t) { - return new u(t); - }), - Object.defineProperty(u.prototype, "foundation", { - get: function() { - return this.foundation_; - }, - enumerable: !0, - configurable: !0 - }), - (u.prototype.getDefaultFoundation = function() { - var n = this, - t = { - getAttr: function(t) { - return n.root_.getAttribute(t); - }, - setAttr: function(t, e) { - return n.root_.setAttribute(t, e); - }, - removeAttr: function(t) { - return n.root_.removeAttribute(t); - }, - setContent: function(t) { - n.root_.textContent = t; - }, - registerInteractionHandler: function(t, e) { - return n.listen(t, e); - }, - deregisterInteractionHandler: function(t, e) { - return n.unlisten(t, e); - }, - notifyIconAction: function() { - return n.emit( - a.MDCTextFieldIconFoundation.strings.ICON_EVENT, - {}, - !0 - ); - } - }; - return new a.MDCTextFieldIconFoundation(t); - }), - u); - function u() { - return (null !== o && o.apply(this, arguments)) || this; - } - e.MDCTextFieldIcon = c; - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }), - o = - (this && this.__assign) || - function() { - return (o = - Object.assign || - function(t) { - for (var e, n = 1, i = arguments.length; n < i; n++) - for (var r in (e = arguments[n])) - Object.prototype.hasOwnProperty.call(e, r) && - (t[r] = e[r]); - return t; - }).apply(this, arguments); - }; - Object.defineProperty(e, "__esModule", { value: !0 }); - var s, - a = n(0), - c = n(102), - u = ["click", "keydown"], - l = - ((s = a.MDCFoundation), - r(d, s), - Object.defineProperty(d, "strings", { - get: function() { - return c.strings; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(d, "cssClasses", { - get: function() { - return c.cssClasses; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(d, "defaultAdapter", { - get: function() { - return { - getAttr: function() { - return null; - }, - setAttr: function() {}, - removeAttr: function() {}, - setContent: function() {}, - registerInteractionHandler: function() {}, - deregisterInteractionHandler: function() {}, - notifyIconAction: function() {} - }; - }, - enumerable: !0, - configurable: !0 - }), - (d.prototype.init = function() { - var e = this; - (this.savedTabIndex_ = this.adapter_.getAttr("tabindex")), - u.forEach(function(t) { - e.adapter_.registerInteractionHandler( - t, - e.interactionHandler_ - ); - }); - }), - (d.prototype.destroy = function() { - var e = this; - u.forEach(function(t) { - e.adapter_.deregisterInteractionHandler( - t, - e.interactionHandler_ - ); - }); - }), - (d.prototype.setDisabled = function(t) { - this.savedTabIndex_ && - (t - ? (this.adapter_.setAttr("tabindex", "-1"), - this.adapter_.removeAttr("role")) - : (this.adapter_.setAttr("tabindex", this.savedTabIndex_), - this.adapter_.setAttr("role", c.strings.ICON_ROLE))); - }), - (d.prototype.setAriaLabel = function(t) { - this.adapter_.setAttr("aria-label", t); - }), - (d.prototype.setContent = function(t) { - this.adapter_.setContent(t); - }), - (d.prototype.handleInteraction = function(t) { - var e = "Enter" === t.key || 13 === t.keyCode; - ("click" !== t.type && !e) || - (t.preventDefault(), this.adapter_.notifyIconAction()); - }), - d); - function d(t) { - var e = s.call(this, o(o({}, d.defaultAdapter), t)) || this; - return ( - (e.savedTabIndex_ = null), - (e.interactionHandler_ = function(t) { - return e.handleInteraction(t); - }), - e - ); - } - (e.MDCTextFieldIconFoundation = l), (e.default = l); - }, - function(t, e, n) { - "use strict"; - Object.defineProperty(e, "__esModule", { value: !0 }); - e.strings = { ICON_EVENT: "MDCTextField:icon", ICON_ROLE: "button" }; - e.cssClasses = { ROOT: "mdc-text-field__icon" }; - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }); - Object.defineProperty(e, "__esModule", { value: !0 }); - var o, - s = n(7), - a = n(37), - c = - ((o = a.MDCTopAppBarFoundation), - r(u, o), - (u.prototype.handleTargetScroll = function() { - this.adapter_.getViewportScrollY() <= 0 - ? this.wasScrolled_ && - (this.adapter_.removeClass(s.cssClasses.FIXED_SCROLLED_CLASS), - (this.wasScrolled_ = !1)) - : this.wasScrolled_ || - (this.adapter_.addClass(s.cssClasses.FIXED_SCROLLED_CLASS), - (this.wasScrolled_ = !0)); - }), - u); - function u() { - var t = (null !== o && o.apply(this, arguments)) || this; - return (t.wasScrolled_ = !1), t; - } - (e.MDCFixedTopAppBarFoundation = c), (e.default = c); - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }); - Object.defineProperty(e, "__esModule", { value: !0 }); - var o, - s = n(7), - a = n(38), - c = - ((o = a.MDCTopAppBarBaseFoundation), - r(u, o), - Object.defineProperty(u.prototype, "isCollapsed", { - get: function() { - return this.isCollapsed_; - }, - enumerable: !0, - configurable: !0 - }), - (u.prototype.init = function() { - o.prototype.init.call(this), - 0 < this.adapter_.getTotalActionItems() && - this.adapter_.addClass( - s.cssClasses.SHORT_HAS_ACTION_ITEM_CLASS - ), - this.setAlwaysCollapsed( - this.adapter_.hasClass(s.cssClasses.SHORT_COLLAPSED_CLASS) - ); - }), - (u.prototype.setAlwaysCollapsed = function(t) { - (this.isAlwaysCollapsed_ = !!t), - this.isAlwaysCollapsed_ - ? this.collapse_() - : this.maybeCollapseBar_(); - }), - (u.prototype.getAlwaysCollapsed = function() { - return this.isAlwaysCollapsed_; - }), - (u.prototype.handleTargetScroll = function() { - this.maybeCollapseBar_(); - }), - (u.prototype.maybeCollapseBar_ = function() { - this.isAlwaysCollapsed_ || - (this.adapter_.getViewportScrollY() <= 0 - ? this.isCollapsed_ && this.uncollapse_() - : this.isCollapsed_ || this.collapse_()); - }), - (u.prototype.uncollapse_ = function() { - this.adapter_.removeClass(s.cssClasses.SHORT_COLLAPSED_CLASS), - (this.isCollapsed_ = !1); - }), - (u.prototype.collapse_ = function() { - this.adapter_.addClass(s.cssClasses.SHORT_COLLAPSED_CLASS), - (this.isCollapsed_ = !0); - }), - u); - function u(t) { - var e = o.call(this, t) || this; - return (e.isCollapsed_ = !1), (e.isAlwaysCollapsed_ = !1), e; - } - (e.MDCShortTopAppBarFoundation = c), (e.default = c); - }, - function(t, e, n) { - "use strict"; - var i = - (this && this.__importDefault) || - function(t) { - return t && t.__esModule ? t : { default: t }; - }, - r = - (this && this.__importStar) || - function(t) { - if (t && t.__esModule) return t; - var e = {}; - if (null != t) - for (var n in t) - Object.hasOwnProperty.call(t, n) && (e[n] = t[n]); - return (e.default = t), e; - }; - Object.defineProperty(e, "__esModule", { value: !0 }); - var o = i(n(106)); - e.autoInit = o.default; - var s = r(n(108)); - e.base = s; - var a = r(n(109)); - e.checkbox = a; - var c = r(n(110)); - e.chips = c; - var u = r(n(117)); - e.circularProgress = u; - var l = r(n(119)); - e.dataTable = l; - var d = r(n(121)); - e.dialog = d; - var p = r(n(123)); - e.dom = p; - var _ = r(n(124)); - e.drawer = _; - var f = r(n(126)); - e.floatingLabel = f; - var h = r(n(127)); - e.formField = h; - var C = r(n(129)); - e.iconButton = C; - var y = r(n(131)); - e.lineRipple = y; - var E = r(n(132)); - e.linearProgress = E; - var g = r(n(134)); - e.list = g; - var m = r(n(135)); - e.menuSurface = m; - var A = r(n(136)); - e.menu = A; - var v = r(n(137)); - e.notchedOutline = v; - var b = r(n(138)); - e.radio = b; - var O = r(n(140)); - e.ripple = O; - var T = r(n(141)); - e.select = T; - var I = r(n(145)); - e.slider = I; - var S = r(n(147)); - e.snackbar = S; - var R = r(n(149)); - e.switchControl = R; - var L = r(n(151)); - e.tabBar = L; - var D = r(n(156)); - e.tabIndicator = D; - var P = r(n(157)); - e.tabScroller = P; - var M = r(n(158)); - e.tab = M; - var N = r(n(159)); - e.textField = N; - var w = r(n(164)); - (e.topAppBar = w), - o.default.register("MDCCheckbox", a.MDCCheckbox), - o.default.register("MDCChip", c.MDCChip), - o.default.register("MDCChipSet", c.MDCChipSet), - o.default.register("MDCCircularProgress", u.MDCCircularProgress), - o.default.register("MDCDataTable", l.MDCDataTable), - o.default.register("MDCDialog", d.MDCDialog), - o.default.register("MDCDrawer", _.MDCDrawer), - o.default.register("MDCFloatingLabel", f.MDCFloatingLabel), - o.default.register("MDCFormField", h.MDCFormField), - o.default.register("MDCIconButtonToggle", C.MDCIconButtonToggle), - o.default.register("MDCLineRipple", y.MDCLineRipple), - o.default.register("MDCLinearProgress", E.MDCLinearProgress), - o.default.register("MDCList", g.MDCList), - o.default.register("MDCMenu", A.MDCMenu), - o.default.register("MDCMenuSurface", m.MDCMenuSurface), - o.default.register("MDCNotchedOutline", v.MDCNotchedOutline), - o.default.register("MDCRadio", b.MDCRadio), - o.default.register("MDCRipple", O.MDCRipple), - o.default.register("MDCSelect", T.MDCSelect), - o.default.register("MDCSlider", I.MDCSlider), - o.default.register("MDCSnackbar", S.MDCSnackbar), - o.default.register("MDCSwitch", R.MDCSwitch), - o.default.register("MDCTabBar", L.MDCTabBar), - o.default.register("MDCTextField", N.MDCTextField), - o.default.register("MDCTopAppBar", w.MDCTopAppBar); - }, - function(t, e, n) { - "use strict"; - var d = - (this && this.__values) || - function(t) { - var e = "function" == typeof Symbol && Symbol.iterator, - n = e && t[e], - i = 0; - if (n) return n.call(t); - if (t && "number" == typeof t.length) - return { - next: function() { - return ( - t && i >= t.length && (t = void 0), - { value: t && t[i++], done: !t } - ); - } - }; - throw new TypeError( - e ? "Object is not iterable." : "Symbol.iterator is not defined." - ); - }; - Object.defineProperty(e, "__esModule", { value: !0 }); - var i = n(107), - p = i.strings.AUTO_INIT_ATTR, - _ = i.strings.AUTO_INIT_STATE_ATTR, - f = i.strings.INITIALIZED_STATE, - h = {}, - r = console.warn.bind(console); - function o(t) { - var e, n; - void 0 === t && (t = document); - var i = [], - r = [].slice.call(t.querySelectorAll("[" + p + "]")); - r = r.filter(function(t) { - return t.getAttribute(_) !== f; - }); - try { - for (var o = d(r), s = o.next(); !s.done; s = o.next()) { - var a = s.value, - c = a.getAttribute(p); - if (!c) - throw new Error( - "(mdc-auto-init) Constructor name must be given." - ); - var u = h[c]; - if ("function" != typeof u) - throw new Error( - "(mdc-auto-init) Could not find constructor in registry for " + - c - ); - var l = u.attachTo(a); - Object.defineProperty(a, c, { - configurable: !0, - enumerable: !1, - value: l, - writable: !1 - }), - i.push(l), - a.setAttribute(_, f); - } - } catch (t) { - e = { error: t }; - } finally { - try { - s && !s.done && (n = o.return) && n.call(o); - } finally { - if (e) throw e.error; - } - } - return ( - (function(t, e, n) { - var i; - void 0 === n && (n = !1), - "function" == typeof CustomEvent - ? (i = new CustomEvent(t, { bubbles: n, detail: e })) - : (i = document.createEvent("CustomEvent")).initCustomEvent( - t, - n, - !1, - e - ), - document.dispatchEvent(i); - })("MDCAutoInit:End", {}), - i - ); - } - ((e.mdcAutoInit = o).register = function(t, e, n) { - if ((void 0 === n && (n = r), "function" != typeof e)) - throw new Error( - "(mdc-auto-init) Invalid Constructor value: " + - e + - ". Expected function." - ); - var i = h[t]; - i && - n( - "(mdc-auto-init) Overriding registration for " + - t + - " with " + - e + - ". Was: " + - i - ), - (h[t] = e); - }), - (o.deregister = function(t) { - delete h[t]; - }), - (o.deregisterAll = function() { - Object.keys(h).forEach(this.deregister, this); - }), - (e.default = o); - }, - function(t, e, n) { - "use strict"; - Object.defineProperty(e, "__esModule", { value: !0 }), - (e.strings = { - AUTO_INIT_ATTR: "data-mdc-auto-init", - AUTO_INIT_STATE_ATTR: "data-mdc-auto-init-state", - INITIALIZED_STATE: "initialized" - }); - }, - function(t, n, e) { - "use strict"; - function i(t) { - for (var e in t) n.hasOwnProperty(e) || (n[e] = t[e]); - } - Object.defineProperty(n, "__esModule", { value: !0 }), i(e(1)), i(e(0)); - }, - function(t, n, e) { - "use strict"; - function i(t) { - for (var e in t) n.hasOwnProperty(e) || (n[e] = t[e]); - } - Object.defineProperty(n, "__esModule", { value: !0 }), - i(e(39)), - i(e(17)), - i(e(41)); - }, - function(t, n, e) { - "use strict"; - function i(t) { - for (var e in t) n.hasOwnProperty(e) || (n[e] = t[e]); - } - Object.defineProperty(n, "__esModule", { value: !0 }), - i(e(111)), - i(e(113)), - i(e(114)); - }, - function(t, n, e) { - "use strict"; - function i(t) { - for (var e in t) n.hasOwnProperty(e) || (n[e] = t[e]); - } - Object.defineProperty(n, "__esModule", { value: !0 }), - i(e(112)), - i(e(42)); - var r = e(18); - n.trailingActionStrings = r.strings; - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }); - Object.defineProperty(e, "__esModule", { value: !0 }); - var o, - s = n(1), - a = n(3), - c = n(4), - u = n(18), - l = n(42), - d = - ((o = s.MDCComponent), - r(p, o), - Object.defineProperty(p.prototype, "ripple", { - get: function() { - return this.ripple_; - }, - enumerable: !0, - configurable: !0 - }), - (p.attachTo = function(t) { - return new p(t); - }), - (p.prototype.initialize = function(t) { - void 0 === t && - (t = function(t, e) { - return new a.MDCRipple(t, e); - }); - var e = a.MDCRipple.createAdapter(this); - this.ripple_ = t(this.root_, new c.MDCRippleFoundation(e)); - }), - (p.prototype.initialSyncWithDOM = function() { - var e = this; - (this.handleClick_ = function(t) { - e.foundation_.handleClick(t); - }), - (this.handleKeydown_ = function(t) { - e.foundation_.handleKeydown(t); - }), - this.listen("click", this.handleClick_), - this.listen("keydown", this.handleKeydown_); - }), - (p.prototype.destroy = function() { - this.ripple_.destroy(), - this.unlisten("click", this.handleClick_), - this.unlisten("keydown", this.handleKeydown_), - o.prototype.destroy.call(this); - }), - (p.prototype.getDefaultFoundation = function() { - var n = this, - t = { - focus: function() { - n.root_.focus(); - }, - getAttribute: function(t) { - return n.root_.getAttribute(t); - }, - notifyInteraction: function(t) { - return n.emit( - u.strings.INTERACTION_EVENT, - { trigger: t }, - !0 - ); - }, - notifyNavigation: function(t) { - n.emit(u.strings.NAVIGATION_EVENT, { key: t }, !0); - }, - setAttribute: function(t, e) { - n.root_.setAttribute(t, e); - } - }; - return new l.MDCChipTrailingActionFoundation(t); - }), - (p.prototype.isNavigable = function() { - return this.foundation_.isNavigable(); - }), - (p.prototype.focus = function() { - this.foundation_.focus(); - }), - (p.prototype.removeFocus = function() { - this.foundation_.removeFocus(); - }), - p); - function p() { - return (null !== o && o.apply(this, arguments)) || this; - } - e.MDCChipTrailingAction = d; - }, - function(t, n, e) { - "use strict"; - function i(t) { - for (var e in t) n.hasOwnProperty(e) || (n[e] = t[e]); - } - Object.defineProperty(n, "__esModule", { value: !0 }), - i(e(44)), - i(e(19)); - var r = e(8); - (n.chipCssClasses = r.cssClasses), (n.chipStrings = r.strings); - }, - function(t, n, e) { - "use strict"; - function i(t) { - for (var e in t) n.hasOwnProperty(e) || (n[e] = t[e]); - } - Object.defineProperty(n, "__esModule", { value: !0 }), - i(e(115)), - i(e(45)); - var r = e(46); - (n.chipSetCssClasses = r.cssClasses), (n.chipSetStrings = r.strings); - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }); - Object.defineProperty(e, "__esModule", { value: !0 }); - var o, - s = n(1), - a = n(116), - c = n(44), - u = n(19), - l = n(45), - d = u.MDCChipFoundation.strings, - p = d.INTERACTION_EVENT, - _ = d.SELECTION_EVENT, - f = d.REMOVAL_EVENT, - h = d.NAVIGATION_EVENT, - C = l.MDCChipSetFoundation.strings.CHIP_SELECTOR, - y = 0, - E = - ((o = s.MDCComponent), - r(g, o), - (g.attachTo = function(t) { - return new g(t); - }), - Object.defineProperty(g.prototype, "chips", { - get: function() { - return this.chips_.slice(); - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(g.prototype, "selectedChipIds", { - get: function() { - return this.foundation_.getSelectedChipIds(); - }, - enumerable: !0, - configurable: !0 - }), - (g.prototype.initialize = function(t) { - void 0 === t && - (t = function(t) { - return new c.MDCChip(t); - }), - (this.chipFactory_ = t), - (this.chips_ = this.instantiateChips_(this.chipFactory_)); - }), - (g.prototype.initialSyncWithDOM = function() { - var e = this; - this.chips_.forEach(function(t) { - t.id && t.selected && e.foundation_.select(t.id); - }), - (this.handleChipInteraction_ = function(t) { - return e.foundation_.handleChipInteraction(t.detail); - }), - (this.handleChipSelection_ = function(t) { - return e.foundation_.handleChipSelection(t.detail); - }), - (this.handleChipRemoval_ = function(t) { - return e.foundation_.handleChipRemoval(t.detail); - }), - (this.handleChipNavigation_ = function(t) { - return e.foundation_.handleChipNavigation(t.detail); - }), - this.listen(p, this.handleChipInteraction_), - this.listen(_, this.handleChipSelection_), - this.listen(f, this.handleChipRemoval_), - this.listen(h, this.handleChipNavigation_); - }), - (g.prototype.destroy = function() { - this.chips_.forEach(function(t) { - t.destroy(); - }), - this.unlisten(p, this.handleChipInteraction_), - this.unlisten(_, this.handleChipSelection_), - this.unlisten(f, this.handleChipRemoval_), - this.unlisten(h, this.handleChipNavigation_), - o.prototype.destroy.call(this); - }), - (g.prototype.addChip = function(t) { - (t.id = t.id || "mdc-chip-" + ++y), - this.chips_.push(this.chipFactory_(t)); - }), - (g.prototype.getDefaultFoundation = function() { - var i = this, - t = { - announceMessage: function(t) { - a.announce(t); - }, - focusChipPrimaryActionAtIndex: function(t) { - i.chips_[t].focusPrimaryAction(); - }, - focusChipTrailingActionAtIndex: function(t) { - i.chips_[t].focusTrailingAction(); - }, - getChipListCount: function() { - return i.chips_.length; - }, - getIndexOfChipById: function(t) { - return i.findChipIndex_(t); - }, - hasClass: function(t) { - return i.root_.classList.contains(t); - }, - isRTL: function() { - return ( - "rtl" === - window - .getComputedStyle(i.root_) - .getPropertyValue("direction") - ); - }, - removeChipAtIndex: function(t) { - 0 <= t && - t < i.chips_.length && - (i.chips_[t].destroy(), - i.chips_[t].remove(), - i.chips_.splice(t, 1)); - }, - removeFocusFromChipAtIndex: function(t) { - i.chips_[t].removeFocus(); - }, - selectChipAtIndex: function(t, e, n) { - 0 <= t && - t < i.chips_.length && - i.chips_[t].setSelectedFromChipSet(e, n); - } - }; - return new l.MDCChipSetFoundation(t); - }), - (g.prototype.instantiateChips_ = function(e) { - return [].slice - .call(this.root_.querySelectorAll(C)) - .map(function(t) { - return (t.id = t.id || "mdc-chip-" + ++y), e(t); - }); - }), - (g.prototype.findChipIndex_ = function(t) { - for (var e = 0; e < this.chips_.length; e++) - if (this.chips_[e].id === t) return e; - return -1; - }), - g); - function g() { - return (null !== o && o.apply(this, arguments)) || this; - } - e.MDCChipSet = E; - }, - function(t, e, n) { - "use strict"; - var i, r; - Object.defineProperty(e, "__esModule", { value: !0 }), - ((r = i = e.AnnouncerPriority || (e.AnnouncerPriority = {})).POLITE = - "polite"), - (r.ASSERTIVE = "assertive"), - (e.announce = function(t, e) { - o.getInstance().say(t, e); - }); - var o = - ((s.getInstance = function() { - return s.instance || (s.instance = new s()), s.instance; - }), - (s.prototype.say = function(t, e) { - void 0 === e && (e = i.POLITE); - var n = this.getLiveRegion(e); - (n.textContent = ""), - setTimeout(function() { - n.textContent = t; - }, 1); - }), - (s.prototype.getLiveRegion = function(t) { - var e = this.liveRegions.get(t); - if (e && document.body.contains(e)) return e; - var n = this.createLiveRegion(t); - return this.liveRegions.set(t, n), n; - }), - (s.prototype.createLiveRegion = function(t) { - var e = document.createElement("div"); - return ( - (e.style.position = "absolute"), - (e.style.top = "-9999px"), - (e.style.left = "-9999px"), - (e.style.height = "1px"), - (e.style.overflow = "hidden"), - e.setAttribute("aria-atomic", "true"), - e.setAttribute("aria-live", t), - document.body.appendChild(e), - e - ); - }), - s); - function s() { - this.liveRegions = new Map(); - } - }, - function(t, n, e) { - "use strict"; - function i(t) { - for (var e in t) n.hasOwnProperty(e) || (n[e] = t[e]); - } - Object.defineProperty(n, "__esModule", { value: !0 }), - i(e(118)), - i(e(48)), - i(e(47)); - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }); - Object.defineProperty(e, "__esModule", { value: !0 }); - var o, - s = n(1), - a = n(47), - c = - ((o = s.MDCComponent), - r(u, o), - (u.prototype.initialize = function() { - this.determinateCircle_ = this.root_.querySelector( - a.MDCCircularProgressFoundation.strings - .DETERMINATE_CIRCLE_SELECTOR - ); - }), - (u.attachTo = function(t) { - return new u(t); - }), - Object.defineProperty(u.prototype, "determinate", { - set: function(t) { - this.foundation_.setDeterminate(t); - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(u.prototype, "progress", { - set: function(t) { - this.foundation_.setProgress(t); - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(u.prototype, "isClosed", { - get: function() { - return this.foundation_.isClosed(); - }, - enumerable: !0, - configurable: !0 - }), - (u.prototype.open = function() { - this.foundation_.open(); - }), - (u.prototype.close = function() { - this.foundation_.close(); - }), - (u.prototype.getDefaultFoundation = function() { - var n = this, - t = { - addClass: function(t) { - return n.root_.classList.add(t); - }, - getDeterminateCircleAttribute: function(t) { - return n.determinateCircle_.getAttribute(t); - }, - hasClass: function(t) { - return n.root_.classList.contains(t); - }, - removeClass: function(t) { - return n.root_.classList.remove(t); - }, - removeAttribute: function(t) { - return n.root_.removeAttribute(t); - }, - setAttribute: function(t, e) { - return n.root_.setAttribute(t, e); - }, - setDeterminateCircleAttribute: function(t, e) { - return n.determinateCircle_.setAttribute(t, e); - } - }; - return new a.MDCCircularProgressFoundation(t); - }), - u); - function u() { - return (null !== o && o.apply(this, arguments)) || this; - } - e.MDCCircularProgress = c; - }, - function(t, n, e) { - "use strict"; - function i(t) { - for (var e in t) n.hasOwnProperty(e) || (n[e] = t[e]); - } - Object.defineProperty(n, "__esModule", { value: !0 }), - i(e(120)), - i(e(49)), - i(e(20)); - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }); - Object.defineProperty(e, "__esModule", { value: !0 }); - var o, - s = n(1), - a = n(39), - c = n(2), - u = n(20), - l = n(49), - d = - ((o = s.MDCComponent), - r(p, o), - (p.attachTo = function(t) { - return new p(t); - }), - (p.prototype.initialize = function(t) { - void 0 === t && - (t = function(t) { - return new a.MDCCheckbox(t); - }), - (this.checkboxFactory_ = t); - }), - (p.prototype.initialSyncWithDOM = function() { - var e = this; - (this.headerRow_ = this.root_.querySelector( - "." + u.cssClasses.HEADER_ROW - )), - (this.handleHeaderRowCheckboxChange_ = function() { - return e.foundation_.handleHeaderRowCheckboxChange(); - }), - this.headerRow_.addEventListener( - "change", - this.handleHeaderRowCheckboxChange_ - ), - (this.content_ = this.root_.querySelector( - "." + u.cssClasses.CONTENT - )), - (this.handleRowCheckboxChange_ = function(t) { - return e.foundation_.handleRowCheckboxChange(t); - }), - this.content_.addEventListener( - "change", - this.handleRowCheckboxChange_ - ), - this.layout(); - }), - (p.prototype.layout = function() { - this.foundation_.layout(); - }), - (p.prototype.getRows = function() { - return this.foundation_.getRows(); - }), - (p.prototype.getSelectedRowIds = function() { - return this.foundation_.getSelectedRowIds(); - }), - (p.prototype.setSelectedRowIds = function(t) { - this.foundation_.setSelectedRowIds(t); - }), - (p.prototype.destroy = function() { - this.headerRow_.removeEventListener( - "change", - this.handleHeaderRowCheckboxChange_ - ), - this.content_.removeEventListener( - "change", - this.handleRowCheckboxChange_ - ), - this.headerRowCheckbox_.destroy(), - this.rowCheckboxList_.forEach(function(t) { - return t.destroy(); - }); - }), - (p.prototype.getDefaultFoundation = function() { - var i = this, - t = { - addClassAtRowIndex: function(t, e) { - i.getRows()[t].classList.add(e); - }, - getRowCount: function() { - return i.getRows().length; - }, - getRowElements: function() { - return [].slice.call( - i.root_.querySelectorAll(u.strings.ROW_SELECTOR) - ); - }, - getRowIdAtIndex: function(t) { - return i - .getRows() - [t].getAttribute(u.strings.DATA_ROW_ID_ATTR); - }, - getRowIndexByChildElement: function(t) { - return i - .getRows() - .indexOf(c.closest(t, u.strings.ROW_SELECTOR)); - }, - getSelectedRowCount: function() { - return i.root_.querySelectorAll( - u.strings.ROW_SELECTED_SELECTOR - ).length; - }, - isCheckboxAtRowIndexChecked: function(t) { - return i.rowCheckboxList_[t].checked; - }, - isHeaderRowCheckboxChecked: function() { - return i.headerRowCheckbox_.checked; - }, - isRowsSelectable: function() { - return !!i.root_.querySelector( - u.strings.ROW_CHECKBOX_SELECTOR - ); - }, - notifyRowSelectionChanged: function(t) { - i.emit( - u.events.ROW_SELECTION_CHANGED, - { - row: i.getRowByIndex_(t.rowIndex), - rowId: i.getRowIdByIndex_(t.rowIndex), - rowIndex: t.rowIndex, - selected: t.selected - }, - !0 - ); - }, - notifySelectedAll: function() { - i.emit(u.events.SELECTED_ALL, {}, !0); - }, - notifyUnselectedAll: function() { - i.emit(u.events.UNSELECTED_ALL, {}, !0); - }, - registerHeaderRowCheckbox: function() { - i.headerRowCheckbox_ && i.headerRowCheckbox_.destroy(); - var t = i.root_.querySelector( - u.strings.HEADER_ROW_CHECKBOX_SELECTOR - ); - i.headerRowCheckbox_ = i.checkboxFactory_(t); - }, - registerRowCheckboxes: function() { - i.rowCheckboxList_ && - i.rowCheckboxList_.forEach(function(t) { - return t.destroy(); - }), - (i.rowCheckboxList_ = []), - i.getRows().forEach(function(t) { - var e = i.checkboxFactory_( - t.querySelector(u.strings.ROW_CHECKBOX_SELECTOR) - ); - i.rowCheckboxList_.push(e); - }); - }, - removeClassAtRowIndex: function(t, e) { - i.getRows()[t].classList.remove(e); - }, - setAttributeAtRowIndex: function(t, e, n) { - i.getRows()[t].setAttribute(e, n); - }, - setHeaderRowCheckboxChecked: function(t) { - i.headerRowCheckbox_.checked = t; - }, - setHeaderRowCheckboxIndeterminate: function(t) { - i.headerRowCheckbox_.indeterminate = t; - }, - setRowCheckboxCheckedAtIndex: function(t, e) { - i.rowCheckboxList_[t].checked = e; - } - }; - return new l.MDCDataTableFoundation(t); - }), - (p.prototype.getRowByIndex_ = function(t) { - return this.getRows()[t]; - }), - (p.prototype.getRowIdByIndex_ = function(t) { - return this.getRowByIndex_(t).getAttribute( - u.strings.DATA_ROW_ID_ATTR - ); - }), - p); - function p() { - return (null !== o && o.apply(this, arguments)) || this; - } - e.MDCDataTable = d; - }, - function(t, n, e) { - "use strict"; - function i(t) { - for (var e in t) n.hasOwnProperty(e) || (n[e] = t[e]); - } - var r = - (this && this.__importStar) || - function(t) { - if (t && t.__esModule) return t; - var e = {}; - if (null != t) - for (var n in t) - Object.hasOwnProperty.call(t, n) && (e[n] = t[n]); - return (e.default = t), e; - }; - Object.defineProperty(n, "__esModule", { value: !0 }); - var o = r(e(50)); - (n.util = o), i(e(122)), i(e(52)), i(e(51)); - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }), - a = - (this && this.__values) || - function(t) { - var e = "function" == typeof Symbol && Symbol.iterator, - n = e && t[e], - i = 0; - if (n) return n.call(t); - if (t && "number" == typeof t.length) - return { - next: function() { - return ( - t && i >= t.length && (t = void 0), - { value: t && t[i++], done: !t } - ); - } - }; - throw new TypeError( - e - ? "Object is not iterable." - : "Symbol.iterator is not defined." - ); - }, - o = - (this && this.__importStar) || - function(t) { - if (t && t.__esModule) return t; - var e = {}; - if (null != t) - for (var n in t) - Object.hasOwnProperty.call(t, n) && (e[n] = t[n]); - return (e.default = t), e; - }; - Object.defineProperty(e, "__esModule", { value: !0 }); - var s, - c = n(1), - u = n(21), - l = n(2), - d = n(3), - p = n(51), - _ = o(n(50)), - f = p.MDCDialogFoundation.strings, - h = - ((s = c.MDCComponent), - r(C, s), - Object.defineProperty(C.prototype, "isOpen", { - get: function() { - return this.foundation_.isOpen(); - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(C.prototype, "escapeKeyAction", { - get: function() { - return this.foundation_.getEscapeKeyAction(); - }, - set: function(t) { - this.foundation_.setEscapeKeyAction(t); - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(C.prototype, "scrimClickAction", { - get: function() { - return this.foundation_.getScrimClickAction(); - }, - set: function(t) { - this.foundation_.setScrimClickAction(t); - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(C.prototype, "autoStackButtons", { - get: function() { - return this.foundation_.getAutoStackButtons(); - }, - set: function(t) { - this.foundation_.setAutoStackButtons(t); - }, - enumerable: !0, - configurable: !0 - }), - (C.attachTo = function(t) { - return new C(t); - }), - (C.prototype.initialize = function(t) { - var e, n; - void 0 === t && - (t = function(t, e) { - return new u.FocusTrap(t, e); - }); - var i = this.root_.querySelector(f.CONTAINER_SELECTOR); - if (!i) - throw new Error( - "Dialog component requires a " + - f.CONTAINER_SELECTOR + - " container element" - ); - (this.container_ = i), - (this.content_ = this.root_.querySelector(f.CONTENT_SELECTOR)), - (this.buttons_ = [].slice.call( - this.root_.querySelectorAll(f.BUTTON_SELECTOR) - )), - (this.defaultButton_ = this.root_.querySelector( - "[" + f.BUTTON_DEFAULT_ATTRIBUTE + "]" - )), - (this.focusTrapFactory_ = t), - (this.buttonRipples_ = []); - try { - for ( - var r = a(this.buttons_), o = r.next(); - !o.done; - o = r.next() - ) { - var s = o.value; - this.buttonRipples_.push(new d.MDCRipple(s)); - } - } catch (t) { - e = { error: t }; - } finally { - try { - o && !o.done && (n = r.return) && n.call(r); - } finally { - if (e) throw e.error; - } - } - }), - (C.prototype.initialSyncWithDOM = function() { - var e = this; - (this.focusTrap_ = _.createFocusTrapInstance( - this.container_, - this.focusTrapFactory_, - this.getInitialFocusEl_() || void 0 - )), - (this.handleClick_ = this.foundation_.handleClick.bind( - this.foundation_ - )), - (this.handleKeydown_ = this.foundation_.handleKeydown.bind( - this.foundation_ - )), - (this.handleDocumentKeydown_ = this.foundation_.handleDocumentKeydown.bind( - this.foundation_ - )), - (this.handleLayout_ = this.layout.bind(this)); - var t = ["resize", "orientationchange"]; - (this.handleOpening_ = function() { - t.forEach(function(t) { - return window.addEventListener(t, e.handleLayout_); - }), - document.addEventListener( - "keydown", - e.handleDocumentKeydown_ - ); - }), - (this.handleClosing_ = function() { - t.forEach(function(t) { - return window.removeEventListener(t, e.handleLayout_); - }), - document.removeEventListener( - "keydown", - e.handleDocumentKeydown_ - ); - }), - this.listen("click", this.handleClick_), - this.listen("keydown", this.handleKeydown_), - this.listen(f.OPENING_EVENT, this.handleOpening_), - this.listen(f.CLOSING_EVENT, this.handleClosing_); - }), - (C.prototype.destroy = function() { - this.unlisten("click", this.handleClick_), - this.unlisten("keydown", this.handleKeydown_), - this.unlisten(f.OPENING_EVENT, this.handleOpening_), - this.unlisten(f.CLOSING_EVENT, this.handleClosing_), - this.handleClosing_(), - this.buttonRipples_.forEach(function(t) { - return t.destroy(); - }), - s.prototype.destroy.call(this); - }), - (C.prototype.layout = function() { - this.foundation_.layout(); - }), - (C.prototype.open = function() { - this.foundation_.open(); - }), - (C.prototype.close = function(t) { - void 0 === t && (t = ""), this.foundation_.close(t); - }), - (C.prototype.getDefaultFoundation = function() { - var e = this, - t = { - addBodyClass: function(t) { - return document.body.classList.add(t); - }, - addClass: function(t) { - return e.root_.classList.add(t); - }, - areButtonsStacked: function() { - return _.areTopsMisaligned(e.buttons_); - }, - clickDefaultButton: function() { - return e.defaultButton_ && e.defaultButton_.click(); - }, - eventTargetMatches: function(t, e) { - return !!t && l.matches(t, e); - }, - getActionFromEvent: function(t) { - if (!t.target) return ""; - var e = l.closest(t.target, "[" + f.ACTION_ATTRIBUTE + "]"); - return e && e.getAttribute(f.ACTION_ATTRIBUTE); - }, - getInitialFocusEl: function() { - return e.getInitialFocusEl_(); - }, - hasClass: function(t) { - return e.root_.classList.contains(t); - }, - isContentScrollable: function() { - return _.isScrollable(e.content_); - }, - notifyClosed: function(t) { - return e.emit(f.CLOSED_EVENT, t ? { action: t } : {}); - }, - notifyClosing: function(t) { - return e.emit(f.CLOSING_EVENT, t ? { action: t } : {}); - }, - notifyOpened: function() { - return e.emit(f.OPENED_EVENT, {}); - }, - notifyOpening: function() { - return e.emit(f.OPENING_EVENT, {}); - }, - releaseFocus: function() { - return e.focusTrap_.releaseFocus(); - }, - removeBodyClass: function(t) { - return document.body.classList.remove(t); - }, - removeClass: function(t) { - return e.root_.classList.remove(t); - }, - reverseButtons: function() { - e.buttons_.reverse(), - e.buttons_.forEach(function(t) { - t.parentElement.appendChild(t); - }); - }, - trapFocus: function() { - return e.focusTrap_.trapFocus(); - } - }; - return new p.MDCDialogFoundation(t); - }), - (C.prototype.getInitialFocusEl_ = function() { - return document.querySelector( - "[" + f.INITIAL_FOCUS_ATTRIBUTE + "]" - ); - }), - C); - function C() { - return (null !== s && s.apply(this, arguments)) || this; - } - e.MDCDialog = h; - }, - function(t, e, n) { - "use strict"; - var i = - (this && this.__importStar) || - function(t) { - if (t && t.__esModule) return t; - var e = {}; - if (null != t) - for (var n in t) - Object.hasOwnProperty.call(t, n) && (e[n] = t[n]); - return (e.default = t), e; - }; - Object.defineProperty(e, "__esModule", { value: !0 }); - var r = i(n(5)); - e.events = r; - var o = i(n(21)); - e.focusTrap = o; - var s = i(n(43)); - e.keyboard = s; - var a = i(n(2)); - e.ponyfill = a; - }, - function(t, n, e) { - "use strict"; - function i(t) { - for (var e in t) n.hasOwnProperty(e) || (n[e] = t[e]); - } - var r = - (this && this.__importStar) || - function(t) { - if (t && t.__esModule) return t; - var e = {}; - if (null != t) - for (var n in t) - Object.hasOwnProperty.call(t, n) && (e[n] = t[n]); - return (e.default = t), e; - }; - Object.defineProperty(n, "__esModule", { value: !0 }); - var o = r(e(53)); - (n.util = o), i(e(125)), i(e(54)), i(e(23)), i(e(55)); - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }), - o = - (this && this.__importStar) || - function(t) { - if (t && t.__esModule) return t; - var e = {}; - if (null != t) - for (var n in t) - Object.hasOwnProperty.call(t, n) && (e[n] = t[n]); - return (e.default = t), e; - }; - Object.defineProperty(e, "__esModule", { value: !0 }); - var s, - a = n(1), - c = n(21), - u = n(22), - l = n(10), - d = n(23), - p = n(55), - _ = o(n(53)), - f = d.MDCDismissibleDrawerFoundation.cssClasses, - h = d.MDCDismissibleDrawerFoundation.strings, - C = - ((s = a.MDCComponent), - r(y, s), - (y.attachTo = function(t) { - return new y(t); - }), - Object.defineProperty(y.prototype, "open", { - get: function() { - return this.foundation_.isOpen(); - }, - set: function(t) { - t ? this.foundation_.open() : this.foundation_.close(); - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(y.prototype, "list", { - get: function() { - return this.list_; - }, - enumerable: !0, - configurable: !0 - }), - (y.prototype.initialize = function(t, e) { - void 0 === t && - (t = function(t) { - return new c.FocusTrap(t); - }), - void 0 === e && - (e = function(t) { - return new u.MDCList(t); - }); - var n = this.root_.querySelector( - "." + l.MDCListFoundation.cssClasses.ROOT - ); - n && ((this.list_ = e(n)), (this.list_.wrapFocus = !0)), - (this.focusTrapFactory_ = t); - }), - (y.prototype.initialSyncWithDOM = function() { - var e = this, - t = f.MODAL, - n = h.SCRIM_SELECTOR; - (this.scrim_ = this.root_.parentNode.querySelector(n)), - this.scrim_ && - this.root_.classList.contains(t) && - ((this.handleScrimClick_ = function() { - return e.foundation_.handleScrimClick(); - }), - this.scrim_.addEventListener("click", this.handleScrimClick_), - (this.focusTrap_ = _.createFocusTrapInstance( - this.root_, - this.focusTrapFactory_ - ))), - (this.handleKeydown_ = function(t) { - return e.foundation_.handleKeydown(t); - }), - (this.handleTransitionEnd_ = function(t) { - return e.foundation_.handleTransitionEnd(t); - }), - this.listen("keydown", this.handleKeydown_), - this.listen("transitionend", this.handleTransitionEnd_); - }), - (y.prototype.destroy = function() { - this.unlisten("keydown", this.handleKeydown_), - this.unlisten("transitionend", this.handleTransitionEnd_), - this.list_ && this.list_.destroy(); - var t = f.MODAL; - this.scrim_ && - this.handleScrimClick_ && - this.root_.classList.contains(t) && - (this.scrim_.removeEventListener( - "click", - this.handleScrimClick_ - ), - (this.open = !1)); - }), - (y.prototype.getDefaultFoundation = function() { - var e = this, - t = { - addClass: function(t) { - return e.root_.classList.add(t); - }, - removeClass: function(t) { - return e.root_.classList.remove(t); - }, - hasClass: function(t) { - return e.root_.classList.contains(t); - }, - elementHasClass: function(t, e) { - return t.classList.contains(e); - }, - saveFocus: function() { - return (e.previousFocus_ = document.activeElement); - }, - restoreFocus: function() { - var t = e.previousFocus_; - t && - t.focus && - e.root_.contains(document.activeElement) && - t.focus(); - }, - focusActiveNavigationItem: function() { - var t = e.root_.querySelector( - "." + - l.MDCListFoundation.cssClasses.LIST_ITEM_ACTIVATED_CLASS - ); - t && t.focus(); - }, - notifyClose: function() { - return e.emit(h.CLOSE_EVENT, {}, !0); - }, - notifyOpen: function() { - return e.emit(h.OPEN_EVENT, {}, !0); - }, - trapFocus: function() { - return e.focusTrap_.trapFocus(); - }, - releaseFocus: function() { - return e.focusTrap_.releaseFocus(); - } - }, - n = f.DISMISSIBLE, - i = f.MODAL; - if (this.root_.classList.contains(n)) - return new d.MDCDismissibleDrawerFoundation(t); - if (this.root_.classList.contains(i)) - return new p.MDCModalDrawerFoundation(t); - throw new Error( - "MDCDrawer: Failed to instantiate component. Supported variants are " + - n + - " and " + - i + - "." - ); - }), - y); - function y() { - return (null !== s && s.apply(this, arguments)) || this; - } - e.MDCDrawer = C; - }, - function(t, n, e) { - "use strict"; - function i(t) { - for (var e in t) n.hasOwnProperty(e) || (n[e] = t[e]); - } - Object.defineProperty(n, "__esModule", { value: !0 }), - i(e(24)), - i(e(56)), - i(e(25)); - }, - function(t, n, e) { - "use strict"; - function i(t) { - for (var e in t) n.hasOwnProperty(e) || (n[e] = t[e]); - } - Object.defineProperty(n, "__esModule", { value: !0 }), - i(e(128)), - i(e(58)), - i(e(57)); - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }); - Object.defineProperty(e, "__esModule", { value: !0 }); - var o, - s = n(1), - a = n(57), - c = - ((o = s.MDCComponent), - r(u, o), - (u.attachTo = function(t) { - return new u(t); - }), - Object.defineProperty(u.prototype, "input", { - get: function() { - return this.input_; - }, - set: function(t) { - this.input_ = t; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(u.prototype, "label_", { - get: function() { - var t = a.MDCFormFieldFoundation.strings.LABEL_SELECTOR; - return this.root_.querySelector(t); - }, - enumerable: !0, - configurable: !0 - }), - (u.prototype.getDefaultFoundation = function() { - var n = this, - t = { - activateInputRipple: function() { - n.input_ && n.input_.ripple && n.input_.ripple.activate(); - }, - deactivateInputRipple: function() { - n.input_ && n.input_.ripple && n.input_.ripple.deactivate(); - }, - deregisterInteractionHandler: function(t, e) { - n.label_ && n.label_.removeEventListener(t, e); - }, - registerInteractionHandler: function(t, e) { - n.label_ && n.label_.addEventListener(t, e); - } - }; - return new a.MDCFormFieldFoundation(t); - }), - u); - function u() { - return (null !== o && o.apply(this, arguments)) || this; - } - e.MDCFormField = c; - }, - function(t, n, e) { - "use strict"; - function i(t) { - for (var e in t) n.hasOwnProperty(e) || (n[e] = t[e]); - } - Object.defineProperty(n, "__esModule", { value: !0 }), - i(e(130)), - i(e(60)), - i(e(59)); - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }); - Object.defineProperty(e, "__esModule", { value: !0 }); - var o, - s = n(1), - a = n(3), - c = n(59), - u = c.MDCIconButtonToggleFoundation.strings, - l = - ((o = s.MDCComponent), - r(d, o), - (d.attachTo = function(t) { - return new d(t); - }), - (d.prototype.initialSyncWithDOM = function() { - var t = this; - (this.handleClick_ = function() { - return t.foundation_.handleClick(); - }), - this.listen("click", this.handleClick_); - }), - (d.prototype.destroy = function() { - this.unlisten("click", this.handleClick_), - this.ripple_.destroy(), - o.prototype.destroy.call(this); - }), - (d.prototype.getDefaultFoundation = function() { - var n = this, - t = { - addClass: function(t) { - return n.root_.classList.add(t); - }, - hasClass: function(t) { - return n.root_.classList.contains(t); - }, - notifyChange: function(t) { - n.emit(u.CHANGE_EVENT, t); - }, - removeClass: function(t) { - return n.root_.classList.remove(t); - }, - getAttr: function(t) { - return n.root_.getAttribute(t); - }, - setAttr: function(t, e) { - return n.root_.setAttribute(t, e); - } - }; - return new c.MDCIconButtonToggleFoundation(t); - }), - Object.defineProperty(d.prototype, "ripple", { - get: function() { - return this.ripple_; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(d.prototype, "on", { - get: function() { - return this.foundation_.isOn(); - }, - set: function(t) { - this.foundation_.toggle(t); - }, - enumerable: !0, - configurable: !0 - }), - (d.prototype.createRipple_ = function() { - var t = new a.MDCRipple(this.root_); - return (t.unbounded = !0), t; - }), - d); - function d() { - var t = (null !== o && o.apply(this, arguments)) || this; - return (t.ripple_ = t.createRipple_()), t; - } - e.MDCIconButtonToggle = l; - }, - function(t, n, e) { - "use strict"; - function i(t) { - for (var e in t) n.hasOwnProperty(e) || (n[e] = t[e]); - } - Object.defineProperty(n, "__esModule", { value: !0 }), - i(e(26)), - i(e(62)), - i(e(61)); - }, - function(t, n, e) { - "use strict"; - function i(t) { - for (var e in t) n.hasOwnProperty(e) || (n[e] = t[e]); - } - Object.defineProperty(n, "__esModule", { value: !0 }), - i(e(133)), - i(e(64)), - i(e(63)); - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }); - Object.defineProperty(e, "__esModule", { value: !0 }); - var o, - s = n(1), - a = n(63), - c = - ((o = s.MDCComponent), - r(u, o), - (u.attachTo = function(t) { - return new u(t); - }), - Object.defineProperty(u.prototype, "determinate", { - set: function(t) { - this.foundation_.setDeterminate(t); - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(u.prototype, "progress", { - set: function(t) { - this.foundation_.setProgress(t); - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(u.prototype, "buffer", { - set: function(t) { - this.foundation_.setBuffer(t); - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(u.prototype, "reverse", { - set: function(t) { - this.foundation_.setReverse(t); - }, - enumerable: !0, - configurable: !0 - }), - (u.prototype.open = function() { - this.foundation_.open(); - }), - (u.prototype.close = function() { - this.foundation_.close(); - }), - (u.prototype.getDefaultFoundation = function() { - var n = this, - t = { - addClass: function(t) { - return n.root_.classList.add(t); - }, - forceLayout: function() { - return n.root_.offsetWidth; - }, - setBufferBarStyle: function(t, e) { - n.root_ - .querySelector( - a.MDCLinearProgressFoundation.strings - .BUFFER_BAR_SELECTOR - ) - .style.setProperty(t, e); - }, - setPrimaryBarStyle: function(t, e) { - n.root_ - .querySelector( - a.MDCLinearProgressFoundation.strings - .PRIMARY_BAR_SELECTOR - ) - .style.setProperty(t, e); - }, - hasClass: function(t) { - return n.root_.classList.contains(t); - }, - removeAttribute: function(t) { - n.root_.removeAttribute(t); - }, - removeClass: function(t) { - return n.root_.classList.remove(t); - }, - setAttribute: function(t, e) { - n.root_.setAttribute(t, e); - } - }; - return new a.MDCLinearProgressFoundation(t); - }), - u); - function u() { - return (null !== o && o.apply(this, arguments)) || this; - } - e.MDCLinearProgress = c; - }, - function(t, n, e) { - "use strict"; - function i(t) { - for (var e in t) n.hasOwnProperty(e) || (n[e] = t[e]); - } - Object.defineProperty(n, "__esModule", { value: !0 }), - i(e(22)), - i(e(9)), - i(e(10)); - }, - function(t, n, e) { - "use strict"; - function i(t) { - for (var e in t) n.hasOwnProperty(e) || (n[e] = t[e]); - } - var r = - (this && this.__importStar) || - function(t) { - if (t && t.__esModule) return t; - var e = {}; - if (null != t) - for (var n in t) - Object.hasOwnProperty.call(t, n) && (e[n] = t[n]); - return (e.default = t), e; - }; - Object.defineProperty(n, "__esModule", { value: !0 }); - var o = r(e(65)); - (n.util = o), i(e(66)), i(e(6)), i(e(11)); - }, - function(t, n, e) { - "use strict"; - function i(t) { - for (var e in t) n.hasOwnProperty(e) || (n[e] = t[e]); - } - Object.defineProperty(n, "__esModule", { value: !0 }); - var r = e(6); - (n.Corner = r.Corner), i(e(67)), i(e(12)), i(e(68)); - }, - function(t, n, e) { - "use strict"; - function i(t) { - for (var e in t) n.hasOwnProperty(e) || (n[e] = t[e]); - } - Object.defineProperty(n, "__esModule", { value: !0 }), - i(e(27)), - i(e(28)), - i(e(69)); - }, - function(t, n, e) { - "use strict"; - function i(t) { - for (var e in t) n.hasOwnProperty(e) || (n[e] = t[e]); - } - Object.defineProperty(n, "__esModule", { value: !0 }), - i(e(139)), - i(e(71)), - i(e(70)); - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }), - o = - (this && this.__assign) || - function() { - return (o = - Object.assign || - function(t) { - for (var e, n = 1, i = arguments.length; n < i; n++) - for (var r in (e = arguments[n])) - Object.prototype.hasOwnProperty.call(e, r) && - (t[r] = e[r]); - return t; - }).apply(this, arguments); - }; - Object.defineProperty(e, "__esModule", { value: !0 }); - var s, - a = n(1), - c = n(5), - u = n(3), - l = n(4), - d = n(70), - p = - ((s = a.MDCComponent), - r(_, s), - (_.attachTo = function(t) { - return new _(t); - }), - Object.defineProperty(_.prototype, "checked", { - get: function() { - return this.nativeControl_.checked; - }, - set: function(t) { - this.nativeControl_.checked = t; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(_.prototype, "disabled", { - get: function() { - return this.nativeControl_.disabled; - }, - set: function(t) { - this.foundation_.setDisabled(t); - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(_.prototype, "value", { - get: function() { - return this.nativeControl_.value; - }, - set: function(t) { - this.nativeControl_.value = t; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(_.prototype, "ripple", { - get: function() { - return this.ripple_; - }, - enumerable: !0, - configurable: !0 - }), - (_.prototype.destroy = function() { - this.ripple_.destroy(), s.prototype.destroy.call(this); - }), - (_.prototype.getDefaultFoundation = function() { - var e = this, - t = { - addClass: function(t) { - return e.root_.classList.add(t); - }, - removeClass: function(t) { - return e.root_.classList.remove(t); - }, - setNativeControlDisabled: function(t) { - return (e.nativeControl_.disabled = t); - } - }; - return new d.MDCRadioFoundation(t); - }), - (_.prototype.createRipple_ = function() { - var n = this, - t = o(o({}, u.MDCRipple.createAdapter(this)), { - registerInteractionHandler: function(t, e) { - return n.nativeControl_.addEventListener( - t, - e, - c.applyPassive() - ); - }, - deregisterInteractionHandler: function(t, e) { - return n.nativeControl_.removeEventListener( - t, - e, - c.applyPassive() - ); - }, - isSurfaceActive: function() { - return !1; - }, - isUnbounded: function() { - return !0; - } - }); - return new u.MDCRipple(this.root_, new l.MDCRippleFoundation(t)); - }), - Object.defineProperty(_.prototype, "nativeControl_", { - get: function() { - var t = d.MDCRadioFoundation.strings.NATIVE_CONTROL_SELECTOR, - e = this.root_.querySelector(t); - if (!e) - throw new Error( - "Radio component requires a " + t + " element" - ); - return e; - }, - enumerable: !0, - configurable: !0 - }), - _); - function _() { - var t = (null !== s && s.apply(this, arguments)) || this; - return (t.ripple_ = t.createRipple_()), t; - } - e.MDCRadio = p; - }, - function(t, n, e) { - "use strict"; - function i(t) { - for (var e in t) n.hasOwnProperty(e) || (n[e] = t[e]); - } - var r = - (this && this.__importStar) || - function(t) { - if (t && t.__esModule) return t; - var e = {}; - if (null != t) - for (var n in t) - Object.hasOwnProperty.call(t, n) && (e[n] = t[n]); - return (e.default = t), e; - }; - Object.defineProperty(n, "__esModule", { value: !0 }); - var o = r(e(16)); - (n.util = o), i(e(3)), i(e(40)), i(e(4)); - }, - function(t, n, e) { - "use strict"; - function i(t) { - for (var e in t) n.hasOwnProperty(e) || (n[e] = t[e]); - } - Object.defineProperty(n, "__esModule", { value: !0 }), - i(e(142)), - i(e(29)), - i(e(72)), - i(e(143)), - i(e(144)); - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }), - o = - (this && this.__assign) || - function() { - return (o = - Object.assign || - function(t) { - for (var e, n = 1, i = arguments.length; n < i; n++) - for (var r in (e = arguments[n])) - Object.prototype.hasOwnProperty.call(e, r) && - (t[r] = e[r]); - return t; - }).apply(this, arguments); - }, - s = - (this && this.__importStar) || - function(t) { - if (t && t.__esModule) return t; - var e = {}; - if (null != t) - for (var n in t) - Object.hasOwnProperty.call(t, n) && (e[n] = t[n]); - return (e.default = t), e; - }; - Object.defineProperty(e, "__esModule", { value: !0 }); - var a, - c = n(1), - d = n(24), - p = n(26), - u = s(n(6)), - _ = n(67), - l = s(n(12)), - f = n(27), - h = n(3), - C = n(4), - y = n(29), - E = n(72), - g = n(73), - m = n(76), - A = - ((a = c.MDCComponent), - r(v, a), - (v.attachTo = function(t) { - return new v(t); - }), - (v.prototype.initialize = function(t, e, n, i, r, o) { - if ( - (void 0 === t && - (t = function(t) { - return new d.MDCFloatingLabel(t); - }), - void 0 === e && - (e = function(t) { - return new p.MDCLineRipple(t); - }), - void 0 === n && - (n = function(t) { - return new f.MDCNotchedOutline(t); - }), - void 0 === i && - (i = function(t) { - return new _.MDCMenu(t); - }), - void 0 === r && - (r = function(t) { - return new m.MDCSelectIcon(t); - }), - void 0 === o && - (o = function(t) { - return new g.MDCSelectHelperText(t); - }), - (this.selectAnchor = this.root_.querySelector( - y.strings.SELECT_ANCHOR_SELECTOR - )), - (this.selectedText = this.root_.querySelector( - y.strings.SELECTED_TEXT_SELECTOR - )), - !this.selectedText) - ) - throw new Error( - "MDCSelect: Missing required element: The following selector must be present: '" + - y.strings.SELECTED_TEXT_SELECTOR + - "'" - ); - if (this.selectAnchor.hasAttribute(y.strings.ARIA_CONTROLS)) { - var s = document.getElementById( - this.selectAnchor.getAttribute(y.strings.ARIA_CONTROLS) - ); - s && (this.helperText = o(s)); - } - this.menuSetup(i); - var a = this.root_.querySelector(y.strings.LABEL_SELECTOR); - this.label = a ? t(a) : null; - var c = this.root_.querySelector(y.strings.LINE_RIPPLE_SELECTOR); - this.lineRipple = c ? e(c) : null; - var u = this.root_.querySelector(y.strings.OUTLINE_SELECTOR); - this.outline = u ? n(u) : null; - var l = this.root_.querySelector(y.strings.LEADING_ICON_SELECTOR); - l && (this.leadingIcon = r(l)), - this.root_.classList.contains(y.cssClasses.OUTLINED) || - (this.ripple = this.createRipple()); - }), - (v.prototype.initialSyncWithDOM = function() { - var e = this; - (this.handleChange = function() { - e.foundation_.handleChange(); - }), - (this.handleFocus = function() { - e.foundation_.handleFocus(); - }), - (this.handleBlur = function() { - e.foundation_.handleBlur(); - }), - (this.handleClick = function(t) { - e.selectAnchor.focus(), - e.foundation_.handleClick(e.getNormalizedXCoordinate(t)); - }), - (this.handleKeydown = function(t) { - e.foundation_.handleKeydown(t); - }), - (this.handleMenuItemAction = function(t) { - e.foundation_.handleMenuItemAction(t.detail.index); - }), - (this.handleMenuOpened = function() { - e.foundation_.handleMenuOpened(); - }), - (this.handleMenuClosed = function() { - e.foundation_.handleMenuClosed(); - }), - this.selectAnchor.addEventListener("focus", this.handleFocus), - this.selectAnchor.addEventListener("blur", this.handleBlur), - this.selectAnchor.addEventListener("click", this.handleClick), - this.selectAnchor.addEventListener( - "keydown", - this.handleKeydown - ), - this.menu.listen(u.strings.CLOSED_EVENT, this.handleMenuClosed), - this.menu.listen(u.strings.OPENED_EVENT, this.handleMenuOpened), - this.menu.listen( - l.strings.SELECTED_EVENT, - this.handleMenuItemAction - ), - this.foundation_.init(); - }), - (v.prototype.destroy = function() { - this.selectAnchor.removeEventListener( - "change", - this.handleChange - ), - this.selectAnchor.removeEventListener( - "focus", - this.handleFocus - ), - this.selectAnchor.removeEventListener("blur", this.handleBlur), - this.selectAnchor.removeEventListener( - "keydown", - this.handleKeydown - ), - this.selectAnchor.removeEventListener( - "click", - this.handleClick - ), - this.menu.unlisten( - u.strings.CLOSED_EVENT, - this.handleMenuClosed - ), - this.menu.unlisten( - u.strings.OPENED_EVENT, - this.handleMenuOpened - ), - this.menu.unlisten( - l.strings.SELECTED_EVENT, - this.handleMenuItemAction - ), - this.menu.destroy(), - this.ripple && this.ripple.destroy(), - this.outline && this.outline.destroy(), - this.leadingIcon && this.leadingIcon.destroy(), - this.helperText && this.helperText.destroy(), - a.prototype.destroy.call(this); - }), - Object.defineProperty(v.prototype, "value", { - get: function() { - return this.foundation_.getValue(); - }, - set: function(t) { - this.foundation_.setValue(t); - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(v.prototype, "selectedIndex", { - get: function() { - return this.foundation_.getSelectedIndex(); - }, - set: function(t) { - this.foundation_.setSelectedIndex(t, !0); - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(v.prototype, "disabled", { - get: function() { - return this.foundation_.getDisabled(); - }, - set: function(t) { - this.foundation_.setDisabled(t); - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(v.prototype, "leadingIconAriaLabel", { - set: function(t) { - this.foundation_.setLeadingIconAriaLabel(t); - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(v.prototype, "leadingIconContent", { - set: function(t) { - this.foundation_.setLeadingIconContent(t); - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(v.prototype, "helperTextContent", { - set: function(t) { - this.foundation_.setHelperTextContent(t); - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(v.prototype, "valid", { - get: function() { - return this.foundation_.isValid(); - }, - set: function(t) { - this.foundation_.setValid(t); - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(v.prototype, "required", { - get: function() { - return this.foundation_.getRequired(); - }, - set: function(t) { - this.foundation_.setRequired(t); - }, - enumerable: !0, - configurable: !0 - }), - (v.prototype.layout = function() { - this.foundation_.layout(); - }), - (v.prototype.getDefaultFoundation = function() { - var t = o( - o( - o( - o({}, this.getSelectAdapterMethods()), - this.getCommonAdapterMethods() - ), - this.getOutlineAdapterMethods() - ), - this.getLabelAdapterMethods() - ); - return new E.MDCSelectFoundation(t, this.getFoundationMap()); - }), - (v.prototype.menuSetup = function(t) { - (this.menuElement = this.root_.querySelector( - y.strings.MENU_SELECTOR - )), - (this.menu = t(this.menuElement)); - }), - (v.prototype.createRipple = function() { - var n = this, - t = o( - o( - {}, - h.MDCRipple.createAdapter({ root_: this.selectAnchor }) - ), - { - registerInteractionHandler: function(t, e) { - n.selectAnchor.addEventListener(t, e); - }, - deregisterInteractionHandler: function(t, e) { - n.selectAnchor.removeEventListener(t, e); - } - } - ); - return new h.MDCRipple( - this.selectAnchor, - new C.MDCRippleFoundation(t) - ); - }), - (v.prototype.getSelectAdapterMethods = function() { - var i = this; - return { - getSelectedMenuItem: function() { - return i.menuElement.querySelector( - y.strings.SELECTED_ITEM_SELECTOR - ); - }, - getMenuItemAttr: function(t, e) { - return t.getAttribute(e); - }, - setSelectedText: function(t) { - i.selectedText.value = t; - }, - isSelectAnchorFocused: function() { - return document.activeElement === i.selectAnchor; - }, - getSelectAnchorAttr: function(t) { - return i.selectAnchor.getAttribute(t); - }, - setSelectAnchorAttr: function(t, e) { - i.selectAnchor.setAttribute(t, e); - }, - openMenu: function() { - i.menu.open = !0; - }, - closeMenu: function() { - i.menu.open = !1; - }, - getAnchorElement: function() { - return i.root_.querySelector( - y.strings.SELECT_ANCHOR_SELECTOR - ); - }, - setMenuAnchorElement: function(t) { - i.menu.setAnchorElement(t); - }, - setMenuAnchorCorner: function(t) { - i.menu.setAnchorCorner(t); - }, - setMenuWrapFocus: function(t) { - i.menu.wrapFocus = t; - }, - setAttributeAtIndex: function(t, e, n) { - i.menu.items[t].setAttribute(e, n); - }, - removeAttributeAtIndex: function(t, e) { - i.menu.items[t].removeAttribute(e); - }, - focusMenuItemAtIndex: function(t) { - i.menu.items[t].focus(); - }, - getMenuItemCount: function() { - return i.menu.items.length; - }, - getMenuItemValues: function() { - return i.menu.items.map(function(t) { - return t.getAttribute(y.strings.VALUE_ATTR) || ""; - }); - }, - getMenuItemTextAtIndex: function(t) { - return i.menu.items[t].textContent; - }, - addClassAtIndex: function(t, e) { - i.menu.items[t].classList.add(e); - }, - removeClassAtIndex: function(t, e) { - i.menu.items[t].classList.remove(e); - } - }; - }), - (v.prototype.getCommonAdapterMethods = function() { - var n = this; - return { - addClass: function(t) { - n.root_.classList.add(t); - }, - removeClass: function(t) { - n.root_.classList.remove(t); - }, - hasClass: function(t) { - return n.root_.classList.contains(t); - }, - setRippleCenter: function(t) { - n.lineRipple && n.lineRipple.setRippleCenter(t); - }, - activateBottomLine: function() { - n.lineRipple && n.lineRipple.activate(); - }, - deactivateBottomLine: function() { - n.lineRipple && n.lineRipple.deactivate(); - }, - notifyChange: function(t) { - var e = n.selectedIndex; - n.emit(y.strings.CHANGE_EVENT, { value: t, index: e }, !0); - } - }; - }), - (v.prototype.getOutlineAdapterMethods = function() { - var e = this; - return { - hasOutline: function() { - return Boolean(e.outline); - }, - notchOutline: function(t) { - e.outline && e.outline.notch(t); - }, - closeOutline: function() { - e.outline && e.outline.closeNotch(); - } - }; - }), - (v.prototype.getLabelAdapterMethods = function() { - var e = this; - return { - hasLabel: function() { - return !!e.label; - }, - floatLabel: function(t) { - e.label && e.label.float(t); - }, - getLabelWidth: function() { - return e.label ? e.label.getWidth() : 0; - } - }; - }), - (v.prototype.getNormalizedXCoordinate = function(t) { - var e = t.target.getBoundingClientRect(); - return ( - (this.isTouchEvent(t) ? t.touches[0].clientX : t.clientX) - - e.left - ); - }), - (v.prototype.isTouchEvent = function(t) { - return Boolean(t.touches); - }), - (v.prototype.getFoundationMap = function() { - return { - helperText: this.helperText - ? this.helperText.foundation - : void 0, - leadingIcon: this.leadingIcon - ? this.leadingIcon.foundation - : void 0 - }; - }), - v); - function v() { - return (null !== a && a.apply(this, arguments)) || this; - } - e.MDCSelect = A; - }, - function(t, n, e) { - "use strict"; - function i(t) { - for (var e in t) n.hasOwnProperty(e) || (n[e] = t[e]); - } - Object.defineProperty(n, "__esModule", { value: !0 }), - i(e(73)), - i(e(74)); - var r = e(75); - (n.helperTextCssClasses = r.cssClasses), - (n.helperTextStrings = r.strings); - }, - function(t, n, e) { - "use strict"; - function i(t) { - for (var e in t) n.hasOwnProperty(e) || (n[e] = t[e]); - } - Object.defineProperty(n, "__esModule", { value: !0 }), - i(e(76)), - i(e(77)); - var r = e(78); - n.iconStrings = r.strings; - }, - function(t, n, e) { - "use strict"; - function i(t) { - for (var e in t) n.hasOwnProperty(e) || (n[e] = t[e]); - } - Object.defineProperty(n, "__esModule", { value: !0 }), - i(e(146)), - i(e(30)), - i(e(79)); - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }); - Object.defineProperty(e, "__esModule", { value: !0 }); - var o, - s = n(1), - a = n(5), - c = n(30), - u = n(79), - l = - ((o = s.MDCComponent), - r(d, o), - (d.attachTo = function(t) { - return new d(t); - }), - Object.defineProperty(d.prototype, "value", { - get: function() { - return this.foundation_.getValue(); - }, - set: function(t) { - this.foundation_.setValue(t); - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(d.prototype, "min", { - get: function() { - return this.foundation_.getMin(); - }, - set: function(t) { - this.foundation_.setMin(t); - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(d.prototype, "max", { - get: function() { - return this.foundation_.getMax(); - }, - set: function(t) { - this.foundation_.setMax(t); - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(d.prototype, "step", { - get: function() { - return this.foundation_.getStep(); - }, - set: function(t) { - this.foundation_.setStep(t); - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(d.prototype, "disabled", { - get: function() { - return this.foundation_.isDisabled(); - }, - set: function(t) { - this.foundation_.setDisabled(t); - }, - enumerable: !0, - configurable: !0 - }), - (d.prototype.initialize = function() { - (this.thumbContainer_ = this.root_.querySelector( - c.strings.THUMB_CONTAINER_SELECTOR - )), - (this.track_ = this.root_.querySelector( - c.strings.TRACK_SELECTOR - )), - (this.pinValueMarker_ = this.root_.querySelector( - c.strings.PIN_VALUE_MARKER_SELECTOR - )), - (this.trackMarkerContainer_ = this.root_.querySelector( - c.strings.TRACK_MARKER_CONTAINER_SELECTOR - )); - }), - (d.prototype.getDefaultFoundation = function() { - var o = this, - t = { - hasClass: function(t) { - return o.root_.classList.contains(t); - }, - addClass: function(t) { - return o.root_.classList.add(t); - }, - removeClass: function(t) { - return o.root_.classList.remove(t); - }, - getAttribute: function(t) { - return o.root_.getAttribute(t); - }, - setAttribute: function(t, e) { - return o.root_.setAttribute(t, e); - }, - removeAttribute: function(t) { - return o.root_.removeAttribute(t); - }, - computeBoundingRect: function() { - return o.root_.getBoundingClientRect(); - }, - getTabIndex: function() { - return o.root_.tabIndex; - }, - registerInteractionHandler: function(t, e) { - return o.listen(t, e, a.applyPassive()); - }, - deregisterInteractionHandler: function(t, e) { - return o.unlisten(t, e, a.applyPassive()); - }, - registerThumbContainerInteractionHandler: function(t, e) { - o.thumbContainer_.addEventListener(t, e, a.applyPassive()); - }, - deregisterThumbContainerInteractionHandler: function(t, e) { - o.thumbContainer_.removeEventListener( - t, - e, - a.applyPassive() - ); - }, - registerBodyInteractionHandler: function(t, e) { - return document.body.addEventListener(t, e); - }, - deregisterBodyInteractionHandler: function(t, e) { - return document.body.removeEventListener(t, e); - }, - registerResizeHandler: function(t) { - return window.addEventListener("resize", t); - }, - deregisterResizeHandler: function(t) { - return window.removeEventListener("resize", t); - }, - notifyInput: function() { - return o.emit(c.strings.INPUT_EVENT, o); - }, - notifyChange: function() { - return o.emit(c.strings.CHANGE_EVENT, o); - }, - setThumbContainerStyleProperty: function(t, e) { - o.thumbContainer_.style.setProperty(t, e); - }, - setTrackStyleProperty: function(t, e) { - return o.track_.style.setProperty(t, e); - }, - setMarkerValue: function(t) { - return (o.pinValueMarker_.innerText = t.toLocaleString()); - }, - setTrackMarkers: function(t, e, n) { - var i = t.toLocaleString(), - r = - "linear-gradient(to right, currentColor 2px, transparent 0) 0 center / calc((100% - 2px) / ((" + - e.toLocaleString() + - " - " + - n.toLocaleString() + - ") / " + - i + - ")) 100% repeat-x"; - o.trackMarkerContainer_.style.setProperty("background", r); - }, - isRTL: function() { - return "rtl" === getComputedStyle(o.root_).direction; - } - }; - return new u.MDCSliderFoundation(t); - }), - (d.prototype.initialSyncWithDOM = function() { - var t = this.parseFloat_( - this.root_.getAttribute(c.strings.ARIA_VALUENOW), - this.value - ), - e = this.parseFloat_( - this.root_.getAttribute(c.strings.ARIA_VALUEMIN), - this.min - ), - n = this.parseFloat_( - this.root_.getAttribute(c.strings.ARIA_VALUEMAX), - this.max - ); - e >= this.max - ? ((this.max = n), (this.min = e)) - : ((this.min = e), (this.max = n)), - (this.step = this.parseFloat_( - this.root_.getAttribute(c.strings.STEP_DATA_ATTR), - this.step - )), - (this.value = t), - (this.disabled = - this.root_.hasAttribute(c.strings.ARIA_DISABLED) && - "false" !== this.root_.getAttribute(c.strings.ARIA_DISABLED)), - this.foundation_.setupTrackMarker(); - }), - (d.prototype.layout = function() { - this.foundation_.layout(); - }), - (d.prototype.stepUp = function(t) { - void 0 === t && (t = this.step || 1), (this.value += t); - }), - (d.prototype.stepDown = function(t) { - void 0 === t && (t = this.step || 1), (this.value -= t); - }), - (d.prototype.parseFloat_ = function(t, e) { - var n = parseFloat(t); - return "number" == typeof n && isFinite(n) ? n : e; - }), - d); - function d() { - return (null !== o && o.apply(this, arguments)) || this; - } - e.MDCSlider = l; - }, - function(t, n, e) { - "use strict"; - function i(t) { - for (var e in t) n.hasOwnProperty(e) || (n[e] = t[e]); - } - var r = - (this && this.__importStar) || - function(t) { - if (t && t.__esModule) return t; - var e = {}; - if (null != t) - for (var n in t) - Object.hasOwnProperty.call(t, n) && (e[n] = t[n]); - return (e.default = t), e; - }; - Object.defineProperty(n, "__esModule", { value: !0 }); - var o = r(e(80)); - (n.util = o), i(e(148)), i(e(13)), i(e(81)); - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }), - o = - (this && this.__importStar) || - function(t) { - if (t && t.__esModule) return t; - var e = {}; - if (null != t) - for (var n in t) - Object.hasOwnProperty.call(t, n) && (e[n] = t[n]); - return (e.default = t), e; - }; - Object.defineProperty(e, "__esModule", { value: !0 }); - var s, - a = n(1), - c = n(2), - u = n(13), - l = n(81), - d = o(n(80)), - p = u.strings.SURFACE_SELECTOR, - _ = u.strings.LABEL_SELECTOR, - f = u.strings.ACTION_SELECTOR, - h = u.strings.DISMISS_SELECTOR, - C = u.strings.OPENING_EVENT, - y = u.strings.OPENED_EVENT, - E = u.strings.CLOSING_EVENT, - g = u.strings.CLOSED_EVENT, - m = - ((s = a.MDCComponent), - r(A, s), - (A.attachTo = function(t) { - return new A(t); - }), - (A.prototype.initialize = function(t) { - void 0 === t && - (t = function() { - return d.announce; - }), - (this.announce_ = t()); - }), - (A.prototype.initialSyncWithDOM = function() { - var n = this; - (this.surfaceEl_ = this.root_.querySelector(p)), - (this.labelEl_ = this.root_.querySelector(_)), - (this.actionEl_ = this.root_.querySelector(f)), - (this.handleKeyDown_ = function(t) { - return n.foundation_.handleKeyDown(t); - }), - (this.handleSurfaceClick_ = function(t) { - var e = t.target; - n.isActionButton_(e) - ? n.foundation_.handleActionButtonClick(t) - : n.isActionIcon_(e) && - n.foundation_.handleActionIconClick(t); - }), - this.registerKeyDownHandler_(this.handleKeyDown_), - this.registerSurfaceClickHandler_(this.handleSurfaceClick_); - }), - (A.prototype.destroy = function() { - s.prototype.destroy.call(this), - this.deregisterKeyDownHandler_(this.handleKeyDown_), - this.deregisterSurfaceClickHandler_(this.handleSurfaceClick_); - }), - (A.prototype.open = function() { - this.foundation_.open(); - }), - (A.prototype.close = function(t) { - void 0 === t && (t = ""), this.foundation_.close(t); - }), - (A.prototype.getDefaultFoundation = function() { - var e = this, - t = { - addClass: function(t) { - return e.root_.classList.add(t); - }, - announce: function() { - return e.announce_(e.labelEl_); - }, - notifyClosed: function(t) { - return e.emit(g, t ? { reason: t } : {}); - }, - notifyClosing: function(t) { - return e.emit(E, t ? { reason: t } : {}); - }, - notifyOpened: function() { - return e.emit(y, {}); - }, - notifyOpening: function() { - return e.emit(C, {}); - }, - removeClass: function(t) { - return e.root_.classList.remove(t); - } - }; - return new l.MDCSnackbarFoundation(t); - }), - Object.defineProperty(A.prototype, "timeoutMs", { - get: function() { - return this.foundation_.getTimeoutMs(); - }, - set: function(t) { - this.foundation_.setTimeoutMs(t); - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(A.prototype, "closeOnEscape", { - get: function() { - return this.foundation_.getCloseOnEscape(); - }, - set: function(t) { - this.foundation_.setCloseOnEscape(t); - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(A.prototype, "isOpen", { - get: function() { - return this.foundation_.isOpen(); - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(A.prototype, "labelText", { - get: function() { - return this.labelEl_.textContent; - }, - set: function(t) { - this.labelEl_.textContent = t; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(A.prototype, "actionButtonText", { - get: function() { - return this.actionEl_.textContent; - }, - set: function(t) { - this.actionEl_.textContent = t; - }, - enumerable: !0, - configurable: !0 - }), - (A.prototype.registerKeyDownHandler_ = function(t) { - this.listen("keydown", t); - }), - (A.prototype.deregisterKeyDownHandler_ = function(t) { - this.unlisten("keydown", t); - }), - (A.prototype.registerSurfaceClickHandler_ = function(t) { - this.surfaceEl_.addEventListener("click", t); - }), - (A.prototype.deregisterSurfaceClickHandler_ = function(t) { - this.surfaceEl_.removeEventListener("click", t); - }), - (A.prototype.isActionButton_ = function(t) { - return Boolean(c.closest(t, f)); - }), - (A.prototype.isActionIcon_ = function(t) { - return Boolean(c.closest(t, h)); - }), - A); - function A() { - return (null !== s && s.apply(this, arguments)) || this; - } - e.MDCSnackbar = m; - }, - function(t, n, e) { - "use strict"; - function i(t) { - for (var e in t) n.hasOwnProperty(e) || (n[e] = t[e]); - } - Object.defineProperty(n, "__esModule", { value: !0 }), - i(e(150)), - i(e(83)), - i(e(82)); - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }), - o = - (this && this.__assign) || - function() { - return (o = - Object.assign || - function(t) { - for (var e, n = 1, i = arguments.length; n < i; n++) - for (var r in (e = arguments[n])) - Object.prototype.hasOwnProperty.call(e, r) && - (t[r] = e[r]); - return t; - }).apply(this, arguments); - }, - s = - (this && this.__read) || - function(t, e) { - var n = "function" == typeof Symbol && t[Symbol.iterator]; - if (!n) return t; - var i, - r, - o = n.call(t), - s = []; - try { - for (; (void 0 === e || 0 < e--) && !(i = o.next()).done; ) - s.push(i.value); - } catch (t) { - r = { error: t }; - } finally { - try { - i && !i.done && (n = o.return) && n.call(o); - } finally { - if (r) throw r.error; - } - } - return s; - }, - a = - (this && this.__spread) || - function() { - for (var t = [], e = 0; e < arguments.length; e++) - t = t.concat(s(arguments[e])); - return t; - }; - Object.defineProperty(e, "__esModule", { value: !0 }); - var c, - u = n(1), - l = n(5), - d = n(2), - p = n(3), - _ = n(4), - f = n(82), - h = - ((c = u.MDCComponent), - r(C, c), - (C.attachTo = function(t) { - return new C(t); - }), - (C.prototype.destroy = function() { - c.prototype.destroy.call(this), - this.ripple_.destroy(), - this.nativeControl_.removeEventListener( - "change", - this.changeHandler_ - ); - }), - (C.prototype.initialSyncWithDOM = function() { - var i = this; - (this.changeHandler_ = function() { - for (var t, e = [], n = 0; n < arguments.length; n++) - e[n] = arguments[n]; - return (t = i.foundation_).handleChange.apply(t, a(e)); - }), - this.nativeControl_.addEventListener( - "change", - this.changeHandler_ - ), - (this.checked = this.checked); - }), - (C.prototype.getDefaultFoundation = function() { - var n = this, - t = { - addClass: function(t) { - return n.root_.classList.add(t); - }, - removeClass: function(t) { - return n.root_.classList.remove(t); - }, - setNativeControlChecked: function(t) { - return (n.nativeControl_.checked = t); - }, - setNativeControlDisabled: function(t) { - return (n.nativeControl_.disabled = t); - }, - setNativeControlAttr: function(t, e) { - return n.nativeControl_.setAttribute(t, e); - } - }; - return new f.MDCSwitchFoundation(t); - }), - Object.defineProperty(C.prototype, "ripple", { - get: function() { - return this.ripple_; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(C.prototype, "checked", { - get: function() { - return this.nativeControl_.checked; - }, - set: function(t) { - this.foundation_.setChecked(t); - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(C.prototype, "disabled", { - get: function() { - return this.nativeControl_.disabled; - }, - set: function(t) { - this.foundation_.setDisabled(t); - }, - enumerable: !0, - configurable: !0 - }), - (C.prototype.createRipple_ = function() { - var n = this, - t = f.MDCSwitchFoundation.strings.RIPPLE_SURFACE_SELECTOR, - i = this.root_.querySelector(t), - e = o(o({}, p.MDCRipple.createAdapter(this)), { - addClass: function(t) { - return i.classList.add(t); - }, - computeBoundingRect: function() { - return i.getBoundingClientRect(); - }, - deregisterInteractionHandler: function(t, e) { - n.nativeControl_.removeEventListener( - t, - e, - l.applyPassive() - ); - }, - isSurfaceActive: function() { - return d.matches(n.nativeControl_, ":active"); - }, - isUnbounded: function() { - return !0; - }, - registerInteractionHandler: function(t, e) { - n.nativeControl_.addEventListener(t, e, l.applyPassive()); - }, - removeClass: function(t) { - i.classList.remove(t); - }, - updateCssVariable: function(t, e) { - i.style.setProperty(t, e); - } - }); - return new p.MDCRipple(this.root_, new _.MDCRippleFoundation(e)); - }), - Object.defineProperty(C.prototype, "nativeControl_", { - get: function() { - var t = f.MDCSwitchFoundation.strings.NATIVE_CONTROL_SELECTOR; - return this.root_.querySelector(t); - }, - enumerable: !0, - configurable: !0 - }), - C); - function C() { - var t = (null !== c && c.apply(this, arguments)) || this; - return (t.ripple_ = t.createRipple_()), t; - } - e.MDCSwitch = h; - }, - function(t, n, e) { - "use strict"; - function i(t) { - for (var e in t) n.hasOwnProperty(e) || (n[e] = t[e]); - } - Object.defineProperty(n, "__esModule", { value: !0 }), - i(e(152)), - i(e(94)), - i(e(93)); - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }); - Object.defineProperty(e, "__esModule", { value: !0 }); - var o, - s = n(1), - a = n(84), - c = n(87), - u = n(33), - l = n(93), - d = l.MDCTabBarFoundation.strings, - p = 0, - _ = - ((o = s.MDCComponent), - r(f, o), - (f.attachTo = function(t) { - return new f(t); - }), - Object.defineProperty(f.prototype, "focusOnActivate", { - set: function(e) { - this.tabList_.forEach(function(t) { - return (t.focusOnActivate = e); - }); - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(f.prototype, "useAutomaticActivation", { - set: function(t) { - this.foundation_.setUseAutomaticActivation(t); - }, - enumerable: !0, - configurable: !0 - }), - (f.prototype.initialize = function(t, e) { - void 0 === t && - (t = function(t) { - return new c.MDCTab(t); - }), - void 0 === e && - (e = function(t) { - return new a.MDCTabScroller(t); - }), - (this.tabList_ = this.instantiateTabs_(t)), - (this.tabScroller_ = this.instantiateTabScroller_(e)); - }), - (f.prototype.initialSyncWithDOM = function() { - var e = this; - (this.handleTabInteraction_ = function(t) { - return e.foundation_.handleTabInteraction(t); - }), - (this.handleKeyDown_ = function(t) { - return e.foundation_.handleKeyDown(t); - }), - this.listen( - u.MDCTabFoundation.strings.INTERACTED_EVENT, - this.handleTabInteraction_ - ), - this.listen("keydown", this.handleKeyDown_); - for (var t = 0; t < this.tabList_.length; t++) - if (this.tabList_[t].active) { - this.scrollIntoView(t); - break; - } - }), - (f.prototype.destroy = function() { - o.prototype.destroy.call(this), - this.unlisten( - u.MDCTabFoundation.strings.INTERACTED_EVENT, - this.handleTabInteraction_ - ), - this.unlisten("keydown", this.handleKeyDown_), - this.tabList_.forEach(function(t) { - return t.destroy(); - }), - this.tabScroller_ && this.tabScroller_.destroy(); - }), - (f.prototype.getDefaultFoundation = function() { - var n = this, - t = { - scrollTo: function(t) { - return n.tabScroller_.scrollTo(t); - }, - incrementScroll: function(t) { - return n.tabScroller_.incrementScroll(t); - }, - getScrollPosition: function() { - return n.tabScroller_.getScrollPosition(); - }, - getScrollContentWidth: function() { - return n.tabScroller_.getScrollContentWidth(); - }, - getOffsetWidth: function() { - return n.root_.offsetWidth; - }, - isRTL: function() { - return ( - "rtl" === - window - .getComputedStyle(n.root_) - .getPropertyValue("direction") - ); - }, - setActiveTab: function(t) { - return n.foundation_.activateTab(t); - }, - activateTabAtIndex: function(t, e) { - return n.tabList_[t].activate(e); - }, - deactivateTabAtIndex: function(t) { - return n.tabList_[t].deactivate(); - }, - focusTabAtIndex: function(t) { - return n.tabList_[t].focus(); - }, - getTabIndicatorClientRectAtIndex: function(t) { - return n.tabList_[t].computeIndicatorClientRect(); - }, - getTabDimensionsAtIndex: function(t) { - return n.tabList_[t].computeDimensions(); - }, - getPreviousActiveTabIndex: function() { - for (var t = 0; t < n.tabList_.length; t++) - if (n.tabList_[t].active) return t; - return -1; - }, - getFocusedTabIndex: function() { - var t = n.getTabElements_(), - e = document.activeElement; - return t.indexOf(e); - }, - getIndexOfTabById: function(t) { - for (var e = 0; e < n.tabList_.length; e++) - if (n.tabList_[e].id === t) return e; - return -1; - }, - getTabListLength: function() { - return n.tabList_.length; - }, - notifyTabActivated: function(t) { - return n.emit(d.TAB_ACTIVATED_EVENT, { index: t }, !0); - } - }; - return new l.MDCTabBarFoundation(t); - }), - (f.prototype.activateTab = function(t) { - this.foundation_.activateTab(t); - }), - (f.prototype.scrollIntoView = function(t) { - this.foundation_.scrollIntoView(t); - }), - (f.prototype.getTabElements_ = function() { - return [].slice.call(this.root_.querySelectorAll(d.TAB_SELECTOR)); - }), - (f.prototype.instantiateTabs_ = function(e) { - return this.getTabElements_().map(function(t) { - return (t.id = t.id || "mdc-tab-" + ++p), e(t); - }); - }), - (f.prototype.instantiateTabScroller_ = function(t) { - var e = this.root_.querySelector(d.TAB_SCROLLER_SELECTOR); - return e ? t(e) : null; - }), - f); - function f() { - return (null !== o && o.apply(this, arguments)) || this; - } - e.MDCTabBar = _; - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }); - Object.defineProperty(e, "__esModule", { value: !0 }); - var o, - s = n(32), - a = - ((o = s.MDCTabScrollerRTL), - r(c, o), - (c.prototype.getScrollPositionRTL = function() { - var t = this.adapter_.getScrollAreaScrollLeft(), - e = this.calculateScrollEdges_().right; - return Math.round(e - t); - }), - (c.prototype.scrollToRTL = function(t) { - var e = this.calculateScrollEdges_(), - n = this.adapter_.getScrollAreaScrollLeft(), - i = this.clampScrollValue_(e.right - t); - return { finalScrollPosition: i, scrollDelta: i - n }; - }), - (c.prototype.incrementScrollRTL = function(t) { - var e = this.adapter_.getScrollAreaScrollLeft(), - n = this.clampScrollValue_(e - t); - return { finalScrollPosition: n, scrollDelta: n - e }; - }), - (c.prototype.getAnimatingScrollPosition = function(t) { - return t; - }), - (c.prototype.calculateScrollEdges_ = function() { - return { - left: 0, - right: - this.adapter_.getScrollContentOffsetWidth() - - this.adapter_.getScrollAreaOffsetWidth() - }; - }), - (c.prototype.clampScrollValue_ = function(t) { - var e = this.calculateScrollEdges_(); - return Math.min(Math.max(e.left, t), e.right); - }), - c); - function c() { - return (null !== o && o.apply(this, arguments)) || this; - } - (e.MDCTabScrollerRTLDefault = a), (e.default = a); - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }); - Object.defineProperty(e, "__esModule", { value: !0 }); - var o, - s = n(32), - a = - ((o = s.MDCTabScrollerRTL), - r(c, o), - (c.prototype.getScrollPositionRTL = function(t) { - var e = this.adapter_.getScrollAreaScrollLeft(); - return Math.round(t - e); - }), - (c.prototype.scrollToRTL = function(t) { - var e = this.adapter_.getScrollAreaScrollLeft(), - n = this.clampScrollValue_(-t); - return { finalScrollPosition: n, scrollDelta: n - e }; - }), - (c.prototype.incrementScrollRTL = function(t) { - var e = this.adapter_.getScrollAreaScrollLeft(), - n = this.clampScrollValue_(e - t); - return { finalScrollPosition: n, scrollDelta: n - e }; - }), - (c.prototype.getAnimatingScrollPosition = function(t, e) { - return t - e; - }), - (c.prototype.calculateScrollEdges_ = function() { - var t = this.adapter_.getScrollContentOffsetWidth(); - return { - left: this.adapter_.getScrollAreaOffsetWidth() - t, - right: 0 - }; - }), - (c.prototype.clampScrollValue_ = function(t) { - var e = this.calculateScrollEdges_(); - return Math.max(Math.min(e.right, t), e.left); - }), - c); - function c() { - return (null !== o && o.apply(this, arguments)) || this; - } - (e.MDCTabScrollerRTLNegative = a), (e.default = a); - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }); - Object.defineProperty(e, "__esModule", { value: !0 }); - var o, - s = n(32), - a = - ((o = s.MDCTabScrollerRTL), - r(c, o), - (c.prototype.getScrollPositionRTL = function(t) { - var e = this.adapter_.getScrollAreaScrollLeft(); - return Math.round(e - t); - }), - (c.prototype.scrollToRTL = function(t) { - var e = this.adapter_.getScrollAreaScrollLeft(), - n = this.clampScrollValue_(t); - return { finalScrollPosition: n, scrollDelta: e - n }; - }), - (c.prototype.incrementScrollRTL = function(t) { - var e = this.adapter_.getScrollAreaScrollLeft(), - n = this.clampScrollValue_(e + t); - return { finalScrollPosition: n, scrollDelta: e - n }; - }), - (c.prototype.getAnimatingScrollPosition = function(t, e) { - return t + e; - }), - (c.prototype.calculateScrollEdges_ = function() { - return { - left: - this.adapter_.getScrollContentOffsetWidth() - - this.adapter_.getScrollAreaOffsetWidth(), - right: 0 - }; - }), - (c.prototype.clampScrollValue_ = function(t) { - var e = this.calculateScrollEdges_(); - return Math.min(Math.max(e.right, t), e.left); - }), - c); - function c() { - return (null !== o && o.apply(this, arguments)) || this; - } - (e.MDCTabScrollerRTLReverse = a), (e.default = a); - }, - function(t, n, e) { - "use strict"; - function i(t) { - for (var e in t) n.hasOwnProperty(e) || (n[e] = t[e]); - } - Object.defineProperty(n, "__esModule", { value: !0 }), - i(e(88)), - i(e(90)), - i(e(14)), - i(e(89)), - i(e(91)); - }, - function(t, n, e) { - "use strict"; - function i(t) { - for (var e in t) n.hasOwnProperty(e) || (n[e] = t[e]); - } - var r = - (this && this.__importStar) || - function(t) { - if (t && t.__esModule) return t; - var e = {}; - if (null != t) - for (var n in t) - Object.hasOwnProperty.call(t, n) && (e[n] = t[n]); - return (e.default = t), e; - }; - Object.defineProperty(n, "__esModule", { value: !0 }); - var o = r(e(86)); - (n.util = o), i(e(84)), i(e(31)), i(e(85)); - }, - function(t, n, e) { - "use strict"; - function i(t) { - for (var e in t) n.hasOwnProperty(e) || (n[e] = t[e]); - } - Object.defineProperty(n, "__esModule", { value: !0 }), - i(e(87)), - i(e(92)), - i(e(33)); - }, - function(t, n, e) { - "use strict"; - function i(t) { - for (var e in t) n.hasOwnProperty(e) || (n[e] = t[e]); - } - Object.defineProperty(n, "__esModule", { value: !0 }), - i(e(160)), - i(e(35)), - i(e(97)), - i(e(161)), - i(e(162)), - i(e(163)); - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }), - o = - (this && this.__assign) || - function() { - return (o = - Object.assign || - function(t) { - for (var e, n = 1, i = arguments.length; n < i; n++) - for (var r in (e = arguments[n])) - Object.prototype.hasOwnProperty.call(e, r) && - (t[r] = e[r]); - return t; - }).apply(this, arguments); - }, - s = - (this && this.__importStar) || - function(t) { - if (t && t.__esModule) return t; - var e = {}; - if (null != t) - for (var n in t) - Object.hasOwnProperty.call(t, n) && (e[n] = t[n]); - return (e.default = t), e; - }; - Object.defineProperty(e, "__esModule", { value: !0 }); - var a, - c = n(1), - u = n(5), - l = s(n(2)), - E = n(24), - g = n(26), - m = n(27), - A = n(3), - d = n(4), - v = n(95), - b = n(34), - O = n(35), - p = n(97), - T = n(98), - I = n(36), - S = n(100), - _ = - ((a = c.MDCComponent), - r(f, a), - (f.attachTo = function(t) { - return new f(t); - }), - (f.prototype.initialize = function(t, e, n, i, r, o, s) { - void 0 === t && - (t = function(t, e) { - return new A.MDCRipple(t, e); - }), - void 0 === e && - (e = function(t) { - return new g.MDCLineRipple(t); - }), - void 0 === n && - (n = function(t) { - return new T.MDCTextFieldHelperText(t); - }), - void 0 === i && - (i = function(t) { - return new v.MDCTextFieldCharacterCounter(t); - }), - void 0 === r && - (r = function(t) { - return new S.MDCTextFieldIcon(t); - }), - void 0 === o && - (o = function(t) { - return new E.MDCFloatingLabel(t); - }), - void 0 === s && - (s = function(t) { - return new m.MDCNotchedOutline(t); - }), - (this.input_ = this.root_.querySelector( - O.strings.INPUT_SELECTOR - )); - var a = this.root_.querySelector(O.strings.LABEL_SELECTOR); - this.label_ = a ? o(a) : null; - var c = this.root_.querySelector(O.strings.LINE_RIPPLE_SELECTOR); - this.lineRipple_ = c ? e(c) : null; - var u = this.root_.querySelector(O.strings.OUTLINE_SELECTOR); - this.outline_ = u ? s(u) : null; - var l = I.MDCTextFieldHelperTextFoundation.strings, - d = this.root_.nextElementSibling, - p = d && d.classList.contains(O.cssClasses.HELPER_LINE), - _ = p && d && d.querySelector(l.ROOT_SELECTOR); - this.helperText_ = _ ? n(_) : null; - var f = b.MDCTextFieldCharacterCounterFoundation.strings, - h = this.root_.querySelector(f.ROOT_SELECTOR); - !h && p && d && (h = d.querySelector(f.ROOT_SELECTOR)), - (this.characterCounter_ = h ? i(h) : null); - var C = this.root_.querySelector(O.strings.LEADING_ICON_SELECTOR); - this.leadingIcon_ = C ? r(C) : null; - var y = this.root_.querySelector( - O.strings.TRAILING_ICON_SELECTOR - ); - (this.trailingIcon_ = y ? r(y) : null), - (this.prefix_ = this.root_.querySelector( - O.strings.PREFIX_SELECTOR - )), - (this.suffix_ = this.root_.querySelector( - O.strings.SUFFIX_SELECTOR - )), - (this.ripple = this.createRipple_(t)); - }), - (f.prototype.destroy = function() { - this.ripple && this.ripple.destroy(), - this.lineRipple_ && this.lineRipple_.destroy(), - this.helperText_ && this.helperText_.destroy(), - this.characterCounter_ && this.characterCounter_.destroy(), - this.leadingIcon_ && this.leadingIcon_.destroy(), - this.trailingIcon_ && this.trailingIcon_.destroy(), - this.label_ && this.label_.destroy(), - this.outline_ && this.outline_.destroy(), - a.prototype.destroy.call(this); - }), - (f.prototype.initialSyncWithDOM = function() { - this.disabled = this.input_.disabled; - }), - Object.defineProperty(f.prototype, "value", { - get: function() { - return this.foundation_.getValue(); - }, - set: function(t) { - this.foundation_.setValue(t); - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(f.prototype, "disabled", { - get: function() { - return this.foundation_.isDisabled(); - }, - set: function(t) { - this.foundation_.setDisabled(t); - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(f.prototype, "valid", { - get: function() { - return this.foundation_.isValid(); - }, - set: function(t) { - this.foundation_.setValid(t); - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(f.prototype, "required", { - get: function() { - return this.input_.required; - }, - set: function(t) { - this.input_.required = t; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(f.prototype, "pattern", { - get: function() { - return this.input_.pattern; - }, - set: function(t) { - this.input_.pattern = t; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(f.prototype, "minLength", { - get: function() { - return this.input_.minLength; - }, - set: function(t) { - this.input_.minLength = t; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(f.prototype, "maxLength", { - get: function() { - return this.input_.maxLength; - }, - set: function(t) { - t < 0 - ? this.input_.removeAttribute("maxLength") - : (this.input_.maxLength = t); - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(f.prototype, "min", { - get: function() { - return this.input_.min; - }, - set: function(t) { - this.input_.min = t; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(f.prototype, "max", { - get: function() { - return this.input_.max; - }, - set: function(t) { - this.input_.max = t; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(f.prototype, "step", { - get: function() { - return this.input_.step; - }, - set: function(t) { - this.input_.step = t; - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(f.prototype, "helperTextContent", { - set: function(t) { - this.foundation_.setHelperTextContent(t); - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(f.prototype, "leadingIconAriaLabel", { - set: function(t) { - this.foundation_.setLeadingIconAriaLabel(t); - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(f.prototype, "leadingIconContent", { - set: function(t) { - this.foundation_.setLeadingIconContent(t); - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(f.prototype, "trailingIconAriaLabel", { - set: function(t) { - this.foundation_.setTrailingIconAriaLabel(t); - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(f.prototype, "trailingIconContent", { - set: function(t) { - this.foundation_.setTrailingIconContent(t); - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(f.prototype, "useNativeValidation", { - set: function(t) { - this.foundation_.setUseNativeValidation(t); - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(f.prototype, "prefixText", { - get: function() { - return this.prefix_ ? this.prefix_.textContent : null; - }, - set: function(t) { - this.prefix_ && (this.prefix_.textContent = t); - }, - enumerable: !0, - configurable: !0 - }), - Object.defineProperty(f.prototype, "suffixText", { - get: function() { - return this.suffix_ ? this.suffix_.textContent : null; - }, - set: function(t) { - this.suffix_ && (this.suffix_.textContent = t); - }, - enumerable: !0, - configurable: !0 - }), - (f.prototype.focus = function() { - this.input_.focus(); - }), - (f.prototype.layout = function() { - var t = this.foundation_.shouldFloat; - this.foundation_.notchOutline(t); - }), - (f.prototype.getDefaultFoundation = function() { - var t = o( - o( - o( - o( - o({}, this.getRootAdapterMethods_()), - this.getInputAdapterMethods_() - ), - this.getLabelAdapterMethods_() - ), - this.getLineRippleAdapterMethods_() - ), - this.getOutlineAdapterMethods_() - ); - return new p.MDCTextFieldFoundation(t, this.getFoundationMap_()); - }), - (f.prototype.getRootAdapterMethods_ = function() { - var n = this; - return { - addClass: function(t) { - return n.root_.classList.add(t); - }, - removeClass: function(t) { - return n.root_.classList.remove(t); - }, - hasClass: function(t) { - return n.root_.classList.contains(t); - }, - registerTextFieldInteractionHandler: function(t, e) { - return n.listen(t, e); - }, - deregisterTextFieldInteractionHandler: function(t, e) { - return n.unlisten(t, e); - }, - registerValidationAttributeChangeHandler: function(e) { - var t = new MutationObserver(function(t) { - return e( - (function(t) { - return t - .map(function(t) { - return t.attributeName; - }) - .filter(function(t) { - return t; - }); - })(t) - ); - }); - return t.observe(n.input_, { attributes: !0 }), t; - }, - deregisterValidationAttributeChangeHandler: function(t) { - return t.disconnect(); - } - }; - }), - (f.prototype.getInputAdapterMethods_ = function() { - var n = this; - return { - getNativeInput: function() { - return n.input_; - }, - isFocused: function() { - return document.activeElement === n.input_; - }, - registerInputInteractionHandler: function(t, e) { - return n.input_.addEventListener(t, e, u.applyPassive()); - }, - deregisterInputInteractionHandler: function(t, e) { - return n.input_.removeEventListener(t, e, u.applyPassive()); - } - }; - }), - (f.prototype.getLabelAdapterMethods_ = function() { - var e = this; - return { - floatLabel: function(t) { - return e.label_ && e.label_.float(t); - }, - getLabelWidth: function() { - return e.label_ ? e.label_.getWidth() : 0; - }, - hasLabel: function() { - return Boolean(e.label_); - }, - shakeLabel: function(t) { - return e.label_ && e.label_.shake(t); - } - }; - }), - (f.prototype.getLineRippleAdapterMethods_ = function() { - var e = this; - return { - activateLineRipple: function() { - e.lineRipple_ && e.lineRipple_.activate(); - }, - deactivateLineRipple: function() { - e.lineRipple_ && e.lineRipple_.deactivate(); - }, - setLineRippleTransformOrigin: function(t) { - e.lineRipple_ && e.lineRipple_.setRippleCenter(t); - } - }; - }), - (f.prototype.getOutlineAdapterMethods_ = function() { - var e = this; - return { - closeOutline: function() { - return e.outline_ && e.outline_.closeNotch(); - }, - hasOutline: function() { - return Boolean(e.outline_); - }, - notchOutline: function(t) { - return e.outline_ && e.outline_.notch(t); - } - }; - }), - (f.prototype.getFoundationMap_ = function() { - return { - characterCounter: this.characterCounter_ - ? this.characterCounter_.foundation - : void 0, - helperText: this.helperText_ - ? this.helperText_.foundation - : void 0, - leadingIcon: this.leadingIcon_ - ? this.leadingIcon_.foundation - : void 0, - trailingIcon: this.trailingIcon_ - ? this.trailingIcon_.foundation - : void 0 - }; - }), - (f.prototype.createRipple_ = function(t) { - var n = this, - e = this.root_.classList.contains(O.cssClasses.TEXTAREA), - i = this.root_.classList.contains(O.cssClasses.OUTLINED); - if (e || i) return null; - var r = o(o({}, A.MDCRipple.createAdapter(this)), { - isSurfaceActive: function() { - return l.matches(n.input_, ":active"); - }, - registerInteractionHandler: function(t, e) { - return n.input_.addEventListener(t, e, u.applyPassive()); - }, - deregisterInteractionHandler: function(t, e) { - return n.input_.removeEventListener(t, e, u.applyPassive()); - } - }); - return t(this.root_, new d.MDCRippleFoundation(r)); - }), - f); - function f() { - return (null !== a && a.apply(this, arguments)) || this; - } - e.MDCTextField = _; - }, - function(t, n, e) { - "use strict"; - function i(t) { - for (var e in t) n.hasOwnProperty(e) || (n[e] = t[e]); - } - Object.defineProperty(n, "__esModule", { value: !0 }), - i(e(95)), - i(e(34)); - var r = e(96); - (n.characterCountCssClasses = r.cssClasses), - (n.characterCountStrings = r.strings); - }, - function(t, n, e) { - "use strict"; - function i(t) { - for (var e in t) n.hasOwnProperty(e) || (n[e] = t[e]); - } - Object.defineProperty(n, "__esModule", { value: !0 }), - i(e(98)), - i(e(36)); - var r = e(99); - (n.helperTextCssClasses = r.cssClasses), - (n.helperTextStrings = r.strings); - }, - function(t, n, e) { - "use strict"; - function i(t) { - for (var e in t) n.hasOwnProperty(e) || (n[e] = t[e]); - } - Object.defineProperty(n, "__esModule", { value: !0 }), - i(e(100)), - i(e(101)); - var r = e(102); - (n.iconCssClasses = r.cssClasses), (n.iconStrings = r.strings); - }, - function(t, n, e) { - "use strict"; - function i(t) { - for (var e in t) n.hasOwnProperty(e) || (n[e] = t[e]); - } - Object.defineProperty(n, "__esModule", { value: !0 }), - i(e(165)), - i(e(7)), - i(e(38)), - i(e(103)), - i(e(104)), - i(e(37)); - }, - function(t, e, n) { - "use strict"; - var i, - r = - (this && this.__extends) || - ((i = function(t, e) { - return (i = - Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && - function(t, e) { - t.__proto__ = e; - }) || - function(t, e) { - for (var n in e) e.hasOwnProperty(n) && (t[n] = e[n]); - })(t, e); - }), - function(t, e) { - function n() { - this.constructor = t; - } - i(t, e), - (t.prototype = - null === e - ? Object.create(e) - : ((n.prototype = e.prototype), new n())); - }); - Object.defineProperty(e, "__esModule", { value: !0 }); - var o, - s = n(1), - a = n(3), - c = n(7), - u = n(103), - l = n(104), - d = n(37), - p = - ((o = s.MDCComponent), - r(_, o), - (_.attachTo = function(t) { - return new _(t); - }), - (_.prototype.initialize = function(n) { - void 0 === n && - (n = function(t) { - return a.MDCRipple.attachTo(t); - }), - (this.navIcon_ = this.root_.querySelector( - c.strings.NAVIGATION_ICON_SELECTOR - )); - var t = [].slice.call( - this.root_.querySelectorAll(c.strings.ACTION_ITEM_SELECTOR) - ); - this.navIcon_ && t.push(this.navIcon_), - (this.iconRipples_ = t.map(function(t) { - var e = n(t); - return (e.unbounded = !0), e; - })), - (this.scrollTarget_ = window); - }), - (_.prototype.initialSyncWithDOM = function() { - (this.handleNavigationClick_ = this.foundation_.handleNavigationClick.bind( - this.foundation_ - )), - (this.handleWindowResize_ = this.foundation_.handleWindowResize.bind( - this.foundation_ - )), - (this.handleTargetScroll_ = this.foundation_.handleTargetScroll.bind( - this.foundation_ - )), - this.scrollTarget_.addEventListener( - "scroll", - this.handleTargetScroll_ - ), - this.navIcon_ && - this.navIcon_.addEventListener( - "click", - this.handleNavigationClick_ - ); - var t = this.root_.classList.contains(c.cssClasses.FIXED_CLASS); - this.root_.classList.contains(c.cssClasses.SHORT_CLASS) || - t || - window.addEventListener("resize", this.handleWindowResize_); - }), - (_.prototype.destroy = function() { - this.iconRipples_.forEach(function(t) { - return t.destroy(); - }), - this.scrollTarget_.removeEventListener( - "scroll", - this.handleTargetScroll_ - ), - this.navIcon_ && - this.navIcon_.removeEventListener( - "click", - this.handleNavigationClick_ - ); - var t = this.root_.classList.contains(c.cssClasses.FIXED_CLASS); - this.root_.classList.contains(c.cssClasses.SHORT_CLASS) || - t || - window.removeEventListener("resize", this.handleWindowResize_), - o.prototype.destroy.call(this); - }), - (_.prototype.setScrollTarget = function(t) { - this.scrollTarget_.removeEventListener( - "scroll", - this.handleTargetScroll_ - ), - (this.scrollTarget_ = t), - (this.handleTargetScroll_ = this.foundation_.handleTargetScroll.bind( - this.foundation_ - )), - this.scrollTarget_.addEventListener( - "scroll", - this.handleTargetScroll_ - ); - }), - (_.prototype.getDefaultFoundation = function() { - var n = this, - t = { - hasClass: function(t) { - return n.root_.classList.contains(t); - }, - addClass: function(t) { - return n.root_.classList.add(t); - }, - removeClass: function(t) { - return n.root_.classList.remove(t); - }, - setStyle: function(t, e) { - return n.root_.style.setProperty(t, e); - }, - getTopAppBarHeight: function() { - return n.root_.clientHeight; - }, - notifyNavigationIconClicked: function() { - return n.emit(c.strings.NAVIGATION_EVENT, {}); - }, - getViewportScrollY: function() { - var t = n.scrollTarget_, - e = n.scrollTarget_; - return void 0 !== t.pageYOffset - ? t.pageYOffset - : e.scrollTop; - }, - getTotalActionItems: function() { - return n.root_.querySelectorAll( - c.strings.ACTION_ITEM_SELECTOR - ).length; - } - }; - return this.root_.classList.contains(c.cssClasses.SHORT_CLASS) - ? new l.MDCShortTopAppBarFoundation(t) - : this.root_.classList.contains(c.cssClasses.FIXED_CLASS) - ? new u.MDCFixedTopAppBarFoundation(t) - : new d.MDCTopAppBarFoundation(t); - }), - _); - function _() { - return (null !== o && o.apply(this, arguments)) || this; - } - e.MDCTopAppBar = p; - } - ]), - (r.c = i), - (r.d = function(t, e, n) { - r.o(t, e) || Object.defineProperty(t, e, { enumerable: !0, get: n }); - }), - (r.r = function(t) { - "undefined" != typeof Symbol && - Symbol.toStringTag && - Object.defineProperty(t, Symbol.toStringTag, { value: "Module" }), - Object.defineProperty(t, "__esModule", { value: !0 }); - }), - (r.t = function(e, t) { - if ((1 & t && (e = r(e)), 8 & t)) return e; - if (4 & t && "object" == typeof e && e && e.__esModule) return e; - var n = Object.create(null); - if ( - (r.r(n), - Object.defineProperty(n, "default", { enumerable: !0, value: e }), - 2 & t && "string" != typeof e) - ) - for (var i in e) - r.d( - n, - i, - function(t) { - return e[t]; - }.bind(null, i) - ); - return n; - }), - (r.n = function(t) { - var e = - t && t.__esModule - ? function() { - return t.default; - } - : function() { - return t; - }; - return r.d(e, "a", e), e; - }), - (r.o = function(t, e) { - return Object.prototype.hasOwnProperty.call(t, e); - }), - (r.p = ""), - r((r.s = 105)) - ); - function r(t) { - if (i[t]) return i[t].exports; - var e = (i[t] = { i: t, l: !1, exports: {} }); - return n[t].call(e.exports, e, e.exports, r), (e.l = !0), e.exports; - } - var n, i; -}); diff --git a/backend/src/main/resources/templates/authorize.html b/backend/src/main/resources/templates/authorize.html deleted file mode 100644 index 4a8652c7f..000000000 --- a/backend/src/main/resources/templates/authorize.html +++ /dev/null @@ -1,73 +0,0 @@ - - - - - - - - - - - - - - - - -
-
- -
- -
-

- Gamma - IT account -

-
- -
- -
-

-

-
- -
- -
- - -
- -
- - -
-
-
- - -
- Made by digIT '18 -
- - - diff --git a/backend/src/main/resources/templates/common-error.html b/backend/src/main/resources/templates/common-error.html deleted file mode 100644 index 64ef8b482..000000000 --- a/backend/src/main/resources/templates/common-error.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - Error Occurred - - -
-

- An error occurred -

-

- This error does not have an internal mapping -

- Status:
- Message:
- Original Url:
-
- - \ No newline at end of file diff --git a/backend/src/main/resources/templates/error-404.html b/backend/src/main/resources/templates/error-404.html deleted file mode 100644 index 88fbf323c..000000000 --- a/backend/src/main/resources/templates/error-404.html +++ /dev/null @@ -1,24 +0,0 @@ - - - - - Not Found - - - -
-

- 404
-

-

- This is not the page you're looking for -

- This image did not load, but imagine it did :) -
-
- - does not exist -
-
- - \ No newline at end of file diff --git a/backend/src/main/resources/templates/error-422.html b/backend/src/main/resources/templates/error-422.html deleted file mode 100644 index ce482b163..000000000 --- a/backend/src/main/resources/templates/error-422.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - - Unprocessable Entity - - -
-

- 422
-

-

- Unprocessable Entity -

-
- The internal reason was: - -
-
- - \ No newline at end of file diff --git a/backend/src/main/resources/templates/error-5xx.html b/backend/src/main/resources/templates/error-5xx.html deleted file mode 100644 index a11304af5..000000000 --- a/backend/src/main/resources/templates/error-5xx.html +++ /dev/null @@ -1,23 +0,0 @@ - - - - - Internal Server Error - - -
-

- 500
-

-

- An internal server error occurred
-

- -

- - Click here to add an issue on - This should be a github logo - -
- - \ No newline at end of file diff --git a/backend/src/main/resources/templates/login.html b/backend/src/main/resources/templates/login.html deleted file mode 100644 index e28f701bc..000000000 --- a/backend/src/main/resources/templates/login.html +++ /dev/null @@ -1,146 +0,0 @@ - - - - - - - - - - - - - - - - - -
-
-
- -
- Invalid cid/email and password. -
-
-
- You have been logged out. -
-
- - -
- -
-

- Gamma - IT account -

-
- -
- - -
- -
-
-
- -
-
-
-
- -
- - -
- -
-
-
- -
-
-
-
- -
- -
- - - -
- -
- -
- -
- - -
-
-
- - -
- Made by digIT '18 -
- - - diff --git a/backend/src/test/java/it/chalmers/gamma/TestUtils.java b/backend/src/test/java/it/chalmers/gamma/TestUtils.java deleted file mode 100644 index d169fac51..000000000 --- a/backend/src/test/java/it/chalmers/gamma/TestUtils.java +++ /dev/null @@ -1,31 +0,0 @@ -package it.chalmers.gamma; - -import it.chalmers.gamma.service.ITUserService; - -import org.springframework.stereotype.Component; -import org.springframework.test.annotation.DirtiesContext; -import org.springframework.test.web.servlet.MockMvc; - -@Component -@SuppressWarnings("PMD.AvoidPrintStackTrace") -@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_CLASS) -public class TestUtils { - - private MockMvc mockMvc; - - private ITUserService userService; - - public void setMockMvc(MockMvc mockMvc, ITUserService userService) { - this.mockMvc = mockMvc; - this.userService = userService; - } - - public MockMvc getMockMvc() { - return this.mockMvc; - } - - public ITUserService getUserService() { - return this.userService; - } - -} diff --git a/backend/src/test/java/it/chalmers/gamma/api/ActivationCodeTests.java b/backend/src/test/java/it/chalmers/gamma/api/ActivationCodeTests.java deleted file mode 100644 index 0d93fa4e8..000000000 --- a/backend/src/test/java/it/chalmers/gamma/api/ActivationCodeTests.java +++ /dev/null @@ -1,67 +0,0 @@ -package it.chalmers.gamma.api; - -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -import it.chalmers.gamma.GammaApplication; -import it.chalmers.gamma.domain.dto.user.ActivationCodeDTO; -import it.chalmers.gamma.factories.MockActivationCodeFactory; -import it.chalmers.gamma.factories.MockWhitelistFactory; -import it.chalmers.gamma.service.ActivationCodeService; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.security.test.context.support.WithUserDetails; -import org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.test.context.web.WebAppConfiguration; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; -import org.springframework.web.context.WebApplicationContext; - -@RunWith(SpringRunner.class) -@WebAppConfiguration -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK, classes = GammaApplication.class) -@ActiveProfiles("test") -public class ActivationCodeTests { - - @Autowired - private WebApplicationContext webApplicationContext; - - private MockMvc mockMvc; - - @Autowired - private MockActivationCodeFactory mockActivationCodeFactory; - - @Autowired - private MockWhitelistFactory mockWhitelistFactory; - - @Autowired - private ActivationCodeService activationCodeService; - - @Before - public void setupTest() { - this.mockMvc = MockMvcBuilders.webAppContextSetup(this.webApplicationContext) - .apply(SecurityMockMvcConfigurers.springSecurity()) - .build(); - } - - @Test - @WithUserDetails("admin") - public void testDeleteActivationCode() throws Exception { - ActivationCodeDTO activationCode = this.mockActivationCodeFactory.saveActivationCode( - this.mockWhitelistFactory.saveWhitelist(this.mockWhitelistFactory.generateWhitelist())); - this.mockMvc.perform(delete(String.format("/admin/activation_codes/%s", activationCode.getCid()))) - .andExpect(status().isAccepted()); - ActivationCodeDTO activationCode2 = this.mockActivationCodeFactory.saveActivationCode( - this.mockWhitelistFactory.saveWhitelist(this.mockWhitelistFactory.generateWhitelist())); - this.mockMvc.perform(delete(String.format("/admin/activation_codes/%s", activationCode2.getId()))) - .andExpect(status().isAccepted()); - Assert.assertFalse(this.activationCodeService.codeExists(activationCode.getCid())); - Assert.assertFalse(this.activationCodeService.codeExists(activationCode2.getId().toString())); - } -} diff --git a/backend/src/test/java/it/chalmers/gamma/api/AdminITUserTests.java b/backend/src/test/java/it/chalmers/gamma/api/AdminITUserTests.java deleted file mode 100644 index c1d520b8f..000000000 --- a/backend/src/test/java/it/chalmers/gamma/api/AdminITUserTests.java +++ /dev/null @@ -1,70 +0,0 @@ -package it.chalmers.gamma.api; - -import it.chalmers.gamma.GammaApplication; -import it.chalmers.gamma.factories.MockITUserFactory; - -import it.chalmers.gamma.utils.JSONUtils; -import it.chalmers.gamma.utils.ResponseUtils; -import java.util.Objects; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.http.MediaType; -import org.springframework.security.test.context.support.WithMockUser; -import org.springframework.security.test.context.support.WithUserDetails; -import org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.test.context.web.WebAppConfiguration; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; -import org.springframework.web.context.WebApplicationContext; - - -@RunWith(SpringRunner.class) -@WebAppConfiguration -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK, classes = GammaApplication.class) -@ActiveProfiles("test") -@SuppressWarnings("PMD.JUnitTestsShouldIncludeAssert") -public class AdminITUserTests { - - @Autowired - private WebApplicationContext webApplicationContext; - - private MockMvc mockMvc; - - @Autowired - private MockITUserFactory mockITUserFactory; - - @Before - public void setupTests() { - this.mockMvc = MockMvcBuilders.webAppContextSetup(this.webApplicationContext) - .apply(SecurityMockMvcConfigurers.springSecurity()) - .build(); - } - - @WithUserDetails("admin") - @Test - public void testAdminCreateUserAsAdmin() throws Exception { - testAdminCreateUser(true); - } - - @WithMockUser - @Test - public void testAdminCreateUserAsNonAdmin() throws Exception { - testAdminCreateUser(false); - } - - private void testAdminCreateUser(boolean authorized) throws Exception { - this.mockMvc.perform(MockMvcRequestBuilders.post( - "/admin/users") - .contentType(MediaType.APPLICATION_JSON) - .content(Objects.requireNonNull(JSONUtils.objectToJSONString( - this.mockITUserFactory.generateValidAdminCreateUserRequest())))) - .andExpect(ResponseUtils.expectedStatus(authorized)); - } - -} diff --git a/backend/src/test/java/it/chalmers/gamma/api/CreateAccountTests.java b/backend/src/test/java/it/chalmers/gamma/api/CreateAccountTests.java deleted file mode 100644 index 138ca0a6c..000000000 --- a/backend/src/test/java/it/chalmers/gamma/api/CreateAccountTests.java +++ /dev/null @@ -1,96 +0,0 @@ -package it.chalmers.gamma.api; - -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -import it.chalmers.gamma.GammaApplication; -import it.chalmers.gamma.domain.dto.user.ActivationCodeDTO; -import it.chalmers.gamma.domain.dto.user.WhitelistDTO; -import it.chalmers.gamma.factories.MockITUserFactory; -import it.chalmers.gamma.factories.MockWhitelistFactory; -import it.chalmers.gamma.service.ActivationCodeService; -import it.chalmers.gamma.service.ITUserService; -import it.chalmers.gamma.utils.JSONUtils; -import java.util.Objects; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.http.MediaType; -import org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.test.context.web.WebAppConfiguration; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; -import org.springframework.web.context.WebApplicationContext; - -@RunWith(SpringRunner.class) -@WebAppConfiguration -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK, classes = GammaApplication.class) -@ActiveProfiles("test") -@SuppressWarnings({"PMD.JUnitTestsShouldIncludeAssert"}) -public class CreateAccountTests { - - @Autowired - private WebApplicationContext webApplicationContext; - - private MockMvc mockMvc; - - @Autowired - private MockWhitelistFactory mockWhitelistFactory; - - @Autowired - private MockITUserFactory mockITUserFactory; - - @Autowired - private ActivationCodeService activationCodeService; - - @Autowired - private ITUserService userService; - - @Before - public void setupTests() { - this.mockMvc = MockMvcBuilders.webAppContextSetup(this.webApplicationContext) - .apply(SecurityMockMvcConfigurers.springSecurity()) - .build(); - } - - @Test - public void testCreateActivationCodeWhitelistedAccount() throws Exception { - WhitelistDTO whitelist = this.mockWhitelistFactory.saveWhitelist(this.mockWhitelistFactory.generateWhitelist()); - this.testCreateActivationCode(whitelist, true); - } - - @Test - public void testCreateActivationCodeNonWhitelistedAccount() throws Exception { - this.testCreateActivationCode(this.mockWhitelistFactory.generateWhitelist(), false); - } - - private void testCreateActivationCode(WhitelistDTO whitelist, boolean shouldCreate) throws Exception { - this.mockMvc.perform(post("/whitelist/activate_cid") - .contentType(MediaType.APPLICATION_JSON) - .content(Objects.requireNonNull(JSONUtils.objectToJSONString( - this.mockWhitelistFactory.createValidRequest(whitelist))))) - .andExpect(status().is(202)); // To hide if user exists, we always return OK - Assert.assertEquals(this.activationCodeService.codeExists(whitelist.getCid()), shouldCreate); - } - - @Test - public void testCreateAccountValidCode() throws Exception { - WhitelistDTO whitelist = this.mockWhitelistFactory.saveWhitelist(this.mockWhitelistFactory.generateWhitelist()); - this.testCreateActivationCode(whitelist, true); - ActivationCodeDTO activationCodeDTO = this.activationCodeService.getActivationCodeDTO(whitelist.getCid()); - this.mockMvc.perform(post("/users/create") - .contentType(MediaType.APPLICATION_JSON) - .content(Objects.requireNonNull(JSONUtils.objectToJSONString( - this.mockITUserFactory.createValidCreateRequest( - this.mockITUserFactory.generateITUser( - "user", - true), - activationCodeDTO))))).andExpect(status().isAccepted()); - Assert.assertTrue(this.userService.userExists(whitelist.getCid())); - } -} diff --git a/backend/src/test/java/it/chalmers/gamma/api/EndpointDeleteTests.java b/backend/src/test/java/it/chalmers/gamma/api/EndpointDeleteTests.java deleted file mode 100644 index 8578aec92..000000000 --- a/backend/src/test/java/it/chalmers/gamma/api/EndpointDeleteTests.java +++ /dev/null @@ -1,93 +0,0 @@ -package it.chalmers.gamma.api; - -import static it.chalmers.gamma.utils.ResponseUtils.expectedStatus; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; -import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; - -import it.chalmers.gamma.GammaApplication; -import it.chalmers.gamma.endoints.Endpoint; -import it.chalmers.gamma.endoints.EndpointsUtils; -import it.chalmers.gamma.endoints.Method; -import it.chalmers.gamma.factories.MockDatabaseGeneratorFactory; -import java.util.Collection; -import java.util.List; -import java.util.stream.Collectors; -import java.util.stream.Stream; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.security.test.context.support.WithMockUser; -import org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.test.context.web.WebAppConfiguration; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; -import org.springframework.web.context.WebApplicationContext; - -@RunWith(SpringRunner.class) -@WebAppConfiguration -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK, classes = GammaApplication.class) -@ActiveProfiles("test") -@SuppressWarnings("PMD.JUnitTestsShouldIncludeAssert") -public class EndpointDeleteTests { - - private static final Logger LOGGER = LoggerFactory.getLogger(EndpointDeleteTests.class); - - - @Autowired - private WebApplicationContext webApplicationContext; - - private MockMvc mockMvc; - - @Autowired - private MockDatabaseGeneratorFactory mockDatabaseGeneratorFactory; - - - @Before - public void setupTests() { - this.mockMvc = MockMvcBuilders.webAppContextSetup(this.webApplicationContext) - .apply(SecurityMockMvcConfigurers.springSecurity()) - .build(); - this.mockDatabaseGeneratorFactory.populateMockDatabase(); - } - - // This should probably not be performed, as some sanity checks should be done before deleting some entities - /* @Test - @WithUserDetails("admin") - public void testDeleteAsAdminUser() throws Exception{ - testDeleteEndpoints(true); - }*/ - - @Test - @WithMockUser - public void testDeleteAsNormalUser() throws Exception { - testDeleteEndpoints(false); - } - - private void testDeleteEndpoints(boolean authorized) throws Exception { - List endpoints = Stream.of( - EndpointsUtils.getAuthorizedEndpoints(), - EndpointsUtils.getNonAuthorizedEndpoints(), - EndpointsUtils.getNormalUserEndpoints()) - .flatMap(Collection::stream) - .collect(Collectors.toList()); - for (Endpoint endpoint : endpoints) { - this.testDeleteEndpoint(String.format(endpoint.getPath(), - this.mockDatabaseGeneratorFactory.getMockedUUID(endpoint.getMockClass())), - endpoint.getMethod(), authorized); - } - } - - private void testDeleteEndpoint(String endpoint, Method method, boolean authorized) throws Exception { - if (method.equals(Method.DELETE)) { - LOGGER.info(String.format("testing %s", endpoint)); - this.mockMvc.perform(delete(endpoint)).andDo(print()).andExpect(expectedStatus(authorized)); - } - } - -} diff --git a/backend/src/test/java/it/chalmers/gamma/api/EndpointGETTests.java b/backend/src/test/java/it/chalmers/gamma/api/EndpointGETTests.java deleted file mode 100644 index 96851af86..000000000 --- a/backend/src/test/java/it/chalmers/gamma/api/EndpointGETTests.java +++ /dev/null @@ -1,116 +0,0 @@ -package it.chalmers.gamma.api; - -import static it.chalmers.gamma.utils.ResponseUtils.expectedStatus; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; - -import it.chalmers.gamma.GammaApplication; -import it.chalmers.gamma.endoints.Endpoint; -import it.chalmers.gamma.endoints.EndpointsUtils; -import it.chalmers.gamma.endoints.Method; -import it.chalmers.gamma.factories.MockDatabaseGeneratorFactory; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.security.test.context.support.WithAnonymousUser; -import org.springframework.security.test.context.support.WithMockUser; -import org.springframework.security.test.context.support.WithUserDetails; -import org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.test.context.web.WebAppConfiguration; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; -import org.springframework.web.context.WebApplicationContext; - -@RunWith(SpringRunner.class) -@WebAppConfiguration -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK, classes = GammaApplication.class) -@ActiveProfiles("test") -@SuppressWarnings({"PMD.ExcessiveImports", "PMD.JUnitTestsShouldIncludeAssert"}) -public class EndpointGETTests { - - private static final Logger LOGGER = LoggerFactory.getLogger(EndpointGETTests.class); - - - @Autowired - private WebApplicationContext webApplicationContext; - - private MockMvc mockMvc; - - @Autowired - private MockDatabaseGeneratorFactory mockDatabaseGeneratorFactory; - - @Before - public void setupTests() { - this.mockMvc = MockMvcBuilders.webAppContextSetup(this.webApplicationContext) - .apply(SecurityMockMvcConfigurers.springSecurity()) - .build(); - this.mockDatabaseGeneratorFactory.populateMockDatabase(); - - } - - @WithUserDetails("admin") - @Test - public void testAllGETEndpointsAsAdmin() throws Exception { - testGetEndpoints( - Stream.of( - EndpointsUtils.getAuthorizedEndpoints(), - EndpointsUtils.getNonAuthorizedEndpoints(), - EndpointsUtils.getNormalUserEndpoints()) - .flatMap(Collection::stream) - .collect(Collectors.toList()), new ArrayList<>()); - } - - @WithMockUser(username = "normal") - @Test // TODO Generate and populate database with mock data - public void testAllGETEndpointsAsNormalUser() throws Exception { - testGetEndpoints( - Stream.concat( - EndpointsUtils.getNormalUserEndpoints().stream(), - EndpointsUtils.getNonAuthorizedEndpoints().stream()) - .collect(Collectors.toList()), - EndpointsUtils.getAuthorizedEndpoints()); - } - - @WithAnonymousUser - @Test - public void testAllGETEndpointsAsAnonymous() throws Exception { - testGetEndpoints(EndpointsUtils.getNonAuthorizedEndpoints(), - Stream.concat( - EndpointsUtils.getNormalUserEndpoints().stream(), - EndpointsUtils.getAuthorizedEndpoints().stream()) - .collect(Collectors.toList())); - } - - private void testGetEndpoints(List allowedEndpoints, List deniedEndpoints) throws Exception { - for (Endpoint endpoint : allowedEndpoints) { - this.testGetEndpoint(String.format(endpoint.getPath(), - this.mockDatabaseGeneratorFactory.getMockedUUID(endpoint.getMockClass())), - endpoint.getMethod(), true); - } - for (Endpoint endpoint : deniedEndpoints) { - this.testGetEndpoint(String.format(endpoint.getPath(), - this.mockDatabaseGeneratorFactory.getMockedUUID(endpoint.getMockClass())), - endpoint.getMethod(), false); - } - } - - private void testGetEndpoint(String endpoint, Method method, boolean authorized) throws Exception { - if (method.equals(Method.GET)) { - LOGGER.info(String.format("testing %s", endpoint)); - this.mockMvc.perform(get(endpoint, String.class)).andExpect(expectedStatus(authorized)).andDo(print()); - } - - } -} diff --git a/backend/src/test/java/it/chalmers/gamma/api/LoginTests.java b/backend/src/test/java/it/chalmers/gamma/api/LoginTests.java deleted file mode 100644 index 7567ec445..000000000 --- a/backend/src/test/java/it/chalmers/gamma/api/LoginTests.java +++ /dev/null @@ -1,128 +0,0 @@ -package it.chalmers.gamma.api; - -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -import it.chalmers.gamma.GammaApplication; -import it.chalmers.gamma.domain.dto.user.ITUserDTO; -import it.chalmers.gamma.endoints.JSONParameter; -import it.chalmers.gamma.factories.MockITUserFactory; -import it.chalmers.gamma.utils.CharacterTypes; -import it.chalmers.gamma.utils.GenerationUtils; -import it.chalmers.gamma.utils.JSONUtils; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.http.MediaType; -import org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.test.context.web.WebAppConfiguration; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; -import org.springframework.web.context.WebApplicationContext; - -@RunWith(SpringRunner.class) -@WebAppConfiguration -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK, classes = GammaApplication.class) -@ActiveProfiles("test") -@SuppressWarnings("PMD.JUnitTestsShouldIncludeAssert") -public class LoginTests { - - @Autowired - private WebApplicationContext webApplicationContext; - - private MockMvc mockMvc; - - @Autowired - private MockITUserFactory mockITUserFactory; - - @Value("${application.frontend-client-details.successful-login-uri}") - private String frontendUri; - - private static final String USERNAME = "username"; - private static final String PASSWORD = "password"; - - @Before - public void setupTests() { - this.mockMvc = MockMvcBuilders.webAppContextSetup(this.webApplicationContext) - .apply(SecurityMockMvcConfigurers.springSecurity()) - .build(); - } - - @Test - public void testSuccessfulLogin() throws Exception { - ITUserDTO user = this.mockITUserFactory.saveUser( - this.mockITUserFactory.generateITUser( - GenerationUtils.generateRandomString( - 10, - CharacterTypes.LOWERCASE), - true)); - String request = JSONUtils.toFormUrlEncoded( - new JSONParameter(USERNAME, user.getCid()), - new JSONParameter(PASSWORD, PASSWORD) - ); - testLogin(request, this.frontendUri); - } - - @Test - public void testWrongPasswordLogin() throws Exception { - String invalidPasswordRequest = JSONUtils.toFormUrlEncoded( - new JSONParameter(USERNAME, "user"), - new JSONParameter(PASSWORD, "invalidPassword") - ); - testLogin(invalidPasswordRequest, "/login?error"); - } - - @Test - public void testWrongUsernameLogin() throws Exception { - String invalidUsernameRequest = JSONUtils.toFormUrlEncoded( - new JSONParameter(USERNAME, "invalidUser"), - new JSONParameter(PASSWORD, PASSWORD) - ); - testLogin(invalidUsernameRequest, "/login?error"); - } - - @Test - public void testNonActivatedRedirect() throws Exception { - ITUserDTO user = this.mockITUserFactory.generateITUser("nActUser", false); - ITUserDTO editedUser = this.mockITUserFactory.saveUser(user); - String nonActivatedPasswordRequest = JSONUtils.toFormUrlEncoded( - new JSONParameter(USERNAME, editedUser.getCid()), - new JSONParameter(PASSWORD, PASSWORD) // Does not do any difference - ); - testLogin(nonActivatedPasswordRequest, - String.format("%s/reset-password/finish?accountLocked=true", this.frontendUri)); - } - - @Test - public void testSuccessfulEmailLogin() throws Exception { - ITUserDTO user = this.mockITUserFactory.saveUser( - this.mockITUserFactory.generateITUser( - GenerationUtils.generateRandomString( - 10, - CharacterTypes.LOWERCASE), - true)); - String request = JSONUtils.toFormUrlEncoded( - new JSONParameter(USERNAME, user.getEmail()), - new JSONParameter(PASSWORD, PASSWORD) - ); - testLogin(request, this.frontendUri); - } - - - private void testLogin(String request, String redirect) throws Exception { - this.mockMvc.perform(post("/login") - .contentType(MediaType.APPLICATION_FORM_URLENCODED) - .content( - request - )) - .andExpect(redirectedUrl(redirect)) - .andExpect(status().is(302)); - } - -} diff --git a/backend/src/test/java/it/chalmers/gamma/api/OauthTests.java b/backend/src/test/java/it/chalmers/gamma/api/OauthTests.java deleted file mode 100644 index c648b2222..000000000 --- a/backend/src/test/java/it/chalmers/gamma/api/OauthTests.java +++ /dev/null @@ -1,181 +0,0 @@ -package it.chalmers.gamma.api; - -import static it.chalmers.gamma.utils.CharacterTypes.LOWERCASE; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrlPattern; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -import it.chalmers.gamma.GammaApplication; -import it.chalmers.gamma.domain.dto.access.ITClientDTO; -import it.chalmers.gamma.endoints.JSONParameter; -import it.chalmers.gamma.factories.MockITClientFactory; -import it.chalmers.gamma.factories.MockITUserApprovalFactory; -import it.chalmers.gamma.utils.GenerationUtils; -import it.chalmers.gamma.utils.JSONUtils; -import java.util.Objects; -import org.apache.commons.codec.binary.Base64; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.http.MediaType; -import org.springframework.security.test.context.support.WithMockUser; -import org.springframework.security.test.context.support.WithUserDetails; -import org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.test.context.web.WebAppConfiguration; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.MvcResult; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; -import org.springframework.web.context.WebApplicationContext; - -@RunWith(SpringRunner.class) -@WebAppConfiguration -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK, classes = GammaApplication.class) -@ActiveProfiles("test") -@SuppressWarnings({"PMD.JUnitTestsShouldIncludeAssert", "PMD.ExcessiveImports"}) -public class OauthTests { - - @Autowired - private WebApplicationContext webApplicationContext; - - private MockMvc mockMvc; - - @Autowired - private MockITClientFactory mockITClientFactory; - - @Autowired - private MockITUserApprovalFactory mockITUserApprovalFactory; - - private static final String TEST_COM = "https://test.com/auth"; - - @Before - public void setupTests() { - this.mockMvc = MockMvcBuilders.webAppContextSetup(this.webApplicationContext) - .apply(SecurityMockMvcConfigurers.springSecurity()) - .build(); - } - - /** - * Tests if going to oauth endpoints as non-authenticated redirects to login page. - * @throws Exception if mockMvc cannot perform - */ - @Test - public void testLoginRedirect() throws Exception { - this.mockMvc.perform( - get("/oauth") - ).andExpect(status().is3xxRedirection()) - .andExpect(redirectedUrl("/login")) - .andDo(print()); - } - - @WithMockUser - @Test - public void testAuthorizationRequestWithIncorrectId() throws Exception { - ITClientDTO clientDTO = this.mockITClientFactory - .saveClient(this.mockITClientFactory.generateClient(TEST_COM)); - - String query = getTestAuthorizationQuery(GenerationUtils.generateRandomString(40, LOWERCASE), - clientDTO.getWebServerRedirectUri()); - this.mockMvc.perform(get(query)) - .andExpect(status().is(422)) - .andExpect(status().reason("NO_SUCH_CLIENT_EXISTS")); - } - - @WithMockUser - @Test - public void testAuthorizationRequestWithIncorrectRedirect() throws Exception { - ITClientDTO clientDTO = this.mockITClientFactory - .saveClient(this.mockITClientFactory.generateClient(TEST_COM)); - - String query = getTestAuthorizationQuery(clientDTO.getClientId(), - GenerationUtils.generateRandomString(40, LOWERCASE)); - this.mockMvc.perform(get(query)).andExpect(status().is(400)); - } - - private String getTestAuthorizationQuery(String clientId, String redirect) { - return String.format("/oauth/authorize?%s", JSONUtils.toFormUrlEncoded( - new JSONParameter("client_id", clientId), - new JSONParameter("redirect_uri", redirect), - new JSONParameter("response_type", "code")) - ); - } - - @WithMockUser("admin") - @Test - public void testSuccessfulAuthorizationRequest() throws Exception { - String redirect = TEST_COM; - ITClientDTO clientDTO = this.mockITClientFactory - .saveClient(this.mockITClientFactory - .generateClient(redirect)); - - String query = getTestAuthorizationQuery(clientDTO.getClientId(), clientDTO.getWebServerRedirectUri()); - this.mockMvc.perform(get(query)).andExpect(redirectedUrlPattern(String.format("%s?code=**", redirect))); - } - - @WithMockUser("admin") - @Test - public void testSuccessfulAuthorizationRequestConfirm() throws Exception { - String redirect = TEST_COM; - ITClientDTO clientDTO = this.mockITClientFactory - .saveClient(this.mockITClientFactory - .generateClientNonAutoApprove(redirect)); - - String query = getTestAuthorizationQuery(clientDTO.getClientId(), clientDTO.getWebServerRedirectUri()); - - this.mockMvc.perform(get(query)).andExpect(result -> { - Assert.assertEquals(result.getResponse().getForwardedUrl(), "/oauth/confirm_access"); - var model = result.getModelAndView().getModel(); - Assert.assertEquals(model.get("client_id"), clientDTO.getClientId()); - Assert.assertEquals(model.get("redirect_uri"), clientDTO.getWebServerRedirectUri()); - }); - } - - //TODO: Kolla så att du kan lägga till en användare som redan har accepterat - @WithUserDetails("admin") - @Test - public void testCorrectRedirectIfAlreadyApproved() throws Exception { - String redirect = TEST_COM; - ITClientDTO clientDTO = this.mockITClientFactory - .saveClient(this.mockITClientFactory - .generateClientNonAutoApprove(redirect)); - - this.mockITUserApprovalFactory.approve("admin", clientDTO.getClientId()); - - String query = getTestAuthorizationQuery(clientDTO.getClientId(), clientDTO.getWebServerRedirectUri()); - - this.mockMvc.perform(get(query)).andExpect(redirectedUrlPattern(String.format("%s?code=**", redirect))); - } - - @WithMockUser("admin") - @Test - public void testSuccessfulAuthorizationCode() throws Exception { - String redirect = TEST_COM; - ITClientDTO clientDTO = this.mockITClientFactory - .saveClient(this.mockITClientFactory - .generateClient(redirect)); - String query = getTestAuthorizationQuery(clientDTO.getClientId(), clientDTO.getWebServerRedirectUri()); - MvcResult result = this.mockMvc.perform(get(query)).andDo(print()).andReturn(); - String code = Objects.requireNonNull(result.getResponse().getRedirectedUrl()).split("code=")[1]; - String tokenQuery = JSONUtils.toFormUrlEncoded( - new JSONParameter("client_id", clientDTO.getClientId()), - new JSONParameter("client_secret", clientDTO.getClientSecret().replace("{noop}", "")), - new JSONParameter("code", code), - new JSONParameter("grant_type", "authorization_code"), - new JSONParameter("redirect_uri", clientDTO.getWebServerRedirectUri()) - ); - String rawAuth = clientDTO.getClientId() + ":" - + clientDTO.getClientSecret().replace("{noop}", ""); - String auth = Base64.encodeBase64String(rawAuth.getBytes()); - this.mockMvc.perform(post("/oauth/token") - .contentType(MediaType.APPLICATION_FORM_URLENCODED) - .header("Authorization", "Basic " + auth) - .content(tokenQuery)).andDo(print()).andExpect(status().is(200)); - } -} diff --git a/backend/src/test/java/it/chalmers/gamma/api/WhitelistTests.java b/backend/src/test/java/it/chalmers/gamma/api/WhitelistTests.java deleted file mode 100644 index 593be16a6..000000000 --- a/backend/src/test/java/it/chalmers/gamma/api/WhitelistTests.java +++ /dev/null @@ -1,92 +0,0 @@ -package it.chalmers.gamma.api; - -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -import it.chalmers.gamma.GammaApplication; -import it.chalmers.gamma.domain.dto.user.WhitelistDTO; -import it.chalmers.gamma.factories.MockActivationCodeFactory; -import it.chalmers.gamma.factories.MockWhitelistFactory; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.security.test.context.support.WithUserDetails; -import org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.test.context.web.WebAppConfiguration; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; -import org.springframework.web.context.WebApplicationContext; - -@RunWith(SpringRunner.class) -@WebAppConfiguration -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK, classes = GammaApplication.class) -@ActiveProfiles("test") -@SuppressWarnings({"PMD.JUnitTestsShouldIncludeAssert"}) -public class WhitelistTests { - @Autowired - private WebApplicationContext webApplicationContext; - - private MockMvc mockMvc; - - @Autowired - private MockWhitelistFactory mockWhitelistFactory; - - @Autowired - private MockActivationCodeFactory mockActivationCodeFactory; - - private static final String WHITELIST_URL = "/admin/users/whitelist/%s"; - - @Before - public void setupTests() { - this.mockMvc = MockMvcBuilders.webAppContextSetup(this.webApplicationContext) - .apply(SecurityMockMvcConfigurers.springSecurity()) - .build(); - } - - /** - * Tests first to delete whitelist that has valid activation code using the id, then the cid. - * @throws Exception if mockMvc fails. - */ - @WithUserDetails("admin") - @Test - public void testDeleteWhitelistWithActiveActivationCode() throws Exception { - WhitelistDTO whitelist = this.mockWhitelistFactory.saveWhitelist( - this.mockWhitelistFactory.generateWhitelist()); - this.mockActivationCodeFactory.saveActivationCode(whitelist); - - this.mockMvc.perform(delete(String.format(WHITELIST_URL, whitelist.getId()))) - .andExpect(status().isOk()); - - WhitelistDTO whitelist2 = this.mockWhitelistFactory.saveWhitelist( - this.mockWhitelistFactory.generateWhitelist()); - this.mockActivationCodeFactory.saveActivationCode(whitelist2); - - this.mockMvc.perform(delete(String.format(WHITELIST_URL, whitelist2.getCid()))) - .andExpect(status().isOk()); - } - - /** - * Tests first to delete whitelist that does not hav a activation code using the id, then the cid. - * @throws Exception if mockMvc fails. - */ - @WithUserDetails("admin") - @Test - public void testDeleteWhitelistWithNoActiveActivationCode() throws Exception { - WhitelistDTO whitelist = this.mockWhitelistFactory.saveWhitelist( - this.mockWhitelistFactory.generateWhitelist()); - - this.mockMvc.perform(delete(String.format(WHITELIST_URL, whitelist.getId()))) - .andExpect(status().isOk()); - - WhitelistDTO whitelist2 = this.mockWhitelistFactory.saveWhitelist( - this.mockWhitelistFactory.generateWhitelist()); - - this.mockMvc.perform(delete(String.format(WHITELIST_URL, whitelist2.getCid()))) - .andExpect(status().isOk()); - } - -} diff --git a/backend/src/test/java/it/chalmers/gamma/endoints/Endpoint.java b/backend/src/test/java/it/chalmers/gamma/endoints/Endpoint.java deleted file mode 100644 index 8c19e7fe5..000000000 --- a/backend/src/test/java/it/chalmers/gamma/endoints/Endpoint.java +++ /dev/null @@ -1,41 +0,0 @@ -package it.chalmers.gamma.endoints; - -public class Endpoint { - private final String path; - private final Method method; - private final Class mockClass; - - // Add Permission? - public Endpoint(String path, Method method) { - this.path = path; - this.method = method; - this.mockClass = null; - } - - public Endpoint(String path, Method method, Class c) { - this.path = path; - this.method = method; - this.mockClass = c; - } - - public String getPath() { - return this.path; - } - - public Method getMethod() { - return this.method; - } - - public Class getMockClass() { - return this.mockClass; - } - - @Override - public String toString() { - return "Endpoint{" - + "path='" + this.path + '\'' - + ", method=" + this.method - + ", mockClass=" + this.mockClass - + '}'; - } -} diff --git a/backend/src/test/java/it/chalmers/gamma/endoints/EndpointsUtils.java b/backend/src/test/java/it/chalmers/gamma/endoints/EndpointsUtils.java deleted file mode 100644 index c627a5324..000000000 --- a/backend/src/test/java/it/chalmers/gamma/endoints/EndpointsUtils.java +++ /dev/null @@ -1,120 +0,0 @@ -package it.chalmers.gamma.endoints; - -import static it.chalmers.gamma.endoints.Method.DELETE; -import static it.chalmers.gamma.endoints.Method.GET; -import static it.chalmers.gamma.endoints.Method.POST; -import static it.chalmers.gamma.endoints.Method.PUT; - -import it.chalmers.gamma.domain.dto.access.ApiKeyDTO; -import it.chalmers.gamma.domain.dto.access.ITClientDTO; -import it.chalmers.gamma.domain.dto.authority.AuthorityDTO; -import it.chalmers.gamma.domain.dto.authority.AuthorityLevelDTO; -import it.chalmers.gamma.domain.dto.group.FKITGroupDTO; -import it.chalmers.gamma.domain.dto.group.FKITSuperGroupDTO; -import it.chalmers.gamma.domain.dto.post.PostDTO; -import it.chalmers.gamma.domain.dto.user.ActivationCodeDTO; -import it.chalmers.gamma.domain.dto.user.ITUserDTO; -import it.chalmers.gamma.domain.dto.user.WhitelistDTO; -import it.chalmers.gamma.domain.dto.website.WebsiteDTO; -import java.util.Arrays; -import java.util.List; - -public final class EndpointsUtils { // Doesn't return me endpoints. - - private EndpointsUtils() { - - } - - public static List getNormalUserEndpoints() { - return Arrays.asList( - new Endpoint("/groups", GET), - new Endpoint("/groups/active", GET), - new Endpoint("/groups/minified", GET), - new Endpoint("/groups/posts", GET), - new Endpoint("/groups/posts/%s", GET, PostDTO.class), - new Endpoint("/groups/%s", GET, FKITGroupDTO.class), - new Endpoint("/groups/%s/members", GET, FKITGroupDTO.class), - new Endpoint("/groups/%s/minified", GET, FKITGroupDTO.class), - new Endpoint("/superGroups", GET), - new Endpoint("/superGroups/%s", GET, FKITSuperGroupDTO.class), - new Endpoint("/superGroups/%s/active", GET, FKITSuperGroupDTO.class), - new Endpoint("/superGroups/%s/subgroups", GET, FKITSuperGroupDTO.class), - new Endpoint("/users/minified", GET), - new Endpoint("/users/%s", GET, ITUserDTO.class) - ); - } - // TODO Members, to do that, we need to rework Endpoint class a bit. Also, - // GOLDAPPS Should be re-added once it has been rewritten - public static List getAuthorizedEndpoints() { - return Arrays.asList( - new Endpoint("/admin/activation_codes", GET), - new Endpoint("/admin/activation_codes/%s", GET, ActivationCodeDTO.class), - new Endpoint("/admin/activation_codes/%s", DELETE, ActivationCodeDTO.class), - new Endpoint("/admin/api_keys", GET), - new Endpoint("/admin/api_keys", POST), - new Endpoint("/admin/api_keys/%s", GET, ApiKeyDTO.class), - new Endpoint("/admin/api_keys/%s", DELETE, ApiKeyDTO.class), - new Endpoint("/admin/authority", GET), - new Endpoint("/admin/authority", GET), - new Endpoint("/admin/authority/level", GET), - new Endpoint("/admin/authority/level", POST), - new Endpoint("/admin/authority/level/%s", DELETE, AuthorityLevelDTO.class), - new Endpoint("/admin/authority/%s", GET, AuthorityDTO.class), - new Endpoint("/admin/authority/%s", DELETE, AuthorityDTO.class), - new Endpoint("/admin/clients", GET), - new Endpoint("/admin/clients", POST), - new Endpoint("/admin/clients/%s", GET, ITClientDTO.class), - new Endpoint("/admin/clients/%s", PUT, ITClientDTO.class), - new Endpoint("/admin/clients/%s", DELETE, ITClientDTO.class), - new Endpoint("/admin/gdpr/minified", GET), - new Endpoint("/admin/gdpr/%s", PUT, ITUserDTO.class), - new Endpoint("/admin/groups", POST), - new Endpoint("/admin/groups/%s", PUT, FKITGroupDTO.class), - new Endpoint("/admin/groups/%s", DELETE, FKITGroupDTO.class), - new Endpoint("/admin/groups/%s/avatar", PUT, FKITGroupDTO.class), - new Endpoint("/admin/groups/posts", POST), - new Endpoint("/admin/groups/posts/%s", PUT, PostDTO.class), - new Endpoint("/admin/groups/posts/%s", DELETE, PostDTO.class), - new Endpoint("/admin/groups/posts/%s/usage", GET, PostDTO.class), - new Endpoint("/admin/superGroups", POST), - new Endpoint("/admin/superGroups/%s", PUT, FKITSuperGroupDTO.class), - new Endpoint("/admin/superGroups/%s", DELETE, FKITSuperGroupDTO.class), - new Endpoint("/admin/users", GET), - new Endpoint("/admin/users", POST), - new Endpoint("/admin/users/%s", GET, ITUserDTO.class), - new Endpoint("/admin/users/%s", PUT, ITUserDTO.class), - new Endpoint("/admin/users/%s", DELETE, ITUserDTO.class), - new Endpoint("/admin/users/%s/change_password", PUT, ITUserDTO.class), - new Endpoint("/admin/users/whitelist", GET), - new Endpoint("/admin/users/whitelist", POST), - new Endpoint("/admin/users/whitelist/%s/valid", GET, WhitelistDTO.class), - new Endpoint("/admin/users/whitelist/%s", GET, WhitelistDTO.class), - new Endpoint("/admin/users/whitelist/%s", PUT, WhitelistDTO.class), - new Endpoint("/admin/users/whitelist/%s", DELETE, WhitelistDTO.class), - new Endpoint("/admin/websites", POST), - new Endpoint("/admin/websites/%s", PUT, WebsiteDTO.class), - new Endpoint("/admin/websites/%s", DELETE, WebsiteDTO.class) - - - ); - } - - public static List getMeEndpoints() { - return Arrays.asList( - new Endpoint("/users/me", GET), - new Endpoint("/users/me", PUT), - new Endpoint("/users/me", DELETE), - new Endpoint("/users/me/avatar", PUT), - new Endpoint("/users/me/change_password", POST)); - } - - public static List getNonAuthorizedEndpoints() { - return Arrays.asList( - new Endpoint("/users/reset_password", POST), - new Endpoint("/users/reset_password/finish", PUT), - new Endpoint("/login", GET), - new Endpoint("/whitelist/activate_cid", POST), - new Endpoint("/users/create", POST) - ); - } -} diff --git a/backend/src/test/java/it/chalmers/gamma/endoints/JSONParameter.java b/backend/src/test/java/it/chalmers/gamma/endoints/JSONParameter.java deleted file mode 100644 index 8d04c58cc..000000000 --- a/backend/src/test/java/it/chalmers/gamma/endoints/JSONParameter.java +++ /dev/null @@ -1,27 +0,0 @@ -package it.chalmers.gamma.endoints; - -public class JSONParameter { - private final String key; - private final String value; - - public JSONParameter(String key, String value) { - this.key = key; - this.value = value; - } - - public String getKey() { - return this.key; - } - - public String getValue() { - return this.value; - } - - @Override - public String toString() { - return "JSONParameter{" - + "key='" + this.key + '\'' - + ", value='" + this.value + '\'' - + '}'; - } -} diff --git a/backend/src/test/java/it/chalmers/gamma/endoints/Method.java b/backend/src/test/java/it/chalmers/gamma/endoints/Method.java deleted file mode 100644 index 67393e549..000000000 --- a/backend/src/test/java/it/chalmers/gamma/endoints/Method.java +++ /dev/null @@ -1,5 +0,0 @@ -package it.chalmers.gamma.endoints; - -public enum Method { - GET, POST, PUT, DELETE; -} diff --git a/backend/src/test/java/it/chalmers/gamma/factories/MockActivationCodeFactory.java b/backend/src/test/java/it/chalmers/gamma/factories/MockActivationCodeFactory.java deleted file mode 100644 index 4e1e36a67..000000000 --- a/backend/src/test/java/it/chalmers/gamma/factories/MockActivationCodeFactory.java +++ /dev/null @@ -1,39 +0,0 @@ -package it.chalmers.gamma.factories; - -import it.chalmers.gamma.domain.dto.user.ActivationCodeDTO; -import it.chalmers.gamma.domain.dto.user.WhitelistDTO; -import it.chalmers.gamma.requests.WhitelistCodeRequest; -import it.chalmers.gamma.service.ActivationCodeService; -import it.chalmers.gamma.utils.CharacterTypes; -import it.chalmers.gamma.utils.GenerationUtils; -import java.time.Instant; -import java.util.UUID; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -@Component -public class MockActivationCodeFactory { - - @Autowired - private ActivationCodeService activationCodeService; - - public ActivationCodeDTO generateActivationCode(WhitelistDTO whitelist) { - return new ActivationCodeDTO( - UUID.randomUUID(), - whitelist, - GenerationUtils.generateRandomString(15, CharacterTypes.NUMBERS), - Instant.now(), - 100_000 // Easier to read - ); - } - - public ActivationCodeDTO saveActivationCode(WhitelistDTO whitelist) { - return this.activationCodeService.saveActivationCode(whitelist); - } - - public WhitelistCodeRequest createValidRequest(WhitelistDTO whitelist) { - WhitelistCodeRequest request = new WhitelistCodeRequest(); - request.setCid(whitelist.getCid()); - return request; - } -} diff --git a/backend/src/test/java/it/chalmers/gamma/factories/MockApiKeyFactory.java b/backend/src/test/java/it/chalmers/gamma/factories/MockApiKeyFactory.java deleted file mode 100644 index 0e673dabf..000000000 --- a/backend/src/test/java/it/chalmers/gamma/factories/MockApiKeyFactory.java +++ /dev/null @@ -1,41 +0,0 @@ -package it.chalmers.gamma.factories; - -import it.chalmers.gamma.domain.dto.access.ApiKeyDTO; -import it.chalmers.gamma.requests.CreateApiKeyRequest; -import it.chalmers.gamma.service.ApiKeyService; -import it.chalmers.gamma.utils.CharacterTypes; -import it.chalmers.gamma.utils.GenerationUtils; -import java.time.Instant; -import java.util.UUID; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -@Component -public class MockApiKeyFactory { - - @Autowired - private ApiKeyService apiKeyService; - - public ApiKeyDTO generateApiKey() { - return new ApiKeyDTO( - UUID.randomUUID(), - GenerationUtils.generateRandomString(20, CharacterTypes.LOWERCASE), - GenerationUtils.generateText(), - Instant.now(), - Instant.now(), - GenerationUtils.generateRandomString(20, CharacterTypes.LOWERCASE) - ); - } - - public ApiKeyDTO saveApiKey(ApiKeyDTO apiKeyDTO) { - return this.apiKeyService.createApiKey(apiKeyDTO); - } - - public CreateApiKeyRequest createValidRequest(ApiKeyDTO apiKey) { - CreateApiKeyRequest request = new CreateApiKeyRequest(); - request.setName(apiKey.getName()); - request.setDescription(apiKey.getDescription()); - return request; - } - -} diff --git a/backend/src/test/java/it/chalmers/gamma/factories/MockAuthorityFactory.java b/backend/src/test/java/it/chalmers/gamma/factories/MockAuthorityFactory.java deleted file mode 100644 index fdd9ea512..000000000 --- a/backend/src/test/java/it/chalmers/gamma/factories/MockAuthorityFactory.java +++ /dev/null @@ -1,44 +0,0 @@ -package it.chalmers.gamma.factories; - -import it.chalmers.gamma.domain.dto.authority.AuthorityDTO; -import it.chalmers.gamma.domain.dto.authority.AuthorityLevelDTO; -import it.chalmers.gamma.domain.dto.group.FKITSuperGroupDTO; -import it.chalmers.gamma.domain.dto.post.PostDTO; -import it.chalmers.gamma.requests.AddAuthorityRequest; -import it.chalmers.gamma.service.AuthorityService; -import java.util.UUID; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -@Component -public class MockAuthorityFactory { - - @Autowired - private AuthorityService authorityService; - - public AuthorityDTO generateAuthority(FKITSuperGroupDTO superGroup, - PostDTO post, - AuthorityLevelDTO authorityLevel) { - return new AuthorityDTO( - superGroup, - post, - UUID.randomUUID(), - authorityLevel - ); - } - - public AuthorityDTO saveAuthority(AuthorityDTO authority) { - return this.authorityService.createAuthority( - authority.getSuperGroup(), - authority.getPost(), - authority.getAuthorityLevel()); - } - - public AddAuthorityRequest createValidRequest(AuthorityDTO authority, PostDTO post, FKITSuperGroupDTO superGroup) { - AddAuthorityRequest request = new AddAuthorityRequest(); - request.setAuthority(authority.getAuthorityLevel().getId().toString()); - request.setPost(post.getId().toString()); - request.setSuperGroup(superGroup.getId().toString()); - return request; - } -} diff --git a/backend/src/test/java/it/chalmers/gamma/factories/MockAuthorityLevelFactory.java b/backend/src/test/java/it/chalmers/gamma/factories/MockAuthorityLevelFactory.java deleted file mode 100644 index 2c8cf2cef..000000000 --- a/backend/src/test/java/it/chalmers/gamma/factories/MockAuthorityLevelFactory.java +++ /dev/null @@ -1,34 +0,0 @@ -package it.chalmers.gamma.factories; - -import it.chalmers.gamma.domain.dto.authority.AuthorityLevelDTO; -import it.chalmers.gamma.requests.AddAuthorityLevelRequest; -import it.chalmers.gamma.service.AuthorityLevelService; -import it.chalmers.gamma.utils.CharacterTypes; -import it.chalmers.gamma.utils.GenerationUtils; -import java.util.UUID; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -@Component -public class MockAuthorityLevelFactory { - - @Autowired - private AuthorityLevelService authorityLevelService; - - public AuthorityLevelDTO generateAuthorityLevel() { - return new AuthorityLevelDTO( - UUID.randomUUID(), - GenerationUtils.generateRandomString(10, CharacterTypes.LOWERCASE) - ); - } - - public AuthorityLevelDTO saveAuthorityLevel(AuthorityLevelDTO authorityLevel) { - return this.authorityLevelService.addAuthorityLevel(authorityLevel.getAuthority()); - } - - public AddAuthorityLevelRequest createValidRequest(AuthorityLevelDTO authorityLevel) { - AddAuthorityLevelRequest request = new AddAuthorityLevelRequest(); - request.setAuthorityLevel(authorityLevel.getAuthority()); - return request; - } -} diff --git a/backend/src/test/java/it/chalmers/gamma/factories/MockDatabaseGeneratorFactory.java b/backend/src/test/java/it/chalmers/gamma/factories/MockDatabaseGeneratorFactory.java deleted file mode 100644 index 7bc67e360..000000000 --- a/backend/src/test/java/it/chalmers/gamma/factories/MockDatabaseGeneratorFactory.java +++ /dev/null @@ -1,138 +0,0 @@ -package it.chalmers.gamma.factories; - -import it.chalmers.gamma.domain.dto.access.ApiKeyDTO; -import it.chalmers.gamma.domain.dto.access.ITClientDTO; -import it.chalmers.gamma.domain.dto.authority.AuthorityDTO; -import it.chalmers.gamma.domain.dto.authority.AuthorityLevelDTO; -import it.chalmers.gamma.domain.dto.group.FKITGroupDTO; -import it.chalmers.gamma.domain.dto.group.FKITSuperGroupDTO; -import it.chalmers.gamma.domain.dto.post.PostDTO; -import it.chalmers.gamma.domain.dto.user.ActivationCodeDTO; -import it.chalmers.gamma.domain.dto.user.ITUserDTO; -import it.chalmers.gamma.domain.dto.user.WhitelistDTO; -import it.chalmers.gamma.domain.dto.website.WebsiteDTO; -import it.chalmers.gamma.utils.GenerationUtils; -import java.util.UUID; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -@Component -@SuppressWarnings({"PMD.TooManyFields", "PMD.CyclomaticComplexity", "PMD.NPathComplexity"}) -public class MockDatabaseGeneratorFactory { - - @Autowired - private MockITUserFactory mockITUserFactory; - @Autowired - private MockFKITGroupFactory mockFKITGroupFactory; - @Autowired - private MockITClientFactory mockITClientFactory; - @Autowired - private MockActivationCodeFactory mockActivationCodeFactory; - @Autowired - private MockApiKeyFactory mockApiKeyFactory; - @Autowired - private MockAuthorityLevelFactory mockAuthorityLevelFactory; - @Autowired - private MockSuperGroupFactory mockSuperGroupFactory; - @Autowired - private MockMembershipFactory mockMembershipFactory; - @Autowired - private MockWebsiteFactory mockWebsiteFactory; - @Autowired - private MockAuthorityFactory mockAuthorityFactory; - @Autowired - private MockPostFactory mockPostFactory; - @Autowired - private MockWhitelistFactory mockWhitelistFactory; - - - - private ITUserDTO user; - private PostDTO post; - private FKITGroupDTO group; - private FKITSuperGroupDTO superGroup; - private ActivationCodeDTO activationCode; - private ApiKeyDTO apiKey; - private AuthorityLevelDTO authorityLevel; - private AuthorityDTO authority; - private ITClientDTO client; - private WhitelistDTO whitelist; - private WebsiteDTO website; - - private static boolean hasGeneratedMock; - - public void populateMockDatabase() { // TODO Remove the clutter in this method - if (!hasGeneratedMock) { - this.user = this.mockITUserFactory.saveUser(this.mockITUserFactory.generateITUser("user", true)); - this.post = this.mockPostFactory.savePost(this.mockPostFactory.generatePost()); - this.superGroup = this.mockSuperGroupFactory.saveSuperGroup( - this.mockSuperGroupFactory.generateSuperGroup("group") - ); - this.group = this.mockFKITGroupFactory.saveGroup(this.mockFKITGroupFactory.generateActiveFKITGroup( - "group", - this.superGroup - )); - this.whitelist = this.mockWhitelistFactory.saveWhitelist(this.mockWhitelistFactory.generateWhitelist()); - this.activationCode = this.mockActivationCodeFactory.saveActivationCode(this.whitelist); - this.apiKey = this.mockApiKeyFactory.saveApiKey(this.mockApiKeyFactory.generateApiKey()); - - this.authorityLevel = this.mockAuthorityLevelFactory.saveAuthorityLevel( - this.mockAuthorityLevelFactory.generateAuthorityLevel()); - this.authority = this.mockAuthorityFactory.saveAuthority( - this.mockAuthorityFactory.generateAuthority( - this.superGroup, - this.post, - this.authorityLevel - )); - this.client = this.mockITClientFactory.saveClient(this.mockITClientFactory.generateClient( - GenerationUtils.generateRandomString() - )); - this.website = this.mockWebsiteFactory.saveWebsite(this.mockWebsiteFactory.generateWebsite()); - this.mockMembershipFactory.saveMembership( - this.mockMembershipFactory.generateMembership( - this.post, - this.group, - this.user)); - hasGeneratedMock = true; - } - } - - // Make this prettier by making a list and looping, or by using interfaces - public UUID getMockedUUID(Class c) { - if (this.user.getClass() == c) { - return this.user.getId(); - } - if (this.post.getClass() == c) { - return this.post.getId(); - } - if (this.group.getClass() == c) { - return this.group.getId(); - } - if (this.superGroup.getClass() == c) { - return this.superGroup.getId(); - } - if (this.activationCode.getClass() == c) { - return this.activationCode.getId(); - } - if (this.apiKey.getClass() == c) { - return this.apiKey.getId(); - } - if (this.authority.getClass() == c) { - return this.authority.getId(); - } - if (this.client.getClass() == c) { - return this.client.getId(); - } - if (this.website.getClass() == c) { - return this.website.getId(); - } - if (this.authorityLevel.getClass() == c) { - return this.authorityLevel.getId(); - } - if (this.whitelist.getClass() == c) { - return this.whitelist.getId(); - } - return null; - } - -} diff --git a/backend/src/test/java/it/chalmers/gamma/factories/MockFKITGroupFactory.java b/backend/src/test/java/it/chalmers/gamma/factories/MockFKITGroupFactory.java deleted file mode 100644 index ae46ba89e..000000000 --- a/backend/src/test/java/it/chalmers/gamma/factories/MockFKITGroupFactory.java +++ /dev/null @@ -1,50 +0,0 @@ -package it.chalmers.gamma.factories; - -import it.chalmers.gamma.db.entity.Text; -import it.chalmers.gamma.domain.dto.group.FKITGroupDTO; -import it.chalmers.gamma.domain.dto.group.FKITSuperGroupDTO; -import it.chalmers.gamma.requests.CreateGroupRequest; -import it.chalmers.gamma.service.FKITGroupService; -import it.chalmers.gamma.utils.CharacterTypes; -import it.chalmers.gamma.utils.GenerationUtils; -import java.util.Calendar; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -@Component -public class MockFKITGroupFactory { - - @Autowired - private FKITGroupService groupService; - - public FKITGroupDTO generateActiveFKITGroup(String groupName, FKITSuperGroupDTO superGroupDTO) { - Calendar current = Calendar.getInstance(); - Calendar nextYear = Calendar.getInstance(); - nextYear.add(Calendar.YEAR, 1); - return new FKITGroupDTO( - current, - nextYear, - new Text(), - GenerationUtils.generateRandomString(), - new Text(), - groupName, - groupName, - GenerationUtils.generateRandomString(), - superGroupDTO - ); - } - - public FKITGroupDTO saveGroup(FKITGroupDTO group) { - return this.groupService.createGroup(group); - } - - public CreateGroupRequest createValidRequest() { - CreateGroupRequest request = new CreateGroupRequest(); - request.setName(GenerationUtils.generateRandomString(30, CharacterTypes.LOWERCASE)); - request.setPrettyName(GenerationUtils.generateRandomString(30, CharacterTypes.LOWERCASE)); - request.setFunction(GenerationUtils.generateText()); - request.setBecomesActive(Calendar.getInstance()); - request.setBecomesInactive(Calendar.getInstance()); - return request; - } -} diff --git a/backend/src/test/java/it/chalmers/gamma/factories/MockITClientFactory.java b/backend/src/test/java/it/chalmers/gamma/factories/MockITClientFactory.java deleted file mode 100644 index a6eee28c6..000000000 --- a/backend/src/test/java/it/chalmers/gamma/factories/MockITClientFactory.java +++ /dev/null @@ -1,42 +0,0 @@ -package it.chalmers.gamma.factories; - -import it.chalmers.gamma.domain.dto.access.ITClientDTO; -import it.chalmers.gamma.service.ITClientService; -import it.chalmers.gamma.utils.CharacterTypes; -import it.chalmers.gamma.utils.GenerationUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -@Component -public class MockITClientFactory { - - @Autowired - private ITClientService clientService; - - public ITClientDTO generateClient(String redirect) { - return new ITClientDTO( - redirect, - GenerationUtils.generateRandomString(20, CharacterTypes.LOWERCASE), - GenerationUtils.generateText(), - true - ); - } - - public ITClientDTO generateClientNonAutoApprove(String redirect) { - return new ITClientDTO( - redirect, - GenerationUtils.generateRandomString(20, CharacterTypes.LOWERCASE), - GenerationUtils.generateText(), - false - ); - - } - - public ITClientDTO saveClient(ITClientDTO client) { - return this.clientService.createITClient( - client.getName(), - client.getDescription(), - client.getWebServerRedirectUri(), - client.isAutoApprove()); - } -} diff --git a/backend/src/test/java/it/chalmers/gamma/factories/MockITUserApprovalFactory.java b/backend/src/test/java/it/chalmers/gamma/factories/MockITUserApprovalFactory.java deleted file mode 100644 index f9f20a15c..000000000 --- a/backend/src/test/java/it/chalmers/gamma/factories/MockITUserApprovalFactory.java +++ /dev/null @@ -1,17 +0,0 @@ -package it.chalmers.gamma.factories; - -import it.chalmers.gamma.service.ITUserApprovalService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -@Component -public class MockITUserApprovalFactory { - - @Autowired - private ITUserApprovalService approvalService; - - public void approve(String cid, String clientId) { - this.approvalService.saveApproval(cid, clientId); - } - -} diff --git a/backend/src/test/java/it/chalmers/gamma/factories/MockITUserFactory.java b/backend/src/test/java/it/chalmers/gamma/factories/MockITUserFactory.java deleted file mode 100644 index a82be6750..000000000 --- a/backend/src/test/java/it/chalmers/gamma/factories/MockITUserFactory.java +++ /dev/null @@ -1,85 +0,0 @@ -package it.chalmers.gamma.factories; - -import it.chalmers.gamma.domain.Language; -import it.chalmers.gamma.domain.dto.user.ActivationCodeDTO; -import it.chalmers.gamma.domain.dto.user.ITUserDTO; -import it.chalmers.gamma.requests.AdminViewCreateITUserRequest; -import it.chalmers.gamma.requests.CreateITUserRequest; -import it.chalmers.gamma.service.ITUserService; -import it.chalmers.gamma.utils.CharacterTypes; -import it.chalmers.gamma.utils.GenerationUtils; -import java.time.Year; -import java.util.UUID; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -@Component -public class MockITUserFactory { - - @Autowired - private ITUserService userService; - - public ITUserDTO generateITUser(String cid, boolean activated) { - return new ITUserDTO( - UUID.randomUUID(), - cid, - GenerationUtils.generateRandomString(), - GenerationUtils.generateRandomString(), - GenerationUtils.generateRandomString(), - GenerationUtils.generateEmail(), - GenerationUtils.generateRandomString(), - Language.sv, - "", - false, - true, - false, - Year.of(GenerationUtils.generateIntBetween(2001, 2020)), - activated); - } - - - public AdminViewCreateITUserRequest generateValidAdminCreateUserRequest() { - AdminViewCreateITUserRequest request = new AdminViewCreateITUserRequest(); - request.setAcceptanceYear(GenerationUtils.generateIntBetween(2001, 2020)); - request.setEmail(GenerationUtils.generateEmail()); - request.setFirstName(GenerationUtils.generateRandomString()); - request.setLastName(GenerationUtils.generateRandomString()); - request.setLanguage(Language.sv); - request.setNick(GenerationUtils.generateRandomString()); - request.setPassword(GenerationUtils.generateRandomString()); - request.setUserAgreement(true); - request.setCid(GenerationUtils.generateRandomString(10, CharacterTypes.LOWERCASE)); - return request; - } - - public ITUserDTO saveUser(ITUserDTO userDTO) { - ITUserDTO user = this.userService.createUser( - userDTO.getId(), - userDTO.getNick(), - userDTO.getFirstName(), - userDTO.getLastName(), - userDTO.getCid(), - userDTO.getAcceptanceYear(), - userDTO.isUserAgreement(), - userDTO.getEmail(), - "password" - ); - this.userService.setAccountActivated(user, userDTO.isActivated()); - return this.userService.getITUser(user.getCid()); - } - - public CreateITUserRequest createValidCreateRequest(ITUserDTO user, ActivationCodeDTO activationCode) { - CreateITUserRequest request = new CreateITUserRequest(); - request.setAcceptanceYear(user.getAcceptanceYear().getValue()); - request.setCode(activationCode.getCode()); - request.setEmail(user.getEmail()); - request.setFirstName(user.getFirstName()); - request.setLastName(user.getLastName()); - request.setLanguage(user.getLanguage()); - request.setNick(user.getNick()); - request.setPassword("password"); - request.setUserAgreement(user.isUserAgreement()); - request.setWhitelist(activationCode.getWhitelistDTO()); - return request; - } -} diff --git a/backend/src/test/java/it/chalmers/gamma/factories/MockMembershipFactory.java b/backend/src/test/java/it/chalmers/gamma/factories/MockMembershipFactory.java deleted file mode 100644 index 959fa6932..000000000 --- a/backend/src/test/java/it/chalmers/gamma/factories/MockMembershipFactory.java +++ /dev/null @@ -1,37 +0,0 @@ -package it.chalmers.gamma.factories; - -import it.chalmers.gamma.domain.dto.group.FKITGroupDTO; -import it.chalmers.gamma.domain.dto.membership.MembershipDTO; -import it.chalmers.gamma.domain.dto.post.PostDTO; -import it.chalmers.gamma.domain.dto.user.ITUserDTO; -import it.chalmers.gamma.service.MembershipService; -import it.chalmers.gamma.utils.CharacterTypes; -import it.chalmers.gamma.utils.GenerationUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -@Component -public class MockMembershipFactory { - - @Autowired - private MembershipService membershipService; - - public MembershipDTO generateMembership(PostDTO post, FKITGroupDTO group, ITUserDTO user) { - return new MembershipDTO( - post, - group, - GenerationUtils.generateRandomString(20, CharacterTypes.LOWERCASE), - user - ); - } - - public MembershipDTO saveMembership(MembershipDTO membership) { - return this.membershipService.addUserToGroup( - membership.getFkitGroupDTO(), - membership.getUser(), - membership.getPost(), - membership.getUnofficialPostName() - ); - } - -} diff --git a/backend/src/test/java/it/chalmers/gamma/factories/MockPostFactory.java b/backend/src/test/java/it/chalmers/gamma/factories/MockPostFactory.java deleted file mode 100644 index 4bbc7cbb3..000000000 --- a/backend/src/test/java/it/chalmers/gamma/factories/MockPostFactory.java +++ /dev/null @@ -1,28 +0,0 @@ -package it.chalmers.gamma.factories; - -import it.chalmers.gamma.domain.dto.post.PostDTO; -import it.chalmers.gamma.service.PostService; -import it.chalmers.gamma.utils.GenerationUtils; -import java.util.UUID; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -@Component -public class MockPostFactory { - - @Autowired - private PostService postService; - - public PostDTO generatePost() { - return new PostDTO( - UUID.randomUUID(), - GenerationUtils.generateText(), - GenerationUtils.generateEmail() - ); - } - - public PostDTO savePost(PostDTO post) { - return this.postService.addPost(post.getPostName()); - } - -} diff --git a/backend/src/test/java/it/chalmers/gamma/factories/MockSuperGroupFactory.java b/backend/src/test/java/it/chalmers/gamma/factories/MockSuperGroupFactory.java deleted file mode 100644 index 99f4c1e29..000000000 --- a/backend/src/test/java/it/chalmers/gamma/factories/MockSuperGroupFactory.java +++ /dev/null @@ -1,28 +0,0 @@ -package it.chalmers.gamma.factories; - -import it.chalmers.gamma.domain.GroupType; -import it.chalmers.gamma.domain.dto.group.FKITSuperGroupDTO; -import it.chalmers.gamma.service.FKITSuperGroupService; -import it.chalmers.gamma.utils.GenerationUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -@Component -public class MockSuperGroupFactory { - - @Autowired - private FKITSuperGroupService superGroupService; - - public FKITSuperGroupDTO generateSuperGroup(String groupName) { - return new FKITSuperGroupDTO( - groupName, - groupName, - GroupType.COMMITTEE, - GenerationUtils.generateRandomString() - ); - } - - public FKITSuperGroupDTO saveSuperGroup(FKITSuperGroupDTO superGroup) { - return this.superGroupService.createSuperGroup(superGroup); - } -} diff --git a/backend/src/test/java/it/chalmers/gamma/factories/MockWebsiteFactory.java b/backend/src/test/java/it/chalmers/gamma/factories/MockWebsiteFactory.java deleted file mode 100644 index 3ed80b223..000000000 --- a/backend/src/test/java/it/chalmers/gamma/factories/MockWebsiteFactory.java +++ /dev/null @@ -1,28 +0,0 @@ -package it.chalmers.gamma.factories; - -import it.chalmers.gamma.domain.dto.website.WebsiteDTO; -import it.chalmers.gamma.service.WebsiteService; -import it.chalmers.gamma.utils.CharacterTypes; -import it.chalmers.gamma.utils.GenerationUtils; -import java.util.UUID; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -@Component -public class MockWebsiteFactory { - - @Autowired - private WebsiteService websiteService; - - public WebsiteDTO generateWebsite() { - return new WebsiteDTO( - UUID.randomUUID(), - GenerationUtils.generateRandomString(20, CharacterTypes.LOWERCASE), - GenerationUtils.generateRandomString(20, CharacterTypes.LOWERCASE) - ); - } - - public WebsiteDTO saveWebsite(WebsiteDTO website) { - return this.websiteService.addPossibleWebsite(website.getName(), website.getPrettyName()); - } -} diff --git a/backend/src/test/java/it/chalmers/gamma/factories/MockWhitelistFactory.java b/backend/src/test/java/it/chalmers/gamma/factories/MockWhitelistFactory.java deleted file mode 100644 index ed12263fe..000000000 --- a/backend/src/test/java/it/chalmers/gamma/factories/MockWhitelistFactory.java +++ /dev/null @@ -1,34 +0,0 @@ -package it.chalmers.gamma.factories; - -import it.chalmers.gamma.domain.dto.user.WhitelistDTO; -import it.chalmers.gamma.requests.WhitelistCodeRequest; -import it.chalmers.gamma.service.WhitelistService; -import it.chalmers.gamma.utils.CharacterTypes; -import it.chalmers.gamma.utils.GenerationUtils; -import java.util.UUID; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -@Component -public class MockWhitelistFactory { - - @Autowired - private WhitelistService whitelistService; - - public WhitelistDTO generateWhitelist() { - return new WhitelistDTO( - UUID.randomUUID(), - GenerationUtils.generateRandomString(5, CharacterTypes.LOWERCASE) - ); - } - - public WhitelistDTO saveWhitelist(WhitelistDTO whitelist) { - return this.whitelistService.addWhiteListedCID(whitelist.getCid()); - } - - public WhitelistCodeRequest createValidRequest(WhitelistDTO whitelist) { - WhitelistCodeRequest request = new WhitelistCodeRequest(); - request.setCid(whitelist.getCid()); - return request; - } -} diff --git a/backend/src/test/java/it/chalmers/gamma/service/ActivationCodeServiceTests.java b/backend/src/test/java/it/chalmers/gamma/service/ActivationCodeServiceTests.java deleted file mode 100644 index d675d5950..000000000 --- a/backend/src/test/java/it/chalmers/gamma/service/ActivationCodeServiceTests.java +++ /dev/null @@ -1,40 +0,0 @@ -package it.chalmers.gamma.service; - -import it.chalmers.gamma.domain.dto.user.WhitelistDTO; -import it.chalmers.gamma.factories.MockActivationCodeFactory; -import it.chalmers.gamma.factories.MockWhitelistFactory; -import org.junit.Assert; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.annotation.DirtiesContext; -import org.springframework.test.context.TestPropertySource; -import org.springframework.test.context.junit4.SpringRunner; - -@RunWith(SpringRunner.class) -@SpringBootTest -@TestPropertySource(locations = "classpath:application-test.properties") -@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_CLASS) -public class ActivationCodeServiceTests { - - @Autowired - private MockActivationCodeFactory mockActivationCodeFactory; - - @Autowired - private MockWhitelistFactory mockWhitelistFactory; - - @Autowired - private ActivationCodeService activationCodeService; - - // This - @Test - public void testCreateMultipleActivationCodes() { - WhitelistDTO whitelist = this.mockWhitelistFactory.saveWhitelist(this.mockWhitelistFactory.generateWhitelist()); - this.mockActivationCodeFactory.saveActivationCode(whitelist); - this.mockActivationCodeFactory.saveActivationCode(whitelist); - Assert.assertTrue(this.activationCodeService.codeExists(whitelist.getCid())); - } - - -} diff --git a/backend/src/test/java/it/chalmers/gamma/service/FKITGroupServiceTests.java b/backend/src/test/java/it/chalmers/gamma/service/FKITGroupServiceTests.java deleted file mode 100644 index baf2ed66b..000000000 --- a/backend/src/test/java/it/chalmers/gamma/service/FKITGroupServiceTests.java +++ /dev/null @@ -1,60 +0,0 @@ -package it.chalmers.gamma.service; - -import java.util.Calendar; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.annotation.DirtiesContext; -import org.springframework.test.context.TestPropertySource; -import org.springframework.test.context.junit4.SpringRunner; - -@RunWith(SpringRunner.class) -@SpringBootTest -@TestPropertySource(locations = "classpath:application-test.properties") -@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_CLASS) -@SuppressWarnings("PMD.JUnitTestsShouldIncludeAssert") -public class FKITGroupServiceTests { - - @Autowired - FKITGroupService fkitGroupService; - - @Test - public void createAndValidateGroup() { - Calendar becomesActive = Calendar.getInstance(); - becomesActive.set(Calendar.MONTH, Calendar.JANUARY); - becomesActive.set(Calendar.DAY_OF_MONTH, 1); - - Calendar becomesInactive = Calendar.getInstance(); - becomesInactive.set(Calendar.MONTH, Calendar.MARCH); - becomesInactive.set(Calendar.DAY_OF_MONTH, 1); - - /* CreateGroupRequest createGroupRequest = new CreateGroupRequest("digit", "digIT", - new Text("digIT beskrivning", "digIT description"), - new Text("digIT funktion", "digIT function"), - "url", new ArrayList<>(), becomesActive, becomesInactive, - "admin", "mail@mail.com" - );*/ - - // fkitGroupService.createGroup(createGroupRequest); - // FKITGroup group = fkitGroupService.getDTOGroup(createGroupRequest.getName()); - - // assertRequestEntityEquals(createGroupRequest, group); - } - - /*private void assertRequestEntityEquals(CreateGroupRequest c, FKITGroup g) { - Assert.assertEquals(c.getName(), g.getName()); - Assert.assertEquals(c.getFunction(), g.getFunction()); - Assert.assertEquals(c.getDescription(), g.getDescription()); - Assert.assertEquals(c.getPrettyName(), g.getPrettyName()); - Assert.assertEquals(c.getAvatarURL(), g.getAvatarURL()); - Assert.assertEquals(c.getEmail(), g.getEmail()); - - //Compare dates - //Assert.assertEquals(0, c.getBecomesActive().compareTo(g.getBecomesActive())); - //Assert.assertEquals(0, c.getBecomesInactive().compareTo(g.getBecomesInactive())); - }*/ - -} - diff --git a/backend/src/test/java/it/chalmers/gamma/service/WhitelistServiceTests.java b/backend/src/test/java/it/chalmers/gamma/service/WhitelistServiceTests.java deleted file mode 100644 index 583c36c3e..000000000 --- a/backend/src/test/java/it/chalmers/gamma/service/WhitelistServiceTests.java +++ /dev/null @@ -1,74 +0,0 @@ -package it.chalmers.gamma.service; - -import it.chalmers.gamma.domain.dto.user.WhitelistDTO; -import it.chalmers.gamma.factories.MockActivationCodeFactory; -import it.chalmers.gamma.factories.MockWhitelistFactory; -import org.junit.Assert; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.annotation.DirtiesContext; -import org.springframework.test.context.TestPropertySource; -import org.springframework.test.context.junit4.SpringRunner; - -@RunWith(SpringRunner.class) -@SpringBootTest -@TestPropertySource(locations = "classpath:application-test.properties") -@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_CLASS) -public class WhitelistServiceTests { - - @Autowired - private WhitelistService whitelistService; - - @Autowired - private MockWhitelistFactory mockWhitelistFactory; - - @Autowired - private MockActivationCodeFactory mockActivationCodeFactory; - - /** - * Tests if adding a CID to the whitelist works, and if seeing if a non-whitelisted CID returns correct result. - */ - @Test - public void testWhiteList() { - String cid = "cid3"; - this.whitelistService.addWhiteListedCID(cid); - this.whitelistService.addWhiteListedCID("cid4"); - Assert.assertTrue(this.whitelistService.isCIDWhiteListed(cid)); - Assert.assertFalse(this.whitelistService.isCIDWhiteListed("leif")); - } - - @Test - public void testDeleteActivationCode() { - String cid = "cid5"; - this.whitelistService.addWhiteListedCID(cid); - this.whitelistService.removeWhiteListedCID(cid); - Assert.assertFalse(this.whitelistService.isCIDWhiteListed(cid)); - } - - - /** - * Tests if a CID can be added to the whitelisted database more than once. - */ - @Test - public void testAddWhitelistCIDMultipleTimes() { - String cid = "cid1"; - try { - this.whitelistService.addWhiteListedCID(cid); - this.whitelistService.addWhiteListedCID(cid); - Assert.fail(); - } catch (Exception ignored) { - Assert.assertTrue(true); - } - } - - @Test - public void testRemoveWhitelistWithConnectedActivationCode() { - WhitelistDTO whitelist = this.mockWhitelistFactory.saveWhitelist(this.mockWhitelistFactory.generateWhitelist()); - this.mockActivationCodeFactory.saveActivationCode(whitelist); - this.whitelistService.removeWhiteListedCID(whitelist.getCid()); - Assert.assertFalse(this.whitelistService.isCIDWhiteListed(whitelist.getCid())); - } - -} \ No newline at end of file diff --git a/backend/src/test/java/it/chalmers/gamma/utils/CharacterTypes.java b/backend/src/test/java/it/chalmers/gamma/utils/CharacterTypes.java deleted file mode 100644 index 4783b0bdc..000000000 --- a/backend/src/test/java/it/chalmers/gamma/utils/CharacterTypes.java +++ /dev/null @@ -1,24 +0,0 @@ -package it.chalmers.gamma.utils; - -public enum CharacterTypes { - UPPERCASE("ABCDEFGHIJKLMNOPQRSTUVWXYZ"), - LOWERCASE("abcdefghijklmnopqrstuvwxyz"), - NUMBERS("123456789"), - SPECIALS("!@#$%&()+=[]|/?><"); - - private String characters; - - CharacterTypes(String characters) { - this.characters = characters; - } - - public String getCharacters() { - return this.characters; - } - - public static CharacterTypes[] allValues() { - return new CharacterTypes[]{ - UPPERCASE, LOWERCASE, NUMBERS, SPECIALS - }; - } -} diff --git a/backend/src/test/java/it/chalmers/gamma/utils/GenerationUtils.java b/backend/src/test/java/it/chalmers/gamma/utils/GenerationUtils.java deleted file mode 100644 index 8cd1d0070..000000000 --- a/backend/src/test/java/it/chalmers/gamma/utils/GenerationUtils.java +++ /dev/null @@ -1,55 +0,0 @@ -package it.chalmers.gamma.utils; - -import it.chalmers.gamma.db.entity.Text; -import java.util.Arrays; -import java.util.Random; -import java.util.stream.Collectors; - -public final class GenerationUtils { - - private GenerationUtils() { - - } - - - /** - * Generate String of custom length. - * @param length length of String to generate. - * @param types Types of characters to use. - * @return A randomly generated String of custom length. - */ - public static String generateRandomString(int length, CharacterTypes...types) { - String characters = Arrays.stream(types) - .map(CharacterTypes::getCharacters) - .collect(Collectors.joining()); - Random rand = new Random(); - StringBuilder str = new StringBuilder(); - for (int i = 0; i < length; i++) { - str.append(characters.charAt(rand.nextInt(characters.length() - 1))); - } - return str.toString(); - } - public static String generateRandomString() { - return generateRandomString(50, CharacterTypes.allValues()); - } - - public static String generateEmail() { - return String.format("%s@%s.com", - generateRandomString(generateIntBetween(1, 15), CharacterTypes.LOWERCASE), - generateRandomString(generateIntBetween(1, 15), CharacterTypes.LOWERCASE) - ); - } - - public static Text generateText() { - return new Text(generateRandomString(), generateRandomString()); - } - - /** - * Generate Random String of length 50 characters by default. - * @return randomly generated String. - */ - - public static int generateIntBetween(int min, int max) { - return new Random().nextInt(max - min) + min; - } -} diff --git a/backend/src/test/java/it/chalmers/gamma/utils/JSONUtils.java b/backend/src/test/java/it/chalmers/gamma/utils/JSONUtils.java deleted file mode 100644 index 5a27f1efb..000000000 --- a/backend/src/test/java/it/chalmers/gamma/utils/JSONUtils.java +++ /dev/null @@ -1,50 +0,0 @@ -package it.chalmers.gamma.utils; - -import com.fasterxml.jackson.databind.ObjectMapper; -import it.chalmers.gamma.endoints.JSONParameter; -import java.io.IOException; -import java.util.Arrays; -import java.util.List; - -public final class JSONUtils { - - private JSONUtils() { - - } - - public static String objectToJSONString(Object o) { - - try { - return new ObjectMapper().writeValueAsString(o); - } catch (IOException ignored) { - return null; - } - } - - public static String toJsonTemplate(JSONParameter... rawParameters) { - List parameters = Arrays.asList(rawParameters); - StringBuilder builder = new StringBuilder(); - builder.append("{\n"); - for (JSONParameter parameter : parameters) { - builder.append(String.format("\"%s\": \"%s\"%s", - parameter.getKey(), - parameter.getValue(), - parameter.equals(parameters.get(parameters.size() - 1)) ? "\n}" : ",\n" - )); - } - return builder.toString(); - } - - public static String toFormUrlEncoded(JSONParameter... rawParameters) { - List parameters = Arrays.asList(rawParameters); - StringBuilder builder = new StringBuilder(); - for (JSONParameter parameter : parameters) { - builder.append(String.format("%s=%s%s", - parameter.getKey(), - parameter.getValue(), - parameter.equals(parameters.get(parameters.size() - 1)) ? "" : "&" - )); - } - return builder.toString(); - } -} diff --git a/backend/src/test/java/it/chalmers/gamma/utils/ResponseUtils.java b/backend/src/test/java/it/chalmers/gamma/utils/ResponseUtils.java deleted file mode 100644 index 6a0467b75..000000000 --- a/backend/src/test/java/it/chalmers/gamma/utils/ResponseUtils.java +++ /dev/null @@ -1,22 +0,0 @@ -package it.chalmers.gamma.utils; - -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -import org.springframework.test.web.servlet.ResultMatcher; - -public final class ResponseUtils { - - private ResponseUtils() { - - } - - public static ResultMatcher expectedStatus(boolean authorized) { - if (authorized) { - return status().is2xxSuccessful(); - } else { - return status().is4xxClientError(); - } - } - - -} diff --git a/backend/src/test/resources/application-test.properties b/backend/src/test/resources/application-test.properties deleted file mode 100644 index 75d464dc5..000000000 --- a/backend/src/test/resources/application-test.properties +++ /dev/null @@ -1,13 +0,0 @@ -spring.datasource.url=jdbc:h2:mem:test -spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect -spring.jpa.database-platform=org.hibernate.dialect.H2Dialect -spring.datasource.username=sa -spring.datasource.password=password -spring.datasource.driverClassName=org.h2.Driver -spring.flyway.baseline-on-migrate=true -spring.flyway.locations=classpath:/db/migration -spring.main.web-application-type=none -logging.level.root=INFO -logging.level.org.springframework.web=ERROR -spring.session.store-type=none -application.mocking=false \ No newline at end of file diff --git a/backend/src/test/resources/db/migration/README.md b/backend/src/test/resources/db/migration/README.md deleted file mode 100644 index f89e48ea6..000000000 --- a/backend/src/test/resources/db/migration/README.md +++ /dev/null @@ -1,23 +0,0 @@ -# How to write migrations - -Create a sql file with a V that is +1 of the last one. - -Here's some examples with an sql file named `V99__website-changes.sql`: - -```sql - --- Add column -ALTER TABLE website - ADD test_column varchar(100) not null; - --- Rename column -ALTER TABLE website - RENAME COLUMN name TO name_new; - --- Modify column -ALTER TABLE website - ALTER COLUMN pretty_name TYPE varchar(200); - -``` - -More examples here, check for PostgresSQL: https://www.postgresql.org/docs/9.4/ddl-alter.html diff --git a/backend/src/test/resources/db/migration/V1.1__post_email_prefix.sql b/backend/src/test/resources/db/migration/V1.1__post_email_prefix.sql deleted file mode 100644 index 3c78478df..000000000 --- a/backend/src/test/resources/db/migration/V1.1__post_email_prefix.sql +++ /dev/null @@ -1,2 +0,0 @@ -ALTER TABLE post -ADD email_prefix VARCHAR(20) NOT NULL DEFAULT '' \ No newline at end of file diff --git a/backend/src/test/resources/db/migration/V1.2__user_activated_account.sql b/backend/src/test/resources/db/migration/V1.2__user_activated_account.sql deleted file mode 100644 index 53f7b570b..000000000 --- a/backend/src/test/resources/db/migration/V1.2__user_activated_account.sql +++ /dev/null @@ -1,2 +0,0 @@ -ALTER TABLE ituser -ADD activated BOOLEAN DEFAULT FALSE \ No newline at end of file diff --git a/backend/src/test/resources/db/migration/V1__BASE.sql b/backend/src/test/resources/db/migration/V1__BASE.sql deleted file mode 100644 index dc2d1ff76..000000000 --- a/backend/src/test/resources/db/migration/V1__BASE.sql +++ /dev/null @@ -1,148 +0,0 @@ -create table internal_text ( - id uuid constraint text_pk primary key, - sv text not null, - en text -); - -create table website ( - id uuid constraint websites_pk primary key, - name varchar(100) not null constraint website_name unique, - pretty_name varchar(100) not null -); - -create table website_url ( - id uuid constraint websites_url_pk primary key, - website uuid not null references website, - url varchar(2000) not null -); - -create table ituser ( - id uuid constraint ituser_pk primary key, - cid varchar(10) not null constraint ituser_cid_unique unique, - password varchar(255) not null, - nick varchar(50) not null, - first_name varchar(50) null, - last_name varchar(50) null, - email varchar(100) not null constraint ituser_email_unique unique, - phone varchar(15) null, - language varchar(15) null, - avatar_url varchar(255) default 'default.jpg', - gdpr boolean not null default false, - user_agreement boolean not null default false, - account_locked boolean not null default false, - acceptance_year integer constraint ituser_valid_year check (acceptance_year >= 2001), - created_at timestamp not null default current_timestamp, - last_modified_at timestamp not null default current_timestamp -); - -create table ituser_website ( - id uuid constraint ituser_website_pk primary key, - ituser uuid not null references ituser, - website uuid not null references website_url -); - -create table authority_level ( - id uuid constraint authority_level_pk primary key, - authority_level varchar(30) -); - -create table password_reset_token( - id uuid constraint password_reset_token_pk primary key, - token varchar(100) not null, - ituser uuid references ituser -); - -create table fkit_super_group ( - id uuid constraint fkit_super_group_pk primary key, - name varchar(50) not null constraint fkit_super_group_name_unique unique, - pretty_name varchar(50) not null constraint fkit_super_group_pretty_name_unique unique, - email varchar(100) not null, - type varchar(30) not null -); - -create table fkit_group ( - id uuid constraint fkit_group_pk primary key, - name varchar(50) not null constraint fkit_group_name_unique unique, - pretty_name varchar(50) not null, - description uuid null references internal_text, - function uuid not null references internal_text, - becomes_active date not null, - becomes_inactive date not null, constraint inactive_after_inactive check (becomes_active < becomes_inactive), - fkit_super_group uuid not null references fkit_super_group, - email varchar(100) null, - avatar_url varchar(255) null -); - -create table post ( - id uuid constraint post_pk primary key, - post_name uuid not null references internal_text - -); - -create table authority ( - id uuid constraint authority_unique unique, - fkit_group_id uuid constraint authority_fkit_super_group_fk references fkit_super_group, - post_id uuid constraint authority_post references post, - authority_level uuid constraint authority_authority_level references authority_level, - constraint authority_pk primary key (post_id, fkit_group_id) -); - -create table fkit_group_website( - id uuid constraint fkit_group_website_pk primary key, - fkit_group uuid not null references fkit_group, - website uuid not null references website_url -); - - - -create table membership ( -- Should this be rebuilt to look like all other tables? probably - ituser_id uuid constraint membership_ituser_fk references ituser, - fkit_group_id uuid constraint membership_fkit_group_fk references fkit_group, - post_id uuid constraint membership_post_fk references post, - unofficial_post_name varchar(100) null, - constraint membership_pk primary key (ituser_id, fkit_group_id, post_id) -); - -create table no_account_membership ( - user_name varchar(20) not null, - fkit_group_id uuid constraint no_account_membership_fkit_group_fk references fkit_group, - post_id uuid not null constraint no_account_membership_post_fk references post, - unofficial_post_name varchar(100) null, - constraint no_account_membership_pk primary key (user_name, fkit_group_id) -); - -create table whitelist ( - id uuid constraint whitelist_pk primary key, - cid varchar(10) not null constraint whitelist_cid_unique unique -); - -create table activation_code ( - id uuid constraint activation_code_pk primary key, - cid uuid unique not null references whitelist, - code varchar(30) not null, - created_at timestamp not null default current_timestamp -); - -create table itclient ( - id uuid constraint itclient_pk primary key, - client_id varchar(256) not null, - client_secret varchar(256) not null, - web_server_redirect_uri varchar(256) not null, - --authorities varchar(256) not null, - access_token_validity integer not null, - refresh_token_validity integer not null, - auto_approve boolean default false not null, - name varchar(30) not null, - description uuid references internal_text, - created_at timestamp not null default current_timestamp, - last_modified_at timestamp not null default current_timestamp -); - -create table apikey ( - id uuid constraint apikey_pk primary key, - name varchar(30) not null, - description uuid references internal_text, - key varchar(150) not null, - created_at timestamp not null default current_timestamp, - last_modified_at timestamp not null default current_timestamp -) \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml deleted file mode 100644 index 1488df7a0..000000000 --- a/docker-compose.yml +++ /dev/null @@ -1,39 +0,0 @@ -version: "2" -services: - db: - image: postgres:10 - restart: always - environment: - POSTGRES_PASSWORD: example - ports: - - 5432:5432 - - adminer: - image: adminer - restart: always - ports: - - 8080:8080 - - frontend: - image: frontend:development - build: - context: ./frontend/ - dockerfile: dev.dockerfile - ports: - - 3000:3000 - volumes: - - ./frontend/src:/usr/src/app/src - - ./frontend/public:/usr/src/app/public - network_mode: host - redis: - image: redis:5.0 - restart: always - ports: - - 6379:6379 - backend: - build: - context: ./backend/ - dockerfile: dev.Dockerfile - network_mode: host - environment: - REDIS_HOST: localhost diff --git a/frontend/.dockerignore b/frontend/.dockerignore deleted file mode 100644 index b512c09d4..000000000 --- a/frontend/.dockerignore +++ /dev/null @@ -1 +0,0 @@ -node_modules \ No newline at end of file diff --git a/frontend/.env.development b/frontend/.env.development deleted file mode 100644 index cbe88e97f..000000000 --- a/frontend/.env.development +++ /dev/null @@ -1 +0,0 @@ -HTTP_PROXY="http://localhost:8081" \ No newline at end of file diff --git a/frontend/.gitignore b/frontend/.gitignore deleted file mode 100644 index 02476d501..000000000 --- a/frontend/.gitignore +++ /dev/null @@ -1,140 +0,0 @@ -build - node_modules - yarn-error.log - yarn.lock -# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm -# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 - -# User-specific stuff -.idea/**/workspace.xml -.idea/**/tasks.xml -.idea/**/usage.statistics.xml -.idea/**/dictionaries -.idea/**/shelf - -# Generated files -.idea/**/contentModel.xml - -# Sensitive or high-churn files -.idea/**/dataSources/ -.idea/**/dataSources.ids -.idea/**/dataSources.local.xml -.idea/**/sqlDataSources.xml -.idea/**/dynamic.xml -.idea/**/uiDesigner.xml -.idea/**/dbnavigator.xml - -# Gradle -.idea/**/gradle.xml -.idea/**/libraries - -# Gradle and Maven with auto-import -# When using Gradle or Maven with auto-import, you should exclude module files, -# since they will be recreated, and may cause churn. Uncomment if using -# auto-import. -# .idea/modules.xml -# .idea/*.iml -# .idea/modules - -# CMake -cmake-build-*/ - -# Mongo Explorer plugin -.idea/**/mongoSettings.xml - -# File-based project format -*.iws - -# IntelliJ -out/ - -# mpeltonen/sbt-idea plugin -.idea_modules/ - -# JIRA plugin -atlassian-ide-plugin.xml - -# Cursive Clojure plugin -.idea/replstate.xml - -# Crashlytics plugin (for Android Studio and IntelliJ) -com_crashlytics_export_strings.xml -crashlytics.properties -crashlytics-build.properties -fabric.properties - -# Editor-based Rest Client -.idea/httpRequests - -# Android studio 3.1+ serialized cache file -.idea/caches/build_file_checksums.ser -======= - - # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm - # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 - -workspace.xml - - # User-specific stuff - .idea/**/workspace.xml - .idea/**/tasks.xml - .idea/**/usage.statistics.xml - .idea/**/dictionaries - .idea/**/shelf - - # Generated files - .idea/**/contentModel.xml - - # Sensitive or high-churn files - .idea/**/dataSources/ - .idea/**/dataSources.ids - .idea/**/dataSources.local.xml - .idea/**/sqlDataSources.xml - .idea/**/dynamic.xml - .idea/**/uiDesigner.xml - .idea/**/dbnavigator.xml - - # Gradle - .idea/**/gradle.xml - .idea/**/libraries - - # Gradle and Maven with auto-import - # When using Gradle or Maven with auto-import, you should exclude module files, - # since they will be recreated, and may cause churn. Uncomment if using - # auto-import. - # .idea/modules.xml - # .idea/*.iml - # .idea/modules - - # CMake - cmake-build-*/ - - # Mongo Explorer plugin - .idea/**/mongoSettings.xml - - # File-based project format - *.iws - - # IntelliJ - out/ - - # mpeltonen/sbt-idea plugin - .idea_modules/ - - # JIRA plugin - atlassian-ide-plugin.xml - - # Cursive Clojure plugin - .idea/replstate.xml - - # Crashlytics plugin (for Android Studio and IntelliJ) - com_crashlytics_export_strings.xml - crashlytics.properties - crashlytics-build.properties - fabric.properties - - # Editor-based Rest Client - .idea/httpRequests - - # Android studio 3.1+ serialized cache file - .idea/caches/build_file_checksums.ser diff --git a/frontend/.idea/codeStyles/Project.xml b/frontend/.idea/codeStyles/Project.xml deleted file mode 100644 index b6cbdafd4..000000000 --- a/frontend/.idea/codeStyles/Project.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/frontend/.idea/codeStyles/codeStyleConfig.xml b/frontend/.idea/codeStyles/codeStyleConfig.xml deleted file mode 100644 index 79ee123c2..000000000 --- a/frontend/.idea/codeStyles/codeStyleConfig.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - \ No newline at end of file diff --git a/frontend/.idea/encodings.xml b/frontend/.idea/encodings.xml deleted file mode 100644 index 15a15b218..000000000 --- a/frontend/.idea/encodings.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/frontend/.idea/frontend.iml b/frontend/.idea/frontend.iml deleted file mode 100644 index 24643cc37..000000000 --- a/frontend/.idea/frontend.iml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/frontend/.idea/misc.xml b/frontend/.idea/misc.xml deleted file mode 100644 index 24eb271ab..000000000 --- a/frontend/.idea/misc.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - \ No newline at end of file diff --git a/frontend/.idea/modules.xml b/frontend/.idea/modules.xml deleted file mode 100644 index f3d93d75a..000000000 --- a/frontend/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/frontend/.idea/vcs.xml b/frontend/.idea/vcs.xml deleted file mode 100644 index 6c0b86358..000000000 --- a/frontend/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/frontend/.idea/watcherTasks.xml b/frontend/.idea/watcherTasks.xml deleted file mode 100644 index 8fc25a453..000000000 --- a/frontend/.idea/watcherTasks.xml +++ /dev/null @@ -1,85 +0,0 @@ - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/frontend/.prettierrc b/frontend/.prettierrc deleted file mode 100644 index 16e4e7f1a..000000000 --- a/frontend/.prettierrc +++ /dev/null @@ -1,12 +0,0 @@ -{ - "tabWidth": 4, - "printWidth": 80, - "semi": true, - "arrowParens": "avoid", - "bracketSpacing": true, - "useTabs": false, - "trailingComma": "none", - "jsxBracketSameLine": false, - "singleQuote": false, - "jsxSingleQuote": false -} diff --git a/frontend/Dockerfile b/frontend/Dockerfile deleted file mode 100644 index b05b81f6c..000000000 --- a/frontend/Dockerfile +++ /dev/null @@ -1,13 +0,0 @@ -FROM node:13.2.0 as build -WORKDIR /usr/src/app -COPY package.json yarn.lock ./ -RUN yarn --production --frozen-lockfile --network-timeout 10000000 -COPY src src -COPY public public -ARG REACT_APP_BACKEND_URL=https://gamma.chalmers.it/api -ENV REACT_APP_BACKEND_URL $REACT_APP_BACKEND_URL -RUN yarn build -FROM nginx:1.16.0-alpine -COPY nginx.conf /etc/nginx/nginx.conf -COPY --from=build /usr/src/app/build /usr/share/nginx/html -RUN nginx -t \ No newline at end of file diff --git a/frontend/dev.dockerfile b/frontend/dev.dockerfile deleted file mode 100644 index aada67ff9..000000000 --- a/frontend/dev.dockerfile +++ /dev/null @@ -1,9 +0,0 @@ -FROM node:13.2.0 as build -WORKDIR /usr/src/app -COPY package.json yarn.lock ./ -RUN yarn install --network-timeout 10000000 -COPY .env.development .env -COPY src src -COPY public public -CMD yarn start - diff --git a/frontend/nginx.conf b/frontend/nginx.conf deleted file mode 100644 index 11d325f8e..000000000 --- a/frontend/nginx.conf +++ /dev/null @@ -1,32 +0,0 @@ -user nginx; -worker_processes 1; - -error_log /var/log/nginx/error.log warn; -pid /var/run/nginx.pid; - -events { - worker_connections 1024; -} - -http { - include /etc/nginx/mime.types; - default_type application/octet-stream; - - sendfile off; - - keepalive_timeout 65; - - server { - listen 8080; - server_name localhost; - - root /usr/share/nginx/html/; - index index.html; - - location / { - try_files $uri $uri/ /index.html; - } - } - - include /etc/nginx/conf.d/*.conf; -} \ No newline at end of file diff --git a/frontend/package.json b/frontend/package.json deleted file mode 100644 index 20dd60d71..000000000 --- a/frontend/package.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "name": "gamma", - "version": "0.1.0", - "private": true, - "dependencies": { - "@babel/runtime": "7.5.4", - "@cthit/react-digit-components": "1.0.3-beta.11", - "@material-ui/core": "4.11.0", - "@material-ui/icons": "4.9.1", - "axios": "0.20.0", - "lodash": "4.17.20", - "prop-types": "15.7.2", - "react": "16.13.1", - "react-dom": "16.13.1", - "react-is": "16.13.1", - "react-router-dom": "5.2.0", - "react-scripts": "3.4.0", - "styled-components": "5.1.1", - "yup": "0.27.0" - }, - "scripts": { - "start": "react-scripts start", - "build": "react-scripts build" - }, - "devDependencies": { - "http-proxy-middleware": "^1.0.3", - "prettier": "^1.18.2" - }, - "browserslist": [ - ">0.2%", - "not dead", - "not ie <= 11", - "not op_mini all" - ] -} diff --git a/frontend/public/403.gif b/frontend/public/403.gif deleted file mode 100644 index 64d169a32..000000000 Binary files a/frontend/public/403.gif and /dev/null differ diff --git a/frontend/public/404.jpg b/frontend/public/404.jpg deleted file mode 100644 index ab668e872..000000000 Binary files a/frontend/public/404.jpg and /dev/null differ diff --git a/frontend/public/500.gif b/frontend/public/500.gif deleted file mode 100644 index bd74b3418..000000000 Binary files a/frontend/public/500.gif and /dev/null differ diff --git a/frontend/public/android-chrome-144x144.png b/frontend/public/android-chrome-144x144.png deleted file mode 100644 index 15d6a3553..000000000 Binary files a/frontend/public/android-chrome-144x144.png and /dev/null differ diff --git a/frontend/public/apple-touch-icon.png b/frontend/public/apple-touch-icon.png deleted file mode 100644 index 1f5138a51..000000000 Binary files a/frontend/public/apple-touch-icon.png and /dev/null differ diff --git a/frontend/public/browserconfig.xml b/frontend/public/browserconfig.xml deleted file mode 100644 index 28e88f1b3..000000000 --- a/frontend/public/browserconfig.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - #2196f3 - - - diff --git a/frontend/public/digit18.png b/frontend/public/digit18.png deleted file mode 100644 index 57c2136b7..000000000 Binary files a/frontend/public/digit18.png and /dev/null differ diff --git a/frontend/public/enbarsskar.jpg b/frontend/public/enbarsskar.jpg deleted file mode 100644 index 2a9892329..000000000 Binary files a/frontend/public/enbarsskar.jpg and /dev/null differ diff --git a/frontend/public/favicon-16x16.png b/frontend/public/favicon-16x16.png deleted file mode 100644 index 9bd434c5f..000000000 Binary files a/frontend/public/favicon-16x16.png and /dev/null differ diff --git a/frontend/public/favicon-32x32.png b/frontend/public/favicon-32x32.png deleted file mode 100644 index 40ebf2078..000000000 Binary files a/frontend/public/favicon-32x32.png and /dev/null differ diff --git a/frontend/public/favicon.ico b/frontend/public/favicon.ico deleted file mode 100644 index 3e0f8f7a8..000000000 Binary files a/frontend/public/favicon.ico and /dev/null differ diff --git a/frontend/public/humans.txt b/frontend/public/humans.txt deleted file mode 100644 index 52edaa217..000000000 --- a/frontend/public/humans.txt +++ /dev/null @@ -1 +0,0 @@ -https://gamma.chalmers.it/about \ No newline at end of file diff --git a/frontend/public/index.html b/frontend/public/index.html deleted file mode 100644 index b9a17dfc8..000000000 --- a/frontend/public/index.html +++ /dev/null @@ -1,45 +0,0 @@ - - - - - - - - - - - - - - - - - Gamma - - - - - -
- - diff --git a/frontend/public/manifest.json b/frontend/public/manifest.json deleted file mode 100644 index 9ce961552..000000000 --- a/frontend/public/manifest.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "short_name": "Gamma", - "name": "Gamma - IT-account", - "icons": [ - { - "src": "/android-icon-144x144.png", - "sizes": "144x144", - "type": "image/png", - "density": "3.0" - } - ], - "start_url": "./index.html", - "display": "standalone", - "theme_color": "#2196f3", - "background_color": "#ffffff" -} diff --git a/frontend/public/mstile-150x150.png b/frontend/public/mstile-150x150.png deleted file mode 100644 index 2e1fd33d1..000000000 Binary files a/frontend/public/mstile-150x150.png and /dev/null differ diff --git a/frontend/public/safari-pinned-tab.svg b/frontend/public/safari-pinned-tab.svg deleted file mode 100644 index cb647c57e..000000000 --- a/frontend/public/safari-pinned-tab.svg +++ /dev/null @@ -1,181 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/frontend/public/site.webmanifest b/frontend/public/site.webmanifest deleted file mode 100644 index c83116326..000000000 --- a/frontend/public/site.webmanifest +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "Gamma - IT-account", - "short_name": "Gamma", - "icons": [ - { - "src": "/android-chrome-144x144.png", - "sizes": "144x144", - "type": "image/png" - } - ], - "theme_color": "#ffffff", - "background_color": "#ffffff", - "display": "standalone" -} diff --git a/frontend/public/useragreement-en.md b/frontend/public/useragreement-en.md deleted file mode 100644 index 505f42136..000000000 --- a/frontend/public/useragreement-en.md +++ /dev/null @@ -1,17 +0,0 @@ -### User agreement - -“IT" refers to the organization with the legal name "Teknologsektionen Informationsteknik" and org. number 857209-9524 based in Sweden. - -This agreement refers to IT:s user account system Gamma. - -IT will collect and manage name, nickname, year of admission, CID, phone number, e-mail, added websites, commitées and societies you are and have been part of, prefered language and your profile picture. The data is managed in order to authenticate you to IT and third party services. Furthermore, the data is used to create a profile that connects to IT services as well as any third party services you approve. The data is also used if we need to contact you for matters of special interest to you. The data is also handled for statistical purposes. - -The data is saved until you choose to delete your profile or the IT section decides to delete your data. You will be notified of this at least 30 days prior. - -Name, Chalmers ID, nickname and year of admission is shared with all users of Gamma. Data may also be shared with third party services with the user’s approval. - -You have the right to withdraw your consent to the handling and request to have all data that IT has about you. -If you have any questions or want to exercise your rights you can contact: -* The board of the IT student division: styrit@chalmers.it -* The data audit group at the IT student division: dpo@chalmers.it - diff --git a/frontend/public/useragreement-sv.md b/frontend/public/useragreement-sv.md deleted file mode 100644 index bc3aa92e3..000000000 --- a/frontend/public/useragreement-sv.md +++ /dev/null @@ -1,17 +0,0 @@ -### Användaravtal - -“IT” refererar till Teknologsektionen Informationsteknik, Chalmers Studentkår med org. Nummer 857209-9524. - -Detta avtal rör datahantering i IT:s kontotjänst Gamma. - -IT kommer att samla in och hantera namn, Chalmers-id, smeknamn, antagningsår på Informationsteknik, e-mail, mobiltelefonnummer, hemsidor som du lägger in, vilka organ som du är med i på sektionen, vilket språk du föredrar samt bild kopplad till dig. - -Datan hanteras i syfte att autentisera dig mot IT:s och tredjeparts-tjänster. Datan används för att skapa en profil som kan användas på IT:s tjänster samt även de tredjepartstjänster du godkänner. Datan används även ifall vi behöver kontakta dig vid ärende av särskilt intresse för dig. Datan hanteras även i statistiska syften. - -Datan sparas tills du väljer att ta bort din profil eller att IT sektionen väljer att radera din data. Du kommer att meddelas om detta 30 dagar innan. - -Namn, Chalmers-id, smeknamn och antagningsår på Informationsteknik delas med samtliga användare av gamma. All data kan även delas med tredjepartstjänster vid användarens samtycke. - -Du har rätt att dra tillbaka ditt samtycke till hanteringen, begära att få all data som IT har om dig samt att klaga till Datainspektionen vid missnöje. -* IT:s dataskyddsombud går att nå genom dpo@chalmers.it. -* Ytterst ansvarig för hanteringen går att nå genom ordf@chalmers.it. diff --git a/frontend/src/api/activation-codes/delete.activationCodes.api.js b/frontend/src/api/activation-codes/delete.activationCodes.api.js deleted file mode 100644 index acf961e51..000000000 --- a/frontend/src/api/activation-codes/delete.activationCodes.api.js +++ /dev/null @@ -1,6 +0,0 @@ -import { deleteRequest } from "../utils/api"; -import { ADMIN_ACTIVATION_CODES_ENDPOINT } from "../utils/endpoints"; - -export function deleteActivationCode(activationCodeId) { - return deleteRequest(ADMIN_ACTIVATION_CODES_ENDPOINT + activationCodeId); -} diff --git a/frontend/src/api/activation-codes/get.activationCodes.api.js b/frontend/src/api/activation-codes/get.activationCodes.api.js deleted file mode 100644 index d08dd63f9..000000000 --- a/frontend/src/api/activation-codes/get.activationCodes.api.js +++ /dev/null @@ -1,20 +0,0 @@ -import { getRequest } from "../utils/api"; -import { ADMIN_ACTIVATION_CODES_ENDPOINT } from "../utils/endpoints"; - -export function getActivationCode(activationCodeId) { - return getRequest( - ADMIN_ACTIVATION_CODES_ENDPOINT + activationCodeId, - input => ({ - data: { ...input.data, createdAt: input.data.createdAt * 1000 } /// - }) - ); -} - -export function getActivationCodes() { - return getRequest(ADMIN_ACTIVATION_CODES_ENDPOINT, input => - input.data.map(i => ({ - ...i, - createdAt: i.createdAt * 1000 - })) - ); -} diff --git a/frontend/src/api/activation-codes/props.activationCodes.api.js b/frontend/src/api/activation-codes/props.activationCodes.api.js deleted file mode 100644 index 6e073146f..000000000 --- a/frontend/src/api/activation-codes/props.activationCodes.api.js +++ /dev/null @@ -1,5 +0,0 @@ -export const AC_ID = "id"; -export const AC_CID = "cid"; -export const AC_CODE = "code"; -export const AC_CREATED_AT = "createdAt"; -export const AC_NAME = "name"; diff --git a/frontend/src/api/api-keys/delete.api-keys.api.js b/frontend/src/api/api-keys/delete.api-keys.api.js deleted file mode 100644 index 55301f4f4..000000000 --- a/frontend/src/api/api-keys/delete.api-keys.api.js +++ /dev/null @@ -1,6 +0,0 @@ -import { deleteRequest } from "../utils/api"; -import { ADMIN_API_KEYS_ENDPOINT } from "../utils/endpoints"; - -export function deleteApiKey(apiKeyId) { - return deleteRequest(ADMIN_API_KEYS_ENDPOINT + apiKeyId); -} diff --git a/frontend/src/api/api-keys/get.api-keys.api.js b/frontend/src/api/api-keys/get.api-keys.api.js deleted file mode 100644 index 38705f832..000000000 --- a/frontend/src/api/api-keys/get.api-keys.api.js +++ /dev/null @@ -1,24 +0,0 @@ -import { getRequest } from "../utils/api"; -import { ADMIN_API_KEYS_ENDPOINT } from "../utils/endpoints"; - -export function getApiKeys() { - return getRequest(ADMIN_API_KEYS_ENDPOINT, input => ({ - data: input.data.map(api => ({ - id: api.id, - name: api.name, - descriptionSv: api.description != null ? api.description.sv : "", - descriptionEn: api.description != null ? api.description.en : "" - })) - })); -} - -export function getApiKey(apiKeyId) { - return getRequest(ADMIN_API_KEYS_ENDPOINT + apiKeyId, ({ data }) => ({ - data: { - id: data.id, - name: data.name, - descriptionSv: data.description != null ? data.description.sv : "", - descriptionEn: data.description != null ? data.description.en : "" - } - })); -} diff --git a/frontend/src/api/api-keys/post.api-keys.api.js b/frontend/src/api/api-keys/post.api-keys.api.js deleted file mode 100644 index 4921a51c5..000000000 --- a/frontend/src/api/api-keys/post.api-keys.api.js +++ /dev/null @@ -1,6 +0,0 @@ -import { postRequest } from "../utils/api"; -import { ADMIN_API_KEYS_ENDPOINT } from "../utils/endpoints"; - -export function addApiKey(apiKey) { - return postRequest(ADMIN_API_KEYS_ENDPOINT, apiKey); -} diff --git a/frontend/src/api/api-keys/props.api-keys.api.js b/frontend/src/api/api-keys/props.api-keys.api.js deleted file mode 100644 index 4ec5e0eeb..000000000 --- a/frontend/src/api/api-keys/props.api-keys.api.js +++ /dev/null @@ -1,5 +0,0 @@ -export const API_NAME = "name"; -export const API_DESCRIPTION_SWEDISH = "descriptionSv"; -export const API_DESCRIPTION_ENGLISH = "descriptionEn"; -export const API_ID = "id"; -export const API_SECRET = "secret"; diff --git a/frontend/src/api/approval/get.approval.api.js b/frontend/src/api/approval/get.approval.api.js deleted file mode 100644 index c6641e0c0..000000000 --- a/frontend/src/api/approval/get.approval.api.js +++ /dev/null @@ -1,6 +0,0 @@ -import { getRequest } from "../utils/api"; - -export const getAllApprovalsbyClientId = clientId => - getRequest("/admin/users/approval/" + clientId); - -export const getApprovals = () => getRequest("/users/approval"); diff --git a/frontend/src/api/authorities/delete.authoritites.js b/frontend/src/api/authorities/delete.authoritites.js deleted file mode 100644 index 244f403b0..000000000 --- a/frontend/src/api/authorities/delete.authoritites.js +++ /dev/null @@ -1,6 +0,0 @@ -import { deleteRequest } from "../utils/api"; - -export const deleteAuthorityLevel = id => - deleteRequest("/admin/authority/level/" + id); - -export const deleteAuthority = id => deleteRequest("/admin/authority/" + id); diff --git a/frontend/src/api/authorities/get.authorities.js b/frontend/src/api/authorities/get.authorities.js deleted file mode 100644 index 6f54a33c4..000000000 --- a/frontend/src/api/authorities/get.authorities.js +++ /dev/null @@ -1,8 +0,0 @@ -import { getRequest } from "../utils/api"; - -export const getAuthorityLevel = id => - getRequest("/admin/authority/level/" + id); - -export const getAuthorities = () => getRequest("/admin/authority"); - -export const getAuthorityLevels = () => getRequest("/admin/authority/level"); diff --git a/frontend/src/api/authorities/post.authoritites.js b/frontend/src/api/authorities/post.authoritites.js deleted file mode 100644 index e013edc6a..000000000 --- a/frontend/src/api/authorities/post.authoritites.js +++ /dev/null @@ -1,7 +0,0 @@ -import { postRequest } from "../utils/api"; - -export const addAuthorityLevel = data => - postRequest("/admin/authority/level", data); - -export const addToAuthorityLevel = data => - postRequest("/admin/authority", data); diff --git a/frontend/src/api/clients/delete.clients.api.js b/frontend/src/api/clients/delete.clients.api.js deleted file mode 100644 index 295cf30d9..000000000 --- a/frontend/src/api/clients/delete.clients.api.js +++ /dev/null @@ -1,6 +0,0 @@ -import { deleteRequest } from "../utils/api"; -import { ADMIN_CLIENTS_ENDPOINT } from "../utils/endpoints"; - -export function deleteClient(clientId) { - return deleteRequest(ADMIN_CLIENTS_ENDPOINT + clientId); -} diff --git a/frontend/src/api/clients/get.clients.api.js b/frontend/src/api/clients/get.clients.api.js deleted file mode 100644 index a439ff9b3..000000000 --- a/frontend/src/api/clients/get.clients.api.js +++ /dev/null @@ -1,30 +0,0 @@ -import { getRequest } from "../utils/api"; -import { ADMIN_CLIENTS_ENDPOINT } from "../utils/endpoints"; - -export function getClients() { - return getRequest(ADMIN_CLIENTS_ENDPOINT, input => - input.data.map(client => ({ - id: client.id, - name: client.name, - clientId: client.clientId, - descriptionEn: client.description.en, - descriptionSv: client.description.sv, - webServerRedirectUri: client.webServerRedirectUri, - autoApprove: client.autoApprove + "" - })) - ); -} - -export function getClient(clientId) { - return getRequest(ADMIN_CLIENTS_ENDPOINT + clientId, input => ({ - data: { - id: input.data.id, - name: input.data.additionalInformation.name, - clientId: input.data.clientId, - descriptionEn: input.data.additionalInformation.description.en, - descriptionSv: input.data.additionalInformation.description.sv, - webServerRedirectUri: input.data.webServerRedirectUri, - autoApprove: input.data.autoApprove + "" - } - })); -} diff --git a/frontend/src/api/clients/post.clients.api.js b/frontend/src/api/clients/post.clients.api.js deleted file mode 100644 index 4393b6df9..000000000 --- a/frontend/src/api/clients/post.clients.api.js +++ /dev/null @@ -1,6 +0,0 @@ -import { postRequest } from "../utils/api"; -import { ADMIN_CLIENTS_ENDPOINT } from "../utils/endpoints"; - -export function addClient(client) { - return postRequest(ADMIN_CLIENTS_ENDPOINT, client); -} diff --git a/frontend/src/api/clients/props.clients.api.js b/frontend/src/api/clients/props.clients.api.js deleted file mode 100644 index b98e2e03b..000000000 --- a/frontend/src/api/clients/props.clients.api.js +++ /dev/null @@ -1,8 +0,0 @@ -export const CLIENT_DESCRIPTION_SWEDISH = "descriptionSv"; -export const CLIENT_DESCRIPTION_ENGLISH = "descriptionEn"; -export const CLIENT_ID = "id"; -export const CLIENT_OAUTH_ID = "clientId"; -export const CLIENT_NAME = "name"; -export const CLIENT_REDIRECT = "webServerRedirectUri"; -export const CLIENT_SECRET = "clientSecret"; -export const CLIENT_AUTO_APPROVE = "autoApprove"; diff --git a/frontend/src/api/clients/put.clients.api.js b/frontend/src/api/clients/put.clients.api.js deleted file mode 100644 index ed367f4db..000000000 --- a/frontend/src/api/clients/put.clients.api.js +++ /dev/null @@ -1,6 +0,0 @@ -import { putRequest } from "../utils/api"; -import { ADMIN_CLIENTS_ENDPOINT } from "../utils/endpoints"; - -export function editClient(clientId, client) { - return putRequest(ADMIN_CLIENTS_ENDPOINT + clientId, client); -} diff --git a/frontend/src/api/create-account/post.createAccount.api.js b/frontend/src/api/create-account/post.createAccount.api.js deleted file mode 100644 index b3ce70482..000000000 --- a/frontend/src/api/create-account/post.createAccount.api.js +++ /dev/null @@ -1,8 +0,0 @@ -import { postRequest } from "../utils/api"; -import { CREATE_ACCOUNT_ENDPOINT } from "../utils/endpoints"; - -const CREATE = "create/"; - -export function createAccount(data) { - return postRequest(CREATE_ACCOUNT_ENDPOINT + CREATE, data, false); -} diff --git a/frontend/src/api/gdpr/get.gdpr.api.js b/frontend/src/api/gdpr/get.gdpr.api.js deleted file mode 100644 index dd0400778..000000000 --- a/frontend/src/api/gdpr/get.gdpr.api.js +++ /dev/null @@ -1,6 +0,0 @@ -import { getRequest } from "../utils/api"; -import { ADMIN_GDPR_ENDPOINT } from "../utils/endpoints"; - -export function getUsersWithGDPRMinified() { - return getRequest(ADMIN_GDPR_ENDPOINT + "minified"); -} diff --git a/frontend/src/api/gdpr/put.gdpr.api.js b/frontend/src/api/gdpr/put.gdpr.api.js deleted file mode 100644 index 2d5bc3df4..000000000 --- a/frontend/src/api/gdpr/put.gdpr.api.js +++ /dev/null @@ -1,6 +0,0 @@ -import { putRequest } from "../utils/api"; -import { ADMIN_GDPR_ENDPOINT } from "../utils/endpoints"; - -export function setGDPRValue(userId, data) { - return putRequest(ADMIN_GDPR_ENDPOINT + userId, data); -} diff --git a/frontend/src/api/groups/delete.groups.api.js b/frontend/src/api/groups/delete.groups.api.js deleted file mode 100644 index 4480f1e3a..000000000 --- a/frontend/src/api/groups/delete.groups.api.js +++ /dev/null @@ -1,12 +0,0 @@ -import { deleteRequest } from "../utils/api"; -import { ADMIN_GROUPS_ENDPOINT } from "../utils/endpoints"; - -export function deleteGroup(groupId) { - return deleteRequest(ADMIN_GROUPS_ENDPOINT + groupId); -} - -export function removeUserFromGroup(groupId, userId) { - return deleteRequest( - ADMIN_GROUPS_ENDPOINT + groupId + "/members/" + userId - ); -} diff --git a/frontend/src/api/groups/get.groups.api.js b/frontend/src/api/groups/get.groups.api.js deleted file mode 100644 index 382e853e7..000000000 --- a/frontend/src/api/groups/get.groups.api.js +++ /dev/null @@ -1,39 +0,0 @@ -import { getRequest } from "../utils/api"; -import { ADMIN_GROUPS_ENDPOINT, GROUPS_ENDPOINT } from "../utils/endpoints"; - -const MINIFIED = "minified/"; - -export function getGroups() { - return getRequest(ADMIN_GROUPS_ENDPOINT); -} - -export function getGroup(groupId) { - return getRequest(GROUPS_ENDPOINT + groupId, input => ({ - data: { - ...input.data, - functionSv: input.data["function"].sv, - functionEn: input.data["function"].en, - descriptionSv: input.data.description.sv, - descriptionEn: input.data.description.en, - superGroup: input.data.superGroup.id, - superGroupPrettyName: input.data.superGroup.prettyName, - superGroupName: input.data.superGroup.name - } - })); -} - -export function getGroupsMinified() { - return getRequest(GROUPS_ENDPOINT + MINIFIED, input => - input.data.map(one => ({ - functionSv: one.function.sv, - functionEn: one.function.en, - descriptionEn: one.description.en, - descriptionSv: one.description.sv, - ...one - })) - ); -} - -export function getGroupMinified(groupId) { - return getRequest(GROUPS_ENDPOINT + groupId + "/" + MINIFIED); -} diff --git a/frontend/src/api/groups/post.groups.api.js b/frontend/src/api/groups/post.groups.api.js deleted file mode 100644 index 1a2819f3e..000000000 --- a/frontend/src/api/groups/post.groups.api.js +++ /dev/null @@ -1,13 +0,0 @@ -import { postRequest } from "../utils/api"; -import { ADMIN_GROUPS_ENDPOINT } from "../utils/endpoints"; - -export function addGroup(groupData) { - return postRequest(ADMIN_GROUPS_ENDPOINT, groupData); -} - -export function addUserToGroup(groupId, memberData) { - return postRequest( - ADMIN_GROUPS_ENDPOINT + groupId + "/members", - memberData - ); -} diff --git a/frontend/src/api/groups/props.groups.api.js b/frontend/src/api/groups/props.groups.api.js deleted file mode 100644 index 8217ac298..000000000 --- a/frontend/src/api/groups/props.groups.api.js +++ /dev/null @@ -1,16 +0,0 @@ -export const GROUP_ID = "id"; -export const GROUP_NAME = "name"; -export const GROUP_PRETTY_NAME = "prettyName"; -export const GROUP_DESCRIPTION = "description"; -export const GROUP_EMAIL = "email"; -export const GROUP_FUNCTION = "function"; -export const GROUP_BECOMES_ACTIVE = "becomesActive"; -export const GROUP_BECOMES_INACTIVE = "becomesInactive"; -export const GROUP_SUPER_GROUP = "superGroup"; -export const GROUP_MEMBERS = "groupMembers"; -export const GROUP_SUPER_GROUP_PRETTY_NAME = "superGroupPrettyName"; -export const GROUP_DESCRIPTION_SV = "descriptionSv"; -export const GROUP_DESCRIPTION_EN = "descriptionEn"; -export const GROUP_FUNCTION_SV = "functionSv"; -export const GROUP_FUNCTION_EN = "functionEn"; -export const GROUP_NO_ACCOUNT_MEMBERS = "noAccountMembers"; diff --git a/frontend/src/api/groups/put.groups.api.js b/frontend/src/api/groups/put.groups.api.js deleted file mode 100644 index 345774be0..000000000 --- a/frontend/src/api/groups/put.groups.api.js +++ /dev/null @@ -1,13 +0,0 @@ -import { putRequest } from "../utils/api"; -import { ADMIN_GROUPS_ENDPOINT } from "../utils/endpoints"; - -export function editGroup(groupId, newGroupData) { - return putRequest(ADMIN_GROUPS_ENDPOINT + groupId, newGroupData); -} - -export function editUserInGroup(groupId, userId, memberData) { - return putRequest( - ADMIN_GROUPS_ENDPOINT + groupId + "/members/" + userId, - memberData - ); -} diff --git a/frontend/src/api/image/put.image.api.js b/frontend/src/api/image/put.image.api.js deleted file mode 100644 index fa264f2ab..000000000 --- a/frontend/src/api/image/put.image.api.js +++ /dev/null @@ -1,8 +0,0 @@ -import { putRequest } from "../utils/api"; -import { USERS_ENDPOINT } from "../utils/endpoints"; - -export function uploadUserAvatar(file) { - const data = new FormData(); - data.append("file", file); - return putRequest(USERS_ENDPOINT + "me/avatar", data); -} diff --git a/frontend/src/api/me/delete.me.api.js b/frontend/src/api/me/delete.me.api.js deleted file mode 100644 index 71de21867..000000000 --- a/frontend/src/api/me/delete.me.api.js +++ /dev/null @@ -1,6 +0,0 @@ -import { deleteRequest } from "../utils/api"; -import { USERS_ENDPOINT } from "../utils/endpoints"; - -export function deleteMe(passwordData) { - return deleteRequest(USERS_ENDPOINT + "me", passwordData); -} diff --git a/frontend/src/api/me/props.me.api.js b/frontend/src/api/me/props.me.api.js deleted file mode 100644 index 247c41543..000000000 --- a/frontend/src/api/me/props.me.api.js +++ /dev/null @@ -1,10 +0,0 @@ -export const FIRST_NAME = "firstName"; -export const LAST_NAME = "lastName"; -export const NICK = "nick"; -export const EMAIL = "email"; -export const ACCEPTANCE_YEAR = "acceptanceYear"; -export const ID = "id"; -export const CID = "cid"; -export const USER_AGREEMENT = "userAgreement"; -export const PASSWORD = "password"; -export const LANGUAGE = "language"; diff --git a/frontend/src/api/me/put.me.api.js b/frontend/src/api/me/put.me.api.js deleted file mode 100644 index a889348c3..000000000 --- a/frontend/src/api/me/put.me.api.js +++ /dev/null @@ -1,10 +0,0 @@ -import { putRequest } from "../utils/api"; -import { USERS_ENDPOINT } from "../utils/endpoints"; - -export function editMe(newUserData) { - return putRequest(USERS_ENDPOINT + "me", newUserData); -} - -export function editPassword(passwordData) { - return putRequest(USERS_ENDPOINT + "me/change_password", passwordData); -} diff --git a/frontend/src/api/posts/delete.posts.api.js b/frontend/src/api/posts/delete.posts.api.js deleted file mode 100644 index d782f3a56..000000000 --- a/frontend/src/api/posts/delete.posts.api.js +++ /dev/null @@ -1,6 +0,0 @@ -import { deleteRequest } from "../utils/api"; -import { ADMIN_POSTS_ENDPOINT } from "../utils/endpoints"; - -export function deletePost(postId) { - return deleteRequest(ADMIN_POSTS_ENDPOINT + postId); -} diff --git a/frontend/src/api/posts/get.posts.api.js b/frontend/src/api/posts/get.posts.api.js deleted file mode 100644 index 4a9f25ef0..000000000 --- a/frontend/src/api/posts/get.posts.api.js +++ /dev/null @@ -1,16 +0,0 @@ -import { getRequest } from "../utils/api"; -import { POSTS_ENDPOINT, ADMIN_POSTS_ENDPOINT } from "../utils/endpoints"; - -export function getPosts() { - return getRequest(POSTS_ENDPOINT); -} - -export function getPost(postId) { - return getRequest(POSTS_ENDPOINT + postId); -} - -export function getPostUsage(postId) { - return getRequest(ADMIN_POSTS_ENDPOINT + postId + "/usage", input => ({ - data: { usages: input.data } - })); -} diff --git a/frontend/src/api/posts/post.posts.api.js b/frontend/src/api/posts/post.posts.api.js deleted file mode 100644 index 6bc06c46d..000000000 --- a/frontend/src/api/posts/post.posts.api.js +++ /dev/null @@ -1,14 +0,0 @@ -import { postRequest } from "../utils/api"; -import { ADMIN_POSTS_ENDPOINT } from "../utils/endpoints"; - -/** - * { - * post: { - * sv: String, - * en: String - * } - * } - */ -export function addPost(postData) { - return postRequest(ADMIN_POSTS_ENDPOINT, postData); -} diff --git a/frontend/src/api/posts/props.posts.api.js b/frontend/src/api/posts/props.posts.api.js deleted file mode 100644 index 9c6b90938..000000000 --- a/frontend/src/api/posts/props.posts.api.js +++ /dev/null @@ -1,4 +0,0 @@ -export const POST_ID = "id"; -export const POST_SWEDISH = "sv"; -export const POST_ENGLISH = "en"; -export const EMAIL_PREFIX = "emailPrefix"; diff --git a/frontend/src/api/posts/put.posts.api.js b/frontend/src/api/posts/put.posts.api.js deleted file mode 100644 index da7e22a05..000000000 --- a/frontend/src/api/posts/put.posts.api.js +++ /dev/null @@ -1,14 +0,0 @@ -import { putRequest } from "../utils/api"; -import { ADMIN_POSTS_ENDPOINT } from "../utils/endpoints"; - -/** - * { - * post: { - * sv: String, - * en: String - * } - * } - */ -export function editPost(postId, newPostData) { - return putRequest(ADMIN_POSTS_ENDPOINT + postId, newPostData); -} diff --git a/frontend/src/api/reset-password/post.reset-password.js b/frontend/src/api/reset-password/post.reset-password.js deleted file mode 100644 index 511be51a2..000000000 --- a/frontend/src/api/reset-password/post.reset-password.js +++ /dev/null @@ -1,6 +0,0 @@ -import { postRequest } from "../utils/api"; -import { RESET_PASSWORD_ENDPOINT } from "../utils/endpoints"; - -export function resetPasswordInitialize(data) { - return postRequest(RESET_PASSWORD_ENDPOINT, data, false); -} diff --git a/frontend/src/api/reset-password/put.reset-password.js b/frontend/src/api/reset-password/put.reset-password.js deleted file mode 100644 index fe4e7cc9d..000000000 --- a/frontend/src/api/reset-password/put.reset-password.js +++ /dev/null @@ -1,6 +0,0 @@ -import { putRequest } from "../utils/api"; -import { RESET_PASSWORD_ENDPOINT } from "../utils/endpoints"; - -export function resetPasswordFinalize(data) { - return putRequest(RESET_PASSWORD_ENDPOINT + "finish", data, false); -} diff --git a/frontend/src/api/super-groups/delete.super-groups.api.js b/frontend/src/api/super-groups/delete.super-groups.api.js deleted file mode 100644 index a556359de..000000000 --- a/frontend/src/api/super-groups/delete.super-groups.api.js +++ /dev/null @@ -1,6 +0,0 @@ -import { deleteRequest } from "../utils/api"; -import { ADMIN_SUPER_GROUPS_ENDPOINT } from "../utils/endpoints"; - -export function deleteSuperGroup(superGroupId) { - return deleteRequest(ADMIN_SUPER_GROUPS_ENDPOINT + superGroupId); -} diff --git a/frontend/src/api/super-groups/get.super-groups.api.js b/frontend/src/api/super-groups/get.super-groups.api.js deleted file mode 100644 index 4868e019b..000000000 --- a/frontend/src/api/super-groups/get.super-groups.api.js +++ /dev/null @@ -1,16 +0,0 @@ -import { getRequest } from "../utils/api"; -import { SUPER_GROUPS_ENDPOINT } from "../utils/endpoints"; - -export function getSuperGroups() { - return getRequest(SUPER_GROUPS_ENDPOINT); -} - -export function getSuperGroup(id) { - return getRequest(SUPER_GROUPS_ENDPOINT + id); -} - -export function getSuperGroupSubGroups(id) { - return getRequest(SUPER_GROUPS_ENDPOINT + id + "/subgroups", input => ({ - data: { subGroups: input.data } - })); -} diff --git a/frontend/src/api/super-groups/post.super-groups.api.js b/frontend/src/api/super-groups/post.super-groups.api.js deleted file mode 100644 index e74ff2ee1..000000000 --- a/frontend/src/api/super-groups/post.super-groups.api.js +++ /dev/null @@ -1,6 +0,0 @@ -import { postRequest } from "../utils/api"; -import { ADMIN_SUPER_GROUPS_ENDPOINT } from "../utils/endpoints"; - -export function addSuperGroup(superGroupData) { - return postRequest(ADMIN_SUPER_GROUPS_ENDPOINT, superGroupData); -} diff --git a/frontend/src/api/super-groups/props.super-groups.api.js b/frontend/src/api/super-groups/props.super-groups.api.js deleted file mode 100644 index 8b22e3878..000000000 --- a/frontend/src/api/super-groups/props.super-groups.api.js +++ /dev/null @@ -1,11 +0,0 @@ -export const SG_ID = "id"; -export const SG_NAME = "name"; -export const SG_PRETTY_NAME = "prettyName"; -export const SG_TYPE = "type"; -export const SG_TYPE_SOCIETY = "SOCIETY"; -export const SG_TYPE_COMMITTEE = "COMMITTEE"; -export const SG_TYPE_BOARD = "BOARD"; -export const SG_TYPE_ADMIN = "ADMIN"; -export const SG_TYPE_ALUMNI = "ALUMNI"; -export const SG_TYPE_FUNCTIONARIES = "FUNCTIONARIES"; -export const SG_EMAIL = "email"; diff --git a/frontend/src/api/super-groups/put.super-groups.api.js b/frontend/src/api/super-groups/put.super-groups.api.js deleted file mode 100644 index b96bdc147..000000000 --- a/frontend/src/api/super-groups/put.super-groups.api.js +++ /dev/null @@ -1,9 +0,0 @@ -import { putRequest } from "../utils/api"; -import { ADMIN_SUPER_GROUPS_ENDPOINT } from "../utils/endpoints"; - -export function editSuperGroup(superGroupId, newSuperGroupData) { - return putRequest( - ADMIN_SUPER_GROUPS_ENDPOINT + superGroupId, - newSuperGroupData - ); -} diff --git a/frontend/src/api/users/delete.users.api.js b/frontend/src/api/users/delete.users.api.js deleted file mode 100644 index de2dbe965..000000000 --- a/frontend/src/api/users/delete.users.api.js +++ /dev/null @@ -1,6 +0,0 @@ -import { deleteRequest } from "../utils/api"; -import { ADMIN_USERS_ENDPOINT } from "../utils/endpoints"; - -export function deleteUser(userId) { - return deleteRequest(ADMIN_USERS_ENDPOINT + userId); -} diff --git a/frontend/src/api/users/get.users.api.js b/frontend/src/api/users/get.users.api.js deleted file mode 100644 index 5cf531c46..000000000 --- a/frontend/src/api/users/get.users.api.js +++ /dev/null @@ -1,20 +0,0 @@ -import { getRequest } from "../utils/api"; -import { ADMIN_USERS_ENDPOINT, USERS_ENDPOINT } from "../utils/endpoints"; - -export function getUsersMinified() { - return getRequest(USERS_ENDPOINT + "minified"); -} - -export function getUser(id) { - return getRequest(USERS_ENDPOINT + id, response => { - const user = response.data; - return { data: user }; - }); -} - -export function getUserAdmin(id) { - return getRequest(ADMIN_USERS_ENDPOINT + id, response => { - const user = response.data; - return { data: user }; - }); -} diff --git a/frontend/src/api/users/post.users.api.js b/frontend/src/api/users/post.users.api.js deleted file mode 100644 index e1454b75a..000000000 --- a/frontend/src/api/users/post.users.api.js +++ /dev/null @@ -1,6 +0,0 @@ -import { postRequest } from "../utils/api"; -import { ADMIN_USERS_ENDPOINT } from "../utils/endpoints"; - -export function addUser(userData) { - return postRequest(ADMIN_USERS_ENDPOINT, userData); -} diff --git a/frontend/src/api/users/props.users.api.js b/frontend/src/api/users/props.users.api.js deleted file mode 100644 index 267f4301c..000000000 --- a/frontend/src/api/users/props.users.api.js +++ /dev/null @@ -1,13 +0,0 @@ -export const USER_FIRST_NAME = "firstName"; -export const USER_LAST_NAME = "lastName"; -export const USER_NICK = "nick"; -export const USER_EMAIL = "email"; -export const USER_ACCEPTANCE_YEAR = "acceptanceYear"; -export const USER_ID = "id"; -export const USER_CID = "cid"; -export const USER_AGREEMENT = "userAgreement"; -export const USER_PASSWORD = "password"; -export const USER_LANGUAGE = "language"; -export const USER_GROUPS = "groups"; -export const USER_PHONE = "phone"; -export const USER_RELATIONSHIPS = "relationships"; diff --git a/frontend/src/api/users/put.users.api.js b/frontend/src/api/users/put.users.api.js deleted file mode 100644 index c5577a5c6..000000000 --- a/frontend/src/api/users/put.users.api.js +++ /dev/null @@ -1,10 +0,0 @@ -import { putRequest } from "../utils/api"; -import { ADMIN_USERS_ENDPOINT } from "../utils/endpoints"; - -export function editUser(userId, newUserData) { - return putRequest(ADMIN_USERS_ENDPOINT + userId, newUserData); -} - -export function editPasswordAdmin(userId, data) { - return putRequest(ADMIN_USERS_ENDPOINT + userId + "/change_password", data); -} diff --git a/frontend/src/api/utils/api.js b/frontend/src/api/utils/api.js deleted file mode 100644 index 8a37780f3..000000000 --- a/frontend/src/api/utils/api.js +++ /dev/null @@ -1,77 +0,0 @@ -import axios from "axios"; -import _ from "lodash"; -import { on401 } from "../../common/utils/error-handling/error-handling"; - -const path = "/api"; - -const error401Redirect = error => { - if ( - error != null && - error.response !== null && - error.response.status === 401 - ) { - on401(); - } -}; - -export function getRequest(endpoint, convert, redirect = true) { - if (convert != null) { - return new Promise((resolve, reject) => { - axios - .get(removeLastSlash(path + endpoint)) - .then(response => resolve(convert(response))) - .catch(error => { - if (redirect) { - error401Redirect(error); - } - reject(error); - }); - }); - } - - return wrapWithPromise( - () => axios.get(removeLastSlash(path + endpoint)), - redirect ? error401Redirect : () => {} - ); -} - -export function postRequest(endpoint, data, redirect = true) { - return wrapWithPromise( - () => axios.post(removeLastSlash(path + endpoint), data), - redirect ? error401Redirect : () => {} - ); -} - -export function deleteRequest(endpoint, data, redirect) { - return wrapWithPromise( - () => - axios.delete(removeLastSlash(path + endpoint), { - data: data - }), - redirect ? error401Redirect : () => {} - ); -} - -export function putRequest(endpoint, data, redirect) { - return wrapWithPromise( - () => axios.put(removeLastSlash(path + endpoint), data), - redirect ? error401Redirect : () => {} - ); -} - -function wrapWithPromise(promise, c) { - return new Promise((resolve, reject) => { - promise() - .then(response => { - resolve(response); - }) - .catch(error => { - c(error); - reject(error); - }); - }); -} - -function removeLastSlash(path) { - return _.trimEnd(path, "/"); -} diff --git a/frontend/src/api/utils/commonProps.js b/frontend/src/api/utils/commonProps.js deleted file mode 100644 index 9c5c83c5c..000000000 --- a/frontend/src/api/utils/commonProps.js +++ /dev/null @@ -1,2 +0,0 @@ -export const SWEDISH_LANGUAGE = "sv"; -export const ENGLISH_LANGUAGE = "en"; diff --git a/frontend/src/api/utils/endpoints.js b/frontend/src/api/utils/endpoints.js deleted file mode 100644 index 2683efee9..000000000 --- a/frontend/src/api/utils/endpoints.js +++ /dev/null @@ -1,17 +0,0 @@ -export const ADMIN_WHITELIST_ENDPOINT = "/admin/users/whitelist/"; -export const ADMIN_GROUPS_ENDPOINT = "/admin/groups/"; -export const ADMIN_ACTIVATION_CODES_ENDPOINT = "/admin/activation_codes/"; -export const ADMIN_USERS_ENDPOINT = "/admin/users/"; -export const ADMIN_CLIENTS_ENDPOINT = "/admin/clients/"; -export const ADMIN_SUPER_GROUPS_ENDPOINT = "/admin/superGroups/"; -export const ADMIN_GDPR_ENDPOINT = "/admin/gdpr/"; -export const ADMIN_API_KEYS_ENDPOINT = "/admin/api_keys/"; -export const ADMIN_POSTS_ENDPOINT = "/admin/groups/posts/"; - -export const WHITELIST_ENDPOINT = "/whitelist/"; -export const POSTS_ENDPOINT = "/groups/posts/"; -export const CREATE_ACCOUNT_ENDPOINT = "/users/"; -export const GROUPS_ENDPOINT = "/groups/"; -export const USERS_ENDPOINT = "/users/"; -export const SUPER_GROUPS_ENDPOINT = "/superGroups/"; -export const RESET_PASSWORD_ENDPOINT = "/users/reset_password/"; diff --git a/frontend/src/api/utils/error.js b/frontend/src/api/utils/error.js deleted file mode 100644 index e0c0b20fc..000000000 --- a/frontend/src/api/utils/error.js +++ /dev/null @@ -1,23 +0,0 @@ -class GammaError { - constructor(code, message) { - this.code = code; - this.message = message; - } - - equals(error) { - return ( - this.code == this._statusCode(error) && - this.message == this._statusMessage(error) - ); - } - - _statusCode(error) { - return error.response == null ? -1 : error.response.status; - } - - _statusMessage(error) { - return error.response == null ? null : error.response.data.message; - } -} - -export default GammaError; diff --git a/frontend/src/api/whitelist/delete.whitelist.api.js b/frontend/src/api/whitelist/delete.whitelist.api.js deleted file mode 100644 index 907620db4..000000000 --- a/frontend/src/api/whitelist/delete.whitelist.api.js +++ /dev/null @@ -1,6 +0,0 @@ -import { deleteRequest } from "../utils/api"; -import { ADMIN_WHITELIST_ENDPOINT } from "../utils/endpoints"; - -export function deleteWhitelistItem(whitelistId) { - return deleteRequest(ADMIN_WHITELIST_ENDPOINT + whitelistId); -} diff --git a/frontend/src/api/whitelist/get.whitelist.api.js b/frontend/src/api/whitelist/get.whitelist.api.js deleted file mode 100644 index 0c597fece..000000000 --- a/frontend/src/api/whitelist/get.whitelist.api.js +++ /dev/null @@ -1,10 +0,0 @@ -import { getRequest } from "../utils/api"; -import { ADMIN_WHITELIST_ENDPOINT } from "../utils/endpoints"; - -export function getWhitelistItem(whitelistItemId) { - return getRequest(ADMIN_WHITELIST_ENDPOINT + whitelistItemId); -} - -export function getWhitelist() { - return getRequest(ADMIN_WHITELIST_ENDPOINT); -} diff --git a/frontend/src/api/whitelist/post.whitelist.api.js b/frontend/src/api/whitelist/post.whitelist.api.js deleted file mode 100644 index 27fe15aec..000000000 --- a/frontend/src/api/whitelist/post.whitelist.api.js +++ /dev/null @@ -1,25 +0,0 @@ -import { postRequest } from "../utils/api"; -import { - ADMIN_WHITELIST_ENDPOINT, - WHITELIST_ENDPOINT -} from "../utils/endpoints"; - -const ACTIVATE_CID_ENDPOINT = "activate_cid/"; - -/** - * { - * cids: [String] - * } - */ -export function addUsersToWhitelist(whitelistData) { - return postRequest(ADMIN_WHITELIST_ENDPOINT, whitelistData); -} - -/** - * { - * cid: String - * } - */ -export function activateCid(data) { - return postRequest(WHITELIST_ENDPOINT + ACTIVATE_CID_ENDPOINT, data, false); -} diff --git a/frontend/src/api/whitelist/props.whitelist.api.js b/frontend/src/api/whitelist/props.whitelist.api.js deleted file mode 100644 index 1b8edd243..000000000 --- a/frontend/src/api/whitelist/props.whitelist.api.js +++ /dev/null @@ -1,2 +0,0 @@ -export const WHITELIST_CID = "cid"; -export const WHITELIST_ID = "id"; diff --git a/frontend/src/api/whitelist/put.whitelist.api.js b/frontend/src/api/whitelist/put.whitelist.api.js deleted file mode 100644 index 1da27435a..000000000 --- a/frontend/src/api/whitelist/put.whitelist.api.js +++ /dev/null @@ -1,11 +0,0 @@ -import { putRequest } from "../utils/api"; -import { ADMIN_WHITELIST_ENDPOINT } from "../utils/endpoints"; - -/** - * { - * cid: String - * } - */ -export function editWhitelistItem(whitelistId, newWhitelistData) { - return putRequest(ADMIN_WHITELIST_ENDPOINT + whitelistId, newWhitelistData); -} diff --git a/frontend/src/app/App.jsx b/frontend/src/app/App.jsx deleted file mode 100644 index 2887dd5c9..000000000 --- a/frontend/src/app/App.jsx +++ /dev/null @@ -1,116 +0,0 @@ -import { - DigitHeader, - DigitHeaderDrawer, - DigitLoading, - useDigitTranslations -} from "@cthit/react-digit-components"; -import React, { useContext, useEffect } from "react"; -import { Route, Switch, useLocation } from "react-router-dom"; -import ActivationCodes from "../use-cases/activation-codes"; -import CreateAccount from "../use-cases/create-account"; -import FourOFour from "../use-cases/four-o-four"; -import Gdpr from "../use-cases/gdpr"; -import Groups from "../use-cases/groups"; -import Home from "../use-cases/home"; -import Posts from "../use-cases/posts"; -import Users from "../use-cases/users"; -import Clients from "../use-cases/clients"; -import ApiKeys from "../use-cases/api-keys"; -import Whitelist from "../use-cases/whitelist"; -import translations from "../common/utils/translations/CommonTranslations"; -import SuperGroups from "../use-cases/super-groups"; -import Me from "../use-cases/me"; -import ResetPassword from "../use-cases/reset-password"; -import Drawer from "./views/drawer"; -import Members from "../use-cases/members"; -import GammaUserContext from "../common/context/GammaUser.context"; -import FiveZeroZero from "./elements/five-zero-zero"; -import About from "../use-cases/about"; -import Authorities from "../use-cases/authorities/Authorities"; - -export const App = () => { - const [user, update, [loading, error], ignore] = useContext( - GammaUserContext - ); - const [, , , setCommonTranslations] = useDigitTranslations(translations); - const { pathname } = useLocation(); - - const title = "Gamma"; - - useEffect(() => { - setCommonTranslations(translations); - // translations can't change in run time since it's a json file - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - - useEffect(() => { - if (loading && !user) { - update( - !pathname.startsWith("/create-account") && - (!pathname.startsWith("/reset-password") || - pathname.startsWith("/reset-password/admin")) - ); - } else if ( - pathname.startsWith("/create-account") || - pathname.startsWith("/reset-password") - ) { - ignore(); - } - }, [loading, error, pathname, update, user, ignore]); - - const main = ( - <> - {loading && ( - - )} - {error && } - {!loading && !error && ( - - - - - - - - - - - - - - - - - - - - - )} - - ); - - const headerOptions = { - title, - headerHeight: "200px", - backgroundImage: "url(/enbarsskar.jpg)", - renderMain: () => main - }; - - if (user == null) { - return ; - } - - return ( - - user == null ? null : - } - /> - ); -}; - -export default App; diff --git a/frontend/src/app/ProvidersForApp.jsx b/frontend/src/app/ProvidersForApp.jsx deleted file mode 100644 index 5dff885f0..000000000 --- a/frontend/src/app/ProvidersForApp.jsx +++ /dev/null @@ -1,24 +0,0 @@ -import React from "react"; -import { DigitProviders } from "@cthit/react-digit-components"; -import { GammaLoadingSingletonProvider } from "../common/context/GammaLoading.context"; -import { GammaUserSingletonProvider } from "../common/context/GammaUser.context"; - -const theme = { - breakpoints: { - xs: 0, - sm: 600, - md: 960, - lg: 1280, - xl: 1920 - } -}; - -const ProvidersForApp = ({ children }) => ( - - - {children} - - -); - -export default ProvidersForApp; diff --git a/frontend/src/app/elements/five-zero-zero/FiveZeroZero.element.jsx b/frontend/src/app/elements/five-zero-zero/FiveZeroZero.element.jsx deleted file mode 100644 index 52b952f23..000000000 --- a/frontend/src/app/elements/five-zero-zero/FiveZeroZero.element.jsx +++ /dev/null @@ -1,51 +0,0 @@ -import React, { useState } from "react"; -import translations from "./FiveZeroZero.element.translations"; -import { - DigitDesign, - DigitButton, - DigitText, - useDigitTranslations -} from "@cthit/react-digit-components"; - -const FiveZeroZero = ({ getMe, reset }) => { - const [text] = useDigitTranslations(translations); - const [tryAgainButtonDisabled, setTryAgainButtonDisabled] = useState(false); - - return ( - - - - - - - - - - { - setTryAgainButtonDisabled(true); - if (getMe != null) { - getMe() - .then(() => setTryAgainButtonDisabled(false)) - .catch(() => setTryAgainButtonDisabled(false)); - } else if (reset != null) { - reset(); - } else { - window.location.reload(); - } - }} - /> - - - ); -}; - -export default FiveZeroZero; diff --git a/frontend/src/app/elements/five-zero-zero/FiveZeroZero.element.translations.json b/frontend/src/app/elements/five-zero-zero/FiveZeroZero.element.translations.json deleted file mode 100644 index e5d97abdb..000000000 --- a/frontend/src/app/elements/five-zero-zero/FiveZeroZero.element.translations.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "BackendDownTitle": [ - "500 - Something went wrong", - "500 - Någonting gick fel" - ], - "BackendDown": [ - "Something went wrong when trying to contact the backend, please try again or contact digIT@chalmers.it", - "Någonting gick fel när vi försökte kontakta servern, var vänlig och försök igen eller kontakta digIT@chalmers.it" - ], - "TryAgain": ["Try again", "Försök igen"] -} diff --git a/frontend/src/app/elements/five-zero-zero/index.js b/frontend/src/app/elements/five-zero-zero/index.js deleted file mode 100644 index 64e73fc87..000000000 --- a/frontend/src/app/elements/five-zero-zero/index.js +++ /dev/null @@ -1,2 +0,0 @@ -import FiveZeroZero from "./FiveZeroZero.element"; -export default FiveZeroZero; diff --git a/frontend/src/app/index.js b/frontend/src/app/index.js deleted file mode 100644 index 8ce017e64..000000000 --- a/frontend/src/app/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from "./App"; diff --git a/frontend/src/app/views/drawer/Drawer.view.jsx b/frontend/src/app/views/drawer/Drawer.view.jsx deleted file mode 100644 index 6e183c4c2..000000000 --- a/frontend/src/app/views/drawer/Drawer.view.jsx +++ /dev/null @@ -1,119 +0,0 @@ -import { - DigitLayout, - DigitNavLink, - useDigitTranslations -} from "@cthit/react-digit-components"; -import React from "react"; -import translations from "./Drawer.view.translations"; -import useGammaUser from "../../../common/hooks/use-gamma-user/useGammaUser"; -import useGammaHasAuthority from "../../../common/hooks/use-gamma-has-authority/use-gamma-has-authority"; -import useGammaIsAdmin from "../../../common/hooks/use-gamma-is-admin/useGammaIsAdmin"; -import LanguageSelection from "./elements/language-selection"; -import GammaActions from "./elements/gamma-actions/GammaActions.element"; - -const Drawer = ({ closeDrawer }) => { - const user = useGammaUser(); - const admin = useGammaIsAdmin(); - const dpo = useGammaHasAuthority("gdpr"); - const [text] = useDigitTranslations(translations); - - if (Object.keys(text).length === 0) { - return null; - } - - if (admin) { - return ( - - {user != null && } - - - - - - - - - - - - - - - - ); - } else { - return ( - - {user != null && } - - - - - - - {dpo && ( - - )} - - - ); - } -}; - -export default Drawer; diff --git a/frontend/src/app/views/drawer/Drawer.view.translations.json b/frontend/src/app/views/drawer/Drawer.view.translations.json deleted file mode 100644 index 909892aea..000000000 --- a/frontend/src/app/views/drawer/Drawer.view.translations.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "Home": ["Home", "Hem"], - "Me": ["Me", "Jag"], - "Users": ["Users", "Användare"], - "Groups": ["Groups", "Grupper"], - "SuperGroups": ["Super groups", "Supergrupper"], - "Posts": ["Group posts", "Gruppposter"], - "Whitelist": ["Whitelist", "Whitelist"], - "GDPR": ["GDPR", "GDPR"], - "ActivationCodes": ["Activation code", "Aktiveringskoder"], - "Clients": ["Clients", "Klienter"], - "ApiKeys": ["API keys", "API nycklar"], - "Authorities": ["Authorities", "Rättigheter"] -} diff --git a/frontend/src/app/views/drawer/elements/gamma-actions/GammaActions.element.jsx b/frontend/src/app/views/drawer/elements/gamma-actions/GammaActions.element.jsx deleted file mode 100644 index c3902a288..000000000 --- a/frontend/src/app/views/drawer/elements/gamma-actions/GammaActions.element.jsx +++ /dev/null @@ -1,69 +0,0 @@ -import React, { useContext } from "react"; -import ExpandMore from "@material-ui/icons/ExpandMore"; -import { getBackendUrl } from "../../../../../common/utils/configs/envVariablesLoader"; -import { - useDigitTranslations, - DigitLayout, - DigitAvatar, - DigitMenu -} from "@cthit/react-digit-components"; -import styled from "styled-components"; -import translations from "./GammaActions.element.translations"; -import GammaUserContext from "../../../../../common/context/GammaUser.context"; - -const Nick = styled.h6` - font-family: Roboto, serif; - font-size: 20px; - text-overflow: ellipsis; - max-width: 152px; - overflow: hidden; - white-space: nowrap; -`; - -const GammaActions = () => { - const [user, , [loading]] = useContext(GammaUserContext); - const [text] = useDigitTranslations(translations); - - //this will update the image if updating your avatar - if (loading) { - return null; - } - - return ( - - - {user.nick} - { - switch (item) { - case "signOut": - window.location.href = getBackendUrl() + "/logout"; - break; - default: - break; - } - }} - valueToTextMap={{ - signOut: text.SignOut - }} - order={["signOut"]} - /> - - ); -}; - -export default GammaActions; diff --git a/frontend/src/app/views/drawer/elements/gamma-actions/GammaActions.element.translations.json b/frontend/src/app/views/drawer/elements/gamma-actions/GammaActions.element.translations.json deleted file mode 100644 index f55614be6..000000000 --- a/frontend/src/app/views/drawer/elements/gamma-actions/GammaActions.element.translations.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "SignOut": ["Sign out", "Logga ut"] -} \ No newline at end of file diff --git a/frontend/src/app/views/drawer/elements/language-selection/LanguageSelection.element.jsx b/frontend/src/app/views/drawer/elements/language-selection/LanguageSelection.element.jsx deleted file mode 100644 index 7ec89d026..000000000 --- a/frontend/src/app/views/drawer/elements/language-selection/LanguageSelection.element.jsx +++ /dev/null @@ -1,60 +0,0 @@ -import React, { useEffect, useState } from "react"; -import useGammaUser from "../../../../../common/hooks/use-gamma-user/useGammaUser"; -import { editMe } from "../../../../../api/me/put.me.api"; -import { - DigitSelect, - useDigitToast, - useDigitTranslations -} from "@cthit/react-digit-components"; -import translations from "./LanguageSelection.element.translations"; - -const LanguageSelection = () => { - const user = useGammaUser(); - const [text, activeLanguage, setActiveLanguage] = useDigitTranslations( - translations - ); - const [queueToast] = useDigitToast(); - const [language, setLanguage] = useState(user.language); - const [firstRender, setFirstRender] = useState(true); - - const languageUpdatedText = text.LanguageUpdated; - - useEffect(() => { - setActiveLanguage(language); - if (activeLanguage !== language && !firstRender) { - queueToast({ text: languageUpdatedText }); - } - setFirstRender(false); - }, [ - language, - queueToast, - languageUpdatedText, - setActiveLanguage, - activeLanguage, - setFirstRender, - firstRender - ]); - - return ( - { - editMe({ ...user, language: e.target.value }) - .then(() => { - setLanguage(e.target.value); - }) - .catch(() => { - queueToast({ - text: text.FailedEditMe - }); - }); - }} //update me - valueToTextMap={{ sv: text.Swedish, en: text.English }} - outlined - upperLabel={text.YourLanguage} - /> - ); -}; - -export default LanguageSelection; diff --git a/frontend/src/app/views/drawer/elements/language-selection/LanguageSelection.element.translations.json b/frontend/src/app/views/drawer/elements/language-selection/LanguageSelection.element.translations.json deleted file mode 100644 index 8e58664a1..000000000 --- a/frontend/src/app/views/drawer/elements/language-selection/LanguageSelection.element.translations.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "YourLanguage": ["Your language", "Ditt språk"], - "LanguageUpdated": [ - "Språk uppdaterat till Svenska", - "Language updated to English" - ], - "FailedEditMe": [ - "Failed to update to your selected language", - "Misslyckades att uppdatera till ditt valda språk" - ] -} diff --git a/frontend/src/app/views/drawer/elements/language-selection/index.js b/frontend/src/app/views/drawer/elements/language-selection/index.js deleted file mode 100644 index 95d30e5f0..000000000 --- a/frontend/src/app/views/drawer/elements/language-selection/index.js +++ /dev/null @@ -1,2 +0,0 @@ -import LanguageSelection from "./LanguageSelection.element"; -export default LanguageSelection; diff --git a/frontend/src/app/views/drawer/index.js b/frontend/src/app/views/drawer/index.js deleted file mode 100644 index 8229b47df..000000000 --- a/frontend/src/app/views/drawer/index.js +++ /dev/null @@ -1,2 +0,0 @@ -import Drawer from "./Drawer.view"; -export default Drawer; diff --git a/frontend/src/common/context/GammaLoading.context.jsx b/frontend/src/common/context/GammaLoading.context.jsx deleted file mode 100644 index 05954e3d9..000000000 --- a/frontend/src/common/context/GammaLoading.context.jsx +++ /dev/null @@ -1,41 +0,0 @@ -import React, { createContext, useCallback, useReducer } from "react"; -const GammaLoadingContext = createContext(true); - -const START_LOADING = "start-loading"; -const END_LOADING = "end-loading"; - -const loadingReducer = (state, action) => { - switch (action.type) { - case START_LOADING: - return true; - case END_LOADING: - return false; - default: - return state; - } -}; - -const GammaLoadingSingletonProvider = ({ children }) => { - const [loading, dispatch] = useReducer(loadingReducer, true); - const startLoading = useCallback(() => { - dispatch(START_LOADING); - }, [dispatch]); - const endLoading = useCallback(() => { - dispatch(END_LOADING); - }, [dispatch]); - - return ( - - {children} - - ); -}; - -export { GammaLoadingSingletonProvider }; -export default GammaLoadingContext; diff --git a/frontend/src/common/context/GammaUser.context.jsx b/frontend/src/common/context/GammaUser.context.jsx deleted file mode 100644 index abfbf74ab..000000000 --- a/frontend/src/common/context/GammaUser.context.jsx +++ /dev/null @@ -1,52 +0,0 @@ -import React, { createContext, useCallback, useState } from "react"; -import { getRequest } from "../../api/utils/api"; -import { on401 } from "../utils/error-handling/error-handling"; -const GammaUserContext = createContext(null); - -const GammaUserSingletonProvider = ({ children }) => { - const [[loading, error], setStatus] = useState([true, false]); - const [user, setUser] = useState(null); - - const update = useCallback( - (redirect = true) => { - setStatus([true, false]); - return new Promise((resolve, reject) => { - getRequest("/users/me", null, redirect) - .then(response => { - const user = response.data; - setUser(user); - setStatus([false, false]); - resolve(response); - }) - .catch(error => { - if ( - error.response != null && - error.response.status === 401 && - redirect - ) { - on401(); - } else { - setStatus([false, true]); - } - reject(error); - }); - }); - }, - [setUser] - ); - - const ignore = useCallback(() => { - setStatus([false, false]); - }, [setStatus]); - - return ( - - {children} - - ); -}; - -export { GammaUserSingletonProvider }; -export default GammaUserContext; diff --git a/frontend/src/common/declaratives/map-path-to-step/MapPathToStep.declarative.jsx b/frontend/src/common/declaratives/map-path-to-step/MapPathToStep.declarative.jsx deleted file mode 100644 index 463670e6a..000000000 --- a/frontend/src/common/declaratives/map-path-to-step/MapPathToStep.declarative.jsx +++ /dev/null @@ -1,21 +0,0 @@ -import PropTypes from "prop-types"; - -const MapPathToStep = ({ currentPath, pathToStepMap, render }) => - render(getCurrentStep(currentPath, pathToStepMap)); - -function getCurrentStep(currentPath, pathToStepMap) { - if (!pathToStepMap.hasOwnProperty(currentPath)) { - console.log("WARNING: There isn't a step for the path: " + currentPath); - return 0; - } else { - return pathToStepMap[currentPath]; - } -} - -MapPathToStep.propTypes = { - currentPath: PropTypes.string.isRequired, - pathToStepMap: PropTypes.object.isRequired, - render: PropTypes.func.isRequired -}; - -export default MapPathToStep; diff --git a/frontend/src/common/declaratives/map-path-to-step/index.js b/frontend/src/common/declaratives/map-path-to-step/index.js deleted file mode 100644 index 422f81461..000000000 --- a/frontend/src/common/declaratives/map-path-to-step/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from "./MapPathToStep.declarative"; diff --git a/frontend/src/common/elements/display-groups-table/DisplayGroupsTable.element.jsx b/frontend/src/common/elements/display-groups-table/DisplayGroupsTable.element.jsx deleted file mode 100644 index 130ca8104..000000000 --- a/frontend/src/common/elements/display-groups-table/DisplayGroupsTable.element.jsx +++ /dev/null @@ -1,79 +0,0 @@ -import React from "react"; -import translations from "./DisplayGroupsTable.element.translations"; -import { - DigitTable, - useDigitTranslations -} from "@cthit/react-digit-components"; -import { - GROUP_DESCRIPTION, - GROUP_EMAIL, - GROUP_FUNCTION, - GROUP_ID, - GROUP_NAME, - GROUP_PRETTY_NAME -} from "../../../api/groups/props.groups.api"; - -function generateHeaderTexts(text) { - const output = {}; - - output[GROUP_ID] = text.Id; - output[GROUP_NAME] = text.Name; - output[GROUP_DESCRIPTION] = text.Description; - output[GROUP_EMAIL] = text.Email; - output[GROUP_FUNCTION] = text.Function; - output[GROUP_PRETTY_NAME] = text.PrettyName; - output["__link"] = text.Details; - - return output; -} - -function modifyData(groups, text, activeLanguage, columns) { - return groups.map(group => { - const newGroup = { ...group }; - - newGroup[GROUP_ID] = group[GROUP_ID]; - newGroup[GROUP_NAME] = group[GROUP_NAME]; - newGroup[GROUP_DESCRIPTION] = - columns.includes(GROUP_DESCRIPTION) && - group[GROUP_DESCRIPTION] != null - ? group[GROUP_DESCRIPTION][activeLanguage] - : null; - newGroup[GROUP_EMAIL] = group[GROUP_EMAIL]; - newGroup[GROUP_FUNCTION] = - columns.includes(GROUP_FUNCTION) && group[GROUP_FUNCTION] != null - ? group[GROUP_FUNCTION][activeLanguage] - : null; - newGroup["__link"] = "/groups/" + group[GROUP_ID]; - - return newGroup; - }); -} - -const DisplayGroupsTable = ({ title, groups, columnsOrder, margin = {} }) => { - const [text, activeLanguage] = useDigitTranslations(translations); - - if (groups == null) { - return null; - } - - return ( - - ); -}; - -DisplayGroupsTable.defaultProps = { - columnsOrder: [GROUP_NAME, GROUP_EMAIL] -}; - -export default DisplayGroupsTable; diff --git a/frontend/src/common/elements/display-groups-table/DisplayGroupsTable.element.translations.json b/frontend/src/common/elements/display-groups-table/DisplayGroupsTable.element.translations.json deleted file mode 100644 index 40b734098..000000000 --- a/frontend/src/common/elements/display-groups-table/DisplayGroupsTable.element.translations.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "Groups": ["Groups", "Grupper"], - "Name": ["Name", "Namn"], - "Description": ["Description", "Beskrivning"], - "Email": ["Email", "Email"], - "Function": ["Function", "Uppdrag"], - "PrettyName": ["Name", "Namn"], - "Type": ["Group type", "Grupp typ"], - "Society": ["Society", "Förening"], - "Committee": ["Committee", "Kommitté"], - "Board": ["Board", "Nämnd"], - "Id": ["Id", "Id"], - "Details": ["Details", "Detaljer"], - "NoGroups": ["There's no groups", "Det finns inga grupper"], - "SearchForGroups": ["Search for groups", "Sök efter grupper"] -} diff --git a/frontend/src/common/elements/display-groups-table/index.js b/frontend/src/common/elements/display-groups-table/index.js deleted file mode 100644 index e69de29bb..000000000 diff --git a/frontend/src/common/elements/display-members-table/DisplayMembersTable.element.jsx b/frontend/src/common/elements/display-members-table/DisplayMembersTable.element.jsx deleted file mode 100644 index 41ce65643..000000000 --- a/frontend/src/common/elements/display-members-table/DisplayMembersTable.element.jsx +++ /dev/null @@ -1,94 +0,0 @@ -import React from "react"; -import { - DigitTable, - useDigitTranslations -} from "@cthit/react-digit-components"; - -import translations from "./DisplayMembersTable.element.translations"; - -import { - USER_ACCEPTANCE_YEAR, - USER_CID, - USER_FIRST_NAME, - USER_LAST_NAME, - USER_NICK -} from "../../../api/users/props.users.api"; - -function generateHeaderTexts(text) { - const headerTexts = {}; - - headerTexts[USER_FIRST_NAME] = text.FirstName; - headerTexts[USER_LAST_NAME] = text.LastName; - headerTexts[USER_CID] = text.Cid; - headerTexts[USER_NICK] = text.Nick; - headerTexts[USER_ACCEPTANCE_YEAR] = text.AcceptanceYear; - headerTexts["postName"] = text.PostName; - headerTexts["postEmail"] = text.PostEmail; - headerTexts["__link"] = text.Details; - - return headerTexts; -} - -const DisplayMembersTable = ({ - group, - users, - noUsersText, - margin = "0px", - title -}) => { - const [text, activeLanguage] = useDigitTranslations(translations); - - return ( - { - const officialPostName = - activeLanguage === "sv" ? user.post.sv : user.post.en; - - const unofficialPostName = - user.unofficialPostName === officialPostName || - user.unofficialPostName == null || - user.unofficialPostName === "" - ? "" - : " - " + user.unofficialPostName; - - var postEmail; - - if (group != null && group.active && user.post.emailPrefix) { - postEmail = - user.post.emailPrefix + - "." + - group.superGroupName + - "@chalmers.it"; - } - - return { - ...user, - postName: officialPostName + unofficialPostName, - postEmail, - __link: user.id != null ? "/users/" + user.id : null - }; - })} - emptyTableText={noUsersText || text.NoUsers} - startRowsPerPage={ - users.length < 5 ? 5 : users.length < 10 ? 10 : 25 - } - size={{ minWidth: "288px", height: "100%" }} - /> - ); -}; - -DisplayMembersTable.defaultProps = { - users: [] -}; - -export default DisplayMembersTable; diff --git a/frontend/src/common/elements/display-members-table/DisplayMembersTable.element.translations.json b/frontend/src/common/elements/display-members-table/DisplayMembersTable.element.translations.json deleted file mode 100644 index 2d6ee4c33..000000000 --- a/frontend/src/common/elements/display-members-table/DisplayMembersTable.element.translations.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "FirstName": ["First name", "Förnamn"], - "LastName": ["Last name", "Efternamn"], - "Cid": ["Cid", "Cid"], - "Nick": ["Nick", "Nick"], - "AcceptanceYear": ["Acceptance year", "Antagningsår"], - "Details": ["Details", "Detaljer"], - "NoUsers": [ - "There's no users, wait how are you logged in?!?!?!?!", - "Det finns inga användare, wait hur är du inloggad?!?!?!?!" - ], - "Users": ["Members", "Medlemmar"], - "SearchForUsers": ["Search for users", "Sök efter användare"], - "PostName": ["Post name", "Postnamn"] -} diff --git a/frontend/src/common/elements/display-members-table/index.js b/frontend/src/common/elements/display-members-table/index.js deleted file mode 100644 index 2fbd58551..000000000 --- a/frontend/src/common/elements/display-members-table/index.js +++ /dev/null @@ -1,2 +0,0 @@ -import DisplayMembersTable from "./DisplayMembersTable.element"; -export default DisplayMembersTable; diff --git a/frontend/src/common/elements/display-user-details/DisplayUserDetails.element.jsx b/frontend/src/common/elements/display-user-details/DisplayUserDetails.element.jsx deleted file mode 100644 index bb70b9f18..000000000 --- a/frontend/src/common/elements/display-user-details/DisplayUserDetails.element.jsx +++ /dev/null @@ -1,86 +0,0 @@ -import React from "react"; -import { - DigitButton, - DigitDesign, - DigitDisplayData, - DigitTranslations -} from "@cthit/react-digit-components"; -import { - USER_ACCEPTANCE_YEAR, - USER_CID, - USER_EMAIL, - USER_FIRST_NAME, - USER_LAST_NAME, - USER_NICK -} from "../../../api/users/props.users.api"; - -import translations from "./DisplayUserDetails.element.translations"; - -function createKeysTexts(text) { - const output = {}; - - output[USER_CID] = text.cid; - output[USER_FIRST_NAME] = text.firstName; - output[USER_LAST_NAME] = text.lastName; - output[USER_NICK] = text.nick; - output[USER_EMAIL] = text.email; - output[USER_ACCEPTANCE_YEAR] = text.acceptanceYear; - - return output; -} - -function getUserPath(user, isMe) { - if (isMe) { - return "/me"; - } - return "/users/" + user.id; -} - -const DisplayUserDetails = ({ user, isMe }) => ( - ( - - - - - - - - - - - - - - - )} - /> -); - -export default DisplayUserDetails; diff --git a/frontend/src/common/elements/display-user-details/DisplayUserDetails.element.translations.json b/frontend/src/common/elements/display-user-details/DisplayUserDetails.element.translations.json deleted file mode 100644 index a3b6f4050..000000000 --- a/frontend/src/common/elements/display-user-details/DisplayUserDetails.element.translations.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "Cid": ["Cid", "Cid"], - "FirstName": ["First name", "Förnamn"], - "LastName": ["Last name", "Efternamn"], - "Nick": ["Nick", "Nick"], - "Email": ["Email", "Email"], - "AcceptanceYear": ["Acceptance Year", "Antagningsår"], - "CreatedAt": ["Account created at", "Konto skapat"], - "LastModifiedAt": ["Account last modified at", "Konto senast uppdaterat"], - "Edit": ["Edit account", "Redigera konto"], - "ChangePassword": ["Change Password", "Ändra Lösenord"] -} diff --git a/frontend/src/common/elements/display-user-details/index.js b/frontend/src/common/elements/display-user-details/index.js deleted file mode 100644 index e69de29bb..000000000 diff --git a/frontend/src/common/elements/user-form/UserForm.view.jsx b/frontend/src/common/elements/user-form/UserForm.view.jsx deleted file mode 100644 index 463806d5e..000000000 --- a/frontend/src/common/elements/user-form/UserForm.view.jsx +++ /dev/null @@ -1,188 +0,0 @@ -import { - DigitEditData, - DigitSelect, - DigitTextField, - DigitTranslations -} from "@cthit/react-digit-components"; -import React from "react"; -import * as yup from "yup"; -import { - USER_ACCEPTANCE_YEAR, - USER_CID, - USER_EMAIL, - USER_FIRST_NAME, - USER_LAST_NAME, - USER_NICK, - USER_PASSWORD, - USER_LANGUAGE -} from "../../../api/users/props.users.api"; -import translations from "./UserForm.view.translations.json"; -import { - ENGLISH_LANGUAGE, - SWEDISH_LANGUAGE -} from "../../../api/utils/commonProps"; - -function _getCurrentYear() { - return new Date().getFullYear() + ""; -} - -function _generateAcceptanceYears() { - const output = {}; - const startYear = 2001; - const currentYear = _getCurrentYear(); - for (var i = currentYear; i >= startYear; i--) { - output["" + i] = i; - } - - return output; -} - -function generateValidationSchema(text, includeCidAndPassword) { - const schema = {}; - schema[USER_FIRST_NAME] = yup.string().required(text.FieldRequired); - schema[USER_LAST_NAME] = yup.string().required(text.FieldRequired); - schema[USER_NICK] = yup.string().required(text.FieldRequired); - schema[USER_EMAIL] = yup.string().required(text.FieldRequired); - schema[USER_ACCEPTANCE_YEAR] = yup.number().required(text.FieldRequired); - - if (includeCidAndPassword) { - schema[USER_CID] = yup.string().required(text.FieldRequired); - schema[USER_PASSWORD] = yup.string().required(text.FieldRequired); - } - - return yup.object().shape(schema); -} - -function generateEditComponentData(text, includeCidAndPassword) { - const componentData = {}; - - componentData[USER_FIRST_NAME] = { - component: DigitTextField, - componentProps: { - upperLabel: text.FirstName, - outlined: true - } - }; - - componentData[USER_LAST_NAME] = { - component: DigitTextField, - componentProps: { - upperLabel: text.LastName, - outlined: true - } - }; - - componentData[USER_NICK] = { - component: DigitTextField, - componentProps: { - upperLabel: text.Nick, - outlined: true - } - }; - - componentData[USER_EMAIL] = { - component: DigitTextField, - componentProps: { - upperLabel: text.Email, - outlined: true - } - }; - - componentData[USER_ACCEPTANCE_YEAR] = { - component: DigitSelect, - componentProps: { - upperLabel: text.AcceptanceYear, - valueToTextMap: _generateAcceptanceYears(), - reverse: true, - outlined: true - } - }; - - const languageOptions = {}; - languageOptions[SWEDISH_LANGUAGE] = "Svenska"; - languageOptions[ENGLISH_LANGUAGE] = "English"; - - componentData[USER_LANGUAGE] = { - component: DigitSelect, - componentProps: { - upperLabel: text.Language, - valueToTextMap: languageOptions, - outlined: true - } - }; - - if (includeCidAndPassword) { - componentData[USER_CID] = { - component: DigitTextField, - componentProps: { - upperLabel: text.Cid, - outlined: true - } - }; - - componentData[USER_PASSWORD] = { - component: DigitTextField, - componentProps: { - upperLabel: text.Password, - password: true, - outlined: true - } - }; - } - return componentData; -} - -function getKeysOrder(includeCidAndPassword) { - const output = [ - USER_FIRST_NAME, - USER_LAST_NAME, - USER_NICK, - USER_EMAIL, - USER_ACCEPTANCE_YEAR, - USER_LANGUAGE - ]; - - if (includeCidAndPassword) { - output.push(USER_CID); - output.push(USER_PASSWORD); - } - - return output; -} - -const UserForm = ({ - initialValues, - includeCidAndPassword, - onSubmit, - titleText, - submitText -}) => ( - ( - { - actions.setSubmitting(false); - onSubmit(values, actions); - }} - validationSchema={generateValidationSchema( - text, - includeCidAndPassword - )} - keysOrder={getKeysOrder(includeCidAndPassword)} - keysComponentData={generateEditComponentData( - text, - includeCidAndPassword - )} - /> - )} - /> -); - -export default UserForm; diff --git a/frontend/src/common/elements/user-form/UserForm.view.translations.json b/frontend/src/common/elements/user-form/UserForm.view.translations.json deleted file mode 100644 index f43518dc3..000000000 --- a/frontend/src/common/elements/user-form/UserForm.view.translations.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "Cid": ["Cid", "Cid"], - "FirstName": ["First name", "Förnamn"], - "LastName": ["Last name", "Efternamn"], - "Nick": ["Nick", "Nick"], - "Email": ["Email", "Email"], - "AcceptanceYear": ["Acceptance year", "Antagningsår"], - "Password": ["Password", "Lösenord"], - "Language": ["Language", "Språk"] -} diff --git a/frontend/src/common/elements/user-form/index.js b/frontend/src/common/elements/user-form/index.js deleted file mode 100644 index 41ebc6067..000000000 --- a/frontend/src/common/elements/user-form/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from "./UserForm.view"; diff --git a/frontend/src/common/hooks/use-gamma-has-authority/use-gamma-has-authority.js b/frontend/src/common/hooks/use-gamma-has-authority/use-gamma-has-authority.js deleted file mode 100644 index 5a98fcb43..000000000 --- a/frontend/src/common/hooks/use-gamma-has-authority/use-gamma-has-authority.js +++ /dev/null @@ -1,13 +0,0 @@ -import useGammaUser from "../use-gamma-user/useGammaUser"; -import some from "lodash/some"; - -function useGammaHasAuthority(authority) { - const user = useGammaUser(); - if (user == null) { - return false; - } - - return some(user.authorities, ["authority", authority]); -} - -export default useGammaHasAuthority; diff --git a/frontend/src/common/hooks/use-gamma-is-admin/useGammaIsAdmin.js b/frontend/src/common/hooks/use-gamma-is-admin/useGammaIsAdmin.js deleted file mode 100644 index 6468305f1..000000000 --- a/frontend/src/common/hooks/use-gamma-is-admin/useGammaIsAdmin.js +++ /dev/null @@ -1,7 +0,0 @@ -import useGammaHasAuthority from "../use-gamma-has-authority/use-gamma-has-authority"; - -function useGammaIsAdmin() { - return useGammaHasAuthority("admin"); -} - -export default useGammaIsAdmin; diff --git a/frontend/src/common/hooks/use-gamma-user/useGammaUser.js b/frontend/src/common/hooks/use-gamma-user/useGammaUser.js deleted file mode 100644 index 5bac72bce..000000000 --- a/frontend/src/common/hooks/use-gamma-user/useGammaUser.js +++ /dev/null @@ -1,9 +0,0 @@ -import { useContext } from "react"; -import GammaUserContext from "../../context/GammaUser.context"; - -function useGammaUser() { - const [user] = useContext(GammaUserContext); - return user; -} - -export default useGammaUser; diff --git a/frontend/src/common/utils/checker/gamma.js b/frontend/src/common/utils/checker/gamma.js deleted file mode 100644 index 8f4a0d716..000000000 --- a/frontend/src/common/utils/checker/gamma.js +++ /dev/null @@ -1,10 +0,0 @@ -import some from "lodash/some"; - -const inGroup = (user, group) => { - if (user == null) { - return false; - } - return some(group.groupMembers, ["id", user.id]); -}; - -export { inGroup }; diff --git a/frontend/src/common/utils/configs/envVariablesLoader.js b/frontend/src/common/utils/configs/envVariablesLoader.js deleted file mode 100644 index 300f5b7c3..000000000 --- a/frontend/src/common/utils/configs/envVariablesLoader.js +++ /dev/null @@ -1,6 +0,0 @@ -function getBackendUrl() { - var backendUrl = process.env.REACT_APP_BACKEND_URL; - return backendUrl == null ? "http://localhost:8081/api" : backendUrl; -} - -export { getBackendUrl }; diff --git a/frontend/src/common/utils/error-handling/error-handling.js b/frontend/src/common/utils/error-handling/error-handling.js deleted file mode 100644 index cd956b813..000000000 --- a/frontend/src/common/utils/error-handling/error-handling.js +++ /dev/null @@ -1,5 +0,0 @@ -import { getBackendUrl } from "../configs/envVariablesLoader"; - -export const on401 = () => { - window.location.href = getBackendUrl() + "/login"; -}; diff --git a/frontend/src/common/utils/formatters/statusCode.formatter.js b/frontend/src/common/utils/formatters/statusCode.formatter.js deleted file mode 100644 index 4a1d8d68c..000000000 --- a/frontend/src/common/utils/formatters/statusCode.formatter.js +++ /dev/null @@ -1,3 +0,0 @@ -export default function statusCode(error) { - return error.response == null ? -1 : error.response.status; -} diff --git a/frontend/src/common/utils/formatters/statusMessage.formatter.js b/frontend/src/common/utils/formatters/statusMessage.formatter.js deleted file mode 100644 index 0f070d273..000000000 --- a/frontend/src/common/utils/formatters/statusMessage.formatter.js +++ /dev/null @@ -1,3 +0,0 @@ -export default function statusMessage(error) { - return error.response == null ? null : error.response.data.message; -} diff --git a/frontend/src/common/utils/generators/id.generator.js b/frontend/src/common/utils/generators/id.generator.js deleted file mode 100644 index 880bcefd0..000000000 --- a/frontend/src/common/utils/generators/id.generator.js +++ /dev/null @@ -1,6 +0,0 @@ -let lastId = 0; - -export default function(prefix = "id") { - lastId++; - return `${prefix}-${lastId}`; -} diff --git a/frontend/src/common/utils/generators/user-form.generator.js b/frontend/src/common/utils/generators/user-form.generator.js deleted file mode 100644 index 3bca75e40..000000000 --- a/frontend/src/common/utils/generators/user-form.generator.js +++ /dev/null @@ -1,161 +0,0 @@ -import React from "react"; -import { - USER_ACCEPTANCE_YEAR, - USER_CID, - USER_EMAIL, - USER_FIRST_NAME, - USER_GROUPS, - USER_LANGUAGE, - USER_LAST_NAME, - USER_NICK, - USER_PASSWORD, - USER_PHONE, - USER_AGREEMENT -} from "../../../api/users/props.users.api"; -import { - DigitSelect, - DigitSwitch, - DigitTextField -} from "@cthit/react-digit-components"; -import { - ENGLISH_LANGUAGE, - SWEDISH_LANGUAGE -} from "../../../api/utils/commonProps"; -import DisplayGroupsTable from "../../elements/display-groups-table/DisplayGroupsTable.element"; -import { GROUP_PRETTY_NAME } from "../../../api/groups/props.groups.api"; - -function _getCurrentYear() { - return new Date().getFullYear() + ""; -} - -function _generateAcceptanceYears() { - const output = {}; - const startYear = 2001; - const currentYear = _getCurrentYear(); - for (var i = currentYear; i >= startYear; i--) { - output["" + i] = i; - } - - return output; -} - -export function generateUserEditComponentData(text) { - const componentData = {}; - - componentData[USER_FIRST_NAME] = { - component: DigitTextField, - componentProps: { - upperLabel: text.FirstName, - outlined: true, - maxLength: 50 - } - }; - - componentData[USER_LAST_NAME] = { - component: DigitTextField, - componentProps: { - upperLabel: text.LastName, - outlined: true, - maxLength: 50 - } - }; - - componentData[USER_NICK] = { - component: DigitTextField, - componentProps: { - upperLabel: text.Nick, - outlined: true, - maxLength: 20 - } - }; - - componentData[USER_EMAIL] = { - component: DigitTextField, - componentProps: { - upperLabel: text.Email, - outlined: true, - maxLength: 100 - } - }; - - componentData[USER_ACCEPTANCE_YEAR] = { - component: DigitSelect, - componentProps: { - upperLabel: text.AcceptanceYear, - lowerLabel: text.AcceptanceYearLowerLabel, - valueToTextMap: _generateAcceptanceYears(), - reverse: true, - outlined: true - } - }; - - componentData[USER_CID] = { - component: DigitTextField, - componentProps: { - upperLabel: text.Cid, - outlined: true, - maxLength: 10 - } - }; - - componentData[USER_AGREEMENT] = { - component: DigitSwitch, - componentProps: { - label: text.AcceptUserAgreement, - primary: true - } - }; - - componentData[USER_PHONE] = { - component: DigitTextField, - componentProps: { - upperLabel: text.Phone, - outlined: true, - maxLength: 15 - } - }; - - const languageOptions = {}; - languageOptions[SWEDISH_LANGUAGE] = "Svenska"; - languageOptions[ENGLISH_LANGUAGE] = "English"; - - componentData[USER_LANGUAGE] = { - component: DigitSelect, - componentProps: { - upperLabel: text.Language, - lowerLabel: text.LanguageLowerLabel, - valueToTextMap: languageOptions, - outlined: true - } - }; - - componentData[USER_PASSWORD] = { - component: DigitTextField, - componentProps: { - upperLabel: text.Password, - outlined: true, - password: true - } - }; - - return componentData; -} - -export function generateUserCustomDetailsRenders(text, ignoreGroups) { - const output = {}; - - if (ignoreGroups) { - output[USER_GROUPS] = () => null; - } else { - output[USER_GROUPS] = data => - data[USER_GROUPS] != null ? ( - - ) : null; - } - - return output; -} diff --git a/frontend/src/common/utils/translations/CommonTranslations.json b/frontend/src/common/utils/translations/CommonTranslations.json deleted file mode 100644 index 090121bad..000000000 --- a/frontend/src/common/utils/translations/CommonTranslations.json +++ /dev/null @@ -1,70 +0,0 @@ -{ - "Add": ["Add", "Lägg till"], - "Cancel": ["Cancel", "Avbryt"], - "Back": ["Back", "Tillbaka"], - "Close": ["Close", "Stäng"], - "Edit": ["Edit", "Redigera"], - "Update": ["Edit", "Redigera"], - "Delete": ["Delete", "Radera"], - "Create": ["Create", "Skapa"], - "Details": ["Details", "Detaljer"], - "IsRequired": [" is required", " krävs"], - "FieldNotEmail": ["Must be an email", "Måste vara en giltig emailadress"], - "SomethingWentWrong": [ - "Something went wrong when trying to send the data, please try again or contact digit@chalmers.it", - "Någonting gick snett när vi försökte skicka ditt data, var vänlig och försök igen eller kontakta digit@chalmers.it" - ], - "Logout": ["Logout", "Logga ut"], - "LoggedOut": ["You have logged out", "Du har loggat ut"], - "Save": ["Save", "Spara"], - "Swedish": ["Swedish", "Svenska"], - "English": ["English", "Engelska"], - "Email": ["Email", "Email"], - "Id": ["Id", "Id"], - "Cid": ["Cid", "Cid"], - "Name": ["Name", "Namn"], - "AreYouSure": ["Are you sure?", "Är du säker?"], - "AreYouSureYouWantToDelete": [ - "Are you sure you want to delete", - "Är du säker att du vill radera" - ], - "WasCreatedSuccessfully": [ - "was created successfully", - "skapades framgångsrikt" - ], - "WasDeletedSuccessfully": [ - "was deleted successfully", - "raderades framgångsrikt" - ], - "WasUpdatedSuccessfully": [ - "was updated successfully", - "uppdaterades framgångsrikt" - ], - "FailedDeleting": [ - "Failed when trying to delete", - "Misslyckades att radera" - ], - "Groups": ["Groups", "Grupper"], - "NoGroups": ["No groups", "Inga grupper"], - "Next": ["Next", "Nästa"], - "SwedishDescription": ["Swedish description", "Svensk beskrivning"], - "EnglishDescription": ["English description", "Engelsk beskrivning"], - "Description": ["Description", "Beskrivning"], - "Nick": ["Nick", "Nick"], - "Password": ["Password", "Lösenord"], - "FirstName": ["First name", "Förnamn"], - "LastName": ["Last name", "Efternamn"], - "ConfirmPassword": ["Confirm password", "Bekräfta lösenord"], - "PrettyName": ["Pretty name", "Pretty namn"], - "Type": ["Group type", "Grupp typ"], - "Society": ["Society", "Förening"], - "Committee": ["Committee", "Kommitté"], - "Board": ["Board", "Nämnd"], - "Admin": ["Admin", "Admin"], - "Functionaries": ["Functionaries", "Funktionärer"], - "Alumni": ["Alumni", "Pateter"], - "SuperGroup": ["Super group", "Supergrupp"], - "Post": ["Post", "Post"], - "Search": ["Search", "Sök"], - "PostEmail": ["Post email", "Post mail"] -} diff --git a/frontend/src/common/views/change-language-locally/ChangeLanguageLocally.view.jsx b/frontend/src/common/views/change-language-locally/ChangeLanguageLocally.view.jsx deleted file mode 100644 index 7f90adcdb..000000000 --- a/frontend/src/common/views/change-language-locally/ChangeLanguageLocally.view.jsx +++ /dev/null @@ -1,35 +0,0 @@ -import React from "react"; -import translations from "./ChangeLanguageLocally.view.translations"; -import { - DigitDesign, - DigitSelect, - useDigitTranslations -} from "@cthit/react-digit-components"; - -const ChangeLanguageLocally = () => { - const [text, activeLanguage, setActiveLanguage] = useDigitTranslations( - translations - ); - - return ( - - - - - - { - setActiveLanguage(e.target.value); - }} - valueToTextMap={{ sv: text.Swedish, en: text.English }} - outlined - upperLabel={text.YourLanguage} - /> - - - ); -}; - -export default ChangeLanguageLocally; diff --git a/frontend/src/common/views/change-language-locally/ChangeLanguageLocally.view.translations.json b/frontend/src/common/views/change-language-locally/ChangeLanguageLocally.view.translations.json deleted file mode 100644 index e454a5cad..000000000 --- a/frontend/src/common/views/change-language-locally/ChangeLanguageLocally.view.translations.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "ChooseLanguage": ["Choose language", "Välj språk"] -} diff --git a/frontend/src/common/views/change-language-locally/index.js b/frontend/src/common/views/change-language-locally/index.js deleted file mode 100644 index 5bb7fe80b..000000000 --- a/frontend/src/common/views/change-language-locally/index.js +++ /dev/null @@ -1,2 +0,0 @@ -import ChangeLanguageLocally from "./ChangeLanguageLocally.view"; -export default ChangeLanguageLocally; diff --git a/frontend/src/common/views/insufficient-access/InsufficientAccess.jsx b/frontend/src/common/views/insufficient-access/InsufficientAccess.jsx deleted file mode 100644 index 8c076ee36..000000000 --- a/frontend/src/common/views/insufficient-access/InsufficientAccess.jsx +++ /dev/null @@ -1,29 +0,0 @@ -import React from "react"; -import { - DigitDesign, - DigitLayout, - DigitText, - useDigitTranslations -} from "@cthit/react-digit-components"; - -import translations from "./InsufficientAccess.translations"; - -const InsufficientAccess = () => { - const [text] = useDigitTranslations(translations); - - return ( - - - - - - - - - - - - ); -}; - -export default InsufficientAccess; diff --git a/frontend/src/common/views/insufficient-access/InsufficientAccess.translations.json b/frontend/src/common/views/insufficient-access/InsufficientAccess.translations.json deleted file mode 100644 index 8626df8f4..000000000 --- a/frontend/src/common/views/insufficient-access/InsufficientAccess.translations.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "InsufficientAccess": [ - "403 - Insufficient access", - "403 - Otillräcklig tillgång" - ], - "YouDontHaveAccess": [ - "You do not have access to this page. Please contact digit@chalmers.it if you think this is a mistake.", - "Du har inte tillgång till denna sida. Kontakta digit@chalmers.it om du tror det här är ett misstag." - ] -} diff --git a/frontend/src/common/views/insufficient-access/index.js b/frontend/src/common/views/insufficient-access/index.js deleted file mode 100644 index b15573a4c..000000000 --- a/frontend/src/common/views/insufficient-access/index.js +++ /dev/null @@ -1,2 +0,0 @@ -import InsufficientAccess from "./InsufficientAccess"; -export default InsufficientAccess; diff --git a/frontend/src/index.js b/frontend/src/index.js deleted file mode 100644 index 755f12920..000000000 --- a/frontend/src/index.js +++ /dev/null @@ -1,16 +0,0 @@ -import React from "react"; -import ReactDOM from "react-dom"; - -import App from "./app"; - -import ProvidersForApp from "./app/ProvidersForApp"; - -const Index = () => ( - - - - - -); - -ReactDOM.render(, document.getElementById("root")); diff --git a/frontend/src/registerServiceWorker.js b/frontend/src/registerServiceWorker.js deleted file mode 100644 index 86cfe714f..000000000 --- a/frontend/src/registerServiceWorker.js +++ /dev/null @@ -1,120 +0,0 @@ -// In production, we register a service worker to serve assets from local cache. - -// This lets the app load faster on subsequent visits in production, and gives -// it offline capabilities. However, it also means that developers (and users) -// will only see deployed updates on the "N+1" visit to a page, since previously -// cached resources are updated in the background. - -// To learn more about the benefits of this model, read https://goo.gl/KwvDNy. -// This link also includes instructions on opting out of this behavior. - -const isLocalhost = Boolean( - window.location.hostname === "localhost" || - // [::1] is the IPv6 localhost address. - window.location.hostname === "[::1]" || - // 127.0.0.1/8 is considered localhost for IPv4. - window.location.hostname.match( - /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ - ) -); - -export default function register() { - if (process.env.NODE_ENV === "production" && "serviceWorker" in navigator) { - // The URL constructor is available in all browsers that support SW. - const publicUrl = new URL(process.env.PUBLIC_URL, window.location); - if (publicUrl.origin !== window.location.origin) { - // Our service worker won't work if PUBLIC_URL is on a different origin - // from what our page is served on. This might happen if a CDN is used to - // serve assets; see https://github.com/facebookincubator/create-react-app/issues/2374 - return; - } - - window.addEventListener("load", () => { - const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; - - if (isLocalhost) { - // This is running on localhost. Lets check if a service worker still exists or not. - checkValidServiceWorker(swUrl); - - // Add some additional logging to localhost, pointing developers to the - // service worker/PWA documentation. - navigator.serviceWorker.ready.then(() => { - console.log( - "This web app is being served cache-first by a service " + - "worker. To learn more, visit https://goo.gl/SC7cgQ" - ); - }); - } else { - // Is not local host. Just register service worker - registerValidSW(swUrl); - } - }); - } -} - -function registerValidSW(swUrl) { - navigator.serviceWorker - .register(swUrl) - .then(registration => { - registration.onupdatefound = () => { - const installingWorker = registration.installing; - installingWorker.onstatechange = () => { - if (installingWorker.state === "installed") { - if (navigator.serviceWorker.controller) { - // At this point, the old content will have been purged and - // the fresh content will have been added to the cache. - // It's the perfect time to display a "New content is - // available; please refresh." message in your web app. - console.log( - "New content is available; please refresh." - ); - } else { - // At this point, everything has been precached. - // It's the perfect time to display a - // "Content is cached for offline use." message. - console.log("Content is cached for offline use."); - } - } - }; - }; - }) - .catch(error => { - console.error("Error during service worker registration:", error); - }); -} - -function checkValidServiceWorker(swUrl) { - // Check if the service worker can be found. If it can't reload the page. - fetch(swUrl) - .then(response => { - // Ensure service worker exists, and that we really are getting a JS file. - if ( - response.status === 404 || - response.headers.get("content-type").indexOf("javascript") === - -1 - ) { - // No service worker found. Probably a different app. Reload the page. - navigator.serviceWorker.ready.then(registration => { - registration.unregister().then(() => { - window.location.reload(); - }); - }); - } else { - // Service worker found. Proceed as normal. - registerValidSW(swUrl); - } - }) - .catch(() => { - console.log( - "No internet connection found. App is running in offline mode." - ); - }); -} - -export function unregister() { - if ("serviceWorker" in navigator) { - navigator.serviceWorker.ready.then(registration => { - registration.unregister(); - }); - } -} diff --git a/frontend/src/setupProxy.js b/frontend/src/setupProxy.js deleted file mode 100644 index 7e8033b1a..000000000 --- a/frontend/src/setupProxy.js +++ /dev/null @@ -1,10 +0,0 @@ -const { createProxyMiddleware } = require("http-proxy-middleware"); -module.exports = function(app) { - app.use( - "/api", - createProxyMiddleware({ - target: process.env.HTTP_PROXY, - changeOrigin: true - }) - ); -}; diff --git a/frontend/src/setupTests.js b/frontend/src/setupTests.js deleted file mode 100644 index 3e522ca0b..000000000 --- a/frontend/src/setupTests.js +++ /dev/null @@ -1,8 +0,0 @@ -import Enzyme from "enzyme"; -import Adapter from "enzyme-adapter-react-16"; - -Enzyme.configure({ adapter: new Adapter() }); - -console.error = (warning, ...args) => { - throw new Error(warning); -}; diff --git a/frontend/src/use-cases/about/About.jsx b/frontend/src/use-cases/about/About.jsx deleted file mode 100644 index 3f191a169..000000000 --- a/frontend/src/use-cases/about/About.jsx +++ /dev/null @@ -1,58 +0,0 @@ -import React, { useMemo } from "react"; -import { - DigitDesign, - DigitLayout, - DigitText -} from "@cthit/react-digit-components"; - -const GithubLink = ({ gh }) => ( - - - -); - -const About = () => { - const pg = useMemo(() => { - const pg = [ - { nick: "Portals", gh: "Portals" }, - { nick: "Gurr", gh: "Gurr1" } - ]; - pg.sort(() => { - return 0.5 - Math.random(); - }); - return pg; - }, []); - - return ( - - - - - - - - - - - - - - - - - - - - - ); -}; - -export default About; diff --git a/frontend/src/use-cases/about/index.js b/frontend/src/use-cases/about/index.js deleted file mode 100644 index 1a156f067..000000000 --- a/frontend/src/use-cases/about/index.js +++ /dev/null @@ -1,2 +0,0 @@ -import About from "./About"; -export default About; diff --git a/frontend/src/use-cases/activation-codes/ActivationCodes.jsx b/frontend/src/use-cases/activation-codes/ActivationCodes.jsx deleted file mode 100644 index b06c1c775..000000000 --- a/frontend/src/use-cases/activation-codes/ActivationCodes.jsx +++ /dev/null @@ -1,77 +0,0 @@ -import React from "react"; -import { - getActivationCode, - getActivationCodes -} from "../../api/activation-codes/get.activationCodes.api"; -import { deleteActivationCode } from "../../api/activation-codes/delete.activationCodes.api"; -import { useDigitTranslations, DigitCRUD } from "@cthit/react-digit-components"; -import translations from "./ActivationCodes.translations"; -import InsufficientAccess from "../../common/views/insufficient-access"; -import useGammaIsAdmin from "../../common/hooks/use-gamma-is-admin/useGammaIsAdmin"; -import FourOFour from "../four-o-four"; -import FiveZeroZero from "../../app/elements/five-zero-zero"; -import { keysOrder, keysText } from "./ActivationCodes.options"; -import { - AC_CID, - AC_NAME -} from "../../api/activation-codes/props.activationCodes.api"; - -const ActivationCodes = () => { - const [text] = useDigitTranslations(translations); - - const admin = useGammaIsAdmin(); - if (!admin) { - return ; - } - - return ( - text.AreYouSure} - dialogDeleteDescription={data => - text.WouldYouLikeToDelete + " " + data[AC_CID] - } - dialogDeleteConfirm={() => text.Delete} - dialogDeleteCancel={() => text.Cancel} - toastDeleteSuccessful={data => - data[AC_CID] + " " + text.WasDeletedSuccessfully - } - toastDeleteFailed={data => - text.ActivationCodeDeletionFailed1 + - " " + - data[AC_NAME] + - " " + - text.ActivationCodeDeletionFailed2 - } - detailsTitle={data => data[AC_CID]} - deleteButtonText={data => text.Delete + " " + data[AC_CID]} - detailsButtonText={text.Details} - backButtonText={text.Back} - dateAndTimeProps={["createdAt"]} - statusRenders={{ - 403: () => , - 404: () => , - 500: (error, reset) => - }} - /> - ); -}; - -export default ActivationCodes; diff --git a/frontend/src/use-cases/activation-codes/ActivationCodes.options.js b/frontend/src/use-cases/activation-codes/ActivationCodes.options.js deleted file mode 100644 index 7a4a81c7f..000000000 --- a/frontend/src/use-cases/activation-codes/ActivationCodes.options.js +++ /dev/null @@ -1,18 +0,0 @@ -import { - AC_CID, - AC_CODE, - AC_CREATED_AT, - AC_ID -} from "../../api/activation-codes/props.activationCodes.api"; - -export const keysText = text => { - const keysText = {}; - keysText[AC_ID] = text.Id; - keysText[AC_CID] = text.Cid; - keysText[AC_CODE] = text.Code; - keysText[AC_CREATED_AT] = text.CreatedAt; - - return keysText; -}; - -export const keysOrder = () => [AC_CID, AC_CODE, AC_CREATED_AT]; diff --git a/frontend/src/use-cases/activation-codes/ActivationCodes.translations.json b/frontend/src/use-cases/activation-codes/ActivationCodes.translations.json deleted file mode 100644 index 737b0f34b..000000000 --- a/frontend/src/use-cases/activation-codes/ActivationCodes.translations.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "ActivationCodes": ["Activation codes", "Aktiveringskoder"], - "Cid": ["Cid", "Cid"], - "Code": ["Code", "Kod"], - "CreatedAt": ["Created at", "Skapad"], - "DeleteActivationCode": ["Delete activation code", "Radera aktiveringskod"], - "EditActivationCode": ["Edit activation code", "Redigera aktiveringskod"], - "WouldYouLikeToDelete": [ - "Would you like to delete the activation code for the cid", - "Vill du radera aktiveringskoden för cid:et" - ], - "Details": ["Details", "Detaljer"], - "NoActivationCodes": [ - "There's no activation codes", - "Det finns inga aktiveringskoder" - ], - "SearchForActivationCodes": [ - "Search for activation codes", - "Sök efter aktiveringskoder" - ], - "ActivationCodeDeletionFailed1": [ - "Something went wrong when trying to delete the activation code for the cid", - "Någonting gick fel när aktiveringskoden för cid:et" - ], - "ActivationCodeDeletionFailed2": ["", "försökte raderas"] -} diff --git a/frontend/src/use-cases/activation-codes/index.js b/frontend/src/use-cases/activation-codes/index.js deleted file mode 100644 index 26c159f3f..000000000 --- a/frontend/src/use-cases/activation-codes/index.js +++ /dev/null @@ -1,2 +0,0 @@ -import ActivationCodes from "./ActivationCodes"; -export default ActivationCodes; diff --git a/frontend/src/use-cases/api-keys/ApiKeys.jsx b/frontend/src/use-cases/api-keys/ApiKeys.jsx deleted file mode 100644 index e07e8a5c6..000000000 --- a/frontend/src/use-cases/api-keys/ApiKeys.jsx +++ /dev/null @@ -1,123 +0,0 @@ -import React from "react"; -import { - DigitButton, - DigitCRUD, - DigitText, - useDigitCustomDialog, - useDigitTranslations -} from "@cthit/react-digit-components"; -import { getApiKey, getApiKeys } from "../../api/api-keys/get.api-keys.api"; -import { addApiKey } from "../../api/api-keys/post.api-keys.api"; -import { deleteApiKey } from "../../api/api-keys/delete.api-keys.api"; -import translations from "./ApiKeys.translations"; -import InsufficientAccess from "../../common/views/insufficient-access"; -import useGammaIsAdmin from "../../common/hooks/use-gamma-is-admin/useGammaIsAdmin"; -import FourOFour from "../four-o-four"; -import FiveZeroZero from "../../app/elements/five-zero-zero"; -import { - initialValues, - keysComponentData, - keysOrder, - keysText, - validationSchema -} from "./ApiKeys.options"; -import { - API_ID, - API_NAME, - API_SECRET -} from "../../api/api-keys/props.api-keys.api"; - -const ApiKeys = () => { - const [text] = useDigitTranslations(translations); - const [showDialog] = useDigitCustomDialog({ - title: text.YourApiKeySecret, - renderButtons: confirm => ( - - ) - }); - - const admin = useGammaIsAdmin(); - if (!admin) { - return ; - } - - return ( - - addApiKey({ - name: newApi.name, - description: { - sv: newApi.descriptionSv, - en: newApi.descriptionEn - } - }) - } - onCreate={response => { - const secret = response.data[API_SECRET]; - showDialog({ - renderMain: () => ( - <> - - - - ) - }); - }} - idProp={API_ID} - name={"api"} - path={"/access-keys"} - tableProps={{ - titleText: text.ApiKeysTitle, - startOrderBy: API_NAME, - search: true, - flex: "1", - startOrderByDirection: "asc", - size: { minWidth: "288px" }, - padding: "0px", - searchText: text.Search - }} - detailsButtonText={text.Details} - dialogDeleteConfirm={data => text.Delete + " " + data[API_NAME]} - dialogDeleteTitle={() => text.DialogDeleteTitle} - dialogDeleteDescription={data => - text.DialogDeleteDescription1 + - data[API_NAME] + - text.DialogDeleteDescription2 - } - toastDeleteSuccessful={data => - text.ToastDelete1 + data[API_NAME] + text.ToastDeleteSuccessful2 - } - toastDeleteFailed={data => - text.ToastDelete1 + data[API_NAME] + text.ToastDeleteFailed2 - } - backButtonText={text.Back} - deleteButtonText={data => text.Delete + " " + data[API_NAME]} - createButtonText={text.Create} - createTitle={text.CreateNewApiKey} - statusRenders={{ - 403: () => , - 404: () => , - 500: (error, reset) => - }} - detailsTitle={one => one[API_NAME]} - createSubtitle={text.CreateApiKeySubtitle} - createProps={{ - size: { maxWidth: "400px" } - }} - toastCreateSuccessful={() => text.ApiKeyCreated} - toastCreateFailed={() => text.ApiKeyCreateFailed} - /> - ); -}; - -export default ApiKeys; diff --git a/frontend/src/use-cases/api-keys/ApiKeys.options.js b/frontend/src/use-cases/api-keys/ApiKeys.options.js deleted file mode 100644 index 4f13cf169..000000000 --- a/frontend/src/use-cases/api-keys/ApiKeys.options.js +++ /dev/null @@ -1,82 +0,0 @@ -import * as yup from "yup"; -import { DigitTextArea, DigitTextField } from "@cthit/react-digit-components"; -import { - API_DESCRIPTION_ENGLISH, - API_DESCRIPTION_SWEDISH, - API_NAME -} from "../../api/api-keys/props.api-keys.api"; - -export const validationSchema = text => { - const schema = {}; - schema[API_NAME] = yup.string().required(text.Name + text.IsRequired); - - schema[API_DESCRIPTION_SWEDISH] = yup - .string() - .required(text.SwedishDescription + text.IsRequired); - - schema[API_DESCRIPTION_ENGLISH] = yup - .string() - .required(text.EnglishDescription + text.IsRequired); - - return yup.object().shape(schema); -}; - -export const initialValues = () => { - const initialValues = {}; - initialValues[API_NAME] = ""; - initialValues[API_DESCRIPTION_SWEDISH] = ""; - initialValues[API_DESCRIPTION_ENGLISH] = ""; - - return initialValues; -}; - -export const keysComponentData = text => { - const keysComponentData = {}; - keysComponentData[API_NAME] = { - component: DigitTextField, - componentProps: { - outlined: true, - upperLabel: text.Name, - maxLength: 50 - } - }; - - keysComponentData[API_DESCRIPTION_SWEDISH] = { - component: DigitTextArea, - componentProps: { - outlined: true, - rows: 3, - upperLabel: text.SwedishDescription, - maxLength: 500 - } - }; - - keysComponentData[API_DESCRIPTION_ENGLISH] = { - component: DigitTextArea, - componentProps: { - outlined: true, - rows: 3, - upperLabel: text.EnglishDescription, - maxLength: 500, - onKeyPress: null - } - }; - - return keysComponentData; -}; - -export const keysText = text => { - const keysText = {}; - - keysText[API_NAME] = text.Name; - keysText[API_DESCRIPTION_SWEDISH] = text.SwedishDescription; - keysText[API_DESCRIPTION_ENGLISH] = text.EnglishDescription; - - return keysText; -}; - -export const keysOrder = () => [ - API_NAME, - API_DESCRIPTION_SWEDISH, - API_DESCRIPTION_ENGLISH -]; diff --git a/frontend/src/use-cases/api-keys/ApiKeys.translations.json b/frontend/src/use-cases/api-keys/ApiKeys.translations.json deleted file mode 100644 index 09b3f7b97..000000000 --- a/frontend/src/use-cases/api-keys/ApiKeys.translations.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "ApiKeysTitle": ["API keys", "API nycklar"], - "DialogDeleteTitle": ["Are you sure?", "Är du säker?"], - "DialogDeleteDescription1": [ - "Are you sure that you want to delete the API key ", - "Är du säker att du vill radera API nyckeln " - ], - "DialogDeleteDescription2": [ - "? This is permanent.", - "? Detta är permanent." - ], - "Name": ["API key name", "API nyckelnamn"], - "ToastDelete1": ["Deletion of ", "Radering av "], - "ToastDeleteFailed2": [" failed", " misslyckades"], - "ToastDeleteSuccessful2": [" was successful", " lyckades"], - "CreateNewApiKey": ["Create a new API key", "Skapa en ny API nyckel"], - "YourApiKeySecret": [ - "The secret for you API key", - "Hemliga lösenordet för din API nyckel" - ], - "YourApiKeySecretDescription": [ - "Make sure this is kept safe. This key can be used to access everything in Gamma! This will be the last time it will be shown.", - "Se till att denna nyckel behålls hemlig. Denna nyckel kan användas för att få tillgång till allting! Detta är enda gången den kommer att synas." - ], - "CreateApiKeySubtitle": [ - "Here you can create your own Api key, but be careful! These Api keys are very powerful and can be used to access and edit everything stored on Gamma.", - "Här kan du skapa din egna api nyckel, men va försiktig! Dessa api nycklar har väldigt mycket makt och kan användas för att komma åt och redigera allting som sparas på Gamma." - ], - "ApiKeyCreated": [ - "Api key was created successfully", - "En api nyckel har skapats" - ], - "ApiKeyCreateFailed": [ - "Something went wrong when deleting the api key", - "Någonting gick fel när api nyckeln försöktes raderas" - ] -} diff --git a/frontend/src/use-cases/api-keys/index.js b/frontend/src/use-cases/api-keys/index.js deleted file mode 100644 index 77aab1e10..000000000 --- a/frontend/src/use-cases/api-keys/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from "./ApiKeys"; diff --git a/frontend/src/use-cases/authorities/Authorities.jsx b/frontend/src/use-cases/authorities/Authorities.jsx deleted file mode 100644 index 7d33e5358..000000000 --- a/frontend/src/use-cases/authorities/Authorities.jsx +++ /dev/null @@ -1,25 +0,0 @@ -import React from "react"; -import { Route, Switch } from "react-router-dom"; -import ViewAuthorities from "./screens/view-authorities"; -import CreateAuthorityLevel from "./screens/create-authority-level"; -import AddToAuthorityLevel from "./screens/edit-authority"; - -const Authorities = () => { - return ( - - - - - - ); -}; - -export default Authorities; diff --git a/frontend/src/use-cases/authorities/Authorities.translations.json b/frontend/src/use-cases/authorities/Authorities.translations.json deleted file mode 100644 index 1fcfce6e6..000000000 --- a/frontend/src/use-cases/authorities/Authorities.translations.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "CreateAuthority": ["Create authority", "Skapa rättigheter"] -} diff --git a/frontend/src/use-cases/authorities/index.js b/frontend/src/use-cases/authorities/index.js deleted file mode 100644 index 12fd5a1ed..000000000 --- a/frontend/src/use-cases/authorities/index.js +++ /dev/null @@ -1,2 +0,0 @@ -import Authorities from "./Authorities"; -export default Authorities; diff --git a/frontend/src/use-cases/authorities/screens/create-authority-level/CreateAuthorityLevel.screen.jsx b/frontend/src/use-cases/authorities/screens/create-authority-level/CreateAuthorityLevel.screen.jsx deleted file mode 100644 index 750286d46..000000000 --- a/frontend/src/use-cases/authorities/screens/create-authority-level/CreateAuthorityLevel.screen.jsx +++ /dev/null @@ -1,66 +0,0 @@ -import React from "react"; -import { - DigitLayout, - DigitEditDataCard, - DigitTextField, - useDigitTranslations, - useDigitToast -} from "@cthit/react-digit-components"; -import translations from "./CreateAuthorityLevel.screen.translations"; -import * as yup from "yup"; -import { useHistory } from "react-router-dom"; -import { addAuthorityLevel } from "../../../../api/authorities/post.authoritites"; - -const CreateAuthorityLevel = () => { - const [text] = useDigitTranslations(translations); - const [queueToast] = useDigitToast(); - const history = useHistory(); - - return ( - - { - addAuthorityLevel(values) - .then(() => { - actions.resetForm(); - queueToast({ - text: values.authorityLevel + text.AddSuccessful - }); - }) - .catch(() => { - queueToast({ - text: text.AddError - }); - }); - }} - keysComponentData={{ - authorityLevel: { - component: DigitTextField, - componentProps: { - outlined: true, - upperLabel: text.AuthorityLevel, - maxLength: 20 - } - } - }} - keysOrder={["authorityLevel"]} - validationSchema={yup.object().shape({ - authorityLevel: yup - .string() - .required(text.AuthorityLevel + text.IsRequired) - })} - extraButton={{ - text: text.Back, - onClick: () => history.goBack() - }} - submitText={text.Create} - /> - - ); -}; - -export default CreateAuthorityLevel; diff --git a/frontend/src/use-cases/authorities/screens/create-authority-level/CreateAuthorityLevel.screen.translations.json b/frontend/src/use-cases/authorities/screens/create-authority-level/CreateAuthorityLevel.screen.translations.json deleted file mode 100644 index 3fb2dfd66..000000000 --- a/frontend/src/use-cases/authorities/screens/create-authority-level/CreateAuthorityLevel.screen.translations.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "AuthorityLevel": ["Authority level name", "Rättighetsnivå namn"], - "CreateAuthorityLevel": ["Create authority level", "Skapa rättighetsnivå"], - "AddError": [ - "Something went wrong when adding authority level", - "Någonting gick fel när rättighetsnivån skulle läggas till" - ], - "AddSuccessful": [" was added", " las till"] -} diff --git a/frontend/src/use-cases/authorities/screens/create-authority-level/index.js b/frontend/src/use-cases/authorities/screens/create-authority-level/index.js deleted file mode 100644 index 74f698f71..000000000 --- a/frontend/src/use-cases/authorities/screens/create-authority-level/index.js +++ /dev/null @@ -1,2 +0,0 @@ -import CreateAuthorityLevel from "./CreateAuthorityLevel.screen"; -export default CreateAuthorityLevel; diff --git a/frontend/src/use-cases/authorities/screens/edit-authority/EditAuthority.screen.jsx b/frontend/src/use-cases/authorities/screens/edit-authority/EditAuthority.screen.jsx deleted file mode 100644 index 87bfc19dc..000000000 --- a/frontend/src/use-cases/authorities/screens/edit-authority/EditAuthority.screen.jsx +++ /dev/null @@ -1,211 +0,0 @@ -import React, { useEffect, useState } from "react"; -import { useParams } from "react-router-dom"; -import { getAuthorityLevel } from "../../../../api/authorities/get.authorities"; -import { - DigitButton, - DigitDesign, - DigitLayout, - DigitEditDataCard, - useDigitTranslations, - DigitSelect, - useDigitToast, - DigitText, - DigitList, - useDigitDialog -} from "@cthit/react-digit-components"; -import translations from "./EditAuthority.screen.translations"; -import { useHistory } from "react-router-dom"; -import { getSuperGroups } from "../../../../api/super-groups/get.super-groups.api"; -import { getPosts } from "../../../../api/posts/get.posts.api"; -import { - SG_ID, - SG_PRETTY_NAME -} from "../../../../api/super-groups/props.super-groups.api"; -import { POST_ID } from "../../../../api/posts/props.posts.api"; -import { addToAuthorityLevel } from "../../../../api/authorities/post.authoritites"; -import FiveZeroZero from "../../../../app/elements/five-zero-zero"; -import * as yup from "yup"; -import DeleteIcon from "@material-ui/icons/Delete"; -import { deleteAuthority } from "../../../../api/authorities/delete.authoritites"; - -const EditAuthority = () => { - const [text, activeLanguage] = useDigitTranslations(translations); - const [queueToast] = useDigitToast(); - const [openDialog] = useDigitDialog(); - - const { id } = useParams(); - const history = useHistory(); - const [error, setError] = useState(); - const [authorityLevel, setAuthorityLevel] = useState(null); - const [superGroupMap, setSuperGroups] = useState(null); - const [postMap, setPosts] = useState(null); - const [read, setRead] = useState(true); - - useEffect(() => { - if (read) { - getAuthorityLevel(id) - .then(response => { - setAuthorityLevel(response.data); - }) - .catch(error => { - setError(error); - }); - } - setRead(false); - }, [id, read]); - - useEffect(() => { - Promise.all([getSuperGroups(), getPosts()]) - .then(([superGroupsResponse, postsResponse]) => { - const superGroups = superGroupsResponse.data; - const superGroupMap = {}; - for (let i = 0; i < superGroups.length; i++) { - superGroupMap[superGroups[i][SG_ID]] = - superGroups[i][SG_PRETTY_NAME]; - } - - setSuperGroups(superGroupMap); - - const posts = postsResponse.data; - const postMap = {}; - for (let i = 0; i < posts.length; i++) { - postMap[posts[i][POST_ID]] = posts[i][activeLanguage]; - } - - setPosts(postMap); - }) - .catch(error => { - setError(error); - }); - }, [activeLanguage]); - - if (error != null && error.response.status === 500) { - return setError(null)} />; - } - - if (authorityLevel == null || superGroupMap == null || postMap == null) { - return null; - } - - return ( - - - - - - - {authorityLevel.authorities.length === 0 && ( - - )} - {authorityLevel.authorities.length > 0 && ( - ({ - text: - authority.superGroup[SG_PRETTY_NAME] + - " - " + - authority.post[activeLanguage], - actionIcon: DeleteIcon, - actionOnClick: () => { - openDialog({ - title: text.AreYouSure, - description: - text.DeleteAuthorityDescription, - cancelButtonText: text.Cancel, - confirmButtonText: text.Delete, - onConfirm: () => { - deleteAuthority(authority.id) - .then(() => { - setRead(true); - queueToast({ - text: - text.AuthorityDeleted - }); - }) - .catch(() => { - queueToast({ - text: - text.FailedAuthorityDeleted - }); - }); - } - }); - } - }) - )} - onClick={null} - dense - /> - )} - - - history.goBack()} - /> - - - - addToAuthorityLevel({ - post: values.post, - superGroup: values.superGroup, - authority: id - }) - .then(() => { - setRead(true); - actions.resetForm(); - queueToast({ - text: text.AddedToAuthorityLevel - }); - }) - .catch(() => { - queueToast({ - text: text.FailedToAuthorityLevel - }); - }) - } - keysOrder={["superGroup", "post"]} - keysComponentData={{ - superGroup: { - component: DigitSelect, - componentProps: { - upperLabel: text.SuperGroup, - valueToTextMap: superGroupMap, - outlined: true - } - }, - post: { - component: DigitSelect, - componentProps: { - upperLabel: text.Post, - valueToTextMap: postMap, - outlined: true - } - } - }} - /> - - ); -}; - -export default EditAuthority; diff --git a/frontend/src/use-cases/authorities/screens/edit-authority/EditAuthority.screen.translations.json b/frontend/src/use-cases/authorities/screens/edit-authority/EditAuthority.screen.translations.json deleted file mode 100644 index d53f5bd4e..000000000 --- a/frontend/src/use-cases/authorities/screens/edit-authority/EditAuthority.screen.translations.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "AddToAuthorityLevel": [ - "Add to authority level", - "Lägg till rättighetsnivå" - ], - "AddedToAuthorityLevel": [ - "Added to authority level", - "Tillagd i rättighetsnivån" - ], - "FailedToAuthorityLevel": [ - "Failed to add to authority level", - "Misslyckades att lägga till i rättighetsnivån" - ], - "NoAuthorities": [ - "No authorities assigned for this authority level", - "Inga har tilldelas denna rättighet" - ], - "DeleteAuthorityDescription": [ - "This can lead to breaking changes for other applications", - "Det här kan leda till 'breaking changes' för andra applikationer" - ], - "AuthorityDeleted": ["Authority deleted", "Rättighet raderad"], - "FailedAuthorityDeleted": [ - "Something went wrong when deleting the authority", - "Någonting gick fel när rättigheten försöktes raderas" - ] -} diff --git a/frontend/src/use-cases/authorities/screens/edit-authority/index.js b/frontend/src/use-cases/authorities/screens/edit-authority/index.js deleted file mode 100644 index b0f106c9d..000000000 --- a/frontend/src/use-cases/authorities/screens/edit-authority/index.js +++ /dev/null @@ -1,2 +0,0 @@ -import EditAuthority from "./EditAuthority.screen"; -export default EditAuthority; diff --git a/frontend/src/use-cases/authorities/screens/view-authorities/ViewAuthorities.screen.jsx b/frontend/src/use-cases/authorities/screens/view-authorities/ViewAuthorities.screen.jsx deleted file mode 100644 index 444c88277..000000000 --- a/frontend/src/use-cases/authorities/screens/view-authorities/ViewAuthorities.screen.jsx +++ /dev/null @@ -1,92 +0,0 @@ -import { - DigitFAB, - DigitLayout, - DigitDesign, - useDigitTranslations -} from "@cthit/react-digit-components"; -import Add from "@material-ui/icons/Add"; -import React, { useEffect, useState } from "react"; -import translations from "../../Authorities.translations"; -import { - getAuthorities, - getAuthorityLevels -} from "../../../../api/authorities/get.authorities"; -import AuthorityLevelCard from "./elements/authority-level-card"; -import styled from "styled-components"; - -const Grid = styled.div` - flex: 1; - - display: grid; - grid-template-columns: repeat(auto-fit, minmax(288px, 400px)); - column-gap: 16px; - row-gap: 16px; - - justify-content: center; - - margin-bottom: calc(56px + 16px); -`; - -const ViewAuthorities = () => { - const [authorityLevels, setAuthorityLevels] = useState(null); - const [authorities, setAuthorities] = useState(null); - const [text] = useDigitTranslations(translations); - const [read, setRead] = useState(true); - - useEffect(() => { - if (read) { - Promise.all([getAuthorities(), getAuthorityLevels()]).then( - ([authoritiesResponse, authorityLevelsResponse]) => { - const newAuthorities = {}; - authoritiesResponse.data.authorities.forEach(authority => { - const { superGroup, post, authorityLevel } = authority; - - var auth = newAuthorities[authorityLevel.id]; - if (auth == null) { - auth = []; - } - - auth.push({ - superGroup, - post - }); - - newAuthorities[authorityLevel.id] = auth; - }); - - setAuthorities(newAuthorities); - setAuthorityLevels( - authorityLevelsResponse.data.authorityLevels - ); - } - ); - } - setRead(false); - }, [read, setRead]); - - if (authorityLevels == null || authorities == null) { - return null; - } - - return ( - <> - - {authorityLevels.map(authorityLevel => ( - setRead(true)} - /> - ))} - - - - - - - - ); -}; - -export default ViewAuthorities; diff --git a/frontend/src/use-cases/authorities/screens/view-authorities/ViewAuthorities.screen.translations.json b/frontend/src/use-cases/authorities/screens/view-authorities/ViewAuthorities.screen.translations.json deleted file mode 100644 index 0967ef424..000000000 --- a/frontend/src/use-cases/authorities/screens/view-authorities/ViewAuthorities.screen.translations.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/frontend/src/use-cases/authorities/screens/view-authorities/elements/authority-level-card/AuthorityLevelCard.element.jsx b/frontend/src/use-cases/authorities/screens/view-authorities/elements/authority-level-card/AuthorityLevelCard.element.jsx deleted file mode 100644 index f249598b7..000000000 --- a/frontend/src/use-cases/authorities/screens/view-authorities/elements/authority-level-card/AuthorityLevelCard.element.jsx +++ /dev/null @@ -1,81 +0,0 @@ -import React from "react"; -import { - DigitButton, - DigitDesign, - DigitList, - DigitText, - useDigitDialog, - useDigitToast, - useDigitTranslations -} from "@cthit/react-digit-components"; -import { deleteAuthorityLevel } from "../../../../../../api/authorities/delete.authoritites"; -import translations from "./AuthorityLevelCard.element.translations"; - -const AuthorityLevelCard = ({ - authorityLevel, - authorities = [], - forceUpdate -}) => { - const [text, activeLanguage] = useDigitTranslations(translations); - const [openDialog] = useDigitDialog(); - const [queueToast] = useDigitToast(); - - return ( - - - - - - {authorities.length === 0 && ( - - )} - {authorities.length > 0 && ( -
- ({ - text: - authority.superGroup.prettyName + - " - " + - authority.post[activeLanguage] - }))} - onClick={null} - dense - /> -
- )} -
- - { - openDialog({ - title: text.AreYouSure, - description: text.AreYouSureDeleteAuthorityLevel, - confirmButtonText: text.ImSure, - cancelButtonText: text.Cancel, - onConfirm: () => { - deleteAuthorityLevel(authorityLevel.id) - .then(() => { - queueToast({ - text: text.DeleteSuccessful - }); - forceUpdate(); - }) - .catch(() => { - queueToast({ - text: text.DeleteFailed - }); - }); - } - }); - }} - /> - - - - -
- ); -}; - -export default AuthorityLevelCard; diff --git a/frontend/src/use-cases/authorities/screens/view-authorities/elements/authority-level-card/AuthorityLevelCard.element.translations.json b/frontend/src/use-cases/authorities/screens/view-authorities/elements/authority-level-card/AuthorityLevelCard.element.translations.json deleted file mode 100644 index 1f1e97872..000000000 --- a/frontend/src/use-cases/authorities/screens/view-authorities/elements/authority-level-card/AuthorityLevelCard.element.translations.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "NoAuthorities": [ - "No authorities assigned for this authority level", - "Inga har tilldelas denna rättighet" - ], - "AreYouSureDeleteAuthorityLevel": [ - "Are you sure you want to delete this authority level? This can cause major issues with other application using this authority level.", - "Är du säker att du vill radera denna rättighetsnivå? Det kan skapa stora problem med andra applikationer som förlitar sig på denna rättighetsnivå." - ], - "ImSure": ["Im sure, delete", "Jag är säker, radera"], - "DeleteFailed": [ - "Something went wrong when trying to delete authority level", - "Någonting gick fel när rättighetsnivån försöktes raderas" - ], - "DeleteSuccessful": [ - "Authority level was deleted", - "Rättighetsnivån har raderats" - ] -} diff --git a/frontend/src/use-cases/authorities/screens/view-authorities/elements/authority-level-card/index.js b/frontend/src/use-cases/authorities/screens/view-authorities/elements/authority-level-card/index.js deleted file mode 100644 index 41bd8e2e5..000000000 --- a/frontend/src/use-cases/authorities/screens/view-authorities/elements/authority-level-card/index.js +++ /dev/null @@ -1,2 +0,0 @@ -import AuthorityLevelCard from "./AuthorityLevelCard.element"; -export default AuthorityLevelCard; diff --git a/frontend/src/use-cases/authorities/screens/view-authorities/index.js b/frontend/src/use-cases/authorities/screens/view-authorities/index.js deleted file mode 100644 index ad5a9c1d3..000000000 --- a/frontend/src/use-cases/authorities/screens/view-authorities/index.js +++ /dev/null @@ -1,2 +0,0 @@ -import ViewAuthorities from "./ViewAuthorities.screen"; -export default ViewAuthorities; diff --git a/frontend/src/use-cases/clients/Clients.jsx b/frontend/src/use-cases/clients/Clients.jsx deleted file mode 100644 index cf28a1ddd..000000000 --- a/frontend/src/use-cases/clients/Clients.jsx +++ /dev/null @@ -1,153 +0,0 @@ -import { - DigitCRUD, - useDigitTranslations, - DigitText, - DigitButton, - useDigitCustomDialog -} from "@cthit/react-digit-components"; -import React from "react"; -import { getClient, getClients } from "../../api/clients/get.clients.api"; -import { addClient } from "../../api/clients/post.clients.api"; -import translations from "./Clients.translations"; -import { deleteClient } from "../../api/clients/delete.clients.api"; -import InsufficientAccess from "../../common/views/insufficient-access"; -import { - CLIENT_DESCRIPTION_ENGLISH, - CLIENT_DESCRIPTION_SWEDISH, - CLIENT_NAME, - CLIENT_REDIRECT, - CLIENT_SECRET, - CLIENT_ID -} from "../../api/clients/props.clients.api"; -import useGammaIsAdmin from "../../common/hooks/use-gamma-is-admin/useGammaIsAdmin"; -import FourOFour from "../four-o-four"; -import FiveZeroZero from "../../app/elements/five-zero-zero"; -import { - initialValues, - keysComponentData, - keysOrder, - readAllKeysOrder, - keysText, - validationSchema -} from "./Clients.options"; -import UserClientApprovals from "./views/user-client-approvals"; - -const Clients = () => { - const [text] = useDigitTranslations(translations); - const [openDialog] = useDigitCustomDialog({ - title: text.YourClientSecret, - renderButtons: confirm => ( - - ) - }); - - const admin = useGammaIsAdmin(); - if (!admin) { - return ; - } - - return ( - - new Promise((resolve, reject) => - addClient({ - name: client[CLIENT_NAME], - description: { - sv: client[CLIENT_DESCRIPTION_SWEDISH], - en: client[CLIENT_DESCRIPTION_ENGLISH] - }, - webServerRedirectUri: client[CLIENT_REDIRECT] - }) - .then(response => { - openDialog({ - renderMain: () => ( - <> - - - - ) - }); - resolve(response); - }) - .catch(error => reject(error)) - ) - } - tableProps={{ - titleText: text.Clients, - startOrderBy: CLIENT_NAME, - search: true, - flex: "1", - startOrderByDirection: "asc", - size: { minWidth: "288px" }, - padding: "0px", - searchText: text.Search - }} - idProp={CLIENT_ID} - createTitle={text.CreateClient} - createButtonText={text.CreateClient} - detailsTitle={data => data[CLIENT_NAME]} - toastCreateSuccessful={data => - data[CLIENT_NAME] + " " + text.ClientCreatingSuccessful - } - toastCreateFailed={() => text.ErrorCreatingClient} - toastDeleteSuccessful={data => - data[CLIENT_NAME] + " " + text.ClientDeletionSuccessful - } - toastDeleteFailed={data => - text.ClientDeletionFailed1 + - " " + - data[CLIENT_NAME] + - " " + - text.ClientDeletionFailed2 - } - dialogDeleteTitle={() => text.AreYouSure} - dialogDeleteDescription={data => - text.AreYouSureYouWantToDelete + " " + data[CLIENT_NAME] - } - dialogDeleteConfirm={() => text.Delete} - dialogDeleteCancel={() => text.Cancel} - backButtonText={text.Back} - detailsButtonText={text.Details} - deleteButtonText={data => text.Delete + " " + data[CLIENT_NAME]} - statusRenders={{ - 403: () => , - 404: () => , - 500: (error, reset) => - }} - useKeyTextsInUpperLabel - detailsRenderEnd={client => - String(client.autoApprove) === "false" ? ( - - ) : null - } - readOneProps={{ - margin: { - bottom: "16px" - } - }} - /> - ); -}; - -export default Clients; diff --git a/frontend/src/use-cases/clients/Clients.options.js b/frontend/src/use-cases/clients/Clients.options.js deleted file mode 100644 index c022ab2fd..000000000 --- a/frontend/src/use-cases/clients/Clients.options.js +++ /dev/null @@ -1,119 +0,0 @@ -import * as yup from "yup"; -import { - DigitCheckbox, - DigitTextArea, - DigitTextField -} from "@cthit/react-digit-components"; -import { - CLIENT_DESCRIPTION_ENGLISH, - CLIENT_DESCRIPTION_SWEDISH, - CLIENT_OAUTH_ID, - CLIENT_NAME, - CLIENT_REDIRECT, - CLIENT_AUTO_APPROVE -} from "../../api/clients/props.clients.api"; - -export const validationSchema = text => { - const schema = {}; - schema[CLIENT_NAME] = yup.string().required(text.Name + text.IsRequired); - - schema[CLIENT_REDIRECT] = yup - .string() - .required(text.RedirectURI + text.IsRequired); - - schema[CLIENT_DESCRIPTION_SWEDISH] = yup - .string() - .required(text.SwedishDescription + text.IsRequired); - - schema[CLIENT_DESCRIPTION_ENGLISH] = yup - .string() - .required(text.EnglishDescription + text.IsRequired); - - schema[CLIENT_AUTO_APPROVE] = yup.bool().required(); - - return yup.object().shape(schema); -}; - -export const initialValues = () => { - const initialValues = {}; - initialValues[CLIENT_NAME] = ""; - initialValues[CLIENT_REDIRECT] = ""; - initialValues[CLIENT_DESCRIPTION_SWEDISH] = ""; - initialValues[CLIENT_DESCRIPTION_ENGLISH] = ""; - initialValues[CLIENT_AUTO_APPROVE] = false; - - return initialValues; -}; - -export const keysComponentData = text => { - const keysComponentData = {}; - keysComponentData[CLIENT_NAME] = { - component: DigitTextField, - componentProps: { - outlined: true, - maxLength: 50 - } - }; - - keysComponentData[CLIENT_REDIRECT] = { - component: DigitTextField, - componentProps: { - outlined: true, - maxLength: 100 - } - }; - - keysComponentData[CLIENT_DESCRIPTION_SWEDISH] = { - component: DigitTextArea, - componentProps: { - outlined: true, - rows: 3, - maxRows: 5, - maxLength: 500 - } - }; - - keysComponentData[CLIENT_DESCRIPTION_ENGLISH] = { - component: DigitTextArea, - componentProps: { - outlined: true, - rows: 3, - maxRows: 5, - maxLength: 500 - } - }; - - keysComponentData[CLIENT_AUTO_APPROVE] = { - component: DigitCheckbox, - componentProps: { - primary: true, - label: text.AutoApprove - } - }; - - return keysComponentData; -}; - -export const keysText = text => { - const keysText = {}; - - keysText[CLIENT_NAME] = text.Name; - keysText[CLIENT_REDIRECT] = text.RedirectURI; - keysText[CLIENT_DESCRIPTION_SWEDISH] = text.SwedishDescription; - keysText[CLIENT_DESCRIPTION_ENGLISH] = text.EnglishDescription; - keysText[CLIENT_OAUTH_ID] = text.ClientId; - keysText[CLIENT_AUTO_APPROVE] = text.AutoApprove; - - return keysText; -}; - -export const keysOrder = () => [ - CLIENT_NAME, - CLIENT_OAUTH_ID, - CLIENT_REDIRECT, - CLIENT_DESCRIPTION_SWEDISH, - CLIENT_DESCRIPTION_ENGLISH, - CLIENT_AUTO_APPROVE -]; - -export const readAllKeysOrder = () => [CLIENT_NAME, CLIENT_REDIRECT]; diff --git a/frontend/src/use-cases/clients/Clients.translations.json b/frontend/src/use-cases/clients/Clients.translations.json deleted file mode 100644 index 1013c53db..000000000 --- a/frontend/src/use-cases/clients/Clients.translations.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "Details": ["Details", "Detaljer"], - "ClientId": ["Client Id", "Klient Id"], - "RedirectURI": ["Redirect URI", "Redirect URI"], - "SearchForClients": ["Search for client", "Sök efter klient"], - "NoClients": ["No Clients Registered", "Inga klienter registrerade"], - "Clients": ["Registered clients", "Registrerade klienter"], - "ClientName": ["Client name", "Klientnamn"], - "ClientRedirect": ["Client redirect", "Klient omdirigeringslänk"], - "CreateClient": ["Create new client", "Skapa ny klient"], - "SubmitClient": ["Create client", "Skapa klient"], - "YourClientSecret": ["Your client secret", "Din klient secret"], - "YourClientSecretDescription": [ - "Make sure this is kept safe. This secret can be used to access other users information! This will be the last time it will be shown.", - "Se till att denna nyckel behålls hemlig. Denna hemliga nyckel kan användas för att komma åt andra användares data! Detta är enda gången den kommer att synas." - ], - "CopyToClipboard": ["Copy to clipboard", "kopiera till urklipp"], - "ClientCreatingSuccessful": [ - "was successfully created", - "skapades framgångsrikt" - ], - "ErrorCreatingClient": [ - "Something went wrong when trying to add the client", - "Någonting gick fel när klienten försökter läggas till" - ], - "ClientDeletionSuccessful": [ - "was successfully deleted", - "raderades framgångsrikt" - ], - "ClientDeletionFailed1": [ - "Something went wrong when trying to delete the client", - "Någonting gick fel när klienten" - ], - "ClientDeletionFailed2": ["", "försökte raderas"], - "AutoApprove": ["Auto approve client", "Automatiskt godkänn client"] -} diff --git a/frontend/src/use-cases/clients/index.js b/frontend/src/use-cases/clients/index.js deleted file mode 100644 index 275567e51..000000000 --- a/frontend/src/use-cases/clients/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from "./Clients"; diff --git a/frontend/src/use-cases/clients/views/user-client-approvals/UserClientApprovals.translations.view.json b/frontend/src/use-cases/clients/views/user-client-approvals/UserClientApprovals.translations.view.json deleted file mode 100644 index f6efccb10..000000000 --- a/frontend/src/use-cases/clients/views/user-client-approvals/UserClientApprovals.translations.view.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "UsersThatApproved": ["Users that approved ", "Användare som accepterade "] -} diff --git a/frontend/src/use-cases/clients/views/user-client-approvals/UserClientApprovals.view.jsx b/frontend/src/use-cases/clients/views/user-client-approvals/UserClientApprovals.view.jsx deleted file mode 100644 index c0421c144..000000000 --- a/frontend/src/use-cases/clients/views/user-client-approvals/UserClientApprovals.view.jsx +++ /dev/null @@ -1,52 +0,0 @@ -import React, { useEffect, useState } from "react"; -import { getAllApprovalsbyClientId } from "../../../../api/approval/get.approval.api"; -import { - DigitTable, - useDigitTranslations -} from "@cthit/react-digit-components"; -import translations from "./UserClientApprovals.translations.view"; - -const UserClientApprovals = ({ client }) => { - const [text] = useDigitTranslations(translations); - const [users, setUsers] = useState(null); - - const clientId = client.clientId; - - useEffect(() => { - getAllApprovalsbyClientId(clientId).then(response => { - setUsers(response.data); - }); - }, [clientId]); - - if (users == null) { - return null; - } - - return ( - ({ - firstName, - nick, - lastName, - __link: "/users/" + id - }))} - headerTexts={{ - firstName: text.FirstName, - nick: text.Nick, - lastName: text.LastName, - __link: text.Details - }} - columnsOrder={["firstName", "nick", "lastName"]} - titleText={text.UsersThatApproved + client.name} - margin={{ - bottom: "calc(56px + 16px)" - }} - search - searchText={text.Search} - /> - ); -}; - -export default UserClientApprovals; diff --git a/frontend/src/use-cases/clients/views/user-client-approvals/index.js b/frontend/src/use-cases/clients/views/user-client-approvals/index.js deleted file mode 100644 index 5cbe3d78f..000000000 --- a/frontend/src/use-cases/clients/views/user-client-approvals/index.js +++ /dev/null @@ -1,2 +0,0 @@ -import UserClientApprovals from "./UserClientApprovals.view"; -export default UserClientApprovals; diff --git a/frontend/src/use-cases/create-account/CreateAccount.jsx b/frontend/src/use-cases/create-account/CreateAccount.jsx deleted file mode 100644 index 8d6a9ed16..000000000 --- a/frontend/src/use-cases/create-account/CreateAccount.jsx +++ /dev/null @@ -1,88 +0,0 @@ -import { - DigitLayout, - DigitStepper, - DigitDesign, - DigitText, - useDigitTranslations, - DigitButton -} from "@cthit/react-digit-components"; -import PropTypes from "prop-types"; -import React from "react"; -import MapPathToStep from "../../common/declaratives/map-path-to-step"; -import translations from "./CreateAccount.translations.json"; -import CreationOfAccountFinished from "./views/creation-of-account-finished"; -import EmailHasBeenSent from "./views/email-has-been-sent"; -import InputCid from "./views/input-cid"; -import InputDataAndCode from "./views/input-data-and-code"; -import { useHistory, useLocation } from "react-router-dom"; -import useGammaUser from "../../common/hooks/use-gamma-user/useGammaUser"; - -const CreateAccount = () => { - const [text] = useDigitTranslations(translations); - const user = useGammaUser(); - const location = useLocation(); - const history = useHistory(); - - if (user != null) { - return ( - - - - - - - - - history.push("/")} - raised - primary - /> - - - ); - } - - return ( - ( - - - {step === 0 && } - {step === 1 && } - {step === 2 && } - {step === 3 && } - - )} - /> - ); -}; - -CreateAccount.propTypes = { - location: PropTypes.object.isRequired -}; - -export default CreateAccount; diff --git a/frontend/src/use-cases/create-account/CreateAccount.translations.json b/frontend/src/use-cases/create-account/CreateAccount.translations.json deleted file mode 100644 index 3cd0751b0..000000000 --- a/frontend/src/use-cases/create-account/CreateAccount.translations.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "SendCid": ["Send email", "Skicka email"], - "GetActivationCode": ["Get activation code", "Hämta aktiveringskod"], - "CreateAccount": ["Create account", "Skapa konto"], - "YouAlreadyHaveAnAccount": ["Another account??", "Ett till konto??"], - "YouAlreadyHaveAnAccountDescription": [ - "You really want another account??", - "Vill du verkligen ha ett till konto??" - ], - "NahImGood": ["Nah Im good", "Neee jag är nöjd tack"] -} diff --git a/frontend/src/use-cases/create-account/index.js b/frontend/src/use-cases/create-account/index.js deleted file mode 100644 index f090e0a74..000000000 --- a/frontend/src/use-cases/create-account/index.js +++ /dev/null @@ -1,2 +0,0 @@ -import { default as CreateAccount } from "./CreateAccount"; -export default CreateAccount; diff --git a/frontend/src/use-cases/create-account/views/creation-of-account-finished/CreationOfAccountFinished.view.jsx b/frontend/src/use-cases/create-account/views/creation-of-account-finished/CreationOfAccountFinished.view.jsx deleted file mode 100644 index 925a07f2a..000000000 --- a/frontend/src/use-cases/create-account/views/creation-of-account-finished/CreationOfAccountFinished.view.jsx +++ /dev/null @@ -1,43 +0,0 @@ -import { - DigitButton, - DigitDesign, - DigitLayout, - DigitText, - useDigitTranslations -} from "@cthit/react-digit-components"; -import React from "react"; -import translations from "./CreationOfAccountFinished.view.translations.json"; -import { getBackendUrl } from "../../../../common/utils/configs/envVariablesLoader"; - -const CreationOfAccountFinished = () => { - const [text] = useDigitTranslations(translations); - - return ( - - - - - - - - - - - - { - window.location.href = getBackendUrl() + "/login"; - }} - /> - - - - ); -}; - -CreationOfAccountFinished.propTypes = {}; - -export default CreationOfAccountFinished; diff --git a/frontend/src/use-cases/create-account/views/creation-of-account-finished/CreationOfAccountFinished.view.translations.json b/frontend/src/use-cases/create-account/views/creation-of-account-finished/CreationOfAccountFinished.view.translations.json deleted file mode 100644 index e38629c35..000000000 --- a/frontend/src/use-cases/create-account/views/creation-of-account-finished/CreationOfAccountFinished.view.translations.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "CongratsTitle": [ - "Congrats! You have created an IT-account", - "Grattis! Du har skapat ett IT-konto!" - ], - "CongratsBody": [ - "You can now use digITs services.", - "Du kan nu använda digITs tjänster" - ], - "LoginForTheFirstTime": [ - "Login for the first time", - "Logga in för första gången" - ] -} diff --git a/frontend/src/use-cases/create-account/views/creation-of-account-finished/index.js b/frontend/src/use-cases/create-account/views/creation-of-account-finished/index.js deleted file mode 100644 index 9628cf272..000000000 --- a/frontend/src/use-cases/create-account/views/creation-of-account-finished/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from "./CreationOfAccountFinished.view"; diff --git a/frontend/src/use-cases/create-account/views/email-has-been-sent/EmailHasBeenSent.view.jsx b/frontend/src/use-cases/create-account/views/email-has-been-sent/EmailHasBeenSent.view.jsx deleted file mode 100644 index cffc1d377..000000000 --- a/frontend/src/use-cases/create-account/views/email-has-been-sent/EmailHasBeenSent.view.jsx +++ /dev/null @@ -1,48 +0,0 @@ -import { - DigitButton, - DigitDesign, - DigitText, - DigitLayout, - useDigitTranslations -} from "@cthit/react-digit-components"; -import React from "react"; -import translations from "./EmailHasBeenSent.view.translations.json"; - -const EmailHasBeenSent = () => { - const [text] = useDigitTranslations(translations); - - return ( - - - - - - - - - - - {}} - text={text.HaveReceivedACode} - /> - - - - - - - - ); -}; - -EmailHasBeenSent.propTypes = {}; - -export default EmailHasBeenSent; diff --git a/frontend/src/use-cases/create-account/views/email-has-been-sent/EmailHasBeenSent.view.translations.json b/frontend/src/use-cases/create-account/views/email-has-been-sent/EmailHasBeenSent.view.translations.json deleted file mode 100644 index e524dcd89..000000000 --- a/frontend/src/use-cases/create-account/views/email-has-been-sent/EmailHasBeenSent.view.translations.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "AnEmailShouldBeSent": [ - "An email should be sent to your student email", - "Ett mail ska ha skickats till din studentmail" - ], - "AnEmailShouldBeSentDescription": [ - "If you have not recieved an email within a few minutes, you may have entered the wrong cid. If you're sure that you have written the correct cid and you still haven't recieved an email please contact digIT at digit@chalmers.it", - "Om du inte får ett mail på några minuter kan du ha råkat skriva fel cid. Om du är säker att du skriver rätt med fortfarande inte får ett mail kan det antingen bero på att mailet har hamnat i skräppost, eller så är du inte inlagd i digITs system. I det senare fallet, var vänligen och skicka ett mail till digit@chalmers.it." - ], - "HaveReceivedACode": ["I have received a code", "Jag har fått en kod"], - "IHaveNotReceivedACode": [ - "I have not received a code", - "Jag har inte fått en kod" - ] -} diff --git a/frontend/src/use-cases/create-account/views/email-has-been-sent/index.js b/frontend/src/use-cases/create-account/views/email-has-been-sent/index.js deleted file mode 100644 index f15d1b9ff..000000000 --- a/frontend/src/use-cases/create-account/views/email-has-been-sent/index.js +++ /dev/null @@ -1,2 +0,0 @@ -import { default as EmailHasBeenSent } from "./EmailHasBeenSent.view"; -export default EmailHasBeenSent; diff --git a/frontend/src/use-cases/create-account/views/input-cid/InputCid.view.jsx b/frontend/src/use-cases/create-account/views/input-cid/InputCid.view.jsx deleted file mode 100644 index 5df972d8d..000000000 --- a/frontend/src/use-cases/create-account/views/input-cid/InputCid.view.jsx +++ /dev/null @@ -1,60 +0,0 @@ -import { - useDigitTranslations, - DigitEditDataCard, - DigitLayout, - useDigitToast -} from "@cthit/react-digit-components"; -import React from "react"; -import translations from "./InputCid.view.translations"; -import { useHistory } from "react-router-dom"; -import { activateCid } from "../../../../api/whitelist/post.whitelist.api"; -import { - initialValues, - keysComponentData, - keysOrder, - validationSchema -} from "./InputCid.view.options"; -import ChangeLanguageLocally from "../../../../common/views/change-language-locally"; - -const InputCid = () => { - const [queueToast] = useDigitToast(); - const [text] = useDigitTranslations(translations); - const history = useHistory(); - - return ( - - - { - activateCid(values) - .then(() => { - actions.resetForm(); - actions.setSubmitting(false); - history.push("/create-account/email-sent"); - }) - .catch(() => { - queueToast({ - text: text.SomethingWentWrong, - duration: 3000 - }); - }); - }} - size={{ width: "300px", height: "300px" }} - titleText={text.EnterYourCid} - subtitleText={text.EnterYourCidDescription} - submitText={text.SendCid} - extraButton={{ - text: text.AlreadyHaveCode - }} - extraButtonTo={"/create-account/email-sent"} - /> - - ); -}; - -export default InputCid; diff --git a/frontend/src/use-cases/create-account/views/input-cid/InputCid.view.options.js b/frontend/src/use-cases/create-account/views/input-cid/InputCid.view.options.js deleted file mode 100644 index 5113944db..000000000 --- a/frontend/src/use-cases/create-account/views/input-cid/InputCid.view.options.js +++ /dev/null @@ -1,33 +0,0 @@ -import * as yup from "yup"; -import { USER_CID } from "../../../../api/users/props.users.api"; -import { DigitTextField } from "@cthit/react-digit-components"; - -export const validationSchema = text => { - const schema = {}; - schema[USER_CID] = yup.string().required(text.Cid + text.IsRequired); - - return yup.object().shape(schema); -}; - -export const initialValues = () => { - const initialValues = {}; - initialValues[USER_CID] = ""; - - return initialValues; -}; - -export const keysComponentData = text => { - const keysComponentData = {}; - keysComponentData[USER_CID] = { - component: DigitTextField, - componentProps: { - upperLabel: text.Cid, - outlined: true, - maxLength: 10 - } - }; - - return keysComponentData; -}; - -export const keysOrder = () => [USER_CID]; diff --git a/frontend/src/use-cases/create-account/views/input-cid/InputCid.view.translations.json b/frontend/src/use-cases/create-account/views/input-cid/InputCid.view.translations.json deleted file mode 100644 index 6635588ed..000000000 --- a/frontend/src/use-cases/create-account/views/input-cid/InputCid.view.translations.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "EnterYourCid": ["Enter your cid", "Skriv in ditt cid"], - "EnterYourCidDescription": [ - "We will send an email to your student email to confirm your identity.", - "Vi kommer skicka ett mail till din studentmail för att bekräfta din identitet." - ], - "SendCid": ["Send cid", "Skicka cid"], - "SomethingWentWrong": [ - "Something went wrong when trying to send the cid, please try again or contact digit@chalmers.it", - "Någonting gick snett när vi försökte skicka ditt cid, var vänlig och försök igen eller kontakta digit@chalmers.it" - ], - "AlreadyHaveCode": ["Already have code", "Har redan en kod"] -} diff --git a/frontend/src/use-cases/create-account/views/input-cid/index.js b/frontend/src/use-cases/create-account/views/input-cid/index.js deleted file mode 100644 index e969abf68..000000000 --- a/frontend/src/use-cases/create-account/views/input-cid/index.js +++ /dev/null @@ -1,2 +0,0 @@ -import { default as InputCid } from "./InputCid.view"; -export default InputCid; diff --git a/frontend/src/use-cases/create-account/views/input-data-and-code/InputDataAndCode.view.jsx b/frontend/src/use-cases/create-account/views/input-data-and-code/InputDataAndCode.view.jsx deleted file mode 100644 index f90cb4ab9..000000000 --- a/frontend/src/use-cases/create-account/views/input-data-and-code/InputDataAndCode.view.jsx +++ /dev/null @@ -1,136 +0,0 @@ -import { - DigitButton, - DigitDesign, - useDigitTranslations, - useDigitToast, - DigitEditDataCard, - useDigitCustomDialog, - DigitMarkdown -} from "@cthit/react-digit-components"; -import React, { useEffect, useState } from "react"; -import statusCode from "../../../../common/utils/formatters/statusCode.formatter"; -import statusMessage from "../../../../common/utils/formatters/statusMessage.formatter"; -import translations from "./InputDataAndCode.view.translations.json"; -import { useHistory } from "react-router-dom"; -import { createAccount } from "../../../../api/create-account/post.createAccount.api"; -import { - initialValues, - keysComponentData, - keysOrder, - validationSchema -} from "./InputDataAndCode.view.options"; -import axios from "axios"; - -const InputDataAndCode = () => { - const [text, activeLanguage] = useDigitTranslations(translations); - const [queueToast] = useDigitToast(); - const [showDialog] = useDigitCustomDialog(); - const history = useHistory(); - const [userAgreement, setUserAgreement] = useState(); - - useEffect(() => { - axios.get("/useragreement-" + activeLanguage + ".md").then(response => { - setUserAgreement(response.data); - }); - }, [activeLanguage]); - - return ( - <> - - - - - - { - showDialog({ - renderMain: () => ( - - ), - renderButtons: confirm => ( - - ) - }); - }} - /> - - - history.goBack() - }} - onSubmit={(values, actions) => { - const cid = values.cid; - const user = { - whitelist: { - cid: cid - }, - ...values - }; - createAccount(user) - .then(() => { - actions.resetForm(); - history.push("/create-account/finished"); - }) - .catch(error => { - const code = statusCode(error); - const message = statusMessage(error); - var errorMessage; - switch (code) { - case 422: - switch (message) { - case "CODE_OR_CID_IS_WRONG": - errorMessage = - text.CODE_OR_CID_IS_WRONG; - break; - case "TOO_SHORT_PASSWORD": - errorMessage = - text.TOO_SHORT_PASSWORD; - break; - default: - errorMessage = - text.SomethingWentWrong; - } - break; - default: - errorMessage = text.SomethingWentWrong; - } - queueToast({ - text: errorMessage, - duration: 5000 - }); - }); - }} - size={{ minWidth: "300px", maxWidth: "600px" }} - /> - - ); -}; - -export default InputDataAndCode; diff --git a/frontend/src/use-cases/create-account/views/input-data-and-code/InputDataAndCode.view.options.js b/frontend/src/use-cases/create-account/views/input-data-and-code/InputDataAndCode.view.options.js deleted file mode 100644 index f32fc44c7..000000000 --- a/frontend/src/use-cases/create-account/views/input-data-and-code/InputDataAndCode.view.options.js +++ /dev/null @@ -1,209 +0,0 @@ -import * as yup from "yup"; -import { - USER_ACCEPTANCE_YEAR, - USER_CID, - USER_EMAIL, - USER_FIRST_NAME, - USER_LAST_NAME, - USER_NICK, - USER_PASSWORD, - USER_AGREEMENT -} from "../../../../api/users/props.users.api"; -import { - DigitSelect, - DigitSwitch, - DigitTextField -} from "@cthit/react-digit-components"; - -const CODE = "code"; -const PASSWORD_CONFIRMATION = "passwordConfirmation"; - -const _getCurrentYear = () => { - return new Date().getFullYear() + ""; -}; - -const _generateAcceptanceYears = () => { - const output = {}; - const startYear = 2001; - const currentYear = _getCurrentYear(); - for (var i = currentYear; i >= startYear; i--) { - output[i] = i + ""; - } - return output; -}; - -export const validationSchema = text => { - const schema = {}; - schema[USER_CID] = yup.string().required(text.Cid + text.IsRequired); - schema[CODE] = yup.string().required(text.Code + text.IsRequired); - schema[USER_NICK] = yup.string().required(text.Nick + text.IsRequired); - schema[USER_FIRST_NAME] = yup - .string() - .required(text.FirstName + text.IsRequired); - - schema[USER_LAST_NAME] = yup - .string() - .required(text.LastName + text.IsRequired); - schema[USER_EMAIL] = yup - .string() - .required(text.Email + text.IsRequired) - .email(text.NotEmail) - .matches(/(^((?!@student.chalmers.se).)*$)/, text.NonStudentEmailError); - - schema[USER_ACCEPTANCE_YEAR] = yup - .number() - .min(2001) - .max(_getCurrentYear()) - .required(text.AcceptanceYear + text.IsRequired); - - schema[USER_PASSWORD] = yup - .string() - .min(8, text.MinimumLength) - .required(text.Password + text.IsRequired); - - schema[PASSWORD_CONFIRMATION] = yup - .string() - .oneOf([yup.ref("password")], text.PasswordsDoNotMatch) - .required(text.Password + text.IsRequired); - - schema[USER_AGREEMENT] = yup - .boolean() - .oneOf([true]) - .required(text.YouMustAccept); - - return yup.object().shape(schema); -}; - -export const initialValues = () => { - const initialValues = {}; - initialValues[USER_CID] = ""; - initialValues[CODE] = ""; - initialValues[USER_NICK] = ""; - initialValues[USER_FIRST_NAME] = ""; - initialValues[USER_LAST_NAME] = ""; - initialValues[USER_EMAIL] = ""; - initialValues[USER_ACCEPTANCE_YEAR] = ""; - initialValues[USER_PASSWORD] = ""; - initialValues[PASSWORD_CONFIRMATION] = ""; - initialValues[USER_AGREEMENT] = false; - - return initialValues; -}; - -export const keysComponentData = text => { - const keysComponentData = {}; - keysComponentData[USER_CID] = { - component: DigitTextField, - componentProps: { - upperLabel: text.YourCid, - outlined: true, - maxLength: 10, - size: { width: "280px" } - } - }; - - keysComponentData[CODE] = { - component: DigitTextField, - componentProps: { - upperLabel: text.CodeFromYourStudentEmail, - outlined: true, - maxLength: 15, - size: { width: "280px" } - } - }; - - keysComponentData[USER_NICK] = { - component: DigitTextField, - componentProps: { - upperLabel: text.Nick, - outlined: true, - maxLength: 20, - size: { width: "280px" } - } - }; - - keysComponentData[USER_FIRST_NAME] = { - component: DigitTextField, - componentProps: { - upperLabel: text.FirstName, - outlined: true, - maxLength: 15, - size: { width: "280px" } - } - }; - - keysComponentData[USER_LAST_NAME] = { - component: DigitTextField, - componentProps: { - upperLabel: text.LastName, - outlined: true, - maxLength: 15, - size: { width: "280px" } - } - }; - - keysComponentData[USER_EMAIL] = { - component: DigitTextField, - componentProps: { - upperLabel: text.NonStudentEmail, - outlined: true, - maxLength: 100, - size: { width: "280px" } - } - }; - - keysComponentData[USER_ACCEPTANCE_YEAR] = { - component: DigitSelect, - componentProps: { - valueToTextMap: _generateAcceptanceYears(), - upperLabel: text.WhichYearDidYouStart, - reverse: true, - outlined: true, - size: { width: "280px" } - } - }; - - keysComponentData[USER_PASSWORD] = { - component: DigitTextField, - componentProps: { - upperLabel: text.Password, - outlined: true, - password: true, - size: { width: "280px" } - } - }; - - keysComponentData[PASSWORD_CONFIRMATION] = { - component: DigitTextField, - componentProps: { - upperLabel: text.ConfirmPassword, - outlined: true, - password: true, - size: { width: "280px" } - } - }; - - keysComponentData[USER_AGREEMENT] = { - component: DigitSwitch, - componentProps: { - label: text.AcceptUserAgreement, - primary: true, - size: { width: "280px" } - } - }; - - return keysComponentData; -}; - -export const keysOrder = () => [ - USER_CID, - CODE, - USER_PASSWORD, - PASSWORD_CONFIRMATION, - USER_NICK, - USER_FIRST_NAME, - USER_LAST_NAME, - USER_EMAIL, - USER_ACCEPTANCE_YEAR, - USER_AGREEMENT -]; diff --git a/frontend/src/use-cases/create-account/views/input-data-and-code/InputDataAndCode.view.translations.json b/frontend/src/use-cases/create-account/views/input-data-and-code/InputDataAndCode.view.translations.json deleted file mode 100644 index 6ba24052d..000000000 --- a/frontend/src/use-cases/create-account/views/input-data-and-code/InputDataAndCode.view.translations.json +++ /dev/null @@ -1,52 +0,0 @@ -{ - "CompleteCreation": [ - "Complete creation of your account", - "Slutför registreringen av konto" - ], - "CompleteCreationDescription": [ - "Enter your cid and your code that you recieved from your student email along with the following information.", - "Skriv in ditt cid och koden du fick på din skolmail samt följande information." - ], - "YourCid": ["Your cid", "Ditt cid"], - "CodeFromYourStudentEmail": [ - "Code from your student email", - "Kod från din studentmail" - ], - "NotEmail": ["Not a valid email", "Inte en giltig email"], - "NonStudentEmailError": [ - "Email needs to be non-student email", - "Email måste vara icke-studentmail" - ], - "NonStudentEmail": [ - "Enter a non-student email", - "Skriv in din icke-studentmail" - ], - "WhichYearDidYouStart": [ - "Which year did you start at IT?", - "Vilket år började du på IT?" - ], - "AcceptUserAgreement": [ - "I accept the user agreement", - "Jag accepterar användaravtalet" - ], - "CreateAccount": ["Create account", "Skapa konto"], - "PasswordsDoNotMatch": [ - "Passwords do not match", - "Lösenorden matchar inte" - ], - "TOO_SHORT_PASSWORD": [ - "The password must be atleast 8 characters", - "Lösenordet måste vara minst 8 karaktärer" - ], - "CODE_OR_CID_IS_WRONG": [ - "Your cid or code is wrong, please try again or contact digit@chalmers.it", - "Ditt cid eller din kod är fel, var vänlig och försök igen eller kontakta digit@chalmers.it" - ], - "YouMustAccept": [ - "You must accept the user agreement", - "Du måste acceptera användaravtalen" - ], - "Code": ["Code", "Kod"], - "UserAgreement": ["User agreement", "Användaravtal"], - "ShowUserAgreement": ["Show user agreement", "Visa användaravtal"] -} diff --git a/frontend/src/use-cases/create-account/views/input-data-and-code/index.js b/frontend/src/use-cases/create-account/views/input-data-and-code/index.js deleted file mode 100644 index 90b37f8aa..000000000 --- a/frontend/src/use-cases/create-account/views/input-data-and-code/index.js +++ /dev/null @@ -1,2 +0,0 @@ -import { default as InputDataAndCode } from "./InputDataAndCode.view"; -export default InputDataAndCode; diff --git a/frontend/src/use-cases/four-o-four/FourOFour.jsx b/frontend/src/use-cases/four-o-four/FourOFour.jsx deleted file mode 100644 index 612799c56..000000000 --- a/frontend/src/use-cases/four-o-four/FourOFour.jsx +++ /dev/null @@ -1,46 +0,0 @@ -import React from "react"; - -import { - DigitButton, - DigitDesign, - DigitText, - useDigitTranslations -} from "@cthit/react-digit-components"; -import { useHistory } from "react-router-dom"; - -import translations from "./FourOFour.translations.json"; - -const FourOFour = () => { - const [text] = useDigitTranslations(translations); - const history = useHistory(); - - return ( - - - - - - - - - - history.push("/")} - /> - - - ); -}; -export default FourOFour; diff --git a/frontend/src/use-cases/four-o-four/FourOFour.translations.json b/frontend/src/use-cases/four-o-four/FourOFour.translations.json deleted file mode 100644 index 9b80087a0..000000000 --- a/frontend/src/use-cases/four-o-four/FourOFour.translations.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "ContactDigit": [ - "If you still think it is? Contact digIT@chalmers.it.", - "Om du fortfarande tror att du har träffat rätt, kontaka digIT@chalmers.it." - ], - "PageNotFound": ["404 - Page not found", "404 - Sida ej funnen"], - "TakeMeHome": ["Take me home", "Ta mig hem"] -} diff --git a/frontend/src/use-cases/four-o-four/index.js b/frontend/src/use-cases/four-o-four/index.js deleted file mode 100644 index adbf893cf..000000000 --- a/frontend/src/use-cases/four-o-four/index.js +++ /dev/null @@ -1,2 +0,0 @@ -import { default as FourOFour } from "./FourOFour"; -export default FourOFour; diff --git a/frontend/src/use-cases/gdpr/Gdpr.jsx b/frontend/src/use-cases/gdpr/Gdpr.jsx deleted file mode 100644 index 3586c3075..000000000 --- a/frontend/src/use-cases/gdpr/Gdpr.jsx +++ /dev/null @@ -1,146 +0,0 @@ -import { - DigitSelectMultipleTable, - useDigitTranslations, - useDigitToast, - DigitLoading, - DigitLayout -} from "@cthit/react-digit-components"; -import React, { useCallback, useEffect, useState } from "react"; -import translations from "./Gdpr.translations.json"; -import { - USER_CID, - USER_FIRST_NAME, - USER_ID, - USER_LAST_NAME, - USER_NICK -} from "../../api/users/props.users.api"; -import * as _ from "lodash"; -import InsufficientAccess from "../../common/views/insufficient-access"; -import { getUsersWithGDPRMinified } from "../../api/gdpr/get.gdpr.api"; -import { setGDPRValue } from "../../api/gdpr/put.gdpr.api"; -import useGammaIsAdmin from "../../common/hooks/use-gamma-is-admin/useGammaIsAdmin"; -import useGammaHasAuthority from "../../common/hooks/use-gamma-has-authority/use-gamma-has-authority"; - -function _generateHeaderTexts(text) { - const output = {}; - - output[USER_CID] = text.Cid; - output[USER_FIRST_NAME] = text.FirstName; - output[USER_LAST_NAME] = text.LastName; - output[USER_NICK] = text.Nick; - output[USER_ID] = text.Id; - output["__checkbox"] = text.HasGDPR; - - return output; -} - -const Gdpr = () => { - const [text] = useDigitTranslations(translations); - const [queueToast] = useDigitToast(); - const [users, setUsers] = useState(null); - - const [lastSelected, setLastSelected] = useState([]); - const admin = useGammaIsAdmin(); - const gdpr = useGammaHasAuthority("gdpr"); - const access = admin || gdpr; - const getUsersWithGDPRCallback = useCallback(getUsersWithGDPRMinified, []); - - useEffect(() => { - if (access) { - getUsersWithGDPRCallback().then(response => { - setUsers(response.data); - setLastSelected( - response.data.filter(user => user.gdpr).map(user => user.id) - ); - }); - } - }, [access, getUsersWithGDPRCallback]); - - if (!access) { - return ; - } - - if (users == null) { - return ( - - - - ); - } - - return ( - { - const c = _.xorWith(selected, lastSelected, _.isEqual); - - if (c.length > 0) { - var newGDPRValue = false; - - if (selected.length > lastSelected.length) { - //add - newGDPRValue = true; - } - - setGDPRValue(c[0], { - gdpr: newGDPRValue - }) - .then(() => { - queueToast({ - text: - text.SuccessfullySetOfGDPRTo + - " " + - _.find(users, { - id: c[0] - })[USER_NICK] + - " " + - text.To + - ": " + - newGDPRValue - }); - - getUsersWithGDPRCallback().then(response => { - setUsers(response.data); - setLastSelected( - response.data - .filter(user => user.gdpr) - .map(user => user.id) - ); - }); - }) - .catch(error => { - queueToast({ - text: text.SomethingWentWrong - }); - }); - } - }} - value={users.filter(user => user.gdpr).map(user => user.id)} - columnsOrder={[ - USER_CID, - USER_FIRST_NAME, - USER_NICK, - USER_LAST_NAME - ]} - headerTexts={_generateHeaderTexts(text)} - data={users.map(user => { - return { - ...user, - __checkbox: user.gdpr - }; - })} - startRowsPerPage={25} - /> - ); -}; - -export default Gdpr; diff --git a/frontend/src/use-cases/gdpr/Gdpr.translations.json b/frontend/src/use-cases/gdpr/Gdpr.translations.json deleted file mode 100644 index f8fc91799..000000000 --- a/frontend/src/use-cases/gdpr/Gdpr.translations.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "Cid": ["Cid", "Cid"], - "FirstName": ["First name", "Förnamn"], - "LastName": ["Last name", "Efternamn"], - "Nick": ["Nick", "Nick"], - "Users": ["Users", "Användare"], - "SearchForUsers": ["Search for users", "Sök efter användare"], - "HasGDPR": ["Have finished GDPR training", "Har genomfört GDPR utbildning"], - "SuccessfullySetOfGDPRTo": [ - "Successfully set GDPR status of", - "Satt status av GDPR på" - ], - "To": ["to", "till"] -} diff --git a/frontend/src/use-cases/gdpr/index.js b/frontend/src/use-cases/gdpr/index.js deleted file mode 100644 index 5c0dc66ce..000000000 --- a/frontend/src/use-cases/gdpr/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from "./Gdpr.jsx"; diff --git a/frontend/src/use-cases/groups/Groups.jsx b/frontend/src/use-cases/groups/Groups.jsx deleted file mode 100644 index bff583c04..000000000 --- a/frontend/src/use-cases/groups/Groups.jsx +++ /dev/null @@ -1,221 +0,0 @@ -import React, { useEffect, useState } from "react"; -import { addDays } from "date-fns"; -import { - DigitCRUD, - useDigitTranslations, - DigitButton, - DigitLayout -} from "@cthit/react-digit-components"; -import translations from "./Groups.translations"; -import { getGroup, getGroupsMinified } from "../../api/groups/get.groups.api"; -import { - GROUP_BECOMES_ACTIVE, - GROUP_BECOMES_INACTIVE, - GROUP_MEMBERS, - GROUP_ID, - GROUP_NAME, - GROUP_PRETTY_NAME, - GROUP_SUPER_GROUP, - GROUP_EMAIL, - GROUP_DESCRIPTION_EN, - GROUP_DESCRIPTION_SV, - GROUP_FUNCTION_EN, - GROUP_FUNCTION_SV, - GROUP_NO_ACCOUNT_MEMBERS -} from "../../api/groups/props.groups.api"; -import { editGroup } from "../../api/groups/put.groups.api"; -import { getSuperGroups } from "../../api/super-groups/get.super-groups.api"; -import { addGroup } from "../../api/groups/post.groups.api"; -import DisplayMembersTable from "../../common/elements/display-members-table"; -import { useHistory } from "react-router-dom"; -import useGammaIsAdmin from "../../common/hooks/use-gamma-is-admin/useGammaIsAdmin"; -import { deleteGroup } from "../../api/groups/delete.groups.api"; -import FourOFour from "../four-o-four"; -import FiveZeroZero from "../../app/elements/five-zero-zero"; -import { - initialValues, - keysOrder, - keysText, - readAllKeysOrder, - readOneKeysOrder, - keysComponentData, - validationSchema, - updateKeysOrder -} from "./Groups.options"; -import InsufficientAccess from "../../common/views/insufficient-access"; - -const Groups = () => { - const [text] = useDigitTranslations(translations); - const admin = useGammaIsAdmin(); - const [superGroups, setSuperGroups] = useState([]); - const history = useHistory(); - - useEffect(() => { - getSuperGroups().then(response => { - setSuperGroups(response.data); - }); - }, []); - - if (superGroups.length === 0) { - return null; - } - - return ( - admin} - canUpdate={() => admin} //|| inGroup(user, group)} - name={"groups"} - path={"/groups"} - readAllRequest={getGroupsMinified} - readOneRequest={getGroup} - deleteRequest={deleteGroup} - updateRequest={(id, data) => { - const becomesActive = addDays(data.becomesActive, 1); - const becomesInactive = addDays(data.becomesInactive, 1); - - return editGroup(id, { - name: data.name, - function: { - sv: data.functionSv, - en: data.functionEn - }, - description: { - sv: data.descriptionSv, - en: data.descriptionEn - }, - email: data.email, - superGroup: data.superGroup, - prettyName: data.prettyName, - becomesActive: becomesActive, - becomesInactive: becomesInactive - }); - }} - createRequest={ - admin - ? data => { - const becomesActive = addDays( - data[GROUP_BECOMES_ACTIVE], - 1 - ); - const becomesInactive = addDays( - data[GROUP_BECOMES_INACTIVE], - 1 - ); - - return addGroup({ - name: data[GROUP_NAME], - function: { - sv: data[GROUP_FUNCTION_SV], - en: data[GROUP_FUNCTION_EN] - }, - description: { - sv: data[GROUP_DESCRIPTION_SV], - en: data[GROUP_DESCRIPTION_EN] - }, - email: data[GROUP_EMAIL], - superGroup: data[GROUP_SUPER_GROUP], - prettyName: data[GROUP_PRETTY_NAME], - becomesActive, - becomesInactive - }); - } - : null - } - tableProps={{ - orderBy: GROUP_NAME, - startOrderBy: GROUP_NAME, - titleText: text.Groups, - search: true, - flex: "1", - startOrderByDirection: "asc", - size: { minWidth: "288px" }, - padding: "0px", - searchText: text.Search - }} - idProp={GROUP_ID} - detailsRenderCardEnd={data => - admin ? ( - history.push("/members/" + data.id)} - /> - ) : null - } - detailsRenderEnd={data => ( - - 0 - ? "8px" - : "0px" - }} - noUsersText={text.NoGroupMembers} - users={data[GROUP_MEMBERS]} - group={data} - /> - - {data[GROUP_NO_ACCOUNT_MEMBERS].length > 0 && ( - ({ - nick: member.cid, - ...member - }) - )} - /> - )} - - )} - dateProps={[GROUP_BECOMES_ACTIVE, GROUP_BECOMES_INACTIVE]} - createButtonText={text.Create + " " + text.Group} - updateTitle={group => text.Update + " " + group[GROUP_PRETTY_NAME]} - createTitle={text.CreateGroup} - detailsTitle={group => group[GROUP_PRETTY_NAME]} - statusRenders={{ - 403: () => , - 404: () => , - 500: (error, reset) => - }} - toastCreateSuccessful={() => text.GroupWasCreated} - toastCreateFailed={() => text.GroupCreateFailed} - toastDeleteSuccessful={() => text.GroupWasDeleted} - toastDeleteFailed={() => text.GroupDeleteFailed} - toastUpdateSuccessful={one => - one[GROUP_PRETTY_NAME] + text.GroupWasUpdated - } - toastUpdateFailed={() => text.GroupUpdateFailed} - backButtonText={text.Back} - updateButtonText={() => text.Edit} - deleteButtonText={one => text.Delete + " " + one[GROUP_PRETTY_NAME]} - detailsButtonText={text.Details} - dialogDeleteCancel={() => text.Cancel} - dialogDeleteConfirm={() => text.Delete} - dialogDeleteTitle={() => text.AreYouSure} - dialogDeleteDescription={one => - text.AreYouSureYouWantToDelete + - " " + - one[GROUP_PRETTY_NAME] + - "?" - } - useHistoryGoBackOnBack - /> - ); -}; - -export default Groups; diff --git a/frontend/src/use-cases/groups/Groups.options.js b/frontend/src/use-cases/groups/Groups.options.js deleted file mode 100644 index 33ba3c056..000000000 --- a/frontend/src/use-cases/groups/Groups.options.js +++ /dev/null @@ -1,230 +0,0 @@ -import * as yup from "yup"; -import { - DigitDatePicker, - DigitSelect, - DigitTextArea, - DigitTextField -} from "@cthit/react-digit-components"; -import { - GROUP_BECOMES_ACTIVE, - GROUP_BECOMES_INACTIVE, - GROUP_DESCRIPTION_EN, - GROUP_DESCRIPTION_SV, - GROUP_EMAIL, - GROUP_FUNCTION_EN, - GROUP_FUNCTION_SV, - GROUP_ID, - GROUP_NAME, - GROUP_PRETTY_NAME, - GROUP_SUPER_GROUP, - GROUP_SUPER_GROUP_PRETTY_NAME -} from "../../api/groups/props.groups.api"; - -export const validationSchema = text => { - const schema = {}; - - schema[GROUP_NAME] = yup.string().required(text.Name + text.IsRequired); - schema[GROUP_PRETTY_NAME] = yup - .string() - .required(text.PrettyName + text.IsRequired); - schema[GROUP_EMAIL] = yup.string().required(text.Email + text.IsRequired); - - schema[GROUP_DESCRIPTION_SV] = yup.string(); - schema[GROUP_DESCRIPTION_EN] = yup.string(); - - schema[GROUP_FUNCTION_SV] = yup.string(); - schema[GROUP_FUNCTION_EN] = yup.string(); - - schema[GROUP_SUPER_GROUP] = yup - .string() - .required(text.GroupMustHaveSuperGroup); - - return yup.object().shape(schema); -}; - -export const initialValues = () => { - const output = {}; - - output[GROUP_ID] = ""; - output[GROUP_NAME] = ""; - output[GROUP_EMAIL] = ""; - output[GROUP_DESCRIPTION_SV] = ""; - output[GROUP_DESCRIPTION_EN] = ""; - output[GROUP_FUNCTION_SV] = ""; - output[GROUP_FUNCTION_EN] = ""; - output[GROUP_SUPER_GROUP] = ""; - output[GROUP_PRETTY_NAME] = ""; - output[GROUP_BECOMES_ACTIVE] = new Date(); - - var aYearFromNow = new Date(); - aYearFromNow.setFullYear(aYearFromNow.getFullYear() + 1); - output[GROUP_BECOMES_INACTIVE] = aYearFromNow; - - return output; -}; - -export const keysComponentData = (text, superGroups = []) => { - const componentData = {}; - - componentData[GROUP_NAME] = { - component: DigitTextField, - componentProps: { - upperLabel: text.Name, - maxLength: 50, - outlined: true - } - }; - - componentData[GROUP_PRETTY_NAME] = { - component: DigitTextField, - componentProps: { - upperLabel: text.PrettyName, - maxLength: 50, - outlined: true - } - }; - - componentData[GROUP_DESCRIPTION_SV] = { - component: DigitTextArea, - componentProps: { - upperLabel: text.DescriptionSv, - maxLength: 500, - rows: 5, - maxRows: 10, - outlined: true - } - }; - - componentData[GROUP_DESCRIPTION_EN] = { - component: DigitTextArea, - componentProps: { - upperLabel: text.DescriptionEn, - maxLength: 500, - rows: 5, - maxRows: 10, - outlined: true - } - }; - - componentData[GROUP_EMAIL] = { - component: DigitTextField, - componentProps: { - upperLabel: text.Email, - maxLength: 100, - outlined: true - } - }; - - componentData[GROUP_FUNCTION_SV] = { - component: DigitTextField, - componentProps: { - upperLabel: text.FunctionSv, - maxLength: 100, - outlined: true - } - }; - - componentData[GROUP_FUNCTION_EN] = { - component: DigitTextField, - componentProps: { - maxLength: 100, - upperLabel: text.FunctionEn, - outlined: true - } - }; - - const superGroupMap = {}; - for (let i = 0; i < superGroups.length; i++) { - superGroupMap[superGroups[i].id] = superGroups[i].prettyName; - } - - componentData[GROUP_SUPER_GROUP] = { - component: DigitSelect, - componentProps: { - upperLabel: text.SuperGroup, - valueToTextMap: superGroupMap, - outlined: true - } - }; - - componentData[GROUP_BECOMES_ACTIVE] = { - component: DigitDatePicker, - componentProps: { - upperLabel: text.BecomesActive, - outlined: true - } - }; - - componentData[GROUP_BECOMES_INACTIVE] = { - component: DigitDatePicker, - componentProps: { - upperLabel: text.BecomesInactive, - outlined: true - } - }; - - return componentData; -}; - -export const keysText = text => { - const keysText = {}; - - keysText[GROUP_ID] = text.Id; - keysText[GROUP_NAME] = text.Name; - keysText[GROUP_EMAIL] = text.Email; - keysText[GROUP_DESCRIPTION_SV] = text.DescriptionSv; - keysText[GROUP_DESCRIPTION_EN] = text.DescriptionEn; - keysText[GROUP_FUNCTION_SV] = text.FunctionSv; - keysText[GROUP_FUNCTION_EN] = text.FunctionEn; - keysText[GROUP_SUPER_GROUP] = text.SuperGroup; - keysText[GROUP_SUPER_GROUP_PRETTY_NAME] = text.SuperGroup; - keysText[GROUP_PRETTY_NAME] = text.PrettyName; - keysText[GROUP_BECOMES_ACTIVE] = text.BecomesActive; - keysText[GROUP_BECOMES_INACTIVE] = text.BecomesInactive; - - return keysText; -}; - -export const keysOrder = () => [ - GROUP_PRETTY_NAME, - GROUP_NAME, - GROUP_EMAIL, - GROUP_DESCRIPTION_SV, - GROUP_DESCRIPTION_EN, - GROUP_FUNCTION_SV, - GROUP_FUNCTION_EN, - GROUP_SUPER_GROUP, - GROUP_BECOMES_ACTIVE, - GROUP_BECOMES_INACTIVE -]; - -export const readOneKeysOrder = () => [ - GROUP_PRETTY_NAME, - GROUP_NAME, - GROUP_EMAIL, - GROUP_DESCRIPTION_SV, - GROUP_DESCRIPTION_EN, - GROUP_FUNCTION_SV, - GROUP_FUNCTION_EN, - GROUP_SUPER_GROUP_PRETTY_NAME, - GROUP_BECOMES_ACTIVE, - GROUP_BECOMES_INACTIVE -]; - -export const readAllKeysOrder = () => [ - GROUP_NAME, - GROUP_PRETTY_NAME, - GROUP_EMAIL -]; - -export const updateKeysOrder = () => [ - GROUP_PRETTY_NAME, - GROUP_EMAIL, - GROUP_DESCRIPTION_SV, - GROUP_DESCRIPTION_EN, - GROUP_FUNCTION_SV, - GROUP_FUNCTION_EN, - GROUP_SUPER_GROUP, - GROUP_BECOMES_ACTIVE, - GROUP_BECOMES_INACTIVE -]; diff --git a/frontend/src/use-cases/groups/Groups.translations.json b/frontend/src/use-cases/groups/Groups.translations.json deleted file mode 100644 index 5a15e0759..000000000 --- a/frontend/src/use-cases/groups/Groups.translations.json +++ /dev/null @@ -1,51 +0,0 @@ -{ - "Group": ["Group", "Grupp"], - "CreateGroup": ["Create group", "Skapa grupp"], - "SaveGroup": ["Save group", "Spara grupp"], - "Name": ["Name", "Namn"], - "PrettyName": ["Pretty name", "Pretty name"], - "DescriptionSv": ["Description swedish", "Beskrivning svenska"], - "DescriptionEn": ["Description english", "Beskrivning engelska"], - "Email": ["Email", "Email"], - "FunctionSv": ["Function swedish", "Uppdrag svenska"], - "FunctionEn": ["Function english", "Uppdrag engelska"], - "Type": ["Group type", "Grupp typ"], - "Society": ["Society", "Förening"], - "Committee": ["Committee", "Kommitté"], - "Board": ["Board", "Nämnd"], - "BecomesActive": ["Becomes active", "Blir aktiva"], - "BecomesInactive": ["Becomes inactitve", "Blir inaktiva"], - "NoGroup": ["None", "Ingen"], - "SuperGroup": ["Super group", "Super grupp"], - "Groups": ["Groups", "Grupper"], - "Description": ["Description", "Beskrivning"], - "Function": ["Function", "Uppdrag"], - "Details": ["Details", "Detaljer"], - "NoGroups": ["There's no groups", "Det finns inga grupper"], - "SearchForGroups": ["Search for groups", "Sök efter grupper"], - "NoGroupMembers": [ - "There's no users in this group", - "Det finns inga användare i den här gruppen" - ], - "NoAccountMembers": [ - "Have no account members", - "Har inget konto medlemmar" - ], - "GroupMustHaveSuperGroup": [ - "A group must have a supergroup", - "En grupp måste ha en supergrupp" - ], - "GroupWasCreated": ["Group was created", "Gruppen skapades"], - "GroupCreateFailed": [ - "Something went wrong! Group wasn't created.", - "Någonting gick fel! Gruppen skapades inte." - ], - "GroupWasDeleted": ["Group was deleted", "Gruppen raderades"], - "GroupDeleteFailed": ["Something went wrong! Group wasn't created."], - "GroupWasUpdated": [" was updated", " har uppdaterats"], - "GroupUpdateFailed": [ - "Something went wrong! Group wasn't updated.", - "Någonting gick fel! Grupp uppdaterades inte." - ], - "EditMembers": ["Edit members", "Redigera medlemmarna"] -} diff --git a/frontend/src/use-cases/groups/index.js b/frontend/src/use-cases/groups/index.js deleted file mode 100644 index 53159a580..000000000 --- a/frontend/src/use-cases/groups/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from "./Groups"; diff --git a/frontend/src/use-cases/home/Home.jsx b/frontend/src/use-cases/home/Home.jsx deleted file mode 100644 index b31542f57..000000000 --- a/frontend/src/use-cases/home/Home.jsx +++ /dev/null @@ -1,38 +0,0 @@ -import React from "react"; - -import { DigitLayout } from "@cthit/react-digit-components"; - -import UserOptions from "./elements/user-options"; -import AdminOptions from "./elements/admin-options"; -import WelcomeUser from "./elements/welcome-user"; -import useGammaIsAdmin from "../../common/hooks/use-gamma-is-admin/useGammaIsAdmin"; -import useGammaUser from "../../common/hooks/use-gamma-user/useGammaUser"; - -const Home = () => { - const admin = useGammaIsAdmin(); - const user = useGammaUser(); - - if (user == null) { - return null; - } - - return ( - - - - - 0} - /> - {admin && ( - <> - - - - )} - - - ); -}; - -export default Home; diff --git a/frontend/src/use-cases/home/elements/admin-options/AdminOptions.element.jsx b/frontend/src/use-cases/home/elements/admin-options/AdminOptions.element.jsx deleted file mode 100644 index e1f6f9e77..000000000 --- a/frontend/src/use-cases/home/elements/admin-options/AdminOptions.element.jsx +++ /dev/null @@ -1,36 +0,0 @@ -import React from "react"; - -import { - DigitDesign, - DigitLayout, - useDigitTranslations -} from "@cthit/react-digit-components"; - -import translations from "./AdminOptions.element.translations.json"; -import HomeLink from "../../elements/home-link"; - -const AdminOptions = () => { - const [text] = useDigitTranslations(translations); - - return ( - - - - - - - - - - - - - - - ); -}; - -export default AdminOptions; diff --git a/frontend/src/use-cases/home/elements/admin-options/AdminOptions.element.translations.json b/frontend/src/use-cases/home/elements/admin-options/AdminOptions.element.translations.json deleted file mode 100644 index 2bfc1611b..000000000 --- a/frontend/src/use-cases/home/elements/admin-options/AdminOptions.element.translations.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "AdminOptions": ["Admin options", "Admin alternativ"], - "ActivationCodes": ["Activation codes", "Aktiveringskoder"], - "GDPR": ["GDPR certified", "GDPR certifierade"], - "GroupPosts": ["Group posts", "Grupp poster"], - "Whitelist": ["Whitelist of cids", "Whitelist av cids"], - "Clients": ["Clients", "Klienter"], - "SuperGroups": ["Super groups", "Supergrupper"], - "ApiKeys": ["API keys", "API nycklar"] -} diff --git a/frontend/src/use-cases/home/elements/admin-options/index.js b/frontend/src/use-cases/home/elements/admin-options/index.js deleted file mode 100644 index 2e8bd824c..000000000 --- a/frontend/src/use-cases/home/elements/admin-options/index.js +++ /dev/null @@ -1,2 +0,0 @@ -import AdminOptions from "./AdminOptions.element"; -export default AdminOptions; diff --git a/frontend/src/use-cases/home/elements/home-link/HomeLink.element.jsx b/frontend/src/use-cases/home/elements/home-link/HomeLink.element.jsx deleted file mode 100644 index 6d60beb13..000000000 --- a/frontend/src/use-cases/home/elements/home-link/HomeLink.element.jsx +++ /dev/null @@ -1,17 +0,0 @@ -import React from "react"; -import styled from "styled-components"; - -import { DigitText } from "@cthit/react-digit-components"; -import { Link } from "react-router-dom"; - -const NoStyleLink = styled(Link)` - color: black; -`; - -const HomeLink = ({ text, link }) => ( - - - -); - -export default HomeLink; diff --git a/frontend/src/use-cases/home/elements/home-link/index.js b/frontend/src/use-cases/home/elements/home-link/index.js deleted file mode 100644 index a5ae36aa6..000000000 --- a/frontend/src/use-cases/home/elements/home-link/index.js +++ /dev/null @@ -1,2 +0,0 @@ -import HomeLink from "./HomeLink.element"; -export default HomeLink; diff --git a/frontend/src/use-cases/home/elements/user-options/UserOptions.element.jsx b/frontend/src/use-cases/home/elements/user-options/UserOptions.element.jsx deleted file mode 100644 index a7ae5e16f..000000000 --- a/frontend/src/use-cases/home/elements/user-options/UserOptions.element.jsx +++ /dev/null @@ -1,38 +0,0 @@ -import React from "react"; - -import { - DigitDesign, - DigitLayout, - useDigitTranslations -} from "@cthit/react-digit-components"; - -import HomeLink from "../../elements/home-link"; - -import translations from "./UserOptions.element.translations.json"; - -const UserOptions = ({ hasGroups }) => { - const [text] = useDigitTranslations(translations); - - return ( - - - - - - {hasGroups && ( - - )} - - - - - - - - ); -}; - -export default UserOptions; diff --git a/frontend/src/use-cases/home/elements/user-options/UserOptions.element.translations.json b/frontend/src/use-cases/home/elements/user-options/UserOptions.element.translations.json deleted file mode 100644 index ceaa74db1..000000000 --- a/frontend/src/use-cases/home/elements/user-options/UserOptions.element.translations.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "UserOptions": ["User options", "Användare alternativ"], - "MyAccount": ["My account", "Mitt konto"], - "MyGroups": ["My groups", "Mina grupper"], - "ChangePassword": ["Change my password", "Ändra mitt lösenord"], - "ChangeAvatar": ["Change avatar", "Ändra avatar"], - "AllUsers": ["All users", "Alla användare"], - "AllGroups": ["All groups", "Alla grupper"] -} diff --git a/frontend/src/use-cases/home/elements/user-options/index.js b/frontend/src/use-cases/home/elements/user-options/index.js deleted file mode 100644 index e59a179e4..000000000 --- a/frontend/src/use-cases/home/elements/user-options/index.js +++ /dev/null @@ -1,2 +0,0 @@ -import UserOptions from "./UserOptions.element"; -export default UserOptions; diff --git a/frontend/src/use-cases/home/elements/welcome-user/WelcomeUser.element.jsx b/frontend/src/use-cases/home/elements/welcome-user/WelcomeUser.element.jsx deleted file mode 100644 index bc44955cd..000000000 --- a/frontend/src/use-cases/home/elements/welcome-user/WelcomeUser.element.jsx +++ /dev/null @@ -1,21 +0,0 @@ -import React from "react"; - -import translations from "./WelcomeUser.element.translations.json"; - -import { DigitText, useDigitTranslations } from "@cthit/react-digit-components"; - -import { USER_NICK } from "../../../../api/users/props.users.api"; - -const WelcomeUser = ({ user }) => { - const [text] = useDigitTranslations(translations); - return ( - <> - - - - ); -}; - -export default WelcomeUser; diff --git a/frontend/src/use-cases/home/elements/welcome-user/WelcomeUser.element.translations.json b/frontend/src/use-cases/home/elements/welcome-user/WelcomeUser.element.translations.json deleted file mode 100644 index c6dd1bd07..000000000 --- a/frontend/src/use-cases/home/elements/welcome-user/WelcomeUser.element.translations.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "Hi": ["Hi", "Hej"], - "WelcomeToIT": [ - "Welcome to the IT student division authentication system", - "Välkommen till IT-sektionens autentiseringssystem" - ] -} diff --git a/frontend/src/use-cases/home/elements/welcome-user/index.js b/frontend/src/use-cases/home/elements/welcome-user/index.js deleted file mode 100644 index 6a9b73c0a..000000000 --- a/frontend/src/use-cases/home/elements/welcome-user/index.js +++ /dev/null @@ -1,2 +0,0 @@ -import WelcomeUser from "./WelcomeUser.element"; -export default WelcomeUser; diff --git a/frontend/src/use-cases/home/index.js b/frontend/src/use-cases/home/index.js deleted file mode 100644 index ffa79319e..000000000 --- a/frontend/src/use-cases/home/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from "./Home"; diff --git a/frontend/src/use-cases/me/Me.jsx b/frontend/src/use-cases/me/Me.jsx deleted file mode 100644 index f96b57114..000000000 --- a/frontend/src/use-cases/me/Me.jsx +++ /dev/null @@ -1,25 +0,0 @@ -import React from "react"; -import { Switch, Route } from "react-router-dom"; -import MeChangePassword from "./screens/me-change-password"; -import MeGroups from "./screens/me-groups"; -import MeAvatar from "./screens/me-avatar"; -import MeApprovals from "./screens/me-approvals"; -import MeCRUD from "./screens/me-crud"; - -const Me = () => { - return ( - - - - - - - - ); -}; - -export default Me; diff --git a/frontend/src/use-cases/me/Me.options.js b/frontend/src/use-cases/me/Me.options.js deleted file mode 100644 index d762cfe1a..000000000 --- a/frontend/src/use-cases/me/Me.options.js +++ /dev/null @@ -1,75 +0,0 @@ -import * as yup from "yup"; -import { - USER_ACCEPTANCE_YEAR, - USER_AGREEMENT, - USER_CID, - USER_EMAIL, - USER_FIRST_NAME, - USER_GROUPS, - USER_ID, - USER_LANGUAGE, - USER_LAST_NAME, - USER_NICK, - USER_PASSWORD, - USER_PHONE -} from "../../api/users/props.users.api"; - -export const validationSchema = text => { - const schema = {}; - - schema[USER_FIRST_NAME] = yup.string().required(text.FieldRequired); - schema[USER_LAST_NAME] = yup.string().required(text.FieldRequired); - schema[USER_NICK] = yup.string().required(text.FieldRequired); - schema[USER_EMAIL] = yup.string().required(text.FieldRequired); - schema[USER_ACCEPTANCE_YEAR] = yup.number().required(text.FieldRequired); - schema[USER_PHONE] = yup.string().nullable(); - - return yup.object().shape(schema); -}; - -export const initialValues = () => { - const output = {}; - - output[USER_FIRST_NAME] = ""; - output[USER_LAST_NAME] = ""; - output[USER_NICK] = ""; - output[USER_EMAIL] = ""; - output[USER_ACCEPTANCE_YEAR] = ""; - output[USER_LANGUAGE] = ""; - output[USER_AGREEMENT] = false; - output[USER_CID] = ""; - output[USER_PASSWORD] = ""; - output[USER_PHONE] = ""; - - return output; -}; - -export const keysText = text => { - const output = {}; - - output[USER_ID] = text.Id; - output[USER_CID] = text.Cid; - output[USER_FIRST_NAME] = text.FirstName; - output[USER_LAST_NAME] = text.LastName; - output[USER_NICK] = text.Nick; - output[USER_EMAIL] = text.Email; - output[USER_ACCEPTANCE_YEAR] = text.AcceptanceYear; - output[USER_LANGUAGE] = text.Language; - output[USER_CID] = text.Cid; - output[USER_AGREEMENT] = text.AcceptUserAgreement; - output[USER_PASSWORD] = text.Password; - output[USER_PHONE] = text.Phone; - - return output; -}; - -export const keysOrder = () => [ - USER_FIRST_NAME, - USER_LAST_NAME, - USER_NICK, - USER_EMAIL, - USER_ACCEPTANCE_YEAR, - USER_PHONE, - USER_LANGUAGE, - USER_GROUPS -]; diff --git a/frontend/src/use-cases/me/index.js b/frontend/src/use-cases/me/index.js deleted file mode 100644 index 031ed6b8a..000000000 --- a/frontend/src/use-cases/me/index.js +++ /dev/null @@ -1,2 +0,0 @@ -import Me from "./Me"; -export default Me; diff --git a/frontend/src/use-cases/me/screens/me-approvals/MeApprovals.screen.jsx b/frontend/src/use-cases/me/screens/me-approvals/MeApprovals.screen.jsx deleted file mode 100644 index 58717172f..000000000 --- a/frontend/src/use-cases/me/screens/me-approvals/MeApprovals.screen.jsx +++ /dev/null @@ -1,48 +0,0 @@ -import React, { useEffect, useState } from "react"; -import { getApprovals } from "../../../../api/approval/get.approval.api"; -import { - DigitLoading, - DigitTable, - useDigitTranslations -} from "@cthit/react-digit-components"; -import translations from "./MeApprovals.translations.screen"; - -const MeApprovals = () => { - const [approvals, setApprovals] = useState(null); - const [text, activeLanguage] = useDigitTranslations(translations); - - useEffect(() => { - getApprovals().then(response => { - setApprovals( - response.data.map(approval => ({ - name: approval.name, - description: approval.description[activeLanguage] - })) - ); - }); - }, [activeLanguage]); - - if (approvals == null) { - return ; - } - - return ( - - ); -}; - -export default MeApprovals; diff --git a/frontend/src/use-cases/me/screens/me-approvals/MeApprovals.translations.screen.json b/frontend/src/use-cases/me/screens/me-approvals/MeApprovals.translations.screen.json deleted file mode 100644 index a15cf44fe..000000000 --- a/frontend/src/use-cases/me/screens/me-approvals/MeApprovals.translations.screen.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "YourApprovedClients": ["Your approved clients", "Dina godkända klienter"] -} diff --git a/frontend/src/use-cases/me/screens/me-approvals/index.js b/frontend/src/use-cases/me/screens/me-approvals/index.js deleted file mode 100644 index f3d05657d..000000000 --- a/frontend/src/use-cases/me/screens/me-approvals/index.js +++ /dev/null @@ -1,2 +0,0 @@ -import MeApprovalsScreen from "./MeApprovals.screen"; -export default MeApprovalsScreen; diff --git a/frontend/src/use-cases/me/screens/me-avatar/MeAvatar.screen.jsx b/frontend/src/use-cases/me/screens/me-avatar/MeAvatar.screen.jsx deleted file mode 100644 index d2ef916e0..000000000 --- a/frontend/src/use-cases/me/screens/me-avatar/MeAvatar.screen.jsx +++ /dev/null @@ -1,85 +0,0 @@ -import React, { useContext, useState } from "react"; -import { - DigitButton, - DigitDesign, - DigitLayout, - DigitSelectFile, - DigitText, - useDigitTranslations, - useDigitToast -} from "@cthit/react-digit-components"; -import translations from "./MeAvatar.screen.translations"; -import { uploadUserAvatar } from "../../../../api/image/put.image.api"; -import statusCode from "../../../../common/utils/formatters/statusCode.formatter"; -import { useHistory } from "react-router-dom"; -import GammaUserContext from "../../../../common/context/GammaUser.context"; - -const MeAvatar = () => { - const history = useHistory(); - const [text] = useDigitTranslations(translations); - const [file, setFile] = useState(null); - const [queueToast] = useDigitToast(); - const [user, update] = useContext(GammaUserContext); - - return ( - - - - - - - {user.avatarUrl == null && ( - - )} - {user.avatarUrl != null && ( - {"Avatar"} - )} - - - history.goBack()} - outlined - /> - { - uploadUserAvatar(file) - .then(() => { - update(); - }) - .catch(error => { - const code = statusCode(error); - let errorMessage = text.UploadFailed; - if (code === 413) { - errorMessage = text.TooLargeFile; - } else if (code === 415) { - errorMessage = text.InvalidFileType; - } - queueToast({ - text: errorMessage, - duration: 5000 - }); - }); - }} - /> - - - - - ); -}; - -export default MeAvatar; diff --git a/frontend/src/use-cases/me/screens/me-avatar/MeAvatar.screen.translations.json b/frontend/src/use-cases/me/screens/me-avatar/MeAvatar.screen.translations.json deleted file mode 100644 index 08e15dfd0..000000000 --- a/frontend/src/use-cases/me/screens/me-avatar/MeAvatar.screen.translations.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "MeAvatarTitle": ["Change your avatar image", "Ändra din profilbild"], - "SelectImage": ["Select image", "Välj bild"], - "UploadImage": ["Upload image", "Ladda upp bild"], - "NoAvatar": ["You have no avatar", "Du har ingen profilbild"], - "UploadFailed": ["Avatar upload failed", "Avatar uppladdning misslyckades"], - "TooLargeFile": [ - "File is to large (Max 2MB)", - "Filen är för stor (Max 2MB)" - ], - "InvalidFileType": ["Invalid file type", "Ogiltig filtyp"] -} diff --git a/frontend/src/use-cases/me/screens/me-avatar/index.js b/frontend/src/use-cases/me/screens/me-avatar/index.js deleted file mode 100644 index 0ecd4a6a7..000000000 --- a/frontend/src/use-cases/me/screens/me-avatar/index.js +++ /dev/null @@ -1,2 +0,0 @@ -import MeAvatar from "./MeAvatar.screen"; -export default MeAvatar; diff --git a/frontend/src/use-cases/me/screens/me-change-password/MeChangePassword.screen.jsx b/frontend/src/use-cases/me/screens/me-change-password/MeChangePassword.screen.jsx deleted file mode 100644 index e46bf9a1f..000000000 --- a/frontend/src/use-cases/me/screens/me-change-password/MeChangePassword.screen.jsx +++ /dev/null @@ -1,96 +0,0 @@ -import React from "react"; -import { - DigitEditDataCard, - useDigitTranslations, - DigitTextField, - DigitLayout, - useDigitToast -} from "@cthit/react-digit-components"; -import * as yup from "yup"; -import translations from "./MeChangePassword.screen.translations"; -import { editPassword } from "../../../../api/me/put.me.api"; -import { useHistory } from "react-router-dom"; -import useGammaUser from "../../../../common/hooks/use-gamma-user/useGammaUser"; -const MeChangePassword = () => { - const me = useGammaUser(); - const [text] = useDigitTranslations(translations); - const [queueToast] = useDigitToast(); - const history = useHistory(); - - return ( - - { - const { oldPassword, password } = v; - editPassword({ - oldPassword, - password - }) - .then(() => { - queueToast({ text: text.PasswordWasChanged }); - history.push("/me"); - }) - .catch(() => - queueToast({ - text: - text.SomethingWentWrongWhenChangingPassword - }) - ); - }} - validationSchema={yup.object().shape({ - oldPassword: yup.string(), - password: yup - .string() - .min(8, text.MinimumLength) - .required(text.FieldRequired), - confirmNewPassword: yup - .string() - .oneOf([yup.ref("password")], text.PasswordDoNotMatch) - .required(text.FieldRequired) - })} - keysComponentData={{ - oldPassword: { - component: DigitTextField, - componentProps: { - upperLabel: text.OldPassword, - password: true, - outlined: true - } - }, - password: { - component: DigitTextField, - componentProps: { - upperLabel: text.NewPassword, - password: true, - outlined: true - } - }, - confirmNewPassword: { - component: DigitTextField, - componentProps: { - upperLabel: text.ConfirmNewPassword, - password: true, - outlined: true - } - } - }} - initialValues={{ - oldPassword: "", - password: "", - confirmNewPassword: "" - }} - keysOrder={["oldPassword", "password", "confirmNewPassword"]} - submitText={text.ChangePassword} - titleText={text.ChangePasswordOn + " " + me.nick} - extraButton={{ - onClick: () => history.goBack(), - text: text.Back, - outlined: true - }} - /> - - ); -}; - -export default MeChangePassword; diff --git a/frontend/src/use-cases/me/screens/me-change-password/MeChangePassword.screen.translations.json b/frontend/src/use-cases/me/screens/me-change-password/MeChangePassword.screen.translations.json deleted file mode 100644 index 643966d25..000000000 --- a/frontend/src/use-cases/me/screens/me-change-password/MeChangePassword.screen.translations.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "ChangePasswordOn": ["Change Password of ", "Ändra Lösenord på "], - "ChangePassword": ["Change Password", "Ändra Lösenord"], - "OldPassword": ["Old Password", "Gammalt Lösenord"], - "NewPassword": ["New Password", "Nytt Lösenord"], - "ConfirmNewPassword": ["Confirm new Password", "Bekräfta nytt Lösenord"], - "PasswordDoNotMatch": [ - "Passwords does not match", - "Lösenorden matchar inte" - ], - "PasswordWasChanged": [ - "Your password was successfully changed", - "Ditt lösenord har bytts" - ], - "SomethingWentWrongWhenChangingPassword": [ - "Something went wrong when trying to change your password", - "Någonting gick fel när lösenordet försöktes byta" - ] -} diff --git a/frontend/src/use-cases/me/screens/me-change-password/index.js b/frontend/src/use-cases/me/screens/me-change-password/index.js deleted file mode 100644 index 9c14d20c8..000000000 --- a/frontend/src/use-cases/me/screens/me-change-password/index.js +++ /dev/null @@ -1,2 +0,0 @@ -import MeChangePassword from "./MeChangePassword.screen"; -export default MeChangePassword; diff --git a/frontend/src/use-cases/me/screens/me-crud/MeCRUD.screen.jsx b/frontend/src/use-cases/me/screens/me-crud/MeCRUD.screen.jsx deleted file mode 100644 index 43503774c..000000000 --- a/frontend/src/use-cases/me/screens/me-crud/MeCRUD.screen.jsx +++ /dev/null @@ -1,159 +0,0 @@ -import React, { useContext } from "react"; -import { - initialValues, - keysOrder, - keysText, - validationSchema -} from "../../Me.options"; -import { - generateUserCustomDetailsRenders, - generateUserEditComponentData -} from "../../../../common/utils/generators/user-form.generator"; -import { editMe } from "../../../../api/me/put.me.api"; -import { - DigitButton, - DigitCRUD, - DigitLayout, - DigitTextField, - useDigitTranslations -} from "@cthit/react-digit-components"; -import { deleteMe } from "../../../../api/me/delete.me.api"; -import { - USER_FIRST_NAME, - USER_LAST_NAME, - USER_NICK, - USER_PASSWORD -} from "../../../../api/users/props.users.api"; -import * as yup from "yup"; -import InsufficientAccess from "../../../../common/views/insufficient-access"; -import FourOFour from "../../../four-o-four"; -import FiveZeroZero from "../../../../app/elements/five-zero-zero"; -import translations from "./MeCRUD.screen.translations"; -import GammaUserContext from "../../../../common/context/GammaUser.context"; -import { Link, useHistory } from "react-router-dom"; -import styled from "styled-components"; - -const NoStyleLink = styled(Link)` - color: inherit; - text-decoration: none; - display: flex; - justify-content: center; -`; - -const UserImage = styled.img` - width: 250px; - max-height: 500px; - margin: auto; -`; - -const MeCRUD = () => { - const [text] = useDigitTranslations(translations); - const [user, update] = useContext(GammaUserContext); - const history = useHistory(); - - const fullName = data => - data[USER_FIRST_NAME] + - " '" + - data[USER_NICK] + - "' " + - data[USER_LAST_NAME]; - - if (user == null) { - return null; - } - return ( - - new Promise(resolve => { - resolve({ data: user }); - }) - } - updateRequest={(id, newData) => - new Promise((resolve, reject) => - editMe(newData) - .then(response => { - resolve(response); - update().then(() => { - history.push("/me"); - }); - }) - .catch(error => reject(error)) - ) - } - detailsRenderCardStart={data => ( - <> - - - - - - - - - - - - - - )} - customDetailsRenders={generateUserCustomDetailsRenders(text, true)} - detailsTitle={data => text.YourInformation} - updateTitle={data => fullName(data)} - deleteRequest={(_, form) => - deleteMe(form).then(() => { - window.location.reload(); - }) - } - dialogDeleteTitle={() => text.AreYouSure} - dialogDeleteDescription={() => text.AreYouReallySure} - dialogDeleteConfirm={() => text.Delete} - dialogDeleteCancel={() => text.Cancel} - deleteDialogFormKeysOrder={[USER_PASSWORD]} - deleteDialogFormValidationSchema={() => - yup.object().shape({ - password: yup - .string() - .min(8) - .required(text.YouMustEnterPassword) - }) - } - deleteDialogFormInitialValues={{ password: "" }} - deleteDialogFormComponentData={{ - password: { - component: DigitTextField, - componentProps: { - upperLabel: text.Password, - password: true, - outlined: true - } - } - }} - statusRenders={{ - 403: () => , - 404: () => , - 500: (error, reset) => - }} - backButtonText={text.Back} - deleteButtonText={() => text.DeleteMe} - updateButtonText={() => text.EditMe} - toastUpdateSuccessful={() => text.UpdateMe} - toastUpdateFailed={() => text.UpdateMeFailed} - /> - ); -}; - -export default MeCRUD; diff --git a/frontend/src/use-cases/me/screens/me-crud/MeCRUD.screen.translations.json b/frontend/src/use-cases/me/screens/me-crud/MeCRUD.screen.translations.json deleted file mode 100644 index d8b88f814..000000000 --- a/frontend/src/use-cases/me/screens/me-crud/MeCRUD.screen.translations.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "Cid": ["Cid", "Cid"], - "FirstName": ["First name", "Förnamn"], - "LastName": ["Last name", "Efternamn"], - "Nick": ["Nick", "Nick"], - "Email": ["Email", "Email"], - "AcceptanceYear": ["Acceptance Year", "Antagningsår"], - "CreatedAt": ["Account created at", "Konto skapat"], - "LastModifiedAt": ["Account last modified at", "Konto senast uppdaterat"], - "Edit": ["Edit account", "Redigera konto"], - "ChangePassword": ["Change Password", "Ändra Lösenord"], - "Language": ["Language", "Språk"], - "LanguageLowerLabel": ["Your preferred language", "Din föredragna språk"], - "AcceptanceYearLowerLabel": ["When you started IT", "När du började IT"], - "Password": ["Your password", "Ditt lösenord"], - "AreYouReallySure": [ - "Are you really sure you want to permanently delete your own account. This action is irreversibel.", - "Är du säker att du verkligen vill radera ditt konto permanent? Denna återgärd är oåterkallelig." - ], - "YouMustEnterPassword": [ - "You need to confirm your password to be able to delete your account", - "Du måste bekräfta ditt lösenord för att kunna radera ditt konto" - ], - "YourGroups": ["Your groups", "Dina grupper"], - "ChangeAvatar": ["Change avatar image", "Ändra avatar bild"], - "Phone": ["Phone number", "Telefonnummer"], - "DeleteMe": ["Delete my account", "Radera mitt konto"], - "UpdateMe": [ - "You have updated your account", - "Du har uppdaterat ditt konto" - ], - "UpdateMeFailed": [ - "Something went wrong when updating your account", - "Någonting gick fel när du försökte uppdatera ditt konto" - ], - "EditMe": ["Edit your information", "Redigera dina uppgifter"], - "YourInformation": ["Your information", "Din information"], - "YourApprovals": ["Your client approvals", "Dina klient godkännanden"] -} diff --git a/frontend/src/use-cases/me/screens/me-crud/index.js b/frontend/src/use-cases/me/screens/me-crud/index.js deleted file mode 100644 index 8020a5a8e..000000000 --- a/frontend/src/use-cases/me/screens/me-crud/index.js +++ /dev/null @@ -1,2 +0,0 @@ -import MeCRUD from "./MeCRUD.screen"; -export default MeCRUD; diff --git a/frontend/src/use-cases/me/screens/me-groups/MeGroups.screen.jsx b/frontend/src/use-cases/me/screens/me-groups/MeGroups.screen.jsx deleted file mode 100644 index 3e7cae49a..000000000 --- a/frontend/src/use-cases/me/screens/me-groups/MeGroups.screen.jsx +++ /dev/null @@ -1,73 +0,0 @@ -import React, { useMemo } from "react"; -import { - DigitText, - DigitLayout, - useDigitTranslations -} from "@cthit/react-digit-components"; -import translations from "./MeGroups.screen.translations"; -import DisplayGroupsTable from "../../../../common/elements/display-groups-table/DisplayGroupsTable.element"; -import useGammaUser from "../../../../common/hooks/use-gamma-user/useGammaUser"; - -const MeGroups = () => { - const [text] = useDigitTranslations(translations); - const user = useGammaUser(); - - const [activeGroups, pastGroups, futureGroups] = useMemo(() => { - const now = new Date().getTime(); - - return user == null - ? [[], [], []] - : [ - user.groups.filter(g => g.active), - user.groups.filter(g => !g.active && g.becomesActive <= now), - user.groups.filter(g => !g.active && g.becomesActive > now) - ]; - }, [user]); - - if (user == null) { - return null; - } - - if ( - activeGroups.length === 0 && - pastGroups.length === 0 && - futureGroups.length === 0 - ) { - return ( - - - - ); - } - - return ( - - {futureGroups.length > 0 && ( - - )} - {activeGroups.length > 0 && ( - 0 ? { top: "16px" } : {}} - title={text.ActiveGroups} - groups={activeGroups} - /> - )} - {pastGroups.length > 0 && ( - 0 || activeGroups.length > 0 - ? { top: "16px" } - : {} - } - title={text.PastGroups} - groups={pastGroups} - /> - )} - - ); -}; - -export default MeGroups; diff --git a/frontend/src/use-cases/me/screens/me-groups/MeGroups.screen.translations.json b/frontend/src/use-cases/me/screens/me-groups/MeGroups.screen.translations.json deleted file mode 100644 index 37413e51a..000000000 --- a/frontend/src/use-cases/me/screens/me-groups/MeGroups.screen.translations.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "ActiveGroups": ["Your active groups", "Dina aktiva grupper"], - "NoActiveGroups": ["No active groups", "Inga aktiva grupper"], - "PastGroups": ["Your past groups", "Dina gamla grupper"], - "NoPastGroups": ["No past groups", "Inga gamla grupper"], - "NoGroupsForYou": [ - "You have no groups.... yet ;)", - "Du har inga grupper... än ;)" - ], - "FutureGroups": [ - "Future groups (Not active yet)", - "Framtida grupper (Inte aktiv än)" - ] -} diff --git a/frontend/src/use-cases/me/screens/me-groups/index.js b/frontend/src/use-cases/me/screens/me-groups/index.js deleted file mode 100644 index 4c0ffd877..000000000 --- a/frontend/src/use-cases/me/screens/me-groups/index.js +++ /dev/null @@ -1,2 +0,0 @@ -import MeGroups from "./MeGroups.screen"; -export default MeGroups; diff --git a/frontend/src/use-cases/members/Members.jsx b/frontend/src/use-cases/members/Members.jsx deleted file mode 100644 index c255ab46e..000000000 --- a/frontend/src/use-cases/members/Members.jsx +++ /dev/null @@ -1,140 +0,0 @@ -import React, { useEffect, useState } from "react"; -import { - DigitStepper, - DigitLayout, - useDigitTranslations, - DigitLoading -} from "@cthit/react-digit-components"; -import { Route, Switch, useHistory, useLocation } from "react-router-dom"; -import { GROUP_NAME } from "../../api/groups/props.groups.api"; -import InsufficientAccess from "../../common/views/insufficient-access"; -import translations from "./Members.translations"; -import SetPostNames from "./views/set-post-names"; -import ReviewChanges from "./views/review-changes"; -import SelectMembers from "./views/select-members"; -import { getPosts } from "../../api/posts/get.posts.api"; -import { getUsersMinified } from "../../api/users/get.users.api"; -import { getGroup } from "../../api/groups/get.groups.api"; -import useGammaIsAdmin from "../../common/hooks/use-gamma-is-admin/useGammaIsAdmin"; - -const Members = () => { - const history = useHistory(); - const location = useLocation(); - const [text] = useDigitTranslations(translations); - const groupId = location.pathname.split("/")[2]; - const [selectedMemberIds, setSelectedMemberIds] = useState(null); - const [newMembersData, setNewMembersData] = useState(null); - const [group, setGroup] = useState(null); - const [users, setUsers] = useState(null); - const [posts, setPosts] = useState(null); - - const admin = useGammaIsAdmin(); - - useEffect(() => { - if (admin) { - Promise.all([ - getPosts(), - getUsersMinified(), - getGroup(groupId) - ]).then(response => { - if (response.length === 3) { - setPosts(response[0].data); - setUsers(response[1].data); - setGroup(response[2].data); - } - }); - } - }, [admin, groupId]); - - const route = location.pathname; - const step = route.endsWith("/posts") - ? 1 - : route.endsWith("/review") - ? 2 - : 0; //Ends with members - - useEffect(() => { - //turn into effect instead - if (step > 0 && selectedMemberIds == null) { - history.push("/members/" + groupId); - } - }, [step, selectedMemberIds, groupId, history]); - - const onMembersSelected = selectedMembers => { - setSelectedMemberIds(selectedMembers); - history.push("/members/" + groupId + "/posts"); - }; - - if (!admin) { - return ; - } - - if (group == null || users == null || posts == null) { - return ; - } - - return ( - - - - - ( - - )} - /> - ( - { - setNewMembersData(value.members); - history.push("/members/" + groupId + "/review"); - }} - /> - )} - /> - ( - { - history.push("/groups"); - history.push("/groups/" + group.id); - }} - /> - )} - /> - - - ); -}; -export default Members; diff --git a/frontend/src/use-cases/members/Members.translations.json b/frontend/src/use-cases/members/Members.translations.json deleted file mode 100644 index 3e5f3db98..000000000 --- a/frontend/src/use-cases/members/Members.translations.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "SelectMembers": ["Select members", "Välj medlemmar"], - "SetPostNames": ["Set post names", "Sätt postnamn"], - "ReviewChanges": ["Review changes", "Granska ändringar"] -} diff --git a/frontend/src/use-cases/members/index.js b/frontend/src/use-cases/members/index.js deleted file mode 100644 index b14abd439..000000000 --- a/frontend/src/use-cases/members/index.js +++ /dev/null @@ -1,2 +0,0 @@ -import Members from "./Members"; -export default Members; diff --git a/frontend/src/use-cases/members/views/review-changes/ReviewChanges.view.jsx b/frontend/src/use-cases/members/views/review-changes/ReviewChanges.view.jsx deleted file mode 100644 index 07481e24e..000000000 --- a/frontend/src/use-cases/members/views/review-changes/ReviewChanges.view.jsx +++ /dev/null @@ -1,159 +0,0 @@ -import React, { useEffect } from "react"; -import Save from "@material-ui/icons/Save"; -import { - DigitLayout, - DigitDesign, - useDigitTranslations, - DigitButton, - DigitText, - useDigitToast -} from "@cthit/react-digit-components"; -import * as _ from "lodash"; -import translations from "./ReviewChanges.view.translations"; -import { editUserInGroup } from "../../../../api/groups/put.groups.api"; -import { removeUserFromGroup } from "../../../../api/groups/delete.groups.api"; -import { addUserToGroup } from "../../../../api/groups/post.groups.api"; -import { useHistory } from "react-router-dom"; -import DisplayMembersTable from "../../../../common/elements/display-members-table"; - -function getAdditions(previousMembers, newMembers) { - return newMembers.filter( - newMember => _.findIndex(previousMembers, ["id", newMember.id]) === -1 - ); -} - -function getDeletions(previousMembers, newMembers) { - return previousMembers.filter( - previousMember => - _.findIndex(newMembers, ["id", previousMember.id]) === -1 - ); -} - -function getEdits(previousMembers, newMembers) { - return _.intersectionWith( - previousMembers, - newMembers, - (previousMember, newMember) => previousMember.id === newMember.id - ); -} - -const save = ( - previousMembers, - newMembersData, - groupId, - onFinished, - queueToast, - text -) => { - const additions = getAdditions(previousMembers, newMembersData).map( - member => - addUserToGroup(groupId, { - userId: member.id, - post: member.postId, - unofficialName: member.unofficialPostName - }) - ); - - const deletions = getDeletions( - previousMembers, - newMembersData - ).map(previousMember => removeUserFromGroup(groupId, previousMember.id)); - - const edits = getEdits(previousMembers, newMembersData).map(member => { - const newMemberData = _.find(newMembersData, { id: member.id }); - - return editUserInGroup(groupId, member.id, { - userId: newMemberData.id, - post: newMemberData.postId, - unofficialName: newMemberData.unofficialPostName - }); - }); - - Promise.all([...additions, ...deletions, ...edits]) - .then(() => { - onFinished(); - queueToast({ - text: text.MembersSaved - }); - }) - .catch(e => { - queueToast({ - text: text.MembersError - }); - console.log(e); - }); -}; - -const ReviewChanges = ({ - groupName, - previousMembers, - groupId, - posts, - onFinished, - newMembersData -}) => { - const [queueToast] = useDigitToast(); - const [text] = useDigitTranslations(translations); - const history = useHistory(); - - useEffect(() => { - if (newMembersData == null) { - history.push("/members/" + groupId); - } - }, [newMembersData, history, groupId]); - - return ( - <> - - - - - - history.goBack()} - /> - - save( - previousMembers, - newMembersData, - groupId, - onFinished, - queueToast, - text - ) - } - startIcon={} - raised - primary - /> - - - - - ({ - ...member, - post: _.find(posts, { id: member.postId }), - unofficialPostName: member.unofficialPostName - }))} - noUsersText={text.NoUsers} - /> - - ); -}; - -export default ReviewChanges; diff --git a/frontend/src/use-cases/members/views/review-changes/ReviewChanges.view.translations.json b/frontend/src/use-cases/members/views/review-changes/ReviewChanges.view.translations.json deleted file mode 100644 index c34816b70..000000000 --- a/frontend/src/use-cases/members/views/review-changes/ReviewChanges.view.translations.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "NewMembersForGroup": [ - "New members for the group", - "Nya medlemmar för gruppen" - ], - "NoUsers": ["No users selected", "Inga användare valda"], - "MembersSaved": ["Members saved", "Medlemmarna sparade"], - "MembersError": [ - "Something went wrong when saving the members", - "Någonting gick fel när medlemmarna försökter sparas" - ] -} diff --git a/frontend/src/use-cases/members/views/review-changes/elements/new-member/NewMember.element.jsx b/frontend/src/use-cases/members/views/review-changes/elements/new-member/NewMember.element.jsx deleted file mode 100644 index 140ea9246..000000000 --- a/frontend/src/use-cases/members/views/review-changes/elements/new-member/NewMember.element.jsx +++ /dev/null @@ -1,28 +0,0 @@ -import React from "react"; - -import { DigitText } from "@cthit/react-digit-components"; - -const NewMember = ({ - firstName, - lastName, - nick, - unofficialPostName, - post = {}, - activeLanguage -}) => ( - -); - -export default NewMember; diff --git a/frontend/src/use-cases/members/views/review-changes/elements/new-member/index.js b/frontend/src/use-cases/members/views/review-changes/elements/new-member/index.js deleted file mode 100644 index 97f3aa1e0..000000000 --- a/frontend/src/use-cases/members/views/review-changes/elements/new-member/index.js +++ /dev/null @@ -1,2 +0,0 @@ -import NewMember from "./NewMember.element"; -export default NewMember; diff --git a/frontend/src/use-cases/members/views/review-changes/index.js b/frontend/src/use-cases/members/views/review-changes/index.js deleted file mode 100644 index a63067191..000000000 --- a/frontend/src/use-cases/members/views/review-changes/index.js +++ /dev/null @@ -1,2 +0,0 @@ -import ReviewChanges from "./ReviewChanges.view"; -export default ReviewChanges; diff --git a/frontend/src/use-cases/members/views/select-members/SelectMembers.view.jsx b/frontend/src/use-cases/members/views/select-members/SelectMembers.view.jsx deleted file mode 100644 index d40daa832..000000000 --- a/frontend/src/use-cases/members/views/select-members/SelectMembers.view.jsx +++ /dev/null @@ -1,116 +0,0 @@ -import React, { useMemo, useState } from "react"; -import { - DigitButton, - DigitSelectMultipleTable, - DigitText, - DigitLayout, - DigitDesign, - useDigitTranslations -} from "@cthit/react-digit-components"; -import translations from "./SelectMembers.view.translations"; -import UsersInGroupChanges from "./elements/users-in-group-changes"; -import * as _ from "lodash"; -import { GROUP_PRETTY_NAME } from "../../../../api/groups/props.groups.api"; -import { - USER_FIRST_NAME, - USER_ID, - USER_LAST_NAME, - USER_NICK -} from "../../../../api/users/props.users.api"; -import styled from "styled-components"; - -const Table = styled.div` - display: grid; - grid-template-columns: min-content auto; - grid-auto-rows: min-content; - grid-gap: 1rem; - - @media (max-width: 600px) { - grid-template-columns: auto; - } -`; - -const SpannedCard = styled(DigitDesign.Card)` - @media (min-width: 600px) { - grid-column-start: 1; - grid-column-end: 3; - } -`; - -const generateHeaderTexts = text => { - const headerTexts = {}; - - headerTexts[USER_FIRST_NAME] = text.FirstName; - headerTexts[USER_LAST_NAME] = text.LastName; - headerTexts[USER_NICK] = text.Nickname; - headerTexts[USER_ID] = text.Id; - - return headerTexts; -}; - -const SelectMembers = ({ users, group, onMembersSelected }) => { - const [text] = useDigitTranslations(translations); - const [selectedMemberIds, setSelectedMemberIds] = useState( - group.groupMembers.map(member => member.id) - ); - - const unsavedEdits = useMemo( - () => selectedMemberIds.length !== group.groupMembers.length, - [selectedMemberIds, group.groupMembers] - ); - - return ( - - - - - - { - onMembersSelected(selectedMemberIds); - }} - /> - - - - - _.find(users, { id: memberId }) - )} - /> - { - setSelectedMemberIds(newSelected); - }} - search - titleText={text.UsersFor + group[GROUP_PRETTY_NAME]} - searchText={text.Search} - idProp="id" - startOrderBy={USER_NICK} - columnsOrder={[USER_FIRST_NAME, USER_NICK, USER_LAST_NAME]} - headerTexts={generateHeaderTexts(text)} - data={users} - /> -
- ); -}; - -export default SelectMembers; diff --git a/frontend/src/use-cases/members/views/select-members/SelectMembers.view.translations.json b/frontend/src/use-cases/members/views/select-members/SelectMembers.view.translations.json deleted file mode 100644 index 7468b57c7..000000000 --- a/frontend/src/use-cases/members/views/select-members/SelectMembers.view.translations.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "FirstName": ["First name", "Förnamn"], - "LastName": ["Last name", "Efternamn"], - "Id": ["Id", "Id"], - "Checkbox": ["Choose users", "Välj användare"], - "UsersFor": ["Users for ", "Användare för "], - "Link": ["Details", "Detaljer"], - "UnsavedEdits": ["You have unsaved edits", "Du har osparade ändringar"], - "Nickname": ["Nickname", "Nick"], - "NoChanges": ["You have no changes", "Du har inga ändringar"], - "Next": ["Next", "Nästa"], - "PostName": ["Post name", "Postnamn"] -} diff --git a/frontend/src/use-cases/members/views/select-members/elements/users-in-group-changes/UsersInGroupChanges.element.jsx b/frontend/src/use-cases/members/views/select-members/elements/users-in-group-changes/UsersInGroupChanges.element.jsx deleted file mode 100644 index ebcc42bcb..000000000 --- a/frontend/src/use-cases/members/views/select-members/elements/users-in-group-changes/UsersInGroupChanges.element.jsx +++ /dev/null @@ -1,54 +0,0 @@ -import React from "react"; - -import { - DigitDesign, - DigitText, - useDigitTranslations -} from "@cthit/react-digit-components"; -import MemberCurrent from "./sub-elements/member-current"; -import * as _ from "lodash"; -import MemberAddition from "./sub-elements/member-addition"; -import MemberDeletion from "./sub-elements/member-deletion"; -import translations from "./UsersInGroupChanges.element.translations"; - -function findAdditions(currentMembers, selectedMembers) { - return selectedMembers.filter( - member => _.find(currentMembers, { id: member.id }) == null - ); -} - -function findDeletions(currentMembers, selectedMembers) { - return currentMembers.filter( - member => _.find(selectedMembers, { id: member.id }) == null - ); -} - -const UsersInGroupChanges = ({ currentMembers, selectedMembers }) => { - const [text] = useDigitTranslations(translations); - - return ( - - - - {currentMembers.map(member => ( - - ))} - - {findAdditions(currentMembers, selectedMembers).map(member => ( - - ))} - - {findDeletions(currentMembers, selectedMembers).map(member => ( - - ))} - - - ); -}; - -UsersInGroupChanges.defaultProps = { - currentMembers: [], - selectedMembers: [] -}; - -export default UsersInGroupChanges; diff --git a/frontend/src/use-cases/members/views/select-members/elements/users-in-group-changes/UsersInGroupChanges.element.translations.json b/frontend/src/use-cases/members/views/select-members/elements/users-in-group-changes/UsersInGroupChanges.element.translations.json deleted file mode 100644 index a5349f6dc..000000000 --- a/frontend/src/use-cases/members/views/select-members/elements/users-in-group-changes/UsersInGroupChanges.element.translations.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "Current": ["Current", "Nurvarande"], - "Additions": ["Additions", "Tillägg"], - "Deletions": ["Deletions", "Borttagningar"] -} diff --git a/frontend/src/use-cases/members/views/select-members/elements/users-in-group-changes/index.js b/frontend/src/use-cases/members/views/select-members/elements/users-in-group-changes/index.js deleted file mode 100644 index 03b401ad4..000000000 --- a/frontend/src/use-cases/members/views/select-members/elements/users-in-group-changes/index.js +++ /dev/null @@ -1,2 +0,0 @@ -import UsersInGroupChanges from "./UsersInGroupChanges.element"; -export default UsersInGroupChanges; diff --git a/frontend/src/use-cases/members/views/select-members/elements/users-in-group-changes/sub-elements/member-addition/MemberAddition.element.jsx b/frontend/src/use-cases/members/views/select-members/elements/users-in-group-changes/sub-elements/member-addition/MemberAddition.element.jsx deleted file mode 100644 index 8b8d04272..000000000 --- a/frontend/src/use-cases/members/views/select-members/elements/users-in-group-changes/sub-elements/member-addition/MemberAddition.element.jsx +++ /dev/null @@ -1,22 +0,0 @@ -import React from "react"; - -import { DigitText } from "@cthit/react-digit-components"; -import { - USER_FIRST_NAME, - USER_LAST_NAME, - USER_NICK -} from "../../../../../../../../api/users/props.users.api"; - -const MemberAddition = ({ member }) => ( - -); - -export default MemberAddition; diff --git a/frontend/src/use-cases/members/views/select-members/elements/users-in-group-changes/sub-elements/member-addition/index.js b/frontend/src/use-cases/members/views/select-members/elements/users-in-group-changes/sub-elements/member-addition/index.js deleted file mode 100644 index 1c9188695..000000000 --- a/frontend/src/use-cases/members/views/select-members/elements/users-in-group-changes/sub-elements/member-addition/index.js +++ /dev/null @@ -1,2 +0,0 @@ -import MemberAddition from "./MemberAddition.element"; -export default MemberAddition; diff --git a/frontend/src/use-cases/members/views/select-members/elements/users-in-group-changes/sub-elements/member-current/MemberCurrent.element.jsx b/frontend/src/use-cases/members/views/select-members/elements/users-in-group-changes/sub-elements/member-current/MemberCurrent.element.jsx deleted file mode 100644 index 2532113a2..000000000 --- a/frontend/src/use-cases/members/views/select-members/elements/users-in-group-changes/sub-elements/member-current/MemberCurrent.element.jsx +++ /dev/null @@ -1,28 +0,0 @@ -import React from "react"; - -import { DigitLayout, DigitText } from "@cthit/react-digit-components"; -import { - USER_FIRST_NAME, - USER_LAST_NAME, - USER_NICK -} from "../../../../../../../../api/users/props.users.api"; - -const MemberCurrent = ({ member }) => ( - - - -); - -MemberCurrent.defaultProps = { - members: [] -}; - -export default MemberCurrent; diff --git a/frontend/src/use-cases/members/views/select-members/elements/users-in-group-changes/sub-elements/member-current/index.js b/frontend/src/use-cases/members/views/select-members/elements/users-in-group-changes/sub-elements/member-current/index.js deleted file mode 100644 index 83dd68a4f..000000000 --- a/frontend/src/use-cases/members/views/select-members/elements/users-in-group-changes/sub-elements/member-current/index.js +++ /dev/null @@ -1,2 +0,0 @@ -import MemberCurrent from "./MemberCurrent.element"; -export default MemberCurrent; diff --git a/frontend/src/use-cases/members/views/select-members/elements/users-in-group-changes/sub-elements/member-deletion/MemberDeletion.element.jsx b/frontend/src/use-cases/members/views/select-members/elements/users-in-group-changes/sub-elements/member-deletion/MemberDeletion.element.jsx deleted file mode 100644 index a15d5c74b..000000000 --- a/frontend/src/use-cases/members/views/select-members/elements/users-in-group-changes/sub-elements/member-deletion/MemberDeletion.element.jsx +++ /dev/null @@ -1,22 +0,0 @@ -import React from "react"; - -import { DigitText } from "@cthit/react-digit-components"; -import { - USER_FIRST_NAME, - USER_LAST_NAME, - USER_NICK -} from "../../../../../../../../api/users/props.users.api"; - -const MemberDeletion = ({ member }) => ( - -); - -export default MemberDeletion; diff --git a/frontend/src/use-cases/members/views/select-members/elements/users-in-group-changes/sub-elements/member-deletion/index.js b/frontend/src/use-cases/members/views/select-members/elements/users-in-group-changes/sub-elements/member-deletion/index.js deleted file mode 100644 index c56f29519..000000000 --- a/frontend/src/use-cases/members/views/select-members/elements/users-in-group-changes/sub-elements/member-deletion/index.js +++ /dev/null @@ -1,2 +0,0 @@ -import MemberDeletion from "./MemberDeletion.element"; -export default MemberDeletion; diff --git a/frontend/src/use-cases/members/views/select-members/index.js b/frontend/src/use-cases/members/views/select-members/index.js deleted file mode 100644 index 915ea734b..000000000 --- a/frontend/src/use-cases/members/views/select-members/index.js +++ /dev/null @@ -1,2 +0,0 @@ -import SelectMembers from "./SelectMembers.view"; -export default SelectMembers; diff --git a/frontend/src/use-cases/members/views/set-post-names/SetPostNames.view.jsx b/frontend/src/use-cases/members/views/set-post-names/SetPostNames.view.jsx deleted file mode 100644 index f0eb54e85..000000000 --- a/frontend/src/use-cases/members/views/set-post-names/SetPostNames.view.jsx +++ /dev/null @@ -1,136 +0,0 @@ -import React from "react"; -import translations from "./SetPostNames.view.translations.json"; -import { - DigitButton, - DigitDesign, - DigitForm, - DigitLayout, - DigitText, - useDigitTranslations -} from "@cthit/react-digit-components"; -import NewMembershipArray from "./sub-views/new-membership-array"; -import _ from "lodash"; -import * as yup from "yup"; -import { - USER_ACCEPTANCE_YEAR, - USER_CID, - USER_FIRST_NAME, - USER_ID, - USER_LAST_NAME, - USER_NICK -} from "../../../../api/users/props.users.api"; -import { useHistory } from "react-router-dom"; -import Save from "@material-ui/icons/Save"; - -function getInitialValues(selectedMemberIds, currentMembers, users) { - const necessaryMembersData = selectedMemberIds.map(selectedMember => { - const user = _.find(users, { id: selectedMember }); - - const necessaryMemberData = {}; - necessaryMemberData[USER_FIRST_NAME] = user[USER_FIRST_NAME]; - necessaryMemberData[USER_LAST_NAME] = user[USER_LAST_NAME]; - necessaryMemberData[USER_NICK] = user[USER_NICK]; - necessaryMemberData[USER_CID] = user[USER_CID]; - necessaryMemberData[USER_ACCEPTANCE_YEAR] = user[USER_ACCEPTANCE_YEAR]; - necessaryMemberData[USER_ID] = user[USER_ID]; - - const previousMemberData = _.find(currentMembers, { id: user.id }); - - var postId = ""; - var unofficialPostName = ""; - - if (previousMemberData != null) { - postId = previousMemberData.post.id; - unofficialPostName = previousMemberData.unofficialPostName; - } - - necessaryMemberData.postId = postId; - necessaryMemberData.unofficialPostName = unofficialPostName; - - return necessaryMemberData; - }); - - return { - members: necessaryMembersData - }; -} - -const SetPostNames = ({ - selectedMemberIds, - groupId, - posts, - currentMembers, - users, - onNewMembers -}) => { - const [text] = useDigitTranslations(translations); - const history = useHistory(); - - return ( - ( - <> - - - - - - history.goBack()} - /> - } - raised - primary - submit - disabled={!isValid} - /> - - - - - - - {selectedMemberIds.length === 0 && ( - - )} - - - - - )} - /> - ); -}; - -export default SetPostNames; diff --git a/frontend/src/use-cases/members/views/set-post-names/SetPostNames.view.translations.json b/frontend/src/use-cases/members/views/set-post-names/SetPostNames.view.translations.json deleted file mode 100644 index 650362627..000000000 --- a/frontend/src/use-cases/members/views/set-post-names/SetPostNames.view.translations.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "SetPostNames": ["Set posts", "Bestäm poster"], - "NoSelectedMembers": [ - "No members are selected for this group", - "Inga medlemmar valda för denna grupp" - ], - "Post": ["Post", "Post"], - "UnofficialPostName": ["Unofficial post name", "Inofficiellt post namn"] -} diff --git a/frontend/src/use-cases/members/views/set-post-names/index.js b/frontend/src/use-cases/members/views/set-post-names/index.js deleted file mode 100644 index 52c3b028a..000000000 --- a/frontend/src/use-cases/members/views/set-post-names/index.js +++ /dev/null @@ -1,2 +0,0 @@ -import SetPostNames from "./SetPostNames.view"; -export default SetPostNames; diff --git a/frontend/src/use-cases/members/views/set-post-names/sub-views/create-membership/CreateMembership.view.jsx b/frontend/src/use-cases/members/views/set-post-names/sub-views/create-membership/CreateMembership.view.jsx deleted file mode 100644 index 25e1ff925..000000000 --- a/frontend/src/use-cases/members/views/set-post-names/sub-views/create-membership/CreateMembership.view.jsx +++ /dev/null @@ -1,71 +0,0 @@ -import React from "react"; -import { - DigitTextField, - DigitText, - DigitSelect, - useDigitTranslations -} from "@cthit/react-digit-components"; -import translations from "./CreateMembership.view.translations"; -import { - USER_FIRST_NAME, - USER_LAST_NAME, - USER_NICK -} from "../../../../../../api/users/props.users.api"; -import styled from "styled-components"; - -const CustomRow = styled.div` - display: flex; - flex-direction: row; - margin-bottom: 16px; - align-items: baseline; - - @media (max-width: 600px) { - flex-direction: column; - align-self: center; - } -`; - -function getDifferentPostNames(posts, activeLanguage) { - const output = {}; - posts.forEach(post => { - output[post.id] = post[activeLanguage]; - }); - - return output; -} - -const CreateMembership = ({ posts, value, onChange, innerInputs }) => { - const [text, activeLanguage] = useDigitTranslations(translations); - - return ( - -
- -
- - -
- ); -}; - -export default CreateMembership; diff --git a/frontend/src/use-cases/members/views/set-post-names/sub-views/create-membership/CreateMembership.view.translations.json b/frontend/src/use-cases/members/views/set-post-names/sub-views/create-membership/CreateMembership.view.translations.json deleted file mode 100644 index f7072b3b1..000000000 --- a/frontend/src/use-cases/members/views/set-post-names/sub-views/create-membership/CreateMembership.view.translations.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "Post": ["Post", "Post"], - "UnofficialPostName": ["Unofficial post name", "Inofficiellt post namn"] -} diff --git a/frontend/src/use-cases/members/views/set-post-names/sub-views/create-membership/index.js b/frontend/src/use-cases/members/views/set-post-names/sub-views/create-membership/index.js deleted file mode 100644 index dfc046a78..000000000 --- a/frontend/src/use-cases/members/views/set-post-names/sub-views/create-membership/index.js +++ /dev/null @@ -1,2 +0,0 @@ -import CreateMembership from "./CreateMembership.view"; -export default CreateMembership; diff --git a/frontend/src/use-cases/members/views/set-post-names/sub-views/new-membership-array/NewMembershipArray.view.jsx b/frontend/src/use-cases/members/views/set-post-names/sub-views/new-membership-array/NewMembershipArray.view.jsx deleted file mode 100644 index d3ff468c5..000000000 --- a/frontend/src/use-cases/members/views/set-post-names/sub-views/new-membership-array/NewMembershipArray.view.jsx +++ /dev/null @@ -1,20 +0,0 @@ -import React from "react"; -import CreateMembership from "../create-membership"; -import { useDigitFormFieldArray } from "@cthit/react-digit-components"; - -const NewPostsArray = ({ posts }) => { - const { innerInputs, value } = useDigitFormFieldArray("members", { - inputs: ["postId", "unofficialPostName"] - }); - - return value.map((value, i) => ( - - )); -}; - -export default NewPostsArray; diff --git a/frontend/src/use-cases/members/views/set-post-names/sub-views/new-membership-array/NewMembershipArray.view.translations.json b/frontend/src/use-cases/members/views/set-post-names/sub-views/new-membership-array/NewMembershipArray.view.translations.json deleted file mode 100644 index 0967ef424..000000000 --- a/frontend/src/use-cases/members/views/set-post-names/sub-views/new-membership-array/NewMembershipArray.view.translations.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/frontend/src/use-cases/members/views/set-post-names/sub-views/new-membership-array/index.js b/frontend/src/use-cases/members/views/set-post-names/sub-views/new-membership-array/index.js deleted file mode 100644 index 4b9de9202..000000000 --- a/frontend/src/use-cases/members/views/set-post-names/sub-views/new-membership-array/index.js +++ /dev/null @@ -1,2 +0,0 @@ -import NewPostsArray from "./NewMembershipArray.view"; -export default NewPostsArray; diff --git a/frontend/src/use-cases/posts/Posts.jsx b/frontend/src/use-cases/posts/Posts.jsx deleted file mode 100644 index 2eb996f21..000000000 --- a/frontend/src/use-cases/posts/Posts.jsx +++ /dev/null @@ -1,177 +0,0 @@ -import React from "react"; -import { - DigitCRUD, - DigitText, - useDigitTranslations -} from "@cthit/react-digit-components"; -import translations from "./Posts.translations"; -import { getPost, getPosts, getPostUsage } from "../../api/posts/get.posts.api"; -import { addPost } from "../../api/posts/post.posts.api"; -import { deletePost } from "../../api/posts/delete.posts.api"; -import { - ENGLISH_LANGUAGE, - SWEDISH_LANGUAGE -} from "../../api/utils/commonProps"; -import { editPost } from "../../api/posts/put.posts.api"; -import InsufficientAccess from "../../common/views/insufficient-access"; -import DisplayGroupsTable from "../../common/elements/display-groups-table/DisplayGroupsTable.element"; -import { - GROUP_NAME, - GROUP_PRETTY_NAME -} from "../../api/groups/props.groups.api"; -import useGammaIsAdmin from "../../common/hooks/use-gamma-is-admin/useGammaIsAdmin"; -import FourOFour from "../four-o-four"; -import FiveZeroZero from "../../app/elements/five-zero-zero"; -import { - initialValues, - keysComponentData, - keysOrder, - keysText, - validationSchema -} from "./Posts.options"; -import { - POST_ENGLISH, - POST_ID, - POST_SWEDISH, - EMAIL_PREFIX -} from "../../api/posts/props.posts.api"; - -const Posts = () => { - const [text] = useDigitTranslations(translations); - - const admin = useGammaIsAdmin(); - if (!admin) { - return ; - } - - return ( - - editPost(id, { - post: { sv: data[POST_SWEDISH], en: data[POST_ENGLISH] }, - emailPrefix: data[EMAIL_PREFIX] - }) - } - createRequest={data => - addPost({ - post: { sv: data[POST_SWEDISH], en: data[POST_ENGLISH] }, - emailPrefix: data[EMAIL_PREFIX] - }) - } - readAllRequest={getPosts} - readOneRequest={id => Promise.all([getPost(id), getPostUsage(id)])} - createTitle={text.AddNewPost} - tableProps={{ - titleText: text.Posts, - startOrderBy: POST_SWEDISH, - search: true, - flex: "1", - startOrderByDirection: "asc", - size: { minWidth: "288px" }, - padding: "0px", - searchText: text.Search - }} - detailsButtonText={text.Details} - deleteRequest={deletePost} - idProp={POST_ID} - detailsRenderCardEnd={data => ( - <> - {(data.usages == null || data.usages.length) === 0 && ( - - )} - - )} - detailsRenderEnd={data => ( - <> - {data.usages != null && data.usages.length > 0 && ( - - )} - - )} - createButtonText={text.CreatePost} - backButtonText={text.Back} - updateButtonText={() => text.Update} - toastCreateSuccessful={data => - data[SWEDISH_LANGUAGE] + - "/" + - data[ENGLISH_LANGUAGE] + - " " + - text.WasCreatedSuccessfully - } - toastCreateFailed={() => text.FailedCreatingPostt} - toastDeleteSuccessful={data => - data[SWEDISH_LANGUAGE] + - "/" + - data[ENGLISH_LANGUAGE] + - " " + - text.WasDeletedSuccessfully - } - toastDeleteFailed={data => - text.PostDeletionFailed1 + - " " + - data[SWEDISH_LANGUAGE] + - "/" + - data[ENGLISH_LANGUAGE] + - " " + - text.PostDeletionFailed2 - } - toastUpdateSuccessful={data => - data[SWEDISH_LANGUAGE] + - "/" + - data[ENGLISH_LANGUAGE] + - " " + - text.WasUpdatedSuccessfully - } - toastUpdateFailed={data => - text.PostUpdateFailed1 + - " " + - data[SWEDISH_LANGUAGE] + - "/" + - data[ENGLISH_LANGUAGE] + - " " + - text.PostUpdateFailed2 - } - dialogDeleteCancel={() => text.Cancel} - dialogDeleteConfirm={() => text.Delete} - dialogDeleteTitle={() => text.AreYouSure} - dialogDeleteDescription={data => - text.AreYouSureYouWantToDelete + - " " + - data[SWEDISH_LANGUAGE] + - "/" + - data[ENGLISH_LANGUAGE] + - "?" - } - updateTitle={data => - text.Update + - " " + - data[SWEDISH_LANGUAGE] + - "/" + - data[ENGLISH_LANGUAGE] - } - deleteButtonText={() => text.DeletePost} - canDelete={data => !data.usages || data.usages.length === 0} - detailsTitle={() => text.Details} - statusRenders={{ - 403: () => , - 404: () => , - 500: (error, reset) => - }} - useHistoryGoBackOnBack - /> - ); -}; - -export default Posts; diff --git a/frontend/src/use-cases/posts/Posts.options.js b/frontend/src/use-cases/posts/Posts.options.js deleted file mode 100644 index e95f21d82..000000000 --- a/frontend/src/use-cases/posts/Posts.options.js +++ /dev/null @@ -1,80 +0,0 @@ -import * as yup from "yup"; -import { DigitTextField } from "@cthit/react-digit-components"; -import { - ENGLISH_LANGUAGE, - SWEDISH_LANGUAGE -} from "../../api/utils/commonProps"; -import { - EMAIL_PREFIX, - POST_ENGLISH, - POST_SWEDISH -} from "../../api/posts/props.posts.api"; - -export const validationSchema = text => { - const schema = {}; - - schema[POST_SWEDISH] = yup - .string() - .required(text.SwedishInput + text.IsRequired); - schema[POST_ENGLISH] = yup - .string() - .required(text.EnglishInput + text.IsRequired); - schema[EMAIL_PREFIX] = yup.string(); - - return yup.object().shape(schema); -}; - -export const initialValues = () => { - const output = {}; - - output[POST_SWEDISH] = ""; - output[POST_ENGLISH] = ""; - output[EMAIL_PREFIX] = ""; - - return output; -}; - -export const keysComponentData = text => { - const componentData = {}; - - componentData[SWEDISH_LANGUAGE] = { - component: DigitTextField, - componentProps: { - upperLabel: text.SwedishInput, - outlined: true, - maxLength: 50 - } - }; - - componentData[ENGLISH_LANGUAGE] = { - component: DigitTextField, - componentProps: { - upperLabel: text.EnglishInput, - outlined: true, - maxLength: 50 - } - }; - - componentData[EMAIL_PREFIX] = { - component: DigitTextField, - componentProps: { - upperLabel: text.EmailPrefix, - outlined: true, - maxLength: 20 - } - }; - - return componentData; -}; - -export const keysText = text => { - const keysText = {}; - - keysText[POST_SWEDISH] = text.Swedish; - keysText[POST_ENGLISH] = text.English; - keysText[EMAIL_PREFIX] = text.EmailPrefix; - - return keysText; -}; - -export const keysOrder = () => [POST_SWEDISH, POST_ENGLISH, EMAIL_PREFIX]; diff --git a/frontend/src/use-cases/posts/Posts.translations.json b/frontend/src/use-cases/posts/Posts.translations.json deleted file mode 100644 index 26cc82159..000000000 --- a/frontend/src/use-cases/posts/Posts.translations.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "AddNewPost": ["Add new post", "Lägg till ny post"], - "SwedishInput": ["Swedish post name", "Svenska post namnet"], - "EnglishInput": ["English post name", "Engelska post namnet"], - "CreatePost": ["Create post", "Skapa post"], - "PostAdded": ["Post added", "Post tillagd"], - "PostAlreadyExists": ["Post already exists", "Posten finns redan"], - "Posts": ["Posts", "Poster"], - "Usages": ["Group usages", "Gruppanvändningar"], - "NoUsages": [ - "This post isn't used by any group", - "Denna post används inte av någon grupp" - ], - "FailedCreatingPost": [ - "Failed to create post", - "Misslyckades att skapa post" - ], - "PostDeletionFailed1": [ - "Something went wrong when trying to delete the post", - "Någonting gick fel när posten" - ], - "PostDeletionFailed2": ["", "försökte raderas"], - "PostUpdateFailed1": [ - "Something went wrong when trying to update the post", - "Någonting gick fel när posten" - ], - "PostUpdateFailed2": ["", "försökte uppdateras"], - "DeletePost": ["Delete post", "Radera post"], - "EmailPrefix": ["Email prefix", "Mail prefix"] -} diff --git a/frontend/src/use-cases/posts/elements/display-post-usages/DisplayPostUsages.element.jsx b/frontend/src/use-cases/posts/elements/display-post-usages/DisplayPostUsages.element.jsx deleted file mode 100644 index 660c377ee..000000000 --- a/frontend/src/use-cases/posts/elements/display-post-usages/DisplayPostUsages.element.jsx +++ /dev/null @@ -1,24 +0,0 @@ -import React from "react"; - -import { DigitLayout, DigitText } from "@cthit/react-digit-components"; -import { - GROUP_ID, - GROUP_PRETTY_NAME -} from "../../../../api/groups/props.groups.api"; - -const DisplayPostUsages = ({ usages }) => ( - - {usages.map(usage => ( - - ))} - -); - -DisplayPostUsages.defaultProps = { - usages: [] -}; - -export default DisplayPostUsages; diff --git a/frontend/src/use-cases/posts/elements/display-post-usages/index.js b/frontend/src/use-cases/posts/elements/display-post-usages/index.js deleted file mode 100644 index bcdcbb7b0..000000000 --- a/frontend/src/use-cases/posts/elements/display-post-usages/index.js +++ /dev/null @@ -1,2 +0,0 @@ -import DisplayPostUsages from "./DisplayPostUsages.element"; -export default DisplayPostUsages; diff --git a/frontend/src/use-cases/posts/index.js b/frontend/src/use-cases/posts/index.js deleted file mode 100644 index b87be7119..000000000 --- a/frontend/src/use-cases/posts/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from "./Posts"; diff --git a/frontend/src/use-cases/reset-password/ResetPassword.jsx b/frontend/src/use-cases/reset-password/ResetPassword.jsx deleted file mode 100644 index cb4bbc6d4..000000000 --- a/frontend/src/use-cases/reset-password/ResetPassword.jsx +++ /dev/null @@ -1,29 +0,0 @@ -import React from "react"; -import { Route, Switch } from "react-router-dom"; -import ResetPasswordInitialize from "./screens/reset-password-initalize"; -import ResetPasswordFinish from "./screens/reset-password-finish"; -import ResetPasswordAdmin from "./screens/reset-password-admin"; - -const ResetPassword = () => { - return ( - - - - - - ); -}; - -export default ResetPassword; diff --git a/frontend/src/use-cases/reset-password/index.js b/frontend/src/use-cases/reset-password/index.js deleted file mode 100644 index 77a239af5..000000000 --- a/frontend/src/use-cases/reset-password/index.js +++ /dev/null @@ -1,2 +0,0 @@ -import ResetPassword from "./ResetPassword"; -export default ResetPassword; diff --git a/frontend/src/use-cases/reset-password/screens/reset-password-admin/ResetPasswordAdmin.screen.jsx b/frontend/src/use-cases/reset-password/screens/reset-password-admin/ResetPasswordAdmin.screen.jsx deleted file mode 100644 index 141652aec..000000000 --- a/frontend/src/use-cases/reset-password/screens/reset-password-admin/ResetPasswordAdmin.screen.jsx +++ /dev/null @@ -1,89 +0,0 @@ -import React, { useEffect, useState } from "react"; -import { - DigitLayout, - DigitEditDataCard, - DigitTextField, - useDigitTranslations, - useDigitToast -} from "@cthit/react-digit-components"; -import translations from "./ResetPasswordAdmin.screen.translations"; -import useGammaIsAdmin from "../../../../common/hooks/use-gamma-is-admin/useGammaIsAdmin"; -import InsufficientAccess from "../../../../common/views/insufficient-access"; -import { useHistory, useParams } from "react-router-dom"; -import { getUser } from "../../../../api/users/get.users.api"; -import * as yup from "yup"; -import { editPasswordAdmin } from "../../../../api/users/put.users.api"; - -const ResetPasswordAdmin = () => { - const [text] = useDigitTranslations(translations); - const admin = useGammaIsAdmin(); - const history = useHistory(); - const [queueToast] = useDigitToast(); - const [user, setUser] = useState(null); - const { id } = useParams(); - - useEffect(() => { - getUser(id).then(response => { - setUser(response.data); - }); - }, [id]); - - if (!admin) { - return ; - } - - if (user == null) { - return null; - } - - return ( - - { - editPasswordAdmin(user.id, { password }) - .then(() => { - queueToast({ - text: text.PasswordChanged - }); - actions.resetForm(); - history.goBack(); - }) - .catch(() => { - queueToast({ - text: text.SomethingWentWrong - }); - }); - }} - keysComponentData={{ - password: { - component: DigitTextField, - componentProps: { - upperLabel: text.NewPassword, - outlined: true - } - } - }} - extraButton={{ - text: text.Back, - outlined: true, - onClick: () => history.goBack() - }} - validationSchema={yup.object().shape({ - password: yup - .string() - .min(8, text.MinimumLength) - .required(text.FieldRequired) - })} - initialValues={{ - password: "" - }} - /> - - ); -}; - -export default ResetPasswordAdmin; diff --git a/frontend/src/use-cases/reset-password/screens/reset-password-admin/ResetPasswordAdmin.screen.translations.json b/frontend/src/use-cases/reset-password/screens/reset-password-admin/ResetPasswordAdmin.screen.translations.json deleted file mode 100644 index e070aa254..000000000 --- a/frontend/src/use-cases/reset-password/screens/reset-password-admin/ResetPasswordAdmin.screen.translations.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "ChangePassword": ["Change password", "Ändra lösenordet"], - "NewPassword": ["New password", "Nytt lösenord"], - "ChangePasswordFor": ["Change password for", "Ändra lösenord för"], - "PasswordChanged": ["Password successfully changed", "Lösenordet ändrades"] -} diff --git a/frontend/src/use-cases/reset-password/screens/reset-password-admin/index.js b/frontend/src/use-cases/reset-password/screens/reset-password-admin/index.js deleted file mode 100644 index c927312f6..000000000 --- a/frontend/src/use-cases/reset-password/screens/reset-password-admin/index.js +++ /dev/null @@ -1,2 +0,0 @@ -import ResetPasswordAdmin from "./ResetPasswordAdmin.screen"; -export default ResetPasswordAdmin; diff --git a/frontend/src/use-cases/reset-password/screens/reset-password-finish/ResetPasswordFinish.screen.jsx b/frontend/src/use-cases/reset-password/screens/reset-password-finish/ResetPasswordFinish.screen.jsx deleted file mode 100644 index 32f7b673f..000000000 --- a/frontend/src/use-cases/reset-password/screens/reset-password-finish/ResetPasswordFinish.screen.jsx +++ /dev/null @@ -1,150 +0,0 @@ -import React from "react"; -import { - DigitTextField, - useDigitTranslations, - DigitEditDataCard, - useDigitToast, - DigitDesign, - DigitText, - DigitLayout -} from "@cthit/react-digit-components"; -import * as yup from "yup"; -import translations from "./ResetPasswordFinish.screen.translations"; -import statusCode from "../../../../common/utils/formatters/statusCode.formatter"; -import statusMessage from "../../../../common/utils/formatters/statusMessage.formatter"; -import { resetPasswordFinalize } from "../../../../api/reset-password/put.reset-password"; -import { getBackendUrl } from "../../../../common/utils/configs/envVariablesLoader"; -import { useLocation } from "react-router-dom"; -import ChangeLanguageLocally from "../../../../common/views/change-language-locally"; - -const ResetPasswordFinish = () => { - const [text] = useDigitTranslations(translations); - const [queueToast] = useDigitToast(); - const { search } = useLocation(); - const accountLocked = search.includes("accountLocked=true"); - - return ( - - {accountLocked && ( - <> - - - - - - - - - - - )} - { - resetPasswordFinalize(values) - .then(() => { - actions.resetForm(); - actions.setSubmitting(false); - queueToast({ - text: text.Success, - duration: 5000 - }); - setTimeout(() => { - window.location.href = - getBackendUrl() + "/login"; - }, 5000); - }) - .catch(error => { - const code = statusCode(error); - const message = statusMessage(error); - let errorMessage = text.SomethingWentWrong; - if (code === 422) { - switch (message) { - case "CODE_OR_CID_IS_WRONG": - errorMessage = text.CodeOrCidIsWrong; - break; - case "TOO_SHORT_PASSWORD": - errorMessage = text.PasswordTooShort; - break; - default: - errorMessage = text.SomethingWentWrong; - } - } - queueToast({ - text: errorMessage, - duration: 5000 - }); - }); - }} - keysOrder={["cid", "token", "password", "passwordConfirmation"]} - keysComponentData={{ - cid: { - component: DigitTextField, - componentProps: { - upperLabel: text.Cid, - filled: false, - outlined: true, - maxLength: 15 - } - }, - token: { - component: DigitTextField, - componentProps: { - upperLabel: text.Code, - filled: false, - outlined: true - } - }, - password: { - component: DigitTextField, - componentProps: { - upperLabel: text.Password, - password: true, - outlined: true - } - }, - passwordConfirmation: { - component: DigitTextField, - componentProps: { - upperLabel: text.PasswordConfirmation, - password: true, - outlined: true - } - } - }} - submitText={text.ResetPassword} - subtitleText={text.ResetDescription} - titleText={text.PasswordResetTitle} - /> - - ); -}; - -export default ResetPasswordFinish; diff --git a/frontend/src/use-cases/reset-password/screens/reset-password-finish/ResetPasswordFinish.screen.translations.json b/frontend/src/use-cases/reset-password/screens/reset-password-finish/ResetPasswordFinish.screen.translations.json deleted file mode 100644 index 56b41a9de..000000000 --- a/frontend/src/use-cases/reset-password/screens/reset-password-finish/ResetPasswordFinish.screen.translations.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "PasswordResetTitle": ["Password reset", "Lösenordsåterställning"], - "ResetDescription": [ - "Enter your Cid and the code you received by Email", - "Skriv in ditt Cid och koden du fick i ett Email" - ], - "Cid": ["Cid or Email", "Cid eller Email"], - "ResetPassword": ["Reset Password", "Återställ lösenord"], - "SomethingWentWrong": [ - "Something went wrong while trying to reset the password", - "Något gick fel under återställandet av lösenordet" - ], - "Code": ["Code", "Kod"], - "Password": ["New Password", "Nytt Lösenord"], - "PasswordConfirmation": ["Confirm Password", "Bekräfta Lösenord"], - "CodeOrCidIsWrong": [ - "The received code and cid does not match", - "Den mottagna koden matchar inte Cid:et" - ], - "TooShortPassword": ["Too Short Password", "För kort lösenord"], - "Success": [ - "Your password was successfully reset, redirecting to login...", - "Ditt lösenord återställdes, omdirigerar dig till inloggningssidan..." - ], - "AccountLockedTitle": [ - "First sign-in from old account system", - "Första inloggning från gamla konto tjänsten" - ], - "AccountLocked": [ - "This is the first time you're logging in to our new account service! This means that we need to do a password reset for safety reasons!", - "Det här är första gången du loggar in i vår nya kontotjänst! Det här innebär att du behöver göra en lösenordsåterställning för säkerhetens skull!" - ], - "PasswordsDoNotMatch": ["Passwords do not match", "Lösenorden matchar inte"] -} diff --git a/frontend/src/use-cases/reset-password/screens/reset-password-finish/index.js b/frontend/src/use-cases/reset-password/screens/reset-password-finish/index.js deleted file mode 100644 index 1f81be851..000000000 --- a/frontend/src/use-cases/reset-password/screens/reset-password-finish/index.js +++ /dev/null @@ -1,2 +0,0 @@ -import ResetPasswordFinish from "./ResetPasswordFinish.screen"; -export default ResetPasswordFinish; diff --git a/frontend/src/use-cases/reset-password/screens/reset-password-initalize/ResetPasswordInitialize.screen.jsx b/frontend/src/use-cases/reset-password/screens/reset-password-initalize/ResetPasswordInitialize.screen.jsx deleted file mode 100644 index 48efdd564..000000000 --- a/frontend/src/use-cases/reset-password/screens/reset-password-initalize/ResetPasswordInitialize.screen.jsx +++ /dev/null @@ -1,72 +0,0 @@ -import React from "react"; -import { - DigitTextField, - DigitEditDataCard, - useDigitTranslations, - useDigitToast, - DigitLayout -} from "@cthit/react-digit-components"; -import translations from "./ResetPasswordInitialize.screen.translations"; -import * as yup from "yup"; -import statusCode from "../../../../common/utils/formatters/statusCode.formatter"; -import statusMessage from "../../../../common/utils/formatters/statusMessage.formatter"; -import { resetPasswordInitialize } from "../../../../api/reset-password/post.reset-password"; -import { useHistory } from "react-router-dom"; -import ChangeLanguageLocally from "../../../../common/views/change-language-locally"; - -const ResetPasswordInitialize = () => { - const [text] = useDigitTranslations(translations); - const history = useHistory(); - const [queueToast] = useDigitToast(); - - return ( - - - { - resetPasswordInitialize(values) - .then(() => { - actions.resetForm(); - actions.setSubmitting(false); - history.push("/reset-password/finish"); - }) - .catch(error => { - const code = statusCode(error); - const message = statusMessage(error); - let errorMessage = text.SomethingWentWrong; - if (code === 422) { - if (message === "NO_USER_FOUND") { - errorMessage = text.CredentialsDoNotMatch; - } - } - queueToast({ - text: errorMessage, - duration: 5000 - }); - }); - }} - titleText={text.PasswordResetTitle} - subtitleText={text.ResetDescription} - submitText={text.ResetPassword} - size={{ width: "300px", height: "300px" }} - keysComponentData={{ - cid: { - component: DigitTextField, - componentProps: { - upperLabel: text.Cid, - outlined: true - } - } - }} - keysOrder={["cid"]} - /> - - ); -}; - -export default ResetPasswordInitialize; diff --git a/frontend/src/use-cases/reset-password/screens/reset-password-initalize/ResetPasswordInitialize.screen.translations.json b/frontend/src/use-cases/reset-password/screens/reset-password-initalize/ResetPasswordInitialize.screen.translations.json deleted file mode 100644 index 987a8cdd9..000000000 --- a/frontend/src/use-cases/reset-password/screens/reset-password-initalize/ResetPasswordInitialize.screen.translations.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "PasswordResetTitle": ["Password reset", "Lösenordsåterställning"], - "ResetDescription": [ - "Enter your Cid or Email address", - "Skriv in ditt Cid eller email adress" - ], - "Cid": ["Cid or Email", "Cid eller Email"], - "ResetPassword": ["Reset Password", "Återställ lösenord"], - "SomethingWentWrong": [ - "Something went wrong while trying to reset the password", - "Något gick fel under återställandet av lösenordet" - ], - "CredentialsDoNotMatch": [ - "Credentials do not match any known account", - "Den angivna informationen matchar inget känt konto" - ] -} diff --git a/frontend/src/use-cases/reset-password/screens/reset-password-initalize/index.js b/frontend/src/use-cases/reset-password/screens/reset-password-initalize/index.js deleted file mode 100644 index d6ae78678..000000000 --- a/frontend/src/use-cases/reset-password/screens/reset-password-initalize/index.js +++ /dev/null @@ -1,2 +0,0 @@ -import ResetPasswordInitialize from "./ResetPasswordInitialize.screen"; -export default ResetPasswordInitialize; diff --git a/frontend/src/use-cases/super-groups/SuperGroups.jsx b/frontend/src/use-cases/super-groups/SuperGroups.jsx deleted file mode 100644 index accb44617..000000000 --- a/frontend/src/use-cases/super-groups/SuperGroups.jsx +++ /dev/null @@ -1,112 +0,0 @@ -import React from "react"; -import { SG_ID, SG_NAME } from "../../api/super-groups/props.super-groups.api"; -import { useDigitTranslations, DigitCRUD } from "@cthit/react-digit-components"; -import translations from "./SuperGroups.translations"; -import { - getSuperGroup, - getSuperGroups, - getSuperGroupSubGroups -} from "../../api/super-groups/get.super-groups.api"; -import { addSuperGroup } from "../../api/super-groups/post.super-groups.api"; -import { deleteSuperGroup } from "../../api/super-groups/delete.super-groups.api"; -import { editSuperGroup } from "../../api/super-groups/put.super-groups.api"; -import ShowSubGroups from "./elements/show-sub-groups"; -import useGammaIsAdmin from "../../common/hooks/use-gamma-is-admin/useGammaIsAdmin"; -import FourOFour from "../four-o-four"; -import FiveZeroZero from "../../app/elements/five-zero-zero"; -import { - initialValues, - keysComponentData, - keysOrder, - keysText, - validationSchema -} from "./SuperGroups.options"; -import InsufficientAccess from "../../common/views/insufficient-access"; - -const SuperGroups = () => { - const [text] = useDigitTranslations(translations); - - const admin = useGammaIsAdmin(); - - return ( - - Promise.all([getSuperGroup(id), getSuperGroupSubGroups(id)]) - } - createRequest={admin ? addSuperGroup : null} - deleteRequest={admin ? deleteSuperGroup : null} - updateRequest={admin ? editSuperGroup : null} - tableProps={{ - titleText: text.SuperGroups, - startOrderBy: SG_NAME, - search: true, - flex: "1", - startOrderByDirection: "asc", - size: { minWidth: "288px" }, - padding: "0px", - searchText: text.Search - }} - idProp={SG_ID} - detailsRenderEnd={one => ( - - )} - toastCreateSuccessful={data => - data[SG_NAME] + " " + text.WasCreatedSuccessfully - } - toastCreateFailed={() => text.FailedCreatingSuperGroup} - toastDeleteSuccessful={data => - data[SG_NAME] + " " + text.WasDeletedSuccessfully - } - toastDeleteFailed={data => - text.SuperGroupDeletionFailed1 + - " " + - data[SG_NAME] + - " " + - text.SuperGroupDeletionFailed2 - } - toastUpdateSuccessful={data => - data[SG_NAME] + " " + text.WasUpdatedSuccessfully - } - toastUpdateFailed={data => - text.SuperGroupUpdateFailed1 + - " " + - data[SG_NAME] + - " " + - text.SuperGroupUpdateFailed2 - } - dialogDeleteCancel={() => text.Cancel} - dialogDeleteConfirm={() => text.Delete} - dialogDeleteTitle={() => text.AreYouSure} - dialogDeleteDescription={data => - text.AreYouSureYouWantToDelete + " " + data[SG_NAME] + "?" - } - backButtonText={text.Back} - detailsButtonText={text.Details} - createTitle={text.CreateSuperGroup} - createButtonText={text.CreateSuperGroup} - updateTitle={data => text.Update + " " + data[SG_NAME]} - updateButtonText={data => text.Update + " " + data[SG_NAME]} - deleteButtonText={data => text.Delete + " " + data[SG_NAME]} - detailsTitle={data => data[SG_NAME]} - statusRenders={{ - 403: () => , - 404: () => , - 500: (error, reset) => - }} - useHistoryGoBackOnBack - /> - ); -}; - -export default SuperGroups; diff --git a/frontend/src/use-cases/super-groups/SuperGroups.options.js b/frontend/src/use-cases/super-groups/SuperGroups.options.js deleted file mode 100644 index 7256e1221..000000000 --- a/frontend/src/use-cases/super-groups/SuperGroups.options.js +++ /dev/null @@ -1,104 +0,0 @@ -import * as yup from "yup"; -import { DigitSelect, DigitTextField } from "@cthit/react-digit-components"; - -import { - SG_EMAIL, - SG_NAME, - SG_PRETTY_NAME, - SG_TYPE, - SG_TYPE_ADMIN, - SG_TYPE_ALUMNI, - SG_TYPE_BOARD, - SG_TYPE_COMMITTEE, - SG_TYPE_FUNCTIONARIES, - SG_TYPE_SOCIETY -} from "../../api/super-groups/props.super-groups.api"; - -export const validationSchema = text => { - const schema = {}; - schema[SG_NAME] = yup.string().required(text.Name + text.IsRequired); - schema[SG_PRETTY_NAME] = yup - .string() - .required(text.PrettyName + text.IsRequired); - schema[SG_TYPE] = yup.string().required(text.Type + text.IsRequired); - schema[SG_EMAIL] = yup - .string() - .email(text.FieldNotEmail) - .required(text.Email + text.IsRequired); - - return yup.object().shape(schema); -}; - -export const initialValues = () => { - const output = {}; - - output[SG_NAME] = ""; - output[SG_PRETTY_NAME] = ""; - output[SG_TYPE] = SG_TYPE_SOCIETY; - output[SG_EMAIL] = ""; - - return output; -}; - -export const keysComponentData = text => { - const componentData = {}; - - componentData[SG_NAME] = { - component: DigitTextField, - componentProps: { - upperLabel: text.Name, - outlined: true, - maxLength: 50 - } - }; - - componentData[SG_PRETTY_NAME] = { - component: DigitTextField, - componentProps: { - upperLabel: text.PrettyName, - outlined: true, - maxLength: 50 - } - }; - - componentData[SG_EMAIL] = { - component: DigitTextField, - componentProps: { - upperLabel: text.Email, - outlined: true, - maxLength: 100 - } - }; - - const typeValueToTextMap = {}; - typeValueToTextMap[SG_TYPE_SOCIETY] = text.Society; - typeValueToTextMap[SG_TYPE_COMMITTEE] = text.Committee; - typeValueToTextMap[SG_TYPE_BOARD] = text.Board; - typeValueToTextMap[SG_TYPE_ADMIN] = text.Admin; - typeValueToTextMap[SG_TYPE_FUNCTIONARIES] = text.Functionaries; - typeValueToTextMap[SG_TYPE_ALUMNI] = text.Alumni; - - componentData[SG_TYPE] = { - component: DigitSelect, - componentProps: { - upperLabel: text.Type, - valueToTextMap: typeValueToTextMap, - outlined: true - } - }; - - return componentData; -}; - -export const keysText = text => { - const keysText = {}; - - keysText[SG_NAME] = text.Name; - keysText[SG_PRETTY_NAME] = text.PrettyName; - keysText[SG_TYPE] = text.Type; - keysText[SG_EMAIL] = text.Email; - - return keysText; -}; - -export const keysOrder = () => [SG_NAME, SG_PRETTY_NAME, SG_TYPE, SG_EMAIL]; diff --git a/frontend/src/use-cases/super-groups/SuperGroups.translations.json b/frontend/src/use-cases/super-groups/SuperGroups.translations.json deleted file mode 100644 index 26a839fb3..000000000 --- a/frontend/src/use-cases/super-groups/SuperGroups.translations.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "DeleteSuperGroup": ["Delete super group", "Radera supergrupp"], - "WouldYouLikeToDelete": [ - "Would you like to delete the super group", - "Vill du radera supergruppen" - ], - "SubGroups": ["Sub groups", "Subgrupper"], - "Details": ["Details", "Detaljer"], - "NoSuperGroups": [ - "There's no super groups", - "Det finns inga super grupper" - ], - "EditSuperGroup": ["Edit super group", "Redigera supergruppen"], - "CreateSuperGroup": ["Create Super group", "Skapa supergrupp"], - "SuperGroup": ["Super group", "Supergrupp"], - "SaveSuperGroup": ["Save super group", "Spara supergrupp"], - "DescriptionSv": ["Description swedish", "Beskrivning svenska"], - "DescriptionEn": ["Description english", "Beskrivning engelska"], - "FunctionSv": ["Function swedish", "Uppdrag svenska"], - "FunctionEn": ["Function english", "Uppdrag engelska"], - "SuperGroups": ["Super groups", "Supergrupper"], - "FailedCreatingSuperGroup": [ - "Failed to create super group", - "Misslyckades att skapa supergrupp" - ], - "SuperGroupDeletionFailed1": [ - "Something went wrong when trying to delete the super group", - "Någonting gick fel när supergruppen" - ], - "SuperGroupDeletionFailed2": ["", "försökte raderas"], - "SuperGroupUpdateFailed1": [ - "Something went wrong when trying to update the super group", - "Någonting gick fel när supergruppen" - ], - "SuperGroupUpdateFailed2": ["", "försökte uppdateras"] -} diff --git a/frontend/src/use-cases/super-groups/elements/show-sub-groups/ShowSubGroups.element.jsx b/frontend/src/use-cases/super-groups/elements/show-sub-groups/ShowSubGroups.element.jsx deleted file mode 100644 index 786106ec5..000000000 --- a/frontend/src/use-cases/super-groups/elements/show-sub-groups/ShowSubGroups.element.jsx +++ /dev/null @@ -1,23 +0,0 @@ -import React from "react"; - -import { DigitText, useDigitTranslations } from "@cthit/react-digit-components"; - -import translations from "./ShowSubGroups.element.translations"; -import DisplayGroupsTable from "../../../../common/elements/display-groups-table/DisplayGroupsTable.element"; - -const ShowSubGroups = ({ title, subGroups, margin }) => { - const [text] = useDigitTranslations(translations); - if (subGroups == null || subGroups.length === 0) { - return ; - } else { - return ( - - ); - } -}; - -export default ShowSubGroups; diff --git a/frontend/src/use-cases/super-groups/elements/show-sub-groups/ShowSubGroups.element.translations.json b/frontend/src/use-cases/super-groups/elements/show-sub-groups/ShowSubGroups.element.translations.json deleted file mode 100644 index bb18c9f18..000000000 --- a/frontend/src/use-cases/super-groups/elements/show-sub-groups/ShowSubGroups.element.translations.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "NoSubGroups": ["There's no sub groups", "Det finns inga subgrupper"] -} diff --git a/frontend/src/use-cases/super-groups/elements/show-sub-groups/index.js b/frontend/src/use-cases/super-groups/elements/show-sub-groups/index.js deleted file mode 100644 index 36a9b09a7..000000000 --- a/frontend/src/use-cases/super-groups/elements/show-sub-groups/index.js +++ /dev/null @@ -1,2 +0,0 @@ -import ShowSubGroups from "./ShowSubGroups.element"; -export default ShowSubGroups; diff --git a/frontend/src/use-cases/super-groups/index.js b/frontend/src/use-cases/super-groups/index.js deleted file mode 100644 index 8e139d056..000000000 --- a/frontend/src/use-cases/super-groups/index.js +++ /dev/null @@ -1,2 +0,0 @@ -import SuperGroups from "./SuperGroups"; -export default SuperGroups; diff --git a/frontend/src/use-cases/users/Users.jsx b/frontend/src/use-cases/users/Users.jsx deleted file mode 100644 index 06fd6a0ea..000000000 --- a/frontend/src/use-cases/users/Users.jsx +++ /dev/null @@ -1,176 +0,0 @@ -import React from "react"; -import { useHistory } from "react-router-dom"; -import { - DigitButton, - DigitCRUD, - DigitLayout, - useDigitTranslations -} from "@cthit/react-digit-components"; -import { - getUser, - getUserAdmin, - getUsersMinified -} from "../../api/users/get.users.api"; -import translations from "./Users.translations"; -import { - USER_FIRST_NAME, - USER_ID, - USER_LAST_NAME, - USER_NICK, - USER_GROUPS -} from "../../api/users/props.users.api"; -import { editUser } from "../../api/users/put.users.api"; -import { deleteUser } from "../../api/users/delete.users.api"; -import { - generateUserCustomDetailsRenders, - generateUserEditComponentData -} from "../../common/utils/generators/user-form.generator"; -import { addUser } from "../../api/users/post.users.api"; -import useGammaIsAdmin from "../../common/hooks/use-gamma-is-admin/useGammaIsAdmin"; -import DisplayGroupsTable from "../../common/elements/display-groups-table/DisplayGroupsTable.element"; -import FourOFour from "../four-o-four"; -import FiveZeroZero from "../../app/elements/five-zero-zero"; -import { - createKeysOrder, - createValidationSchema, - initialValues, - keysOrder, - keysText, - readAllKeysOrder, - readOneKeysOrder, - updateKeysOrder, - updateValidationSchema -} from "./Users.options"; -import { GROUP_PRETTY_NAME } from "../../api/groups/props.groups.api"; -import InsufficientAccess from "../../common/views/insufficient-access"; -import styled from "styled-components"; - -const UserImage = styled.img` - width: 250px; - max-height: 500px; - margin: auto; -`; - -const Users = () => { - const admin = useGammaIsAdmin(); - const [text] = useDigitTranslations(translations); - const history = useHistory(); - - const fullName = data => - data[USER_FIRST_NAME] + - " '" + - data[USER_NICK] + - "' " + - data[USER_LAST_NAME]; - - return ( - updateValidationSchema(text)} - formComponentData={generateUserEditComponentData(text)} - name={"users"} - path={"/users"} - readAllRequest={getUsersMinified} - readOneRequest={admin ? getUserAdmin : getUser} - updateRequest={admin ? editUser : null} - deleteRequest={admin ? deleteUser : null} - createRequest={admin ? addUser : null} - idProp={USER_ID} - tableProps={{ - titleText: text.Users, - startOrderBy: USER_NICK, - search: true, - flex: "1", - startOrderByDirection: "asc", - size: { minWidth: "288px" }, - padding: "0px", - searchText: text.Search - }} - customDetailsRenders={generateUserCustomDetailsRenders(text)} - backButtonText={text.Back} - detailsButtonText={text.Details} - createButtonText={text.Create} - updateButtonText={data => text.Update + " " + data[USER_NICK]} - deleteButtonText={data => text.Delete + " " + data[USER_NICK]} - dialogDeleteTitle={() => text.AreYouSure} - dialogDeleteDescription={data => - text.AreYouSureYouWantToDelete + " " + fullName(data) + "?" - } - detailsTitle={data => fullName(data)} - dialogDeleteConfirm={() => text.Delete} - dialogDeleteCancel={() => text.Cancel} - createTitle={text.CreateUser} - updateTitle={data => text.Update + " " + fullName(data)} - toastUpdateSuccessful={data => - fullName(data) + " " + text.WasUpdatedSuccessfully - } - toastUpdateFailed={data => - text.UserUpdateFailed1 + - " " + - fullName(data) + - " " + - text.UserUpdateFailed2 - } - toastDeleteSuccessful={data => - fullName(data) + " " + text.WasDeletedSuccessfully - } - toastDeleteFailed={data => - text.UserDeletionFailed1 + - " " + - fullName(data) + - " " + - text.UserDeletionFailed2 - } - toastCreateSuccessful={data => - fullName(data) + " " + text.WasCreatedSuccessfully - } - toastCreateFailed={() => text.FailedCreatingUser} - formInitialValues={initialValues()} - detailsRenderCardStart={data => ( - - )} - detailsRenderEnd={data => ( - <> - - - )} - detailsRenderCardEnd={data => - admin ? ( - <> -
- - - history.push( - "/reset-password/admin/" + data[USER_ID] - ) - } - /> - - - ) : null - } - statusRenders={{ - 403: () => , - 404: () => , - 500: (error, reset) => - }} - useHistoryGoBackOnBack - /> - ); -}; - -export default Users; diff --git a/frontend/src/use-cases/users/Users.options.js b/frontend/src/use-cases/users/Users.options.js deleted file mode 100644 index 2bc3b9f0c..000000000 --- a/frontend/src/use-cases/users/Users.options.js +++ /dev/null @@ -1,167 +0,0 @@ -import * as yup from "yup"; -import { - USER_ACCEPTANCE_YEAR, - USER_CID, - USER_EMAIL, - USER_FIRST_NAME, - USER_GROUPS, - USER_LANGUAGE, - USER_LAST_NAME, - USER_NICK, - USER_PASSWORD, - USER_PHONE, - USER_RELATIONSHIPS, - USER_AGREEMENT, - USER_ID -} from "../../api/users/props.users.api"; - -export const createValidationSchema = text => { - const schema = {}; - schema[USER_FIRST_NAME] = yup - .string() - .required(text.FirstName + text.IsRequired); - - schema[USER_LAST_NAME] = yup - .string() - .required(text.LastName + text.IsRequired); - - schema[USER_NICK] = yup.string().required(text.Nick + text.IsRequired); - schema[USER_EMAIL] = yup.string().required(text.Email + text.IsRequired); - - schema[USER_ACCEPTANCE_YEAR] = yup - .number() - .required(text.AcceptanceYear + text.IsRequired); - - schema[USER_PHONE] = yup.string().nullable(); - - schema[USER_AGREEMENT] = yup - .boolean() - .oneOf([true]) - .required(text.YouMustAccept); - - schema[USER_CID] = yup - .string() - .min(4, text.Min4CharCid) - .max(12) - .required(text.Cid + text.IsRequired); - - schema[USER_PASSWORD] = yup - .string() - .min(8, text.PasswordTooShort) - .required(text.Password + text.IsRequired); - - return yup.object().shape(schema); -}; - -export const updateValidationSchema = text => { - const schema = {}; - schema[USER_FIRST_NAME] = yup - .string() - .required(text.FirstName + text.IsRequired); - - schema[USER_LAST_NAME] = yup - .string() - .required(text.LastName + text.IsRequired); - schema[USER_NICK] = yup.string().required(text.Nick + text.IsRequired); - schema[USER_EMAIL] = yup.string().required(text.Email + text.IsRequired); - - schema[USER_ACCEPTANCE_YEAR] = yup - .number() - .required(text.AcceptanceYear + text.IsRequired); - - schema[USER_PHONE] = yup.string().nullable(); - return yup.object().shape(schema); -}; - -export const initialValues = () => { - const output = {}; - - output[USER_FIRST_NAME] = ""; - output[USER_LAST_NAME] = ""; - output[USER_NICK] = ""; - output[USER_EMAIL] = ""; - output[USER_ACCEPTANCE_YEAR] = ""; - output[USER_LANGUAGE] = ""; - output[USER_AGREEMENT] = false; - output[USER_CID] = ""; - output[USER_PASSWORD] = ""; - output[USER_PHONE] = ""; - - return output; -}; - -export const keysText = text => { - const output = {}; - - output[USER_ID] = text.Id; - output[USER_CID] = text.Cid; - output[USER_FIRST_NAME] = text.FirstName; - output[USER_LAST_NAME] = text.LastName; - output[USER_NICK] = text.Nick; - output[USER_EMAIL] = text.Email; - output[USER_ACCEPTANCE_YEAR] = text.AcceptanceYear; - output[USER_LANGUAGE] = text.Language; - output[USER_CID] = text.Cid; - output[USER_AGREEMENT] = text.AcceptUserAgreement; - output[USER_PASSWORD] = text.Password; - output[USER_PHONE] = text.Phone; - - return output; -}; - -export const keysOrder = () => [ - USER_CID, - USER_FIRST_NAME, - USER_LAST_NAME, - USER_NICK, - USER_EMAIL, - USER_ACCEPTANCE_YEAR, - USER_PHONE, - USER_LANGUAGE, - USER_AGREEMENT, - USER_GROUPS -]; - -export const readOneKeysOrder = () => [ - USER_CID, - USER_FIRST_NAME, - USER_LAST_NAME, - USER_NICK, - USER_EMAIL, - USER_ACCEPTANCE_YEAR, - USER_PHONE, - USER_LANGUAGE, - USER_RELATIONSHIPS -]; - -export const readAllKeysOrder = () => [ - USER_CID, - USER_FIRST_NAME, - USER_NICK, - USER_LAST_NAME, - USER_ACCEPTANCE_YEAR -]; - -export const updateKeysOrder = () => [ - USER_FIRST_NAME, - USER_LAST_NAME, - USER_NICK, - USER_EMAIL, - USER_ACCEPTANCE_YEAR, - USER_PHONE, - USER_LANGUAGE -]; - -export const createKeysOrder = () => [ - USER_CID, - USER_PASSWORD, - USER_FIRST_NAME, - USER_LAST_NAME, - USER_NICK, - USER_EMAIL, - USER_ACCEPTANCE_YEAR, - USER_PHONE, - USER_LANGUAGE, - USER_AGREEMENT, - USER_GROUPS -]; diff --git a/frontend/src/use-cases/users/Users.translations.json b/frontend/src/use-cases/users/Users.translations.json deleted file mode 100644 index b8e934648..000000000 --- a/frontend/src/use-cases/users/Users.translations.json +++ /dev/null @@ -1,57 +0,0 @@ -{ - "CreateUser": ["Create user", "Skapa användare"], - "EditUser": ["Edit user", "Redigera användare"], - "SaveUser": ["Save user", "Spara användare"], - "UserUpdated": ["Updated user ", "Uppdaterade användare "], - "FirstName": ["First name", "Förnamn"], - "LastName": ["Last name", "Efternamn"], - "Cid": ["Cid", "Cid"], - "Nick": ["Nick", "Nick"], - "Language": ["Language", "Språk"], - "LanguageLowerLabel": ["Your preferred language", "Din föredragna språk"], - "Email": ["Email", "Email"], - "AcceptanceYear": ["Acceptance year", "Antagningsår"], - "AcceptanceYearLowerLabel": ["When you started IT", "När du började IT"], - "Details": ["Details", "Detaljer"], - "NoUsers": [ - "There's no users, wait how are you logged in?!?!?!?!", - "Det finns inga användare, wait hur är du inloggad?!?!?!?!" - ], - "Users": ["Users", "Användare"], - "SearchForUsers": ["Search for users", "Sök efter användare"], - "FailedCreatingUser": [ - "Failed to create user", - "Misslyckades att skapa användaren" - ], - "UserDeletionFailed1": [ - "Something went wrong when trying to delete the user", - "Någonting gick fel när användaren" - ], - "UserDeletionFailed2": ["", "försökte raderas"], - "UserUpdateFailed1": [ - "Something went wrong when trying to update the user", - "Någonting gick fel när användaren" - ], - "UserUpdateFailed2": ["", "försökte uppdateras"], - "AcceptUserAgreement": [ - "I accept the user agreements", - "Jag accepterar användaravtalet" - ], - "Password": ["Password", "Lösenord"], - "PasswordAtleast": ["Minimum 8 chars", "Minst 8 karaktärer"], - "PasswordTooShort": [ - "The password must be atleast 8 characters", - "Lösenordet måste vara minst 8 karaktärer" - ], - "ChangePassword": ["Change password", "Ändra lösenordet"], - "Phone": ["Phone number", "Telefonnummer"], - "YouMustAccept": [ - "You must accept the user agreement", - "Du måste acceptera användaravtalen" - ], - "Min4CharCid": [ - "Cid must be atleast 4 characters", - "Cid måste vara minst 4 karaktärer" - ], - "EditPassword": ["Edit password", "Redigera lösenord"] -} diff --git a/frontend/src/use-cases/users/index.js b/frontend/src/use-cases/users/index.js deleted file mode 100644 index d25de51bd..000000000 --- a/frontend/src/use-cases/users/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from "./Users"; diff --git a/frontend/src/use-cases/whitelist/Whitelist.jsx b/frontend/src/use-cases/whitelist/Whitelist.jsx deleted file mode 100644 index 59fc82745..000000000 --- a/frontend/src/use-cases/whitelist/Whitelist.jsx +++ /dev/null @@ -1,107 +0,0 @@ -import React from "react"; -import { DigitCRUD, useDigitTranslations } from "@cthit/react-digit-components"; -import { - getWhitelist, - getWhitelistItem -} from "../../api/whitelist/get.whitelist.api"; -import { addUsersToWhitelist } from "../../api/whitelist/post.whitelist.api"; -import { editWhitelistItem } from "../../api/whitelist/put.whitelist.api"; -import translations from "./Whitelist.translations"; -import { deleteWhitelistItem } from "../../api/whitelist/delete.whitelist.api"; -import InsufficientAccess from "../../common/views/insufficient-access"; -import useGammaIsAdmin from "../../common/hooks/use-gamma-is-admin/useGammaIsAdmin"; -import FourOFour from "../four-o-four"; -import FiveZeroZero from "../../app/elements/five-zero-zero"; -import { - initialValues, - keysComponentData, - keysOrder, - keysText, - validationSchema -} from "./Whitelist.options"; -import { - WHITELIST_CID, - WHITELIST_ID -} from "../../api/whitelist/props.whitelist.api"; - -const Whitelist = () => { - const [text] = useDigitTranslations(translations); - - const admin = useGammaIsAdmin(); - if (!admin) { - return ; - } - - return ( - - addUsersToWhitelist({ cids: [data[WHITELIST_CID]] }) - } - updateRequest={editWhitelistItem} - deleteRequest={deleteWhitelistItem} - keysOrder={keysOrder()} - formComponentData={keysComponentData()} - formValidationSchema={validationSchema(text)} - formInitialValues={initialValues()} - idProp={WHITELIST_ID} - tableProps={{ - titleText: text.Whitelist, - startOrderBy: WHITELIST_CID, - search: true, - flex: "1", - startOrderByDirection: "asc", - size: { minWidth: "288px" }, - padding: "0px", - searchText: text.Search - }} - toastCreateSuccessful={data => - data[WHITELIST_CID] + " " + text.WasCreatedSuccessfully - } - toastCreateFailed={() => text.FailedCreatingWhitelist} - toastDeleteSuccessful={data => - data[WHITELIST_CID] + " " + text.WasDeletedSuccessfully - } - toastDeleteFailed={data => - text.FailedDeleting + " " + data[WHITELIST_CID] - } - toastUpdateSuccessful={data => - data[WHITELIST_CID] + " " + text.WasUpdatedSuccessfully - } - toastUpdateFailed={data => - text.WhitelistUpdateFailed1 + - " " + - data[WHITELIST_CID] + - " " + - text.WhitelistUpdateFailed2 - } - createTitle={text.SaveCidToWhitelist} - createButtonText={text.AddWhitelist} - updateTitle={data => text.Update + " " + data[WHITELIST_CID]} - updateButtonText={data => text.Update + " " + data[WHITELIST_CID]} - backButtonText={text.Back} - dialogDeleteTitle={() => text.AreYouSure} - dialogDeleteCancel={() => text.Cancel} - dialogDeleteConfirm={() => text.Delete} - dialogDeleteDescription={data => - text.WouldYouLikeToDelete + " " + data[WHITELIST_CID] + "?" - } - detailsTitle={data => data.cid} - deleteButtonText={data => text.Delete + " " + data[WHITELIST_CID]} - detailsButtonText={text.Details} - statusRenders={{ - 403: () => , - 404: () => , - 500: (error, reset) => - }} - useKeyTextsInUpperLabel - useHistoryGoBackOnBack - /> - ); -}; - -export default Whitelist; diff --git a/frontend/src/use-cases/whitelist/Whitelist.options.js b/frontend/src/use-cases/whitelist/Whitelist.options.js deleted file mode 100644 index 428204670..000000000 --- a/frontend/src/use-cases/whitelist/Whitelist.options.js +++ /dev/null @@ -1,51 +0,0 @@ -import * as yup from "yup"; -import { DigitTextField } from "@cthit/react-digit-components"; -import { - WHITELIST_CID, - WHITELIST_ID -} from "../../api/whitelist/props.whitelist.api"; - -export const validationSchema = text => { - const schema = {}; - - schema[WHITELIST_CID] = yup - .string() - .min(4) - .required(text.Cid + text.IsRequired); - - return yup.object().shape(schema); -}; - -export const initialValues = () => { - const output = {}; - - output[WHITELIST_CID] = ""; - - return output; -}; - -export const keysComponentData = () => { - const componentData = {}; - componentData[WHITELIST_CID] = { - component: DigitTextField, - componentProps: { - outlined: true, - maxLength: 10, - alignSelf: "center", - flex: "1" - } - }; - - return componentData; -}; - -export const keysText = text => { - const keysText = {}; - - keysText[WHITELIST_ID] = text.Id; - keysText[WHITELIST_CID] = text.Cid; - - return keysText; -}; - -export const keysOrder = () => [WHITELIST_CID]; diff --git a/frontend/src/use-cases/whitelist/Whitelist.translations.json b/frontend/src/use-cases/whitelist/Whitelist.translations.json deleted file mode 100644 index 6131c7be0..000000000 --- a/frontend/src/use-cases/whitelist/Whitelist.translations.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "Cid": ["Cid", "Cid"], - "SaveCidToWhitelist": [ - "Add cid to the whitelist", - "Lägg till cid till whitelist" - ], - "SaveCid": ["Save cid", "Spara cid"], - "SuccessfulAdd": [ - "You've successfully added cids to the whitelist", - "Du har sparat cids" - ], - "AddWhitelist": ["Add cid", "Lägg till cid"], - "EditCid": ["Edit whitelist item", "Redigera"], - "SuccessfullyEdit": ["You've saved the cid", "Du har sparat cidet"], - "EmptyWhitelist": ["The whitelist is empty", "Whitelist är tom"], - "Whitelist": ["Whitelist", "Whitelist"], - "SearchForWhitelistItem": [ - "Search for whitelist item", - "Sök efter whitelist inlägg" - ], - "DeleteWhitelistItem": ["Delete whitelist item", "Radera whitelist inlägg"], - "EditWhitelistItem": ["Edit whitelist item", "Redigera whitelist inlägg"], - "WouldYouLikeToDelete": [ - "Would you like to delete the whitelist item ", - "Vill du radera whitelist inlägget" - ], - "DeleteSuccessfully": ["You have deleted", "Du har raderat"], - "FailedCreatingWhitelist": [ - "Failed to add cid to whitelist", - "Misslyckades att lägga in cid i whitelist" - ], - "WhitelistUpdateFailed1": [ - "Something went wrong when trying to update the cid for the whitelist", - "Någonting gick fel när whitelist för cid:et" - ], - "WhitelistUpdateFailed2": ["", "försökte uppdateras"] -} diff --git a/frontend/src/use-cases/whitelist/index.js b/frontend/src/use-cases/whitelist/index.js deleted file mode 100644 index 994e8de6e..000000000 --- a/frontend/src/use-cases/whitelist/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from "./Whitelist"; diff --git a/frontend/yarn.lock b/frontend/yarn.lock deleted file mode 100644 index c0d1a073c..000000000 --- a/frontend/yarn.lock +++ /dev/null @@ -1,11522 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@babel/code-frame@7.8.3", "@babel/code-frame@^7.0.0", "@babel/code-frame@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.8.3.tgz#33e25903d7481181534e12ec0a25f16b6fcf419e" - integrity sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g== - dependencies: - "@babel/highlight" "^7.8.3" - -"@babel/compat-data@^7.9.0", "@babel/compat-data@^7.9.6": - version "7.9.6" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.9.6.tgz#3f604c40e420131affe6f2c8052e9a275ae2049b" - integrity sha512-5QPTrNen2bm7RBc7dsOmcA5hbrS4O2Vhmk5XOL4zWW/zD/hV0iinpefDlkm+tBBy8kDtFaaeEvmAqt+nURAV2g== - dependencies: - browserslist "^4.11.1" - invariant "^2.2.4" - semver "^5.5.0" - -"@babel/core@7.8.4": - version "7.8.4" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.8.4.tgz#d496799e5c12195b3602d0fddd77294e3e38e80e" - integrity sha512-0LiLrB2PwrVI+a2/IEskBopDYSd8BCb3rOvH7D5tzoWd696TBEduBvuLVm4Nx6rltrLZqvI3MCalB2K2aVzQjA== - dependencies: - "@babel/code-frame" "^7.8.3" - "@babel/generator" "^7.8.4" - "@babel/helpers" "^7.8.4" - "@babel/parser" "^7.8.4" - "@babel/template" "^7.8.3" - "@babel/traverse" "^7.8.4" - "@babel/types" "^7.8.3" - convert-source-map "^1.7.0" - debug "^4.1.0" - gensync "^1.0.0-beta.1" - json5 "^2.1.0" - lodash "^4.17.13" - resolve "^1.3.2" - semver "^5.4.1" - source-map "^0.5.0" - -"@babel/core@7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.9.0.tgz#ac977b538b77e132ff706f3b8a4dbad09c03c56e" - integrity sha512-kWc7L0fw1xwvI0zi8OKVBuxRVefwGOrKSQMvrQ3dW+bIIavBY3/NpXmpjMy7bQnLgwgzWQZ8TlM57YHpHNHz4w== - dependencies: - "@babel/code-frame" "^7.8.3" - "@babel/generator" "^7.9.0" - "@babel/helper-module-transforms" "^7.9.0" - "@babel/helpers" "^7.9.0" - "@babel/parser" "^7.9.0" - "@babel/template" "^7.8.6" - "@babel/traverse" "^7.9.0" - "@babel/types" "^7.9.0" - convert-source-map "^1.7.0" - debug "^4.1.0" - gensync "^1.0.0-beta.1" - json5 "^2.1.2" - lodash "^4.17.13" - resolve "^1.3.2" - semver "^5.4.1" - source-map "^0.5.0" - -"@babel/core@^7.1.0", "@babel/core@^7.4.5": - version "7.9.6" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.9.6.tgz#d9aa1f580abf3b2286ef40b6904d390904c63376" - integrity sha512-nD3deLvbsApbHAHttzIssYqgb883yU/d9roe4RZymBCDaZryMJDbptVpEpeQuRh4BJ+SYI8le9YGxKvFEvl1Wg== - dependencies: - "@babel/code-frame" "^7.8.3" - "@babel/generator" "^7.9.6" - "@babel/helper-module-transforms" "^7.9.0" - "@babel/helpers" "^7.9.6" - "@babel/parser" "^7.9.6" - "@babel/template" "^7.8.6" - "@babel/traverse" "^7.9.6" - "@babel/types" "^7.9.6" - convert-source-map "^1.7.0" - debug "^4.1.0" - gensync "^1.0.0-beta.1" - json5 "^2.1.2" - lodash "^4.17.13" - resolve "^1.3.2" - semver "^5.4.1" - source-map "^0.5.0" - -"@babel/generator@^7.4.0", "@babel/generator@^7.8.4", "@babel/generator@^7.9.0", "@babel/generator@^7.9.6": - version "7.9.6" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.9.6.tgz#5408c82ac5de98cda0d77d8124e99fa1f2170a43" - integrity sha512-+htwWKJbH2bL72HRluF8zumBxzuX0ZZUFl3JLNyoUjM/Ho8wnVpPXM6aUz8cfKDqQ/h7zHqKt4xzJteUosckqQ== - dependencies: - "@babel/types" "^7.9.6" - jsesc "^2.5.1" - lodash "^4.17.13" - source-map "^0.5.0" - -"@babel/helper-annotate-as-pure@^7.0.0", "@babel/helper-annotate-as-pure@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.8.3.tgz#60bc0bc657f63a0924ff9a4b4a0b24a13cf4deee" - integrity sha512-6o+mJrZBxOoEX77Ezv9zwW7WV8DdluouRKNY/IR5u/YTMuKHgugHOzYWlYvYLpLA9nPsQCAAASpCIbjI9Mv+Uw== - dependencies: - "@babel/types" "^7.8.3" - -"@babel/helper-builder-binary-assignment-operator-visitor@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.8.3.tgz#c84097a427a061ac56a1c30ebf54b7b22d241503" - integrity sha512-5eFOm2SyFPK4Rh3XMMRDjN7lBH0orh3ss0g3rTYZnBQ+r6YPj7lgDyCvPphynHvUrobJmeMignBr6Acw9mAPlw== - dependencies: - "@babel/helper-explode-assignable-expression" "^7.8.3" - "@babel/types" "^7.8.3" - -"@babel/helper-builder-react-jsx-experimental@^7.9.0": - version "7.9.5" - resolved "https://registry.yarnpkg.com/@babel/helper-builder-react-jsx-experimental/-/helper-builder-react-jsx-experimental-7.9.5.tgz#0b4b3e04e6123f03b404ca4dfd6528fe6bb92fe3" - integrity sha512-HAagjAC93tk748jcXpZ7oYRZH485RCq/+yEv9SIWezHRPv9moZArTnkUNciUNzvwHUABmiWKlcxJvMcu59UwTg== - dependencies: - "@babel/helper-annotate-as-pure" "^7.8.3" - "@babel/helper-module-imports" "^7.8.3" - "@babel/types" "^7.9.5" - -"@babel/helper-builder-react-jsx@^7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/helper-builder-react-jsx/-/helper-builder-react-jsx-7.9.0.tgz#16bf391990b57732700a3278d4d9a81231ea8d32" - integrity sha512-weiIo4gaoGgnhff54GQ3P5wsUQmnSwpkvU0r6ZHq6TzoSzKy4JxHEgnxNytaKbov2a9z/CVNyzliuCOUPEX3Jw== - dependencies: - "@babel/helper-annotate-as-pure" "^7.8.3" - "@babel/types" "^7.9.0" - -"@babel/helper-compilation-targets@^7.8.7", "@babel/helper-compilation-targets@^7.9.6": - version "7.9.6" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.9.6.tgz#1e05b7ccc9d38d2f8b40b458b380a04dcfadd38a" - integrity sha512-x2Nvu0igO0ejXzx09B/1fGBxY9NXQlBW2kZsSxCJft+KHN8t9XWzIvFxtPHnBOAXpVsdxZKZFbRUC8TsNKajMw== - dependencies: - "@babel/compat-data" "^7.9.6" - browserslist "^4.11.1" - invariant "^2.2.4" - levenary "^1.1.1" - semver "^5.5.0" - -"@babel/helper-create-class-features-plugin@^7.8.3", "@babel/helper-create-class-features-plugin@^7.9.6": - version "7.9.6" - resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.9.6.tgz#965c8b0a9f051801fd9d3b372ca0ccf200a90897" - integrity sha512-6N9IeuyHvMBRyjNYOMJHrhwtu4WJMrYf8hVbEHD3pbbbmNOk1kmXSQs7bA4dYDUaIx4ZEzdnvo6NwC3WHd/Qow== - dependencies: - "@babel/helper-function-name" "^7.9.5" - "@babel/helper-member-expression-to-functions" "^7.8.3" - "@babel/helper-optimise-call-expression" "^7.8.3" - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/helper-replace-supers" "^7.9.6" - "@babel/helper-split-export-declaration" "^7.8.3" - -"@babel/helper-create-regexp-features-plugin@^7.8.3", "@babel/helper-create-regexp-features-plugin@^7.8.8": - version "7.8.8" - resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.8.8.tgz#5d84180b588f560b7864efaeea89243e58312087" - integrity sha512-LYVPdwkrQEiX9+1R29Ld/wTrmQu1SSKYnuOk3g0CkcZMA1p0gsNxJFj/3gBdaJ7Cg0Fnek5z0DsMULePP7Lrqg== - dependencies: - "@babel/helper-annotate-as-pure" "^7.8.3" - "@babel/helper-regex" "^7.8.3" - regexpu-core "^4.7.0" - -"@babel/helper-define-map@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-define-map/-/helper-define-map-7.8.3.tgz#a0655cad5451c3760b726eba875f1cd8faa02c15" - integrity sha512-PoeBYtxoZGtct3md6xZOCWPcKuMuk3IHhgxsRRNtnNShebf4C8YonTSblsK4tvDbm+eJAw2HAPOfCr+Q/YRG/g== - dependencies: - "@babel/helper-function-name" "^7.8.3" - "@babel/types" "^7.8.3" - lodash "^4.17.13" - -"@babel/helper-explode-assignable-expression@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.8.3.tgz#a728dc5b4e89e30fc2dfc7d04fa28a930653f982" - integrity sha512-N+8eW86/Kj147bO9G2uclsg5pwfs/fqqY5rwgIL7eTBklgXjcOJ3btzS5iM6AitJcftnY7pm2lGsrJVYLGjzIw== - dependencies: - "@babel/traverse" "^7.8.3" - "@babel/types" "^7.8.3" - -"@babel/helper-function-name@^7.8.3", "@babel/helper-function-name@^7.9.5": - version "7.9.5" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.9.5.tgz#2b53820d35275120e1874a82e5aabe1376920a5c" - integrity sha512-JVcQZeXM59Cd1qanDUxv9fgJpt3NeKUaqBqUEvfmQ+BCOKq2xUgaWZW2hr0dkbyJgezYuplEoh5knmrnS68efw== - dependencies: - "@babel/helper-get-function-arity" "^7.8.3" - "@babel/template" "^7.8.3" - "@babel/types" "^7.9.5" - -"@babel/helper-get-function-arity@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz#b894b947bd004381ce63ea1db9f08547e920abd5" - integrity sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA== - dependencies: - "@babel/types" "^7.8.3" - -"@babel/helper-hoist-variables@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.8.3.tgz#1dbe9b6b55d78c9b4183fc8cdc6e30ceb83b7134" - integrity sha512-ky1JLOjcDUtSc+xkt0xhYff7Z6ILTAHKmZLHPxAhOP0Nd77O+3nCsd6uSVYur6nJnCI029CrNbYlc0LoPfAPQg== - dependencies: - "@babel/types" "^7.8.3" - -"@babel/helper-member-expression-to-functions@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.8.3.tgz#659b710498ea6c1d9907e0c73f206eee7dadc24c" - integrity sha512-fO4Egq88utkQFjbPrSHGmGLFqmrshs11d46WI+WZDESt7Wu7wN2G2Iu+NMMZJFDOVRHAMIkB5SNh30NtwCA7RA== - dependencies: - "@babel/types" "^7.8.3" - -"@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.8.3.tgz#7fe39589b39c016331b6b8c3f441e8f0b1419498" - integrity sha512-R0Bx3jippsbAEtzkpZ/6FIiuzOURPcMjHp+Z6xPe6DtApDJx+w7UYyOLanZqO8+wKR9G10s/FmHXvxaMd9s6Kg== - dependencies: - "@babel/types" "^7.8.3" - -"@babel/helper-module-transforms@^7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.9.0.tgz#43b34dfe15961918707d247327431388e9fe96e5" - integrity sha512-0FvKyu0gpPfIQ8EkxlrAydOWROdHpBmiCiRwLkUiBGhCUPRRbVD2/tm3sFr/c/GWFrQ/ffutGUAnx7V0FzT2wA== - dependencies: - "@babel/helper-module-imports" "^7.8.3" - "@babel/helper-replace-supers" "^7.8.6" - "@babel/helper-simple-access" "^7.8.3" - "@babel/helper-split-export-declaration" "^7.8.3" - "@babel/template" "^7.8.6" - "@babel/types" "^7.9.0" - lodash "^4.17.13" - -"@babel/helper-optimise-call-expression@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.8.3.tgz#7ed071813d09c75298ef4f208956006b6111ecb9" - integrity sha512-Kag20n86cbO2AvHca6EJsvqAd82gc6VMGule4HwebwMlwkpXuVqrNRj6CkCV2sKxgi9MyAUnZVnZ6lJ1/vKhHQ== - dependencies: - "@babel/types" "^7.8.3" - -"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz#9ea293be19babc0f52ff8ca88b34c3611b208670" - integrity sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ== - -"@babel/helper-regex@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-regex/-/helper-regex-7.8.3.tgz#139772607d51b93f23effe72105b319d2a4c6965" - integrity sha512-BWt0QtYv/cg/NecOAZMdcn/waj/5P26DR4mVLXfFtDokSR6fyuG0Pj+e2FqtSME+MqED1khnSMulkmGl8qWiUQ== - dependencies: - lodash "^4.17.13" - -"@babel/helper-remap-async-to-generator@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.8.3.tgz#273c600d8b9bf5006142c1e35887d555c12edd86" - integrity sha512-kgwDmw4fCg7AVgS4DukQR/roGp+jP+XluJE5hsRZwxCYGg+Rv9wSGErDWhlI90FODdYfd4xG4AQRiMDjjN0GzA== - dependencies: - "@babel/helper-annotate-as-pure" "^7.8.3" - "@babel/helper-wrap-function" "^7.8.3" - "@babel/template" "^7.8.3" - "@babel/traverse" "^7.8.3" - "@babel/types" "^7.8.3" - -"@babel/helper-replace-supers@^7.8.3", "@babel/helper-replace-supers@^7.8.6", "@babel/helper-replace-supers@^7.9.6": - version "7.9.6" - resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.9.6.tgz#03149d7e6a5586ab6764996cd31d6981a17e1444" - integrity sha512-qX+chbxkbArLyCImk3bWV+jB5gTNU/rsze+JlcF6Nf8tVTigPJSI1o1oBow/9Resa1yehUO9lIipsmu9oG4RzA== - dependencies: - "@babel/helper-member-expression-to-functions" "^7.8.3" - "@babel/helper-optimise-call-expression" "^7.8.3" - "@babel/traverse" "^7.9.6" - "@babel/types" "^7.9.6" - -"@babel/helper-simple-access@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.8.3.tgz#7f8109928b4dab4654076986af575231deb639ae" - integrity sha512-VNGUDjx5cCWg4vvCTR8qQ7YJYZ+HBjxOgXEl7ounz+4Sn7+LMD3CFrCTEU6/qXKbA2nKg21CwhhBzO0RpRbdCw== - dependencies: - "@babel/template" "^7.8.3" - "@babel/types" "^7.8.3" - -"@babel/helper-split-export-declaration@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz#31a9f30070f91368a7182cf05f831781065fc7a9" - integrity sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA== - dependencies: - "@babel/types" "^7.8.3" - -"@babel/helper-validator-identifier@^7.9.0", "@babel/helper-validator-identifier@^7.9.5": - version "7.9.5" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.5.tgz#90977a8e6fbf6b431a7dc31752eee233bf052d80" - integrity sha512-/8arLKUFq882w4tWGj9JYzRpAlZgiWUJ+dtteNTDqrRBz9Iguck9Rn3ykuBDoUwh2TO4tSAJlrxDUOXWklJe4g== - -"@babel/helper-wrap-function@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.8.3.tgz#9dbdb2bb55ef14aaa01fe8c99b629bd5352d8610" - integrity sha512-LACJrbUET9cQDzb6kG7EeD7+7doC3JNvUgTEQOx2qaO1fKlzE/Bf05qs9w1oXQMmXlPO65lC3Tq9S6gZpTErEQ== - dependencies: - "@babel/helper-function-name" "^7.8.3" - "@babel/template" "^7.8.3" - "@babel/traverse" "^7.8.3" - "@babel/types" "^7.8.3" - -"@babel/helpers@^7.8.4", "@babel/helpers@^7.9.0", "@babel/helpers@^7.9.6": - version "7.9.6" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.9.6.tgz#092c774743471d0bb6c7de3ad465ab3d3486d580" - integrity sha512-tI4bUbldloLcHWoRUMAj4g1bF313M/o6fBKhIsb3QnGVPwRm9JsNf/gqMkQ7zjqReABiffPV6RWj7hEglID5Iw== - dependencies: - "@babel/template" "^7.8.3" - "@babel/traverse" "^7.9.6" - "@babel/types" "^7.9.6" - -"@babel/highlight@^7.8.3": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.9.0.tgz#4e9b45ccb82b79607271b2979ad82c7b68163079" - integrity sha512-lJZPilxX7Op3Nv/2cvFdnlepPXDxi29wxteT57Q965oc5R9v86ztx0jfxVrTcBk8C2kcPkkDa2Z4T3ZsPPVWsQ== - dependencies: - "@babel/helper-validator-identifier" "^7.9.0" - chalk "^2.0.0" - js-tokens "^4.0.0" - -"@babel/parser@^7.0.0", "@babel/parser@^7.1.0", "@babel/parser@^7.4.3", "@babel/parser@^7.8.4", "@babel/parser@^7.8.6", "@babel/parser@^7.9.0", "@babel/parser@^7.9.6": - version "7.9.6" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.9.6.tgz#3b1bbb30dabe600cd72db58720998376ff653bc7" - integrity sha512-AoeIEJn8vt+d/6+PXDRPaksYhnlbMIiejioBZvvMQsOjW/JYK6k/0dKnvvP3EhK5GfMBWDPtrxRtegWdAcdq9Q== - -"@babel/plugin-proposal-async-generator-functions@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.8.3.tgz#bad329c670b382589721b27540c7d288601c6e6f" - integrity sha512-NZ9zLv848JsV3hs8ryEh7Uaz/0KsmPLqv0+PdkDJL1cJy0K4kOCFa8zc1E3mp+RHPQcpdfb/6GovEsW4VDrOMw== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/helper-remap-async-to-generator" "^7.8.3" - "@babel/plugin-syntax-async-generators" "^7.8.0" - -"@babel/plugin-proposal-class-properties@7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.8.3.tgz#5e06654af5cd04b608915aada9b2a6788004464e" - integrity sha512-EqFhbo7IosdgPgZggHaNObkmO1kNUe3slaKu54d5OWvy+p9QIKOzK1GAEpAIsZtWVtPXUHSMcT4smvDrCfY4AA== - dependencies: - "@babel/helper-create-class-features-plugin" "^7.8.3" - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-proposal-decorators@7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.8.3.tgz#2156860ab65c5abf068c3f67042184041066543e" - integrity sha512-e3RvdvS4qPJVTe288DlXjwKflpfy1hr0j5dz5WpIYYeP7vQZg2WfAEIp8k5/Lwis/m5REXEteIz6rrcDtXXG7w== - dependencies: - "@babel/helper-create-class-features-plugin" "^7.8.3" - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/plugin-syntax-decorators" "^7.8.3" - -"@babel/plugin-proposal-dynamic-import@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.8.3.tgz#38c4fe555744826e97e2ae930b0fb4cc07e66054" - integrity sha512-NyaBbyLFXFLT9FP+zk0kYlUlA8XtCUbehs67F0nnEg7KICgMc2mNkIeu9TYhKzyXMkrapZFwAhXLdnt4IYHy1w== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/plugin-syntax-dynamic-import" "^7.8.0" - -"@babel/plugin-proposal-json-strings@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.8.3.tgz#da5216b238a98b58a1e05d6852104b10f9a70d6b" - integrity sha512-KGhQNZ3TVCQG/MjRbAUwuH+14y9q0tpxs1nWWs3pbSleRdDro9SAMMDyye8HhY1gqZ7/NqIc8SKhya0wRDgP1Q== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/plugin-syntax-json-strings" "^7.8.0" - -"@babel/plugin-proposal-nullish-coalescing-operator@7.8.3", "@babel/plugin-proposal-nullish-coalescing-operator@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.8.3.tgz#e4572253fdeed65cddeecfdab3f928afeb2fd5d2" - integrity sha512-TS9MlfzXpXKt6YYomudb/KU7nQI6/xnapG6in1uZxoxDghuSMZsPb6D2fyUwNYSAp4l1iR7QtFOjkqcRYcUsfw== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.0" - -"@babel/plugin-proposal-numeric-separator@7.8.3", "@babel/plugin-proposal-numeric-separator@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.8.3.tgz#5d6769409699ec9b3b68684cd8116cedff93bad8" - integrity sha512-jWioO1s6R/R+wEHizfaScNsAx+xKgwTLNXSh7tTC4Usj3ItsPEhYkEpU4h+lpnBwq7NBVOJXfO6cRFYcX69JUQ== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/plugin-syntax-numeric-separator" "^7.8.3" - -"@babel/plugin-proposal-object-rest-spread@^7.9.0", "@babel/plugin-proposal-object-rest-spread@^7.9.6": - version "7.9.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.9.6.tgz#7a093586fcb18b08266eb1a7177da671ac575b63" - integrity sha512-Ga6/fhGqA9Hj+y6whNpPv8psyaK5xzrQwSPsGPloVkvmH+PqW1ixdnfJ9uIO06OjQNYol3PMnfmJ8vfZtkzF+A== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/plugin-syntax-object-rest-spread" "^7.8.0" - "@babel/plugin-transform-parameters" "^7.9.5" - -"@babel/plugin-proposal-optional-catch-binding@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.8.3.tgz#9dee96ab1650eed88646ae9734ca167ac4a9c5c9" - integrity sha512-0gkX7J7E+AtAw9fcwlVQj8peP61qhdg/89D5swOkjYbkboA2CVckn3kiyum1DE0wskGb7KJJxBdyEBApDLLVdw== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/plugin-syntax-optional-catch-binding" "^7.8.0" - -"@babel/plugin-proposal-optional-chaining@7.9.0", "@babel/plugin-proposal-optional-chaining@^7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.9.0.tgz#31db16b154c39d6b8a645292472b98394c292a58" - integrity sha512-NDn5tu3tcv4W30jNhmc2hyD5c56G6cXx4TesJubhxrJeCvuuMpttxr0OnNCqbZGhFjLrg+NIhxxC+BK5F6yS3w== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/plugin-syntax-optional-chaining" "^7.8.0" - -"@babel/plugin-proposal-unicode-property-regex@^7.4.4", "@babel/plugin-proposal-unicode-property-regex@^7.8.3": - version "7.8.8" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.8.8.tgz#ee3a95e90cdc04fe8cd92ec3279fa017d68a0d1d" - integrity sha512-EVhjVsMpbhLw9ZfHWSx2iy13Q8Z/eg8e8ccVWt23sWQK5l1UdkoLJPN5w69UA4uITGBnEZD2JOe4QOHycYKv8A== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.8.8" - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-syntax-async-generators@^7.8.0": - version "7.8.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" - integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-decorators@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.8.3.tgz#8d2c15a9f1af624b0025f961682a9d53d3001bda" - integrity sha512-8Hg4dNNT9/LcA1zQlfwuKR8BUc/if7Q7NkTam9sGTcJphLwpf2g4S42uhspQrIrR+dpzE0dtTqBVFoHl8GtnnQ== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-syntax-dynamic-import@^7.8.0": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3" - integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-flow@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.8.3.tgz#f2c883bd61a6316f2c89380ae5122f923ba4527f" - integrity sha512-innAx3bUbA0KSYj2E2MNFSn9hiCeowOFLxlsuhXzw8hMQnzkDomUr9QCD7E9VF60NmnG1sNTuuv6Qf4f8INYsg== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-syntax-json-strings@^7.8.0": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" - integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-jsx@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.8.3.tgz#521b06c83c40480f1e58b4fd33b92eceb1d6ea94" - integrity sha512-WxdW9xyLgBdefoo0Ynn3MRSkhe5tFVxxKNVdnZSh318WrG2e2jH+E9wd/++JsqcLJZPfz87njQJ8j2Upjm0M0A== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.0": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" - integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-numeric-separator@^7.8.0", "@babel/plugin-syntax-numeric-separator@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.8.3.tgz#0e3fb63e09bea1b11e96467271c8308007e7c41f" - integrity sha512-H7dCMAdN83PcCmqmkHB5dtp+Xa9a6LKSvA2hiFBC/5alSHxM5VgWZXFqDi0YFe8XNGT6iCa+z4V4zSt/PdZ7Dw== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-syntax-object-rest-spread@^7.0.0", "@babel/plugin-syntax-object-rest-spread@^7.8.0": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" - integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-optional-catch-binding@^7.8.0": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" - integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-optional-chaining@^7.8.0": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" - integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-top-level-await@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.8.3.tgz#3acdece695e6b13aaf57fc291d1a800950c71391" - integrity sha512-kwj1j9lL/6Wd0hROD3b/OZZ7MSrZLqqn9RAZ5+cYYsflQ9HZBIKCUkr3+uL1MEJ1NePiUbf98jjiMQSv0NMR9g== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-syntax-typescript@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.8.3.tgz#c1f659dda97711a569cef75275f7e15dcaa6cabc" - integrity sha512-GO1MQ/SGGGoiEXY0e0bSpHimJvxqB7lktLLIq2pv8xG7WZ8IMEle74jIe1FhprHBWjwjZtXHkycDLZXIWM5Wfg== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-transform-arrow-functions@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.8.3.tgz#82776c2ed0cd9e1a49956daeb896024c9473b8b6" - integrity sha512-0MRF+KC8EqH4dbuITCWwPSzsyO3HIWWlm30v8BbbpOrS1B++isGxPnnuq/IZvOX5J2D/p7DQalQm+/2PnlKGxg== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-transform-async-to-generator@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.8.3.tgz#4308fad0d9409d71eafb9b1a6ee35f9d64b64086" - integrity sha512-imt9tFLD9ogt56Dd5CI/6XgpukMwd/fLGSrix2httihVe7LOGVPhyhMh1BU5kDM7iHD08i8uUtmV2sWaBFlHVQ== - dependencies: - "@babel/helper-module-imports" "^7.8.3" - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/helper-remap-async-to-generator" "^7.8.3" - -"@babel/plugin-transform-block-scoped-functions@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.8.3.tgz#437eec5b799b5852072084b3ae5ef66e8349e8a3" - integrity sha512-vo4F2OewqjbB1+yaJ7k2EJFHlTP3jR634Z9Cj9itpqNjuLXvhlVxgnjsHsdRgASR8xYDrx6onw4vW5H6We0Jmg== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-transform-block-scoping@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.8.3.tgz#97d35dab66857a437c166358b91d09050c868f3a" - integrity sha512-pGnYfm7RNRgYRi7bids5bHluENHqJhrV4bCZRwc5GamaWIIs07N4rZECcmJL6ZClwjDz1GbdMZFtPs27hTB06w== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - lodash "^4.17.13" - -"@babel/plugin-transform-classes@^7.9.0", "@babel/plugin-transform-classes@^7.9.5": - version "7.9.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.9.5.tgz#800597ddb8aefc2c293ed27459c1fcc935a26c2c" - integrity sha512-x2kZoIuLC//O5iA7PEvecB105o7TLzZo8ofBVhP79N+DO3jaX+KYfww9TQcfBEZD0nikNyYcGB1IKtRq36rdmg== - dependencies: - "@babel/helper-annotate-as-pure" "^7.8.3" - "@babel/helper-define-map" "^7.8.3" - "@babel/helper-function-name" "^7.9.5" - "@babel/helper-optimise-call-expression" "^7.8.3" - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/helper-replace-supers" "^7.8.6" - "@babel/helper-split-export-declaration" "^7.8.3" - globals "^11.1.0" - -"@babel/plugin-transform-computed-properties@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.8.3.tgz#96d0d28b7f7ce4eb5b120bb2e0e943343c86f81b" - integrity sha512-O5hiIpSyOGdrQZRQ2ccwtTVkgUDBBiCuK//4RJ6UfePllUTCENOzKxfh6ulckXKc0DixTFLCfb2HVkNA7aDpzA== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-transform-destructuring@^7.8.3", "@babel/plugin-transform-destructuring@^7.9.5": - version "7.9.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.9.5.tgz#72c97cf5f38604aea3abf3b935b0e17b1db76a50" - integrity sha512-j3OEsGel8nHL/iusv/mRd5fYZ3DrOxWC82x0ogmdN/vHfAP4MYw+AFKYanzWlktNwikKvlzUV//afBW5FTp17Q== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-transform-dotall-regex@^7.4.4", "@babel/plugin-transform-dotall-regex@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.8.3.tgz#c3c6ec5ee6125c6993c5cbca20dc8621a9ea7a6e" - integrity sha512-kLs1j9Nn4MQoBYdRXH6AeaXMbEJFaFu/v1nQkvib6QzTj8MZI5OQzqmD83/2jEM1z0DLilra5aWO5YpyC0ALIw== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.8.3" - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-transform-duplicate-keys@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.8.3.tgz#8d12df309aa537f272899c565ea1768e286e21f1" - integrity sha512-s8dHiBUbcbSgipS4SMFuWGqCvyge5V2ZeAWzR6INTVC3Ltjig/Vw1G2Gztv0vU/hRG9X8IvKvYdoksnUfgXOEQ== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-transform-exponentiation-operator@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.8.3.tgz#581a6d7f56970e06bf51560cd64f5e947b70d7b7" - integrity sha512-zwIpuIymb3ACcInbksHaNcR12S++0MDLKkiqXHl3AzpgdKlFNhog+z/K0+TGW+b0w5pgTq4H6IwV/WhxbGYSjQ== - dependencies: - "@babel/helper-builder-binary-assignment-operator-visitor" "^7.8.3" - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-transform-flow-strip-types@7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.9.0.tgz#8a3538aa40434e000b8f44a3c5c9ac7229bd2392" - integrity sha512-7Qfg0lKQhEHs93FChxVLAvhBshOPQDtJUTVHr/ZwQNRccCm4O9D79r9tVSoV8iNwjP1YgfD+e/fgHcPkN1qEQg== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/plugin-syntax-flow" "^7.8.3" - -"@babel/plugin-transform-for-of@^7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.9.0.tgz#0f260e27d3e29cd1bb3128da5e76c761aa6c108e" - integrity sha512-lTAnWOpMwOXpyDx06N+ywmF3jNbafZEqZ96CGYabxHrxNX8l5ny7dt4bK/rGwAh9utyP2b2Hv7PlZh1AAS54FQ== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-transform-function-name@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.8.3.tgz#279373cb27322aaad67c2683e776dfc47196ed8b" - integrity sha512-rO/OnDS78Eifbjn5Py9v8y0aR+aSYhDhqAwVfsTl0ERuMZyr05L1aFSCJnbv2mmsLkit/4ReeQ9N2BgLnOcPCQ== - dependencies: - "@babel/helper-function-name" "^7.8.3" - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-transform-literals@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.8.3.tgz#aef239823d91994ec7b68e55193525d76dbd5dc1" - integrity sha512-3Tqf8JJ/qB7TeldGl+TT55+uQei9JfYaregDcEAyBZ7akutriFrt6C/wLYIer6OYhleVQvH/ntEhjE/xMmy10A== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-transform-member-expression-literals@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.8.3.tgz#963fed4b620ac7cbf6029c755424029fa3a40410" - integrity sha512-3Wk2EXhnw+rP+IDkK6BdtPKsUE5IeZ6QOGrPYvw52NwBStw9V1ZVzxgK6fSKSxqUvH9eQPR3tm3cOq79HlsKYA== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-transform-modules-amd@^7.9.0", "@babel/plugin-transform-modules-amd@^7.9.6": - version "7.9.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.9.6.tgz#8539ec42c153d12ea3836e0e3ac30d5aae7b258e" - integrity sha512-zoT0kgC3EixAyIAU+9vfaUVKTv9IxBDSabgHoUCBP6FqEJ+iNiN7ip7NBKcYqbfUDfuC2mFCbM7vbu4qJgOnDw== - dependencies: - "@babel/helper-module-transforms" "^7.9.0" - "@babel/helper-plugin-utils" "^7.8.3" - babel-plugin-dynamic-import-node "^2.3.3" - -"@babel/plugin-transform-modules-commonjs@^7.9.0", "@babel/plugin-transform-modules-commonjs@^7.9.6": - version "7.9.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.9.6.tgz#64b7474a4279ee588cacd1906695ca721687c277" - integrity sha512-7H25fSlLcn+iYimmsNe3uK1at79IE6SKW9q0/QeEHTMC9MdOZ+4bA+T1VFB5fgOqBWoqlifXRzYD0JPdmIrgSQ== - dependencies: - "@babel/helper-module-transforms" "^7.9.0" - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/helper-simple-access" "^7.8.3" - babel-plugin-dynamic-import-node "^2.3.3" - -"@babel/plugin-transform-modules-systemjs@^7.9.0", "@babel/plugin-transform-modules-systemjs@^7.9.6": - version "7.9.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.9.6.tgz#207f1461c78a231d5337a92140e52422510d81a4" - integrity sha512-NW5XQuW3N2tTHim8e1b7qGy7s0kZ2OH3m5octc49K1SdAKGxYxeIx7hiIz05kS1R2R+hOWcsr1eYwcGhrdHsrg== - dependencies: - "@babel/helper-hoist-variables" "^7.8.3" - "@babel/helper-module-transforms" "^7.9.0" - "@babel/helper-plugin-utils" "^7.8.3" - babel-plugin-dynamic-import-node "^2.3.3" - -"@babel/plugin-transform-modules-umd@^7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.9.0.tgz#e909acae276fec280f9b821a5f38e1f08b480697" - integrity sha512-uTWkXkIVtg/JGRSIABdBoMsoIeoHQHPTL0Y2E7xf5Oj7sLqwVsNXOkNk0VJc7vF0IMBsPeikHxFjGe+qmwPtTQ== - dependencies: - "@babel/helper-module-transforms" "^7.9.0" - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-transform-named-capturing-groups-regex@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.8.3.tgz#a2a72bffa202ac0e2d0506afd0939c5ecbc48c6c" - integrity sha512-f+tF/8UVPU86TrCb06JoPWIdDpTNSGGcAtaD9mLP0aYGA0OS0j7j7DHJR0GTFrUZPUU6loZhbsVZgTh0N+Qdnw== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.8.3" - -"@babel/plugin-transform-new-target@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.8.3.tgz#60cc2ae66d85c95ab540eb34babb6434d4c70c43" - integrity sha512-QuSGysibQpyxexRyui2vca+Cmbljo8bcRckgzYV4kRIsHpVeyeC3JDO63pY+xFZ6bWOBn7pfKZTqV4o/ix9sFw== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-transform-object-super@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.8.3.tgz#ebb6a1e7a86ffa96858bd6ac0102d65944261725" - integrity sha512-57FXk+gItG/GejofIyLIgBKTas4+pEU47IXKDBWFTxdPd7F80H8zybyAY7UoblVfBhBGs2EKM+bJUu2+iUYPDQ== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/helper-replace-supers" "^7.8.3" - -"@babel/plugin-transform-parameters@^7.8.7", "@babel/plugin-transform-parameters@^7.9.5": - version "7.9.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.9.5.tgz#173b265746f5e15b2afe527eeda65b73623a0795" - integrity sha512-0+1FhHnMfj6lIIhVvS4KGQJeuhe1GI//h5uptK4PvLt+BGBxsoUJbd3/IW002yk//6sZPlFgsG1hY6OHLcy6kA== - dependencies: - "@babel/helper-get-function-arity" "^7.8.3" - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-transform-property-literals@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.8.3.tgz#33194300d8539c1ed28c62ad5087ba3807b98263" - integrity sha512-uGiiXAZMqEoQhRWMK17VospMZh5sXWg+dlh2soffpkAl96KAm+WZuJfa6lcELotSRmooLqg0MWdH6UUq85nmmg== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-transform-react-constant-elements@^7.0.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.9.0.tgz#a75abc936a3819edec42d3386d9f1c93f28d9d9e" - integrity sha512-wXMXsToAUOxJuBBEHajqKLFWcCkOSLshTI2ChCFFj1zDd7od4IOxiwLCOObNUvOpkxLpjIuaIdBMmNt6ocCPAw== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-transform-react-display-name@7.8.3", "@babel/plugin-transform-react-display-name@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.8.3.tgz#70ded987c91609f78353dd76d2fb2a0bb991e8e5" - integrity sha512-3Jy/PCw8Fe6uBKtEgz3M82ljt+lTg+xJaM4og+eyu83qLT87ZUSckn0wy7r31jflURWLO83TW6Ylf7lyXj3m5A== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-transform-react-jsx-development@^7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.9.0.tgz#3c2a130727caf00c2a293f0aed24520825dbf754" - integrity sha512-tK8hWKrQncVvrhvtOiPpKrQjfNX3DtkNLSX4ObuGcpS9p0QrGetKmlySIGR07y48Zft8WVgPakqd/bk46JrMSw== - dependencies: - "@babel/helper-builder-react-jsx-experimental" "^7.9.0" - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/plugin-syntax-jsx" "^7.8.3" - -"@babel/plugin-transform-react-jsx-self@^7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.9.0.tgz#f4f26a325820205239bb915bad8e06fcadabb49b" - integrity sha512-K2ObbWPKT7KUTAoyjCsFilOkEgMvFG+y0FqOl6Lezd0/13kMkkjHskVsZvblRPj1PHA44PrToaZANrryppzTvQ== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/plugin-syntax-jsx" "^7.8.3" - -"@babel/plugin-transform-react-jsx-source@^7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.9.0.tgz#89ef93025240dd5d17d3122294a093e5e0183de0" - integrity sha512-K6m3LlSnTSfRkM6FcRk8saNEeaeyG5k7AVkBU2bZK3+1zdkSED3qNdsWrUgQBeTVD2Tp3VMmerxVO2yM5iITmw== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/plugin-syntax-jsx" "^7.8.3" - -"@babel/plugin-transform-react-jsx@^7.9.1", "@babel/plugin-transform-react-jsx@^7.9.4": - version "7.9.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.9.4.tgz#86f576c8540bd06d0e95e0b61ea76d55f6cbd03f" - integrity sha512-Mjqf3pZBNLt854CK0C/kRuXAnE6H/bo7xYojP+WGtX8glDGSibcwnsWwhwoSuRg0+EBnxPC1ouVnuetUIlPSAw== - dependencies: - "@babel/helper-builder-react-jsx" "^7.9.0" - "@babel/helper-builder-react-jsx-experimental" "^7.9.0" - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/plugin-syntax-jsx" "^7.8.3" - -"@babel/plugin-transform-regenerator@^7.8.7": - version "7.8.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.8.7.tgz#5e46a0dca2bee1ad8285eb0527e6abc9c37672f8" - integrity sha512-TIg+gAl4Z0a3WmD3mbYSk+J9ZUH6n/Yc57rtKRnlA/7rcCvpekHXe0CMZHP1gYp7/KLe9GHTuIba0vXmls6drA== - dependencies: - regenerator-transform "^0.14.2" - -"@babel/plugin-transform-reserved-words@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.8.3.tgz#9a0635ac4e665d29b162837dd3cc50745dfdf1f5" - integrity sha512-mwMxcycN3omKFDjDQUl+8zyMsBfjRFr0Zn/64I41pmjv4NJuqcYlEtezwYtw9TFd9WR1vN5kiM+O0gMZzO6L0A== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-transform-runtime@7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.9.0.tgz#45468c0ae74cc13204e1d3b1f4ce6ee83258af0b" - integrity sha512-pUu9VSf3kI1OqbWINQ7MaugnitRss1z533436waNXp+0N3ur3zfut37sXiQMxkuCF4VUjwZucen/quskCh7NHw== - dependencies: - "@babel/helper-module-imports" "^7.8.3" - "@babel/helper-plugin-utils" "^7.8.3" - resolve "^1.8.1" - semver "^5.5.1" - -"@babel/plugin-transform-shorthand-properties@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.8.3.tgz#28545216e023a832d4d3a1185ed492bcfeac08c8" - integrity sha512-I9DI6Odg0JJwxCHzbzW08ggMdCezoWcuQRz3ptdudgwaHxTjxw5HgdFJmZIkIMlRymL6YiZcped4TTCB0JcC8w== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-transform-spread@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.8.3.tgz#9c8ffe8170fdfb88b114ecb920b82fb6e95fe5e8" - integrity sha512-CkuTU9mbmAoFOI1tklFWYYbzX5qCIZVXPVy0jpXgGwkplCndQAa58s2jr66fTeQnA64bDox0HL4U56CFYoyC7g== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-transform-sticky-regex@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.8.3.tgz#be7a1290f81dae767475452199e1f76d6175b100" - integrity sha512-9Spq0vGCD5Bb4Z/ZXXSK5wbbLFMG085qd2vhL1JYu1WcQ5bXqZBAYRzU1d+p79GcHs2szYv5pVQCX13QgldaWw== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/helper-regex" "^7.8.3" - -"@babel/plugin-transform-template-literals@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.8.3.tgz#7bfa4732b455ea6a43130adc0ba767ec0e402a80" - integrity sha512-820QBtykIQOLFT8NZOcTRJ1UNuztIELe4p9DCgvj4NK+PwluSJ49we7s9FB1HIGNIYT7wFUJ0ar2QpCDj0escQ== - dependencies: - "@babel/helper-annotate-as-pure" "^7.8.3" - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-transform-typeof-symbol@^7.8.4": - version "7.8.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.8.4.tgz#ede4062315ce0aaf8a657a920858f1a2f35fc412" - integrity sha512-2QKyfjGdvuNfHsb7qnBBlKclbD4CfshH2KvDabiijLMGXPHJXGxtDzwIF7bQP+T0ysw8fYTtxPafgfs/c1Lrqg== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-transform-typescript@^7.9.0": - version "7.9.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.9.6.tgz#2248971416a506fc78278fc0c0ea3179224af1e9" - integrity sha512-8OvsRdvpt3Iesf2qsAn+YdlwAJD7zJ+vhFZmDCa4b8dTp7MmHtKk5FF2mCsGxjZwuwsy/yIIay/nLmxST1ctVQ== - dependencies: - "@babel/helper-create-class-features-plugin" "^7.9.6" - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/plugin-syntax-typescript" "^7.8.3" - -"@babel/plugin-transform-unicode-regex@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.8.3.tgz#0cef36e3ba73e5c57273effb182f46b91a1ecaad" - integrity sha512-+ufgJjYdmWfSQ+6NS9VGUR2ns8cjJjYbrbi11mZBTaWm+Fui/ncTLFF28Ei1okavY+xkojGr1eJxNsWYeA5aZw== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.8.3" - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/preset-env@7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.9.0.tgz#a5fc42480e950ae8f5d9f8f2bbc03f52722df3a8" - integrity sha512-712DeRXT6dyKAM/FMbQTV/FvRCms2hPCx+3weRjZ8iQVQWZejWWk1wwG6ViWMyqb/ouBbGOl5b6aCk0+j1NmsQ== - dependencies: - "@babel/compat-data" "^7.9.0" - "@babel/helper-compilation-targets" "^7.8.7" - "@babel/helper-module-imports" "^7.8.3" - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/plugin-proposal-async-generator-functions" "^7.8.3" - "@babel/plugin-proposal-dynamic-import" "^7.8.3" - "@babel/plugin-proposal-json-strings" "^7.8.3" - "@babel/plugin-proposal-nullish-coalescing-operator" "^7.8.3" - "@babel/plugin-proposal-numeric-separator" "^7.8.3" - "@babel/plugin-proposal-object-rest-spread" "^7.9.0" - "@babel/plugin-proposal-optional-catch-binding" "^7.8.3" - "@babel/plugin-proposal-optional-chaining" "^7.9.0" - "@babel/plugin-proposal-unicode-property-regex" "^7.8.3" - "@babel/plugin-syntax-async-generators" "^7.8.0" - "@babel/plugin-syntax-dynamic-import" "^7.8.0" - "@babel/plugin-syntax-json-strings" "^7.8.0" - "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.0" - "@babel/plugin-syntax-numeric-separator" "^7.8.0" - "@babel/plugin-syntax-object-rest-spread" "^7.8.0" - "@babel/plugin-syntax-optional-catch-binding" "^7.8.0" - "@babel/plugin-syntax-optional-chaining" "^7.8.0" - "@babel/plugin-syntax-top-level-await" "^7.8.3" - "@babel/plugin-transform-arrow-functions" "^7.8.3" - "@babel/plugin-transform-async-to-generator" "^7.8.3" - "@babel/plugin-transform-block-scoped-functions" "^7.8.3" - "@babel/plugin-transform-block-scoping" "^7.8.3" - "@babel/plugin-transform-classes" "^7.9.0" - "@babel/plugin-transform-computed-properties" "^7.8.3" - "@babel/plugin-transform-destructuring" "^7.8.3" - "@babel/plugin-transform-dotall-regex" "^7.8.3" - "@babel/plugin-transform-duplicate-keys" "^7.8.3" - "@babel/plugin-transform-exponentiation-operator" "^7.8.3" - "@babel/plugin-transform-for-of" "^7.9.0" - "@babel/plugin-transform-function-name" "^7.8.3" - "@babel/plugin-transform-literals" "^7.8.3" - "@babel/plugin-transform-member-expression-literals" "^7.8.3" - "@babel/plugin-transform-modules-amd" "^7.9.0" - "@babel/plugin-transform-modules-commonjs" "^7.9.0" - "@babel/plugin-transform-modules-systemjs" "^7.9.0" - "@babel/plugin-transform-modules-umd" "^7.9.0" - "@babel/plugin-transform-named-capturing-groups-regex" "^7.8.3" - "@babel/plugin-transform-new-target" "^7.8.3" - "@babel/plugin-transform-object-super" "^7.8.3" - "@babel/plugin-transform-parameters" "^7.8.7" - "@babel/plugin-transform-property-literals" "^7.8.3" - "@babel/plugin-transform-regenerator" "^7.8.7" - "@babel/plugin-transform-reserved-words" "^7.8.3" - "@babel/plugin-transform-shorthand-properties" "^7.8.3" - "@babel/plugin-transform-spread" "^7.8.3" - "@babel/plugin-transform-sticky-regex" "^7.8.3" - "@babel/plugin-transform-template-literals" "^7.8.3" - "@babel/plugin-transform-typeof-symbol" "^7.8.4" - "@babel/plugin-transform-unicode-regex" "^7.8.3" - "@babel/preset-modules" "^0.1.3" - "@babel/types" "^7.9.0" - browserslist "^4.9.1" - core-js-compat "^3.6.2" - invariant "^2.2.2" - levenary "^1.1.1" - semver "^5.5.0" - -"@babel/preset-env@^7.4.5": - version "7.9.6" - resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.9.6.tgz#df063b276c6455ec6fcfc6e53aacc38da9b0aea6" - integrity sha512-0gQJ9RTzO0heXOhzftog+a/WyOuqMrAIugVYxMYf83gh1CQaQDjMtsOpqOwXyDL/5JcWsrCm8l4ju8QC97O7EQ== - dependencies: - "@babel/compat-data" "^7.9.6" - "@babel/helper-compilation-targets" "^7.9.6" - "@babel/helper-module-imports" "^7.8.3" - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/plugin-proposal-async-generator-functions" "^7.8.3" - "@babel/plugin-proposal-dynamic-import" "^7.8.3" - "@babel/plugin-proposal-json-strings" "^7.8.3" - "@babel/plugin-proposal-nullish-coalescing-operator" "^7.8.3" - "@babel/plugin-proposal-numeric-separator" "^7.8.3" - "@babel/plugin-proposal-object-rest-spread" "^7.9.6" - "@babel/plugin-proposal-optional-catch-binding" "^7.8.3" - "@babel/plugin-proposal-optional-chaining" "^7.9.0" - "@babel/plugin-proposal-unicode-property-regex" "^7.8.3" - "@babel/plugin-syntax-async-generators" "^7.8.0" - "@babel/plugin-syntax-dynamic-import" "^7.8.0" - "@babel/plugin-syntax-json-strings" "^7.8.0" - "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.0" - "@babel/plugin-syntax-numeric-separator" "^7.8.0" - "@babel/plugin-syntax-object-rest-spread" "^7.8.0" - "@babel/plugin-syntax-optional-catch-binding" "^7.8.0" - "@babel/plugin-syntax-optional-chaining" "^7.8.0" - "@babel/plugin-syntax-top-level-await" "^7.8.3" - "@babel/plugin-transform-arrow-functions" "^7.8.3" - "@babel/plugin-transform-async-to-generator" "^7.8.3" - "@babel/plugin-transform-block-scoped-functions" "^7.8.3" - "@babel/plugin-transform-block-scoping" "^7.8.3" - "@babel/plugin-transform-classes" "^7.9.5" - "@babel/plugin-transform-computed-properties" "^7.8.3" - "@babel/plugin-transform-destructuring" "^7.9.5" - "@babel/plugin-transform-dotall-regex" "^7.8.3" - "@babel/plugin-transform-duplicate-keys" "^7.8.3" - "@babel/plugin-transform-exponentiation-operator" "^7.8.3" - "@babel/plugin-transform-for-of" "^7.9.0" - "@babel/plugin-transform-function-name" "^7.8.3" - "@babel/plugin-transform-literals" "^7.8.3" - "@babel/plugin-transform-member-expression-literals" "^7.8.3" - "@babel/plugin-transform-modules-amd" "^7.9.6" - "@babel/plugin-transform-modules-commonjs" "^7.9.6" - "@babel/plugin-transform-modules-systemjs" "^7.9.6" - "@babel/plugin-transform-modules-umd" "^7.9.0" - "@babel/plugin-transform-named-capturing-groups-regex" "^7.8.3" - "@babel/plugin-transform-new-target" "^7.8.3" - "@babel/plugin-transform-object-super" "^7.8.3" - "@babel/plugin-transform-parameters" "^7.9.5" - "@babel/plugin-transform-property-literals" "^7.8.3" - "@babel/plugin-transform-regenerator" "^7.8.7" - "@babel/plugin-transform-reserved-words" "^7.8.3" - "@babel/plugin-transform-shorthand-properties" "^7.8.3" - "@babel/plugin-transform-spread" "^7.8.3" - "@babel/plugin-transform-sticky-regex" "^7.8.3" - "@babel/plugin-transform-template-literals" "^7.8.3" - "@babel/plugin-transform-typeof-symbol" "^7.8.4" - "@babel/plugin-transform-unicode-regex" "^7.8.3" - "@babel/preset-modules" "^0.1.3" - "@babel/types" "^7.9.6" - browserslist "^4.11.1" - core-js-compat "^3.6.2" - invariant "^2.2.2" - levenary "^1.1.1" - semver "^5.5.0" - -"@babel/preset-modules@^0.1.3": - version "0.1.3" - resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.3.tgz#13242b53b5ef8c883c3cf7dddd55b36ce80fbc72" - integrity sha512-Ra3JXOHBq2xd56xSF7lMKXdjBn3T772Y1Wet3yWnkDly9zHvJki029tAFzvAAK5cf4YV3yoxuP61crYRol6SVg== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-proposal-unicode-property-regex" "^7.4.4" - "@babel/plugin-transform-dotall-regex" "^7.4.4" - "@babel/types" "^7.4.4" - esutils "^2.0.2" - -"@babel/preset-react@7.9.1": - version "7.9.1" - resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.9.1.tgz#b346403c36d58c3bb544148272a0cefd9c28677a" - integrity sha512-aJBYF23MPj0RNdp/4bHnAP0NVqqZRr9kl0NAOP4nJCex6OYVio59+dnQzsAWFuogdLyeaKA1hmfUIVZkY5J+TQ== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/plugin-transform-react-display-name" "^7.8.3" - "@babel/plugin-transform-react-jsx" "^7.9.1" - "@babel/plugin-transform-react-jsx-development" "^7.9.0" - "@babel/plugin-transform-react-jsx-self" "^7.9.0" - "@babel/plugin-transform-react-jsx-source" "^7.9.0" - -"@babel/preset-react@^7.0.0": - version "7.9.4" - resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.9.4.tgz#c6c97693ac65b6b9c0b4f25b948a8f665463014d" - integrity sha512-AxylVB3FXeOTQXNXyiuAQJSvss62FEotbX2Pzx3K/7c+MKJMdSg6Ose6QYllkdCFA8EInCJVw7M/o5QbLuA4ZQ== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/plugin-transform-react-display-name" "^7.8.3" - "@babel/plugin-transform-react-jsx" "^7.9.4" - "@babel/plugin-transform-react-jsx-development" "^7.9.0" - "@babel/plugin-transform-react-jsx-self" "^7.9.0" - "@babel/plugin-transform-react-jsx-source" "^7.9.0" - -"@babel/preset-typescript@7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.9.0.tgz#87705a72b1f0d59df21c179f7c3d2ef4b16ce192" - integrity sha512-S4cueFnGrIbvYJgwsVFKdvOmpiL0XGw9MFW9D0vgRys5g36PBhZRL8NX8Gr2akz8XRtzq6HuDXPD/1nniagNUg== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/plugin-transform-typescript" "^7.9.0" - -"@babel/runtime@7.5.4": - version "7.5.4" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.5.4.tgz#cb7d1ad7c6d65676e66b47186577930465b5271b" - integrity sha512-Na84uwyImZZc3FKf4aUF1tysApzwf3p2yuFBIyBfbzT5glzKTdvYI4KVW4kcgjrzoGUjC7w3YyCHcJKaRxsr2Q== - dependencies: - regenerator-runtime "^0.13.2" - -"@babel/runtime@7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.9.0.tgz#337eda67401f5b066a6f205a3113d4ac18ba495b" - integrity sha512-cTIudHnzuWLS56ik4DnRnqqNf8MkdUzV4iFFI1h7Jo9xvrpQROYaAnaSd2mHLQAzzZAPfATynX5ord6YlNYNMA== - dependencies: - regenerator-runtime "^0.13.4" - -"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.3.1", "@babel/runtime@^7.3.4", "@babel/runtime@^7.4.4", "@babel/runtime@^7.4.5", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.0", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.3", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": - version "7.9.6" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.9.6.tgz#a9102eb5cadedf3f31d08a9ecf294af7827ea29f" - integrity sha512-64AF1xY3OAkFHqOb9s4jpgk1Mm5vDZ4L3acHvAml+53nO1XbXLuDodsVpO4OIUsmemlUHMxNdYMNJmsvOwLrvQ== - dependencies: - regenerator-runtime "^0.13.4" - -"@babel/runtime@^7.9.6": - version "7.10.3" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.10.3.tgz#670d002655a7c366540c67f6fd3342cd09500364" - integrity sha512-RzGO0RLSdokm9Ipe/YD+7ww8X2Ro79qiXZF3HU9ljrM+qnJmH1Vqth+hbiQZy761LnMJTMitHDuKVYTk3k4dLw== - dependencies: - regenerator-runtime "^0.13.4" - -"@babel/template@^7.4.0", "@babel/template@^7.8.3", "@babel/template@^7.8.6": - version "7.8.6" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.8.6.tgz#86b22af15f828dfb086474f964dcc3e39c43ce2b" - integrity sha512-zbMsPMy/v0PWFZEhQJ66bqjhH+z0JgMoBWuikXybgG3Gkd/3t5oQ1Rw2WQhnSrsOmsKXnZOx15tkC4qON/+JPg== - dependencies: - "@babel/code-frame" "^7.8.3" - "@babel/parser" "^7.8.6" - "@babel/types" "^7.8.6" - -"@babel/traverse@^7.0.0", "@babel/traverse@^7.1.0", "@babel/traverse@^7.4.3", "@babel/traverse@^7.4.5", "@babel/traverse@^7.8.3", "@babel/traverse@^7.8.4", "@babel/traverse@^7.9.0", "@babel/traverse@^7.9.6": - version "7.9.6" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.9.6.tgz#5540d7577697bf619cc57b92aa0f1c231a94f442" - integrity sha512-b3rAHSjbxy6VEAvlxM8OV/0X4XrG72zoxme6q1MOoe2vd0bEc+TwayhuC1+Dfgqh1QEG+pj7atQqvUprHIccsg== - dependencies: - "@babel/code-frame" "^7.8.3" - "@babel/generator" "^7.9.6" - "@babel/helper-function-name" "^7.9.5" - "@babel/helper-split-export-declaration" "^7.8.3" - "@babel/parser" "^7.9.6" - "@babel/types" "^7.9.6" - debug "^4.1.0" - globals "^11.1.0" - lodash "^4.17.13" - -"@babel/types@^7.0.0", "@babel/types@^7.3.0", "@babel/types@^7.4.0", "@babel/types@^7.4.4", "@babel/types@^7.8.3", "@babel/types@^7.8.6", "@babel/types@^7.9.0", "@babel/types@^7.9.5", "@babel/types@^7.9.6": - version "7.9.6" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.9.6.tgz#2c5502b427251e9de1bd2dff95add646d95cc9f7" - integrity sha512-qxXzvBO//jO9ZnoasKF1uJzHd2+M6Q2ZPIVfnFps8JJvXy0ZBbwbNOmE6SGIY5XOY6d1Bo5lb9d9RJ8nv3WSeA== - dependencies: - "@babel/helper-validator-identifier" "^7.9.5" - lodash "^4.17.13" - to-fast-properties "^2.0.0" - -"@cnakazawa/watch@^1.0.3": - version "1.0.4" - resolved "https://registry.yarnpkg.com/@cnakazawa/watch/-/watch-1.0.4.tgz#f864ae85004d0fcab6f50be9141c4da368d1656a" - integrity sha512-v9kIhKwjeZThiWrLmj0y17CWoyddASLj9O2yvbZkbvw/N3rWOYy9zkV66ursAoVr0mV15bL8g0c4QZUE6cdDoQ== - dependencies: - exec-sh "^0.3.2" - minimist "^1.2.0" - -"@csstools/convert-colors@^1.4.0": - version "1.4.0" - resolved "https://registry.yarnpkg.com/@csstools/convert-colors/-/convert-colors-1.4.0.tgz#ad495dc41b12e75d588c6db8b9834f08fa131eb7" - integrity sha512-5a6wqoJV/xEdbRNKVo6I4hO3VjyDq//8q2f9I6PBAvMesJHFauXDorcNCsr9RzvsZnaWi5NYCcfyqP1QeFHFbw== - -"@csstools/normalize.css@^10.1.0": - version "10.1.0" - resolved "https://registry.yarnpkg.com/@csstools/normalize.css/-/normalize.css-10.1.0.tgz#f0950bba18819512d42f7197e56c518aa491cf18" - integrity sha512-ij4wRiunFfaJxjB0BdrYHIH8FxBJpOwNPhhAcunlmPdXudL1WQV1qoP9un6JsEBAgQH+7UXyyjh0g7jTxXK6tg== - -"@cthit/react-digit-components@1.0.3-beta.11": - version "1.0.3-beta.11" - resolved "https://registry.yarnpkg.com/@cthit/react-digit-components/-/react-digit-components-1.0.3-beta.11.tgz#0951922fc406ad507cf63989190066eababa2460" - integrity sha512-AQmIa9mtTUW31egaZBZpC3cXrEj70NN3ypx4LM91kEf8qiQiA0TRQsauEWqqyM4YV6VcL9MUKty0zo7s7A0fXQ== - dependencies: - "@date-io/date-fns" "1.3.13" - "@material-ui/core" "4.11.0" - "@material-ui/icons" "4.9.1" - "@material-ui/lab" "4.0.0-alpha.56" - "@material-ui/pickers" "3.2.10" - "@material-ui/styles" "4.10.0" - date-fns "2.14.0" - lodash "4.17.15" - prop-types "15.7.2" - react-is "16.13.1" - react-markdown "4.3.1" - yup "0.29.1" - -"@date-io/core@1.x", "@date-io/core@^1.3.13": - version "1.3.13" - resolved "https://registry.yarnpkg.com/@date-io/core/-/core-1.3.13.tgz#90c71da493f20204b7a972929cc5c482d078b3fa" - integrity sha512-AlEKV7TxjeK+jxWVKcCFrfYAk8spX9aCyiToFIiLPtfQbsjmRGLIhb5VZgptQcJdHtLXo7+m0DuurwFgUToQuA== - -"@date-io/date-fns@1.3.13": - version "1.3.13" - resolved "https://registry.yarnpkg.com/@date-io/date-fns/-/date-fns-1.3.13.tgz#7798844041640ab393f7e21a7769a65d672f4735" - integrity sha512-yXxGzcRUPcogiMj58wVgFjc9qUYrCnnU9eLcyNbsQCmae4jPuZCDoIBR21j8ZURsM7GRtU62VOw5yNd4dDHunA== - dependencies: - "@date-io/core" "^1.3.13" - -"@emotion/hash@^0.8.0": - version "0.8.0" - resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.8.0.tgz#bbbff68978fefdbe68ccb533bc8cbe1d1afb5413" - integrity sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow== - -"@emotion/is-prop-valid@^0.8.8": - version "0.8.8" - resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz#db28b1c4368a259b60a97311d6a952d4fd01ac1a" - integrity sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA== - dependencies: - "@emotion/memoize" "0.7.4" - -"@emotion/memoize@0.7.4": - version "0.7.4" - resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.7.4.tgz#19bf0f5af19149111c40d98bb0cf82119f5d9eeb" - integrity sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw== - -"@emotion/stylis@^0.8.4": - version "0.8.5" - resolved "https://registry.yarnpkg.com/@emotion/stylis/-/stylis-0.8.5.tgz#deacb389bd6ee77d1e7fcaccce9e16c5c7e78e04" - integrity sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ== - -"@emotion/unitless@^0.7.4": - version "0.7.5" - resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.5.tgz#77211291c1900a700b8a78cfafda3160d76949ed" - integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg== - -"@hapi/address@2.x.x": - version "2.1.4" - resolved "https://registry.yarnpkg.com/@hapi/address/-/address-2.1.4.tgz#5d67ed43f3fd41a69d4b9ff7b56e7c0d1d0a81e5" - integrity sha512-QD1PhQk+s31P1ixsX0H0Suoupp3VMXzIVMSwobR3F3MSUO2YCV0B7xqLcUw/Bh8yuvd3LhpyqLQWTNcRmp6IdQ== - -"@hapi/bourne@1.x.x": - version "1.3.2" - resolved "https://registry.yarnpkg.com/@hapi/bourne/-/bourne-1.3.2.tgz#0a7095adea067243ce3283e1b56b8a8f453b242a" - integrity sha512-1dVNHT76Uu5N3eJNTYcvxee+jzX4Z9lfciqRRHCU27ihbUcYi+iSc2iml5Ke1LXe1SyJCLA0+14Jh4tXJgOppA== - -"@hapi/hoek@8.x.x", "@hapi/hoek@^8.3.0": - version "8.5.1" - resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-8.5.1.tgz#fde96064ca446dec8c55a8c2f130957b070c6e06" - integrity sha512-yN7kbciD87WzLGc5539Tn0sApjyiGHAJgKvG9W8C7O+6c7qmoQMfVs0W4bX17eqz6C78QJqqFrtgdK5EWf6Qow== - -"@hapi/joi@^15.0.0": - version "15.1.1" - resolved "https://registry.yarnpkg.com/@hapi/joi/-/joi-15.1.1.tgz#c675b8a71296f02833f8d6d243b34c57b8ce19d7" - integrity sha512-entf8ZMOK8sc+8YfeOlM8pCfg3b5+WZIKBfUaaJT8UsjAAPjartzxIYm3TIbjvA4u+u++KbcXD38k682nVHDAQ== - dependencies: - "@hapi/address" "2.x.x" - "@hapi/bourne" "1.x.x" - "@hapi/hoek" "8.x.x" - "@hapi/topo" "3.x.x" - -"@hapi/topo@3.x.x": - version "3.1.6" - resolved "https://registry.yarnpkg.com/@hapi/topo/-/topo-3.1.6.tgz#68d935fa3eae7fdd5ab0d7f953f3205d8b2bfc29" - integrity sha512-tAag0jEcjwH+P2quUfipd7liWCNX2F8NvYjQp2wtInsZxnMlypdw0FtAOLxtvvkO+GSRRbmNi8m/5y42PQJYCQ== - dependencies: - "@hapi/hoek" "^8.3.0" - -"@jest/console@^24.7.1", "@jest/console@^24.9.0": - version "24.9.0" - resolved "https://registry.yarnpkg.com/@jest/console/-/console-24.9.0.tgz#79b1bc06fb74a8cfb01cbdedf945584b1b9707f0" - integrity sha512-Zuj6b8TnKXi3q4ymac8EQfc3ea/uhLeCGThFqXeC8H9/raaH8ARPUTdId+XyGd03Z4In0/VjD2OYFcBF09fNLQ== - dependencies: - "@jest/source-map" "^24.9.0" - chalk "^2.0.1" - slash "^2.0.0" - -"@jest/core@^24.9.0": - version "24.9.0" - resolved "https://registry.yarnpkg.com/@jest/core/-/core-24.9.0.tgz#2ceccd0b93181f9c4850e74f2a9ad43d351369c4" - integrity sha512-Fogg3s4wlAr1VX7q+rhV9RVnUv5tD7VuWfYy1+whMiWUrvl7U3QJSJyWcDio9Lq2prqYsZaeTv2Rz24pWGkJ2A== - dependencies: - "@jest/console" "^24.7.1" - "@jest/reporters" "^24.9.0" - "@jest/test-result" "^24.9.0" - "@jest/transform" "^24.9.0" - "@jest/types" "^24.9.0" - ansi-escapes "^3.0.0" - chalk "^2.0.1" - exit "^0.1.2" - graceful-fs "^4.1.15" - jest-changed-files "^24.9.0" - jest-config "^24.9.0" - jest-haste-map "^24.9.0" - jest-message-util "^24.9.0" - jest-regex-util "^24.3.0" - jest-resolve "^24.9.0" - jest-resolve-dependencies "^24.9.0" - jest-runner "^24.9.0" - jest-runtime "^24.9.0" - jest-snapshot "^24.9.0" - jest-util "^24.9.0" - jest-validate "^24.9.0" - jest-watcher "^24.9.0" - micromatch "^3.1.10" - p-each-series "^1.0.0" - realpath-native "^1.1.0" - rimraf "^2.5.4" - slash "^2.0.0" - strip-ansi "^5.0.0" - -"@jest/environment@^24.3.0", "@jest/environment@^24.9.0": - version "24.9.0" - resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-24.9.0.tgz#21e3afa2d65c0586cbd6cbefe208bafade44ab18" - integrity sha512-5A1QluTPhvdIPFYnO3sZC3smkNeXPVELz7ikPbhUj0bQjB07EoE9qtLrem14ZUYWdVayYbsjVwIiL4WBIMV4aQ== - dependencies: - "@jest/fake-timers" "^24.9.0" - "@jest/transform" "^24.9.0" - "@jest/types" "^24.9.0" - jest-mock "^24.9.0" - -"@jest/fake-timers@^24.3.0", "@jest/fake-timers@^24.9.0": - version "24.9.0" - resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-24.9.0.tgz#ba3e6bf0eecd09a636049896434d306636540c93" - integrity sha512-eWQcNa2YSwzXWIMC5KufBh3oWRIijrQFROsIqt6v/NS9Io/gknw1jsAC9c+ih/RQX4A3O7SeWAhQeN0goKhT9A== - dependencies: - "@jest/types" "^24.9.0" - jest-message-util "^24.9.0" - jest-mock "^24.9.0" - -"@jest/reporters@^24.9.0": - version "24.9.0" - resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-24.9.0.tgz#86660eff8e2b9661d042a8e98a028b8d631a5b43" - integrity sha512-mu4X0yjaHrffOsWmVLzitKmmmWSQ3GGuefgNscUSWNiUNcEOSEQk9k3pERKEQVBb0Cnn88+UESIsZEMH3o88Gw== - dependencies: - "@jest/environment" "^24.9.0" - "@jest/test-result" "^24.9.0" - "@jest/transform" "^24.9.0" - "@jest/types" "^24.9.0" - chalk "^2.0.1" - exit "^0.1.2" - glob "^7.1.2" - istanbul-lib-coverage "^2.0.2" - istanbul-lib-instrument "^3.0.1" - istanbul-lib-report "^2.0.4" - istanbul-lib-source-maps "^3.0.1" - istanbul-reports "^2.2.6" - jest-haste-map "^24.9.0" - jest-resolve "^24.9.0" - jest-runtime "^24.9.0" - jest-util "^24.9.0" - jest-worker "^24.6.0" - node-notifier "^5.4.2" - slash "^2.0.0" - source-map "^0.6.0" - string-length "^2.0.0" - -"@jest/source-map@^24.3.0", "@jest/source-map@^24.9.0": - version "24.9.0" - resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-24.9.0.tgz#0e263a94430be4b41da683ccc1e6bffe2a191714" - integrity sha512-/Xw7xGlsZb4MJzNDgB7PW5crou5JqWiBQaz6xyPd3ArOg2nfn/PunV8+olXbbEZzNl591o5rWKE9BRDaFAuIBg== - dependencies: - callsites "^3.0.0" - graceful-fs "^4.1.15" - source-map "^0.6.0" - -"@jest/test-result@^24.9.0": - version "24.9.0" - resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-24.9.0.tgz#11796e8aa9dbf88ea025757b3152595ad06ba0ca" - integrity sha512-XEFrHbBonBJ8dGp2JmF8kP/nQI/ImPpygKHwQ/SY+es59Z3L5PI4Qb9TQQMAEeYsThG1xF0k6tmG0tIKATNiiA== - dependencies: - "@jest/console" "^24.9.0" - "@jest/types" "^24.9.0" - "@types/istanbul-lib-coverage" "^2.0.0" - -"@jest/test-sequencer@^24.9.0": - version "24.9.0" - resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-24.9.0.tgz#f8f334f35b625a4f2f355f2fe7e6036dad2e6b31" - integrity sha512-6qqsU4o0kW1dvA95qfNog8v8gkRN9ph6Lz7r96IvZpHdNipP2cBcb07J1Z45mz/VIS01OHJ3pY8T5fUY38tg4A== - dependencies: - "@jest/test-result" "^24.9.0" - jest-haste-map "^24.9.0" - jest-runner "^24.9.0" - jest-runtime "^24.9.0" - -"@jest/transform@^24.9.0": - version "24.9.0" - resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-24.9.0.tgz#4ae2768b296553fadab09e9ec119543c90b16c56" - integrity sha512-TcQUmyNRxV94S0QpMOnZl0++6RMiqpbH/ZMccFB/amku6Uwvyb1cjYX7xkp5nGNkbX4QPH/FcB6q1HBTHynLmQ== - dependencies: - "@babel/core" "^7.1.0" - "@jest/types" "^24.9.0" - babel-plugin-istanbul "^5.1.0" - chalk "^2.0.1" - convert-source-map "^1.4.0" - fast-json-stable-stringify "^2.0.0" - graceful-fs "^4.1.15" - jest-haste-map "^24.9.0" - jest-regex-util "^24.9.0" - jest-util "^24.9.0" - micromatch "^3.1.10" - pirates "^4.0.1" - realpath-native "^1.1.0" - slash "^2.0.0" - source-map "^0.6.1" - write-file-atomic "2.4.1" - -"@jest/types@^24.3.0", "@jest/types@^24.9.0": - version "24.9.0" - resolved "https://registry.yarnpkg.com/@jest/types/-/types-24.9.0.tgz#63cb26cb7500d069e5a389441a7c6ab5e909fc59" - integrity sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw== - dependencies: - "@types/istanbul-lib-coverage" "^2.0.0" - "@types/istanbul-reports" "^1.1.1" - "@types/yargs" "^13.0.0" - -"@material-ui/core@4.11.0": - version "4.11.0" - resolved "https://registry.yarnpkg.com/@material-ui/core/-/core-4.11.0.tgz#b69b26e4553c9e53f2bfaf1053e216a0af9be15a" - integrity sha512-bYo9uIub8wGhZySHqLQ833zi4ZML+XCBE1XwJ8EuUVSpTWWG57Pm+YugQToJNFsEyiKFhPh8DPD0bgupz8n01g== - dependencies: - "@babel/runtime" "^7.4.4" - "@material-ui/styles" "^4.10.0" - "@material-ui/system" "^4.9.14" - "@material-ui/types" "^5.1.0" - "@material-ui/utils" "^4.10.2" - "@types/react-transition-group" "^4.2.0" - clsx "^1.0.4" - hoist-non-react-statics "^3.3.2" - popper.js "1.16.1-lts" - prop-types "^15.7.2" - react-is "^16.8.0" - react-transition-group "^4.4.0" - -"@material-ui/icons@4.9.1": - version "4.9.1" - resolved "https://registry.yarnpkg.com/@material-ui/icons/-/icons-4.9.1.tgz#fdeadf8cb3d89208945b33dbc50c7c616d0bd665" - integrity sha512-GBitL3oBWO0hzBhvA9KxqcowRUsA0qzwKkURyC8nppnC3fw54KPKZ+d4V1Eeg/UnDRSzDaI9nGCdel/eh9AQMg== - dependencies: - "@babel/runtime" "^7.4.4" - -"@material-ui/lab@4.0.0-alpha.56": - version "4.0.0-alpha.56" - resolved "https://registry.yarnpkg.com/@material-ui/lab/-/lab-4.0.0-alpha.56.tgz#ff63080949b55b40625e056bbda05e130d216d34" - integrity sha512-xPlkK+z/6y/24ka4gVJgwPfoCF4RCh8dXb1BNE7MtF9bXEBLN/lBxNTK8VAa0qm3V2oinA6xtUIdcRh0aeRtVw== - dependencies: - "@babel/runtime" "^7.4.4" - "@material-ui/utils" "^4.10.2" - clsx "^1.0.4" - prop-types "^15.7.2" - react-is "^16.8.0" - -"@material-ui/pickers@3.2.10": - version "3.2.10" - resolved "https://registry.yarnpkg.com/@material-ui/pickers/-/pickers-3.2.10.tgz#19df024895876eb0ec7cd239bbaea595f703f0ae" - integrity sha512-B8G6Obn5S3RCl7hwahkQj9sKUapwXWFjiaz/Bsw1fhYFdNMnDUolRiWQSoKPb1/oKe37Dtfszoywi1Ynbo3y8w== - dependencies: - "@babel/runtime" "^7.6.0" - "@date-io/core" "1.x" - "@types/styled-jsx" "^2.2.8" - clsx "^1.0.2" - react-transition-group "^4.0.0" - rifm "^0.7.0" - -"@material-ui/styles@4.10.0", "@material-ui/styles@^4.10.0": - version "4.10.0" - resolved "https://registry.yarnpkg.com/@material-ui/styles/-/styles-4.10.0.tgz#2406dc23aa358217aa8cc772e6237bd7f0544071" - integrity sha512-XPwiVTpd3rlnbfrgtEJ1eJJdFCXZkHxy8TrdieaTvwxNYj42VnnCyFzxYeNW9Lhj4V1oD8YtQ6S5Gie7bZDf7Q== - dependencies: - "@babel/runtime" "^7.4.4" - "@emotion/hash" "^0.8.0" - "@material-ui/types" "^5.1.0" - "@material-ui/utils" "^4.9.6" - clsx "^1.0.4" - csstype "^2.5.2" - hoist-non-react-statics "^3.3.2" - jss "^10.0.3" - jss-plugin-camel-case "^10.0.3" - jss-plugin-default-unit "^10.0.3" - jss-plugin-global "^10.0.3" - jss-plugin-nested "^10.0.3" - jss-plugin-props-sort "^10.0.3" - jss-plugin-rule-value-function "^10.0.3" - jss-plugin-vendor-prefixer "^10.0.3" - prop-types "^15.7.2" - -"@material-ui/system@^4.9.14": - version "4.9.14" - resolved "https://registry.yarnpkg.com/@material-ui/system/-/system-4.9.14.tgz#4b00c48b569340cefb2036d0596b93ac6c587a5f" - integrity sha512-oQbaqfSnNlEkXEziDcJDDIy8pbvwUmZXWNqlmIwDqr/ZdCK8FuV3f4nxikUh7hvClKV2gnQ9djh5CZFTHkZj3w== - dependencies: - "@babel/runtime" "^7.4.4" - "@material-ui/utils" "^4.9.6" - csstype "^2.5.2" - prop-types "^15.7.2" - -"@material-ui/types@^5.1.0": - version "5.1.0" - resolved "https://registry.yarnpkg.com/@material-ui/types/-/types-5.1.0.tgz#efa1c7a0b0eaa4c7c87ac0390445f0f88b0d88f2" - integrity sha512-7cqRjrY50b8QzRSYyhSpx4WRw2YuO0KKIGQEVk5J8uoz2BanawykgZGoWEqKm7pVIbzFDN0SpPcVV4IhOFkl8A== - -"@material-ui/utils@^4.10.2": - version "4.10.2" - resolved "https://registry.yarnpkg.com/@material-ui/utils/-/utils-4.10.2.tgz#3fd5470ca61b7341f1e0468ac8f29a70bf6df321" - integrity sha512-eg29v74P7W5r6a4tWWDAAfZldXIzfyO1am2fIsC39hdUUHm/33k6pGOKPbgDjg/U/4ifmgAePy/1OjkKN6rFRw== - dependencies: - "@babel/runtime" "^7.4.4" - prop-types "^15.7.2" - react-is "^16.8.0" - -"@material-ui/utils@^4.9.6": - version "4.9.12" - resolved "https://registry.yarnpkg.com/@material-ui/utils/-/utils-4.9.12.tgz#0d639f1c1ed83fffb2ae10c21d15a938795d9e65" - integrity sha512-/0rgZPEOcZq5CFA4+4n6Q6zk7fi8skHhH2Bcra8R3epoJEYy5PL55LuMazPtPH1oKeRausDV/Omz4BbgFsn1HQ== - dependencies: - "@babel/runtime" "^7.4.4" - prop-types "^15.7.2" - react-is "^16.8.0" - -"@mrmlnc/readdir-enhanced@^2.2.1": - version "2.2.1" - resolved "https://registry.yarnpkg.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde" - integrity sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g== - dependencies: - call-me-maybe "^1.0.1" - glob-to-regexp "^0.3.0" - -"@nodelib/fs.stat@^1.1.2": - version "1.1.3" - resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz#2b5a3ab3f918cca48a8c754c08168e3f03eba61b" - integrity sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw== - -"@svgr/babel-plugin-add-jsx-attribute@^4.2.0": - version "4.2.0" - resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-4.2.0.tgz#dadcb6218503532d6884b210e7f3c502caaa44b1" - integrity sha512-j7KnilGyZzYr/jhcrSYS3FGWMZVaqyCG0vzMCwzvei0coIkczuYMcniK07nI0aHJINciujjH11T72ICW5eL5Ig== - -"@svgr/babel-plugin-remove-jsx-attribute@^4.2.0": - version "4.2.0" - resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-4.2.0.tgz#297550b9a8c0c7337bea12bdfc8a80bb66f85abc" - integrity sha512-3XHLtJ+HbRCH4n28S7y/yZoEQnRpl0tvTZQsHqvaeNXPra+6vE5tbRliH3ox1yZYPCxrlqaJT/Mg+75GpDKlvQ== - -"@svgr/babel-plugin-remove-jsx-empty-expression@^4.2.0": - version "4.2.0" - resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-4.2.0.tgz#c196302f3e68eab6a05e98af9ca8570bc13131c7" - integrity sha512-yTr2iLdf6oEuUE9MsRdvt0NmdpMBAkgK8Bjhl6epb+eQWk6abBaX3d65UZ3E3FWaOwePyUgNyNCMVG61gGCQ7w== - -"@svgr/babel-plugin-replace-jsx-attribute-value@^4.2.0": - version "4.2.0" - resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-4.2.0.tgz#310ec0775de808a6a2e4fd4268c245fd734c1165" - integrity sha512-U9m870Kqm0ko8beHawRXLGLvSi/ZMrl89gJ5BNcT452fAjtF2p4uRzXkdzvGJJJYBgx7BmqlDjBN/eCp5AAX2w== - -"@svgr/babel-plugin-svg-dynamic-title@^4.3.3": - version "4.3.3" - resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-4.3.3.tgz#2cdedd747e5b1b29ed4c241e46256aac8110dd93" - integrity sha512-w3Be6xUNdwgParsvxkkeZb545VhXEwjGMwExMVBIdPQJeyMQHqm9Msnb2a1teHBqUYL66qtwfhNkbj1iarCG7w== - -"@svgr/babel-plugin-svg-em-dimensions@^4.2.0": - version "4.2.0" - resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-4.2.0.tgz#9a94791c9a288108d20a9d2cc64cac820f141391" - integrity sha512-C0Uy+BHolCHGOZ8Dnr1zXy/KgpBOkEUYY9kI/HseHVPeMbluaX3CijJr7D4C5uR8zrc1T64nnq/k63ydQuGt4w== - -"@svgr/babel-plugin-transform-react-native-svg@^4.2.0": - version "4.2.0" - resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-4.2.0.tgz#151487322843359a1ca86b21a3815fd21a88b717" - integrity sha512-7YvynOpZDpCOUoIVlaaOUU87J4Z6RdD6spYN4eUb5tfPoKGSF9OG2NuhgYnq4jSkAxcpMaXWPf1cePkzmqTPNw== - -"@svgr/babel-plugin-transform-svg-component@^4.2.0": - version "4.2.0" - resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-4.2.0.tgz#5f1e2f886b2c85c67e76da42f0f6be1b1767b697" - integrity sha512-hYfYuZhQPCBVotABsXKSCfel2slf/yvJY8heTVX1PCTaq/IgASq1IyxPPKJ0chWREEKewIU/JMSsIGBtK1KKxw== - -"@svgr/babel-preset@^4.3.3": - version "4.3.3" - resolved "https://registry.yarnpkg.com/@svgr/babel-preset/-/babel-preset-4.3.3.tgz#a75d8c2f202ac0e5774e6bfc165d028b39a1316c" - integrity sha512-6PG80tdz4eAlYUN3g5GZiUjg2FMcp+Wn6rtnz5WJG9ITGEF1pmFdzq02597Hn0OmnQuCVaBYQE1OVFAnwOl+0A== - dependencies: - "@svgr/babel-plugin-add-jsx-attribute" "^4.2.0" - "@svgr/babel-plugin-remove-jsx-attribute" "^4.2.0" - "@svgr/babel-plugin-remove-jsx-empty-expression" "^4.2.0" - "@svgr/babel-plugin-replace-jsx-attribute-value" "^4.2.0" - "@svgr/babel-plugin-svg-dynamic-title" "^4.3.3" - "@svgr/babel-plugin-svg-em-dimensions" "^4.2.0" - "@svgr/babel-plugin-transform-react-native-svg" "^4.2.0" - "@svgr/babel-plugin-transform-svg-component" "^4.2.0" - -"@svgr/core@^4.3.3": - version "4.3.3" - resolved "https://registry.yarnpkg.com/@svgr/core/-/core-4.3.3.tgz#b37b89d5b757dc66e8c74156d00c368338d24293" - integrity sha512-qNuGF1QON1626UCaZamWt5yedpgOytvLj5BQZe2j1k1B8DUG4OyugZyfEwBeXozCUwhLEpsrgPrE+eCu4fY17w== - dependencies: - "@svgr/plugin-jsx" "^4.3.3" - camelcase "^5.3.1" - cosmiconfig "^5.2.1" - -"@svgr/hast-util-to-babel-ast@^4.3.2": - version "4.3.2" - resolved "https://registry.yarnpkg.com/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-4.3.2.tgz#1d5a082f7b929ef8f1f578950238f630e14532b8" - integrity sha512-JioXclZGhFIDL3ddn4Kiq8qEqYM2PyDKV0aYno8+IXTLuYt6TOgHUbUAAFvqtb0Xn37NwP0BTHglejFoYr8RZg== - dependencies: - "@babel/types" "^7.4.4" - -"@svgr/plugin-jsx@^4.3.3": - version "4.3.3" - resolved "https://registry.yarnpkg.com/@svgr/plugin-jsx/-/plugin-jsx-4.3.3.tgz#e2ba913dbdfbe85252a34db101abc7ebd50992fa" - integrity sha512-cLOCSpNWQnDB1/v+SUENHH7a0XY09bfuMKdq9+gYvtuwzC2rU4I0wKGFEp1i24holdQdwodCtDQdFtJiTCWc+w== - dependencies: - "@babel/core" "^7.4.5" - "@svgr/babel-preset" "^4.3.3" - "@svgr/hast-util-to-babel-ast" "^4.3.2" - svg-parser "^2.0.0" - -"@svgr/plugin-svgo@^4.3.1": - version "4.3.1" - resolved "https://registry.yarnpkg.com/@svgr/plugin-svgo/-/plugin-svgo-4.3.1.tgz#daac0a3d872e3f55935c6588dd370336865e9e32" - integrity sha512-PrMtEDUWjX3Ea65JsVCwTIXuSqa3CG9px+DluF1/eo9mlDrgrtFE7NE/DjdhjJgSM9wenlVBzkzneSIUgfUI/w== - dependencies: - cosmiconfig "^5.2.1" - merge-deep "^3.0.2" - svgo "^1.2.2" - -"@svgr/webpack@4.3.3": - version "4.3.3" - resolved "https://registry.yarnpkg.com/@svgr/webpack/-/webpack-4.3.3.tgz#13cc2423bf3dff2d494f16b17eb7eacb86895017" - integrity sha512-bjnWolZ6KVsHhgyCoYRFmbd26p8XVbulCzSG53BDQqAr+JOAderYK7CuYrB3bDjHJuF6LJ7Wrr42+goLRV9qIg== - dependencies: - "@babel/core" "^7.4.5" - "@babel/plugin-transform-react-constant-elements" "^7.0.0" - "@babel/preset-env" "^7.4.5" - "@babel/preset-react" "^7.0.0" - "@svgr/core" "^4.3.3" - "@svgr/plugin-jsx" "^4.3.3" - "@svgr/plugin-svgo" "^4.3.1" - loader-utils "^1.2.3" - -"@types/babel__core@^7.1.0": - version "7.1.7" - resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.7.tgz#1dacad8840364a57c98d0dd4855c6dd3752c6b89" - integrity sha512-RL62NqSFPCDK2FM1pSDH0scHpJvsXtZNiYlMB73DgPBaG1E38ZYVL+ei5EkWRbr+KC4YNiAUNBnRj+bgwpgjMw== - dependencies: - "@babel/parser" "^7.1.0" - "@babel/types" "^7.0.0" - "@types/babel__generator" "*" - "@types/babel__template" "*" - "@types/babel__traverse" "*" - -"@types/babel__generator@*": - version "7.6.1" - resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.1.tgz#4901767b397e8711aeb99df8d396d7ba7b7f0e04" - integrity sha512-bBKm+2VPJcMRVwNhxKu8W+5/zT7pwNEqeokFOmbvVSqGzFneNxYcEBro9Ac7/N9tlsaPYnZLK8J1LWKkMsLAew== - dependencies: - "@babel/types" "^7.0.0" - -"@types/babel__template@*": - version "7.0.2" - resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.0.2.tgz#4ff63d6b52eddac1de7b975a5223ed32ecea9307" - integrity sha512-/K6zCpeW7Imzgab2bLkLEbz0+1JlFSrUMdw7KoIIu+IUdu51GWaBZpd3y1VXGVXzynvGa4DaIaxNZHiON3GXUg== - dependencies: - "@babel/parser" "^7.1.0" - "@babel/types" "^7.0.0" - -"@types/babel__traverse@*", "@types/babel__traverse@^7.0.6": - version "7.0.11" - resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.0.11.tgz#1ae3010e8bf8851d324878b42acec71986486d18" - integrity sha512-ddHK5icION5U6q11+tV2f9Mo6CZVuT8GJKld2q9LqHSZbvLbH34Kcu2yFGckZut453+eQU6btIA3RihmnRgI+Q== - dependencies: - "@babel/types" "^7.3.0" - -"@types/color-name@^1.1.1": - version "1.1.1" - resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0" - integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ== - -"@types/eslint-visitor-keys@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#1ee30d79544ca84d68d4b3cdb0af4f205663dd2d" - integrity sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag== - -"@types/events@*": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@types/events/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7" - integrity sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g== - -"@types/glob@^7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.1.tgz#aa59a1c6e3fbc421e07ccd31a944c30eba521575" - integrity sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w== - dependencies: - "@types/events" "*" - "@types/minimatch" "*" - "@types/node" "*" - -"@types/http-proxy@^1.17.3": - version "1.17.4" - resolved "https://registry.yarnpkg.com/@types/http-proxy/-/http-proxy-1.17.4.tgz#e7c92e3dbe3e13aa799440ff42e6d3a17a9d045b" - integrity sha512-IrSHl2u6AWXduUaDLqYpt45tLVCtYv7o4Z0s1KghBCDgIIS9oW5K1H8mZG/A2CfeLdEa7rTd1ACOiHBc1EMT2Q== - dependencies: - "@types/node" "*" - -"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0": - version "2.0.1" - resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz#42995b446db9a48a11a07ec083499a860e9138ff" - integrity sha512-hRJD2ahnnpLgsj6KWMYSrmXkM3rm2Dl1qkx6IOFD5FnuNPXJIG5L0dhgKXCYTRMGzU4n0wImQ/xfmRc4POUFlg== - -"@types/istanbul-lib-report@*": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#c14c24f18ea8190c118ee7562b7ff99a36552686" - integrity sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg== - dependencies: - "@types/istanbul-lib-coverage" "*" - -"@types/istanbul-reports@^1.1.1": - version "1.1.1" - resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-1.1.1.tgz#7a8cbf6a406f36c8add871625b278eaf0b0d255a" - integrity sha512-UpYjBi8xefVChsCoBpKShdxTllC9pwISirfoZsUa2AAdQg/Jd2KQGtSbw+ya7GPo7x/wAPlH6JBhKhAsXUEZNA== - dependencies: - "@types/istanbul-lib-coverage" "*" - "@types/istanbul-lib-report" "*" - -"@types/json-schema@^7.0.3": - version "7.0.4" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.4.tgz#38fd73ddfd9b55abb1e1b2ed578cb55bd7b7d339" - integrity sha512-8+KAKzEvSUdeo+kmqnKrqgeE+LcA0tjYWFY7RPProVYwnqDjukzO+3b6dLD56rYX5TdWejnEOLJYOIeh4CXKuA== - -"@types/minimatch@*": - version "3.0.3" - resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d" - integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA== - -"@types/node@*": - version "13.13.5" - resolved "https://registry.yarnpkg.com/@types/node/-/node-13.13.5.tgz#96ec3b0afafd64a4ccea9107b75bf8489f0e5765" - integrity sha512-3ySmiBYJPqgjiHA7oEaIo2Rzz0HrOZ7yrNO5HWyaE5q0lQ3BppDZ3N53Miz8bw2I7gh1/zir2MGVZBvpb1zq9g== - -"@types/parse-json@^4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" - integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== - -"@types/prop-types@*": - version "15.7.3" - resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.3.tgz#2ab0d5da2e5815f94b0b9d4b95d1e5f243ab2ca7" - integrity sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw== - -"@types/q@^1.5.1": - version "1.5.2" - resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.2.tgz#690a1475b84f2a884fd07cd797c00f5f31356ea8" - integrity sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw== - -"@types/react-transition-group@^4.2.0": - version "4.2.4" - resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.2.4.tgz#c7416225987ccdb719262766c1483da8f826838d" - integrity sha512-8DMUaDqh0S70TjkqU0DxOu80tFUiiaS9rxkWip/nb7gtvAsbqOXm02UCmR8zdcjWujgeYPiPNTVpVpKzUDotwA== - dependencies: - "@types/react" "*" - -"@types/react@*": - version "16.9.34" - resolved "https://registry.yarnpkg.com/@types/react/-/react-16.9.34.tgz#f7d5e331c468f53affed17a8a4d488cd44ea9349" - integrity sha512-8AJlYMOfPe1KGLKyHpflCg5z46n0b5DbRfqDksxBLBTUpB75ypDBAO9eCUcjNwE6LCUslwTz00yyG/X9gaVtow== - dependencies: - "@types/prop-types" "*" - csstype "^2.2.0" - -"@types/stack-utils@^1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-1.0.1.tgz#0a851d3bd96498fa25c33ab7278ed3bd65f06c3e" - integrity sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw== - -"@types/styled-jsx@^2.2.8": - version "2.2.8" - resolved "https://registry.yarnpkg.com/@types/styled-jsx/-/styled-jsx-2.2.8.tgz#b50d13d8a3c34036282d65194554cf186bab7234" - integrity sha512-Yjye9VwMdYeXfS71ihueWRSxrruuXTwKCbzue4+5b2rjnQ//AtyM7myZ1BEhNhBQ/nL/RE7bdToUoLln2miKvg== - dependencies: - "@types/react" "*" - -"@types/yargs-parser@*": - version "15.0.0" - resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-15.0.0.tgz#cb3f9f741869e20cce330ffbeb9271590483882d" - integrity sha512-FA/BWv8t8ZWJ+gEOnLLd8ygxH/2UFbAvgEonyfN6yWGLKc7zVjbpl2Y4CTjid9h2RfgPP6SEt6uHwEOply00yw== - -"@types/yargs@^13.0.0": - version "13.0.8" - resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-13.0.8.tgz#a38c22def2f1c2068f8971acb3ea734eb3c64a99" - integrity sha512-XAvHLwG7UQ+8M4caKIH0ZozIOYay5fQkAgyIXegXT9jPtdIGdhga+sUEdAr1CiG46aB+c64xQEYyEzlwWVTNzA== - dependencies: - "@types/yargs-parser" "*" - -"@typescript-eslint/eslint-plugin@^2.10.0": - version "2.31.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.31.0.tgz#942c921fec5e200b79593c71fafb1e3f57aa2e36" - integrity sha512-iIC0Pb8qDaoit+m80Ln/aaeu9zKQdOLF4SHcGLarSeY1gurW6aU4JsOPMjKQwXlw70MvWKZQc6S2NamA8SJ/gg== - dependencies: - "@typescript-eslint/experimental-utils" "2.31.0" - functional-red-black-tree "^1.0.1" - regexpp "^3.0.0" - tsutils "^3.17.1" - -"@typescript-eslint/experimental-utils@2.31.0": - version "2.31.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-2.31.0.tgz#a9ec514bf7fd5e5e82bc10dcb6a86d58baae9508" - integrity sha512-MI6IWkutLYQYTQgZ48IVnRXmLR/0Q6oAyJgiOror74arUMh7EWjJkADfirZhRsUMHeLJ85U2iySDwHTSnNi9vA== - dependencies: - "@types/json-schema" "^7.0.3" - "@typescript-eslint/typescript-estree" "2.31.0" - eslint-scope "^5.0.0" - eslint-utils "^2.0.0" - -"@typescript-eslint/parser@^2.10.0": - version "2.31.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-2.31.0.tgz#beddd4e8efe64995108b229b2862cd5752d40d6f" - integrity sha512-uph+w6xUOlyV2DLSC6o+fBDzZ5i7+3/TxAsH4h3eC64tlga57oMb96vVlXoMwjR/nN+xyWlsnxtbDkB46M2EPQ== - dependencies: - "@types/eslint-visitor-keys" "^1.0.0" - "@typescript-eslint/experimental-utils" "2.31.0" - "@typescript-eslint/typescript-estree" "2.31.0" - eslint-visitor-keys "^1.1.0" - -"@typescript-eslint/typescript-estree@2.31.0": - version "2.31.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-2.31.0.tgz#ac536c2d46672aa1f27ba0ec2140d53670635cfd" - integrity sha512-vxW149bXFXXuBrAak0eKHOzbcu9cvi6iNcJDzEtOkRwGHxJG15chiAQAwhLOsk+86p9GTr/TziYvw+H9kMaIgA== - dependencies: - debug "^4.1.1" - eslint-visitor-keys "^1.1.0" - glob "^7.1.6" - is-glob "^4.0.1" - lodash "^4.17.15" - semver "^6.3.0" - tsutils "^3.17.1" - -"@webassemblyjs/ast@1.8.5": - version "1.8.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.8.5.tgz#51b1c5fe6576a34953bf4b253df9f0d490d9e359" - integrity sha512-aJMfngIZ65+t71C3y2nBBg5FFG0Okt9m0XEgWZ7Ywgn1oMAT8cNwx00Uv1cQyHtidq0Xn94R4TAywO+LCQ+ZAQ== - dependencies: - "@webassemblyjs/helper-module-context" "1.8.5" - "@webassemblyjs/helper-wasm-bytecode" "1.8.5" - "@webassemblyjs/wast-parser" "1.8.5" - -"@webassemblyjs/floating-point-hex-parser@1.8.5": - version "1.8.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.8.5.tgz#1ba926a2923613edce496fd5b02e8ce8a5f49721" - integrity sha512-9p+79WHru1oqBh9ewP9zW95E3XAo+90oth7S5Re3eQnECGq59ly1Ri5tsIipKGpiStHsUYmY3zMLqtk3gTcOtQ== - -"@webassemblyjs/helper-api-error@1.8.5": - version "1.8.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.8.5.tgz#c49dad22f645227c5edb610bdb9697f1aab721f7" - integrity sha512-Za/tnzsvnqdaSPOUXHyKJ2XI7PDX64kWtURyGiJJZKVEdFOsdKUCPTNEVFZq3zJ2R0G5wc2PZ5gvdTRFgm81zA== - -"@webassemblyjs/helper-buffer@1.8.5": - version "1.8.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.8.5.tgz#fea93e429863dd5e4338555f42292385a653f204" - integrity sha512-Ri2R8nOS0U6G49Q86goFIPNgjyl6+oE1abW1pS84BuhP1Qcr5JqMwRFT3Ah3ADDDYGEgGs1iyb1DGX+kAi/c/Q== - -"@webassemblyjs/helper-code-frame@1.8.5": - version "1.8.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.8.5.tgz#9a740ff48e3faa3022b1dff54423df9aa293c25e" - integrity sha512-VQAadSubZIhNpH46IR3yWO4kZZjMxN1opDrzePLdVKAZ+DFjkGD/rf4v1jap744uPVU6yjL/smZbRIIJTOUnKQ== - dependencies: - "@webassemblyjs/wast-printer" "1.8.5" - -"@webassemblyjs/helper-fsm@1.8.5": - version "1.8.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-fsm/-/helper-fsm-1.8.5.tgz#ba0b7d3b3f7e4733da6059c9332275d860702452" - integrity sha512-kRuX/saORcg8se/ft6Q2UbRpZwP4y7YrWsLXPbbmtepKr22i8Z4O3V5QE9DbZK908dh5Xya4Un57SDIKwB9eow== - -"@webassemblyjs/helper-module-context@1.8.5": - version "1.8.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-module-context/-/helper-module-context-1.8.5.tgz#def4b9927b0101dc8cbbd8d1edb5b7b9c82eb245" - integrity sha512-/O1B236mN7UNEU4t9X7Pj38i4VoU8CcMHyy3l2cV/kIF4U5KoHXDVqcDuOs1ltkac90IM4vZdHc52t1x8Yfs3g== - dependencies: - "@webassemblyjs/ast" "1.8.5" - mamacro "^0.0.3" - -"@webassemblyjs/helper-wasm-bytecode@1.8.5": - version "1.8.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.8.5.tgz#537a750eddf5c1e932f3744206551c91c1b93e61" - integrity sha512-Cu4YMYG3Ddl72CbmpjU/wbP6SACcOPVbHN1dI4VJNJVgFwaKf1ppeFJrwydOG3NDHxVGuCfPlLZNyEdIYlQ6QQ== - -"@webassemblyjs/helper-wasm-section@1.8.5": - version "1.8.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.8.5.tgz#74ca6a6bcbe19e50a3b6b462847e69503e6bfcbf" - integrity sha512-VV083zwR+VTrIWWtgIUpqfvVdK4ff38loRmrdDBgBT8ADXYsEZ5mPQ4Nde90N3UYatHdYoDIFb7oHzMncI02tA== - dependencies: - "@webassemblyjs/ast" "1.8.5" - "@webassemblyjs/helper-buffer" "1.8.5" - "@webassemblyjs/helper-wasm-bytecode" "1.8.5" - "@webassemblyjs/wasm-gen" "1.8.5" - -"@webassemblyjs/ieee754@1.8.5": - version "1.8.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.8.5.tgz#712329dbef240f36bf57bd2f7b8fb9bf4154421e" - integrity sha512-aaCvQYrvKbY/n6wKHb/ylAJr27GglahUO89CcGXMItrOBqRarUMxWLJgxm9PJNuKULwN5n1csT9bYoMeZOGF3g== - dependencies: - "@xtuc/ieee754" "^1.2.0" - -"@webassemblyjs/leb128@1.8.5": - version "1.8.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.8.5.tgz#044edeb34ea679f3e04cd4fd9824d5e35767ae10" - integrity sha512-plYUuUwleLIziknvlP8VpTgO4kqNaH57Y3JnNa6DLpu/sGcP6hbVdfdX5aHAV716pQBKrfuU26BJK29qY37J7A== - dependencies: - "@xtuc/long" "4.2.2" - -"@webassemblyjs/utf8@1.8.5": - version "1.8.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.8.5.tgz#a8bf3b5d8ffe986c7c1e373ccbdc2a0915f0cedc" - integrity sha512-U7zgftmQriw37tfD934UNInokz6yTmn29inT2cAetAsaU9YeVCveWEwhKL1Mg4yS7q//NGdzy79nlXh3bT8Kjw== - -"@webassemblyjs/wasm-edit@1.8.5": - version "1.8.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.8.5.tgz#962da12aa5acc1c131c81c4232991c82ce56e01a" - integrity sha512-A41EMy8MWw5yvqj7MQzkDjU29K7UJq1VrX2vWLzfpRHt3ISftOXqrtojn7nlPsZ9Ijhp5NwuODuycSvfAO/26Q== - dependencies: - "@webassemblyjs/ast" "1.8.5" - "@webassemblyjs/helper-buffer" "1.8.5" - "@webassemblyjs/helper-wasm-bytecode" "1.8.5" - "@webassemblyjs/helper-wasm-section" "1.8.5" - "@webassemblyjs/wasm-gen" "1.8.5" - "@webassemblyjs/wasm-opt" "1.8.5" - "@webassemblyjs/wasm-parser" "1.8.5" - "@webassemblyjs/wast-printer" "1.8.5" - -"@webassemblyjs/wasm-gen@1.8.5": - version "1.8.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.8.5.tgz#54840766c2c1002eb64ed1abe720aded714f98bc" - integrity sha512-BCZBT0LURC0CXDzj5FXSc2FPTsxwp3nWcqXQdOZE4U7h7i8FqtFK5Egia6f9raQLpEKT1VL7zr4r3+QX6zArWg== - dependencies: - "@webassemblyjs/ast" "1.8.5" - "@webassemblyjs/helper-wasm-bytecode" "1.8.5" - "@webassemblyjs/ieee754" "1.8.5" - "@webassemblyjs/leb128" "1.8.5" - "@webassemblyjs/utf8" "1.8.5" - -"@webassemblyjs/wasm-opt@1.8.5": - version "1.8.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.8.5.tgz#b24d9f6ba50394af1349f510afa8ffcb8a63d264" - integrity sha512-HKo2mO/Uh9A6ojzu7cjslGaHaUU14LdLbGEKqTR7PBKwT6LdPtLLh9fPY33rmr5wcOMrsWDbbdCHq4hQUdd37Q== - dependencies: - "@webassemblyjs/ast" "1.8.5" - "@webassemblyjs/helper-buffer" "1.8.5" - "@webassemblyjs/wasm-gen" "1.8.5" - "@webassemblyjs/wasm-parser" "1.8.5" - -"@webassemblyjs/wasm-parser@1.8.5": - version "1.8.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.8.5.tgz#21576f0ec88b91427357b8536383668ef7c66b8d" - integrity sha512-pi0SYE9T6tfcMkthwcgCpL0cM9nRYr6/6fjgDtL6q/ZqKHdMWvxitRi5JcZ7RI4SNJJYnYNaWy5UUrHQy998lw== - dependencies: - "@webassemblyjs/ast" "1.8.5" - "@webassemblyjs/helper-api-error" "1.8.5" - "@webassemblyjs/helper-wasm-bytecode" "1.8.5" - "@webassemblyjs/ieee754" "1.8.5" - "@webassemblyjs/leb128" "1.8.5" - "@webassemblyjs/utf8" "1.8.5" - -"@webassemblyjs/wast-parser@1.8.5": - version "1.8.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-parser/-/wast-parser-1.8.5.tgz#e10eecd542d0e7bd394f6827c49f3df6d4eefb8c" - integrity sha512-daXC1FyKWHF1i11obK086QRlsMsY4+tIOKgBqI1lxAnkp9xe9YMcgOxm9kLe+ttjs5aWV2KKE1TWJCN57/Btsg== - dependencies: - "@webassemblyjs/ast" "1.8.5" - "@webassemblyjs/floating-point-hex-parser" "1.8.5" - "@webassemblyjs/helper-api-error" "1.8.5" - "@webassemblyjs/helper-code-frame" "1.8.5" - "@webassemblyjs/helper-fsm" "1.8.5" - "@xtuc/long" "4.2.2" - -"@webassemblyjs/wast-printer@1.8.5": - version "1.8.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.8.5.tgz#114bbc481fd10ca0e23b3560fa812748b0bae5bc" - integrity sha512-w0U0pD4EhlnvRyeJzBqaVSJAo9w/ce7/WPogeXLzGkO6hzhr4GnQIZ4W4uUt5b9ooAaXPtnXlj0gzsXEOUNYMg== - dependencies: - "@webassemblyjs/ast" "1.8.5" - "@webassemblyjs/wast-parser" "1.8.5" - "@xtuc/long" "4.2.2" - -"@xtuc/ieee754@^1.2.0": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790" - integrity sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA== - -"@xtuc/long@4.2.2": - version "4.2.2" - resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d" - integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== - -abab@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.3.tgz#623e2075e02eb2d3f2475e49f99c91846467907a" - integrity sha512-tsFzPpcttalNjFBCFMqsKYQcWxxen1pgJR56by//QwvJc4/OUS3kPOOttx2tSIfjsylB0pYu7f5D3K1RCxUnUg== - -accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.7: - version "1.3.7" - resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" - integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA== - dependencies: - mime-types "~2.1.24" - negotiator "0.6.2" - -acorn-globals@^4.1.0, acorn-globals@^4.3.0: - version "4.3.4" - resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-4.3.4.tgz#9fa1926addc11c97308c4e66d7add0d40c3272e7" - integrity sha512-clfQEh21R+D0leSbUdWf3OcfqyaCSAQ8Ryq00bofSekfr9W8u1jyYZo6ir0xu9Gtcf7BjcHJpnbZH7JOCpP60A== - dependencies: - acorn "^6.0.1" - acorn-walk "^6.0.1" - -acorn-jsx@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.2.0.tgz#4c66069173d6fdd68ed85239fc256226182b2ebe" - integrity sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ== - -acorn-walk@^6.0.1: - version "6.2.0" - resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-6.2.0.tgz#123cb8f3b84c2171f1f7fb252615b1c78a6b1a8c" - integrity sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA== - -acorn@^5.5.3: - version "5.7.4" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.4.tgz#3e8d8a9947d0599a1796d10225d7432f4a4acf5e" - integrity sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg== - -acorn@^6.0.1, acorn@^6.0.4, acorn@^6.2.1: - version "6.4.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.1.tgz#531e58ba3f51b9dacb9a6646ca4debf5b14ca474" - integrity sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA== - -acorn@^7.1.1: - version "7.1.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.1.1.tgz#e35668de0b402f359de515c5482a1ab9f89a69bf" - integrity sha512-add7dgA5ppRPxCFJoAGfMDi7PIBXq1RtGo7BhbLaxwrXPOmw8gq48Y9ozT01hUKy9byMjlR20EJhu5zlkErEkg== - -address@1.1.2, address@^1.0.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/address/-/address-1.1.2.tgz#bf1116c9c758c51b7a933d296b72c221ed9428b6" - integrity sha512-aT6camzM4xEA54YVJYSqxz1kv4IHnQZRtThJJHhUMRExaU5spC7jX5ugSwTaTgJliIgs4VhZOk7htClvQ/LmRA== - -adjust-sourcemap-loader@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/adjust-sourcemap-loader/-/adjust-sourcemap-loader-2.0.0.tgz#6471143af75ec02334b219f54bc7970c52fb29a4" - integrity sha512-4hFsTsn58+YjrU9qKzML2JSSDqKvN8mUGQ0nNIrfPi8hmIONT4L3uUaT6MKdMsZ9AjsU6D2xDkZxCkbQPxChrA== - dependencies: - assert "1.4.1" - camelcase "5.0.0" - loader-utils "1.2.3" - object-path "0.11.4" - regex-parser "2.2.10" - -aggregate-error@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.0.1.tgz#db2fe7246e536f40d9b5442a39e117d7dd6a24e0" - integrity sha512-quoaXsZ9/BLNae5yiNoUz+Nhkwz83GhWwtYFglcjEQB2NDHCIpApbqXxIFnm4Pq/Nvhrsq5sYJFyohrrxnTGAA== - dependencies: - clean-stack "^2.0.0" - indent-string "^4.0.0" - -ajv-errors@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/ajv-errors/-/ajv-errors-1.0.1.tgz#f35986aceb91afadec4102fbd85014950cefa64d" - integrity sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ== - -ajv-keywords@^3.1.0, ajv-keywords@^3.4.1: - version "3.4.1" - resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.4.1.tgz#ef916e271c64ac12171fd8384eaae6b2345854da" - integrity sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ== - -ajv@^6.1.0, ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.0, ajv@^6.5.5: - version "6.12.2" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.2.tgz#c629c5eced17baf314437918d2da88c99d5958cd" - integrity sha512-k+V+hzjm5q/Mr8ef/1Y9goCmlsK4I6Sm74teeyGvFk1XrOsbsKLjEdrvny42CZ+a8sXbk8KWpY/bDwS+FLL2UQ== - dependencies: - fast-deep-equal "^3.1.1" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.4.1" - uri-js "^4.2.2" - -alphanum-sort@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3" - integrity sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM= - -ansi-colors@^3.0.0: - version "3.2.4" - resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.4.tgz#e3a3da4bfbae6c86a9c285625de124a234026fbf" - integrity sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA== - -ansi-escapes@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" - integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ== - -ansi-escapes@^4.2.1: - version "4.3.1" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.1.tgz#a5c47cc43181f1f38ffd7076837700d395522a61" - integrity sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA== - dependencies: - type-fest "^0.11.0" - -ansi-html@0.0.7: - version "0.0.7" - resolved "https://registry.yarnpkg.com/ansi-html/-/ansi-html-0.0.7.tgz#813584021962a9e9e6fd039f940d12f56ca7859e" - integrity sha1-gTWEAhliqenm/QOflA0S9WynhZ4= - -ansi-regex@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" - integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= - -ansi-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" - integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= - -ansi-regex@^4.0.0, ansi-regex@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" - integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== - -ansi-regex@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" - integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg== - -ansi-styles@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" - integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4= - -ansi-styles@^3.2.0, ansi-styles@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" - integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== - dependencies: - color-convert "^1.9.0" - -ansi-styles@^4.1.0: - version "4.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.2.1.tgz#90ae75c424d008d2624c5bf29ead3177ebfcf359" - integrity sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA== - dependencies: - "@types/color-name" "^1.1.1" - color-convert "^2.0.1" - -anymatch@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" - integrity sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw== - dependencies: - micromatch "^3.1.4" - normalize-path "^2.1.1" - -anymatch@~3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.1.tgz#c55ecf02185e2469259399310c173ce31233b142" - integrity sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg== - dependencies: - normalize-path "^3.0.0" - picomatch "^2.0.4" - -aproba@^1.1.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" - integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== - -argparse@^1.0.7: - version "1.0.10" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" - integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== - dependencies: - sprintf-js "~1.0.2" - -aria-query@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-3.0.0.tgz#65b3fcc1ca1155a8c9ae64d6eee297f15d5133cc" - integrity sha1-ZbP8wcoRVajJrmTW7uKX8V1RM8w= - dependencies: - ast-types-flow "0.0.7" - commander "^2.11.0" - -arity-n@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/arity-n/-/arity-n-1.0.4.tgz#d9e76b11733e08569c0847ae7b39b2860b30b745" - integrity sha1-2edrEXM+CFacCEeuezmyhgswt0U= - -arr-diff@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" - integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA= - -arr-flatten@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" - integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== - -arr-union@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" - integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= - -array-equal@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93" - integrity sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM= - -array-flatten@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" - integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= - -array-flatten@^2.1.0: - version "2.1.2" - resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-2.1.2.tgz#24ef80a28c1a893617e2149b0c6d0d788293b099" - integrity sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ== - -array-includes@^3.0.3, array-includes@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.1.tgz#cdd67e6852bdf9c1215460786732255ed2459348" - integrity sha512-c2VXaCHl7zPsvpkFsw4nxvFie4fh1ur9bpcgsVkIjqn0H/Xwdg+7fv3n2r/isyS8EBj5b06M9kHyZuIr4El6WQ== - dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.0" - is-string "^1.0.5" - -array-union@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" - integrity sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk= - dependencies: - array-uniq "^1.0.1" - -array-uniq@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" - integrity sha1-r2rId6Jcx/dOBYiUdThY39sk/bY= - -array-unique@^0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" - integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= - -array.prototype.flat@^1.2.1: - version "1.2.3" - resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.2.3.tgz#0de82b426b0318dbfdb940089e38b043d37f6c7b" - integrity sha512-gBlRZV0VSmfPIeWfuuy56XZMvbVfbEUnOXUvt3F/eUUUSyzlgLxhEX4YAEpxNAogRGehPSnfXyPtYyKAhkzQhQ== - dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.0-next.1" - -arrify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" - integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0= - -asap@~2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" - integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY= - -asn1.js@^4.0.0: - version "4.10.1" - resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.10.1.tgz#b9c2bf5805f1e64aadeed6df3a2bfafb5a73f5a0" - integrity sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw== - dependencies: - bn.js "^4.0.0" - inherits "^2.0.1" - minimalistic-assert "^1.0.0" - -asn1@~0.2.3: - version "0.2.4" - resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" - integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg== - dependencies: - safer-buffer "~2.1.0" - -assert-plus@1.0.0, assert-plus@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" - integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= - -assert@1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/assert/-/assert-1.4.1.tgz#99912d591836b5a6f5b345c0f07eefc08fc65d91" - integrity sha1-mZEtWRg2tab1s0XA8H7vwI/GXZE= - dependencies: - util "0.10.3" - -assert@^1.1.1: - version "1.5.0" - resolved "https://registry.yarnpkg.com/assert/-/assert-1.5.0.tgz#55c109aaf6e0aefdb3dc4b71240c70bf574b18eb" - integrity sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA== - dependencies: - object-assign "^4.1.1" - util "0.10.3" - -assign-symbols@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" - integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= - -ast-types-flow@0.0.7, ast-types-flow@^0.0.7: - version "0.0.7" - resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.7.tgz#f70b735c6bca1a5c9c22d982c3e39e7feba3bdad" - integrity sha1-9wtzXGvKGlycItmCw+Oef+ujva0= - -astral-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" - integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== - -async-each@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf" - integrity sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ== - -async-limiter@~1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" - integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ== - -async@^2.6.2: - version "2.6.3" - resolved "https://registry.yarnpkg.com/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff" - integrity sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg== - dependencies: - lodash "^4.17.14" - -asynckit@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" - integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= - -atob@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" - integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== - -autoprefixer@^9.6.1: - version "9.7.6" - resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.7.6.tgz#63ac5bbc0ce7934e6997207d5bb00d68fa8293a4" - integrity sha512-F7cYpbN7uVVhACZTeeIeealwdGM6wMtfWARVLTy5xmKtgVdBNJvbDRoCK3YO1orcs7gv/KwYlb3iXwu9Ug9BkQ== - dependencies: - browserslist "^4.11.1" - caniuse-lite "^1.0.30001039" - chalk "^2.4.2" - normalize-range "^0.1.2" - num2fraction "^1.2.2" - postcss "^7.0.27" - postcss-value-parser "^4.0.3" - -aws-sign2@~0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" - integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= - -aws4@^1.8.0: - version "1.9.1" - resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.9.1.tgz#7e33d8f7d449b3f673cd72deb9abdc552dbe528e" - integrity sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug== - -axios@0.20.0: - version "0.20.0" - resolved "https://registry.yarnpkg.com/axios/-/axios-0.20.0.tgz#057ba30f04884694993a8cd07fa394cff11c50bd" - integrity sha512-ANA4rr2BDcmmAQLOKft2fufrtuvlqR+cXNNinUmvfeSNCOF98PZL+7M/v1zIdGo7OLjEA9J2gXJL+j4zGsl0bA== - dependencies: - follow-redirects "^1.10.0" - -axobject-query@^2.0.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.1.2.tgz#2bdffc0371e643e5f03ba99065d5179b9ca79799" - integrity sha512-ICt34ZmrVt8UQnvPl6TVyDTkmhXmAyAT4Jh5ugfGUX4MOrZ+U/ZY6/sdylRw3qGNr9Ub5AJsaHeDMzNLehRdOQ== - -babel-code-frame@^6.22.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" - integrity sha1-Y/1D99weO7fONZR9uP42mj9Yx0s= - dependencies: - chalk "^1.1.3" - esutils "^2.0.2" - js-tokens "^3.0.2" - -babel-eslint@10.0.3: - version "10.0.3" - resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-10.0.3.tgz#81a2c669be0f205e19462fed2482d33e4687a88a" - integrity sha512-z3U7eMY6r/3f3/JB9mTsLjyxrv0Yb1zb8PCWCLpguxfCzBIZUwy23R1t/XKewP+8mEN2Ck8Dtr4q20z6ce6SoA== - dependencies: - "@babel/code-frame" "^7.0.0" - "@babel/parser" "^7.0.0" - "@babel/traverse" "^7.0.0" - "@babel/types" "^7.0.0" - eslint-visitor-keys "^1.0.0" - resolve "^1.12.0" - -babel-extract-comments@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/babel-extract-comments/-/babel-extract-comments-1.0.0.tgz#0a2aedf81417ed391b85e18b4614e693a0351a21" - integrity sha512-qWWzi4TlddohA91bFwgt6zO/J0X+io7Qp184Fw0m2JYRSTZnJbFR8+07KmzudHCZgOiKRCrjhylwv9Xd8gfhVQ== - dependencies: - babylon "^6.18.0" - -babel-jest@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-24.9.0.tgz#3fc327cb8467b89d14d7bc70e315104a783ccd54" - integrity sha512-ntuddfyiN+EhMw58PTNL1ph4C9rECiQXjI4nMMBKBaNjXvqLdkXpPRcMSr4iyBrJg/+wz9brFUD6RhOAT6r4Iw== - dependencies: - "@jest/transform" "^24.9.0" - "@jest/types" "^24.9.0" - "@types/babel__core" "^7.1.0" - babel-plugin-istanbul "^5.1.0" - babel-preset-jest "^24.9.0" - chalk "^2.4.2" - slash "^2.0.0" - -babel-loader@8.0.6: - version "8.0.6" - resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.0.6.tgz#e33bdb6f362b03f4bb141a0c21ab87c501b70dfb" - integrity sha512-4BmWKtBOBm13uoUwd08UwjZlaw3O9GWf456R9j+5YykFZ6LUIjIKLc0zEZf+hauxPOJs96C8k6FvYD09vWzhYw== - dependencies: - find-cache-dir "^2.0.0" - loader-utils "^1.0.2" - mkdirp "^0.5.1" - pify "^4.0.1" - -babel-plugin-dynamic-import-node@^2.3.3: - version "2.3.3" - resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz#84fda19c976ec5c6defef57f9427b3def66e17a3" - integrity sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ== - dependencies: - object.assign "^4.1.0" - -babel-plugin-istanbul@^5.1.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-5.2.0.tgz#df4ade83d897a92df069c4d9a25cf2671293c854" - integrity sha512-5LphC0USA8t4i1zCtjbbNb6jJj/9+X6P37Qfirc/70EQ34xKlMW+a1RHGwxGI+SwWpNwZ27HqvzAobeqaXwiZw== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - find-up "^3.0.0" - istanbul-lib-instrument "^3.3.0" - test-exclude "^5.2.3" - -babel-plugin-jest-hoist@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-24.9.0.tgz#4f837091eb407e01447c8843cbec546d0002d756" - integrity sha512-2EMA2P8Vp7lG0RAzr4HXqtYwacfMErOuv1U3wrvxHX6rD1sV6xS3WXG3r8TRQ2r6w8OhvSdWt+z41hQNwNm3Xw== - dependencies: - "@types/babel__traverse" "^7.0.6" - -babel-plugin-macros@2.8.0: - version "2.8.0" - resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-2.8.0.tgz#0f958a7cc6556b1e65344465d99111a1e5e10138" - integrity sha512-SEP5kJpfGYqYKpBrj5XU3ahw5p5GOHJ0U5ssOSQ/WBVdwkD2Dzlce95exQTs3jOVWPPKLBN2rlEWkCK7dSmLvg== - dependencies: - "@babel/runtime" "^7.7.2" - cosmiconfig "^6.0.0" - resolve "^1.12.0" - -babel-plugin-named-asset-import@^0.3.6: - version "0.3.6" - resolved "https://registry.yarnpkg.com/babel-plugin-named-asset-import/-/babel-plugin-named-asset-import-0.3.6.tgz#c9750a1b38d85112c9e166bf3ef7c5dbc605f4be" - integrity sha512-1aGDUfL1qOOIoqk9QKGIo2lANk+C7ko/fqH0uIyC71x3PEGz0uVP8ISgfEsFuG+FKmjHTvFK/nNM8dowpmUxLA== - -"babel-plugin-styled-components@>= 1": - version "1.10.7" - resolved "https://registry.yarnpkg.com/babel-plugin-styled-components/-/babel-plugin-styled-components-1.10.7.tgz#3494e77914e9989b33cc2d7b3b29527a949d635c" - integrity sha512-MBMHGcIA22996n9hZRf/UJLVVgkEOITuR2SvjHLb5dSTUyR4ZRGn+ngITapes36FI3WLxZHfRhkA1ffHxihOrg== - dependencies: - "@babel/helper-annotate-as-pure" "^7.0.0" - "@babel/helper-module-imports" "^7.0.0" - babel-plugin-syntax-jsx "^6.18.0" - lodash "^4.17.11" - -babel-plugin-syntax-jsx@^6.18.0: - version "6.18.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz#0af32a9a6e13ca7a3fd5069e62d7b0f58d0d8946" - integrity sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY= - -babel-plugin-syntax-object-rest-spread@^6.8.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz#fd6536f2bce13836ffa3a5458c4903a597bb3bf5" - integrity sha1-/WU28rzhODb/o6VFjEkDpZe7O/U= - -babel-plugin-transform-object-rest-spread@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.26.0.tgz#0f36692d50fef6b7e2d4b3ac1478137a963b7b06" - integrity sha1-DzZpLVD+9rfi1LOsFHgTepY7ewY= - dependencies: - babel-plugin-syntax-object-rest-spread "^6.8.0" - babel-runtime "^6.26.0" - -babel-plugin-transform-react-remove-prop-types@0.4.24: - version "0.4.24" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-remove-prop-types/-/babel-plugin-transform-react-remove-prop-types-0.4.24.tgz#f2edaf9b4c6a5fbe5c1d678bfb531078c1555f3a" - integrity sha512-eqj0hVcJUR57/Ug2zE1Yswsw4LhuqqHhD+8v120T1cl3kjg76QwtyBrdIk4WVwK+lAhBJVYCd/v+4nc4y+8JsA== - -babel-preset-jest@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-24.9.0.tgz#192b521e2217fb1d1f67cf73f70c336650ad3cdc" - integrity sha512-izTUuhE4TMfTRPF92fFwD2QfdXaZW08qvWTFCI51V8rW5x00UuPgc3ajRoWofXOuxjfcOM5zzSYsQS3H8KGCAg== - dependencies: - "@babel/plugin-syntax-object-rest-spread" "^7.0.0" - babel-plugin-jest-hoist "^24.9.0" - -babel-preset-react-app@^9.1.1: - version "9.1.2" - resolved "https://registry.yarnpkg.com/babel-preset-react-app/-/babel-preset-react-app-9.1.2.tgz#54775d976588a8a6d1a99201a702befecaf48030" - integrity sha512-k58RtQOKH21NyKtzptoAvtAODuAJJs3ZhqBMl456/GnXEQ/0La92pNmwgWoMn5pBTrsvk3YYXdY7zpY4e3UIxA== - dependencies: - "@babel/core" "7.9.0" - "@babel/plugin-proposal-class-properties" "7.8.3" - "@babel/plugin-proposal-decorators" "7.8.3" - "@babel/plugin-proposal-nullish-coalescing-operator" "7.8.3" - "@babel/plugin-proposal-numeric-separator" "7.8.3" - "@babel/plugin-proposal-optional-chaining" "7.9.0" - "@babel/plugin-transform-flow-strip-types" "7.9.0" - "@babel/plugin-transform-react-display-name" "7.8.3" - "@babel/plugin-transform-runtime" "7.9.0" - "@babel/preset-env" "7.9.0" - "@babel/preset-react" "7.9.1" - "@babel/preset-typescript" "7.9.0" - "@babel/runtime" "7.9.0" - babel-plugin-macros "2.8.0" - babel-plugin-transform-react-remove-prop-types "0.4.24" - -babel-runtime@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" - integrity sha1-llxwWGaOgrVde/4E/yM3vItWR/4= - dependencies: - core-js "^2.4.0" - regenerator-runtime "^0.11.0" - -babylon@^6.18.0: - version "6.18.0" - resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" - integrity sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ== - -bail@^1.0.0: - version "1.0.5" - resolved "https://registry.yarnpkg.com/bail/-/bail-1.0.5.tgz#b6fa133404a392cbc1f8c4bf63f5953351e7a776" - integrity sha512-xFbRxM1tahm08yHBP16MMjVUAvDaBMD38zsM9EMAUN61omwLmKlOpB/Zku5QkjZ8TZ4vn53pj+t518cH0S03RQ== - -balanced-match@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" - integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= - -base64-js@^1.0.2: - version "1.3.1" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.1.tgz#58ece8cb75dd07e71ed08c736abc5fac4dbf8df1" - integrity sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g== - -base@^0.11.1: - version "0.11.2" - resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" - integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== - dependencies: - cache-base "^1.0.1" - class-utils "^0.3.5" - component-emitter "^1.2.1" - define-property "^1.0.0" - isobject "^3.0.1" - mixin-deep "^1.2.0" - pascalcase "^0.1.1" - -batch@0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/batch/-/batch-0.6.1.tgz#dc34314f4e679318093fc760272525f94bf25c16" - integrity sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY= - -bcrypt-pbkdf@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" - integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4= - dependencies: - tweetnacl "^0.14.3" - -big.js@^5.2.2: - version "5.2.2" - resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" - integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== - -binary-extensions@^1.0.0: - version "1.13.1" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65" - integrity sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw== - -binary-extensions@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.0.0.tgz#23c0df14f6a88077f5f986c0d167ec03c3d5537c" - integrity sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow== - -bindings@^1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" - integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== - dependencies: - file-uri-to-path "1.0.0" - -bluebird@^3.5.5: - version "3.7.2" - resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" - integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== - -bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.4.0: - version "4.11.8" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" - integrity sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA== - -bn.js@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.1.1.tgz#48efc4031a9c4041b9c99c6941d903463ab62eb5" - integrity sha512-IUTD/REb78Z2eodka1QZyyEk66pciRcP6Sroka0aI3tG/iwIdYLrBD62RsubR7vqdt3WyX8p4jxeatzmRSphtA== - -body-parser@1.19.0: - version "1.19.0" - resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a" - integrity sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw== - dependencies: - bytes "3.1.0" - content-type "~1.0.4" - debug "2.6.9" - depd "~1.1.2" - http-errors "1.7.2" - iconv-lite "0.4.24" - on-finished "~2.3.0" - qs "6.7.0" - raw-body "2.4.0" - type-is "~1.6.17" - -bonjour@^3.5.0: - version "3.5.0" - resolved "https://registry.yarnpkg.com/bonjour/-/bonjour-3.5.0.tgz#8e890a183d8ee9a2393b3844c691a42bcf7bc9f5" - integrity sha1-jokKGD2O6aI5OzhExpGkK897yfU= - dependencies: - array-flatten "^2.1.0" - deep-equal "^1.0.1" - dns-equal "^1.0.0" - dns-txt "^2.0.2" - multicast-dns "^6.0.1" - multicast-dns-service-types "^1.1.0" - -boolbase@^1.0.0, boolbase@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" - integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24= - -brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== - dependencies: - balanced-match "^1.0.0" - concat-map "0.0.1" - -braces@^2.3.1, braces@^2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" - integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== - dependencies: - arr-flatten "^1.1.0" - array-unique "^0.3.2" - extend-shallow "^2.0.1" - fill-range "^4.0.0" - isobject "^3.0.1" - repeat-element "^1.1.2" - snapdragon "^0.8.1" - snapdragon-node "^2.0.1" - split-string "^3.0.2" - to-regex "^3.0.1" - -braces@^3.0.1, braces@~3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" - integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== - dependencies: - fill-range "^7.0.1" - -brorand@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" - integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8= - -browser-process-hrtime@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626" - integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow== - -browser-resolve@^1.11.3: - version "1.11.3" - resolved "https://registry.yarnpkg.com/browser-resolve/-/browser-resolve-1.11.3.tgz#9b7cbb3d0f510e4cb86bdbd796124d28b5890af6" - integrity sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ== - dependencies: - resolve "1.1.7" - -browserify-aes@^1.0.0, browserify-aes@^1.0.4: - version "1.2.0" - resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" - integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA== - dependencies: - buffer-xor "^1.0.3" - cipher-base "^1.0.0" - create-hash "^1.1.0" - evp_bytestokey "^1.0.3" - inherits "^2.0.1" - safe-buffer "^5.0.1" - -browserify-cipher@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.1.tgz#8d6474c1b870bfdabcd3bcfcc1934a10e94f15f0" - integrity sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w== - dependencies: - browserify-aes "^1.0.4" - browserify-des "^1.0.0" - evp_bytestokey "^1.0.0" - -browserify-des@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.2.tgz#3af4f1f59839403572f1c66204375f7a7f703e9c" - integrity sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A== - dependencies: - cipher-base "^1.0.1" - des.js "^1.0.0" - inherits "^2.0.1" - safe-buffer "^5.1.2" - -browserify-rsa@^4.0.0, browserify-rsa@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.0.1.tgz#21e0abfaf6f2029cf2fafb133567a701d4135524" - integrity sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ= - dependencies: - bn.js "^4.1.0" - randombytes "^2.0.1" - -browserify-sign@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.1.0.tgz#4fe971b379a5aeb4925e06779f9fa1f41d249d70" - integrity sha512-VYxo7cDCeYUoBZ0ZCy4UyEUCP3smyBd4DRQM5nrFS1jJjPJjX7rP3oLRpPoWfkhQfyJ0I9ZbHbKafrFD/SGlrg== - dependencies: - bn.js "^5.1.1" - browserify-rsa "^4.0.1" - create-hash "^1.2.0" - create-hmac "^1.1.7" - elliptic "^6.5.2" - inherits "^2.0.4" - parse-asn1 "^5.1.5" - readable-stream "^3.6.0" - -browserify-zlib@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.2.0.tgz#2869459d9aa3be245fe8fe2ca1f46e2e7f54d73f" - integrity sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA== - dependencies: - pako "~1.0.5" - -browserslist@4.10.0: - version "4.10.0" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.10.0.tgz#f179737913eaf0d2b98e4926ac1ca6a15cbcc6a9" - integrity sha512-TpfK0TDgv71dzuTsEAlQiHeWQ/tiPqgNZVdv046fvNtBZrjbv2O3TsWCDU0AWGJJKCF/KsjNdLzR9hXOsh/CfA== - dependencies: - caniuse-lite "^1.0.30001035" - electron-to-chromium "^1.3.378" - node-releases "^1.1.52" - pkg-up "^3.1.0" - -browserslist@^4.0.0, browserslist@^4.11.1, browserslist@^4.6.2, browserslist@^4.6.4, browserslist@^4.8.5, browserslist@^4.9.1: - version "4.12.0" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.12.0.tgz#06c6d5715a1ede6c51fc39ff67fd647f740b656d" - integrity sha512-UH2GkcEDSI0k/lRkuDSzFl9ZZ87skSy9w2XAn1MsZnL+4c4rqbBd3e82UWHbYDpztABrPBhZsTEeuxVfHppqDg== - dependencies: - caniuse-lite "^1.0.30001043" - electron-to-chromium "^1.3.413" - node-releases "^1.1.53" - pkg-up "^2.0.0" - -bser@2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" - integrity sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ== - dependencies: - node-int64 "^0.4.0" - -buffer-from@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" - integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== - -buffer-indexof@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/buffer-indexof/-/buffer-indexof-1.1.1.tgz#52fabcc6a606d1a00302802648ef68f639da268c" - integrity sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g== - -buffer-xor@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" - integrity sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk= - -buffer@^4.3.0: - version "4.9.2" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.2.tgz#230ead344002988644841ab0244af8c44bbe3ef8" - integrity sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg== - dependencies: - base64-js "^1.0.2" - ieee754 "^1.1.4" - isarray "^1.0.0" - -builtin-status-codes@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" - integrity sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug= - -bytes@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" - integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg= - -bytes@3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" - integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg== - -cacache@^12.0.2: - version "12.0.4" - resolved "https://registry.yarnpkg.com/cacache/-/cacache-12.0.4.tgz#668bcbd105aeb5f1d92fe25570ec9525c8faa40c" - integrity sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ== - dependencies: - bluebird "^3.5.5" - chownr "^1.1.1" - figgy-pudding "^3.5.1" - glob "^7.1.4" - graceful-fs "^4.1.15" - infer-owner "^1.0.3" - lru-cache "^5.1.1" - mississippi "^3.0.0" - mkdirp "^0.5.1" - move-concurrently "^1.0.1" - promise-inflight "^1.0.1" - rimraf "^2.6.3" - ssri "^6.0.1" - unique-filename "^1.1.1" - y18n "^4.0.0" - -cacache@^13.0.1: - version "13.0.1" - resolved "https://registry.yarnpkg.com/cacache/-/cacache-13.0.1.tgz#a8000c21697089082f85287a1aec6e382024a71c" - integrity sha512-5ZvAxd05HDDU+y9BVvcqYu2LLXmPnQ0hW62h32g4xBTgL/MppR4/04NHfj/ycM2y6lmTnbw6HVi+1eN0Psba6w== - dependencies: - chownr "^1.1.2" - figgy-pudding "^3.5.1" - fs-minipass "^2.0.0" - glob "^7.1.4" - graceful-fs "^4.2.2" - infer-owner "^1.0.4" - lru-cache "^5.1.1" - minipass "^3.0.0" - minipass-collect "^1.0.2" - minipass-flush "^1.0.5" - minipass-pipeline "^1.2.2" - mkdirp "^0.5.1" - move-concurrently "^1.0.1" - p-map "^3.0.0" - promise-inflight "^1.0.1" - rimraf "^2.7.1" - ssri "^7.0.0" - unique-filename "^1.1.1" - -cache-base@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" - integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== - dependencies: - collection-visit "^1.0.0" - component-emitter "^1.2.1" - get-value "^2.0.6" - has-value "^1.0.0" - isobject "^3.0.1" - set-value "^2.0.0" - to-object-path "^0.3.0" - union-value "^1.0.0" - unset-value "^1.0.0" - -call-me-maybe@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.1.tgz#26d208ea89e37b5cbde60250a15f031c16a4d66b" - integrity sha1-JtII6onje1y95gJQoV8DHBak1ms= - -caller-callsite@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/caller-callsite/-/caller-callsite-2.0.0.tgz#847e0fce0a223750a9a027c54b33731ad3154134" - integrity sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ= - dependencies: - callsites "^2.0.0" - -caller-path@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-2.0.0.tgz#468f83044e369ab2010fac5f06ceee15bb2cb1f4" - integrity sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ= - dependencies: - caller-callsite "^2.0.0" - -callsites@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50" - integrity sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA= - -callsites@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" - integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== - -camel-case@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-4.1.1.tgz#1fc41c854f00e2f7d0139dfeba1542d6896fe547" - integrity sha512-7fa2WcG4fYFkclIvEmxBbTvmibwF2/agfEBc6q3lOpVu0A13ltLsA+Hr/8Hp6kp5f+G7hKi6t8lys6XxP+1K6Q== - dependencies: - pascal-case "^3.1.1" - tslib "^1.10.0" - -camelcase@5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.0.0.tgz#03295527d58bd3cd4aa75363f35b2e8d97be2f42" - integrity sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA== - -camelcase@5.3.1, camelcase@^5.0.0, camelcase@^5.3.1: - version "5.3.1" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" - integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== - -camelize@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/camelize/-/camelize-1.0.0.tgz#164a5483e630fa4321e5af07020e531831b2609b" - integrity sha1-FkpUg+Yw+kMh5a8HAg5TGDGyYJs= - -caniuse-api@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-3.0.0.tgz#5e4d90e2274961d46291997df599e3ed008ee4c0" - integrity sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw== - dependencies: - browserslist "^4.0.0" - caniuse-lite "^1.0.0" - lodash.memoize "^4.1.2" - lodash.uniq "^4.5.0" - -caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000981, caniuse-lite@^1.0.30001035, caniuse-lite@^1.0.30001039, caniuse-lite@^1.0.30001043: - version "1.0.30001053" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001053.tgz#b7ae027567ce2665b965b0437e4512b296ccd20d" - integrity sha512-HtV4wwIZl6GA4Oznse8aR274XUOYGZnQLcf/P8vHgmlfqSNelwD+id8CyHOceqLqt9yfKmo7DUZTh1EuS9pukg== - -capture-exit@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/capture-exit/-/capture-exit-2.0.0.tgz#fb953bfaebeb781f62898239dabb426d08a509a4" - integrity sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g== - dependencies: - rsvp "^4.8.4" - -case-sensitive-paths-webpack-plugin@2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.3.0.tgz#23ac613cc9a856e4f88ff8bb73bbb5e989825cf7" - integrity sha512-/4YgnZS8y1UXXmC02xD5rRrBEu6T5ub+mQHLNRj0fzTRbgdBYhsNo2V5EqwgqrExjxsjtF/OpAKAMkKsxbD5XQ== - -caseless@~0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" - integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= - -chalk@2.4.2, chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.4.1, chalk@^2.4.2: - version "2.4.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" - integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== - dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" - -chalk@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" - integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg= - dependencies: - ansi-styles "^2.2.1" - escape-string-regexp "^1.0.2" - has-ansi "^2.0.0" - strip-ansi "^3.0.0" - supports-color "^2.0.0" - -chalk@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4" - integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - -character-entities-legacy@^1.0.0: - version "1.1.4" - resolved "https://registry.yarnpkg.com/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz#94bc1845dce70a5bb9d2ecc748725661293d8fc1" - integrity sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA== - -character-entities@^1.0.0: - version "1.2.4" - resolved "https://registry.yarnpkg.com/character-entities/-/character-entities-1.2.4.tgz#e12c3939b7eaf4e5b15e7ad4c5e28e1d48c5b16b" - integrity sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw== - -character-reference-invalid@^1.0.0: - version "1.1.4" - resolved "https://registry.yarnpkg.com/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz#083329cda0eae272ab3dbbf37e9a382c13af1560" - integrity sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg== - -chardet@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" - integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== - -chokidar@^2.1.8: - version "2.1.8" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.8.tgz#804b3a7b6a99358c3c5c61e71d8728f041cff917" - integrity sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg== - dependencies: - anymatch "^2.0.0" - async-each "^1.0.1" - braces "^2.3.2" - glob-parent "^3.1.0" - inherits "^2.0.3" - is-binary-path "^1.0.0" - is-glob "^4.0.0" - normalize-path "^3.0.0" - path-is-absolute "^1.0.0" - readdirp "^2.2.1" - upath "^1.1.1" - optionalDependencies: - fsevents "^1.2.7" - -chokidar@^3.3.0: - version "3.4.0" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.4.0.tgz#b30611423ce376357c765b9b8f904b9fba3c0be8" - integrity sha512-aXAaho2VJtisB/1fg1+3nlLJqGOuewTzQpd/Tz0yTg2R0e4IGtshYvtjowyEumcBv2z+y4+kc75Mz7j5xJskcQ== - dependencies: - anymatch "~3.1.1" - braces "~3.0.2" - glob-parent "~5.1.0" - is-binary-path "~2.1.0" - is-glob "~4.0.1" - normalize-path "~3.0.0" - readdirp "~3.4.0" - optionalDependencies: - fsevents "~2.1.2" - -chownr@^1.1.1, chownr@^1.1.2: - version "1.1.4" - resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" - integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== - -chrome-trace-event@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz#234090ee97c7d4ad1a2c4beae27505deffc608a4" - integrity sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ== - dependencies: - tslib "^1.9.0" - -ci-info@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" - integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== - -cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" - integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q== - dependencies: - inherits "^2.0.1" - safe-buffer "^5.0.1" - -class-utils@^0.3.5: - version "0.3.6" - resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" - integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== - dependencies: - arr-union "^3.1.0" - define-property "^0.2.5" - isobject "^3.0.0" - static-extend "^0.1.1" - -clean-css@^4.2.3: - version "4.2.3" - resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.2.3.tgz#507b5de7d97b48ee53d84adb0160ff6216380f78" - integrity sha512-VcMWDN54ZN/DS+g58HYL5/n4Zrqe8vHJpGA8KdgUXFU4fuP/aHNw8eld9SyEIyabIMJX/0RaY/fplOo5hYLSFA== - dependencies: - source-map "~0.6.0" - -clean-stack@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" - integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== - -cli-cursor@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" - integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== - dependencies: - restore-cursor "^3.1.0" - -cli-width@^2.0.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.1.tgz#b0433d0b4e9c847ef18868a4ef16fd5fc8271c48" - integrity sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw== - -cliui@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-4.1.0.tgz#348422dbe82d800b3022eef4f6ac10bf2e4d1b49" - integrity sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ== - dependencies: - string-width "^2.1.1" - strip-ansi "^4.0.0" - wrap-ansi "^2.0.0" - -cliui@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5" - integrity sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA== - dependencies: - string-width "^3.1.0" - strip-ansi "^5.2.0" - wrap-ansi "^5.1.0" - -clone-deep@^0.2.4: - version "0.2.4" - resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-0.2.4.tgz#4e73dd09e9fb971cc38670c5dced9c1896481cc6" - integrity sha1-TnPdCen7lxzDhnDF3O2cGJZIHMY= - dependencies: - for-own "^0.1.3" - is-plain-object "^2.0.1" - kind-of "^3.0.2" - lazy-cache "^1.0.3" - shallow-clone "^0.1.2" - -clone-deep@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387" - integrity sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ== - dependencies: - is-plain-object "^2.0.4" - kind-of "^6.0.2" - shallow-clone "^3.0.0" - -clsx@^1.0.2, clsx@^1.0.4: - version "1.1.0" - resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.1.0.tgz#62937c6adfea771247c34b54d320fb99624f5702" - integrity sha512-3avwM37fSK5oP6M5rQ9CNe99lwxhXDOeSWVPAOYF6OazUTgZCMb0yWlJpmdD74REy1gkEaFiub2ULv4fq9GUhA== - -co@^4.6.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" - integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ= - -coa@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/coa/-/coa-2.0.2.tgz#43f6c21151b4ef2bf57187db0d73de229e3e7ec3" - integrity sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA== - dependencies: - "@types/q" "^1.5.1" - chalk "^2.4.1" - q "^1.1.2" - -code-point-at@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" - integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= - -collapse-white-space@^1.0.2: - version "1.0.6" - resolved "https://registry.yarnpkg.com/collapse-white-space/-/collapse-white-space-1.0.6.tgz#e63629c0016665792060dbbeb79c42239d2c5287" - integrity sha512-jEovNnrhMuqyCcjfEJA56v0Xq8SkIoPKDyaHahwo3POf4qcSXqMYuwNcOTzp74vTsR9Tn08z4MxWqAhcekogkQ== - -collection-visit@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" - integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA= - dependencies: - map-visit "^1.0.0" - object-visit "^1.0.0" - -color-convert@^1.9.0, color-convert@^1.9.1: - version "1.9.3" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" - integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== - dependencies: - color-name "1.1.3" - -color-convert@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" - integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== - dependencies: - color-name "~1.1.4" - -color-name@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" - integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= - -color-name@^1.0.0, color-name@~1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" - integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== - -color-string@^1.5.2: - version "1.5.3" - resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.5.3.tgz#c9bbc5f01b58b5492f3d6857459cb6590ce204cc" - integrity sha512-dC2C5qeWoYkxki5UAXapdjqO672AM4vZuPGRQfO8b5HKuKGBbKWpITyDYN7TOFKvRW7kOgAn3746clDBMDJyQw== - dependencies: - color-name "^1.0.0" - simple-swizzle "^0.2.2" - -color@^3.0.0: - version "3.1.2" - resolved "https://registry.yarnpkg.com/color/-/color-3.1.2.tgz#68148e7f85d41ad7649c5fa8c8106f098d229e10" - integrity sha512-vXTJhHebByxZn3lDvDJYw4lR5+uB3vuoHsuYA5AKuxRVn5wzzIfQKGLBmgdVRHKTJYeK5rvJcHnrd0Li49CFpg== - dependencies: - color-convert "^1.9.1" - color-string "^1.5.2" - -combined-stream@^1.0.6, combined-stream@~1.0.6: - version "1.0.8" - resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" - integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== - dependencies: - delayed-stream "~1.0.0" - -commander@^2.11.0, commander@^2.20.0: - version "2.20.3" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" - integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== - -commander@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068" - integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA== - -common-tags@^1.8.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/common-tags/-/common-tags-1.8.0.tgz#8e3153e542d4a39e9b10554434afaaf98956a937" - integrity sha512-6P6g0uetGpW/sdyUy/iQQCbFF0kWVMSIVSyYz7Zgjcgh8mgw8PQzDNZeyZ5DQ2gM7LBoZPHmnjz8rUthkBG5tw== - -commondir@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" - integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= - -component-emitter@^1.2.1: - version "1.3.0" - resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" - integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== - -compose-function@3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/compose-function/-/compose-function-3.0.3.tgz#9ed675f13cc54501d30950a486ff6a7ba3ab185f" - integrity sha1-ntZ18TzFRQHTCVCkhv9qe6OrGF8= - dependencies: - arity-n "^1.0.4" - -compressible@~2.0.16: - version "2.0.18" - resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.18.tgz#af53cca6b070d4c3c0750fbd77286a6d7cc46fba" - integrity sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg== - dependencies: - mime-db ">= 1.43.0 < 2" - -compression@^1.7.4: - version "1.7.4" - resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.4.tgz#95523eff170ca57c29a0ca41e6fe131f41e5bb8f" - integrity sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ== - dependencies: - accepts "~1.3.5" - bytes "3.0.0" - compressible "~2.0.16" - debug "2.6.9" - on-headers "~1.0.2" - safe-buffer "5.1.2" - vary "~1.1.2" - -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= - -concat-stream@^1.5.0: - version "1.6.2" - resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" - integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== - dependencies: - buffer-from "^1.0.0" - inherits "^2.0.3" - readable-stream "^2.2.2" - typedarray "^0.0.6" - -confusing-browser-globals@^1.0.9: - version "1.0.9" - resolved "https://registry.yarnpkg.com/confusing-browser-globals/-/confusing-browser-globals-1.0.9.tgz#72bc13b483c0276801681871d4898516f8f54fdd" - integrity sha512-KbS1Y0jMtyPgIxjO7ZzMAuUpAKMt1SzCL9fsrKsX6b0zJPTaT0SiSPmewwVZg9UAO83HVIlEhZF84LIjZ0lmAw== - -connect-history-api-fallback@^1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz#8b32089359308d111115d81cad3fceab888f97bc" - integrity sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg== - -console-browserify@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.2.0.tgz#67063cef57ceb6cf4993a2ab3a55840ae8c49336" - integrity sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA== - -constants-browserify@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" - integrity sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U= - -contains-path@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a" - integrity sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo= - -content-disposition@0.5.3: - version "0.5.3" - resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd" - integrity sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g== - dependencies: - safe-buffer "5.1.2" - -content-type@~1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" - integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== - -convert-source-map@1.7.0, convert-source-map@^1.4.0, convert-source-map@^1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442" - integrity sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA== - dependencies: - safe-buffer "~5.1.1" - -convert-source-map@^0.3.3: - version "0.3.5" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-0.3.5.tgz#f1d802950af7dd2631a1febe0596550c86ab3190" - integrity sha1-8dgClQr33SYxof6+BZZVDIarMZA= - -cookie-signature@1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" - integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw= - -cookie@0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba" - integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg== - -copy-concurrently@^1.0.0: - version "1.0.5" - resolved "https://registry.yarnpkg.com/copy-concurrently/-/copy-concurrently-1.0.5.tgz#92297398cae34937fcafd6ec8139c18051f0b5e0" - integrity sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A== - dependencies: - aproba "^1.1.1" - fs-write-stream-atomic "^1.0.8" - iferr "^0.1.5" - mkdirp "^0.5.1" - rimraf "^2.5.4" - run-queue "^1.0.0" - -copy-descriptor@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" - integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= - -core-js-compat@^3.6.2: - version "3.6.5" - resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.6.5.tgz#2a51d9a4e25dfd6e690251aa81f99e3c05481f1c" - integrity sha512-7ItTKOhOZbznhXAQ2g/slGg1PJV5zDO/WdkTwi7UEOJmkvsE32PWvx6mKtDjiMpjnR2CNf6BAD6sSxIlv7ptng== - dependencies: - browserslist "^4.8.5" - semver "7.0.0" - -core-js@^2.4.0: - version "2.6.11" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.11.tgz#38831469f9922bded8ee21c9dc46985e0399308c" - integrity sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg== - -core-js@^3.5.0: - version "3.6.5" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.6.5.tgz#7395dc273af37fb2e50e9bd3d9fe841285231d1a" - integrity sha512-vZVEEwZoIsI+vPEuoF9Iqf5H7/M3eeQqWlQnYa8FSKKePuYTf5MWnxb5SDAzCa60b3JBRS5g9b+Dq7b1y/RCrA== - -core-util-is@1.0.2, core-util-is@~1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" - integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= - -cosmiconfig@^5.0.0, cosmiconfig@^5.2.1: - version "5.2.1" - resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.2.1.tgz#040f726809c591e77a17c0a3626ca45b4f168b1a" - integrity sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA== - dependencies: - import-fresh "^2.0.0" - is-directory "^0.3.1" - js-yaml "^3.13.1" - parse-json "^4.0.0" - -cosmiconfig@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-6.0.0.tgz#da4fee853c52f6b1e6935f41c1a2fc50bd4a9982" - integrity sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg== - dependencies: - "@types/parse-json" "^4.0.0" - import-fresh "^3.1.0" - parse-json "^5.0.0" - path-type "^4.0.0" - yaml "^1.7.2" - -create-ecdh@^4.0.0: - version "4.0.3" - resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.3.tgz#c9111b6f33045c4697f144787f9254cdc77c45ff" - integrity sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw== - dependencies: - bn.js "^4.1.0" - elliptic "^6.0.0" - -create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" - integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg== - dependencies: - cipher-base "^1.0.1" - inherits "^2.0.1" - md5.js "^1.3.4" - ripemd160 "^2.0.1" - sha.js "^2.4.0" - -create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7: - version "1.1.7" - resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" - integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg== - dependencies: - cipher-base "^1.0.3" - create-hash "^1.1.0" - inherits "^2.0.1" - ripemd160 "^2.0.0" - safe-buffer "^5.0.1" - sha.js "^2.4.8" - -cross-spawn@7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.1.tgz#0ab56286e0f7c24e153d04cc2aa027e43a9a5d14" - integrity sha512-u7v4o84SwFpD32Z8IIcPZ6z1/ie24O6RU3RbtL5Y316l3KuHVPx9ItBgWQ6VlfAFnRnTtMUrsQ9MUUTuEZjogg== - dependencies: - path-key "^3.1.0" - shebang-command "^2.0.0" - which "^2.0.1" - -cross-spawn@^6.0.0, cross-spawn@^6.0.5: - version "6.0.5" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" - integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== - dependencies: - nice-try "^1.0.4" - path-key "^2.0.1" - semver "^5.5.0" - shebang-command "^1.2.0" - which "^1.2.9" - -crypto-browserify@^3.11.0: - version "3.12.0" - resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" - integrity sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg== - dependencies: - browserify-cipher "^1.0.0" - browserify-sign "^4.0.0" - create-ecdh "^4.0.0" - create-hash "^1.1.0" - create-hmac "^1.1.0" - diffie-hellman "^5.0.0" - inherits "^2.0.1" - pbkdf2 "^3.0.3" - public-encrypt "^4.0.0" - randombytes "^2.0.0" - randomfill "^1.0.3" - -css-blank-pseudo@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/css-blank-pseudo/-/css-blank-pseudo-0.1.4.tgz#dfdefd3254bf8a82027993674ccf35483bfcb3c5" - integrity sha512-LHz35Hr83dnFeipc7oqFDmsjHdljj3TQtxGGiNWSOsTLIAubSm4TEz8qCaKFpk7idaQ1GfWscF4E6mgpBysA1w== - dependencies: - postcss "^7.0.5" - -css-color-keywords@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/css-color-keywords/-/css-color-keywords-1.0.0.tgz#fea2616dc676b2962686b3af8dbdbe180b244e05" - integrity sha1-/qJhbcZ2spYmhrOvjb2+GAskTgU= - -css-color-names@0.0.4, css-color-names@^0.0.4: - version "0.0.4" - resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0" - integrity sha1-gIrcLnnPhHOAabZGyyDsJ762KeA= - -css-declaration-sorter@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-4.0.1.tgz#c198940f63a76d7e36c1e71018b001721054cb22" - integrity sha512-BcxQSKTSEEQUftYpBVnsH4SF05NTuBokb19/sBt6asXGKZ/6VP7PLG1CBCkFDYOnhXhPh0jMhO6xZ71oYHXHBA== - dependencies: - postcss "^7.0.1" - timsort "^0.3.0" - -css-has-pseudo@^0.10.0: - version "0.10.0" - resolved "https://registry.yarnpkg.com/css-has-pseudo/-/css-has-pseudo-0.10.0.tgz#3c642ab34ca242c59c41a125df9105841f6966ee" - integrity sha512-Z8hnfsZu4o/kt+AuFzeGpLVhFOGO9mluyHBaA2bA8aCGTwah5sT3WV/fTHH8UNZUytOIImuGPrl/prlb4oX4qQ== - dependencies: - postcss "^7.0.6" - postcss-selector-parser "^5.0.0-rc.4" - -css-loader@3.4.2: - version "3.4.2" - resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-3.4.2.tgz#d3fdb3358b43f233b78501c5ed7b1c6da6133202" - integrity sha512-jYq4zdZT0oS0Iykt+fqnzVLRIeiPWhka+7BqPn+oSIpWJAHak5tmB/WZrJ2a21JhCeFyNnnlroSl8c+MtVndzA== - dependencies: - camelcase "^5.3.1" - cssesc "^3.0.0" - icss-utils "^4.1.1" - loader-utils "^1.2.3" - normalize-path "^3.0.0" - postcss "^7.0.23" - postcss-modules-extract-imports "^2.0.0" - postcss-modules-local-by-default "^3.0.2" - postcss-modules-scope "^2.1.1" - postcss-modules-values "^3.0.0" - postcss-value-parser "^4.0.2" - schema-utils "^2.6.0" - -css-prefers-color-scheme@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/css-prefers-color-scheme/-/css-prefers-color-scheme-3.1.1.tgz#6f830a2714199d4f0d0d0bb8a27916ed65cff1f4" - integrity sha512-MTu6+tMs9S3EUqzmqLXEcgNRbNkkD/TGFvowpeoWJn5Vfq7FMgsmRQs9X5NXAURiOBmOxm/lLjsDNXDE6k9bhg== - dependencies: - postcss "^7.0.5" - -css-select-base-adapter@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz#3b2ff4972cc362ab88561507a95408a1432135d7" - integrity sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w== - -css-select@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/css-select/-/css-select-1.2.0.tgz#2b3a110539c5355f1cd8d314623e870b121ec858" - integrity sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg= - dependencies: - boolbase "~1.0.0" - css-what "2.1" - domutils "1.5.1" - nth-check "~1.0.1" - -css-select@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/css-select/-/css-select-2.1.0.tgz#6a34653356635934a81baca68d0255432105dbef" - integrity sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ== - dependencies: - boolbase "^1.0.0" - css-what "^3.2.1" - domutils "^1.7.0" - nth-check "^1.0.2" - -css-to-react-native@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/css-to-react-native/-/css-to-react-native-3.0.0.tgz#62dbe678072a824a689bcfee011fc96e02a7d756" - integrity sha512-Ro1yETZA813eoyUp2GDBhG2j+YggidUmzO1/v9eYBKR2EHVEniE2MI/NqpTQ954BMpTPZFsGNPm46qFB9dpaPQ== - dependencies: - camelize "^1.0.0" - css-color-keywords "^1.0.0" - postcss-value-parser "^4.0.2" - -css-tree@1.0.0-alpha.37: - version "1.0.0-alpha.37" - resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.0.0-alpha.37.tgz#98bebd62c4c1d9f960ec340cf9f7522e30709a22" - integrity sha512-DMxWJg0rnz7UgxKT0Q1HU/L9BeJI0M6ksor0OgqOnF+aRCDWg/N2641HmVyU9KVIu0OVVWOb2IpC9A+BJRnejg== - dependencies: - mdn-data "2.0.4" - source-map "^0.6.1" - -css-tree@1.0.0-alpha.39: - version "1.0.0-alpha.39" - resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.0.0-alpha.39.tgz#2bff3ffe1bb3f776cf7eefd91ee5cba77a149eeb" - integrity sha512-7UvkEYgBAHRG9Nt980lYxjsTrCyHFN53ky3wVsDkiMdVqylqRt+Zc+jm5qw7/qyOvN2dHSYtX0e4MbCCExSvnA== - dependencies: - mdn-data "2.0.6" - source-map "^0.6.1" - -css-vendor@^2.0.7: - version "2.0.8" - resolved "https://registry.yarnpkg.com/css-vendor/-/css-vendor-2.0.8.tgz#e47f91d3bd3117d49180a3c935e62e3d9f7f449d" - integrity sha512-x9Aq0XTInxrkuFeHKbYC7zWY8ai7qJ04Kxd9MnvbC1uO5DagxoHQjm4JvG+vCdXOoFtCjbL2XSZfxmoYa9uQVQ== - dependencies: - "@babel/runtime" "^7.8.3" - is-in-browser "^1.0.2" - -css-what@2.1: - version "2.1.3" - resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.3.tgz#a6d7604573365fe74686c3f311c56513d88285f2" - integrity sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg== - -css-what@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/css-what/-/css-what-3.2.1.tgz#f4a8f12421064621b456755e34a03a2c22df5da1" - integrity sha512-WwOrosiQTvyms+Ti5ZC5vGEK0Vod3FTt1ca+payZqvKuGJF+dq7bG63DstxtN0dpm6FxY27a/zS3Wten+gEtGw== - -css@^2.0.0: - version "2.2.4" - resolved "https://registry.yarnpkg.com/css/-/css-2.2.4.tgz#c646755c73971f2bba6a601e2cf2fd71b1298929" - integrity sha512-oUnjmWpy0niI3x/mPL8dVEI1l7MnG3+HHyRPHf+YFSbK+svOhXpmSOcDURUh2aOCgl2grzrOPt1nHLuCVFULLw== - dependencies: - inherits "^2.0.3" - source-map "^0.6.1" - source-map-resolve "^0.5.2" - urix "^0.1.0" - -cssdb@^4.4.0: - version "4.4.0" - resolved "https://registry.yarnpkg.com/cssdb/-/cssdb-4.4.0.tgz#3bf2f2a68c10f5c6a08abd92378331ee803cddb0" - integrity sha512-LsTAR1JPEM9TpGhl/0p3nQecC2LJ0kD8X5YARu1hk/9I1gril5vDtMZyNxcEpxxDj34YNck/ucjuoUd66K03oQ== - -cssesc@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-2.0.0.tgz#3b13bd1bb1cb36e1bcb5a4dcd27f54c5dcb35703" - integrity sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg== - -cssesc@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" - integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== - -cssnano-preset-default@^4.0.7: - version "4.0.7" - resolved "https://registry.yarnpkg.com/cssnano-preset-default/-/cssnano-preset-default-4.0.7.tgz#51ec662ccfca0f88b396dcd9679cdb931be17f76" - integrity sha512-x0YHHx2h6p0fCl1zY9L9roD7rnlltugGu7zXSKQx6k2rYw0Hi3IqxcoAGF7u9Q5w1nt7vK0ulxV8Lo+EvllGsA== - dependencies: - css-declaration-sorter "^4.0.1" - cssnano-util-raw-cache "^4.0.1" - postcss "^7.0.0" - postcss-calc "^7.0.1" - postcss-colormin "^4.0.3" - postcss-convert-values "^4.0.1" - postcss-discard-comments "^4.0.2" - postcss-discard-duplicates "^4.0.2" - postcss-discard-empty "^4.0.1" - postcss-discard-overridden "^4.0.1" - postcss-merge-longhand "^4.0.11" - postcss-merge-rules "^4.0.3" - postcss-minify-font-values "^4.0.2" - postcss-minify-gradients "^4.0.2" - postcss-minify-params "^4.0.2" - postcss-minify-selectors "^4.0.2" - postcss-normalize-charset "^4.0.1" - postcss-normalize-display-values "^4.0.2" - postcss-normalize-positions "^4.0.2" - postcss-normalize-repeat-style "^4.0.2" - postcss-normalize-string "^4.0.2" - postcss-normalize-timing-functions "^4.0.2" - postcss-normalize-unicode "^4.0.1" - postcss-normalize-url "^4.0.1" - postcss-normalize-whitespace "^4.0.2" - postcss-ordered-values "^4.1.2" - postcss-reduce-initial "^4.0.3" - postcss-reduce-transforms "^4.0.2" - postcss-svgo "^4.0.2" - postcss-unique-selectors "^4.0.1" - -cssnano-util-get-arguments@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/cssnano-util-get-arguments/-/cssnano-util-get-arguments-4.0.0.tgz#ed3a08299f21d75741b20f3b81f194ed49cc150f" - integrity sha1-7ToIKZ8h11dBsg87gfGU7UnMFQ8= - -cssnano-util-get-match@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/cssnano-util-get-match/-/cssnano-util-get-match-4.0.0.tgz#c0e4ca07f5386bb17ec5e52250b4f5961365156d" - integrity sha1-wOTKB/U4a7F+xeUiULT1lhNlFW0= - -cssnano-util-raw-cache@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/cssnano-util-raw-cache/-/cssnano-util-raw-cache-4.0.1.tgz#b26d5fd5f72a11dfe7a7846fb4c67260f96bf282" - integrity sha512-qLuYtWK2b2Dy55I8ZX3ky1Z16WYsx544Q0UWViebptpwn/xDBmog2TLg4f+DBMg1rJ6JDWtn96WHbOKDWt1WQA== - dependencies: - postcss "^7.0.0" - -cssnano-util-same-parent@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/cssnano-util-same-parent/-/cssnano-util-same-parent-4.0.1.tgz#574082fb2859d2db433855835d9a8456ea18bbf3" - integrity sha512-WcKx5OY+KoSIAxBW6UBBRay1U6vkYheCdjyVNDm85zt5K9mHoGOfsOsqIszfAqrQQFIIKgjh2+FDgIj/zsl21Q== - -cssnano@^4.1.10: - version "4.1.10" - resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-4.1.10.tgz#0ac41f0b13d13d465487e111b778d42da631b8b2" - integrity sha512-5wny+F6H4/8RgNlaqab4ktc3e0/blKutmq8yNlBFXA//nSFFAqAngjNVRzUvCgYROULmZZUoosL/KSoZo5aUaQ== - dependencies: - cosmiconfig "^5.0.0" - cssnano-preset-default "^4.0.7" - is-resolvable "^1.0.0" - postcss "^7.0.0" - -csso@^4.0.2: - version "4.0.3" - resolved "https://registry.yarnpkg.com/csso/-/csso-4.0.3.tgz#0d9985dc852c7cc2b2cacfbbe1079014d1a8e903" - integrity sha512-NL3spysxUkcrOgnpsT4Xdl2aiEiBG6bXswAABQVHcMrfjjBisFOKwLDOmf4wf32aPdcJws1zds2B0Rg+jqMyHQ== - dependencies: - css-tree "1.0.0-alpha.39" - -cssom@0.3.x, "cssom@>= 0.3.2 < 0.4.0", cssom@^0.3.4: - version "0.3.8" - resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a" - integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg== - -cssstyle@^1.0.0, cssstyle@^1.1.1: - version "1.4.0" - resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-1.4.0.tgz#9d31328229d3c565c61e586b02041a28fccdccf1" - integrity sha512-GBrLZYZ4X4x6/QEoBnIrqb8B/f5l4+8me2dkom/j1Gtbxy0kBv6OGzKuAsGM75bkGwGAFkt56Iwg28S3XTZgSA== - dependencies: - cssom "0.3.x" - -csstype@^2.2.0, csstype@^2.5.2, csstype@^2.6.5, csstype@^2.6.7: - version "2.6.10" - resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.10.tgz#e63af50e66d7c266edb6b32909cfd0aabe03928b" - integrity sha512-D34BqZU4cIlMCY93rZHbrq9pjTAQJ3U8S8rfBqjwHxkGPThWFjzZDQpgMJY0QViLxth6ZKYiwFBo14RdN44U/w== - -cyclist@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-1.0.1.tgz#596e9698fd0c80e12038c2b82d6eb1b35b6224d9" - integrity sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk= - -d@1, d@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/d/-/d-1.0.1.tgz#8698095372d58dbee346ffd0c7093f99f8f9eb5a" - integrity sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA== - dependencies: - es5-ext "^0.10.50" - type "^1.0.1" - -damerau-levenshtein@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.6.tgz#143c1641cb3d85c60c32329e26899adea8701791" - integrity sha512-JVrozIeElnj3QzfUIt8tB8YMluBJom4Vw9qTPpjGYQ9fYlB3D/rb6OordUxf3xeFB35LKWs0xqcO5U6ySvBtug== - -dashdash@^1.12.0: - version "1.14.1" - resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" - integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA= - dependencies: - assert-plus "^1.0.0" - -data-urls@^1.0.0, data-urls@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-1.1.0.tgz#15ee0582baa5e22bb59c77140da8f9c76963bbfe" - integrity sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ== - dependencies: - abab "^2.0.0" - whatwg-mimetype "^2.2.0" - whatwg-url "^7.0.0" - -date-fns@2.14.0: - version "2.14.0" - resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.14.0.tgz#359a87a265bb34ef2e38f93ecf63ac453f9bc7ba" - integrity sha512-1zD+68jhFgDIM0rF05rcwYO8cExdNqxjq4xP1QKM60Q45mnO6zaMWB4tOzrIr4M4GSLntsKeE4c9Bdl2jhL/yw== - -debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.0, debug@^2.6.9: - version "2.6.9" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" - integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== - dependencies: - ms "2.0.0" - -debug@^3.0.0, debug@^3.1.1, debug@^3.2.5: - version "3.2.6" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" - integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== - dependencies: - ms "^2.1.1" - -debug@^4.0.1, debug@^4.1.0, debug@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" - integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== - dependencies: - ms "^2.1.1" - -decamelize@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" - integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= - -decode-uri-component@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" - integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= - -deep-equal@^1.0.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.1.1.tgz#b5c98c942ceffaf7cb051e24e1434a25a2e6076a" - integrity sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g== - dependencies: - is-arguments "^1.0.4" - is-date-object "^1.0.1" - is-regex "^1.0.4" - object-is "^1.0.1" - object-keys "^1.1.1" - regexp.prototype.flags "^1.2.0" - -deep-is@~0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" - integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= - -default-gateway@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/default-gateway/-/default-gateway-4.2.0.tgz#167104c7500c2115f6dd69b0a536bb8ed720552b" - integrity sha512-h6sMrVB1VMWVrW13mSc6ia/DwYYw5MN6+exNu1OaJeFac5aSAvwM7lZ0NVfTABuSkQelr4h5oebg3KB1XPdjgA== - dependencies: - execa "^1.0.0" - ip-regex "^2.1.0" - -define-properties@^1.1.2, define-properties@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" - integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== - dependencies: - object-keys "^1.0.12" - -define-property@^0.2.5: - version "0.2.5" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" - integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY= - dependencies: - is-descriptor "^0.1.0" - -define-property@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" - integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY= - dependencies: - is-descriptor "^1.0.0" - -define-property@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" - integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ== - dependencies: - is-descriptor "^1.0.2" - isobject "^3.0.1" - -del@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/del/-/del-4.1.1.tgz#9e8f117222ea44a31ff3a156c049b99052a9f0b4" - integrity sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ== - dependencies: - "@types/glob" "^7.1.1" - globby "^6.1.0" - is-path-cwd "^2.0.0" - is-path-in-cwd "^2.0.0" - p-map "^2.0.0" - pify "^4.0.1" - rimraf "^2.6.3" - -delayed-stream@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" - integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= - -depd@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" - integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= - -des.js@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.1.tgz#5382142e1bdc53f85d86d53e5f4aa7deb91e0843" - integrity sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA== - dependencies: - inherits "^2.0.1" - minimalistic-assert "^1.0.0" - -destroy@~1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" - integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= - -detect-newline@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-2.1.0.tgz#f41f1c10be4b00e87b5f13da680759f2c5bfd3e2" - integrity sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I= - -detect-node@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.4.tgz#014ee8f8f669c5c58023da64b8179c083a28c46c" - integrity sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw== - -detect-port-alt@1.1.6: - version "1.1.6" - resolved "https://registry.yarnpkg.com/detect-port-alt/-/detect-port-alt-1.1.6.tgz#24707deabe932d4a3cf621302027c2b266568275" - integrity sha512-5tQykt+LqfJFBEYaDITx7S7cR7mJ/zQmLXZ2qt5w04ainYZw6tBf9dBunMjVeVOdYVRUzUOE4HkY5J7+uttb5Q== - dependencies: - address "^1.0.1" - debug "^2.6.0" - -diff-sequences@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-24.9.0.tgz#5715d6244e2aa65f48bba0bc972db0b0b11e95b5" - integrity sha512-Dj6Wk3tWyTE+Fo1rW8v0Xhwk80um6yFYKbuAxc9c3EZxIHFDYwbi34Uk42u1CdnIiVorvt4RmlSDjIPyzGC2ew== - -diffie-hellman@^5.0.0: - version "5.0.3" - resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" - integrity sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg== - dependencies: - bn.js "^4.1.0" - miller-rabin "^4.0.0" - randombytes "^2.0.0" - -dir-glob@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-2.0.0.tgz#0b205d2b6aef98238ca286598a8204d29d0a0034" - integrity sha512-37qirFDz8cA5fimp9feo43fSuRo2gHwaIn6dXL8Ber1dGwUosDrGZeCCXq57WnIqE4aQ+u3eQZzsk1yOzhdwag== - dependencies: - arrify "^1.0.1" - path-type "^3.0.0" - -dns-equal@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/dns-equal/-/dns-equal-1.0.0.tgz#b39e7f1da6eb0a75ba9c17324b34753c47e0654d" - integrity sha1-s55/HabrCnW6nBcySzR1PEfgZU0= - -dns-packet@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/dns-packet/-/dns-packet-1.3.1.tgz#12aa426981075be500b910eedcd0b47dd7deda5a" - integrity sha512-0UxfQkMhYAUaZI+xrNZOz/as5KgDU0M/fQ9b6SpkyLbk3GEswDi6PADJVaYJradtRVsRIlF1zLyOodbcTCDzUg== - dependencies: - ip "^1.1.0" - safe-buffer "^5.0.1" - -dns-txt@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/dns-txt/-/dns-txt-2.0.2.tgz#b91d806f5d27188e4ab3e7d107d881a1cc4642b6" - integrity sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY= - dependencies: - buffer-indexof "^1.0.0" - -doctrine@1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" - integrity sha1-N53Ocw9hZvds76TmcHoVmwLFpvo= - dependencies: - esutils "^2.0.2" - isarray "^1.0.0" - -doctrine@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" - integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== - dependencies: - esutils "^2.0.2" - -doctrine@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" - integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== - dependencies: - esutils "^2.0.2" - -dom-converter@^0.2: - version "0.2.0" - resolved "https://registry.yarnpkg.com/dom-converter/-/dom-converter-0.2.0.tgz#6721a9daee2e293682955b6afe416771627bb768" - integrity sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA== - dependencies: - utila "~0.4" - -dom-helpers@^5.0.1: - version "5.1.4" - resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-5.1.4.tgz#4609680ab5c79a45f2531441f1949b79d6587f4b" - integrity sha512-TjMyeVUvNEnOnhzs6uAn9Ya47GmMo3qq7m+Lr/3ON0Rs5kHvb8I+SQYjLUSYn7qhEm0QjW0yrBkvz9yOrwwz1A== - dependencies: - "@babel/runtime" "^7.8.7" - csstype "^2.6.7" - -dom-serializer@0, dom-serializer@^0.2.1: - version "0.2.2" - resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.2.2.tgz#1afb81f533717175d478655debc5e332d9f9bb51" - integrity sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g== - dependencies: - domelementtype "^2.0.1" - entities "^2.0.0" - -domain-browser@^1.1.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda" - integrity sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA== - -domelementtype@1, domelementtype@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.1.tgz#d048c44b37b0d10a7f2a3d5fee3f4333d790481f" - integrity sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w== - -domelementtype@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.0.1.tgz#1f8bdfe91f5a78063274e803b4bdcedf6e94f94d" - integrity sha512-5HOHUDsYZWV8FGWN0Njbr/Rn7f/eWSQi1v7+HsUVwXgn8nWWlL64zKDkS0n8ZmQ3mlWOMuXOnR+7Nx/5tMO5AQ== - -domexception@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/domexception/-/domexception-1.0.1.tgz#937442644ca6a31261ef36e3ec677fe805582c90" - integrity sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug== - dependencies: - webidl-conversions "^4.0.2" - -domhandler@^2.3.0: - version "2.4.2" - resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.4.2.tgz#8805097e933d65e85546f726d60f5eb88b44f803" - integrity sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA== - dependencies: - domelementtype "1" - -domhandler@^3.0, domhandler@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-3.0.0.tgz#51cd13efca31da95bbb0c5bee3a48300e333b3e9" - integrity sha512-eKLdI5v9m67kbXQbJSNn1zjh0SDzvzWVWtX+qEI3eMjZw8daH9k8rlj1FZY9memPwjiskQFbe7vHVVJIAqoEhw== - dependencies: - domelementtype "^2.0.1" - -domutils@1.5.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.5.1.tgz#dcd8488a26f563d61079e48c9f7b7e32373682cf" - integrity sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8= - dependencies: - dom-serializer "0" - domelementtype "1" - -domutils@^1.5.1, domutils@^1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.7.0.tgz#56ea341e834e06e6748af7a1cb25da67ea9f8c2a" - integrity sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg== - dependencies: - dom-serializer "0" - domelementtype "1" - -domutils@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.0.0.tgz#15b8278e37bfa8468d157478c58c367718133c08" - integrity sha512-n5SelJ1axbO636c2yUtOGia/IcJtVtlhQbFiVDBZHKV5ReJO1ViX7sFEemtuyoAnBxk5meNSYgA8V4s0271efg== - dependencies: - dom-serializer "^0.2.1" - domelementtype "^2.0.1" - domhandler "^3.0.0" - -dot-case@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/dot-case/-/dot-case-3.0.3.tgz#21d3b52efaaba2ea5fda875bb1aa8124521cf4aa" - integrity sha512-7hwEmg6RiSQfm/GwPL4AAWXKy3YNNZA3oFv2Pdiey0mwkRCPZ9x6SZbkLcn8Ma5PYeVokzoD4Twv2n7LKp5WeA== - dependencies: - no-case "^3.0.3" - tslib "^1.10.0" - -dot-prop@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-5.2.0.tgz#c34ecc29556dc45f1f4c22697b6f4904e0cc4fcb" - integrity sha512-uEUyaDKoSQ1M4Oq8l45hSE26SnTxL6snNnqvK/VWx5wJhmff5z0FUVJDKDanor/6w3kzE3i7XZOk+7wC0EXr1A== - dependencies: - is-obj "^2.0.0" - -dotenv-expand@5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/dotenv-expand/-/dotenv-expand-5.1.0.tgz#3fbaf020bfd794884072ea26b1e9791d45a629f0" - integrity sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA== - -dotenv@8.2.0: - version "8.2.0" - resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.2.0.tgz#97e619259ada750eea3e4ea3e26bceea5424b16a" - integrity sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw== - -duplexer@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.1.tgz#ace6ff808c1ce66b57d1ebf97977acb02334cfc1" - integrity sha1-rOb/gIwc5mtX0ev5eXessCM0z8E= - -duplexify@^3.4.2, duplexify@^3.6.0: - version "3.7.1" - resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.7.1.tgz#2a4df5317f6ccfd91f86d6fd25d8d8a103b88309" - integrity sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g== - dependencies: - end-of-stream "^1.0.0" - inherits "^2.0.1" - readable-stream "^2.0.0" - stream-shift "^1.0.0" - -ecc-jsbn@~0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" - integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk= - dependencies: - jsbn "~0.1.0" - safer-buffer "^2.1.0" - -ee-first@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" - integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= - -electron-to-chromium@^1.3.378, electron-to-chromium@^1.3.413: - version "1.3.430" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.430.tgz#33914f7c2db771bdcf30977bd4fd6258ee8a2f37" - integrity sha512-HMDYkANGhx6vfbqpOf/hc6hWEmiOipOHGDeRDeUb3HLD3XIWpvKQxFgWf0tgHcr3aNv6I/8VPecplqmQsXoZSw== - -elliptic@^6.0.0, elliptic@^6.5.2: - version "6.5.2" - resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.2.tgz#05c5678d7173c049d8ca433552224a495d0e3762" - integrity sha512-f4x70okzZbIQl/NSRLkI/+tteV/9WqL98zx+SQ69KbXxmVrmjwsNUPn/gYJJ0sHvEak24cZgHIPegRePAtA/xw== - dependencies: - bn.js "^4.4.0" - brorand "^1.0.1" - hash.js "^1.0.0" - hmac-drbg "^1.0.0" - inherits "^2.0.1" - minimalistic-assert "^1.0.0" - minimalistic-crypto-utils "^1.0.0" - -emoji-regex@^7.0.1, emoji-regex@^7.0.2: - version "7.0.3" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" - integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== - -emoji-regex@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" - integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== - -emojis-list@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" - integrity sha1-TapNnbAPmBmIDHn6RXrlsJof04k= - -emojis-list@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78" - integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q== - -encodeurl@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" - integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= - -end-of-stream@^1.0.0, end-of-stream@^1.1.0: - version "1.4.4" - resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" - integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== - dependencies: - once "^1.4.0" - -enhanced-resolve@^4.1.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.1.1.tgz#2937e2b8066cd0fe7ce0990a98f0d71a35189f66" - integrity sha512-98p2zE+rL7/g/DzMHMTF4zZlCgeVdJ7yr6xzEpJRYwFYrGi9ANdn5DnJURg6RpBkyk60XYDnWIv51VfIhfNGuA== - dependencies: - graceful-fs "^4.1.2" - memory-fs "^0.5.0" - tapable "^1.0.0" - -entities@^1.1.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56" - integrity sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w== - -entities@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/entities/-/entities-2.0.0.tgz#68d6084cab1b079767540d80e56a39b423e4abf4" - integrity sha512-D9f7V0JSRwIxlRI2mjMqufDrRDnx8p+eEOz7aUM9SuvF8gsBzra0/6tbjl1m8eQHrZlYj6PxqE00hZ1SAIKPLw== - -errno@^0.1.3, errno@~0.1.7: - version "0.1.7" - resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618" - integrity sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg== - dependencies: - prr "~1.0.1" - -error-ex@^1.2.0, error-ex@^1.3.1: - version "1.3.2" - resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" - integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== - dependencies: - is-arrayish "^0.2.1" - -es-abstract@^1.17.0, es-abstract@^1.17.0-next.1, es-abstract@^1.17.2, es-abstract@^1.17.5: - version "1.17.5" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.5.tgz#d8c9d1d66c8981fb9200e2251d799eee92774ae9" - integrity sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg== - dependencies: - es-to-primitive "^1.2.1" - function-bind "^1.1.1" - has "^1.0.3" - has-symbols "^1.0.1" - is-callable "^1.1.5" - is-regex "^1.0.5" - object-inspect "^1.7.0" - object-keys "^1.1.1" - object.assign "^4.1.0" - string.prototype.trimleft "^2.1.1" - string.prototype.trimright "^2.1.1" - -es-to-primitive@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" - integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== - dependencies: - is-callable "^1.1.4" - is-date-object "^1.0.1" - is-symbol "^1.0.2" - -es5-ext@^0.10.35, es5-ext@^0.10.50: - version "0.10.53" - resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.53.tgz#93c5a3acfdbef275220ad72644ad02ee18368de1" - integrity sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q== - dependencies: - es6-iterator "~2.0.3" - es6-symbol "~3.1.3" - next-tick "~1.0.0" - -es6-iterator@2.0.3, es6-iterator@~2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7" - integrity sha1-p96IkUGgWpSwhUQDstCg+/qY87c= - dependencies: - d "1" - es5-ext "^0.10.35" - es6-symbol "^3.1.1" - -es6-symbol@^3.1.1, es6-symbol@~3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.3.tgz#bad5d3c1bcdac28269f4cb331e431c78ac705d18" - integrity sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA== - dependencies: - d "^1.0.1" - ext "^1.1.2" - -escape-html@~1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" - integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= - -escape-string-regexp@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" - integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== - -escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= - -escodegen@^1.11.0, escodegen@^1.9.1: - version "1.14.1" - resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.14.1.tgz#ba01d0c8278b5e95a9a45350142026659027a457" - integrity sha512-Bmt7NcRySdIfNPfU2ZoXDrrXsG9ZjvDxcAlMfDUgRBjLOWTuIACXPBFJH7Z+cLb40JeQco5toikyc9t9P8E9SQ== - dependencies: - esprima "^4.0.1" - estraverse "^4.2.0" - esutils "^2.0.2" - optionator "^0.8.1" - optionalDependencies: - source-map "~0.6.1" - -eslint-config-react-app@^5.2.0: - version "5.2.1" - resolved "https://registry.yarnpkg.com/eslint-config-react-app/-/eslint-config-react-app-5.2.1.tgz#698bf7aeee27f0cea0139eaef261c7bf7dd623df" - integrity sha512-pGIZ8t0mFLcV+6ZirRgYK6RVqUIKRIi9MmgzUEmrIknsn3AdO0I32asO86dJgloHq+9ZPl8UIg8mYrvgP5u2wQ== - dependencies: - confusing-browser-globals "^1.0.9" - -eslint-import-resolver-node@^0.3.2: - version "0.3.3" - resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.3.tgz#dbaa52b6b2816b50bc6711af75422de808e98404" - integrity sha512-b8crLDo0M5RSe5YG8Pu2DYBj71tSB6OvXkfzwbJU2w7y8P4/yo0MyF8jU26IEuEuHF2K5/gcAJE3LhQGqBBbVg== - dependencies: - debug "^2.6.9" - resolve "^1.13.1" - -eslint-loader@3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/eslint-loader/-/eslint-loader-3.0.3.tgz#e018e3d2722381d982b1201adb56819c73b480ca" - integrity sha512-+YRqB95PnNvxNp1HEjQmvf9KNvCin5HXYYseOXVC2U0KEcw4IkQ2IQEBG46j7+gW39bMzeu0GsUhVbBY3Votpw== - dependencies: - fs-extra "^8.1.0" - loader-fs-cache "^1.0.2" - loader-utils "^1.2.3" - object-hash "^2.0.1" - schema-utils "^2.6.1" - -eslint-module-utils@^2.4.1: - version "2.6.0" - resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.6.0.tgz#579ebd094f56af7797d19c9866c9c9486629bfa6" - integrity sha512-6j9xxegbqe8/kZY8cYpcp0xhbK0EgJlg3g9mib3/miLaExuuwc3n5UEfSnU6hWMbT0FAYVvDbL9RrRgpUeQIvA== - dependencies: - debug "^2.6.9" - pkg-dir "^2.0.0" - -eslint-plugin-flowtype@4.6.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-flowtype/-/eslint-plugin-flowtype-4.6.0.tgz#82b2bd6f21770e0e5deede0228e456cb35308451" - integrity sha512-W5hLjpFfZyZsXfo5anlu7HM970JBDqbEshAJUkeczP6BFCIfJXuiIBQXyberLRtOStT0OGPF8efeTbxlHk4LpQ== - dependencies: - lodash "^4.17.15" - -eslint-plugin-import@2.20.0: - version "2.20.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.20.0.tgz#d749a7263fb6c29980def8e960d380a6aa6aecaa" - integrity sha512-NK42oA0mUc8Ngn4kONOPsPB1XhbUvNHqF+g307dPV28aknPoiNnKLFd9em4nkswwepdF5ouieqv5Th/63U7YJQ== - dependencies: - array-includes "^3.0.3" - array.prototype.flat "^1.2.1" - contains-path "^0.1.0" - debug "^2.6.9" - doctrine "1.5.0" - eslint-import-resolver-node "^0.3.2" - eslint-module-utils "^2.4.1" - has "^1.0.3" - minimatch "^3.0.4" - object.values "^1.1.0" - read-pkg-up "^2.0.0" - resolve "^1.12.0" - -eslint-plugin-jsx-a11y@6.2.3: - version "6.2.3" - resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.2.3.tgz#b872a09d5de51af70a97db1eea7dc933043708aa" - integrity sha512-CawzfGt9w83tyuVekn0GDPU9ytYtxyxyFZ3aSWROmnRRFQFT2BiPJd7jvRdzNDi6oLWaS2asMeYSNMjWTV4eNg== - dependencies: - "@babel/runtime" "^7.4.5" - aria-query "^3.0.0" - array-includes "^3.0.3" - ast-types-flow "^0.0.7" - axobject-query "^2.0.2" - damerau-levenshtein "^1.0.4" - emoji-regex "^7.0.2" - has "^1.0.3" - jsx-ast-utils "^2.2.1" - -eslint-plugin-react-hooks@^1.6.1: - version "1.7.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-1.7.0.tgz#6210b6d5a37205f0b92858f895a4e827020a7d04" - integrity sha512-iXTCFcOmlWvw4+TOE8CLWj6yX1GwzT0Y6cUfHHZqWnSk144VmVIRcVGtUAzrLES7C798lmvnt02C7rxaOX1HNA== - -eslint-plugin-react@7.18.0: - version "7.18.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.18.0.tgz#2317831284d005b30aff8afb7c4e906f13fa8e7e" - integrity sha512-p+PGoGeV4SaZRDsXqdj9OWcOrOpZn8gXoGPcIQTzo2IDMbAKhNDnME9myZWqO3Ic4R3YmwAZ1lDjWl2R2hMUVQ== - dependencies: - array-includes "^3.1.1" - doctrine "^2.1.0" - has "^1.0.3" - jsx-ast-utils "^2.2.3" - object.entries "^1.1.1" - object.fromentries "^2.0.2" - object.values "^1.1.1" - prop-types "^15.7.2" - resolve "^1.14.2" - -eslint-scope@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.3.tgz#ca03833310f6889a3264781aa82e63eb9cfe7848" - integrity sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg== - dependencies: - esrecurse "^4.1.0" - estraverse "^4.1.1" - -eslint-scope@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.0.0.tgz#e87c8887c73e8d1ec84f1ca591645c358bfc8fb9" - integrity sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw== - dependencies: - esrecurse "^4.1.0" - estraverse "^4.1.1" - -eslint-utils@^1.4.3: - version "1.4.3" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.3.tgz#74fec7c54d0776b6f67e0251040b5806564e981f" - integrity sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q== - dependencies: - eslint-visitor-keys "^1.1.0" - -eslint-utils@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.0.0.tgz#7be1cc70f27a72a76cd14aa698bcabed6890e1cd" - integrity sha512-0HCPuJv+7Wv1bACm8y5/ECVfYdfsAm9xmVb7saeFlxjPYALefjhbYoCkBjPdPzGH8wWyTpAez82Fh3VKYEZ8OA== - dependencies: - eslint-visitor-keys "^1.1.0" - -eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz#e2a82cea84ff246ad6fb57f9bde5b46621459ec2" - integrity sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A== - -eslint@^6.6.0: - version "6.8.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-6.8.0.tgz#62262d6729739f9275723824302fb227c8c93ffb" - integrity sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig== - dependencies: - "@babel/code-frame" "^7.0.0" - ajv "^6.10.0" - chalk "^2.1.0" - cross-spawn "^6.0.5" - debug "^4.0.1" - doctrine "^3.0.0" - eslint-scope "^5.0.0" - eslint-utils "^1.4.3" - eslint-visitor-keys "^1.1.0" - espree "^6.1.2" - esquery "^1.0.1" - esutils "^2.0.2" - file-entry-cache "^5.0.1" - functional-red-black-tree "^1.0.1" - glob-parent "^5.0.0" - globals "^12.1.0" - ignore "^4.0.6" - import-fresh "^3.0.0" - imurmurhash "^0.1.4" - inquirer "^7.0.0" - is-glob "^4.0.0" - js-yaml "^3.13.1" - json-stable-stringify-without-jsonify "^1.0.1" - levn "^0.3.0" - lodash "^4.17.14" - minimatch "^3.0.4" - mkdirp "^0.5.1" - natural-compare "^1.4.0" - optionator "^0.8.3" - progress "^2.0.0" - regexpp "^2.0.1" - semver "^6.1.2" - strip-ansi "^5.2.0" - strip-json-comments "^3.0.1" - table "^5.2.3" - text-table "^0.2.0" - v8-compile-cache "^2.0.3" - -espree@^6.1.2: - version "6.2.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-6.2.1.tgz#77fc72e1fd744a2052c20f38a5b575832e82734a" - integrity sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw== - dependencies: - acorn "^7.1.1" - acorn-jsx "^5.2.0" - eslint-visitor-keys "^1.1.0" - -esprima@^4.0.0, esprima@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" - integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== - -esquery@^1.0.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.3.1.tgz#b78b5828aa8e214e29fb74c4d5b752e1c033da57" - integrity sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ== - dependencies: - estraverse "^5.1.0" - -esrecurse@^4.1.0: - version "4.2.1" - resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf" - integrity sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ== - dependencies: - estraverse "^4.1.0" - -estraverse@^4.1.0, estraverse@^4.1.1, estraverse@^4.2.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" - integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== - -estraverse@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.1.0.tgz#374309d39fd935ae500e7b92e8a6b4c720e59642" - integrity sha512-FyohXK+R0vE+y1nHLoBM7ZTyqRpqAlhdZHCWIWEviFLiGB8b04H6bQs8G+XTthacvT8VuwvteiP7RJSxMs8UEw== - -esutils@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" - integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== - -etag@~1.8.1: - version "1.8.1" - resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" - integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= - -eventemitter3@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.0.tgz#d65176163887ee59f386d64c82610b696a4a74eb" - integrity sha512-qerSRB0p+UDEssxTtm6EDKcE7W4OaoisfIMl4CngyEhjpYglocpNg6UEqCvemdGhosAsg4sO2dXJOdyBifPGCg== - -events@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/events/-/events-3.1.0.tgz#84279af1b34cb75aa88bf5ff291f6d0bd9b31a59" - integrity sha512-Rv+u8MLHNOdMjTAFeT3nCjHn2aGlx435FP/sDHNaRhDEMwyI/aB22Kj2qIN8R0cw3z28psEQLYwxVKLsKrMgWg== - -eventsource@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/eventsource/-/eventsource-1.0.7.tgz#8fbc72c93fcd34088090bc0a4e64f4b5cee6d8d0" - integrity sha512-4Ln17+vVT0k8aWq+t/bF5arcS3EpT9gYtW66EPacdj/mAFevznsnyoHLPy2BA8gbIQeIHoPsvwmfBftfcG//BQ== - dependencies: - original "^1.0.0" - -evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" - integrity sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA== - dependencies: - md5.js "^1.3.4" - safe-buffer "^5.1.1" - -exec-sh@^0.3.2: - version "0.3.4" - resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.3.4.tgz#3a018ceb526cc6f6df2bb504b2bfe8e3a4934ec5" - integrity sha512-sEFIkc61v75sWeOe72qyrqg2Qg0OuLESziUDk/O/z2qgS15y2gWVFrI6f2Qn/qw/0/NCfCEsmNA4zOjkwEZT1A== - -execa@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" - integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA== - dependencies: - cross-spawn "^6.0.0" - get-stream "^4.0.0" - is-stream "^1.1.0" - npm-run-path "^2.0.0" - p-finally "^1.0.0" - signal-exit "^3.0.0" - strip-eof "^1.0.0" - -exit@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" - integrity sha1-BjJjj42HfMghB9MKD/8aF8uhzQw= - -expand-brackets@^2.1.4: - version "2.1.4" - resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" - integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI= - dependencies: - debug "^2.3.3" - define-property "^0.2.5" - extend-shallow "^2.0.1" - posix-character-classes "^0.1.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - -expect@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/expect/-/expect-24.9.0.tgz#b75165b4817074fa4a157794f46fe9f1ba15b6ca" - integrity sha512-wvVAx8XIol3Z5m9zvZXiyZOQ+sRJqNTIm6sGjdWlaZIeupQGO3WbYI+15D/AmEwZywL6wtJkbAbJtzkOfBuR0Q== - dependencies: - "@jest/types" "^24.9.0" - ansi-styles "^3.2.0" - jest-get-type "^24.9.0" - jest-matcher-utils "^24.9.0" - jest-message-util "^24.9.0" - jest-regex-util "^24.9.0" - -express@^4.17.1: - version "4.17.1" - resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134" - integrity sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g== - dependencies: - accepts "~1.3.7" - array-flatten "1.1.1" - body-parser "1.19.0" - content-disposition "0.5.3" - content-type "~1.0.4" - cookie "0.4.0" - cookie-signature "1.0.6" - debug "2.6.9" - depd "~1.1.2" - encodeurl "~1.0.2" - escape-html "~1.0.3" - etag "~1.8.1" - finalhandler "~1.1.2" - fresh "0.5.2" - merge-descriptors "1.0.1" - methods "~1.1.2" - on-finished "~2.3.0" - parseurl "~1.3.3" - path-to-regexp "0.1.7" - proxy-addr "~2.0.5" - qs "6.7.0" - range-parser "~1.2.1" - safe-buffer "5.1.2" - send "0.17.1" - serve-static "1.14.1" - setprototypeof "1.1.1" - statuses "~1.5.0" - type-is "~1.6.18" - utils-merge "1.0.1" - vary "~1.1.2" - -ext@^1.1.2: - version "1.4.0" - resolved "https://registry.yarnpkg.com/ext/-/ext-1.4.0.tgz#89ae7a07158f79d35517882904324077e4379244" - integrity sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A== - dependencies: - type "^2.0.0" - -extend-shallow@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" - integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8= - dependencies: - is-extendable "^0.1.0" - -extend-shallow@^3.0.0, extend-shallow@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" - integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg= - dependencies: - assign-symbols "^1.0.0" - is-extendable "^1.0.1" - -extend@^3.0.0, extend@~3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" - integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== - -external-editor@^3.0.3: - version "3.1.0" - resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" - integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew== - dependencies: - chardet "^0.7.0" - iconv-lite "^0.4.24" - tmp "^0.0.33" - -extglob@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" - integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== - dependencies: - array-unique "^0.3.2" - define-property "^1.0.0" - expand-brackets "^2.1.4" - extend-shallow "^2.0.1" - fragment-cache "^0.2.1" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - -extsprintf@1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" - integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU= - -extsprintf@^1.2.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" - integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= - -fast-deep-equal@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz#545145077c501491e33b15ec408c294376e94ae4" - integrity sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA== - -fast-glob@^2.0.2: - version "2.2.7" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-2.2.7.tgz#6953857c3afa475fff92ee6015d52da70a4cd39d" - integrity sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw== - dependencies: - "@mrmlnc/readdir-enhanced" "^2.2.1" - "@nodelib/fs.stat" "^1.1.2" - glob-parent "^3.1.0" - is-glob "^4.0.0" - merge2 "^1.2.3" - micromatch "^3.1.10" - -fast-json-stable-stringify@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" - integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== - -fast-levenshtein@~2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" - integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= - -faye-websocket@^0.10.0: - version "0.10.0" - resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.10.0.tgz#4e492f8d04dfb6f89003507f6edbf2d501e7c6f4" - integrity sha1-TkkvjQTftviQA1B/btvy1QHnxvQ= - dependencies: - websocket-driver ">=0.5.1" - -faye-websocket@~0.11.1: - version "0.11.3" - resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.11.3.tgz#5c0e9a8968e8912c286639fde977a8b209f2508e" - integrity sha512-D2y4bovYpzziGgbHYtGCMjlJM36vAl/y+xUyn1C+FVx8szd1E+86KwVw6XvYSzOP8iMpm1X0I4xJD+QtUb36OA== - dependencies: - websocket-driver ">=0.5.1" - -fb-watchman@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.1.tgz#fc84fb39d2709cf3ff6d743706157bb5708a8a85" - integrity sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg== - dependencies: - bser "2.1.1" - -figgy-pudding@^3.5.1: - version "3.5.2" - resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.2.tgz#b4eee8148abb01dcf1d1ac34367d59e12fa61d6e" - integrity sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw== - -figures@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" - integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg== - dependencies: - escape-string-regexp "^1.0.5" - -file-entry-cache@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-5.0.1.tgz#ca0f6efa6dd3d561333fb14515065c2fafdf439c" - integrity sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g== - dependencies: - flat-cache "^2.0.1" - -file-loader@4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-4.3.0.tgz#780f040f729b3d18019f20605f723e844b8a58af" - integrity sha512-aKrYPYjF1yG3oX0kWRrqrSMfgftm7oJW5M+m4owoldH5C51C0RkIwB++JbRvEW3IU6/ZG5n8UvEcdgwOt2UOWA== - dependencies: - loader-utils "^1.2.3" - schema-utils "^2.5.0" - -file-uri-to-path@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" - integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== - -filesize@6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/filesize/-/filesize-6.0.1.tgz#f850b509909c7c86f7e450ea19006c31c2ed3d2f" - integrity sha512-u4AYWPgbI5GBhs6id1KdImZWn5yfyFrrQ8OWZdN7ZMfA8Bf4HcO0BGo9bmUIEV8yrp8I1xVfJ/dn90GtFNNJcg== - -fill-range@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" - integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc= - dependencies: - extend-shallow "^2.0.1" - is-number "^3.0.0" - repeat-string "^1.6.1" - to-regex-range "^2.1.0" - -fill-range@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" - integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== - dependencies: - to-regex-range "^5.0.1" - -finalhandler@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" - integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA== - dependencies: - debug "2.6.9" - encodeurl "~1.0.2" - escape-html "~1.0.3" - on-finished "~2.3.0" - parseurl "~1.3.3" - statuses "~1.5.0" - unpipe "~1.0.0" - -find-cache-dir@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-0.1.1.tgz#c8defae57c8a52a8a784f9e31c57c742e993a0b9" - integrity sha1-yN765XyKUqinhPnjHFfHQumToLk= - dependencies: - commondir "^1.0.1" - mkdirp "^0.5.1" - pkg-dir "^1.0.0" - -find-cache-dir@^2.0.0, find-cache-dir@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-2.1.0.tgz#8d0f94cd13fe43c6c7c261a0d86115ca918c05f7" - integrity sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ== - dependencies: - commondir "^1.0.1" - make-dir "^2.0.0" - pkg-dir "^3.0.0" - -find-cache-dir@^3.2.0: - version "3.3.1" - resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.3.1.tgz#89b33fad4a4670daa94f855f7fbe31d6d84fe880" - integrity sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ== - dependencies: - commondir "^1.0.1" - make-dir "^3.0.2" - pkg-dir "^4.1.0" - -find-up@4.1.0, find-up@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" - integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== - dependencies: - locate-path "^5.0.0" - path-exists "^4.0.0" - -find-up@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" - integrity sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8= - dependencies: - path-exists "^2.0.0" - pinkie-promise "^2.0.0" - -find-up@^2.0.0, find-up@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" - integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c= - dependencies: - locate-path "^2.0.0" - -find-up@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" - integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== - dependencies: - locate-path "^3.0.0" - -flat-cache@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0" - integrity sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA== - dependencies: - flatted "^2.0.0" - rimraf "2.6.3" - write "1.0.3" - -flatted@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138" - integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA== - -flatten@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.3.tgz#c1283ac9f27b368abc1e36d1ff7b04501a30356b" - integrity sha512-dVsPA/UwQ8+2uoFe5GHtiBMu48dWLTdsuEd7CKGlZlD78r1TTWBvDuFaFGKCo/ZfEr95Uk56vZoX86OsHkUeIg== - -flush-write-stream@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.1.1.tgz#8dd7d873a1babc207d94ead0c2e0e44276ebf2e8" - integrity sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w== - dependencies: - inherits "^2.0.3" - readable-stream "^2.3.6" - -fn-name@~2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/fn-name/-/fn-name-2.0.1.tgz#5214d7537a4d06a4a301c0cc262feb84188002e7" - integrity sha1-UhTXU3pNBqSjAcDMJi/rhBiAAuc= - -fn-name@~3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/fn-name/-/fn-name-3.0.0.tgz#0596707f635929634d791f452309ab41558e3c5c" - integrity sha512-eNMNr5exLoavuAMhIUVsOKF79SWd/zG104ef6sxBTSw+cZc6BXdQXDvYcGvp0VbxVVSp1XDUNoz7mg1xMtSznA== - -follow-redirects@^1.0.0: - version "1.11.0" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.11.0.tgz#afa14f08ba12a52963140fe43212658897bc0ecb" - integrity sha512-KZm0V+ll8PfBrKwMzdo5D13b1bur9Iq9Zd/RMmAoQQcl2PxxFml8cxXPaaPYVbV0RjNjq1CU7zIzAOqtUPudmA== - dependencies: - debug "^3.0.0" - -follow-redirects@^1.10.0: - version "1.13.0" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.0.tgz#b42e8d93a2a7eea5ed88633676d6597bc8e384db" - integrity sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA== - -for-in@^0.1.3: - version "0.1.8" - resolved "https://registry.yarnpkg.com/for-in/-/for-in-0.1.8.tgz#d8773908e31256109952b1fdb9b3fa867d2775e1" - integrity sha1-2Hc5COMSVhCZUrH9ubP6hn0ndeE= - -for-in@^1.0.1, for-in@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" - integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= - -for-own@^0.1.3: - version "0.1.5" - resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce" - integrity sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4= - dependencies: - for-in "^1.0.1" - -forever-agent@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" - integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= - -fork-ts-checker-webpack-plugin@3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-3.1.1.tgz#a1642c0d3e65f50c2cc1742e9c0a80f441f86b19" - integrity sha512-DuVkPNrM12jR41KM2e+N+styka0EgLkTnXmNcXdgOM37vtGeY+oCBK/Jx0hzSeEU6memFCtWb4htrHPMDfwwUQ== - dependencies: - babel-code-frame "^6.22.0" - chalk "^2.4.1" - chokidar "^3.3.0" - micromatch "^3.1.10" - minimatch "^3.0.4" - semver "^5.6.0" - tapable "^1.0.0" - worker-rpc "^0.1.0" - -form-data@~2.3.2: - version "2.3.3" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" - integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.6" - mime-types "^2.1.12" - -forwarded@~0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" - integrity sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ= - -fragment-cache@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" - integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk= - dependencies: - map-cache "^0.2.2" - -fresh@0.5.2: - version "0.5.2" - resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" - integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= - -from2@^2.1.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" - integrity sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8= - dependencies: - inherits "^2.0.1" - readable-stream "^2.0.0" - -fs-extra@^4.0.2: - version "4.0.3" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.3.tgz#0d852122e5bc5beb453fb028e9c0c9bf36340c94" - integrity sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg== - dependencies: - graceful-fs "^4.1.2" - jsonfile "^4.0.0" - universalify "^0.1.0" - -fs-extra@^7.0.0: - version "7.0.1" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9" - integrity sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw== - dependencies: - graceful-fs "^4.1.2" - jsonfile "^4.0.0" - universalify "^0.1.0" - -fs-extra@^8.1.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" - integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g== - dependencies: - graceful-fs "^4.2.0" - jsonfile "^4.0.0" - universalify "^0.1.0" - -fs-minipass@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb" - integrity sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg== - dependencies: - minipass "^3.0.0" - -fs-write-stream-atomic@^1.0.8: - version "1.0.10" - resolved "https://registry.yarnpkg.com/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz#b47df53493ef911df75731e70a9ded0189db40c9" - integrity sha1-tH31NJPvkR33VzHnCp3tAYnbQMk= - dependencies: - graceful-fs "^4.1.2" - iferr "^0.1.5" - imurmurhash "^0.1.4" - readable-stream "1 || 2" - -fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= - -fsevents@2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.2.tgz#4c0a1fb34bc68e543b4b82a9ec392bfbda840805" - integrity sha512-R4wDiBwZ0KzpgOWetKDug1FZcYhqYnUYKtfZYt4mD5SBz76q0KR4Q9o7GIPamsVPGmW3EYPPJ0dOOjvx32ldZA== - -fsevents@^1.2.7: - version "1.2.13" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.13.tgz#f325cb0455592428bcf11b383370ef70e3bfcc38" - integrity sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw== - dependencies: - bindings "^1.5.0" - nan "^2.12.1" - -fsevents@~2.1.2: - version "2.1.3" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.3.tgz#fb738703ae8d2f9fe900c33836ddebee8b97f23e" - integrity sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ== - -function-bind@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" - integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== - -functional-red-black-tree@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" - integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= - -gensync@^1.0.0-beta.1: - version "1.0.0-beta.1" - resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.1.tgz#58f4361ff987e5ff6e1e7a210827aa371eaac269" - integrity sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg== - -get-caller-file@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" - integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w== - -get-caller-file@^2.0.1: - version "2.0.5" - resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" - integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== - -get-own-enumerable-property-symbols@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz#b5fde77f22cbe35f390b4e089922c50bce6ef664" - integrity sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g== - -get-stream@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" - integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== - dependencies: - pump "^3.0.0" - -get-value@^2.0.3, get-value@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" - integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= - -getpass@^0.1.1: - version "0.1.7" - resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" - integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo= - dependencies: - assert-plus "^1.0.0" - -glob-parent@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" - integrity sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4= - dependencies: - is-glob "^3.1.0" - path-dirname "^1.0.0" - -glob-parent@^5.0.0, glob-parent@~5.1.0: - version "5.1.1" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.1.tgz#b6c1ef417c4e5663ea498f1c45afac6916bbc229" - integrity sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ== - dependencies: - is-glob "^4.0.1" - -glob-to-regexp@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab" - integrity sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs= - -glob@^7.0.3, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: - version "7.1.6" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" - integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - -global-modules@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-2.0.0.tgz#997605ad2345f27f51539bea26574421215c7780" - integrity sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A== - dependencies: - global-prefix "^3.0.0" - -global-prefix@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-3.0.0.tgz#fc85f73064df69f50421f47f883fe5b913ba9b97" - integrity sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg== - dependencies: - ini "^1.3.5" - kind-of "^6.0.2" - which "^1.3.1" - -globals@^11.1.0: - version "11.12.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" - integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== - -globals@^12.1.0: - version "12.4.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-12.4.0.tgz#a18813576a41b00a24a97e7f815918c2e19925f8" - integrity sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg== - dependencies: - type-fest "^0.8.1" - -globby@8.0.2: - version "8.0.2" - resolved "https://registry.yarnpkg.com/globby/-/globby-8.0.2.tgz#5697619ccd95c5275dbb2d6faa42087c1a941d8d" - integrity sha512-yTzMmKygLp8RUpG1Ymu2VXPSJQZjNAZPD4ywgYEaG7e4tBJeUQBO8OpXrf1RCNcEs5alsoJYPAMiIHP0cmeC7w== - dependencies: - array-union "^1.0.1" - dir-glob "2.0.0" - fast-glob "^2.0.2" - glob "^7.1.2" - ignore "^3.3.5" - pify "^3.0.0" - slash "^1.0.0" - -globby@^6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/globby/-/globby-6.1.0.tgz#f5a6d70e8395e21c858fb0489d64df02424d506c" - integrity sha1-9abXDoOV4hyFj7BInWTfAkJNUGw= - dependencies: - array-union "^1.0.1" - glob "^7.0.3" - object-assign "^4.0.1" - pify "^2.0.0" - pinkie-promise "^2.0.0" - -graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.2: - version "4.2.4" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb" - integrity sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw== - -growly@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" - integrity sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE= - -gzip-size@5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-5.1.1.tgz#cb9bee692f87c0612b232840a873904e4c135274" - integrity sha512-FNHi6mmoHvs1mxZAds4PpdCS6QG8B4C1krxJsMutgxl5t3+GlRTzzI3NEkifXx2pVsOvJdOGSmIgDhQ55FwdPA== - dependencies: - duplexer "^0.1.1" - pify "^4.0.1" - -handle-thing@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-2.0.1.tgz#857f79ce359580c340d43081cc648970d0bb234e" - integrity sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg== - -har-schema@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" - integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI= - -har-validator@~5.1.3: - version "5.1.3" - resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.3.tgz#1ef89ebd3e4996557675eed9893110dc350fa080" - integrity sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g== - dependencies: - ajv "^6.5.5" - har-schema "^2.0.0" - -harmony-reflect@^1.4.6: - version "1.6.1" - resolved "https://registry.yarnpkg.com/harmony-reflect/-/harmony-reflect-1.6.1.tgz#c108d4f2bb451efef7a37861fdbdae72c9bdefa9" - integrity sha512-WJTeyp0JzGtHcuMsi7rw2VwtkvLa+JyfEKJCFyfcS0+CDkjQ5lHPu7zEhFZP+PDSRrEgXa5Ah0l1MbgbE41XjA== - -has-ansi@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" - integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE= - dependencies: - ansi-regex "^2.0.0" - -has-flag@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" - integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= - -has-flag@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" - integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== - -has-symbols@^1.0.0, has-symbols@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8" - integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg== - -has-value@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" - integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8= - dependencies: - get-value "^2.0.3" - has-values "^0.1.4" - isobject "^2.0.0" - -has-value@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" - integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc= - dependencies: - get-value "^2.0.6" - has-values "^1.0.0" - isobject "^3.0.0" - -has-values@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" - integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E= - -has-values@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" - integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8= - dependencies: - is-number "^3.0.0" - kind-of "^4.0.0" - -has@^1.0.0, has@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" - integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== - dependencies: - function-bind "^1.1.1" - -hash-base@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.1.0.tgz#55c381d9e06e1d2997a883b4a3fddfe7f0d3af33" - integrity sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA== - dependencies: - inherits "^2.0.4" - readable-stream "^3.6.0" - safe-buffer "^5.2.0" - -hash.js@^1.0.0, hash.js@^1.0.3: - version "1.1.7" - resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" - integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== - dependencies: - inherits "^2.0.3" - minimalistic-assert "^1.0.1" - -he@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" - integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== - -hex-color-regex@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/hex-color-regex/-/hex-color-regex-1.1.0.tgz#4c06fccb4602fe2602b3c93df82d7e7dbf1a8a8e" - integrity sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ== - -history@^4.9.0: - version "4.10.1" - resolved "https://registry.yarnpkg.com/history/-/history-4.10.1.tgz#33371a65e3a83b267434e2b3f3b1b4c58aad4cf3" - integrity sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew== - dependencies: - "@babel/runtime" "^7.1.2" - loose-envify "^1.2.0" - resolve-pathname "^3.0.0" - tiny-invariant "^1.0.2" - tiny-warning "^1.0.0" - value-equal "^1.0.1" - -hmac-drbg@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" - integrity sha1-0nRXAQJabHdabFRXk+1QL8DGSaE= - dependencies: - hash.js "^1.0.3" - minimalistic-assert "^1.0.0" - minimalistic-crypto-utils "^1.0.1" - -hoist-non-react-statics@^3.0.0, hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.3.2: - version "3.3.2" - resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" - integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== - dependencies: - react-is "^16.7.0" - -hosted-git-info@^2.1.4: - version "2.8.8" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.8.tgz#7539bd4bc1e0e0a895815a2e0262420b12858488" - integrity sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg== - -hpack.js@^2.1.6: - version "2.1.6" - resolved "https://registry.yarnpkg.com/hpack.js/-/hpack.js-2.1.6.tgz#87774c0949e513f42e84575b3c45681fade2a0b2" - integrity sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI= - dependencies: - inherits "^2.0.1" - obuf "^1.0.0" - readable-stream "^2.0.1" - wbuf "^1.1.0" - -hsl-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/hsl-regex/-/hsl-regex-1.0.0.tgz#d49330c789ed819e276a4c0d272dffa30b18fe6e" - integrity sha1-1JMwx4ntgZ4nakwNJy3/owsY/m4= - -hsla-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/hsla-regex/-/hsla-regex-1.0.0.tgz#c1ce7a3168c8c6614033a4b5f7877f3b225f9c38" - integrity sha1-wc56MWjIxmFAM6S194d/OyJfnDg= - -html-comment-regex@^1.1.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/html-comment-regex/-/html-comment-regex-1.1.2.tgz#97d4688aeb5c81886a364faa0cad1dda14d433a7" - integrity sha512-P+M65QY2JQ5Y0G9KKdlDpo0zK+/OHptU5AaBwUfAIDJZk1MYf32Frm84EcOytfJE0t5JvkAnKlmjsXDnWzCJmQ== - -html-encoding-sniffer@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz#e70d84b94da53aa375e11fe3a351be6642ca46f8" - integrity sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw== - dependencies: - whatwg-encoding "^1.0.1" - -html-entities@^1.2.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.3.1.tgz#fb9a1a4b5b14c5daba82d3e34c6ae4fe701a0e44" - integrity sha512-rhE/4Z3hIhzHAUKbW8jVcCyuT5oJCXXqhN/6mXXVCpzTmvJnoH2HL/bt3EZ6p55jbFJBeAe1ZNpL5BugLujxNA== - -html-escaper@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" - integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== - -html-minifier-terser@^5.0.1: - version "5.1.0" - resolved "https://registry.yarnpkg.com/html-minifier-terser/-/html-minifier-terser-5.1.0.tgz#95d3df037f04835e9d1a09d1767c0e361a7de916" - integrity sha512-tiYE76O1zunboByeB/nFGwUEb263Z3nkNv6Lz2oLC1s6M36bLKfTrjQ+7ssVfaucVllE+N7hh/FbpbxvnIA+LQ== - dependencies: - camel-case "^4.1.1" - clean-css "^4.2.3" - commander "^4.1.1" - he "^1.2.0" - param-case "^3.0.3" - relateurl "^0.2.7" - terser "^4.6.3" - -html-to-react@^1.3.4: - version "1.4.2" - resolved "https://registry.yarnpkg.com/html-to-react/-/html-to-react-1.4.2.tgz#7b628ab56cd63a52f2d0b79d0fa838a51f088a57" - integrity sha512-TdTfxd95sRCo6QL8admCkE7mvNNrXtGoVr1dyS+7uvc8XCqAymnf/6ckclvnVbQNUo2Nh21VPwtfEHd0khiV7g== - dependencies: - domhandler "^3.0" - htmlparser2 "^4.0" - lodash.camelcase "^4.3.0" - ramda "^0.26" - -html-webpack-plugin@4.0.0-beta.11: - version "4.0.0-beta.11" - resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-4.0.0-beta.11.tgz#3059a69144b5aecef97708196ca32f9e68677715" - integrity sha512-4Xzepf0qWxf8CGg7/WQM5qBB2Lc/NFI7MhU59eUDTkuQp3skZczH4UA1d6oQyDEIoMDgERVhRyTdtUPZ5s5HBg== - dependencies: - html-minifier-terser "^5.0.1" - loader-utils "^1.2.3" - lodash "^4.17.15" - pretty-error "^2.1.1" - tapable "^1.1.3" - util.promisify "1.0.0" - -htmlparser2@^3.3.0: - version "3.10.1" - resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.10.1.tgz#bd679dc3f59897b6a34bb10749c855bb53a9392f" - integrity sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ== - dependencies: - domelementtype "^1.3.1" - domhandler "^2.3.0" - domutils "^1.5.1" - entities "^1.1.1" - inherits "^2.0.1" - readable-stream "^3.1.1" - -htmlparser2@^4.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-4.1.0.tgz#9a4ef161f2e4625ebf7dfbe6c0a2f52d18a59e78" - integrity sha512-4zDq1a1zhE4gQso/c5LP1OtrhYTncXNSpvJYtWJBtXAETPlMfi3IFNjGuQbYLuVY4ZR0QMqRVvo4Pdy9KLyP8Q== - dependencies: - domelementtype "^2.0.1" - domhandler "^3.0.0" - domutils "^2.0.0" - entities "^2.0.0" - -http-deceiver@^1.2.7: - version "1.2.7" - resolved "https://registry.yarnpkg.com/http-deceiver/-/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87" - integrity sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc= - -http-errors@1.7.2: - version "1.7.2" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f" - integrity sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg== - dependencies: - depd "~1.1.2" - inherits "2.0.3" - setprototypeof "1.1.1" - statuses ">= 1.5.0 < 2" - toidentifier "1.0.0" - -http-errors@~1.6.2: - version "1.6.3" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" - integrity sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0= - dependencies: - depd "~1.1.2" - inherits "2.0.3" - setprototypeof "1.1.0" - statuses ">= 1.4.0 < 2" - -http-errors@~1.7.2: - version "1.7.3" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06" - integrity sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw== - dependencies: - depd "~1.1.2" - inherits "2.0.4" - setprototypeof "1.1.1" - statuses ">= 1.5.0 < 2" - toidentifier "1.0.0" - -"http-parser-js@>=0.4.0 <0.4.11": - version "0.4.10" - resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.4.10.tgz#92c9c1374c35085f75db359ec56cc257cbb93fa4" - integrity sha1-ksnBN0w1CF912zWexWzCV8u5P6Q= - -http-proxy-middleware@0.19.1: - version "0.19.1" - resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz#183c7dc4aa1479150306498c210cdaf96080a43a" - integrity sha512-yHYTgWMQO8VvwNS22eLLloAkvungsKdKTLO8AJlftYIKNfJr3GK3zK0ZCfzDDGUBttdGc8xFy1mCitvNKQtC3Q== - dependencies: - http-proxy "^1.17.0" - is-glob "^4.0.0" - lodash "^4.17.11" - micromatch "^3.1.10" - -http-proxy-middleware@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-1.0.3.tgz#f73daad8dac622d51fe1769960c914b9b1f75a72" - integrity sha512-GHvPeBD+A357zS5tHjzj6ISrVOjjCiy0I92bdyTJz0pNmIjFxO0NX/bX+xkGgnclKQE/5hHAB9JEQ7u9Pw4olg== - dependencies: - "@types/http-proxy" "^1.17.3" - http-proxy "^1.18.0" - is-glob "^4.0.1" - lodash "^4.17.15" - micromatch "^4.0.2" - -http-proxy@^1.17.0, http-proxy@^1.18.0: - version "1.18.0" - resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.0.tgz#dbe55f63e75a347db7f3d99974f2692a314a6a3a" - integrity sha512-84I2iJM/n1d4Hdgc6y2+qY5mDaz2PUVjlg9znE9byl+q0uC3DeByqBGReQu5tpLK0TAqTIXScRUV+dg7+bUPpQ== - dependencies: - eventemitter3 "^4.0.0" - follow-redirects "^1.0.0" - requires-port "^1.0.0" - -http-signature@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" - integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE= - dependencies: - assert-plus "^1.0.0" - jsprim "^1.2.2" - sshpk "^1.7.0" - -https-browserify@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" - integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM= - -hyphenate-style-name@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/hyphenate-style-name/-/hyphenate-style-name-1.0.3.tgz#097bb7fa0b8f1a9cf0bd5c734cf95899981a9b48" - integrity sha512-EcuixamT82oplpoJ2XU4pDtKGWQ7b00CD9f1ug9IaQ3p1bkHMiKCZ9ut9QDI6qsa6cpUuB+A/I+zLtdNK4n2DQ== - -iconv-lite@0.4.24, iconv-lite@^0.4.24: - version "0.4.24" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" - integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== - dependencies: - safer-buffer ">= 2.1.2 < 3" - -icss-utils@^4.0.0, icss-utils@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-4.1.1.tgz#21170b53789ee27447c2f47dd683081403f9a467" - integrity sha512-4aFq7wvWyMHKgxsH8QQtGpvbASCf+eM3wPRLI6R+MgAnTCZ6STYsRvttLvRWK0Nfif5piF394St3HeJDaljGPA== - dependencies: - postcss "^7.0.14" - -identity-obj-proxy@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/identity-obj-proxy/-/identity-obj-proxy-3.0.0.tgz#94d2bda96084453ef36fbc5aaec37e0f79f1fc14" - integrity sha1-lNK9qWCERT7zb7xarsN+D3nx/BQ= - dependencies: - harmony-reflect "^1.4.6" - -ieee754@^1.1.4: - version "1.1.13" - resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84" - integrity sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg== - -iferr@^0.1.5: - version "0.1.5" - resolved "https://registry.yarnpkg.com/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501" - integrity sha1-xg7taebY/bazEEofy8ocGS3FtQE= - -ignore@^3.3.5: - version "3.3.10" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.10.tgz#0a97fb876986e8081c631160f8f9f389157f0043" - integrity sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug== - -ignore@^4.0.6: - version "4.0.6" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" - integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== - -immer@1.10.0: - version "1.10.0" - resolved "https://registry.yarnpkg.com/immer/-/immer-1.10.0.tgz#bad67605ba9c810275d91e1c2a47d4582e98286d" - integrity sha512-O3sR1/opvCDGLEVcvrGTMtLac8GJ5IwZC4puPrLuRj3l7ICKvkmA0vGuU9OW8mV9WIBRnaxp5GJh9IEAaNOoYg== - -import-cwd@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/import-cwd/-/import-cwd-2.1.0.tgz#aa6cf36e722761285cb371ec6519f53e2435b0a9" - integrity sha1-qmzzbnInYShcs3HsZRn1PiQ1sKk= - dependencies: - import-from "^2.1.0" - -import-fresh@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-2.0.0.tgz#d81355c15612d386c61f9ddd3922d4304822a546" - integrity sha1-2BNVwVYS04bGH53dOSLUMEgipUY= - dependencies: - caller-path "^2.0.0" - resolve-from "^3.0.0" - -import-fresh@^3.0.0, import-fresh@^3.1.0: - version "3.2.1" - resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.2.1.tgz#633ff618506e793af5ac91bf48b72677e15cbe66" - integrity sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ== - dependencies: - parent-module "^1.0.0" - resolve-from "^4.0.0" - -import-from@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/import-from/-/import-from-2.1.0.tgz#335db7f2a7affd53aaa471d4b8021dee36b7f3b1" - integrity sha1-M1238qev/VOqpHHUuAId7ja387E= - dependencies: - resolve-from "^3.0.0" - -import-local@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/import-local/-/import-local-2.0.0.tgz#55070be38a5993cf18ef6db7e961f5bee5c5a09d" - integrity sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ== - dependencies: - pkg-dir "^3.0.0" - resolve-cwd "^2.0.0" - -imurmurhash@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" - integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= - -indent-string@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" - integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== - -indexes-of@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/indexes-of/-/indexes-of-1.0.1.tgz#f30f716c8e2bd346c7b67d3df3915566a7c05607" - integrity sha1-8w9xbI4r00bHtn0985FVZqfAVgc= - -infer-owner@^1.0.3, infer-owner@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/infer-owner/-/infer-owner-1.0.4.tgz#c4cefcaa8e51051c2a40ba2ce8a3d27295af9467" - integrity sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A== - -inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= - dependencies: - once "^1.3.0" - wrappy "1" - -inherits@2, inherits@2.0.4, inherits@^2.0.0, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3: - version "2.0.4" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" - integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== - -inherits@2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" - integrity sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE= - -inherits@2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" - integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= - -ini@^1.3.5: - version "1.3.5" - resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" - integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== - -inquirer@7.0.4: - version "7.0.4" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.0.4.tgz#99af5bde47153abca23f5c7fc30db247f39da703" - integrity sha512-Bu5Td5+j11sCkqfqmUTiwv+tWisMtP0L7Q8WrqA2C/BbBhy1YTdFrvjjlrKq8oagA/tLQBski2Gcx/Sqyi2qSQ== - dependencies: - ansi-escapes "^4.2.1" - chalk "^2.4.2" - cli-cursor "^3.1.0" - cli-width "^2.0.0" - external-editor "^3.0.3" - figures "^3.0.0" - lodash "^4.17.15" - mute-stream "0.0.8" - run-async "^2.2.0" - rxjs "^6.5.3" - string-width "^4.1.0" - strip-ansi "^5.1.0" - through "^2.3.6" - -inquirer@^7.0.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.1.0.tgz#1298a01859883e17c7264b82870ae1034f92dd29" - integrity sha512-5fJMWEmikSYu0nv/flMc475MhGbB7TSPd/2IpFV4I4rMklboCH2rQjYY5kKiYGHqUF9gvaambupcJFFG9dvReg== - dependencies: - ansi-escapes "^4.2.1" - chalk "^3.0.0" - cli-cursor "^3.1.0" - cli-width "^2.0.0" - external-editor "^3.0.3" - figures "^3.0.0" - lodash "^4.17.15" - mute-stream "0.0.8" - run-async "^2.4.0" - rxjs "^6.5.3" - string-width "^4.1.0" - strip-ansi "^6.0.0" - through "^2.3.6" - -internal-ip@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/internal-ip/-/internal-ip-4.3.0.tgz#845452baad9d2ca3b69c635a137acb9a0dad0907" - integrity sha512-S1zBo1D6zcsyuC6PMmY5+55YMILQ9av8lotMx447Bq6SAgo/sDK6y6uUKmuYhW7eacnIhFfsPmCNYdDzsnnDCg== - dependencies: - default-gateway "^4.2.0" - ipaddr.js "^1.9.0" - -invariant@^2.2.2, invariant@^2.2.4: - version "2.2.4" - resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" - integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== - dependencies: - loose-envify "^1.0.0" - -invert-kv@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-2.0.0.tgz#7393f5afa59ec9ff5f67a27620d11c226e3eec02" - integrity sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA== - -ip-regex@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9" - integrity sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk= - -ip@^1.1.0, ip@^1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" - integrity sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo= - -ipaddr.js@1.9.1, ipaddr.js@^1.9.0: - version "1.9.1" - resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" - integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== - -is-absolute-url@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-2.1.0.tgz#50530dfb84fcc9aa7dbe7852e83a37b93b9f2aa6" - integrity sha1-UFMN+4T8yap9vnhS6Do3uTufKqY= - -is-absolute-url@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-3.0.3.tgz#96c6a22b6a23929b11ea0afb1836c36ad4a5d698" - integrity sha512-opmNIX7uFnS96NtPmhWQgQx6/NYFgsUXYMllcfzwWKUMwfo8kku1TvE6hkNcH+Q1ts5cMVrsY7j0bxXQDciu9Q== - -is-accessor-descriptor@^0.1.6: - version "0.1.6" - resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" - integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY= - dependencies: - kind-of "^3.0.2" - -is-accessor-descriptor@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" - integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ== - dependencies: - kind-of "^6.0.0" - -is-alphabetical@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-alphabetical/-/is-alphabetical-1.0.4.tgz#9e7d6b94916be22153745d184c298cbf986a686d" - integrity sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg== - -is-alphanumerical@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz#7eb9a2431f855f6b1ef1a78e326df515696c4dbf" - integrity sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A== - dependencies: - is-alphabetical "^1.0.0" - is-decimal "^1.0.0" - -is-arguments@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.0.4.tgz#3faf966c7cba0ff437fb31f6250082fcf0448cf3" - integrity sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA== - -is-arrayish@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" - integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= - -is-arrayish@^0.3.1: - version "0.3.2" - resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03" - integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== - -is-binary-path@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" - integrity sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg= - dependencies: - binary-extensions "^1.0.0" - -is-binary-path@~2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" - integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== - dependencies: - binary-extensions "^2.0.0" - -is-buffer@^1.0.2, is-buffer@^1.1.4, is-buffer@^1.1.5: - version "1.1.6" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" - integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== - -is-callable@^1.1.4, is-callable@^1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.5.tgz#f7e46b596890456db74e7f6e976cb3273d06faab" - integrity sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q== - -is-ci@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c" - integrity sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w== - dependencies: - ci-info "^2.0.0" - -is-color-stop@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-color-stop/-/is-color-stop-1.1.0.tgz#cfff471aee4dd5c9e158598fbe12967b5cdad345" - integrity sha1-z/9HGu5N1cnhWFmPvhKWe1za00U= - dependencies: - css-color-names "^0.0.4" - hex-color-regex "^1.1.0" - hsl-regex "^1.0.0" - hsla-regex "^1.0.0" - rgb-regex "^1.0.1" - rgba-regex "^1.0.0" - -is-data-descriptor@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" - integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y= - dependencies: - kind-of "^3.0.2" - -is-data-descriptor@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" - integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ== - dependencies: - kind-of "^6.0.0" - -is-date-object@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.2.tgz#bda736f2cd8fd06d32844e7743bfa7494c3bfd7e" - integrity sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g== - -is-decimal@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-decimal/-/is-decimal-1.0.4.tgz#65a3a5958a1c5b63a706e1b333d7cd9f630d3fa5" - integrity sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw== - -is-descriptor@^0.1.0: - version "0.1.6" - resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" - integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg== - dependencies: - is-accessor-descriptor "^0.1.6" - is-data-descriptor "^0.1.4" - kind-of "^5.0.0" - -is-descriptor@^1.0.0, is-descriptor@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" - integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg== - dependencies: - is-accessor-descriptor "^1.0.0" - is-data-descriptor "^1.0.0" - kind-of "^6.0.2" - -is-directory@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1" - integrity sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE= - -is-docker@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.0.0.tgz#2cb0df0e75e2d064fe1864c37cdeacb7b2dcf25b" - integrity sha512-pJEdRugimx4fBMra5z2/5iRdZ63OhYV0vr0Dwm5+xtW4D1FvRkB8hamMIhnWfyJeDdyr/aa7BDyNbtG38VxgoQ== - -is-extendable@^0.1.0, is-extendable@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" - integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= - -is-extendable@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" - integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA== - dependencies: - is-plain-object "^2.0.4" - -is-extglob@^2.1.0, is-extglob@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" - integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= - -is-fullwidth-code-point@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" - integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs= - dependencies: - number-is-nan "^1.0.0" - -is-fullwidth-code-point@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" - integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= - -is-fullwidth-code-point@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" - integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== - -is-generator-fn@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" - integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== - -is-glob@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" - integrity sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo= - dependencies: - is-extglob "^2.1.0" - -is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" - integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== - dependencies: - is-extglob "^2.1.1" - -is-hexadecimal@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz#cc35c97588da4bd49a8eedd6bc4082d44dcb23a7" - integrity sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw== - -is-in-browser@^1.0.2, is-in-browser@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/is-in-browser/-/is-in-browser-1.1.3.tgz#56ff4db683a078c6082eb95dad7dc62e1d04f835" - integrity sha1-Vv9NtoOgeMYILrldrX3GLh0E+DU= - -is-number@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" - integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU= - dependencies: - kind-of "^3.0.2" - -is-number@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" - integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== - -is-obj@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" - integrity sha1-PkcprB9f3gJc19g6iW2rn09n2w8= - -is-obj@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982" - integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w== - -is-path-cwd@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-2.2.0.tgz#67d43b82664a7b5191fd9119127eb300048a9fdb" - integrity sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ== - -is-path-in-cwd@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-2.1.0.tgz#bfe2dca26c69f397265a4009963602935a053acb" - integrity sha512-rNocXHgipO+rvnP6dk3zI20RpOtrAM/kzbB258Uw5BWr3TpXi861yzjo16Dn4hUox07iw5AyeMLHWsujkjzvRQ== - dependencies: - is-path-inside "^2.1.0" - -is-path-inside@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-2.1.0.tgz#7c9810587d659a40d27bcdb4d5616eab059494b2" - integrity sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg== - dependencies: - path-is-inside "^1.0.2" - -is-plain-obj@^1.0.0, is-plain-obj@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" - integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4= - -is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" - integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== - dependencies: - isobject "^3.0.1" - -is-regex@^1.0.4, is-regex@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.5.tgz#39d589a358bf18967f726967120b8fc1aed74eae" - integrity sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ== - dependencies: - has "^1.0.3" - -is-regexp@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-regexp/-/is-regexp-1.0.0.tgz#fd2d883545c46bac5a633e7b9a09e87fa2cb5069" - integrity sha1-/S2INUXEa6xaYz57mgnof6LLUGk= - -is-resolvable@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.1.0.tgz#fb18f87ce1feb925169c9a407c19318a3206ed88" - integrity sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg== - -is-root@2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-root/-/is-root-2.1.0.tgz#809e18129cf1129644302a4f8544035d51984a9c" - integrity sha512-AGOriNp96vNBd3HtU+RzFEc75FfR5ymiYv8E553I71SCeXBiMsVDUtdio1OEFvrPyLIQ9tVR5RxXIFe5PUFjMg== - -is-stream@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" - integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= - -is-string@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.5.tgz#40493ed198ef3ff477b8c7f92f644ec82a5cd3a6" - integrity sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ== - -is-svg@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-svg/-/is-svg-3.0.0.tgz#9321dbd29c212e5ca99c4fa9794c714bcafa2f75" - integrity sha512-gi4iHK53LR2ujhLVVj+37Ykh9GLqYHX6JOVXbLAucaG/Cqw9xwdFOjDM2qeifLs1sF1npXXFvDu0r5HNgCMrzQ== - dependencies: - html-comment-regex "^1.1.0" - -is-symbol@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937" - integrity sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ== - dependencies: - has-symbols "^1.0.1" - -is-typedarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" - integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= - -is-whitespace-character@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-whitespace-character/-/is-whitespace-character-1.0.4.tgz#0858edd94a95594c7c9dd0b5c174ec6e45ee4aa7" - integrity sha512-SDweEzfIZM0SJV0EUga669UTKlmL0Pq8Lno0QDQsPnvECB3IM2aP0gdx5TrU0A01MAPfViaZiI2V1QMZLaKK5w== - -is-windows@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" - integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== - -is-word-character@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-word-character/-/is-word-character-1.0.4.tgz#ce0e73216f98599060592f62ff31354ddbeb0230" - integrity sha512-5SMO8RVennx3nZrqtKwCGyyetPE9VDba5ugvKLaD4KopPG5kR4mQ7tNt/r7feL5yt5h3lpuBbIUmCOG2eSzXHA== - -is-wsl@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" - integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0= - -is-wsl@^2.1.1: - version "2.2.0" - resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" - integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== - dependencies: - is-docker "^2.0.0" - -isarray@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" - integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= - -isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" - integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= - -isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= - -isobject@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" - integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk= - dependencies: - isarray "1.0.0" - -isobject@^3.0.0, isobject@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" - integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= - -isstream@~0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" - integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= - -istanbul-lib-coverage@^2.0.2, istanbul-lib-coverage@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz#675f0ab69503fad4b1d849f736baaca803344f49" - integrity sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA== - -istanbul-lib-instrument@^3.0.1, istanbul-lib-instrument@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-3.3.0.tgz#a5f63d91f0bbc0c3e479ef4c5de027335ec6d630" - integrity sha512-5nnIN4vo5xQZHdXno/YDXJ0G+I3dAm4XgzfSVTPLQpj/zAV2dV6Juy0yaf10/zrJOJeHoN3fraFe+XRq2bFVZA== - dependencies: - "@babel/generator" "^7.4.0" - "@babel/parser" "^7.4.3" - "@babel/template" "^7.4.0" - "@babel/traverse" "^7.4.3" - "@babel/types" "^7.4.0" - istanbul-lib-coverage "^2.0.5" - semver "^6.0.0" - -istanbul-lib-report@^2.0.4: - version "2.0.8" - resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-2.0.8.tgz#5a8113cd746d43c4889eba36ab10e7d50c9b4f33" - integrity sha512-fHBeG573EIihhAblwgxrSenp0Dby6tJMFR/HvlerBsrCTD5bkUuoNtn3gVh29ZCS824cGGBPn7Sg7cNk+2xUsQ== - dependencies: - istanbul-lib-coverage "^2.0.5" - make-dir "^2.1.0" - supports-color "^6.1.0" - -istanbul-lib-source-maps@^3.0.1: - version "3.0.6" - resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz#284997c48211752ec486253da97e3879defba8c8" - integrity sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw== - dependencies: - debug "^4.1.1" - istanbul-lib-coverage "^2.0.5" - make-dir "^2.1.0" - rimraf "^2.6.3" - source-map "^0.6.1" - -istanbul-reports@^2.2.6: - version "2.2.7" - resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-2.2.7.tgz#5d939f6237d7b48393cc0959eab40cd4fd056931" - integrity sha512-uu1F/L1o5Y6LzPVSVZXNOoD/KXpJue9aeLRd0sM9uMXfZvzomB0WxVamWb5ue8kA2vVWEmW7EG+A5n3f1kqHKg== - dependencies: - html-escaper "^2.0.0" - -jest-changed-files@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-24.9.0.tgz#08d8c15eb79a7fa3fc98269bc14b451ee82f8039" - integrity sha512-6aTWpe2mHF0DhL28WjdkO8LyGjs3zItPET4bMSeXU6T3ub4FPMw+mcOcbdGXQOAfmLcxofD23/5Bl9Z4AkFwqg== - dependencies: - "@jest/types" "^24.9.0" - execa "^1.0.0" - throat "^4.0.0" - -jest-cli@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-24.9.0.tgz#ad2de62d07472d419c6abc301fc432b98b10d2af" - integrity sha512-+VLRKyitT3BWoMeSUIHRxV/2g8y9gw91Jh5z2UmXZzkZKpbC08CSehVxgHUwTpy+HwGcns/tqafQDJW7imYvGg== - dependencies: - "@jest/core" "^24.9.0" - "@jest/test-result" "^24.9.0" - "@jest/types" "^24.9.0" - chalk "^2.0.1" - exit "^0.1.2" - import-local "^2.0.0" - is-ci "^2.0.0" - jest-config "^24.9.0" - jest-util "^24.9.0" - jest-validate "^24.9.0" - prompts "^2.0.1" - realpath-native "^1.1.0" - yargs "^13.3.0" - -jest-config@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-24.9.0.tgz#fb1bbc60c73a46af03590719efa4825e6e4dd1b5" - integrity sha512-RATtQJtVYQrp7fvWg6f5y3pEFj9I+H8sWw4aKxnDZ96mob5i5SD6ZEGWgMLXQ4LE8UurrjbdlLWdUeo+28QpfQ== - dependencies: - "@babel/core" "^7.1.0" - "@jest/test-sequencer" "^24.9.0" - "@jest/types" "^24.9.0" - babel-jest "^24.9.0" - chalk "^2.0.1" - glob "^7.1.1" - jest-environment-jsdom "^24.9.0" - jest-environment-node "^24.9.0" - jest-get-type "^24.9.0" - jest-jasmine2 "^24.9.0" - jest-regex-util "^24.3.0" - jest-resolve "^24.9.0" - jest-util "^24.9.0" - jest-validate "^24.9.0" - micromatch "^3.1.10" - pretty-format "^24.9.0" - realpath-native "^1.1.0" - -jest-diff@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-24.9.0.tgz#931b7d0d5778a1baf7452cb816e325e3724055da" - integrity sha512-qMfrTs8AdJE2iqrTp0hzh7kTd2PQWrsFyj9tORoKmu32xjPjeE4NyjVRDz8ybYwqS2ik8N4hsIpiVTyFeo2lBQ== - dependencies: - chalk "^2.0.1" - diff-sequences "^24.9.0" - jest-get-type "^24.9.0" - pretty-format "^24.9.0" - -jest-docblock@^24.3.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-24.9.0.tgz#7970201802ba560e1c4092cc25cbedf5af5a8ce2" - integrity sha512-F1DjdpDMJMA1cN6He0FNYNZlo3yYmOtRUnktrT9Q37njYzC5WEaDdmbynIgy0L/IvXvvgsG8OsqhLPXTpfmZAA== - dependencies: - detect-newline "^2.1.0" - -jest-each@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-24.9.0.tgz#eb2da602e2a610898dbc5f1f6df3ba86b55f8b05" - integrity sha512-ONi0R4BvW45cw8s2Lrx8YgbeXL1oCQ/wIDwmsM3CqM/nlblNCPmnC3IPQlMbRFZu3wKdQ2U8BqM6lh3LJ5Bsog== - dependencies: - "@jest/types" "^24.9.0" - chalk "^2.0.1" - jest-get-type "^24.9.0" - jest-util "^24.9.0" - pretty-format "^24.9.0" - -jest-environment-jsdom-fourteen@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/jest-environment-jsdom-fourteen/-/jest-environment-jsdom-fourteen-1.0.1.tgz#4cd0042f58b4ab666950d96532ecb2fc188f96fb" - integrity sha512-DojMX1sY+at5Ep+O9yME34CdidZnO3/zfPh8UW+918C5fIZET5vCjfkegixmsi7AtdYfkr4bPlIzmWnlvQkP7Q== - dependencies: - "@jest/environment" "^24.3.0" - "@jest/fake-timers" "^24.3.0" - "@jest/types" "^24.3.0" - jest-mock "^24.0.0" - jest-util "^24.0.0" - jsdom "^14.1.0" - -jest-environment-jsdom@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-24.9.0.tgz#4b0806c7fc94f95edb369a69cc2778eec2b7375b" - integrity sha512-Zv9FV9NBRzLuALXjvRijO2351DRQeLYXtpD4xNvfoVFw21IOKNhZAEUKcbiEtjTkm2GsJ3boMVgkaR7rN8qetA== - dependencies: - "@jest/environment" "^24.9.0" - "@jest/fake-timers" "^24.9.0" - "@jest/types" "^24.9.0" - jest-mock "^24.9.0" - jest-util "^24.9.0" - jsdom "^11.5.1" - -jest-environment-node@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-24.9.0.tgz#333d2d2796f9687f2aeebf0742b519f33c1cbfd3" - integrity sha512-6d4V2f4nxzIzwendo27Tr0aFm+IXWa0XEUnaH6nU0FMaozxovt+sfRvh4J47wL1OvF83I3SSTu0XK+i4Bqe7uA== - dependencies: - "@jest/environment" "^24.9.0" - "@jest/fake-timers" "^24.9.0" - "@jest/types" "^24.9.0" - jest-mock "^24.9.0" - jest-util "^24.9.0" - -jest-get-type@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-24.9.0.tgz#1684a0c8a50f2e4901b6644ae861f579eed2ef0e" - integrity sha512-lUseMzAley4LhIcpSP9Jf+fTrQ4a1yHQwLNeeVa2cEmbCGeoZAtYPOIv8JaxLD/sUpKxetKGP+gsHl8f8TSj8Q== - -jest-haste-map@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-24.9.0.tgz#b38a5d64274934e21fa417ae9a9fbeb77ceaac7d" - integrity sha512-kfVFmsuWui2Sj1Rp1AJ4D9HqJwE4uwTlS/vO+eRUaMmd54BFpli2XhMQnPC2k4cHFVbB2Q2C+jtI1AGLgEnCjQ== - dependencies: - "@jest/types" "^24.9.0" - anymatch "^2.0.0" - fb-watchman "^2.0.0" - graceful-fs "^4.1.15" - invariant "^2.2.4" - jest-serializer "^24.9.0" - jest-util "^24.9.0" - jest-worker "^24.9.0" - micromatch "^3.1.10" - sane "^4.0.3" - walker "^1.0.7" - optionalDependencies: - fsevents "^1.2.7" - -jest-jasmine2@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-24.9.0.tgz#1f7b1bd3242c1774e62acabb3646d96afc3be6a0" - integrity sha512-Cq7vkAgaYKp+PsX+2/JbTarrk0DmNhsEtqBXNwUHkdlbrTBLtMJINADf2mf5FkowNsq8evbPc07/qFO0AdKTzw== - dependencies: - "@babel/traverse" "^7.1.0" - "@jest/environment" "^24.9.0" - "@jest/test-result" "^24.9.0" - "@jest/types" "^24.9.0" - chalk "^2.0.1" - co "^4.6.0" - expect "^24.9.0" - is-generator-fn "^2.0.0" - jest-each "^24.9.0" - jest-matcher-utils "^24.9.0" - jest-message-util "^24.9.0" - jest-runtime "^24.9.0" - jest-snapshot "^24.9.0" - jest-util "^24.9.0" - pretty-format "^24.9.0" - throat "^4.0.0" - -jest-leak-detector@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-24.9.0.tgz#b665dea7c77100c5c4f7dfcb153b65cf07dcf96a" - integrity sha512-tYkFIDsiKTGwb2FG1w8hX9V0aUb2ot8zY/2nFg087dUageonw1zrLMP4W6zsRO59dPkTSKie+D4rhMuP9nRmrA== - dependencies: - jest-get-type "^24.9.0" - pretty-format "^24.9.0" - -jest-matcher-utils@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-24.9.0.tgz#f5b3661d5e628dffe6dd65251dfdae0e87c3a073" - integrity sha512-OZz2IXsu6eaiMAwe67c1T+5tUAtQyQx27/EMEkbFAGiw52tB9em+uGbzpcgYVpA8wl0hlxKPZxrly4CXU/GjHA== - dependencies: - chalk "^2.0.1" - jest-diff "^24.9.0" - jest-get-type "^24.9.0" - pretty-format "^24.9.0" - -jest-message-util@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-24.9.0.tgz#527f54a1e380f5e202a8d1149b0ec872f43119e3" - integrity sha512-oCj8FiZ3U0hTP4aSui87P4L4jC37BtQwUMqk+zk/b11FR19BJDeZsZAvIHutWnmtw7r85UmR3CEWZ0HWU2mAlw== - dependencies: - "@babel/code-frame" "^7.0.0" - "@jest/test-result" "^24.9.0" - "@jest/types" "^24.9.0" - "@types/stack-utils" "^1.0.1" - chalk "^2.0.1" - micromatch "^3.1.10" - slash "^2.0.0" - stack-utils "^1.0.1" - -jest-mock@^24.0.0, jest-mock@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-24.9.0.tgz#c22835541ee379b908673ad51087a2185c13f1c6" - integrity sha512-3BEYN5WbSq9wd+SyLDES7AHnjH9A/ROBwmz7l2y+ol+NtSFO8DYiEBzoO1CeFc9a8DYy10EO4dDFVv/wN3zl1w== - dependencies: - "@jest/types" "^24.9.0" - -jest-pnp-resolver@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.1.tgz#ecdae604c077a7fbc70defb6d517c3c1c898923a" - integrity sha512-pgFw2tm54fzgYvc/OHrnysABEObZCUNFnhjoRjaVOCN8NYc032/gVjPaHD4Aq6ApkSieWtfKAFQtmDKAmhupnQ== - -jest-regex-util@^24.3.0, jest-regex-util@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-24.9.0.tgz#c13fb3380bde22bf6575432c493ea8fe37965636" - integrity sha512-05Cmb6CuxaA+Ys6fjr3PhvV3bGQmO+2p2La4hFbU+W5uOc479f7FdLXUWXw4pYMAhhSZIuKHwSXSu6CsSBAXQA== - -jest-resolve-dependencies@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-24.9.0.tgz#ad055198959c4cfba8a4f066c673a3f0786507ab" - integrity sha512-Fm7b6AlWnYhT0BXy4hXpactHIqER7erNgIsIozDXWl5dVm+k8XdGVe1oTg1JyaFnOxarMEbax3wyRJqGP2Pq+g== - dependencies: - "@jest/types" "^24.9.0" - jest-regex-util "^24.3.0" - jest-snapshot "^24.9.0" - -jest-resolve@24.9.0, jest-resolve@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-24.9.0.tgz#dff04c7687af34c4dd7e524892d9cf77e5d17321" - integrity sha512-TaLeLVL1l08YFZAt3zaPtjiVvyy4oSA6CRe+0AFPPVX3Q/VI0giIWWoAvoS5L96vj9Dqxj4fB5p2qrHCmTU/MQ== - dependencies: - "@jest/types" "^24.9.0" - browser-resolve "^1.11.3" - chalk "^2.0.1" - jest-pnp-resolver "^1.2.1" - realpath-native "^1.1.0" - -jest-runner@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-24.9.0.tgz#574fafdbd54455c2b34b4bdf4365a23857fcdf42" - integrity sha512-KksJQyI3/0mhcfspnxxEOBueGrd5E4vV7ADQLT9ESaCzz02WnbdbKWIf5Mkaucoaj7obQckYPVX6JJhgUcoWWg== - dependencies: - "@jest/console" "^24.7.1" - "@jest/environment" "^24.9.0" - "@jest/test-result" "^24.9.0" - "@jest/types" "^24.9.0" - chalk "^2.4.2" - exit "^0.1.2" - graceful-fs "^4.1.15" - jest-config "^24.9.0" - jest-docblock "^24.3.0" - jest-haste-map "^24.9.0" - jest-jasmine2 "^24.9.0" - jest-leak-detector "^24.9.0" - jest-message-util "^24.9.0" - jest-resolve "^24.9.0" - jest-runtime "^24.9.0" - jest-util "^24.9.0" - jest-worker "^24.6.0" - source-map-support "^0.5.6" - throat "^4.0.0" - -jest-runtime@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-24.9.0.tgz#9f14583af6a4f7314a6a9d9f0226e1a781c8e4ac" - integrity sha512-8oNqgnmF3v2J6PVRM2Jfuj8oX3syKmaynlDMMKQ4iyzbQzIG6th5ub/lM2bCMTmoTKM3ykcUYI2Pw9xwNtjMnw== - dependencies: - "@jest/console" "^24.7.1" - "@jest/environment" "^24.9.0" - "@jest/source-map" "^24.3.0" - "@jest/transform" "^24.9.0" - "@jest/types" "^24.9.0" - "@types/yargs" "^13.0.0" - chalk "^2.0.1" - exit "^0.1.2" - glob "^7.1.3" - graceful-fs "^4.1.15" - jest-config "^24.9.0" - jest-haste-map "^24.9.0" - jest-message-util "^24.9.0" - jest-mock "^24.9.0" - jest-regex-util "^24.3.0" - jest-resolve "^24.9.0" - jest-snapshot "^24.9.0" - jest-util "^24.9.0" - jest-validate "^24.9.0" - realpath-native "^1.1.0" - slash "^2.0.0" - strip-bom "^3.0.0" - yargs "^13.3.0" - -jest-serializer@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-24.9.0.tgz#e6d7d7ef96d31e8b9079a714754c5d5c58288e73" - integrity sha512-DxYipDr8OvfrKH3Kel6NdED3OXxjvxXZ1uIY2I9OFbGg+vUkkg7AGvi65qbhbWNPvDckXmzMPbK3u3HaDO49bQ== - -jest-snapshot@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-24.9.0.tgz#ec8e9ca4f2ec0c5c87ae8f925cf97497b0e951ba" - integrity sha512-uI/rszGSs73xCM0l+up7O7a40o90cnrk429LOiK3aeTvfC0HHmldbd81/B7Ix81KSFe1lwkbl7GnBGG4UfuDew== - dependencies: - "@babel/types" "^7.0.0" - "@jest/types" "^24.9.0" - chalk "^2.0.1" - expect "^24.9.0" - jest-diff "^24.9.0" - jest-get-type "^24.9.0" - jest-matcher-utils "^24.9.0" - jest-message-util "^24.9.0" - jest-resolve "^24.9.0" - mkdirp "^0.5.1" - natural-compare "^1.4.0" - pretty-format "^24.9.0" - semver "^6.2.0" - -jest-util@^24.0.0, jest-util@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-24.9.0.tgz#7396814e48536d2e85a37de3e4c431d7cb140162" - integrity sha512-x+cZU8VRmOJxbA1K5oDBdxQmdq0OIdADarLxk0Mq+3XS4jgvhG/oKGWcIDCtPG0HgjxOYvF+ilPJQsAyXfbNOg== - dependencies: - "@jest/console" "^24.9.0" - "@jest/fake-timers" "^24.9.0" - "@jest/source-map" "^24.9.0" - "@jest/test-result" "^24.9.0" - "@jest/types" "^24.9.0" - callsites "^3.0.0" - chalk "^2.0.1" - graceful-fs "^4.1.15" - is-ci "^2.0.0" - mkdirp "^0.5.1" - slash "^2.0.0" - source-map "^0.6.0" - -jest-validate@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-24.9.0.tgz#0775c55360d173cd854e40180756d4ff52def8ab" - integrity sha512-HPIt6C5ACwiqSiwi+OfSSHbK8sG7akG8eATl+IPKaeIjtPOeBUd/g3J7DghugzxrGjI93qS/+RPKe1H6PqvhRQ== - dependencies: - "@jest/types" "^24.9.0" - camelcase "^5.3.1" - chalk "^2.0.1" - jest-get-type "^24.9.0" - leven "^3.1.0" - pretty-format "^24.9.0" - -jest-watch-typeahead@0.4.2: - version "0.4.2" - resolved "https://registry.yarnpkg.com/jest-watch-typeahead/-/jest-watch-typeahead-0.4.2.tgz#e5be959698a7fa2302229a5082c488c3c8780a4a" - integrity sha512-f7VpLebTdaXs81rg/oj4Vg/ObZy2QtGzAmGLNsqUS5G5KtSN68tFcIsbvNODfNyQxU78g7D8x77o3bgfBTR+2Q== - dependencies: - ansi-escapes "^4.2.1" - chalk "^2.4.1" - jest-regex-util "^24.9.0" - jest-watcher "^24.3.0" - slash "^3.0.0" - string-length "^3.1.0" - strip-ansi "^5.0.0" - -jest-watcher@^24.3.0, jest-watcher@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-24.9.0.tgz#4b56e5d1ceff005f5b88e528dc9afc8dd4ed2b3b" - integrity sha512-+/fLOfKPXXYJDYlks62/4R4GoT+GU1tYZed99JSCOsmzkkF7727RqKrjNAxtfO4YpGv11wybgRvCjR73lK2GZw== - dependencies: - "@jest/test-result" "^24.9.0" - "@jest/types" "^24.9.0" - "@types/yargs" "^13.0.0" - ansi-escapes "^3.0.0" - chalk "^2.0.1" - jest-util "^24.9.0" - string-length "^2.0.0" - -jest-worker@^24.6.0, jest-worker@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-24.9.0.tgz#5dbfdb5b2d322e98567898238a9697bcce67b3e5" - integrity sha512-51PE4haMSXcHohnSMdM42anbvZANYTqMrr52tVKPqqsPJMzoP6FYYDVqahX/HrAoKEKz3uUPzSvKs9A3qR4iVw== - dependencies: - merge-stream "^2.0.0" - supports-color "^6.1.0" - -jest-worker@^25.1.0: - version "25.5.0" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-25.5.0.tgz#2611d071b79cea0f43ee57a3d118593ac1547db1" - integrity sha512-/dsSmUkIy5EBGfv/IjjqmFxrNAUpBERfGs1oHROyD7yxjG/w+t0GOJDX8O1k32ySmd7+a5IhnJU2qQFcJ4n1vw== - dependencies: - merge-stream "^2.0.0" - supports-color "^7.0.0" - -jest@24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest/-/jest-24.9.0.tgz#987d290c05a08b52c56188c1002e368edb007171" - integrity sha512-YvkBL1Zm7d2B1+h5fHEOdyjCG+sGMz4f8D86/0HiqJ6MB4MnDc8FgP5vdWsGnemOQro7lnYo8UakZ3+5A0jxGw== - dependencies: - import-local "^2.0.0" - jest-cli "^24.9.0" - -"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" - integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== - -js-tokens@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" - integrity sha1-mGbfOVECEw449/mWvOtlRDIJwls= - -js-yaml@^3.13.1: - version "3.13.1" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" - integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw== - dependencies: - argparse "^1.0.7" - esprima "^4.0.0" - -jsbn@~0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" - integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= - -jsdom@^11.5.1: - version "11.12.0" - resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-11.12.0.tgz#1a80d40ddd378a1de59656e9e6dc5a3ba8657bc8" - integrity sha512-y8Px43oyiBM13Zc1z780FrfNLJCXTL40EWlty/LXUtcjykRBNgLlCjWXpfSPBl2iv+N7koQN+dvqszHZgT/Fjw== - dependencies: - abab "^2.0.0" - acorn "^5.5.3" - acorn-globals "^4.1.0" - array-equal "^1.0.0" - cssom ">= 0.3.2 < 0.4.0" - cssstyle "^1.0.0" - data-urls "^1.0.0" - domexception "^1.0.1" - escodegen "^1.9.1" - html-encoding-sniffer "^1.0.2" - left-pad "^1.3.0" - nwsapi "^2.0.7" - parse5 "4.0.0" - pn "^1.1.0" - request "^2.87.0" - request-promise-native "^1.0.5" - sax "^1.2.4" - symbol-tree "^3.2.2" - tough-cookie "^2.3.4" - w3c-hr-time "^1.0.1" - webidl-conversions "^4.0.2" - whatwg-encoding "^1.0.3" - whatwg-mimetype "^2.1.0" - whatwg-url "^6.4.1" - ws "^5.2.0" - xml-name-validator "^3.0.0" - -jsdom@^14.1.0: - version "14.1.0" - resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-14.1.0.tgz#916463b6094956b0a6c1782c94e380cd30e1981b" - integrity sha512-O901mfJSuTdwU2w3Sn+74T+RnDVP+FuV5fH8tcPWyqrseRAb0s5xOtPgCFiPOtLcyK7CLIJwPyD83ZqQWvA5ng== - dependencies: - abab "^2.0.0" - acorn "^6.0.4" - acorn-globals "^4.3.0" - array-equal "^1.0.0" - cssom "^0.3.4" - cssstyle "^1.1.1" - data-urls "^1.1.0" - domexception "^1.0.1" - escodegen "^1.11.0" - html-encoding-sniffer "^1.0.2" - nwsapi "^2.1.3" - parse5 "5.1.0" - pn "^1.1.0" - request "^2.88.0" - request-promise-native "^1.0.5" - saxes "^3.1.9" - symbol-tree "^3.2.2" - tough-cookie "^2.5.0" - w3c-hr-time "^1.0.1" - w3c-xmlserializer "^1.1.2" - webidl-conversions "^4.0.2" - whatwg-encoding "^1.0.5" - whatwg-mimetype "^2.3.0" - whatwg-url "^7.0.0" - ws "^6.1.2" - xml-name-validator "^3.0.0" - -jsesc@^2.5.1: - version "2.5.2" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" - integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== - -jsesc@~0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" - integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0= - -json-parse-better-errors@^1.0.1, json-parse-better-errors@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" - integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== - -json-schema-traverse@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" - integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== - -json-schema@0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" - integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= - -json-stable-stringify-without-jsonify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" - integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= - -json-stable-stringify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" - integrity sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8= - dependencies: - jsonify "~0.0.0" - -json-stringify-safe@~5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" - integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= - -json3@^3.3.2: - version "3.3.3" - resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.3.tgz#7fc10e375fc5ae42c4705a5cc0aa6f62be305b81" - integrity sha512-c7/8mbUsKigAbLkD5B010BK4D9LZm7A1pNItkEwiUZRpIN66exu/e7YQWysGun+TRKaJp8MhemM+VkfWv42aCA== - -json5@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" - integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow== - dependencies: - minimist "^1.2.0" - -json5@^2.1.0, json5@^2.1.2: - version "2.1.3" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.3.tgz#c9b0f7fa9233bfe5807fe66fcf3a5617ed597d43" - integrity sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA== - dependencies: - minimist "^1.2.5" - -jsonfile@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" - integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= - optionalDependencies: - graceful-fs "^4.1.6" - -jsonify@~0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" - integrity sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM= - -jsprim@^1.2.2: - version "1.4.1" - resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" - integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI= - dependencies: - assert-plus "1.0.0" - extsprintf "1.3.0" - json-schema "0.2.3" - verror "1.10.0" - -jss-plugin-camel-case@^10.0.3: - version "10.1.1" - resolved "https://registry.yarnpkg.com/jss-plugin-camel-case/-/jss-plugin-camel-case-10.1.1.tgz#8e73ecc4f1d0f8dfe4dd31f6f9f2782588970e78" - integrity sha512-MDIaw8FeD5uFz1seQBKz4pnvDLnj5vIKV5hXSVdMaAVq13xR6SVTVWkIV/keyTs5txxTvzGJ9hXoxgd1WTUlBw== - dependencies: - "@babel/runtime" "^7.3.1" - hyphenate-style-name "^1.0.3" - jss "10.1.1" - -jss-plugin-default-unit@^10.0.3: - version "10.1.1" - resolved "https://registry.yarnpkg.com/jss-plugin-default-unit/-/jss-plugin-default-unit-10.1.1.tgz#2df86016dfe73085eead843f5794e3890e9c5c47" - integrity sha512-UkeVCA/b3QEA4k0nIKS4uWXDCNmV73WLHdh2oDGZZc3GsQtlOCuiH3EkB/qI60v2MiCq356/SYWsDXt21yjwdg== - dependencies: - "@babel/runtime" "^7.3.1" - jss "10.1.1" - -jss-plugin-global@^10.0.3: - version "10.1.1" - resolved "https://registry.yarnpkg.com/jss-plugin-global/-/jss-plugin-global-10.1.1.tgz#36b0d6d9facb74dfd99590643708a89260747d14" - integrity sha512-VBG3wRyi3Z8S4kMhm8rZV6caYBegsk+QnQZSVmrWw6GVOT/Z4FA7eyMu5SdkorDlG/HVpHh91oFN56O4R9m2VA== - dependencies: - "@babel/runtime" "^7.3.1" - jss "10.1.1" - -jss-plugin-nested@^10.0.3: - version "10.1.1" - resolved "https://registry.yarnpkg.com/jss-plugin-nested/-/jss-plugin-nested-10.1.1.tgz#5c3de2b8bda344de1ebcef3a4fd30870a29a8a8c" - integrity sha512-ozEu7ZBSVrMYxSDplPX3H82XHNQk2DQEJ9TEyo7OVTPJ1hEieqjDFiOQOxXEj9z3PMqkylnUbvWIZRDKCFYw5Q== - dependencies: - "@babel/runtime" "^7.3.1" - jss "10.1.1" - tiny-warning "^1.0.2" - -jss-plugin-props-sort@^10.0.3: - version "10.1.1" - resolved "https://registry.yarnpkg.com/jss-plugin-props-sort/-/jss-plugin-props-sort-10.1.1.tgz#34bddcbfaf9430ec8ccdf92729f03bb10caf1785" - integrity sha512-g/joK3eTDZB4pkqpZB38257yD4LXB0X15jxtZAGbUzcKAVUHPl9Jb47Y7lYmiGsShiV4YmQRqG1p2DHMYoK91g== - dependencies: - "@babel/runtime" "^7.3.1" - jss "10.1.1" - -jss-plugin-rule-value-function@^10.0.3: - version "10.1.1" - resolved "https://registry.yarnpkg.com/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.1.1.tgz#be00dac6fc394aaddbcef5860b9eca6224d96382" - integrity sha512-ClV1lvJ3laU9la1CUzaDugEcwnpjPTuJ0yGy2YtcU+gG/w9HMInD5vEv7xKAz53Bk4WiJm5uLOElSEshHyhKNw== - dependencies: - "@babel/runtime" "^7.3.1" - jss "10.1.1" - -jss-plugin-vendor-prefixer@^10.0.3: - version "10.1.1" - resolved "https://registry.yarnpkg.com/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.1.1.tgz#8348b20749f790beebab3b6a8f7075b07c2cfcfd" - integrity sha512-09MZpQ6onQrhaVSF6GHC4iYifQ7+4YC/tAP6D4ZWeZotvCMq1mHLqNKRIaqQ2lkgANjlEot2JnVi1ktu4+L4pw== - dependencies: - "@babel/runtime" "^7.3.1" - css-vendor "^2.0.7" - jss "10.1.1" - -jss@10.1.1, jss@^10.0.3: - version "10.1.1" - resolved "https://registry.yarnpkg.com/jss/-/jss-10.1.1.tgz#450b27d53761af3e500b43130a54cdbe157ea332" - integrity sha512-Xz3qgRUFlxbWk1czCZibUJqhVPObrZHxY3FPsjCXhDld4NOj1BgM14Ir5hVm+Qr6OLqVljjGvoMcCdXNOAbdkQ== - dependencies: - "@babel/runtime" "^7.3.1" - csstype "^2.6.5" - is-in-browser "^1.1.3" - tiny-warning "^1.0.2" - -jsx-ast-utils@^2.2.1, jsx-ast-utils@^2.2.3: - version "2.2.3" - resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-2.2.3.tgz#8a9364e402448a3ce7f14d357738310d9248054f" - integrity sha512-EdIHFMm+1BPynpKOpdPqiOsvnIrInRGJD7bzPZdPkjitQEqpdpUuFpq4T0npZFKTiB3RhWFdGN+oqOJIdhDhQA== - dependencies: - array-includes "^3.0.3" - object.assign "^4.1.0" - -killable@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/killable/-/killable-1.0.1.tgz#4c8ce441187a061c7474fb87ca08e2a638194892" - integrity sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg== - -kind-of@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-2.0.1.tgz#018ec7a4ce7e3a86cb9141be519d24c8faa981b5" - integrity sha1-AY7HpM5+OobLkUG+UZ0kyPqpgbU= - dependencies: - is-buffer "^1.0.2" - -kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: - version "3.2.2" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" - integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ= - dependencies: - is-buffer "^1.1.5" - -kind-of@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" - integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc= - dependencies: - is-buffer "^1.1.5" - -kind-of@^5.0.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" - integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== - -kind-of@^6.0.0, kind-of@^6.0.2: - version "6.0.3" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" - integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== - -kleur@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" - integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== - -last-call-webpack-plugin@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/last-call-webpack-plugin/-/last-call-webpack-plugin-3.0.0.tgz#9742df0e10e3cf46e5c0381c2de90d3a7a2d7555" - integrity sha512-7KI2l2GIZa9p2spzPIVZBYyNKkN+e/SQPpnjlTiPhdbDW3F86tdKKELxKpzJ5sgU19wQWsACULZmpTPYHeWO5w== - dependencies: - lodash "^4.17.5" - webpack-sources "^1.1.0" - -lazy-cache@^0.2.3: - version "0.2.7" - resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-0.2.7.tgz#7feddf2dcb6edb77d11ef1d117ab5ffdf0ab1b65" - integrity sha1-f+3fLctu23fRHvHRF6tf/fCrG2U= - -lazy-cache@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e" - integrity sha1-odePw6UEdMuAhF07O24dpJpEbo4= - -lcid@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/lcid/-/lcid-2.0.0.tgz#6ef5d2df60e52f82eb228a4c373e8d1f397253cf" - integrity sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA== - dependencies: - invert-kv "^2.0.0" - -left-pad@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/left-pad/-/left-pad-1.3.0.tgz#5b8a3a7765dfe001261dde915589e782f8c94d1e" - integrity sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA== - -leven@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" - integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== - -levenary@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/levenary/-/levenary-1.1.1.tgz#842a9ee98d2075aa7faeedbe32679e9205f46f77" - integrity sha512-mkAdOIt79FD6irqjYSs4rdbnlT5vRonMEvBVPVb3XmevfS8kgRXwfes0dhPdEtzTWD/1eNE/Bm/G1iRt6DcnQQ== - dependencies: - leven "^3.1.0" - -levn@^0.3.0, levn@~0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" - integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= - dependencies: - prelude-ls "~1.1.2" - type-check "~0.3.2" - -lines-and-columns@^1.1.6: - version "1.1.6" - resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00" - integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA= - -load-json-file@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8" - integrity sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg= - dependencies: - graceful-fs "^4.1.2" - parse-json "^2.2.0" - pify "^2.0.0" - strip-bom "^3.0.0" - -load-json-file@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b" - integrity sha1-L19Fq5HjMhYjT9U62rZo607AmTs= - dependencies: - graceful-fs "^4.1.2" - parse-json "^4.0.0" - pify "^3.0.0" - strip-bom "^3.0.0" - -loader-fs-cache@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/loader-fs-cache/-/loader-fs-cache-1.0.3.tgz#f08657646d607078be2f0a032f8bd69dd6f277d9" - integrity sha512-ldcgZpjNJj71n+2Mf6yetz+c9bM4xpKtNds4LbqXzU/PTdeAX0g3ytnU1AJMEcTk2Lex4Smpe3Q/eCTsvUBxbA== - dependencies: - find-cache-dir "^0.1.1" - mkdirp "^0.5.1" - -loader-runner@^2.4.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.4.0.tgz#ed47066bfe534d7e84c4c7b9998c2a75607d9357" - integrity sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw== - -loader-utils@1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.2.3.tgz#1ff5dc6911c9f0a062531a4c04b609406108c2c7" - integrity sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA== - dependencies: - big.js "^5.2.2" - emojis-list "^2.0.0" - json5 "^1.0.1" - -loader-utils@^1.0.2, loader-utils@^1.1.0, loader-utils@^1.2.3: - version "1.4.0" - resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.4.0.tgz#c579b5e34cb34b1a74edc6c1fb36bfa371d5a613" - integrity sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA== - dependencies: - big.js "^5.2.2" - emojis-list "^3.0.0" - json5 "^1.0.1" - -locate-path@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" - integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4= - dependencies: - p-locate "^2.0.0" - path-exists "^3.0.0" - -locate-path@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" - integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== - dependencies: - p-locate "^3.0.0" - path-exists "^3.0.0" - -locate-path@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" - integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== - dependencies: - p-locate "^4.1.0" - -lodash-es@^4.17.11: - version "4.17.15" - resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.15.tgz#21bd96839354412f23d7a10340e5eac6ee455d78" - integrity sha512-rlrc3yU3+JNOpZ9zj5pQtxnx2THmvRykwL4Xlxoa8I9lHBlVbbyPhgyPMioxVZ4NqyxaVVtaJnzsyOidQIhyyQ== - -lodash._reinterpolate@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" - integrity sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0= - -lodash.camelcase@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" - integrity sha1-soqmKIorn8ZRA1x3EfZathkDMaY= - -lodash.memoize@^4.1.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" - integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4= - -lodash.sortby@^4.7.0: - version "4.7.0" - resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" - integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg= - -lodash.template@^4.4.0, lodash.template@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-4.5.0.tgz#f976195cf3f347d0d5f52483569fe8031ccce8ab" - integrity sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A== - dependencies: - lodash._reinterpolate "^3.0.0" - lodash.templatesettings "^4.0.0" - -lodash.templatesettings@^4.0.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz#e481310f049d3cf6d47e912ad09313b154f0fb33" - integrity sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ== - dependencies: - lodash._reinterpolate "^3.0.0" - -lodash.uniq@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" - integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= - -lodash@4.17.15, "lodash@>=3.5 <5", lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.5: - version "4.17.15" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" - integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== - -lodash@4.17.20: - version "4.17.20" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52" - integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA== - -loglevel@^1.6.6: - version "1.6.8" - resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.6.8.tgz#8a25fb75d092230ecd4457270d80b54e28011171" - integrity sha512-bsU7+gc9AJ2SqpzxwU3+1fedl8zAntbtC5XYlt3s2j1hJcn2PsXSmgN8TaLG/J1/2mod4+cE/3vNL70/c1RNCA== - -loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3.1, loose-envify@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" - integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== - dependencies: - js-tokens "^3.0.0 || ^4.0.0" - -lower-case@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-2.0.1.tgz#39eeb36e396115cc05e29422eaea9e692c9408c7" - integrity sha512-LiWgfDLLb1dwbFQZsSglpRj+1ctGnayXz3Uv0/WO8n558JycT5fg6zkNcnW0G68Nn0aEldTFeEfmjCfmqry/rQ== - dependencies: - tslib "^1.10.0" - -lru-cache@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" - integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== - dependencies: - yallist "^3.0.2" - -make-dir@^2.0.0, make-dir@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" - integrity sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA== - dependencies: - pify "^4.0.1" - semver "^5.6.0" - -make-dir@^3.0.2: - version "3.1.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" - integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== - dependencies: - semver "^6.0.0" - -makeerror@1.0.x: - version "1.0.11" - resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c" - integrity sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw= - dependencies: - tmpl "1.0.x" - -mamacro@^0.0.3: - version "0.0.3" - resolved "https://registry.yarnpkg.com/mamacro/-/mamacro-0.0.3.tgz#ad2c9576197c9f1abf308d0787865bd975a3f3e4" - integrity sha512-qMEwh+UujcQ+kbz3T6V+wAmO2U8veoq2w+3wY8MquqwVA3jChfwY+Tk52GZKDfACEPjuZ7r2oJLejwpt8jtwTA== - -map-age-cleaner@^0.1.1: - version "0.1.3" - resolved "https://registry.yarnpkg.com/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz#7d583a7306434c055fe474b0f45078e6e1b4b92a" - integrity sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w== - dependencies: - p-defer "^1.0.0" - -map-cache@^0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" - integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= - -map-visit@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" - integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48= - dependencies: - object-visit "^1.0.0" - -markdown-escapes@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/markdown-escapes/-/markdown-escapes-1.0.4.tgz#c95415ef451499d7602b91095f3c8e8975f78535" - integrity sha512-8z4efJYk43E0upd0NbVXwgSTQs6cT3T06etieCMEg7dRbzCbxUCK/GHlX8mhHRDcp+OLlHkPKsvqQTCvsRl2cg== - -md5.js@^1.3.4: - version "1.3.5" - resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" - integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg== - dependencies: - hash-base "^3.0.0" - inherits "^2.0.1" - safe-buffer "^5.1.2" - -mdast-add-list-metadata@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/mdast-add-list-metadata/-/mdast-add-list-metadata-1.0.1.tgz#95e73640ce2fc1fa2dcb7ec443d09e2bfe7db4cf" - integrity sha512-fB/VP4MJ0LaRsog7hGPxgOrSL3gE/2uEdZyDuSEnKCv/8IkYHiDkIQSbChiJoHyxZZXZ9bzckyRk+vNxFzh8rA== - dependencies: - unist-util-visit-parents "1.1.2" - -mdn-data@2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.4.tgz#699b3c38ac6f1d728091a64650b65d388502fd5b" - integrity sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA== - -mdn-data@2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.6.tgz#852dc60fcaa5daa2e8cf6c9189c440ed3e042978" - integrity sha512-rQvjv71olwNHgiTbfPZFkJtjNMciWgswYeciZhtvWLO8bmX3TnhyA62I6sTWOyZssWHJJjY6/KiWwqQsWWsqOA== - -media-typer@0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" - integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= - -mem@^4.0.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/mem/-/mem-4.3.0.tgz#461af497bc4ae09608cdb2e60eefb69bff744178" - integrity sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w== - dependencies: - map-age-cleaner "^0.1.1" - mimic-fn "^2.0.0" - p-is-promise "^2.0.0" - -memory-fs@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552" - integrity sha1-OpoguEYlI+RHz7x+i7gO1me/xVI= - dependencies: - errno "^0.1.3" - readable-stream "^2.0.1" - -memory-fs@^0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.5.0.tgz#324c01288b88652966d161db77838720845a8e3c" - integrity sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA== - dependencies: - errno "^0.1.3" - readable-stream "^2.0.1" - -merge-deep@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/merge-deep/-/merge-deep-3.0.2.tgz#f39fa100a4f1bd34ff29f7d2bf4508fbb8d83ad2" - integrity sha512-T7qC8kg4Zoti1cFd8Cr0M+qaZfOwjlPDEdZIIPPB2JZctjaPM4fX+i7HOId69tAti2fvO6X5ldfYUONDODsrkA== - dependencies: - arr-union "^3.1.0" - clone-deep "^0.2.4" - kind-of "^3.0.2" - -merge-descriptors@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" - integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= - -merge-stream@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" - integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== - -merge2@^1.2.3: - version "1.3.0" - resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.3.0.tgz#5b366ee83b2f1582c48f87e47cf1a9352103ca81" - integrity sha512-2j4DAdlBOkiSZIsaXk4mTE3sRS02yBHAtfy127xRV3bQUFqXkjHCHLW6Scv7DwNRbIWNHH8zpnz9zMaKXIdvYw== - -methods@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" - integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= - -microevent.ts@~0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/microevent.ts/-/microevent.ts-0.1.1.tgz#70b09b83f43df5172d0205a63025bce0f7357fa0" - integrity sha512-jo1OfR4TaEwd5HOrt5+tAZ9mqT4jmpNAusXtyfNzqVm9uiSYFZlKM1wYL4oU7azZW/PxQW53wM0S6OR1JHNa2g== - -micromatch@^3.1.10, micromatch@^3.1.4: - version "3.1.10" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" - integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== - dependencies: - arr-diff "^4.0.0" - array-unique "^0.3.2" - braces "^2.3.1" - define-property "^2.0.2" - extend-shallow "^3.0.2" - extglob "^2.0.4" - fragment-cache "^0.2.1" - kind-of "^6.0.2" - nanomatch "^1.2.9" - object.pick "^1.3.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.2" - -micromatch@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.2.tgz#4fcb0999bf9fbc2fcbdd212f6d629b9a56c39259" - integrity sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q== - dependencies: - braces "^3.0.1" - picomatch "^2.0.5" - -miller-rabin@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" - integrity sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA== - dependencies: - bn.js "^4.0.0" - brorand "^1.0.1" - -mime-db@1.44.0, "mime-db@>= 1.43.0 < 2": - version "1.44.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.44.0.tgz#fa11c5eb0aca1334b4233cb4d52f10c5a6272f92" - integrity sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg== - -mime-types@^2.1.12, mime-types@~2.1.17, mime-types@~2.1.19, mime-types@~2.1.24: - version "2.1.27" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.27.tgz#47949f98e279ea53119f5722e0f34e529bec009f" - integrity sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w== - dependencies: - mime-db "1.44.0" - -mime@1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" - integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== - -mime@^2.4.4: - version "2.4.5" - resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.5.tgz#d8de2ecb92982dedbb6541c9b6841d7f218ea009" - integrity sha512-3hQhEUF027BuxZjQA3s7rIv/7VCQPa27hN9u9g87sEkWaKwQPuXOkVKtOeiyUrnWqTDiOs8Ed2rwg733mB0R5w== - -mimic-fn@^2.0.0, mimic-fn@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" - integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== - -mini-create-react-context@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/mini-create-react-context/-/mini-create-react-context-0.4.0.tgz#df60501c83151db69e28eac0ef08b4002efab040" - integrity sha512-b0TytUgFSbgFJGzJqXPKCFCBWigAjpjo+Fl7Vf7ZbKRDptszpppKxXH6DRXEABZ/gcEQczeb0iZ7JvL8e8jjCA== - dependencies: - "@babel/runtime" "^7.5.5" - tiny-warning "^1.0.3" - -mini-css-extract-plugin@0.9.0: - version "0.9.0" - resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-0.9.0.tgz#47f2cf07aa165ab35733b1fc97d4c46c0564339e" - integrity sha512-lp3GeY7ygcgAmVIcRPBVhIkf8Us7FZjA+ILpal44qLdSu11wmjKQ3d9k15lfD7pO4esu9eUIAW7qiYIBppv40A== - dependencies: - loader-utils "^1.1.0" - normalize-url "1.9.1" - schema-utils "^1.0.0" - webpack-sources "^1.1.0" - -minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" - integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== - -minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" - integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo= - -minimatch@3.0.4, minimatch@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" - integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== - dependencies: - brace-expansion "^1.1.7" - -minimist@^1.1.1, minimist@^1.2.0, minimist@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" - integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== - -minipass-collect@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/minipass-collect/-/minipass-collect-1.0.2.tgz#22b813bf745dc6edba2576b940022ad6edc8c617" - integrity sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA== - dependencies: - minipass "^3.0.0" - -minipass-flush@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/minipass-flush/-/minipass-flush-1.0.5.tgz#82e7135d7e89a50ffe64610a787953c4c4cbb373" - integrity sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw== - dependencies: - minipass "^3.0.0" - -minipass-pipeline@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/minipass-pipeline/-/minipass-pipeline-1.2.2.tgz#3dcb6bb4a546e32969c7ad710f2c79a86abba93a" - integrity sha512-3JS5A2DKhD2g0Gg8x3yamO0pj7YeKGwVlDS90pF++kxptwx/F+B//roxf9SqYil5tQo65bijy+dAuAFZmYOouA== - dependencies: - minipass "^3.0.0" - -minipass@^3.0.0, minipass@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.1.1.tgz#7607ce778472a185ad6d89082aa2070f79cedcd5" - integrity sha512-UFqVihv6PQgwj8/yTGvl9kPz7xIAY+R5z6XYjRInD3Gk3qx6QGSD6zEcpeG4Dy/lQnv1J6zv8ejV90hyYIKf3w== - dependencies: - yallist "^4.0.0" - -mississippi@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-3.0.0.tgz#ea0a3291f97e0b5e8776b363d5f0a12d94c67022" - integrity sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA== - dependencies: - concat-stream "^1.5.0" - duplexify "^3.4.2" - end-of-stream "^1.1.0" - flush-write-stream "^1.0.0" - from2 "^2.1.0" - parallel-transform "^1.1.0" - pump "^3.0.0" - pumpify "^1.3.3" - stream-each "^1.1.0" - through2 "^2.0.0" - -mixin-deep@^1.2.0: - version "1.3.2" - resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" - integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA== - dependencies: - for-in "^1.0.2" - is-extendable "^1.0.1" - -mixin-object@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/mixin-object/-/mixin-object-2.0.1.tgz#4fb949441dab182540f1fe035ba60e1947a5e57e" - integrity sha1-T7lJRB2rGCVA8f4DW6YOGUel5X4= - dependencies: - for-in "^0.1.3" - is-extendable "^0.1.1" - -mkdirp@^0.5.1, mkdirp@~0.5.1: - version "0.5.5" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" - integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== - dependencies: - minimist "^1.2.5" - -move-concurrently@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92" - integrity sha1-viwAX9oy4LKa8fBdfEszIUxwH5I= - dependencies: - aproba "^1.1.1" - copy-concurrently "^1.0.0" - fs-write-stream-atomic "^1.0.8" - mkdirp "^0.5.1" - rimraf "^2.5.4" - run-queue "^1.0.3" - -ms@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" - integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= - -ms@2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" - integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== - -ms@^2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== - -multicast-dns-service-types@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz#899f11d9686e5e05cb91b35d5f0e63b773cfc901" - integrity sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE= - -multicast-dns@^6.0.1: - version "6.2.3" - resolved "https://registry.yarnpkg.com/multicast-dns/-/multicast-dns-6.2.3.tgz#a0ec7bd9055c4282f790c3c82f4e28db3b31b229" - integrity sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g== - dependencies: - dns-packet "^1.3.1" - thunky "^1.0.2" - -mute-stream@0.0.8: - version "0.0.8" - resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" - integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== - -nan@^2.12.1: - version "2.14.1" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.1.tgz#d7be34dfa3105b91494c3147089315eff8874b01" - integrity sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw== - -nanomatch@^1.2.9: - version "1.2.13" - resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" - integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== - dependencies: - arr-diff "^4.0.0" - array-unique "^0.3.2" - define-property "^2.0.2" - extend-shallow "^3.0.2" - fragment-cache "^0.2.1" - is-windows "^1.0.2" - kind-of "^6.0.2" - object.pick "^1.3.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - -natural-compare@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" - integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= - -negotiator@0.6.2: - version "0.6.2" - resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" - integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== - -neo-async@^2.5.0, neo-async@^2.6.1: - version "2.6.1" - resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.1.tgz#ac27ada66167fa8849a6addd837f6b189ad2081c" - integrity sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw== - -next-tick@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c" - integrity sha1-yobR/ogoFpsBICCOPchCS524NCw= - -nice-try@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" - integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== - -no-case@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/no-case/-/no-case-3.0.3.tgz#c21b434c1ffe48b39087e86cfb4d2582e9df18f8" - integrity sha512-ehY/mVQCf9BL0gKfsJBvFJen+1V//U+0HQMPrWct40ixE4jnv0bfvxDbWtAHL9EcaPEOJHVVYKoQn1TlZUB8Tw== - dependencies: - lower-case "^2.0.1" - tslib "^1.10.0" - -node-forge@0.9.0: - version "0.9.0" - resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.9.0.tgz#d624050edbb44874adca12bb9a52ec63cb782579" - integrity sha512-7ASaDa3pD+lJ3WvXFsxekJQelBKRpne+GOVbLbtHYdd7pFspyeuJHnWfLplGf3SwKGbfs/aYl5V/JCIaHVUKKQ== - -node-int64@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" - integrity sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs= - -node-libs-browser@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.2.1.tgz#b64f513d18338625f90346d27b0d235e631f6425" - integrity sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q== - dependencies: - assert "^1.1.1" - browserify-zlib "^0.2.0" - buffer "^4.3.0" - console-browserify "^1.1.0" - constants-browserify "^1.0.0" - crypto-browserify "^3.11.0" - domain-browser "^1.1.1" - events "^3.0.0" - https-browserify "^1.0.0" - os-browserify "^0.3.0" - path-browserify "0.0.1" - process "^0.11.10" - punycode "^1.2.4" - querystring-es3 "^0.2.0" - readable-stream "^2.3.3" - stream-browserify "^2.0.1" - stream-http "^2.7.2" - string_decoder "^1.0.0" - timers-browserify "^2.0.4" - tty-browserify "0.0.0" - url "^0.11.0" - util "^0.11.0" - vm-browserify "^1.0.1" - -node-modules-regexp@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz#8d9dbe28964a4ac5712e9131642107c71e90ec40" - integrity sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA= - -node-notifier@^5.4.2: - version "5.4.3" - resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-5.4.3.tgz#cb72daf94c93904098e28b9c590fd866e464bd50" - integrity sha512-M4UBGcs4jeOK9CjTsYwkvH6/MzuUmGCyTW+kCY7uO+1ZVr0+FHGdPdIf5CCLqAaxnRrWidyoQlNkMIIVwbKB8Q== - dependencies: - growly "^1.3.0" - is-wsl "^1.1.0" - semver "^5.5.0" - shellwords "^0.1.1" - which "^1.3.0" - -node-releases@^1.1.52, node-releases@^1.1.53: - version "1.1.55" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.55.tgz#8af23b7c561d8e2e6e36a46637bab84633b07cee" - integrity sha512-H3R3YR/8TjT5WPin/wOoHOUPHgvj8leuU/Keta/rwelEQN9pA/S2Dx8/se4pZ2LBxSd0nAGzsNzhqwa77v7F1w== - -normalize-package-data@^2.3.2: - version "2.5.0" - resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" - integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== - dependencies: - hosted-git-info "^2.1.4" - resolve "^1.10.0" - semver "2 || 3 || 4 || 5" - validate-npm-package-license "^3.0.1" - -normalize-path@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" - integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk= - dependencies: - remove-trailing-separator "^1.0.1" - -normalize-path@^3.0.0, normalize-path@~3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" - integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== - -normalize-range@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942" - integrity sha1-LRDAa9/TEuqXd2laTShDlFa3WUI= - -normalize-url@1.9.1: - version "1.9.1" - resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-1.9.1.tgz#2cc0d66b31ea23036458436e3620d85954c66c3c" - integrity sha1-LMDWazHqIwNkWENuNiDYWVTGbDw= - dependencies: - object-assign "^4.0.1" - prepend-http "^1.0.0" - query-string "^4.1.0" - sort-keys "^1.0.0" - -normalize-url@^3.0.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-3.3.0.tgz#b2e1c4dc4f7c6d57743df733a4f5978d18650559" - integrity sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg== - -npm-run-path@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" - integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8= - dependencies: - path-key "^2.0.0" - -nth-check@^1.0.2, nth-check@~1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-1.0.2.tgz#b2bd295c37e3dd58a3bf0700376663ba4d9cf05c" - integrity sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg== - dependencies: - boolbase "~1.0.0" - -num2fraction@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/num2fraction/-/num2fraction-1.2.2.tgz#6f682b6a027a4e9ddfa4564cd2589d1d4e669ede" - integrity sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4= - -number-is-nan@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" - integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= - -nwsapi@^2.0.7, nwsapi@^2.1.3: - version "2.2.0" - resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.0.tgz#204879a9e3d068ff2a55139c2c772780681a38b7" - integrity sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ== - -oauth-sign@~0.9.0: - version "0.9.0" - resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" - integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== - -object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= - -object-copy@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" - integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw= - dependencies: - copy-descriptor "^0.1.0" - define-property "^0.2.5" - kind-of "^3.0.3" - -object-hash@^2.0.1: - version "2.0.3" - resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-2.0.3.tgz#d12db044e03cd2ca3d77c0570d87225b02e1e6ea" - integrity sha512-JPKn0GMu+Fa3zt3Bmr66JhokJU5BaNBIh4ZeTlaCBzrBsOeXzwcKKAK1tbLiPKgvwmPXsDvvLHoWh5Bm7ofIYg== - -object-inspect@^1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.7.0.tgz#f4f6bd181ad77f006b5ece60bd0b6f398ff74a67" - integrity sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw== - -object-is@^1.0.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.2.tgz#c5d2e87ff9e119f78b7a088441519e2eec1573b6" - integrity sha512-5lHCz+0uufF6wZ7CRFWJN3hp8Jqblpgve06U5CMQ3f//6iDjPr2PEo9MWCjEssDsa+UZEL4PkFpr+BMop6aKzQ== - dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.5" - -object-keys@^1.0.11, object-keys@^1.0.12, object-keys@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" - integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== - -object-path@0.11.4: - version "0.11.4" - resolved "https://registry.yarnpkg.com/object-path/-/object-path-0.11.4.tgz#370ae752fbf37de3ea70a861c23bba8915691949" - integrity sha1-NwrnUvvzfePqcKhhwju6iRVpGUk= - -object-visit@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" - integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs= - dependencies: - isobject "^3.0.0" - -object.assign@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da" - integrity sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w== - dependencies: - define-properties "^1.1.2" - function-bind "^1.1.1" - has-symbols "^1.0.0" - object-keys "^1.0.11" - -object.entries@^1.1.0, object.entries@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.1.tgz#ee1cf04153de02bb093fec33683900f57ce5399b" - integrity sha512-ilqR7BgdyZetJutmDPfXCDffGa0/Yzl2ivVNpbx/g4UeWrCdRnFDUBrKJGLhGieRHDATnyZXWBeCb29k9CJysQ== - dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.0-next.1" - function-bind "^1.1.1" - has "^1.0.3" - -object.fromentries@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.2.tgz#4a09c9b9bb3843dd0f89acdb517a794d4f355ac9" - integrity sha512-r3ZiBH7MQppDJVLx6fhD618GKNG40CZYH9wgwdhKxBDDbQgjeWGGd4AtkZad84d291YxvWe7bJGuE65Anh0dxQ== - dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.0-next.1" - function-bind "^1.1.1" - has "^1.0.3" - -object.getownpropertydescriptors@^2.0.3, object.getownpropertydescriptors@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz#369bf1f9592d8ab89d712dced5cb81c7c5352649" - integrity sha512-Z53Oah9A3TdLoblT7VKJaTDdXdT+lQO+cNpKVnya5JDe9uLvzu1YyY1yFDFrcxrlRgWrEFH0jJtD/IbuwjcEVg== - dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.0-next.1" - -object.pick@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" - integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c= - dependencies: - isobject "^3.0.1" - -object.values@^1.1.0, object.values@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.1.tgz#68a99ecde356b7e9295a3c5e0ce31dc8c953de5e" - integrity sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA== - dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.0-next.1" - function-bind "^1.1.1" - has "^1.0.3" - -obuf@^1.0.0, obuf@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e" - integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg== - -on-finished@~2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" - integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= - dependencies: - ee-first "1.1.1" - -on-headers@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" - integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== - -once@^1.3.0, once@^1.3.1, once@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= - dependencies: - wrappy "1" - -onetime@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.0.tgz#fff0f3c91617fe62bb50189636e99ac8a6df7be5" - integrity sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q== - dependencies: - mimic-fn "^2.1.0" - -open@^7.0.2: - version "7.0.3" - resolved "https://registry.yarnpkg.com/open/-/open-7.0.3.tgz#db551a1af9c7ab4c7af664139930826138531c48" - integrity sha512-sP2ru2v0P290WFfv49Ap8MF6PkzGNnGlAwHweB4WR4mr5d2d0woiCluUeJ218w7/+PmoBy9JmYgD5A4mLcWOFA== - dependencies: - is-docker "^2.0.0" - is-wsl "^2.1.1" - -opn@^5.5.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/opn/-/opn-5.5.0.tgz#fc7164fab56d235904c51c3b27da6758ca3b9bfc" - integrity sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA== - dependencies: - is-wsl "^1.1.0" - -optimize-css-assets-webpack-plugin@5.0.3: - version "5.0.3" - resolved "https://registry.yarnpkg.com/optimize-css-assets-webpack-plugin/-/optimize-css-assets-webpack-plugin-5.0.3.tgz#e2f1d4d94ad8c0af8967ebd7cf138dcb1ef14572" - integrity sha512-q9fbvCRS6EYtUKKSwI87qm2IxlyJK5b4dygW1rKUBT6mMDhdG5e5bZT63v6tnJR9F9FB/H5a0HTmtw+laUBxKA== - dependencies: - cssnano "^4.1.10" - last-call-webpack-plugin "^3.0.0" - -optionator@^0.8.1, optionator@^0.8.3: - version "0.8.3" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" - integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== - dependencies: - deep-is "~0.1.3" - fast-levenshtein "~2.0.6" - levn "~0.3.0" - prelude-ls "~1.1.2" - type-check "~0.3.2" - word-wrap "~1.2.3" - -original@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/original/-/original-1.0.2.tgz#e442a61cffe1c5fd20a65f3261c26663b303f25f" - integrity sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg== - dependencies: - url-parse "^1.4.3" - -os-browserify@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" - integrity sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc= - -os-locale@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-3.1.0.tgz#a802a6ee17f24c10483ab9935719cef4ed16bf1a" - integrity sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q== - dependencies: - execa "^1.0.0" - lcid "^2.0.0" - mem "^4.0.0" - -os-tmpdir@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" - integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= - -p-defer@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c" - integrity sha1-n26xgvbJqozXQwBKfU+WsZaw+ww= - -p-each-series@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-each-series/-/p-each-series-1.0.0.tgz#930f3d12dd1f50e7434457a22cd6f04ac6ad7f71" - integrity sha1-kw89Et0fUOdDRFeiLNbwSsatf3E= - dependencies: - p-reduce "^1.0.0" - -p-finally@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" - integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= - -p-is-promise@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-2.1.0.tgz#918cebaea248a62cf7ffab8e3bca8c5f882fc42e" - integrity sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg== - -p-limit@^1.1.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" - integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== - dependencies: - p-try "^1.0.0" - -p-limit@^2.0.0, p-limit@^2.2.0, p-limit@^2.2.2: - version "2.3.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" - integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== - dependencies: - p-try "^2.0.0" - -p-locate@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" - integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM= - dependencies: - p-limit "^1.1.0" - -p-locate@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" - integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== - dependencies: - p-limit "^2.0.0" - -p-locate@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" - integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== - dependencies: - p-limit "^2.2.0" - -p-map@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/p-map/-/p-map-2.1.0.tgz#310928feef9c9ecc65b68b17693018a665cea175" - integrity sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw== - -p-map@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/p-map/-/p-map-3.0.0.tgz#d704d9af8a2ba684e2600d9a215983d4141a979d" - integrity sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ== - dependencies: - aggregate-error "^3.0.0" - -p-reduce@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-reduce/-/p-reduce-1.0.0.tgz#18c2b0dd936a4690a529f8231f58a0fdb6a47dfa" - integrity sha1-GMKw3ZNqRpClKfgjH1ig/bakffo= - -p-retry@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/p-retry/-/p-retry-3.0.1.tgz#316b4c8893e2c8dc1cfa891f406c4b422bebf328" - integrity sha512-XE6G4+YTTkT2a0UWb2kjZe8xNwf8bIbnqpc/IS/idOBVhyves0mK5OJgeocjx7q5pvX/6m23xuzVPYT1uGM73w== - dependencies: - retry "^0.12.0" - -p-try@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" - integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= - -p-try@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" - integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== - -pako@~1.0.5: - version "1.0.11" - resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" - integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw== - -parallel-transform@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/parallel-transform/-/parallel-transform-1.2.0.tgz#9049ca37d6cb2182c3b1d2c720be94d14a5814fc" - integrity sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg== - dependencies: - cyclist "^1.0.1" - inherits "^2.0.3" - readable-stream "^2.1.5" - -param-case@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/param-case/-/param-case-3.0.3.tgz#4be41f8399eff621c56eebb829a5e451d9801238" - integrity sha512-VWBVyimc1+QrzappRs7waeN2YmoZFCGXWASRYX1/rGHtXqEcrGEIDm+jqIwFa2fRXNgQEwrxaYuIrX0WcAguTA== - dependencies: - dot-case "^3.0.3" - tslib "^1.10.0" - -parent-module@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" - integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== - dependencies: - callsites "^3.0.0" - -parse-asn1@^5.0.0, parse-asn1@^5.1.5: - version "5.1.5" - resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.5.tgz#003271343da58dc94cace494faef3d2147ecea0e" - integrity sha512-jkMYn1dcJqF6d5CpU689bq7w/b5ALS9ROVSpQDPrZsqqesUJii9qutvoT5ltGedNXMO2e16YUWIghG9KxaViTQ== - dependencies: - asn1.js "^4.0.0" - browserify-aes "^1.0.0" - create-hash "^1.1.0" - evp_bytestokey "^1.0.0" - pbkdf2 "^3.0.3" - safe-buffer "^5.1.1" - -parse-entities@^1.1.0: - version "1.2.2" - resolved "https://registry.yarnpkg.com/parse-entities/-/parse-entities-1.2.2.tgz#c31bf0f653b6661354f8973559cb86dd1d5edf50" - integrity sha512-NzfpbxW/NPrzZ/yYSoQxyqUZMZXIdCfE0OIN4ESsnptHJECoUk3FZktxNuzQf4tjt5UEopnxpYJbvYuxIFDdsg== - dependencies: - character-entities "^1.0.0" - character-entities-legacy "^1.0.0" - character-reference-invalid "^1.0.0" - is-alphanumerical "^1.0.0" - is-decimal "^1.0.0" - is-hexadecimal "^1.0.0" - -parse-json@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" - integrity sha1-9ID0BDTvgHQfhGkJn43qGPVaTck= - dependencies: - error-ex "^1.2.0" - -parse-json@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" - integrity sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA= - dependencies: - error-ex "^1.3.1" - json-parse-better-errors "^1.0.1" - -parse-json@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.0.0.tgz#73e5114c986d143efa3712d4ea24db9a4266f60f" - integrity sha512-OOY5b7PAEFV0E2Fir1KOkxchnZNCdowAJgQ5NuxjpBKTRP3pQhwkrkxqQjeoKJ+fO7bCpmIZaogI4eZGDMEGOw== - dependencies: - "@babel/code-frame" "^7.0.0" - error-ex "^1.3.1" - json-parse-better-errors "^1.0.1" - lines-and-columns "^1.1.6" - -parse5@4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/parse5/-/parse5-4.0.0.tgz#6d78656e3da8d78b4ec0b906f7c08ef1dfe3f608" - integrity sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA== - -parse5@5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/parse5/-/parse5-5.1.0.tgz#c59341c9723f414c452975564c7c00a68d58acd2" - integrity sha512-fxNG2sQjHvlVAYmzBZS9YlDp6PTSSDwa98vkD4QgVDDCAo84z5X1t5XyJQ62ImdLXx5NdIIfihey6xpum9/gRQ== - -parseurl@~1.3.2, parseurl@~1.3.3: - version "1.3.3" - resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" - integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== - -pascal-case@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/pascal-case/-/pascal-case-3.1.1.tgz#5ac1975133ed619281e88920973d2cd1f279de5f" - integrity sha512-XIeHKqIrsquVTQL2crjq3NfJUxmdLasn3TYOU0VBM+UX2a6ztAWBlJQBePLGY7VHW8+2dRadeIPK5+KImwTxQA== - dependencies: - no-case "^3.0.3" - tslib "^1.10.0" - -pascalcase@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" - integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= - -path-browserify@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.1.tgz#e6c4ddd7ed3aa27c68a20cc4e50e1a4ee83bbc4a" - integrity sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ== - -path-dirname@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" - integrity sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA= - -path-exists@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" - integrity sha1-D+tsZPD8UY2adU3V77YscCJ2H0s= - dependencies: - pinkie-promise "^2.0.0" - -path-exists@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" - integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= - -path-exists@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" - integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== - -path-is-absolute@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= - -path-is-inside@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" - integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM= - -path-key@^2.0.0, path-key@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" - integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= - -path-key@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" - integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== - -path-parse@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" - integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== - -path-to-regexp@0.1.7: - version "0.1.7" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" - integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= - -path-to-regexp@^1.7.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.8.0.tgz#887b3ba9d84393e87a0a0b9f4cb756198b53548a" - integrity sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA== - dependencies: - isarray "0.0.1" - -path-type@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73" - integrity sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM= - dependencies: - pify "^2.0.0" - -path-type@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f" - integrity sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg== - dependencies: - pify "^3.0.0" - -path-type@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" - integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== - -pbkdf2@^3.0.3: - version "3.0.17" - resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.17.tgz#976c206530617b14ebb32114239f7b09336e93a6" - integrity sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA== - dependencies: - create-hash "^1.1.2" - create-hmac "^1.1.4" - ripemd160 "^2.0.1" - safe-buffer "^5.0.1" - sha.js "^2.4.8" - -performance-now@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" - integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= - -picomatch@^2.0.4, picomatch@^2.0.5, picomatch@^2.2.1: - version "2.2.2" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad" - integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg== - -pify@^2.0.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" - integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= - -pify@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" - integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= - -pify@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" - integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== - -pinkie-promise@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" - integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o= - dependencies: - pinkie "^2.0.0" - -pinkie@^2.0.0: - version "2.0.4" - resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" - integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= - -pirates@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.1.tgz#643a92caf894566f91b2b986d2c66950a8e2fb87" - integrity sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA== - dependencies: - node-modules-regexp "^1.0.0" - -pkg-dir@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-1.0.0.tgz#7a4b508a8d5bb2d629d447056ff4e9c9314cf3d4" - integrity sha1-ektQio1bstYp1EcFb/TpyTFM89Q= - dependencies: - find-up "^1.0.0" - -pkg-dir@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b" - integrity sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s= - dependencies: - find-up "^2.1.0" - -pkg-dir@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-3.0.0.tgz#2749020f239ed990881b1f71210d51eb6523bea3" - integrity sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw== - dependencies: - find-up "^3.0.0" - -pkg-dir@^4.1.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" - integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== - dependencies: - find-up "^4.0.0" - -pkg-up@3.1.0, pkg-up@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-3.1.0.tgz#100ec235cc150e4fd42519412596a28512a0def5" - integrity sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA== - dependencies: - find-up "^3.0.0" - -pkg-up@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-2.0.0.tgz#c819ac728059a461cab1c3889a2be3c49a004d7f" - integrity sha1-yBmscoBZpGHKscOImivjxJoATX8= - dependencies: - find-up "^2.1.0" - -pn@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/pn/-/pn-1.1.0.tgz#e2f4cef0e219f463c179ab37463e4e1ecdccbafb" - integrity sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA== - -pnp-webpack-plugin@1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/pnp-webpack-plugin/-/pnp-webpack-plugin-1.6.0.tgz#d5c068013a2fdc82224ca50ed179c8fba9036a8e" - integrity sha512-ZcMGn/xF/fCOq+9kWMP9vVVxjIkMCja72oy3lziR7UHy0hHFZ57iVpQ71OtveVbmzeCmphBg8pxNdk/hlK99aQ== - dependencies: - ts-pnp "^1.1.2" - -popper.js@1.16.1-lts: - version "1.16.1-lts" - resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.16.1-lts.tgz#cf6847b807da3799d80ee3d6d2f90df8a3f50b05" - integrity sha512-Kjw8nKRl1m+VrSFCoVGPph93W/qrSO7ZkqPpTf7F4bk/sqcfWK019dWBUpE/fBOsOQY1dks/Bmcbfn1heM/IsA== - -portfinder@^1.0.25: - version "1.0.26" - resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.26.tgz#475658d56ca30bed72ac7f1378ed350bd1b64e70" - integrity sha512-Xi7mKxJHHMI3rIUrnm/jjUgwhbYMkp/XKEcZX3aG4BrumLpq3nmoQMX+ClYnDZnZ/New7IatC1no5RX0zo1vXQ== - dependencies: - async "^2.6.2" - debug "^3.1.1" - mkdirp "^0.5.1" - -posix-character-classes@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" - integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= - -postcss-attribute-case-insensitive@^4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-4.0.2.tgz#d93e46b504589e94ac7277b0463226c68041a880" - integrity sha512-clkFxk/9pcdb4Vkn0hAHq3YnxBQ2p0CGD1dy24jN+reBck+EWxMbxSUqN4Yj7t0w8csl87K6p0gxBe1utkJsYA== - dependencies: - postcss "^7.0.2" - postcss-selector-parser "^6.0.2" - -postcss-browser-comments@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/postcss-browser-comments/-/postcss-browser-comments-3.0.0.tgz#1248d2d935fb72053c8e1f61a84a57292d9f65e9" - integrity sha512-qfVjLfq7HFd2e0HW4s1dvU8X080OZdG46fFbIBFjW7US7YPDcWfRvdElvwMJr2LI6hMmD+7LnH2HcmXTs+uOig== - dependencies: - postcss "^7" - -postcss-calc@^7.0.1: - version "7.0.2" - resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-7.0.2.tgz#504efcd008ca0273120568b0792b16cdcde8aac1" - integrity sha512-rofZFHUg6ZIrvRwPeFktv06GdbDYLcGqh9EwiMutZg+a0oePCCw1zHOEiji6LCpyRcjTREtPASuUqeAvYlEVvQ== - dependencies: - postcss "^7.0.27" - postcss-selector-parser "^6.0.2" - postcss-value-parser "^4.0.2" - -postcss-color-functional-notation@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/postcss-color-functional-notation/-/postcss-color-functional-notation-2.0.1.tgz#5efd37a88fbabeb00a2966d1e53d98ced93f74e0" - integrity sha512-ZBARCypjEDofW4P6IdPVTLhDNXPRn8T2s1zHbZidW6rPaaZvcnCS2soYFIQJrMZSxiePJ2XIYTlcb2ztr/eT2g== - dependencies: - postcss "^7.0.2" - postcss-values-parser "^2.0.0" - -postcss-color-gray@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/postcss-color-gray/-/postcss-color-gray-5.0.0.tgz#532a31eb909f8da898ceffe296fdc1f864be8547" - integrity sha512-q6BuRnAGKM/ZRpfDascZlIZPjvwsRye7UDNalqVz3s7GDxMtqPY6+Q871liNxsonUw8oC61OG+PSaysYpl1bnw== - dependencies: - "@csstools/convert-colors" "^1.4.0" - postcss "^7.0.5" - postcss-values-parser "^2.0.0" - -postcss-color-hex-alpha@^5.0.3: - version "5.0.3" - resolved "https://registry.yarnpkg.com/postcss-color-hex-alpha/-/postcss-color-hex-alpha-5.0.3.tgz#a8d9ca4c39d497c9661e374b9c51899ef0f87388" - integrity sha512-PF4GDel8q3kkreVXKLAGNpHKilXsZ6xuu+mOQMHWHLPNyjiUBOr75sp5ZKJfmv1MCus5/DWUGcK9hm6qHEnXYw== - dependencies: - postcss "^7.0.14" - postcss-values-parser "^2.0.1" - -postcss-color-mod-function@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/postcss-color-mod-function/-/postcss-color-mod-function-3.0.3.tgz#816ba145ac11cc3cb6baa905a75a49f903e4d31d" - integrity sha512-YP4VG+xufxaVtzV6ZmhEtc+/aTXH3d0JLpnYfxqTvwZPbJhWqp8bSY3nfNzNRFLgB4XSaBA82OE4VjOOKpCdVQ== - dependencies: - "@csstools/convert-colors" "^1.4.0" - postcss "^7.0.2" - postcss-values-parser "^2.0.0" - -postcss-color-rebeccapurple@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/postcss-color-rebeccapurple/-/postcss-color-rebeccapurple-4.0.1.tgz#c7a89be872bb74e45b1e3022bfe5748823e6de77" - integrity sha512-aAe3OhkS6qJXBbqzvZth2Au4V3KieR5sRQ4ptb2b2O8wgvB3SJBsdG+jsn2BZbbwekDG8nTfcCNKcSfe/lEy8g== - dependencies: - postcss "^7.0.2" - postcss-values-parser "^2.0.0" - -postcss-colormin@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-4.0.3.tgz#ae060bce93ed794ac71264f08132d550956bd381" - integrity sha512-WyQFAdDZpExQh32j0U0feWisZ0dmOtPl44qYmJKkq9xFWY3p+4qnRzCHeNrkeRhwPHz9bQ3mo0/yVkaply0MNw== - dependencies: - browserslist "^4.0.0" - color "^3.0.0" - has "^1.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-convert-values@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-4.0.1.tgz#ca3813ed4da0f812f9d43703584e449ebe189a7f" - integrity sha512-Kisdo1y77KUC0Jmn0OXU/COOJbzM8cImvw1ZFsBgBgMgb1iL23Zs/LXRe3r+EZqM3vGYKdQ2YJVQ5VkJI+zEJQ== - dependencies: - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-custom-media@^7.0.8: - version "7.0.8" - resolved "https://registry.yarnpkg.com/postcss-custom-media/-/postcss-custom-media-7.0.8.tgz#fffd13ffeffad73621be5f387076a28b00294e0c" - integrity sha512-c9s5iX0Ge15o00HKbuRuTqNndsJUbaXdiNsksnVH8H4gdc+zbLzr/UasOwNG6CTDpLFekVY4672eWdiiWu2GUg== - dependencies: - postcss "^7.0.14" - -postcss-custom-properties@^8.0.11: - version "8.0.11" - resolved "https://registry.yarnpkg.com/postcss-custom-properties/-/postcss-custom-properties-8.0.11.tgz#2d61772d6e92f22f5e0d52602df8fae46fa30d97" - integrity sha512-nm+o0eLdYqdnJ5abAJeXp4CEU1c1k+eB2yMCvhgzsds/e0umabFrN6HoTy/8Q4K5ilxERdl/JD1LO5ANoYBeMA== - dependencies: - postcss "^7.0.17" - postcss-values-parser "^2.0.1" - -postcss-custom-selectors@^5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/postcss-custom-selectors/-/postcss-custom-selectors-5.1.2.tgz#64858c6eb2ecff2fb41d0b28c9dd7b3db4de7fba" - integrity sha512-DSGDhqinCqXqlS4R7KGxL1OSycd1lydugJ1ky4iRXPHdBRiozyMHrdu0H3o7qNOCiZwySZTUI5MV0T8QhCLu+w== - dependencies: - postcss "^7.0.2" - postcss-selector-parser "^5.0.0-rc.3" - -postcss-dir-pseudo-class@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/postcss-dir-pseudo-class/-/postcss-dir-pseudo-class-5.0.0.tgz#6e3a4177d0edb3abcc85fdb6fbb1c26dabaeaba2" - integrity sha512-3pm4oq8HYWMZePJY+5ANriPs3P07q+LW6FAdTlkFH2XqDdP4HeeJYMOzn0HYLhRSjBO3fhiqSwwU9xEULSrPgw== - dependencies: - postcss "^7.0.2" - postcss-selector-parser "^5.0.0-rc.3" - -postcss-discard-comments@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-discard-comments/-/postcss-discard-comments-4.0.2.tgz#1fbabd2c246bff6aaad7997b2b0918f4d7af4033" - integrity sha512-RJutN259iuRf3IW7GZyLM5Sw4GLTOH8FmsXBnv8Ab/Tc2k4SR4qbV4DNbyyY4+Sjo362SyDmW2DQ7lBSChrpkg== - dependencies: - postcss "^7.0.0" - -postcss-discard-duplicates@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-discard-duplicates/-/postcss-discard-duplicates-4.0.2.tgz#3fe133cd3c82282e550fc9b239176a9207b784eb" - integrity sha512-ZNQfR1gPNAiXZhgENFfEglF93pciw0WxMkJeVmw8eF+JZBbMD7jp6C67GqJAXVZP2BWbOztKfbsdmMp/k8c6oQ== - dependencies: - postcss "^7.0.0" - -postcss-discard-empty@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/postcss-discard-empty/-/postcss-discard-empty-4.0.1.tgz#c8c951e9f73ed9428019458444a02ad90bb9f765" - integrity sha512-B9miTzbznhDjTfjvipfHoqbWKwd0Mj+/fL5s1QOz06wufguil+Xheo4XpOnc4NqKYBCNqqEzgPv2aPBIJLox0w== - dependencies: - postcss "^7.0.0" - -postcss-discard-overridden@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/postcss-discard-overridden/-/postcss-discard-overridden-4.0.1.tgz#652aef8a96726f029f5e3e00146ee7a4e755ff57" - integrity sha512-IYY2bEDD7g1XM1IDEsUT4//iEYCxAmP5oDSFMVU/JVvT7gh+l4fmjciLqGgwjdWpQIdb0Che2VX00QObS5+cTg== - dependencies: - postcss "^7.0.0" - -postcss-double-position-gradients@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/postcss-double-position-gradients/-/postcss-double-position-gradients-1.0.0.tgz#fc927d52fddc896cb3a2812ebc5df147e110522e" - integrity sha512-G+nV8EnQq25fOI8CH/B6krEohGWnF5+3A6H/+JEpOncu5dCnkS1QQ6+ct3Jkaepw1NGVqqOZH6lqrm244mCftA== - dependencies: - postcss "^7.0.5" - postcss-values-parser "^2.0.0" - -postcss-env-function@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/postcss-env-function/-/postcss-env-function-2.0.2.tgz#0f3e3d3c57f094a92c2baf4b6241f0b0da5365d7" - integrity sha512-rwac4BuZlITeUbiBq60h/xbLzXY43qOsIErngWa4l7Mt+RaSkT7QBjXVGTcBHupykkblHMDrBFh30zchYPaOUw== - dependencies: - postcss "^7.0.2" - postcss-values-parser "^2.0.0" - -postcss-flexbugs-fixes@4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/postcss-flexbugs-fixes/-/postcss-flexbugs-fixes-4.1.0.tgz#e094a9df1783e2200b7b19f875dcad3b3aff8b20" - integrity sha512-jr1LHxQvStNNAHlgco6PzY308zvLklh7SJVYuWUwyUQncofaAlD2l+P/gxKHOdqWKe7xJSkVLFF/2Tp+JqMSZA== - dependencies: - postcss "^7.0.0" - -postcss-focus-visible@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/postcss-focus-visible/-/postcss-focus-visible-4.0.0.tgz#477d107113ade6024b14128317ade2bd1e17046e" - integrity sha512-Z5CkWBw0+idJHSV6+Bgf2peDOFf/x4o+vX/pwcNYrWpXFrSfTkQ3JQ1ojrq9yS+upnAlNRHeg8uEwFTgorjI8g== - dependencies: - postcss "^7.0.2" - -postcss-focus-within@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/postcss-focus-within/-/postcss-focus-within-3.0.0.tgz#763b8788596cee9b874c999201cdde80659ef680" - integrity sha512-W0APui8jQeBKbCGZudW37EeMCjDeVxKgiYfIIEo8Bdh5SpB9sxds/Iq8SEuzS0Q4YFOlG7EPFulbbxujpkrV2w== - dependencies: - postcss "^7.0.2" - -postcss-font-variant@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/postcss-font-variant/-/postcss-font-variant-4.0.0.tgz#71dd3c6c10a0d846c5eda07803439617bbbabacc" - integrity sha512-M8BFYKOvCrI2aITzDad7kWuXXTm0YhGdP9Q8HanmN4EF1Hmcgs1KK5rSHylt/lUJe8yLxiSwWAHdScoEiIxztg== - dependencies: - postcss "^7.0.2" - -postcss-gap-properties@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/postcss-gap-properties/-/postcss-gap-properties-2.0.0.tgz#431c192ab3ed96a3c3d09f2ff615960f902c1715" - integrity sha512-QZSqDaMgXCHuHTEzMsS2KfVDOq7ZFiknSpkrPJY6jmxbugUPTuSzs/vuE5I3zv0WAS+3vhrlqhijiprnuQfzmg== - dependencies: - postcss "^7.0.2" - -postcss-image-set-function@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/postcss-image-set-function/-/postcss-image-set-function-3.0.1.tgz#28920a2f29945bed4c3198d7df6496d410d3f288" - integrity sha512-oPTcFFip5LZy8Y/whto91L9xdRHCWEMs3e1MdJxhgt4jy2WYXfhkng59fH5qLXSCPN8k4n94p1Czrfe5IOkKUw== - dependencies: - postcss "^7.0.2" - postcss-values-parser "^2.0.0" - -postcss-initial@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/postcss-initial/-/postcss-initial-3.0.2.tgz#f018563694b3c16ae8eaabe3c585ac6319637b2d" - integrity sha512-ugA2wKonC0xeNHgirR4D3VWHs2JcU08WAi1KFLVcnb7IN89phID6Qtg2RIctWbnvp1TM2BOmDtX8GGLCKdR8YA== - dependencies: - lodash.template "^4.5.0" - postcss "^7.0.2" - -postcss-lab-function@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/postcss-lab-function/-/postcss-lab-function-2.0.1.tgz#bb51a6856cd12289ab4ae20db1e3821ef13d7d2e" - integrity sha512-whLy1IeZKY+3fYdqQFuDBf8Auw+qFuVnChWjmxm/UhHWqNHZx+B99EwxTvGYmUBqe3Fjxs4L1BoZTJmPu6usVg== - dependencies: - "@csstools/convert-colors" "^1.4.0" - postcss "^7.0.2" - postcss-values-parser "^2.0.0" - -postcss-load-config@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-2.1.0.tgz#c84d692b7bb7b41ddced94ee62e8ab31b417b003" - integrity sha512-4pV3JJVPLd5+RueiVVB+gFOAa7GWc25XQcMp86Zexzke69mKf6Nx9LRcQywdz7yZI9n1udOxmLuAwTBypypF8Q== - dependencies: - cosmiconfig "^5.0.0" - import-cwd "^2.0.0" - -postcss-loader@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-3.0.0.tgz#6b97943e47c72d845fa9e03f273773d4e8dd6c2d" - integrity sha512-cLWoDEY5OwHcAjDnkyRQzAXfs2jrKjXpO/HQFcc5b5u/r7aa471wdmChmwfnv7x2u840iat/wi0lQ5nbRgSkUA== - dependencies: - loader-utils "^1.1.0" - postcss "^7.0.0" - postcss-load-config "^2.0.0" - schema-utils "^1.0.0" - -postcss-logical@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/postcss-logical/-/postcss-logical-3.0.0.tgz#2495d0f8b82e9f262725f75f9401b34e7b45d5b5" - integrity sha512-1SUKdJc2vuMOmeItqGuNaC+N8MzBWFWEkAnRnLpFYj1tGGa7NqyVBujfRtgNa2gXR+6RkGUiB2O5Vmh7E2RmiA== - dependencies: - postcss "^7.0.2" - -postcss-media-minmax@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/postcss-media-minmax/-/postcss-media-minmax-4.0.0.tgz#b75bb6cbc217c8ac49433e12f22048814a4f5ed5" - integrity sha512-fo9moya6qyxsjbFAYl97qKO9gyre3qvbMnkOZeZwlsW6XYFsvs2DMGDlchVLfAd8LHPZDxivu/+qW2SMQeTHBw== - dependencies: - postcss "^7.0.2" - -postcss-merge-longhand@^4.0.11: - version "4.0.11" - resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-4.0.11.tgz#62f49a13e4a0ee04e7b98f42bb16062ca2549e24" - integrity sha512-alx/zmoeXvJjp7L4mxEMjh8lxVlDFX1gqWHzaaQewwMZiVhLo42TEClKaeHbRf6J7j82ZOdTJ808RtN0ZOZwvw== - dependencies: - css-color-names "0.0.4" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - stylehacks "^4.0.0" - -postcss-merge-rules@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-4.0.3.tgz#362bea4ff5a1f98e4075a713c6cb25aefef9a650" - integrity sha512-U7e3r1SbvYzO0Jr3UT/zKBVgYYyhAz0aitvGIYOYK5CPmkNih+WDSsS5tvPrJ8YMQYlEMvsZIiqmn7HdFUaeEQ== - dependencies: - browserslist "^4.0.0" - caniuse-api "^3.0.0" - cssnano-util-same-parent "^4.0.0" - postcss "^7.0.0" - postcss-selector-parser "^3.0.0" - vendors "^1.0.0" - -postcss-minify-font-values@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-minify-font-values/-/postcss-minify-font-values-4.0.2.tgz#cd4c344cce474343fac5d82206ab2cbcb8afd5a6" - integrity sha512-j85oO6OnRU9zPf04+PZv1LYIYOprWm6IA6zkXkrJXyRveDEuQggG6tvoy8ir8ZwjLxLuGfNkCZEQG7zan+Hbtg== - dependencies: - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-minify-gradients@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-minify-gradients/-/postcss-minify-gradients-4.0.2.tgz#93b29c2ff5099c535eecda56c4aa6e665a663471" - integrity sha512-qKPfwlONdcf/AndP1U8SJ/uzIJtowHlMaSioKzebAXSG4iJthlWC9iSWznQcX4f66gIWX44RSA841HTHj3wK+Q== - dependencies: - cssnano-util-get-arguments "^4.0.0" - is-color-stop "^1.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-minify-params@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-4.0.2.tgz#6b9cef030c11e35261f95f618c90036d680db874" - integrity sha512-G7eWyzEx0xL4/wiBBJxJOz48zAKV2WG3iZOqVhPet/9geefm/Px5uo1fzlHu+DOjT+m0Mmiz3jkQzVHe6wxAWg== - dependencies: - alphanum-sort "^1.0.0" - browserslist "^4.0.0" - cssnano-util-get-arguments "^4.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - uniqs "^2.0.0" - -postcss-minify-selectors@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-minify-selectors/-/postcss-minify-selectors-4.0.2.tgz#e2e5eb40bfee500d0cd9243500f5f8ea4262fbd8" - integrity sha512-D5S1iViljXBj9kflQo4YutWnJmwm8VvIsU1GeXJGiG9j8CIg9zs4voPMdQDUmIxetUOh60VilsNzCiAFTOqu3g== - dependencies: - alphanum-sort "^1.0.0" - has "^1.0.0" - postcss "^7.0.0" - postcss-selector-parser "^3.0.0" - -postcss-modules-extract-imports@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-2.0.0.tgz#818719a1ae1da325f9832446b01136eeb493cd7e" - integrity sha512-LaYLDNS4SG8Q5WAWqIJgdHPJrDDr/Lv775rMBFUbgjTz6j34lUznACHcdRWroPvXANP2Vj7yNK57vp9eFqzLWQ== - dependencies: - postcss "^7.0.5" - -postcss-modules-local-by-default@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-3.0.2.tgz#e8a6561be914aaf3c052876377524ca90dbb7915" - integrity sha512-jM/V8eqM4oJ/22j0gx4jrp63GSvDH6v86OqyTHHUvk4/k1vceipZsaymiZ5PvocqZOl5SFHiFJqjs3la0wnfIQ== - dependencies: - icss-utils "^4.1.1" - postcss "^7.0.16" - postcss-selector-parser "^6.0.2" - postcss-value-parser "^4.0.0" - -postcss-modules-scope@^2.1.1: - version "2.2.0" - resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-2.2.0.tgz#385cae013cc7743f5a7d7602d1073a89eaae62ee" - integrity sha512-YyEgsTMRpNd+HmyC7H/mh3y+MeFWevy7V1evVhJWewmMbjDHIbZbOXICC2y+m1xI1UVfIT1HMW/O04Hxyu9oXQ== - dependencies: - postcss "^7.0.6" - postcss-selector-parser "^6.0.0" - -postcss-modules-values@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-3.0.0.tgz#5b5000d6ebae29b4255301b4a3a54574423e7f10" - integrity sha512-1//E5jCBrZ9DmRX+zCtmQtRSV6PV42Ix7Bzj9GbwJceduuf7IqP8MgeTXuRDHOWj2m0VzZD5+roFWDuU8RQjcg== - dependencies: - icss-utils "^4.0.0" - postcss "^7.0.6" - -postcss-nesting@^7.0.0: - version "7.0.1" - resolved "https://registry.yarnpkg.com/postcss-nesting/-/postcss-nesting-7.0.1.tgz#b50ad7b7f0173e5b5e3880c3501344703e04c052" - integrity sha512-FrorPb0H3nuVq0Sff7W2rnc3SmIcruVC6YwpcS+k687VxyxO33iE1amna7wHuRVzM8vfiYofXSBHNAZ3QhLvYg== - dependencies: - postcss "^7.0.2" - -postcss-normalize-charset@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/postcss-normalize-charset/-/postcss-normalize-charset-4.0.1.tgz#8b35add3aee83a136b0471e0d59be58a50285dd4" - integrity sha512-gMXCrrlWh6G27U0hF3vNvR3w8I1s2wOBILvA87iNXaPvSNo5uZAMYsZG7XjCUf1eVxuPfyL4TJ7++SGZLc9A3g== - dependencies: - postcss "^7.0.0" - -postcss-normalize-display-values@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-normalize-display-values/-/postcss-normalize-display-values-4.0.2.tgz#0dbe04a4ce9063d4667ed2be476bb830c825935a" - integrity sha512-3F2jcsaMW7+VtRMAqf/3m4cPFhPD3EFRgNs18u+k3lTJJlVe7d0YPO+bnwqo2xg8YiRpDXJI2u8A0wqJxMsQuQ== - dependencies: - cssnano-util-get-match "^4.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-normalize-positions@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-normalize-positions/-/postcss-normalize-positions-4.0.2.tgz#05f757f84f260437378368a91f8932d4b102917f" - integrity sha512-Dlf3/9AxpxE+NF1fJxYDeggi5WwV35MXGFnnoccP/9qDtFrTArZ0D0R+iKcg5WsUd8nUYMIl8yXDCtcrT8JrdA== - dependencies: - cssnano-util-get-arguments "^4.0.0" - has "^1.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-normalize-repeat-style@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-4.0.2.tgz#c4ebbc289f3991a028d44751cbdd11918b17910c" - integrity sha512-qvigdYYMpSuoFs3Is/f5nHdRLJN/ITA7huIoCyqqENJe9PvPmLhNLMu7QTjPdtnVf6OcYYO5SHonx4+fbJE1+Q== - dependencies: - cssnano-util-get-arguments "^4.0.0" - cssnano-util-get-match "^4.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-normalize-string@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-normalize-string/-/postcss-normalize-string-4.0.2.tgz#cd44c40ab07a0c7a36dc5e99aace1eca4ec2690c" - integrity sha512-RrERod97Dnwqq49WNz8qo66ps0swYZDSb6rM57kN2J+aoyEAJfZ6bMx0sx/F9TIEX0xthPGCmeyiam/jXif0eA== - dependencies: - has "^1.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-normalize-timing-functions@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-4.0.2.tgz#8e009ca2a3949cdaf8ad23e6b6ab99cb5e7d28d9" - integrity sha512-acwJY95edP762e++00Ehq9L4sZCEcOPyaHwoaFOhIwWCDfik6YvqsYNxckee65JHLKzuNSSmAdxwD2Cud1Z54A== - dependencies: - cssnano-util-get-match "^4.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-normalize-unicode@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/postcss-normalize-unicode/-/postcss-normalize-unicode-4.0.1.tgz#841bd48fdcf3019ad4baa7493a3d363b52ae1cfb" - integrity sha512-od18Uq2wCYn+vZ/qCOeutvHjB5jm57ToxRaMeNuf0nWVHaP9Hua56QyMF6fs/4FSUnVIw0CBPsU0K4LnBPwYwg== - dependencies: - browserslist "^4.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-normalize-url@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/postcss-normalize-url/-/postcss-normalize-url-4.0.1.tgz#10e437f86bc7c7e58f7b9652ed878daaa95faae1" - integrity sha512-p5oVaF4+IHwu7VpMan/SSpmpYxcJMtkGppYf0VbdH5B6hN8YNmVyJLuY9FmLQTzY3fag5ESUUHDqM+heid0UVA== - dependencies: - is-absolute-url "^2.0.0" - normalize-url "^3.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-normalize-whitespace@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-normalize-whitespace/-/postcss-normalize-whitespace-4.0.2.tgz#bf1d4070fe4fcea87d1348e825d8cc0c5faa7d82" - integrity sha512-tO8QIgrsI3p95r8fyqKV+ufKlSHh9hMJqACqbv2XknufqEDhDvbguXGBBqxw9nsQoXWf0qOqppziKJKHMD4GtA== - dependencies: - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-normalize@8.0.1: - version "8.0.1" - resolved "https://registry.yarnpkg.com/postcss-normalize/-/postcss-normalize-8.0.1.tgz#90e80a7763d7fdf2da6f2f0f82be832ce4f66776" - integrity sha512-rt9JMS/m9FHIRroDDBGSMsyW1c0fkvOJPy62ggxSHUldJO7B195TqFMqIf+lY5ezpDcYOV4j86aUp3/XbxzCCQ== - dependencies: - "@csstools/normalize.css" "^10.1.0" - browserslist "^4.6.2" - postcss "^7.0.17" - postcss-browser-comments "^3.0.0" - sanitize.css "^10.0.0" - -postcss-ordered-values@^4.1.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-4.1.2.tgz#0cf75c820ec7d5c4d280189559e0b571ebac0eee" - integrity sha512-2fCObh5UanxvSxeXrtLtlwVThBvHn6MQcu4ksNT2tsaV2Fg76R2CV98W7wNSlX+5/pFwEyaDwKLLoEV7uRybAw== - dependencies: - cssnano-util-get-arguments "^4.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-overflow-shorthand@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/postcss-overflow-shorthand/-/postcss-overflow-shorthand-2.0.0.tgz#31ecf350e9c6f6ddc250a78f0c3e111f32dd4c30" - integrity sha512-aK0fHc9CBNx8jbzMYhshZcEv8LtYnBIRYQD5i7w/K/wS9c2+0NSR6B3OVMu5y0hBHYLcMGjfU+dmWYNKH0I85g== - dependencies: - postcss "^7.0.2" - -postcss-page-break@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/postcss-page-break/-/postcss-page-break-2.0.0.tgz#add52d0e0a528cabe6afee8b46e2abb277df46bf" - integrity sha512-tkpTSrLpfLfD9HvgOlJuigLuk39wVTbbd8RKcy8/ugV2bNBUW3xU+AIqyxhDrQr1VUj1RmyJrBn1YWrqUm9zAQ== - dependencies: - postcss "^7.0.2" - -postcss-place@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/postcss-place/-/postcss-place-4.0.1.tgz#e9f39d33d2dc584e46ee1db45adb77ca9d1dcc62" - integrity sha512-Zb6byCSLkgRKLODj/5mQugyuj9bvAAw9LqJJjgwz5cYryGeXfFZfSXoP1UfveccFmeq0b/2xxwcTEVScnqGxBg== - dependencies: - postcss "^7.0.2" - postcss-values-parser "^2.0.0" - -postcss-preset-env@6.7.0: - version "6.7.0" - resolved "https://registry.yarnpkg.com/postcss-preset-env/-/postcss-preset-env-6.7.0.tgz#c34ddacf8f902383b35ad1e030f178f4cdf118a5" - integrity sha512-eU4/K5xzSFwUFJ8hTdTQzo2RBLbDVt83QZrAvI07TULOkmyQlnYlpwep+2yIK+K+0KlZO4BvFcleOCCcUtwchg== - dependencies: - autoprefixer "^9.6.1" - browserslist "^4.6.4" - caniuse-lite "^1.0.30000981" - css-blank-pseudo "^0.1.4" - css-has-pseudo "^0.10.0" - css-prefers-color-scheme "^3.1.1" - cssdb "^4.4.0" - postcss "^7.0.17" - postcss-attribute-case-insensitive "^4.0.1" - postcss-color-functional-notation "^2.0.1" - postcss-color-gray "^5.0.0" - postcss-color-hex-alpha "^5.0.3" - postcss-color-mod-function "^3.0.3" - postcss-color-rebeccapurple "^4.0.1" - postcss-custom-media "^7.0.8" - postcss-custom-properties "^8.0.11" - postcss-custom-selectors "^5.1.2" - postcss-dir-pseudo-class "^5.0.0" - postcss-double-position-gradients "^1.0.0" - postcss-env-function "^2.0.2" - postcss-focus-visible "^4.0.0" - postcss-focus-within "^3.0.0" - postcss-font-variant "^4.0.0" - postcss-gap-properties "^2.0.0" - postcss-image-set-function "^3.0.1" - postcss-initial "^3.0.0" - postcss-lab-function "^2.0.1" - postcss-logical "^3.0.0" - postcss-media-minmax "^4.0.0" - postcss-nesting "^7.0.0" - postcss-overflow-shorthand "^2.0.0" - postcss-page-break "^2.0.0" - postcss-place "^4.0.1" - postcss-pseudo-class-any-link "^6.0.0" - postcss-replace-overflow-wrap "^3.0.0" - postcss-selector-matches "^4.0.0" - postcss-selector-not "^4.0.0" - -postcss-pseudo-class-any-link@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-6.0.0.tgz#2ed3eed393b3702879dec4a87032b210daeb04d1" - integrity sha512-lgXW9sYJdLqtmw23otOzrtbDXofUdfYzNm4PIpNE322/swES3VU9XlXHeJS46zT2onFO7V1QFdD4Q9LiZj8mew== - dependencies: - postcss "^7.0.2" - postcss-selector-parser "^5.0.0-rc.3" - -postcss-reduce-initial@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-4.0.3.tgz#7fd42ebea5e9c814609639e2c2e84ae270ba48df" - integrity sha512-gKWmR5aUulSjbzOfD9AlJiHCGH6AEVLaM0AV+aSioxUDd16qXP1PCh8d1/BGVvpdWn8k/HiK7n6TjeoXN1F7DA== - dependencies: - browserslist "^4.0.0" - caniuse-api "^3.0.0" - has "^1.0.0" - postcss "^7.0.0" - -postcss-reduce-transforms@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-reduce-transforms/-/postcss-reduce-transforms-4.0.2.tgz#17efa405eacc6e07be3414a5ca2d1074681d4e29" - integrity sha512-EEVig1Q2QJ4ELpJXMZR8Vt5DQx8/mo+dGWSR7vWXqcob2gQLyQGsionYcGKATXvQzMPn6DSN1vTN7yFximdIAg== - dependencies: - cssnano-util-get-match "^4.0.0" - has "^1.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-replace-overflow-wrap@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/postcss-replace-overflow-wrap/-/postcss-replace-overflow-wrap-3.0.0.tgz#61b360ffdaedca84c7c918d2b0f0d0ea559ab01c" - integrity sha512-2T5hcEHArDT6X9+9dVSPQdo7QHzG4XKclFT8rU5TzJPDN7RIRTbO9c4drUISOVemLj03aezStHCR2AIcr8XLpw== - dependencies: - postcss "^7.0.2" - -postcss-safe-parser@4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/postcss-safe-parser/-/postcss-safe-parser-4.0.1.tgz#8756d9e4c36fdce2c72b091bbc8ca176ab1fcdea" - integrity sha512-xZsFA3uX8MO3yAda03QrG3/Eg1LN3EPfjjf07vke/46HERLZyHrTsQ9E1r1w1W//fWEhtYNndo2hQplN2cVpCQ== - dependencies: - postcss "^7.0.0" - -postcss-selector-matches@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/postcss-selector-matches/-/postcss-selector-matches-4.0.0.tgz#71c8248f917ba2cc93037c9637ee09c64436fcff" - integrity sha512-LgsHwQR/EsRYSqlwdGzeaPKVT0Ml7LAT6E75T8W8xLJY62CE4S/l03BWIt3jT8Taq22kXP08s2SfTSzaraoPww== - dependencies: - balanced-match "^1.0.0" - postcss "^7.0.2" - -postcss-selector-not@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/postcss-selector-not/-/postcss-selector-not-4.0.0.tgz#c68ff7ba96527499e832724a2674d65603b645c0" - integrity sha512-W+bkBZRhqJaYN8XAnbbZPLWMvZD1wKTu0UxtFKdhtGjWYmxhkUneoeOhRJKdAE5V7ZTlnbHfCR+6bNwK9e1dTQ== - dependencies: - balanced-match "^1.0.0" - postcss "^7.0.2" - -postcss-selector-parser@^3.0.0: - version "3.1.2" - resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz#b310f5c4c0fdaf76f94902bbaa30db6aa84f5270" - integrity sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA== - dependencies: - dot-prop "^5.2.0" - indexes-of "^1.0.1" - uniq "^1.0.1" - -postcss-selector-parser@^5.0.0-rc.3, postcss-selector-parser@^5.0.0-rc.4: - version "5.0.0" - resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz#249044356697b33b64f1a8f7c80922dddee7195c" - integrity sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ== - dependencies: - cssesc "^2.0.0" - indexes-of "^1.0.1" - uniq "^1.0.1" - -postcss-selector-parser@^6.0.0, postcss-selector-parser@^6.0.2: - version "6.0.2" - resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.2.tgz#934cf799d016c83411859e09dcecade01286ec5c" - integrity sha512-36P2QR59jDTOAiIkqEprfJDsoNrvwFei3eCqKd1Y0tUsBimsq39BLp7RD+JWny3WgB1zGhJX8XVePwm9k4wdBg== - dependencies: - cssesc "^3.0.0" - indexes-of "^1.0.1" - uniq "^1.0.1" - -postcss-svgo@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-4.0.2.tgz#17b997bc711b333bab143aaed3b8d3d6e3d38258" - integrity sha512-C6wyjo3VwFm0QgBy+Fu7gCYOkCmgmClghO+pjcxvrcBKtiKt0uCF+hvbMO1fyv5BMImRK90SMb+dwUnfbGd+jw== - dependencies: - is-svg "^3.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - svgo "^1.0.0" - -postcss-unique-selectors@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-4.0.1.tgz#9446911f3289bfd64c6d680f073c03b1f9ee4bac" - integrity sha512-+JanVaryLo9QwZjKrmJgkI4Fn8SBgRO6WXQBJi7KiAVPlmxikB5Jzc4EvXMT2H0/m0RjrVVm9rGNhZddm/8Spg== - dependencies: - alphanum-sort "^1.0.0" - postcss "^7.0.0" - uniqs "^2.0.0" - -postcss-value-parser@^3.0.0: - version "3.3.1" - resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz#9ff822547e2893213cf1c30efa51ac5fd1ba8281" - integrity sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ== - -postcss-value-parser@^4.0.0, postcss-value-parser@^4.0.2, postcss-value-parser@^4.0.3: - version "4.1.0" - resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz#443f6a20ced6481a2bda4fa8532a6e55d789a2cb" - integrity sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ== - -postcss-values-parser@^2.0.0, postcss-values-parser@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/postcss-values-parser/-/postcss-values-parser-2.0.1.tgz#da8b472d901da1e205b47bdc98637b9e9e550e5f" - integrity sha512-2tLuBsA6P4rYTNKCXYG/71C7j1pU6pK503suYOmn4xYrQIzW+opD+7FAFNuGSdZC/3Qfy334QbeMu7MEb8gOxg== - dependencies: - flatten "^1.0.2" - indexes-of "^1.0.1" - uniq "^1.0.1" - -postcss@7.0.21: - version "7.0.21" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.21.tgz#06bb07824c19c2021c5d056d5b10c35b989f7e17" - integrity sha512-uIFtJElxJo29QC753JzhidoAhvp/e/Exezkdhfmt8AymWT6/5B7W1WmponYWkHk2eg6sONyTch0A3nkMPun3SQ== - dependencies: - chalk "^2.4.2" - source-map "^0.6.1" - supports-color "^6.1.0" - -postcss@^7, postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.14, postcss@^7.0.16, postcss@^7.0.17, postcss@^7.0.2, postcss@^7.0.23, postcss@^7.0.27, postcss@^7.0.5, postcss@^7.0.6: - version "7.0.29" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.29.tgz#d3a903872bd52280b83bce38cdc83ce55c06129e" - integrity sha512-ba0ApvR3LxGvRMMiUa9n0WR4HjzcYm7tS+ht4/2Nd0NLtHpPIH77fuB9Xh1/yJVz9O/E/95Y/dn8ygWsyffXtw== - dependencies: - chalk "^2.4.2" - source-map "^0.6.1" - supports-color "^6.1.0" - -prelude-ls@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" - integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= - -prepend-http@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" - integrity sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw= - -prettier@^1.18.2: - version "1.19.1" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb" - integrity sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew== - -pretty-bytes@^5.1.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.3.0.tgz#f2849e27db79fb4d6cfe24764fc4134f165989f2" - integrity sha512-hjGrh+P926p4R4WbaB6OckyRtO0F0/lQBiT+0gnxjV+5kjPBrfVBFCsCLbMqVQeydvIoouYTCmmEURiH3R1Bdg== - -pretty-error@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/pretty-error/-/pretty-error-2.1.1.tgz#5f4f87c8f91e5ae3f3ba87ab4cf5e03b1a17f1a3" - integrity sha1-X0+HyPkeWuPzuoerTPXgOxoX8aM= - dependencies: - renderkid "^2.0.1" - utila "~0.4" - -pretty-format@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-24.9.0.tgz#12fac31b37019a4eea3c11aa9a959eb7628aa7c9" - integrity sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA== - dependencies: - "@jest/types" "^24.9.0" - ansi-regex "^4.0.0" - ansi-styles "^3.2.0" - react-is "^16.8.4" - -private@^0.1.8: - version "0.1.8" - resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" - integrity sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg== - -process-nextick-args@~2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" - integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== - -process@^0.11.10: - version "0.11.10" - resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" - integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI= - -progress@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" - integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== - -promise-inflight@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" - integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM= - -promise@^8.0.3: - version "8.1.0" - resolved "https://registry.yarnpkg.com/promise/-/promise-8.1.0.tgz#697c25c3dfe7435dd79fcd58c38a135888eaf05e" - integrity sha512-W04AqnILOL/sPRXziNicCjSNRruLAuIHEOVBazepu0545DDNGYHz7ar9ZgZ1fMU8/MA4mVxp5rkBWRi6OXIy3Q== - dependencies: - asap "~2.0.6" - -prompts@^2.0.1: - version "2.3.2" - resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.3.2.tgz#480572d89ecf39566d2bd3fe2c9fccb7c4c0b068" - integrity sha512-Q06uKs2CkNYVID0VqwfAl9mipo99zkBv/n2JtWY89Yxa3ZabWSrs0e2KTudKVa3peLUvYXMefDqIleLPVUBZMA== - dependencies: - kleur "^3.0.3" - sisteransi "^1.0.4" - -prop-types@15.7.2, prop-types@^15.6.2, prop-types@^15.7.2: - version "15.7.2" - resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" - integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== - dependencies: - loose-envify "^1.4.0" - object-assign "^4.1.1" - react-is "^16.8.1" - -property-expr@^1.5.0: - version "1.5.1" - resolved "https://registry.yarnpkg.com/property-expr/-/property-expr-1.5.1.tgz#22e8706894a0c8e28d58735804f6ba3a3673314f" - integrity sha512-CGuc0VUTGthpJXL36ydB6jnbyOf/rAHFvmVrJlH+Rg0DqqLFQGAP6hIaxD/G0OAmBJPhXDHuEJigrp0e0wFV6g== - -property-expr@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/property-expr/-/property-expr-2.0.2.tgz#fff2a43919135553a3bc2fdd94bdb841965b2330" - integrity sha512-bc/5ggaYZxNkFKj374aLbEDqVADdYaLcFo8XBkishUWbaAdjlphaBFns9TvRA2pUseVL/wMFmui9X3IdNDU37g== - -proxy-addr@~2.0.5: - version "2.0.6" - resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.6.tgz#fdc2336505447d3f2f2c638ed272caf614bbb2bf" - integrity sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw== - dependencies: - forwarded "~0.1.2" - ipaddr.js "1.9.1" - -prr@~1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" - integrity sha1-0/wRS6BplaRexok/SEzrHXj19HY= - -psl@^1.1.28: - version "1.8.0" - resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24" - integrity sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ== - -public-encrypt@^4.0.0: - version "4.0.3" - resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.3.tgz#4fcc9d77a07e48ba7527e7cbe0de33d0701331e0" - integrity sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q== - dependencies: - bn.js "^4.1.0" - browserify-rsa "^4.0.0" - create-hash "^1.1.0" - parse-asn1 "^5.0.0" - randombytes "^2.0.1" - safe-buffer "^5.1.2" - -pump@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909" - integrity sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA== - dependencies: - end-of-stream "^1.1.0" - once "^1.3.1" - -pump@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" - integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== - dependencies: - end-of-stream "^1.1.0" - once "^1.3.1" - -pumpify@^1.3.3: - version "1.5.1" - resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-1.5.1.tgz#36513be246ab27570b1a374a5ce278bfd74370ce" - integrity sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ== - dependencies: - duplexify "^3.6.0" - inherits "^2.0.3" - pump "^2.0.0" - -punycode@1.3.2: - version "1.3.2" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" - integrity sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0= - -punycode@^1.2.4: - version "1.4.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" - integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= - -punycode@^2.1.0, punycode@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" - integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== - -q@^1.1.2: - version "1.5.1" - resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" - integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc= - -qs@6.7.0: - version "6.7.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" - integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== - -qs@~6.5.2: - version "6.5.2" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" - integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== - -query-string@^4.1.0: - version "4.3.4" - resolved "https://registry.yarnpkg.com/query-string/-/query-string-4.3.4.tgz#bbb693b9ca915c232515b228b1a02b609043dbeb" - integrity sha1-u7aTucqRXCMlFbIosaArYJBD2+s= - dependencies: - object-assign "^4.1.0" - strict-uri-encode "^1.0.0" - -querystring-es3@^0.2.0: - version "0.2.1" - resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" - integrity sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM= - -querystring@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" - integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA= - -querystringify@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.1.1.tgz#60e5a5fd64a7f8bfa4d2ab2ed6fdf4c85bad154e" - integrity sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA== - -raf@^3.4.1: - version "3.4.1" - resolved "https://registry.yarnpkg.com/raf/-/raf-3.4.1.tgz#0742e99a4a6552f445d73e3ee0328af0ff1ede39" - integrity sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA== - dependencies: - performance-now "^2.1.0" - -ramda@^0.26: - version "0.26.1" - resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.26.1.tgz#8d41351eb8111c55353617fc3bbffad8e4d35d06" - integrity sha512-hLWjpy7EnsDBb0p+Z3B7rPi3GDeRG5ZtiI33kJhTt+ORCd38AbAIjB/9zRIUoeTbE/AVX5ZkU7m6bznsvrf8eQ== - -randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5: - version "2.1.0" - resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" - integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== - dependencies: - safe-buffer "^5.1.0" - -randomfill@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.4.tgz#c92196fc86ab42be983f1bf31778224931d61458" - integrity sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw== - dependencies: - randombytes "^2.0.5" - safe-buffer "^5.1.0" - -range-parser@^1.2.1, range-parser@~1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" - integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== - -raw-body@2.4.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.0.tgz#a1ce6fb9c9bc356ca52e89256ab59059e13d0332" - integrity sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q== - dependencies: - bytes "3.1.0" - http-errors "1.7.2" - iconv-lite "0.4.24" - unpipe "1.0.0" - -react-app-polyfill@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/react-app-polyfill/-/react-app-polyfill-1.0.6.tgz#890f8d7f2842ce6073f030b117de9130a5f385f0" - integrity sha512-OfBnObtnGgLGfweORmdZbyEz+3dgVePQBb3zipiaDsMHV1NpWm0rDFYIVXFV/AK+x4VIIfWHhrdMIeoTLyRr2g== - dependencies: - core-js "^3.5.0" - object-assign "^4.1.1" - promise "^8.0.3" - raf "^3.4.1" - regenerator-runtime "^0.13.3" - whatwg-fetch "^3.0.0" - -react-dev-utils@^10.2.0: - version "10.2.1" - resolved "https://registry.yarnpkg.com/react-dev-utils/-/react-dev-utils-10.2.1.tgz#f6de325ae25fa4d546d09df4bb1befdc6dd19c19" - integrity sha512-XxTbgJnYZmxuPtY3y/UV0D8/65NKkmaia4rXzViknVnZeVlklSh8u6TnaEYPfAi/Gh1TP4mEOXHI6jQOPbeakQ== - dependencies: - "@babel/code-frame" "7.8.3" - address "1.1.2" - browserslist "4.10.0" - chalk "2.4.2" - cross-spawn "7.0.1" - detect-port-alt "1.1.6" - escape-string-regexp "2.0.0" - filesize "6.0.1" - find-up "4.1.0" - fork-ts-checker-webpack-plugin "3.1.1" - global-modules "2.0.0" - globby "8.0.2" - gzip-size "5.1.1" - immer "1.10.0" - inquirer "7.0.4" - is-root "2.1.0" - loader-utils "1.2.3" - open "^7.0.2" - pkg-up "3.1.0" - react-error-overlay "^6.0.7" - recursive-readdir "2.2.2" - shell-quote "1.7.2" - strip-ansi "6.0.0" - text-table "0.2.0" - -react-dom@16.13.1: - version "16.13.1" - resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.13.1.tgz#c1bd37331a0486c078ee54c4740720993b2e0e7f" - integrity sha512-81PIMmVLnCNLO/fFOQxdQkvEq/+Hfpv24XNJfpyZhTRfO0QcmQIF/PgCa1zCOj2w1hrn12MFLyaJ/G0+Mxtfag== - dependencies: - loose-envify "^1.1.0" - object-assign "^4.1.1" - prop-types "^15.6.2" - scheduler "^0.19.1" - -react-error-overlay@^6.0.7: - version "6.0.7" - resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.7.tgz#1dcfb459ab671d53f660a991513cb2f0a0553108" - integrity sha512-TAv1KJFh3RhqxNvhzxj6LeT5NWklP6rDr2a0jaTfsZ5wSZWHOGeqQyejUp3xxLfPt2UpyJEcVQB/zyPcmonNFA== - -react-is@16.13.1, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.0, react-is@^16.8.1, react-is@^16.8.4, react-is@^16.8.6: - version "16.13.1" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" - integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== - -react-markdown@4.3.1: - version "4.3.1" - resolved "https://registry.yarnpkg.com/react-markdown/-/react-markdown-4.3.1.tgz#39f0633b94a027445b86c9811142d05381300f2f" - integrity sha512-HQlWFTbDxTtNY6bjgp3C3uv1h2xcjCSi1zAEzfBW9OwJJvENSYiLXWNXN5hHLsoqai7RnZiiHzcnWdXk2Splzw== - dependencies: - html-to-react "^1.3.4" - mdast-add-list-metadata "1.0.1" - prop-types "^15.7.2" - react-is "^16.8.6" - remark-parse "^5.0.0" - unified "^6.1.5" - unist-util-visit "^1.3.0" - xtend "^4.0.1" - -react-router-dom@5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-5.2.0.tgz#9e65a4d0c45e13289e66c7b17c7e175d0ea15662" - integrity sha512-gxAmfylo2QUjcwxI63RhQ5G85Qqt4voZpUXSEqCwykV0baaOTQDR1f0PmY8AELqIyVc0NEZUj0Gov5lNGcXgsA== - dependencies: - "@babel/runtime" "^7.1.2" - history "^4.9.0" - loose-envify "^1.3.1" - prop-types "^15.6.2" - react-router "5.2.0" - tiny-invariant "^1.0.2" - tiny-warning "^1.0.0" - -react-router@5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/react-router/-/react-router-5.2.0.tgz#424e75641ca8747fbf76e5ecca69781aa37ea293" - integrity sha512-smz1DUuFHRKdcJC0jobGo8cVbhO3x50tCL4icacOlcwDOEQPq4TMqwx3sY1TP+DvtTgz4nm3thuo7A+BK2U0Dw== - dependencies: - "@babel/runtime" "^7.1.2" - history "^4.9.0" - hoist-non-react-statics "^3.1.0" - loose-envify "^1.3.1" - mini-create-react-context "^0.4.0" - path-to-regexp "^1.7.0" - prop-types "^15.6.2" - react-is "^16.6.0" - tiny-invariant "^1.0.2" - tiny-warning "^1.0.0" - -react-scripts@3.4.0: - version "3.4.0" - resolved "https://registry.yarnpkg.com/react-scripts/-/react-scripts-3.4.0.tgz#f413680f0b5b937c8879ba1ffdae9b8c5b364bf5" - integrity sha512-pBqaAroFoHnFAkuX+uSK9Th1uEh2GYdGY2IG1I9/7HmuEf+ls3lLCk1p2GFYRSrLMz6ieQR/SyN6TLIGK3hKRg== - dependencies: - "@babel/core" "7.8.4" - "@svgr/webpack" "4.3.3" - "@typescript-eslint/eslint-plugin" "^2.10.0" - "@typescript-eslint/parser" "^2.10.0" - babel-eslint "10.0.3" - babel-jest "^24.9.0" - babel-loader "8.0.6" - babel-plugin-named-asset-import "^0.3.6" - babel-preset-react-app "^9.1.1" - camelcase "^5.3.1" - case-sensitive-paths-webpack-plugin "2.3.0" - css-loader "3.4.2" - dotenv "8.2.0" - dotenv-expand "5.1.0" - eslint "^6.6.0" - eslint-config-react-app "^5.2.0" - eslint-loader "3.0.3" - eslint-plugin-flowtype "4.6.0" - eslint-plugin-import "2.20.0" - eslint-plugin-jsx-a11y "6.2.3" - eslint-plugin-react "7.18.0" - eslint-plugin-react-hooks "^1.6.1" - file-loader "4.3.0" - fs-extra "^8.1.0" - html-webpack-plugin "4.0.0-beta.11" - identity-obj-proxy "3.0.0" - jest "24.9.0" - jest-environment-jsdom-fourteen "1.0.1" - jest-resolve "24.9.0" - jest-watch-typeahead "0.4.2" - mini-css-extract-plugin "0.9.0" - optimize-css-assets-webpack-plugin "5.0.3" - pnp-webpack-plugin "1.6.0" - postcss-flexbugs-fixes "4.1.0" - postcss-loader "3.0.0" - postcss-normalize "8.0.1" - postcss-preset-env "6.7.0" - postcss-safe-parser "4.0.1" - react-app-polyfill "^1.0.6" - react-dev-utils "^10.2.0" - resolve "1.15.0" - resolve-url-loader "3.1.1" - sass-loader "8.0.2" - semver "6.3.0" - style-loader "0.23.1" - terser-webpack-plugin "2.3.4" - ts-pnp "1.1.5" - url-loader "2.3.0" - webpack "4.41.5" - webpack-dev-server "3.10.2" - webpack-manifest-plugin "2.2.0" - workbox-webpack-plugin "4.3.1" - optionalDependencies: - fsevents "2.1.2" - -react-transition-group@^4.0.0, react-transition-group@^4.4.0: - version "4.4.1" - resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.1.tgz#63868f9325a38ea5ee9535d828327f85773345c9" - integrity sha512-Djqr7OQ2aPUiYurhPalTrVy9ddmFCCzwhqQmtN+J3+3DzLO209Fdr70QrN8Z3DsglWql6iY1lDWAfpFiBtuKGw== - dependencies: - "@babel/runtime" "^7.5.5" - dom-helpers "^5.0.1" - loose-envify "^1.4.0" - prop-types "^15.6.2" - -react@16.13.1: - version "16.13.1" - resolved "https://registry.yarnpkg.com/react/-/react-16.13.1.tgz#2e818822f1a9743122c063d6410d85c1e3afe48e" - integrity sha512-YMZQQq32xHLX0bz5Mnibv1/LHb3Sqzngu7xstSM+vrkE5Kzr9xE0yMByK5kMoTK30YVJE61WfbxIFFvfeDKT1w== - dependencies: - loose-envify "^1.1.0" - object-assign "^4.1.1" - prop-types "^15.6.2" - -read-pkg-up@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be" - integrity sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4= - dependencies: - find-up "^2.0.0" - read-pkg "^2.0.0" - -read-pkg-up@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-4.0.0.tgz#1b221c6088ba7799601c808f91161c66e58f8978" - integrity sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA== - dependencies: - find-up "^3.0.0" - read-pkg "^3.0.0" - -read-pkg@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8" - integrity sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg= - dependencies: - load-json-file "^2.0.0" - normalize-package-data "^2.3.2" - path-type "^2.0.0" - -read-pkg@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389" - integrity sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k= - dependencies: - load-json-file "^4.0.0" - normalize-package-data "^2.3.2" - path-type "^3.0.0" - -"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.6: - version "2.3.7" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" - integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.3" - isarray "~1.0.0" - process-nextick-args "~2.0.0" - safe-buffer "~5.1.1" - string_decoder "~1.1.1" - util-deprecate "~1.0.1" - -readable-stream@^3.0.6, readable-stream@^3.1.1, readable-stream@^3.6.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" - integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== - dependencies: - inherits "^2.0.3" - string_decoder "^1.1.1" - util-deprecate "^1.0.1" - -readdirp@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525" - integrity sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ== - dependencies: - graceful-fs "^4.1.11" - micromatch "^3.1.10" - readable-stream "^2.0.2" - -readdirp@~3.4.0: - version "3.4.0" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.4.0.tgz#9fdccdf9e9155805449221ac645e8303ab5b9ada" - integrity sha512-0xe001vZBnJEK+uKcj8qOhyAKPzIT+gStxWr3LCB0DwcXR5NZJ3IaC+yGnHCYzB/S7ov3m3EEbZI2zeNvX+hGQ== - dependencies: - picomatch "^2.2.1" - -realpath-native@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/realpath-native/-/realpath-native-1.1.0.tgz#2003294fea23fb0672f2476ebe22fcf498a2d65c" - integrity sha512-wlgPA6cCIIg9gKz0fgAPjnzh4yR/LnXovwuo9hvyGvx3h8nX4+/iLZplfUWasXpqD8BdnGnP5njOFjkUwPzvjA== - dependencies: - util.promisify "^1.0.0" - -recursive-readdir@2.2.2: - version "2.2.2" - resolved "https://registry.yarnpkg.com/recursive-readdir/-/recursive-readdir-2.2.2.tgz#9946fb3274e1628de6e36b2f6714953b4845094f" - integrity sha512-nRCcW9Sj7NuZwa2XvH9co8NPeXUBhZP7CRKJtU+cS6PW9FpCIFoI5ib0NT1ZrbNuPoRy0ylyCaUL8Gih4LSyFg== - dependencies: - minimatch "3.0.4" - -regenerate-unicode-properties@^8.2.0: - version "8.2.0" - resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz#e5de7111d655e7ba60c057dbe9ff37c87e65cdec" - integrity sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA== - dependencies: - regenerate "^1.4.0" - -regenerate@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11" - integrity sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg== - -regenerator-runtime@^0.11.0: - version "0.11.1" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" - integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg== - -regenerator-runtime@^0.13.2, regenerator-runtime@^0.13.3, regenerator-runtime@^0.13.4: - version "0.13.5" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz#d878a1d094b4306d10b9096484b33ebd55e26697" - integrity sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA== - -regenerator-transform@^0.14.2: - version "0.14.4" - resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.4.tgz#5266857896518d1616a78a0479337a30ea974cc7" - integrity sha512-EaJaKPBI9GvKpvUz2mz4fhx7WPgvwRLY9v3hlNHWmAuJHI13T4nwKnNvm5RWJzEdnI5g5UwtOww+S8IdoUC2bw== - dependencies: - "@babel/runtime" "^7.8.4" - private "^0.1.8" - -regex-not@^1.0.0, regex-not@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" - integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A== - dependencies: - extend-shallow "^3.0.2" - safe-regex "^1.1.0" - -regex-parser@2.2.10: - version "2.2.10" - resolved "https://registry.yarnpkg.com/regex-parser/-/regex-parser-2.2.10.tgz#9e66a8f73d89a107616e63b39d4deddfee912b37" - integrity sha512-8t6074A68gHfU8Neftl0Le6KTDwfGAj7IyjPIMSfikI2wJUTHDMaIq42bUsfVnj8mhx0R+45rdUXHGpN164avA== - -regexp.prototype.flags@^1.2.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz#7aba89b3c13a64509dabcf3ca8d9fbb9bdf5cb75" - integrity sha512-2+Q0C5g951OlYlJz6yu5/M33IcsESLlLfsyIaLJaG4FA2r4yP8MvVMJUUP/fVBkSpbbbZlS5gynbEWLipiiXiQ== - dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.0-next.1" - -regexpp@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" - integrity sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw== - -regexpp@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.1.0.tgz#206d0ad0a5648cffbdb8ae46438f3dc51c9f78e2" - integrity sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q== - -regexpu-core@^4.7.0: - version "4.7.0" - resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.7.0.tgz#fcbf458c50431b0bb7b45d6967b8192d91f3d938" - integrity sha512-TQ4KXRnIn6tz6tjnrXEkD/sshygKH/j5KzK86X8MkeHyZ8qst/LZ89j3X4/8HEIfHANTFIP/AbXakeRhWIl5YQ== - dependencies: - regenerate "^1.4.0" - regenerate-unicode-properties "^8.2.0" - regjsgen "^0.5.1" - regjsparser "^0.6.4" - unicode-match-property-ecmascript "^1.0.4" - unicode-match-property-value-ecmascript "^1.2.0" - -regjsgen@^0.5.1: - version "0.5.1" - resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.5.1.tgz#48f0bf1a5ea205196929c0d9798b42d1ed98443c" - integrity sha512-5qxzGZjDs9w4tzT3TPhCJqWdCc3RLYwy9J2NB0nm5Lz+S273lvWcpjaTGHsT1dc6Hhfq41uSEOw8wBmxrKOuyg== - -regjsparser@^0.6.4: - version "0.6.4" - resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.6.4.tgz#a769f8684308401a66e9b529d2436ff4d0666272" - integrity sha512-64O87/dPDgfk8/RQqC4gkZoGyyWFIEUTTh80CU6CWuK5vkCGyekIx+oKcEIYtP/RAxSQltCZHCNu/mdd7fqlJw== - dependencies: - jsesc "~0.5.0" - -relateurl@^0.2.7: - version "0.2.7" - resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9" - integrity sha1-VNvzd+UUQKypCkzSdGANP/LYiKk= - -remark-parse@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/remark-parse/-/remark-parse-5.0.0.tgz#4c077f9e499044d1d5c13f80d7a98cf7b9285d95" - integrity sha512-b3iXszZLH1TLoyUzrATcTQUZrwNl1rE70rVdSruJFlDaJ9z5aMkhrG43Pp68OgfHndL/ADz6V69Zow8cTQu+JA== - dependencies: - collapse-white-space "^1.0.2" - is-alphabetical "^1.0.0" - is-decimal "^1.0.0" - is-whitespace-character "^1.0.0" - is-word-character "^1.0.0" - markdown-escapes "^1.0.0" - parse-entities "^1.1.0" - repeat-string "^1.5.4" - state-toggle "^1.0.0" - trim "0.0.1" - trim-trailing-lines "^1.0.0" - unherit "^1.0.4" - unist-util-remove-position "^1.0.0" - vfile-location "^2.0.0" - xtend "^4.0.1" - -remove-trailing-separator@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" - integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= - -renderkid@^2.0.1: - version "2.0.3" - resolved "https://registry.yarnpkg.com/renderkid/-/renderkid-2.0.3.tgz#380179c2ff5ae1365c522bf2fcfcff01c5b74149" - integrity sha512-z8CLQp7EZBPCwCnncgf9C4XAi3WR0dv+uWu/PjIyhhAb5d6IJ/QZqlHFprHeKT+59//V6BNUsLbvN8+2LarxGA== - dependencies: - css-select "^1.1.0" - dom-converter "^0.2" - htmlparser2 "^3.3.0" - strip-ansi "^3.0.0" - utila "^0.4.0" - -repeat-element@^1.1.2: - version "1.1.3" - resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce" - integrity sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g== - -repeat-string@^1.5.4, repeat-string@^1.6.1: - version "1.6.1" - resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" - integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= - -replace-ext@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-1.0.0.tgz#de63128373fcbf7c3ccfa4de5a480c45a67958eb" - integrity sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs= - -request-promise-core@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/request-promise-core/-/request-promise-core-1.1.3.tgz#e9a3c081b51380dfea677336061fea879a829ee9" - integrity sha512-QIs2+ArIGQVp5ZYbWD5ZLCY29D5CfWizP8eWnm8FoGD1TX61veauETVQbrV60662V0oFBkrDOuaBI8XgtuyYAQ== - dependencies: - lodash "^4.17.15" - -request-promise-native@^1.0.5: - version "1.0.8" - resolved "https://registry.yarnpkg.com/request-promise-native/-/request-promise-native-1.0.8.tgz#a455b960b826e44e2bf8999af64dff2bfe58cb36" - integrity sha512-dapwLGqkHtwL5AEbfenuzjTYg35Jd6KPytsC2/TLkVMz8rm+tNt72MGUWT1RP/aYawMpN6HqbNGBQaRcBtjQMQ== - dependencies: - request-promise-core "1.1.3" - stealthy-require "^1.1.1" - tough-cookie "^2.3.3" - -request@^2.87.0, request@^2.88.0: - version "2.88.2" - resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" - integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== - dependencies: - aws-sign2 "~0.7.0" - aws4 "^1.8.0" - caseless "~0.12.0" - combined-stream "~1.0.6" - extend "~3.0.2" - forever-agent "~0.6.1" - form-data "~2.3.2" - har-validator "~5.1.3" - http-signature "~1.2.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.19" - oauth-sign "~0.9.0" - performance-now "^2.1.0" - qs "~6.5.2" - safe-buffer "^5.1.2" - tough-cookie "~2.5.0" - tunnel-agent "^0.6.0" - uuid "^3.3.2" - -require-directory@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" - integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= - -require-main-filename@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" - integrity sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE= - -require-main-filename@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" - integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== - -requires-port@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" - integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8= - -resolve-cwd@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a" - integrity sha1-AKn3OHVW4nA46uIyyqNypqWbZlo= - dependencies: - resolve-from "^3.0.0" - -resolve-from@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" - integrity sha1-six699nWiBvItuZTM17rywoYh0g= - -resolve-from@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" - integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== - -resolve-pathname@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/resolve-pathname/-/resolve-pathname-3.0.0.tgz#99d02224d3cf263689becbb393bc560313025dcd" - integrity sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng== - -resolve-url-loader@3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/resolve-url-loader/-/resolve-url-loader-3.1.1.tgz#28931895fa1eab9be0647d3b2958c100ae3c0bf0" - integrity sha512-K1N5xUjj7v0l2j/3Sgs5b8CjrrgtC70SmdCuZiJ8tSyb5J+uk3FoeZ4b7yTnH6j7ngI+Bc5bldHJIa8hYdu2gQ== - dependencies: - adjust-sourcemap-loader "2.0.0" - camelcase "5.3.1" - compose-function "3.0.3" - convert-source-map "1.7.0" - es6-iterator "2.0.3" - loader-utils "1.2.3" - postcss "7.0.21" - rework "1.0.1" - rework-visit "1.0.0" - source-map "0.6.1" - -resolve-url@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" - integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= - -resolve@1.1.7: - version "1.1.7" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" - integrity sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs= - -resolve@1.15.0: - version "1.15.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.15.0.tgz#1b7ca96073ebb52e741ffd799f6b39ea462c67f5" - integrity sha512-+hTmAldEGE80U2wJJDC1lebb5jWqvTYAfm3YZ1ckk1gBr0MnCqUKlwK1e+anaFljIl+F5tR5IoZcm4ZDA1zMQw== - dependencies: - path-parse "^1.0.6" - -resolve@^1.10.0, resolve@^1.12.0, resolve@^1.13.1, resolve@^1.14.2, resolve@^1.3.2, resolve@^1.8.1: - version "1.17.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.17.0.tgz#b25941b54968231cc2d1bb76a79cb7f2c0bf8444" - integrity sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w== - dependencies: - path-parse "^1.0.6" - -restore-cursor@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" - integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA== - dependencies: - onetime "^5.1.0" - signal-exit "^3.0.2" - -ret@~0.1.10: - version "0.1.15" - resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" - integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== - -retry@^0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" - integrity sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs= - -rework-visit@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/rework-visit/-/rework-visit-1.0.0.tgz#9945b2803f219e2f7aca00adb8bc9f640f842c9a" - integrity sha1-mUWygD8hni96ygCtuLyfZA+ELJo= - -rework@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/rework/-/rework-1.0.1.tgz#30806a841342b54510aa4110850cd48534144aa7" - integrity sha1-MIBqhBNCtUUQqkEQhQzUhTQUSqc= - dependencies: - convert-source-map "^0.3.3" - css "^2.0.0" - -rgb-regex@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/rgb-regex/-/rgb-regex-1.0.1.tgz#c0e0d6882df0e23be254a475e8edd41915feaeb1" - integrity sha1-wODWiC3w4jviVKR16O3UGRX+rrE= - -rgba-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/rgba-regex/-/rgba-regex-1.0.0.tgz#43374e2e2ca0968b0ef1523460b7d730ff22eeb3" - integrity sha1-QzdOLiyglosO8VI0YLfXMP8i7rM= - -rifm@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/rifm/-/rifm-0.7.0.tgz#debe951a9c83549ca6b33e5919f716044c2230be" - integrity sha512-DSOJTWHD67860I5ojetXdEQRIBvF6YcpNe53j0vn1vp9EUb9N80EiZTxgP+FkDKorWC8PZw052kTF4C1GOivCQ== - dependencies: - "@babel/runtime" "^7.3.1" - -rimraf@2.6.3: - version "2.6.3" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" - integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== - dependencies: - glob "^7.1.3" - -rimraf@^2.5.4, rimraf@^2.6.3, rimraf@^2.7.1: - version "2.7.1" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" - integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== - dependencies: - glob "^7.1.3" - -ripemd160@^2.0.0, ripemd160@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" - integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA== - dependencies: - hash-base "^3.0.0" - inherits "^2.0.1" - -rsvp@^4.8.4: - version "4.8.5" - resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.5.tgz#c8f155311d167f68f21e168df71ec5b083113734" - integrity sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA== - -run-async@^2.2.0, run-async@^2.4.0: - version "2.4.1" - resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" - integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== - -run-queue@^1.0.0, run-queue@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/run-queue/-/run-queue-1.0.3.tgz#e848396f057d223f24386924618e25694161ec47" - integrity sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec= - dependencies: - aproba "^1.1.1" - -rxjs@^6.5.3: - version "6.5.5" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.5.tgz#c5c884e3094c8cfee31bf27eb87e54ccfc87f9ec" - integrity sha512-WfQI+1gohdf0Dai/Bbmk5L5ItH5tYqm3ki2c5GdWhKjalzjg93N3avFjVStyZZz+A2Em+ZxKH5bNghw9UeylGQ== - dependencies: - tslib "^1.9.0" - -safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: - version "5.1.2" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" - integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== - -safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519" - integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg== - -safe-regex@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" - integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4= - dependencies: - ret "~0.1.10" - -"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: - version "2.1.2" - resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" - integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== - -sane@^4.0.3: - version "4.1.0" - resolved "https://registry.yarnpkg.com/sane/-/sane-4.1.0.tgz#ed881fd922733a6c461bc189dc2b6c006f3ffded" - integrity sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA== - dependencies: - "@cnakazawa/watch" "^1.0.3" - anymatch "^2.0.0" - capture-exit "^2.0.0" - exec-sh "^0.3.2" - execa "^1.0.0" - fb-watchman "^2.0.0" - micromatch "^3.1.4" - minimist "^1.1.1" - walker "~1.0.5" - -sanitize.css@^10.0.0: - version "10.0.0" - resolved "https://registry.yarnpkg.com/sanitize.css/-/sanitize.css-10.0.0.tgz#b5cb2547e96d8629a60947544665243b1dc3657a" - integrity sha512-vTxrZz4dX5W86M6oVWVdOVe72ZiPs41Oi7Z6Km4W5Turyz28mrXSJhhEBZoRtzJWIv3833WKVwLSDWWkEfupMg== - -sass-loader@8.0.2: - version "8.0.2" - resolved "https://registry.yarnpkg.com/sass-loader/-/sass-loader-8.0.2.tgz#debecd8c3ce243c76454f2e8290482150380090d" - integrity sha512-7o4dbSK8/Ol2KflEmSco4jTjQoV988bM82P9CZdmo9hR3RLnvNc0ufMNdMrB0caq38JQ/FgF4/7RcbcfKzxoFQ== - dependencies: - clone-deep "^4.0.1" - loader-utils "^1.2.3" - neo-async "^2.6.1" - schema-utils "^2.6.1" - semver "^6.3.0" - -sax@^1.2.4, sax@~1.2.4: - version "1.2.4" - resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" - integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== - -saxes@^3.1.9: - version "3.1.11" - resolved "https://registry.yarnpkg.com/saxes/-/saxes-3.1.11.tgz#d59d1fd332ec92ad98a2e0b2ee644702384b1c5b" - integrity sha512-Ydydq3zC+WYDJK1+gRxRapLIED9PWeSuuS41wqyoRmzvhhh9nc+QQrVMKJYzJFULazeGhzSV0QleN2wD3boh2g== - dependencies: - xmlchars "^2.1.1" - -scheduler@^0.19.1: - version "0.19.1" - resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.19.1.tgz#4f3e2ed2c1a7d65681f4c854fa8c5a1ccb40f196" - integrity sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA== - dependencies: - loose-envify "^1.1.0" - object-assign "^4.1.1" - -schema-utils@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-1.0.0.tgz#0b79a93204d7b600d4b2850d1f66c2a34951c770" - integrity sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g== - dependencies: - ajv "^6.1.0" - ajv-errors "^1.0.0" - ajv-keywords "^3.1.0" - -schema-utils@^2.5.0, schema-utils@^2.6.0, schema-utils@^2.6.1, schema-utils@^2.6.4: - version "2.6.6" - resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.6.6.tgz#299fe6bd4a3365dc23d99fd446caff8f1d6c330c" - integrity sha512-wHutF/WPSbIi9x6ctjGGk2Hvl0VOz5l3EKEuKbjPlB30mKZUzb9A5k9yEXRX3pwyqVLPvpfZZEllaFq/M718hA== - dependencies: - ajv "^6.12.0" - ajv-keywords "^3.4.1" - -select-hose@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca" - integrity sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo= - -selfsigned@^1.10.7: - version "1.10.7" - resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-1.10.7.tgz#da5819fd049d5574f28e88a9bcc6dbc6e6f3906b" - integrity sha512-8M3wBCzeWIJnQfl43IKwOmC4H/RAp50S8DF60znzjW5GVqTcSe2vWclt7hmYVPkKPlHWOu5EaWOMZ2Y6W8ZXTA== - dependencies: - node-forge "0.9.0" - -"semver@2 || 3 || 4 || 5", semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0: - version "5.7.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" - integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== - -semver@6.3.0, semver@^6.0.0, semver@^6.1.2, semver@^6.2.0, semver@^6.3.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" - integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== - -semver@7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" - integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A== - -send@0.17.1: - version "0.17.1" - resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8" - integrity sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg== - dependencies: - debug "2.6.9" - depd "~1.1.2" - destroy "~1.0.4" - encodeurl "~1.0.2" - escape-html "~1.0.3" - etag "~1.8.1" - fresh "0.5.2" - http-errors "~1.7.2" - mime "1.6.0" - ms "2.1.1" - on-finished "~2.3.0" - range-parser "~1.2.1" - statuses "~1.5.0" - -serialize-javascript@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-2.1.2.tgz#ecec53b0e0317bdc95ef76ab7074b7384785fa61" - integrity sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ== - -serve-index@^1.9.1: - version "1.9.1" - resolved "https://registry.yarnpkg.com/serve-index/-/serve-index-1.9.1.tgz#d3768d69b1e7d82e5ce050fff5b453bea12a9239" - integrity sha1-03aNabHn2C5c4FD/9bRTvqEqkjk= - dependencies: - accepts "~1.3.4" - batch "0.6.1" - debug "2.6.9" - escape-html "~1.0.3" - http-errors "~1.6.2" - mime-types "~2.1.17" - parseurl "~1.3.2" - -serve-static@1.14.1: - version "1.14.1" - resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9" - integrity sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg== - dependencies: - encodeurl "~1.0.2" - escape-html "~1.0.3" - parseurl "~1.3.3" - send "0.17.1" - -set-blocking@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" - integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= - -set-value@^2.0.0, set-value@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" - integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw== - dependencies: - extend-shallow "^2.0.1" - is-extendable "^0.1.1" - is-plain-object "^2.0.3" - split-string "^3.0.1" - -setimmediate@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" - integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU= - -setprototypeof@1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" - integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ== - -setprototypeof@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683" - integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw== - -sha.js@^2.4.0, sha.js@^2.4.8: - version "2.4.11" - resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" - integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== - dependencies: - inherits "^2.0.1" - safe-buffer "^5.0.1" - -shallow-clone@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-0.1.2.tgz#5909e874ba77106d73ac414cfec1ffca87d97060" - integrity sha1-WQnodLp3EG1zrEFM/sH/yofZcGA= - dependencies: - is-extendable "^0.1.1" - kind-of "^2.0.1" - lazy-cache "^0.2.3" - mixin-object "^2.0.1" - -shallow-clone@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3" - integrity sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA== - dependencies: - kind-of "^6.0.2" - -shallowequal@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-1.1.0.tgz#188d521de95b9087404fd4dcb68b13df0ae4e7f8" - integrity sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ== - -shebang-command@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" - integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= - dependencies: - shebang-regex "^1.0.0" - -shebang-command@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" - integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== - dependencies: - shebang-regex "^3.0.0" - -shebang-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" - integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= - -shebang-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" - integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== - -shell-quote@1.7.2: - version "1.7.2" - resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.2.tgz#67a7d02c76c9da24f99d20808fcaded0e0e04be2" - integrity sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg== - -shellwords@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" - integrity sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww== - -signal-exit@^3.0.0, signal-exit@^3.0.2: - version "3.0.3" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" - integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== - -simple-swizzle@^0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a" - integrity sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo= - dependencies: - is-arrayish "^0.3.1" - -sisteransi@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" - integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== - -slash@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" - integrity sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU= - -slash@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44" - integrity sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A== - -slash@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" - integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== - -slice-ansi@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636" - integrity sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ== - dependencies: - ansi-styles "^3.2.0" - astral-regex "^1.0.0" - is-fullwidth-code-point "^2.0.0" - -snapdragon-node@^2.0.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" - integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== - dependencies: - define-property "^1.0.0" - isobject "^3.0.0" - snapdragon-util "^3.0.1" - -snapdragon-util@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" - integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ== - dependencies: - kind-of "^3.2.0" - -snapdragon@^0.8.1: - version "0.8.2" - resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" - integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== - dependencies: - base "^0.11.1" - debug "^2.2.0" - define-property "^0.2.5" - extend-shallow "^2.0.1" - map-cache "^0.2.2" - source-map "^0.5.6" - source-map-resolve "^0.5.0" - use "^3.1.0" - -sockjs-client@1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/sockjs-client/-/sockjs-client-1.4.0.tgz#c9f2568e19c8fd8173b4997ea3420e0bb306c7d5" - integrity sha512-5zaLyO8/nri5cua0VtOrFXBPK1jbL4+1cebT/mmKA1E1ZXOvJrII75bPu0l0k843G/+iAbhEqzyKr0w/eCCj7g== - dependencies: - debug "^3.2.5" - eventsource "^1.0.7" - faye-websocket "~0.11.1" - inherits "^2.0.3" - json3 "^3.3.2" - url-parse "^1.4.3" - -sockjs@0.3.19: - version "0.3.19" - resolved "https://registry.yarnpkg.com/sockjs/-/sockjs-0.3.19.tgz#d976bbe800af7bd20ae08598d582393508993c0d" - integrity sha512-V48klKZl8T6MzatbLlzzRNhMepEys9Y4oGFpypBFFn1gLI/QQ9HtLLyWJNbPlwGLelOVOEijUbTTJeLLI59jLw== - dependencies: - faye-websocket "^0.10.0" - uuid "^3.0.1" - -sort-keys@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-1.1.2.tgz#441b6d4d346798f1b4e49e8920adfba0e543f9ad" - integrity sha1-RBttTTRnmPG05J6JIK37oOVD+a0= - dependencies: - is-plain-obj "^1.0.0" - -source-list-map@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34" - integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw== - -source-map-resolve@^0.5.0, source-map-resolve@^0.5.2: - version "0.5.3" - resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a" - integrity sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw== - dependencies: - atob "^2.1.2" - decode-uri-component "^0.2.0" - resolve-url "^0.2.1" - source-map-url "^0.4.0" - urix "^0.1.0" - -source-map-support@^0.5.6, source-map-support@~0.5.12: - version "0.5.19" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61" - integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw== - dependencies: - buffer-from "^1.0.0" - source-map "^0.6.0" - -source-map-url@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" - integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM= - -source-map@0.6.1, source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" - integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== - -source-map@^0.5.0, source-map@^0.5.6: - version "0.5.7" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" - integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= - -spdx-correct@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.0.tgz#fb83e504445268f154b074e218c87c003cd31df4" - integrity sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q== - dependencies: - spdx-expression-parse "^3.0.0" - spdx-license-ids "^3.0.0" - -spdx-exceptions@^2.1.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz#3f28ce1a77a00372683eade4a433183527a2163d" - integrity sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A== - -spdx-expression-parse@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0" - integrity sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg== - dependencies: - spdx-exceptions "^2.1.0" - spdx-license-ids "^3.0.0" - -spdx-license-ids@^3.0.0: - version "3.0.5" - resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz#3694b5804567a458d3c8045842a6358632f62654" - integrity sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q== - -spdy-transport@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/spdy-transport/-/spdy-transport-3.0.0.tgz#00d4863a6400ad75df93361a1608605e5dcdcf31" - integrity sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw== - dependencies: - debug "^4.1.0" - detect-node "^2.0.4" - hpack.js "^2.1.6" - obuf "^1.1.2" - readable-stream "^3.0.6" - wbuf "^1.7.3" - -spdy@^4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/spdy/-/spdy-4.0.2.tgz#b74f466203a3eda452c02492b91fb9e84a27677b" - integrity sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA== - dependencies: - debug "^4.1.0" - handle-thing "^2.0.0" - http-deceiver "^1.2.7" - select-hose "^2.0.0" - spdy-transport "^3.0.0" - -split-string@^3.0.1, split-string@^3.0.2: - version "3.1.0" - resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" - integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw== - dependencies: - extend-shallow "^3.0.0" - -sprintf-js@~1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" - integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= - -sshpk@^1.7.0: - version "1.16.1" - resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877" - integrity sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg== - dependencies: - asn1 "~0.2.3" - assert-plus "^1.0.0" - bcrypt-pbkdf "^1.0.0" - dashdash "^1.12.0" - ecc-jsbn "~0.1.1" - getpass "^0.1.1" - jsbn "~0.1.0" - safer-buffer "^2.0.2" - tweetnacl "~0.14.0" - -ssri@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/ssri/-/ssri-6.0.1.tgz#2a3c41b28dd45b62b63676ecb74001265ae9edd8" - integrity sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA== - dependencies: - figgy-pudding "^3.5.1" - -ssri@^7.0.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/ssri/-/ssri-7.1.0.tgz#92c241bf6de82365b5c7fb4bd76e975522e1294d" - integrity sha512-77/WrDZUWocK0mvA5NTRQyveUf+wsrIc6vyrxpS8tVvYBcX215QbafrJR3KtkpskIzoFLqqNuuYQvxaMjXJ/0g== - dependencies: - figgy-pudding "^3.5.1" - minipass "^3.1.1" - -stable@^0.1.8: - version "0.1.8" - resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf" - integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w== - -stack-utils@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-1.0.2.tgz#33eba3897788558bebfc2db059dc158ec36cebb8" - integrity sha512-MTX+MeG5U994cazkjd/9KNAapsHnibjMLnfXodlkXw76JEea0UiNzrqidzo1emMwk7w5Qhc9jd4Bn9TBb1MFwA== - -state-toggle@^1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/state-toggle/-/state-toggle-1.0.3.tgz#e123b16a88e143139b09c6852221bc9815917dfe" - integrity sha512-d/5Z4/2iiCnHw6Xzghyhb+GcmF89bxwgXG60wjIiZaxnymbyOmI8Hk4VqHXiVVp6u2ysaskFfXg3ekCj4WNftQ== - -static-extend@^0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" - integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY= - dependencies: - define-property "^0.2.5" - object-copy "^0.1.0" - -"statuses@>= 1.4.0 < 2", "statuses@>= 1.5.0 < 2", statuses@~1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" - integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= - -stealthy-require@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b" - integrity sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks= - -stream-browserify@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.2.tgz#87521d38a44aa7ee91ce1cd2a47df0cb49dd660b" - integrity sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg== - dependencies: - inherits "~2.0.1" - readable-stream "^2.0.2" - -stream-each@^1.1.0: - version "1.2.3" - resolved "https://registry.yarnpkg.com/stream-each/-/stream-each-1.2.3.tgz#ebe27a0c389b04fbcc233642952e10731afa9bae" - integrity sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw== - dependencies: - end-of-stream "^1.1.0" - stream-shift "^1.0.0" - -stream-http@^2.7.2: - version "2.8.3" - resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.8.3.tgz#b2d242469288a5a27ec4fe8933acf623de6514fc" - integrity sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw== - dependencies: - builtin-status-codes "^3.0.0" - inherits "^2.0.1" - readable-stream "^2.3.6" - to-arraybuffer "^1.0.0" - xtend "^4.0.0" - -stream-shift@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.1.tgz#d7088281559ab2778424279b0877da3c392d5a3d" - integrity sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ== - -strict-uri-encode@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" - integrity sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM= - -string-length@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/string-length/-/string-length-2.0.0.tgz#d40dbb686a3ace960c1cffca562bf2c45f8363ed" - integrity sha1-1A27aGo6zpYMHP/KVivyxF+DY+0= - dependencies: - astral-regex "^1.0.0" - strip-ansi "^4.0.0" - -string-length@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/string-length/-/string-length-3.1.0.tgz#107ef8c23456e187a8abd4a61162ff4ac6e25837" - integrity sha512-Ttp5YvkGm5v9Ijagtaz1BnN+k9ObpvS0eIBblPMp2YWL8FBmi9qblQ9fexc2k/CXFgrTIteU3jAw3payCnwSTA== - dependencies: - astral-regex "^1.0.0" - strip-ansi "^5.2.0" - -string-width@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" - integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= - dependencies: - code-point-at "^1.0.0" - is-fullwidth-code-point "^1.0.0" - strip-ansi "^3.0.0" - -string-width@^2.0.0, string-width@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" - integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== - dependencies: - is-fullwidth-code-point "^2.0.0" - strip-ansi "^4.0.0" - -string-width@^3.0.0, string-width@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" - integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== - dependencies: - emoji-regex "^7.0.1" - is-fullwidth-code-point "^2.0.0" - strip-ansi "^5.1.0" - -string-width@^4.1.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.0.tgz#952182c46cc7b2c313d1596e623992bd163b72b5" - integrity sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.0" - -string.prototype.trimend@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz#85812a6b847ac002270f5808146064c995fb6913" - integrity sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g== - dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.5" - -string.prototype.trimleft@^2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/string.prototype.trimleft/-/string.prototype.trimleft-2.1.2.tgz#4408aa2e5d6ddd0c9a80739b087fbc067c03b3cc" - integrity sha512-gCA0tza1JBvqr3bfAIFJGqfdRTyPae82+KTnm3coDXkZN9wnuW3HjGgN386D7hfv5CHQYCI022/rJPVlqXyHSw== - dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.5" - string.prototype.trimstart "^1.0.0" - -string.prototype.trimright@^2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/string.prototype.trimright/-/string.prototype.trimright-2.1.2.tgz#c76f1cef30f21bbad8afeb8db1511496cfb0f2a3" - integrity sha512-ZNRQ7sY3KroTaYjRS6EbNiiHrOkjihL9aQE/8gfQ4DtAC/aEBRHFJa44OmoWxGGqXuJlfKkZW4WcXErGr+9ZFg== - dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.5" - string.prototype.trimend "^1.0.0" - -string.prototype.trimstart@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz#14af6d9f34b053f7cfc89b72f8f2ee14b9039a54" - integrity sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw== - dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.5" - -string_decoder@^1.0.0, string_decoder@^1.1.1: - version "1.3.0" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" - integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== - dependencies: - safe-buffer "~5.2.0" - -string_decoder@~1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" - integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== - dependencies: - safe-buffer "~5.1.0" - -stringify-object@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/stringify-object/-/stringify-object-3.3.0.tgz#703065aefca19300d3ce88af4f5b3956d7556629" - integrity sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw== - dependencies: - get-own-enumerable-property-symbols "^3.0.0" - is-obj "^1.0.1" - is-regexp "^1.0.0" - -strip-ansi@6.0.0, strip-ansi@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532" - integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w== - dependencies: - ansi-regex "^5.0.0" - -strip-ansi@^3.0.0, strip-ansi@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" - integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= - dependencies: - ansi-regex "^2.0.0" - -strip-ansi@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" - integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= - dependencies: - ansi-regex "^3.0.0" - -strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" - integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== - dependencies: - ansi-regex "^4.1.0" - -strip-bom@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" - integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= - -strip-comments@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/strip-comments/-/strip-comments-1.0.2.tgz#82b9c45e7f05873bee53f37168af930aa368679d" - integrity sha512-kL97alc47hoyIQSV165tTt9rG5dn4w1dNnBhOQ3bOU1Nc1hel09jnXANaHJ7vzHLd4Ju8kseDGzlev96pghLFw== - dependencies: - babel-extract-comments "^1.0.0" - babel-plugin-transform-object-rest-spread "^6.26.0" - -strip-eof@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" - integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= - -strip-json-comments@^3.0.1: - version "3.1.0" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.0.tgz#7638d31422129ecf4457440009fba03f9f9ac180" - integrity sha512-e6/d0eBu7gHtdCqFt0xJr642LdToM5/cN4Qb9DbHjVx1CP5RyeM+zH7pbecEmDv/lBqb0QH+6Uqq75rxFPkM0w== - -style-loader@0.23.1: - version "0.23.1" - resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-0.23.1.tgz#cb9154606f3e771ab6c4ab637026a1049174d925" - integrity sha512-XK+uv9kWwhZMZ1y7mysB+zoihsEj4wneFWAS5qoiLwzW0WzSqMrrsIy+a3zkQJq0ipFtBpX5W3MqyRIBF/WFGg== - dependencies: - loader-utils "^1.1.0" - schema-utils "^1.0.0" - -styled-components@5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-5.1.1.tgz#96dfb02a8025794960863b9e8e365e3b6be5518d" - integrity sha512-1ps8ZAYu2Husx+Vz8D+MvXwEwvMwFv+hqqUwhNlDN5ybg6A+3xyW1ECrAgywhvXapNfXiz79jJyU0x22z0FFTg== - dependencies: - "@babel/helper-module-imports" "^7.0.0" - "@babel/traverse" "^7.4.5" - "@emotion/is-prop-valid" "^0.8.8" - "@emotion/stylis" "^0.8.4" - "@emotion/unitless" "^0.7.4" - babel-plugin-styled-components ">= 1" - css-to-react-native "^3.0.0" - hoist-non-react-statics "^3.0.0" - shallowequal "^1.1.0" - supports-color "^5.5.0" - -stylehacks@^4.0.0: - version "4.0.3" - resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-4.0.3.tgz#6718fcaf4d1e07d8a1318690881e8d96726a71d5" - integrity sha512-7GlLk9JwlElY4Y6a/rmbH2MhVlTyVmiJd1PfTCqFaIBEGMYNsrO/v3SeGTdhBThLg4Z+NbOk/qFMwCa+J+3p/g== - dependencies: - browserslist "^4.0.0" - postcss "^7.0.0" - postcss-selector-parser "^3.0.0" - -supports-color@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" - integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= - -supports-color@^5.3.0, supports-color@^5.5.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" - integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== - dependencies: - has-flag "^3.0.0" - -supports-color@^6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.1.0.tgz#0764abc69c63d5ac842dd4867e8d025e880df8f3" - integrity sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ== - dependencies: - has-flag "^3.0.0" - -supports-color@^7.0.0, supports-color@^7.1.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.1.0.tgz#68e32591df73e25ad1c4b49108a2ec507962bfd1" - integrity sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g== - dependencies: - has-flag "^4.0.0" - -svg-parser@^2.0.0: - version "2.0.4" - resolved "https://registry.yarnpkg.com/svg-parser/-/svg-parser-2.0.4.tgz#fdc2e29e13951736140b76cb122c8ee6630eb6b5" - integrity sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ== - -svgo@^1.0.0, svgo@^1.2.2: - version "1.3.2" - resolved "https://registry.yarnpkg.com/svgo/-/svgo-1.3.2.tgz#b6dc511c063346c9e415b81e43401145b96d4167" - integrity sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw== - dependencies: - chalk "^2.4.1" - coa "^2.0.2" - css-select "^2.0.0" - css-select-base-adapter "^0.1.1" - css-tree "1.0.0-alpha.37" - csso "^4.0.2" - js-yaml "^3.13.1" - mkdirp "~0.5.1" - object.values "^1.1.0" - sax "~1.2.4" - stable "^0.1.8" - unquote "~1.1.1" - util.promisify "~1.0.0" - -symbol-tree@^3.2.2: - version "3.2.4" - resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" - integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== - -synchronous-promise@^2.0.10, synchronous-promise@^2.0.6: - version "2.0.10" - resolved "https://registry.yarnpkg.com/synchronous-promise/-/synchronous-promise-2.0.10.tgz#e64c6fd3afd25f423963353043f4a68ebd397fd8" - integrity sha512-6PC+JRGmNjiG3kJ56ZMNWDPL8hjyghF5cMXIFOKg+NiwwEZZIvxTWd0pinWKyD227odg9ygF8xVhhz7gb8Uq7A== - -table@^5.2.3: - version "5.4.6" - resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e" - integrity sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug== - dependencies: - ajv "^6.10.2" - lodash "^4.17.14" - slice-ansi "^2.1.0" - string-width "^3.0.0" - -tapable@^1.0.0, tapable@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2" - integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA== - -terser-webpack-plugin@2.3.4: - version "2.3.4" - resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-2.3.4.tgz#ac045703bd8da0936ce910d8fb6350d0e1dee5fe" - integrity sha512-Nv96Nws2R2nrFOpbzF6IxRDpIkkIfmhvOws+IqMvYdFLO7o6wAILWFKONFgaYy8+T4LVz77DQW0f7wOeDEAjrg== - dependencies: - cacache "^13.0.1" - find-cache-dir "^3.2.0" - jest-worker "^25.1.0" - p-limit "^2.2.2" - schema-utils "^2.6.4" - serialize-javascript "^2.1.2" - source-map "^0.6.1" - terser "^4.4.3" - webpack-sources "^1.4.3" - -terser-webpack-plugin@^1.4.3: - version "1.4.3" - resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.4.3.tgz#5ecaf2dbdc5fb99745fd06791f46fc9ddb1c9a7c" - integrity sha512-QMxecFz/gHQwteWwSo5nTc6UaICqN1bMedC5sMtUc7y3Ha3Q8y6ZO0iCR8pq4RJC8Hjf0FEPEHZqcMB/+DFCrA== - dependencies: - cacache "^12.0.2" - find-cache-dir "^2.1.0" - is-wsl "^1.1.0" - schema-utils "^1.0.0" - serialize-javascript "^2.1.2" - source-map "^0.6.1" - terser "^4.1.2" - webpack-sources "^1.4.0" - worker-farm "^1.7.0" - -terser@^4.1.2, terser@^4.4.3, terser@^4.6.3: - version "4.6.13" - resolved "https://registry.yarnpkg.com/terser/-/terser-4.6.13.tgz#e879a7364a5e0db52ba4891ecde007422c56a916" - integrity sha512-wMvqukYgVpQlymbnNbabVZbtM6PN63AzqexpwJL8tbh/mRT9LE5o+ruVduAGL7D6Fpjl+Q+06U5I9Ul82odAhw== - dependencies: - commander "^2.20.0" - source-map "~0.6.1" - source-map-support "~0.5.12" - -test-exclude@^5.2.3: - version "5.2.3" - resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-5.2.3.tgz#c3d3e1e311eb7ee405e092dac10aefd09091eac0" - integrity sha512-M+oxtseCFO3EDtAaGH7iiej3CBkzXqFMbzqYAACdzKui4eZA+pq3tZEwChvOdNfa7xxy8BfbmgJSIr43cC/+2g== - dependencies: - glob "^7.1.3" - minimatch "^3.0.4" - read-pkg-up "^4.0.0" - require-main-filename "^2.0.0" - -text-table@0.2.0, text-table@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" - integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= - -throat@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/throat/-/throat-4.1.0.tgz#89037cbc92c56ab18926e6ba4cbb200e15672a6a" - integrity sha1-iQN8vJLFarGJJua6TLsgDhVnKmo= - -through2@^2.0.0: - version "2.0.5" - resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" - integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== - dependencies: - readable-stream "~2.3.6" - xtend "~4.0.1" - -through@^2.3.6: - version "2.3.8" - resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" - integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= - -thunky@^1.0.2: - version "1.1.0" - resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.1.0.tgz#5abaf714a9405db0504732bbccd2cedd9ef9537d" - integrity sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA== - -timers-browserify@^2.0.4: - version "2.0.11" - resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.11.tgz#800b1f3eee272e5bc53ee465a04d0e804c31211f" - integrity sha512-60aV6sgJ5YEbzUdn9c8kYGIqOubPoUdqQCul3SBAsRCZ40s6Y5cMcrW4dt3/k/EsbLVJNl9n6Vz3fTc+k2GeKQ== - dependencies: - setimmediate "^1.0.4" - -timsort@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4" - integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q= - -tiny-invariant@^1.0.2: - version "1.1.0" - resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.1.0.tgz#634c5f8efdc27714b7f386c35e6760991d230875" - integrity sha512-ytxQvrb1cPc9WBEI/HSeYYoGD0kWnGEOR8RY6KomWLBVhqz0RgTwVO9dLrGz7dC+nN9llyI7OKAgRq8Vq4ZBSw== - -tiny-warning@^1.0.0, tiny-warning@^1.0.2, tiny-warning@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754" - integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA== - -tmp@^0.0.33: - version "0.0.33" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" - integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== - dependencies: - os-tmpdir "~1.0.2" - -tmpl@1.0.x: - version "1.0.4" - resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1" - integrity sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE= - -to-arraybuffer@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" - integrity sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M= - -to-fast-properties@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" - integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= - -to-object-path@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" - integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68= - dependencies: - kind-of "^3.0.2" - -to-regex-range@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" - integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg= - dependencies: - is-number "^3.0.0" - repeat-string "^1.6.1" - -to-regex-range@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" - integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== - dependencies: - is-number "^7.0.0" - -to-regex@^3.0.1, to-regex@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" - integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== - dependencies: - define-property "^2.0.2" - extend-shallow "^3.0.2" - regex-not "^1.0.2" - safe-regex "^1.1.0" - -toidentifier@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" - integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw== - -toposort@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/toposort/-/toposort-2.0.2.tgz#ae21768175d1559d48bef35420b2f4962f09c330" - integrity sha1-riF2gXXRVZ1IvvNUILL0li8JwzA= - -tough-cookie@^2.3.3, tough-cookie@^2.3.4, tough-cookie@^2.5.0, tough-cookie@~2.5.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" - integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g== - dependencies: - psl "^1.1.28" - punycode "^2.1.1" - -tr46@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/tr46/-/tr46-1.0.1.tgz#a8b13fd6bfd2489519674ccde55ba3693b706d09" - integrity sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk= - dependencies: - punycode "^2.1.0" - -trim-trailing-lines@^1.0.0: - version "1.1.3" - resolved "https://registry.yarnpkg.com/trim-trailing-lines/-/trim-trailing-lines-1.1.3.tgz#7f0739881ff76657b7776e10874128004b625a94" - integrity sha512-4ku0mmjXifQcTVfYDfR5lpgV7zVqPg6zV9rdZmwOPqq0+Zq19xDqEgagqVbc4pOOShbncuAOIs59R3+3gcF3ZA== - -trim@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/trim/-/trim-0.0.1.tgz#5858547f6b290757ee95cccc666fb50084c460dd" - integrity sha1-WFhUf2spB1fulczMZm+1AITEYN0= - -trough@^1.0.0: - version "1.0.5" - resolved "https://registry.yarnpkg.com/trough/-/trough-1.0.5.tgz#b8b639cefad7d0bb2abd37d433ff8293efa5f406" - integrity sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA== - -ts-pnp@1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/ts-pnp/-/ts-pnp-1.1.5.tgz#840e0739c89fce5f3abd9037bb091dbff16d9dec" - integrity sha512-ti7OGMOUOzo66wLF3liskw6YQIaSsBgc4GOAlWRnIEj8htCxJUxskanMUoJOD6MDCRAXo36goXJZch+nOS0VMA== - -ts-pnp@^1.1.2: - version "1.2.0" - resolved "https://registry.yarnpkg.com/ts-pnp/-/ts-pnp-1.2.0.tgz#a500ad084b0798f1c3071af391e65912c86bca92" - integrity sha512-csd+vJOb/gkzvcCHgTGSChYpy5f1/XKNsmvBGO4JXS+z1v2HobugDz4s1IeFXM3wZB44uczs+eazB5Q/ccdhQw== - -tslib@^1.10.0, tslib@^1.8.1, tslib@^1.9.0: - version "1.11.2" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.11.2.tgz#9c79d83272c9a7aaf166f73915c9667ecdde3cc9" - integrity sha512-tTSkux6IGPnUGUd1XAZHcpu85MOkIl5zX49pO+jfsie3eP0B6pyhOlLXm3cAC6T7s+euSDDUUV+Acop5WmtkVg== - -tsutils@^3.17.1: - version "3.17.1" - resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.17.1.tgz#ed719917f11ca0dee586272b2ac49e015a2dd759" - integrity sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g== - dependencies: - tslib "^1.8.1" - -tty-browserify@0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" - integrity sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY= - -tunnel-agent@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" - integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0= - dependencies: - safe-buffer "^5.0.1" - -tweetnacl@^0.14.3, tweetnacl@~0.14.0: - version "0.14.5" - resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" - integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= - -type-check@~0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" - integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= - dependencies: - prelude-ls "~1.1.2" - -type-fest@^0.11.0: - version "0.11.0" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.11.0.tgz#97abf0872310fed88a5c466b25681576145e33f1" - integrity sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ== - -type-fest@^0.8.1: - version "0.8.1" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" - integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== - -type-is@~1.6.17, type-is@~1.6.18: - version "1.6.18" - resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" - integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== - dependencies: - media-typer "0.3.0" - mime-types "~2.1.24" - -type@^1.0.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/type/-/type-1.2.0.tgz#848dd7698dafa3e54a6c479e759c4bc3f18847a0" - integrity sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg== - -type@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/type/-/type-2.0.0.tgz#5f16ff6ef2eb44f260494dae271033b29c09a9c3" - integrity sha512-KBt58xCHry4Cejnc2ISQAF7QY+ORngsWfxezO68+12hKV6lQY8P/psIkcbjeHWn7MqcgciWJyCCevFMJdIXpow== - -typedarray@^0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" - integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= - -unherit@^1.0.4: - version "1.1.3" - resolved "https://registry.yarnpkg.com/unherit/-/unherit-1.1.3.tgz#6c9b503f2b41b262330c80e91c8614abdaa69c22" - integrity sha512-Ft16BJcnapDKp0+J/rqFC3Rrk6Y/Ng4nzsC028k2jdDII/rdZ7Wd3pPT/6+vIIxRagwRc9K0IUX0Ra4fKvw+WQ== - dependencies: - inherits "^2.0.0" - xtend "^4.0.0" - -unicode-canonical-property-names-ecmascript@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818" - integrity sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ== - -unicode-match-property-ecmascript@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz#8ed2a32569961bce9227d09cd3ffbb8fed5f020c" - integrity sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg== - dependencies: - unicode-canonical-property-names-ecmascript "^1.0.4" - unicode-property-aliases-ecmascript "^1.0.4" - -unicode-match-property-value-ecmascript@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz#0d91f600eeeb3096aa962b1d6fc88876e64ea531" - integrity sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ== - -unicode-property-aliases-ecmascript@^1.0.4: - version "1.1.0" - resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz#dd57a99f6207bedff4628abefb94c50db941c8f4" - integrity sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg== - -unified@^6.1.5: - version "6.2.0" - resolved "https://registry.yarnpkg.com/unified/-/unified-6.2.0.tgz#7fbd630f719126d67d40c644b7e3f617035f6dba" - integrity sha512-1k+KPhlVtqmG99RaTbAv/usu85fcSRu3wY8X+vnsEhIxNP5VbVIDiXnLqyKIG+UMdyTg0ZX9EI6k2AfjJkHPtA== - dependencies: - bail "^1.0.0" - extend "^3.0.0" - is-plain-obj "^1.1.0" - trough "^1.0.0" - vfile "^2.0.0" - x-is-string "^0.1.0" - -union-value@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" - integrity sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg== - dependencies: - arr-union "^3.1.0" - get-value "^2.0.6" - is-extendable "^0.1.1" - set-value "^2.0.1" - -uniq@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff" - integrity sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8= - -uniqs@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/uniqs/-/uniqs-2.0.0.tgz#ffede4b36b25290696e6e165d4a59edb998e6b02" - integrity sha1-/+3ks2slKQaW5uFl1KWe25mOawI= - -unique-filename@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230" - integrity sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ== - dependencies: - unique-slug "^2.0.0" - -unique-slug@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-2.0.2.tgz#baabce91083fc64e945b0f3ad613e264f7cd4e6c" - integrity sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w== - dependencies: - imurmurhash "^0.1.4" - -unist-util-is@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/unist-util-is/-/unist-util-is-3.0.0.tgz#d9e84381c2468e82629e4a5be9d7d05a2dd324cd" - integrity sha512-sVZZX3+kspVNmLWBPAB6r+7D9ZgAFPNWm66f7YNb420RlQSbn+n8rG8dGZSkrER7ZIXGQYNm5pqC3v3HopH24A== - -unist-util-remove-position@^1.0.0: - version "1.1.4" - resolved "https://registry.yarnpkg.com/unist-util-remove-position/-/unist-util-remove-position-1.1.4.tgz#ec037348b6102c897703eee6d0294ca4755a2020" - integrity sha512-tLqd653ArxJIPnKII6LMZwH+mb5q+n/GtXQZo6S6csPRs5zB0u79Yw8ouR3wTw8wxvdJFhpP6Y7jorWdCgLO0A== - dependencies: - unist-util-visit "^1.1.0" - -unist-util-stringify-position@^1.0.0, unist-util-stringify-position@^1.1.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/unist-util-stringify-position/-/unist-util-stringify-position-1.1.2.tgz#3f37fcf351279dcbca7480ab5889bb8a832ee1c6" - integrity sha512-pNCVrk64LZv1kElr0N1wPiHEUoXNVFERp+mlTg/s9R5Lwg87f9bM/3sQB99w+N9D/qnM9ar3+AKDBwo/gm/iQQ== - -unist-util-visit-parents@1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/unist-util-visit-parents/-/unist-util-visit-parents-1.1.2.tgz#f6e3afee8bdbf961c0e6f028ea3c0480028c3d06" - integrity sha512-yvo+MMLjEwdc3RhhPYSximset7rwjMrdt9E41Smmvg25UQIenzrN83cRnF1JMzoMi9zZOQeYXHSDf7p+IQkW3Q== - -unist-util-visit-parents@^2.0.0: - version "2.1.2" - resolved "https://registry.yarnpkg.com/unist-util-visit-parents/-/unist-util-visit-parents-2.1.2.tgz#25e43e55312166f3348cae6743588781d112c1e9" - integrity sha512-DyN5vD4NE3aSeB+PXYNKxzGsfocxp6asDc2XXE3b0ekO2BaRUpBicbbUygfSvYfUz1IkmjFR1YF7dPklraMZ2g== - dependencies: - unist-util-is "^3.0.0" - -unist-util-visit@^1.1.0, unist-util-visit@^1.3.0: - version "1.4.1" - resolved "https://registry.yarnpkg.com/unist-util-visit/-/unist-util-visit-1.4.1.tgz#4724aaa8486e6ee6e26d7ff3c8685960d560b1e3" - integrity sha512-AvGNk7Bb//EmJZyhtRUnNMEpId/AZ5Ph/KUpTI09WHQuDZHKovQ1oEv3mfmKpWKtoMzyMC4GLBm1Zy5k12fjIw== - dependencies: - unist-util-visit-parents "^2.0.0" - -universalify@^0.1.0: - version "0.1.2" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" - integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== - -unpipe@1.0.0, unpipe@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" - integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= - -unquote@~1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/unquote/-/unquote-1.1.1.tgz#8fded7324ec6e88a0ff8b905e7c098cdc086d544" - integrity sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ= - -unset-value@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" - integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk= - dependencies: - has-value "^0.3.1" - isobject "^3.0.0" - -upath@^1.1.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/upath/-/upath-1.2.0.tgz#8f66dbcd55a883acdae4408af8b035a5044c1894" - integrity sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg== - -uri-js@^4.2.2: - version "4.2.2" - resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" - integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ== - dependencies: - punycode "^2.1.0" - -urix@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" - integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= - -url-loader@2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/url-loader/-/url-loader-2.3.0.tgz#e0e2ef658f003efb8ca41b0f3ffbf76bab88658b" - integrity sha512-goSdg8VY+7nPZKUEChZSEtW5gjbS66USIGCeSJ1OVOJ7Yfuh/36YxCwMi5HVEJh6mqUYOoy3NJ0vlOMrWsSHog== - dependencies: - loader-utils "^1.2.3" - mime "^2.4.4" - schema-utils "^2.5.0" - -url-parse@^1.4.3: - version "1.4.7" - resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.4.7.tgz#a8a83535e8c00a316e403a5db4ac1b9b853ae278" - integrity sha512-d3uaVyzDB9tQoSXFvuSUNFibTd9zxd2bkVrDRvF5TmvWWQwqE4lgYJ5m+x1DbecWkw+LK4RNl2CU1hHuOKPVlg== - dependencies: - querystringify "^2.1.1" - requires-port "^1.0.0" - -url@^0.11.0: - version "0.11.0" - resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" - integrity sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE= - dependencies: - punycode "1.3.2" - querystring "0.2.0" - -use@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" - integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== - -util-deprecate@^1.0.1, util-deprecate@~1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" - integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= - -util.promisify@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.0.0.tgz#440f7165a459c9a16dc145eb8e72f35687097030" - integrity sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA== - dependencies: - define-properties "^1.1.2" - object.getownpropertydescriptors "^2.0.3" - -util.promisify@^1.0.0, util.promisify@~1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.0.1.tgz#6baf7774b80eeb0f7520d8b81d07982a59abbaee" - integrity sha512-g9JpC/3He3bm38zsLupWryXHoEcS22YHthuPQSJdMy6KNrzIRzWqcsHzD/WUnqe45whVou4VIsPew37DoXWNrA== - dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.2" - has-symbols "^1.0.1" - object.getownpropertydescriptors "^2.1.0" - -util@0.10.3: - version "0.10.3" - resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" - integrity sha1-evsa/lCAUkZInj23/g7TeTNqwPk= - dependencies: - inherits "2.0.1" - -util@^0.11.0: - version "0.11.1" - resolved "https://registry.yarnpkg.com/util/-/util-0.11.1.tgz#3236733720ec64bb27f6e26f421aaa2e1b588d61" - integrity sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ== - dependencies: - inherits "2.0.3" - -utila@^0.4.0, utila@~0.4: - version "0.4.0" - resolved "https://registry.yarnpkg.com/utila/-/utila-0.4.0.tgz#8a16a05d445657a3aea5eecc5b12a4fa5379772c" - integrity sha1-ihagXURWV6Oupe7MWxKk+lN5dyw= - -utils-merge@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" - integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= - -uuid@^3.0.1, uuid@^3.3.2: - version "3.4.0" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" - integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== - -v8-compile-cache@^2.0.3: - version "2.1.0" - resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz#e14de37b31a6d194f5690d67efc4e7f6fc6ab30e" - integrity sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g== - -validate-npm-package-license@^3.0.1: - version "3.0.4" - resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" - integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== - dependencies: - spdx-correct "^3.0.0" - spdx-expression-parse "^3.0.0" - -value-equal@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/value-equal/-/value-equal-1.0.1.tgz#1e0b794c734c5c0cade179c437d356d931a34d6c" - integrity sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw== - -vary@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" - integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= - -vendors@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/vendors/-/vendors-1.0.4.tgz#e2b800a53e7a29b93506c3cf41100d16c4c4ad8e" - integrity sha512-/juG65kTL4Cy2su4P8HjtkTxk6VmJDiOPBufWniqQ6wknac6jNiXS9vU+hO3wgusiyqWlzTbVHi0dyJqRONg3w== - -verror@1.10.0: - version "1.10.0" - resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" - integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA= - dependencies: - assert-plus "^1.0.0" - core-util-is "1.0.2" - extsprintf "^1.2.0" - -vfile-location@^2.0.0: - version "2.0.6" - resolved "https://registry.yarnpkg.com/vfile-location/-/vfile-location-2.0.6.tgz#8a274f39411b8719ea5728802e10d9e0dff1519e" - integrity sha512-sSFdyCP3G6Ka0CEmN83A2YCMKIieHx0EDaj5IDP4g1pa5ZJ4FJDvpO0WODLxo4LUX4oe52gmSCK7Jw4SBghqxA== - -vfile-message@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/vfile-message/-/vfile-message-1.1.1.tgz#5833ae078a1dfa2d96e9647886cd32993ab313e1" - integrity sha512-1WmsopSGhWt5laNir+633LszXvZ+Z/lxveBf6yhGsqnQIhlhzooZae7zV6YVM1Sdkw68dtAW3ow0pOdPANugvA== - dependencies: - unist-util-stringify-position "^1.1.1" - -vfile@^2.0.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/vfile/-/vfile-2.3.0.tgz#e62d8e72b20e83c324bc6c67278ee272488bf84a" - integrity sha512-ASt4mBUHcTpMKD/l5Q+WJXNtshlWxOogYyGYYrg4lt/vuRjC1EFQtlAofL5VmtVNIZJzWYFJjzGWZ0Gw8pzW1w== - dependencies: - is-buffer "^1.1.4" - replace-ext "1.0.0" - unist-util-stringify-position "^1.0.0" - vfile-message "^1.0.0" - -vm-browserify@^1.0.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0" - integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ== - -w3c-hr-time@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd" - integrity sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ== - dependencies: - browser-process-hrtime "^1.0.0" - -w3c-xmlserializer@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-1.1.2.tgz#30485ca7d70a6fd052420a3d12fd90e6339ce794" - integrity sha512-p10l/ayESzrBMYWRID6xbuCKh2Fp77+sA0doRuGn4tTIMrrZVeqfpKjXHY+oDh3K4nLdPgNwMTVP6Vp4pvqbNg== - dependencies: - domexception "^1.0.1" - webidl-conversions "^4.0.2" - xml-name-validator "^3.0.0" - -walker@^1.0.7, walker@~1.0.5: - version "1.0.7" - resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb" - integrity sha1-L3+bj9ENZ3JisYqITijRlhjgKPs= - dependencies: - makeerror "1.0.x" - -watchpack@^1.6.0: - version "1.6.1" - resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.6.1.tgz#280da0a8718592174010c078c7585a74cd8cd0e2" - integrity sha512-+IF9hfUFOrYOOaKyfaI7h7dquUIOgyEMoQMLA7OP5FxegKA2+XdXThAZ9TU2kucfhDH7rfMHs1oPYziVGWRnZA== - dependencies: - chokidar "^2.1.8" - graceful-fs "^4.1.2" - neo-async "^2.5.0" - -wbuf@^1.1.0, wbuf@^1.7.3: - version "1.7.3" - resolved "https://registry.yarnpkg.com/wbuf/-/wbuf-1.7.3.tgz#c1d8d149316d3ea852848895cb6a0bfe887b87df" - integrity sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA== - dependencies: - minimalistic-assert "^1.0.0" - -webidl-conversions@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" - integrity sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg== - -webpack-dev-middleware@^3.7.2: - version "3.7.2" - resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-3.7.2.tgz#0019c3db716e3fa5cecbf64f2ab88a74bab331f3" - integrity sha512-1xC42LxbYoqLNAhV6YzTYacicgMZQTqRd27Sim9wn5hJrX3I5nxYy1SxSd4+gjUFsz1dQFj+yEe6zEVmSkeJjw== - dependencies: - memory-fs "^0.4.1" - mime "^2.4.4" - mkdirp "^0.5.1" - range-parser "^1.2.1" - webpack-log "^2.0.0" - -webpack-dev-server@3.10.2: - version "3.10.2" - resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-3.10.2.tgz#3403287d674c7407aab6d9b3f72259ecd0aa0874" - integrity sha512-pxZKPYb+n77UN8u9YxXT4IaIrGcNtijh/mi8TXbErHmczw0DtPnMTTjHj+eNjkqLOaAZM/qD7V59j/qJsEiaZA== - dependencies: - ansi-html "0.0.7" - bonjour "^3.5.0" - chokidar "^2.1.8" - compression "^1.7.4" - connect-history-api-fallback "^1.6.0" - debug "^4.1.1" - del "^4.1.1" - express "^4.17.1" - html-entities "^1.2.1" - http-proxy-middleware "0.19.1" - import-local "^2.0.0" - internal-ip "^4.3.0" - ip "^1.1.5" - is-absolute-url "^3.0.3" - killable "^1.0.1" - loglevel "^1.6.6" - opn "^5.5.0" - p-retry "^3.0.1" - portfinder "^1.0.25" - schema-utils "^1.0.0" - selfsigned "^1.10.7" - semver "^6.3.0" - serve-index "^1.9.1" - sockjs "0.3.19" - sockjs-client "1.4.0" - spdy "^4.0.1" - strip-ansi "^3.0.1" - supports-color "^6.1.0" - url "^0.11.0" - webpack-dev-middleware "^3.7.2" - webpack-log "^2.0.0" - ws "^6.2.1" - yargs "12.0.5" - -webpack-log@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/webpack-log/-/webpack-log-2.0.0.tgz#5b7928e0637593f119d32f6227c1e0ac31e1b47f" - integrity sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg== - dependencies: - ansi-colors "^3.0.0" - uuid "^3.3.2" - -webpack-manifest-plugin@2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/webpack-manifest-plugin/-/webpack-manifest-plugin-2.2.0.tgz#19ca69b435b0baec7e29fbe90fb4015de2de4f16" - integrity sha512-9S6YyKKKh/Oz/eryM1RyLVDVmy3NSPV0JXMRhZ18fJsq+AwGxUY34X54VNwkzYcEmEkDwNxuEOboCZEebJXBAQ== - dependencies: - fs-extra "^7.0.0" - lodash ">=3.5 <5" - object.entries "^1.1.0" - tapable "^1.0.0" - -webpack-sources@^1.1.0, webpack-sources@^1.4.0, webpack-sources@^1.4.1, webpack-sources@^1.4.3: - version "1.4.3" - resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.4.3.tgz#eedd8ec0b928fbf1cbfe994e22d2d890f330a933" - integrity sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ== - dependencies: - source-list-map "^2.0.0" - source-map "~0.6.1" - -webpack@4.41.5: - version "4.41.5" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.41.5.tgz#3210f1886bce5310e62bb97204d18c263341b77c" - integrity sha512-wp0Co4vpyumnp3KlkmpM5LWuzvZYayDwM2n17EHFr4qxBBbRokC7DJawPJC7TfSFZ9HZ6GsdH40EBj4UV0nmpw== - dependencies: - "@webassemblyjs/ast" "1.8.5" - "@webassemblyjs/helper-module-context" "1.8.5" - "@webassemblyjs/wasm-edit" "1.8.5" - "@webassemblyjs/wasm-parser" "1.8.5" - acorn "^6.2.1" - ajv "^6.10.2" - ajv-keywords "^3.4.1" - chrome-trace-event "^1.0.2" - enhanced-resolve "^4.1.0" - eslint-scope "^4.0.3" - json-parse-better-errors "^1.0.2" - loader-runner "^2.4.0" - loader-utils "^1.2.3" - memory-fs "^0.4.1" - micromatch "^3.1.10" - mkdirp "^0.5.1" - neo-async "^2.6.1" - node-libs-browser "^2.2.1" - schema-utils "^1.0.0" - tapable "^1.1.3" - terser-webpack-plugin "^1.4.3" - watchpack "^1.6.0" - webpack-sources "^1.4.1" - -websocket-driver@>=0.5.1: - version "0.7.3" - resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.7.3.tgz#a2d4e0d4f4f116f1e6297eba58b05d430100e9f9" - integrity sha512-bpxWlvbbB459Mlipc5GBzzZwhoZgGEZLuqPaR0INBGnPAY1vdBX6hPnoFXiw+3yWxDuHyQjO2oXTMyS8A5haFg== - dependencies: - http-parser-js ">=0.4.0 <0.4.11" - safe-buffer ">=5.1.0" - websocket-extensions ">=0.1.1" - -websocket-extensions@>=0.1.1: - version "0.1.3" - resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.3.tgz#5d2ff22977003ec687a4b87073dfbbac146ccf29" - integrity sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg== - -whatwg-encoding@^1.0.1, whatwg-encoding@^1.0.3, whatwg-encoding@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz#5abacf777c32166a51d085d6b4f3e7d27113ddb0" - integrity sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw== - dependencies: - iconv-lite "0.4.24" - -whatwg-fetch@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz#fc804e458cc460009b1a2b966bc8817d2578aefb" - integrity sha512-9GSJUgz1D4MfyKU7KRqwOjXCXTqWdFNvEr7eUBYchQiVc744mqK/MzXPNR2WsPkmkOa4ywfg8C2n8h+13Bey1Q== - -whatwg-mimetype@^2.1.0, whatwg-mimetype@^2.2.0, whatwg-mimetype@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf" - integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g== - -whatwg-url@^6.4.1: - version "6.5.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-6.5.0.tgz#f2df02bff176fd65070df74ad5ccbb5a199965a8" - integrity sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ== - dependencies: - lodash.sortby "^4.7.0" - tr46 "^1.0.1" - webidl-conversions "^4.0.2" - -whatwg-url@^7.0.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-7.1.0.tgz#c2c492f1eca612988efd3d2266be1b9fc6170d06" - integrity sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg== - dependencies: - lodash.sortby "^4.7.0" - tr46 "^1.0.1" - webidl-conversions "^4.0.2" - -which-module@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" - integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= - -which@^1.2.9, which@^1.3.0, which@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" - integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== - dependencies: - isexe "^2.0.0" - -which@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" - integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== - dependencies: - isexe "^2.0.0" - -word-wrap@~1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" - integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== - -workbox-background-sync@^4.3.1: - version "4.3.1" - resolved "https://registry.yarnpkg.com/workbox-background-sync/-/workbox-background-sync-4.3.1.tgz#26821b9bf16e9e37fd1d640289edddc08afd1950" - integrity sha512-1uFkvU8JXi7L7fCHVBEEnc3asPpiAL33kO495UMcD5+arew9IbKW2rV5lpzhoWcm/qhGB89YfO4PmB/0hQwPRg== - dependencies: - workbox-core "^4.3.1" - -workbox-broadcast-update@^4.3.1: - version "4.3.1" - resolved "https://registry.yarnpkg.com/workbox-broadcast-update/-/workbox-broadcast-update-4.3.1.tgz#e2c0280b149e3a504983b757606ad041f332c35b" - integrity sha512-MTSfgzIljpKLTBPROo4IpKjESD86pPFlZwlvVG32Kb70hW+aob4Jxpblud8EhNb1/L5m43DUM4q7C+W6eQMMbA== - dependencies: - workbox-core "^4.3.1" - -workbox-build@^4.3.1: - version "4.3.1" - resolved "https://registry.yarnpkg.com/workbox-build/-/workbox-build-4.3.1.tgz#414f70fb4d6de47f6538608b80ec52412d233e64" - integrity sha512-UHdwrN3FrDvicM3AqJS/J07X0KXj67R8Cg0waq1MKEOqzo89ap6zh6LmaLnRAjpB+bDIz+7OlPye9iii9KBnxw== - dependencies: - "@babel/runtime" "^7.3.4" - "@hapi/joi" "^15.0.0" - common-tags "^1.8.0" - fs-extra "^4.0.2" - glob "^7.1.3" - lodash.template "^4.4.0" - pretty-bytes "^5.1.0" - stringify-object "^3.3.0" - strip-comments "^1.0.2" - workbox-background-sync "^4.3.1" - workbox-broadcast-update "^4.3.1" - workbox-cacheable-response "^4.3.1" - workbox-core "^4.3.1" - workbox-expiration "^4.3.1" - workbox-google-analytics "^4.3.1" - workbox-navigation-preload "^4.3.1" - workbox-precaching "^4.3.1" - workbox-range-requests "^4.3.1" - workbox-routing "^4.3.1" - workbox-strategies "^4.3.1" - workbox-streams "^4.3.1" - workbox-sw "^4.3.1" - workbox-window "^4.3.1" - -workbox-cacheable-response@^4.3.1: - version "4.3.1" - resolved "https://registry.yarnpkg.com/workbox-cacheable-response/-/workbox-cacheable-response-4.3.1.tgz#f53e079179c095a3f19e5313b284975c91428c91" - integrity sha512-Rp5qlzm6z8IOvnQNkCdO9qrDgDpoPNguovs0H8C+wswLuPgSzSp9p2afb5maUt9R1uTIwOXrVQMmPfPypv+npw== - dependencies: - workbox-core "^4.3.1" - -workbox-core@^4.3.1: - version "4.3.1" - resolved "https://registry.yarnpkg.com/workbox-core/-/workbox-core-4.3.1.tgz#005d2c6a06a171437afd6ca2904a5727ecd73be6" - integrity sha512-I3C9jlLmMKPxAC1t0ExCq+QoAMd0vAAHULEgRZ7kieCdUd919n53WC0AfvokHNwqRhGn+tIIj7vcb5duCjs2Kg== - -workbox-expiration@^4.3.1: - version "4.3.1" - resolved "https://registry.yarnpkg.com/workbox-expiration/-/workbox-expiration-4.3.1.tgz#d790433562029e56837f341d7f553c4a78ebe921" - integrity sha512-vsJLhgQsQouv9m0rpbXubT5jw0jMQdjpkum0uT+d9tTwhXcEZks7qLfQ9dGSaufTD2eimxbUOJfWLbNQpIDMPw== - dependencies: - workbox-core "^4.3.1" - -workbox-google-analytics@^4.3.1: - version "4.3.1" - resolved "https://registry.yarnpkg.com/workbox-google-analytics/-/workbox-google-analytics-4.3.1.tgz#9eda0183b103890b5c256e6f4ea15a1f1548519a" - integrity sha512-xzCjAoKuOb55CBSwQrbyWBKqp35yg1vw9ohIlU2wTy06ZrYfJ8rKochb1MSGlnoBfXGWss3UPzxR5QL5guIFdg== - dependencies: - workbox-background-sync "^4.3.1" - workbox-core "^4.3.1" - workbox-routing "^4.3.1" - workbox-strategies "^4.3.1" - -workbox-navigation-preload@^4.3.1: - version "4.3.1" - resolved "https://registry.yarnpkg.com/workbox-navigation-preload/-/workbox-navigation-preload-4.3.1.tgz#29c8e4db5843803b34cd96dc155f9ebd9afa453d" - integrity sha512-K076n3oFHYp16/C+F8CwrRqD25GitA6Rkd6+qAmLmMv1QHPI2jfDwYqrytOfKfYq42bYtW8Pr21ejZX7GvALOw== - dependencies: - workbox-core "^4.3.1" - -workbox-precaching@^4.3.1: - version "4.3.1" - resolved "https://registry.yarnpkg.com/workbox-precaching/-/workbox-precaching-4.3.1.tgz#9fc45ed122d94bbe1f0ea9584ff5940960771cba" - integrity sha512-piSg/2csPoIi/vPpp48t1q5JLYjMkmg5gsXBQkh/QYapCdVwwmKlU9mHdmy52KsDGIjVaqEUMFvEzn2LRaigqQ== - dependencies: - workbox-core "^4.3.1" - -workbox-range-requests@^4.3.1: - version "4.3.1" - resolved "https://registry.yarnpkg.com/workbox-range-requests/-/workbox-range-requests-4.3.1.tgz#f8a470188922145cbf0c09a9a2d5e35645244e74" - integrity sha512-S+HhL9+iTFypJZ/yQSl/x2Bf5pWnbXdd3j57xnb0V60FW1LVn9LRZkPtneODklzYuFZv7qK6riZ5BNyc0R0jZA== - dependencies: - workbox-core "^4.3.1" - -workbox-routing@^4.3.1: - version "4.3.1" - resolved "https://registry.yarnpkg.com/workbox-routing/-/workbox-routing-4.3.1.tgz#a675841af623e0bb0c67ce4ed8e724ac0bed0cda" - integrity sha512-FkbtrODA4Imsi0p7TW9u9MXuQ5P4pVs1sWHK4dJMMChVROsbEltuE79fBoIk/BCztvOJ7yUpErMKa4z3uQLX+g== - dependencies: - workbox-core "^4.3.1" - -workbox-strategies@^4.3.1: - version "4.3.1" - resolved "https://registry.yarnpkg.com/workbox-strategies/-/workbox-strategies-4.3.1.tgz#d2be03c4ef214c115e1ab29c9c759c9fe3e9e646" - integrity sha512-F/+E57BmVG8dX6dCCopBlkDvvhg/zj6VDs0PigYwSN23L8hseSRwljrceU2WzTvk/+BSYICsWmRq5qHS2UYzhw== - dependencies: - workbox-core "^4.3.1" - -workbox-streams@^4.3.1: - version "4.3.1" - resolved "https://registry.yarnpkg.com/workbox-streams/-/workbox-streams-4.3.1.tgz#0b57da70e982572de09c8742dd0cb40a6b7c2cc3" - integrity sha512-4Kisis1f/y0ihf4l3u/+ndMkJkIT4/6UOacU3A4BwZSAC9pQ9vSvJpIi/WFGQRH/uPXvuVjF5c2RfIPQFSS2uA== - dependencies: - workbox-core "^4.3.1" - -workbox-sw@^4.3.1: - version "4.3.1" - resolved "https://registry.yarnpkg.com/workbox-sw/-/workbox-sw-4.3.1.tgz#df69e395c479ef4d14499372bcd84c0f5e246164" - integrity sha512-0jXdusCL2uC5gM3yYFT6QMBzKfBr2XTk0g5TPAV4y8IZDyVNDyj1a8uSXy3/XrvkVTmQvLN4O5k3JawGReXr9w== - -workbox-webpack-plugin@4.3.1: - version "4.3.1" - resolved "https://registry.yarnpkg.com/workbox-webpack-plugin/-/workbox-webpack-plugin-4.3.1.tgz#47ff5ea1cc074b6c40fb5a86108863a24120d4bd" - integrity sha512-gJ9jd8Mb8wHLbRz9ZvGN57IAmknOipD3W4XNE/Lk/4lqs5Htw4WOQgakQy/o/4CoXQlMCYldaqUg+EJ35l9MEQ== - dependencies: - "@babel/runtime" "^7.0.0" - json-stable-stringify "^1.0.1" - workbox-build "^4.3.1" - -workbox-window@^4.3.1: - version "4.3.1" - resolved "https://registry.yarnpkg.com/workbox-window/-/workbox-window-4.3.1.tgz#ee6051bf10f06afa5483c9b8dfa0531994ede0f3" - integrity sha512-C5gWKh6I58w3GeSc0wp2Ne+rqVw8qwcmZnQGpjiek8A2wpbxSJb1FdCoQVO+jDJs35bFgo/WETgl1fqgsxN0Hg== - dependencies: - workbox-core "^4.3.1" - -worker-farm@^1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.7.0.tgz#26a94c5391bbca926152002f69b84a4bf772e5a8" - integrity sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw== - dependencies: - errno "~0.1.7" - -worker-rpc@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/worker-rpc/-/worker-rpc-0.1.1.tgz#cb565bd6d7071a8f16660686051e969ad32f54d5" - integrity sha512-P1WjMrUB3qgJNI9jfmpZ/htmBEjFh//6l/5y8SD9hg1Ef5zTTVVoRjTrTEzPrNBQvmhMxkoTsjOXN10GWU7aCg== - dependencies: - microevent.ts "~0.1.1" - -wrap-ansi@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" - integrity sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU= - dependencies: - string-width "^1.0.1" - strip-ansi "^3.0.1" - -wrap-ansi@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09" - integrity sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q== - dependencies: - ansi-styles "^3.2.0" - string-width "^3.0.0" - strip-ansi "^5.0.0" - -wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= - -write-file-atomic@2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.4.1.tgz#d0b05463c188ae804396fd5ab2a370062af87529" - integrity sha512-TGHFeZEZMnv+gBFRfjAcxL5bPHrsGKtnb4qsFAws7/vlh+QfwAaySIw4AXP9ZskTTh5GWu3FLuJhsWVdiJPGvg== - dependencies: - graceful-fs "^4.1.11" - imurmurhash "^0.1.4" - signal-exit "^3.0.2" - -write@1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/write/-/write-1.0.3.tgz#0800e14523b923a387e415123c865616aae0f5c3" - integrity sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig== - dependencies: - mkdirp "^0.5.1" - -ws@^5.2.0: - version "5.2.2" - resolved "https://registry.yarnpkg.com/ws/-/ws-5.2.2.tgz#dffef14866b8e8dc9133582514d1befaf96e980f" - integrity sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA== - dependencies: - async-limiter "~1.0.0" - -ws@^6.1.2, ws@^6.2.1: - version "6.2.1" - resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.1.tgz#442fdf0a47ed64f59b6a5d8ff130f4748ed524fb" - integrity sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA== - dependencies: - async-limiter "~1.0.0" - -x-is-string@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/x-is-string/-/x-is-string-0.1.0.tgz#474b50865af3a49a9c4657f05acd145458f77d82" - integrity sha1-R0tQhlrzpJqcRlfwWs0UVFj3fYI= - -xml-name-validator@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" - integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw== - -xmlchars@^2.1.1: - version "2.2.0" - resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" - integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== - -xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" - integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== - -"y18n@^3.2.1 || ^4.0.0", y18n@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" - integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w== - -yallist@^3.0.2: - version "3.1.1" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" - integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== - -yallist@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" - integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== - -yaml@^1.7.2: - version "1.9.2" - resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.9.2.tgz#f0cfa865f003ab707663e4f04b3956957ea564ed" - integrity sha512-HPT7cGGI0DuRcsO51qC1j9O16Dh1mZ2bnXwsi0jrSpsLz0WxOLSLXfkABVl6bZO629py3CU+OMJtpNHDLB97kg== - dependencies: - "@babel/runtime" "^7.9.2" - -yargs-parser@^11.1.1: - version "11.1.1" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-11.1.1.tgz#879a0865973bca9f6bab5cbdf3b1c67ec7d3bcf4" - integrity sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ== - dependencies: - camelcase "^5.0.0" - decamelize "^1.2.0" - -yargs-parser@^13.1.2: - version "13.1.2" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.2.tgz#130f09702ebaeef2650d54ce6e3e5706f7a4fb38" - integrity sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg== - dependencies: - camelcase "^5.0.0" - decamelize "^1.2.0" - -yargs@12.0.5: - version "12.0.5" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-12.0.5.tgz#05f5997b609647b64f66b81e3b4b10a368e7ad13" - integrity sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw== - dependencies: - cliui "^4.0.0" - decamelize "^1.2.0" - find-up "^3.0.0" - get-caller-file "^1.0.1" - os-locale "^3.0.0" - require-directory "^2.1.1" - require-main-filename "^1.0.1" - set-blocking "^2.0.0" - string-width "^2.0.0" - which-module "^2.0.0" - y18n "^3.2.1 || ^4.0.0" - yargs-parser "^11.1.1" - -yargs@^13.3.0: - version "13.3.2" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.2.tgz#ad7ffefec1aa59565ac915f82dccb38a9c31a2dd" - integrity sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw== - dependencies: - cliui "^5.0.0" - find-up "^3.0.0" - get-caller-file "^2.0.1" - require-directory "^2.1.1" - require-main-filename "^2.0.0" - set-blocking "^2.0.0" - string-width "^3.0.0" - which-module "^2.0.0" - y18n "^4.0.0" - yargs-parser "^13.1.2" - -yup@0.27.0: - version "0.27.0" - resolved "https://registry.yarnpkg.com/yup/-/yup-0.27.0.tgz#f8cb198c8e7dd2124beddc2457571329096b06e7" - integrity sha512-v1yFnE4+u9za42gG/b/081E7uNW9mUj3qtkmelLbW5YPROZzSH/KUUyJu9Wt8vxFJcT9otL/eZopS0YK1L5yPQ== - dependencies: - "@babel/runtime" "^7.0.0" - fn-name "~2.0.1" - lodash "^4.17.11" - property-expr "^1.5.0" - synchronous-promise "^2.0.6" - toposort "^2.0.2" - -yup@0.29.1: - version "0.29.1" - resolved "https://registry.yarnpkg.com/yup/-/yup-0.29.1.tgz#35d25aab470a0c3950f66040ba0ff4b1b6efe0d9" - integrity sha512-U7mPIbgfQWI6M3hZCJdGFrr+U0laG28FxMAKIgNvgl7OtyYuUoc4uy9qCWYHZjh49b8T7Ug8NNDdiMIEytcXrQ== - dependencies: - "@babel/runtime" "^7.9.6" - fn-name "~3.0.0" - lodash "^4.17.15" - lodash-es "^4.17.11" - property-expr "^2.0.2" - synchronous-promise "^2.0.10" - toposort "^2.0.2" diff --git a/nginx-proxy.conf b/nginx-proxy.conf deleted file mode 100644 index 796cd1ab8..000000000 --- a/nginx-proxy.conf +++ /dev/null @@ -1,15 +0,0 @@ -events {} - -http { - server { - listen 80; - - location / { - proxy_pass http://frontend:8080; - } - - location /api/ { - proxy_pass http://backend:8081; - } - } -} diff --git a/no_backend.docker-compose.yml b/no_backend.docker-compose.yml deleted file mode 100644 index 1a9d04374..000000000 --- a/no_backend.docker-compose.yml +++ /dev/null @@ -1,32 +0,0 @@ -version: "2" -services: - db: - image: postgres:10 - restart: always - environment: - POSTGRES_PASSWORD: example - ports: - - 5432:5432 - - adminer: - image: adminer - restart: always - ports: - - 8080:8080 - - frontend: - image: frontend:development - build: - context: ./frontend/ - dockerfile: dev.dockerfile - ports: - - 3000:3000 - volumes: - - ./frontend/src:/usr/src/app/src - - ./frontend/public:/usr/src/app/public - network_mode: host - redis: - image: redis:5.0 - restart: always - ports: - - 6379:6379 diff --git a/prod.docker-compose.yml b/prod.docker-compose.yml deleted file mode 100644 index 086cbe88a..000000000 --- a/prod.docker-compose.yml +++ /dev/null @@ -1,97 +0,0 @@ -version: "3" -networks: - gamma: - -services: - db: - image: postgres:10 - restart: always - environment: - POSTGRES_USER: user # These should all be changed - POSTGRES_PASSWORD: password - POSTGRES_DB: db - networks: - - gamma - - frontend: - image: frontend:latest - build: - context: ./frontend/ - dockerfile: Dockerfile - args: - REACT_APP_BACKEND_URL: http://localhost:8080/api - depends_on: - - backend - networks: - - gamma - - backend: - build: - context: ./backend/ - dockerfile: dockerfile - environment: - # Default admin user name = admin - # Default admin password = password - - DB_USER: user - DB_PASSWORD: password - DB_HOST: db - DB_PORT: 5432 - DB_NAME: postgres - - REDIS_HOST: redis - REDIS_PASSWORD: "" - REDIS_PORT: 6379 - - GOTIFY_KEY: "123abc" - GOTIFY_URL: http://gotify:8080/mail - - SERVER_PORT: 8081 - SUCCESSFUL_LOGIN: http://localhost:8080 - CORS_ALLOWED_ORIGIN: http://localhost:8080 - BACKEND_URI: http://localhost:8080/api/ - PRODUCTION: "false" - COOKIE_DOMAIN: localhost - IS_MOCKING_CLIENT: "true" - depends_on: - - redis - - db - networks: - - gamma - - redis: - image: redis - networks: - - gamma - - adminer: - image: adminer - restart: always - networks: - - gamma - ports: - - 8082:8080 - - gotify: - image: cthit/gotify - networks: - - gamma - environment: - GOTIFY_PRE-SHARED-KEY: 123abc - GOTIFY_MOCK-MODE: "true" - - proxy: - image: nginx:1.16.0-alpine - networks: - - gamma - ports: - - 8080:80 - environment: - - NGINX_HOST=localhost - - NGINX_PORT=80 - volumes: - - ./nginx-proxy.conf:/etc/nginx/nginx.conf:ro - depends_on: - - frontend - - backend - command: [nginx-debug, '-g', 'daemon off;'] \ No newline at end of file