diff --git a/.gitignore b/.gitignore index 54cb8bb..6c01beb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,16 +1,8 @@ -*.rbc -*.sassc -.sass-cache -capybara-*.html -.rspec -/.bundle -/vendor/bundle -/log/* -/tmp/* -/db/*.sqlite3 -/public/system/* -/coverage/ -/spec/tmp/* -**.orig -rerun.txt -pickle-email-*.html \ No newline at end of file +.DS_Store +config/deploy.yml +config/database.yml +config/app_config.yml +config/initializers/secret_token.rb +log +tmp +doc diff --git a/.rspec b/.rspec new file mode 100644 index 0000000..4e1e0d2 --- /dev/null +++ b/.rspec @@ -0,0 +1 @@ +--color diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..bc08fe2 --- /dev/null +++ b/COPYING @@ -0,0 +1,619 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. diff --git a/Capfile b/Capfile new file mode 100644 index 0000000..91a2295 --- /dev/null +++ b/Capfile @@ -0,0 +1,4 @@ +load 'deploy' +# Uncomment if you are using Rails' asset pipeline +# load 'deploy/assets' # Assets compilation is done in custom task +load 'config/deploy' # remove this line to skip loading any of the default tasks \ No newline at end of file diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..9214307 --- /dev/null +++ b/Gemfile @@ -0,0 +1,51 @@ +source 'http://rubygems.org' + +gem 'rails', '3.2.13' +gem 'jquery-rails', '2.2.1' +gem 'haml', '4.0.1' + +gem 'nokogiri', '1.5.6' +gem 'feedzirra', '0.2.0.rc2' #, '0.1.3' #, :git => 'https://github.com/pauldix/feedzirra.git' + +gem 'net-ldap', '0.3.1' +gem 'bcrypt-ruby', '3.0.1' + +gem 'dalli', '2.6.2' +gem 'mysql2', '0.3.11' + +gem 'paperclip', '3.4.1' +gem 'cocaine', '0.5.1' + +gem 'daemons-rails' + +gem 'capistrano' +gem 'capistrano-ext' +gem 'whenever', require: false + +group :development, :local_test do + gem 'quiet_assets' + gem 'thin' +end + +group :test, :local_test do + gem 'rspec-rails' + gem 'factory_girl_rails' + gem 'capybara' + gem 'poltergeist' + gem 'database_cleaner' + gem 'guard-rspec' + gem 'rb-fsevent' + gem 'launchy' +end + +group :assets do + gem 'sass-rails', '3.2.6' + gem 'uglifier', '2.0.1' + gem 'therubyracer', '0.11.4', require: 'v8' +end + +group :production do +end + +group :'2_0' do +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..818c82a --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,264 @@ +GEM + remote: http://rubygems.org/ + specs: + actionmailer (3.2.13) + actionpack (= 3.2.13) + mail (~> 2.5.3) + actionpack (3.2.13) + activemodel (= 3.2.13) + activesupport (= 3.2.13) + builder (~> 3.0.0) + erubis (~> 2.7.0) + journey (~> 1.0.4) + rack (~> 1.4.5) + rack-cache (~> 1.2) + rack-test (~> 0.6.1) + sprockets (~> 2.2.1) + activemodel (3.2.13) + activesupport (= 3.2.13) + builder (~> 3.0.0) + activerecord (3.2.13) + activemodel (= 3.2.13) + activesupport (= 3.2.13) + arel (~> 3.0.2) + tzinfo (~> 0.3.29) + activeresource (3.2.13) + activemodel (= 3.2.13) + activesupport (= 3.2.13) + activesupport (3.2.13) + i18n (= 0.6.1) + multi_json (~> 1.0) + addressable (2.3.3) + arel (3.0.2) + bcrypt-ruby (3.0.1) + builder (3.0.4) + capistrano (2.14.2) + highline + net-scp (>= 1.0.0) + net-sftp (>= 2.0.0) + net-ssh (>= 2.0.14) + net-ssh-gateway (>= 1.1.0) + capistrano-ext (1.2.1) + capistrano (>= 1.0.0) + capybara (2.0.3) + mime-types (>= 1.16) + nokogiri (>= 1.3.3) + rack (>= 1.0.0) + rack-test (>= 0.5.4) + selenium-webdriver (~> 2.0) + xpath (~> 1.0.0) + childprocess (0.3.9) + ffi (~> 1.0, >= 1.0.11) + chronic (0.9.1) + climate_control (0.0.3) + activesupport (>= 3.0) + cocaine (0.5.1) + climate_control (>= 0.0.3, < 1.0) + coderay (1.0.9) + curb (0.8.3) + daemons (1.1.9) + daemons-rails (1.1.2) + daemons + multi_json (~> 1.0) + rails (~> 3.0) + dalli (2.6.2) + database_cleaner (0.9.1) + diff-lcs (1.2.2) + erubis (2.7.0) + eventmachine (1.0.3) + execjs (1.4.0) + multi_json (~> 1.0) + factory_girl (4.2.0) + activesupport (>= 3.0.0) + factory_girl_rails (4.2.1) + factory_girl (~> 4.2.0) + railties (>= 3.0.0) + faye-websocket (0.4.7) + eventmachine (>= 0.12.0) + feedzirra (0.2.0.rc2) + curb (~> 0.8.0) + gorillib (~> 0.1.9) + loofah (~> 1.2.1) + nokogiri (~> 1.5.3) + sax-machine (~> 0.2.0.rc1) + ffi (1.6.0) + formatador (0.2.4) + gorillib (0.1.11) + json + guard (1.7.0) + formatador (>= 0.2.4) + listen (>= 0.6.0) + lumberjack (>= 1.0.2) + pry (>= 0.9.10) + thor (>= 0.14.6) + guard-rspec (2.5.2) + guard (>= 1.1) + rspec (~> 2.11) + haml (4.0.1) + tilt + highline (1.6.16) + hike (1.2.1) + http_parser.rb (0.5.3) + i18n (0.6.1) + journey (1.0.4) + jquery-rails (2.2.1) + railties (>= 3.0, < 5.0) + thor (>= 0.14, < 2.0) + json (1.7.7) + launchy (2.2.0) + addressable (~> 2.3) + libv8 (3.11.8.17) + listen (0.7.3) + loofah (1.2.1) + nokogiri (>= 1.4.4) + lumberjack (1.0.3) + mail (2.5.3) + i18n (>= 0.4.0) + mime-types (~> 1.16) + treetop (~> 1.4.8) + method_source (0.8.1) + mime-types (1.22) + multi_json (1.7.2) + mysql2 (0.3.11) + net-ldap (0.3.1) + net-scp (1.1.0) + net-ssh (>= 2.6.5) + net-sftp (2.1.1) + net-ssh (>= 2.6.5) + net-ssh (2.6.6) + net-ssh-gateway (1.2.0) + net-ssh (>= 2.6.5) + nokogiri (1.5.6) + paperclip (3.4.1) + activemodel (>= 3.0.0) + activerecord (>= 3.0.0) + activesupport (>= 3.0.0) + cocaine (~> 0.5.0) + mime-types + poltergeist (1.1.0) + capybara (~> 2.0, >= 2.0.1) + faye-websocket (~> 0.4, >= 0.4.4) + http_parser.rb (~> 0.5.3) + polyglot (0.3.3) + pry (0.9.12) + coderay (~> 1.0.5) + method_source (~> 0.8) + slop (~> 3.4) + quiet_assets (1.0.2) + railties (>= 3.1, < 5.0) + rack (1.4.5) + rack-cache (1.2) + rack (>= 0.4) + rack-ssl (1.3.3) + rack + rack-test (0.6.2) + rack (>= 1.0) + rails (3.2.13) + actionmailer (= 3.2.13) + actionpack (= 3.2.13) + activerecord (= 3.2.13) + activeresource (= 3.2.13) + activesupport (= 3.2.13) + bundler (~> 1.0) + railties (= 3.2.13) + railties (3.2.13) + actionpack (= 3.2.13) + activesupport (= 3.2.13) + rack-ssl (~> 1.3.2) + rake (>= 0.8.7) + rdoc (~> 3.4) + thor (>= 0.14.6, < 2.0) + rake (10.0.4) + rb-fsevent (0.9.3) + rdoc (3.12.2) + json (~> 1.4) + ref (1.0.4) + rspec (2.13.0) + rspec-core (~> 2.13.0) + rspec-expectations (~> 2.13.0) + rspec-mocks (~> 2.13.0) + rspec-core (2.13.1) + rspec-expectations (2.13.0) + diff-lcs (>= 1.1.3, < 2.0) + rspec-mocks (2.13.1) + rspec-rails (2.13.0) + actionpack (>= 3.0) + activesupport (>= 3.0) + railties (>= 3.0) + rspec-core (~> 2.13.0) + rspec-expectations (~> 2.13.0) + rspec-mocks (~> 2.13.0) + rubyzip (0.9.9) + sass (3.2.7) + sass-rails (3.2.6) + railties (~> 3.2.0) + sass (>= 3.1.10) + tilt (~> 1.3) + sax-machine (0.2.0.rc1) + nokogiri (~> 1.5.2) + selenium-webdriver (2.31.0) + childprocess (>= 0.2.5) + multi_json (~> 1.0) + rubyzip + websocket (~> 1.0.4) + slop (3.4.4) + sprockets (2.2.2) + hike (~> 1.2) + multi_json (~> 1.0) + rack (~> 1.0) + tilt (~> 1.1, != 1.3.0) + therubyracer (0.11.4) + libv8 (~> 3.11.8.12) + ref + thin (1.5.1) + daemons (>= 1.0.9) + eventmachine (>= 0.12.6) + rack (>= 1.0.0) + thor (0.18.1) + tilt (1.3.6) + treetop (1.4.12) + polyglot + polyglot (>= 0.3.1) + tzinfo (0.3.37) + uglifier (2.0.1) + execjs (>= 0.3.0) + multi_json (~> 1.0, >= 1.0.2) + websocket (1.0.7) + whenever (0.8.2) + activesupport (>= 2.3.4) + chronic (>= 0.6.3) + xpath (1.0.0) + nokogiri (~> 1.3) + +PLATFORMS + ruby + +DEPENDENCIES + bcrypt-ruby (= 3.0.1) + capistrano + capistrano-ext + capybara + cocaine (= 0.5.1) + daemons-rails + dalli (= 2.6.2) + database_cleaner + factory_girl_rails + feedzirra (= 0.2.0.rc2) + guard-rspec + haml (= 4.0.1) + jquery-rails (= 2.2.1) + launchy + mysql2 (= 0.3.11) + net-ldap (= 0.3.1) + nokogiri (= 1.5.6) + paperclip (= 3.4.1) + poltergeist + quiet_assets + rails (= 3.2.13) + rb-fsevent + rspec-rails + sass-rails (= 3.2.6) + therubyracer (= 0.11.4) + thin + uglifier (= 2.0.1) + whenever diff --git a/Guardfile b/Guardfile new file mode 100644 index 0000000..bdf93fc --- /dev/null +++ b/Guardfile @@ -0,0 +1,16 @@ +guard 'rspec' do + # Spec files + watch(%r{^spec/.+_spec\.rb$}) + watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" } + watch('spec/spec_helper.rb') { "spec" } + watch('spec/factories.rb') { "spec" } + + # Rails files + watch(%r{^app/views/(.+)/.*\.(erb|haml)$}) { |m| "spec/features/#{m[1]}_spec.rb" } + watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| "spec/features/#{m[1]}_spec.rb" } + watch(%r{^spec/support/(.+)\.rb$}) { "spec" } + watch('config/routes.rb') { "spec/routing" } + watch('app/controllers/application_controller.rb') { "spec/controllers" } + watch(%r{^app/services/(.+)/?.*\.rb$}) { |m| "spec/services" } +end + diff --git a/README.md b/README.md deleted file mode 100644 index 84c1d6a..0000000 --- a/README.md +++ /dev/null @@ -1,4 +0,0 @@ -Dashboard -========= - -Intranet dashboard \ No newline at end of file diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..7c85094 --- /dev/null +++ b/Rakefile @@ -0,0 +1,7 @@ +#!/usr/bin/env rake +# Add your own tasks in files placed in lib/tasks ending in .rake, +# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. + +require File.expand_path('../config/application', __FILE__) + +DashboardKomin::Application.load_tasks diff --git a/app/assets/images/avatar.jpg b/app/assets/images/avatar.jpg new file mode 100644 index 0000000..5fbc498 Binary files /dev/null and b/app/assets/images/avatar.jpg differ diff --git a/app/assets/images/avatar.png b/app/assets/images/avatar.png new file mode 100644 index 0000000..8aebea2 Binary files /dev/null and b/app/assets/images/avatar.png differ diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js new file mode 100644 index 0000000..d685188 --- /dev/null +++ b/app/assets/javascripts/application.js @@ -0,0 +1,2 @@ +//= require jquery_ujs +//= require_directory . diff --git a/app/assets/javascripts/colleagues.js.erb b/app/assets/javascripts/colleagues.js.erb new file mode 100644 index 0000000..fa6fc5f --- /dev/null +++ b/app/assets/javascripts/colleagues.js.erb @@ -0,0 +1,104 @@ +// Add and remove colleagues +jQuery(document).ready(function($) { + var $colleagues = $('#colleagues'); + if ( $colleagues.length ) { + var $addTrigger = $("#add-colleague-trigger"); + var $field = $('#add_colleague'); + var $form = $('#add-colleague-form'); + var $fieldset = $form.find('fieldset'); + var $submit = $form.find("input[type=submit]"); + var $cancel = $form.find('.cancel'); + var $list = $colleagues.find('ul.box-content'); + var selectedColleagueId; + + $addTrigger.click( function(event) { + showForm(); + return false; // IE7 is very slow with preventDefault here. + }); + + var showForm = function() { + $field.val(''); + selectedColleagueId = false; + $fieldset.addClass('show'); + $field.attr('autocomplete',"off").focus(); + $addTrigger.removeClass('show'); + $list.find('.warning').remove(); + selectedUsername = ""; + }; + + // Hide the update form + var hideForm = function(initial) { + $fieldset.removeClass('show'); + $(".add p.help").hide(); + $('#add-colleague-trigger').addClass('show'); + if (!initial) { + $("#add-colleague-trigger").focus(); + } + }; + + $field.focus(function() { + // Hide on escape key + $field.on('keyup', function(e) { + if (e.which == 27) { + hideForm(); + } + }); + }); + + $field.blur(function() { + // Release esc key listners + $field.off('keyup'); + }); + + $field.autocomplete({ + source: "<%= asset_path("/colleagueships/search") %>", + minLength: 2, + autoFocus: true, + select: function( event, ui ) { + selectedColleagueId = ui.item.id; + $form.submit(); + hideForm(); + } + }) + .data( "autocomplete" )._renderItem = function( ul, item ) { + ul.addClass('search_colleagues image-list'); + return $( "
  • " ) + .data( "item.autocomplete", item ) + .append( "" + + "

    " + item.first_name + " " + item.last_name + + "
    (" + item.username + ")

    " ) + .appendTo( ul ); + }; + + $form.submit(function(event) { + event.preventDefault(); + var $newItem = $('
  • ').insertBefore( $list.find('li:last') ); + var formData = !!selectedColleagueId ? ("colleague_id=" + selectedColleagueId) : "" + $.ajax({ + type: 'POST', + url: $form.attr("action"), + data: formData, + success: function(data, textStatus, jqXHR) { + // Add the colleague to the list + $newItem.remove(); + $(data).insertBefore( $list.find('li:last') ); + hideForm(); + }, + error: function(jqXHR, textStatus, errorThrown) { + $newItem.replaceWith($('

    Ett fel inträffade. Försök lite senare.

    ')); + hideForm(); + }, + dataType: "html" + }); + }); + + // Hide colleague from list when removed (deleting managed by link) + $list.on('click', 'a.delete', function() { + $(this).closest('li').slideUp(100); + }); + // Start with hiding status form + if ( !$('#add-colleague-form fieldset.show.no-colleagues').length ) { + hideForm(true); + } + } +}); diff --git a/app/assets/javascripts/dashboard.js b/app/assets/javascripts/dashboard.js new file mode 100644 index 0000000..1d8c10b --- /dev/null +++ b/app/assets/javascripts/dashboard.js @@ -0,0 +1,14 @@ +jQuery(document).ready(function($) { + $('#username').focus(); + + // Load more feed entries async + $('.feeds').on("click", '.load-more input', function(event) { + event.preventDefault(); + $trigger = $(this); + $trigger.val("Hämtar fler...").addClass('disabled'); + + $.get($trigger.attr('data-path'), function(data) { + $trigger.parent().replaceWith(data); + }); + }); +}); diff --git a/app/assets/javascripts/edit.js b/app/assets/javascripts/edit.js new file mode 100644 index 0000000..27429b2 --- /dev/null +++ b/app/assets/javascripts/edit.js @@ -0,0 +1,32 @@ +jQuery(document).ready(function($) { + + // Check all/none checkbox for role assignment + var $toggleDepartments = $("#toggle-departments"); + var $toggleWorkingFields = $("#toggle-working_fields"); + if ( $toggleDepartments.length ) { + checkcheck($toggleDepartments, $("#check-departments")); + } + if ( $toggleDepartments.length ) { + checkcheck($toggleWorkingFields, $("#check-working_fields")); + } + + // Check/uncheck roles + function checkcheck($toggler, $roles) { + allchecked($toggler, $roles); + $toggler.change( function() { + $roles.find(":checkbox").attr("checked", $(this).is(':checked') ? true : false); + }); + $roles.change( function() { + allchecked($toggler, $roles); + }); + } + + // Check/uncheck the "All" checkbox depending on the role checkbox values + function allchecked($toggler, $roles) { + if ( $roles.find(":checkbox:checked").length === $roles.find(":checkbox").length ) { + $toggler.attr("checked", true); + } else { + $toggler.attr("checked", false); + } + } +}); diff --git a/app/assets/javascripts/search_person.js b/app/assets/javascripts/search_person.js new file mode 100644 index 0000000..1367c67 --- /dev/null +++ b/app/assets/javascripts/search_person.js @@ -0,0 +1,17 @@ +jQuery(document).ready(function($) { + + // Person search form + var $searchFormPerson = $('#search-person-form'); + + if ( $searchFormPerson.length ) { + $searchField = $('#query-person'); + + // Route form to Aastra phone catalog in new window + $searchFormPerson.submit(function(event) { + event.preventDefault(); + $searchFormPerson.find("label").removeClass("warning"); + var searchUrl = 'http://srvwindccmg02.malmo.se/netwiseoffice/common/newframes.asp?callingButton=FirstSearch&oldsearch=lname,' + escape($searchField.val()) + '|'; + window.open(searchUrl, "phonebook"); + }); + } +}); diff --git a/app/assets/javascripts/search_users.js.erb b/app/assets/javascripts/search_users.js.erb new file mode 100644 index 0000000..e91c7ef --- /dev/null +++ b/app/assets/javascripts/search_users.js.erb @@ -0,0 +1,24 @@ +// Autocomplete search for local users +jQuery(document).ready(function($) { + + var $searchUsers = $("#search-user #term"); + if ( $searchUsers.length ) { + $searchUsers.focus().autocomplete({ + source: "<%= asset_path("/users/search") %>", + minLength: 2, + autoFocus: true, + select: function( event, ui ) { + document.location = '<%= asset_path("/users/") %>' + ui.item.username; + } + }) + .data( "autocomplete" )._renderItem = function( ul, item ) { + ul.addClass('search_users image-list'); + return $( "
  • " ) + .data( "item.autocomplete", item ) + .append( "" + + "

    " + item.first_name + " " + item.last_name + + "
    (" + item.username + ")

    " ) + .appendTo( ul ); + }; + } +}); diff --git a/app/assets/javascripts/site_search.js.erb b/app/assets/javascripts/site_search.js.erb new file mode 100644 index 0000000..9cce3e6 --- /dev/null +++ b/app/assets/javascripts/site_search.js.erb @@ -0,0 +1,86 @@ +jQuery(document).ready(function($) { + + if ( $('#full-search').length ) { + if (!$('#q').val().length) $('#q').focus(); + + // Load more results async + $('#load-more-search-results a').on("click", function(event) { + event.preventDefault(); + $.get($('#load-more-search-results a').attr("href"), function(data) { + $('#load-more-search-results').replaceWith(data); + }); + $(this).text("Laddar fler...").addClass('disabled'); + }); + } + + // Autocomplete + var $searchFields = $('#q'); + if ( $searchFields.length ) { + $searchFields.autocomplete({ + source: function(request, response) { + $.ajax({ + url: "<%= APP_CONFIG['site_search_autocomplete_url'] %>", + data: { + q: request.term, + ilang: 'sv' + }, + dataType: "jsonp", + jsonpCallback: "results", + success: function(data) { + if (data.length) { + response($.map(data, function(item) { + return { + hits: item.nHits, + suggestionHighlighted: item.suggestionHighlighted, + value: item.suggestion + }; + })); + } + } + }); + }, + minLength: 1, + select: function(event, ui) { + document.location = $("#full-search").attr('action') + '?q=' + unescape(ui.item.value); + }, + open: function(event, ui) { + $searchFields.autocomplete("widget").css('width','282px'); + } + }) + .data( "autocomplete" )._renderItem = function( ul, item ) { + return $( "
  • " ) + .data( "item.autocomplete", item ) + .append( "" + item.hits + "" + item.suggestionHighlighted + "" ) + .appendTo( ul ); + }; + } + + // Event tracking of details for selected link in the search results + if ( $("section.site-search").length ) { + // Function defined in Assets 3.0 + $('section.site-search h2 a, section.site-search .ess-bestbets a, section.site-search ul.breadcrumb a, section.site-search-categories a').click(function(event) { + var $a = $(this); + if (typeof(gaDelayEvent) == "function") gaDelayEvent($a, event); + var link = $a.attr('href'); + var GAAction = $("#q").val(); + var GALabel = $.trim($a.text()) + " " + link; + + // Track all clicks in the results list + _gaq.push(['_trackEvent', 'SearchClickPosition', GAAction, GALabel, parseInt($a.closest('li').attr('data-position'), 10)]); + + // Track clicks on breadcrumbs in the results list + if ($a.closest(".breadcrumb").length > 0) { + _gaq.push(['_trackEvent', 'SearchClickBreadcrumb', GAAction, GALabel]); + } + // Track clicks on editors choich in the results list + if ($a.closest(".editors_choice").length > 0) { + _gaq.push(['_trackEvent', 'SearchClickEditorsChoice', GAAction, GALabel]); + } + + // Track clicks on editors choich in the results list + if ($a.closest(".site-search-categories").length > 0) { + _gaq.push(['_trackEvent', 'SearchClickCategory', GAAction, GALabel]); + } + }); + } +}); diff --git a/app/assets/javascripts/status_message.js b/app/assets/javascripts/status_message.js new file mode 100644 index 0000000..a538b4a --- /dev/null +++ b/app/assets/javascripts/status_message.js @@ -0,0 +1,128 @@ +// User status message update +jQuery(document).ready(function($) { + + var $form = $('#update-status-form'); + if ( $form.length ) { + var $field = $('#status_message'); + var $fieldset = $form.find("fieldset"); + var $controls = $form.find(".controls"); + var $count = $form.find(".count"); + var $submit = $form.find("input[type=submit]"); + var $cancel = $form.find('.cancel'); + var $myStatus = $('#my-status .status'); + var viewportContent = $("meta[name=viewport]").attr("content"); + + // Hide the update form + var resetForm = function() { + $field.attr('rows', 1).val("").height("1.5em").blur(); + $controls.hide(); + }; + + var narrow = function() { + return ( $(window).width() <= 480 ); + } + + // Display left characters count and disable submit button if negative + // Note: keydown/up will not do, it is possible to perform cut/paste from browser menu + $field.focus(function() { + $controls.show(); + $field.timer = setInterval( function() { + showCount($field.val(), 70 ); + autoExpand(); + }, 50); + + // Minor narrow device adjustments on focus + if ( narrow() ) $("meta[name=viewport]").attr("content", viewportContent + ', maximum-scale=1'); + + // Hide on escape key + $field.on('keyup', function(e) { + if (e.which == 27) { + resetForm(); + } + }); + // Submit on enter, strange in a textarea but it was a very explicit feature request + $field.on('keydown', function(event) { + if (event.which == 13) { + event.preventDefault(); + if ( $field.val().length > 1 && $field.val().length <= 70 ) { + $form.submit(); + } + } + }); + }); + + // Release count and esc key listners + $field.blur(function() { + clearInterval($field.timer); + // Reset viewport + if ( narrow() ) $("meta[name=viewport]").attr("content", viewportContent + ', maximum-scale=10'); + }); + + // Expand textarea height if we get scrollbars + var autoExpand = function () { + if ( $field[0].scrollHeight > $field[0].clientHeight ) { + $field.height(($field.height() + 13) + "px"); + } + }; + + var showCount = function ( chars, limit ) { + var length = chars.length; + + $count.html(limit - length); + + if ( chars.replace(/\s/g, "").length === 0 ) { // Don't allow empty updates + $submit.attr('disabled', true); + } else { + $submit.attr('disabled', false); + } + + if ( limit - length < 0 ) { + $count.addClass("error"); + $submit.attr('disabled', true); + } + else if ( limit - length < 10 ) { + $count.addClass("warning"); + } else { + $count.addClass("success"); + } + }; + + $form.submit( function(event) { + event.preventDefault(); + oldStatus = $myStatus.text(); + // Show new status immediately and close form + $myStatus.text($field.val()); + + // Put status to server and watch out for the repsonse + $.ajax({ + type: 'POST', + url: $form.attr("action"), + data: $form.serialize(), + success: function(data, textStatus, jqXHR) { + $myStatus.text(data.status_message).addClass('success'); // New status from server, just in case + $('#my-status .updated_at').text('Precis uppdaterad'); + resetForm(); + }, + error: function(jqXHR, textStatus, errorThrown) { + $myStatus.after('

    Ett fel inträffade. Försök lite senare.' + textStatus + " | " + errorThrown + '

    '); + $('#my-status .status').text(oldStatus); // Revert to old status + }, + dataType: "json" + }); + }); + } +}); + + + // Minor small device adjustments + if ( $(window).width() <= 480 ) { + // Temporarily disable zoom on text field focus + $('input') + .focus( function() { + $("meta[name=viewport]").attr("content", viewportContent + ', maximum-scale=1'); + }) + .blur( function() { + $("meta[name=viewport]").attr("content", viewportContent + ', maximum-scale=10'); + } + ); + } diff --git a/app/assets/stylesheets/application.css.scss b/app/assets/stylesheets/application.css.scss new file mode 100644 index 0000000..7b06173 --- /dev/null +++ b/app/assets/stylesheets/application.css.scss @@ -0,0 +1,7 @@ +/* Sass imports merges in to malmo.css */ +@import 'variables', 'mixins', 'functions', + 'grid', + 'feeds', 'colleagues_status', 'shortcuts', 'search_person', 'site_search', 'login', + 'edit', + 'media_queries', + 'print'; diff --git a/app/assets/stylesheets/colleagues_status.css.scss b/app/assets/stylesheets/colleagues_status.css.scss new file mode 100644 index 0000000..02b0cd2 --- /dev/null +++ b/app/assets/stylesheets/colleagues_status.css.scss @@ -0,0 +1,177 @@ +section.box#colleagues { + h1 { + margin-bottom: 0; + } + ul.box-content { + margin: 0; + li { + position: relative; + clear: both; + margin: .2em .6em 1em; + img { + float: left; + width: 46px; + height: 46px; + margin: .2em .6em 1em 0; + border: none; + } + .text { + overflow: hidden; + h2.name { + font-size: emize(13); + font-weight: normal; + line-height: emize(16, 13); + margin: 0; + } + p.status { + font-size: emize(13); + line-height: emize(16, 13); + margin-bottom: 0; + &.success { + padding: .1em .3em; + margin-bottom: .2em; + @include box-sizing(border-box); + } + } + p.updated_at { + font-family: $sansSerif; + font-size: emize(11); + color: $textColorDark; + line-height: emize(13, 11); + margin-bottom: 0; + } + } + a.delete { + position: absolute; + top: 0; + right: 0; + margin: 0; + font-family: $sansSerif; + font-size: emize(13); + color: $menuColor; + span { + font-size: emize(13); + @include opacity(.2); + } + } + &:hover a.delete { + color: $dangerColor; + span { + @include opacity(1); + } + } + &.add { + margin-top: .7em; + .help { + margin-bottom: .4em; + } + } + &.waiting { + height: 4em; + background-color: white; + background-position: left 40%; + } + .warning { + padding: .5em .8em; + font-family: $sansSerif; + } + } + li#my-status { + position: relative; + .change-image { + position: absolute; + top: 0em; + left: 0; + @include box-sizing(border-box); + display: none; + @include opacity(1); + padding: .2em .2em .3em; + width: 46px; + text-align: center; + font-size: emize(11); + font-family: $sansSerif; + background: $backgroundDarker; + color: white; + } + .img:hover .change-image { + display: block; + } + h2 a { + color: $menuColor; + } + } + .no-colleagues { + font-size: emize(13); + line-height: emize(17, 13); + margin-bottom: 1em; + label.show { + font-size: emize(13, 13); + } + } + } + + // Change status + #change-status-trigger, #add-colleague-trigger { + display: none; + font-size: emize(13); + font-family: $sansSerif; + &.show { + display: block; + } + } + + #update-status-form, #add-colleague-form { + fieldset { + display: none; + clear: both; + padding: 0 0 .4em; + margin: 0; + &.show, .show { + display: block; + } + label { + display: none; + margin-bottom: 0.1em; + font-family: $sansSerif; + } + #status_message { + width: 93%; + margin-bottom: .3em; + resize: none; + height: 1.5em; + overflow: hidden; + } + #add_colleague { + width: 95%; + margin-bottom: .3em; + } + .controls { + display: none; + } + } + } + #update-status-form { + padding: .4em .4em 0; + margin-bottom: .3em; + background: $backgroundLight; + border-bottom: $border; + border-top: $border; + .count { + float: right; + padding: .1em; + width: 2.2em; + text-align: center; + font-family: $sansSerif; + font-size: emize(11); + @include radius(3px); + } + #cancel-trigger { + float: left; + } + } +} + +// jQ UI theme overide +.suggest_colleagues { + font-size: emize(11) !important; +} diff --git a/app/assets/stylesheets/edit.css.scss b/app/assets/stylesheets/edit.css.scss new file mode 100644 index 0000000..e895364 --- /dev/null +++ b/app/assets/stylesheets/edit.css.scss @@ -0,0 +1,78 @@ +.edit { + section.form, section.index, section.show { + @include columns(9); + margin-bottom: 2em; + } + + .avatar { + .control-group { + clear: both; + } + } + .edit_avatar { + width: 30%; + float: left; + img { + width: 90%; + max-width: 12em; + height: auto; + } + } + .avatar-help { + overflow: hidden; + } + + table { + width: 100%; + td, th { + &.url, &.title { + max-width: 16em; + span { + display: block; + max-width: 15em; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + } + } + } + } + + + nav.admin { + @include columns(3, true); + margin-bottom: 2em; + background: $backgroundLight; + h2 { + @include radius(0); + margin: 0; + } + ul { + &.users .users a, + &.roles .roles a, + &.feeds .feeds a, + &.shortcuts .shortcuts a, + a:hover { + background: $backgroundLightHover; + } + } + li { + a { + display: block; + padding: .5em 1em .6em; + border-top: white 1px solid; + border-bottom: $border; + font-size: emize(13); + line-height: emize(17, 13); + font-family: $sansSerif; + color: $menuColor; + &:focus, &:hover { + background: $backgroundLightHover; + } + } + } + &:last-child { + border-bottom: none; + } + } +} diff --git a/app/assets/stylesheets/feeds.css.scss b/app/assets/stylesheets/feeds.css.scss new file mode 100644 index 0000000..8ede003 --- /dev/null +++ b/app/assets/stylesheets/feeds.css.scss @@ -0,0 +1,143 @@ +section.box.feeds { + h1 { + margin-bottom: 0; + } + .box-content { + margin: 0; + ul { + margin: 0; + padding: 0; + } + li { + margin: 0; + overflow: hidden; + a { + display: block; + @include box-sizing('border-box'); + padding: 0.4em .7em 0; + border: solid white; + border-width: 1px 0; + margin: 0; + &:hover { + cursor: pointer; + background-color: $backgroundLight; + border-color: $borderColor; + } + p.summary, p.meta { + color: black; + } + } + img, span.icon-twitter, span.icon-rss { + float: left; + width: 46px; + margin: 3px 10px 11px 0; + border: none; + } + span.icon-twitter, span.icon-rss { + font-size: emize(46); + color: $backgroundDark; + overflow: hidden; + } + .text { + overflow: hidden; + margin-bottom: .5em; + h2 { + margin: 0 0 .1em; + padding: 0; + font-size: emize(20); + line-height: 1.2; + font-weight: normal; + } + p.summary, p.nomore { + font-size: emize(16); + line-height: emize(21, 16); + margin-bottom: .1em; + } + p.meta { + font-family: $sansSerif; + font-size: emize(13); + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + margin: 0; + color: $textColorDark; + span.comments { + display: block; + .icon-comment, .icon-comment-alt { + font-size: emize(15, 13); + color: $linkColor; + } + } + } + } + } + li.load-more { + padding: .2em .8em .8em; + .btn { + font-size: emize(13); + } + } + } +} + +section.box#feeds-news { + .box-content { + li { + img { + width: 68px; + margin-top: .3em; + } + } + li:first-child { + a { + padding-bottom: 0.4em; + } + img { + width: 120px; + margin: .3em 1em 0 0; + } + h2 { + margin: 0; + padding: 0; + font-size: emize(28); + line-height: emize(28, 26); + font-weight: normal; + } + p.summary { + font-size: emize(20); + line-height: emize(26, 20); + } + p.meta { + font-size: emize(13); + } + } + } +} + +section.box#feeds-feature { + .text { + clear: both; + h2 { + font-size: emize(20); + } + } + .crop { + max-height: 9em; + overflow: hidden; + margin-bottom: .5em; + border: $border; + } + img { + width: 100%; + height: auto; + } + .more { + margin: 0; + } + .more a { + font-family: $sansSerif; + font-size: emize(13); + padding-bottom: .4em; + border-bottom: 0; + } +} diff --git a/app/assets/stylesheets/functions.css.scss b/app/assets/stylesheets/functions.css.scss new file mode 100644 index 0000000..d00aaa0 --- /dev/null +++ b/app/assets/stylesheets/functions.css.scss @@ -0,0 +1,7 @@ +// Convenience function that calulates a size in em's based on the $context +// Note: Use only for font-size and line-height +// $target = rendering in pixel (well, maybe) +// $context = the DOM context em size +@function emize($target, $context: 16) { + @return ($target / $context) * 1em; +} diff --git a/app/assets/stylesheets/grid.css.scss b/app/assets/stylesheets/grid.css.scss new file mode 100644 index 0000000..20e0031 --- /dev/null +++ b/app/assets/stylesheets/grid.css.scss @@ -0,0 +1,22 @@ +body.malmo-masthead-dashboard { + padding: 0 .5em; + min-width: 56em; +} + +.wrapper { + max-width: 75em; + margin: 1em auto; +} + +.column { + margin-bottom: 1em; +} +.column-1 { + @include columns(3); +} +.column-2 { + @include columns(6); +} +.column-3 { + @include columns(3, true); +} diff --git a/app/assets/stylesheets/legacy/ie7.css.scss b/app/assets/stylesheets/legacy/ie7.css.scss new file mode 100644 index 0000000..26b0c65 --- /dev/null +++ b/app/assets/stylesheets/legacy/ie7.css.scss @@ -0,0 +1,21 @@ +section.box#search-person { + .box-content { + input#query-person { + width: 62%; + } + } +} + +section.box#colleagues { + padding-bottom: 1em; + #update-status-form { + fieldset { + .controls { + display: block; + } + } + input { + float: left; + } + } +} diff --git a/app/assets/stylesheets/legacy/ie9.css.scss b/app/assets/stylesheets/legacy/ie9.css.scss new file mode 100644 index 0000000..cb03b94 --- /dev/null +++ b/app/assets/stylesheets/legacy/ie9.css.scss @@ -0,0 +1,9 @@ +section.box#colleagues { + #update-status-form { + fieldset { + label { + display: block; + } + } + } +} diff --git a/app/assets/stylesheets/login.css.scss b/app/assets/stylesheets/login.css.scss new file mode 100644 index 0000000..29b532b --- /dev/null +++ b/app/assets/stylesheets/login.css.scss @@ -0,0 +1,57 @@ +.login .column-1 { + @include columns(5); +} +.login .column-2 { + @include columns(7, true); +} + +section#feature { + margin-top: 1.2em; + h1 { + font-size: emize(32); + line-height: emize(38, 32); + font-weight: normal; + margin: 0em 0 .1em; + } + p.about { + font-size: emize(20); + line-height: emize(28, 20); + font-style: italic; + margin-bottom: 1em; + } +} + +section#login { + margin-top: 1.6em; + label { + font-size: emize(13); + } + input[type="text"], + input[type="password"] { + font-size: emize(15); + } + input.btn { + margin-top: 1em; + clear: both; + } + ul.warning { + margin: 0 0 1em; + padding: 0; + li { + font-family: $sansSerif; + } + } + .login-instructions { + margin-top: 2em; + padding-top: .5em; + border-top: $border; + font-style: normal; + font-size: emize(15); + line-height: emize(19, 15); + margin-bottom: .5em; + } + .login .warning { + width: 28.8em; + margin: 0 auto -3em; + } +} diff --git a/app/assets/stylesheets/media_queries.css.scss b/app/assets/stylesheets/media_queries.css.scss new file mode 100644 index 0000000..d627a3b --- /dev/null +++ b/app/assets/stylesheets/media_queries.css.scss @@ -0,0 +1,361 @@ +@media ( min-width: 68em ) { + section.box#feeds-news .box-content li:first-child { + h2 { + font-size: emize(32); + } + } +} + +@media ( max-width: 68em ) { + body.malmo-masthead-dashboard { + min-width: 0; + } + section.box#feeds-news .box-content { + li.first-child { + h2 { + font-size: emize(20); + } + p.summary { + font-size: emize(15); + line-height: emize(19, 15);; + } + img { + width: 68px; + margin-top: .3em; + } + } + } + section#feature { + h1 { + font-size: emize(28); + } + p.about { + font-size: emize(18); + } + } +} + +@media ( max-width: 62em ) { + .column-1 { + @include columns(4); + } + .column-2 { + @include columns(8, true); + } + .column-3 { + clear: both; + @include columns(12); + } + + section#feature { + h1 { + font-size: emize(26); + line-height: emize(28, 26); + } + p.about { + font-size: emize(18); + line-height: emize(26, 18); + } + } + section.box#shortcuts-tools, + section.box#shortcuts-i-want { + h1.box-title { + margin-bottom: 0; + } + .box-content { + margin: 0; + li { + margin: 0; + a { + display: block; + margin: 0; + padding: .7em; + border-bottom: 1px $borderColor solid; + &:focus, &:hover, &:active { + background-color: $backgroundLight; + } + } + } + } + } + + .malmo-form .edit { + th.url, td.url { + display: none; + } + } +} + +@media ( max-width: 51em ) { + .column-1 { + @include columns(4); + } + .column-2 { + @include columns(8, true); + } + + body { + .wrapper { + margin: 0 1em; + padding-bottom: 1em; + } + padding: 0; + margin-left: 0; + margin-right: 0; + section.box { + margin: 0 0 1em; + h1 { + padding-left: .8em; + } + label.context-menu { + right: .6em; + } + } + } + + section.box#colleagues ul.box-content li img { + width: 32px; + height: 32px; + } + + .login .column-1 { + @include columns(6); + } + .login .column-2 { + @include columns(6, true); + } + section#login { + border-left: none; + padding-top: 0; + margin-top: 0; + } + + section#feature { + h1 { + margin: 0 0 .2em; + font-size: emize(26); + } + p.about { + font-size: emize(16); + line-height: emize(24, 16); + } + } + + .malmo-form .edit { + section.index, section.show, section.form, nav.admin { + @include columns(12); + } + th.secondary, td.secondary { + display: none; + } + } +} + +@media ( max-width: 52em ) { + section.site-search { + @include columns(8); + } + section.site-search-categories { + @include columns(4, true); + } +} + +@media ( max-width: 46em ) { + section.site-search, section.site-search-categories { + @include columns(12); + } + section.site-search { + margin-bottom: 0; + } + section.site-search-categories { + .ess-cat-bd-category, .ess-cat-bd-heading, .ess-cat-bd-all { + font-size: emize(15); + margin-bottom: .5em; + } + } + section.site-search-categories .ess-cat-bd-heading { + margin-top: 1.5em; + } + .malmo-form.edit { + nav.admin { + clear: both; + } + h1, nav.admin h2 { + @include radius(0); + } + section.form, section.show, section.index, nav.admin { + width: 100%; + @include radius(0); + } + section.index, section.show, section.form { + @include radius(0); + border: none; + margin-bottom: 0; + } + div.field { + label { + clear: both; + width: 100%; + float: none; + } + .help { + margin-left: 0; + } + } + .avatar-help, .edit_avatar { + width: 100%; + clear: both; + } + } + .malmo-form { + .form-horizontal { + .controls, .actions, .readonly { + margin-left: 0; + clear: both; + } + .control-label { + width: auto; + } + } + .control-group.readonly { + margin-bottom: 1em; + .control-label, .controls { + padding: 0; + } + } + } +} + +@media ( max-width: 44em ) { + body.site-search .wrapper { + font-size: emize(16, 16); + padding: 0 1em; + } + + body { + margin-left: 0; + margin-right: 0; + background-color: white; + .wrapper { + // font-size: emize(18, 16); + margin: 0; + } + + // One column layout + .column { + float: none; + margin-bottom: 0; + @include columns(12); + &.column-1, &.column-2, &.column-3 { + margin-right: 0; + margin-left: 0; + width: 100%; + } + } + + &.malmo-masthead-dashboard { + padding: 0; + margin: 0; + section.box { + border: none; + @include radius(0); + margin: 0 0 1em; + h1 { + padding-left: .8em; + @include radius(0); + } + label.context-menu { + right: .6em; + } + } + + section.box#colleagues ul.box-content li img { + width: 46px; + height: 46px; + } + + section.box.feeds { + .box-content li { + .summary { + display: none; + } + .text { + h2 { + margin: 0; + padding: 0; + } + p.meta { + font-size: emize(11); + } + } + } + } + section.box#feeds-news, section.box#feeds-dialog, section.box#my_own { + .box-content li { + a { + @include clearfix(); + } + img { + width: 46px; + height: 46px; + } + } + } + + section.box#feeds-news .box-content li:first-child { + img { + width: 46px; + margin: 3px 10px 11px 0; + } + h2 { + font-size: emize(20); + } + p.summary { + font-size: emize(16); + } + } + + section.box#feeds-feature { + a { + @include clearfix(); + } + img { + @include columns(6); + max-width: 12em; + max-height: 12em; + } + .crop { + overflow: visible; + margin-bottom: 0; + border: none; + } + .text { + @include columns(6, true); + clear: none; + h2 { + font-family: $serif; + font-size: emize(20); + } + } + .more { + clear: both; + } + } + } + } + section#feature { + margin: 1em .7em 1em; + } +} + + +// Force a one column form +@media ( max-width: 40em ) { + @include form-force-vertical; +} + +@media ( max-width: 36em ) { + section.site-search #q { + max-width: 60%; + } +} diff --git a/app/assets/stylesheets/mixins.css.scss b/app/assets/stylesheets/mixins.css.scss new file mode 100644 index 0000000..dcabf51 --- /dev/null +++ b/app/assets/stylesheets/mixins.css.scss @@ -0,0 +1,81 @@ +@mixin columns($span, $last: false, $gutter: 2%) { + $total-columns: 12; // Number of columns in the grid + + // (column width in percentage) minus its (own portion of all the gutters) + width: percentage($span / $total-columns) - (($total-columns / $span - 1) * $gutter / ($total-columns / $span)); + *width: percentage($span / $total-columns) - (($total-columns / $span) * $gutter / ($total-columns / $span)); // IE7 hack, difficult to put in ie7css + + // No gutter to the left if the column is the last to the right + @if not $last { + margin-right: $gutter; + } @else { + margin-right: 0; + } + @if $span == $total-columns { + margin-right: 0; + float: none; + } + + float: left; + @include box-sizing(border-box); +} + +@mixin radius($values) { + -moz-border-radius: $values; + -webkit-border-radius: $values; + border-radius: $values; +} + +@mixin transition($values) { + -webkit-transition: $values; + -moz-transition: $values; + -o-transition: $values; + transition: $values; +} + +@mixin box-shadow($values) { + -moz-box-shadow: $values; + -webkit-box-shadow: $values; + box-shadow: $values; +} + +@mixin opacity($value) { + -ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=(#{$value * 100})); + filter: alpha(opacity=($value * 100)); + opacity: $value; +} + +@mixin box-sizing($boxmodel) { + -ms-box-sizing: $boxmodel; + -webkit-box-sizing: $boxmodel; + -moz-box-sizing: $boxmodel; + box-sizing: $boxmodel; +} + +// Use with a media query to disable the hz mode below a breakpoint +@mixin form-force-vertical() { + .form-horizontal { + .control-label { + display: block; + width: 100%; + } + .controls { + width: 100%; + margin-left: 0; + clear: both; + } + } +} + +@mixin clearfix() { + *zoom: 1; + &:before, + &:after { + display: table; + content: ""; + line-height: 0; + } + &:after { + clear: both; + } +} diff --git a/app/assets/stylesheets/print.css.scss b/app/assets/stylesheets/print.css.scss new file mode 100644 index 0000000..0abbe7c --- /dev/null +++ b/app/assets/stylesheets/print.css.scss @@ -0,0 +1,9 @@ +@media print { + #update-status-form, + #search-person, + #colleagues .add, + #shortcuts-tools, + #shortcuts-i-want { + display: none !important; + } +} diff --git a/app/assets/stylesheets/search_person.css.scss b/app/assets/stylesheets/search_person.css.scss new file mode 100644 index 0000000..0b34712 --- /dev/null +++ b/app/assets/stylesheets/search_person.css.scss @@ -0,0 +1,20 @@ +section.box#search-person { + .box-content { + margin-top: 0; + padding: 0; + label, p { + font-family: $sansSerif; + font-size: emize(13); + } + label { + display: block; + margin-bottom: .1em; + } + input#query-person { + width: 68%; + } + } +} +.search_users .suggest-users p { + font-size: emize(13, 14); +} diff --git a/app/assets/stylesheets/shortcuts.css.scss b/app/assets/stylesheets/shortcuts.css.scss new file mode 100644 index 0000000..7920960 --- /dev/null +++ b/app/assets/stylesheets/shortcuts.css.scss @@ -0,0 +1,11 @@ +section.box#shortcuts-tools, +section.box#shortcuts-i-want { + .box-content { + li { + margin-bottom: .2em; + font-size: emize(13); + line-height: emize(21, 13); + font-family: $sansSerif; + } + } +} diff --git a/app/assets/stylesheets/site_search.css.scss b/app/assets/stylesheets/site_search.css.scss new file mode 100644 index 0000000..1bd8c54 --- /dev/null +++ b/app/assets/stylesheets/site_search.css.scss @@ -0,0 +1,156 @@ +body.site-search .wrapper { + max-width: 56em; + margin: 0 auto; + @include clearfix(); +} + +section.site-search { + margin: .45em 0 2em; + @include columns(9, false, 4%); +} + +section.site-search-categories { + margin-top: 0; + @include columns(3, true, 4%); +} + +section.site-search { + h1 { + display: none; + } + form label { + font-family: $serif; + font-size: emize(32); + margin-bottom: .4em; + } + #q { + width: 30em; + max-width: 75%; + } + .sort { + margin-bottom: 1.5em; + font-family: $sansSerif; + font-size: emize(13); + } + .sort li { + display: inline; + margin: 0; + } + .results { + ul { + margin: 0; + } + h2 { + margin-top: 0; + } + li { + margin: 0 0 1.5em; + } + } + .results { + ul, li { + list-style: none; + margin-left: 0; + padding-left: 0; + } + .extract { + margin-bottom: .3em; + .date, .file_info { + font-family: $sansSerif; + font-size: emize(13); + } + .date { + margin-left: .5em; + } + } + .category { + font-family: $sansSerif; + font-size: emize(13); + margin-bottom: .4em; + } + .breadcrumb { + margin: 0; + line-height: 1.1; + font-family: $sansSerif; + li { + display: inline; + font-size: emize(13); + line-height: 1.1; + a:after { + content: ("\f054"); + font-family: $iconFont; + margin: 0 .5em 0 .7em; + font-size: emize(13); + } + } + } + } + .suggestions { + list-style: none; + margin: 0; + padding: 0; + li { + display: inline; + margin-left: 0; + } + } + .summary { + margin-bottom: .5em; + font-family: $sansSerif; + font-size: emize(13); + } + .ess-bestbets { + .ess-header { + font-size: emize(22); + line-height: 1.1; + margin: 1em 0 .1em; + } + dd { + margin: 0; + padding: 0; + } + } +} + +section.site-search-categories { + h2 { + margin-top: 0; + } + font-family: $sansSerif; + div { + margin-bottom: 1em; + } + .ess-heading { + font-family: $sansSerif; + margin-bottom: .2em; + padding-bottom: .2em; + border-bottom: $border; + font-weight: bold; + font-size: emize(15); + } + .ess-cat-bd-heading { + margin-bottom: .2em; + font-weight: bold; + font-size: emize(13); + } + .ess-cat-bd-category, .ess-cat-bd-all { + margin-bottom: .2em; + font-size: emize(13); + } + strong { + font-weight: normal; + } + .ess-current, .ess-current strong { + font-weight: bold; + } +} + +ul.ui-autocomplete { + width: 24.7em !important; + li { + font-size: emize(13); + .hits { + float: right; + } + } +} diff --git a/app/assets/stylesheets/variables.css.scss b/app/assets/stylesheets/variables.css.scss new file mode 100644 index 0000000..9fcae81 --- /dev/null +++ b/app/assets/stylesheets/variables.css.scss @@ -0,0 +1,32 @@ +// Colors +$bodyColor: black; +$menuColor: $bodyColor; + +$linkColor: #007133; + +$borderColor: #ccc; +$border: $borderColor 1px solid; +$borderColorDark: darken($borderColor, 20%); +$borderDark: $borderColorDark 1px solid; + +$backgroundLight: #f5f5f5; +$backgroundLightHover: darken($backgroundLight, 5%); +$backgroundDark: #888; +$backgroundDarker: darken($backgroundDark, 14%); + +$textColorDark: $backgroundDark; + +$mastheadBackground: #444; +$mastheadBackgroundHighlight: #b10000; +$mastheadBackgroundHighlightGlare: lighten($mastheadBackgroundHighlight, 9%); + +$boxShadow: 2px 2px 3px #ccc; + +$dangerColor: #c00; + +// Fonts +$sansSerif: 'OpenSans', 'Verdana', 'DejaVu Sans', 'Bitstream Vera Sans', sans-serif; +$serif: Georgia, 'DejaVu Serif', 'Bitstream Vera Serif', serif; +/* NOTE: Use with font-weight: normal */; +$sansSerifSemibold: 'OpenSansSemibold', 'DejaVu Sans', 'Bitstream Vera Sans', sans-serif; +$iconFont: FontAwesome; \ No newline at end of file diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb new file mode 100644 index 0000000..568aa44 --- /dev/null +++ b/app/controllers/application_controller.rb @@ -0,0 +1,130 @@ +# -*- coding: utf-8 -*- +class ApplicationController < ActionController::Base + protect_from_forgery + before_filter :init_body_class + + # Set a permanent cookie w/data from the user profile. Used by the masthead in other webapps + def set_profile_cookie + departments = current_user.roles.map { |d| { name: d.name, homepage_url: d.homepage_url } if d.category == 'department' }.compact + workingfields = current_user.roles.map { |w| { name: w.name, homepage_url: w.homepage_url } if w.category == 'working_field' }.compact + + if Rails.env.development? + myprofile = "myprofile-development" + elsif Rails.env.test? + myprofile = "myprofile-test" + else + myprofile = "myprofile" + end + + cookies.permanent[myprofile] = { + value: { + # Singular is for old style masthead + department: departments.present? ? departments.first[:homepage_url].gsub('http://komin.malmo.se/', '') : '', + workingfield: workingfields.present? ? workingfields.first[:homepage_url].gsub('http://komin.malmo.se/', '') : '', + # Plural for masthead w/dropdowns + departments: departments, + workingfields: workingfields + }.to_json, + expires: 365*10, + path: '/', + domain: 'malmo.se' + } + end + + # Catch errors and record not founds + unless Rails.env.development? + rescue_from ActionController::RoutingError, with: :not_found + rescue_from AbstractController::ActionNotFound, with: :not_found + rescue_from ActiveRecord::RecordNotFound, with: :not_found + rescue_from Exception, with: :error + end + def method_missing(method, *args) + not_found + end + + def not_found(exception = "404") + logger.warn "#{exception} #{request.fullpath}" + reset_body_classes + render template: "404", status: 404 + end + + def error(exception = "500") + logger.error("Exception: #{exception}\n" + + "#{' ' * 32 }User id: #{user? ? session[:user_id] : 'anonymous'}\n" + + "#{' ' * 32 }Params: #{params}") + reset_body_classes + render template: "500", status: 500 + end + + protected + + def user? + session[:user_id] + end + + def current_user + @current_user ||= User.find(session[:user_id]) if user? + end + + def admin? + user? and current_user.is_admin + end + + def require_user + redirect_to login_path unless user? + end + helper_method :user?, :admin?, :current_user + + def require_admin + not_authorized unless admin? + end + + # Use only when params[:id] is users id + def editing_myself? + current_user.id.to_i === params[:id].to_i + end + helper_method :editing_myself? + + def require_admin_or_myself + not_authorized unless admin? or editing_myself? + end + + def not_authorized(msg = "Du saknar behörighet för detta" ) + flash[:error] = msg + redirect_to root_path + end + + def allow_stubs? + + unless APP_CONFIG['allow_stubs'] + flash[:error] = 'Stubs are not activated' + redirect_to root_path + end + end + + def init_body_class + add_body_class(Rails.env) + add_body_class('malmo-masthead-dashboard') + add_body_class("user") if current_user + end + + # Adds classnames to the body tag + def add_body_class(name) + @body_classes ||= "" + @body_classes << "#{name} " + end + + def reset_body_classes + @body_classes = nil + init_body_class + end + + def sub_layout(name = "") + @sub_layout = name + end + + def avatar_full_url(username, style = :medium_quadrat) + "#{request.protocol}#{File.join(APP_CONFIG['avatar_base_url'], username, style.to_s)}.jpg" + end + helper_method :avatar_full_url +end diff --git a/app/controllers/avatars_controller.rb b/app/controllers/avatars_controller.rb new file mode 100644 index 0000000..557a333 --- /dev/null +++ b/app/controllers/avatars_controller.rb @@ -0,0 +1,43 @@ +# -*- coding: utf-8 -*- +class AvatarsController < ApplicationController + + before_filter { add_body_class('edit') } + before_filter { sub_layout("admin") if admin? } + before_filter :require_user, except: "show" + before_filter :require_admin_or_myself, except: "show" + + # Stream the :usernames's profile picture, or use the fallback avatar.png + def show + @user = User.where(username: params[:username]).first + if @user.blank? + render text: '404 Not found', status: 404 + else + style = params[:style].present? ? params[:style] : @user.avatar.default_style.to_s + begin + # Send etag based on the age of the image and the style + fresh_when etag: @user.avatar_updated_at.to_s + style + send_file @user.avatar.path(style) || File.join(Rails.root, 'app/assets/images/avatar.jpg'), + type: @user.avatar_content_type || "image/jpg", + disposition: 'inline' + rescue + render text: '404 Not found', status: 404 + end + end + end + + def edit + @user = User.find(params[:id]) + # We need to know where we should send the user after update + session[:referer] = request.env["HTTP_REFERER"] || nil + end + + def update + @user = User.find(params[:id]) + # Some User fields require admin rights for mass assignment + if @user.update_attributes(params[:user], as: ( :admin if admin? )) + redirect_to session[:referer] || user_path(@user.username), notice: "Profilbilden uppdaterades" + else + render action: "edit" + end + end +end diff --git a/app/controllers/colleagueships_controller.rb b/app/controllers/colleagueships_controller.rb new file mode 100644 index 0000000..756b1bb --- /dev/null +++ b/app/controllers/colleagueships_controller.rb @@ -0,0 +1,31 @@ +class ColleagueshipsController < ApplicationController + before_filter :require_user + + def search + term = "%#{params[:term]}%" + if term.present? + @colleagues = Colleagueship.search(current_user, term, 20) + else + @colleagues = {} + end + render json: @colleagues.map { |c| + email = (c.email.present? ? c.email : "ingen e-postaddress").downcase + { id: c.id, username: c.username, email: email, avatar_full_url: "#{avatar_full_url(c.username, :mini_quadrat)}", first_name: c.first_name, last_name: c.last_name } + } + end + + def create + @colleagueship = current_user.colleagueships.build(colleague_id: params[:colleague_id]) + if @colleagueship.save + render "created", layout: false + else + render "failed", layout: false + end + end + + def destroy + @colleagueship = current_user.colleagueships.find(params[:id]) + @colleagueship.destroy + render json: { status: :deleted } + end +end diff --git a/app/controllers/dashboard_controller.rb b/app/controllers/dashboard_controller.rb new file mode 100644 index 0000000..7f4d983 --- /dev/null +++ b/app/controllers/dashboard_controller.rb @@ -0,0 +1,51 @@ +# -*- coding: utf-8 -*- + +# Model-less controller for dashboard data from other models +class DashboardController < ApplicationController + before_filter :require_user + + def index + @limit = 5 + @feature_entry = cache_users_entries_for("feature").first + @feature_feed_url = Feed.where(category: "feature").first + + @news_entries = cache_users_entries_for("news") + @dialog_entries = cache_users_entries_for("dialog") + @my_own_entries = cache_users_entries_for("my_own") + + @tools_and_systems = cache_users_shortcuts_for("tools_and_systems") + @i_want = cache_users_shortcuts_for("i_want") + + @colleagueships = current_user.sorted_colleagues + end + + # Load more feed entries in requested category + def more_feed_entries + @limit = 10 + @category = params[:category] + @entries = current_user.feed_entries_in_category(@category, before: Time.at(params[:before].to_i), limit: @limit) + if @entries.present? + render :more_feed_entries, layout: false + else + render :no_more_feed_entries, layout: false + end + end + + private + + # Cache the user’s and her role’s feed entries in a given category + def cache_users_entries_for(category) + key = "feed_entries-#{current_user.id}-#{category}" + + Rails.cache.fetch(key, expires_in: 1.minute) do + current_user.feed_entries_in_category(category) + end + end + + # Cache the user’s shortcuts and her role’s shortcuts in a given category + def cache_users_shortcuts_for(category) + Rails.cache.fetch("shortcuts-#{current_user.id}-#{category}", expires_in: 10.minute) do + current_user.shortcuts_in_category(category) + end + end +end diff --git a/app/controllers/feeds_controller.rb b/app/controllers/feeds_controller.rb new file mode 100644 index 0000000..bcb1d08 --- /dev/null +++ b/app/controllers/feeds_controller.rb @@ -0,0 +1,46 @@ +# -*- coding: utf-8 -*- + +# News feeds administration +class FeedsController < ApplicationController + before_filter { add_body_class('edit feeds') } + before_filter { sub_layout("admin") } + before_filter :require_admin + + def index + @feeds = Feed.order("recent_failures desc, total_failures desc").includes(:users) + end + + def new + @feed = Feed.new + end + + def edit + @feed = Feed.where(id: params[:id]).includes(:roles).first + end + + def create + @feed = Feed.new(params[:feed]) + + if @feed.save + redirect_to feeds_path, notice: "Nyhetsflödet skapades" + else + render action: "new" + end + end + + def update + @feed = Feed.find(params[:id]) + + if @feed.update_attributes(params[:feed]) + redirect_to feeds_path, notice: "Nyhetsflödet uppdaterades" + else + render action: "edit" + end + end + + def destroy + @feed = Feed.find(params[:id]) + @feed.destroy + redirect_to feeds_path, notice: "Nyhetsflödet raderades" + end +end diff --git a/app/controllers/my_own_feeds_controller.rb b/app/controllers/my_own_feeds_controller.rb new file mode 100644 index 0000000..f07ef60 --- /dev/null +++ b/app/controllers/my_own_feeds_controller.rb @@ -0,0 +1,78 @@ +# -*- coding: utf-8 -*- + +# Users own feeds, not avaiable to anybody else +# Those feeds are stored as regular Feed objects with the "my_own" category +class MyOwnFeedsController < ApplicationController + before_filter { add_body_class('edit feeds') } + before_filter :require_user, :clear_feed_entries_cache + + def index + @feeds = Feed.joins(:users).where(category: "my_own", users: { id: current_user.id } ) + end + + def new + @feed = Feed.new + end + + def edit + # Get feed and secure that it is the users own feed + @feed = Feed.joins(:users).where(id: params[:id], category: "my_own", users: { id: current_user.id } ).first + end + + def create + @feed = Feed.new(params[:feed]) + + # Glue feed to the user + @feed.category = "my_own" + @feed.user_ids = current_user.id + + if @feed.save + redirect_to my_own_feeds_path, notice: "Ditt nyhetsflöde skapades" + else + render action: "new" + end + end + + def update + # Check that it is the users own feed + safe_id = Feed.joins(:users).where(id: params[:id], category: "my_own", users: { id: current_user.id } ).first.id + @feed = Feed.find(safe_id) + + # Glue feed params to user + @feed.category = "my_own" + @feed.user_ids = current_user.id + + if @feed.update_attributes(params[:feed]) + redirect_to my_own_feeds_path, notice: "Ditt nyhetsflöde uppdaterades" + else + render action: "edit" + end + end + + def destroy + # Check that it is the users own feed + @feed = Feed.joins(:users).where(id: params[:id], category: "my_own", users: { id: current_user.id } ).first + if @feed.destroy + redirect_to my_own_feeds_path, notice: "Ditt nyhetsflöde raderades" + else + redirect_to my_own_feeds_path, warning: "Nyhetsflödet kunde inte raderas" + end + end + + def destroy_all + # Destroy all the users own feeds + @feeds = Feed.joins(:users).where(category: "my_own", users: { id: current_user.id } ) + if @feeds.destroy_all + redirect_to root_path, notice: "Alla Mina flöden raderades" + else + redirect_to my_own_feeds_path, warning: "Nyhetsflödena kunde inte raderas" + end + end + + private + + # Clear the users key/value ttl cache for feed entries + def clear_feed_entries_cache + Rails.cache.delete("feed_entries-#{current_user.id}-my_own") + end +end diff --git a/app/controllers/roles_controller.rb b/app/controllers/roles_controller.rb new file mode 100644 index 0000000..0019a45 --- /dev/null +++ b/app/controllers/roles_controller.rb @@ -0,0 +1,46 @@ +# -*- coding: utf-8 -*- + +class RolesController < ApplicationController + + before_filter { add_body_class('edit') } + before_filter { sub_layout("admin") if admin? } + before_filter :require_admin + + def index + @roles = Role.all + end + + def new + @role = Role.new + end + + def edit + @role = Role.find(params[:id]) + end + + def create + @role = Role.new(params[:role]) + + if @role.save + redirect_to roles_url, notice: "Rollen skapades" + else + render action: "new" + end + end + + def update + @role = Role.find(params[:id]) + + if @role.update_attributes(params[:role]) + redirect_to roles_url, notice: "Rollen uppdaterades" + else + render action: "edit" + end + end + + def destroy + @role = Role.find(params[:id]) + @role.destroy + redirect_to roles_url, notice: "Rollen togs bort" + end +end diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb new file mode 100644 index 0000000..1cf7f92 --- /dev/null +++ b/app/controllers/sessions_controller.rb @@ -0,0 +1,52 @@ +# -*- coding: utf-8 -*- +class SessionsController < ApplicationController + before_filter { add_body_class('login') } + + def new + # Establish a user session if the user_agent cookie satisfy the remember me criterias + @user_agent = UserAgent.find( cookies.signed[:user_agent][:id] ) + if @user_agent.authenticate( cookies.signed[:user_agent][:token] ) + session[:user_id] = @user_agent.user_id + @user_agent.user.update_attribute("latest_login", Time.now) + + set_profile_cookie + redirect_to root_url + end + rescue # Login form + end + + def create + # Establish a user session if username/password is valid + @user = Authentication.authenticate( params[:username], params[:password] ) + if @user + + tracker = UserAgent.track( @user.id, cookies.signed[:user_agent], params[:remember_me], request.env['HTTP_USER_AGENT'] ) + # Set/update a cookie that keep tracks of this, and only this, user agent + cookies.permanent.signed[:user_agent] = { + value: { id: tracker[:id], token: tracker[:token] }, + secure: !Rails.env.development?, + path: root_path + } + session[:user_id] = @user.id + @user.latest_login = Time.now + @user.save + + set_profile_cookie + redirect_to root_url + else + @login_failed = "Fel användarnamn eller lösenord. Vänligen försök igen." + render "new" + end + end + + def destroy + begin + @user_agent = UserAgent.find(cookies.signed[:user_agent][:id]) + @user_agent.update_attributes( remember_me: false ) + rescue + logger.warn { "'Remember me' for user #{current_user.id} couldn't be reset on logout" } + end + session[:user_id] = nil + redirect_to root_url, notice: "Nu är du utloggad" + end +end diff --git a/app/controllers/shortcuts_controller.rb b/app/controllers/shortcuts_controller.rb new file mode 100644 index 0000000..6cec5e8 --- /dev/null +++ b/app/controllers/shortcuts_controller.rb @@ -0,0 +1,46 @@ +# -*- coding: utf-8 -*- +require 'digest/sha1' + +class ShortcutsController < ApplicationController + before_filter { add_body_class('edit') } + before_filter { sub_layout("admin") } + before_filter :require_admin + + def index + @shortcuts = Shortcut.all + end + + def new + @shortcut = Shortcut.new + end + + def edit + @shortcut = Shortcut.where(id: params[:id]).includes(:roles).first + end + + def create + @shortcut = Shortcut.new(params[:shortcut]) + + if @shortcut.save + redirect_to shortcuts_url, notice: "Genvägen skapades" + else + render action: "new" + end + end + + def update + @shortcut = Shortcut.find(params[:id]) + + if @shortcut.update_attributes(params[:shortcut]) + redirect_to shortcuts_url, notice: "Genvägen uppdaterades" + else + render action: "edit" + end + end + + def destroy + @shortcut = Shortcut.find(params[:id]) + @shortcut.destroy + redirect_to shortcuts_url, notice: "Genvägen togs bort" + end +end diff --git a/app/controllers/site_search_controller.rb b/app/controllers/site_search_controller.rb new file mode 100644 index 0000000..e787c32 --- /dev/null +++ b/app/controllers/site_search_controller.rb @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- +require 'open-uri' + +class SiteSearchController < ApplicationController + before_filter { add_body_class "site-search" } + + def index + @terms = params[:q] + if @terms.present? + @results = SiteSearch::Search.new(params.except(:action, :controller).to_query, APP_CONFIG['site_search_query_url']) + end + + if request.xhr? + render :more, layout: false + else + render :index + end + end + + def autocomplete + begin + results = open("#{APP_CONFIG['site_search_autocomplete_url']}?q=#{params[:q]}&ilang=sv&callback=results", read_timeout: 5).first + rescue Exception => e + results = 'results({})' + end + render json: results + end +end diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb new file mode 100644 index 0000000..34eefb6 --- /dev/null +++ b/app/controllers/users_controller.rb @@ -0,0 +1,167 @@ +# -*- coding: utf-8 -*- +class UsersController < ApplicationController + + before_filter { add_body_class('edit') } + before_filter { sub_layout("admin") if admin? } + before_filter :require_user + before_filter :require_admin_or_myself, only: [ :edit, :update ] + before_filter :require_admin, only: :destroy + + def index + @total_users = User.count + @last_week_users = User.where("latest_login > ?", Time.now - 1.week).count + @registered_last_week_users = User.where("created_at > ?", Time.now - 1.week).count + @has_status = User.where("status_message != ?", "").count + end + + # Search user on the fields username, email, first_name, last_name + # Returns a hash in json or a @users array for html rendering + def search + term = "%#{params[:term]}%" + if term.present? + @users = User.search(term, 50) + else + @users = {} + end + + respond_to do |format| + format.html + format.json { + render json: @users.map { |u| + email = (u.email.present? ? u.email : "ingen e-postaddress").downcase + { id: u.id, username: u.username, email: email, avatar_full_url: "#{avatar_full_url(u.username, :mini_quadrat)}", first_name: u.first_name, last_name: u.last_name } + } + } + end + end + + def show + @user = User.where(username: params[:username]).first + if @user.blank? + reset_body_classes + sub_layout + render template: "404", status: 404 + end + end + + def edit + @user = User.where(id: params[:id]).includes(:roles).first + @user_roles = user_roles + @roles = Role.all + end + + def update + @user = User.find(params[:id]) + @roles = Role.all + # Prevent and admin from un-admin herself + if admin? && editing_myself? && params[:user][:is_admin] == "0" + flash.now[:warning] = "Du kan inte ta bort din egen administratörsrättighet!" + render action: "edit" + else + # Pass empty role HBTM array if all roles are unchecked + params[:user] = { role_ids: [] } if params[:user][:role_ids].blank? + # some fields require admin rights for mass assignment + if @user.update_attributes(params[:user], as: ( :admin if admin? )) + set_profile_cookie + redirect_to user_path(@user.username), notice: "Användaren uppdaterades" + else + render action: "edit" + end + end + end + + def update_status_message + respond_to do |format| + current_user.status_message = params[:status_message] + current_user.status_message_updated_at = Time.now + if current_user.save + format.html { redirect_to root_path } + format.json { render json: { response: "ok", status_message: User.find(current_user.id).status_message }, status: 200 } + else + format.html { redirect_to root_path; flash[:warning] = "Din status kunde inte uppdateras. Försök lite senare." } + format.json { render json: { response: "error", status_message: current_user.status_message }, status: 500 } + end + end + end + + def my_profile + redirect_to user_path(current_user.username) + end + + def my_roles + redirect_to edit_user_path(current_user.id) + end + + # User selects optional feeds + def select_feeds + @user = User.where(id: current_user.id).includes(:roles, :feeds).first + @feeds = Feed.where(category: params[:category]).includes(:roles) + end + + def update_feeds + # Get users feed ids for **all other** feed categories so we don't delete them + other_categories_feeds = current_user.feeds.where("category != ?", params[:category]).pluck(:id) + + # Set **all** the users feeds + current_user.feed_ids = other_categories_feeds + ( params[:user][:feed_ids] or [] ) + + clear_feed_entries_cache(params[:category]) + redirect_to root_path, notice: "Dina flöden uppdaterades" + end + + # Reset user feeds to default for one params[:category] + def reset_feeds + # Get users feed ids for **all other** feed categories so we don't delete them + current_user.feed_ids = current_user.feeds.where("category != ?", params[:category]).pluck(:id) + + clear_feed_entries_cache(params[:category]) + redirect_to root_path, notice: "Inställningarna för #{Feed::CATEGORIES[params[:category]]} återställdes" + end + + # User selects optional shortcuts + def select_shortcuts + @user = User.where(id: current_user.id).includes(:roles, :shortcuts).first + @shortcuts = Shortcut.where(category: params[:category]).includes(:roles) + end + + def update_shortcuts + # Get users shortcuts ids for **all other** shortcut categories so we don't delete them + other_categories_shortcuts = current_user.shortcuts.where("category != ?", params[:category]).pluck(:id) + + # Set **all** the users shortcuts + current_user.shortcut_ids = other_categories_shortcuts + ( params[:user][:shortcut_ids] or [] ) + + clear_shortcut_cache(params[:category]) + redirect_to root_url, notice: "Dina #{Shortcut::CATEGORIES[params[:category]]} uppdaterades" + end + + # Reset user shortcuts to default for one params[:category] + def reset_shortcuts + # Get users shortcuts ids for **all other** shortcut categories so we don't delete them + current_user.shortcut_ids = current_user.shortcuts.where("category != ?", params[:category]).pluck(:id) + + clear_shortcut_cache(params[:category]) + redirect_to root_url, notice: "Inställningarna för #{Shortcut::CATEGORIES[params[:category]]} återställdes" + end + + def add_colleague + @user = User.where(username: params[:add_colleague]).first + render :layout => false + end + + def user_roles + current_user.roles.map { |r| r.category == "department" ? 'department': 'working_field' }.compact + end + + private + + # Clear the users key/value ttl cache for feed entries + def clear_feed_entries_cache(category) + Rails.cache.delete("feed_entries-#{current_user.id}-#{category}") + end + + # Clear the users key/value ttl cache for shortcuts + def clear_shortcut_cache(category) + Rails.cache.delete("shortcuts-#{current_user.id}-#{category}") + end +end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb new file mode 100644 index 0000000..7759ca3 --- /dev/null +++ b/app/helpers/application_helper.rb @@ -0,0 +1,31 @@ +# -*- coding: utf-8 -*- +module ApplicationHelper + + def title(t) + @title = t + end + + def title_suffix + APP_CONFIG["title_suffix"] + end + + def h1 + @title + end + + def separator(current, total, question=false) + separator = ", " if total > current + 2 + separator = " eller " if total == current + 2 + separator = "?" if total == current + 1 && question + separator + end + + def page_title + !@title.nil? ? "#{@title} - #{title_suffix}" : title_suffix + end + + def tags_whitelist + { tags: %w(a i em li ul ol h1 h2 h3 blockquote br sub sup p img), + attributes: %w(href src) } + end +end diff --git a/app/helpers/dashboard_helper.rb b/app/helpers/dashboard_helper.rb new file mode 100644 index 0000000..a586f10 --- /dev/null +++ b/app/helpers/dashboard_helper.rb @@ -0,0 +1,12 @@ +# -*- coding: utf-8 -*- + +module DashboardHelper + def summary(text) + sanitize truncate( strip_tags(text), { separator: ' ', length: 140, omission: ' …' } ) + end + + # Is the feed entry a tweet? + def tweet?(entry) + entry.guid.present? && !!entry.guid.match('^http://twitter.com/') + end +end diff --git a/app/models/colleagueship.rb b/app/models/colleagueship.rb new file mode 100644 index 0000000..c419725 --- /dev/null +++ b/app/models/colleagueship.rb @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- + +class Colleagueship < ActiveRecord::Base + attr_accessible :colleague_id, :create, :destroy, :user_id + + belongs_to :user + belongs_to :colleague, :class_name => "User" + + validates :colleague_id, presence: true + + # Prevent duplicate entries of colleague_id and user_id + validates :colleague_id, :uniqueness => {:scope => :user_id} + + def self.search(user, term, max = 20) + User.where("(username LIKE ? OR + first_name LIKE ? OR + last_name LIKE ? OR + concat_ws(' ', first_name, last_name) LIKE ? OR + email LIKE ?) AND + id NOT IN (?)", + term, term, term, term, term, user.colleagues.map(&:id).push(user.id)) + .order(:first_name).limit(max) + end +end diff --git a/app/models/feed.rb b/app/models/feed.rb new file mode 100644 index 0000000..a9b6d46 --- /dev/null +++ b/app/models/feed.rb @@ -0,0 +1,93 @@ +# -*- coding: utf-8 -*- +require 'open-uri' + +# News feeds +class Feed < ActiveRecord::Base + CATEGORIES = { + "news" => "nyheter", + "dialog" => "diskussioner", + "feature" => "tema", + "my_own" => "användare" + } + + has_and_belongs_to_many :roles + has_and_belongs_to_many :users + has_many :feed_entries, dependent: :destroy + + attr_accessible :title, :feed_url, :category, :role_ids + + # Bind some data to the feed during fetching and parsing + attr_accessor :content, :parsed_feed, :updated + + # Fetch url and parse it is part of the form validation. + # Validation is disabled in workers batch mode + before_validation :fix_url, :fetch, :parse + + after_save :save_feed_entries + + # Fetch a feed w/open-uri + def fetch + begin + timeout(5) do + self.content = open(feed_url).read + end + true + rescue Exception => e + errors.add(:feed_url, "Flödet kunde inte hämtas.") + logger.warn "Couldn't fetch feed #{id} #{feed_url}: #{e}" + false + end + end + + # Parse a feed file w/Feedzirra + def parse + begin + self.parsed_feed = Feedzirra::Feed.parse(content) + self.title = parsed_feed.title || "Utan titel" + self.url = parsed_feed.url + self.fetched_at = Time.now + previous_checksum = checksum + self.checksum = Digest::MD5.hexdigest(content) + + # Is the feed updated since last fetch? + self.updated = previous_checksum != checksum + true + rescue => e + # Parsing failed + logger.warn "Couldn't parse feed #{id} #{feed_url}: #{e}" + errors.add(:feed_url, "Flödet kunde inte tolkas. Kontrollera att det är ett giltigt RSS- eller Atom-flöde.") + false + end + end + + private + + def save_feed_entries + # Save feed_entries for feed + FeedEntry.add_entries(id, parsed_feed.entries) if updated + end + + # Pre-parsing and fixing of a feed url, manipulate it for some special cases + def fix_url + # Remove Safari’s pseudo protocol + self.feed_url.gsub!(/^feed:\/\//, '') + + # Convert # to a twitter search feed for given hash tag(s) + if feed_url.match(/^#/) + self.feed_url = "http://search.twitter.com/search.rss?q=#{URI.escape(feed_url)}" + + # Convert @user to a twitter search feed for that user + elsif feed_url.match(/^@/) + feed_url.gsub!(/@/, '') + self.feed_url = "http://twitter.com/statuses/user_timeline/#{URI.escape(feed_url)}.rss" + + # Convert shotnames to a Komin blog feed + elsif feed_url.present? && !feed_url.match(/[\.\/]/) + self.feed_url = "http://webapps04.malmo.se/blogg/author/#{URI.escape(feed_url)}/feed/" + + # Add http:// if not there + else + self.feed_url = "http://#{feed_url}" unless feed_url.match(/^https?:\/\//) + end + end +end diff --git a/app/models/feed_entry.rb b/app/models/feed_entry.rb new file mode 100644 index 0000000..dbc49fe --- /dev/null +++ b/app/models/feed_entry.rb @@ -0,0 +1,39 @@ +require 'digest/sha1' + +# Feedzirra entries +class FeedEntry < ActiveRecord::Base + belongs_to :feed + + attr_accessor :pubDate + + # Define additional feed entry elements + [ [ "wfw:commentRss", as: "comment_rss" ], + [ "slash:comments", as: "count_comments" ], + [ "comments", as: "comments_link" ], + [ "enclosure", as: "image_url", value: "url" ], + [ "published", as: "pubDate" ], + [ "guid", as: "entry_id" ] # Feedzirra::Parser::ITunesRSSItem is using guid instead of entry_id + ].each do |element| + Feedzirra::Feed.add_common_feed_entry_element( element[0], element[1] ) + end + + # Create or update feed entries for the feed + def self.add_entries(feed_id, entries) + entries.each do |entry| + entry.published ||= entry.pubDate unless entry.pubDate.blank? + entry.entry_id ||= entry.url unless entry.url.blank? + + begin + # Create a new feed entry or update existing + e = where(guid: entry.entry_id, feed_id: feed_id).first_or_initialize + e.feed_id = feed_id + e.full = entry + e.published_at = entry.published + + e.save + rescue => e + logger.error "Couldn't add feed entry #{e}" + end + end + end +end diff --git a/app/models/role.rb b/app/models/role.rb new file mode 100644 index 0000000..661be09 --- /dev/null +++ b/app/models/role.rb @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- + +# Roles are assigned to users and to information objects like feeds and shortcuts +class Role < ActiveRecord::Base + + CATEGORIES = { + "department" => "Förvaltning", + "working_field" => "Arbetsfält" + } + + has_and_belongs_to_many :users + has_and_belongs_to_many :shortcuts + has_and_belongs_to_many :feeds + + attr_accessible :name, :category, :homepage_url + + validates :name, + presence: { is: true, message: "Namnet måste fyllas i." }, + uniqueness: { is: true, message: "Det finns redan en roll med det namnet." } + validates :homepage_url, + presence: { is: true, message: "URL till hemsida måste anges" } + validates :category, + presence: { is: true, message: "Du måste välja en kategori." } + + + def self.roles_by_feeds_categories(feed_category) + where(feeds.category => feed_category) + end +end \ No newline at end of file diff --git a/app/models/shortcut.rb b/app/models/shortcut.rb new file mode 100644 index 0000000..8b2708a --- /dev/null +++ b/app/models/shortcut.rb @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- +require 'digest/sha1' + +# Shortcut links like "Verktyg & system" +class Shortcut < ActiveRecord::Base + + CATEGORIES = { + "tools_and_systems" => "Verktyg & system", + "i_want" => "Jag vill" + } + + has_and_belongs_to_many :roles + has_and_belongs_to_many :users + default_scope order("name ASC") + + attr_accessible :name, :url, :category, :role_ids + + validates :name, :url, + presence: { is: true, message: "Namnet måste fyllas i." } + validates :url, + format: { with: /^https?:\/\//, message: "URL:en måste starta med http:// eller https://." }, + length: { minimum: 11, message: "URL:en är inte korrekt." } + + before_validation do + self.url = "http://#{url}" unless url.match(/^https?:\/\//) + end +end diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 0000000..c6a8fc3 --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,92 @@ +# -*- coding: utf-8 -*- + +class User < ActiveRecord::Base + + has_and_belongs_to_many :roles + has_and_belongs_to_many :feeds + has_and_belongs_to_many :shortcuts + has_many :user_agents, dependent: :destroy + + has_many :colleagueships, dependent: :destroy + has_many :colleagues, through: :colleagueships + has_many :inverse_colleagueships, class_name: "Colleagueship", foreign_key: "colleague_id", dependent: :destroy + has_many :inverse_colleagues, through: :inverse_colleagueships, source: :user + + attr_accessible :phone, :cell_phone, :short_bio, :status_message, :avatar, :role_ids, :feed_ids, :feeds, :shortcut_ids, :shortcuts + attr_accessible :phone, :cell_phone, :short_bio, :status_message, :avatar, :role_ids, :is_admin, as: :admin + attr_accessor :avatar + attr_reader :avatar_remote_url + + before_validation do + self.status_message = status_message.slice(0, 70) if status_message.present? + end + + validates_uniqueness_of :username + validates :username, presence: { allow_blank: false } + + # Paperclip image, options is in the Paperclip initializer + has_attached_file :avatar + before_post_process :validate_avatar_file_size + + validates_attachment_content_type :avatar, + content_type: ['image/tiff', 'image/jpeg', 'image/pjpeg', 'image/jp2'], + message: "Fel bildformat. Du kan ladda upp en jpeg- eller tiff-bild" + + validates_attachment_size :avatar, + less_than: 4.megabyte, + message: "Bilden får inte vara större än 4MB." + + # Get users feeds in a given category + # A user has feeds directly and through her roles + def feeds_in_category(category) + user_selected = feeds.where(category: category).pluck(:id) + through_roles = roles.where('feeds.category' => category).includes(:feeds).select(:id).map {|r| r.feeds.map(&:id) } + (user_selected + through_roles).flatten.uniq + end + + # Select feed_entries from the users feeds in a given category + def feed_entries_in_category(category, options = {}) + options = { limit: 5, before: Time.now }.merge(options) + + # Select the latest feed_entries. Or (used for "load more") those published before options[:before] + FeedEntry.where("feed_id IN (?) AND published_at < ?", feeds_in_category(category), options[:before]) + .group(:guid) + .includes(:feed) + .order("published_at DESC") + .limit(options[:limit]).each { |e| e.full = YAML.load e.full } + end + + def shortcuts_in_category(category) + through_roles = roles.where('shortcuts.category' => category).includes(:shortcuts).map {|r| r.shortcuts } + my_own = shortcuts.map { |s| s if s.category == category } + (my_own.compact + through_roles).flatten.uniq.sort { |a, b| a.name <=> b.name } + end + + # Sort colleagues by their status_message_updated_at + def sorted_colleagues + colleagueships.includes(:colleague).sort do |a,b| + ( b.colleague.status_message_updated_at && a.colleague.status_message_updated_at ) ? + b.colleague.status_message_updated_at <=> a.colleague.status_message_updated_at : ( a.colleague.status_message_updated_at ? -1 : 1 ) + end + end + + # Search for users + def self.search(term, limit = 20) + where( + "username LIKE ? OR + first_name LIKE ? OR + last_name LIKE ? OR + concat_ws(' ', first_name, last_name) LIKE ? OR + email LIKE ?", + term, term, term, term, term) + .order(:first_name).limit(limit) + end + + private + + # Validate avatar before scaling it + def validate_avatar_file_size + valid? + errors.messages.blank? + end +end diff --git a/app/models/user_agent.rb b/app/models/user_agent.rb new file mode 100644 index 0000000..4bdbd4f --- /dev/null +++ b/app/models/user_agent.rb @@ -0,0 +1,40 @@ +# -*- coding: utf-8 -*- +require "bcrypt" + +# Autentication with a "remember me" token +# Each user has one or more user agents with an individual token, remember_me setting and modified date +class UserAgent < ActiveRecord::Base + + belongs_to :user + attr_accessible :user_id, :remember_me, :remember_me_hash, :user_agent_tag + + def authenticate(token) + remember_me? && !expired? && valid_token?(token) + end + + def valid_token?(token) + BCrypt::Password.new(remember_me_hash) == token + end + + def expired? + updated_at < Date.today - APP_CONFIG['remember_me_days'].days + end + + def self.track( user_id, tracker, remember_me, tag ) + begin + user_agent = find_or_create_by_id( tracker[:id] ) + rescue + user_agent = new + end + + # Create a new token every time it is set for the user agent + token = Array.new(64).map { (65 + rand(58)).chr }.join + user_agent.update_attributes({ + user_id: user_id, + user_agent_tag: tag, + remember_me: remember_me, + remember_me_hash: BCrypt::Password.create(token) + }) + { id: user_agent.id, token: token } + end +end diff --git a/app/services/authentication.rb b/app/services/authentication.rb new file mode 100644 index 0000000..8cc6346 --- /dev/null +++ b/app/services/authentication.rb @@ -0,0 +1,76 @@ +# -*- coding: utf-8 -*- + +class Authentication + # Check credentials for a user with an ldap server + # Return a User object or false + def self.authenticate(username, password) + Ldap.authenticate(username, password) + end + + class Ldap + def self.authenticate(username, password) + return stub_auth(username) if APP_CONFIG['ldap_stub'] + return false if username.strip.empty? || password.strip.empty? + + ldap = Net::LDAP.new( + host: APP_CONFIG["ldap"]["host"], + port: APP_CONFIG["ldap"]["port"], + encryption: { method: :simple_tls }, + auth: { + method: :simple, + username: "cn=#{username},#{APP_CONFIG['ldap']['base_dn']}", + password: password + } + ) + + # Authenticate user + bind_user = ldap.bind_as(:base => APP_CONFIG["ldap"]["base_dn"], :filter => "cn=#{username}", :password => password ) + + # Fetch user attributes + ldap_user = ldap.search( base: APP_CONFIG['ldap']['base_dn'], filter: "cn=#{username}", + attributes: %w( cn givenname sn displayname mail telephonenumber mobile title company manager directreports ) ) + + if ldap_user.present? && bind_user.present? + # Find local user or create a new one + @user = User.find_or_create_by_username(username) + sync_attributes(ldap_user.first) + @user + else + Rails.logger.warn "LDAP: #{username} failed to log in. #{ldap.get_operation_result}" + return false + end + end + + private + + # Update local user from the ldap user + def self.sync_attributes(ldap_user) + @user.first_name = ldap_user['givenname'].first + @user.last_name = ldap_user['sn'].first + @user.displayname = ldap_user['displayname'].first + @user.title = ldap_user['title'].first + @user.email = ldap_user['mail'].first + @user.company = ldap_user['company'].first + @user.manager = ldap_user["manager"].map { |m| extract_cn(m) }.join(", ") + @user.directreports = ldap_user["directreports"].map { |m| extract_cn(m) }.join(", ") + @user.phone = phone ||= ldap_user['telephonenumber'].first + @user.cell_phone = cell_phone ||= ldap_user['mobile'].first + @user.save + end + + # Extract username from a ldap cn record + def self.extract_cn(dn) + dn[/cn=(.+?),/i, 1] unless dn.blank? + end + + # Stub auth w/out ldap + # Returns an **existing** user by username + def self.stub_auth(username) + u = User.find_by_username(username) + u.touch + u + rescue + false + end + end +end diff --git a/app/services/site_search.rb b/app/services/site_search.rb new file mode 100644 index 0000000..bc5237e --- /dev/null +++ b/app/services/site_search.rb @@ -0,0 +1,206 @@ +# # -*- coding: utf-8 -*- +require 'open-uri' + +# XPath selectors are efficient, CSS selectors are readable +module SiteSearch + class Search + attr_reader :error + + def initialize(query, base_search_url, options={}) + @query = query + @base_search_url = "#{base_search_url}?oenc=UTF-8&" + @options = { read_timeout: 10 }.merge(options) + search + end + + # Send a GET request to the Siteseeker server and create a Nokogiri doc from the returned HTML + def search + begin + html = open("#{@base_search_url}#{@query}", read_timeout: @options[:read_timeout]) + document = Nokogiri::HTML(html, nil, "UTF-8") + @results = clean_up(document).xpath("/html/body") + rescue Exception => e + Rails.logger.error "Siteseeker: #{e}" + @error = e + @results = Nokogiri::HTML("#{e}") + end + end + + SortItem = Struct.new :text, :query, :current + def sorting + @results.css('div.ess-sortlinks').xpath("a | span[@class='ess-current']").map do |sort_by| + SortItem.new( + sort_by.text.strip, + URI::parse(sort_by.xpath("@href").text).query, + sort_by.xpath("@href").empty? + ) + end + end + + def total + @results.css('#essi-hitcount').text.to_i + end + + def paging + extract_links(@results.xpath("//*[@class='ess-respages']/*[@class='ess-page' or @class='ess-current']")) + end + + def more_query + URI::parse(@results.xpath("//*[@class='ess-respages']/*[@class='ess-next']/@href").text).query + end + + def editors_choice + ec = @results.xpath("//*[@class='ess-bestbets']") + { url: ec.xpath("dt/a/@href").text, + text: ec.xpath("dt/a").text, + description: ec.xpath("dd").text } + end + + def suggestions + extract_links(@results.xpath("//*[@class='ess-spelling']/ul/li/a")) + end + + def entries + @results.css("dl.ess-hits dt").map do |entry| + Entry.new(entry) + end + end + + CategoryGroups = Struct.new :title, :categories + def category_groups + @results.css("[id^=essi-bd-cg-]").map do |category_group| + CategoryGroups.new( + category_group.css(".ess-cat-bd-heading").text.strip.gsub(/:$/, ""), + category_group.css(".ess-cat-bd-category").map { |entry| Category.new(entry) } + ) + end + end + + def to_json + %w(sorting total title paging more_query categories editors_choice suggestions).map do |m| + { m => send(m), entries: entries } + end.to_json + end + + protected + + def extract_links(node_set) + node_set.map do |entry| + { query: URI::parse(entry.xpath("@href").text).query, text: entry.text } + end + end + + # Rewrite href's in each a element + def rewrite_urls(node_set) + node_set.map do |entry| + entry.css("a").each do |a| + a.set_attribute("href", "?#{URI::parse(a.xpath("@href").text).query}") + end + entry + end + node_set + end + + # Depollute some Siteseeker crap + def clean_up(doc) + doc.css(".ess-separator").remove + doc.css("@title").remove + doc.css("@onclick").remove + doc.css("@tabindex").remove + doc.css(".ess-label-hits").remove + doc.css(".ess-clear").remove + doc + end + end + + class Entry + def initialize(entry) + @entry = entry + end + + def number + @entry.css('.ess-hitnum').text.to_i + end + + def title + @entry.css('a').first.text.strip + end + + def summary + @entry.xpath("following-sibling::*[1]/div[@class='ess-hit-extract']").text.strip + end + + def url + @entry.css("a").first['href'] + end + + def content_type + @entry.css('.ess-dtypelabel').text.gsub(/[\[\]]/, "").strip + end + + def date + @entry.xpath("following-sibling::dd[2]").css('.ess-date').text.strip + end + + EntryBreadcrumb = Struct.new :text, :url + def breadcrumb + @entry.xpath("following-sibling::dd[1]/div[@class='ess-special']/ul/li").map do |item| + EntryBreadcrumb.new(item.css("a").text.strip, item.css("a/@href").text) + end + end + + def category + @entry.xpath("following-sibling::*[2]").css('.ess-category').text.strip + end + end + + class Category + def initialize(category) + @category = category + end + + def title + @category.css("a").text.strip + end + + def query + URI::parse(@category.css("a").first['href']).query.strip + end + + def hits + @category.css(".ess-num").text.strip + end + end +end + +# results = SiteSearch::Search.new("semester", APP_CONFIG['site_search_base_url']) +# puts results.error.class +# puts results.sorting[1].text.class +# puts results.sorting[1].query.class +# puts results.sorting[1].current.class +# puts results.sorting.class +# puts results.total +# puts results.paging.class +# puts results.more_query.class +# puts results.editors_choice.class +# puts results.suggestions.class +# puts "=" * 72 +# puts results.category_groups.class +# puts results.category_groups.first.class +# puts results.category_groups.first.title.class +# puts results.category_groups.first.categories.first.title.class +# puts results.category_groups.first.categories.first.query.class +# puts results.category_groups.first.categories.first.hits.class +# puts "=" * 72 +# puts results.entries +# puts results.entries.first.title +# puts results.entries.first.summary.class +# puts results.entries.first.url.class +# puts results.entries.first.number.class +# puts results.entries.first.date.class +# puts results.entries.first.content_type.class +# puts results.entries.first.category.class +# puts results.entries.first.breadcrumb.class +# puts results.entries.first.breadcrumb.first.class +# puts results.entries.first.breadcrumb.first.text.class +# puts results.entries.first.breadcrumb.first.url.class diff --git a/app/services/site_seeker.rb b/app/services/site_seeker.rb new file mode 100644 index 0000000..d373535 --- /dev/null +++ b/app/services/site_seeker.rb @@ -0,0 +1,81 @@ +# -*- coding: utf-8 -*- +require 'open-uri' + +class SiteSeeker + def search(query, search_base) + @query = query.to_query + @search_base = search_base + parse(clean_up(fetch_results)) + end + + # Send a GET request to the Siteseeker server and create a Nokogiri doc from the returned HTML + def fetch_results + begin + html = open("#{APP_CONFIG['site_search_query_url']}/?#{@query}&oenc=utf-8", :read_timeout => 10) + doc = Nokogiri::HTML( html, nil, "UTF-8" ) + rescue Exception => e + Rails.logger.error "Siteseeker: #{e}" + doc = Nokogiri::HTML("#{e}") + end + end + +private + # Select the data we need and but in a ruby object + def parse(results) + if results.css('error').present? + { error: results.css('error').text } + else + { + sorting: extract_links(results.css(".ess-sortlinks").xpath("a | span/strong")), + count: results.css('#essi-hitcount').text, + summary: results.xpath("//h2[@class='ess-topcell']").text.gsub(/Resultat:/, ""), + entries: results.css("dl.ess-hits dt").map do |entry| + { + number: entry.css('.ess-hitnum').text.to_i, + title: entry.css('a[class^=ess-dtype]'), + extract: entry.xpath("following-sibling::*[1]/div[@class='ess-hit-extract']").text, + breadcrumb: entry.xpath("following-sibling::*[1]/div[@class='ess-special']/ul/li"), + category: entry.xpath("following-sibling::*[2]").css('.ess-category').text, + date: entry.xpath("following-sibling::*[2]").css('.ess-date').text, + content_type: entry.css('.ess-dtypelabel').text.gsub(/[\[\]]/, ""), + file_size: entry.css('.ess-size').text.gsub(/- /, "") + } + end, + paging: extract_links(results.xpath("//*[@class='ess-respages']/*[@class='ess-page' or @class='ess-current']")), + more_query: URI::parse(results.css(".ess-respages .ess-next").xpath("@href").text).query, + categories_sum: results.css(".ess-cat-bd .ess-cat-bd-all"), + categories: url_rewrite(results.css(".ess-cat-bd [class^=ess-cat-bd]")), + editors_choice: results.css(".ess-bestbets"), + suggestions: extract_links(results.xpath("//*[@class='ess-spelling']/ul/li/a")) + } + end + end + + def extract_links(node_set) + node_set.map do |entry| + { query: URI::parse(entry.xpath("@href").text).query, text: entry.text } + end + end + + # Rewrite href's in each a element based on the @search_base + def url_rewrite(node_set) + node_set.map do |entry| + entry.css("a").each do |a| + a.set_attribute("href", "#{@search_base}?#{URI::parse(a.xpath("@href").text).query}") + end + entry + end + node_set + end + + # Depollute some Siteseeker crap + def clean_up(doc) + doc.css(".ess-separator").remove + doc.css("@title").remove + doc.css("@onclick").remove + doc.css("@tabindex").remove + doc.css(".ess-label-hits").remove + doc.css(".ess-clear").remove + doc + end +end diff --git a/app/views/404.html b/app/views/404.html new file mode 100644 index 0000000..a4bdb39 --- /dev/null +++ b/app/views/404.html @@ -0,0 +1,4 @@ +
    +

    Sidan kunde inte hittas

    +

    Prova att söka efter sidan i sökfältet uppe till höger eller använd menyerna.

    +
    diff --git a/app/views/500.html b/app/views/500.html new file mode 100644 index 0000000..ad3cd55 --- /dev/null +++ b/app/views/500.html @@ -0,0 +1,4 @@ +
    +

    Nu gick något fel

    +

    Prova att navigera med menyn ovan.

    +
    diff --git a/app/views/avatars/edit.html.haml b/app/views/avatars/edit.html.haml new file mode 100644 index 0000000..1b5b300 --- /dev/null +++ b/app/views/avatars/edit.html.haml @@ -0,0 +1,29 @@ +- title "Profilbild för #{@user.displayname}" +%section.box.form.avatar + %h1.box-title= h1 + .box-content + = form_for @user, url: avatar_path(params[:id]), html: { multipart: true, class: "form-horizontal" } do |f| + .edit_avatar + = image_tag avatar_full_url(@user.username, :medium_quadrat), alt: "Profilbild" + .avatar-help.help + %p Här laddar du upp en bild på dig själv. Bilden visas i Komin bredvid blogginlägg, nyheter, kommentarer och bredvid din status. + %p Bilden ska vara en välliknande porträttbild av dig själv. + %p I och med att du laddar upp en bild av dig själv godkänner du att bilden lagras och används i Komin. Ladda inte upp bilder som någon annan äger rätten till. + + - if @user.errors.any? + .warning= t 'messages.validation_errors' + + .control-group + = f.label :avatar, "Ny bild:", class: "control-label" + .controls + = f.file_field :avatar, class: "fileupload" + .help-inline= 'Du kan ladda upp en jpeg- eller tiff-bild. Max filstrolek är 4MB.' + - @user.errors[:avatar_file_size].each do |msg| + .help-inline.warning= "#{msg}" + - @user.errors[:avatar_content_type].each do |msg| + .help-inline.warning= "#{msg}" + + .control-group + .controls + = f.submit "Ladda upp", class: "btn btn-primary" + = link_to t( 'actions.cancel' ), ( session[:referer] || user_path(@user.username) ), class: "btn" diff --git a/app/views/colleagueships/created.html.haml b/app/views/colleagueships/created.html.haml new file mode 100644 index 0000000..a47a754 --- /dev/null +++ b/app/views/colleagueships/created.html.haml @@ -0,0 +1,10 @@ +%li + = image_tag avatar_full_url(@colleagueship.colleague.username, :tiny_quadrat) + .text + %h2.name= "#{@colleagueship.colleague.first_name} #{@colleagueship.colleague.last_name}" + %p.status= @colleagueship.colleague.status_message ||= "Jag har ingen status än!" + - if @colleagueship.colleague.status_message_updated_at + %p.updated_at= "#{distance_of_time_in_words_to_now( @colleagueship.colleague.status_message_updated_at ).humanize()} sen" + + %a.delete{ href: colleagueship_path(@colleagueship.id), "data-method" => "delete", "data-remote" => "true", "rel" => "nofollow" } + %span.icon-remove diff --git a/app/views/colleagueships/failed.html.haml b/app/views/colleagueships/failed.html.haml new file mode 100644 index 0000000..ba9cc7b --- /dev/null +++ b/app/views/colleagueships/failed.html.haml @@ -0,0 +1,2 @@ +%li + %p.warning Arbetskamraten har ännu inte börjat använda Min sida, eller så finns personen redan i din lista ovan. Försök igen eller be din arbetskamrat att logga in på Min sida. \ No newline at end of file diff --git a/app/views/dashboard/_colleagues.html.haml b/app/views/dashboard/_colleagues.html.haml new file mode 100644 index 0000000..02c1f8f --- /dev/null +++ b/app/views/dashboard/_colleagues.html.haml @@ -0,0 +1,49 @@ +%section.box#colleagues + %h1.box-title Mina arbetskamrater + - has_status = current_user.status_message.present? + = form_tag(user_update_status_message_path, method: "put", id: "update-status-form") do + %fieldset.show{ class: has_status ? '' : 'no-status'} + = label_tag :status_message, "Vad gör du idag?" + = text_area_tag :status_message, nil, rows: 1, placeholder: "Vad gör du idag?" + .controls + = submit_tag "OK", { class: "btn btn-primary btn-small", disabled: true } + %p.count.ok 70 + %ul.box-content + %li#my-status + .img + = link_to image_tag(avatar_full_url(current_user.username, :tiny_quadrat), alt: ""), edit_avatar_path(current_user.id) + = link_to "Byt bild", edit_avatar_path(current_user.id), class: "change-image" + .text + %h2.name= link_to current_user.displayname, user_path(current_user.username) + %p.status + = has_status ? current_user.status_message : "Jag har ingen status än!" + %p.updated_at + - if current_user.status_message_updated_at + = "#{distance_of_time_in_words_to_now( current_user.status_message_updated_at ).humanize()} sen" + + - @colleagueships.each do |colleagueship| + %li + = image_tag avatar_full_url(colleagueship.colleague.username, :tiny_quadrat), alt: "" + .text + %h2.name= "#{colleagueship.colleague.displayname}" + %p.status= colleagueship.colleague.status_message ||= "Jag har ingen status än!" + - if colleagueship.colleague.status_message_updated_at + %p.updated_at= "#{distance_of_time_in_words_to_now( colleagueship.colleague.status_message_updated_at ).humanize()} sen" + %a.delete{ href: colleagueship_path(colleagueship.id), "data-method" => "delete", "data-remote" => "true", "rel" => "nofollow", title: "Ta bort #{colleagueship.colleague.first_name}" } + %span.icon-remove + + %li.add + - unless @colleagueships.present? + %p.no-colleagues I den här boxen kan du lägga till arbetskamrater och se deras status. + = link_to "Lägg till en arbetskamrat", users_path, id: "add-colleague-trigger" + = form_tag(colleagueships_path, method: "post", id: "add-colleague-form") do + %fieldset.show{ class: @colleagueships.present? ? '' : "no-colleagues" } + = label_tag :add_colleague, "Lägg till en arbetskamrat:", class: "show" + = text_field_tag :add_colleague, nil, placeholder: "Sök arbetskamrat" + + - if admin? + .dropdown.box-menu.pull-right + %a#colleagues-menu.dropdown-toggle{ "role" => "button", "data-toggle" => "dropdown", "href" => "#", "title" => "Anpassa denna box" } + %span.icon-caret-down.icon-large + %menu.dropdown-menu{ "aria-labelledby" => "colleagues-menu" } + %li= link_to "Administrera användare...", users_path diff --git a/app/views/dashboard/_feeds_dialog.html.haml b/app/views/dashboard/_feeds_dialog.html.haml new file mode 100644 index 0000000..6cad916 --- /dev/null +++ b/app/views/dashboard/_feeds_dialog.html.haml @@ -0,0 +1,18 @@ +%section.box.feeds#feeds-dialog + %h1.box-title Mina Komindiskussioner + .box-instructions{ class: @dialog_entries.present? ? "" : "show"} + %p= raw "Denna box visar blogg- och foruminlägg från Min förvaltning och Mitt arbetsfält, baserat på vad du valt i #{link_to "Min profil", edit_user_path(current_user)}." + %p Du kan dessutom lägga till fler diskussioner genom att klicka på pilen uppe till höger i denna box. + %ul.box-content + = render "feeds_entries", entries: @dialog_entries, category: 'dialog' + + %a.toggle-instructions{ "role" => "button", href: "#", title: "Visa instruktioner"} ? + + .dropdown.box-menu.pull-right + %a#feeds-dialog-menu.dropdown-toggle{ "role" => "button", "data-toggle" => "dropdown", "href" => "#", "title" => "Anpassa denna box" } + %span.icon-caret-down.icon-large + %menu.dropdown-menu{ "aria-labelledby" => "feeds-dialog-menu" } + %li= link_to "Hantera dessa flöden...", user_select_feeds_path('dialog') + %li= link_to "Återställ dessa flöden", user_reset_feeds_path(:dialog), data: { confirm: 'Vill du återställa alla flöden för Mina Komindiskussioner?', method: :put } + - if admin? + %li= link_to "Administrera...", feeds_path diff --git a/app/views/dashboard/_feeds_entries.html.haml b/app/views/dashboard/_feeds_entries.html.haml new file mode 100644 index 0000000..5f001d6 --- /dev/null +++ b/app/views/dashboard/_feeds_entries.html.haml @@ -0,0 +1,28 @@ +- entries.each do |entry| + %li + %a{ href: entry.full.url, rel: "external" } + - if entry.full.image_url.present? + = image_tag( entry.full.image_url, alt: '' ) + - elsif tweet?(entry) + %span.icon-twitter + - elsif category == 'my_own' + %span.icon-rss + .text + %h2= sanitize( entry.full.title ) + %p.summary{ class: category }= summary(entry.full.summary) + %p.meta + = "#{distance_of_time_in_words_to_now(entry.full.published).humanize()} sen från " + = entry.feed.title + - if entry.full.count_comments.to_i > 0 + - c = entry.full.count_comments.to_i == 1 ? "kommentar" : "kommentarer" + %span.comments + = " #{entry.full.count_comments} #{c}" + %span.icon-comment-alt + +- if entries.size == @limit + %li.load-more + %input.btn.btn-mini{ type: "button", value: "Visa fler", "data-path" => more_feed_entries_path(category, entries.last.full.published.to_i)} +- elsif entries.size < @limit + %li.load-more + .text + %p.nomore Det finns inget mer i denna kategori diff --git a/app/views/dashboard/_feeds_feature.html.haml b/app/views/dashboard/_feeds_feature.html.haml new file mode 100644 index 0000000..63c6bb8 --- /dev/null +++ b/app/views/dashboard/_feeds_feature.html.haml @@ -0,0 +1,13 @@ +%section#feeds-feature.box.feeds + %h1.box-title Tema + - if @feature_entry.present? + %ul.box-content + %li + %a{ href: @feature_entry.full.url, rel: "external" } + - if @feature_entry.full.image_url.present? + .crop + = image_tag( @feature_entry.full.image_url, alt: '' ) + .text + %h2= sanitize( @feature_entry.full.title ) + %p.more= link_to "Fler temanyheter", @feature_feed_url.feed_url.gsub(/\/feed\/*$/, "") + diff --git a/app/views/dashboard/_feeds_my_own.html.haml b/app/views/dashboard/_feeds_my_own.html.haml new file mode 100644 index 0000000..77af706 --- /dev/null +++ b/app/views/dashboard/_feeds_my_own.html.haml @@ -0,0 +1,15 @@ +%section.box.feeds#feeds-my-own + %h1.box-title Mina flöden + .box-instructions{ class: @my_own_entries.present? ? "" : "show"} + %p Min sida kan visa nyhetsflöden från internet. Klicka på pilen uppe till höger i denna box för att lägga till ett flöde. + %ul.box-content + = render "feeds_entries", entries: @my_own_entries, category: 'my_own' + + %a.toggle-instructions{ "role" => "button", href: "#", title: "Visa instruktioner"} ? + + .dropdown.box-menu.pull-right + %a#feeds-my-own-menu.dropdown-toggle{ "role" => "button", "data-toggle" => "dropdown", "href" => "#", "title" => "Anpassa denna box" } + %span.icon-caret-down.icon-large + %menu.dropdown-menu{ "aria-labelledby" => "feeds-my-own-menu" } + %li= link_to "Hantera dessa flöden...", my_own_feeds_path + %li= link_to "Ta bort dessa flöden", my_own_feeds_delete_all_path, data: { confirm: 'Vill du ta bort alla dessa flöden?', method: :delete } diff --git a/app/views/dashboard/_feeds_news.html.haml b/app/views/dashboard/_feeds_news.html.haml new file mode 100644 index 0000000..e6ca22b --- /dev/null +++ b/app/views/dashboard/_feeds_news.html.haml @@ -0,0 +1,18 @@ +%section#feeds-news.box.feeds + %h1.box-title Mina Kominnyheter + .box-instructions{ class: @news_entries.present? ? "" : "show"} + %p= raw "Denna box visar nyheter från Vår kommun, Dator & telefon, Min förvaltning och Mitt arbetsfält, baserat på vad du valt i #{link_to "Min profil", edit_user_path(current_user)}." + %p Du kan dessutom lägga till fler nyhetsflöden genom att klicka på pilen uppe till höger i denna box. + %ul.box-content + = render "feeds_entries", entries: @news_entries, category: 'news' + + %a.toggle-instructions{ "role" => "button", href: "#", title: "Visa instruktioner"} ? + + .dropdown.box-menu.pull-right + %a#feeds-news-menu.dropdown-toggle{ "role" => "button", "data-toggle" => "dropdown", "href" => "#", "title" => "Anpassa denna box" } + %span.icon-caret-down.icon-large + %menu.dropdown-menu{ "aria-labelledby" => "feeds-news-menu" } + %li= link_to "Hantera dessa flöden...", user_select_feeds_path('news') + %li= link_to "Återställ dessa flöden", user_reset_feeds_path(:news), data: { confirm: 'Vill du återställa alla flöden för Mina Kominnyheter?', method: :put } + - if admin? + %li= link_to "Administrera...", feeds_path diff --git a/app/views/dashboard/_search_person.html.haml b/app/views/dashboard/_search_person.html.haml new file mode 100644 index 0000000..cf0e9f6 --- /dev/null +++ b/app/views/dashboard/_search_person.html.haml @@ -0,0 +1,14 @@ +%section.box#search-person + %h1.box-title Sök medarbetare + .box-content + %form{ id: "search-person-form", method: :get, action: "http://srvwindccmg02.malmo.se/netwiseoffice/common/newframes.asp?callingButton=FirstSearch&oldsearch=lname" } + %label{ for: "query-person" } Sök på efternamn: + .input-append + %input#query-person{ type: "text", name: :query, placeholder: "Efternamn" } + %input.btn{ type: "submit", value: "Sök" } + - if admin? + .dropdown.box-menu.pull-right + %a#search-person-menu.dropdown-toggle{ "role" => "button", "data-toggle" => "dropdown", "href" => "#", "title" => "Anpassa denna box" } + %span.icon-caret-down.icon-large + %menu.dropdown-menu{ "aria-labelledby" => "search-person-menu" } + %li= link_to "Administrera...", users_path diff --git a/app/views/dashboard/_shortcuts_i_want.haml b/app/views/dashboard/_shortcuts_i_want.haml new file mode 100644 index 0000000..3b90653 --- /dev/null +++ b/app/views/dashboard/_shortcuts_i_want.haml @@ -0,0 +1,20 @@ +%section.box#shortcuts-i-want + %h1.box-title Jag vill + .box-instructions{ class: @i_want.present? ? "" : "show"} + %p= raw "Denna box visar Jag vill baserat på vad du valt för förvaltning och arbetsfält i #{link_to 'Min profil', edit_user_path(current_user)}." + %p Du kan dessutom lägga till fler Jag vill genom att klicka på pilen uppe till höger i denna box. + + %ul.box-content + - @i_want.each do |shortcut| + %li= link_to shortcut.name, shortcut.url + + %a.toggle-instructions{ "role" => "button", href: "#", title: "Visa instruktioner"} ? + + .dropdown.box-menu.pull-right + %a#shortcuts-i-want-menu.dropdown-toggle{ "role" => "button", "data-toggle" => "dropdown", "href" => "#", "title" => "Anpassa denna box" } + %span.icon-caret-down.icon-large + %menu.dropdown-menu{ "aria-labelledby" => "shortcuts-i-want-menu" } + %li= link_to "Hantera dessa genvägar...", user_select_shortcuts_path('i_want') + %li= link_to "Återställ dessa genvägar", user_reset_shortcuts_path('i_want'), data: { confirm: 'Vill du återställa alla genvägar för Verkgyt & system?', method: :put } + - if admin? + %li= link_to "Administrera...", shortcuts_path diff --git a/app/views/dashboard/_shortcuts_tools_and_systems.haml b/app/views/dashboard/_shortcuts_tools_and_systems.haml new file mode 100644 index 0000000..94b3a34 --- /dev/null +++ b/app/views/dashboard/_shortcuts_tools_and_systems.haml @@ -0,0 +1,19 @@ +%section.box#shortcuts-tools + %h1.box-title Verktyg & system + .box-instructions{ class: @tools_and_systems.present? ? "" : "show"} + %p= raw "Denna box visar verktyg & system baserat på vad du valt för förvaltning och arbetsfält i #{link_to "Min profil", edit_user_path(current_user)}." + %p Du kan dessutom lägga till fler verktyg & system genom att klicka på pilen uppe till höger i denna box. + %ul.box-content + - @tools_and_systems.each do |shortcut| + %li= link_to shortcut.name, shortcut.url + + %a.toggle-instructions{ "role" => "button", href: "#", title: "Visa instruktioner"} ? + + .dropdown.box-menu.pull-right + %a#shortcuts-tools-menu.dropdown-toggle{ "role" => "button", "data-toggle" => "dropdown", "href" => "#", "title" => "Anpassa denna box" } + %span.icon-caret-down.icon-large + %menu.dropdown-menu{ "aria-labelledby" => "shortcuts-tools-menu" } + %li= link_to "Hantera dessa genvägar...", user_select_shortcuts_path('tools_and_systems') + %li= link_to "Återställ dessa genvägar", user_reset_shortcuts_path(:tools_and_systems), data: { confirm: 'Vill du återställa alla genvägar för Verkgyt & system?', method: :put } + - if admin? + %li= link_to "Administrera...", shortcuts_path diff --git a/app/views/dashboard/index.html.haml b/app/views/dashboard/index.html.haml new file mode 100644 index 0000000..b41e896 --- /dev/null +++ b/app/views/dashboard/index.html.haml @@ -0,0 +1,14 @@ +- title "Min sida" +.column.column-1 + = render "feeds_feature" + = render 'colleagues' + +.column.column-2 + = render "feeds_news" + = render "feeds_dialog" + = render "feeds_my_own" + +.column.column-3 + = render "search_person" + = render "shortcuts_tools_and_systems" + = render "shortcuts_i_want" diff --git a/app/views/dashboard/more_feed_entries.haml b/app/views/dashboard/more_feed_entries.haml new file mode 100644 index 0000000..99ff927 --- /dev/null +++ b/app/views/dashboard/more_feed_entries.haml @@ -0,0 +1 @@ += render "feeds_entries", entries: @entries, category: @category diff --git a/app/views/dashboard/no_more_feed_entries.haml b/app/views/dashboard/no_more_feed_entries.haml new file mode 100644 index 0000000..65d0d37 --- /dev/null +++ b/app/views/dashboard/no_more_feed_entries.haml @@ -0,0 +1,4 @@ +%li.load-more + .text + %p.summary Det finns inget mer i dessa flöden + diff --git a/app/views/feeds/_form.html.haml b/app/views/feeds/_form.html.haml new file mode 100644 index 0000000..e577000 --- /dev/null +++ b/app/views/feeds/_form.html.haml @@ -0,0 +1,60 @@ += form_for @feed, html: { class: "form-horizontal" } do |f| + .box-content + - if @feed.errors.any? + .warning= t 'messages.validation_errors' + + .control-group + = f.label :feed_url, "RSS-adress:", class: "control-label" + .controls + = f.text_field :feed_url, class: 'input-wide' + - @feed.errors[:feed_url].each do |msg| + .help-inline.warning= "#{msg}" + .help-inline + = 'Du kan lägga till följande typer:' + %ul + %li= raw 'Ett RSS-flöde som startar med http://' + %li= raw 'Ett användarnamn för Komin-bloggen, t.ex. jesbyl' + / %li.instruction= raw "En Twitter-användare, t.ex. @malmostad" + / %li.instruction= raw 'En eller flera Twitter-hashtag(ar), t.ex. #malmö' + + - if @feed.category != "my_own" + .control-group.readonly + .control-label Kategori: + .controls= select(:feed, :category, Feed::CATEGORIES.except('my_own').map { |key, val| [val, key] } ) + - elsif @feed.users.present? + .control-group.readonly + .control-label Prenumerant: + .controls + = link_to "#{@feed.users.first.first_name} #{@feed.users.first.last_name} (#{@feed.users.first.username})", user_path(@feed.users.first.username) + + .control-group.readonly + .control-label Fel på raken: + .controls + = @feed.recent_failures + .control-group.readonly + .control-label Totalt antal fel: + .controls + = @feed.total_failures + + - if @feed.category != "my_own" + %h2.form-group-title Obligatorisk för följande roller + - Role::CATEGORIES.each do |key, val| + .control-group + .control-label= "#{val}:" + = hidden_field_tag "feed[role_ids][]", nil + .controls + %label.checkbox + = check_box_tag("toggle-#{key}s") + Alla + + .roles{ id: "check-#{key}s" } + - Role.where(category: key).each do |role| + - is_checked = !@feed.new_record? && @feed.role_ids.include?(role.id) ? true : false + %label.checkbox + = check_box_tag "feed[role_ids][]", role.id, is_checked, id: dom_id(role) + = role.name + + .control-group + .controls + = f.submit "Spara och hämta", class: "btn btn-primary" + = link_to t('actions.cancel'), feeds_path, class: "btn" diff --git a/app/views/feeds/edit.html.haml b/app/views/feeds/edit.html.haml new file mode 100644 index 0000000..aef3b43 --- /dev/null +++ b/app/views/feeds/edit.html.haml @@ -0,0 +1,4 @@ +- title "Redigera nyhetsflöde" +%section.box.form + %h1.box-title= h1 + = render 'form' diff --git a/app/views/feeds/index.html.haml b/app/views/feeds/index.html.haml new file mode 100644 index 0000000..2e04327 --- /dev/null +++ b/app/views/feeds/index.html.haml @@ -0,0 +1,31 @@ +- title "Nyhetsflöden" +%section.box.index + %h1.box-title= h1 + .table-wrapper + %table + %thead + %tr + %th Titel + %th.url Url + %th.secondary Ägare + %th.secondary Fel på raken + %th.secondary Fel totalt + %th + %tbody + - @feeds.each do |feed| + %tr + %td.title= link_to feed.title, edit_feed_path(feed) + %td.url + %span= link_to feed.feed_url, feed.feed_url + + - if feed.category == "my_own" && feed.users.present? + %td.secondary= link_to feed.users.first.username, user_path(feed.users.first.username) + - else + %td.secondary= Feed::CATEGORIES[feed.category] + %td.secondary{ class: feed.recent_failures > 0 ? "error" : "success" }= feed.recent_failures + %td.secondary= feed.total_failures + %td= link_to " #{t( 'actions.delete' )}", feed, data: { confirm: 'Är du säker?', method: :delete }, class: "btn btn-danger btn-mini icon-trash icon-large" + + %tr + %td{ colspan: 3 } + .actions= link_to " #{t( "messages.new_post" )}", new_feed_path, class: "btn btn-primary icon-plus" diff --git a/app/views/feeds/new.html.haml b/app/views/feeds/new.html.haml new file mode 100644 index 0000000..393700d --- /dev/null +++ b/app/views/feeds/new.html.haml @@ -0,0 +1,4 @@ +- title "Nytt nyhetsflöde" +%section.box.form + %h1.box-title= h1 + = render 'form' diff --git a/app/views/layouts/_admin_nav.html.haml b/app/views/layouts/_admin_nav.html.haml new file mode 100644 index 0000000..6ec53e6 --- /dev/null +++ b/app/views/layouts/_admin_nav.html.haml @@ -0,0 +1,7 @@ +%nav.box.admin + %h2.box-title Administrera + %ul{ class: controller.controller_name } + %li.users.first= link_to "Användare", users_path + %li.roles= link_to "Roller", roles_path + %li.feeds= link_to "Nyhetsflöden", feeds_path + %li.shortcuts.last= link_to "Genvägar", shortcuts_path diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml new file mode 100644 index 0000000..e5fa644 --- /dev/null +++ b/app/views/layouts/application.html.haml @@ -0,0 +1,29 @@ +!!! 5 +%html + %head + %meta{ charset: 'utf-8' } + %meta{ name: 'viewport', content: 'width=device-width, initial-scale=1.0' } + %meta{ name: 'robots', content: 'noindex, nofollow' } + %title= page_title + /[if IE] + %meta{ "http-equiv" => "X-UA-Compatible", "content" => "IE=edge"} + /[if lte IE 8] + = javascript_include_tag "#{APP_CONFIG['assets_url_base']}html5shiv-printshiv.js" + = stylesheet_link_tag "#{APP_CONFIG['assets_url_stylesheet']}", media: 'all' + = stylesheet_link_tag "application", media: 'all' + /[if lte IE 9] + = stylesheet_link_tag "#{APP_CONFIG['assets_url_base']}legacy/ie9.css", media: 'all' + = stylesheet_link_tag "legacy/ie9", media: 'all' + /[if lte IE 7] + = stylesheet_link_tag "#{APP_CONFIG['assets_url_base']}legacy/ie7.css", media: 'all' + = stylesheet_link_tag "legacy/ie7", media: 'all' + = csrf_meta_tag + %body{ class: "#{@body_classes} malmo-form" } + .wrapper + - flash.each do |key, value| + %p{ class: "flash #{key}" }= value + = yield + - if @sub_layout == "admin" + = render "layouts/admin_nav" + = javascript_include_tag "#{APP_CONFIG['assets_url_javascript']}" + = javascript_include_tag "application" diff --git a/app/views/my_own_feeds/_form.html.haml b/app/views/my_own_feeds/_form.html.haml new file mode 100644 index 0000000..10b9f1f --- /dev/null +++ b/app/views/my_own_feeds/_form.html.haml @@ -0,0 +1,22 @@ +- if @feed.errors.any? + .warning= t 'messages.validation_errors' + +.control-group + = f.label :feed_url, "RSS-adress:", class: "control-label" + .controls + = f.text_field :feed_url, class: "input-wide" + - @feed.errors[:feed_url].each do |msg| + .help-inline.warning= "#{msg}" + + .help-inline + = 'Du kan lägga till följande typer:' + %ul + %li= raw 'Ett RSS-flöde som startar med http://' + %li= raw 'Ett användarnamn för Komin-bloggen, t.ex. jesbyl' + / %li.instruction= raw "En Twitter-användare, t.ex. @malmostad" + / %li.instruction= raw 'En eller flera Twitter-hashtag(ar), t.ex. #malmö' + +.control-group + .controls + = f.submit value: t( "actions.save" ), class: "btn btn-primary" + = link_to t('actions.cancel'), my_own_feeds_path, class: "btn" diff --git a/app/views/my_own_feeds/edit.html.haml b/app/views/my_own_feeds/edit.html.haml new file mode 100644 index 0000000..e61ab71 --- /dev/null +++ b/app/views/my_own_feeds/edit.html.haml @@ -0,0 +1,6 @@ +- title "Redigera nyhetsflöde" +%section.box.form + %h1.box-title= h1 + .box-content + = form_for @feed, url: my_own_feed_path(@feed), html: { class: "form-horizontal" } do |f| + = render 'form', f: f diff --git a/app/views/my_own_feeds/index.html.haml b/app/views/my_own_feeds/index.html.haml new file mode 100644 index 0000000..73c8708 --- /dev/null +++ b/app/views/my_own_feeds/index.html.haml @@ -0,0 +1,26 @@ +- title "Mina flöden" +%section.box.index + %h1.box-title= h1 + %table + - if @feeds.present? + %thead + %tr + %th Titel + %th Url + %th Fel på raken + %th Fel totalt + %th + %tbody + - @feeds.each do |feed| + %tr + %td= feed.title + %td.url + %span= link_to feed.feed_url, feed.feed_url + - status = feed.recent_failures > 0 ? "error" : "success" + %td{ class: status }= feed.recent_failures + %td= feed.total_failures + %td= link_to " #{t( 'actions.delete' )}", my_own_feed_path(feed), data: { confirm: 'Är du säker?', method: :delete }, class: "btn btn-danger btn-mini icon-trash icon-large" + + %tr + %td{ colspan: 5 } + .actions= link_to " #{t( "messages.new_post" )}", new_my_own_feed_path, class: "btn btn-primary icon-plus" diff --git a/app/views/my_own_feeds/new.html.haml b/app/views/my_own_feeds/new.html.haml new file mode 100644 index 0000000..9d55070 --- /dev/null +++ b/app/views/my_own_feeds/new.html.haml @@ -0,0 +1,6 @@ +- title "Nytt nyhetsflöde" +%section.box.form + %h1.box-title= h1 + .box-content + = form_for @feed, url: my_own_feeds_path, html: { class: "form-horizontal" } do |f| + = render 'form', f: f diff --git a/app/views/roles/_form.html.haml b/app/views/roles/_form.html.haml new file mode 100644 index 0000000..3badd8c --- /dev/null +++ b/app/views/roles/_form.html.haml @@ -0,0 +1,26 @@ += form_for @role, html: { class: "form-horizontal" } do |f| + .box-content + - if @role.errors.any? + .warning= t 'messages.validation_errors' + + .control-group + = f.label :name, "Namn:", class: "control-label" + .controls + = f.text_field :name, class: 'input-wide' + - @role.errors[:name].each do |msg| + .help-inline.warning= "#{msg}" + + .control-group + = f.label :homepage_url, "Hemsida:", class: "control-label" + .controls + = f.text_field :homepage_url, value: ( @role.homepage_url.present? ? @role.homepage_url : 'http://' ), class: 'input-wide' + - @role.errors[:homepage_url].each do |msg| + .help-inline.warning= "#{msg}" + + .control-group + = label_tag 'role_category', "Kategori:", class: "control-label" + .controls= select(:role, :category, Role::CATEGORIES.map { |key, val| [val, key] } ) + .control-group + .controls + = f.submit t( 'actions.save' ), class: "btn btn-primary" + = link_to t('actions.cancel'), roles_path, class: "btn" diff --git a/app/views/roles/edit.html.haml b/app/views/roles/edit.html.haml new file mode 100644 index 0000000..45a3cde --- /dev/null +++ b/app/views/roles/edit.html.haml @@ -0,0 +1,4 @@ +- title "Redigera roll" +%section.box.form + %h1.box-title= h1 + = render 'form' diff --git a/app/views/roles/index.html.haml b/app/views/roles/index.html.haml new file mode 100644 index 0000000..55aad51 --- /dev/null +++ b/app/views/roles/index.html.haml @@ -0,0 +1,21 @@ +- title "Roller" +%section.box.index + %h1.box-title= h1 + %table + %thead + %tr + %th Namn + %th Kategori + %th + %tbody + - @roles.each do |role| + %tr + %td= link_to role.name, edit_role_path(role) + %td= Role::CATEGORIES[role.category] + %td= link_to " #{t( 'actions.delete' )}", role, data: { confirm: 'Är du säker?', method: :delete }, class: "btn btn-danger btn-mini icon-trash icon-large" + + %tr + %td{ colspan: 3 } + .actions= link_to " #{t( "messages.new_post" )}", new_role_path, class: "btn btn-primary icon-plus" + + diff --git a/app/views/roles/new.html.haml b/app/views/roles/new.html.haml new file mode 100644 index 0000000..e47810d --- /dev/null +++ b/app/views/roles/new.html.haml @@ -0,0 +1,4 @@ +- title "Ny roll" +%section.box.form + %h1.box-title= h1 + = render 'form' diff --git a/app/views/sessions/new.html.haml b/app/views/sessions/new.html.haml new file mode 100644 index 0000000..3d79f5f --- /dev/null +++ b/app/views/sessions/new.html.haml @@ -0,0 +1,26 @@ +- title "Min sida - Logga in" +.column.column-1 + %section#login.box + %h1.box-title Logga in + .box-content + - if @login_failed.present? + %ul + %li.warning + = @login_failed + = form_tag login_path, class: 'login' do + %fieldset + = label_tag :username, 'Användarnamn:' + = text_field_tag :username, params[:username], class: "input-wide" + = label_tag :password, 'Lösenord:' + = password_field_tag :password, nil, class: "input-wide" + %label.checkbox + = check_box_tag :remember_me, 1, params[:remember_me], checked: true + = 'Kom ihåg mig (ej för delade datorer)' + = submit_tag "Logga in", class: "btn btn-primary" + %p.login-instructions Om du kryssar i ”Kom ihåg mig” är du inloggad i 30 dagar. Använd samma användarnamn och lösenord som du loggar in på din dator med. + +.column.column-2 + %section#feature + .box-content + %h1 Min sida är en personlig startsida för dig + %p.about På sidan får du nyheter och diskussioner från vår kommun, din förvaltning och ditt arbetsfält. Dessutom får du snabb tillgång till de verktyg och system du behöver. Du kan också omvärldsbevaka andra webbplatsers nyheter direkt på sidan. diff --git a/app/views/shortcuts/_form.html.haml b/app/views/shortcuts/_form.html.haml new file mode 100644 index 0000000..6e8a12e --- /dev/null +++ b/app/views/shortcuts/_form.html.haml @@ -0,0 +1,45 @@ += form_for @shortcut, html: { class: "form-horizontal" } do |f| + .box-content + - if @shortcut.errors.any? + .warning= t 'messages.validation_errors' + + .control-group + = f.label :name, "Namn:", class: "control-label" + .controls + = f.text_field :name, class: "input-wide" + - @shortcut.errors[:name].each do |msg| + .help-inline.warning= "#{msg}" + + .control-group + = f.label :url, "Url:", class: "control-label" + .controls + = f.url_field :url, class: "input-wide", value: (@shortcut.new_record? and @shortcut.url.blank?) ? 'http://' : @shortcut.url + - @shortcut.errors[:url].each do |msg| + .help-inline.warning= "#{msg}" + + .control-group + = label_tag 'shortcut_category', "Kategori:", class: "control-label" + .controls= select(:shortcut, :category, Shortcut::CATEGORIES.map { |key, val| [val, key] } ) + + %h2.form-group-title Obligatorisk för följande roller + - Role::CATEGORIES.each do |key, val| + .control-group + .control-label="#{val}:" + = hidden_field_tag "shortcut[role_ids][]", nil + .controls + %label.checkbox + = check_box_tag("toggle-#{key}s") + Alla + + .roles{ id: "check-#{key}s" } + - Role.where(category: key).each do |role| + %label.checkbox + - is_checked = !@shortcut.new_record? && @shortcut.role_ids.include?(role.id) ? true : false + = check_box_tag "shortcut[role_ids][]", role.id, is_checked, id: dom_id(role) + = role.name + + .control-group + .controls + = f.submit t( 'actions.save' ), class: "btn btn-primary" + = link_to t('actions.cancel'), shortcuts_path, class: "btn" + diff --git a/app/views/shortcuts/edit.html.haml b/app/views/shortcuts/edit.html.haml new file mode 100644 index 0000000..e978a8a --- /dev/null +++ b/app/views/shortcuts/edit.html.haml @@ -0,0 +1,4 @@ +- title "Redigera genväg" +%section.box.form + %h1.box-title= h1 + = render 'form' diff --git a/app/views/shortcuts/index.html.haml b/app/views/shortcuts/index.html.haml new file mode 100644 index 0000000..148c16a --- /dev/null +++ b/app/views/shortcuts/index.html.haml @@ -0,0 +1,19 @@ +- title "Genvägar" +%section.box.index + %h1.box-title= h1 + %table + %thead + %tr + %th Namn + %th.secondary Kategori + %th + %tbody + - @shortcuts.each do |shortcut| + %tr + %td= link_to shortcut.name, edit_shortcut_path(shortcut) + %td.secondary= Shortcut::CATEGORIES[shortcut.category] + %td= link_to " #{t( 'actions.delete' )}", shortcut, data: { confirm: 'Är du säker?', method: :delete }, class: "btn btn-danger btn-mini icon-trash icon-large" + + %tr + %td{ colspan: 3 } + .actions= link_to " #{t( "messages.new_post" )}", new_shortcut_path, class: "btn btn-primary icon-plus" diff --git a/app/views/shortcuts/new.html.haml b/app/views/shortcuts/new.html.haml new file mode 100644 index 0000000..fb86f95 --- /dev/null +++ b/app/views/shortcuts/new.html.haml @@ -0,0 +1,4 @@ +- title "Ny genväg" +%section.box.form + %h1.box-title= h1 + = render 'form' diff --git a/app/views/site_search/_results.html.haml b/app/views/site_search/_results.html.haml new file mode 100644 index 0000000..10d31f8 --- /dev/null +++ b/app/views/site_search/_results.html.haml @@ -0,0 +1,15 @@ +- increase_numbering = @results.editors_choice.count +- @results.entries.each do |entry| + %li{ "data-position" => entry.number + increase_numbering } + %h2= entry.title + %p.extract + = entry.summary + %span.date= entry.date + - # unless entry.content_type == "html" + - # %span.file_info= "(#{entry.content_type} #{entry.file_size})" + + %p.category= entry.category + - # %ul.breadcrumb= entry.breadcrumb + +- if @results.more_query.present? + %li#load-more-search-results= link_to "Visa fler träffar", "#{search_path}?#{@results.more_query}", class: "btn" diff --git a/app/views/site_search/index.html.haml b/app/views/site_search/index.html.haml new file mode 100644 index 0000000..3bfe677 --- /dev/null +++ b/app/views/site_search/index.html.haml @@ -0,0 +1,48 @@ +- title "Sök på Komin" +%section.site-search.body-copy + %h1= h1 + = form_tag(search_path, method: "get", id: "full-search") do + %fieldset + = label_tag "q", "#{h1}: ", class: "control-label" + .input-append + = text_field_tag :q, @terms, { placeholder: "Ett eller flera sökord" } + = submit_tag "Sök", { class: "btn", name: nil } + + - if @results.present? + %p.summary= "Din sökning gav #{@results.total} träffar" + - if @results.error.present? + .error= "Ett fel inträffade med Euroling Siteseeker (#{@results.error})" + + - if @results.suggestions.present? + %ul.suggestions + %li Kanske menade du + - @results.suggestions.each_with_index do |entry, i| + %li + = succeed separator(i, @results.suggestions.count, true) do + = link_to entry.text, "#{search_path}?#{entry.query}" + + .menu.sort + %li.label Sortera efter + - @results.sorting.each_with_index do |entry, i| + %li{ class: (entry.current ? "current" : nil) } + = succeed separator(i, @results.sorting.count) do + - if entry.query + = link_to entry.text.downcase, "#{search_path}?#{entry.query}" + - else + = entry.text.downcase + + %section.results + %ul + - @results.editors_choice.each_with_index do |entry, i| + %li{ class: "editors_choice", "data-entry" => i + 1 }= entry + = render "results" + + - if @results.category_groups.present? + %section.site-search-categories + %ul + - @results.category_groups.each do |category_group| + %li= category_group.title + - # category_group.each do |category| + - # %li + - # = link_to category.title, category.query + - # %span= category.hits diff --git a/app/views/site_search/more.html.haml b/app/views/site_search/more.html.haml new file mode 100644 index 0000000..8fb0a6b --- /dev/null +++ b/app/views/site_search/more.html.haml @@ -0,0 +1 @@ += render "results" \ No newline at end of file diff --git a/app/views/users/_search_form.html.haml b/app/views/users/_search_form.html.haml new file mode 100644 index 0000000..1b58fa8 --- /dev/null +++ b/app/views/users/_search_form.html.haml @@ -0,0 +1,14 @@ += form_tag(users_search_path, method: "get", id: "search-user", class: "form-horizontal") do + .control-group + = label_tag "term", "Sök användare: ", class: "control-label" + .controls + .input-append + = text_field_tag "term", params[:term] + = submit_tag "Sök", { class: "btn" } + - if params[:term].blank? || @users.blank? + .help-inline Sök på förnamn, efternamn, e-postadress eller användarnamn. + - if params[:term].blank? + .body-copy + %p.help + = "Trivia: Det är #{@total_users} användare som loggat in på Min sida varav #{@registered_last_week_users} nya har tillkommit senaste sju dagarna." + = "#{@last_week_users} användare har loggat in senaste sju dagarna. Totalt #{@has_status} har ett statusmeddelande." diff --git a/app/views/users/edit.html.haml b/app/views/users/edit.html.haml new file mode 100644 index 0000000..987acfe --- /dev/null +++ b/app/views/users/edit.html.haml @@ -0,0 +1,42 @@ +- title "Grundprofil för #{@user.displayname}" +%section.box.form + %h1.box-title= h1 + .box-content + = form_for @user, html: { class: "form-horizontal" } do |f| + + + - if !@user_roles.present? + %p.warning= "Välj en eller flera förvaltningar och arbetsfält nedan." + - elsif !@user_roles.include? 'department' + %p.warning= "Välj en eller flera förvaltningar nedan." + - elsif !@user_roles.include? 'working_field' + %p.warning= "Välj en eller flera arbetsfält nedan." + + %p.help= "På den här sidan ställer du in din grundprofil – alltså vilken förvaltning du arbetar på och vilket arbetsfält du är verksam inom." + %p.help= "Din grundprofil styr vilka nyheter, diskussioner, verktyg & system och Jag vill som visas på Min sida. Grundprofilen styr också vad som visas i flikarna Min förvaltning och Mitt arbetsfält." + + - if @user.errors.any? + .warning= t 'messages.validation_errors' + + - if admin? + .control-group + .control-label Rättigheter: + .controls + %label.checkbox + = f.check_box :is_admin + Administratör + + - Role::CATEGORIES.each do |key, val| + .control-group + .control-label= "#{val}:" + .controls + - @roles.select { |r| r.category == key }.each do |role| + %label.checkbox + = check_box_tag "user[role_ids][]", role.id, @user.role_ids.include?(role.id), id: dom_id(role) + = role.name + + .control-group + .controls + = f.submit t( 'actions.save' ), class: "btn btn-primary" + = link_to t( 'actions.cancel' ), user_path(@user.username), class: "btn" + diff --git a/app/views/users/index.html.haml b/app/views/users/index.html.haml new file mode 100644 index 0000000..c61a8fb --- /dev/null +++ b/app/views/users/index.html.haml @@ -0,0 +1,5 @@ +- title "Användare" +%section.box.index + %h1.box-title= h1 + .box-content + = render "search_form" diff --git a/app/views/users/search.html.haml b/app/views/users/search.html.haml new file mode 100644 index 0000000..12f3d61 --- /dev/null +++ b/app/views/users/search.html.haml @@ -0,0 +1,23 @@ +- title "Användare" +%section.box.index + %h1.box-title= h1 + .box-content + - if @users.empty? + %p.warning Ingen användare matchade din sökning + = render "search_form" + + - if @users.present? + %table + %thead + %tr + %th Användarnamn + %th Förnamn + %th Efternamn + %th.secondary E-post + %tbody + - @users.each do |user| + %tr + %td= link_to user.username, user_path(user.username) + %td= user.first_name + %td= user.last_name + %td.secondary= user.email diff --git a/app/views/users/select_feeds.html.haml b/app/views/users/select_feeds.html.haml new file mode 100644 index 0000000..c216290 --- /dev/null +++ b/app/views/users/select_feeds.html.haml @@ -0,0 +1,33 @@ +- title "Välj flöden för Komin#{Feed::CATEGORIES[params[:category]]}" +%section.box.form + %h1.box-title= h1 + .box-content + %p.instruction + = "På den här sidan kryssar du i vilka fler flöden du vill visa i boxen Mina Komin#{Feed::CATEGORIES[params[:category]]}." + = 'De flöden som inte går att kryssa ur är obligatoriska baserat på vad du ' + = link_to "valt i din grundprofil.", edit_user_path(@user) + + = form_for @user, url: user_select_feeds_path, html: { class: "form-horizontal" } do |f| + - if @user.errors.any? + %ul.warning + - @user.errors.messages.each do |msg| + %li= msg[1].first + + .control-group + = hidden_field_tag "user[id]", @user.id + .control-label= "Flöden:" + .controls + - @feeds.each do |feed| + - is_mandatory = @user.role_ids.select { |r| feed.role_ids.include?(r) }.present? + %label.checkbox + = check_box_tag("user[feed_ids][]", + feed.id, + ( is_mandatory or @user.feed_ids.include?(feed.id) ), + id: "user_feed_ids_#{feed.id}", + disabled: is_mandatory ) + = feed.title + + .control-group + .controls + = submit_tag t( "actions.save" ), class: "btn btn-primary" + = link_to t( 'actions.cancel' ), root_path, class: "btn" diff --git a/app/views/users/select_shortcuts.html.haml b/app/views/users/select_shortcuts.html.haml new file mode 100644 index 0000000..1d0dbb7 --- /dev/null +++ b/app/views/users/select_shortcuts.html.haml @@ -0,0 +1,31 @@ +- title "Välj genvägar till #{Shortcut::CATEGORIES[params[:category]]}" +%section.box.form + %h1.box-title= h1 + .box-content + %p.help + = "På den här sidan kryssar du i vilka fler länkar du vill visa i boxen #{Shortcut::CATEGORIES[params[:category]]}." + = 'De länkar som inte går att kryssa ur är obligatoriska baserat på vad du ' + = link_to "valt i din grundprofil.", edit_user_path(@user) + + = form_for @user, url: user_select_shortcuts_path, html: { class: "form-horizontal" } do |f| + - if @user.errors.any? + %ul.warning + - @user.errors.messages.each do |msg| + %li= msg[1].first + .control-group + .control-label= "#{Shortcut::CATEGORIES[params[:category]]}:" + .controls + = hidden_field_tag "user[id]", @user.id + - @shortcuts.each do |shortcut| + - is_mandatory = @user.role_ids.select { |r| shortcut.role_ids.include?(r) }.present? + %label.checkbox + = check_box_tag("user[shortcut_ids][]", + shortcut.id, + ( is_mandatory or @user.shortcut_ids.include?(shortcut.id) ), + id: "user_shortcut_ids_#{shortcut.id}", + disabled: is_mandatory ) + = shortcut.name + .control-group + .controls + = submit_tag t( "actions.save" ), class: "btn btn-primary" + = link_to t( 'actions.cancel' ), root_path, class: "btn" diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml new file mode 100644 index 0000000..a02905c --- /dev/null +++ b/app/views/users/show.html.haml @@ -0,0 +1,67 @@ +- title "Grundprofil för #{@user.displayname}" +%section.box.show + %h1.box-title= h1 + .box-content.form-horizontal.form-data + .control-group.readonly + .control-label Profilbild: + .controls.show_avatar + = link_to "Ändra", edit_avatar_path(@user), class: "change btn btn-small" + = image_tag "#{avatar_full_url(@user.username, :medium_quadrat)}?#{Time.now.to_i}", alt: "Profilbild" + .control-group.readonly + .control-label Användarnamn: + .controls= @user.username + .control-group.readonly + .control-label Förnamn: + .controls= @user.first_name + .control-group.readonly + .control-label Efternamn: + .controls= @user.last_name + + .control-group.readonly + .control-label Grundprofil i Komin: + .controls + - if admin? || current_user.username == @user.username + = link_to "Ändra", edit_user_path(@user), class: "change btn btn-small" + = @user.roles.collect(&:name).to_sentence + + - if admin? + %h2.form-group-title Övriga uppgifter + .control-group.readonly + .control-label Administratör: + .controls= @user.is_admin ? "Ja" : "Nej" + .control-group.readonly + .control-label Senast inloggad: + - if @user.latest_login.blank? + .controls – + - else + .controls= l @user.latest_login, format: :short + .control-group.readonly + .control-label Användaren skapades: + .controls= l @user.created_at, format: :short + .control-group.readonly + .control-label Visningsnamn: + .controls= @user.displayname + .control-group.readonly + .control-label E-postadress: + .controls= @user.email + .control-group.readonly + .control-label Telefon: + .controls= @user.phone + .control-group.readonly + .control-label Mobiltelefon: + .controls= @user.cell_phone + .control-group.readonly + .control-label Titel: + .controls= @user.title + .control-group.readonly + .control-label Förvaltning: + .controls= @user.company + .control-group.readonly + .control-label Chef: + .controls= @user.manager + .control-group.readonly + .control-label Chef till: + .controls= @user.directreports + .control-group.readonly + .control-label Om mig (lokal data): + .controls= @user.short_bio diff --git a/app/workers/feed_worker.rb b/app/workers/feed_worker.rb new file mode 100644 index 0000000..de3a5e7 --- /dev/null +++ b/app/workers/feed_worker.rb @@ -0,0 +1,68 @@ +class FeedWorker + # Called by a background job to update all feeds + # Most of the code are conditionals for counters for statistics + def self.update_all + started_at = Time.now.to_f + failed = succeeded = updated = skipped = 0 + + # Process feeds in shuffled order in smaller chunks + Feed.all.shuffle.each_slice(APP_CONFIG['feed_worker_concurrency']) do |feeds| + threads = [] + fetched_feeds = [] + failed_feeds = [] + feeds.each do |feed| + # Penalty: Skip fetching of the feed in this round if it has enough of bad reputation + if feed.recent_failures**2 > feed.recent_skips + feed.update_attribute("recent_skips", feed.recent_skips + 1) + skipped += 1 + next + end + + # Threaded fetching of the feeds + threads << Thread.new do + if feed.fetch + fetched_feeds << feed + else + failed_feeds << feed + end + end + end + threads.each {|t| t.join } + + # Parse and save the chunk of fetched feed + fetched_feeds.each do |fetched_feed| + if fetched_feed.parse + succeeded += 1 + if fetched_feed.updated + updated += 1 + elsif fetched_feed.recent_failures == 0 # Save only if prev fetch failed + next + end + fetched_feed.recent_failures = 0 + fetched_feed.save(validate: false) + else + failed_feeds << fetched_feed + end + end + + # Save stats for failed feed + failed_feeds.each do |failed_feed| + failed += 1 + failed_feed.recent_failures += 1 + failed_feed.total_failures += 1 + failed_feed.save(validate: false) + end + sleep APP_CONFIG['feed_worker_batch_pause'] + end + + # Log stats + Rails.logger.warn " FeedWorker updated feeds in #{(Time.now.to_f - started_at).ceil} seconds." + Rails.logger.warn " Succeeded: #{succeeded}" + Rails.logger.warn " Failed: #{failed}" + Rails.logger.warn " Skipped: #{skipped}" + Rails.logger.warn " Updated: #{updated}" + Rails.logger.warn " Total: #{failed + succeeded + skipped}" + + sleep APP_CONFIG['feed_worker_cycle_pause'] + end +end diff --git a/config.ru b/config.ru new file mode 100644 index 0000000..abb44df --- /dev/null +++ b/config.ru @@ -0,0 +1,4 @@ +# This file is used by Rack-based servers to start the application. + +require ::File.expand_path('../config/environment', __FILE__) +run DashboardKomin::Application diff --git a/config/app_config.yml.example b/config/app_config.yml.example new file mode 100644 index 0000000..9a20d9a --- /dev/null +++ b/config/app_config.yml.example @@ -0,0 +1,69 @@ +defaults: &defaults + ldap: + host: "FILL IN" + port: "636" + base_dn: "FILL IN" + allow_stubs: false + site_search_query_url: "FILL IN" + site_search_autocomplete_url: "FILL IN" + site_search_autocomplete_url: "/search/autocomplete" + remember_me_days: 30 + feed_worker_concurrency: 10 + feed_worker_batch_pause: 1 + feed_worker_cycle_pause: 10 + +development: + <<: *defaults + ldap_stub: true + allow_stubs: true + title_suffix: "Komin (development)" + # Full base system path to avatar storage + avatar_base_path: "~/workspaces/intranet-dashboard/public/system/avatars/" + # Full base url to avatar service, omit protocol + avatar_base_url: "avatars.example.org/avatars/" + # Full url to default avatar service, omit protocol + avatar_default_url: "avatars.example.org/assets/avatar.jpg" + assets_url_base: "//www.local.example.org:3001/assets/" + assets_url_javascript: "//www.local.example.org:3001/assets/application.js" + assets_url_stylesheet: "//www.local.example.org:3001/assets/application.css" + feed_worker_concurrency: 2 + feed_worker_batch_pause: 20 + feed_worker_cycle_pause: 60 + +local_test: + <<: *defaults + ldap_stub: true + allow_stubs: true + title_suffix: "Komin (local_test)" + avatar_base_path: "~/workspaces/intranet-dashboard/public/system/avatars/" + avatar_base_url: "www.local.example.org:3000/system/avatars/" + avatar_default_url: "www.local.example.org:3000/assets/avatar.jpg" + assets_url_base: "//www.local.example.org:3001/assets/" + assets_url_javascript: "//www.local.example.org:3001/assets/application.js" + assets_url_stylesheet: "//www.local.example.org:3001/assets/application.css" + +test: + <<: *defaults + title_suffix: "Komin (test)" + avatar_base_path: "/var/www/public/avatars-test/" + avatar_base_url: "avatars.example.org/avatars-test/" + avatar_default_url: "avatars.example.org/default_avatar.jpg" + assets_url_base: "//assets.example.org/assets-3.0-test/" + assets_url_javascript: "//assets.example.org/assets-3.0-test/application.js" + assets_url_stylesheet: "//assets.example.org/assets-3.0-test/application.css" + site_search_autocomplete_url: "/dashboard-test/search/autocomplete" + feed_worker_concurrency: 2 + feed_worker_batch_pause: 20 + feed_worker_cycle_pause: 60 + + +production: + <<: *defaults + title_suffix: "Komin" + avatar_base_path: "/var/www/public/avatars/" + avatar_base_url: "avatars.example.org/avatars/" + avatar_default_url: "avatars.example.org/default_avatar.jpg" + assets_url_base: "//assets.example.org/assets-3.0/" + assets_url_javascript: "//assets.example.org/assets-3.0/application.js" + assets_url_stylesheet: "//assets.example.org/assets-3.0/application.css" + site_search_autocomplete_url: "/dashboard/search/autocomplete" \ No newline at end of file diff --git a/config/application.rb b/config/application.rb new file mode 100644 index 0000000..9895b46 --- /dev/null +++ b/config/application.rb @@ -0,0 +1,59 @@ +require File.expand_path('../boot', __FILE__) + +require 'rails/all' + +if defined?(Bundler) + # If you precompile assets before deploying to production, use this line + Bundler.require(*Rails.groups(:assets => %w(development local_test))) + # If you want your assets lazily compiled in production, use this line + # Bundler.require(:default, :assets, Rails.env) +end + +module DashboardKomin + class Application < Rails::Application + # Settings in config/environments/* take precedence over those specified here. + # Application configuration should go into files in config/initializers + # -- all .rb files in that directory are automatically loaded. + + # Custom directories with classes and modules you want to be autoloadable. + # config.autoload_paths += %W(#{Rails.root}/app/services) + + # Only load the plugins named here, in the order given (default is alphabetical). + # :all can be used as a placeholder for all plugins not explicitly named. + # config.plugins = [ :exception_notification, :ssl_requirement, :all ] + + # Activate observers that should always be running. + # config.active_record.observers = :cacher, :garbage_collector, :forum_observer + + # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. + # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. + config.time_zone = 'Stockholm' + + # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. + # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] + + # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. + # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] + config.i18n.default_locale = "sv-SE" + + # Configure the default encoding used in templates for Ruby 1.9. + config.encoding = "utf-8" + + # Configure sensitive parameters which will be filtered from the log file. + config.filter_parameters += [:password] + + # Workaround for https://github.com/rails/sass-rails/issues/111 + Sprockets::Compressors.register_css_compressor(:scss, 'Sass::Rails::CssCompressor', :require => 'sass/rails/compressor') + + # Enable the asset pipeline + config.assets.enabled = true + + # Version of your assets, change this if you want to expire all your assets + config.assets.version = '1.0' + config.assets.precompile += %w( legacy/ie7.css legacy/ie9.css ) + + config.generators do |g| + g.template_engine :haml + end + end +end diff --git a/config/boot.rb b/config/boot.rb new file mode 100644 index 0000000..4489e58 --- /dev/null +++ b/config/boot.rb @@ -0,0 +1,6 @@ +require 'rubygems' + +# Set up gems listed in the Gemfile. +ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) + +require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE']) diff --git a/config/daemons.god b/config/daemons.god new file mode 100644 index 0000000..f99f1f4 --- /dev/null +++ b/config/daemons.god @@ -0,0 +1,92 @@ +# -*- coding: utf-8 -*- + +# Point /etc/init.d/dashboard-god to this file + +# Use it standalone like: +# $ sudo god -c config/daemons.god +# $ sudo god status +# $ sudo god stop feed_daemon +# $ sudo god terminate + +def monitor(w, app_root, options = {}) + script = "#{app_root}/lib/daemons/feed_daemon_ctl" + w.interval = 10.seconds + w.start = "#{script} start" + w.restart = "#{script} restart" + w.stop = "#{script} stop" + w.stop_grace = 240.seconds + w.start_grace = 120.seconds + w.restart_grace = 60.seconds + w.pid_file = "#{app_root}/log/feed_daemon.pid" + w.log = "#{app_root}/log/god.log" + + w.behavior(:clean_pid_file) + + w.start_if do |start| + start.condition(:process_running) do |c| + c.interval = 10.seconds + c.running = false + end + end + + w.restart_if do |restart| + restart.condition(:memory_usage) do |c| + c.above = 200.megabytes + c.times = [3, 5] # 3 out of 5 intervals + end + + restart.condition(:cpu_usage) do |c| + c.above = 50.percent + c.times = 5 + end + end + + w.lifecycle do |on| + on.condition(:flapping) do |c| + c.to_state = [:start, :restart] + c.times = 5 + c.within = 5.minute + c.transition = :unmonitored + c.retry_in = 10.minutes + c.retry_times = 5 + c.retry_within = 2.hours + end + end + + # w.transition(:up, :start) do |on| + # on.condition(:process_exits) do |c| + # c.notify = 'developers' + # end + # end +end + +#require 'tlsmail' +# God::Contacts::Email.defaults do |d| +# Net::SMTP.enable_tls(OpenSSL::SSL::VERIFY_NONE) +# d.server_host = 'smtp.example.org' +# d.from_email = "noreply@example.org" +# d.from_name = "Dashboard monitoring" +# d.delivery_method = :smtp +# end + +# God.contact(:email) do |c| +# c.name = "Dev Guy" +# c.group = "developers" +# c.to_email = "dev.guy@example.org" +# c.to_name = "Dev Guy" +# end + + +# God.watch do |w| +# w.name = "feed_daemon" +# w.env = { 'RAILS_ENV' => "production" } +# app_root = "/var/www/dashboard/production/current" +# monitor(w, app_root) +# end + +God.watch do |w| + w.name = "feed_daemon_test" + w.env = { 'RAILS_ENV' => "test" } + app_root = "/var/www/dashboard/test/current" + monitor(w, app_root) +end \ No newline at end of file diff --git a/config/dashboard-god b/config/dashboard-god new file mode 100644 index 0000000..0f2a0eb --- /dev/null +++ b/config/dashboard-god @@ -0,0 +1,43 @@ +#!/bin/bash +# +# Install as /etc/init.d/dashboard-god +# +# god Startup script for god (http://god.rubyforge.org) +# +# chkconfig: - 85 15 +# description: God is an easy to configure, easy to extend monitoring \ +# framework written in Ruby. +# + +RETVAL=0 + +GOD=/usr/local/bin/god +GOD_SCRIPT=/var/www/dashboard/daemons.god + +case "$1" in + start) + $GOD -P /var/run/god.pid -l /var/log/god.log + $GOD load $GOD_SCRIPT + RETVAL=$? + ;; + stop) + $GOD terminate + RETVAL=$? + ;; + restart) + $GOD terminate + $GOD -P /var/run/god.pid -l /var/log/god.log + $GOD load /var/www/dashboard/daemons.god + RETVAL=$? + ;; + status) + $GOD status + RETVAL=$? + ;; + *) + echo "Usage: god {start|stop|restart|status}" + exit 1 + ;; +esac + +exit $RETVAL \ No newline at end of file diff --git a/config/database.yml.example b/config/database.yml.example new file mode 100644 index 0000000..34910ac --- /dev/null +++ b/config/database.yml.example @@ -0,0 +1,19 @@ +development: + adapter: mysql2 + encoding: utf8 + collation: utf8_swedish_ci + database: dashboard + username: username + password: your_secret + host: localhost + pool: 20 + +local_test: + adapter: mysql2 + encoding: utf8 + collation: utf8_swedish_ci + database: dashboard_local_test + username: username + password: your_secret + host: localhost + pool: 20 diff --git a/config/deploy.rb b/config/deploy.rb new file mode 100644 index 0000000..cd39399 --- /dev/null +++ b/config/deploy.rb @@ -0,0 +1,124 @@ +# The Capistrano tasks will use your **working copy**, compile the assets and deploy them to the server_address +# Execute one of the following to deploy into test or production: +# $ cap staging deploy +# $ cap production deploy +# Rollback one step: +# $ cap [staging|production] deploy:rollback + +require "bundler/capistrano" +require 'capistrano/ext/multistage' + +config = YAML::load_file(File.join(File.dirname(File.expand_path(__FILE__)), 'deploy.yml')) + +set :application, "dashboard_komin" + +set :stages, %w(staging production) # 'test' is a reserved word +set :default_stage, "staging" + +set :whenever_command, "bundle exec whenever" +set :whenever_environment, defer { stage } +set :whenever_identifier, defer { "#{application}_#{stage}" } +require "whenever/capistrano" + +_cset :asset_env, "RAILS_GROUPS=assets" +_cset :assets_prefix, "assets" +_cset :assets_role, [:web] +_cset :normalize_asset_timestamps, true +set :precompile_assets, "locally" # remote, locally or none + +set :server_address, config['server_address'] +server server_address, :web, :app, :db, primary: true +set :use_sudo, false + +set :backup_dir, '/var/www/dump/' + +set :scm, :none +set :repository, "." +set :deploy_via, :copy # Use local copy, be sure to update to the stuff you want to deploy +set :copy_exclude, ["log/*", "**/.git", "**/.svn", "tmp/*", "doc", "**/.DS_Store", + "**/*.example", "config/database.yml", "config/deploy.yml", "config/app_config.yml", "config/initializers/secret_token.rb" + ".bundle", ".rspec", "spec"] + +# set :scm, :git +# set :repository_root, config[:repository_root] + +default_run_options[:pty] = true +ssh_options[:forward_agent] = true + +set(:user) do + Capistrano::CLI.ui.ask "\nUsername for #{server_address}: " +end + +before "deploy", "prompt:continue", "assets:precompile_#{precompile_assets}", 'backup:mysql' +before 'deploy:restart', 'deploy:symlink_config', 'deploy:migrate' +after 'deploy', 'deploy:restart_daemons', 'deploy:cleanup', 'assets:cleanup' + +namespace :deploy do + desc 'Symlink to shared files' + task :symlink_config, roles: :app do + run "ln -nfs #{shared_path}/config/database.yml #{release_path}/config/database.yml" + run "ln -nfs #{shared_path}/config/app_config.yml #{release_path}/config/app_config.yml" + run "ln -nfs #{shared_path}/config/initializers/secret_token.rb #{release_path}/config/initializers/secret_token.rb" + end + + desc 'Restart the application' + task :restart do + run "touch #{release_path}/tmp/restart.txt" + end + + desc 'Restart daemons' + task :restart_daemons do + puts "Restarting daemons, this can take a while..." + run "RAILS_ENV=#{rails_env} #{release_path}/lib/daemons/feed_worker_ctl restart" + end +end + +namespace :assets do + desc "Precompile assets on server" + task :precompile_remote, roles: assets_role, :except => { :no_release => true } do + run "cd #{latest_release} && #{rake} RAILS_ENV=#{rails_env} #{asset_env} assets:precompile" + end + + desc "Precompile assets locally" + task :precompile_locally do + run_locally("rake assets:clean RAILS_ENV=#{rails_env} && rake assets:precompile RAILS_ENV=#{rails_env}") + end + + desc "Don't precompile assets" + task :precompile_none do + end + + desc "Remove locally compiled assets" + task :cleanup do + run_locally("rake assets:clean:all RAILS_ENV=#{rails_env}") + end +end + +namespace :prompt do + task :continue do + puts "\nThis will use your **working copy** and deploy a **#{rails_env}** version to #{server_address} #{releases_path}/#{release_name}" + puts "Task performed:" + puts " * Assets compiled #{precompile_assets}" + puts " * Database dumped to #{backup_dir}" + puts " * Migration run" + puts " * App restarted and linked as current version" + continue = Capistrano::CLI.ui.ask "\nDo you want to continue [y/n]: " + if continue.downcase != 'y' && continue.downcase != 'yes' + puts "Deployment halted by user" + Kernel.exit(1) + end + end +end + +namespace :backup do + desc 'performs a backup using mysqldump' + task :mysql, :roles => :db, :only => { :primary => true } do + filepath = "#{backup_dir}#{application}-#{rails_env}-predeploy-#{release_name}.sql.bz2" + text = capture "cat #{shared_path}/config/database.yml" + yaml = YAML::load(text) + + run "mysqldump -u #{yaml[rails_env]['username']} -p #{yaml[rails_env]['database']} | bzip2 -c > #{filepath}" do |ch, stream, out| + ch.send_data "#{yaml[rails_env]['password']}\n" if out =~ /^Enter password:/ + end + end +end diff --git a/config/deploy.yml.example b/config/deploy.yml.example new file mode 100644 index 0000000..f318fb8 --- /dev/null +++ b/config/deploy.yml.example @@ -0,0 +1,2 @@ +server_address: server.example.org +repository_root: git@github.com:malmostad/intranet-assets.git diff --git a/config/deploy/production.rb b/config/deploy/production.rb new file mode 100644 index 0000000..b77daa0 --- /dev/null +++ b/config/deploy/production.rb @@ -0,0 +1,5 @@ +set :rails_env, "production" +set :deploy_to, "/var/www/dashboard/production" +set :bundle_without, [:development, :test] +set :bundle_dir, "" +set :bundle_flags, "" diff --git a/config/deploy/staging.rb b/config/deploy/staging.rb new file mode 100644 index 0000000..07cc8c6 --- /dev/null +++ b/config/deploy/staging.rb @@ -0,0 +1,6 @@ + # 'test' is a reserved word, 'staging' is used for the "test" environment on the **server** +set :rails_env, "test" +set :deploy_to, "/var/www/dashboard/test" +set :bundle_without, [:development, :production] +set :bundle_dir, "" +set :bundle_flags, "" diff --git a/config/environment.rb b/config/environment.rb new file mode 100644 index 0000000..4dad561 --- /dev/null +++ b/config/environment.rb @@ -0,0 +1,8 @@ +# Load the rails application +require File.expand_path('../application', __FILE__) + +# Initialize the rails application +DashboardKomin::Application.initialize! + +# html5 is used in templates. This will autoclose empty tags. +Haml::Template.options[:format] = :xhtml \ No newline at end of file diff --git a/config/environments/2_0.rb b/config/environments/2_0.rb new file mode 100644 index 0000000..973911e --- /dev/null +++ b/config/environments/2_0.rb @@ -0,0 +1,19 @@ +DashboardKomin::Application.configure do + config.action_controller.relative_url_root = "/dashboard-2.0" + config.cache_classes = true + + config.consider_all_requests_local = false + config.action_controller.perform_caching = true + + config.static_cache_control = "public, max-age=3600" + config.serve_static_assets = false + config.assets.compress = true + config.assets.js_compressor = :uglifier + config.assets.css_compressor = :yui + config.assets.compile = false + config.assets.digest = true + + config.i18n.fallbacks = true + + config.active_support.deprecation = :notify +end diff --git a/config/environments/development.rb b/config/environments/development.rb new file mode 100644 index 0000000..c1c9399 --- /dev/null +++ b/config/environments/development.rb @@ -0,0 +1,30 @@ +DashboardKomin::Application.configure do + + config.cache_classes = false + config.action_controller.perform_caching = false + + # Note: A cache store must be available since we use key-value caching + # With memory_store, some code changes requires a restart of the server + config.cache_store = :dalli_store, '127.0.0.1:11211', { namespace: "dashboard-development" } + # config.cache_store = :mem_cache_store + + config.whiny_nils = true + + config.consider_all_requests_local = true + config.log_level = :debug +# config.colorize_logging = false + + config.action_mailer.raise_delivery_errors = false + + config.active_support.deprecation = :log + + config.action_dispatch.best_standards_support = :builtin + + config.active_record.mass_assignment_sanitizer = :strict + + config.assets.compress = false + config.assets.debug = true + + # ImageMagick resize. (Use "which convert" path) + Paperclip.options[:command_path] = "/usr/local/bin/convert" +end diff --git a/config/environments/local_test.rb b/config/environments/local_test.rb new file mode 100644 index 0000000..b7f38eb --- /dev/null +++ b/config/environments/local_test.rb @@ -0,0 +1,20 @@ +DashboardKomin::Application.configure do + config.cache_classes = false + config.action_controller.perform_caching = false + config.cache_store = :memory_store + + config.whiny_nils = true + config.consider_all_requests_local = true + config.log_level = :debug + config.action_mailer.raise_delivery_errors = false + config.active_support.deprecation = :log + + config.action_dispatch.best_standards_support = :builtin + + config.active_record.mass_assignment_sanitizer = :strict + + config.assets.debug = true + config.assets.compress = false + + Paperclip.options[:command_path] = "/usr/local/bin/convert" +end diff --git a/config/environments/production.rb b/config/environments/production.rb new file mode 100644 index 0000000..97db9ad --- /dev/null +++ b/config/environments/production.rb @@ -0,0 +1,25 @@ +DashboardKomin::Application.configure do + + config.log_level = :warn + config.action_controller.relative_url_root = "/dashboard" + config.consider_all_requests_local = false + + config.cache_classes = true + config.action_controller.perform_caching = true + config.cache_store = :dalli_store, '127.0.0.1:11211', { namespace: "dashboard-production" } + + config.serve_static_assets = true + config.static_cache_control = "public, max-age=3600" + + config.assets.compress = true + config.assets.js_compressor = :uglifier + config.assets.css_compressor = :scss + config.assets.compile = false + config.assets.digest = true + + config.i18n.fallbacks = true + + config.active_support.deprecation = :notify + + Paperclip.options[:command_path] = "/usr/bin/" +end \ No newline at end of file diff --git a/config/environments/test.rb b/config/environments/test.rb new file mode 100644 index 0000000..a8ff1a7 --- /dev/null +++ b/config/environments/test.rb @@ -0,0 +1,38 @@ +DashboardKomin::Application.configure do + + config.log_level = :info + + config.action_controller.relative_url_root = "/dashboard-test" + + config.consider_all_requests_local = false + + config.cache_classes = true + config.action_controller.perform_caching = true + # config.cache_store = :mem_cache_store + config.cache_store = :dalli_store, '127.0.0.1:11211', { namespace: "dashboard-test" } + + config.serve_static_assets = true + config.static_cache_control = "public, max-age=3600" + config.assets.compress = true + config.assets.js_compressor = :uglifier + config.assets.css_compressor = :scss + config.assets.compile = false + config.assets.digest = true + + config.whiny_nils = true + + config.action_dispatch.show_exceptions = false + config.action_controller.allow_forgery_protection = false + + # Use SQL instead of Active Record's schema dumper when creating the test database. + # This is necessary if your schema can't be completely dumped by the schema dumper, + # like if you have constraints or database-specific column types + # config.active_record.schema_format = :sql + + config.active_support.deprecation = :log + + config.active_record.mass_assignment_sanitizer = :strict + + # ImageMagick resize. (Use "which convert" path) + Paperclip.options[:command_path] = "/usr/bin/" +end diff --git a/config/initializers/app_config.rb b/config/initializers/app_config.rb new file mode 100644 index 0000000..1e946d3 --- /dev/null +++ b/config/initializers/app_config.rb @@ -0,0 +1 @@ +APP_CONFIG = YAML.load_file("#{Rails.root.to_s}/config/app_config.yml")[Rails.env] diff --git a/config/initializers/backtrace_silencers.rb b/config/initializers/backtrace_silencers.rb new file mode 100644 index 0000000..59385cd --- /dev/null +++ b/config/initializers/backtrace_silencers.rb @@ -0,0 +1,7 @@ +# Be sure to restart your server when you modify this file. + +# You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. +# Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } + +# You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. +# Rails.backtrace_cleaner.remove_silencers! diff --git a/config/initializers/inflections.rb b/config/initializers/inflections.rb new file mode 100644 index 0000000..9e8b013 --- /dev/null +++ b/config/initializers/inflections.rb @@ -0,0 +1,10 @@ +# Be sure to restart your server when you modify this file. + +# Add new inflection rules using the following format +# (all these examples are active by default): +# ActiveSupport::Inflector.inflections do |inflect| +# inflect.plural /^(ox)$/i, '\1en' +# inflect.singular /^(ox)en/i, '\1' +# inflect.irregular 'person', 'people' +# inflect.uncountable %w( fish sheep ) +# end diff --git a/config/initializers/log_formatter.rb b/config/initializers/log_formatter.rb new file mode 100644 index 0000000..845f5cb --- /dev/null +++ b/config/initializers/log_formatter.rb @@ -0,0 +1,5 @@ +class Logger::SimpleFormatter + def call(severity, time, progname, msg) + "#{Time.now} #{severity} #{msg}\n" + end +end diff --git a/config/initializers/mime_types.rb b/config/initializers/mime_types.rb new file mode 100644 index 0000000..72aca7e --- /dev/null +++ b/config/initializers/mime_types.rb @@ -0,0 +1,5 @@ +# Be sure to restart your server when you modify this file. + +# Add new mime types for use in respond_to blocks: +# Mime::Type.register "text/richtext", :rtf +# Mime::Type.register_alias "text/html", :iphone diff --git a/config/initializers/paperclip.rb b/config/initializers/paperclip.rb new file mode 100644 index 0000000..14ceb0d --- /dev/null +++ b/config/initializers/paperclip.rb @@ -0,0 +1,71 @@ +Paperclip.interpolates :username do |attachment, style_name| + attachment.instance.username +end + +Paperclip::Attachment.default_options.update({ + default_style: :medium_quadrat, + + # Dynamic values, work on those if we get more than avatar uploads + # path: ":rails_root/public/system/:attachment/:username/:style.:extension", + # url: "#{ActionController::Base.relative_url_root}/system/:attachment/:username/:style.:extension", + # default_url: "#{ActionController::Base.relative_url_root}/assets/avatar.png", + + path: "#{APP_CONFIG['avatar_base_path']}:username/:style.:extension", + url: "http://#{APP_CONFIG['avatar_base_url']}:username/:style.:extension", + default_url: "http://#{APP_CONFIG["avatar_default_url"]}", + styles: { + xlarge: { + geometry: '600x', + format: 'jpg', + quality: 70 + }, + large: { + geometry: '300x', + format: 'jpg', + quality: 70 + }, + large_quadrat: { + geometry: '300x300#', + format: 'jpg', + quality: 70 + }, + medium: { + geometry: '180x', + format: 'jpg', + quality: 70 + }, + medium_quadrat: { + geometry: '180x180#', + format: 'jpg', + quality: 70 + }, + small: { + geometry: '120x', + format: 'jpg', + quality: 70 + }, + small_quadrat: { + geometry: '120x120#', + format: 'jpg', + quality: 70 + }, + thumb_quadrat: { + geometry: '60x60#', + format: 'jpg', + quality: 50 + }, + tiny_quadrat: { + geometry: '46x46#', + format: 'jpg', + quality: 50 + }, + mini_quadrat: { + geometry: '32x32#', + format: 'jpg', + quality: 50 + } + }, + convert_options: { + all: "-strip -auto-orient " + } +}) diff --git a/config/initializers/secret_token.rb.example b/config/initializers/secret_token.rb.example new file mode 100644 index 0000000..bd2edde --- /dev/null +++ b/config/initializers/secret_token.rb.example @@ -0,0 +1,7 @@ +# Be sure to restart your server when you modify this file. + +# Your secret key for verifying the integrity of signed cookies. +# If you change this key, all old signed cookies will become invalid! +# Make sure the secret is at least 30 characters and all random, +# no regular words or you'll be exposed to dictionary attacks. +DashboardKomin::Application.config.secret_token = '128_CHARS_HEX_STRING' diff --git a/config/initializers/session_store.rb b/config/initializers/session_store.rb new file mode 100644 index 0000000..909ea7d --- /dev/null +++ b/config/initializers/session_store.rb @@ -0,0 +1 @@ +DashboardKomin::Application.config.session_store :active_record_store, { key: Rails.env.test? ? "_session_id_test" : "_session_id" } \ No newline at end of file diff --git a/config/initializers/wrap_parameters.rb b/config/initializers/wrap_parameters.rb new file mode 100644 index 0000000..999df20 --- /dev/null +++ b/config/initializers/wrap_parameters.rb @@ -0,0 +1,14 @@ +# Be sure to restart your server when you modify this file. +# +# This file contains settings for ActionController::ParamsWrapper which +# is enabled by default. + +# Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. +ActiveSupport.on_load(:action_controller) do + wrap_parameters format: [:json] +end + +# Disable root element in JSON by default. +ActiveSupport.on_load(:active_record) do + self.include_root_in_json = false +end diff --git a/config/locales/sv-SE.yml b/config/locales/sv-SE.yml new file mode 100644 index 0000000..0b78a3a --- /dev/null +++ b/config/locales/sv-SE.yml @@ -0,0 +1,218 @@ +# https://github.com/svenfuchs/rails-i18n/blob/master/rails/locale/sv-SE.yml + +sv-SE: + +# Project specifics + messages: + post_created: "Posten skapades" + post_updated: "Posten uppdaterades" + correct_form: "Vänligen korrigera följande:" + new_post: "Lägg till" + validation_errors: "Vänligen korrigera nedanstående markerade uppgifter." + actions: + save: "Spara" + cancel: "Avbryt" + show_all: "Visa alla" + edit: "Redigera" + delete: "Radera" + +# default + date: + abbr_day_names: + - sön + - mån + - tis + - ons + - tor + - fre + - lör + abbr_month_names: + - + - jan + - feb + - mar + - apr + - maj + - jun + - jul + - aug + - sep + - okt + - nov + - dec + day_names: + - söndag + - måndag + - tisdag + - onsdag + - torsdag + - fredag + - lördag + formats: + default: ! '%Y-%m-%d' + long: ! '%e %B %Y' + short: ! '%e %b' + month_names: + - + - januari + - februari + - mars + - april + - maj + - juni + - juli + - augusti + - september + - oktober + - november + - december + order: + - :day + - :month + - :year + datetime: + distance_in_words: + about_x_hours: + one: ungefär en timme + other: ungefär %{count} timmar + about_x_months: + one: ungefär en månad + other: ungefär %{count} månader + about_x_years: + one: ungefär ett år + other: ungefär %{count} år + almost_x_years: + one: nästan ett år + other: nästan %{count} år + half_a_minute: en halv minut + less_than_x_minutes: + one: mindre än en minut + other: mindre än %{count} minuter + less_than_x_seconds: + one: mindre än en sekund + other: mindre än %{count} sekunder + over_x_years: + one: mer än ett år + other: mer än %{count} år + x_days: + one: en dag + other: ! '%{count} dagar' + x_minutes: + one: en minut + other: ! '%{count} minuter' + x_months: + one: en månad + other: ! '%{count} månader' + x_seconds: + one: en sekund + other: ! '%{count} sekunder' + prompts: + day: Dag + hour: Timme + minute: Minut + month: Månad + second: Sekund + year: År + errors: &errors + format: ! '%{attribute} %{message}' + messages: + accepted: måste vara accepterad + blank: måste anges + confirmation: stämmer inte överens + empty: får ej vara tom + equal_to: måste vara samma som + even: måste vara jämnt + exclusion: är reserverat + greater_than: måste vara större än %{count} + greater_than_or_equal_to: måste vara större än eller lika med %{count} + inclusion: finns inte i listan + invalid: har fel format + less_than: måste vara mindre än %{count} + less_than_or_equal_to: måste vara mindre än eller lika med %{count} + not_a_number: är inte ett nummer + not_an_integer: måste vara ett heltal + odd: måste vara udda + record_invalid: ! 'Ett fel uppstod: %{errors}' + taken: har redan tagits + too_long: är för lång (maximum är %{count} tecken) + too_short: är för kort (minimum är %{count} tecken) + wrong_length: har fel längd (ska vara %{count} tecken) + template: + body: ! 'Det var problem med följande fält:' + header: + one: Ett fel förhindrade denna %{model} från att sparas + other: ! '%{count} fel förhindrade denna %{model} från att sparas' + helpers: + select: + prompt: Välj + submit: + create: Skapa %{model} + submit: Spara %{model} + update: Ändra %{model} + number: + currency: + format: + delimiter: ! ',' + format: ! '%n %u' + precision: 2 + separator: . + significant: false + strip_insignificant_zeros: false + unit: kr + format: + delimiter: + precision: 2 + separator: ! ',' + significant: false + strip_insignificant_zeros: false + human: + decimal_units: + format: ! '%n %u' + units: + billion: Miljard + million: Miljon + quadrillion: Biljard + thousand: Tusen + trillion: Biljon + unit: '' + format: + delimiter: '' + precision: 1 + significant: true + strip_insignificant_zeros: true + storage_units: + format: ! '%n %u' + units: + byte: + one: Byte + other: Bytes + gb: GB + kb: KB + mb: MB + tb: TB + percentage: + format: + delimiter: '' + precision: + format: + delimiter: '' + support: + array: + last_word_connector: ! ' och ' + two_words_connector: ! ' och ' + words_connector: ! ', ' + time: + am: '' + formats: + default: ! '%a, %e %b %Y %H:%M:%S %z' + long: ! '%Y-%m-%d %H:%M:%S' + short: ! '%Y-%m-%d %H:%M' + pm: '' + # remove these aliases after 'activemodel' and 'activerecord' namespaces are removed from Rails repository + activemodel: + errors: + <<: *errors + activerecord: + errors: + <<: *errors + diff --git a/config/memcached b/config/memcached new file mode 100644 index 0000000..7a86ba5 --- /dev/null +++ b/config/memcached @@ -0,0 +1,74 @@ +#! /bin/sh +### BEGIN INIT INFO +# Provides: memcached +# Required-Start: $syslog +# Required-Stop: $syslog +# Should-Start: $local_fs +# Should-Stop: $local_fs +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: memcached - Memory caching daemon +# Description: memcached - Memory caching daemon +### END INIT INFO + +# Install as /etc/init.d/memcached + +PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin +DAEMON=/usr/bin/memcached +DAEMONBOOTSTRAP=/usr/share/memcached/scripts/start-memcached +NAME=memcached +DESC=memcached +PIDFILE=/var/run/$NAME.pid + +test -x $DAEMON || exit 0 +test -x $DAEMONBOOTSTRAP || exit 0 + +set -e + +. /lib/lsb/init-functions + +# Edit /etc/default/memcached to change this. +ENABLE_MEMCACHED=no +test -r /etc/default/memcached && . /etc/default/memcached + +case "$1" in + start) + echo -n "Starting $DESC: " + if [ $ENABLE_MEMCACHED = yes ]; then + start-stop-daemon --start --quiet --exec $DAEMONBOOTSTRAP + echo "$NAME." + else + echo "$NAME disabled in /etc/default/memcached." + fi + ;; + stop) + echo -n "Stopping $DESC: " + start-stop-daemon --stop --quiet --oknodo --pidfile $PIDFILE --exec $DAEMON + echo "$NAME." + rm -f $PIDFILE + ;; + + restart|force-reload) + # + # If the "reload" option is implemented, move the "force-reload" + # option to the "reload" entry above. If not, "force-reload" is + # just the same as "restart". + # + echo -n "Restarting $DESC: " + start-stop-daemon --stop --quiet --oknodo --pidfile $PIDFILE + rm -f $PIDFILE + sleep 1 + start-stop-daemon --start --quiet --exec $DAEMONBOOTSTRAP + echo "$NAME." + ;; + status) + status_of_proc $DAEMON $NAME + ;; + *) + N=/etc/init.d/$NAME + echo "Usage: $N {start|stop|restart|force-reload|status}" >&2 + exit 1 + ;; +esac + +exit 0 \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb new file mode 100644 index 0000000..f4f93e2 --- /dev/null +++ b/config/routes.rb @@ -0,0 +1,43 @@ +DashboardKomin::Application.routes.draw do + + root to: "dashboard#index" + + get "/more_feed_entries/:category/:before" => "dashboard#more_feed_entries", as: "more_feed_entries" + + get "/users/select_feeds/:category" => "users#select_feeds", as: "user_select_feeds" + put "/users/select_feeds/:category" => "users#update_feeds" + put "/users/reset_feeds/:category" => "users#reset_feeds", as: "user_reset_feeds" + get "/users/select_shortcuts/:category" => "users#select_shortcuts", as: "user_select_shortcuts" + put "/users/select_shortcuts/:category" => "users#update_shortcuts" + put "/users/reset_shortcuts/:category" => "users#reset_shortcuts", as: "user_reset_shortcuts" + get "/users/search" => "users#search", as: "users_search" + put "/users/update_status_message" => "users#update_status_message", as: "user_update_status_message" + + # Avatars belongs to users but has its own controller + resources :avatars + # Stream out :username's avatar + get "/users/:username/avatars/(:style)" => "avatars#show", as: "user_avatar" + + # Map username instead of user id + get "/users/:username" => "users#show", as: "user" + resources :users, except: [:show] + get "/my_profile" => "users#my_profile", as: "my_profile" + get "/my_roles" => "users#my_roles", as: "my_roles" + + get "/colleagueships/search" => "colleagueships#search", as: "colleagueships_search" + resources :colleagueships + + delete "/my_own_feeds/delete_all" => "my_own_feeds#destroy_all" + + resources :shortcuts, :roles, :feeds, :my_own_feeds, except: [:show] + + # get "/search" => "site_search#index" + # get "/search/autocomplete" => "site_search#autocomplete", as: "site_search_autocomplete" + + get "/login" => "sessions#new" + post "/login" => "sessions#create" + get "/logout" => "sessions#destroy" + + # Catch everything else. "a" is the path in Rails 3's routing + match '*a', to: 'application#not_found', format: false +end diff --git a/config/schedule.rb b/config/schedule.rb new file mode 100644 index 0000000..4a70a33 --- /dev/null +++ b/config/schedule.rb @@ -0,0 +1,34 @@ +# Whenever cron manager http://github.com/javan/whenever + +# Installed w/capistrano: deploy.rb + +# Check output with +# $ bundle exec whenever --set 'environment=production' + +set :output, "#{path}/log/cron.log" +set :real_environment, environment == "staging" ? "test" : "production" # 'staging' is a pseudo environment +job_type :rake, "cd :path && PATH=/usr/local/bin:$PATH RAILS_ENV=:real_environment bundle exec rake :task --silent :output" + +if environment == "staging" + every :day, :at => '2:13am' do + rake "delete_old_feed_entries" + end + + every :day, :at => '2:43am' do + rake "clear_expired_sessions" + end +end + +if environment == "production" + every :day, :at => '4:13am' do + rake "delete_old_feed_entries" + end + + every :day, :at => '4:43am' do + rake "clear_expired_sessions" + end +end + +every :reboot do + command "RAILS_ENV=#{real_environment} #{path}/lib/daemons/feed_worker_ctl start" +end diff --git a/db/migrate/20111114225613_create_users.rb b/db/migrate/20111114225613_create_users.rb new file mode 100644 index 0000000..122ba6f --- /dev/null +++ b/db/migrate/20111114225613_create_users.rb @@ -0,0 +1,20 @@ +class CreateUsers < ActiveRecord::Migration + def change + create_table :users do |t| + t.string :username + t.string :first_name + t.string :last_name + t.string :email + t.string :phone + t.string :cell_phone + t.string :title + t.text :short_bio + t.string :status_message + t.string :password_digest + t.string :salt + t.boolean :is_admin + t.timestamps + end + add_index :users, :username, :unique => true + end +end diff --git a/db/migrate/20111123140706_create_feeds.rb b/db/migrate/20111123140706_create_feeds.rb new file mode 100644 index 0000000..6e90939 --- /dev/null +++ b/db/migrate/20111123140706_create_feeds.rb @@ -0,0 +1,13 @@ +class CreateFeeds < ActiveRecord::Migration + def change + create_table :feeds do |t| + t.string :name + t.string :url + t.string :category + t.string :targeting + t.integer :recent_failures, :default => 0 + t.integer :total_failures, :default => 0 + t.timestamps + end + end +end diff --git a/db/migrate/20111221124118_create_sessions.rb b/db/migrate/20111221124118_create_sessions.rb new file mode 100644 index 0000000..c1de174 --- /dev/null +++ b/db/migrate/20111221124118_create_sessions.rb @@ -0,0 +1,11 @@ +class CreateSessions < ActiveRecord::Migration + def change + create_table :sessions do |t| + t.string :session_id, :null => false + t.text :data + t.timestamps + end + add_index :sessions, :session_id + add_index :sessions, :updated_at + end +end diff --git a/db/migrate/20120118125533_create_shortcuts.rb b/db/migrate/20120118125533_create_shortcuts.rb new file mode 100644 index 0000000..6c1b078 --- /dev/null +++ b/db/migrate/20120118125533_create_shortcuts.rb @@ -0,0 +1,11 @@ +class CreateShortcuts < ActiveRecord::Migration + def change + create_table :shortcuts do |t| + t.string :name + t.string :url + t.string :targeting + t.string :category + t.timestamps + end + end +end diff --git a/db/migrate/20120122142627_create_roles.rb b/db/migrate/20120122142627_create_roles.rb new file mode 100644 index 0000000..e873723 --- /dev/null +++ b/db/migrate/20120122142627_create_roles.rb @@ -0,0 +1,10 @@ +class CreateRoles < ActiveRecord::Migration + def change + create_table :roles do |t| + t.string :name + t.string :category + t.timestamps + end + add_index :roles, :name, :unique => true + end +end diff --git a/db/migrate/20120122144640_add_join_tables.rb b/db/migrate/20120122144640_add_join_tables.rb new file mode 100644 index 0000000..9dfafce --- /dev/null +++ b/db/migrate/20120122144640_add_join_tables.rb @@ -0,0 +1,31 @@ +class AddJoinTables < ActiveRecord::Migration + def change + create_table :roles_users, :id => false do |t| + t.references :role + t.references :user + t.timestamps + end + add_index :roles_users, [ :role_id, :user_id ], :unique => true, :name => :index_roles_users + + create_table :roles_shortcuts, :id => false do |t| + t.references :role + t.references :shortcut + t.timestamps + end + add_index :roles_shortcuts, [ :role_id, :shortcut_id ], :unique => true, :name => :index_roles_shortcuts + + create_table :feeds_roles, :id => false do |t| + t.references :feed + t.references :role + t.timestamps + end + add_index :feeds_roles, [ :feed_id, :role_id ], :unique => true, :name => :index_feeds_roles + + create_table :feeds_users, :id => false do |t| + t.references :feed + t.references :user + t.timestamps + end + add_index :feeds_users, [ :feed_id, :user_id ], :unique => true, :name => :index_feeds_user + end +end diff --git a/db/migrate/20120209103434_create_feed_entries.rb b/db/migrate/20120209103434_create_feed_entries.rb new file mode 100644 index 0000000..dac98f5 --- /dev/null +++ b/db/migrate/20120209103434_create_feed_entries.rb @@ -0,0 +1,13 @@ +class CreateFeedEntries < ActiveRecord::Migration + def change + create_table :feed_entries do |t| + t.text :entry + t.datetime :published_at + t.string :guid + t.references :feed + + t.timestamps + end + add_index :feed_entries, :feed_id + end +end diff --git a/db/migrate/20120407155519_add_etag_and_published_at_to_feeds.rb b/db/migrate/20120407155519_add_etag_and_published_at_to_feeds.rb new file mode 100644 index 0000000..470ce88 --- /dev/null +++ b/db/migrate/20120407155519_add_etag_and_published_at_to_feeds.rb @@ -0,0 +1,6 @@ +class AddEtagAndPublishedAtToFeeds < ActiveRecord::Migration + def change + add_column :feeds, :etag, :string + add_column :feeds, :published_at, :datetime + end +end diff --git a/db/migrate/20120409103246_change_on_feed_entry.rb b/db/migrate/20120409103246_change_on_feed_entry.rb new file mode 100644 index 0000000..4b0c6f6 --- /dev/null +++ b/db/migrate/20120409103246_change_on_feed_entry.rb @@ -0,0 +1,10 @@ +class ChangeOnFeedEntry < ActiveRecord::Migration + def up + rename_column :feed_entries, :entry, :full + change_column :feed_entries, :full, :text, :limit => 500.kilobytes + end + def down + change_column :feed_entries, :entry, :string + rename_column :feed_entries, :full, :entry + end +end diff --git a/db/migrate/20120410081302_add_link_to_feed.rb b/db/migrate/20120410081302_add_link_to_feed.rb new file mode 100644 index 0000000..c715a1c --- /dev/null +++ b/db/migrate/20120410081302_add_link_to_feed.rb @@ -0,0 +1,5 @@ +class AddLinkToFeed < ActiveRecord::Migration + def change + add_column :feeds, :link, :string + end +end diff --git a/db/migrate/20120410082544_change_names_on_feed.rb b/db/migrate/20120410082544_change_names_on_feed.rb new file mode 100644 index 0000000..765a940 --- /dev/null +++ b/db/migrate/20120410082544_change_names_on_feed.rb @@ -0,0 +1,7 @@ +class ChangeNamesOnFeed < ActiveRecord::Migration + def change + rename_column :feeds, :name, :title + rename_column :feeds, :url, :feed_url + rename_column :feeds, :link, :url + end +end diff --git a/db/migrate/20120410124328_change_guid_type_on_feed_entry.rb b/db/migrate/20120410124328_change_guid_type_on_feed_entry.rb new file mode 100644 index 0000000..7c4d30c --- /dev/null +++ b/db/migrate/20120410124328_change_guid_type_on_feed_entry.rb @@ -0,0 +1,8 @@ +class ChangeGuidTypeOnFeedEntry < ActiveRecord::Migration + def up + change_column :feed_entries, :guid, :text, :limit => 2.kilobytes + end + def down + change_column :feed_entries, :guid, :string + end +end diff --git a/db/migrate/20120410145731_change_ur_l_type_on_feed.rb b/db/migrate/20120410145731_change_ur_l_type_on_feed.rb new file mode 100644 index 0000000..17faa74 --- /dev/null +++ b/db/migrate/20120410145731_change_ur_l_type_on_feed.rb @@ -0,0 +1,10 @@ +class ChangeUrLTypeOnFeed < ActiveRecord::Migration + def up + change_column :feeds, :url, :text, :limit => 2.kilobytes + change_column :feeds, :feed_url, :text, :limit => 2.kilobytes + end + def down + change_column :feeds, :url, :string + change_column :feeds, :feed_url, :string + end +end diff --git a/db/migrate/20120413120655_change_columns_on_user.rb b/db/migrate/20120413120655_change_columns_on_user.rb new file mode 100644 index 0000000..051b861 --- /dev/null +++ b/db/migrate/20120413120655_change_columns_on_user.rb @@ -0,0 +1,13 @@ +class ChangeColumnsOnUser < ActiveRecord::Migration + def change + change_table :users do |t| + t.string :displayname + t.string :company + t.string :manager + t.string :directreports + t.boolean :remember_me, default: false + t.string :remember_me_key + end + remove_column :users, :password_digest + end +end diff --git a/db/migrate/20120414172144_change_fields_on_user.rb b/db/migrate/20120414172144_change_fields_on_user.rb new file mode 100644 index 0000000..ec41ff6 --- /dev/null +++ b/db/migrate/20120414172144_change_fields_on_user.rb @@ -0,0 +1,7 @@ +class ChangeFieldsOnUser < ActiveRecord::Migration + def change + rename_column :users, :remember_me_key, :auth_token + remove_column :users, :remember_me + change_column :users, :is_admin, :boolean, :null => false + end +end diff --git a/db/migrate/20120416114332_change_column_properties_on_user.rb b/db/migrate/20120416114332_change_column_properties_on_user.rb new file mode 100644 index 0000000..41eb399 --- /dev/null +++ b/db/migrate/20120416114332_change_column_properties_on_user.rb @@ -0,0 +1,9 @@ +class ChangeColumnPropertiesOnUser < ActiveRecord::Migration + def up + change_column :users, :is_admin, :boolean, :default => false, :null => false + end + + def down + change_column :users, :is_admin, :boolean, :default => false + end +end diff --git a/db/migrate/20120419090517_remove_targeting_from_feeds_and_shortcuts.rb b/db/migrate/20120419090517_remove_targeting_from_feeds_and_shortcuts.rb new file mode 100644 index 0000000..b59568f --- /dev/null +++ b/db/migrate/20120419090517_remove_targeting_from_feeds_and_shortcuts.rb @@ -0,0 +1,10 @@ +class RemoveTargetingFromFeedsAndShortcuts < ActiveRecord::Migration + def up + remove_column :feeds, :targeting + remove_column :shortcuts, :targeting + end + def down + add_column :feeds, :targeting, :string + add_column :shortcuts, :targeting, :string + end +end diff --git a/db/migrate/20120428114806_add_shortcuts_users.rb b/db/migrate/20120428114806_add_shortcuts_users.rb new file mode 100644 index 0000000..1b6b9f7 --- /dev/null +++ b/db/migrate/20120428114806_add_shortcuts_users.rb @@ -0,0 +1,9 @@ +class AddShortcutsUsers < ActiveRecord::Migration + def change + create_table :shortcuts_users, :id => false do |t| + t.references :shortcut + t.references :user + end + add_index :shortcuts_users, [ :shortcut_id, :user_id ], :unique => true, :name => :index_shortcuts_user + end +end diff --git a/db/migrate/20120428142451_remove_timestamps_from_join_tables.rb b/db/migrate/20120428142451_remove_timestamps_from_join_tables.rb new file mode 100644 index 0000000..75642e2 --- /dev/null +++ b/db/migrate/20120428142451_remove_timestamps_from_join_tables.rb @@ -0,0 +1,22 @@ +class RemoveTimestampsFromJoinTables < ActiveRecord::Migration + def up + remove_column :roles_users, :created_at + remove_column :roles_users, :updated_at + remove_column :roles_shortcuts, :created_at + remove_column :roles_shortcuts, :updated_at + remove_column :feeds_roles, :created_at + remove_column :feeds_roles, :updated_at + remove_column :feeds_users, :created_at + remove_column :feeds_users, :updated_at + remove_column :feed_entries, :created_at + remove_column :feed_entries, :updated_at + end + + def down + add_timestamps :roles_users + add_timestamps :roles_shortcuts + add_timestamps :feeds_roles + add_timestamps :feeds_users + add_timestamps :feed_entries + end +end diff --git a/db/migrate/20120430135511_change_auth_columns_on_user.rb b/db/migrate/20120430135511_change_auth_columns_on_user.rb new file mode 100644 index 0000000..fa2d825 --- /dev/null +++ b/db/migrate/20120430135511_change_auth_columns_on_user.rb @@ -0,0 +1,13 @@ +class ChangeAuthColumnsOnUser < ActiveRecord::Migration + def up + rename_column :users, :auth_token, :remember_me_hash + add_column :users, :remember_me_id, :string + add_column :users, :remember_me, :boolean + end + + def down + rename_column :users, :remember_me_hash, :auth_token + remove_column :users, :remember_me_id + remove_column :users, :remember_me + end +end diff --git a/db/migrate/20120617111217_create_user_agents.rb b/db/migrate/20120617111217_create_user_agents.rb new file mode 100644 index 0000000..12efc48 --- /dev/null +++ b/db/migrate/20120617111217_create_user_agents.rb @@ -0,0 +1,17 @@ +class CreateUserAgents < ActiveRecord::Migration + def change + create_table :user_agents do |t| + t.references :user + t.boolean :remember_me, default: false + t.string :remember_me_hash + t.string :user_agent_tag + t.timestamps + end + add_index :user_agents, [ :id, :user_id ], :unique => true + + remove_column :users, :remember_me_hash + remove_column :users, :remember_me_id + remove_column :users, :remember_me + remove_column :users, :salt + end +end diff --git a/db/migrate/20120626215920_add_checksum_to_feeds.rb b/db/migrate/20120626215920_add_checksum_to_feeds.rb new file mode 100644 index 0000000..63b2a80 --- /dev/null +++ b/db/migrate/20120626215920_add_checksum_to_feeds.rb @@ -0,0 +1,5 @@ +class AddChecksumToFeeds < ActiveRecord::Migration + def change + add_column :feeds, :checksum, :string + end +end diff --git a/db/migrate/20120627105124_change_column_on_feeds.rb b/db/migrate/20120627105124_change_column_on_feeds.rb new file mode 100644 index 0000000..e01eedf --- /dev/null +++ b/db/migrate/20120627105124_change_column_on_feeds.rb @@ -0,0 +1,6 @@ +class ChangeColumnOnFeeds < ActiveRecord::Migration + def change + rename_column :feeds, :published_at, :fetched_at + remove_column :feeds, :etag + end +end diff --git a/db/migrate/20120810103514_add_latest_login_to_users.rb b/db/migrate/20120810103514_add_latest_login_to_users.rb new file mode 100644 index 0000000..182988f --- /dev/null +++ b/db/migrate/20120810103514_add_latest_login_to_users.rb @@ -0,0 +1,5 @@ +class AddLatestLoginToUsers < ActiveRecord::Migration + def change + add_column :users, :latest_login, :timestamp + end +end diff --git a/db/migrate/20120820161743_change_collation_on_all.rb b/db/migrate/20120820161743_change_collation_on_all.rb new file mode 100644 index 0000000..50839a0 --- /dev/null +++ b/db/migrate/20120820161743_change_collation_on_all.rb @@ -0,0 +1,16 @@ +class ChangeCollationOnAll < ActiveRecord::Migration + + tables = %w(feed_entries feeds feeds_roles feeds_users roles roles_shortcuts roles_users schema_migrations sessions shortcuts shortcuts_users user_agents users) + + def up + tables.each do |t| + execute "ALTER TABLE #{t} CONVERT TO CHARACTER SET utf8 COLLATE utf8_swedish_ci;" + end + end + + def down + tables.each do |t| + execute "ALTER TABLE #{t} CONVERT TO CHARACTER SET utf8 COLLATE utf8_unicode_ci;" + end + end +end diff --git a/db/migrate/20120822122622_create_colleagueships.rb b/db/migrate/20120822122622_create_colleagueships.rb new file mode 100644 index 0000000..c923fb4 --- /dev/null +++ b/db/migrate/20120822122622_create_colleagueships.rb @@ -0,0 +1,11 @@ +class CreateColleagueships < ActiveRecord::Migration + def change + create_table :colleagueships do |t| + t.integer :user_id + t.integer :colleague_id + + t.timestamps + end + add_index :colleagueships, [:user_id, :colleague_id], :unique => true + end +end diff --git a/db/migrate/20120828083249_add_attachment_avatar_to_users.rb b/db/migrate/20120828083249_add_attachment_avatar_to_users.rb new file mode 100644 index 0000000..879368d --- /dev/null +++ b/db/migrate/20120828083249_add_attachment_avatar_to_users.rb @@ -0,0 +1,7 @@ +class AddAttachmentAvatarToUsers < ActiveRecord::Migration + def change + change_table :users do |t| + t.has_attached_file :avatar + end + end +end diff --git a/db/migrate/20120904122636_add_timestamps_to_feed_entries.rb b/db/migrate/20120904122636_add_timestamps_to_feed_entries.rb new file mode 100644 index 0000000..70cb3a6 --- /dev/null +++ b/db/migrate/20120904122636_add_timestamps_to_feed_entries.rb @@ -0,0 +1,5 @@ +class AddTimestampsToFeedEntries < ActiveRecord::Migration + def change + add_timestamps :feed_entries + end +end diff --git a/db/migrate/20120907111836_add_fetched_gravatar_to_user.rb b/db/migrate/20120907111836_add_fetched_gravatar_to_user.rb new file mode 100644 index 0000000..1a9f59f --- /dev/null +++ b/db/migrate/20120907111836_add_fetched_gravatar_to_user.rb @@ -0,0 +1,5 @@ +class AddFetchedGravatarToUser < ActiveRecord::Migration + def change + add_column :users, :fetched_gravatar, :boolean, default: false + end +end diff --git a/db/migrate/20120907113704_set_default_values_on_user.rb b/db/migrate/20120907113704_set_default_values_on_user.rb new file mode 100644 index 0000000..2725f63 --- /dev/null +++ b/db/migrate/20120907113704_set_default_values_on_user.rb @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +class SetDefaultValuesOnUser < ActiveRecord::Migration + + def up + change_column_default(:users, :first_name, 'Förnamn saknas') + change_column_default(:users, :last_name, 'Efternamn saknas') + change_column_default(:users, :email, 'E-post saknas') + + User.all.each do |u| + if u.first_name == nil + u.first_name = 'Förnamn saknas' + end + + if u.last_name == nil + u.last_name = 'Efternamn saknas' + end + + if u.email == nil + u.email = 'E-post saknas' + end + u.save(validate: false) + end + end +end diff --git a/db/migrate/20121129102626_add_url_to_roles.rb b/db/migrate/20121129102626_add_url_to_roles.rb new file mode 100644 index 0000000..c051f31 --- /dev/null +++ b/db/migrate/20121129102626_add_url_to_roles.rb @@ -0,0 +1,57 @@ +# -*- coding: utf-8 -*- + +# Map technical department name to human name +DEPT = { + "centrum" => "Centrum", + "fastighetskontoret" => "Fastighetskontoret", + "fosie" => "Fosie", + "fritidsforvaltningen" => "Fritidsförvaltningen", + "gatukontoret" => "Gatukontoret", + "husie" => "Husie", + "hyllie" => "Hyllie", + "kirseberg" => "Kirseberg", + "kulturforvaltningen" => "Kulturförvaltningen", + "limhamn-bunkeflo" => "Limhamn-Bunkeflo", + "miljoforvaltningen" => "Miljöförvaltningen", + "oxie" => "Oxie", + "rosengard" => "Rosengård", + "serviceforvaltningen" => "Serviceförvaltningen", + "sociala-resursforvaltningen" => "Sociala resursförvaltningen", + "stadsbyggnadskontoret" => "Stadsbyggnadskontoret", + "stadskontoret" => "Stadskontoret", + "stadsrevisionen" => "Stadsrevisionen", + "sodra-innerstaden" => "Södra innerstaden", + "utbildningsforvaltningen" => "Utbildningsförvaltningen", + "vastra-innerstaden" => "Västra innerstaden", + "overformyndarforvaltningen" => "Överförmyndarförvaltningen", + "ekonomi" => "Ekonomi", + "folkhalsa" => "Folkhälsa", + "forskola-utbildning" => "Förskola & utbildning", + "individ-familj" => "Individ & familj", + "integration-arbetsmarknad" => "Integration & arbetsmarknad", + "it" => "IT", + "hr" => "HR", + "kommunikationsarbete" => "Kommunikationsarbete", + "naringsliv-foretagare" => "Näringsliv/företagare", + "trygghets-sakerhetsarbete" => "Trygghets- & säkerhetsarbete", + "turism" => "Turism", + "vard-omsorg" => "Vård & omsorg", + "arendeberedning" => "Ärendeberedning" +} + +class AddUrlToRoles < ActiveRecord::Migration + def up + add_column :roles, :homepage_url, :string + + # Set initial values of homepage_url field based on DEPT and human name in name column + Role.reset_column_information + Role.all.each do |r| + r.homepage_url = "http://komin.malmo.se/#{ DEPT.invert[r.name] }" + r.save(validate: false) + end + end + + def down + remove_column :roles, :homepage_url + end +end diff --git a/db/migrate/20121129134140_add_add_status_message_updated_at_to_user.rb b/db/migrate/20121129134140_add_add_status_message_updated_at_to_user.rb new file mode 100644 index 0000000..cec557e --- /dev/null +++ b/db/migrate/20121129134140_add_add_status_message_updated_at_to_user.rb @@ -0,0 +1,5 @@ +class AddAddStatusMessageUpdatedAtToUser < ActiveRecord::Migration + def change + add_column :users, :status_message_updated_at, :datetime, default: nil + end +end diff --git a/db/migrate/20121129134835_remove_fetched_gravatar_from_user.rb b/db/migrate/20121129134835_remove_fetched_gravatar_from_user.rb new file mode 100644 index 0000000..06a02c9 --- /dev/null +++ b/db/migrate/20121129134835_remove_fetched_gravatar_from_user.rb @@ -0,0 +1,5 @@ +class RemoveFetchedGravatarFromUser < ActiveRecord::Migration + def change + remove_column :users, :fetched_gravatar + end +end diff --git a/db/migrate/20130314134446_add_recent_skips_to_feeds.rb b/db/migrate/20130314134446_add_recent_skips_to_feeds.rb new file mode 100644 index 0000000..a84bc6c --- /dev/null +++ b/db/migrate/20130314134446_add_recent_skips_to_feeds.rb @@ -0,0 +1,5 @@ +class AddRecentSkipsToFeeds < ActiveRecord::Migration + def change + add_column :feeds, :recent_skips, :integer, default: 0 + end +end diff --git a/db/schema.rb b/db/schema.rb new file mode 100644 index 0000000..a29e803 --- /dev/null +++ b/db/schema.rb @@ -0,0 +1,151 @@ +# encoding: UTF-8 +# This file is auto-generated from the current state of the database. Instead +# of editing this file, please use the migrations feature of Active Record to +# incrementally modify your database, and then regenerate this schema definition. +# +# Note that this schema.rb definition is the authoritative source for your +# database schema. If you need to create the application database on another +# system, you should be using db:schema:load, not running all the migrations +# from scratch. The latter is a flawed and unsustainable approach (the more migrations +# you'll amass, the slower it'll run and the greater likelihood for issues). +# +# It's strongly recommended to check this file into your version control system. + +ActiveRecord::Schema.define(:version => 20130314134446) do + + create_table "colleagueships", :force => true do |t| + t.integer "user_id" + t.integer "colleague_id" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + + add_index "colleagueships", ["user_id", "colleague_id"], :name => "index_colleagueships_on_user_id_and_colleague_id", :unique => true + + create_table "feed_entries", :force => true do |t| + t.text "full", :limit => 16777215 + t.datetime "published_at" + t.text "guid" + t.integer "feed_id" + t.datetime "created_at" + t.datetime "updated_at" + end + + add_index "feed_entries", ["feed_id"], :name => "index_feed_entries_on_feed_id" + + create_table "feeds", :force => true do |t| + t.string "title" + t.text "feed_url" + t.string "category" + t.integer "recent_failures", :default => 0 + t.integer "total_failures", :default => 0 + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.datetime "fetched_at" + t.text "url" + t.string "checksum" + t.integer "recent_skips", :default => 0 + end + + create_table "feeds_roles", :id => false, :force => true do |t| + t.integer "feed_id" + t.integer "role_id" + end + + add_index "feeds_roles", ["feed_id", "role_id"], :name => "index_feeds_roles", :unique => true + + create_table "feeds_users", :id => false, :force => true do |t| + t.integer "feed_id" + t.integer "user_id" + end + + add_index "feeds_users", ["feed_id", "user_id"], :name => "index_feeds_user", :unique => true + + create_table "roles", :force => true do |t| + t.string "name" + t.string "category" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.string "homepage_url" + end + + add_index "roles", ["name"], :name => "index_roles_on_name", :unique => true + + create_table "roles_shortcuts", :id => false, :force => true do |t| + t.integer "role_id" + t.integer "shortcut_id" + end + + add_index "roles_shortcuts", ["role_id", "shortcut_id"], :name => "index_roles_shortcuts", :unique => true + + create_table "roles_users", :id => false, :force => true do |t| + t.integer "role_id" + t.integer "user_id" + end + + add_index "roles_users", ["role_id", "user_id"], :name => "index_roles_users", :unique => true + + create_table "sessions", :force => true do |t| + t.string "session_id", :null => false + t.text "data" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + + add_index "sessions", ["session_id"], :name => "index_sessions_on_session_id" + add_index "sessions", ["updated_at"], :name => "index_sessions_on_updated_at" + + create_table "shortcuts", :force => true do |t| + t.string "name" + t.string "url" + t.string "category" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + + create_table "shortcuts_users", :id => false, :force => true do |t| + t.integer "shortcut_id" + t.integer "user_id" + end + + add_index "shortcuts_users", ["shortcut_id", "user_id"], :name => "index_shortcuts_user", :unique => true + + create_table "user_agents", :force => true do |t| + t.integer "user_id" + t.boolean "remember_me", :default => false + t.string "remember_me_hash" + t.string "user_agent_tag" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + + add_index "user_agents", ["id", "user_id"], :name => "index_user_agents_on_id_and_user_id", :unique => true + + create_table "users", :force => true do |t| + t.string "username" + t.string "first_name", :default => "Förnamn saknas" + t.string "last_name", :default => "Efternamn saknas" + t.string "email", :default => "E-post saknas" + t.string "phone" + t.string "cell_phone" + t.string "title" + t.text "short_bio" + t.string "status_message" + t.boolean "is_admin", :default => false, :null => false + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.string "displayname" + t.string "company" + t.string "manager" + t.string "directreports" + t.datetime "latest_login" + t.string "avatar_file_name" + t.string "avatar_content_type" + t.integer "avatar_file_size" + t.datetime "avatar_updated_at" + t.datetime "status_message_updated_at" + end + + add_index "users", ["username"], :name => "index_users_on_username", :unique => true + +end diff --git a/lib/daemons/feed_worker b/lib/daemons/feed_worker new file mode 100755 index 0000000..f5fde5a --- /dev/null +++ b/lib/daemons/feed_worker @@ -0,0 +1,17 @@ +#!/usr/bin/env ruby + +root = File.expand_path(File.dirname(File.dirname(File.dirname(__FILE__)))) +Dir.chdir(root) + +require File.join(root, "config", "environment") + +$running = true +Signal.trap("TERM") do + $running = false +end + +# Run the FeedWorker in +while($running) do + FeedWorker.update_all + sleep 5 +end diff --git a/lib/daemons/feed_worker_ctl b/lib/daemons/feed_worker_ctl new file mode 100755 index 0000000..047e065 --- /dev/null +++ b/lib/daemons/feed_worker_ctl @@ -0,0 +1,22 @@ +#!/usr/bin/env ruby + +# Run with: +# $ RAILS_ENV= lib/daemons/feed_worker_ctl start + +require "daemons" + +ENV['RAILS_ENV'] ||= "production" + +ENV["APP_ROOT"] = File.expand_path(File.dirname(File.dirname(File.dirname(__FILE__)))) + +script = File.join(ENV["APP_ROOT"], "lib", "daemons", "feed_worker" ) +config = { + dir_mode: :normal, + dir: "#{ENV["APP_ROOT"]}/log", # `daemons` put log and pid in same dir + multiple: false, + backtrace: true, + monitor: true, + ontop: false +} + +Daemons.run script, config diff --git a/lib/tasks/clear_expired_sessions.rake b/lib/tasks/clear_expired_sessions.rake new file mode 100644 index 0000000..6e7fb0a --- /dev/null +++ b/lib/tasks/clear_expired_sessions.rake @@ -0,0 +1,7 @@ +desc "Clear expired sessions and optimize the table" +task clear_expired_sessions: :environment do + t = Time.new.to_f + ActiveRecord::Base.connection.execute('DELETE FROM sessions WHERE updated_at < DATE_SUB(NOW(), INTERVAL 1 DAY);') + ActiveRecord::Base.connection.execute('OPTIMIZE TABLE sessions;') + puts "#{Time.now} Expired sessions removed in #{(Time.new.to_f - t)} seconds" +end diff --git a/lib/tasks/delete_old_feed_entries.rake b/lib/tasks/delete_old_feed_entries.rake new file mode 100644 index 0000000..340df74 --- /dev/null +++ b/lib/tasks/delete_old_feed_entries.rake @@ -0,0 +1,9 @@ +desc "Delete old feed entries and optimize the table" +task delete_old_feed_entries: :environment do + t = Time.new.to_f + fe_before = FeedEntry.count + ActiveRecord::Base.connection.execute('DELETE FROM feed_entries WHERE published_at < DATE_SUB(NOW(), INTERVAL 4 WEEK);') + ActiveRecord::Base.connection.execute('OPTIMIZE TABLE feed_entries;') + fe_after = FeedEntry.count + puts "#{Time.now} #{fe_before - fe_after} expired feed entries removed in #{(Time.new.to_f - t)} seconds" +end diff --git a/public/404.html b/public/404.html new file mode 100644 index 0000000..61f0a99 --- /dev/null +++ b/public/404.html @@ -0,0 +1,26 @@ + + + + The page you were looking for doesn't exist (404) + + + + + +
    +

    Sidan kunde inte hittas

    +

    Prova att söka efter sidan i sökfältet uppe till höger eller använd menyerna.

    +
    + + diff --git a/public/422.html b/public/422.html new file mode 100644 index 0000000..83660ab --- /dev/null +++ b/public/422.html @@ -0,0 +1,26 @@ + + + + The change you wanted was rejected (422) + + + + + +
    +

    The change you wanted was rejected.

    +

    Maybe you tried to change something you didn't have access to.

    +
    + + diff --git a/public/500.html b/public/500.html new file mode 100644 index 0000000..53fc070 --- /dev/null +++ b/public/500.html @@ -0,0 +1,17 @@ + + + + + Nu gick något helt fel + + + +
    +

    Nu gick något helt fel

    +

    Vänligen försök igen lite senare

    +
    + + diff --git a/public/503.html b/public/503.html new file mode 100644 index 0000000..e4f2a15 --- /dev/null +++ b/public/503.html @@ -0,0 +1,18 @@ + + + + + + + Min sida - Komin + + + +

    Underhållsarbete pågår

    +

    Välkommen åter om en liten stund

    + + \ No newline at end of file diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000..e69de29 diff --git a/public/robots.txt b/public/robots.txt new file mode 100644 index 0000000..8e1d420 --- /dev/null +++ b/public/robots.txt @@ -0,0 +1,5 @@ +# See http://www.robotstxt.org/wc/norobots.html for documentation on how to use the robots.txt file +# +# To ban all spiders from the entire site uncomment the next two lines: +User-Agent: * +Disallow: / diff --git a/public/system/maintenance.html b/public/system/maintenance.html new file mode 100644 index 0000000..53a8211 --- /dev/null +++ b/public/system/maintenance.html @@ -0,0 +1,29 @@ + + + + + + + Min sida - Komin + + + +

    Underhållsarbete pågår

    +

    Välkommen åter om en liten stund

    + + + \ No newline at end of file diff --git a/script/rails b/script/rails new file mode 100755 index 0000000..f8da2cf --- /dev/null +++ b/script/rails @@ -0,0 +1,6 @@ +#!/usr/bin/env ruby +# This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application. + +APP_PATH = File.expand_path('../../config/application', __FILE__) +require File.expand_path('../../config/boot', __FILE__) +require 'rails/commands' diff --git a/spec/factories.rb b/spec/factories.rb new file mode 100644 index 0000000..1463f59 --- /dev/null +++ b/spec/factories.rb @@ -0,0 +1,41 @@ +# -*- coding: utf-8 -*- + +FactoryGirl.define do + factory :user do + sequence(:username) { |n| "user-#{n}" } + first_name 'First' + last_name 'Last' + sequence(:email) { |n| "user-#{n}@example.org" } + sequence(:displayname) { |n| "First-#{n} Last-#{n}" } + latest_login Time.now + end + + factory :admin_user, parent: :user do + is_admin true + end + + factory :user_with_status_message, parent: :user do + status_message 'It’s work, all that matters is work' + status_message_updated_at Time.now + end + + factory :add_collagues, parent: :user do + end + + factory :role do + sequence(:name) { |n| "Role-#{n}" } + homepage_url 'http://rspec.info/' + category Role::CATEGORIES.keys.first + end + + factory :feed do + feed_url "http://www.whitehouse.gov/feed/press" + category Feed::CATEGORIES.keys.first + end + + factory :shortcut do + name "Fox barx" + url "http://www.example.com" + category Shortcut::CATEGORIES.keys.first + end +end diff --git a/spec/features/authentication_spec.rb b/spec/features/authentication_spec.rb new file mode 100644 index 0000000..7b3f6d5 --- /dev/null +++ b/spec/features/authentication_spec.rb @@ -0,0 +1,48 @@ +# -*- coding: utf-8 -*- +require 'spec_helper' + +feature "Authentication" do + scenario "should require login for the dashboard" do + visit root_path + current_path.should eq(login_path) + page.should have_selector('h1', text: "Logga in") + page.should have_field("password") + end + + scenario "should require login for profile page" do + user = FactoryGirl.create(:user) + visit user_path(user.username) + current_path.should eq(login_path) + page.should have_selector('h1', text: "Logga in") + end + + scenario "should require login for an admin page" do + visit roles_path + current_path.should eq(login_path) + page.should have_selector('h1', text: "Logga in") + end + + scenario "should not sign in a user with incorrect credentials" do + visit login_path + fill_in 'username', with: 'Fox' + fill_in 'password', with: 'barx' + click_button 'Logga in' + current_path.should eq(login_path) + page.should have_selector('.warning', text: 'Fel användarnamn eller lösenord') + end + + scenario "should not sign in a user without credentials" do + visit login_path + fill_in 'username', with: '' + fill_in 'password', with: '' + click_button 'Logga in' + current_path.should eq(login_path) + page.should have_selector('.warning', text: 'Fel användarnamn eller lösenord') + end + + scenario "should sign in a user with correct credentials" do + create_user_and_login + current_path.should eq(root_path) + page.should have_selector('h1', text: "Mina Kominnyheter") + end +end \ No newline at end of file diff --git a/spec/features/authorization_spec.rb b/spec/features/authorization_spec.rb new file mode 100644 index 0000000..782501b --- /dev/null +++ b/spec/features/authorization_spec.rb @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +require 'spec_helper' + +feature "Authorization" do + scenario "should require admin role" do + user = FactoryGirl.create(:user) + visit login_path + fill_in 'username', with: user.username + click_button 'Logga in' + visit feeds_path + page.should have_selector('.error', text: "Du saknar behörighet") + end + + scenario "should honor admin role" do + user = FactoryGirl.create(:admin_user) + visit login_path + fill_in 'username', with: user.username + click_button 'Logga in' + visit feeds_path + page.should have_selector('h1', text: "Nyhetsflöden") + end +end diff --git a/spec/features/colleagueship_spec.rb b/spec/features/colleagueship_spec.rb new file mode 100644 index 0000000..ee8fc9e --- /dev/null +++ b/spec/features/colleagueship_spec.rb @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +require 'spec_helper' + +feature "Colleagueships" do + scenario "should not be set" do + create_user_and_login + visit root_path + page.should have_selector('.no-colleagues') + end + + scenario "should be set" do + follower = FactoryGirl.create(:user) + followed = FactoryGirl.create(:user) + Colleagueship.create(user_id: follower.id, colleague_id: followed.id) + login(follower.username, 'stub') + visit root_path + page.should_not have_selector('.no-colleagues') + page.should have_xpath("//li[not(@id='my-status')][1]", text: followed.displayname) + end +end diff --git a/spec/features/feeds_spec.rb b/spec/features/feeds_spec.rb new file mode 100644 index 0000000..ace52f4 --- /dev/null +++ b/spec/features/feeds_spec.rb @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- +require 'spec_helper' + +# NOTE: THis spec doesn't work with the rest of the specs, probably a db cleaning issue + +# feature "Feeds" do +# let(:user) { create_user_with_roles_with_feeds } +# before(:each) { login(user.username, 'stub') } + +# scenario "should have news feed entries" do +# all("#feeds-news .box-content li").count.should > 1 +# end + +# scenario "should have dialog feed entries" do +# all("#feeds-dialog .box-content li").count.should > 1 +# end + +# scenario "should have one feture feed entry" do +# all("#feeds-feature .box-content li").count.should == 1 +# end + +# scenario "should load more new feed entries", :js => true do +# before = all("#feeds-news .box-content li").count +# find("#feeds-news .box-content li.load-more input").click +# sleep 1 +# before.should < all("#feeds-news .box-content li").count +# end +# end diff --git a/spec/features/global_assets_spec.rb b/spec/features/global_assets_spec.rb new file mode 100644 index 0000000..6a03f15 --- /dev/null +++ b/spec/features/global_assets_spec.rb @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- +require 'spec_helper' + +feature "Global assets javascript" do + before(:each) do + visit login_path + end + + scenario "should have injected the masthead", js: true do + page.should have_selector('header#malmo-masthead') + end + + scenario "should have a link to Our organization", js: true do + page.should have_selector('#nav-our-organization', text: 'Vår kommun') + end + + scenario "should have a link to the dashboard", js: true do + page.should have_selector('#nav-dashboard', text: 'Min sida') + end + + scenario "should have a form for employee search", js: true do + page.should have_selector('#masthead-search-person') + end + + scenario "should have a form for intranet search", js: true do + page.should have_selector('#masthead-search-intranet') + end +end diff --git a/spec/features/site_seeker_spec.rb b/spec/features/site_seeker_spec.rb new file mode 100644 index 0000000..fc4d1a1 --- /dev/null +++ b/spec/features/site_seeker_spec.rb @@ -0,0 +1,45 @@ +# -*- coding: utf-8 -*- +require 'spec_helper' + +feature SiteSeeker do + scenario "should not require login" do + visit search_path + current_path.should eq(search_path) + end + + scenario "should have a search form" do + visit search_path + page.should have_selector('form#full-search') + end +end + +feature "Search results" do + scenario "should have a search form" do + visit search_path + page.should have_selector('form#full-search') + end + + scenario "should have a prefilled form" do + query = "semester lön" + visit "/search?#{ {q: query}.to_query}" + find('form#full-search input[name=q]').value.should include query + end + + scenario "should display a results" do + visit "/search?#{ {q: "semester lön"}.to_query}" + page.should have_selector('.results') + end + + scenario "should have a load more link" do + visit "/search?#{ {q: "semester"}.to_query}" + page.should have_selector('#load-more-search-results', text: "Visa fler") + end + + scenario "should load more results", js: true do + visit "/search?#{ {q: "semester"}.to_query}" + before = all("section.results li h2").count + click_link("Visa fler") + sleep 1 + before.should < all("section.results li h2").count + end +end diff --git a/spec/features/status_message_spec.rb b/spec/features/status_message_spec.rb new file mode 100644 index 0000000..46cb976 --- /dev/null +++ b/spec/features/status_message_spec.rb @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +require 'spec_helper' + +feature "Status message" do + scenario "should not be set" do + create_user_and_login + visit root_path + page.should have_selector('#my-status .status', text: "Jag har ingen status än!") + end + + scenario "should be set" do + user = FactoryGirl.create(:user_with_status_message) + login(user.username, 'stub') + visit root_path + page.should_not have_selector('#my-status .status', text: "Jag har ingen status än!") + end + + scenario "should be set interactively", js: true do + create_user_and_login + visit root_path + status = 'My new status message' + find('#status_message').set status + page.execute_script("$('#update-status-form').submit()") + page.should have_selector('#my-status .status', text: status) + end +end diff --git a/spec/models/colleagueship_spec.rb b/spec/models/colleagueship_spec.rb new file mode 100644 index 0000000..ca306c2 --- /dev/null +++ b/spec/models/colleagueship_spec.rb @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +require 'spec_helper' + +describe Colleagueship do + let(:follower) { FactoryGirl.create(:user) } + let(:followed) { FactoryGirl.create(:user) } + + it "should not be set" do + follower.colleagueships.should be_blank + end + + it "should be set" do + Colleagueship.create(user_id: follower.id, colleague_id: followed.id) + follower.colleagueships.should be_present + end + + it "should be removed" do + Colleagueship.create(user_id: follower.id, colleague_id: followed.id) + followed.destroy + follower.colleagueships.should be_blank + end +end diff --git a/spec/models/feed_spec.rb b/spec/models/feed_spec.rb new file mode 100644 index 0000000..34db50d --- /dev/null +++ b/spec/models/feed_spec.rb @@ -0,0 +1,77 @@ +# -*- coding: utf-8 -*- +require 'spec_helper' + +describe Feed do + + it "should be valid" do + FactoryGirl.build(:feed).should be_valid + end + + it "should be invalid" do + FactoryGirl.build(:feed, feed_url: "www.example.com").should be_invalid + end + + it "should be invalid" do + FactoryGirl.build(:feed, feed_url: "http://www.example.com").should be_invalid + end + + it "should be valid" do + FactoryGirl.build(:feed, feed_url: "feed://www.whitehouse.gov/feed/press").should be_valid + end + + it "should be valid" do + FactoryGirl.build(:feed, feed_url: "www.whitehouse.gov/feed/press").should be_valid + end + + it "should not be valid without a feed_url" do + FactoryGirl.build(:feed, feed_url: "").should_not be_valid + end + + it "should be created" do + expect { FactoryGirl.create(:feed) }.to change(Feed, :count).by(1) + end + + it "should have a title" do + FactoryGirl.build(:feed).should respond_to :title + end + + it "should have a title" do + FactoryGirl.create(:feed).title.should be_present + end + + it "should have a feed_url" do + FactoryGirl.create(:feed).feed_url.should be_present + end + + it "should have a feed_url" do + FactoryGirl.create(:feed).feed_url.should be_present + end + + it "should have an url" do + FactoryGirl.create(:feed).url.should be_present + end + + it "should have a checksum" do + FactoryGirl.create(:feed).checksum.should be_present + end + + it "should have feed entries" do + expect { FactoryGirl.create(:feed) }.to change(FeedEntry, :count).by(30) + end + + it "should have a valid category" do + feed = FactoryGirl.create(:feed) + Feed::CATEGORIES.should have_key(feed.category) + end + + it "should be destroyed" do + feed = FactoryGirl.create(:feed) + expect { feed.destroy }.to change(Feed, :count).by(-1) + end + + it "should destroy associated feed_entries" do + feed = FactoryGirl.create(:feed) + items = feed.feed_entries.size + expect { feed.destroy }.to change(FeedEntry, :count).by(-items) + end +end diff --git a/spec/models/role_spec.rb b/spec/models/role_spec.rb new file mode 100644 index 0000000..b60553e --- /dev/null +++ b/spec/models/role_spec.rb @@ -0,0 +1,39 @@ +# -*- coding: utf-8 -*- +require 'spec_helper' + +describe Role do + let(:role) { FactoryGirl.create(:role) } + + it "should be valid" do + FactoryGirl.build(:role).should be_valid + end + + it "should be created" do + expect { FactoryGirl.create(:role) }.to change(Role, :count).by(1) + end + + it "should have a unique name" do + FactoryGirl.build(:role, name: role.name).should_not be_valid + end + + it "should not be valid without a category" do + FactoryGirl.build(:role, category: nil).should_not be_valid + end + + it "should not be valid without a homepage" do + FactoryGirl.build(:role, homepage_url: nil).should_not be_valid + end + + it "should have a homepage" do + role.homepage_url.should be_present + end + + it "should have a valid category" do + Role::CATEGORIES.should have_key(role.category) + end + + it "should be destroyed" do + role = FactoryGirl.create(:role) + expect { role.destroy }.to change(Role, :count).by(-1) + end +end diff --git a/spec/models/shortcut_spec.rb b/spec/models/shortcut_spec.rb new file mode 100644 index 0000000..ee379ef --- /dev/null +++ b/spec/models/shortcut_spec.rb @@ -0,0 +1,42 @@ +# -*- coding: utf-8 -*- +require 'spec_helper' + +describe Shortcut do + it "should be valid" do + FactoryGirl.build(:shortcut).should be_valid + end + + it "should have an url" do + FactoryGirl.build(:shortcut, url: "").should be_invalid + end + + it "should have a valid url" do + FactoryGirl.build(:shortcut, url: "http://x.y").should be_invalid + end + + it "should have a name" do + FactoryGirl.build(:shortcut, name: "").should be_invalid + end + + it "should have a name" do + FactoryGirl.create(:shortcut).name.should be_present + end + + it "should be created" do + expect { FactoryGirl.create(:shortcut) }.to change(Shortcut, :count).by(1) + end + + it "should have a feed_url" do + FactoryGirl.create(:shortcut).url.should be_present + end + + it "should have a valid category" do + shortcut = FactoryGirl.build(:shortcut) + Shortcut::CATEGORIES.should have_key(shortcut.category) + end + + it "should be destroyed" do + shortcut = FactoryGirl.create(:shortcut) + expect { shortcut.destroy }.to change(Shortcut, :count).by(-1) + end +end diff --git a/spec/samples/whitehouse.rss b/spec/samples/whitehouse.rss new file mode 100644 index 0000000..c34fa1b --- /dev/null +++ b/spec/samples/whitehouse.rss @@ -0,0 +1,2315 @@ + + + White House.gov Press Office Feed + http://www.whitehouse.gov/hispanic/blog/feed + + en + + WEEKLY ADDRESS: The President’s Plan to Create Jobs and Cut the Deficit + http://www.whitehouse.gov/the-press-office/2013/04/06/weekly-address-president-s-plan-create-jobs-and-cut-deficit + WASHINGTON, DC—President Obama used his weekly address to tell the American people about the Budget he is sending to Congress this week, which makes the tough choices required to grow our economy and shrink our deficits.  The President’s Budget calls for a balanced approach to deficit reduction, including reforms that strengthen Medicare for future generations and tax reform that closes wasteful loopholes, so we can afford the investments required to grow grow the economy, create new jobs, and reignite the engine of our economic growth: a rising, thriving middle class.

    +

    The audio of the address and video of the address will be available online at www.whitehouse.gov at 6:00 a.m. ET, Saturday, April 6, 2013.

    +

    Remarks of President Barack Obama
    + Weekly Address
    + The White House
    + April 6, 2013

    +

    Hi, everybody.  Our top priority as a nation, and my top priority as President, must be doing everything we can to reignite the engine of America’s growth: a rising, thriving middle class.  That’s our North Star.  That must drive every decision we make.

    +

    Now, yesterday, we learned that our businesses created 95,000 new jobs last month.  That’s about 500,000 new jobs this year, and nearly 6.5 million new jobs over the past three years. 

    +

    But we’ve got more work to do to get the economy growing faster, so that everybody who wants a job can find one.  And that means we need fewer self-inflicted wounds from Washington, like the across-the-board spending cuts that are already hurting many communities – cuts that economists predict will cost our economy hundreds of thousands of jobs this year.

    +

    If we want to keep rebuilding this economy on a stronger, sturdier foundation for growth – growth that creates good, middle-class jobs – we need to make smarter choices.

    +

    This week, I’ll send a budget to Congress that will help do just that – a fiscally-responsible blueprint for middle-class jobs and growth.

    +

    For years, an argument in Washington has raged between reducing our deficits at all costs, and making the investments we need to grow the economy.  My budget puts that argument to rest.  Because we don’t have to choose between these goals – we can do both.  After all, as we saw in the 1990s, nothing reduces deficits faster than a growing economy. 

    +

    My budget will reduce our deficits not with aimless, reckless spending cuts that hurt students and seniors and middle-class families – but through the balanced approach that the American people prefer, and the investments that a growing economy demands.

    +

    Now, the truth is, our deficits are already shrinking.  That’s a fact.  I’ve already signed more than $2.5 trillion in deficit reduction into law, and my budget will reduce our deficits by nearly $2 trillion more, without harming the recovery.  That surpasses the goal of $4 trillion in deficit reduction that many economists believe will stabilize our finances.

    +

    We’ll make the tough reforms required to strengthen Medicare for the future, without undermining the rock-solid guarantee at its core.  And we’ll enact commonsense tax reform that includes closing wasteful tax loopholes for the wealthy and well-connected – loopholes like the ones that can allow a billionaire to pay a lower tax rate than his or her secretary.

    +

    This is the compromise I offered the Speaker of the House at the end of last year.  While it’s not my ideal plan to further reduce the deficit, it’s a compromise I’m willing to accept in order to move beyond a cycle of short-term, crisis-driven decision-making, and focus on growing our economy and our middle class for the long run.  It includes ideas many Republicans have said they could accept as well.  It’s a way we can make progress together.

    +

    But deficit reduction cannot come at the cost of economic growth or middle-class security.  And it doesn’t have to.  My budget will make critical investments to grow the economy, create jobs, and strengthen the middle class. 

    +

    As I said in my State of the Union Address, every day, we should ask ourselves three questions: how do we make America a magnet for good jobs?  How do we give our workers the skills they need to do those jobs?  And how do we make sure that hard work leads to a decent living?

    +

    To make America a magnet for good jobs, we’ll invest in high-tech manufacturing and homegrown American energy, put people to work building new roads, bridges, and schools, and cut red tape to help businesses grow.

    +

    To give workers the skills they need to do those jobs, we’ll invest in education that begins in the earliest years, and job training that better equips workers to compete in a 21st century economy.

    +

    To make sure hard work is rewarded, we’ll build new ladders of opportunity into the middle class, and focus on revitalizing some of our communities hardest-hit by recession and job loss.

    +

    All of these investments will help grow the economy and create jobs.  None of them will add to the deficit.  And I will lay out these priorities in greater detail in the days ahead.

    +

    It’s a budget that doesn’t spend beyond our means.  And it’s a budget that doesn’t make harsh and unnecessary cuts that only serve to slow our economy.  We’ll keep our promise to an aging generation by shoring up Medicare.  And we’ll keep our promise to the next generation by investing in the fundamentals that have always made America strong – manufacturing and innovation, energy and education. 

    +

    Because that’s what it’ll take to make sure America remains strong in the years ahead – and to leave behind something better for our kids.

    +

    Thank you.

    +

    ###

    +]]>
    + Speeches and Remarks + Speeches and Remarks + Office of the Press Secretary + Sat, 06 Apr 2013 10:00:00 +0000 + The White House + 207476 at http://www.whitehouse.gov +
    + + Press Briefing by Press Secretary Jay Carney, 4/5/2013 + http://www.whitehouse.gov/the-press-office/2013/04/05/press-briefing-press-secretary-jay-carney-452013 +  

    +
    + James S. Brady Press Briefing Room
    +
    +  
    +
    +  
    +
    + 1:26 P.M. EDT
    +
    +  
    +
    +

    MR. CARNEY:  Before I take your questions, I just wanted to let you know about some events next week related to the President's push for common-sense measures to reduce gun violence.

    +

    As the Senate returns from the Easter recess to begin considering such measures, the President, the Vice President and the First Lady will hold events outside of Washington D.C. and at the White House to encourage Americans to make their voices heard in this important debate.  As you know, the President will visit Hartford, Connecticut, where he will meet with families affected by the shooting at Sandy Hook Elementary School, and to give a speech reminding members of Congress that those who have been most affected by tragic gun violence deserve a vote on the measures currently being considered.

    +

    On Tuesday, the Vice President will hold an event with law enforcement officials here at the White House, echoing the President's call on Congress to pass common-sense gun legislation.

    +

    On Wednesday, the First Lady will visit her hometown of Chicago, where she will speak from her experience as a Chicagoan and a mother about the importance of providing young people with opportunities to achieve their full potential, including by allowing them to grow up in safe, violence-free communities.

    +

    And then on Thursday, Vice President Biden will appear on MSNBC's "Morning Joe" for a roundtable discussion with the show's hosts and experts with diverse opinions on the gun safety debate.

    +

    And with that, I will take your questions.  Jim, Associated Press.

    +

    Q    Budget question, and one other topic.  The budget the President will propose incorporates what you have put up on the screen there, which is the President's offer to Speaker Boehner back in December.  That offer was rejected by House Republicans, and I'm wondering what the President thinks has changed that would actually make this a viable proposal now, four months later, or even during the year, as that budget gets debated?

    +

    Q    Well, I'll say a couple of things.  One, it wasn't rejected by House Republicans.  The Speaker of the House walked away from those negotiations, unfortunately.  I think the offer the President made to Speaker of the House Boehner was widely viewed -- appropriately -- as a good-faith offer that met the Republicans halfway on the issues of revenue on the one hand, and entitlement reforms and savings from entitlement reforms on the other.

    +

    And as we have been saying all along, that offer stands.  It has been available to Republicans ever since.  And it is, I can confirm, a part of the President's budget proposal next week. 

    +

    It is part of it because the President believes we need a broad, balanced approach to our fiscal challenges.  We need a budget that reduces the deficit but also invests in infrastructure and education and innovation; that makes the investments that help the middle class grow; that protects middle-class families; that puts in place the building blocks for future economic growth. 

    +

    And what the President's budget will demonstrate is that it is not an either/or proposition; that if you make wise, balanced choices when it comes to deficit reduction, if you ask everyone to chip in, if you ask the very wealthy and the well-connected to contribute by eliminating their special tax provisions and loopholes from the tax code, you can put forward a plan that exceeds the goal of $4 trillion in deficit reduction over 10 years, that stabilizes our debt, and invests in our economy, invests in our families, invests in our businesses.  And that’s what the President's budget will do. 

    +

    Q    Does he think that this is any more palatable today to, let’s say -- you said rejected by the Speaker -- but any more palatable to the Speaker?

    +

    MR. CARNEY:  Well, let’s examine what we’ve seen from Republicans in terms of budget proposals.  We have a wildly ideological document produced by House Republicans that’s been broadly dismissed by economists as fanciful, even in its claims to balance over 10 years; that represents an effort to drastically cut programs that help middle-class families; that voucherizes Medicare, shifts costs onto seniors who can’t afford it while giving a $5.7 trillion tax cut mostly to the wealthy.  That has not been taken very seriously.

    +

    The President’s proposal, as I think people have been discussing this morning, represents a middle-of-the-road, common-sense approach to dealing with these challenges.  The President has been engaged over the past weeks in a conversation with lawmakers of both parties about the need to find common ground, and he has been exploring with Republic lawmakers where that common ground can be found. 

    +

    And there has been interest expressed by Republican lawmakers in the idea when it comes to our budget challenges of taking a balanced approach -- that if we achieve savings through entitlement reforms, we should also, in the name of balance and in the -- with the goal of a budget that allows our economy to grow and create jobs, ask the well-off and well-connected to contribute through tax reform -- tax reform which, by the way, was elemental to the proposal that the Speaker put forward last year; said he could achieve up to a trillion dollars in revenue from the wealthy through the process of closing loopholes.  It was elemental to the proposal that the Republican nominee for President made last year.  He said that he would go after deductions as a means of achieving some revenue.  Obviously there were huge problems with the rest of his plan. 

    +

    But the President’s proposal, as you know, includes the provision that would cap deductions for wealthier Americans at 28 percent -- a very common-sense proposition.

    +

    Q    Speaking of revenue, as you know, the President has this inflation-adjustment proposal in this plan.  Time and again, the President has said that he would not raise taxes on the middle class.  One of the effects of that so-called chained CPI inflation adjustment is that it kicks people into higher tax brackets faster.  That’s an impact on the middle class.  Isn’t that an increase on the middle class, and is the President backtracking on this --

    +

    MR. CARNEY:  Well, let’s be clear, this is a technical adjustment to the so-called CPI -- called chained CPI that has been advocated by Republicans, that Mitch McConnell asked for in a letter that he presented during the negotiations over these budget issues.  The offer that the President made to Speaker Boehner, and which is incorporated in the President’s budget, is not the President’s ideal approach to our budget challenges, but it is a serious compromise proposition that demonstrates that he wants to get things done, that he believes that we in Washington ought to do the business of the American people by coming together and finding common ground.

    +

    And what his budget will prove is that you can do this.  You can deal with our deficits without gutting programs that help the middle class, that help seniors; without slashing investments in airports and roads and highways and schools that we need to help our economy grow, not just next year but 10 years from now and 20 years from now; without eliminating investments or cutting investments in innovative research and development, whether it’s medical research or technological research that help our economy grow and help improve the health of our citizenry.

    +

    So that’s what the -- that’s the proposition the President will put forward on Wednesday.  And he believes that there is an opportunity now to come together as a nation, come together as Republicans and Democrats here in Washington, and get this done for the American people, for the middle class.

    +

    Q    Jay, I know my colleagues have more questions on this, but I just wanted to quickly ask about these visits that the President is going to have from leaders of Turkey, Jordan, UAE and Qatar.  Is the President trying to coordinate assistance to Syrian rebels by having all of these leaders of countries that have been in the process of helping disparate elements of the opposition in Syria?

    +

    MR. CARNEY:  It is true that, as you saw earlier today, we announced a number of upcoming visits by leaders from the Middle East as well as from Turkey.  The President looks forward to welcoming his counterparts from the UAE, from Qatar, Jordan and Turkey to Washington over the next several weeks. 

    +

    As you know, President Obama has very close relationships with these leaders, and he has a deep personal interest in the region, as you saw during his recent trip.  He will use these opportunities to discuss the complex developments in the broader Middle East -- so not just Syria, but including Syria.  There are obviously a number of issues for these leaders and the President to discuss, including Syria; including his recent visit to Jordan, Israel and the Palestinian territories; including the broader developments in the Arab Spring. 

    +

    So he looks forward to these visits.  And they reflect his commitment and interest in the region and in our policies towards the region.

    +

    Q    Follow up, Jay?  Going back to Jim's earlier questions about the budget -- Speaker Boehner this morning said the President was ignoring Republican's pleas not to make entitlement reforms hostage to more revenues.  Given his staunch refusal to contemplate further revenues, what makes the President think he can persuade him or Republicans to accept the increase in revenues that you're putting forward in your budget proposal?  And is going beyond Speaker Boehner part of your strategy?

    +

    MR. CARNEY:  Well, it's an excellent question, because you're basically asking, do we believe that Speaker Boehner could come to accept the proposals that Speaker Boehner made in December, and actually -- achieving less revenue than Speaker Boehner said he could achieve by closing loopholes and eliminating special tax provisions.

    +

    We hope that’s possible.  We believe it's the right thing to do.  When he talks about holding entitlement reforms hostage, his proposal -- the proposal he endorsed that the House passed that Chairman Ryan put forward -- eliminates Medicare as we know it; voucherizes the program; shifts costs, I believe -- I forget the exact figure -- $4,000 or $5,000 on average to seniors annually, unnecessarily.

    +

    It would be one thing -- it wouldn’t still be good policy -- but it would be one thing if that was the proposition alone, and it was an argument that we needed to do this in and of itself -- to voucherize Medicare, shift all these thousands of dollars of costs to each senior in America.  But it is coupled with a proposal that tax -- that gives tax cuts of $5.7 trillion over 10 years disproportionately to the wealthy.  And the President is very comfortable saying that that is the wrong approach.  And that’s not just his opinion, it's the opinion of a majority of the American people.

    +

    This is the debate we had during the election.  It was the number-one debate of the election.  And that approach was I think very soundly rejected by the American people. 

    +

    The President is engaged in conversations with potential members of the common-sense caucus, with Republicans who will at least entertain the idea of dealing with our budget challenges in a balanced way -- not just through spending cuts and cuts to entitlement programs, but through a package of proposals that ask the wealthy and well-to-do to give up their tax breaks, their special provisions in the tax code; that make sensible reforms to our entitlements; that protect our seniors and strengthen those programs and allow us -- the overall package allows us to make investments in key areas of our economy and in our people and the middle class so that we can grow and expand and create jobs.

    +

    That’s the sort of fundamental principle that he is putting forward, and it will be reflected in his budget.  And he's -- it's more a matter of coincidence than anything else, but he's having dinner that very night that his budget is released with another group of senators, Republican senators.  And he looks forward to that discussion very much.

    +

    Q    Can I just ask, on North Korea -- you addressed this quickly yesterday on the way back -- but there are reports that North Korea is moving missiles to the coast.  Wanted to know if you had any more information about whether that constitutes another threat, or whether there is a concern that they may be planning a missile test?  I guess the birthday of Kim Il-sung is coming up soon.  Is it possible to connect --

    +

    MR. CARNEY:  Thank you for the question.  We've obviously seen the reports that North Korea may be making preparations to launch a missile, and we're monitoring this situation closely.  And we would not be surprised to see them take such an action.   We have seen them launch missiles in the past, and the United Nations Security Council has repeatedly condemned them as violations of the North's obligations under numerous Security Council resolutions, and it would fit their current pattern of bellicose, unhelpful and unconstructive rhetoric and actions.

    +

    We urge them to stop with the provocations, and to focus instead on meeting their international obligations and feeding their own people.  They are only making themselves more and more isolated from the rest of the world, as I've been saying all week, and undermining their stated goal of economic development.

    +

    Jon.

    +

    Q    Jay, some of the President's strongest supporters are -- think this is a terrible idea, of eliminating -- of limiting cost-of-living increases for Social Security.  The Progressive Change Campaign said this morning, "You can't call yourself a Democrat and support Social Security benefit cuts.  The President is proposing to steal thousands of dollars from grandparents and veterans."  Your response?

    +

    MR. CARNEY:  The President believes that the budget he will put forward next Wednesday represents a balanced approach to dealing with our deficit challenges and making the necessary investments in our economy and our people. 

    +

    It protects our seniors.  It does not go the Republican route of eviscerating social programs and voucherizing Medicare.  It is not the ideal proposal, but the President recognizes, unlike, I guess, Republicans, that we're not in the business in Washington of getting everything we want.  That does not happen.  Negotiation and compromise requires a willingness to accept less than 100 percent of what you want.

    +

    The President believes that the entitlement reforms he put forward to Speaker of the House John Boehner late last year, which are embodied in this budget proposal which you're referring to right now, are acceptable within the context of a broader budget that invests in the economy, that protects and assists the middle class, that protects seniors and allows us to grow and create jobs.  The alternative approach is not acceptable.  It's not acceptable to the President, and it is not acceptable to the American people. 

    +

    We see these ideological documents put forward and it certainly makes you wonder whether there is a genuine effort underway -- at least on the House Republican side -- to try to find something that can be agreed to by everybody in Washington.  Because compromise is not saying, I'm going to wait here until you come to me 100 percent.  It's not going to happen.  The President will not voucherize Medicare.  He will not eviscerate programs that invest in infrastructure and education.  He will not slash investments in research and development, and technologies that will help us grow in the future.

    +

    He does believe that if we take a balanced approach, we can achieve the kind of deficit reduction that's necessary to stabilize our debt and that will allow us to continue to grow and create jobs. 

    +

    Q    But when John McCain floated the idea of raising the retirement age and doing exactly this on cost-of-living increases in 2008, the President went before the AARP and he said, point blank, "Let me be clear:  I will not do either."  So what's changed?  Why did he switch his position?

    +

    MR. CARNEY:  Well, first of all, he is not proposing to raise the retirement age, as you know.

    +

    Q    But he is proposing to do this cost-of-living --

    +

    MR. CARNEY:  And, secondly, as I think I've said a couple of times now, this is not the President's ideal budget proposal.  It is a budget proposal that represents a good-faith compromise position that reflects the offer he made to the Speaker of the House that was widely seen as a compromise good-faith effort that met Republicans halfway, and that reflected the people's will that we address these challenges in a way that's balanced and fair -- and that we don't go down the road that has been rejected by the public of doing great harm to programs that are fundamental to the well-being of our senior citizens and do great harm to programs that assist families who have kids with disabilities or that assist middle-class Americans trying to get by.  That's just not acceptable to this President.  And it's not acceptable to the American people.

    +

    Q    Just a technical question -- the $1.8 trillion you're claiming here, you would replace the $1.2 trillion in sequester cuts.  So isn't it true that the actual deficit -- the added deficit reduction here is $600 billion?

    +

    MR. CARNEY:  Well, that's a complete false equivalence.  The $1.2 trillion was part of the Budget Control Act that was part of the overall goal of achieving $4 trillion.  Absolutely, we would replace the sequester.  And in addition to replacing the sequester, we would have an additional $600 billion in deficit reduction bringing us to $4.3 trillion overall over a decade, which exceeds the goal set by bipartisan commissions.  That's the fact.

    +

    Q    Okay.  And then, just one thing on the President's salary --

    +

    MR. CARNEY:  I mean, if you're suggesting -- well, anyway.

    +

    Q    Well, it's just that the current --

    +

    MR. CARNEY:  I mean, let's review the sequester.  The sequester is bad policy -- designed to be bad policy with negative impacts across --

    +

    Q    But it is $1.2 trillion in deficit reduction.

    +

    MR. CARNEY:  No question.  But it's not the kind of deficit reduction Republicans said they wanted until they changed positions and called it a home run.  It doesn’t achieve any of the reforms that Republicans say they want -- no tax reform, no entitlement reforms.  It's not -- it doesn’t do any long, long-term benefit to our economy. 

    +

    What the President is proposing is that we eliminate not just the sequester through deficit reduction that's balanced, but go beyond that.  And that’s the right --

    +

    Q    Six hundred billion dollars --

    +

    MR. CARNEY:  -- to $4.3 trillion.  I think you're changing the bar here.  I think $4.3 trillion is recognized by everyone as exceeding $4 trillion, even at the level of math that I got to in college.

    +

    Q    And just a quick thing on the President's salary give-back.  We now heard he is going to give back 5 percent of his salary -- the Attorney General, Secretaries of Defense, Homeland Security, State -- et cetera.  What about the Vice President?

    +

    MR. CARNEY:  Well, I would, first of all, refer you to the Vice President's office.  Secondly, I would say that the President made clear when the sequester was about to kick in that he wanted to do this and asked his staff to work on a way for him to do it.  But we've made clear that this is a decision that everybody can make for themselves, whether they're Cabinet secretaries, other members of the administration -- or members of Congress could also make that choice.

    +

    Q    Would you expect the Vice President though to follow suit?

    +

    MR. CARNEY:  Again, we're not setting expectations.  But I think everyone, including members of Congress, can make a decision as they see fit.

    +

    Brianna, did you have anything?  You're looking pensive.

    +

    Q    No, I'm waiting.

    +

    MR. CARNEY:  Major.

    +

    Q    I'll get to the budget in a second.  How discouraged is the White House today about the jobs numbers report?

    +

    MR. CARNEY:  Well, I think you saw Alan Krueger and others discuss this.  We're disappointed that they're not better.  But the fact is, this is now 37 months -- more than three years straight -- of private-sector job creation, almost 6.5 million jobs created thanks to the policies that averted a depression and set the economy back on a trajectory of growth and job creation. 

    +

    But as we have said consistently -- and we have said when job numbers exceed expectations and when they come in below expectations -- we have more work to do.  This President is not ever going to be satisfied until everybody who is looking for a job can get a job.  And that's why we have to have economic policies that encourage growth, that reduce our deficit in a fair way -- in a way that allows us to continue to invest in the economy.  Because we have work to do here.  We can put teachers and construction workers back to work with the proposals that the President has put forward and Republicans have rejected. 

    +

    We can put -- the President has had a proposal for families to refinance their homes that would be $3,000 on average in the pockets of middle-class families.  We should move on that.

    +

    Q    How much does this administration believe the jobs report reflects either sequestration anxiety or actual economic impact?

    +

    MR. CARNEY:  Well, I would point you to our experts and others.  I think that it is certainly a part of the equation in our estimation.  There's no question that anticipation of sequester as well as the fact of sequester -- as outside economists have said -- would have a negative impact on job growth and economic growth.  The exact measurement of that with regard to this report I think economists will probably make in the future.  Our focus is on making sure that we don't unduly and unnecessarily inflict harm on the economy. 

    +

    Q    Is this a warning --

    +

    MR. CARNEY:  And the sequester is one of those instances where a decision was made by Republicans in Congress, rather than asking wealthier folks to give up --

    +

    Q    Are you saying this jobs report is a warning sign in that context?

    +

    MR. CARNEY:  I think that outside economists have predicted that the sequester, if it is not undone, will cost I think roughly a half a percentage point in economic growth, in GDP, and something like 750,000 jobs.  That would be bad.  That is unnecessary.  That would be the result of an unnecessary choice made by Republicans in the House who thought that that was a better outcome -- or Republicans in both Houses -- that that was a better outcome for the American people -- reduced economic growth, reduced job creation -- than asking folks to give up special tax breaks -- corporate jet owners, wealthy individuals who get special deductions. 

    +

    These are proposals, again, that the Speaker of the House said he supported in December, and now he claims are off the table in March and April.

    +

    Q    A follow-up on Jim’s question -- you do not and the White House does not dispute that if the chained CPI were put in -- to be put into effect, it would raise taxes on middle-income Americans?

    +

    MR. CARNEY:  The chained CPI, which is a technical adjustment to how we measure the consumer price index --

    +

    Q    But its practical effect would be --

    +

    MR. CARNEY:  Again --

    +

    Q    -- to raise taxes on --

    +

    MR. CARNEY:  I’m not disputing that, but I’m saying that it is not the President’s ideal policy.  It is in a letter from the Senate Minority Leader requesting that it be part of a negotiation deal.

    +

    Q    All right, I'm just saying you don’t disagree, that those things happen?

    +

    MR. CARNEY:  Right, but Major, and --

    +

    Q    -- a tax increase?

    +

    MR. CARNEY:  -- let’s be clear, as we’ve said all along, that the offer was on the table.  The President made that offer because he was hopeful that we would see commensurate willingness to compromise from Republicans.  Unfortunately, we haven’t seen that. 

    +

    The President is engaged in conversations with Republicans in the Senate in particular but also in the House in an effort to find common ground, to see if there is a willingness to embrace the idea that we can reduce our deficits in a balanced way and continue to invest in our economy and middle-class families.  And if there is, then we’ll be able to get something done.

    +

    Q    And to critics who would say to this President, looking at this proposal, this is the last and possibly worst time -- from their point of view -- to raise taxes on the middle class, inflict benefit cuts on elderly on fixed incomes, even in the pursuit of deficit reduction, the President would say what?

    +

    MR. CARNEY:  The President would say that as part of a balanced approach that asks the wealthy and well-to-do and well-connected to contribute their fair share through tax reform, elimination of special tax breaks that average folks don’t get, that we can also include entitlement reforms that allow us to achieve deficit reduction in a balanced way and allow us to continue to invest in our economy in ways that will help it grow and create jobs. 

    +

    As I think I’ve said, this is not the President’s ideal approach, but he believes that we were sent here to get things done on behalf of the American people and the American economy.  He doesn’t believe that it is the right approach to take to write and pass ideological documents that purport to balance the budget in 10 years when they’re just a bunch of top lines with a zero at the end and not a credible economist out there believes that’s achieved, or that the policies contained within make sense economically.  Well, that doesn’t do anybody any good.  And it certainly doesn’t bring us closer to a deal and compromise.

    +

    There are Republicans, however, in Washington, this President believes, who are open to the idea that we can do this in a balanced way; that everybody has to move off of their starting position and accept some compromise.  And that means the President being willing to do some limited entitlement reforms that continue to protect our seniors and strengthen the programs.  And it means Republicans being willing to accept what Speaker of the House John Boehner said was good policy three months ago -- not an outlandish request.

    +

    Q    Last question.  Will the President fight as hard for chained CPI as he is gun control and immigration?

    +

    MR. CARNEY:  The President will fight for the principles in his budget, and the President will fight for a balanced --

    +

    Q    As visibly?  As repetitively?

    +

    MR. CARNEY:  These are two different policy proposals.  The President believes that we ought to deal with our deficit challenges in a balanced way, and he’s looking for partners on the other side of the aisle who agree with him.

    +

    Yes, sir.  Okay, Ed.

    +

    Q    Thank you, sir.  I see in there you have your list, including nondefense discretionary spending cuts.  I believe it says $100 billion?

    +

    MR. CARNEY:  That’s correct.

    +

    Q    Can you tell us -- so when will we see a list of those spending cuts?

    +

    MR. CARNEY:  On Wednesday.

    +

    Q    Is that when the budget -- so it will have -- line by line it will say --

    +

    MR. CARNEY:  I can promise everyone here that this President’s budget will be so much more detailed than anything you’ve seen from the Republicans, it will blow your mind.

    +

    Q    Wow.  (Laughter.)  That’s exciting.  Thank you.

    +

    MR. CARNEY:  That’s your question?  (Laughter.)

    +

    Q    No, I’ve got more, I’ve got more.  Jim asked you at the beginning about Republican support for this and what’s changed since December.  What about Democratic support?  You mentioned limiting tax deductions to 28 percent.  The President has proposed that before.  He proposed it for health care -- rejected by Democrats as well as Republicans.  He proposed it as a way to pay for the American Jobs Act, as I recall, in 2011 -- Democrats like Max Baucus said that’s going to hurt charitable contributions, et cetera.  It was rejected.  So how can you get Democrats to support that now when they’ve rejected it before?

    +

    MR. CARNEY:  If the Republicans are willing to give up --

    +

    Q    But these are Democrat --

    +

    MR. CARNEY:  Hold on, and I’ll get to this. 

    +

    Q    Okay.

    +

    MR. CARNEY:  It’s a compound sentence.  If the Republicans are willing to move off of their position -- or at least the ones that leaders have staked out -- that the wealthy should not pay another dime in the supposedly all-in American effort to reduce our deficit, the President is convinced that he can lead Democrats to a compromise solution.  That was the case in December.  It was the case in the summer of 2011.  It has been the case all along.

    +

    Unfortunately, what we have seen is the opposite of that, which is an inability of leaders of the Republican Party to bring their rank-and-file lawmakers behind compromise solutions.  Instead, rump groups within conferences have dictated to leaders what the no-compromise positions should be and ought to be taken, and that results obviously in nothing but bad news, generally, for the American people. 

    +

    So yes, the President believes that these are not all ideal choices that he would make or Democrats would make.  But as is true with Senator Murray’s budget and is true with the President’s budget, this represents a balanced approach to our deficit challenges.  And the President believes that if there is a commensurate willingness by Republicans to compromise, as opposed to just pursue ideological purity, we can actually get something done for the American people.

    +

    Q    One other on Democrats.  To be clear, on chained CPI, most people focus on cuts to Social Security and then also, mentioned by Major, changes to taxes.  But as the President and you have talked about before, it affects a whole range of federal programs, so I want to clarify:  Democrats like Bernie Sanders today are saying this will mean cuts to veterans’ benefits as well.  Bernie Sanders claims $2,000 or $3,000 a year for some veterans.  Is that true?

    +

    MR. CARNEY:  Well, I would --

    +

    Q    Will it affect those benefits?  I know you might not have the number, but will it affect veterans?

    +

    MR. CARNEY:  Again, I think that the application of this particular proposal exempts certain categories of vulnerable Americans.  That has been the case, was the case when the President proposed it last year, and will be the case in the President’s budget.  The details I will have to ask you to wait for until Wednesday.  I want to give you something to cover next week, not just today.

    +

    Q    But so what -- is that a yes or no on veterans?  I don’t --

    +

    MR. CARNEY:  Well, again, I don’t --

    +

    Q    Because veterans are out there wondering.

    +

    MR. CARNEY:  -- have the specific interest -- I mean the specific, itemized breakdowns of how this works.  I would wait for the budget for those, or ask you to wait for the budget for those.

    +

    What I will say is that this is not the President’s idealized budget.  It is not what he would do if he were king or if only people who supported his proposals were in Congress.  It is what he believes is a fair and balanced approach to our deficit challenges, one that allows us to invest, that protects seniors, that helps secure the middle class and give ladders to those who want to get into the middle class.  And very importantly, it provides investments in areas of the economy that will allow us to grow, not just next year and the year after, but 10 years from now and 20 years from now.

    +

    Luke.  Sorry, Mike then Luke.

    +

    Q    So can I just shift you to the FDA morning-after pill decision today?  Does the administration intend to appeal that decision?  And regardless of the legal question, if that’s not something you’re prepared to answer, is it still the policy position of the administration that the pill should be only available to folks -- to women 16 and older?

    +

    MR. CARNEY:  I’ll say a couple of things.  On the legal issue, I would refer you to the Department of Justice, which is currently reviewing the ruling. 

    +

    On the second part of the question, Secretary Sebelius made this decision.  The President supported that decision after she made it, and I think said so in the briefing room when he was asked about it.  And he supports that decision today.  He believes it was the right common-sense approach to this issue.  Beyond that, obviously, on the legal issue, I would refer you to the Department of Justice. 

    +

    Q    But there's no sense in which something has changed in terms of the substance of the issue, in that the judge made some pretty sort of arguments that go beyond just legal arguments?  And about the sort of fairness question, there's nothing -- are you guys at all reviewing the policy position as -- to see whether something should have changed?

    +

    MR. CARNEY:  Well, again, I would -- Secretary Sebelius made this decision, so I would refer you to her and her office on the policy specifics.  But when the Secretary made this decision, the President supported it.  He believed it was a common-sense approach when it comes to Plan B and its availability over the counter to girls under, I believe, 17, and he believed that was a sensible approach.  And I believe, again, this is under review by the Department of Justice.  And I expect they will be making a decision about options --

    +

    Q    But he still thinks that it's a sensible approach?

    +

    MR. CARNEY:  His position has not changed. 

    +

    Sorry, I think Luke and then Briana.

    +

    Q    To follow up on Major's point --

    +

    MR. CARNEY:  Welcome, by the way.

    +

    Q    Thank you very much.  Opening day here.  To follow up on Major's point about the sequester -- today, Senator Reid said, "Today's employment report again shows that our economy cannot afford more self-inflicted setbacks like the sequester.  We need to focus on growth, not austerity."  Do you agree with Senator Reid on that? 

    +

    MR. CARNEY:  Word for word.

    +

    Q    Is this poor jobs numbers a direct result of the sequester?

    +

    MR. CARNEY:  Well, I think the point he made is that we cannot afford more self-inflicted -- tell me the whole quote there.

    +

    Q    "Self-inflicted setbacks like the sequester."

    +

    MR. CARNEY:  "Self-inflicted setbacks like the sequester."  You would have to turn in your economics degree if you did not concur with the universally-held opinion that sequester would result in reduction in GDP and reduction in job growth.  That is a broadly accepted fact.  And it was wholly unnecessary.

    +

    I don’t think anybody believes that we should be embracing economic policies that cause our economy to grow less fast and create fewer jobs.  I'm going to say 535 lawmakers up on Capitol Hill agree with the idea that we should embrace economic policies that do the opposite of that.

    +

    So the sequester is bad policy.  It was an unnecessary setback.  It was self-inflicted.  We believe -- again, I'm just pointing to assessments, early assessments made by the Council of Economic Advisers and Dr. Krueger -- that sequester had an impact on this, but it's hard to assess exactly how much.  Obviously there are other factors at play here.

    +

    Broadly, whether it was 200,000, 95,000, I think, private sector jobs, or 50,000, our answer is always going to be the same, which is that we have more work to do.  And we have to embrace and implement policies that help our economy grow and help it create jobs.  And that’s why the President is putting forward the budget that he'll put forward on Wednesday.  And that is the spirit and objective that has guided all of his budget proposals throughout the years of his presidency. 

    +

    Q    So it's fair to say that the White House agrees that today we are, as a country, are feeling the effects of sequester in this jobs report?

    +

    MR. CARNEY:  Well, I think, again, to a degree that is hard to measure early on, the answer is yes.  And I think that we are feeling the negative effects of the sequester in other ways -- the kids who aren't in Head Start this week are feeling it.  Their parents are feeling it.  Folks who have been furloughed or who worked in air traffic control towers that have been closed.  I mean, we see -- there has been a lot of focus in Washington on White House tours, which was an unfortunate result of implementation of the sequester, but if you look at the regional coverage of the impacts of sequester, it focuses on real people and how they have been hurt by this unnecessary policy and the decision -- the unfortunate decision by Republicans to not just allow it to happen, but to embrace it as a political victory and a homerun.

    +

    Q    Lastly, on the chained CPI idea, I spoke to some folks on the Hill on the Democratic side that were uneasy about this because it says you’re giving Speaker Boehner and the House Republicans too much leverage; that by putting chained CPI out on the table right now, the Republicans will ask for that in any type of deal moving forward saying that it was in the President’s own budget, that he believed in it so much to put it in his own budget.  Why give this away right now in April --

    +

    MR. CARNEY:  We’re not giving anything away.

    +

    Q    -- ahead of the debt limit fight coming up in the summer and a lot of other important things?

    +

    MR. CARNEY:  What the President is putting forward is a budget -- not a single policy proposal, not -- it is not line items that he is giving away or taking.  It is a budget proposal that is broad and comprehensive that represents a balanced approach to helping the economy grow, reducing our deficit, making the middle class more secure and providing opportunity to those who aspire to the middle class.  And that’s the approach we should take.

    +

    If the charge is that he should not be serious about trying to find common ground, then he disagrees with that.  He believes that we should.  But make no mistake -- he is not going to embrace Republican proposals that suggest we should just ask seniors -- just make entitlements reform changes, and not take a balanced approach to deficit reduction -- basically tell seniors, it’s all on you now, it’s all on middle-class families, families with kids who have disabilities, it’s all on those who benefit from education-assistance programs or others, and folks who benefit hugely from the tax code, wealthy individuals who pay a far lower effective tax rate than I’m sure most people in this room and certainly school teachers and police officers and bus drivers, factory workers, that they should be asked to do nothing.  That’s never going to be the President’s position.

    +

    Q    Jay?

    +

    MR. CARNEY:  Briana, you’re --

    +

    Q    Jay, I have a non-budget question.  (Laughter.) 

    +

    MR. CARNEY:  Come on, you enjoyed that.  (Laughter.)

    +

    Q    Let's see if you enjoy this one.  President Obama yesterday called California Attorney General Kamala Harris, “by far the best-looking attorney general.”  It created quite a buzz and an uproar.  Some say it highlights what they see as a troubling pattern of a woman’s success being linked to her appearance, and that it’s unseemly for the President of the United States to say that.  How has he reflected on his comments since making them?  And has he called Harris?

    +

    MR. CARNEY:  The President did speak with Attorney General Harris last night after he came back from his trip.  And he called her to apologize for the distraction created by his comments.  And they are old friends and good friends, and he did not want in any way to diminish the Attorney General’s professional accomplishments and her capabilities.  And I would note that he called her, in those same comments, “brilliant,” “dedicated” and “tough,” and she is all those things. 

    +

    She has been a remarkably effective leader as Attorney General.  She is a key player in the mortgage settlement which will help many, many middle-class families who are struggling to deal with the mortgage situation in this country.  And he believes and fully recognizes that the challenges women -- or he fully recognizes the challenge women continue to face in the workplace and that they should not be judged based on appearance.

    +

    Q    He felt like he messed up is what he said?

    +

    MR. CARNEY:  Look, I think I made clear he apologized for creating this distraction and believes very strongly that Attorney General Harris is an excellent Attorney General and that she’s done great work and she’s dedicated and tough and brilliant.

    +

    Q    And on the FDA -- the judge, Edward Korman, said that the decisions of the Secretary were arbitrary, capricious and unreasonable.  And, I mean, that was his opinion, and the President obviously supported Secretary Sebelius’s decision on this.  What’s your reaction to that?

    +

    MR. CARNEY:  Well, I would -- as a legal matter and a response to the decision by the court I would refer you to the Department of Justice, which will review this and make decisions about appeal.  I think it’s important to remember, however, that the Secretary’s decision in this matter was not about whether Plan B would be available to women, but rather whether it should be available over the counter to girls of all ages without consenting -- without consulting with a health care professional.  And Secretary Sebelius made the decision she made, which the President viewed as a very common-sense decision, one that he as a parent and other parents, he believed, would agree was a common-sense solution.  

    +

    But beyond that, I think that I’ll leave it to the Justice Department to make --

    +

    Q    Would he disagree that it was arbitrary?

    +

    MR. CARNEY:  Yes.

    +

    Q    This judgment?

    +

    MR. CARNEY:  Yes.  He supported the Secretary’s decision.

    +

    Mark.

    +

    Q    Jay, just to follow up on Harris -- twice you said that the President apologized for the distraction.  Does he not think that the remark was sexist?

    +

    MR. CARNEY:  Well, he apologized for the remark.  And they’re old friends.  And, look, I mean, the President --

    +

    Q    So he acknowledges it was inappropriate?

    +

    MR. CARNEY:  -- has known her for a long time and he apologized for it.  And he certainly regretted that it caused the distraction that Briana referred to, and --

    +

    Q    You seem to make a distinction.

    +

    MR. CARNEY:  No.  I’m making clear, I think, that he apologized for it and believes that she is a superb Attorney General for the state of California, has done an excellent job in all areas, and especially on this mortgage settlement issue.

    +

    MR. CARNEY:  Scott.

    +

    Q    Jay, are you saying that the Plan B decision was common sense because it’s a contraceptive?  Because the judge points out that you can get Tylenol at any age, and that’s more dangerous.

    +

    MR. CARNEY:  Well, again, I think the President spoke at length about this from this very podium.  His views are best expressed by him.  And I could read them to you but they’re available online, and those are his views.  And he believed it was a common-sense decision.  I think it’s important to remember that what Secretary Sebelius said and decided is that we do not have enough evidence to show that all those who could use this medicine, Plan B, can understand the label and use the product appropriately.

    +

    So I would refer you to Secretary Sebelius about the policy deliberations that went into her decision.  I can tell you that the President, as he said from this podium at the time, supported that decision and believes it was the right decision.

    +

    Q    But is that because it’s a contraceptive, not because it’s a dangerous product?

    +

    MR. CARNEY:  Well, I think that as the statement I just said makes clear, it could be dangerous if misused.  And the President felt that it was the right thing -- the right decision to make.

    +

    Roger.

    +

    Q    In the budget statement this morning, there was a reference to one of the Presidents investments, about kindergarten and the plan that he’s advancing.  And it said it would be paid for by increased taxes on tobacco.  How much of a tax is required to offset that cost?

    +

    MR. CARNEY:  Well, I don’t have specifics for you that will be available on Wednesday.  As I said, if I gave all the specifics now, you wouldn’t have anything to write about or ask me about on Wednesday.  So we’ll wait for the specifics there.  The President believes that universal pre-K is an excellent investment to make in our future.  And I think it is widely recognized by experts to be a very sensible policy approach that will pay dividends and benefits well in excess of the costs if we can get it done.  And that’s correct that his proposal, his budget will -- all of the investments that are in his budget will be paid for entirely within his budget. 

    +

    And this particular investment will be paid for by a cigarette tax, which he believes is the right way to go in this case.  Getting all of our kids into pre-K would have enormous positive impacts for those kids, for their families, and for those kids’ futures in the education system and beyond that in the workforce in the years to come.

    +

    Q    Okay.  And also, on corporate rate tax cuts -- there was talk in the campaign about lowering them at some point.  Should we expect that in the budget next Wednesday?  Some master plan or proposal?

    +

    MR. CARNEY:  I think we’ve shown --

    +

    Q    Or are you going to wait until afterward?

    +

    MR. CARNEY:  We’ve shown a lot on what’s in the budget thus far.  And I think that we’ll wait until Wednesday to provide more details about what’s in it.

    +

    Q    Okay.  And if there are details on this subject --

    +

    MR. CARNEY:  There will be.  Well --

    +

    Q    -- will they show a specific --

    +

    MR. CARNEY:  Let me finish the sentence:  There will be more details in the budget, yes.

    +

    Q    Okay.  And will it show how it’s paid for?

    +

    MR. CARNEY:  Again, I would ask you to wait, but I can say that everything in the budget that the President proposes in terms of investments and changes will be paid for.

    +

    Donovan.

    +

    Q    Thanks, Jay.  Just going back again on the budget.  I think some of the criticism from the left, from Democrats, is by his including the CPI and some of these other things that this becomes a starting point; that he’s essentially already given it away.  Why did he choose to do that now versus -- you’ve said before that the President’s budget reflects his priorities, and now you’re saying it’s not ideal.  Why are you guys taking this strategy?

    +

    MR. CARNEY:  Well, the budget reflects his priorities within a budget world that’s not ideal, within a budget decision-making process that’s not ideal, obviously, as he sees it.  It requires compromise and negotiation and a willingness to accept that you won't get 100 percent of what you want. 

    +

    I can tell you this is not -- as I said before, he is not negotiating away items of his budget.  He is presenting a comprehensive proposal that's balanced in nature, that asks the wealthiest Americans and those who get special deals through our tax code to give up those tax breaks in the name of further deficit reduction.  And he also includes entitlement reforms that he believes can be achieved as part of a balanced package that will protect our seniors and allow us to reduce our deficit in a way that also allows the economy to grow and create jobs, to continue to do that, and put us on a foundation economically that will allow us to grow well into the future.

    +

    There's no question that it's not what we would do if he could just pass a budget himself or that Democrats could do if they got to dictate everything that would come out of it.  But we have made clear since the President made this offer to Speaker Boehner -- you have asked me, others have asked me in this room many times about that offer -- and I've been clear that the offer remains on the table.  And I think it stands in stark contrast to the intransigence and the embrace of ideological purity that the House Republican budget represents. 

    +

    Look at the difference.  We've been having this discussion now for several years about how do we get our deficits under control and how do we do it in a way as we emerge from the Great Recession that keeps the economy growing -- and hopefully growing faster -- and keeps it creating jobs?  And the President has always taken an approach that says we have to do this in a balanced way.  The well-off and well-connected have to contribute as well. 

    +

    His proposals represent that spirit of compromise -- a spirit of compromise that does not forsake his principles, but that recognizes he cannot get everything he wants.  And what he asks, and what I think the American people are asking is that Republicans accept that they don't get everything they want, that they embrace proposals that they said were the right policy in December because they're the right thing to do. 

    +

    Whether you're a corporate jet owner or a company -- an oil and gas company that benefits from century-old tax provisions, tax breaks that we need to do away with or you get to use the tax code and the exemptions available in it to reduce your tax burden if you're a millionaire or billionaire -- we can’t afford that anymore.  Because the alternative -- I mean, it's a great exercise.  The alternative to doing it in a balanced way is the way that we've seen from Republicans, which is middle-class Americans taking a massive hit, senior citizens taking a huge hit -- investments that help our economy grow in the future eviscerated.  And then, those same people who should be asked to give a little bit more instead getting showered with tax cuts.

    +

    I don't know what debate some people missed last year.  But this was debated and discussed, and I think the American people were pretty clear about the direction they didn't want to take.

    +

    Q    North Korea follow-up?

    +

    MR. CARNEY:  North Korea follow-up, sure.

    +

    Q    Are there any plans to evacuate the American embassy or evacuate Americans from South Korea?

    +

    MR. CARNEY:  No.  I would refer you to the State Department, but no.

    +

    Q    Would you let us know if there are changes?

    +

    MR. CARNEY:  I think what I said about North Korea and its provocative actions and its bellicose rhetoric reflects our concern about this path that the North Koreans are on, and the fact that this is a familiar path and a familiar pattern that we're seeing out of the North Korean regime.  And we're taking all necessary precautions, and they have been reported on, and we will continue to do that.  We're consulting closely with our allies in Tokyo and Seoul. 

    +

    We're working constructively with the Russians and the Chinese to try to get them -- in particular, the Chinese -- to use their influence with the North Koreans to persuade them to change their behavior and to instead travel the path that will allow them to rejoin the community of nations, allow them to assist their own citizens, feed their own people and allow their economy to grow instead of atrophy.  That's our position.

    +

    Q    -- warn Americans and foreigners to get their people out?

    +

    MR. CARNEY:  Well, look, I think the leadership in North Korea says a lot of things, and it tends to be bellicose and provocative of late.  And none of those statements or actions are helpful to the cause of peace and stability in the region.

    +

    Q    On Syria, Jay?

    +

    MR. CARNEY:  Yes, Syria.

    +

    Q    Thank you.  Just follow up the previous question.  Is the leaders -- neighbor's leaders are coming -- Turkey and Jordan and Qatar.  And as the latest numbers by the U.N., close to 4 million displaced people inside and 1.2 million outside.  So a quarter of Syria, if you put the U.S. numbers, about 80 million people right now displaced.  Are you going to be able to use this opportunity to talk to these leaders, bring a new way, a new step?  Or do you have any kind of new plan?  Because apparently diplomacy is not working and whatever has been done for the last two years is also not working.  Do you have anything new we are going to be able to see?

    +

    MR. CARNEY:  The President will, in these meetings, discuss the tragic situation in Syria, there is no question, as well as other topics. 

    +

    The United States, as you know, is the single-largest donor of humanitarian aid to the Syrian people, who have been tragically affected by President Assad’s brutal repression and murder of his own people, refugees, displaced Syrians.  And we will continue to work with our partners in the effort to provide assistance to the Syrian people.  We also will continue the effort to -- in support of the Syrian opposition.  We have provided substantial nonlethal aid to the opposition.  We are working with our partners in helping the opposition organize itself, and we’ll continue to do that.

    +

    So I don’t want to preview these discussions, I think I should make clear that, as I did earlier, these meetings the President will be having with leaders from the region will focus on a number of issues, including, of course, Syria, which is very important and which has -- on which the President is greatly focused.

    +

    This is a problem and a situation that we are constantly working with our partners on, and our policies are constantly being reviewed to find -- to see if we can find ways to provide more humanitarian assistance and more assistant to the opposition, and we will continue to do that.

    +

    Q    Thanks, Jay.

    +

    MR. CARNEY:  I’ll do one more. 

    +

    Yes.

    +

    Q    Thank you, Jay.  There’s a big judiciary hearing coming up, obviously, on Wednesday.  You talked from the lectern before about the importance to the courts in having those holes filled.  But from the President’s perspective, how important is it to get those holes filled to get his agenda moved forward, particularly on that D.C. court?

    +

    MR. CARNEY:  Well, it’s not a question about getting his agenda moved forward.  It’s a question of a fair process where, as I said the other day I think in a prolonged and brilliant topper to the briefing, I made clear our unhappiness with the pace of consideration of nominees to the Judiciary.  The delays are something like triple or quadruple the rate that were in effect under President George W. Bush.  And while we have seen some progress and some nominees confirmed of late, we still have far too many vacancies and on a number of courts, I mean, across the country.

    +

    And so the President hopes and urges the Senate -- hopes that and urges the Senate to move forward with consideration of nominees.  I mean, the problem that we’ve seen is you’ve had a number of nominees who have been confirmed unanimously out of committee, and then who are held up, month after month after month, and then once the block has been lifted are voted out overwhelmingly, confirmed overwhelmingly. 

    +

    So normal Americans who are out there wondering how Washington works and why it seems dysfunctional in their view could look at that process and scratch their heads, and say, wait, if there wasn’t a problem, if the votes were there from both sides, from both parties, why did it take 134 days?  And, unfortunately, the answer is politics.  It’s using this process, the confirmation process, to attempt to achieve other aims, which is doing harm to our Judiciary.

    +

    Q    I talked to Senator Grassley the other day, and he said the problem, at least from his perspective, is that the nominations have been slow getting to them.

    +

    MR. CARNEY:  Well, I think that would be the case if there -- how does that explain the -- I think it’s -- I don’t have the paper with me now -- I think it’s 134-day average wait for nominees compared to something like 30-odd days under President George W. Bush.  These are existent, not hypothetical nominees that have been waiting far too long for proper consideration by the Senate.

    +

    Thanks, everybody.

    +

    Q    Week ahead?

    +

    MR. CARNEY:  One day I’ll remember.

    +

    Week ahead.  On Monday, the President will travel to the University of Hartford where he will continue asking the American people to join him in calling on Congress to pass common-sense measures to reduce gun violence. 

    +

    On Tuesday, as part of their “In Performance at the White House” series, the President and First Lady will invite music legends and contemporary major artists to the White House for a celebration of Memphis soul music.

    +

    On Wednesday, the President will deliver a statement on his budget at the White House.  In the evening, the President will meet with 12 Republican senators for dinner.

    +

    On Thursday, the President will award Chaplain (Captain) Emil J. Kapaun, U.S. Army, the Medal of Honor for conspicuous gallantry at the White House.  Chaplain (Captain) Kapaun will receive the Medal of Honor posthumously for his extraordinary heroism while serving with the 3rd Battalion, 8th Cavalry Regiment, 1st Cavalry Division, during combat operations against an armed enemy at Unsan, Korea, and as a prisoner of war from November 1st through 2nd, 1950.  The First Lady will also attend this event.

    +

    On Friday, the President will welcome the United States Naval Academy football team to the White House to present them with the 2012 Commander-in-Chief’s Trophy.  And that is your week ahead.

    +

    Thanks, all.

    +

    END

    +
    + 2:21 P.M. EDT
    +]]>
    + The President + Press Briefings + Press Briefings + Office of the Press Secretary + The President + Sat, 06 Apr 2013 00:11:45 +0000 + The White House + 207491 at http://www.whitehouse.gov +
    + + Executive Order -- Continuance of Advisory Council + http://www.whitehouse.gov/the-press-office/2013/04/05/executive-order-continuance-advisory-council + EXECUTIVE ORDER

    +

    - - - - - - -

    +

    CONTINUANCE OF ADVISORY COUNCIL

    +

    By the authority vested in me as President by the Constitution and the laws of the United States of America, and consistent with the provisions of the Federal Advisory Committee Act, as amended (5 U.S.C. App.), it is hereby ordered as follows:

    +

    Section 1. Continuing the President's Advisory Council on Faith-Based and Neighborhood Partnerships. The President's Advisory Council on Faith-Based and Neighborhood Partnerships, as set forth under the provisions of Executive Order 13498 of February 5, 2009, and reestablished by section 5 of Executive Order 13569 of April 5, 2011, is hereby extended and shall terminate 2 years from the date of this order unless further extended by the President.

    +

    Sec. 2. General Provisions. (a) Nothing in this order shall be construed to impair or otherwise affect:

    +

    (1) the authority granted by law to an executive department, agency, or the head thereof; or

    +

    (2) the functions of the Director of the Office of Management and Budget relating to budgetary, administrative, or legislative proposals.

    +

    (b) This order shall be implemented consistent with applicable law and subject to the availability of appropriations.

    +

    (c) This order is not intended to, and does not, create any right or benefit, substantive or procedural, enforceable at law or in equity by any party against the United States, its departments, agencies, or entities, its officers, employees, or agents, or any other person.

    +

    BARACK OBAMA

    +]]>
    + The President + Executive Orders + Executive Orders + Office of the Press Secretary + The President + Fri, 05 Apr 2013 19:54:00 +0000 + The White House + 207436 at http://www.whitehouse.gov +
    + + Executive Order -- Adjustments of Certain Rates of Pay + http://www.whitehouse.gov/the-press-office/2013/04/05/executive-order-adjustments-certain-rates-pay + EXECUTIVE ORDER

    +

    - - - - - - -

    +

    ADJUSTMENTS OF CERTAIN RATES OF PAY

    +

    By the authority vested in me as President by the Constitution and the laws of the United States of America, including the Continuing Appropriations and Surface Transportation Extensions Act, 2011 (Public Law 111-322), as extended by the Consolidated and Further Continuing Appropriations Act, 2013 (Public Law 113-6), which requires certain pay schedules for civilian Federal employees to remain at 2010 levels through 2013, it is hereby ordered as follows:

    +

    Section 1. Statutory Pay Systems. Pursuant to the Consolidated and Further Continuing Appropriations Act, 2013 (Public Law 113-6), the rates of basic pay or salaries of the statutory pay systems (as defined in 5 U.S.C. 5302(1)) are set forth on the schedules attached hereto and made a part hereof:

    +

    (a) The General Schedule (5 U.S.C. 5332(a)) at Schedule 1;

    +

    (b) The Foreign Service Schedule (22 U.S.C. 3963) at Schedule 2; and

    +

    (c) The schedules for the Veterans Health Administration of the Department of Veterans Affairs (38 U.S.C. 7306, 7404; section 301(a) of Public Law 102-40) at Schedule 3.

    +

    Sec. 2. Senior Executive Service. The ranges of rates of basic pay for senior executives in the Senior Executive Service, as established pursuant to 5 U.S.C. 5382, are set forth on Schedule 4 attached hereto and made a part hereof.

    +

    Sec. 3. Certain Executive, Legislative, and Judicial Salaries. The rates of basic pay or salaries for the following offices and positions are set forth on the schedules attached hereto and made a part hereof:

    +

    (a) The Executive Schedule (5 U.S.C. 5312-5318) at Schedule 5;

    +

    (b) The Vice President (3 U.S.C. 104) and the Congress (2 U.S.C. 31) at Schedule 6; and

    +

    (c) Justices and judges (28 U.S.C. 5, 44(d), 135, 252, and 461(a), and section 140 of Public Law 97-92) at Schedule

    +

    Sec. 4. Uniformed Services. The rates of monthly basic pay (37 U.S.C. 203(a)) for members of the uniformed services, as adjusted under 37 U.S.C. 1009, and the rate of monthly cadet or midshipman pay (37 U.S.C. 203(c)) are set forth on Schedule 8 attached hereto and made a part hereof.

    +

    Sec. 5. Locality-Based Comparability Payments. (a) Pursuant to sections 5304 and 5304a of title 5, United States Code, and the Continuing Appropriations and Surface Transportation Extensions Act, 2011 (Public Law 111-322), as extended by the Consolidated and Further Continuing Appropriations Act, 2013 (Public Law 113-6), locality-based comparability payments shall be paid in accordance with Schedule 9 attached hereto and made a part hereof.

    +

    (b) The Director of the Office of Personnel Management shall take such actions as may be necessary to implement these payments and to publish appropriate notice of such payments in the Federal Register.

    +

    Sec. 6. Administrative Law Judges. Pursuant to section 5372 of title 5, United States Code, the rates of basic pay for administrative law judges are set forth on Schedule 10 attached hereto and made a part hereof.

    +

    Sec. 7. Effective Dates. Schedule 8 is effective January 1, 2013. The other schedules contained herein are effective on the first day of the first applicable pay period beginning on or after January 1, 2013.

    +

    Sec. 8. Prior Order Superseded. Executive Order 13635 of December 27, 2012, is superseded as of the effective dates specified in section 7 of this order.

    +

    BARACK OBAMA

    +]]>
    + The President + Executive Orders + Executive Orders + Office of the Press Secretary + The President + Fri, 05 Apr 2013 19:35:00 +0000 + The White House + 207421 at http://www.whitehouse.gov +
    + + Presidential Memorandum -- Federal Employee Pay Schedules and Rates that are set by Administrative Discretion + http://www.whitehouse.gov/the-press-office/2013/04/05/presidential-memorandum-federal-employee-pay-schedules-and-rates-are-set + MEMORANDUM FOR THE HEADS OF EXECUTIVE DEPARTMENTS AND AGENCIES

    +

    SUBJECT: Federal Employee Pay Schedules and Rates That Are Set by Administrative Discretion

    +

    Section 1112 of the Consolidated and Further Continuing Appropriations Act, 2013 (Public Law 113-6), reflects the Congress's decision to continue to deny statutory adjustments to any pay systems or pay schedules covering executive branch employees. In light of the Congress's action, I am instructing heads of executive departments and agencies to continue through December 31, 2013, to adhere to the policy set forth in my memoranda of December 22, 2010, and December 21, 2012, regarding general increases in pay schedules and employees' rates of pay that might otherwise take effect as a result of the exercise of administrative discretion.

    +

    This memorandum shall be carried out to the extent permitted by law and consistent with executive departments' and agencies' legal authorities. This memorandum is not intended to, and does not, create any right or benefit, substantive or procedural, enforceable at law or in equity by any party against the United States, its departments, agencies, or entities, its officers, employees, or agents, or any other person.

    +

    The Director of the Office of Personnel Management shall issue any necessary guidance on implementing this memorandum, and is also hereby authorized and directed to publish this memorandum in the Federal Register.

    +

    BARACK OBAMA

    +]]>
    + The President + Presidential Memoranda + Presidential Memoranda + Office of the Press Secretary + The President + Fri, 05 Apr 2013 19:29:00 +0000 + The White House + 207416 at http://www.whitehouse.gov +
    + + Presidential Memorandum -- Delegation of Functions Under Sections 404 and 406 of Public Law 112-208 + http://www.whitehouse.gov/the-press-office/2013/04/05/presidential-memorandum-delegation-functions-under-sections-404-and-406- + MEMORANDUM FOR THE SECRETARY OF STATE
    + THE SECRETARY OF THE TREASURY

    +

    SUBJECT: Delegation of Functions Under Sections 404 and 406 of Public Law 112-208

    +

    By the authority vested in me as President by the Constitution and the laws of the United States of America, including section 301 of title 3, United States Code, I hereby delegate the functions conferred upon the President by sections 404 and 406 of Public Law 112-208 as follows:

    +

    I hereby delegate to the Secretary of the Treasury, in consultation with the Secretary of State, the functions and authorities set forth in:

    +

    • subsections 404(a), 404(b), and 404(d), with respect to the determinations provided for therein;
    + • subsection 404(c)(3);
    + • subsection 404(c)(4), consistent with subsection 404(f); and
    + • subsection 406(a)(1).
    + I hereby delegate to the Secretary of State, in consultation with the Secretary of the Treasury, the functions and authorities set forth in:
    + • subsections 404(a), 404(b), and 404(d), with respect to the submission of the list, updates, and reports described in those respective subsections;
    + • subsection 404(e); and subsections 404(c)(2) and 406(a)(2).

    +

    The Secretary of State is authorized and directed to publish this memorandum in the Federal Register.

    +

    BARACK OBAMA

    +]]>
    + The President + Presidential Memoranda + Presidential Memoranda + Office of the Press Secretary + The President + Fri, 05 Apr 2013 19:24:00 +0000 + The White House + 207411 at http://www.whitehouse.gov +
    + + Fact Sheet: U.S. Security Sector Assistance Policy + http://www.whitehouse.gov/the-press-office/2013/04/05/fact-sheet-us-security-sector-assistance-policy + United States policy on Security Sector Assistance is aimed at strengthening the ability of the United States to help allies and partner nations build their own security capacity, consistent with the principles of good governance and rule of law.  The United States has long recognized that the diversity and complexity of the threats to our national interest require a collaborative approach, both within the United States Government and among allies, partners, and multilateral organizations.  More than ever before, we share security responsibilities with other nations and groups to help address security challenges in their countries and regions, whether it is fighting alongside our forces, countering terrorist and international criminal networks, participating in international peacekeeping operations, or building institutions capable of maintaining security, law, and order, and applying justice.  U.S. assistance to build capabilities to meet these challenges can yield critical benefits, including reducing the possibility that the United States or partner nations may be required to intervene abroad in response to instability. 

    +

    Effectively building security capacity requires multi-year investments, though such up-front costs are relatively small when compared to the larger political, economic, and societal costs in the event that local institutions flounder and instability ensues.  While security sector assistance can yield significant benefits, the United States cannot build capacity in all countries.  It is essential that we are selective and focus our targeted assistance where it can be effective and is in line with our broader foreign policy and national security objectives.  Investments of such assistance are critical to better share the costs and responsibility of global leadership. 

    +

    To address these challenges, the United States must improve its ability to enable partners in providing security and justice for their own people and responding to common security challenges.   Therefore, the United States will pursue a new approach to security sector assistance to better meet this complex and interdependent security environment.  This approach will align with the goals and guidelines outlined below.

    +

    The Definition of Security Sector Assistance

    +

    The security sector is composed of those institutions - to include partner governments and international organizations - that have the authority to use force to protect both the state and its citizens at home or abroad, to maintain international peace and security, and to enforce the law and provide oversight of those organizations and forces.  It includes both military and civilian organizations and personnel operating at the international, regional, national, and sub-national levels.  Security sector actors include state security and law enforcement providers, governmental security and justice management and oversight bodies, civil society, institutions responsible for border management, customs and civil emergencies, and non-state justice and security providers.  Security sector assistance refers to the policies, programs, and activities the United States uses to:
    +  
    + • Engage with foreign partners and help shape their policies and actions in the security sector;
    + • Help foreign partners build and sustain the capacity and effectiveness of legitimate institutions to provide security, safety, and justice for their people; and,
    + • Enable foreign partners to contribute to efforts that address common security challenges.

    +

    Goals for U.S. Security Sector Assistance

    +

    The principal goals of our security sector assistance are to: 

    +

    1. Help partner nations build sustainable capacity to address common security challenges, specifically to:  disrupt and defeat transnational threats; sustain legitimate and effective public safety, security, and justice sector institutions; support legitimate self-defense; contribute to U.S. or partner military operations which may have urgent requirements; maintain control of their territory and jurisdiction waters including air, land, and sea borders; and help indigenous forces assume greater responsibility for operations where U.S. military forces are present. 

    +

    2. Promote partner support for U.S. interests, through cooperation on national, regional, and global priorities, including, but not limited to, such areas as:  military access to airspace and basing rights; improved interoperability and training opportunities; and cooperation on law enforcement, counterterrorism, counternarcotics, combating organized crime and arms trafficking, countering Weapons of Mass Destruction proliferation, and terrorism, intelligence, peacekeeping, and humanitarian efforts. 

    +

    3. Promote universal values, such as good governance, transparent and accountable oversight of security forces, rule of law, transparency, accountability, delivery of fair and effective justice, and respect for human rights. 

    +

    4. Strengthen collective security and multinational defense arrangements and organizations, including by helping to build the capacity of troop- and police-contributing nations to United Nations and other multilateral peacekeeping missions, as well as through regional exercises, expert exchanges, and coordination of regional intelligence and law enforcement information exchanges. 

    +

    Our assistance can also yield the benefit of the adoption of U.S. products and technology, which increases interoperability and interdependence between the United States and partners, lowers the unit cost for all, and strengthens the industrial base. 

    +

    Policy Guidelines for U.S. Security Sector Assistance

    +

    To effectively achieve the goals identified above, the United States must strengthen its own capacity to plan, synchronize, and implement security sector assistance through a deliberate and inclusive whole-of-government process that ensures alignment of activities and resources with our national security priorities.  Therefore, the United States will: 

    +

    • Ensure consistency with broader national security goals.  Security Sector Assistance programs will support and complement the full range of broad U.S. national security and foreign assistance objectives.

    +

    • Foster United States Government policy coherence and interagency collaboration.  Transparency and coordination across the United States Government are needed to integrate  security sector assistance into broader strategies, synchronize agency efforts, reduce redundancies, minimize assistance-delivery timelines, ensure considerations of the full range of policy and operational equities, improve data collection, measure effectiveness, enhance and sustain the United States Government’s security sector assistance knowledge and skills, and identify gaps.   

    +

    • Build sustainable capacity through comprehensive sector strategies.  Partner capacity can only be sustained over the long-term when partner governments have the political will, absorptive capacity, credible and effective institutions, willingness to independently sustain U.S. investments, an equal stake in the success of security sector initiatives, and policy commitment to security sector reform.  United States Government efforts must be sensitive to these requirements, including anticipation of partner capacity, sustainment and oversight needs, coordination with partner governments across the breadth of security sector assistance activities, and pursuit of security sector reform as part of a broader, long term effort to improve governance and promote sustainable economic development. 
    +  
    + • Be more selective and use resources for the greatest impact. To maximize the impact of limited resources for security sector assistance, the United States Government will be strategic and focused on investments aligned with national security priorities and in countries where the conditions are right for sustained progress.  Resource allocation will be evaluated based on common U.S. Government assessments, multi-year strategies, and performance against measures of effectiveness. 

    +

    • Be responsive to urgent crises, emergent opportunities, and changes in partner security environments.  Though a more strategic, anticipatory approach to security sector assistance should limit this requirement, the United States should have the ability to allocate flexible security sector assistance to respond to short-notice requirements.  Timely shifts in partner interests, emerging threats, or performance against security sector objectives may require review of whether security sector investments remain an effective tool in meeting U.S. national security goals.  In such instances, U.S. policymakers should consider initiating, restructuring, or terminating security sector assistance programs either as part of the annual planning cycle or on an immediate basis.   

    +

    • Ensure that short-term interventions are consistent with long term goals.  Any instance of surging security sector assistance to meet unforeseen urgent and emergent needs or opportunities should be incorporated into a broader United States Government strategy to sustain any new capacity, mitigate potential negative impacts on other national security objectives, and achieve longer-term U.S. goals and objectives.

    +

    • Inform policy with rigorous analysis, assessments, and evaluations.  The United States Government will introduce common standards and expectations for assessing security sector assistance requirements, in addition to investing in monitoring and evaluation of security sector assistance programs.  Such standards will be aided by a requirement for measurable security sector assistance objectives, appropriate data collection of the impacts and results of security sector assistance programs, and improved efforts to inform decision-making processes with data on what works and what does not work through impact evaluations when permissible.  Such standards and data collection will take into account the varying security and information environments where U.S. programs operate. 

    +

    • Analyze, plan, and act regionally.  Security sector assistance programs should be complemented by and linked to a broader regional approach, including cross-border program coordination, support for regional organizations, and facilitation of linkages among partner countries, where appropriate. 

    +

    Coordinate with other donors.  The United States Government will establish a division of labor with other bilateral, multilateral, and regional actors based on capacity, effectiveness, and comparative advantage.  Such coordination will be aimed at sharing the burden across a greater number of interested parties and enhanced coordination with the partner governments to achieve mutually agreed outcomes.

    +]]>
    + The President + Statements and Releases + Statements and Releases + Office of the Press Secretary + The President + Fri, 05 Apr 2013 19:20:00 +0000 + The White House + 207406 at http://www.whitehouse.gov +
    + + Statement by the Press Secretary on the U.S. Security Sector Assistance Policy + http://www.whitehouse.gov/the-press-office/2013/04/05/statement-press-secretary-us-security-sector-assistance-policy + Today, President Obama issued a new policy directive on security sector assistance.  The goals of this new policy are to:  help partner nations build the sustainable capacity to address common security challenges; promote partner support for the policies and interests of the United States; strengthen collective security and multinational defense arrangements and organizations; and promote universal values. 

    +

    The “security sector” of a government is composed of institutions that have the authority to use force to protect both the state and its citizens at home or abroad, maintain international peace and security, and to enforce the law and provide oversight of security institutions and forces.  Security sector assistance refers to the policies, programs, and activities the United States Government employs to engage with foreign partners in these areas, including to help them build and sustain the capacity and effectiveness of  institutions to provide security, safety, and justice for their people; and  to contribute to efforts that address common security challenges. 

    +

    The United States has long recognized that the diversity and complexity of the threats to our national security require a collaborative approach, both within the United States Government and among allies, partners, and multilateral organizations.  U.S. security sector assistance yields important and tangible benefits, including reducing the need for the United States or partner nations to intervene abroad in response to instability.  The policy directive issued by the President today will enhance the responsiveness, impact, and effectiveness of our security sector assistance, including through effective management and alignment of efforts across multiple agencies. 

    +]]>
    + The President + Statements and Releases + Statements and Releases + Office of the Press Secretary + The President + Fri, 05 Apr 2013 19:16:00 +0000 + The White House + 207401 at http://www.whitehouse.gov +
    + + President Obama to Welcome the 2012 Commander in Chief Bowl Winners to the White House + http://www.whitehouse.gov/the-press-office/2013/04/05/president-obama-welcome-2012-commander-chief-bowl-winners-white-house + WASHINGTON, DC— On Friday, April 12th, President Obama will welcome the United States Naval Academy Football Team to the White House to present them with the 2012 Commander in Chief’s Trophy.

    +

    The Commander in Chief's trophy was established in 1972.  It is awarded to the service academy with the best overall record against the other two service academies.  Every year since 1984, except 1993 when there was no outright winner, the President has personally presented the Trophy to members of the victorious Academy's football team at the White House. 

    +

    This event will be open press.  Members of the media who wish to cover this event must send NAME, MEDIA OUTLET, PHONE AND EMAIL for each person planning to cover the event to media_affairs@who.eop.gov by 12:00PM ET Wednesday, April 10th.  NOTE: Members of the media who do not have a White House hard pass must also submit their full name, date of birth, Social Security number, gender, country of birth, country of citizenship and current city and state of residence. If we are able to accommodate your request for credentials, we will send a confirmation with further instructions and logistical details.

    +]]>
    + The President + Statements and Releases + Statements and Releases + Office of the Press Secretary + The President + Fri, 05 Apr 2013 14:52:00 +0000 + The White House + 207326 at http://www.whitehouse.gov +
    + + Statement by the Press Secretary on the Visit of Prime Minister Erdogan of Turkey + http://www.whitehouse.gov/the-press-office/2013/04/05/statement-press-secretary-visit-prime-minister-erdogan-turkey + On Thursday, May 16, President Obama will welcome Prime Minister Recep Tayyip Erdogan of Turkey to the White House.  As friends and NATO allies, the United States and Turkey are partners in addressing a range of critical global and regional issues.  The President looks forward to discussing these issues with the Prime Minister, to include Syria, trade and economic cooperation, and countering terrorism.

    +

    The Prime Minister’s visit underscores the close friendship between the United States and Turkey and the strategic importance we place on broadening and strengthening our relationship moving forward. 

    +]]>
    + The President + Statements and Releases + Statements and Releases + Office of the Press Secretary + The President + Fri, 05 Apr 2013 14:36:00 +0000 + The White House + 207321 at http://www.whitehouse.gov +
    + + Statement by the Press Secretary on the Visit of King Abdullah II of Jordan + http://www.whitehouse.gov/the-press-office/2013/04/05/statement-press-secretary-visit-king-abdullah-ii-jordan + President Obama will host His Majesty King Abdullah II of Jordan at the White House on Friday, April 26.  The President deeply appreciated the hospitality he received in Jordan last month and looks forward to continuing his consultations with King Abdullah on Jordan’s political and economic reforms, the humanitarian crisis in Syria, and additional regional issues of mutual concern.  As the President said in Amman last month, Jordan is an invaluable ally and close friend.  King Abdullah's visit is a demonstration of the close partnership between the United States and Jordan.

    +]]>
    + The President + Statements and Releases + Statements and Releases + Office of the Press Secretary + The President + Fri, 05 Apr 2013 14:21:00 +0000 + The White House + 207316 at http://www.whitehouse.gov +
    + + Remarks by the President and Vice President at Easter Prayer Breakfast + http://www.whitehouse.gov/the-press-office/2013/04/05/remarks-president-and-vice-president-easter-prayer-breakfast + East Room

    +

    9:28 A.M. EDT

    +

    THE VICE PRESIDENT:  Well, thank you all for being here today.  And welcome to the White House, and a belated happy Easter -- this time of the year when we celebrate renewal and we reflect on the faith that brings us together.

    +

    For me, the essence of my faith is tolerance:  not being judgmental about people of different faiths.  When I was in Rome a few weeks ago, Pope Francis spoke movingly in his homily about our commitments to each other, not just as people of faith, but, he went on to say, but as human beings.

    +

    I grew up in a tradition of Catholic social doctrine, and I was incredibly impressed by His Holiness’s homily, his sense of social justice.  But I believe his message reads something essential about all faiths, and that is ultimately we all believe that we have a responsibility to one another and we all are our brothers’ and our sisters’ keepers.

    +

    When it comes down to it, we all know that we’re connected by much more than divides us, although the focus is always on what divides us.  As we move forward as a nation, I do believe we’re going to be judged on how we answer that call -- that call of moral responsibility, to whether we stand up for those who have the least among us, whether we act on their behalf.

    +

    And one of the things that I think at least the President and I believe has been the essence of this administration is the most animating principle of the administration has been just that:  to look out for the least among us.  Those are the values that I know that the President -- and I personally know -- the President holds extremely close to his heart. 

    +

    So I’d like to introduce to you now, my friend, and our President, President Barack Obama.  (Applause.)

    +

    THE PRESIDENT:  Thank you.  (Applause.)  Thank you so much.  Everybody, please have a seat.  Thank you. 

    +

    Well, good morning, everybody. 

    +

    AUDIENCE:  Good morning.

    +

    THE PRESIDENT:  Welcome, once again, to the White House.  It is always wonderful to see so many friends from all across the country.  I want to thank you for joining us today.  I want to thank everybody for their prayers, but, most importantly, I want to thank everybody for their good works through your ministries.  It's making a difference in communities all across this nation, and we could not be more proud to often have a chance to work with you.

    +

    To all the pastors in the house, I hope you’ve enjoyed some well-deserved rest after a very busy Holy Week.  I see some chuckles, so maybe not.  (Laughter.)  Here at the White House, I’m pleased to say that we survived yet another Easter Egg Roll.  (Laughter.) 
    +  
    + Now, if you’ve been to this breakfast before, you know that I always try to avoid preaching in front of people who do it for a living.  That's sound advice.  So this morning, I'm just going to leave the sermon to others and offer maybe a few remarks as we mark this -- the end of this Easter season.

    +

    In these sacred days, those of us as Christians remember the tremendous sacrifice Jesus made for each of us –- how, in all His humility and His grace, He took on the sins of the world and extended the gift of salvation.  And we recommit ourselves to following His example –- to loving the Lord our God with all our hearts and all our souls and with all our minds, and to loving our neighbors as ourselves. 

    +

    That’s the eternal spirit of Easter.  And this year, I had -- I think was particularly special for me because right before Easter I had a chance to feel that spirit during my trip to the Holy Land.  And I think so many of you here know there are few experiences more powerful or more humbling than visiting that sacred earth. 

    +

    It brings Scripture to life.  It brings us closer to Christ.  It reminds us that our Savior, who suffered and died was resurrected, both fully God and also a man; a human being who lived, and walked, and felt joy and sorrow just like us.  

    +

    And so for Christians to walk where He walked and see what He saw are blessed moments.  And while I had been to Jerusalem before, where Jesus healed the sick, and cured the blind, and embraced the least of these, I also had a chance to go to the Church of the Nativity in Bethlehem.  And those of you who have been there know that entering the church is a remarkable experience, although it is a useful instruction to see how managing different sections of the church and different clergy -- it feels familiar.  (Laughter.)  Let’s just put it that way.  (Laughter.) 

    +

    And as I approached the Altar of the Nativity, as I neared the 14-pointed Silver Star that marks the spot where Christ was born, the Patriarch of Jerusalem welcomed me to, in his words, “the place where heaven and Earth met.”

    +

    And there, I had a chance to pray and reflect on Christ’s birth, and His life, His sacrifice, His Resurrection.  I thought about all the faithful pilgrims who for two thousand years have done the same thing -- giving thanks for the fact that, as the book of Romans tells us, “just as Christ was raised from the dead through the glory of the Father, we too may live a new life.” 

    +

    I thought of the poor and the sick who seek comfort, and the marginalized and the forsaken who seek solace, and the grateful who merely seek to offer thanks for the simple blessings of this life and the awesome glory of the next.  I thought of all who would travel to this place for centuries to come and the lives they might know. 

    +

    And I was reminded that while our time on Earth is fleeting, He is eternal.  His life, His lessons live on in our hearts and, most importantly, in our actions.  When we tend to the sick, when we console those in pain, when we sacrifice for those in need, wherever and whenever we are there to give comfort and to guide and to love, then Christ is with us. 

    +

    So this morning, let us pray that we’re worthy of His many blessings, that this nation is worthy of His many blessings.  Let us promise to keep in our hearts, in our souls, in our minds, on this day and on every day, the life and lessons of Christ, our Lord.

    +

    And with that, I’d like to ask Father Larry Snyder to deliver our opening prayer.  

    +

    END 
    + 9:36 A.M. EDT

    +]]>
    + The President + Speeches and Remarks + Speeches and Remarks + Office of the Press Secretary + The President + Fri, 05 Apr 2013 14:20:00 +0000 + The White House + 207311 at http://www.whitehouse.gov +
    + + Statement by the Press Secretary on the Visit of the Amir of Qatar + http://www.whitehouse.gov/the-press-office/2013/04/05/statement-press-secretary-visit-amir-qatar + President Obama will welcome to the White House the Amir of Qatar, His Highness Hamad bin Khalifa al-Thani, on Tuesday, April 23rd.  The United States and Qatar have a strong bilateral relationship, reflecting our close defense partnership, expanding commercial ties, and many other areas of cooperation. 

    +

    The United States is firmly committed to continuing to deepen our consultations with Qatar on the many important developments in the region.  The President looks forward to a broad discussion with the Amir on a range of mutual interests and regional issues to further strengthen our bilateral partnership. 

    +]]>
    + The President + Statements and Releases + Statements and Releases + Office of the Press Secretary + The President + Fri, 05 Apr 2013 14:06:00 +0000 + The White House + 207306 at http://www.whitehouse.gov +
    + + Statement by NSC Spokesperson Caitlin Hayden on the Removal of Highly Enriched Uranium from the Czech Republic + http://www.whitehouse.gov/the-press-office/2013/04/05/statement-nsc-spokesperson-caitlin-hayden-removal-highly-enriched-uraniu + Today we can announce that the United States, with the cooperation of our international partners, successfully removed 68 kilograms of highly enriched uranium (HEU) – enough material for two nuclear weapons - from the Czech Republic. The HEU was securely transported to Russia, where it will be downblended into low enriched uranium (LEU) for use in nuclear power reactors. Unlike highly enriched uranium, low enriched uranium cannot be used to make a nuclear weapon. With this shipment, the Czech Republic becomes the tenth country from which all HEU has been removed since President Obama announced the international effort to secure all vulnerable nuclear material around the world.

    +

    This achievement comes on the anniversary of President Obama’s remarks in Prague on April 5, 2009, where he stated that nuclear terrorism remains our greatest threat. The President called on the world to act with a sense of purpose and without delay to secure vulnerable nuclear material.  The United States and the global community have responded with an unprecedented effort that has secured thousands of kilograms of HEU and plutonium, enough for dozens of nuclear weapons.

    +

    The removal of highly enriched uranium from the Czech Republic was the culmination of a multi-year effort by the United States’ National Nuclear Security Administration, the Czech Republic’s Nuclear Research Institute, Russia’s Federal Atomic Energy Agency, and the International Atomic Energy Agency (IAEA).  The United States is grateful to these partners and to the Czech and Russian governments for their outstanding cooperation.

    +]]>
    + The President + Statements and Releases + Statements and Releases + Office of the Press Secretary + The President + Fri, 05 Apr 2013 13:02:00 +0000 + The White House + 207286 at http://www.whitehouse.gov +
    + + Press Gaggle by Press Secretary Jay Carney Aboard Air Force One en route Andrews Air Force Base, 4/4/2013 + http://www.whitehouse.gov/the-press-office/2013/04/05/press-gaggle-press-secretary-jay-carney-aboard-air-force-one-en-route-an + Aboard Air Force One
    + En Route Andrews Air Force Base

    +

    2:55 P.M. PDT

    +

    MR. CARNEY:  Fire away.

    +

    Q    The North Koreans have moved missiles into position in the east.  Before the response was nothing new has happened.  Can we just get a response to that?

    +

    MR. CARNEY:  I can tell you that we've seen the press reports and we continue to closely monitor the situation on the Peninsula.  Threats and provocative actions will not bring the DPRK the security, international respect, and economic development that it seeks.  We continue to urge the North Korean leadership to heed President Obama's call to choose the path of peace and come into compliance with its international obligations. 

    +

    Q    Have you verified with those reports independently?

    +

    MR. CARNEY:  I'm not going to comment on intelligence matters.  I can tell you that simply we have seen the reports and the response is, as we've been saying, that actions and provocative rhetoric only serve to further isolate North Korea, to harm the North Korean economy, to set back any efforts the North Koreans might want to take towards rejoining the community of nations.  There is a path available to North Korea, a path that would allow it to rejoin the international community, but it would require commitment to renounce its nuclear weapons ambitions and to abide by its international obligations.

    +

    Q    Jay, given these latest reports, does this suggest that this is more than just bluster, that North Korea is actually going to take action this time?

    +

    MR. CARNEY:  I would simply say that we're monitoring both the actions taken by and the statements made by the North Korean leadership.  And we're also taking prudent measures to respond to that activity and to those statements.  It is still important to note that, as those who have worked on this issue or reported on this issue over the years know, what we are seeing now is a familiar pattern of behavior out of the North Koreans -- regrettable, but familiar.

    +

    Q    Will the President address this personally -- publicly?  Will the President address this?

    +

    MR. CARNEY:  I don't have any scheduling announcements today. 

    +

    Q    Jay, does the President see a potential red line, though, that the Koreans, the North Koreans might cross that would require a different kind of response from the U.S.?

    +

    MR. CARNEY:  We're taking I think a series of precautionary measures that have been reported and that we've discussed.  The fact of the matter is North Korea has one path available to it if it seeks to improve its economy and reenter the community of nations, and that is to work towards abiding by its international obligations. 

    +

    I think that it's important to note, again, as I said, that there is an element to this that is familiar, for those of you who have covered it and to those who have worked on it.  It’s obviously of concern, and we're taking all the necessary precautions.

    +

    Q    Did the President see Keystone protesters last night?  And will they influence his decision, thinking on this?

    +

    MR. CARNEY:  I'm not sure if in the motorcade he saw them.  I think that, as he said, there is obviously a great deal of passion around this issue.  But it is, as a policy matter, being assessed appropriately in the State Department through a process that has been longstanding through previous administrations of both parties.  This is something that is evaluated on the merits, and that process is underway.

    +

    Q    Jay, to go back to North Korea for a moment, can you update us on the latest conversations that the President has had with leaders in the region, with the leader of South Korea and Japan?

    +

    MR. CARNEY:  I don’t have any leader-to-leader conversations to read out to you.  The President has been regularly updated on both the actions and statements by the North Koreans, as well as the responsive measures, prudent measures that we've taken.  We are obviously consulting regularly with our allies in Seoul and Tokyo, as well as other allies and partners. 

    +

    And we are working with other nations, including the Russians and the Chinese, to try to influence North Korean behavior to, as I think we discussed on the plane yesterday, to discuss with the Chinese in particular the need to use the influence that they have with the North Korean regime to try to get the -- to ratchet down the provocative behavior and actions, and to maintain stability in the region.

    +

    Q    Will there be any further test strikes, or is that something that the United States thinks now might actually inflame the situation?

    +

    MR. CARNEY:  Will there be further what?  I'm sorry.

    +

    Q    Test strikes, test flights?

    +

    MR. CARNEY:  Strikes or flights?  Sorry.  I think, look, we’ve engaged in exercises with the South Koreans regularly at, I believe, this time of year.  I don’t anticipate any change in that, but I would refer you to the Defense Department.

    +

    Q    Back on Keystone.  Yesterday, at one of the events, the President made clear that any steps on environment and on climate change have to be taken with consideration of the economic needs of the middle class, as well.  I'm wondering if that’s a consideration that he keeps in mind, the job creation potential of Keystone, of the pipeline as he makes -- as the administration makes that decision.

    +

    MR. CARNEY:  Again, this is a decision that’s housed within the State Department and made on the merits.  I've seen some reports that stretch the meaning of what the President said beyond reason.  He was not referring to Keystone.  He never mentioned Keystone.  And I would treat -- I think those reports suggesting that that’s what he was talking about are not backed up by facts.

    +

    But obviously, broadly speaking, matters of economic growth and job creation as well as middle-class security are always at the forefront of the President's mind, and they’re his top priorities.  It is also a high priority of the President to take action to both enhance our energy independence and reduce the impact of carbon emissions on the environment.  And he did that in his first term by passing the historic increase in fuel efficiency standards that will have an enormous positive effect on carbon emissions. 

    +

    Q    The host of the first fundraiser yesterday is very opposed to Keystone.  Did the President discuss that with him beforehand?  And how does the President feel about the actions that he's taking regarding the Massachusetts race?

    +

    MR. CARNEY:  I haven't discussed that with the President, and I don’t have any private conversations to read out to you between the President and anybody yesterday.

    +

    Q    If you could get back to us -- because at the top, the President said that he discussed kind of climate change with Tom Steyer, the host of the first event.  If Keystone was part of that, if you could get back to us on that, that would be helpful.

    +

    MR. CARNEY:  Again, I’m not going to read out a private conversation.  I think the President -- look, the President addressed this to the extent that he did, and I would refer you to his remarks.

    +

    Q    Jay, on the President’s decision to give 5 percent of his pay back to the Treasury Department, when did he make that decision?  Was it his idea?

    +

    MR. CARNEY:  It was his idea.  Right when the implementation of the sequester was upon us, the President indicated to staff that this was something he would like to do.  He was aware, obviously, and mindful of the fact that hardworking Americans across the federal government, across the country would be affected by the implementation of the sequester -- the regrettable implementation of the sequester and indicated that this was something he wanted to do. 

    +

    Q    Jay, just another quick comment on that.  Will he be taking that as a deduction -- the $20,000?

    +

    MR. CARNEY:  He will not, no.

    +

    Q    Is he calling on other people to give their pay?  Members of Congress?

    +

    MR. CARNEY:  No, this is a decision that each individual will make for himself or herself.

    +

    Q    We've seen other Cabinet members take the same step.  Does he expect other Cabinet members --

    +

    MR. CARNEY:  No.  This is obviously something that each such individual would decide for himself of herself.

    +

    Q    Jay, you said he won’t take it as a deduction?

    +

    MR. CARNEY:  He will not.  Correct.

    +

    Q    I wanted to ask you about the shootings of the prosecutor in Texas.  Has the President been briefed about that?  And how concerned is he that that’s been going on?

    +

    MR. CARNEY:  He has been briefed about it.  Obviously, a battle like this is always of concern.  I believe I can refer you to the FBI for more information about what is obviously a state investigation, or a local investigation.  But I believe they’re -- the FBI is where I can direct you for the federal response.

    +

    Q    How concerned is the President about safety of prosecutors?  There have been calls for federal prosecutors to be armed to protect themselves.

    +

    MR. CARNEY:  I haven’t discussed that with him.  Obviously, the President is concerned whenever a law enforcement official is attacked or killed.  But I would hesitate to comment any further on a case that’s under investigation and about the circumstances of which we don’t, as I understand, based on public reports, we don’t know a great deal about.

    +

    Q    Jay, you mentioned earlier this week that OMB staff was going to be taking -- was going to be hit by furloughs, I believe.  Any further information on how the rest of the White House staff might be affected by sequester?

    +

    MR. CARNEY:  Well, as you know, there are 11 components of the Executive Office of the President.  Other components will be receiving -- staff members will be receiving furlough notices.  I don’t have any specific updates for you, but I believe that process has begun. 

    +

    Q    Jay, can we expect the President to continue to make trips like this to talk about passing new gun laws?

    +

    MR. CARNEY:  Well, you can certainly expect the President to continue to speak out on this issue and to encourage Americans to have their voices heard on the need for common-sense measures to reduce gun violence.  What specific venues there will be and the methods that he will use to communicate that message I can’t preview for you now.  But he will, as he has been for weeks and months now, he’ll be actively engaged in the effort to try to work with Congress to pass these very sensible, very common-sense measures to reduce gun violence.

    +

    Q    And I understand from some of the people who are working on the legislation that they are thinking about some sort of compromise on background checks, potentially allowing a loophole for family-to-family purchases.  Would the President accept something like that?  And what is his expectation when it comes to background checks?  Does he expect that to pass?

    +

    MR. CARNEY:  I wouldn’t put odds from him or from me on any of this, any of the elements of the legislative package.  As he said in the beginning and I have echoed of late, all of this is hard, and it has been hard for quite a long time.  And it requires a concerted effort of discussion and conversation and negotiation.  It requires members of Congress and others involved in this effort, who are concerned about this issue, to step back and think about these issues differently, perhaps, from the way that they have in the past.  And a lot of that has taken place. 

    +

    And I think it’s -- while we are certainly far from having accomplished what needs to be accomplished yet, there has been progress, and that’s welcome.  But I think, as the President has been saying, this is going to be -- these issues are -- have always been hard and require a lot of work, a lot of negotiation, and a recognition, I think, by everyone involved that, for example, when it comes to background checks, this is not an issue of registering guns. 

    +

    I believe one of the representatives from a sportsmen's group who participated in the roundtable yesterday I saw had an article I believe in Politico, and he made clear that he believes and his members believe that background checks is an area where there should be broad agreement that sportsmen and women, responsible gun owners support background checks.  And, as he said, I believe in that piece, and he said in the roundtable with the President, the legislation under consideration in Congress does not and will not establish a gun registry.  So assertions to the contrary are false.

    +

    Q    -- what happened in the last hour or hour and a half, but Chicago’s famous movie critic and Pulitzer Prize winner, Roger Ebert, died, from the President’s hometown.  I don’t know if he had a chance to see it, if the President heard about that news and if he had a reaction, and if he’s ever met Roger Ebert?

    +

    MR. CARNEY:  He is aware of it.  We talked about it on the helicopter ride that we most recently took.  And as a Chicagoan, I think he feels the loss in a way that I think only Chicagoans can.  Obviously, Roger Ebert became a national figure associated with the movies for Americans across the country.  But it is a particularly keen loss for I think the city of Chicago.

    +

    Q    Did you hear me say -- had the President ever met him, by any chance?

    +

    MR. CARNEY:  I did not ask him that.  I can find try to find that out.

    +

    Q    Jay, can I ask you, at one point last night, the President said that he expected Nancy Pelosi to return as Speaker of the House, which implies, obviously, that Democrats retake control of the House.  Most handicappers don’t think that's incredibly likely next year.  Why does the President feel that that is likely?

    +

    MR. CARNEY:  I think the President is always optimistic about a process in which voters across the country decide which candidates support their priorities and support an agenda that has the middle class as its focus.  And that’s certainly what the President has been putting forward and what former-Speaker Pelosi, Leader Pelosi supports.  He obviously has been out working to, in these last 24 hours, to help candidates who support and share his priorities get elected.

    +

    I think it’s important to note that -- because you’ve seen a lot of rhetoric from the other side suggesting that there is something wrong with that -- that Republican leaders in the House and the Senate have been out raising money for Republican candidates; that this is a traditional exercise.  And the President will continue to work with and expect and hope to work with Republicans in Congress to achieve bipartisan compromise on a whole host of important issues.  And he certainly expects and believes that Republicans who are engaged in the effort to get Republicans elected will also continue to work with Democrats and with the President to try to achieve bipartisan compromise.

    +

    Q    Does he actually expect to have a Democratic House for the second half of his second term?

    +

    MR. CARNEY:  I think the President is hopeful that candidates who support a common-sense agenda, a middle-of-the-road agenda focused on strengthening the middle class and investing in our children and in innovation will win the support of their constituents.  I’m not sure, beyond what the President himself said, as you noted, that he or I is going to engage in more specific predictions about midterm elections.  They’re a long way off.

    +

    Q    Can follow up on that?  The President said yesterday, both at the public event and also at the private fundraisers, he spent a lot of time talking about both sides need to maybe calm the rhetoric, listen to each other, and not talk across each other, beyond -- past each other.  And he also said that he did believe there are Republicans who cared about their -- good Republicans out there who cared about their children's future. 

    +

    At the same time, when he left the room yesterday, I believe it's been reported by people who are familiar with Steve Israel's comments, that he was very critical of Republicans.  He called them "obstructionists," and basically disruptive to the country.  He said that Republicans -- if they don’t -- if you don't elect a good leader like Democrats, Republicans are not going to have a good future for their children.  Is the President familiar with the representative's remarks?  Does he have a concern about that tone?

    +

    MR. CARNEY:  I'm not familiar with them.  And if you're telling me they occurred after the President left, I don't think the President is familiar with them.  So I don't really have any comment beyond the fact that you guys are discovering the wheel here, or rediscovering it if you are surprised by the fact that Democrats are trying to get elected and so are Republicans in midterm elections. 

    +

    Q    That’s an election strategy, rather than if they -- I mean, you're saying it's sort of good cop/bad cop, the President saying it's okay to work with Republicans, but other -- that other is a strategy to get elected.

    +

    MR. CARNEY:  I really don't see a story here.  I mean, I saw a pool report yesterday that suggested the President was "bashing" Republicans.  And I challenge anybody to find evidence of language that reflected bashing.  Of course, he wasn't.  But he does support candidates -- Democratic candidates who support the common-sense, middle-of-the-road agenda to strengthen the middle class. 

    +

    And, look, as he said in the remarks that you cited at the top of your question, he believes that Republican leaders and rank-and-file Republicans believe in their positions and are advocating for their positions both in Washington and on the hustings.  And that's obviously how it should be.

    +

    Q    But he’s been much tougher on Republicans before.  So was he purposefully dialing back his comments this time, then?

    +

    MR. CARNEY:  I get confused about which piece of conventional wisdom I'm attempting to understand and rebut, because I thought we were engaged in a charm offensive.  Hasn't that been the narrative of late, right?  (Laughter.)

    +

    Q    Carney is bringing his A-game.  (Laughter.)  Let the record show that Carney is bringing it.

    +

    MR. CARNEY:  Let the record show that I appreciate the comments by Mr. Nichols.  Look, both are true.  The President obviously supports those candidates and those incumbents who are pressing for the same priorities that he is pressing for.  It is also true that he believes we have an opportunity, particularly at this time, to get some big things done on behalf of the American people, things that will only happen if we get bipartisan agreement. 

    +

    And that includes comprehensive immigration reform.  It includes common-sense measures to reduce gun violence.  It includes -- if there is a willingness by Republicans to take a balanced approach to deficit reduction -- achieving the full $4 trillion-plus in deficit reduction over 10 years that was laid out by the fiscal commission and others, and that the President has envisioned in the proposals he has put forward, in an approach that would both produce more savings through spending cuts and entitlement savings, but also ask the wealthiest and the well-connected to pay a little bit more through tax reform that closes loopholes that Republicans themselves only a few months ago said should be closed.

    +

    Q    A foreign policy question.  Japan's central bank took measures today to boost the Japanese economy through monetary easing, which may make it more expensive for manufacturers to sell to Japan.  Does the U.S. have a position on that? 

    +

    MR. CARNEY:  If it does, it can be found at the Treasury Department.  (Laughter.)  

    +

    Q    Let the record show I tried.  (Laughter.)

    +

    Q    Reports that the White House is telling lawmakers the chained CPI is going to be in the budget.  Given that you guys have said that that offer is on the table, is that a pretty safe assumption to make that it will be in there?

    +

    MR. CARNEY:  You know what they say about assuming. 

    +

    Q    (Inaudible.)

    +

    MR. CARNEY:  Well, I will deliver you from all the speculation on April 10th, when the President releases his budget.  And until then, I'm not going to preview the budget in part or in whole.  We have said that since he made it, the President's offer to Speaker Boehner remains on the table.  It was regrettable that the Speaker walked away from it at the end of last year, because it represented a good-faith attempt to meet Republicans more than halfway on spending cuts and revenues and savings from entitlements.  And that offer has remained on the table. 

    +

    But obviously the President's budget is something that won't be released until April 10th.  And when it is, we'll overwhelm you with details and briefings. 

    +

    Q    And the President is pretty excited about releasing his budget?

    +

    MR. CARNEY:  As excited as he ever is -- always is.  Thank you.

    +

    END
    + 3:17 P.M. PDT

    +]]>
    + The President + Press Briefings + Press Briefings + Office of the Press Secretary + The President + Thu, 04 Apr 2013 23:00:00 +0000 + The White House + 207251 at http://www.whitehouse.gov +
    + + Statement by the Press Secretary Announcing the Visit of Crown Prince Mohammed bin Zayed Al Nahyan of the United Arab Emirates + http://www.whitehouse.gov/the-press-office/2013/04/04/statement-press-secretary-announcing-visit-crown-prince-mohammed-bin-zay + President Obama will welcome Crown Prince Mohammed bin Zayed Al Nahyan of the United Arab Emirates to the White House on Tuesday, April 16.  The President looks forward to discussing with the Crown Prince the strong and enduring ties between the United States and the UAE and consulting on common strategic interests in the Gulf region and broader Middle East. 

    +

    The United States and the UAE enjoy a vibrant and expanding bilateral relationship, including strong defense cooperation and economic ties, and a shared commitment to advancing peace, economic opportunity, and stability throughout the world.  The United States remains firmly committed to continuing to deepen the U.S.-UAE partnership through close and regular consultations between our two countries. 

    +]]>
    + The President + Statements and Releases + Statements and Releases + Office of the Press Secretary + The President + Thu, 04 Apr 2013 21:38:00 +0000 + The White House + 207246 at http://www.whitehouse.gov +
    + + Remarks by the President at a DNC Event -- Atherton, CA + http://www.whitehouse.gov/the-press-office/2013/04/04/remarks-president-dnc-event-atherton-ca-0 +  

    +
    + Private Residence
    +
    + Atherton, California
    +
    +  
    +
    +  
    +
    + 12:12 P.M. PDT 
    +
    +  
    +
    + THE PRESIDENT:  Hello, everybody!  (Applause.)  It is good to be back in California.
    +
    +  
    +
    + AUDIENCE:  It’s good to have you!  (Laughter.)
    +
    +  
    +
    + THE PRESIDENT:  Thank you.  Somebody said -- somebody told me, they were in the photo line, they said, we’re glad you could join our state.  (Laughter.)  They made it sound like a health club or something.  (Laughter.)  But I appreciate that you allowed me to join -- (laughter) -- because it is obviously a spectacular place and we’ve got so many good friends here, and some of you I see out there worked tirelessly dating back to when people could not pronounce my name.  (Laughter.)  And so I’m grateful to all of you. 
    +
    +  
    +
    + First of all, though, I want to give a special acknowledgement to John and Marcia for the incredible job they've done and their great hospitality.  Thank you so much.  (Applause.)  And I must say that if you had a cute baby competition, their granddaughter would have to be an entry.  (Laughter.)  And I got to say, I might have to pick her, because she is adorable and did not drool on my suit when I grabbed her.  (Laughter.)  So I'm grateful.  I'm grateful to her for that.  
    +
    +  
    +
    + We've got some elected officials who are doing incredible work -- great friends.  First of all, somebody who works tirelessly on behalf of California every day, but also works on behalf of working people and makes sure that we've got a more inclusive America -- a good friend of mine, somebody who you guys should be very proud of, Congressman Mike Honda is here.  Where is Mike?  (Applause.)  He is around here somewhere.  There he is.  Yes, I mean, he's not like a real tall guy, but he's a great guy.  (Laughter.) 
    +
    +  
    +
    + Second of all, you have to be careful to, first of all, say she is brilliant and she is dedicated and she is tough, and she is exactly what you'd want in anybody who is administering the law, and making sure that everybody is getting a fair shake.  She also happens to be by far the best-looking attorney general in the country -- Kamala Harris is here.  (Applause.)  It's true.  Come on.  (Laughter.)  And she is a great friend and has just been a great supporter for many, many years. 
    +
    +  
    +
    + And, finally, somebody who is not yet probably as well known on the national scene but is certainly well known in all of us who worked on my campaign this last time out.  He did incredible work, could not have been more effective, and has now taken on what can sometimes be a thankless job of being the DNC finance chair -- Henry Muñoz is here.  Can everybody please give Henry Muñoz a big round of applause.  (Applause.) 
    +
    +  
    +
    + So my election is over and you thought you wouldn’t have to see me again at these fundraisers.  (Laughter.)  And a close friend of mine, Abner Mikva, who was White House counsel -- he was a long-time congressman from the Chicago area -- he used to say that being friends with a politician is like perpetually having a child in college.  (Laughter.)  It's like every few months you have to write this check and you're thinking when is it going to be over.  With elected officials, it's never over.
    +
    +  
    +
    + But the reason I'm here is not for me.  The reason I'm here is because the country still needs you.  We have, as John indicated, done some work that I'm very, very proud of over the last four years.  We took an economy that was about to go into a great depression and we were able to yank it out and put us back on a path towards growth and putting people back to work.  We were able to make sure that in the process we rebuilt roads and bridges and a smarter infrastructure all across the country; and invested in clean energy; and made sure that schools got the kinds of Internet connections that they needed; and invested in basic science and research -- all of which will pay dividends for years and years to come. 
    +
    +  
    +
    + We said that in a country as wealthy as ours, nobody should go bankrupt just because they got sick.  And, already, millions of people are benefiting from the Affordable Care Act.  And, by next year, we will know that millions of people all across the country who previously did not have health insurance will have it, including folks with preexisting conditions, which will make everybody a little bit more secure.  (Applause.) 
    +
    +  
    +
    + We expanded access to college by expanding our student loan programs.  We are in the process of reforming our schools to make sure that every child gets a fair shot in life.  We ended "don't ask, don't tell" -- laying the groundwork to make sure that this was a country where you were treated fairly and equally no matter who you love.  (Applause.) 
    +
    +  
    +
    + We expanded national service.  We doubled fuel efficiency on cars.  We doubled the production of wind and solar energy.  We made sure that the Violence Against Women Act was resigned and that it provided even greater protection for women all across this country.  (Applause.)  We ended one war, as promised.  We're in the process of ending another, and at the same time have been able to keep the American people safe.  
    +
    + And so I'm very proud of the work that we've done.  But we've got a lot more work to do.  We all know that.  This country is the greatest nation on Earth, but it can be even greater.  And my main message here today is that America’s greatness will not result simply from who you elect to office; it’s going to depend on you, as citizens, and how badly you want it.  
    +
    +  
    +
    + During the State of the Union speech, as well as my inauguration speech, I talked about citizenship.  And this is a word that I spend a lot of time thinking about these days, partly because my background, my orientation, I came into politics believing that politics works best when people are involved.  I’ve never believed that more than I do now, in my second term as President, that the idea of citizenship is not just that you vote, it’s not just that you write a check where you can to support a candidate.  It’s this notion, fundamental to who we are, that we have responsibilities to ourselves and our families, but we also have obligations to our neighborhood, our community, our cities, our states, and ultimately the nation and the next generation.  
    +
    +  
    +
    + And the only way that this country moves forward is when we, the people, collectively, make it our business to meet the challenges of our time.  And we know what those challenges are.  And we know we’ve got to do better.
    +
    +  
    +
    + Now, in the next couple of months, we’ve got the opportunity to make some very significant changes.  Number one, I believe that we can get comprehensive immigration reform passed -- (applause) -- and that is going to mean that America can continue to be a nation of laws, but also a nation of immigrants, and attract the best and the brightest from all around the world.  And if we push hard and we stay focused, we’ve got the opportunity to get this done over the next couple of months.  
    +
    +  
    +
    + I believe that we have a chance to, after 30 years, frankly, of doing almost nothing, to reduce gun violence in our society.  (Applause.)  And it’s going to be hard, it’s going to be tough, but I think we’ve got a chance to get some stuff done on that.
    +
    +  
    +
    + Now, one of the things that I want to be very clear on is that this year, next year, and for the next four years that I’m in office, I am always going to be seeking, wherever I can, bipartisan solutions.  And I intend to continue to reach out to Republicans because I genuinely believe that the politics that you see in Washington isn’t representative of America; that most people actually have common sense, and most folks think cooperation and occasional compromise is part of life.  And I also think that we have to govern, not simply politick.  
    +
    +  
    +
    + And so, whether it’s on immigration reform or the budget or any of these issues, I will continue to do everything I can to reach out to my friends on the other side of the aisle.  And look, I believe that they love their kids and this country just as much as we do, and although we may have some very fundamental disagreements about how to get there, I don’t think we’ve got a disagreement about what we need to be as a nation.  
    +
    +  
    +
    + Having said that, though, there are still some really big arguments that we’re having in Washington, and I believe that Democrats represent those values that will best advance the interests of middle-class families and everybody who is willing to work hard to get into the middle class; that will grow this economy in a broad-based way, and that will lay the foundation for prosperity for generations to come.  
    +
    +  
    +
    + And you believe that, too.  That’s why you’re here.  In order for us to do that, you’re going to have to stay involved.  Think about some of the things I spoke about during the State of the Union address:  making sure that every child in America has outstanding, high-quality, early childhood education.  We know that there’s nothing more important to a child’s success than those early years.  And if we do that right, not only are we going to see better performance in our schools, we’re going to see better performance in our economy.  And we can do it.  We can afford to do it.  
    +
    +  
    +
    + But in order for us to make that happen, we’re going to have to have an active, motivated, Democratic national party.  People here in this area care deeply about issues of energy and climate change.  And I think that the science is indisputable, and this is an obligation we owe to future generations.  And as I said, we’ve already done a lot to reduce our carbon footprint and to make our economy more energy efficient.  But if we’re going to do more, then we’ve got to make sure that we’re active and involved, and helping to educate our friends and our neighbors and our coworkers about why this is important and why there’s no contradiction between a sound environment and strong economic growth; that, in fact, if we do this right, the energy sources of the future, the clean energy sources of the future can be an engine for economic growth for decades and decades to come.
    +
    +  
    +
    + When it comes to our economy -- making sure that we’re investing in basic research and science.  This is the epicenter of innovation in this nation.  Some of you saw, a couple of days ago, I announced a new BRAIN Initiative that will allow us to crack the code and map -- (applause) -- what this incredible gray matter between our ears, one of the greatest mysteries there is, what’s causing things like Alzheimer’s and Parkinson’s, and to not just provide cures but also to help generate entire new industries that can put people to work in this region and around the country.  
    +
    +  
    +
    + In order for us to make sure that we’re investing sufficiently in basic science and research, you’re going to have to be involved.  You have to push.  You can’t just wait for it to happen, because there are going to be competing interests and folks who want to spend those resources in a different way.  
    +
    +  
    +
    + When it comes to our budget, I actually think that we can stabilize our finances, reduce our debt, reduce our deficit in a prudent, balanced way.  But we’ve got the other side insisting that somehow we can cut our way to prosperity.  I disagree with that.  I will take that case to the American people.  But for me to be successful in resolving that argument in a way that allows us to keep growing and keep investing, I’m going to need your help.  
    +
    +  
    +
    + Making sure that we’re providing ladders of opportunity in communities all across the country that have been left behind -- and, in some cases, have been behind for decades -- so that we’re not just investing in education, but also making sure that we’re providing transportation assistance and tax credits so that impoverished communities can be part of this global economy.  That will make us all stronger.  I can’t do that unless I have your help.
    +
    +  
    +
    + And for us to continue to make progress so that this is a society that is more just and more equal and more inclusive -- we’ve made remarkable progress over these last few years, but that’s not because of what started in Washington, it’s because of what happened in communities all across the country.
    +
    +  
    +
    + I was mentioning to people I had a chance to see an early screening of this new movie called “42”; it’s about Jackie Robinson.  And I look around the room -- young people -- (laughter) -- kind of vaguely know, yes, Jackie Robinson -- (laughter) -- first African American baseball player.  His widow was there, Rachel Robinson, who’s gorgeous and 90, but looks better than I do -- (laughter) -- and could not be more gracious.  
    +
    +  
    +
    + And to sit there in a movie theater watching what happened in her lifetime, and to know that because of the decisions and courage of Jackie Robison and Branch Rickey, and all the other path breakers, that we now have a country that is fairer and better for it is a reminder of how change happens in this country.  It doesn’t happen all at once.  It doesn’t happen in one fell swoop.  It doesn’t happen because a President gives a speech.  It happens because a whole bunch of people out there, day in and day out, are making choices and decisions about whether we’re going to be fair or less fair; whether we’re going to be generous or less generous; whether we are going to be inclusive or less inclusive.  And that changing of our hearts and our minds ultimately translates itself into politics, but it begins with citizens.  It begins with you.
    +
    +  
    +
    + And if the Democratic Party stands for anything, then it has to stand for that basic proposition that not only do we want an economy where if you work hard, you can make it if you try -- no matter where you come from, what you look like, who you love -- but also that the way to get there is by giving everybody a voice and making sure everybody is involved and everybody is included.  If we stand for anything as Democrats, that’s got to be what we stand for.
    +
    +  
    +
    + And so the DNC is an important part of that overall process.  And the fact that you are here, the fact that John and Marcia were willing to open up their home like this gives me confidence that, in fact, we will be able to sustain these efforts.  And it has to be sustained beyond elections.  You can’t just wait until a presidential election to do this.  It’s all those days in between that are going to determine whether or not we bring about the changes that we so desperately believe in.
    +
    +  
    +
    + So to all of you, I want to say thank you.  But understand this is just a beginning, it’s not an end.  You are going to be called on to do more work.  You are going to be called on to get more engaged and more involved.  And if you ever have any doubts as to why you’re doing it, then you have to look at John and Marcia’s grandbaby, or that young man who’s falling asleep because I’ve been talking too long.  (Laughter.)  And you will remember that, ultimately, the only thing that matters is whether or not we’re leaving behind a country that’s a little bit better than the one we founded for them.  That’s why we do what we do.  That’s why I do what I do -- for Malia and Sasha, and all the Malias and Sashas out there, I want to make sure we’re doing right by them.
    +
    +  
    +
    + All right, thank you very much, everybody.  (Applause.)  God bless you.  Thank you.
    +
    +  
    +
    + END
    +
    + 12:31 P.M. PDT
    +]]>
    + The President + Speeches and Remarks + Speeches and Remarks + Office of the Press Secretary + The President + Thu, 04 Apr 2013 21:33:00 +0000 + The White House + 207256 at http://www.whitehouse.gov +
    + + Statement by the President on the Passing of Roger Ebert + http://www.whitehouse.gov/the-press-office/2013/04/04/statement-president-passing-roger-ebert + Michelle and I are saddened to hear about the passing of Roger Ebert.  For a generation of Americans - and especially Chicagoans - Roger was the movies.  When he didn't like a film, he was honest; when he did, he was effusive - capturing the unique power of the movies to take us somewhere magical.  Even amidst his own battles with cancer, Roger was as productive as he was resilient - continuing to share his passion and perspective with the world.  The movies won't be the same without Roger, and our thoughts and prayers are with Chaz and the rest of the Ebert family.

    +]]>
    + The President + Statements and Releases + Statements and Releases + Office of the Press Secretary + The President + Thu, 04 Apr 2013 20:47:00 +0000 + The White House + 207171 at http://www.whitehouse.gov +
    + + Remarks by the First Lady at Kitchen Garden Planting Event + http://www.whitehouse.gov/the-press-office/2013/04/04/remarks-first-lady-kitchen-garden-planting-event + White House Kitchen Garden 

    +

    1:16 P.M. EDT
    + MRS. OBAMA:  How are you guys doing?

    +

    CHILDREN:  Good.

    +

    MRS. OBAMA:  Is it a little chilly?

    +

    CHILDREN:  Yes.

    +

    MRS. OBAMA:  Where are your jackets?  I'm going to be the mother.  Where are your jackets?  (Laughter.)  All right, so we're going to put you to work. 

    +

    Well, welcome.  This is the fifth planting of the White House Kitchen Garden.  Are you guys excited?

    +

    CHILDREN:  Yes.

    +

    MRS. OBAMA:  So that we know who is here, I want to make sure that all these wonderful people with their cameras know which schools are here.  So when I say your school name, raise your hand, or scream or something like that. 

    +

    Milton Elementary School from Milton, Vermont.  Woo-hoo!  Yes, is that the principal?  It's like woo-hoo, party on.  Sarah Moore Greene Magnet Technology Academy in Knox County, Tennessee.  Woo-hoo!  (Applause.)  Arthur D. Healey School, Somerville Public Schools in Somerville, Massachusetts.  Woo-hoo!  (Applause.)  Benjamin David Gullett Elementary School in Bradenton, Florida.  (Applause.)  Yes, that was it.  That was it.  I know you all are cold, coming from Florida.  And then we have our partners from many, many, many years -- Bancroft Elementary School.  (Applause.)  There we go.  See, they're comfortable yelling in the White House.  (Laughter.)  And then we have the Harriet Tubman Elementary School students.  (Applause.)

    +

    So it's great to have you guys here.  Are you ready to go?  One of the reasons we invited these schools -- Harriet Tubman School and Bancroft, they have been our partners for years.  But the schools from across the country who have come, you guys are here because you are doing such wonderful things to implement the new school nutrition standards at your school.  So do you like your school lunches?  They are healthy and they are good?  And you're eating your vegetables?  And many of you have gardens of your own?  Awesome.  So you know what to do here, right?  Are you ready to plant?

    +

    All right, let's get going.  Let's do it! 

    +

    END
    + 1:18 P.M. EDT

    +]]>
    + The First Lady + Speeches and Remarks + Speeches and Remarks + Office of the First Lady + The First Lady + Thu, 04 Apr 2013 19:40:00 +0000 + The White House + 207156 at http://www.whitehouse.gov +
    + + Remarks by the President at a DNC Event -- Atherton, CA + http://www.whitehouse.gov/the-press-office/2013/04/04/remarks-president-dnc-event-atherton-ca + Private Residence
    + Atherton, California

    +

    10:28 A.M. PDT

    +

    THE PRESIDENT:  Thank you.  (Applause.)  Thank you so much.  Well, it is wonderful to see all of you.  This is an intimate group.  What I want to do is mostly have a conversation.  But, first of all, obviously I want to thank Liz and Mark for their incredible hospitality.  We couldn’t be more appreciative.  And I want to thank all of you for being here today.

    +

    A lot of you -- in fact, almost everybody here I’ve known, have supported me.  Some of you were involved in my first campaign when nobody could pronounce my name.  (Laughter.)  And you stuck with me through thick and thin, and I just want to say how much I appreciate all of you for taking the time.

    +

    Some people have been asking me -- well, what’s different about the second term?  And I say, well, for one thing, I’m not raising money for myself, and that’s good.  (Laughter.)  For another thing, the girls are getting old enough now where they don’t want to spend time with us on the weekends.  (Laughter.)  They have sleepovers and parties and sports, and all that stuff.  I don’t know if you guys are doing the same thing to your parents, but it’s starting to happen.

    +

    But I think the most important thing is that when you don’t have another race to run, all you’re really thinking about it is how do I leave a legacy, not simply for the next President, but for the next generation that makes America stronger; that helps assure our children can compete with an ever-changing world; that we are solving what I think is one of the core challenges we face as a generation, and that is making sure that we have a strong, growing middle class and ladders of opportunity for everybody who is willing to work to get into that middle class; that we continue to be innovative; that we address some of our core environmental challenges, particularly climate change, to make sure that the planet we leave behind is one that our children can thrive in.

    +

    So you end up taking the long view on things.  And you also feel a great urgency because you know you don’t have a lot of time.  And so the main message I want to deliver here today is that I could not be prouder of the track record that we’ve put together over the last four years and two months, whether it was saving an economy from a great depression; doubling fuel efficiency standards on cars; expanding access to college for the millions of young people; making sure that nobody in this country has to go bankrupt because they get sick; re-upping the law preventing violence against women; making sure that we have the "don't ask, don't tell" policy, which I think has laid the groundwork for further progress when it comes to LGBT rights.

    +

    On so many issues, we’ve made progress.  But we’ve got so much more work to do.  And I laid out what that vision might look like during both the inauguration speech and in the State of the Union.  I want to make sure that we’ve got the best education system in the world and that starts young.  And so we’ve given all the research that we have.  Expanding our investment in childhood education can make all the difference in the world, and will pay enormous dividends for a very, very long time.

    +

    I want to make sure that we’re rebuilding this country, our infrastructure.  We’ve got $2 trillion in deferred maintenance.  We could be putting people back to work right now, and not only improving our current economic growth, but laying the foundation for economic growth for many years to come.  Many of you are aware that I am a big proponent of investments in science and research, and obviously, this entire region has thrived precisely because it has been the epicenter of innovation.  And that requires us putting money into research in biomedicine, in nanoscience.  Our recent initiative around the brain and being able to map that and crack the code potentially not only can help us cure things like Alzheimer’s and Parkinson’s, but can generate entire new industries and put people back to work and be the next great challenge for the American economy.

    +

    And I believe that we’ve got to get a handle on our energy policy so that we are growing and we are productive, but we are not simply investing in the energy sources of the past; we’re also investing in the energy sources of the future.  We’ve doubled fuel efficiency standards on cars, but we’ve also had a chance to double our production in solar and wind and biofuels.  We can continue to make progress on that front.  We can continue to make sure that electric cars and other new technologies for transportation are built here in the United States of America and not someplace else. 

    +

    We can make sure that our buildings, our schools, our hospitals are more efficient.  If we were able to achieve the same efficiencies that Japan already has achieved using existing technologies, we'd cut our power utilization by 15, 20 percent -- which would have enormous ramifications in bringing down our carbon footprint.

    +

    And we can do all this without spending massive amounts of money.  The truth is, is that our fiscal situation has improved significantly since I first came into office, but we still have a long way to go.  The way for us to do it intelligently is the kind of balanced approach I've talked about in the past:  making sure that everybody is doing their fair share; making sure that those of us in this room and, frankly, in this whole town probably -- (laughter) -- recognizes the incredible blessings that we've been given and make sure that we're willing to invest back in the next generation, and also making sure that our money is wisely spent. 

    +

    We still waste money in all kinds of things that don't work, and we have the capacity to shift those dollars into things that do work and that will grow our economy.  And we can reduce our deficit, stabilize our debt, and do so without sacrificing the kinds of investments that are going to be required to grow.

    +

    Now, the last point I'll make is just politics.  Our policies, the ones that we prevented -- or the ones that we've presented, traditionally, would be considered pretty bipartisan.  There's nothing particularly Democratic about road building or basic science or environmental protection.  Teddy Roosevelt started the conservation movement.  Abraham Lincoln, the first Republican President, was pretty big on building infrastructure and investing in things like science and research. 

    +

    Unfortunately, we continue to still have some of that gridlock in Washington.  Part of it is fed by changes in information and communications that amplify conflict and extremes as opposed to trying to bring people together.  I know it's a great source of frustration for the American people.  I assure you it's a source of frustration for me as well.  (Laughter.)

    +

    But what I believed when I was running for this office back in 2007-2008, what I believed when I was running for a second term is what I still believe now -- and that is this country is not as divided as our politics would suggest.  And the only way we break through this gridlock is when people's voices are heard and people are engaged and involved.  I am very optimistic that we get immigration reform done in the next few months.  And the reason I'm optimistic is because people spoke out through the ballot box, and that's breaking gridlock. 

    +

    It's going to be tougher to get better gun legislation to reduce gun violence through the Senate and the House that so many of us I think want to see, particularly after the tragedy in Newtown.  But I still think it can get done if people are activated and involved. 

    +

    And so, on every front, on every issue that all of you care about, making sure that we can provide good information to the American people, engage them, inform them; make sure that they are embracing a form of citizenship that goes beyond just voting, but involves understanding what's at stake and talking to their neighbors, talking to their coworkers, talking to their friends, writing to their members of Congress, getting organized, getting mobilized -- all that ends up being really the critical ingredient and the constant dynamic change and improvement that has characterized this country for so long.

    +

    And your involvement with the DNC helps us do that.  It will help us register voters.  It will help us make sure that they understand what's at stake in all of these issues.  It's hugely important.  It's not always glamorous.  It's not always sexy.  But it's really what ends up driving our ability to make policy and to deliver for the young people who are here today. 

    +

    So, again, I want to thank Liz and Mark for making this spectacular home available to us.  And I want to thank all of you for not only what you've done in the past on my behalf, but more importantly what you're continuing to do on behalf of this country as a whole. 

    +

    Thank you, so much.  I appreciate it.  (Applause.)

    +

    END
    + 10:39 A.M. PDT

    +]]>
    + The President + Speeches and Remarks + Speeches and Remarks + Office of the Press Secretary + The President + Thu, 04 Apr 2013 19:02:00 +0000 + The White House + 207151 at http://www.whitehouse.gov +
    + + Letter -- Continuation of the National Emergency with Respect to Somalia + http://www.whitehouse.gov/the-press-office/2013/04/04/letter-continuation-national-emergency-respect-somalia + April 4, 2013

    +

    Dear Mr. Speaker: (Dear Mr. President:)

    +

    Section 202(d) of the National Emergencies Act (50 U.S.C. 1622(d)) provides for the automatic termination of a national emergency unless, within 90 days prior to the anniversary date of its declaration, the President publishes in the Federal Register and transmits to the Congress a notice stating that the emergency is to continue in effect beyond the anniversary date. In accordance with this provision, I have sent to the Federal Register for publication the enclosed notice stating that the national emergency declared in Executive Order 13536 of April 12, 2010, with respect to Somalia is to continue in effect beyond April 12, 2013.

    +

    On January 17, 2013, the United States Government announced its formal recognition of the Government of Somalia. The United States had not recognized a government in Somalia for the previous 22 years. Although the U.S. recognition underscores a strong commitment to Somalia's stabilization, it does not remove the importance of U.S. sanctions, especially against persons undermining the stability of Somalia. For this reason, I have determined that it is necessary to continue the national emergency with respect to Somalia and to maintain in force the sanctions to respond to this threat.

    +

    Sincerely,

    +

    BARACK OBAMA

    +]]>
    + The President + Statements and Releases + Statements and Releases + Office of the Press Secretary + The President + Thu, 04 Apr 2013 18:17:00 +0000 + The White House + 207141 at http://www.whitehouse.gov +
    + + Notice -- Continuation of the National Emergency with Respect to Somalia + http://www.whitehouse.gov/the-press-office/2013/04/04/notice-continuation-national-emergency-respect-somalia + NOTICE

    +

    - - - - - - -

    +

    CONTINUATION OF THE NATIONAL EMERGENCY WITH RESPECT TO SOMALIA

    +

    On April 12, 2010, by Executive Order 13536, I declared a national emergency pursuant to the International Emergency Economic Powers Act (50 U.S.C. 1701-1706) to deal with the unusual and extraordinary threat to the national security and foreign policy of the United States constituted by the deterioration of the security situation and the persistence of violence in Somalia, acts of piracy and armed robbery at sea off the coast of Somalia, which have repeatedly been the subject of United Nations Security Council resolutions, and violations of the arms embargo imposed by the United Nations Security Council.

    +

    On July 20, 2012, I issued Executive Order 13620 to take additional steps to deal with the national emergency declared in Executive Order 13536 in view of United Nations Security Council Resolution 2036 of February 22, 2012, and Resolution 2002 of July 29, 2011, and to address: exports of charcoal from Somalia, which generate significant revenue for al-Shabaab; the misappropriation of Somali public assets; and certain acts of violence committed against civilians in Somalia, all of which contribute to the deterioration of the security situation and the persistence of violence in Somalia.

    +

    The situation with respect to Somalia continues to pose an unusual and extraordinary threat to the national security and foreign policy of the United States. For this reason, the national emergency declared on April 12, 2010, and the measures adopted on that date and on July 20, 2012, to deal with that emergency, must continue in effect beyond April 12, 2013. Therefore, in accordance with section 202(d) of the National Emergencies Act (50 U.S.C. 1622(d)), I am continuing for 1 year the national emergency declared in Executive Order 13536.

    +

    This notice shall be published in the Federal Register and transmitted to the Congress.

    +

    BARACK OBAMA

    +]]>
    + The President + Statements and Releases + Statements and Releases + Office of the Press Secretary + The President + Thu, 04 Apr 2013 18:17:00 +0000 + The White House + 207136 at http://www.whitehouse.gov +
    + + Remarks by the President at a DCCC Event -- San Francisco, CA + http://www.whitehouse.gov/the-press-office/2013/04/04/remarks-president-dccc-event-san-francisco-ca-0 + + Private Residence +
    + San Francisco, California
    +
    +  
    +
    +  
    +
    + 8:24 P.M. PDT
    +
    +  
    +
    + THE PRESIDENT:  Thank you.  (Applause.)  Well, first of all, let me thank Ann and Gordon for once again extending such gracious hospitality to all of us.  I was reminded that I was first here in 2008, when I was running the first time, and I had much less gray hair.  (Laughter.)  But they were kind to me then and have been kind to me since, and I appreciate very much their friendship and support.  
    +
    +  
    +
    + I want to acknowledge Steve Israel, who is here and has an often thankless, extraordinarily difficult but critically important job, and he’s done so with good humor and boundless energy.  And so please give Congressman Steve Israel a big round of applause.  (Applause.)  
    +
    +  
    +
    + And of course I’m here because your neighbor told me I needed to be here.  (Laughter.)  And I am here because there are very few people in public office who I am more fond of and respectful than the person who just introduced me, Nancy Pelosi.  She is thoughtful, she’s visionary, she’s as tough as nails.  (Laughter.)  She is practical.  She never lets ideology cloud her judgment.  She’s constantly motivated by how do we create a country that is more just, more fair, more dynamic.  She knows why she’s in public life.  It’s connected to her values -- the values that she grew up with, the values that she’s raised her kids, and now spoils her grandkids with.  (Laughter.)  And I’m just so proud to call her a friend.  
    +
    +  
    +
    + And I am here because I won my last election, but I’m here because my job is not simply to occupy the Oval Office.  My job is to make sure we move the country forward, and I think we can best do that if Nancy Pelosi is Speaker of the House once again.  (Applause.)
    +
    +  
    +
    + Nancy used a word that I’ve spent a lot of time thinking about these days.  And that’s the word “citizenship.”  I talked about it at the inauguration speech.  I talked about it at the State of the Union speech.  I actually talked about it at the convention, my acceptance speech.  And the reason I care about the word so much is because there are times in today’s busy world, the media chatter, where there’s a government over here somewhere, and then there’s people and ordinary life and the private sector, and all that stuff is over there.  And somehow the notion is that these two things are separate. 
    +
    +  
    +
    + And some of the folks who most adamantly insist that government is something alien and distant are the same folks who claim the mantle of the Founders and believe that their views best represent the original intentions of those who fought for and formed this country.
    +
    +  
    +
    + And yet, when I read the Declaration of Independence, when I read the Constitution, when I look at all the great documents and laws that have been passed that built this country up, what I see is this central idea that citizenship means we are the government -- the government of and by and for the people -- which means we have responsibilities that extend beyond voting or even writing a check.  
    +
    +  
    +
    + It speaks to rights, but it also speaks to responsibilities and obligations.  It suggests that we are responsible for ourselves, and our families, and our neighborhoods, and our cities, and our farmlands, and our neighbors, and our nation, and future generations.  And so we don't just think about “us,” we think about “we, the people.”  That’s the idea that motivated me to get into public service in the first place.  That’s what I think has always been at the heart of America.  
    +
    +  
    +
    + And the reason that we’ve been able to make significant progress over the last four years and couple months is because a lot of you have believed it, too.  That’s how I got elected in 2008.  That’s how Nancy Pelosi became Speaker in 2006.  That’s the reason that we were able to yank an economy on the verge of depression and get it back on track to growth and job creation.  That’s the reason that we were able to pass a health care law that is already helping millions of people, and will help millions more when it is fully implemented next year.  (Applause.)  
    +
    + That’s the reason we’ve been able to put people back to work building roads and bridges and water systems and new park trails all across this country.  That’s the reason that we were able to double fuel efficiency standards on cars, begin the process of reducing carbons and making our economy more energy-efficient, and doubling the amount of clean energy that we’re producing through wind and solar and other renewables.  
    +
    + It’s the reason that we’ve been able slowly to nurse the housing market back to health.  That is the reason that we’ve been able to keep this country safe while still being true to our values and principles of rule of law.  
    +
    +  
    +
    + That is the reason why we’ve been able to help millions of kids all across this country go to college who couldn't otherwise afford it.  We’ve started to reform schools at the K-12 level.  
    +
    +  
    +
    + We were able to do all this because you believed in citizenship.  And the reason I ran for another term was because I think we’ve got more work to do.  And the reason that Nancy wants to be Speaker again is because she thinks we have more work to do.  (Applause.)  I assure you that she does not like being away from her grandkids.  (Laughter.)  She could be doing a lot of other stuff.  Steve makes enormous sacrifices.  He’s got to travel all across the country raising money constantly and recruiting candidates.  He’d love to be home.  But we think we’ve got more work to do.
    +
    +  
    +
    + Now, this year, we have a window.  Just completed one election.  We would like to see some governing done in Washington before the next election starts.  (Laughter.)  And so we’ve got this opportunity that we need to seize to initiate serious gun safety legislation, reduce gun violence -- (applause) -- to make sure that we finally get a comprehensive immigration reform done, because we are a nation of laws but we are also a nation of immigrants, and those two things are not incompatible.  (Applause.)  
    +
    +  
    +
    + We have more work to do to make sure that we stabilize our finances in a way that still allows us to make investments in critical infrastructure and basic research.  Somebody mentioned to me they heard my speech about the new BRAIN Initiative that we’ve put forward; just an entire sweeping horizon of possibilities when it comes to -- (applause) -- curing Alzheimer’s, and curing Parkinson’s, and so many diseases, but also just allowing us to do things that we couldn't even imagine a year ago, two years ago.  Now we’re on the threshold of cracking a code that could open up endless possibilities.  
    +
    +  
    +
    + Now, in order to do that, we’ve got to be able to pass laws.  There are some things I can do administratively, a lot of stuff that we can do administratively, but a lot of stuff we’ve got to do legislatively.  Right now we’re constrained by what we get done.  And I have said publicly and I will say it to this room once again that I believe that Republicans love their kids and their country as much as we do, and there are a whole bunch of folks out there who I believe actually want to cooperate with us but feel constrained right now because of their own politics.   
    +
    +  
    +
    + I’m looking and probing for every crack and possible opportunity to join in a bipartisan fashion to solve these problems, because I think most of the problems out there are ones that, at least historically, have garnered support from Democrats and Republicans, and that’s -- there is nothing inherently Democratic about building roads or funding research or looking out for the environment.  It used to be a great bipartisan set of ideas.
    +
    +  
    +
    + And so my hope is, is that we can get some governing done this year, and I know that Nancy feels the same way.  By the way, she’s already worked with her caucus to deliver votes on things that aren’t necessarily politically advantageous but are the right thing to do.  She did it as Speaker, and she’s done it as Democratic Leader in the House.  So we want to get this -- we just want to get stuff done.  
    +
    +  
    +
    + And I won’t say -- I won’t speak for Nancy here, I will speak for myself.  I would love nothing better than an effective, loyal opposition that is willing to meet us halfway and move the country forward -- because that’s what the American people are looking for.  The economy is growing but there is still a lot of folks out there who are struggling; still way too many people who are unemployed; people who haven’t seen a raise in a decade; people whose homes are still underwater; people who when they see $4-a-gallon gas know that that is money that’s coming straight out of their pockets or their retirement funds and is going to be very hard to make up.  And they’re hoping that we can do some governing.  And that’s what I intend to do this year, and the year after that and the year after that. 
    +
    +  
    +
    + But I would be dishonest if I didn’t say that it would be a whole lot easier to govern if I had Nancy Pelosi as Speaker.  (Laughter and applause.)  Because here are the stakes -- I actually think we’ve got a great chance of getting immigration reform done.  I think we have a good chance of getting serious gun safety legislation done.  But if we’re going to move forward on some of the other things I talked about in the State of the Union -- making sure that we’ve got early childhood education for every child in America so that they can (inaudible.) (Applause.)  
    +
    +  
    +
    + If we’re going to deal with the $2 trillion of deferred maintenance we’ve got in terms of infrastructure -- not just roads and bridges, but a smart grid that can connect up clean energy to our cities and make sure that we continue to reduce not only existing loads of renewable energy, but also discovering those breakthroughs that are going to make all the difference down the future, then I’m going to need some more help in Congress. 
    +
    +  
    +
    + If we’re going to deal with climate change in a serious way, then we’ve got to have folks in Congress -- even when it’s not politically convenient -- to talk about it and advocate for it, and break out of this notion that somehow there’s a contradiction between us being good stewards of the environment and us growing this economy.  They are not a contradiction.  We can grow this economy fast and faster if we are seizing the opportunities of the future and not just looking at the energy sources of the past.  We’re going to need some help. 
    +
    +  
    +
    + I’m going to need some help if we are going to continue to make progress in assuring that every young person in this country has a chance to go to college and that they can afford it.  I’m going to need some help if we’re going to make sure that simple stuff -- what should be simple -- that everybody in America right now can refinance their homes.  We could put $3,000 a year into the pockets of every single American just by passing a law in Congress that, by the way, Mitt Romney’s key economic advisor, chief economic advisor says was a good idea.  For some reason, we still can’t get it through the Congress -- 3,000 bucks.  It’s like free money for families who right now are struggling.  Think about what they could do with it, and what that will do in terms of boosting our growth.  I need some help.
    +
    +  
    +
    + And my hope is, is that we’re going to see more and more Republicans who say, you know what, I didn’t come here just to fight the President or demonize Nancy Pelosi, I came here to get some stuff done.  And they will be greeted with great enthusiasm by me and I think by Nancy, if we could get some more stuff done right now.  But, realistically, I could get a whole lot more done if Nancy Pelosi is Speaker of the House.  (Applause.) 
    +
    +  
    +
    + So let me just close by saying this.  And I know that Nancy’s people will have a chance to answer some more specific questions about their game plan, all the great candidates they’ve recruited, the significant financial burden that will have to be bent in order to help elect these candidates.  
    +
    +  
    +
    + But let me close by saying this, go back to where I started this notion of citizenship.  People ask me, does it feel different now in your second term than it did in your first?  It does.  Look, I would hope I’m better at my job now than I was when I first came in.  I’ve got some nicks, bruises to prove that I’ve been to this rodeo before.  Hopefully, I’m making better decisions and our team is better organized, and we know what works and what doesn’t, what some of the pitfalls are. 
    +
    +  
    +
    + But the main difference really is a sense of perspective and realization that nothing worthwhile happens in six months or a year.  It happens over decades.  It happens over generations, that the story of America has been us steadily, through fits and starts, expanding opportunity, creating a more perfect union, seizing the promise of the future, fighting off some of our own worst impulses.  And that any one of us, our job is not to do it by ourselves or get it all done in one year or one term or even necessarily in our lifetimes, but our job is to make sure that we’re pressing and pushing so that the whole country, over time, is moving in the right direction.
    +
    +  
    +
    + We did a screening of the Jackie -- there’s a new movie about Jackie Robinson called “42,” which I usually don’t plug movies, but I strongly recommend people take their kids and their grandkids to see this.  A lot of people don’t necessarily remember the story of Jackie Robinson or if they it’s sort of vague.  His widow, Rachel Robinson was there.  She’s 90 years old and gorgeous.  And in the theater at the White House, I thanked her.  I thanked the people who made the film, just for reminding me in very visceral terms that in her lifetime, she saw her husband being the first African American to play in Major League Baseball, and now she’s sitting there with me, in the White House.  That’s a long time -- 70 years.  On the other hand, that’s a blink of an eye in terms of human history.  And that required Branch Rickey, it required Jackie Robinson, and then it required --
    +
    +  
    +
    + AUDIENCE MEMBER:  Chandler.  The commissioner, Happy Chandler.
    +
    +  
    +
    + THE PRESIDENT:  -- and it just -- it required a succession of people making tough choices, but the right choice.  And then slowly things changed.  A culture transformed itself.  
    +
    +  
    +
    + I was just in another house here in, very close by.  A wonderful young woman, singer-songwriter Brandi Carlile was performing.  And she was with her wife -- just got married I guess the day that I announced that I supported same-sex marriage.  And she’s a young woman, and I’m assuming she’s thinking about all the people who were fighting the good fight not just in Stonewall, but well before that.   
    +
    +  
    +
    + And so generation after generation, we just plug away, and sometimes we make progress and sometimes it feels like we’re not making progress.  We just stay at it and stay at it.  And then suddenly there’s a breakthrough, and the entire culture shifts.  
    +
    +  
    +
    + And that’s what citizenship means.  That’s why it’s so important, because it’s not going to happen all at once.  And all of us have to carry the burden of moving things forward. 
    +
    +  
    +
    + So I hope that when you hear from Nancy and Steve, I hope that all of you understand this is not just a one-off, this is not just checking this off the list.  You’ve got to stay with them.  And it’ll be frustrating, it’ll be slow, and there will be times where you lose hope, and there will be times where you won’t be mad at Nancy, but there will certainly be times where you’re mad at me.  (Laughter.)   
    +
    +  
    +
    + But if you stay with it, if you and your neighbors and your friends and your children and your grandchildren, if they maintain that sense that this is our government not somebody else’s, and we can change it, then I’ve got great optimism for the future of this country and for the future of citizens in America. 
    +
    +  
    +
    + Thank you very much, everybody.  (Applause.)
    +
    +  
    +
    + END
    +
    + 8:48 P.M. PDT
    +]]>
    + The President + Speeches and Remarks + Speeches and Remarks + Office of the Press Secretary + The President + Thu, 04 Apr 2013 10:25:00 +0000 + The White House + 207091 at http://www.whitehouse.gov +
    + + Remarks by the President at a DCCC Event -- San Francisco, CA + http://www.whitehouse.gov/the-press-office/2013/04/04/remarks-president-dccc-event-san-francisco-ca + + Private Residence +
    + San Francisco, California
    +
    +  
    +
    +  
    +
    + 6:53 P.M. PDT
    +
    +  
    +
    + THE PRESIDENT:  Thank you.  (Applause.)  Thank you, everybody.  Thank you.   Well, first of all, I want to thank Tom and Kat for opening up this spectacular home.  They were bragging about the view -- (laughter) -- but Secret Service wasn’t going to let me look at the view.  But I’m now in my second term, so I can -- (laughter) -- so I called an audible, and I went out there, and it is spectacular.  And they were all apologetic.  They said, well, you can’t see the bridge.  (Laughter.)  I said, it’s okay, I can see the Pacific Ocean; that’s pretty good.  (Laughter.)  So I was perfectly satisfied with the view, and I could not be more grateful and thankful to them for hosting us here tonight.  So give them a big round of applause.  (Applause.)
    +
    +  
    +
    + I want to thank Brandi Carlile for singing the -- (applause) -- there she is.  Now, I just -- the reason I know Brandi is because the White House photographer, Pete Souza, was a fan of Brandi’s before the rest of the world knew Brandi, and followed her around everywhere.  He didn’t stalk her, he was just -- (laughter) -- he was a fan.  And so Pete Souza gets credit, before Jimmy Fallon or anybody else, for Brandi Carlile being discovered, at least by me.  (Laughter.)  But we’re so grateful for her participating here tonight.
    +
    +  
    +
    + The main reason we’re here is actually not me.  The main reason we’re here is because we have got a fearless leader who happens to be your neighbor, who day in, day out is fighting the good fight on every single issue that matters in terms of making this a more equitable, more prosperous, more generous, more competitive nation.  And she has been an extraordinary friend of mine, but more importantly, she’s a friend to working families all across the country each and every day.  I could not be prouder of her, and I expect that she is going to be once again the Speaker of the House -- Nancy Pelosi.  Love Nancy.  (Applause.)
    +
    +  
    +
    + And Nancy wouldn’t be -- I think would be the first to say that she could not do what she does if it weren’t for her extraordinary members.  Right now, her chief rebounder, assist person, handyman -- (laughter) -- the guy who is making this enormous effort work is Steve Israel.  So we want to thank Congressman Steve Israel.  (Applause.)  And we’ve got three other members here today.  Mike Honda -- where’s Mike?  There he is in the back.  (Applause.)  Jared Huffman.  Jared is right there.  (Applause.)  And Eric Swalwell.  There he is.  (Applause.)  
    +
    +  
    +
    + All right, now, first of all, Tom used that analogy I think two days after I went two for twenty at -- (laughter) -- at the Easter Egg Roll, guarded by a number of 6-year-olds.  (Laughter.)  So clearly I have not been playing enough basketball for anybody to want to use that analogy.  But what I think is absolutely true is that the way I have always thought about politics, I know the way Nancy thinks about politics, is that we are a team.  And when I say “we,” I’m not simply referring to the people in Washington.  
    +
    +  
    +
    + If you noticed, during my inauguration address and my State of the Union, I talked about citizenship; I talked about what it means to be a citizen.  And the notion of citizenship is not simply a matter of voting, it’s not simply a matter of writing a check to a candidate who you like.  The notion of citizenship is that all of us have obligations to this nation, to our fellow citizens, and to future generations, and that each and every day we are tested and asked to participate in ways large and small to push that boulder up the hill a little bit, and to make sure that when our time here has passed, we can say, America is stronger, it’s more prosperous, and opportunity is available to every single American.
    +
    +  
    +
    + That’s not just my job, it’s not just Nancy’s job -- it’s your job, as well.  And the fact that all of you are here is an indicator that you take this notion of citizenship seriously.  And because you do, Nancy and I, and Steve and others, we’ve had an opportunity over these last four years and a couple of months to make some extraordinary changes in this country. 
    +
    +  
    +
    + We were able to yank an economy that was on the verge of a depression out of depression.  And although we’re not all the way back, the economy has stabilized, our financial markets have stabilized, housing is beginning to come back, and families are starting to feel a little more hopeful about their prospects for the future.
    +
    +  
    +
    + Because of you, because of our team, we have been able to assure that people who already have health insurance have better health insurance; that they’ve got preventive care, they’ve got contraceptive care; that insurance companies can’t drop them for no good reason; that young people can stay on their parent’s plan until they’re 26.  And by next year, we’ll know that 35 million people, most of whom work, are never again going to have to say to themselves that because of a preexisting condition or simply a lack of money, that they end up bankrupt or end up in an emergency room when they or their family members get sick.  That happened because of all of you.  (Applause.)  
    +
    +  
    +
    + Because of you, we were able to make sure that serving your country didn't depend on who you loved, and as a consequence of some of those changes, we’re now starting to see a extraordinary transformation in our culture that assures that the LGBT community has full and equal citizenship in this country.  (Applause.)  That happened because of you.  
    +
    +  
    +
    + Because of you, roads have been built that needed repair, and people were put back to work.  Because of you, research has happened that is looking to cure everything from Alzheimer’s to Parkinson’s to juvenile diabetes.  Because of you, we’re actually seeing genuine improvement in our schools, and states all across the country -- including very red states -- have embarked on a reform agenda that makes certain that our kids can compete in this new global economy.
    +
    +  
    +
    + Because of you, millions of young people have health insurance -- they have health insurance but are also able to afford college, and couldn't afford it before.  And because of you, despite a very aggressive agenda on the other side to block action, we’ve been able to double fuel efficiency standards on cars.  We’ve been able to take mercury out of our air.  We have been able to reduce carbon emissions in this country and have made not only this a healthier place to live, but have also begun to address in a serious way one of the biggest challenges of our time, and that is the challenge of climate change.  That all happened because of you.  (Applause.) 
    +
    +  
    +
    + But here is the thing:  We’ve got a lot more work to do.  That’s why I ran for a second term.  The plane is nice -- (laughter) -- but the truth is, is that being in the bubble drives me crazy.  So if I didn't think I was actually going to get something done, I wouldn’t have run.  
    +
    +  
    +
    + Nancy has gorgeous grandchildren.  And if it weren’t for the fact that we have more work to do, I’m sure that she wouldn’t be going after the speakership again.  The reason we do so, and the reason you’re here, is because we know we can do so much more to make this country what it can be.
    +
    +  
    +
    + Now, over the next couple of months, we’ve got a couple of issues:  gun control.  (Applause.)  I just came from Denver, where the issue of gun violence is something that has haunted families for way too long, and it is possible for us to create common-sense gun safety measures that respect the traditions of gun ownership in this country and hunters and sportsmen, but also make sure that we don’t have another 20 children in a classroom gunned down by a semiautomatic weapon -- by a fully automatic weapon in that case, sadly.  
    +
    +  
    +
    + Immigration reform is something that I believe that we can get done over the next couple of months.  It’s interesting how clarifying to the mind Democrats getting 70 percent of the Latino vote was in suggesting that maybe we needed to get -- finally fix a broken immigration system, and making sure that we’re both a nation of laws and a nation of immigrants.  
    +
    +  
    +
    + But even if we’re able to get those two things done -- and I’m hopeful that we do over the next couple of months -- we’re going to have some big challenges.  We still have to rebuild this country.  We’ve got about $2 trillion worth of deferred maintenance.  We could be putting back to work Americans all across this country not just rebuilding roads and bridges, but building state-of-the-art schools and a smart grid that would make sure that we’re wasting less energy, and link cities that are using energy with wind farms in the Dakotas and in the plains of Colorado.  
    +
    +  
    +
    + We’ve got still more work to do to make college more affordable.  We’re going to have a lot more work to do to make sure that hard work pays off, which is why passing a minimum wage increase is so important -- because there are a lot of families out there, even who have jobs, who are having a tough time each and every day.
    +
    +  
    +
    + And something that I know is near and dear to Tom and Kat’s hearts, and to Nancy’s -- we’ve got more work to do in terms of dealing with climate change and making sure that we’ve got an economy that is energy-efficient, that is productive, that is cutting-edge, and thinks about not just the energy sources of the past, but also the energy promise of the future.  
    +
    +  
    +
    + And the thing that I’m going to have to try to work to persuade the American people a little more convincingly on is this notion that there’s a contradiction between our economy and our environment is just a false choice -- that if we invest now, we will create jobs, we will create entire new industries; other countries will be looking to catch up, they will be looking to import what we do.  We will set the standard, and everybody else will have to adapt.  
    +
    +  
    +
    + But -- and I mentioned this to Tom and Kat and a few folks right before I came out here -- the politics of this are tough. Because if you haven’t seen a raise in a decade; if your house is still $25,000, $30,000 underwater; if you’re just happy that you’ve still got that factor job that is powered by cheap energy; if every time you go to fill up your old car because you can’t afford to buy a new one, and you certainly can’t afford to buy a Prius, you’re spending 40 bucks that you don’t have, which means that you may not be able to save for retirement -- you may be concerned about the temperature of the planet, but it’s probably not rising to your number-one concern.  And if people think, well, that’s shortsighted, that’s what happens when you’re struggling to get by.  You’re thinking about what’s right in front of you, which is how do I fill up my gas tank and how do I feed my family.
    +
    +  
    +
    + And so part of what we’re going to have to do is to marry a genuine, passionate concern about middle-class families and everybody who is trying to get into the middle class to show them that we’re working just as hard for them as we are for our environmental agenda, and that we can bridge these things in a way that advances the causes of both.  And that’s going to take some work. 
    +
    +  
    +
    + But the most important thing that it’s going to take is people in Washington who are willing to speak truth to power, are willing to take some risks politically, are willing to get a little bit out ahead of the curve -- not two miles ahead of the curve, but just a little bit ahead of it.  And that’s why your presence here is so important.  
    +
    +  
    +
    + Look, my intention here is to try to get as much done with the Republican Party over the next two years as I can, because we can’t have perpetual campaigns.  And so I mean what I say.  I am looking to find areas of common ground with Republicans every single day.  I want to make sure that we’re working together to stabilize our finances.  And I think actually that we can come up with a fiscal deal that instead of lurching from crisis to crisis every three months, we lay the groundwork for long-term growth -- controlling our deficits, controlling our debt, but also making sure we can invest in our future.  I want to get an immigration deal done.  I want to find some common-sense gun safety legislation that we can get done.  And I do believe that there are well-meaning Republicans out there who care about their kids just as passionately as we do.  
    +
    +  
    +
    + Despite all the rhetoric on television, I actually believe that Americans have a lot more in common than our political rhetoric would give us credit for.  But having said all that, I know Nancy Pelosi.  I’ve seen her courage.  I know that she is willing to do the right thing, even when it’s not politically popular.  And I want her once again as a fully empowered partner for us to be able to move our agenda forward.  
    +
    +  
    +
    + And so I’m going to expect that you guys are fighting for issues, helping to move public opinion; engaging in organizing and engaging in advocacy and public policy work -- all the stuff that -- and I’m looking around this room, it’s full of do-gooders here -- all the stuff you do.  But I also want to make sure that you are paying attention to what can we do to support the prospect of Nancy Pelosi being Speaker once again.  
    +
    +  
    +
    + If we do that, then I’m confident that not only can we deliver on this profound issue of climate change, not only can we make sure that clean energy is the norm here in America, but I also think that we can give America that sense of confidence and forward movement that’s always been our hallmark that characterizes who we are.  To do that, I’m going to need you and Nancy is going to need you. 
    +
    +  
    +
    + And so I hope that this is not the end of your involvement.  I hope it is the beginning.  If, in fact, all the energy that’s represented in this room is fully deployed, then I feel pretty good about Malia and Sasha, I feel pretty good about these young people right here.  They’re smarter than we are.  If we hand off the kind of America that we should be handing off to them, I promise you they will take it to ever greater heights.  
    +
    +  
    +
    + All right, thank you very much, everybody.  God bless you.  God bless America.  (Applause.) 
    +
    +  
    +
    + END
    +
    + 7:12 P.M. PDT
    +]]>
    + The President + Speeches and Remarks + Speeches and Remarks + Office of the Press Secretary + The President + Thu, 04 Apr 2013 04:50:00 +0000 + The White House + 207071 at http://www.whitehouse.gov +
    + + Remarks by the President on Reducing Gun Violence -- Denver, Colorado + http://www.whitehouse.gov/the-press-office/2013/04/03/remarks-president-reducing-gun-violence-denver-colorado + Denver Police Academy
    + Denver, Colorado

    +

    3:19 P.M. MDT

    +

    THE PRESIDENT:  Thank you!  (Applause.)  Thank you so much.  Everybody, please have a seat.  Thank you.  Well, it is wonderful to be back in Colorado.  It is wonderful to be back in Denver.  I want to thank Chief White for that introduction.  You’ve got some outstanding elected officials who are here today, and I want to acknowledge them.  First of all, a wonderful governor -- John Hickenlooper is here.  (Applause.)  He’s here somewhere.  I know, because I just talked to him.  There he is.  Next to him an outstanding lieutenant governor, Joe Garcia.  (Applause.)  One of the finest young senators in the country -- Michael Bennet is here.  (Applause.)  Terrific members of the House of Representatives -- Ed Perlmutter -- (applause) -- and Dianna Degette.  (Applause.)  And your own mayor, Michael Hancock, is here.  (Applause.) 

    +

    I want to say thank you to the Denver Police for having me here, and more importantly, for the outstanding work that all of you do each and every day to serve your communities and protect your citizens. 

    +

    Before I came out here, I had a chance to sit down with some local law enforcement, Attorney General Holder, and some of the leaders I just mentioned, the wonderful mayor of Aurora who’s here, sportsmen, parents, loved ones of the victims of the shootings in Columbine and Aurora.  And we talked about what we can do to protect more of our citizens from gun violence. 

    +

    And from the beginning of this effort, we’ve wanted law enforcement front and center in shaping this discussion and the reforms that emerge from it -- because law enforcement lives this every day.  Law enforcement are the first to see the terrible consequences of any kind of violence, certainly gun violence -- lives lost, families broken, communities that are changed forever.  They’re very often in the line of fire.  The law enforcement knows what works and what doesn’t, and so we wanted that experience and that advice. 

    +

    And it was also important for us to hear from mayors like Steve Hogan, because he’s been on the front lines having to deal with these issues under incredibly sad circumstances.  And I’ve come to Denver today in particular because Colorado is proving a model of what’s possible.

    +

    It’s now been just over 100 days since the murder of 20 innocent children and six brave educators in Newtown, Connecticut -- an event that shocked this country and I think galvanized parents all across the country to say, we’ve got to do something more to protect our kids.  But consider this:  Over those 100 days or so, more than 100 times as many Americans have fallen victim to gun violence.  More than 2,000 of our fellow citizens, struck down, often because they were just going about their daily round.  They weren’t doing anything special.  Just doing what folks do every day -- shopping, going to school.  Every day that we wait to do something about it, even more of our fellow citizens are stolen from our lives by a bullet from a gun.

    +

    Now, the good news is Colorado has already chosen to do something about it.  (Applause.)  Look, this is a state that has suffered the tragedy of two of the worst mass shootings in our history -- 14 years ago this month in Columbine, and just last year in Aurora.  But this is also a state that treasures its Second Amendment rights -- the state of proud hunters and sportsmen.  And, by the way, the Governor wanted me to remind everybody that there is outstanding elk hunting here in Colorado.  (Laughter.)  There’s a strong tradition of gun ownership that’s handed down from generation to generation, and it’s part of the fabric of people’s lives.  And they treat gun ownership with reverence and respect.

    +

    And so I’m here because I believe there doesn't have to be a conflict in reconciling these realities.  There doesn’t have to be a conflict between protecting our citizens and protecting our Second Amendment rights.  I’ve got stacks of letters in my office from proud gun owners, whether they’re for sport, or protection, or collection, who tell me how deeply they cherish their rights, don’t want them infringed upon, but they still want us to do something to stop the epidemic of gun violence.  And I appreciate every one of those letters.  And I’ve learned from them. 

    +

    And I think that Colorado has shown that practical progress is possible thanks to the leadership of Governor Hickenlooper and some of the state legislators who are here today.  When I was talking to Steve, he mentioned that Aurora is very much a purple city.  It’s got a majority Republican city council; a majority of the state legislators are Democrat.  But they came together understanding that out of this tragedy there had to be something that made sense.  And so we’ve seen enacted tougher background checks that won’t infringe on the rights of responsible gun owners, but will help keep guns out of the hands of dangerous people.  (Applause.)

    +

    Now, in January, just a few weeks after Newtown, I put forward a series of common-sense proposals along the same lines as what’s passed here in Colorado, to reduce gun violence and keep our kids safe.  In my State of the Union address, I urged Congress to give these proposals a vote.  And, by the way, before we even asked for a vote, I had already signed numerous executive orders doing what we could administratively to make sure that guns don't fall into the hands of the wrong people.

    +

    But what I said then is still true:  If we're really going to tackle this problem seriously, then we've got to get Congress to take the next step.  And as soon as next week, they will be voting.  As soon as next week, every senator will get to vote on whether or not we should require background checks for anyone who wants to purchase a gun. 

    +

    Now, some say, well, we already have background checks.  And they're right.  Over the past 20 years, those background checks have kept more than 2 million dangerous people from buying a gun.  But the loopholes that currently exist in the law have allowed way too many criminals and folks who shouldn’t be getting guns -- it has allowed them to avoid background checks entirely.  That makes it harder for law enforcement to do its job.  It's not safe.  It's not smart.  And, by the way, it's not fair to responsible gun owners who are playing by the rules.

    +

    Now, understand, nobody is talking about creating an entirely new system.  We are simply talking about plugging holes, sealing a porous system that isn't working as well as it should.  If you want to buy a gun, whether it's from a licensed dealer or a private seller, you should at least have to pass a background check to show you're not a criminal or someone legally prohibited from buying on.  And that’s just common sense.  (Applause.) 

    +

    During our roundtable discussion with Governor Hickenlooper, who I know was in the midst of this passionate debate about the legislation here in Colorado, and some people said, well, background checks aren't going to stop everybody.  And the Governor was the first one to acknowledge, yes, they won't stop everybody, but as he pointed out, statistically, there are a whole bunch of folks who have been stopped. 

    +

    As a consequence of background checks, law enforcement has been able to stop people who have been convicted of murder from getting a gun, people who are under restraining orders for having committed violent domestic abuse from getting a gun.  In a couple of cases the governor mentioned to me, law enforcement has actually been able to arrest people who came to pick up their gun -- (laughter) -- because they were criminals, wanted.

    +

    So this does work.  And, by the way, if you’re selling a gun, wouldn’t you want to know who you’re selling it to?  Wouldn’t you want to know?  Wouldn’t you want in your conscience to know that the person you’re selling to isn’t going to commit a crime?  (Applause.) 

    +

    So these enhanced background checks won’t stop all gun crimes, but they will certainly help prevent some.  This is common sense.  And, by the way, most gun owners -- more than 80 percent -- agree this makes sense.  More than 70 percent of NRA members agree.  Ninety percent of the American people agree.  So there’s no reason we can’t do this unless politics is getting in the way.  There’s no reason we can’t do this.

    +

    As soon as next week, every senator will get a chance to vote on a proposal to help strengthen school safety and help people struggling with mental health problems get the treatment that they need.

    +

    As soon as next week, every senator will get to vote on whether or not we should crack down on folks who buy guns as part of a scheme to arm criminals.  That would keep more guns off the streets and out of the hands of people who are intent on doing harm.  And it would make life a whole lot easier and safer for the people behind me -- police officers. 

    +

    Every senator will get a say on whether or not we should keep weapons of war and high-capacity ammunition magazines that facilitate mass killings off our streets.  The type of assault rifle used in Aurora, for example, when paired with a high-capacity magazine, has one purpose:  to pump out as many bullets as possible, as fast as possible.  It’s what allowed that gunman to shoot 70 people and kill 12 in a matter of a few minutes.  I don’t believe that weapons designed for theaters of war have a place in movie theaters.  Most Americans agree with that.  (Applause.) 

    +

    Most of these ideas are not controversial.  Right now, 90 percent of Americans -- 90 percent -- support background checks that will keep criminals and people who have been found to be a danger to themselves or others from buying a gun.  More than 80 percent of Republicans agree.  Most gun owners agree.  Think about it:  How often do 90 percent of Americans agree on anything?  (Laughter.)

    +

    And yet, there are already some senators back in Washington floating the idea that they might use obscure procedural stunts to prevent or delay any of these votes on reform.  Think about that.  They’re not just saying they’ll vote “no” on the proposal that most Americans support.  They’re saying they’ll do everything they can to avoid even allowing a vote on a proposal that the overwhelming majority of the American people support.  They’re saying your opinion doesn’t matter. 

    +

    We knew from the beginning that change wouldn’t be easy.  And we knew that there would be powerful voices that would do everything they could to run out the clock, change the subject, ignore the majority of the American people.  We knew they’d try to make any progress collapse under the weight of fear and frustration, or maybe people would just stop paying attention.

    +

    The only way this time will be different is if the American people demand that this time it must be different -- that this time, we must do something to protect our communities and our kids.  (Applause.)  We need parents, we need teachers, we need police officers, we need pastors, we need hunters and sportsmen, Americans of every background to say, we’ve suffered too much pain and care too much about our children to allow this to continue.  We’re not going to just wait for the next Newtown or the next Aurora before we act.  And I genuinely believe that’s what the overwhelming majority of Americans -- I don’t care what party they belong to -- that’s what they want.  They just want to see some progress. 

    +

    It was interesting, during the conversation, a number of people talked about the trust issue.  Part of the reason it's so hard to get this done is because both sides of the debate sometimes don't listen to each other.  The people who take absolute positions on these issues, on both sides, sometimes aren't willing to concede even an inch of ground. 

    +

    And so one of the questions we talked about was, how do you build trust?  How do you rebuild some trust?  And I told the story about two conversations I had.  The first conversation was when Michelle came back from doing some campaigning out in rural Iowa.  And we were sitting at dinner, and she had been to like a big county, a lot of driving out there, a lot of farmland.  And she said, if I was living out in a farm in Iowa, I'd probably want a gun, too.  If somebody just drives up into your driveway and you're not home -- you don't know who these people are and you don't know how long it's going to take for the sheriffs to respond.  I can see why you'd want some guns for protection.  That's one conversation.

    +

    I had another conversation just a couple of months ago with a mom from Chicago -- actually, Evanston, Illinois -- whose son had been killed in a random shooting.  And she said, you know, I hate it when people tell me that my son was shot because he was in the wrong place at the wrong time.  He was in the right place.  He was on his way to school.  He wasn't in the wrong place.  He was exactly where he was supposed to be. 

    +

    Now, both those things are true.  And sometimes we're so divided between rural and urban, and folks whose hunting is part of their lives and folks whose only experience with guns is street crime.  And the two sides just talk past one another.  And more than anything, what I want to just emphasize is there are good people on both sides of this thing, but we have to be able to put ourselves in the other person's shoes.  If you're a hunter, if you're a sportsman -- if you have a gun in your house for protection -- you've got to understand what it feels like for that mom whose son was randomly shot. 

    +

    And if you live in an urban area and you're worried about street crime, you've got to understand what it might be like if you grew out on a ranch and your dad had been taking you hunting all your life.  And we had a couple of sportsmen in our conversation today, and I thought one of them said something very important.  He said, all my experiences with guns have been positive, but I realize that for others, all their experiences about guns have been negative.  Well, that's a start, right?  If we start listening to each other, then we should be able to get something done that's constructive.  We should be able to get that done.  (Applause.) 

    +

    One last thing I’m going to mention is that during this conversation -- I hope you don't mind me quoting you, Joe.  Joe Garcia, I thought, also made an important point, and that is that the opponents of some of these common-sense laws have ginned up fears among responsible gun owners that have nothing to do with what’s being proposed and nothing to do with the facts, but feeds into this suspicion about government. 

    +

    You hear some of these quotes:  “I need a gun to protect myself from the government.”  “We can't do background checks because the government is going to come take my guns away.” 

    +

    Well, the government is us.  These officials are elected by you.  (Applause.)  They are elected by you.  I am elected by you.  I am constrained, as they are constrained, by a system that our Founders put in place.  It’s a government of and by and for the people.

    +

    And so, surely, we can have a debate that's not based on the notion somehow that your elected representatives are trying to do something to you other than potentially prevent another group of families from grieving the way the families of Aurora or Newtown or Columbine have grieved.  We’ve got to get past some of the rhetoric that gets perpetuated that breaks down trust and is so over the top that it just shuts down all discussion.  And it’s important for all of us when we hear that kind of talk to say, hold on a second.  If there are any folks who are out there right now who are gun owners, and you’ve been hearing that somehow somebody is taking away your guns, get the facts.  We’re not proposing a gun registration system, we’re proposing background checks for criminals.  (Applause.)

    +

    Don't just listen to what some advocates or folks who have an interest in this thing are saying.  Look at the actual legislation.  That's what happened here in Colorado.  And hopefully, if we know the facts and we’re listening to each other, then we can actually move forward. 

    +

    And that’s what members of Congress need to hear from you.  Right now, members of Congress are at home in their districts.  Many of them are holding events where they can hear from their constituents.  So I'm asking anyone out there who is listening today, find out where your member of Congress stands on these issues.  If they're not part of the 90 percent of Americans who agree on background checks, then ask them why not.  Why wouldn’t you want to make it more difficult for a dangerous criminal to get his or her hands on a gun?  Why wouldn’t you want to close the loophole that allows too many criminals to buy a gun without even the simplest of background checks?  Why on Earth wouldn’t you want to make it easier rather than harder for law enforcement to do their job?

    +

    I know that some of the officers here today know what it's like to look into the eyes of a parent or a grandparent, a brother or a sister, or a spouse who has just lost a loved one to an act of violence.  Some of those families, by the way, are here today.  And as police officers, you know as well as anybody, there is no magic solution to prevent every bad thing from happening in the world.  You still suit up, you put on your badge, put yourself at risk every single day.  Every single day, you go to work and you try to do the best you can to protect the people you're sworn to protect and serve.  Well, how can the rest of us as citizens do anything less?

    +

    If there is just one step we can take to prevent more Americans from knowing the pain that some of the families who are here have known, don’t we have an obligation to try?  Don’t we have an obligation to try?  (Applause.)  If these reforms keep one person from murdering dozens of innocent children or worshippers or moviegoers in a span of minutes, isn't it worth fighting for?  (Applause.)  I believe it is.  That’s why I'm going to keep on working.  I'm going to keep on giving it my best efforts.  But I'm going to need your help. 

    +

    This is not easy.  And I'll be blunt -- a lot of members of Congress, this is tough for them.  Because those who are opposed to any form of legislation affecting guns, they're very well-organized and they're very well-financed.  But it can be done if enough voices are heard.

    +

    So I want to thank all the police officers who are here for giving their best efforts every single day.  (Applause.)  I want to thank Governor Hickenlooper for his outstanding leadership.  (Applause.)  I want to thank all the families who are here for your courage in being willing to take out of this tragedy something positive.  I want to thank the people of Colorado for coming together in sensible ways.  (Applause.)  Let's see if we can get the whole country to do so.

    +

    Thank you, Denver.  God bless you.  And God bless the United States of America.  (Applause.)

    +

                                      END                3:45 P.M. MDT

    +]]>
    + The President + Speeches and Remarks + Speeches and Remarks + Office of the Press Secretary + The President + Wed, 03 Apr 2013 23:00:30 +0000 + The White House + 207011 at http://www.whitehouse.gov +
    + + Press Gaggle by Press Secretary Jay Carney Aboard Air Force One en route Denver, Colorado, 4/3/2013 + http://www.whitehouse.gov/the-press-office/2013/04/03/press-gaggle-press-secretary-jay-carney-aboard-air-force-one-en-route-de +  

    +
    + Aboard Air Force One
    +
    + En Route Denver, Colorado
    +
    +  
    +
    +  
    +
    + 2:14 P.M. EDT
    +
    +  
    +
    + MR. CARNEY:  Thanks for joining us today on our flight to Denver, where, as you know, the President will be meeting with law enforcement officials and others at the Denver Police Academy where he will discuss the need for Congress to act on common-sense measures to reduce the scourge of gun violence in America.  
    +
    +  
    +
    + I think you can expect that he will note that the legislation he supports that has been moving through Congress represents real, sensible, middle-of-the-road attempts to address this problem; that nothing he supports would in any way violate the Second Amendment rights of the American people, the Second Amendment rights that the President strongly supports.
    +
    +  
    +
    + One provision that he supports -- the effort to close loopholes in our background check system -- is supported by over 90 percent of the American people, by vast majorities of Republicans and Democrats and independents, by a substantial majority of gun owners, and a substantial majority of members of the NRA.  
    +
    +  
    +
    + He has made clear in his effort, his concerted effort, to move forward with these measures since the Newtown tragedy; that it is imperative the elected officials of the American people allow all of these measures to come to a vote -- and, in his view, to vote for them -- but at the very least, to allow them to come to a vote.  Because if you disagree with 90 percent of the American people on background checks, you ought to vote no, and not oppose -- not use parliamentary maneuvers to prevent a vote.  That’s the President’s view.  
    +
    +  
    +
    + In any case, he looks forward to this event.  As you know, he will be going to Connecticut on Monday to continue this conversation.  
    +
    +  
    +
    + Q    When the President insists on these votes, particularly on assault weapons and the high-capacity magazines, is it because he thinks that there is a price to pay for voting no?  And isn’t there just as well a price to pay by some members of Congress, some Democrats, for voting yes on those issues?
    +
    +  
    +
    + MR. CARNEY:  Jim, there are definitely political issues involved in this.  This has always been the case.  But the President doesn’t look at this through a political lens.  He’s not asking for a vote for political reasons, he’s asking for a vote because the victims of Newtown and of Aurora and Virginia Tech, and the countless lesser-known victims of gun violence across America deserve at least a vote.  And the kids who were killed -- the 20 children who were killed in Newtown, they weren’t Republicans or Democrats; they didn’t care, and their parents don’t care about the political implications of voting yes or no on these bills.  They want things done that give other children more protection from this kind of violence, and that includes every measure that the President supports. 
    +
    +  
    +
    + Q    Any reaction to reports that current and former cops think that today’s Denver venue is not the right place to have a speech?
    +
    +  
    +
    + MR. CARNEY:  Well, look, obviously people have a variety of views on these issues across America.  I think it’s irrefutable that a majority of law enforcement professionals in America support common-sense measures that are at issue now and subject to votes in Congress.  I don't think anybody would argue with that.
    +
    +  
    +
    + I think most law enforcement officials agree that closing loopholes in our background check system assists them in their job to protect the American people from gun violence.  If you're opposed to taking measures to prevent criminals from getting weapons, vote no and explain why.  Most police officers, law enforcement officers support the idea that we ought to take measures to ensure that the system that already exists is actually effective so that those who by law should not have weapons cannot obtain them.  It’s a pretty simple proposition.
    +
    +  
    +
    + Q    How do you fight the perception, though, that these measures are losing steam in Congress? 
    +
    +  
    +
    + MR. CARNEY:  I think perceptions are one thing, reality is another.  And the fact is we are moving forward with Congress and are in regular conversation with members and staff from both parties about how to move forward.  And the President is committed to pressing this agenda because it’s the right thing to do for our children and all the potential victims of gun violence in the country. 
    +
    +  
    +
    + I think that as I said the other day and the President has made clear, he never believed and we never suggested that any of this would be easy.  There’s a reason why these kinds of actions have not succeeded for many years now.  There are a variety of reasons why.  But it is incumbent upon every elected official sent to Washington to address this challenge, this scourge, and to -- he believes -- do the common-sense things that can help save the lives of our children in the future.
    +
    +  
    +
    + Q    But there’s a difference, isn’t there, between saying this isn’t going to be easy and counting votes.  And the votes for a lot of these things aren’t there.
    +
    +  
    +
    + MR. CARNEY:  Well, again, the votes haven’t happened, first of all.  Secondly, if the votes were there, Jeff, they would have been voted and done and signed into law a long time ago.  That's why a process like this exists.  That’s why negotiations are ongoing on a variety of pieces of this proposal in an effort to try to find the votes necessary.  And, unfortunately, it is, as we've said many times, a feature of our system now that everything in the Senate is subject to a filibuster.  And what the President has said I think very clearly is that it would be shameful to not allow any one of these measures to come up to a vote.  
    +
    +  
    +
    + Q    You talked about parliamentary procedures.  Would you consider a filibuster an illegitimate procedure?  I mean, it is part of the rules.
    +
    +  
    +
    + MR. CARNEY:  I didn’t say it wasn't part of the rules.  I said that the victims of Newtown -- the 20 kids and the 6 educators who lost their lives -- deserve a vote.  And that if you want to vote no, vote no.  Don’t block a vote.  That’s not doing service to the memory of these kids.  
    +
    +  
    +
    + Q    You said that -- you have emphasized that the President doesn’t mean to impinge on anyone's Second Amendment rights, but there are a lot of people out there who believe that he does.  And if I'm not mistaken, Saturday is the five-year anniversary of his speech in San Francisco where he talked about small-town Americans clinging to guns and religion.  What about the optics of going there right after this event in Denver to call attention to his views on guns?
    +
    +  
    +
    + MR. CARNEY:  As you know, and as everyone who is an expert on this issue can attest, there is not a single thing that the President has proposed that would take a single firearm away from a single law-abiding citizen in America.  This President supports our Second Amendment rights.  The proposals he put forward -- like banning military-style assault weapons, like limiting high-capacity ammunition clips -- these are proposals that in no way infringe upon Second Amendment rights, and, again, would not take any firearm away from any law enforcement -- law-abiding citizen.
    +
    +  
    +
    + When it comes to straw purchases -- I mean, again, this is about enforcing the law.  If you have individuals who are routinely buying weapons as straw purchasers on behalf of criminals who cannot buy weapons themselves because of their criminal record, that’s a violation of the law, and we ought to take action to ensure that the law is enforced.  That seems like a very common-sense, conservative principle to me, as does the idea that the background check system that already exists should be improved so that loopholes are closed that make sure that it does what it was intended to do, and that is ensure that those with criminal records and others who by law should not be allowed to, or are not allowed to purchase weapons cannot circumvent the law because of the loopholes in the system.
    +
    +  
    +
    + Q    Does the President see Colorado as a model for other states after the legislation that they passed here?
    +
    +  
    +
    + MR. CARNEY:  The President believes that actions in Colorado, the actions underway in Connecticut do represent important progress on these issues, and I think are useful models to look at as we undertake efforts in Washington.
    +
    +  
    +
    + Q    Do you know which lawmakers are going to be at the event?
    +
    +  
    +
    + MR. CARNEY:  I don’t.  I can try -- if I can find out, I’ll get that for you.
    +
    +  
    +
    + Q    There’s a report that Senator Bennet would be there, but the other senator wouldn’t.
    +
    +  
    +
    + MR. CARNEY:  Again, I don’t know.  I’ll have to find out, or we may find out when we get there.
    +
    +  
    +
    + Q    On a different subject.  The President and Mrs. Obama are going to Dallas for the Bush Library opening.  Can you tell me how that decision came about, how excited he is about going to Dallas to do this?  What will be on his mind?
    +
    +  
    +
    + MR. CARNEY:  He’s very pleased to be going, and looks forward to it.  The office of the President of the United States is a pretty rare position to hold, and only those who have held it can fully appreciate what it means to be President of the United States.  And he shares in common with President George W. Bush a love, a deep love for his country, and appreciates President Bush’s service, and looks forward to being there with him as well as President George H. W. Bush and Presidents Clinton and Carter.
    +
    +  
    +
    + Q    Jay, on Keystone pipeline.  One of his hosts today at the fundraiser in San Francisco is an active opponent of the Keystone pipeline -- Tom Steyer.  There are also going to be protests planned outside the Getty mansion tonight.  I guess I’ll try a third time on the Arkansas spill:  Have you had a chance to talk to the President about that spill?  And how does it affect -- how does the Utah spill affect his thinking on the Keystone pipeline, and what would he tell his hosts today if that issue comes up?
    +
    +  
    +
    + MR. CARNEY:  Well, I’m not going to preview hypothetical answers to hypothetical questions.  What I will say is that there are procedures in place --
    +
    +  
    +
    + Q    The answers wouldn’t be hypothetical, the questions would be.  The answers would be answers to the hypothetical.
    +
    +  
    +
    + MR. CARNEY:  Well, I think the whole thing would be hypothetical, Hans, but thank you for your --
    +
    +  
    +
    + Q    I’m just clarifying.
    +
    +  
    +
    + MR. CARNEY:  I think you’re muddying, actually, but thanks.
    +
    +  
    +
    + Q    No, you hide behind this hypothetical thing all the time.
    +
    +  
    +
    + MR. CARNEY:  He asked me, if he’s asked, what would he say?
    +
    +  
    +
    + Q    Right, but what he’d say would be his answer.  The “if” is the hypothetical.
    +
    +  
    +
    + MR. CARNEY:  Well, first of all, the question hasn’t been asked.  He’s not here to give the answer to the hypothetical.
    +
    +  
    +
    + Q    -- to the question is the hypothetical.
    +
    +  
    +
    + MR. CARNEY:  Thank you for your assistance in the briefing, Hans.  As you know, when an incident like what has happened in Arkansas occurs, there are procedures in place.  The EPA takes the lead; the responsible party is held responsible, as is the case in this situation.  When it comes to Keystone, that is a process, as we’ve discussed many times, that is evaluated at the State Department, as has been the case for many, many years under multiple presidencies, and as is appropriate given the fact that it is a pipeline that crosses international borders.  And that process is underway, as you know.
    +
    +  
    +
    + Q    But do incidents such as Arkansas, such as the spill in Utah, inform the decision-making?
    +
    +  
    +
    + MR. CARNEY:  Again, the evaluation of these proposals is made at the State Department.  You can certainly ask the State Department about whether any incidents, present or past, what those incidents have in terms of an impact on their evaluation process.  I think there are standards that are followed in this evaluation process that are being followed today at the State Department, but the State Department is the location where this process takes place.
    +
    +  
    +
    + Q    Is the decision of the administration at all influenced by people like Mr. Steyer, who is hosting the President today?  Is it at all influenced by the protest and demonstrators that the President sees?
    +
    +  
    +
    + MR. CARNEY:  Look, I think we’ve seen over time that there are strongly held views on this issue, on both sides.  And the President is following a process that has been in place for quite some time, through multiple administrations of both parties, and that is the way it should be.  As you know, the process was delayed because of a political action by Congress, but the -- nevertheless, the process is underway and being undertaken by the State Department.
    +
    +  
    +
    + Q    Are there any updates, Jay, on North Korea and monitoring of the North Korea situation?
    +
    +  
    +
    + MR. CARNEY:  Well, we continue to monitor the situation.  The provocative actions and bellicose rhetoric that we see from North Korea is obviously of concern, and we take -- are taking the necessary precautionary measures, many of which have been reported on.  It is also the case that the behavior of the regime in Pyongyang that we are seeing now has a -- represents a familiar pattern, and as I think we’ve seen over the past several administrations.  
    +
    +  
    +
    + So we are taking the necessary precautionary measures, but it is important to view this within the context of the kind of behavior that we’ve seen out of North Korea in the past.  And it’s important to say that, in every instance, this refusal to abide by its international obligations and to engage in threats and provocative rhetoric and behavior only serves to isolate North Korea further, to make it more and more difficult for the North Korean economy to develop, and imposes more and more hardships on the North Korean people.  
    +
    +  
    +
    + North Korea knows the path that's available to it -- the regime does -- and that is a path towards greater integration in the international community, stronger economic development, and better prospects for the North Korean people if they take substantive steps towards denuclearization and abide by the series of international obligations that they are currently flouting.
    +
    +  
    +
    + Q    Jay, I don’t know if you were asked this in the past few days.  But on immigration, Senator Leahy is saying he is calling for, once a bill is introduced by the Gang of Eight, that he wants to accelerate the process, to mark it up, and then advance it to the Senate floor.  Marco Rubio is calling for regular order -- wants hearings, wants more hearings.  He says we need to make sure that we really understand this bill.  What is the administration's view?  Do you believe that, like Senator Leahy, you have to move as fast as possible on this thing, because otherwise it could just die in the Senate because of it just being drawn out, and that we shouldn't go through regular order just because we've already had enough hearings over the past several years?
    +
    +  
    +
    + MR. CARNEY:  I think the characterization of regular order here has to be understood within the context of the fact that this legislation in essence has been on the table and subject to debate in the United States Congress for many years now.  The basic outlines of what has been under consideration and is being worked on by the Gang of Eight and has been proposed by the President reflects legislation that was considered in Congress, in 2006, 2007, I believe.  
    +
    +  
    +
    + Senator Leahy, as I understand it -- and I would refer you to him and his statements -- has held multiple hearings on this issue.  And the Gang of Eight and all of its members are the ones writing the legislation, which the President obviously believes is a good thing.  And the progress that they have made thus far is also a good thing.  
    +
    +  
    +
    + So I leave it to and we leave it to the Chairman and other leaders in the Senate to decide on the process they want to follow.  But the President has made clear that he believes there is no reason to delay this process.  There is no reason to postpone it.  And he has been encouraged by the progress thus far, and hopes and expects that that progress will continue, and that it will result in the production of a bill and the consideration of the bill and a vote on the bill.
    +
    +  
    +
    + Q    Now Rubio and other Republicans are saying, wait a minute, why rush it -- if it's good legislation, doesn't it deserve the test of scrutiny, of talking -- it is a new Congress.  The country has changed in the past six years; don't we want to talk it over and look at it more, possibly offer other amendments, make it better.  Do you fear that it would just get killed if it's going to be dragged out?  Is that the problem?  Or is it that people are being deported and you need to get this on the books and end the deportations that the administration is carrying out?
    +
    +  
    +
    + MR. CARNEY:  Again, as veterans of the Senate know, this issue has been under consideration at very serious levels periodically for a long time now.  There is a great need to act on comprehensive immigration reform and a great opportunity to do it now, as the President has made clear.  It has been in the past, and seems to be now, a bipartisan priority.  And that is as it should be, in the President's view.  
    +
    +  
    +
    + And he has been encouraged by and welcomes the progress being made by the bipartisan Group of Eight.  He has contributed to this process through the blueprint that has been available publicly for a long time now that outlines his principles when it comes to comprehensive immigration reform, and again, looks forward to further progress by the Senate, and action -- and consideration of the bill and action on the bill.
    +
    +  
    +
    + Q    Jay, on another -- one last thing.  There’s a new independent report today -- among its leaders are Senator Sam Nunn -- and it says that the U.S. and Russia need to gradually take their nuclear weapons off ready-to-launch status.  I was wondering if you were familiar with that, if the President is familiar with it.  Does he endorse that idea?  
    +
    +  
    +
    + MR. CARNEY:  I am not familiar with it.  I am obviously familiar with the very important work that former Senator Nunn and former Senator Lugar have done on the issues of proliferation and reduction of nuclear arsenals, but I’m not familiar with this report.  
    +
    +  
    +
    + END
    +
    + 2:35 P.M. EDT
    +]]>
    + The President + Press Briefings + Press Briefings + Office of the Press Secretary + The President + Wed, 03 Apr 2013 20:04:00 +0000 + The White House + 207001 at http://www.whitehouse.gov +
    + + First Lady Michelle Obama and Epicurious Host Second Recipe Challenge + http://www.whitehouse.gov/the-press-office/2013/04/03/first-lady-michelle-obama-and-epicurious-host-second-recipe-challenge-0 + FIRST LADY MICHELLE OBAMA AND EPICURIOUS HOST
    + SECOND RECIPE CHALLENGE
    + TO PROMOTE HEALTHY EATING NATIONWIDE

    +

    “The Healthy Lunchtime Challenge” Welcomes Children and Their Parents to Create 
    + Healthy Lunch Recipes for an Invite to a Kids’ “State Dinner” at the White House

    +

     

    +

    New York, NY (April 3, 2013) – With the overwhelming success of the inaugural Healthy Lunchtime Challenge & Kids' “State Dinner” in 2012, First Lady Michelle Obama is again teaming up with Epicurious, the U.S. Department of Education, and the Department of Agriculture to host a nationwide recipe challenge to promote healthy eating among America’s youth.

    +

    “Last year’s Kids State dinner was one of my favorite events we’ve ever done for Let’s Move! because it perfectly captured how young people, parents, community leaders and businesses can come together for innovative, healthy solutions,” said First Lady Michelle Obama.  “Last year’s young chefs impressed and inspired me with their creativity, and I can’t wait to welcome a whole new group to the White House this summer and taste their creations.  So kids, let’s get cooking!”

    +

    The second Healthy Lunchtime Challenge & Kids' “State Dinner” invites parents or guardians and their children, ages 8-12, to create and submit an original lunch recipe that is healthy, affordable, and tasty.  In support of Let’s Move!, launched by the First Lady to solve the issue of childhood obesity, each recipe must adhere to the guidance that supports USDA’s MyPlate (at ChooseMyPlate.gov) to ensure that the criteria of a healthy meal are met.  Entries must represent each of the food groups, either in one dish or as parts of a lunch meal, including fruits, vegetables, whole grains, lean proteins and low-fat dairy foods, with fruits and veggies making up roughly half the plate or recipe.

    +

    All U.S. states and territories, including Washington, D.C., Puerto Rico, Guam, American Samoa, the U.S. Virgin Islands, and the Northern Mariana Islands, are invited to participate. Fifty-six children and their parent/guardian (one pair from each of the 50 states, plus the U.S. Territories, D.C., and Puerto Rico) will be flown to the nation’s capital where they will have the opportunity to attend a Kids’ “State Dinner” at the White House this summer, hosted by Mrs. Obama.  A selection of the winning healthy recipes will be served.  

    +

    “In order to promote a healthier next generation of Americans, we need to encourage kids to make healthier choices now – which they can carry into adulthood,” said Agriculture Secretary Tom Vilsack.  “USDA is thrilled to be part of the Healthy Lunchtime Challenge again this year because it inspires kids to use USDA’s MyPlate to take a hands-on approach to building healthier meal times.”

    +

    “We know healthy kids are healthy students, and healthy students are better able to engage in the classroom and excel academically,” said U.S. Secretary of Education Arne Duncan. “If we can get our children to eat healthier and exercise more, that’s a recipe for success. Kids are the best judges of what looks and tastes good, so we’re challenging them to create lunches that all their peers will enjoy.”

    +

    “We are thrilled to once again partner with Mrs. Obama, and to champion her Let’s Move! initiative, in an effort to raise awareness for the importance of healthy eating among kids,” said Tanya Steel, editor-in-chief of Epicurious.  "Through ‘The Healthy Lunchtime Challenge,’ we will, for the second year, create a call to action for kids, highlighting the importance of healthy meals. This initiative will continue to make a positive impact on the way our children eat, and will reinforce that meals, especially school lunches, can be delicious and nutritious.”

    +

    The winning recipes will be chosen by a panel of judges, including Tanya Steel, Let’s Move! Executive Director Sam Kass, USDA and U.S. Department of Education representatives, as well as a celebrity chef, to be named.  At the conclusion of the Challenge, a free, downloadable and printable e-cookbook featuring the winning recipes, nutritional analysis, photos and drawings, will be available via LetsMove.gov, USDA.gov, Ed.gov and recipechallenge.epicurious.com.

    +

    The White House Kids’ “State Dinner” is currently scheduled to take place in July or August 2013.

    +

    Recipes can be submitted April 3 through May 12, online at recipechallenge.epicurious.com, or via mail at “The Healthy Lunchtime Challenge c/o Epicurious.com,” 1166 Avenue of the Americas, 15th Floor, New York, NY 10036. Winners will be notified at the end of June. For more information and contest rules visit recipechallenge.epicurious.com.

    +]]>
    + The First Lady + Statements and Releases + Statements and Releases + Office of the First Lady + The First Lady + Wed, 03 Apr 2013 13:21:00 +0000 + The White House + 206856 at http://www.whitehouse.gov +
    + + Upcoming Guidance on “in Performance at the White House: Memphis Soul” + http://www.whitehouse.gov/the-press-office/2013/04/02/upcoming-guidance-performance-white-house-memphis-soul + Event includes Evening Performances and Daytime Student Workshop
    + Honoring Memphis Soul Sound

    +

    Tuesday, April 9 * White House – As part of their “In Performance at the White House” series, the President and First Lady will invite music legends and contemporary major artists to the White House for a celebration of Memphis Soul music. The program will include performances by Alabama Shakes, William Bell, Steve Cropper, Al Green, Ben Harper, Queen Latifah, Cyndi Lauper, Joshua Ledet, Sam Moore, Charlie Musselwhite, Mavis Staples and Justin Timberlake, with Booker T. Jones as music director and band leader. The President’s remarks will be pooled press and the entire event will be streamed live on  www.whitehouse.gov/live starting at 6:55 PM ET.  “In Performance at the White House: Memphis Soul” will be broadcast Tuesday, April 16 at 8 PM ET on PBS stations nationwide (check local listings).  The program will also be broadcast at a later date via the American Forces Network to American service men and women and civilians at U.S. Department of Defense locations around the world.

    +

    As she has done with previous White House music events, the First Lady will host a special daytime event for students. The First Lady will welcome 120 middle and high school students from across the country to take part in an interactive student workshop event: “Soulsville, USA: The History of Memphis Soul.” Beginning at 11:00 AM in the State Dining Room, Robert Santelli, Executive Director of The GRAMMY Museum in Los Angeles, will lead the students in an overview of the origins of Memphis Soul, discuss important artists from throughout its history, and explore the elements of soul and gospel that helped contribute to the genre’s unique sound.   Featured performers from the evening event will share their experiences as well as answer student questions about the music and entertainment world.  Students from 16 schools and organizations from the following ten communities will participate: Herndon, Virginia; Los Angeles and Oakland, California; Memphis, Tennessee; New York, New York; Sandy Spring, Maryland; Seminole, Tampa; Tarpon Springs, Florida; and Washington, D.C.

    +

    The workshop, “Soulsville, USA: The History of Memphis Soul,” will stream live on www.whitehouse.gov/live. This event will be open press, but space is limited. Members of the media who wish to cover this event must RSVP to firstladypress@who.eop.gov by Friday, April 5, 2013 at 12:00 PM ET. Press who do not have a White House hard pass must include their social security number, date of birth, country of citizenship, current city/state of residence and gender.

    +

    “In Performance at the White House: Memphis Soul” will be the tenth “In Performance at the White House” program hosted by the President and Mrs. Obama.  Starting in February 2009, these events have honored the musical genius of Stevie Wonder, Sir Paul McCartney, Burt Bacharach and Hal David; celebrated Hispanic musical heritage during Hispanic Heritage Month; marked Black History Month with events featuring music from the Civil Rights Movement, Motown and the Blues; spotlighted Broadway and the unique spirit of the American musical; and explored the rich roots and resiliency of Country Music.

    +]]>
    + The First Lady + Statements and Releases + Statements and Releases + Office of the First Lady + The First Lady + Tue, 02 Apr 2013 22:18:00 +0000 + The White House + 206871 at http://www.whitehouse.gov +
    + + Press Briefing by Press Secretary Jay Carney, 4/2/2013 + http://www.whitehouse.gov/the-press-office/2013/04/02/press-briefing-press-secretary-jay-carney-422013 +  

    +
    + James S. Brady Press Briefing Room
    +
    +  
    +
    +  
    +
    + 12:50 P.M. EDT
    +
    +  
    +
    + MR. CARNEY:  Good afternoon.  Thank you all for being here.  Before I start, I have two very important announcements to make.  The first, contradicting the April Fool’s joke that Jon-Christopher made yesterday, the Red Sox walloped the Yankees on opening day -- that’s important to note -- 8-2.  And second, the Nationals blanked the Marlins 2-0 with two homeruns by Bryce Harper in his first two at bats.  Excellent opening day.  
    +
    +  
    +
    + Second announcement is Monday travel.  You probably have seen, but I want to reiterate that on Monday, April 8th, President Obama will travel to the University of Hartford, where he will continue asking the American people to join him in calling on Congress to pass common-sense legislation to reduce gun violence.  Additional details on the President’s event at the University of Hartford will be forthcoming.
    +
    +  
    +
    + With that, I will take your questions.  Jim.
    +
    +  
    +
    + Q    Thanks, Jay.  I wanted to start with North Korea.  Yesterday you said that the U.S. has seen no large-scale mobilizations or reposition of forces in North Korea.  Today, Pyongyang said it will restart its plutonium reactor and increase production of nuclear weapons material.  And I wondered if -- does that give the President some pause?  And are you reconsidering the view that this is a familiar pattern or simply belligerent rhetoric?   
    +
    +  
    +
    + MR. CARNEY:  I appreciate the question.  The fact is that North Korea’s announcement that it will reopen or restart its nuclear facilities at Yongbyon is another indication of its pattern of contradicting its own commitments and its pattern of violating its international obligations.  As you know, that facility has been dormant, as part of an agreement which North Korea, at least with this announcement, seems to be willing to violate.
    +
    +  
    +
    + And there is a path open to North Korea to achieve the security, international respect, and economic development that it seeks.  But this is surely not the path.  And as I said yesterday, it is our position and the position of a broad international alliance, if you will, that North Korea must abandon its pursuit of nuclear weapons and abide by all of its international commitments.
    +
    +  
    +
    + We seek the complete, verifiable, and irreversible denuclearization through authentic and credible negotiations.  The U.S. and our international partners have a shared goal of ensuring the denuclearization of the Korean Peninsula and a strong, common interest in peace and stability in Southeast Asia.  
    +
    +  
    +
    + As I said yesterday, we are working very closely with our allies in the region.  We are taking appropriate measures in response to the bellicose rhetoric and provocative actions out of North Korea.  But it is -- these actions and this rhetoric is in keeping with a pattern of behavior by the regime in Pyongyang.
    +
    +  
    +
    + Q    Jay, at the U.N. today, Ban Ki-moon seemed a little more alarmed, saying the current crisis has gone too far.  He said North Korea is “on a collision course with the international community” and that international negotiations are urgently needed.  Does the President agree?
    +
    +  
    +
    + MR. CARNEY:  The President has expressed his concern about the actions and behavior of the regime in North Korea.  And we have worked with our allies, most recognizably at the United Nations Security Council, when a resolution was passed unanimously, with China and Russia, condemning North Korean behavior in this arena.  And we will continue to do that.  And the steps we take, together with our partners, put more pressure on North Korea, further isolate North Korea; make it clear to the regime there that there is no benefit to the North Korean people to the path that they are taking.
    +
    +  
    +
    + Meanwhile, we obviously take the steps necessary to ensure the capacity to assist our allies and defend the United States.
    +
    +  
    +
    + Q    On the trip to Hartford, coming after the trip to Denver tomorrow, is this a recognition by the President that he faces some real obstacles in Congress on anti-gun legislation or gun violence legislation -- even on the background checks that seemed to have some movement before?
    +
    +  
    +
    + MR. CARNEY:  The President has always said, we have always said that this would be hard.  If that weren’t the case, it would have been done before.  If it were simple to pass measures through Congress that are very common sense but would reduce gun violence in America, those measures would have passed already.  And the President has always recognized that this is something that would be a challenge, but that in the wake of the horrific shootings at Newtown, was an obligation of all of us to work on and to try to get done.  
    +
    +  
    +
    + We remain engaged in conversations with the Senate and those senators who are interested in forging a bipartisan compromise on measures to reduce gun violence.  I noted, and the President has noted, that when it comes to background checks -- the measure you mentioned -- this is something that's supported by over 90 percent of the American people.  When you ask an average American whether or not it makes sense to have -- to require a background check if you're going to purchase a weapon, overwhelmingly, 90 percent-plus, they say of course it makes sense.  And most of them say -- or many of them say they just assume that system already exists.  And that's an important point to make, too, here, is that the system does exist.  
    +
    +  
    +
    + The goal of those, like the President, who are trying to improve the system, is to close loopholes within it that make it imperfect; that allow those who should not obtain weapons to obtain them.  And this is something we're working on very closely with members of both parties.  And that's why the President is going to Denver.  That's why the President is going to Hartford.  That's why the Vice President has held so many events and meetings and conversations.  And you can assume safely that lots of conversations take place between the administration and both staff and lawmakers on Capitol Hill on this issue, and we're going to continue to press forward.  It's very important.  
    +
    +  
    +
    + It's essential to the memory of the victims of Newtown that all of these measures get a vote, that they are not filibustered, and it is essential that action be taken, as the President said so passionately last week.
    +
    +  
    +
    + Q    Jay, back on North Korea.  When you say "working with our allies," what exactly does that mean? 
    +
    +  
    +
    + MR. CARNEY:  Well, we are in close contact -- have been and continue to be -- with our allies in Seoul and Tokyo to coordinate on this issue, and we are regularly reaching out to Beijing and Moscow to encourage them to do more to restrain the North Koreans.  And as I noted moments ago, that we have seen cooperation from all the members of the Security Council, as well as obviously our allies in the region, on this issue, and that is very helpful when it comes to putting the necessary pressure on North Korea.
    +
    +  
    +
    + This is part of a pattern of behavior that we've seen out of North Korea.  North Korea acquired a nuclear weapon and tested it under the previous administration, and we have seen consistent behavior that is counterproductive, to say the least, to a goal that one assumes North Korea's leaders aspire to, which is an improvement of the lot of the North Korean people and an end to the isolation of their country within the international community.  
    +
    +  
    +
    + So the President is being regularly updated on this and briefed on this.  The entire national security team is obviously focused on this, as you would expect.  But I think it's important to note that, as I said yesterday, the rhetoric has not been backed up by action, and there is a pattern here, a pattern that is familiar.
    +
    +  
    +
    + Q    What are the Chinese and Russians not doing that they should be that would be more helpful?
    +
    +  
    +
    + MR. CARNEY:  Well, I think it's not a mystery to anyone that China has influence on North Korea, or potentially has influence on North Korea, and we have in the past, and we are now, urged China to use that influence to try to affect North Korean behavior.  That is also true of our interactions with the Russians.  This is a broad diplomatic effort that includes coordination with our allies in Japan and the Republic of Korea as well as with China and Russia and others.  So we're going to keep up that effort.
    +
    +  
    +
    + Q    And are you sort of waiting for this whole crisis atmosphere to blow over and then engage the North Koreans to try to get them back to the negotiating table?
    +
    +  
    +
    + MR. CARNEY:  Well, I think North Korea understands fully what steps it needs to take to move down the path towards ending its isolation, and those steps have to be concrete towards abiding by its international obligations.  And there's a system in place for that to move forward.  
    +
    +  
    +
    + Meanwhile, during a period like this where we're seeing this kind of pattern of behavior reassert itself, we're consulting with our allies, taking necessary precautions, making clear to the North Koreans what our views are, what the consensus view is of the international community; what steps they need to take to improve their situation within the world.  And that process will continue.
    +
    +  
    +
    + Dan.
    +
    +  
    +
    + Q    Thank you.  Just to follow on Jim's question -- does the President concede that the kind of bipartisan enthusiasm that existed after the Sandy Hook shootings is no longer there?
    +
    +  
    +
    + MR. CARNEY:  Well, I would point you to what the President said last Thursday.  And he took great issue with the suggestion or the implication that a mere 100 days after that terrible event, somehow the country or Washington could move on.  The families that suffered the loss in Newtown will never fully be able to move on.  And those of us across the country who were horrified -- and as I think everyone in the country was -- by what happened in Newtown will never forget that day or the days after.  And it's a reminder constantly of why we need to act. 
    +
    +  
    +
    + As the President said way back in the wake of Newtown, if we can take some common-sense measures that would save one life, one child's life, we ought to do it.  And if we can do more than that through the proposals that he has urged Congress to act on and the initiatives that he has acted on and is acting on administratively -- if we can reduce the amount of gun violence, if we can protect our children better -- then we will have at least partly fulfilled our most fundamental obligation.  
    +
    +  
    +
    + And he believes that that passion, that urgency still exists around the country and still exists -- if not in full, then in part -- in Washington.  And that is why he is continuing to make the case and why he will make the case in Denver and will make the case in Connecticut.  It is why we are engaging with Congress on this very important matter. 
    +
    +  
    +
    + And I would just note that this process continues to move forward.  Negotiations and conversations continue to take place.  And it is essential that Congress act and essential that it take action. 
    +
    +  
    +
    + Q    Would the President, though, be as aggressively pursuing this on the road -- and the Vice President and others in the administration -- if the conversation up on the Hill was in a better place?
    +
    +  
    +
    + MR. CARNEY:  I think that sort of turns on its head the basic point, which is the President in the wake of Newtown made clear that the country needed to act and that he would act.  He immediately called on Congress to take up measures that he supported, in terms of legislation that would help reduce gun violence, common-sense legislation that in no way infringes upon Americans' Second Amendment rights.  He then asked the Vice President to lead an effort to assess what else we could do, what package of initiatives we could act on to address this problem.  And that, within a month, was put forward to the American people, and we have been pressing ever since.  
    +
    +  
    +
    + But from the beginning, as everyone here knows, the proposition itself was a challenging one for all the reasons that we understand about the efforts in the past to address gun violence through common-sense legislation or other means.  This is not easy stuff.  And the President has been clear about that from the beginning.  But that is not an excuse not to do everything you can to make it happen. 
    +
    +  
    +
    + Q    On another subject, former-Secretary of State Clinton will be stepping out to make a public speech this evening.  And I'm wondering if the President is paying any attention to this at all.  And does he continue to get any foreign policy advice from her?
    +
    +  
    +
    + MR. CARNEY:  Well, I have no private conversations to read out to you with Secretary Clinton or anyone else.  But you know how the President feels about Secretary Clinton, about her remarkable service in this administration in his first term.  And I am sure -- I think you're referring to the Vital Voices event, and I'm sure he wishes her well tonight and going forward.
    +
    +  
    +
    + Q    Jay, does the President think he can change votes in Congress by going out into the country and making this appeal on guns?
    +
    +  
    +
    + MR. CARNEY:  Jon, I don't think it's an issue of changing votes.  It's a matter of what we've always said, which is that these are -- all of these issues that we are addressing here in Washington have a direct impact on the lives of average Americans, and they have a stake in what we do here.  And it has never been the President's belief that Americans elect their representatives, send them to Washington, and then disengage from the process.  In fact, it's been the President's belief that Americans remain focused on a care deeply about what happens here, and that they want to be brought into and engaged in the process.  
    +
    +  
    +
    + And that’s why the President has taken the approach on this issue and so many other issues that he has --because he believes that the voices of the American people are a very important part of moving forward on these tough issues, whether it's budget or fiscal issues, or immigration reform, or measures to reduce gun violence.
    +
    +  
    +
    + So I think that it's important -- it's an important part of the process that those of us who are here in Washington working on these issues are constantly reminded of the Americans out there in the country who care about what happens here and hold us accountable, and hold especially their elected leaders accountable for what they do and how they vote, and how they respond to national tragedies like the tragedy that occurred in Newtown, Connecticut.
    +
    +  
    +
    + So that’s part of a process that he's engaged in.  It's not an either/or, as we've always said.  As you know, and we've been very transparent about, he is engaged very deeply in an effort on this issue and others to have constructive conversations with lawmakers of both parties.  That process continues, and that’s reflected even when Congress is out of town with our engagement at the staff level with staffs of both parties on Capitol Hill on this issue and others.  And that will continue.
    +
    +  
    +
    + But at no point in this process does the President believe we should leave the American people out of it.  He will constantly engage them, and constantly make his views known and ask the American people to make their views known, because that's how stuff gets done, important stuff gets done.
    +
    +  
    +
    + Q    And the President obviously said this in the State of the Union, you just said it again -- it's essential that there be a vote on these issues.  What are you demanding and what's the President demanding?  A vote?  Or to get these things passed?
    +
    +  
    +
    + MR. CARNEY:  Well, he clearly -- every element of the package that he put forward he supports 100 percent.  It is a starting point to insist that they all get a vote, the legislative pieces of this.  Because it would be appalling, in his view, if the memories of the victims of Newtown and other places were forgotten through the process of filibustering a vote on measures that the American people expect, whether they agree or disagree, their elected officials in Washington to vote on.  That’s all.
    +
    +  
    +
    + I mean, these are all tough issues.  We've talked about it with every component of the legislative package.  But at the very least, we need votes on these.  Those who are elected and sent to Washington need to cast a vote and say -- explain their position and say where they stand.  The President is out there making an impassioned case for these common-sense measures.  The Vice President is out there doing the same.  A number of members of Congress are doing the same.  Other leaders around the country are engaged in that.  
    +
    +  
    +
    + And we understand, and the President has made clear that he understands that these are -- that there are regional differences on some of these issues and there are things that we need to engage in and recognize and make part of the discussion.  And the Vice President's process did that.  Conversations the President has had with lawmakers who have an interest in taking common-sense measures but who also historically had strong backing when it comes to their support for the Second Amendment -- the President understands all of this, and he understands it's all part of the process.  But he insists that we act.
    +
    +  
    +
    + Yes.  Welcome to the front row.
    +
    +  
    +
    + Q    A couple of questions revolving around the BRAIN Initiative this morning.  Do you think that this BRAIN Initiative has any chance of moving forward if the President doesn't get his way with the budget?  And if the budget deficit is running into trillions of dollars, how can the President justify proposing spending another $100 million on this?
    +
    +  
    +
    + MR. CARNEY:  Well, first of all, everything that the President is proposing will be paid for and will be in keeping with the cap set by the Budget Control Act.  That's number one.
    +
    +  
    +
    + Number two, there has historically been and there seems to be today bipartisan interest in this kind of innovative research that can pay huge dividends down the road for our country economically, medically, when it comes to the health of our senior citizens who suffer from Alzheimer’s or others who suffer from Parkinson’s.  I mean, this is -- the potential here is enormous and the investment is relatively small compared to the potential.
    +
    +  
    +
    + So the President expects that there will be -- that the tradition of bipartisan support for this kind of initiative and this kind of innovation will prevail.  One of the agencies he’s tasked here with undertaking this initiative is DARPA.  And as you all know, in its previous incarnation as ARPA, this was the agency that was seminal in the effort -- in creating the Internet and launching so many -- so much economic potential in this country and around the globe.
    +
    +  
    +
    + So I think that this is one of those investments, as the President has argued often, that are essential to make if we are going to continue to grow and maintain our lead internationally on the cutting edge of scientific discovery and economic and technological development.
    +
    +  
    +
    + Q    You don't think it’s a long shot given the current climate?
    +
    +  
    +
    + MR. CARNEY:  I don't.  Well, no, I think that budgets are all about priorities.  I think that -- I will stipulate now that the President’s budget will not be passed word for word into law.  It has never happened, and it won’t happen this time.  But the President’s budget will make clear what his priorities are; and many of those priorities will reflect the kinds of things that have enjoyed bipartisan support in the past and we believe enjoy bipartisan support now.  And this kind of innovation and research is key to our future economic development.  It’s also key to the health and welfare of the American people.
    +
    +  
    +
    + Ed.
    +
    +  
    +
    + Q    Speaking about the budget, can you give us an update on the sequester?  Because yesterday the Customs and Border Protection Agency said that they're actually postponing furloughs and overtime cuts for Border Patrol agents.  I thought, in February, when Secretary Napolitano came out here with you, she told us it was dire, these Border Patrol agents were going to be furloughed, and that we were going to be less safe because of that.
    +
    +  
    +
    + MR. CARNEY:  Well, I think both are true.  What is a fact is that when you're dealing with these kinds of across-the-board, forced budget cuts in the middle of a fiscal year and you're having to make all sorts of adjustments to account for them and to reduce your expenditures accordingly, it’s a moving picture.  And that can be on the plus side, where furloughs may take place a little later, or on the minus side, where things may be more immediate.  I mean, that's just a fact.  That's true at every agency.  
    +
    +  
    +
    + But feel free to convey to your readers and viewers that the sequester doesn’t matter.  And then --
    +
    +  
    +
    + Q    Okay, well, first of all, let me just stop you, because I didn't say it didn't matter.
    +
    +  
    +
    + MR. CARNEY:  -- and explain -- nobody said it wasn’t dire.
    +
    +  
    +
    + Q    I said that the Secretary came in here and said that we were going to be less safe, that people were going to be crossing the border because there are less Border Patrol agents.  And then they announced yesterday, actually, we're not doing that.  So I'm not saying it's not important.  I'm saying, did she mislead the public?
    +
    +  
    +
    + MR. CARNEY:  Absolutely not.  And I'm saying that this is  -- I mean, you're editorializing enormously in that, but the --
    +
    +  
    +
    + Q    How so?  February -- I'll give you -- February 25th she said, "If you have 5,000 fewer Border Patrol hours or agents, you have 5,000 fewer Border Patrol agents.  That has a real impact."  Those are her words.  That's not politicizing.
    +
    +  
    +
    + MR. CARNEY:  Right.  And how is that not the case?
    +
    +  
    +
    + Q    They announced yesterday they're not doing that.
    +
    +  
    +
    + MR. CARNEY:  Well, but there are reductions.  And whether it's those Border Patrol --
    +
    +  
    +
    + Q    Well, what are they?
    +
    +  
    +
    + MR. CARNEY:  Go ahead and report that, Ed.  We've made clear, look --
    +
    +  
    +
    + Q    Okay, she said 5,000.  They said yesterday, we're not doing that.
    +
    +  
    +
    + MR. CARNEY:  Talk to those who have been laid off at defense industries.  Talk to those who have been furloughed in the --
    +
    +  
    +
    + Q    Let’s talk about Border Patrol first.
    +
    +  
    +
    + MR. CARNEY:  Look, you can obviously go to DHS and --
    +
    +  
    +
    + Q    Well, that's what she said.  She said we're going to be less safe.  
    +
    +  
    +
    + MR. CARNEY:  Right.  And the impacts of the sequester will not all be immediate.  If you can predict to me when the sequester will end -- if it will end -- when Republicans will make the fateful decision to fund Border Patrol agents or fund our national security interests or fund Head Start at appropriate levels rather than continue to extend tax breaks to the wealthy and well-connected, tell me when that happens, and then we can assess what damage was done after the fact.  
    +
    +  
    +
    + There is no question that when you have these kinds of across-the-board budget cuts, as many Republicans warned -- and as many Republicans when they go home to their districts, as we speak, are complaining about -- when they affect their districts, the impacts are real and they affect real people.  And I know that there hasn't been a lot of coverage of the impacts on real people, on the families who had to be engaged in lotteries to see whether their child, on a Friday, was still going to be in Head Start on Monday.  Tell them it doesn't matter.  Tell them that the impacts aren't real.  
    +
    +  
    +
    + And I take your point.  Look, this is a moving picture.  Budgets are big things.  Outflows and inflows, that's why there are constant adjustments being made at each agency as they deal with their budget in terms of what the impacts of sequester are.  But they are real.  And they are progressive in the sense that they don't all happen at once.  And when we make predictions about what will happen in the future, it's going to change based on how the budget picture looks a month later.  But they're real.
    +
    +  
    +
    + Q    But the last thing on this.  When you said "moving picture," the other thing the administration kept saying in February was that there was no flexibility for these Cabinet Secretaries.  Republicans were saying they can move money around.  You said, Secretary Duncan said, others said you can't do that; there is no flexibility.  Now you're saying it's a moving picture, so the Border Patrol agents won't be laid off today but maybe -- I thought there was no flexibility.  I thought it was indiscriminate, it was across the board --
    +
    +  
    +
    + MR. CARNEY:  The law is written the way it's written, designed specifically not to allow the kinds of choices that the Budget Control Act and the sequester part of it were written to force Congress to make -- to be arbitrary and indiscriminate.  And that remains a fact.  
    +
    +  
    +
    + What is also true is as time progresses and savings are made by eliminating a contract, for example, or ending new purchases of equipment for a period of time, or other things that can be done, changes about the prognosis for furloughs can be made.  But that is not -- any more than it was uniform a month ago, it's not uniform now.  And this will fluctuate as time goes on.  It will fluctuate next month, and if the sequester continues, it will fluctuate on and on and on after that as the agencies adjust to that budget picture.
    +
    +  
    +
    + Q    Jay, thanks.  Does the President regret at all not doing more events like the one he's going to do tomorrow, the one he's going to do on Monday, given that when you look at public opinion polls, they actually show support for stiffer gun laws as dropping?  It's not just what's happening in Congress, but actually what's happening on the American people.
    +
    +  
    +
    + MR. CARNEY:  Well, I think the data on this is quite mixed, and when it comes to some of the measures that we've just been talking about, including closing loopholes in our background check system, the data remains very strong and overwhelming in support of doing just that.  And the President has been doing events, has been talking about gun violence.  I think the most memorable moment I can recall from a State of the Union address in all the time I've been in Washington occurred at the end of the President's State of the Union address this year, when --
    +
    +  
    +
    + Q    But I mean going out, going on the road, talking to people like he's going to be doing tomorrow and on Monday.
    +
    +  
    +
    + MR. CARNEY:  Right.  Well, I mean, I have a list here that I can provide you of everything the President and the Vice President have done, and it's quite extensive, and the dates are December 16th, December 19th, January 19th, January 16th, January 25th, January 28th, February 4th, February 11th, February 12th, February 15th, 19th, 20th, 21st, 27th.  These are all presidential and vice presidential engagements or events regarding this very important issue.  
    +
    +  
    +
    + So I would -- the fact that it’s a challenge is something that was recognized at the outset by everyone, including this President, including the Vice President.  The fact that it would require concerted and consistent effort was recognized by the President and is embodied by -- is reflected in the actions that he’s taken ever since Newtown happened.
    +
    +  
    +
    + So tomorrow’s event, Monday’s event, that's part of this process.  Last week’s event is part of this process.
    +
    +  
    +
    + Q    Jay, on North Korea, one foreign policy expert said to me that Kim Jong-il seemed to know where the line was, and that Kim Jong-un doesn't.  Does the President share that assessment?  And does he therefore see this current leader as being more dangerous and less predictable than his father?
    +
    +  
    +
    + MR. CARNEY:  I would say that we are judging the regime by its actions and its -- mostly its actions, but also by its rhetoric.  And those are the assessments we make, and it’s not personality-based.
    +
    +  
    +
    + The fact is that the pattern we have seen of bellicose rhetoric and provocative behavior long predates the current leader of North Korea, as veterans of previous administrations can tell you.  So assessments about the current leader are obviously things that outside experts make and inside experts make, but as a policy matter, we base our policy decisions on overall actions and behavior by the regime.
    +
    +  
    +
    + Yes, sir.
    +
    +  
    +
    + Q    Yes, on the BRAIN Initiative that the President outlined today, you described the $100 million as this small initial investment --
    +
    +  
    +
    + MR. CARNEY:  I think I said a small investment compared to the potential benefit.
    +
    +  
    +
    + Q    A lot of experts say it’s going to take years and billions of dollars.  The President himself compared it to the Apollo program, which cost hundreds of billions of dollars.  How many years, how much money do you think ultimately it will take to sort of achieve what you guys envision?
    +
    +  
    +
    + MR. CARNEY:  Well, I think that the scientific experts are best at predicting how soon breakthroughs will occur.  And even they, I think as history proves, are not likely to be dead on, spot on in their predictions.  It's impossible to know.  That's what makes this essential and exciting, because the potential is huge.  But it requires investments that allow for the necessary innovation and research that can bring us to that threshold.  
    +
    +  
    +
    + So the President believes this is the kind of thing that we ought to be doing.  It is the kind of thing that Republicans and Democrats have supported in the past as part of our economic development.  And he is very enthusiastic about the prospect for discovery and innovation in this field, as are so many experts in the field.  
    +
    +  
    +
    + Q    So you said that $100 million is small relative to the potential.  Do you agree just small relative to the overall cost involved in this initiative?
    +
    +  
    +
    + MR. CARNEY:  I don't have a projection to lay out to you based on what revelations might come from early stages of research and innovation and development.  What I can tell you is when we talked about budget priorities and we talked about the fact that the President's budget will -- the initiatives that are in it will be paid for, and that it has always been his position -- whether it's investing in infrastructure or in medical research -- that there are things that we need to do investment-wise, even as we trim our budgets and reduce our deficits, that are essential to future economic growth, and this is one of them. 
    +
    +  
    +
    + Roger. 
    +
    +  
    +
    + Q    Jay, the U.N. today passed a treaty regulating world commerce and arms trading.  The Senate last month opposed a symbolic treaty along those same lines, suggesting it's going to be an uphill battle to get it through for ratification.  How are you going to get it through?
    +
    +  
    +
    + MR. CARNEY:  Well, I think that I can say two things.  One, we are pleased with the outcome of the conference, and the text achieves the objectives that we set out for this negotiation.  And we are pleased to join the consensus.  As is the case with all treaties of this nature, we will follow normal procedures to conduct a thorough review of the treaty text to determine whether to sign the treaty.  And what that timeline is, I cannot predict to you now.  And we are just beginning the review process, so I wouldn't want to speculate about when that process will end.  But we're certainly encouraged by and pleased by the outcome. 
    +
    +  
    +
    + Q    Do you have any idea how you're going to get it through the Senate?
    +
    +  
    +
    + MR. CARNEY:  Again, I think before we get to that, we're going to review the treaty and assess it, and then make judgments accordingly. 
    +
    +  
    +
    + Mara. 
    +
    +  
    +
    + Q    I just have a question about background checks.  You pointed out that in many polls it polls above 90 percent.  Yet Michael Bloomberg is spending a lot of money on this.  Organizing for America has made it kind of their maiden grassroots effort.  And the President has been out doing all these events that you cited.  So what is your theory of the case as to why this seems to be losing steam in Congress?
    +
    +  
    +
    + MR. CARNEY:  Well, I would at least in part suggest that the process continues.  And I'm not sure that I would agree with the assessment that it's losing steam.  I think it has always been challenging.  I think that predictions that any element of this legislative package would be easily passed were incorrect and probably naïve if and when they were made, whether it’s this particular aspect of it or any other aspect of it.  This has all traditionally been difficult.
    +
    +  
    +
    + I would note that -- I would send you to members of Congress to explain their position on these issues; if they’re in opposition, why they’re in opposition -- why they’re in opposition to a proposition that has 90 percent support from the American people and that enjoys support in every region of the country, and from Republicans and Democrats and independents.
    +
    +  
    +
    + Having said that, there are obviously challenges and have traditionally been challenges to moving this kind of legislation.  I would note that on the background check issue, a number of Republicans are on the record supporting the idea of closing loopholes in background checks.  A number of them voted for improving our background check system in the late 1990s, and I think there’s a reason for that.  And it’s important to explain to readers and viewers and listeners, and that is that background checks are the quintessence of a common-sense approach to how to address this problem.  And I think most Americans believe it makes absolute sense to check the criminal record of someone before they are allowed to purchase a gun, because they’re not allowed to have one otherwise.
    +
    +  
    +
    + So we’re simply saying, let’s enforce the law through an effective background check system to keep weapons away from those who should not by law have them.  That’s why gun-trafficking measures are so important as well.  
    +
    +  
    +
    + So having said that, this is always going -- it was always going to be a challenge, and that’s why we’re pressing hard to get it done; why the President is out there making the case, the Vice President is out there making the case; why legislators from both parties have been talking about it.  And we’re going to continue to press for action on it.
    +
    +  
    +
    + Q    Well, I can’t think of any other issue that polls above 90 percent and some polls above 94 percent.  I’m just wondering -- there must be a theory for this.  Is it the power of the NRA?  I mean, you guys must have some idea of why you think this particular piece of it is proving to be so difficult.
    +
    +  
    +
    + MR. CARNEY:  Look, I used to write articles about this, but I’m going to leave the political analysis to others and simply say that, for a host of reasons, advancing legislation that is common-sense and reduces gun violence has always been a challenge and probably always will be.  But it is essential to try to get it done and move forward on it.  And the American people expect that it should be done, and they recognize the object rationale behind closing loopholes in the background check system, making sure that people who should not have a gun by law do not obtain a gun, cannot obtain a gun, in a very simple -- and this is about, again, I know I'm repeating myself to you, but for those who are not engaged in this issue all the time, it's important to understand that system exists.  This is not about creating some registry or background check system.  The existing system does not -- is not a registry and will not be a registry.  It is a background check system that is in place, but there are holes in the system and those holes ought to be closed.
    +
    +  
    +
    + April.
    +
    +  
    +
    + Q    I'm following up on Mara -- since the NRA and other gun-lobbying groups are so powerful, has this White House thought about meeting with groups like the NRA again since the Vice President's meeting with the NRA?  Has the President thought about it?  Has the Vice President thought about another meeting?
    +
    +  
    +
    + MR. CARNEY:  Well, we're working -- when it comes to the legislation, we're obviously working with lawmakers of both parties, and that particular organization has connections and contacts on Capitol Hill.  I don’t think there is any danger in us not knowing where they stand on certain issues and vice versa.  There has been outreach and I'm sure -- I'm not saying there won't be continued outreach, but on the legislative side of this, the legislation has been written, it's moving through committees, and we're engaged in that process right now.  And we are working with lawmakers of both parties in trying to achieve a compromise that can make this happen, especially when it comes to the background checks.
    +
    +  
    +
    + Q    But realistically, this whole effort started out bigger -- much bigger than what it was, and it's boiled down to -- you're talking about a consensus on background checks.  And much of the holdup to include ammunitions, the reduction in magazines, is dealing with the NRA and the ammunition manufacturers.  Why not come together and talk it over to possibly find common ground to -- 
    +
    +  
    +
    + MR. CARNEY:  Well, first of all, that’s what the Vice President -- the initiative the Vice President --
    +
    +  
    +
    + Q    That was months ago, and they're getting ready to come back to Congress.
    +
    +  
    +
    + MR. CARNEY:  Months ago -- well, first of all, it wasn't that long -- it was fairly recent, and it was what helped lead to the initiative, the package of initiatives that the Vice President put forward with the President.  
    +
    +  
    +
    + Look, there are a lot of conversations happening around this issue.  And the President's views on what he believes we should do are clearly stated and reflected in this proposal.  And I would challenge that it’s all come down to one thing.  There are other aspects of this that have been moving forward and we are encouraged by that, and we’re going to continue to press to get it done.
    +
    +  
    +
    + Q    And one last question on this -- realistically, once this is all said and done and a vote happens, what do you expect to pass, realistically?
    +
    +  
    +
    + MR. CARNEY:  I would hesitate to make predictions on any of this for the very reason that I’ve been saying, and that is that it was always going to be a challenge.  And if any of this were easy -- I mean the sad fact about Newtown is that it’s not the first of its kind, and the age of the victims made it particularly horrific.  But there have been other incidents at Virginia Tech and Aurora that are similar.  And the idea that suddenly all of this would become easy when it had been difficult in the past was never credible, but that doesn't mean we shouldn’t be working hard to get it done.
    +
    +  
    +
    + Christi.
    +
    +  
    +
    + Q    Thanks, Jay.  Is the President planning on weighing in on the Los Angeles mayor’s race?  Eric Garcetti has been a big supporter of the President over the years.
    +
    +  
    +
    + MR. CARNEY:  I appreciate the question.  In keeping with past practice, when there is a primary, a Democratic primary in a race like this, we’re not -- the President won’t endorse any candidate.  Mr. Garcetti is, of course, someone who has been a long-time supporter of the President.  The President appreciates that support, appreciates their working relationship.  But we won’t -- there won’t be a formal endorsement. 
    +
    +  
    +
    + Q    Do you expect that they will see each other this week when the President is in California?
    +
    +  
    +
    + MR. CARNEY:  I’m not sure.  I think we’re in Northern California. 
    +
    +  
    +
    + Alexis.
    +
    +  
    +
    + Q    Jay, in the President’s visit to Colorado and Connecticut, the common theme in those two states is legislative action in the state, at the state level, and I’m assuming the President is going to talk about that when he’s in both states.  What are the common denominators that the President sees in those two states that compelled them to move in a way that he would like to have Congress pay attention to?  What are the themes, other than the horror being in their midst?  But why would they take action when the NRA has been very active at the state level too, whereas Congress is very reluctant?
    +
    +  
    +
    + MR. CARNEY:  Well, I might look to state experts to make that analysis.  I think that you’re right that action has been taken in both states, and I think they -- a thing that connects them terribly is the tragedies that occurred recently in those states.  Beyond that, I think -- others might have a better assessment about why bipartisan action has happened in those states.  But I think that reflects the capacity around the country for bipartisan action, including here in Washington.
    +
    +  
    +
    + Q    And just to follow up, if the President doesn't see the willingness in Congress to do what he would hope at the federal level, to what extent does he hope that states themselves in a piecemeal basis can begin to act?
    +
    +  
    +
    + MR. CARNEY:  Well, the President is focused right now on the proposal he put forward, the set of proposals which includes pieces of legislation at the federal level.  And that's what he is focused on.  Obviously, he is -- I mean, it is important that other states address this issue as they see fit.  But right now, we're focused on the President's initiative. 
    +
    +  
    +
    + Mark.
    +
    +  
    +
    + Q    Jay, North Korea again.  You spoke about the mismatch between rhetoric and not seeing deployments change on the ground or mobilization.  Specifically on the Yongbyon reactor, have we seen any sign, any preparations that the North Koreans are going to try and restart it?  And beyond that, does the President -- would he accept the restarting of that reactor?  Would he take steps to stop it?
    +
    +  
    +
    + MR. CARNEY:  Well, we do not accept a violation of international obligations by the North Koreans.  And we have -- take action through the United Nations and elsewhere through sanctions and other measures that isolate and put pressure on North Korea for its violations of its international obligations.  I'm not going to predict what next steps will be if this action is followed through on.  I believe it was an announcement that North Korea just made.  I don't have any other information to impart to you about that facility. 
    +
    +  
    +
    + But this -- again, this is in keeping with a pattern.  And that behavior has been met with and responded to -- met with action by the international community, responded to often through consensus as it was at the Security Council not long ago. 
    +
    +  
    +
    + Jon-Christopher.  
    +
    +  
    +
    + Q    Jay, this is the 60th anniversary of the so-called armistice, which Kim Jong-un has basically rescinded.  The conflict there has been going on during 12 presidential administrations.  Has this administration been in touch with any of those individuals, going back to the Truman administration, who can lend some insight and some regional acumen basically to the President in terms of advice?
    +
    +  
    +
    + MR. CARNEY:  Well, I don't have any specific conversations the President has had to read out to you.  The President is constantly speaking with those with expertise in different areas of both foreign policy and domestic policy, and I'm confident that he has had conversations with experts outside of government on this issue.  But I have no specific ones to read out to you.  It is certainly the case that this is -- North Korea's actions have been something that successive administrations have had to deal with, especially the last several.
    +
    +  
    +
    + Q    Thanks, Jay.
    +
    +  
    +
    + MR. CARNEY:  Last one, Ann -- I'm sorry, I did say Connie.   
    +
    +  
    +
    + Q    On the BRAIN research -- and thank you very much -- just some follow ups.  Will there be any private investment into this?  Is there any congressional opposition that you know of?  And would you please announce when there are clinical trials so that people who need them can try to get -- 
    +
    +  
    +
    + MR. CARNEY:  Well, I don't think it will be for the White House to announce clinical trials.  I would point you to those who are overseeing the initiative at the agencies the President mentioned today.  I'm going to go out on a limb and suggest that there might be some congressional opposition.  (Laughter.)  I said earlier that there has been indication that there is bipartisan support for this kind of initiative, this specific initiative, but I can't predict where that will end up. 
    +
    +  
    +
    + What I do know is that this is something that does not have a political or partisan flavor to it.  This is the kind of potentially breakthrough research that results in enormous advances in the health of the American people as well as enormous economic advances, potentially.  So it's the kind of thing that we have done in the past successfully and we should continue to do.  That's what the President believes.  Thanks. 
    +
    +  
    +
    + Q    Private firms -- will private drug firms be involved?
    +
    +  
    +
    + MR. CARNEY:  I think we put out a lot of paper on this in terms of how the investments are made and leveraging issues. 
    +
    +  
    +
    + Ann.
    +
    +  
    +
    + Q    Real quickly -- should the oil spill in Arkansas that blackened a neighborhood have any impact on the State Department's or the President's consideration of Keystone XL?
    +
    +  
    +
    + MR. CARNEY:  Well, first of all, the assessment of that particular pipeline is ongoing at the State Department, and they assess a range of criteria.  And obviously, the assessments they make based on environmental impacts and the assessments that were made in the past had to do with some of these issues.  But I don't have anything for you specific on that, because it's a process that's underway at the State Department.  
    +
    +  
    +
    + Q    Have you spoken to the President about the Arkansas spill?  I know you were asked about it.  
    +
    +  
    +
    + MR. CARNEY:  I have not. 
    +
    +  
    +
    + Q    You still haven't spoken to him about it?
    +
    +  
    +
    + MR. CARNEY:  About that issue, no.  Thanks.
    +
    +  
    +
    +  
    +
    + END
    +
    + 1:40 P.M. EDT
    +]]>
    + The President + Press Briefings + Press Briefings + Office of the Press Secretary + The President + Tue, 02 Apr 2013 21:19:00 +0000 + The White House + 206851 at http://www.whitehouse.gov +
    + + Remarks by President Obama and Prime Minister Lee of Singapore Before Bilateral Meeting + http://www.whitehouse.gov/the-press-office/2013/04/02/remarks-president-obama-and-prime-minister-lee-singapore-bilateral-meeti + Oval Office

    +

    2:14 P.M. EDT

    +

    PRESIDENT OBAMA:  Well, it is a great pleasure for me to welcome my good friend, Prime Minister Lee, to the Oval Office.  He and I have had interacted in a whole range of international forums, and not surprisingly, he has proven to be an outstanding partner for us on the international stage -- not surprising because Singapore and the United States have historically had an extraordinary relationship.  Singapore is one of the most successful countries in the world. 

    +

    I think their progress and their development over the last several decades has been an example for many countries around the world.  We have extremely close military cooperation.  And I want to thank Singapore for all the facilities that they provide that allow us to maintain our effective Pacific presence. 

    +

    They are an outstanding economic partner.  Over the last decade, since we signed our free trade agreement, we have seen a doubling of trade between our countries, and that creates jobs here in the United States as well as in Singapore.  As a leader in ASEAN and the East Asia Summit, they’ve provided I think a steady vision of how countries in the Pacific region can cooperate effectively for the prosperity and security of all, and are strong promoters of rules of the road and international norms that the United States strongly supports. 

    +

    And so, across the board, we have very much appreciated the extraordinary relationship between our two countries.  And personally, I can tell you that there are very few world leaders who I am more appreciative of in terms of their advice and counsel and thoughtful analysis than Prime Minister Lee. 

    +

    And as we continue the process that we called rebalancing when I first came into office, we’ve continued to seek out the advice and good counsel of Singapore in how to effect that in a way that creates not only strong security, but also increase prosperity for both the United States and the countries of the region. 

    +

    So I’m very thankful for Singapore and its partnership.  I’m thankful for Prime Minister Lee for his outstanding work.  I’m grateful for the people of Singapore.  As many of you know, I spent some time in my youth in this part of the world and have a great fondness and affection for the people of Singapore.  I’m extraordinarily pleased to see their great success and I’m looking forward to a very productive discussion about how we can continue to improve prospects for people not just in the Asia Pacific region but around the world. 

    +

    So thank you very much, Mr. Prime Minister.

    +

    PRIME MINISTER LEE:  Thank you, Mr. President.  I’m very happy to be here in Washington during cherry blossom season and very honored to be calling on the President so early in his second term.

    +

    We have very good relations between Singapore and the United States, grown in deep cooperation.  We work together in education, research and development.  We work together in economic areas and trade.  We work together in counterterrorism and defense.  And it’s a comprehensive relationship, and we look forward particularly in the next few weeks to welcoming the first littoral combat ship, which will be arriving in Singapore and we will be playing host to it for a few months.

    +

    But more broadly, Singapore is very happy that the U.S. and the Obama administration has been putting greater emphasis on its relation to Asia; that it’s rebalancing towards Asia, and that it’s engaging Asia across many fronts -- not just security, but also economics, also cultural and educational.  And Singapore would like to be of help in furthering this process in deepening the relationship. 

    +

    The TPP, the Trans-Pacific Partnership, is a very important part of it, and we’re working on that agenda now.  There’s also work going on deepening ASEAN’s relations with the United States, which the President initiated when we last met in November back then. 

    +

    And there are other important bilateral relationships in Asia, including what is perhaps the most important bilateral relationship in the world, which is between the U.S. and China.  And we are happy that the administration’s attention is focused on this, and Singapore will do our part to do what we can to help America engage the region constructively, productively, and in a way in which it fosters stability and prosperity for all the countries.

    +

    So I’m very happy to be here, to be calling on this President, and I hope I’ll have the opportunity to invite him to come and visit Singapore before too long, and for me to reciprocate his wonderful hospitality.

    +

    PRESIDENT OBAMA:  Thank you very much, everybody.

    +

    END
    + 2:20 P.M. EDT

    +]]>
    + The President + Speeches and Remarks + Speeches and Remarks + Office of the Press Secretary + The President + Tue, 02 Apr 2013 20:16:00 +0000 + The White House + 206741 at http://www.whitehouse.gov +
    +
    +
    \ No newline at end of file diff --git a/spec/services/site_seeker_spec.rb b/spec/services/site_seeker_spec.rb new file mode 100644 index 0000000..1253342 --- /dev/null +++ b/spec/services/site_seeker_spec.rb @@ -0,0 +1,85 @@ +# -*- coding: utf-8 -*- +require 'spec_helper' +require 'nokogiri' + +describe SiteSeeker do + describe "results" do + + before(:each) do + query = { q: "semester" } + @site_seeker = SiteSeeker.new + @results = @site_seeker.search(query, "/foo/?") + end + + it "should be a Hash" do + @results.class.should eq Hash + end + + it "should have a Hash for sorting" do + @results[:sorting].class.should be Array + end + + it "should have a first sorting entry with text" do + @results[:sorting][0][:text].should_not be_nil + end + + it "should have a second sorting entry with an url" do + @results[:sorting][1][:query].should_not be_nil + end + + it "should not have an error message" do + @results[:error].should be nil + end + + it "should have a number of hits" do + @results[:count].class.should be String + end + + it "should have results" do + @results[:entries].count.should > 0 + end + + describe "result entry" do + it "should have an order number" do + @results[:entries].first[:number].should eq 1 + end + + it "should have a title" do + @results[:entries].first[:title].class.should be Nokogiri::XML::NodeSet + end + + it "should have an extract" do + @results[:entries].first[:extract].should_not be_nil + end + + it "should have a breadcrumb" do + @results[:entries].first[:breadcrumb].class.should be Nokogiri::XML::NodeSet + end + + it "should have a category" do + @results[:entries].first[:extract].class.should be String + end + + it "should have a date string" do + @results[:entries].first[:date].class.should be String + end + end + + it "should have a paging array" do + @results[:paging].class.should be Array + end + + it "should have a query string for getting more results" do + @results[:more_query].class.should_not be_nil + end + + it "should have a categories NodeSet" do + @results[:categories].class.should be Nokogiri::XML::NodeSet + end + + it "should show a spelling suggestions" do + results = @site_seeker.search({ q: "semstr" }, "/foo/?") + results[:suggestions].count.should > 1 + end + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb new file mode 100644 index 0000000..c96cca7 --- /dev/null +++ b/spec/spec_helper.rb @@ -0,0 +1,30 @@ +ENV["RAILS_ENV"] ||= 'local_test' +require File.expand_path("../../config/environment", __FILE__) +require 'rspec/rails' +require 'rspec/autorun' +require 'capybara/rails' +require 'capybara/poltergeist' +require 'database_cleaner' + +Capybara.javascript_driver = :poltergeist +# Capybara.default_wait_time = 5 + +Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f} + +RSpec.configure do |config| + config.mock_with :rspec + config.infer_base_class_for_anonymous_controllers = true + config.include Capybara::DSL + + # For Phantomjs to work, we use database_cleaner instead of transactional rollback + config.use_transactional_fixtures = false + config.before(:suite) do + DatabaseCleaner.strategy = :truncation + end + config.before(:each) do + DatabaseCleaner.start + end + config.after(:each) do + DatabaseCleaner.clean + end +end diff --git a/spec/support/features_helper.rb b/spec/support/features_helper.rb new file mode 100644 index 0000000..3221960 --- /dev/null +++ b/spec/support/features_helper.rb @@ -0,0 +1,31 @@ +def login(username, password) + visit login_path + fill_in 'username', with: username + fill_in 'password', with: password + click_button 'Logga in' +end + +def create_user_and_login + user = FactoryGirl.create(:user) + login(user.username, 'stub') + user +end + +def create_user_with_roles_with_feeds + 1.upto(100) {|n| FactoryGirl.create(:role, category: Role::CATEGORIES.keys[n % Role::CATEGORIES.size]) } + 1.upto(20) {|n| + f = FactoryGirl.build(:feed, + category: Feed::CATEGORIES.keys[n % Feed::CATEGORIES.size], + feed_url: File.join(Rails.root, "spec/samples/whitehouse.rss") + ) + f.fetch + f.parse + f.parsed_feed.entries.each { |fe| fe.entry_id = "fe-#{n}-#{Kernel.rand(0..1000)}" } + f.save(validate: false) + } + Feed.all.each { |f| f.role_ids = Role.all.each.map(&:id) } + + user = FactoryGirl.create(:user) + user.role_ids = Role.all.each.map(&:id) + user +end \ No newline at end of file