Starting to get the project set up. Nothing is even nearly complete yet.
This commit is contained in:
		
						commit
						b6a24bc1ce
					
				
							
								
								
									
										28
									
								
								Capstanfile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								Capstanfile
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,28 @@ | ||||||
|  | 
 | ||||||
|  | # | ||||||
|  | # Name of the base image. Capstan will download this automatically from | ||||||
|  | # Cloudius S3 repository. | ||||||
|  | # | ||||||
|  | #base: cloudius/osv | ||||||
|  | base: cloudius/osv-openjdk8 | ||||||
|  | 
 | ||||||
|  | # | ||||||
|  | # The command line passed to OSv to start up the application. | ||||||
|  | # | ||||||
|  | cmdline: /java.so -jar /youyesyet/app.jar | ||||||
|  | 
 | ||||||
|  | # | ||||||
|  | # The command to use to build the application. | ||||||
|  | # You can use any build tool/command (make/rake/lein/boot) - this runs locally on your machine | ||||||
|  | # | ||||||
|  | # For Leiningen, you can use: | ||||||
|  | #build: lein uberjar | ||||||
|  | # For Boot, you can use: | ||||||
|  | #build: boot build | ||||||
|  | 
 | ||||||
|  | # | ||||||
|  | # List of files that are included in the generated image. | ||||||
|  | # | ||||||
|  | files: | ||||||
|  |   /youyesyet/app.jar: ./target/uberjar/youyesyet.jar | ||||||
|  | 
 | ||||||
							
								
								
									
										8
									
								
								Dockerfile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								Dockerfile
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,8 @@ | ||||||
|  | FROM java:8-alpine | ||||||
|  | MAINTAINER Your Name <you@example.com> | ||||||
|  | 
 | ||||||
|  | ADD target/uberjar/youyesyet.jar /youyesyet/app.jar | ||||||
|  | 
 | ||||||
|  | EXPOSE 3000 | ||||||
|  | 
 | ||||||
|  | CMD ["java", "-jar", "/youyesyet/app.jar"] | ||||||
							
								
								
									
										258
									
								
								LICENSE
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										258
									
								
								LICENSE
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,258 @@ | ||||||
|  | # GNU GENERAL PUBLIC LICENSE | ||||||
|  | 
 | ||||||
|  | Version 2, June 1991 | ||||||
|  | 
 | ||||||
|  | Copyright (C) 1989, 1991 Free Software Foundation, Inc.   | ||||||
|  | 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA | ||||||
|  | 
 | ||||||
|  | Everyone is permitted to copy and distribute verbatim copies | ||||||
|  | of this license document, but changing it is not allowed. | ||||||
|  | Preamble | ||||||
|  | 
 | ||||||
|  | The licenses for most software are designed to take away your freedom to share  | ||||||
|  | and change it. By contrast, the GNU General Public License is intended to guarantee  | ||||||
|  | your freedom to share and change free software--to make sure the software is free  | ||||||
|  | for all its users. This General Public License applies to most of the Free  | ||||||
|  | Software Foundation's software and to any other program whose authors commit to  | ||||||
|  | using it. (Some other Free Software Foundation software is covered by the GNU  | ||||||
|  | Lesser General Public License instead.) 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 this service 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 make restrictions that forbid anyone to  | ||||||
|  | deny you these rights or to ask you to surrender the rights. These restrictions  | ||||||
|  | translate to certain responsibilities for you if you distribute copies of the  | ||||||
|  | software, or if you modify it. | ||||||
|  | 
 | ||||||
|  | For example, if you distribute copies of such a program, whether gratis or for  | ||||||
|  | a fee, you must give the recipients all the rights that you have. 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. | ||||||
|  | 
 | ||||||
|  | We protect your rights with two steps: (1) copyright the software, and (2)  | ||||||
|  | offer you this license which gives you legal permission to copy, distribute  | ||||||
|  | and/or modify the software. | ||||||
|  | 
 | ||||||
|  | Also, for each author's protection and ours, we want to make certain that  | ||||||
|  | everyone understands that there is no warranty for this free software. If the  | ||||||
|  | software is modified by someone else and passed on, we want its recipients to  | ||||||
|  | know that what they have is not the original, so that any problems introduced  | ||||||
|  | by others will not reflect on the original authors' reputations. | ||||||
|  | 
 | ||||||
|  | Finally, any free program is threatened constantly by software patents. We wish  | ||||||
|  | to avoid the danger that redistributors of a free program will individually  | ||||||
|  | obtain patent licenses, in effect making the program proprietary. To prevent  | ||||||
|  | this, we have made it clear that any patent must be licensed for everyone's  | ||||||
|  | free use or not licensed at all. | ||||||
|  | 
 | ||||||
|  | The precise terms and conditions for copying, distribution and modification follow. | ||||||
|  | 
 | ||||||
|  | ## TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION | ||||||
|  | 
 | ||||||
|  | 0. 	This License applies to any program or other work which contains a notice  | ||||||
|  | 	placed by the copyright holder saying it may be distributed under the terms of  | ||||||
|  | 	this General Public License. The "Program", below, refers to any such program  | ||||||
|  | 	or work, and a "work based on the Program" means either the Program or any  | ||||||
|  | 	derivative work under copyright law: that is to say, a work containing the  | ||||||
|  | 	Program or a portion of it, either verbatim or with modifications and/or  | ||||||
|  | 	translated into another language. (Hereinafter, translation is included without  | ||||||
|  | 	limitation in the term "modification".) Each licensee is addressed as "you". | ||||||
|  | 	 | ||||||
|  | 	Activities other than copying, distribution and modification are not covered by  | ||||||
|  | 	this License; they are outside its scope. The act of running the Program is not  | ||||||
|  | 	restricted, and the output from the Program is covered only if its contents  | ||||||
|  | 	constitute a work based on the Program (independent of having been made by  | ||||||
|  | 	running the Program). Whether that is true depends on what the Program does. | ||||||
|  | 
 | ||||||
|  | 1. 	You may copy and distribute 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 and disclaimer of warranty;  | ||||||
|  | 	keep intact all the notices that refer to this License and to the absence of any  | ||||||
|  | 	warranty; and give any other recipients of the Program a copy of this License  | ||||||
|  | 	along with the Program. | ||||||
|  | 	 | ||||||
|  | 	You may charge a fee for the physical act of transferring a copy, and you may at  | ||||||
|  | 	your option offer warranty protection in exchange for a fee. | ||||||
|  | 	 | ||||||
|  | 2. 	You may modify your copy or copies of the Program or any portion of it, thus  | ||||||
|  | 	forming a work based on the Program, and copy and distribute such modifications  | ||||||
|  | 	or work under the terms of Section 1 above, provided that you also meet all of  | ||||||
|  | 	these conditions: | ||||||
|  | 	 | ||||||
|  | 	a) You must cause the modified files to carry prominent notices stating that  | ||||||
|  | 	   you changed the files and the date of any change. | ||||||
|  | 	b) You must cause any work that you distribute or publish, that in whole or in  | ||||||
|  | 	   part contains or is derived from the Program or any part thereof, to be  | ||||||
|  | 	   licensed as a whole at no charge to all third parties under the terms of this  | ||||||
|  | 	   License. | ||||||
|  | 	c) If the modified program normally reads commands interactively when run, you | ||||||
|  | 	   must cause it, when started running for such interactive use in the most  | ||||||
|  | 	   ordinary way, to print or display an announcement including an appropriate  | ||||||
|  | 	   copyright notice and a notice that there is no warranty (or else, saying  | ||||||
|  | 	   that you provide a warranty) and that users may redistribute the program  | ||||||
|  | 	   under these conditions, and telling the user how to view a copy of this  | ||||||
|  | 	   License. (Exception: if the Program itself is interactive but does not  | ||||||
|  | 	   normally print such an announcement, your work based on the Program is not  | ||||||
|  | 	   required to print an announcement.) | ||||||
|  | 	    | ||||||
|  | 	These requirements apply to the modified work as a whole. If identifiable  | ||||||
|  | 	sections of that work are not derived from the Program, and can be reasonably  | ||||||
|  | 	considered independent and separate works in themselves, then this License,  | ||||||
|  | 	and its terms, do not apply to those sections when you distribute them as  | ||||||
|  | 	separate works. But when you distribute the same sections as part of a whole  | ||||||
|  | 	which is a work based on the Program, the distribution of the whole must be on  | ||||||
|  | 	the terms of this License, whose permissions for other licensees extend to the  | ||||||
|  | 	entire whole, and thus to each and every part regardless of who wrote it. | ||||||
|  | 	 | ||||||
|  | 	Thus, it is not the intent of this section to claim rights or contest your  | ||||||
|  | 	rights to work written entirely by you; rather, the intent is to exercise the  | ||||||
|  | 	right to control the distribution of derivative or collective works based on  | ||||||
|  | 	the Program. | ||||||
|  | 	 | ||||||
|  | 	In addition, mere aggregation of another work not based on the Program with the  | ||||||
|  | 	Program (or with a work based on the Program) on a volume of a storage or  | ||||||
|  | 	distribution medium does not bring the other work under the scope of this  | ||||||
|  | 	License. | ||||||
|  | 	 | ||||||
|  | 	3. You may copy and distribute the Program (or a work based on it, under  | ||||||
|  | 	Section 2) in object code or executable form under the terms of Sections 1  | ||||||
|  | 	and 2 above provided that you also do one of the following: | ||||||
|  | 	 | ||||||
|  | 	a) Accompany it with the complete corresponding machine-readable source code,  | ||||||
|  | 	   which must be distributed under the terms of Sections 1 and 2 above on a  | ||||||
|  | 	   medium customarily used for software interchange; or, | ||||||
|  | 	b) Accompany it with a written offer, valid for at least three years, to give | ||||||
|  | 	   any third party, for a charge no more than your cost of physically  | ||||||
|  | 	   performing source distribution, a complete machine-readable copy of the  | ||||||
|  | 	   corresponding source code, to be distributed under the terms of Sections 1  | ||||||
|  | 	   and 2 above on a medium customarily used for software interchange; or, | ||||||
|  | 	c) Accompany it with the information you received as to the offer to distribute | ||||||
|  | 	   corresponding source code. (This alternative is allowed only for  | ||||||
|  | 	   noncommercial distribution and only if you received the program in object  | ||||||
|  | 	   code or executable form with such an offer, in accord with Subsection b  | ||||||
|  | 	   above.) | ||||||
|  |     | ||||||
|  | 	The source code for a work means the preferred form of the work for making  | ||||||
|  | 	modifications to it. For an executable work, complete source code means all the  | ||||||
|  | 	source code for all modules it contains, plus any associated interface  | ||||||
|  | 	definition files, plus the scripts used to control compilation and installation  | ||||||
|  | 	of the executable. However, as a special exception, the source code distributed  | ||||||
|  | 	need not include anything that is normally distributed (in either source or  | ||||||
|  | 	binary form) with the major components (compiler, kernel, and so on) of the  | ||||||
|  | 	operating system on which the executable runs, unless that component itself  | ||||||
|  | 	accompanies the executable. | ||||||
|  | 	 | ||||||
|  | 	If distribution of executable or object code is made by offering access to  | ||||||
|  | 	copy from a designated place, then offering equivalent access to copy the  | ||||||
|  | 	source code from the same place counts as distribution of the source code,  | ||||||
|  | 	even though third parties are not compelled to copy the source along with the  | ||||||
|  | 	object code. | ||||||
|  | 
 | ||||||
|  | 4. 	You may not copy, modify, sublicense, or distribute the Program except as  | ||||||
|  | 	expressly provided under this License. Any attempt otherwise to copy, modify,  | ||||||
|  | 	sublicense or distribute the Program is void, and will automatically  | ||||||
|  | 	terminate your rights under this License. However, parties who have  | ||||||
|  | 	received copies, or rights, from you under this License will not have their  | ||||||
|  | 	licenses terminated so long as such parties remain in full compliance. | ||||||
|  | 
 | ||||||
|  | 5. 	You are not required to accept this License, since you have not signed it.  | ||||||
|  | 	However, nothing else grants you permission to modify or distribute the  | ||||||
|  | 	Program or its derivative works. These actions are prohibited by law if  | ||||||
|  | 	you do not accept this License. Therefore, by modifying or distributing  | ||||||
|  | 	the Program (or any work based on the Program), you indicate your  | ||||||
|  | 	acceptance of this License to do so, and all its terms and conditions  | ||||||
|  | 	for copying, distributing or modifying the Program or works based on it. | ||||||
|  | 
 | ||||||
|  | 6. 	Each time you redistribute the Program (or any work based on the Program),  | ||||||
|  | 	the recipient automatically receives a license from the original licensor | ||||||
|  | 	to copy, distribute or modify the Program subject to these terms and  | ||||||
|  | 	conditions. You may not impose any further restrictions on the recipients'  | ||||||
|  | 	exercise of the rights granted herein. You are not responsible for enforcing  | ||||||
|  | 	compliance by third parties to this License. | ||||||
|  | 
 | ||||||
|  | 7.  If, as a consequence of a court judgment or allegation of patent infringement  | ||||||
|  | 	or for any other reason (not limited to patent issues), 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 distribute so as to satisfy  | ||||||
|  | 	simultaneously your obligations under this License and any other pertinent  | ||||||
|  | 	obligations, then as a consequence you may not distribute the Program at  | ||||||
|  | 	all. For example, if a patent license would not permit royalty-free  | ||||||
|  | 	redistribution of the Program by all those who receive copies directly or  | ||||||
|  | 	indirectly through you, then the only way you could satisfy both it and  | ||||||
|  | 	this License would be to refrain entirely from distribution of the Program. | ||||||
|  | 
 | ||||||
|  | 	If any portion of this section is held invalid or unenforceable under any  | ||||||
|  | 	particular circumstance, the balance of the section is intended to apply  | ||||||
|  | 	and the section as a whole is intended to apply in other circumstances. | ||||||
|  | 
 | ||||||
|  | 	It is not the purpose of this section to induce you to infringe any patents  | ||||||
|  | 	or other property right claims or to contest validity of any such claims;  | ||||||
|  | 	this section has the sole purpose of protecting the integrity of the free  | ||||||
|  | 	software distribution system, which is implemented by public license  | ||||||
|  | 	practices. Many people have made generous contributions to the wide range  | ||||||
|  | 	of software distributed through that system in reliance on consistent  | ||||||
|  | 	application of that system; it is up to the author/donor to decide if he or  | ||||||
|  | 	she is willing to distribute software through any other system and a  | ||||||
|  | 	licensee cannot impose that choice. | ||||||
|  | 	 | ||||||
|  | 	This section is intended to make thoroughly clear what is believed to be a  | ||||||
|  | 	consequence of the rest of this License. | ||||||
|  | 	 | ||||||
|  | 8. 	If the distribution and/or use of the Program is restricted in certain  | ||||||
|  | 	countries either by patents or by copyrighted interfaces, the original  | ||||||
|  | 	copyright holder who places the Program under this License may add an  | ||||||
|  | 	explicit geographical distribution limitation excluding those countries,  | ||||||
|  | 	so that distribution is permitted only in or among countries not thus  | ||||||
|  | 	excluded. In such case, this License incorporates the limitation as if  | ||||||
|  | 	written in the body of this License. | ||||||
|  | 
 | ||||||
|  | 9. 	The Free Software Foundation may publish revised and/or new versions of the  | ||||||
|  | 	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 a version number of this License which applies to it and  | ||||||
|  | 	"any later version", you have the option of following the terms and  | ||||||
|  | 	conditions either of that version or of any later version published  | ||||||
|  | 	by the Free Software Foundation. If the Program does not specify a version  | ||||||
|  | 	number of this License, you may choose any version ever published by the  | ||||||
|  | 	Free Software Foundation. | ||||||
|  | 
 | ||||||
|  | 10. If you wish to incorporate parts of the Program into other free programs  | ||||||
|  | 	whose distribution conditions are different, write to the author to ask for  | ||||||
|  | 	permission. For software which is copyrighted by the Free Software  | ||||||
|  | 	Foundation, write to the Free Software Foundation; we sometimes make  | ||||||
|  | 	exceptions for this. Our decision will be guided by the two goals of  | ||||||
|  | 	preserving the free status of all derivatives of our free software and of  | ||||||
|  | 	promoting the sharing and reuse of software generally. | ||||||
|  | 
 | ||||||
|  | NO WARRANTY | ||||||
|  | 
 | ||||||
|  | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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. | ||||||
|  | 
 | ||||||
|  | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL  | ||||||
|  | 	ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE | ||||||
|  | 	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. | ||||||
|  | 
 | ||||||
|  | END OF TERMS AND CONDITIONS | ||||||
							
								
								
									
										1
									
								
								Procfile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								Procfile
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1 @@ | ||||||
|  | web: java $JVM_OPTS -cp target/uberjar/youyesyet.jar clojure.main -m youyesyet.core | ||||||
							
								
								
									
										28
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,28 @@ | ||||||
|  | # youyesyet | ||||||
|  | 
 | ||||||
|  | A web-app intended to be used by canvassers campaigning for a 'Yes' vote in the second independence referendum. | ||||||
|  | 
 | ||||||
|  | The web-app will be delivered to canvassers out knocking doors primarily through an HTML5/React single-page app; it's possible that someone else may do an Android of iPhone native app to address the same back end but at present I have no plans for this. | ||||||
|  | 
 | ||||||
|  | There must also be an administrative interface through which privileged users can set the system up and authorise canvassers, and a 'followup' interface through which issue-expert specialist canvassers can address particular electors' queries. | ||||||
|  | 
 | ||||||
|  | generated using Luminus version "2.9.11.05" | ||||||
|  | 
 | ||||||
|  | ## Prerequisites | ||||||
|  | 
 | ||||||
|  | You will need [Leiningen][1] 2.0 or above installed. The database required must be [Postgres][2]. | ||||||
|  | 
 | ||||||
|  | [1]: https://github.com/technomancy/leiningen | ||||||
|  | [2]: https://www.postgresql.org/ | ||||||
|  | 
 | ||||||
|  | ## Running | ||||||
|  | 
 | ||||||
|  | To start a web server for the application, run: | ||||||
|  | 
 | ||||||
|  |     lein run | ||||||
|  | 
 | ||||||
|  | ## License | ||||||
|  | 
 | ||||||
|  | Copyright © 2016 Simon Brooke for the Radical Independence Campaign. | ||||||
|  | 
 | ||||||
|  | Licensed under the GNU General Public License, version 2.0 or (at your option) any later version. | ||||||
							
								
								
									
										
											BIN
										
									
								
								dummies/mapview.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								dummies/mapview.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 3.8 MiB | 
							
								
								
									
										4874
									
								
								dummies/mapview.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4874
									
								
								dummies/mapview.svg
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							| After Width: | Height: | Size: 350 KiB | 
							
								
								
									
										
											BIN
										
									
								
								dummies/mapview.xcf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								dummies/mapview.xcf
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								dummies/mapview_800.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								dummies/mapview_800.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 665 KiB | 
							
								
								
									
										
											BIN
										
									
								
								dummies/mapview_800.xcf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								dummies/mapview_800.xcf
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								dummies/occupants.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								dummies/occupants.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 359 KiB | 
							
								
								
									
										454
									
								
								dummies/occupants.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										454
									
								
								dummies/occupants.svg
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,454 @@ | ||||||
|  | <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||||||
|  | <!-- Created with Inkscape (http://www.inkscape.org/) --> | ||||||
|  | 
 | ||||||
|  | <svg | ||||||
|  |    xmlns:dc="http://purl.org/dc/elements/1.1/" | ||||||
|  |    xmlns:cc="http://creativecommons.org/ns#" | ||||||
|  |    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | ||||||
|  |    xmlns:svg="http://www.w3.org/2000/svg" | ||||||
|  |    xmlns="http://www.w3.org/2000/svg" | ||||||
|  |    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||||||
|  |    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||||||
|  |    width="210mm" | ||||||
|  |    height="297mm" | ||||||
|  |    viewBox="0 0 744.09448819 1052.3622047" | ||||||
|  |    id="svg4435" | ||||||
|  |    version="1.1" | ||||||
|  |    inkscape:version="0.91 r13725" | ||||||
|  |    sodipodi:docname="occupants.svg" | ||||||
|  |    inkscape:export-filename="/home/simon/workspace/youyesyet/dummies/occupants.png" | ||||||
|  |    inkscape:export-xdpi="300" | ||||||
|  |    inkscape:export-ydpi="300"> | ||||||
|  |   <defs | ||||||
|  |      id="defs4437" /> | ||||||
|  |   <sodipodi:namedview | ||||||
|  |      id="base" | ||||||
|  |      pagecolor="#ffffff" | ||||||
|  |      bordercolor="#666666" | ||||||
|  |      borderopacity="1.0" | ||||||
|  |      inkscape:pageopacity="0.0" | ||||||
|  |      inkscape:pageshadow="2" | ||||||
|  |      inkscape:zoom="0.7" | ||||||
|  |      inkscape:cx="51.779153" | ||||||
|  |      inkscape:cy="490.59499" | ||||||
|  |      inkscape:document-units="px" | ||||||
|  |      inkscape:current-layer="layer1" | ||||||
|  |      showgrid="true" | ||||||
|  |      inkscape:window-width="1920" | ||||||
|  |      inkscape:window-height="996" | ||||||
|  |      inkscape:window-x="0" | ||||||
|  |      inkscape:window-y="28" | ||||||
|  |      inkscape:window-maximized="1"> | ||||||
|  |     <inkscape:grid | ||||||
|  |        type="xygrid" | ||||||
|  |        id="grid4987" /> | ||||||
|  |   </sodipodi:namedview> | ||||||
|  |   <metadata | ||||||
|  |      id="metadata4440"> | ||||||
|  |     <rdf:RDF> | ||||||
|  |       <cc:Work | ||||||
|  |          rdf:about=""> | ||||||
|  |         <dc:format>image/svg+xml</dc:format> | ||||||
|  |         <dc:type | ||||||
|  |            rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | ||||||
|  |         <dc:title></dc:title> | ||||||
|  |       </cc:Work> | ||||||
|  |     </rdf:RDF> | ||||||
|  |   </metadata> | ||||||
|  |   <g | ||||||
|  |      inkscape:label="Layer 1" | ||||||
|  |      inkscape:groupmode="layer" | ||||||
|  |      id="layer1"> | ||||||
|  |     <rect | ||||||
|  |        style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2.4000001;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" | ||||||
|  |        id="rect5308" | ||||||
|  |        width="700" | ||||||
|  |        height="1020" | ||||||
|  |        x="20" | ||||||
|  |        y="12.362205" /> | ||||||
|  |     <text | ||||||
|  |        xml:space="preserve" | ||||||
|  |        style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:45px;line-height:125%;font-family:'Arial Black';-inkscape-font-specification:'Arial Black, ';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | ||||||
|  |        x="81.428566" | ||||||
|  |        y="85.219345" | ||||||
|  |        id="text4983" | ||||||
|  |        sodipodi:linespacing="125%"><tspan | ||||||
|  |          sodipodi:role="line" | ||||||
|  |          id="tspan4985" | ||||||
|  |          x="81.428566" | ||||||
|  |          y="85.219345">43 Imaginary Terrace</tspan></text> | ||||||
|  |     <path | ||||||
|  |        style="fill:#808080;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | ||||||
|  |        d="m 151.42857,208.07649 c 0,0 -22.38786,-25.28537 -20,-40 3.02043,-18.6127 21.14382,-40 40,-40 18.85618,0 36.97957,21.3873 40,40 2.38786,14.71463 -20,40 -20,40 0,0 12.56519,-3.0796 20,0 7.43481,3.0796 9.36405,0.69304 20,20 10.63595,19.30696 22.85714,101.42857 22.85714,101.42857 l -20,0 -22.85714,-81.42857 0,78.57143 20,161.42857 -40,0 -20,-120 -20,120 -40,0 17.14286,-158.57143 2.85714,-81.42857 -17.14286,80 -19.999998,0 c 0,0 7.203708,-80.79574 17.142858,-100 9.93915,-19.20426 12.56519,-16.9204 20,-20 7.43481,-3.0796 20,0 20,0" | ||||||
|  |        id="path4989" | ||||||
|  |        inkscape:connector-curvature="0" | ||||||
|  |        sodipodi:nodetypes="csssczzccccccccccccczzc" /> | ||||||
|  |     <path | ||||||
|  |        sodipodi:nodetypes="csssczzccccccccccccccccczzc" | ||||||
|  |        inkscape:connector-curvature="0" | ||||||
|  |        id="path4991" | ||||||
|  |        d="m 351.42857,208.07649 c 0,0 -22.38786,-25.28537 -20,-40 3.02043,-18.6127 21.14382,-40 40,-40 18.85618,0 36.97957,21.3873 40,40 2.38786,14.71463 -20,40 -20,40 0,0 12.56519,-3.0796 20,0 7.43481,3.0796 9.36405,0.69304 20,20 10.63595,19.30696 22.85714,101.42857 22.85714,101.42857 l -20,0 -22.85714,-81.42857 0,78.57143 C 408.57143,353.55268 430,380.45744 427.14286,407.3622 l -24.28572,-2.5 -8.57143,83.21429 c -13.50649,0 -41.87328,0 -22.85714,0 l 0,-77.14286 -1.42857,78.57143 -21.42857,-2.85714 -10.71429,-76.42857 -23.57143,-2.14286 c -3.33333,-26.19048 17.61905,-52.38095 14.28572,-78.57143 l 2.85714,-81.42857 -17.14286,80 -20,0 c 0,0 7.20371,-80.79574 17.14286,-100 9.93915,-19.20426 12.56519,-16.9204 20,-20 7.43481,-3.0796 20,0 20,0" | ||||||
|  |        style="fill:#808080;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /> | ||||||
|  |     <path | ||||||
|  |        style="fill:#808080;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | ||||||
|  |        d="m 548.57143,208.07649 c 0,0 -22.38786,-25.28537 -20,-40 3.02043,-18.6127 21.14382,-40 40,-40 18.85618,0 36.97957,21.3873 40,40 2.38786,14.71463 -20,40 -20,40 0,0 12.56519,-3.0796 20,0 7.43481,3.0796 9.36405,0.69304 20,20 10.63595,19.30696 22.85714,101.42857 22.85714,101.42857 l -20,0 -22.85714,-81.42857 0,78.57143 c -2.85714,26.90476 18.57143,53.80952 15.71429,80.71428 l -24.28572,-2.5 -8.57143,83.21429 c -13.50649,0 -41.87328,0 -22.85714,0 l 0,-77.14286 -1.42857,78.57143 -21.42857,-2.85714 L 535,410.21935 511.42857,408.07649 c -3.33333,-26.19048 17.61905,-52.38095 14.28572,-78.57143 l 2.85714,-81.42857 -17.14286,80 -20,0 c 0,0 7.20371,-80.79574 17.14286,-100 9.93915,-19.20426 12.56519,-16.9204 20,-20 7.43481,-3.0796 20,0 20,0" | ||||||
|  |        id="path4993" | ||||||
|  |        inkscape:connector-curvature="0" | ||||||
|  |        sodipodi:nodetypes="csssczzccccccccccccccccczzc" /> | ||||||
|  |     <text | ||||||
|  |        xml:space="preserve" | ||||||
|  |        style="font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:20px;line-height:125%;font-family:'URW Chancery L';-inkscape-font-specification:'URW Chancery L Bold Italic';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | ||||||
|  |        x="110" | ||||||
|  |        y="549.50507" | ||||||
|  |        id="text4995" | ||||||
|  |        sodipodi:linespacing="125%"><tspan | ||||||
|  |          sodipodi:role="line" | ||||||
|  |          id="tspan4997" | ||||||
|  |          x="110" | ||||||
|  |          y="549.50507" | ||||||
|  |          style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Arial;-inkscape-font-specification:Arial">John McNeil</tspan></text> | ||||||
|  |     <text | ||||||
|  |        xml:space="preserve" | ||||||
|  |        style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;line-height:125%;font-family:Arial;-inkscape-font-specification:Arial;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | ||||||
|  |        x="320" | ||||||
|  |        y="549.50507" | ||||||
|  |        id="text4999" | ||||||
|  |        sodipodi:linespacing="125%"><tspan | ||||||
|  |          sodipodi:role="line" | ||||||
|  |          id="tspan5001" | ||||||
|  |          x="320" | ||||||
|  |          y="549.50507">Anne McNeil</tspan></text> | ||||||
|  |     <text | ||||||
|  |        xml:space="preserve" | ||||||
|  |        style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;line-height:125%;font-family:Arial;-inkscape-font-specification:Arial;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | ||||||
|  |        x="530" | ||||||
|  |        y="549.50507" | ||||||
|  |        id="text5003" | ||||||
|  |        sodipodi:linespacing="125%"><tspan | ||||||
|  |          sodipodi:role="line" | ||||||
|  |          id="tspan5005" | ||||||
|  |          x="530" | ||||||
|  |          y="549.50507">Helen McNeil</tspan></text> | ||||||
|  |     <g | ||||||
|  |        id="g5166" | ||||||
|  |        transform="matrix(2,0,0,2,1117.4431,-216.22311)"> | ||||||
|  |       <path | ||||||
|  |          sodipodi:nodetypes="ccccccccc" | ||||||
|  |          inkscape:connector-curvature="0" | ||||||
|  |          id="path5079" | ||||||
|  |          d="m -300,452.3622 0,-40 c 0,-5 5,-10 10,-10 l 40,0 c 5,0 10,5 10,10 l 0,40 c 0,5 -5,10 -10,10 l -40,0 c -5,0 -10,-5 -10,-10 z" | ||||||
|  |          style="fill:#808080;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /> | ||||||
|  |       <path | ||||||
|  |          inkscape:connector-curvature="0" | ||||||
|  |          id="path5088" | ||||||
|  |          d="m -300,412.27292 0,8.92857 60,31.25 0,-8.92857 -60,-31.25" | ||||||
|  |          style="fill:#ffffff;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /> | ||||||
|  |       <path | ||||||
|  |          style="fill:#ffffff;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | ||||||
|  |          d="m -300,452.45149 0,-8.92857 60,-31.25 0,8.92857 -60,31.25" | ||||||
|  |          id="path5090" | ||||||
|  |          inkscape:connector-curvature="0" /> | ||||||
|  |     </g> | ||||||
|  |     <g | ||||||
|  |        id="g5154" | ||||||
|  |        transform="matrix(2,0,0,2,1117.4431,-216.22311)"> | ||||||
|  |       <path | ||||||
|  |          style="fill:#808080;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | ||||||
|  |          d="m -300,523.07649 0,-40 c 0,-5 5,-10 10,-10 l 40,0 c 5,0 10,5 10,10 l 0,40 c 0,5 -5,10 -10,10 l -40,0 c -5,0 -10,-5 -10,-10 z" | ||||||
|  |          id="path5081" | ||||||
|  |          inkscape:connector-curvature="0" | ||||||
|  |          sodipodi:nodetypes="ccccccccc" /> | ||||||
|  |       <path | ||||||
|  |          style="fill:#ffffff;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | ||||||
|  |          d="m -300.16446,483.03742 0,8.92857 60,31.25 0,-8.92857 -60,-31.25" | ||||||
|  |          id="path5117" | ||||||
|  |          inkscape:connector-curvature="0" /> | ||||||
|  |       <path | ||||||
|  |          inkscape:connector-curvature="0" | ||||||
|  |          id="path5119" | ||||||
|  |          d="m -300.16446,523.21599 0,-8.92857 60,-31.25 0,8.92857 -60,31.25" | ||||||
|  |          style="fill:#ffffff;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /> | ||||||
|  |       <rect | ||||||
|  |          y="483.03741" | ||||||
|  |          x="-275.34302" | ||||||
|  |          height="25" | ||||||
|  |          width="10" | ||||||
|  |          id="rect5121" | ||||||
|  |          style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2.4000001;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> | ||||||
|  |       <rect | ||||||
|  |          y="482.91116" | ||||||
|  |          x="-277.31256" | ||||||
|  |          height="40" | ||||||
|  |          width="13.686545" | ||||||
|  |          id="rect5125" | ||||||
|  |          style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2.4000001;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> | ||||||
|  |       <rect | ||||||
|  |          y="498.03741" | ||||||
|  |          x="-300.34302" | ||||||
|  |          height="10" | ||||||
|  |          width="60" | ||||||
|  |          id="rect5127" | ||||||
|  |          style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2.4000001;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> | ||||||
|  |       <rect | ||||||
|  |          y="483.03741" | ||||||
|  |          x="-275.34302" | ||||||
|  |          height="40" | ||||||
|  |          width="10" | ||||||
|  |          id="rect5129" | ||||||
|  |          style="opacity:1;fill:#b3b3b3;fill-opacity:1;stroke:none;stroke-width:2.4000001;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> | ||||||
|  |       <rect | ||||||
|  |          y="499.55264" | ||||||
|  |          x="-300.34302" | ||||||
|  |          height="7.2220807" | ||||||
|  |          width="60" | ||||||
|  |          id="rect5131" | ||||||
|  |          style="opacity:1;fill:#b3b3b3;fill-opacity:1;stroke:none;stroke-width:2.4000001;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> | ||||||
|  |       <path | ||||||
|  |          inkscape:connector-curvature="0" | ||||||
|  |          id="path5133" | ||||||
|  |          d="m -300.12977,484.76182 59.9778,31.18846 0,5.42957 -60.23034,-31.31472 z" | ||||||
|  |          style="fill:#b3b3b3;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /> | ||||||
|  |       <path | ||||||
|  |          style="fill:#b3b3b3;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | ||||||
|  |          d="m -240.40451,484.76182 -59.9778,31.18846 0,5.42957 60.23034,-31.31472 z" | ||||||
|  |          id="path5135" | ||||||
|  |          inkscape:connector-curvature="0" /> | ||||||
|  |     </g> | ||||||
|  |     <g | ||||||
|  |        id="g5173" | ||||||
|  |        transform="matrix(2,0,0,2,1117.4431,-216.22311)"> | ||||||
|  |       <path | ||||||
|  |          sodipodi:nodetypes="ccccccccc" | ||||||
|  |          inkscape:connector-curvature="0" | ||||||
|  |          id="path5083" | ||||||
|  |          d="m -300,593.25506 0,-40 c 0,-5 5,-10 10,-10 l 40,0 c 5,0 10,5 10,10 l 0,40 c 0,5 -5,10 -10,10 l -40,0 c -5,0 -10,-5 -10,-10 z" | ||||||
|  |          style="fill:#808080;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /> | ||||||
|  |       <text | ||||||
|  |          sodipodi:linespacing="125%" | ||||||
|  |          id="text4292" | ||||||
|  |          y="594.78485" | ||||||
|  |          x="-289.54495" | ||||||
|  |          style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;line-height:125%;font-family:'Arial Black';-inkscape-font-specification:'Arial Black, ';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | ||||||
|  |          xml:space="preserve"><tspan | ||||||
|  |            style="font-size:60px;fill:#ffffff" | ||||||
|  |            y="594.78485" | ||||||
|  |            x="-289.54495" | ||||||
|  |            id="tspan4294" | ||||||
|  |            sodipodi:role="line">?</tspan></text> | ||||||
|  |     </g> | ||||||
|  |     <g | ||||||
|  |        transform="matrix(2,0,0,2,913.15739,-216.22311)" | ||||||
|  |        id="g5178"> | ||||||
|  |       <path | ||||||
|  |          style="fill:#808080;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | ||||||
|  |          d="m -300,452.3622 0,-40 c 0,-5 5,-10 10,-10 l 40,0 c 5,0 10,5 10,10 l 0,40 c 0,5 -5,10 -10,10 l -40,0 c -5,0 -10,-5 -10,-10 z" | ||||||
|  |          id="path5180" | ||||||
|  |          inkscape:connector-curvature="0" | ||||||
|  |          sodipodi:nodetypes="ccccccccc" /> | ||||||
|  |       <path | ||||||
|  |          style="fill:#ffffff;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | ||||||
|  |          d="m -300,412.27292 0,8.92857 60,31.25 0,-8.92857 -60,-31.25" | ||||||
|  |          id="path5182" | ||||||
|  |          inkscape:connector-curvature="0" /> | ||||||
|  |       <path | ||||||
|  |          inkscape:connector-curvature="0" | ||||||
|  |          id="path5184" | ||||||
|  |          d="m -300,452.45149 0,-8.92857 60,-31.25 0,8.92857 -60,31.25" | ||||||
|  |          style="fill:#ffffff;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /> | ||||||
|  |     </g> | ||||||
|  |     <path | ||||||
|  |        style="fill:#000080;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | ||||||
|  |        d="m 313.15739,829.92987 0,-80 c 0,-10 10,-20 20,-20 l 80,0 c 10,0 20,10 20,20 l 0,80 c 0,10 -10,20 -20,20 l -80,0 c -10,0 -20,-10 -20,-20 z" | ||||||
|  |        id="path5188" | ||||||
|  |        inkscape:connector-curvature="0" | ||||||
|  |        sodipodi:nodetypes="ccccccccc" /> | ||||||
|  |     <g | ||||||
|  |        transform="matrix(2,0,0,2,913.15739,-216.22311)" | ||||||
|  |        id="g5208"> | ||||||
|  |       <path | ||||||
|  |          style="fill:#808080;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | ||||||
|  |          d="m -300,593.25506 0,-40 c 0,-5 5,-10 10,-10 l 40,0 c 5,0 10,5 10,10 l 0,40 c 0,5 -5,10 -10,10 l -40,0 c -5,0 -10,-5 -10,-10 z" | ||||||
|  |          id="path5210" | ||||||
|  |          inkscape:connector-curvature="0" | ||||||
|  |          sodipodi:nodetypes="ccccccccc" /> | ||||||
|  |       <text | ||||||
|  |          xml:space="preserve" | ||||||
|  |          style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;line-height:125%;font-family:'Arial Black';-inkscape-font-specification:'Arial Black, ';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | ||||||
|  |          x="-289.54495" | ||||||
|  |          y="594.78485" | ||||||
|  |          id="text5212" | ||||||
|  |          sodipodi:linespacing="125%"><tspan | ||||||
|  |            sodipodi:role="line" | ||||||
|  |            id="tspan5214" | ||||||
|  |            x="-289.54495" | ||||||
|  |            y="594.78485" | ||||||
|  |            style="font-size:60px;fill:#ffffff">?</tspan></text> | ||||||
|  |     </g> | ||||||
|  |     <path | ||||||
|  |        style="fill:#000080;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | ||||||
|  |        d="m 104.58596,688.50129 0,-80 c 0,-10 10,-20 20,-20 l 80,0 c 10,0 20,10 20,20 l 0,80 c 0,10 -10,20 -20,20 l -80,0 c -10,0 -20,-10 -20,-20 z" | ||||||
|  |        id="path5218" | ||||||
|  |        inkscape:connector-curvature="0" | ||||||
|  |        sodipodi:nodetypes="ccccccccc" /> | ||||||
|  |     <path | ||||||
|  |        style="fill:#ffffff;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | ||||||
|  |        d="m 104.58596,608.32273 0,17.85714 120,62.5 0,-17.85714 -120,-62.5" | ||||||
|  |        id="path5220" | ||||||
|  |        inkscape:connector-curvature="0" /> | ||||||
|  |     <path | ||||||
|  |        inkscape:connector-curvature="0" | ||||||
|  |        id="path5222" | ||||||
|  |        d="m 104.58596,688.67987 0,-17.85714 120,-62.5 0,17.85714 -120,62.5" | ||||||
|  |        style="fill:#ffffff;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /> | ||||||
|  |     <g | ||||||
|  |        id="g5224" | ||||||
|  |        transform="matrix(2,0,0,2,704.58596,-216.22311)"> | ||||||
|  |       <path | ||||||
|  |          style="fill:#808080;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | ||||||
|  |          d="m -300,523.07649 0,-40 c 0,-5 5,-10 10,-10 l 40,0 c 5,0 10,5 10,10 l 0,40 c 0,5 -5,10 -10,10 l -40,0 c -5,0 -10,-5 -10,-10 z" | ||||||
|  |          id="path5226" | ||||||
|  |          inkscape:connector-curvature="0" | ||||||
|  |          sodipodi:nodetypes="ccccccccc" /> | ||||||
|  |       <path | ||||||
|  |          style="fill:#ffffff;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | ||||||
|  |          d="m -300.16446,483.03742 0,8.92857 60,31.25 0,-8.92857 -60,-31.25" | ||||||
|  |          id="path5228" | ||||||
|  |          inkscape:connector-curvature="0" /> | ||||||
|  |       <path | ||||||
|  |          inkscape:connector-curvature="0" | ||||||
|  |          id="path5230" | ||||||
|  |          d="m -300.16446,523.21599 0,-8.92857 60,-31.25 0,8.92857 -60,31.25" | ||||||
|  |          style="fill:#ffffff;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /> | ||||||
|  |       <rect | ||||||
|  |          y="483.03741" | ||||||
|  |          x="-275.34302" | ||||||
|  |          height="25" | ||||||
|  |          width="10" | ||||||
|  |          id="rect5232" | ||||||
|  |          style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2.4000001;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> | ||||||
|  |       <rect | ||||||
|  |          y="482.91116" | ||||||
|  |          x="-277.31256" | ||||||
|  |          height="40" | ||||||
|  |          width="13.686545" | ||||||
|  |          id="rect5234" | ||||||
|  |          style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2.4000001;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> | ||||||
|  |       <rect | ||||||
|  |          y="498.03741" | ||||||
|  |          x="-300.34302" | ||||||
|  |          height="10" | ||||||
|  |          width="60" | ||||||
|  |          id="rect5236" | ||||||
|  |          style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2.4000001;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> | ||||||
|  |       <rect | ||||||
|  |          y="483.03741" | ||||||
|  |          x="-275.34302" | ||||||
|  |          height="40" | ||||||
|  |          width="10" | ||||||
|  |          id="rect5238" | ||||||
|  |          style="opacity:1;fill:#b3b3b3;fill-opacity:1;stroke:none;stroke-width:2.4000001;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> | ||||||
|  |       <rect | ||||||
|  |          y="499.55264" | ||||||
|  |          x="-300.34302" | ||||||
|  |          height="7.2220807" | ||||||
|  |          width="60" | ||||||
|  |          id="rect5240" | ||||||
|  |          style="opacity:1;fill:#b3b3b3;fill-opacity:1;stroke:none;stroke-width:2.4000001;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> | ||||||
|  |       <path | ||||||
|  |          inkscape:connector-curvature="0" | ||||||
|  |          id="path5242" | ||||||
|  |          d="m -300.12977,484.76182 59.9778,31.18846 0,5.42957 -60.23034,-31.31472 z" | ||||||
|  |          style="fill:#b3b3b3;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /> | ||||||
|  |       <path | ||||||
|  |          style="fill:#b3b3b3;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | ||||||
|  |          d="m -240.40451,484.76182 -59.9778,31.18846 0,5.42957 60.23034,-31.31472 z" | ||||||
|  |          id="path5244" | ||||||
|  |          inkscape:connector-curvature="0" /> | ||||||
|  |     </g> | ||||||
|  |     <g | ||||||
|  |        id="g5246" | ||||||
|  |        transform="matrix(2,0,0,2,704.58596,-216.22311)"> | ||||||
|  |       <path | ||||||
|  |          sodipodi:nodetypes="ccccccccc" | ||||||
|  |          inkscape:connector-curvature="0" | ||||||
|  |          id="path5248" | ||||||
|  |          d="m -300,593.25506 0,-40 c 0,-5 5,-10 10,-10 l 40,0 c 5,0 10,5 10,10 l 0,40 c 0,5 -5,10 -10,10 l -40,0 c -5,0 -10,-5 -10,-10 z" | ||||||
|  |          style="fill:#808080;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /> | ||||||
|  |       <text | ||||||
|  |          sodipodi:linespacing="125%" | ||||||
|  |          id="text5250" | ||||||
|  |          y="594.78485" | ||||||
|  |          x="-289.54495" | ||||||
|  |          style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;line-height:125%;font-family:'Arial Black';-inkscape-font-specification:'Arial Black, ';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | ||||||
|  |          xml:space="preserve"><tspan | ||||||
|  |            style="font-size:60px;fill:#ffffff" | ||||||
|  |            y="594.78485" | ||||||
|  |            x="-289.54495" | ||||||
|  |            id="tspan5252" | ||||||
|  |            sodipodi:role="line">?</tspan></text> | ||||||
|  |     </g> | ||||||
|  |     <g | ||||||
|  |        transform="matrix(2,0,0,2,1040.3002,-373.36597)" | ||||||
|  |        id="g5267"> | ||||||
|  |       <path | ||||||
|  |          style="fill:#ffffff;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | ||||||
|  |          d="m -363.73589,562.32313 0,8.92857 60,31.25 0,-8.92857 -60,-31.25" | ||||||
|  |          id="path5269" | ||||||
|  |          inkscape:connector-curvature="0" /> | ||||||
|  |       <path | ||||||
|  |          inkscape:connector-curvature="0" | ||||||
|  |          id="path5271" | ||||||
|  |          d="m -363.73589,602.5017 0,-8.92857 60,-31.25 0,8.92857 -60,31.25" | ||||||
|  |          style="fill:#ffffff;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /> | ||||||
|  |       <rect | ||||||
|  |          y="562.32312" | ||||||
|  |          x="-338.91446" | ||||||
|  |          height="25" | ||||||
|  |          width="10" | ||||||
|  |          id="rect5273" | ||||||
|  |          style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2.4000001;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> | ||||||
|  |       <g | ||||||
|  |          id="g5275" | ||||||
|  |          transform="translate(-583.91446,359.96093)"> | ||||||
|  |         <rect | ||||||
|  |            style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2.4000001;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" | ||||||
|  |            id="rect5277" | ||||||
|  |            width="13.686545" | ||||||
|  |            height="40" | ||||||
|  |            x="243.03046" | ||||||
|  |            y="202.23593" /> | ||||||
|  |         <rect | ||||||
|  |            style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2.4000001;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" | ||||||
|  |            id="rect5279" | ||||||
|  |            width="60" | ||||||
|  |            height="10" | ||||||
|  |            x="220" | ||||||
|  |            y="217.3622" /> | ||||||
|  |         <rect | ||||||
|  |            style="opacity:1;fill:#aa0000;fill-opacity:1;stroke:none;stroke-width:2.4000001;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" | ||||||
|  |            id="rect5281" | ||||||
|  |            width="10" | ||||||
|  |            height="40" | ||||||
|  |            x="245" | ||||||
|  |            y="202.3622" /> | ||||||
|  |         <rect | ||||||
|  |            style="opacity:1;fill:#aa0000;fill-opacity:1;stroke:none;stroke-width:2.4000001;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" | ||||||
|  |            id="rect5283" | ||||||
|  |            width="60" | ||||||
|  |            height="7.2220807" | ||||||
|  |            x="220" | ||||||
|  |            y="218.87743" /> | ||||||
|  |       </g> | ||||||
|  |       <path | ||||||
|  |          inkscape:connector-curvature="0" | ||||||
|  |          id="path5285" | ||||||
|  |          d="m -363.7012,564.04753 59.9778,31.18846 0,5.42957 -60.23034,-31.31472 z" | ||||||
|  |          style="fill:#aa0000;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /> | ||||||
|  |       <path | ||||||
|  |          style="fill:#aa0000;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | ||||||
|  |          d="m -303.97594,564.04753 -59.9778,31.18846 0,5.42957 60.23034,-31.31472 z" | ||||||
|  |          id="path5287" | ||||||
|  |          inkscape:connector-curvature="0" /> | ||||||
|  |     </g> | ||||||
|  |   </g> | ||||||
|  | </svg> | ||||||
| After Width: | Height: | Size: 23 KiB | 
							
								
								
									
										
											BIN
										
									
								
								dummies/occupants.xcf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								dummies/occupants.xcf
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								dummies/occupants_800.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								dummies/occupants_800.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 91 KiB | 
							
								
								
									
										
											BIN
										
									
								
								dummies/occupants_800.xcf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								dummies/occupants_800.xcf
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										16
									
								
								env/dev/clj/user.clj
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								env/dev/clj/user.clj
									
									
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,16 @@ | ||||||
|  | (ns user | ||||||
|  |   (:require [mount.core :as mount] | ||||||
|  |             [youyesyet.figwheel :refer [start-fw stop-fw cljs]] | ||||||
|  |             youyesyet.core)) | ||||||
|  | 
 | ||||||
|  | (defn start [] | ||||||
|  |   (mount/start-without #'youyesyet.core/repl-server)) | ||||||
|  | 
 | ||||||
|  | (defn stop [] | ||||||
|  |   (mount/stop-except #'youyesyet.core/repl-server)) | ||||||
|  | 
 | ||||||
|  | (defn restart [] | ||||||
|  |   (stop) | ||||||
|  |   (start)) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
							
								
								
									
										60
									
								
								env/dev/clj/youyesyet/core.clj
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								env/dev/clj/youyesyet/core.clj
									
									
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,60 @@ | ||||||
|  | (ns youyesyet.core | ||||||
|  |   (:require [youyesyet.handler :as handler] | ||||||
|  |             [luminus.repl-server :as repl] | ||||||
|  |             [luminus.http-server :as http] | ||||||
|  |             [luminus-migrations.core :as migrations] | ||||||
|  |             [youyesyet.config :refer [env]] | ||||||
|  |             [clojure.tools.cli :refer [parse-opts]] | ||||||
|  |             [clojure.tools.logging :as log] | ||||||
|  |             [mount.core :as mount]) | ||||||
|  |   (:gen-class)) | ||||||
|  | 
 | ||||||
|  | (def cli-options | ||||||
|  |   [["-p" "--port PORT" "Port number" | ||||||
|  |     :parse-fn #(Integer/parseInt %)]]) | ||||||
|  | 
 | ||||||
|  | (mount/defstate ^{:on-reload :noop} | ||||||
|  |                 http-server | ||||||
|  |                 :start | ||||||
|  |                 (http/start | ||||||
|  |                   (-> env | ||||||
|  |                       (assoc :handler handler/app) | ||||||
|  |                       (update :port #(or (-> env :options :port) %)))) | ||||||
|  |                 :stop | ||||||
|  |                 (http/stop http-server)) | ||||||
|  | 
 | ||||||
|  | (mount/defstate ^{:on-reload :noop} | ||||||
|  |                 repl-server | ||||||
|  |                 :start | ||||||
|  |                 (when-let [nrepl-port (env :nrepl-port)] | ||||||
|  |                   (repl/start {:port nrepl-port})) | ||||||
|  |                 :stop | ||||||
|  |                 (when repl-server | ||||||
|  |                   (repl/stop repl-server))) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | (defn init-jndi [] | ||||||
|  |   (System/setProperty "java.naming.factory.initial" | ||||||
|  |                       "org.apache.naming.java.javaURLContextFactory") | ||||||
|  |   (System/setProperty "java.naming.factory.url.pkgs" | ||||||
|  |                       "org.apache.naming")) | ||||||
|  | 
 | ||||||
|  | (defn start-app [args] | ||||||
|  |   (init-jndi) | ||||||
|  |   (doseq [component (-> args | ||||||
|  |                         (parse-opts cli-options) | ||||||
|  |                         mount/start-with-args | ||||||
|  |                         :started)] | ||||||
|  |     (log/info component "started")) | ||||||
|  |   (.addShutdownHook (Runtime/getRuntime) (Thread. handler/destroy))) | ||||||
|  | 
 | ||||||
|  | (defn -main [& args] | ||||||
|  |   (cond | ||||||
|  |     (some #{"migrate" "rollback"} args) | ||||||
|  |     (do | ||||||
|  |       (mount/start #'youyesyet.config/env) | ||||||
|  |       (migrations/migrate args (select-keys env [:database-url])) | ||||||
|  |       (System/exit 0)) | ||||||
|  |     :else | ||||||
|  |     (start-app args))) | ||||||
|  |    | ||||||
							
								
								
									
										10
									
								
								env/dev/clj/youyesyet/dev_middleware.clj
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								env/dev/clj/youyesyet/dev_middleware.clj
									
									
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,10 @@ | ||||||
|  | (ns youyesyet.dev-middleware | ||||||
|  |   (:require [ring.middleware.reload :refer [wrap-reload]] | ||||||
|  |             [selmer.middleware :refer [wrap-error-page]] | ||||||
|  |             [prone.middleware :refer [wrap-exceptions]])) | ||||||
|  | 
 | ||||||
|  | (defn wrap-dev [handler] | ||||||
|  |   (-> handler | ||||||
|  |       wrap-reload | ||||||
|  |       wrap-error-page | ||||||
|  |       wrap-exceptions)) | ||||||
							
								
								
									
										14
									
								
								env/dev/clj/youyesyet/env.clj
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								env/dev/clj/youyesyet/env.clj
									
									
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,14 @@ | ||||||
|  | (ns youyesyet.env | ||||||
|  |   (:require [selmer.parser :as parser] | ||||||
|  |             [clojure.tools.logging :as log] | ||||||
|  |             [youyesyet.dev-middleware :refer [wrap-dev]])) | ||||||
|  | 
 | ||||||
|  | (def defaults | ||||||
|  |   {:init | ||||||
|  |    (fn [] | ||||||
|  |      (parser/cache-off!) | ||||||
|  |      (log/info "\n-=[youyesyet started successfully using the development profile]=-")) | ||||||
|  |    :stop | ||||||
|  |    (fn [] | ||||||
|  |      (log/info "\n-=[youyesyet has shut down successfully]=-")) | ||||||
|  |    :middleware wrap-dev}) | ||||||
							
								
								
									
										12
									
								
								env/dev/clj/youyesyet/figwheel.clj
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								env/dev/clj/youyesyet/figwheel.clj
									
									
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,12 @@ | ||||||
|  | (ns youyesyet.figwheel | ||||||
|  |   (:require [figwheel-sidecar.repl-api :as ra])) | ||||||
|  | 
 | ||||||
|  | (defn start-fw [] | ||||||
|  |   (ra/start-figwheel!)) | ||||||
|  | 
 | ||||||
|  | (defn stop-fw [] | ||||||
|  |   (ra/stop-figwheel!)) | ||||||
|  | 
 | ||||||
|  | (defn cljs [] | ||||||
|  |   (ra/cljs-repl)) | ||||||
|  | 
 | ||||||
							
								
								
									
										14
									
								
								env/dev/cljs/youyesyet/dev.cljs
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								env/dev/cljs/youyesyet/dev.cljs
									
									
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,14 @@ | ||||||
|  | (ns ^:figwheel-no-load youyesyet.app | ||||||
|  |   (:require [youyesyet.core :as core] | ||||||
|  |             [devtools.core :as devtools] | ||||||
|  |             [figwheel.client :as figwheel :include-macros true])) | ||||||
|  | 
 | ||||||
|  | (enable-console-print!) | ||||||
|  | 
 | ||||||
|  | (figwheel/watch-and-reload | ||||||
|  |   :websocket-url "ws://localhost:3449/figwheel-ws" | ||||||
|  |   :on-jsload core/mount-components) | ||||||
|  | 
 | ||||||
|  | (devtools/install!) | ||||||
|  | 
 | ||||||
|  | (core/init!) | ||||||
							
								
								
									
										4
									
								
								env/dev/resources/config.edn
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								env/dev/resources/config.edn
									
									
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,4 @@ | ||||||
|  | {:dev true | ||||||
|  |  :port 3000 | ||||||
|  |  ;; when :nrepl-port is set the application starts the nREPL server on load | ||||||
|  |  :nrepl-port 7000} | ||||||
							
								
								
									
										51
									
								
								env/dev/resources/logback.xml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								env/dev/resources/logback.xml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,51 @@ | ||||||
|  | <?xml version="1.0" encoding="UTF-8"?> | ||||||
|  | <configuration> | ||||||
|  |     <statusListener class="ch.qos.logback.core.status.NopStatusListener" /> | ||||||
|  |     <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> | ||||||
|  |         <!-- encoders are assigned the type | ||||||
|  |              ch.qos.logback.classic.encoder.PatternLayoutEncoder by default --> | ||||||
|  |         <encoder> | ||||||
|  |             <charset>UTF-8</charset> | ||||||
|  |             <pattern>%date{ISO8601} [%thread] %-5level %logger{36} - %msg %n</pattern> | ||||||
|  |         </encoder> | ||||||
|  |     </appender> | ||||||
|  |     <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> | ||||||
|  |         <file>log/youyesyet.log</file> | ||||||
|  |         <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> | ||||||
|  |             <fileNamePattern>log/youyesyet.%d{yyyy-MM-dd}.%i.log</fileNamePattern> | ||||||
|  |             <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> | ||||||
|  |                 <maxFileSize>100MB</maxFileSize> | ||||||
|  |             </timeBasedFileNamingAndTriggeringPolicy> | ||||||
|  |             <!-- keep 30 days of history --> | ||||||
|  |             <maxHistory>30</maxHistory> | ||||||
|  |         </rollingPolicy> | ||||||
|  |         <encoder> | ||||||
|  |             <charset>UTF-8</charset> | ||||||
|  |             <pattern>%date{ISO8601} [%thread] %-5level %logger{36} - %msg %n</pattern> | ||||||
|  |         </encoder> | ||||||
|  |     </appender> | ||||||
|  |     <logger name="org.apache.http" level="warn"> | ||||||
|  |         <AppenderRef ref="STDOUT"/> | ||||||
|  |         <AppenderRef ref="FILE"/> | ||||||
|  |     </logger> | ||||||
|  |     <logger name="org.xnio.nio" level="warn"> | ||||||
|  |         <AppenderRef ref="STDOUT"/> | ||||||
|  |         <AppenderRef ref="FILE"/> | ||||||
|  |     </logger> | ||||||
|  |     <logger name="com.zaxxer.hikari" level="warn"> | ||||||
|  |         <AppenderRef ref="STDOUT"/> | ||||||
|  |         <AppenderRef ref="FILE"/> | ||||||
|  |     </logger> | ||||||
|  |     <logger name="com.mchange" level="warn"> | ||||||
|  |         <AppenderRef ref="STDOUT"/> | ||||||
|  |         <AppenderRef ref="FILE"/> | ||||||
|  |     </logger> | ||||||
|  |     <logger name="org.eclipse.jetty" level="warn"> | ||||||
|  |         <AppenderRef ref="STDOUT"/> | ||||||
|  |         <AppenderRef ref="FILE"/> | ||||||
|  |     </logger> | ||||||
|  |     <root level="DEBUG"> | ||||||
|  |         <appender-ref ref="STDOUT" /> | ||||||
|  |         <appender-ref ref="FILE" /> | ||||||
|  |     </root> | ||||||
|  | </configuration> | ||||||
							
								
								
									
										11
									
								
								env/prod/clj/youyesyet/env.clj
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								env/prod/clj/youyesyet/env.clj
									
									
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,11 @@ | ||||||
|  | (ns youyesyet.env | ||||||
|  |   (:require [clojure.tools.logging :as log])) | ||||||
|  | 
 | ||||||
|  | (def defaults | ||||||
|  |   {:init | ||||||
|  |    (fn [] | ||||||
|  |      (log/info "\n-=[youyesyet started successfully]=-")) | ||||||
|  |    :stop | ||||||
|  |    (fn [] | ||||||
|  |      (log/info "\n-=[youyesyet has shut down successfully]=-")) | ||||||
|  |    :middleware identity}) | ||||||
							
								
								
									
										7
									
								
								env/prod/cljs/youyesyet/prod.cljs
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								env/prod/cljs/youyesyet/prod.cljs
									
									
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,7 @@ | ||||||
|  | (ns youyesyet.app | ||||||
|  |   (:require [youyesyet.core :as core])) | ||||||
|  | 
 | ||||||
|  | ;;ignore println statements in prod | ||||||
|  | (set! *print-fn* (fn [& _])) | ||||||
|  | 
 | ||||||
|  | (core/init!) | ||||||
							
								
								
									
										2
									
								
								env/prod/resources/config.edn
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								env/prod/resources/config.edn
									
									
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,2 @@ | ||||||
|  | {:production true | ||||||
|  |  :port 3000} | ||||||
							
								
								
									
										37
									
								
								env/prod/resources/logback.xml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								env/prod/resources/logback.xml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,37 @@ | ||||||
|  | <?xml version="1.0" encoding="UTF-8"?> | ||||||
|  | <configuration> | ||||||
|  |     <statusListener class="ch.qos.logback.core.status.NopStatusListener" /> | ||||||
|  |     <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> | ||||||
|  |         <file>log/youyesyet.log</file> | ||||||
|  |         <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> | ||||||
|  |             <fileNamePattern>log/youyesyet.%d{yyyy-MM-dd}.%i.log</fileNamePattern> | ||||||
|  |             <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> | ||||||
|  |                 <maxFileSize>100MB</maxFileSize> | ||||||
|  |             </timeBasedFileNamingAndTriggeringPolicy> | ||||||
|  |             <!-- keep 30 days of history --> | ||||||
|  |             <maxHistory>30</maxHistory> | ||||||
|  |         </rollingPolicy> | ||||||
|  |         <encoder> | ||||||
|  |             <charset>UTF-8</charset> | ||||||
|  |             <pattern>%date{ISO8601} [%thread] %-5level %logger{36} - %msg %n</pattern> | ||||||
|  |         </encoder> | ||||||
|  |     </appender> | ||||||
|  |     <logger name="org.apache.http" level="warn"> | ||||||
|  |         <AppenderRef ref="FILE"/> | ||||||
|  |     </logger> | ||||||
|  |     <logger name="org.xnio.nio" level="warn"> | ||||||
|  |         <AppenderRef ref="FILE"/> | ||||||
|  |     </logger> | ||||||
|  |     <logger name="com.zaxxer.hikari" level="warn"> | ||||||
|  |         <AppenderRef ref="FILE"/> | ||||||
|  |     </logger> | ||||||
|  |     <logger name="com.mchange" level="warn"> | ||||||
|  |         <AppenderRef ref="FILE"/> | ||||||
|  |     </logger> | ||||||
|  |     <logger name="org.eclipse.jetty" level="warn"> | ||||||
|  |         <AppenderRef ref="FILE"/> | ||||||
|  |     </logger> | ||||||
|  |     <root level="INFO"> | ||||||
|  |         <appender-ref ref="FILE" /> | ||||||
|  |     </root> | ||||||
|  | </configuration> | ||||||
							
								
								
									
										3
									
								
								env/test/resources/config.edn
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								env/test/resources/config.edn
									
									
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,3 @@ | ||||||
|  | {:test true | ||||||
|  |  :port 3001 | ||||||
|  |  :nrepl-port 7001} ;; when :nrepl-port is set the application starts the nREPL server on load | ||||||
							
								
								
									
										149
									
								
								project.clj
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										149
									
								
								project.clj
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,149 @@ | ||||||
|  | (defproject youyesyet "0.1.0-SNAPSHOT" | ||||||
|  | 
 | ||||||
|  |   :description "FIXME: write description" | ||||||
|  |   :url "http://example.com/FIXME" | ||||||
|  | 
 | ||||||
|  |   :dependencies [[ring/ring-servlet "1.4.0"] | ||||||
|  |                  [clj-oauth "1.5.4"] | ||||||
|  |                  [ch.qos.logback/logback-classic "1.1.7"] | ||||||
|  |                  [re-frame "0.8.0"] | ||||||
|  |                  [cljs-ajax "0.5.8"] | ||||||
|  |                  [secretary "1.2.3"] | ||||||
|  |                  [reagent-utils "0.2.0"] | ||||||
|  |                  [reagent "0.6.0"] | ||||||
|  |                  [org.clojure/clojurescript "1.9.229" :scope "provided"] | ||||||
|  |                  [org.clojure/clojure "1.8.0"] | ||||||
|  |                  [korma "0.4.0"] | ||||||
|  |                  [selmer "1.0.9"] | ||||||
|  |                  [markdown-clj "0.9.89"] | ||||||
|  |                  [ring-middleware-format "0.7.0"] | ||||||
|  |                  [metosin/ring-http-response "0.8.0"] | ||||||
|  |                  [bouncer "1.0.0"] | ||||||
|  |                  [org.webjars/bootstrap "4.0.0-alpha.3"] | ||||||
|  |                  [org.webjars/font-awesome "4.6.3"] | ||||||
|  |                  [org.webjars.bower/tether "1.3.7"] | ||||||
|  |                  [org.clojure/tools.logging "0.3.1"] | ||||||
|  |                  [compojure "1.5.1"] | ||||||
|  |                  [ring-webjars "0.1.1"] | ||||||
|  |                  [ring/ring-defaults "0.2.1"] | ||||||
|  |                  [luminus/ring-ttl-session "0.3.1"] | ||||||
|  |                  [mount "0.1.10"] | ||||||
|  |                  [cprop "0.1.9"] | ||||||
|  |                  [org.clojure/tools.cli "0.3.5"] | ||||||
|  |                  [luminus-nrepl "0.1.4"] | ||||||
|  |                  [luminus-migrations "0.2.7"] | ||||||
|  |                  [conman "0.6.1"] | ||||||
|  |                  [org.postgresql/postgresql "9.4.1211"] | ||||||
|  |                  ] | ||||||
|  | 
 | ||||||
|  |   :min-lein-version "2.0.0" | ||||||
|  | 
 | ||||||
|  |   :license {:name "GNU General Public License v2" | ||||||
|  |             :url "http://www.gnu.org/licenses/gpl-2.0.html"} | ||||||
|  | 
 | ||||||
|  |   :jvm-opts ["-server" "-Dconf=.lein-env"] | ||||||
|  |   :source-paths ["src/clj" "src/cljc"] | ||||||
|  |   :resource-paths ["resources" "target/cljsbuild"] | ||||||
|  |   :target-path "target/%s/" | ||||||
|  |   :main youyesyet.core | ||||||
|  |   :migratus {:store :database :db ~(get (System/getenv) "DATABASE_URL")} | ||||||
|  | 
 | ||||||
|  |   :plugins [[lein-cprop "1.0.1"] | ||||||
|  |             [migratus-lein "0.4.2"] | ||||||
|  |             [org.clojars.punkisdead/lein-cucumber "1.0.5"] | ||||||
|  |             [lein-cljsbuild "1.1.4"] | ||||||
|  |             [lein-uberwar "0.2.0"]] | ||||||
|  |   :cucumber-feature-paths ["test/clj/features"] | ||||||
|  | 
 | ||||||
|  |   :uberwar | ||||||
|  |   {:handler youyesyet.handler/app | ||||||
|  |    :init youyesyet.handler/init | ||||||
|  |    :destroy youyesyet.handler/destroy | ||||||
|  |    :name "youyesyet.war"} | ||||||
|  | 
 | ||||||
|  |   :clean-targets ^{:protect false} | ||||||
|  |   [:target-path [:cljsbuild :builds :app :compiler :output-dir] [:cljsbuild :builds :app :compiler :output-to]] | ||||||
|  |   :figwheel | ||||||
|  |   {:http-server-root "public" | ||||||
|  |    :nrepl-port 7002 | ||||||
|  |    :css-dirs ["resources/public/css"] | ||||||
|  |    :nrepl-middleware [cemerick.piggieback/wrap-cljs-repl]} | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |   :profiles | ||||||
|  |   {:uberjar {:omit-source true | ||||||
|  |              :prep-tasks ["compile" ["cljsbuild" "once" "min"]] | ||||||
|  |              :cljsbuild | ||||||
|  |              {:builds | ||||||
|  |               {:min | ||||||
|  |                {:source-paths ["src/cljc" "src/cljs" "env/prod/cljs"] | ||||||
|  |                 :compiler | ||||||
|  |                 {:output-to "target/cljsbuild/public/js/app.js" | ||||||
|  |                  :externs ["react/externs/react.js"] | ||||||
|  |                  :optimizations :advanced | ||||||
|  |                  :pretty-print false | ||||||
|  |                  :closure-warnings | ||||||
|  |                  {:externs-validation :off :non-standard-jsdoc :off}}}}} | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |              :aot :all | ||||||
|  |              :uberjar-name "youyesyet.jar" | ||||||
|  |              :source-paths ["env/prod/clj"] | ||||||
|  |              :resource-paths ["env/prod/resources"]} | ||||||
|  | 
 | ||||||
|  |    :dev           [:project/dev :profiles/dev] | ||||||
|  |    :test          [:project/dev :project/test :profiles/test] | ||||||
|  | 
 | ||||||
|  |    :project/dev  {:dependencies [[prone "1.1.2"] | ||||||
|  |                                  [ring/ring-mock "0.3.0"] | ||||||
|  |                                  [ring/ring-devel "1.5.0"] | ||||||
|  |                                  [luminus-jetty "0.1.4"] | ||||||
|  |                                  [pjstadig/humane-test-output "0.8.1"] | ||||||
|  |                                  [org.clojure/core.cache "0.6.3"] | ||||||
|  |                                  [org.apache.httpcomponents/httpcore "4.4"] | ||||||
|  |                                  [clj-webdriver/clj-webdriver "0.7.2"] | ||||||
|  |                                  [org.seleniumhq.selenium/selenium-server "2.48.2"] | ||||||
|  |                                  [doo "0.1.7"] | ||||||
|  |                                  [binaryage/devtools "0.8.2"] | ||||||
|  |                                  [figwheel-sidecar "0.5.8"] | ||||||
|  |                                  [com.cemerick/piggieback "0.2.2-SNAPSHOT"] | ||||||
|  |                                  [directory-naming/naming-java "0.8"]] | ||||||
|  |                   :plugins      [[com.jakemccrary/lein-test-refresh "0.14.0"] | ||||||
|  |                                  [lein-doo "0.1.7"] | ||||||
|  |                                  [lein-figwheel "0.5.8"] | ||||||
|  |                                  [org.clojure/clojurescript "1.9.229"]] | ||||||
|  |                   :cljsbuild | ||||||
|  |                   {:builds | ||||||
|  |                    {:app | ||||||
|  |                     {:source-paths ["src/cljs" "src/cljc" "env/dev/cljs"] | ||||||
|  |                      :compiler | ||||||
|  |                      {:main "youyesyet.app" | ||||||
|  |                       :asset-path "/js/out" | ||||||
|  |                       :output-to "target/cljsbuild/public/js/app.js" | ||||||
|  |                       :output-dir "target/cljsbuild/public/js/out" | ||||||
|  |                       :source-map true | ||||||
|  |                       :optimizations :none | ||||||
|  |                       :pretty-print true}}}} | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |                   :doo {:build "test"} | ||||||
|  |                   :source-paths ["env/dev/clj" "test/clj"] | ||||||
|  |                   :resource-paths ["env/dev/resources"] | ||||||
|  |                   :repl-options {:init-ns user} | ||||||
|  |                   :injections [(require 'pjstadig.humane-test-output) | ||||||
|  |                                (pjstadig.humane-test-output/activate!)]} | ||||||
|  |    :project/test {:resource-paths ["env/dev/resources" "env/test/resources"] | ||||||
|  |                   :cljsbuild | ||||||
|  |                   {:builds | ||||||
|  |                    {:test | ||||||
|  |                     {:source-paths ["src/cljc" "src/cljs" "test/cljs"] | ||||||
|  |                      :compiler | ||||||
|  |                      {:output-to "target/test.js" | ||||||
|  |                       :main "youyesyet.doo-runner" | ||||||
|  |                       :optimizations :whitespace | ||||||
|  |                       :pretty-print true}}}} | ||||||
|  | 
 | ||||||
|  |                   } | ||||||
|  |    :profiles/dev {} | ||||||
|  |    :profiles/test {}}) | ||||||
							
								
								
									
										35
									
								
								resources/docs/docs.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								resources/docs/docs.md
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,35 @@ | ||||||
|  | <div class="bs-callout bs-callout-danger"> | ||||||
|  | 
 | ||||||
|  | ### Database Configuration is Required | ||||||
|  | 
 | ||||||
|  | If you haven't already, then please follow the steps below to configure your database connection and run the necessary migrations. | ||||||
|  | 
 | ||||||
|  | * Create the database for your application. | ||||||
|  | * Update the connection URL in the `profiles.clj` file with your database name and login. | ||||||
|  | * Run `lein run migrate` in the root of the project to create the tables. | ||||||
|  | * Let `mount` know to start the database connection by `require`-ing youyesyet.db.core in some other namespace. | ||||||
|  | * Restart the application. | ||||||
|  | 
 | ||||||
|  | </div> | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | ### Managing Your Middleware | ||||||
|  | 
 | ||||||
|  | Request middleware functions are located under the `youyesyet.middleware` namespace. | ||||||
|  | 
 | ||||||
|  | This namespace is reserved for any custom middleware for the application. Some default middleware is | ||||||
|  | already defined here. The middleware is assembled in the `wrap-base` function. | ||||||
|  | 
 | ||||||
|  | Middleware used for development is placed in the `youyesyet.dev-middleware` namespace found in | ||||||
|  | the `env/dev/clj/` source path. | ||||||
|  | 
 | ||||||
|  | ### Here are some links to get started | ||||||
|  | 
 | ||||||
|  | 1. [HTML templating](http://www.luminusweb.net/docs/html_templating.md) | ||||||
|  | 2. [Accessing the database](http://www.luminusweb.net/docs/database.md) | ||||||
|  | 3. [Setting response types](http://www.luminusweb.net/docs/responses.md) | ||||||
|  | 4. [Defining routes](http://www.luminusweb.net/docs/routes.md) | ||||||
|  | 5. [Adding middleware](http://www.luminusweb.net/docs/middleware.md) | ||||||
|  | 6. [Sessions and cookies](http://www.luminusweb.net/docs/sessions_cookies.md) | ||||||
|  | 7. [Security](http://www.luminusweb.net/docs/security.md) | ||||||
|  | 8. [Deploying the application](http://www.luminusweb.net/docs/deployment.md) | ||||||
|  | @ -0,0 +1 @@ | ||||||
|  | DROP TABLE users; | ||||||
|  | @ -0,0 +1,9 @@ | ||||||
|  | CREATE TABLE users | ||||||
|  | (id VARCHAR(20) PRIMARY KEY, | ||||||
|  |  first_name VARCHAR(30), | ||||||
|  |  last_name VARCHAR(30), | ||||||
|  |  email VARCHAR(30), | ||||||
|  |  admin BOOLEAN, | ||||||
|  |  last_login TIME, | ||||||
|  |  is_active BOOLEAN, | ||||||
|  |  pass VARCHAR(300)); | ||||||
							
								
								
									
										68
									
								
								resources/public/css/screen.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								resources/public/css/screen.css
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,68 @@ | ||||||
|  | html, | ||||||
|  | body { | ||||||
|  | 	font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; | ||||||
|  |     height: 100%; | ||||||
|  | } | ||||||
|  | .navbar { | ||||||
|  |   margin-bottom: 10px; | ||||||
|  | } | ||||||
|  | .navbar-brand { | ||||||
|  |   float: none; | ||||||
|  | } | ||||||
|  | .navbar-nav .nav-item { | ||||||
|  |   float: none; | ||||||
|  | } | ||||||
|  | .navbar-divider, | ||||||
|  | .navbar-nav .nav-item+.nav-item, | ||||||
|  | .navbar-nav .nav-link + .nav-link { | ||||||
|  |   margin-left: 0; | ||||||
|  | } | ||||||
|  | @media (min-width: 34em) { | ||||||
|  |   .navbar-brand { | ||||||
|  |     float: left; | ||||||
|  |   } | ||||||
|  |   .navbar-nav .nav-item { | ||||||
|  |     float: left; | ||||||
|  |   } | ||||||
|  |   .navbar-divider, | ||||||
|  |   .navbar-nav .nav-item+.nav-item, | ||||||
|  |   .navbar-nav .nav-link + .nav-link { | ||||||
|  |     margin-left: 1rem; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | @-moz-keyframes three-quarters-loader { | ||||||
|  |     0% { | ||||||
|  |         -moz-transform: rotate(0deg); | ||||||
|  |         transform: rotate(0deg); | ||||||
|  |     } | ||||||
|  |     100% { | ||||||
|  |         -moz-transform: rotate(360deg); | ||||||
|  |         transform: rotate(360deg); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @-webkit-keyframes three-quarters-loader { | ||||||
|  |     0% { | ||||||
|  |         -webkit-transform: rotate(0deg); | ||||||
|  |         transform: rotate(0deg); | ||||||
|  |     } | ||||||
|  |     100% { | ||||||
|  |         -webkit-transform: rotate(360deg); | ||||||
|  |         transform: rotate(360deg); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @keyframes three-quarters-loader { | ||||||
|  |     0% { | ||||||
|  |         -moz-transform: rotate(0deg); | ||||||
|  |         -ms-transform: rotate(0deg); | ||||||
|  |         -webkit-transform: rotate(0deg); | ||||||
|  |         transform: rotate(0deg); | ||||||
|  |     } | ||||||
|  |     100% { | ||||||
|  |         -moz-transform: rotate(360deg); | ||||||
|  |         -ms-transform: rotate(360deg); | ||||||
|  |         -webkit-transform: rotate(360deg); | ||||||
|  |         transform: rotate(360deg); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
							
								
								
									
										0
									
								
								resources/public/favicon.ico
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								resources/public/favicon.ico
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										21
									
								
								resources/sql/queries.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								resources/sql/queries.sql
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,21 @@ | ||||||
|  | -- :name create-user! :! :n | ||||||
|  | -- :doc creates a new user record | ||||||
|  | INSERT INTO users | ||||||
|  | (id, first_name, last_name, email, pass) | ||||||
|  | VALUES (:id, :first_name, :last_name, :email, :pass) | ||||||
|  | 
 | ||||||
|  | -- :name update-user! :! :n | ||||||
|  | -- :doc update an existing user record | ||||||
|  | UPDATE users | ||||||
|  | SET first_name = :first_name, last_name = :last_name, email = :email | ||||||
|  | WHERE id = :id | ||||||
|  | 
 | ||||||
|  | -- :name get-user :? :1 | ||||||
|  | -- :doc retrieve a user given the id. | ||||||
|  | SELECT * FROM users | ||||||
|  | WHERE id = :id | ||||||
|  | 
 | ||||||
|  | -- :name delete-user! :! :n | ||||||
|  | -- :doc delete a user given the id | ||||||
|  | DELETE FROM users | ||||||
|  | WHERE id = :id | ||||||
							
								
								
									
										56
									
								
								resources/templates/error.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								resources/templates/error.html
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,56 @@ | ||||||
|  | <!DOCTYPE html> | ||||||
|  | <html> | ||||||
|  | <head> | ||||||
|  |     <title>Something bad happened</title> | ||||||
|  |     <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> | ||||||
|  |     <meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||||||
|  |     {% style "/assets/bootstrap/css/bootstrap.min.css" %} | ||||||
|  |     {% style "/assets/bootstrap/css/bootstrap-theme.min.css" %} | ||||||
|  |     <style type="text/css"> | ||||||
|  |         html { | ||||||
|  |             height: 100%; | ||||||
|  |             min-height: 100%; | ||||||
|  |             min-width: 100%; | ||||||
|  |             overflow: hidden; | ||||||
|  |             width: 100%; | ||||||
|  |         } | ||||||
|  |         html body { | ||||||
|  |             height: 100%; | ||||||
|  |             margin: 0; | ||||||
|  |             padding: 0; | ||||||
|  |             width: 100%; | ||||||
|  |         } | ||||||
|  |         html .container-fluid { | ||||||
|  |             display: table; | ||||||
|  |             height: 100%; | ||||||
|  |             padding: 0; | ||||||
|  |             width: 100%; | ||||||
|  |         } | ||||||
|  |         html .row-fluid { | ||||||
|  |             display: table-cell; | ||||||
|  |             height: 100%; | ||||||
|  |             vertical-align: middle; | ||||||
|  |         } | ||||||
|  |     </style> | ||||||
|  | </head> | ||||||
|  | <body> | ||||||
|  | <div class="container-fluid"> | ||||||
|  |     <div class="row-fluid"> | ||||||
|  |         <div class="col-lg-12"> | ||||||
|  |             <div class="centering text-center"> | ||||||
|  |                 <div class="text-center"> | ||||||
|  |                     <h1><span class="text-danger">Error: {{status}}</span></h1> | ||||||
|  |                     <hr> | ||||||
|  |                     {% if title %} | ||||||
|  |                     <h2 class="without-margin">{{title}}</h2> | ||||||
|  |                     {% endif %} | ||||||
|  |                     {% if message %} | ||||||
|  |                     <h4 class="text-danger">{{message}}</h4> | ||||||
|  |                     {% endif %} | ||||||
|  |                 </div> | ||||||
|  |             </div> | ||||||
|  |         </div> | ||||||
|  |     </div> | ||||||
|  | </div> | ||||||
|  | </body> | ||||||
|  | </html> | ||||||
							
								
								
									
										46
									
								
								resources/templates/home.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								resources/templates/home.html
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,46 @@ | ||||||
|  | <!DOCTYPE html> | ||||||
|  | <html> | ||||||
|  |   <head> | ||||||
|  |       <META http-equiv="Content-Type" content="text/html; charset=UTF-8"> | ||||||
|  |       <meta name="viewport" content="width=device-width, initial-scale=1"> | ||||||
|  |       <title>Welcome to youyesyet</title> | ||||||
|  |   </head> | ||||||
|  |   <body> | ||||||
|  |      | ||||||
|  |     <div id="app"> | ||||||
|  |       <div class="container-fluid"> | ||||||
|  |         <div class="card-deck"> | ||||||
|  |           <div class="card-block"> | ||||||
|  |             <h4>Welcome to youyesyet</h4> | ||||||
|  |             <p>If you're seeing this message, that means you haven't yet compiled your ClojureScript!</p> | ||||||
|  |             <p>Please run <code>lein figwheel</code> to start the ClojureScript compiler and reload the page.</p> | ||||||
|  |             <h4>For better ClojureScript development experience in Chrome follow these steps:</h4> | ||||||
|  |             <ul> | ||||||
|  |               <li>Open DevTools | ||||||
|  |               <li>Go to Settings ("three dots" icon in the upper right corner of DevTools > Menu > Settings F1 > General > Console) | ||||||
|  |               <li>Check-in "Enable custom formatters" | ||||||
|  |               <li>Close DevTools | ||||||
|  |               <li>Open DevTools | ||||||
|  |             </ul> | ||||||
|  |             <p>See <a href="http://www.luminusweb.net/docs/clojurescript.md">ClojureScript</a> documentation for further details.</p> | ||||||
|  |           </div> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|  | 
 | ||||||
|  |     <!-- scripts and styles --> | ||||||
|  |     {% style "/assets/bootstrap/css/bootstrap.min.css" %} | ||||||
|  |     {% style "/assets/font-awesome/css/font-awesome.min.css" %} | ||||||
|  |     {% style "/css/screen.css" %} | ||||||
|  | 
 | ||||||
|  |     <script type="text/javascript"> | ||||||
|  |         var context = "{{servlet-context}}"; | ||||||
|  |         var csrfToken = "{{csrf-token}}"; | ||||||
|  |     </script> | ||||||
|  |     {% script "/js/app.js" %} | ||||||
|  |   </body> | ||||||
|  | </html> | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
							
								
								
									
										10
									
								
								src/clj/youyesyet/config.clj
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								src/clj/youyesyet/config.clj
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,10 @@ | ||||||
|  | (ns youyesyet.config | ||||||
|  |   (:require [cprop.core :refer [load-config]] | ||||||
|  |             [cprop.source :as source] | ||||||
|  |             [mount.core :refer [args defstate]])) | ||||||
|  | 
 | ||||||
|  | (defstate env :start (load-config | ||||||
|  |                        :merge | ||||||
|  |                        [(args) | ||||||
|  |                         (source/from-system-props) | ||||||
|  |                         (source/from-env)])) | ||||||
							
								
								
									
										71
									
								
								src/clj/youyesyet/db/core.clj
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								src/clj/youyesyet/db/core.clj
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,71 @@ | ||||||
|  | (ns youyesyet.db.core | ||||||
|  |   (:require | ||||||
|  |     [cheshire.core :refer [generate-string parse-string]] | ||||||
|  |     [clojure.java.jdbc :as jdbc] | ||||||
|  |     [conman.core :as conman] | ||||||
|  |     [youyesyet.config :refer [env]] | ||||||
|  |     [mount.core :refer [defstate]]) | ||||||
|  |   (:import org.postgresql.util.PGobject | ||||||
|  |            java.sql.Array | ||||||
|  |            clojure.lang.IPersistentMap | ||||||
|  |            clojure.lang.IPersistentVector | ||||||
|  |            [java.sql | ||||||
|  |             BatchUpdateException | ||||||
|  |             Date | ||||||
|  |             Timestamp | ||||||
|  |             PreparedStatement])) | ||||||
|  | 
 | ||||||
|  | (defstate ^:dynamic *db* | ||||||
|  |            :start (conman/connect! {:jdbc-url (env :database-url)}) | ||||||
|  |            :stop (conman/disconnect! *db*)) | ||||||
|  | 
 | ||||||
|  | (conman/bind-connection *db* "sql/queries.sql") | ||||||
|  | 
 | ||||||
|  | (defn to-date [^java.sql.Date sql-date] | ||||||
|  |   (-> sql-date (.getTime) (java.util.Date.))) | ||||||
|  | 
 | ||||||
|  | (extend-protocol jdbc/IResultSetReadColumn | ||||||
|  |   Date | ||||||
|  |   (result-set-read-column [v _ _] (to-date v)) | ||||||
|  | 
 | ||||||
|  |   Timestamp | ||||||
|  |   (result-set-read-column [v _ _] (to-date v)) | ||||||
|  | 
 | ||||||
|  |   Array | ||||||
|  |   (result-set-read-column [v _ _] (vec (.getArray v))) | ||||||
|  | 
 | ||||||
|  |   PGobject | ||||||
|  |   (result-set-read-column [pgobj _metadata _index] | ||||||
|  |     (let [type  (.getType pgobj) | ||||||
|  |           value (.getValue pgobj)] | ||||||
|  |       (case type | ||||||
|  |         "json" (parse-string value true) | ||||||
|  |         "jsonb" (parse-string value true) | ||||||
|  |         "citext" (str value) | ||||||
|  |         value)))) | ||||||
|  | 
 | ||||||
|  | (extend-type java.util.Date | ||||||
|  |   jdbc/ISQLParameter | ||||||
|  |   (set-parameter [v ^PreparedStatement stmt ^long idx] | ||||||
|  |     (.setTimestamp stmt idx (Timestamp. (.getTime v))))) | ||||||
|  | 
 | ||||||
|  | (defn to-pg-json [value] | ||||||
|  |       (doto (PGobject.) | ||||||
|  |             (.setType "jsonb") | ||||||
|  |             (.setValue (generate-string value)))) | ||||||
|  | 
 | ||||||
|  | (extend-type clojure.lang.IPersistentVector | ||||||
|  |   jdbc/ISQLParameter | ||||||
|  |   (set-parameter [v ^java.sql.PreparedStatement stmt ^long idx] | ||||||
|  |     (let [conn      (.getConnection stmt) | ||||||
|  |           meta      (.getParameterMetaData stmt) | ||||||
|  |           type-name (.getParameterTypeName meta idx)] | ||||||
|  |       (if-let [elem-type (when (= (first type-name) \_) (apply str (rest type-name)))] | ||||||
|  |         (.setObject stmt idx (.createArrayOf conn elem-type (to-array v))) | ||||||
|  |         (.setObject stmt idx (to-pg-json v)))))) | ||||||
|  | 
 | ||||||
|  | (extend-protocol jdbc/ISQLValue | ||||||
|  |   IPersistentMap | ||||||
|  |   (sql-value [value] (to-pg-json value)) | ||||||
|  |   IPersistentVector | ||||||
|  |   (sql-value [value] (to-pg-json value))) | ||||||
							
								
								
									
										279
									
								
								src/clj/youyesyet/db/schema.clj
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										279
									
								
								src/clj/youyesyet/db/schema.clj
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,279 @@ | ||||||
|  | (ns youyesyet.db.schema | ||||||
|  |   (:require [clojure.java.jdbc :as sql] | ||||||
|  |             [korma.core :as kc] | ||||||
|  |             [youyesyet.db.core :as yyydb])) | ||||||
|  | 
 | ||||||
|  | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||||
|  | ;;;; | ||||||
|  | ;;;; youyesyet.db.schema: database schema for youyesyet. | ||||||
|  | ;;;; | ||||||
|  | ;;;; 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 2 | ||||||
|  | ;;;; 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, write to the Free Software | ||||||
|  | ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, | ||||||
|  | ;;;; USA. | ||||||
|  | ;;;; | ||||||
|  | ;;;; Copyright (C) 2016 Simon Brooke | ||||||
|  | ;;;; | ||||||
|  | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | (defn create-districts-table! | ||||||
|  |   "Create a table to hold the electoral districts in which electors are registered. | ||||||
|  |   Note that, as this app is being developed for the independence referendum in which | ||||||
|  |   polling is across the whole of Scotland, this part of the design isn't fully thought | ||||||
|  |   through; if later adapted to general or local elections, some breakdown or hierarchy | ||||||
|  |   of polling districts into constituencies will be required." | ||||||
|  |   [] | ||||||
|  |   (sql/db-do-commands | ||||||
|  |     yyydb/*db* | ||||||
|  |     (sql/create-table-ddl | ||||||
|  |       :districts | ||||||
|  |       [;; it may be necessary to have a serial abstract primary key but I suspect | ||||||
|  |         ;; polling districts already have numbers assigned by the Electoral Commission and | ||||||
|  |         ;; it would be sensible to use those. TODO: check. | ||||||
|  |         [:id "integer not null primary key"] | ||||||
|  |         [:name "varchar(64) not null"] | ||||||
|  |         ;; TODO: it would make sense to hold polygon data for polling districts so we can reflect | ||||||
|  |         ;; them on the map, but I haven't thought through how to do that yet. | ||||||
|  |         ]))) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | (kc/defentity district | ||||||
|  |   (pk :id) | ||||||
|  |   (table :districts) | ||||||
|  |   (database yyydb/*db*) | ||||||
|  |   (entity-fields :id :name)) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | (defn create-addresses-table! | ||||||
|  |   "Create a table to hold the addresses at which electors are registered." | ||||||
|  |   [] | ||||||
|  |   (sql/db-do-commands | ||||||
|  |     yyydb/*db* | ||||||
|  |     (sql/create-table-ddl | ||||||
|  |       :addresses | ||||||
|  |       [[:id "serial not null primary key"] | ||||||
|  |        ;; we do NOT want to hold multiple address records for the same household. When we receive | ||||||
|  |        ;; the electoral roll data the addresses are likely to be text fields inlined in the elector | ||||||
|  |        ;; record; in digesting the roll data we need to split these out and resolve them against existing | ||||||
|  |        ;; addresses in the table, creating a new address record only if there's no match. | ||||||
|  |        [:address "varchar(256) not null unique"] | ||||||
|  |        [:postcode "varchar(16)"] | ||||||
|  |        [:phone "varchar(16)"] | ||||||
|  |        ;; the electoral district within which this address exists | ||||||
|  |        [:district "integer references districts(id)"] | ||||||
|  |        [:latitude :real] | ||||||
|  |        [:longitude :real]]))) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | (kc/defentity address | ||||||
|  |   (pk :id) | ||||||
|  |   (table :addresses) | ||||||
|  |   (database yyydb/*db*) | ||||||
|  |   (entity-fields :id :address :postcode :phone :district :latitude :longitude)) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | (defn create-authority-table! | ||||||
|  |   "Create a table to hold the oauth authorities against which we with authenticate canvassers." | ||||||
|  |   [] | ||||||
|  |   (sql/db-do-commands | ||||||
|  |     yyydb/*db* | ||||||
|  |     (sql/create-table-ddl | ||||||
|  |       :authority | ||||||
|  |       [[:id "varchar(32) not null primary key"] | ||||||
|  |        ;; more stuff here when I understand more | ||||||
|  |        ]))) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | (kc/defentity authority | ||||||
|  |   (pk :id) | ||||||
|  |   (table :authorities) | ||||||
|  |   (database yyydb/*db*) | ||||||
|  |   (entity-fields :id :authority)) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | (defn create-electors-table! | ||||||
|  |   "Create a table to hold electors data." | ||||||
|  |   [] | ||||||
|  |   (sql/db-do-commands | ||||||
|  |     yyydb/*db* | ||||||
|  |     (sql/create-table-ddl | ||||||
|  |       :electors | ||||||
|  |       [[:rollno "integer primary key"] | ||||||
|  |        [:name "varchar(64) not null"] | ||||||
|  |        [:address "integer not null references addresses(id)" ] | ||||||
|  |        [:phone "varchar(16)"] | ||||||
|  |        ;; we'll probably only capture email data on electors if they request a followup | ||||||
|  |        ;; on a particular issue by email. | ||||||
|  |        [:email "varchar(128)"]]))) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | (kc/defentity elector | ||||||
|  |   (pk :id) | ||||||
|  |   (table :districts) | ||||||
|  |   (database yyydb/*db*) | ||||||
|  |   (entity-fields :id :name)) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | (defn create-canvassers-table! | ||||||
|  |   "Create a table to hold data on canvassers (including authentication data)." | ||||||
|  |   [] | ||||||
|  |   (sql/db-do-commands | ||||||
|  |     yyydb/*db* | ||||||
|  |     (sql/create-table-ddl | ||||||
|  |       :canvassers | ||||||
|  |       [[:username "varchar(32) not null primary key"] | ||||||
|  |        [:fullname "varchar(64) not null"] | ||||||
|  |        ;; most canvassers will be electors, we should link them: | ||||||
|  |        [:elector "integer references electors(rollno) on delete no action"] | ||||||
|  |        ;; but some canvassers may not be electors, so we need contact details separately: | ||||||
|  |        [:address "integer not null references addresses(id)" ] | ||||||
|  |        [:phone "varchar(16)"] | ||||||
|  |        [:email "varchar(128)"] | ||||||
|  |        ;; with which authority do we authenticate this canvasser? I do not want to hold even | ||||||
|  |        ;; encrypted passwords locally | ||||||
|  |        [:authority "varchar(32) not null references authority(id) on delete no action"] | ||||||
|  |        ;; true if the canvasser is authorised to use the app; else false. This allows us to | ||||||
|  |        ;; block canvassers we suspect of misbehaving. | ||||||
|  |        [:authorised :boolean]]))) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | (defn create-visit-table! | ||||||
|  |   "Create a table to record visits by canvassers to addresses (including virtual visits by telephone)." | ||||||
|  |   [] | ||||||
|  |   (sql/db-do-commands | ||||||
|  |     yyydb/*db* | ||||||
|  |     (sql/create-table-ddl | ||||||
|  |       :visits | ||||||
|  |       [[:id "serial not null primary key"] | ||||||
|  |        [:canvasser "varchar(32) references canvassers(username) not null"] | ||||||
|  |        [:date "timestamp with timezone not null default now()"]]))) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | (defn create-option-table! | ||||||
|  |   "Create a table to record options in the vote. This app is being created for the Independence | ||||||
|  |    referendum, which will have just two options, 'Yes' and 'No', but it might later be adapted | ||||||
|  |    for more general political canvassing." | ||||||
|  |   [] | ||||||
|  |   (sql/db-do-commands | ||||||
|  |     yyydb/*db* | ||||||
|  |     (sql/create-table-ddl | ||||||
|  |       :options | ||||||
|  |       [[:option "varchar(32) not null primary key" | ||||||
|  |         ;; To do elections you probably need party and candidate and stuff here, but | ||||||
|  |         ;; for the referendum it's unnecessary. | ||||||
|  |         ]]))) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | (defn create-option-district-table! | ||||||
|  |   "Create a table to link options to the districts in which they are relevant. This is extremely | ||||||
|  |    simple for the referendum: both options are relevant to all districts. This table is essentially | ||||||
|  |    'for later expansion'." | ||||||
|  |   [] | ||||||
|  |   (sql/db-do-commands | ||||||
|  |     yyydb/*db* | ||||||
|  |     (sql/create-table-ddl | ||||||
|  |       :optionsdistricts | ||||||
|  |       [[:option "varchar(32) not null references options(option)"] | ||||||
|  |        [:district "integer not null references districts(id)"]]))) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | (defn create-opinion-table! | ||||||
|  |   "Create a table to record the opinion of an elector as solicited by a canvasser during a visit. | ||||||
|  |   TODO: decide whether to insert a record in this table for 'don't knows'." | ||||||
|  |   [] | ||||||
|  |   (sql/db-do-commands | ||||||
|  |     yyydb/*db* | ||||||
|  |     (sql/create-table-ddl | ||||||
|  |       :opinions | ||||||
|  |       [[:id "serial primary key"] | ||||||
|  |        ;; the elector who gave this opinion | ||||||
|  |        [:elector "integer not null references electors(rollno)"] | ||||||
|  |        ;; the option the elector said they were planning to vote for | ||||||
|  |        [:option "varchar(32) not null references options(option)"] | ||||||
|  |        [:visit "integer not null references visits(id)"]]))) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | (defn create-issues-table! | ||||||
|  |   "A table for issues we predict electors may raise on the doorstep, for which we may be | ||||||
|  |   able to provide extra information or arrange for issue-specialists to phone and talk | ||||||
|  |   to the elector." | ||||||
|  |   [] | ||||||
|  |   (sql/db-do-commands | ||||||
|  |     yyydb/*db* | ||||||
|  |     (sql/create-table-ddl | ||||||
|  |       :issues | ||||||
|  |       [;; short name of this issue, e.g. 'currency', 'defence', 'pensions' | ||||||
|  |         [:issue "varchar(32) not null primary key"] | ||||||
|  |         ;; URL of some brief material the canvasser can use on the doorstap | ||||||
|  |         [:url "varchar(256)"]]))) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | (defn create-followup-method-table! | ||||||
|  |   "Create a table to hold reference data on followup methods." | ||||||
|  |   [] | ||||||
|  |   (sql/db-do-commands | ||||||
|  |     yyydb/*db* | ||||||
|  |     (sql/create-table-ddl | ||||||
|  |       :followupmethod | ||||||
|  |       [[:method "varchar(32) not null primary key"]]))) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | (defn create-issue-expertise-table! | ||||||
|  |   "A table to record which canvassers have expertise in which issues, so that followup | ||||||
|  |   requests can be directed to the right canvassers." | ||||||
|  |   [] | ||||||
|  |   (sql/db-do-commands | ||||||
|  |     yyydb/*db* | ||||||
|  |     (sql/create-table-ddl | ||||||
|  |       :issueexpertise | ||||||
|  |       [[:expert "varchar(32) not null references canvasser(username)"] | ||||||
|  |        [:issue "varchar(32) not null references issues(issue)"] | ||||||
|  |        ;; the method by which this expert can respond to electors on this issue | ||||||
|  |        [:method "varchar 32 not null references followupmethod(method)"]]))) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | (defn create-followup-request-table! | ||||||
|  |   "Create a table to record requests for followup contacts on particular issues." | ||||||
|  |   [] | ||||||
|  |   (sql/db-do-commands | ||||||
|  |     yyydb/*db* | ||||||
|  |     (sql/create-table-ddl | ||||||
|  |       :followuprequest | ||||||
|  |       [[:id "serial primary key"] | ||||||
|  |        [:elector "integer not null references electors(rollno)"] | ||||||
|  |        [:visit "integer not null references visits(id)"] | ||||||
|  |        [:issue "varchar(32) not null references issues(issue)"] | ||||||
|  |        ;; We probably need a followupmethod (telephone, email, postal) and, for telephone, | ||||||
|  |        ;; convenient times but I haven't thought through how to represent this or how | ||||||
|  |        ;; the user interface will work. | ||||||
|  |        [:method "varchar(32) not null references followupmethod(method)"]]))) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | (defn create-followup-action-table! | ||||||
|  |   "Create a table to record actions on followup requests. Record in this table are almost | ||||||
|  |   certainly created through a desktop-style interface rather than through te app, so it's | ||||||
|  |   reasonable that there should be narrative fields." | ||||||
|  |   [] | ||||||
|  |   (sql/db-do-commands | ||||||
|  |     yyydb/*db* | ||||||
|  |     (sql/create-table-ddl | ||||||
|  |       :followupaction | ||||||
|  |       [[:id "serial primary key"] | ||||||
|  |        [:request "integer not null references followuprequest(id)"] | ||||||
|  |        [:actor "varchar(32) not null references canvassers(username)"] | ||||||
|  |        [:date "timestamp with timezone not null default now()"] | ||||||
|  |        [:notes "text"] | ||||||
|  |        ;; true if this action closes the request | ||||||
|  |        [:closed :boolean]]))) | ||||||
|  | 
 | ||||||
							
								
								
									
										47
									
								
								src/clj/youyesyet/handler.clj
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								src/clj/youyesyet/handler.clj
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,47 @@ | ||||||
|  | (ns youyesyet.handler | ||||||
|  |   (:require [compojure.core :refer [routes wrap-routes]] | ||||||
|  |             [youyesyet.layout :refer [error-page]] | ||||||
|  |             [youyesyet.routes.home :refer [home-routes]] | ||||||
|  |             [youyesyet.routes.oauth :refer [oauth-routes]] | ||||||
|  |             [compojure.route :as route] | ||||||
|  |             [youyesyet.env :refer [defaults]] | ||||||
|  |             [mount.core :as mount] | ||||||
|  |             [youyesyet.middleware :as middleware] | ||||||
|  |             [clojure.tools.logging :as log] | ||||||
|  |             [youyesyet.config :refer [env]])) | ||||||
|  | 
 | ||||||
|  | (mount/defstate init-app | ||||||
|  |                 :start ((or (:init defaults) identity)) | ||||||
|  |                 :stop  ((or (:stop defaults) identity))) | ||||||
|  | 
 | ||||||
|  | (defn init | ||||||
|  |   "init will be called once when | ||||||
|  |    app is deployed as a servlet on | ||||||
|  |    an app server such as Tomcat | ||||||
|  |    put any initialization code here" | ||||||
|  |   [] | ||||||
|  |   (doseq [component (:started (mount/start))] | ||||||
|  |     (log/info component "started"))) | ||||||
|  | 
 | ||||||
|  | (defn destroy | ||||||
|  |   "destroy will be called when your application | ||||||
|  |    shuts down, put any clean up code here" | ||||||
|  |   [] | ||||||
|  |   (doseq [component (:stopped (mount/stop))] | ||||||
|  |     (log/info component "stopped")) | ||||||
|  |   (shutdown-agents) | ||||||
|  |   (log/info "youyesyet has shut down!")) | ||||||
|  | 
 | ||||||
|  | (def app-routes | ||||||
|  |   (routes | ||||||
|  |     (-> #'home-routes | ||||||
|  |         (wrap-routes middleware/wrap-csrf) | ||||||
|  |         (wrap-routes middleware/wrap-formats)) | ||||||
|  |     #'oauth-routes | ||||||
|  |     (route/not-found | ||||||
|  |       (:body | ||||||
|  |         (error-page {:status 404 | ||||||
|  |                      :title "page not found"}))))) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | (def app (middleware/wrap-base #'app-routes)) | ||||||
							
								
								
									
										39
									
								
								src/clj/youyesyet/layout.clj
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								src/clj/youyesyet/layout.clj
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,39 @@ | ||||||
|  | (ns youyesyet.layout | ||||||
|  |   (:require [selmer.parser :as parser] | ||||||
|  |             [selmer.filters :as filters] | ||||||
|  |             [markdown.core :refer [md-to-html-string]] | ||||||
|  |             [ring.util.http-response :refer [content-type ok]] | ||||||
|  |             [ring.util.anti-forgery :refer [anti-forgery-field]] | ||||||
|  |             [ring.middleware.anti-forgery :refer [*anti-forgery-token*]])) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | (declare ^:dynamic *app-context*) | ||||||
|  | (parser/set-resource-path!  (clojure.java.io/resource "templates")) | ||||||
|  | (parser/add-tag! :csrf-field (fn [_ _] (anti-forgery-field))) | ||||||
|  | (filters/add-filter! :markdown (fn [content] [:safe (md-to-html-string content)])) | ||||||
|  | 
 | ||||||
|  | (defn render | ||||||
|  |   "renders the HTML template located relative to resources/templates" | ||||||
|  |   [template & [params]] | ||||||
|  |   (content-type | ||||||
|  |     (ok | ||||||
|  |       (parser/render-file | ||||||
|  |         template | ||||||
|  |         (assoc params | ||||||
|  |           :page template | ||||||
|  |           :csrf-token *anti-forgery-token* | ||||||
|  |           :servlet-context *app-context*))) | ||||||
|  |     "text/html; charset=utf-8")) | ||||||
|  | 
 | ||||||
|  | (defn error-page | ||||||
|  |   "error-details should be a map containing the following keys: | ||||||
|  |    :status - error status | ||||||
|  |    :title - error title (optional) | ||||||
|  |    :message - detailed error message (optional) | ||||||
|  | 
 | ||||||
|  |    returns a response map with the error page as the body | ||||||
|  |    and the status specified by the status key" | ||||||
|  |   [error-details] | ||||||
|  |   {:status  (:status error-details) | ||||||
|  |    :headers {"Content-Type" "text/html; charset=utf-8"} | ||||||
|  |    :body    (parser/render-file "error.html" error-details)}) | ||||||
							
								
								
									
										63
									
								
								src/clj/youyesyet/middleware.clj
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								src/clj/youyesyet/middleware.clj
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,63 @@ | ||||||
|  | (ns youyesyet.middleware | ||||||
|  |   (:require [youyesyet.env :refer [defaults]] | ||||||
|  |             [clojure.tools.logging :as log] | ||||||
|  |             [youyesyet.layout :refer [*app-context* error-page]] | ||||||
|  |             [ring.middleware.anti-forgery :refer [wrap-anti-forgery]] | ||||||
|  |             [ring.middleware.webjars :refer [wrap-webjars]] | ||||||
|  |             [ring.middleware.format :refer [wrap-restful-format]] | ||||||
|  |             [youyesyet.config :refer [env]] | ||||||
|  |             [ring-ttl-session.core :refer [ttl-memory-store]] | ||||||
|  |             [ring.middleware.defaults :refer [site-defaults wrap-defaults]]) | ||||||
|  |   (:import [javax.servlet ServletContext])) | ||||||
|  | 
 | ||||||
|  | (defn wrap-context [handler] | ||||||
|  |   (fn [request] | ||||||
|  |     (binding [*app-context* | ||||||
|  |               (if-let [context (:servlet-context request)] | ||||||
|  |                 ;; If we're not inside a servlet environment | ||||||
|  |                 ;; (for example when using mock requests), then | ||||||
|  |                 ;; .getContextPath might not exist | ||||||
|  |                 (try (.getContextPath ^ServletContext context) | ||||||
|  |                      (catch IllegalArgumentException _ context)) | ||||||
|  |                 ;; if the context is not specified in the request | ||||||
|  |                 ;; we check if one has been specified in the environment | ||||||
|  |                 ;; instead | ||||||
|  |                 (:app-context env))] | ||||||
|  |       (handler request)))) | ||||||
|  | 
 | ||||||
|  | (defn wrap-internal-error [handler] | ||||||
|  |   (fn [req] | ||||||
|  |     (try | ||||||
|  |       (handler req) | ||||||
|  |       (catch Throwable t | ||||||
|  |         (log/error t) | ||||||
|  |         (error-page {:status 500 | ||||||
|  |                      :title "Something very bad has happened!" | ||||||
|  |                      :message "We've dispatched a team of highly trained gnomes to take care of the problem."}))))) | ||||||
|  | 
 | ||||||
|  | (defn wrap-csrf [handler] | ||||||
|  |   (wrap-anti-forgery | ||||||
|  |     handler | ||||||
|  |     {:error-response | ||||||
|  |      (error-page | ||||||
|  |        {:status 403 | ||||||
|  |         :title "Invalid anti-forgery token"})})) | ||||||
|  | 
 | ||||||
|  | (defn wrap-formats [handler] | ||||||
|  |   (let [wrapped (wrap-restful-format | ||||||
|  |                   handler | ||||||
|  |                   {:formats [:json-kw :transit-json :transit-msgpack]})] | ||||||
|  |     (fn [request] | ||||||
|  |       ;; disable wrap-formats for websockets | ||||||
|  |       ;; since they're not compatible with this middleware | ||||||
|  |       ((if (:websocket? request) handler wrapped) request)))) | ||||||
|  | 
 | ||||||
|  | (defn wrap-base [handler] | ||||||
|  |   (-> ((:middleware defaults) handler) | ||||||
|  |       wrap-webjars | ||||||
|  |       (wrap-defaults | ||||||
|  |         (-> site-defaults | ||||||
|  |             (assoc-in [:security :anti-forgery] false) | ||||||
|  |             (assoc-in  [:session :store] (ttl-memory-store (* 60 30))))) | ||||||
|  |       wrap-context | ||||||
|  |       wrap-internal-error)) | ||||||
							
								
								
									
										35
									
								
								src/clj/youyesyet/oauth.clj
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								src/clj/youyesyet/oauth.clj
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,35 @@ | ||||||
|  | (ns youyesyet.oauth | ||||||
|  |   (:require [youyesyet.config :refer [env]] | ||||||
|  |             [oauth.client :as oauth] | ||||||
|  |             [mount.core :refer [defstate]] | ||||||
|  |             [clojure.tools.logging :as log])) | ||||||
|  | 
 | ||||||
|  | (defstate consumer | ||||||
|  |   :start (oauth/make-consumer | ||||||
|  |            (env :oauth-consumer-key) | ||||||
|  |            (env :oauth-consumer-secret) | ||||||
|  |            (env :request-token-uri) | ||||||
|  |            (env :access-token-uri) | ||||||
|  |            (env :authorize-uri) | ||||||
|  |            :hmac-sha1)) | ||||||
|  | 
 | ||||||
|  | (defn oauth-callback-uri | ||||||
|  |   "Generates the oauth request callback URI" | ||||||
|  |   [{:keys [headers]}] | ||||||
|  |   (str (headers "x-forwarded-proto") "://" (headers "host") "/oauth/twitter-callback")) | ||||||
|  | 
 | ||||||
|  | (defn fetch-request-token | ||||||
|  |   "Fetches a request token." | ||||||
|  |   [request] | ||||||
|  |   (let [callback-uri (oauth-callback-uri request)] | ||||||
|  |     (log/info "Fetching request token using callback-uri" callback-uri) | ||||||
|  |     (oauth/request-token consumer (oauth-callback-uri request)))) | ||||||
|  | 
 | ||||||
|  | (defn fetch-access-token | ||||||
|  |   [request_token] | ||||||
|  |   (oauth/access-token consumer request_token (:oauth_verifier request_token))) | ||||||
|  | 
 | ||||||
|  | (defn auth-redirect-uri | ||||||
|  |   "Gets the URI the user should be redirected to when authenticating." | ||||||
|  |   [request-token] | ||||||
|  |   (str (oauth/user-approval-uri consumer request-token))) | ||||||
							
								
								
									
										15
									
								
								src/clj/youyesyet/routes/home.clj
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								src/clj/youyesyet/routes/home.clj
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,15 @@ | ||||||
|  | (ns youyesyet.routes.home | ||||||
|  |   (:require [youyesyet.layout :as layout] | ||||||
|  |             [youyesyet.db.core :as db-core] | ||||||
|  |             [compojure.core :refer [defroutes GET]] | ||||||
|  |             [ring.util.http-response :as response] | ||||||
|  |             [clojure.java.io :as io])) | ||||||
|  | 
 | ||||||
|  | (defn home-page [] | ||||||
|  |   (layout/render "home.html")) | ||||||
|  | 
 | ||||||
|  | (defroutes home-routes | ||||||
|  |   (GET "/" [] (home-page)) | ||||||
|  |   (GET "/docs" [] (-> (response/ok (-> "docs/docs.md" io/resource slurp)) | ||||||
|  |                       (response/header "Content-Type" "text/plain; charset=utf-8")))) | ||||||
|  | 
 | ||||||
							
								
								
									
										32
									
								
								src/clj/youyesyet/routes/oauth.clj
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								src/clj/youyesyet/routes/oauth.clj
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,32 @@ | ||||||
|  | (ns youyesyet.routes.oauth | ||||||
|  |   (:require [compojure.core :refer [defroutes GET]] | ||||||
|  |             [ring.util.http-response :refer [ok found]] | ||||||
|  |             [clojure.java.io :as io] | ||||||
|  |             [youyesyet.oauth :as oauth] | ||||||
|  |             [clojure.tools.logging :as log])) | ||||||
|  | 
 | ||||||
|  | (defn oauth-init | ||||||
|  |   "Initiates the Twitter OAuth" | ||||||
|  |   [request] | ||||||
|  |   (-> (oauth/fetch-request-token request) | ||||||
|  |       :oauth_token | ||||||
|  |       oauth/auth-redirect-uri | ||||||
|  |       found)) | ||||||
|  | 
 | ||||||
|  | (defn oauth-callback | ||||||
|  |   "Handles the callback from Twitter." | ||||||
|  |   [request_token {:keys [session]}] | ||||||
|  |   ; oauth request was denied by user | ||||||
|  |   (if (:denied request_token) | ||||||
|  |     (-> (found "/") | ||||||
|  |         (assoc :flash {:denied true})) | ||||||
|  |     ; fetch the request token and do anything else you wanna do if not denied. | ||||||
|  |     (let [{:keys [user_id screen_name]} (oauth/fetch-access-token request_token)] | ||||||
|  |       (log/info "successfully authenticated as" user_id screen_name) | ||||||
|  |       (-> (found "/") | ||||||
|  |           (assoc :session | ||||||
|  |             (assoc session :user-id user_id :screen-name screen_name)))))) | ||||||
|  | 
 | ||||||
|  | (defroutes oauth-routes | ||||||
|  |   (GET "/oauth/oauth-init" req (oauth-init req)) | ||||||
|  |   (GET "/oauth/oauth-callback" [& req_token :as req] (oauth-callback req_token req))) | ||||||
							
								
								
									
										3
									
								
								src/cljc/youyesyet/validation.cljc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								src/cljc/youyesyet/validation.cljc
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,3 @@ | ||||||
|  | (ns youyesyet.validation | ||||||
|  |   (:require [bouncer.core :as b] | ||||||
|  |             [bouncer.validators :as v])) | ||||||
							
								
								
									
										20
									
								
								src/cljs/youyesyet/ajax.cljs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								src/cljs/youyesyet/ajax.cljs
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,20 @@ | ||||||
|  | (ns youyesyet.ajax | ||||||
|  |   (:require [ajax.core :as ajax])) | ||||||
|  | 
 | ||||||
|  | (defn local-uri? [{:keys [uri]}] | ||||||
|  |   (not (re-find #"^\w+?://" uri))) | ||||||
|  | 
 | ||||||
|  | (defn default-headers [request] | ||||||
|  |   (if (local-uri? request) | ||||||
|  |     (-> request | ||||||
|  |         (update :uri #(str js/context %)) | ||||||
|  |         (update :headers #(merge {"x-csrf-token" js/csrfToken} %))) | ||||||
|  |     request)) | ||||||
|  | 
 | ||||||
|  | (defn load-interceptors! [] | ||||||
|  |   (swap! ajax/default-interceptors | ||||||
|  |          conj | ||||||
|  |          (ajax/to-interceptor {:name "default headers" | ||||||
|  |                                :request default-headers}))) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
							
								
								
									
										95
									
								
								src/cljs/youyesyet/core.cljs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								src/cljs/youyesyet/core.cljs
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,95 @@ | ||||||
|  | (ns youyesyet.core | ||||||
|  |   (:require [reagent.core :as r] | ||||||
|  |             [re-frame.core :as rf] | ||||||
|  |             [secretary.core :as secretary] | ||||||
|  |             [goog.events :as events] | ||||||
|  |             [goog.history.EventType :as HistoryEventType] | ||||||
|  |             [markdown.core :refer [md->html]] | ||||||
|  |             [ajax.core :refer [GET POST]] | ||||||
|  |             [youyesyet.ajax :refer [load-interceptors!]] | ||||||
|  |             [youyesyet.handlers] | ||||||
|  |             [youyesyet.subscriptions]) | ||||||
|  |   (:import goog.History)) | ||||||
|  | 
 | ||||||
|  | (defn nav-link [uri title page collapsed?] | ||||||
|  |   (let [selected-page (rf/subscribe [:page])] | ||||||
|  |     [:li.nav-item | ||||||
|  |      {:class (when (= page @selected-page) "active")} | ||||||
|  |      [:a.nav-link | ||||||
|  |       {:href uri | ||||||
|  |        :on-click #(reset! collapsed? true)} title]])) | ||||||
|  | 
 | ||||||
|  | (defn navbar [] | ||||||
|  |   (r/with-let [collapsed? (r/atom true)] | ||||||
|  |     [:nav.navbar.navbar-light.bg-faded | ||||||
|  |      [:button.navbar-toggler.hidden-sm-up | ||||||
|  |       {:on-click #(swap! collapsed? not)} "☰"] | ||||||
|  |      [:div.collapse.navbar-toggleable-xs | ||||||
|  |       (when-not @collapsed? {:class "in"}) | ||||||
|  |       [:a.navbar-brand {:href "#/"} "youyesyet"] | ||||||
|  |       [:ul.nav.navbar-nav | ||||||
|  |        [nav-link "#/" "Home" :home collapsed?] | ||||||
|  |        [nav-link "#/about" "About" :about collapsed?]]]])) | ||||||
|  | 
 | ||||||
|  | (defn about-page [] | ||||||
|  |   [:div.container | ||||||
|  |    [:div.row | ||||||
|  |     [:div.col-md-12 | ||||||
|  |      "this is the story of youyesyet... work in progress"]]]) | ||||||
|  | 
 | ||||||
|  | (defn home-page [] | ||||||
|  |   [:div.container | ||||||
|  |    [:div.jumbotron | ||||||
|  |     [:h1 "Welcome to youyesyet"] | ||||||
|  |     [:p "Time to start building your site!"] | ||||||
|  |     [:p [:a.btn.btn-primary.btn-lg {:href "http://luminusweb.net"} "Learn more »"]]] | ||||||
|  |    (when-let [docs @(rf/subscribe [:docs])] | ||||||
|  |      [:div.row | ||||||
|  |       [:div.col-md-12 | ||||||
|  |        [:div {:dangerouslySetInnerHTML | ||||||
|  |               {:__html (md->html docs)}}]]])]) | ||||||
|  | 
 | ||||||
|  | (def pages | ||||||
|  |   {:home #'home-page | ||||||
|  |    :about #'about-page}) | ||||||
|  | 
 | ||||||
|  | (defn page [] | ||||||
|  |   [:div | ||||||
|  |    [navbar] | ||||||
|  |    [(pages @(rf/subscribe [:page]))]]) | ||||||
|  | 
 | ||||||
|  | ;; ------------------------- | ||||||
|  | ;; Routes | ||||||
|  | (secretary/set-config! :prefix "#") | ||||||
|  | 
 | ||||||
|  | (secretary/defroute "/" [] | ||||||
|  |   (rf/dispatch [:set-active-page :home])) | ||||||
|  | 
 | ||||||
|  | (secretary/defroute "/about" [] | ||||||
|  |   (rf/dispatch [:set-active-page :about])) | ||||||
|  | 
 | ||||||
|  | ;; ------------------------- | ||||||
|  | ;; History | ||||||
|  | ;; must be called after routes have been defined | ||||||
|  | (defn hook-browser-navigation! [] | ||||||
|  |   (doto (History.) | ||||||
|  |     (events/listen | ||||||
|  |       HistoryEventType/NAVIGATE | ||||||
|  |       (fn [event] | ||||||
|  |         (secretary/dispatch! (.-token event)))) | ||||||
|  |     (.setEnabled true))) | ||||||
|  | 
 | ||||||
|  | ;; ------------------------- | ||||||
|  | ;; Initialize app | ||||||
|  | (defn fetch-docs! [] | ||||||
|  |   (GET (str js/context "/docs") {:handler #(rf/dispatch [:set-docs %])})) | ||||||
|  | 
 | ||||||
|  | (defn mount-components [] | ||||||
|  |   (r/render [#'page] (.getElementById js/document "app"))) | ||||||
|  | 
 | ||||||
|  | (defn init! [] | ||||||
|  |   (rf/dispatch-sync [:initialize-db]) | ||||||
|  |   (load-interceptors!) | ||||||
|  |   (fetch-docs!) | ||||||
|  |   (hook-browser-navigation!) | ||||||
|  |   (mount-components)) | ||||||
							
								
								
									
										4
									
								
								src/cljs/youyesyet/db.cljs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								src/cljs/youyesyet/db.cljs
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,4 @@ | ||||||
|  | (ns youyesyet.db) | ||||||
|  | 
 | ||||||
|  | (def default-db | ||||||
|  |   {:page :home}) | ||||||
							
								
								
									
										18
									
								
								src/cljs/youyesyet/handlers.cljs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/cljs/youyesyet/handlers.cljs
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,18 @@ | ||||||
|  | (ns youyesyet.handlers | ||||||
|  |   (:require [youyesyet.db :as db] | ||||||
|  |             [re-frame.core :refer [dispatch reg-event-db]])) | ||||||
|  | 
 | ||||||
|  | (reg-event-db | ||||||
|  |   :initialize-db | ||||||
|  |   (fn [_ _] | ||||||
|  |     db/default-db)) | ||||||
|  | 
 | ||||||
|  | (reg-event-db | ||||||
|  |   :set-active-page | ||||||
|  |   (fn [db [_ page]] | ||||||
|  |     (assoc db :page page))) | ||||||
|  | 
 | ||||||
|  | (reg-event-db | ||||||
|  |   :set-docs | ||||||
|  |   (fn [db [_ docs]] | ||||||
|  |     (assoc db :docs docs))) | ||||||
							
								
								
									
										12
									
								
								src/cljs/youyesyet/subscriptions.cljs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/cljs/youyesyet/subscriptions.cljs
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,12 @@ | ||||||
|  | (ns youyesyet.subscriptions | ||||||
|  |   (:require [re-frame.core :refer [reg-sub]])) | ||||||
|  | 
 | ||||||
|  | (reg-sub | ||||||
|  |   :page | ||||||
|  |   (fn [db _] | ||||||
|  |     (:page db))) | ||||||
|  | 
 | ||||||
|  | (reg-sub | ||||||
|  |   :docs | ||||||
|  |   (fn [db _] | ||||||
|  |     (:docs db))) | ||||||
							
								
								
									
										7
									
								
								test/clj/features/index_page.feature
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								test/clj/features/index_page.feature
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,7 @@ | ||||||
|  | Feature: Cukes | ||||||
|  |   An example of testing a compojure app with cucumber. | ||||||
|  | 
 | ||||||
|  |   Scenario: Index Page | ||||||
|  |     Given I am at the "homepage" | ||||||
|  |     Then I should see "Welcome to youyesyet" | ||||||
|  | 
 | ||||||
							
								
								
									
										11
									
								
								test/clj/features/step_definitions/home_page_steps.clj
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								test/clj/features/step_definitions/home_page_steps.clj
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,11 @@ | ||||||
|  | (require '[clj-webdriver.taxi :as taxi] | ||||||
|  |          '[youyesyet.browser :refer [browser-up browser-down]] | ||||||
|  |          '[clojure.test :refer :all]) | ||||||
|  | 
 | ||||||
|  | (Given #"^I am at the \"homepage\"$" [] | ||||||
|  |        (browser-up) | ||||||
|  |        (taxi/to "http://localhost:3000/")) | ||||||
|  | 
 | ||||||
|  | (Then #"^I should see \"([^\"]*)\"$" [title] | ||||||
|  |       (is (= (taxi/text "div.jumbotron > h1") title)) | ||||||
|  |       (browser-down)) | ||||||
							
								
								
									
										17
									
								
								test/clj/youyesyet/browser.clj
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								test/clj/youyesyet/browser.clj
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,17 @@ | ||||||
|  | (ns youyesyet.browser | ||||||
|  |   (:require [clj-webdriver.taxi :refer :all])) | ||||||
|  | 
 | ||||||
|  | (def ^:private browser-count (atom 0)) | ||||||
|  | 
 | ||||||
|  | (defn browser-up | ||||||
|  |   "Start up a browser if it's not already started." | ||||||
|  |   [] | ||||||
|  |   (when (= 1 (swap! browser-count inc)) | ||||||
|  |     (set-driver! {:browser :firefox}) | ||||||
|  |     (implicit-wait 60000))) | ||||||
|  | 
 | ||||||
|  | (defn browser-down | ||||||
|  |   "If this is the last request, shut the browser down." | ||||||
|  |   [& {:keys [force] :or {force false}}] | ||||||
|  |   (when (zero? (swap! browser-count (if force (constantly 0) dec))) | ||||||
|  |     (quit))) | ||||||
							
								
								
									
										36
									
								
								test/clj/youyesyet/test/db/core.clj
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								test/clj/youyesyet/test/db/core.clj
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,36 @@ | ||||||
|  | (ns youyesyet.test.db.core | ||||||
|  |   (:require [youyesyet.db.core :refer [*db*] :as db] | ||||||
|  |             [luminus-migrations.core :as migrations] | ||||||
|  |             [clojure.test :refer :all] | ||||||
|  |             [clojure.java.jdbc :as jdbc] | ||||||
|  |             [youyesyet.config :refer [env]] | ||||||
|  |             [mount.core :as mount])) | ||||||
|  | 
 | ||||||
|  | (use-fixtures | ||||||
|  |   :once | ||||||
|  |   (fn [f] | ||||||
|  |     (mount/start | ||||||
|  |       #'youyesyet.config/env | ||||||
|  |       #'youyesyet.db.core/*db*) | ||||||
|  |     (migrations/migrate ["migrate"] (select-keys env [:database-url])) | ||||||
|  |     (f))) | ||||||
|  | 
 | ||||||
|  | (deftest test-users | ||||||
|  |   (jdbc/with-db-transaction [t-conn *db*] | ||||||
|  |     (jdbc/db-set-rollback-only! t-conn) | ||||||
|  |     (is (= 1 (db/create-user! | ||||||
|  |                t-conn | ||||||
|  |                {:id         "1" | ||||||
|  |                 :first_name "Sam" | ||||||
|  |                 :last_name  "Smith" | ||||||
|  |                 :email      "sam.smith@example.com" | ||||||
|  |                 :pass       "pass"}))) | ||||||
|  |     (is (= {:id         "1" | ||||||
|  |             :first_name "Sam" | ||||||
|  |             :last_name  "Smith" | ||||||
|  |             :email      "sam.smith@example.com" | ||||||
|  |             :pass       "pass" | ||||||
|  |             :admin      nil | ||||||
|  |             :last_login nil | ||||||
|  |             :is_active  nil} | ||||||
|  |            (db/get-user t-conn {:id "1"}))))) | ||||||
							
								
								
									
										13
									
								
								test/clj/youyesyet/test/handler.clj
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								test/clj/youyesyet/test/handler.clj
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,13 @@ | ||||||
|  | (ns youyesyet.test.handler | ||||||
|  |   (:require [clojure.test :refer :all] | ||||||
|  |             [ring.mock.request :refer :all] | ||||||
|  |             [youyesyet.handler :refer :all])) | ||||||
|  | 
 | ||||||
|  | (deftest test-app | ||||||
|  |   (testing "main route" | ||||||
|  |     (let [response (app (request :get "/"))] | ||||||
|  |       (is (= 200 (:status response))))) | ||||||
|  | 
 | ||||||
|  |   (testing "not-found route" | ||||||
|  |     (let [response (app (request :get "/invalid"))] | ||||||
|  |       (is (= 404 (:status response)))))) | ||||||
							
								
								
									
										8
									
								
								test/cljs/youyesyet/core_test.cljs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								test/cljs/youyesyet/core_test.cljs
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,8 @@ | ||||||
|  | (ns youyesyet.core-test | ||||||
|  |   (:require [cljs.test :refer-macros [is are deftest testing use-fixtures]] | ||||||
|  |             [reagent.core :as reagent :refer [atom]] | ||||||
|  |             [youyesyet.core :as rc])) | ||||||
|  | 
 | ||||||
|  | (deftest test-home | ||||||
|  |   (is (= true true))) | ||||||
|  | 
 | ||||||
							
								
								
									
										6
									
								
								test/cljs/youyesyet/doo_runner.cljs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								test/cljs/youyesyet/doo_runner.cljs
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,6 @@ | ||||||
|  | (ns youyesyet.doo-runner | ||||||
|  |   (:require [doo.runner :refer-macros [doo-tests]] | ||||||
|  |             [youyesyet.core-test])) | ||||||
|  | 
 | ||||||
|  | (doo-tests 'youyesyet.core-test) | ||||||
|  | 
 | ||||||
		Loading…
	
		Reference in a new issue