diff --git a/.coveragerc b/.coveragerc deleted file mode 100644 index 3a2a735..0000000 --- a/.coveragerc +++ /dev/null @@ -1,13 +0,0 @@ -[report] -exclude_lines = - pragma: no cover - def __repr__ - if self.debug: - if settings.DEBUG - raise AssertionError - raise NotImplementedError - if 0: - if __name__ == .__main__.: -[run] -source=. -omit=manage.py diff --git a/.gitignore b/.gitignore index 0dfb587..50281a4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,114 +1,10 @@ -# Created by https://www.gitignore.io/api/python +# Generated by Cargo +# will have compiled files and executables +/target/ +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock +Cargo.lock -# Front-end related -/static/libs/ -node_modules - -# Mac-related -.DS_Store - -# Cache from webassets -/static/.webassets-cache - -# Compiled CSS from SCSS -/static/gen/app.css - -# Compiled from Babel -/static/gen/app.js - -### Python ### -# Byte-compiled / optimized / DLL files -__pycache__/ -*.py[cod] -*$py.class - -# C extensions -*.so - -# Distribution / packaging -.Python -env/ -build/ -develop-eggs/ -dist/ -downloads/ -eggs/ -.eggs/ -lib/ -lib64/ -parts/ -sdist/ -var/ -*.egg-info/ -.installed.cfg -*.egg - -# PyInstaller -# Usually these files are written by a python script from a template -# before PyInstaller builds the exe, so as to inject date/other infos into it. -*.manifest -*.spec - -# Installer logs -pip-log.txt -pip-delete-this-directory.txt - -# Unit test / coverage reports -htmlcov/ -.tox/ -.coverage -.coverage.* -.cache -nosetests.xml -coverage.xml -*,cover -.hypothesis/ - -# Translations -*.mo -*.pot - -# Django stuff: -*.log -local_settings.py - -# Flask instance folder -instance/ - -# Scrapy stuff: -.scrapy - -# Sphinx documentation -docs/_build/ - -# PyBuilder -target/ - -# IPython Notebook -.ipynb_checkpoints - -# pyenv -.python-version - -# celery beat schedule file -celerybeat-schedule - -# dotenv -.env - -# virtualenv -venv/ -ENV/ - -# Spyder project settings -.spyderproject - -# Rope project settings -.ropeproject - -# Vim-related -*.swp - -# Test report -reports/ +# These are backup files generated by rustfmt +**/*.rs.bk diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index b3dd816..0000000 --- a/.gitmodules +++ /dev/null @@ -1,4 +0,0 @@ - -[submodule "config"] - path = app/config - url = git@bitbucket.org:gitplaylist/config.git diff --git a/.pylintrc b/.pylintrc deleted file mode 100644 index 0a3daea..0000000 --- a/.pylintrc +++ /dev/null @@ -1,9 +0,0 @@ -[MASTER] -load-plugins=pylint_mccabe,pylint_flask - -[DESIGN] -max-complexity=10 - -[FORMAT] -# Maximum number of characters on a single line. -max-line-length=100 diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..c5e7c52 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "git_playlist_backend" +version = "0.1.0" +authors = ["Tim "] + +[dependencies] +hyper = "*" +rustc-serialize = "0.3" +valico = "1" + +[dependencies.iron] +version = "*" + +[dependencies.rustless] +git = "https://github.com/rustless/rustless" diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 7905315..0000000 --- a/Dockerfile +++ /dev/null @@ -1,9 +0,0 @@ -# Base image -FROM python:3-onbuild - -# The port number the container should expose -EXPOSE 80 - -# run the application -ENTRYPOINT ["python", "manage.py"] -CMD ["runserver"] diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 9cecc1d..0000000 --- a/LICENSE +++ /dev/null @@ -1,674 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 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 General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - {one line to give the program's name and a brief idea of what it does.} - Copyright (C) {year} {name of author} - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - {project} Copyright (C) {year} {fullname} - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. diff --git a/README.md b/README.md index 1836e0d..7422b99 100644 --- a/README.md +++ b/README.md @@ -1,26 +1,25 @@ -# gitplaylist +# Iron Hello World -[![CircleCI](https://circleci.com/gh/gitplaylist/backend.svg?style=shield)](https://circleci.com/gh/gitplaylist/backend) -[![codecov](https://codecov.io/gh/gitplaylist/backend/branch/master/graph/badge.svg)](https://codecov.io/gh/gitplaylist/backend) -[![docker](https://img.shields.io/docker/pulls/gitplaylist/backend.svg)](https://hub.docker.com/r/gitplaylist/backend/) -[![Imagelayers](https://imagelayers.io/badge/gitplaylist/backend:latest.svg)](https://imagelayers.io/?images=gitplaylist/backend:latest) -[![Requirements Status](https://requires.io/github/gitplaylist/backend/requirements.svg?branch=master)](https://requires.io/github/gitplaylist/backend/requirements/?branch=master) -[![Maintenance](https://img.shields.io/maintenance/yes/2016.svg?maxAge=2592000)](https://github.com/gitplaylist/backend) +## Setup -## Setup -```bash -$ git submodule init && git submodule update -$ pip install pip-save -$ pip install -r requirements.txt -$ ./manage.py runserver -``` +### install rust +```$ curl -sSf https://static.rust-lang.org/rustup.sh | sh``` + +### build project +```$ cargo build``` -In project root directory run: +#### Mac errors & fixes in setup: +`fatal error: 'openssl/ssl.h' file not found`. ``` -ln -s ../../pre-commit.sh .git/hooks/pre-commit -sudo chmod +x .git/hooks/pre-commit +export OPENSSL_INCLUDE_DIR=/usr/local/opt/openssl/include +export DEP_OPENSSL_INCLUDE=/usr/local/opt/openssl/include ``` -## Project Management -[Trello Organization](https://trello.com/gitplaylist) +`note: ld: library not found for -lssl` +https://github.com/sfackler/rust-openssl + +### run project +``` +$ cargo run +``` diff --git a/app/app.py b/app/app.py deleted file mode 100644 index 868b164..0000000 --- a/app/app.py +++ /dev/null @@ -1,80 +0,0 @@ -from flask import Blueprint, Flask -from flask_assets import Bundle, Environment -from flask_cors import CORS, cross_origin -from flask_login import LoginManager -from flask_migrate import Migrate -from flask_oauthlib.client import OAuth -from flask_restful import Api -from flask_sqlalchemy import SQLAlchemy -from webassets.filter import register_filter -from webassets_browserify import Browserify - -from config import Config - -register_filter(Browserify) - -db = SQLAlchemy() -api = Api() -assets = Environment() -login_manager = LoginManager() -oauth = OAuth() - -spotify = oauth.remote_app( - 'Spotify OAuth', - consumer_key=Config.SPOTIFY_CLIENT_ID, - consumer_secret=Config.SPOTIFY_CLIENT_SECRET, - request_token_params={'scope': 'user-read-email'}, - base_url='https://api.spotify.com/', - request_token_url=None, - access_token_method='POST', - access_token_url='https://accounts.spotify.com/api/token', - authorize_url='https://accounts.spotify.com/authorize', -) - -github = oauth.remote_app( - 'Github OAuth', - consumer_key=Config.GITHUB_CLIENT_ID, - consumer_secret=Config.GITHUB_CLIENT_SECRET, - request_token_params={'scope': 'user:email'}, - base_url='https://api.github.com/', - request_token_url=None, - access_token_method='POST', - access_token_url='https://github.com/login/oauth/access_token', - authorize_url='https://github.com/login/oauth/authorize', -) -def change_github_header(uri, headers, body): # pragma: no cover - auth = headers.get('Authorization') - if auth: - auth = auth.replace('Bearer', 'token') - headers['Authorization'] = auth - return uri, headers, body - -github.pre_request = change_github_header - -def create_app(): - """ Initializing the app """ - app = Flask(__name__) - app.config.update(Config.__dict__) - - # Set up extensions - db.init_app(app) - app.db = db - Migrate(app, db) - CORS(app) # TODO: Don't allow all in production - - assets.init_app(app) - login_manager.init_app(app) - - # Install views - from views.oauth import bp as oauth_bp - app.register_blueprint(oauth_bp) - - # Install API - from views import account - from views import authorization - api.init_app(app) - - # Install models - from models.account import User - - return app diff --git a/app/config b/app/config deleted file mode 160000 index da2a248..0000000 --- a/app/config +++ /dev/null @@ -1 +0,0 @@ -Subproject commit da2a2481bbb1028412cf2b85fc3f07d9b8a6acff diff --git a/app/exceptions.py b/app/exceptions.py deleted file mode 100644 index c904dae..0000000 --- a/app/exceptions.py +++ /dev/null @@ -1,8 +0,0 @@ -"""Define exceptions.""" - -class ValidationError(ValueError): - """Define a validation error.""" - - def __init__(self, message): - super(ValidationError, self).__init__(message) - self.message = message diff --git a/app/features/environment.py b/app/features/environment.py deleted file mode 100644 index 5608139..0000000 --- a/app/features/environment.py +++ /dev/null @@ -1,29 +0,0 @@ -"""Define context before any tests run.""" -import os - -from app import create_app, db - - -def before_all(context): - """Create the context bag.""" - # Change the configuration on the fly - os.environ['ENV'] = 'testing' - - # Import this now because the environment variable - # should be changed before this happens. - - context.app = create_app() - - # Create all the tables in memory. - with context.app.app_context(): - db.create_all() - - # Create the test client. - context.client = context.app.test_client() - - -def after_all(context): - """Destroy the context bag.""" - with context.app.app_context(): - db.reflect() - db.drop_all() diff --git a/app/features/login.feature b/app/features/login.feature deleted file mode 100644 index d15de23..0000000 --- a/app/features/login.feature +++ /dev/null @@ -1,22 +0,0 @@ -Feature: Login - Users should be able to login to our service if they have an account on our system. - - Scenario: User logged in with an email and a password - Given the user entered the email and the password - When the user clicked the log in button - Then we should log the user in with a proper session value populated - - Scenario: User logged in with an email and an incorrect password - Given the user entered the email and an incorrect password - When the user clicked the log in button - Then we should not log the user in - - Scenario: User logged in with the Github single sign-on button - Given the user is already signed up with Github - When the user clicked the Github single sign-on button - Then we should log the user in with the proper session value populated - - Scenario: User logged in with the Spotify single sign-on button - Given the user is already signed up with Spotify - When the user clicked the Spotify single sign-on button - Then we should log the user in with the proper session value populated diff --git a/app/features/signup.feature b/app/features/signup.feature deleted file mode 100644 index 6c3e5bc..0000000 --- a/app/features/signup.feature +++ /dev/null @@ -1,28 +0,0 @@ -Feature: Sign Up - There should be a way for users create an account with gitplaylist. It should allow for both - traditional email and password sign up and allow Github single sign on account. - - Scenario: User signed up with an email and a password. - Given the user entered an email and password. - When the user clicked the sign up button. - Then we should create an account for the user with the designated email. - - Scenario: User signed up with an invalid email. - Given the user entered an invalid email. - When the user clicked the sign up button. - Then we should not create an account for the user with the designated email. - - Scenario: User signed up with an invalid password. - Given the user entered an invalid password. - When the user clicked the sign up button. - Then we should not create an account for the user with the designated email. - - Scenario: User signed up with a Github access token/refresh token. - Given the user clicked the Github sign up button with Github account signed in. - When approved on the Github OAuth authorization and called back to our website. - Then we should create an account for the user with the designated Github account. - - Scenario: User signed up with a Spotify access token/refresh token. - Given the user clicked the Spotify sign up button with Spotify account signed in. - When approved on the Spotify OAuth authorization and called back to our website. - Then we should create an account for the user with the designated Spotify account. diff --git a/app/features/steps/login.py b/app/features/steps/login.py deleted file mode 100644 index 13e55bb..0000000 --- a/app/features/steps/login.py +++ /dev/null @@ -1,152 +0,0 @@ -from unittest.mock import MagicMock, Mock, patch - -from behave import given, then, when -from flask import session -from flask_login import current_user, logout_user - -from app import db -from models.account import GithubAccessToken, SpotifyAccessToken, User -from views.oauth import github_oauth_handler, spotify_oauth_handler - - -@given(u'the user entered the email and the password') -def step_impl(context): - context.email = 'login@example.com' - context.password = 'password and some entropy: 12345' - - with context.app.app_context(): - context.user = User( - email=context.email, - password=context.password, - ) - db.session.add(context.user) - db.session.commit() - -@when(u'the user clicked the log in button') -def step_impl(context): - with context.app.app_context(): - context.response = context.client.post('/users/authorize', data={ - "email": context.email, - "password": context.password, - }) - -@then(u'we should log the user in with a proper session value populated') -def step_impl(context): - with context.app.app_context(): - assert context.response.status_code == 200 - -@given(u'the user entered the email and an incorrect password') -def step_impl(context): - context.email = 'badlogin@example.com' - context.password = 'incorrect password' - - with context.app.app_context(): - context.user = User( - email=context.email, - password="incorrect password with entropy", - ) - db.session.add(context.user) - db.session.commit() - -@then(u'we should not log the user in') -def step_impl(context): - with context.app.app_context(): - assert context.response.status_code == 400 - -@given(u'the user is already signed up with Github') -def step_impl(context): - context.email = 'login+1@example.com' - context.access_token = 'existing-token' - context.scope = '' - context.token_type = 'bearer' - - with context.app.app_context(): - context.user = User(email=context.email) - db.session.add(context.user) - db.session.commit() - context.token = GithubAccessToken( - context.user.id, context.token_type, context.scope, context.access_token - ) - db.session.add(context.token) - db.session.commit() - - context.expected_user_id = context.user.id - -@when(u'the user clicked the Github single sign-on button') -def step_impl(context): - github_user_me = MagicMock() - github_user_me.data = {"email": context.email} - github_get = Mock(return_value=github_user_me) - github_authorized_response = Mock(return_value={ - "access_token": context.access_token, - "scope": context.scope, - "token_type": context.token_type, - }) - with\ - patch('app.github.get', github_get),\ - patch('app.github.authorized_response', github_authorized_response),\ - context.app.test_request_context('/callback/github?code=something'): - # Github OAuth callback - res = github_oauth_handler() - context.current_user_id = current_user.id - - # There aren't any errors - assert session.get('_flashes') in (None, []) - assert res.status_code == 302 - assert res.headers['Location'].endswith("/") - -@then(u'we should log the user in with the proper session value populated') -def step_impl(context): - with context.app.app_context(): - assert context.current_user_id == context.expected_user_id - -@given(u'the user is already signed up with Spotify') -def step_impl(context): - context.email = 'login+2@example.com' - context.access_token = 'existing-token' - context.scope = '' - context.token_type = 'bearer' - context.expires_in = 23 - context.refresh_token = 'refresh-token' - - with context.app.app_context(): - context.user = User(email=context.email) - db.session.add(context.user) - db.session.commit() - context.token = SpotifyAccessToken( - user_id=context.user.id, - token_type=context.token_type, - scope=context.scope, - access_token=context.access_token, - expires_in=context.expires_in, - refresh_token=context.refresh_token - ) - db.session.add(context.token) - db.session.commit() - - context.expected_user_id = context.user.id - -@when(u'the user clicked the Spotify single sign-on button') -def step_impl(context): - spotify_user_me = MagicMock() - spotify_user_me.data = {"email": context.email} - spotify_get = Mock(return_value=spotify_user_me) - spotify_authorized_response = Mock(return_value={ - "access_token": context.access_token, - "scope": context.scope, - "token_type": context.token_type, - "expires_in": context.expires_in, - "refresh_token": context.refresh_token, - }) - with\ - patch('app.spotify.get', spotify_get),\ - patch('app.spotify.authorized_response', spotify_authorized_response),\ - context.app.test_request_context('/callback/spotify?code=something'): - # Spotify OAuth callback - res = spotify_oauth_handler() - context.current_user_id = current_user.id - - # There aren't any errors - assert session.get('_flashes') in (None, []) - assert res.status_code == 302 - assert res.headers['Location'].endswith("/") diff --git a/app/features/steps/signup.py b/app/features/steps/signup.py deleted file mode 100644 index a0e5ff7..0000000 --- a/app/features/steps/signup.py +++ /dev/null @@ -1,105 +0,0 @@ -"""Define the behavior of sign up.""" -from unittest.mock import MagicMock, Mock, patch - -from behave import given, then, when -from models.account import User -from views.oauth import github_oauth_handler, spotify_oauth_handler - - -@given(u'the user entered an email and password.') -def step_impl(context): - context.email = 'sign.up@example.com' - context.password = 'stewartthis1isnotasecurepassword' - -@given(u'the user entered an invalid email.') -def step_impl(context): - context.email = 'not an email' - context.password = 'stewartthis1isnotasecurepassword' - -@given(u'the user entered an invalid password.') -def step_impl(context): - context.email = 'bad.sign.up@example.com' - context.password = 'password' - -@when(u'the user clicked the sign up button.') -def step_impl(context): - context.client.post('/users', data={ - "email": context.email, - "password": context.password, - }) - -@then(u'we should create an account for the user with the designated email.') -def step_impl(context): - with context.app.app_context(): - assert User.query.filter(User.email == context.email).first() is not None - -@then(u'we should not create an account for the user with the designated email.') -def step_impl(context): - with context.app.app_context(): - assert User.query.filter(User.email == context.email).first() is None - -@given(u'the user clicked the Github sign up button with Github account signed in.') -def step_impl(context): - res = context.client.get('/users/github') - assert res.status_code == 302 - assert res.headers['Location'].startswith( - 'https://github.com/login/oauth/authorize' - ) - -@when(u'approved on the Github OAuth authorization and called back to our website.') -def step_impl(context): - github_user_me = MagicMock() - github_user_me.data = {"email": "github@example.com"} - github_get = Mock(return_value=github_user_me) - github_authorized_response = Mock(return_value={ - "access_token": "some-token", - "scope": "", - "token_type": "bearer", - }) - with patch('app.github.get', github_get),\ - patch('app.github.authorized_response', github_authorized_response),\ - context.app.test_request_context( - '/callback/github?code=something' - ): - res = github_oauth_handler() - assert res.status_code == 302 - assert res.headers['Location'].endswith("/") - -@then(u'we should create an account for the user with the designated Github account.') -def step_impl(context): - with context.app.app_context(): - assert User.query.filter(User.email == "github@example.com").first() is not None - -@given(u'the user clicked the Spotify sign up button with Spotify account signed in.') -def step_impl(context): - res = context.client.get('/users/spotify') - assert res.status_code == 302 - assert res.headers['Location'].startswith( - 'https://accounts.spotify.com/authorize' - ) - -@when(u'approved on the Spotify OAuth authorization and called back to our website.') -def step_impl(context): - spotify_user_me = MagicMock() - spotify_user_me.data = {"email": "spotify@example.com"} - spotify_get = Mock(return_value=spotify_user_me) - spotify_authorized_response = Mock(return_value={ - "access_token": 'existing-token', - "scope": '', - "token_type": 'bearer', - "expires_in": 42, - "refresh_token": 'refresh-token', - }) - with patch('app.spotify.get', spotify_get),\ - patch('app.spotify.authorized_response', spotify_authorized_response),\ - context.app.test_request_context( - '/callback/spotify?code=something' - ): - res = spotify_oauth_handler() - assert res.status_code == 302 - assert res.headers['Location'].endswith("/") - -@then(u'we should create an account for the user with the designated Spotify account.') -def step_impl(context): - with context.app.app_context(): - assert User.query.filter(User.email == "spotify@example.com").first() is not None diff --git a/app/manage.py b/app/manage.py deleted file mode 100755 index 4b5b6b9..0000000 --- a/app/manage.py +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -from config import Config - -from flask_script import Manager, Server, Shell -from flask_migrate import MigrateCommand - -from app import create_app - -app = create_app() - -manager = Manager(app) - -manager.add_command('db', MigrateCommand) -manager.add_command("runserver", Server(host=Config.HOST, port=Config.PORT)) - -if __name__ == '__main__': - manager.run() diff --git a/app/migrations/README b/app/migrations/README deleted file mode 100755 index 98e4f9c..0000000 --- a/app/migrations/README +++ /dev/null @@ -1 +0,0 @@ -Generic single-database configuration. \ No newline at end of file diff --git a/app/migrations/alembic.ini b/app/migrations/alembic.ini deleted file mode 100644 index a91d116..0000000 --- a/app/migrations/alembic.ini +++ /dev/null @@ -1,45 +0,0 @@ -# A generic, single database configuration. - -[alembic] -# template used to generate migration files -file_template = %%(rev)s_%%(slug)s - -# set to 'true' to run the environment during -# the 'revision' command, regardless of autogenerate -revision_environment = true - - -# Logging configuration -[loggers] -keys = root,sqlalchemy,alembic - -[handlers] -keys = console - -[formatters] -keys = generic - -[logger_root] -level = WARN -handlers = console -qualname = - -[logger_sqlalchemy] -level = WARN -handlers = -qualname = sqlalchemy.engine - -[logger_alembic] -level = INFO -handlers = -qualname = alembic - -[handler_console] -class = StreamHandler -args = (sys.stderr,) -level = NOTSET -formatter = generic - -[formatter_generic] -format = %(levelname)-5.5s [%(name)s] %(message)s -datefmt = %H:%M:%S diff --git a/app/migrations/env.py b/app/migrations/env.py deleted file mode 100755 index 4593816..0000000 --- a/app/migrations/env.py +++ /dev/null @@ -1,87 +0,0 @@ -from __future__ import with_statement -from alembic import context -from sqlalchemy import engine_from_config, pool -from logging.config import fileConfig -import logging - -# this is the Alembic Config object, which provides -# access to the values within the .ini file in use. -config = context.config - -# Interpret the config file for Python logging. -# This line sets up loggers basically. -fileConfig(config.config_file_name) -logger = logging.getLogger('alembic.env') - -# add your model's MetaData object here -# for 'autogenerate' support -# from myapp import mymodel -# target_metadata = mymodel.Base.metadata -from flask import current_app -config.set_main_option('sqlalchemy.url', - current_app.config.get('SQLALCHEMY_DATABASE_URI')) -target_metadata = current_app.extensions['migrate'].db.metadata - -# other values from the config, defined by the needs of env.py, -# can be acquired: -# my_important_option = config.get_main_option("my_important_option") -# ... etc. - - -def run_migrations_offline(): - """Run migrations in 'offline' mode. - - This configures the context with just a URL - and not an Engine, though an Engine is acceptable - here as well. By skipping the Engine creation - we don't even need a DBAPI to be available. - - Calls to context.execute() here emit the given string to the - script output. - - """ - url = config.get_main_option("sqlalchemy.url") - context.configure(url=url) - - with context.begin_transaction(): - context.run_migrations() - - -def run_migrations_online(): - """Run migrations in 'online' mode. - - In this scenario we need to create an Engine - and associate a connection with the context. - - """ - - # this callback is used to prevent an auto-migration from being generated - # when there are no changes to the schema - # reference: http://alembic.readthedocs.org/en/latest/cookbook.html - def process_revision_directives(context, revision, directives): - if getattr(config.cmd_opts, 'autogenerate', False): - script = directives[0] - if script.upgrade_ops.is_empty(): - directives[:] = [] - logger.info('No changes in schema detected.') - - engine = engine_from_config(config.get_section(config.config_ini_section), - prefix='sqlalchemy.', - poolclass=pool.NullPool) - - connection = engine.connect() - context.configure(connection=connection, - target_metadata=target_metadata, - process_revision_directives=process_revision_directives, - **current_app.extensions['migrate'].configure_args) - - try: - with context.begin_transaction(): - context.run_migrations() - finally: - connection.close() - -if context.is_offline_mode(): - run_migrations_offline() -else: - run_migrations_online() diff --git a/app/migrations/script.py.mako b/app/migrations/script.py.mako deleted file mode 100755 index 9570201..0000000 --- a/app/migrations/script.py.mako +++ /dev/null @@ -1,22 +0,0 @@ -"""${message} - -Revision ID: ${up_revision} -Revises: ${down_revision} -Create Date: ${create_date} - -""" - -# revision identifiers, used by Alembic. -revision = ${repr(up_revision)} -down_revision = ${repr(down_revision)} - -from alembic import op -import sqlalchemy as sa -${imports if imports else ""} - -def upgrade(): - ${upgrades if upgrades else "pass"} - - -def downgrade(): - ${downgrades if downgrades else "pass"} diff --git a/app/migrations/versions/529df7cf5c9b_.py b/app/migrations/versions/529df7cf5c9b_.py deleted file mode 100644 index 1391f9b..0000000 --- a/app/migrations/versions/529df7cf5c9b_.py +++ /dev/null @@ -1,40 +0,0 @@ -"""empty message - -Revision ID: 529df7cf5c9b -Revises: e29c6a092c8f -Create Date: 2016-07-10 20:45:48.213523 - -""" - -# revision identifiers, used by Alembic. -revision = '529df7cf5c9b' -down_revision = 'e29c6a092c8f' - -from alembic import op -import sqlalchemy as sa - - -def upgrade(): - ### commands auto generated by Alembic - please adjust! ### - op.create_table('spotify_accesstoken', - sa.Column('id', sa.Integer(), nullable=False), - sa.Column('user_id', sa.Integer(), nullable=True), - sa.Column('access_token', sa.String(length=256), nullable=True), - sa.Column('token_type', sa.String(length=16), nullable=True), - sa.Column('scope', sa.String(length=64), nullable=True), - sa.Column('expires_in', sa.Integer(), nullable=True), - sa.Column('refresh_token', sa.String(length=256), nullable=True), - sa.Column('date_created', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=True), - sa.Column('date_updated', sa.DateTime(timezone=True), nullable=True), - sa.ForeignKeyConstraint(['user_id'], ['user.id'], ), - sa.PrimaryKeyConstraint('id'), - sa.UniqueConstraint('access_token'), - sa.UniqueConstraint('refresh_token') - ) - ### end Alembic commands ### - - -def downgrade(): - ### commands auto generated by Alembic - please adjust! ### - op.drop_table('spotify_accesstoken') - ### end Alembic commands ### diff --git a/app/migrations/versions/e29c6a092c8f_.py b/app/migrations/versions/e29c6a092c8f_.py deleted file mode 100644 index b44ae59..0000000 --- a/app/migrations/versions/e29c6a092c8f_.py +++ /dev/null @@ -1,47 +0,0 @@ -"""empty message - -Revision ID: e29c6a092c8f -Revises: None -Create Date: 2016-06-07 23:07:51.606522 - -""" - -# revision identifiers, used by Alembic. -revision = 'e29c6a092c8f' -down_revision = None - -from alembic import op -import sqlalchemy as sa - - -def upgrade(): - ### commands auto generated by Alembic - please adjust! ### - op.create_table('user', - sa.Column('id', sa.Integer(), nullable=False), - sa.Column('email', sa.String(length=32), nullable=True), - sa.Column('password_hash', sa.String(length=128), nullable=True), - sa.Column('date_created', sa.DateTime(timezone=True), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=True), - sa.Column('date_updated', sa.DateTime(timezone=True), nullable=True), - sa.PrimaryKeyConstraint('id'), - sa.UniqueConstraint('email') - ) - op.create_table('github_accesstoken', - sa.Column('id', sa.Integer(), nullable=False), - sa.Column('user_id', sa.Integer(), nullable=True), - sa.Column('token_type', sa.String(length=16), nullable=True), - sa.Column('scope', sa.String(length=64), nullable=True), - sa.Column('access_token', sa.String(length=40), nullable=True), - sa.Column('date_created', sa.DateTime(timezone=True), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=True), - sa.Column('date_updated', sa.DateTime(timezone=True), nullable=True), - sa.ForeignKeyConstraint(['user_id'], ['user.id'], ), - sa.PrimaryKeyConstraint('id'), - sa.UniqueConstraint('access_token') - ) - ### end Alembic commands ### - - -def downgrade(): - ### commands auto generated by Alembic - please adjust! ### - op.drop_table('github_accesstoken') - op.drop_table('user') - ### end Alembic commands ### diff --git a/app/models/__init__.py b/app/models/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/app/models/account.py b/app/models/account.py deleted file mode 100644 index 7c3006a..0000000 --- a/app/models/account.py +++ /dev/null @@ -1,63 +0,0 @@ -from validate_email import validate_email -import zxcvbn - -from flask_login import UserMixin -from passlib.apps import custom_app_context as pwd_context -from sqlalchemy.orm import validates -from sqlalchemy.sql import func - -from app import db, login_manager -from models.oauth import GithubAccessToken, SpotifyAccessToken -from exceptions import ValidationError - - -class User(db.Model, UserMixin): - """Represent a user model.""" - - __tablename__ = 'user' - id = db.Column(db.Integer, primary_key=True) - email = db.Column(db.String(32), unique=True) - password_hash = db.Column(db.String(128)) - - github_accesstoken = db.relationship(GithubAccessToken, uselist=False, back_populates="user") - spotify_accesstoken = db.relationship(SpotifyAccessToken, uselist=False, back_populates="user") - - date_created = db.Column(db.DateTime(timezone=True), server_default=func.now()) - date_updated = db.Column(db.DateTime(timezone=True), onupdate=func.now()) - - def __init__(self, email, password=None): - self.email = email - if password: - self.password_hash = password - - def __repr__(self): - return '' % (self.email) - - def verify_password(self, password): - """Check if the user's password is right.""" - if self.password_hash: - return pwd_context.verify(password, self.password_hash) - else: - return False - - @validates('email') - def validate_email(self, _, email): - """Validate the email.""" - if not validate_email(email): - raise ValidationError("Invaild email") - return email - - @validates('password_hash') - def validate_password(self, _, password): - """Validate the password if this is valid.""" - password_entropy = zxcvbn.password_strength(password)['entropy'] - if password_entropy < 20: - raise ValidationError("Password too weak") - password_hash = pwd_context.encrypt(password) - return password_hash - - -@login_manager.user_loader -def load_user(user_id): - """Load a user with the user id.""" - return User.query.get(user_id) diff --git a/app/models/oauth.py b/app/models/oauth.py deleted file mode 100644 index 0539e52..0000000 --- a/app/models/oauth.py +++ /dev/null @@ -1,62 +0,0 @@ -from sqlalchemy.sql import func - -from app import db - - -class GithubAccessToken(db.Model): - """Represent a Github access token.""" - - __tablename__ = 'github_accesstoken' - id = db.Column(db.Integer, primary_key=True) - user_id = db.Column(db.Integer, db.ForeignKey('user.id')) - user = db.relationship("User") - - token_type = db.Column(db.String(16)) - scope = db.Column(db.String(64)) - access_token = db.Column(db.String(256), unique=True) - - date_created = db.Column(db.DateTime(timezone=True), server_default=func.now()) - date_updated = db.Column(db.DateTime(timezone=True), onupdate=func.now()) - - def __init__(self, user_id, token_type, scope, access_token): - self.user_id = user_id - self.token_type = token_type - self.scope = scope - self.access_token = access_token - - def __repr__(self): - return ''.format( - self.access_token, - self.user - ) - -class SpotifyAccessToken(db.Model): - """Represent a Spotify access token.""" - - __tablename__ = 'spotify_accesstoken' - id = db.Column(db.Integer, primary_key=True) - user_id = db.Column(db.Integer, db.ForeignKey('user.id')) - user = db.relationship("User") - - access_token = db.Column(db.String(256), unique=True) - token_type = db.Column(db.String(16)) - scope = db.Column(db.String(64)) - expires_in = db.Column(db.Integer) - refresh_token = db.Column(db.String(256), unique=True) - - date_created = db.Column(db.DateTime(timezone=True), server_default=func.now()) - date_updated = db.Column(db.DateTime(timezone=True), onupdate=func.now()) - - def __init__(self, user_id, token_type, scope, access_token, expires_in, refresh_token): - self.user_id = user_id - self.token_type = token_type - self.scope = scope - self.access_token = access_token - self.expires_in = expires_in - self.refresh_token = refresh_token - - def __repr__(self): - return ''.format( - self.access_token, - self.user - ) diff --git a/app/views/__init__.py b/app/views/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/app/views/account.py b/app/views/account.py deleted file mode 100644 index cac3a64..0000000 --- a/app/views/account.py +++ /dev/null @@ -1,45 +0,0 @@ -"""Acconnt endpoints""" -from __future__ import absolute_import - -from flask import request -from flask_restful import fields, marshal, Resource -from flask_login import login_user - -from app import api, db -from models.account import User -from exceptions import ValidationError - - -user_fields = { - 'id': fields.Integer, - 'email': fields.String, - 'date_created': fields.DateTime, - 'date_updated': fields.DateTime, -} - -class UserResource(Resource): - """Define user RESTful endpoints.""" - - def get(self, user_id): - """Serve GET requests.""" - user = User.query.get_or_404(user_id) - return marshal(user, user_fields) - - def post(self): - """Serve POST requests.""" - try: - user = User( - email=request.form.get('email', ''), - password=request.form.get('password', '') - ) - except ValidationError as error: - return {'errors': error.message}, 400 - - db.session.add(user) - db.session.commit() - - login_user(user) - - return marshal(user, user_fields), 201 - -api.add_resource(UserResource, '/users', '/users/') diff --git a/app/views/authorization.py b/app/views/authorization.py deleted file mode 100644 index 55fde98..0000000 --- a/app/views/authorization.py +++ /dev/null @@ -1,27 +0,0 @@ -from __future__ import absolute_import -from flask import request -from flask_login import login_user, logout_user -from flask_restful import Resource - -from app import api -from models.account import User - - -class Authorize(Resource): - - def post(self): - user = User.query.filter(User.email == request.form.get('email')).first() - if user and user.verify_password(request.form.get('password')): - login_user(user) - return user.id - return {'message': 'Invaild authorization information given'}, 400 - -api.add_resource(Authorize, '/users/authorize') - -class Logout(Resource): - - def post(self): - logout_user() - return '' - -api.add_resource(Logout, '/users/logout') diff --git a/app/views/oauth.py b/app/views/oauth.py deleted file mode 100644 index ea2ae79..0000000 --- a/app/views/oauth.py +++ /dev/null @@ -1,123 +0,0 @@ -"""Implement OAuth callbacks.""" -from __future__ import absolute_import -from flask import Blueprint, request, session, url_for, flash, redirect -from flask_login import login_user, current_user - -from app import db, github, spotify -from models.account import GithubAccessToken, SpotifyAccessToken, User - -bp = Blueprint('oauth', __name__) - - -@bp.route('/users/github') -def github_auth(): - return github.authorize( - callback=url_for('oauth.github_oauth_handler', _external=True), - next=request.args.get('next') or request.referrer - ) - -@github.tokengetter -def get_github_token(): - if current_user.is_authenticated: - access_token = current_user.github_accesstoken.access_token - else: - access_token = session.get('github_accesstoken') - return (access_token, "") - -@bp.route('/callback/github') -@github.authorized_handler -def github_oauth_handler(response): - next_url = request.args.get('next') or url_for('app.index') - - if response is None or not response.get('access_token'): - flash(u'You denied the request to sign in') - return redirect(next_url) - - session['github_accesstoken'] = response.get('access_token') - github_user = github.get('user').data - - user = User.query.filter(User.email == github_user.get('email')).first() - if not user: - # Create the user object if the user wasn't signed up. - user = User(github_user.get('email')) - db.session.add(user) - db.session.commit() - - # Save the token for the user. - github_accesstoken = GithubAccessToken( - user.id, - github_user.get('token_type'), - github_user.get('scope'), - github_user.get('access_token'), - ) - db.session.add(github_accesstoken) - db.session.commit() - else: - # Get the access token and change it. - github_accesstoken = user.github_accesstoken - github_accesstoken.token_type = github_user.get('token_type') - github_accesstoken.scope = github_user.get('scope') - github_accesstoken.access_token = github_user.get('access_token') - - login_user(github_accesstoken.user) - - return redirect(next_url) - -@bp.route('/users/spotify') -def spotify_auth(): - return spotify.authorize( - callback=url_for('oauth.spotify_oauth_handler', _external=True), - next=request.args.get('next') or request.referrer - ) - -@spotify.tokengetter -def get_spotify_token(): - if current_user.is_authenticated: - access_token = current_user.spotify_accesstoken.access_token - else: - access_token = session.get('spotify_accesstoken') - return (access_token, "") - -@bp.route('/callback/spotify') -@spotify.authorized_handler -def spotify_oauth_handler(response): - next_url = request.args.get('next') or url_for('app.index') - - if response is None or not response.get('access_token'): - flash(u'You denied the request to sign in') - return redirect(next_url) - - session['spotify_accesstoken'] = response.get('access_token') - spotify_user = spotify.get('/v1/me').data - - user = User.query.filter(User.email == spotify_user.get('email')).first() - if not user: - # Create the user object if the user wasn't signed up. - user = User(spotify_user.get('email')) - db.session.add(user) - db.session.commit() - - if user.spotify_accesstoken: - # Get the access token and change it. - spotify_accesstoken = user.spotify_accesstoken - spotify_accesstoken.token_type = response.get('token_type') - spotify_accesstoken.scope = response.get('scope') - spotify_accesstoken.access_token = response.get('access_token') - spotify_accesstoken.expires_in = response.get('expires_in') - spotify_accesstoken.refresh_token = response.get('refresh_token') - else: - # Save the token for the user. - spotify_accesstoken = SpotifyAccessToken ( - user.id, - spotify_user.get('token_type'), - spotify_user.get('scope'), - spotify_user.get('access_token'), - spotify_user.get('expires_in'), - spotify_user.get('refresh_token'), - ) - db.session.add(spotify_accesstoken) - db.session.commit() - - login_user(spotify_accesstoken.user) - - return redirect(next_url) diff --git a/circle.yml b/circle.yml deleted file mode 100644 index 318e73e..0000000 --- a/circle.yml +++ /dev/null @@ -1,35 +0,0 @@ -machine: - timezone: - America/Los_Angeles - services: - - docker - python: - version: - 3.5.1 - environment: - ENV: testing - -checkout: - post: - - git submodule sync --recursive - - git submodule update --recursive --init - -dependencies: - override: - - npm install - - pip install -r requirements.txt - - gem install sass - -test: - override: - - coverage run --source='.' -m behave - post: - - pip install codecov && codecov - -deployment: - production: - branch: master - commands: - - docker login -e $DOCKER_EMAIL -p $DOCKER_PASS -u $DOCKER_NAME - - docker build -t gitplaylist/gitplaylist:${CIRCLE_SHA} -t gitplaylist/gitplaylist:latest . - - docker push gitplaylist/gitplaylist:latest diff --git a/codecov.yml b/codecov.yml deleted file mode 100644 index da147b5..0000000 --- a/codecov.yml +++ /dev/null @@ -1,27 +0,0 @@ -coverage: - precision: 2 - round: down - range: "70...95" - status: - project: - default: - enabled: yes - target: auto - if_no_uploads: error - patch: - default: - enabled: yes - target: 100% - if_no_uploads: error - changes: - default: - enabled: yes - if_no_uploads: error - notify: - slack: - default: - url: https://hooks.slack.com/services/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 - attachments: "sunburst, diff" -comment: - layout: "header, diff, changes, sunburst, uncovered" - behavior: default diff --git a/pre-commit.sh b/pre-commit.sh deleted file mode 100755 index 0ba6901..0000000 --- a/pre-commit.sh +++ /dev/null @@ -1,112 +0,0 @@ -#!/usr/bin/env python - -import os -import re -import subprocess -import sys - -MODIFIED = re.compile(r'^[MA]\s+(?P.*)$') - -CHECKS = [ - { - 'output': 'Checking for pdbs...', - 'command': 'grep -n "import pdb" %s', - 'ignore_files': ['.*pre-commit'], - }, - { - 'output': 'Checking for ipdbs...', - 'command': 'grep -n "import ipdb" %s', - 'ignore_files': ['.*pre-commit'], - }, - { - 'output': 'Checking for console.log()...', - 'command': 'grep -n console.log %s', - 'match_files': [r'.*yipit/.*\.js$'], - }, - { - 'output': 'Checking for debugger...', - 'command': 'grep -n debugger %s', - 'match_files': [r'.*\.js$'], - }, - { - 'output': 'Running Jshint...', - # By default, jshint prints 'Lint Free!' upon success. We want to filter this out. - 'command': 'jshint %s | grep -v "Lint Free!"', - 'match_files': [r'.*yipit/.*\.js$'], - }, - { - 'output': 'Running pylint...', - 'command': r'pylint --output-format=colorized --reports=no --disable=C -- %s', - 'match_files': [r'.*\.py$'], - }, - { - 'output': 'Running htmlhint...', - 'command': r'htmlhint --config .htmlhintrc %s', - 'match_files': [r'.*\.html$'], - }, - { - 'output': 'Running sass-lint...', - 'command': 'sass-lint %s', - 'match_files': [r'.*\.scss$'], - }, -] - - -def matches_file(file_name, match_files): - return any(re.compile(match_file).match(file_name) for match_file in match_files) - - -def check_files(files, check): - result = 0 - print(check['output']) - for file_name in files: - if not 'match_files' in check or matches_file(file_name, check['match_files']): - if not 'ignore_files' in check or not matches_file(file_name, check['ignore_files']): - process = subprocess.Popen(check['command'] % file_name, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) - out, err = process.communicate() - if out or err: - if check.get('print_filename', True): - prefix = '\t%s:' % file_name - else: - prefix = '\t' - output_lines = ['%s%s' % (prefix, line) for line in out.splitlines()] - print('\n'.join(output_lines)) - if err: - print(err) - result = 1 - return result - - -def main(all_files): - # Stash any changes to the working tree that are not going to be committed - subprocess.call(['git', 'stash', '-u', '--keep-index'], stdout=subprocess.PIPE) - - files = [] - if all_files: - for root, _, file_names in os.walk('.'): - for file_name in file_names: - files.append(os.path.join(root, file_name)) - else: - p = subprocess.Popen(['git', 'status', '--porcelain'], stdout=subprocess.PIPE) - out, _ = p.communicate() - for line in out.splitlines(): - match = MODIFIED.match(line.decode('utf-8')) - if match: - files.append(match.group('name')) - - result = 0 - - for check in CHECKS: - result = check_files(files, check) or result - - # Unstash changes to the working tree that we had stashed - subprocess.call(['git', 'reset', '--hard'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) - subprocess.call(['git', 'stash', 'pop', '--quiet', '--index'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) - sys.exit(result) - - -if __name__ == '__main__': - all_files = False - if len(sys.argv) > 1 and sys.argv[1] == '--all-files': - all_files = True - main(all_files) diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 94e27a9..0000000 --- a/requirements.txt +++ /dev/null @@ -1,52 +0,0 @@ -alembic==0.8.6 -aniso8601==1.1.0 -astroid==1.4.6 -behave==1.2.5 -colorama==0.3.7 -coverage==4.1 -dnspython3==1.12.0 -enum34==1.1.6 -Flask==0.11.1 -Flask-Assets==0.11 -Flask-Login==0.3.2 -Flask-Migrate==1.8.0 -Flask-Passlib==0.1 -Flask-RESTful==0.3.5 -Flask-Script==2.0.5 -Flask-SQLAlchemy==2.1 -Flask-OAuthlib==0.9.3 -idna==2.1 -isbnlib==3.6.1 -iso3166==0.7 -itsdangerous==0.24 -Jinja2==2.8 -lazy-object-proxy==1.2.2 -logilab-common==1.2.2 -Mako==1.0.4 -MarkupSafe==0.23 -parse==1.6.6 -parse-type==0.3.4 -passlib==1.6.5 -pathlib==1.0.1 -psycopg2==2.6.1 -py-moneyed==0.6.0 -pylint==1.5.6 -pylint-flask==0.3 -pylint-plugin-utils==0.2.3 -pylint-mccabe==0.1.3 -pyScss==1.3.5 -python-dateutil==2.5.3 -python-editor==1.0.1 --e git+https://github.com/moreati/python-zxcvbn#egg=zxcvbn -pytz==2016.4 -PyYAML==3.11 -six==1.10.0 -SQLAlchemy==1.0.13 -validate-email==1.3 -webassets==0.11.1 -webassets-babel==0.3.0 -webassets-browserify==1.1.0 -Werkzeug==0.11.10 -wrapt==1.10.8 -Werkzeug==0.11.11 -flask-cors==3.0.2 diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..b021b7a --- /dev/null +++ b/src/main.rs @@ -0,0 +1,65 @@ +#[macro_use] +extern crate rustless; +extern crate hyper; +extern crate iron; +extern crate rustc_serialize as serialize; +extern crate valico; + +use valico::json_dsl; +use hyper::status::StatusCode; +use rustless::{ + Application, Api, Nesting, Versioning +}; +use rustless::json::ToJson; + +fn main() { + + let api = Api::build(|api| { + // Specify API version + api.version("v1", Versioning::AcceptHeader("chat")); + api.prefix("api"); + + // Create API for chats + api.mount(Api::build(|chats_api| { + + chats_api.after(|client, _params| { + client.set_status(StatusCode::NotFound); + Ok(()) + }); + + // Add namespace + chats_api.namespace("chats/:id", |chat_ns| { + + // Valico settings for this namespace + chat_ns.params(|params| { + params.req_typed("id", json_dsl::u64()) + }); + + // Create endpoint for POST /chats/:id/users/:user_id + chat_ns.post("users/:user_id", |endpoint| { + + // Add description + endpoint.desc("Update user"); + + // Valico settings for endpoint params + endpoint.params(|params| { + params.req_typed("user_id", json_dsl::u64()); + params.req_typed("id", json_dsl::string()) + }); + + endpoint.handle(|client, params| { + client.json(¶ms.to_json()) + }) + }); + + }); + })); + }); + + let app = Application::new(api); + + iron::Iron::new(app).http("0.0.0.0:4000").unwrap(); + println!("On 4000"); + + println!("Rustless server started!"); +}