├── .gitignore
├── .travis.yml
├── CODEOWNERS
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── authenticating-users
├── Gemfile
├── README.md
├── app.rb
└── app.yaml
├── bookshelf
├── .gitignore
├── Gemfile
├── README.md
├── Rakefile
├── app.yaml
├── app
│ ├── assets
│ │ ├── config
│ │ │ └── manifest.js
│ │ ├── javascripts
│ │ │ └── application.js
│ │ └── stylesheets
│ │ │ └── application.css
│ ├── controllers
│ │ ├── application_controller.rb
│ │ ├── books_controller.rb
│ │ └── stackdriver_controller.rb
│ ├── models
│ │ └── book.rb
│ └── views
│ │ ├── books
│ │ ├── _form.html.erb
│ │ ├── edit.html.erb
│ │ ├── index.html.erb
│ │ ├── new.html.erb
│ │ └── show.html.erb
│ │ └── layouts
│ │ └── application.html.erb
├── bin
│ ├── bundle
│ ├── rails
│ ├── rake
│ └── setup
├── config.ru
├── config
│ ├── application.rb
│ ├── boot.rb
│ ├── environment.rb
│ ├── environments
│ │ ├── development.rb
│ │ ├── production.rb
│ │ └── test.rb
│ ├── initializers
│ │ ├── cookies_serializer.rb
│ │ ├── filter_parameter_logging.rb
│ │ ├── inflections.rb
│ │ ├── session_store.rb
│ │ └── wrap_parameters.rb
│ ├── routes.rb
│ └── secrets.yml
├── images
│ └── moby-dick.jpg
├── public
│ ├── 404.html
│ ├── 422.html
│ ├── 500.html
│ ├── favicon.ico
│ └── robots.txt
└── spec
│ ├── book_extensions.rb
│ ├── e2e_spec_helper.rb
│ ├── features
│ ├── book_management_e2e_spec.rb
│ └── book_management_spec.rb
│ ├── models
│ └── book_spec.rb
│ ├── setup.sh
│ └── spec_helper.rb
├── credentials.json.enc
├── gce
├── Gemfile
├── README.md
├── app.rb
├── deploy.sh
├── rubyapp.conf
├── startup-script.sh
└── teardown.sh
└── sessions
├── Gemfile
├── README.md
├── Rakefile
├── acceptance
└── app_test.rb
├── app.rb
├── app.yaml
├── firestore_session.rb
└── test
├── app_test.rb
└── test_helper.rb
/.gitignore:
--------------------------------------------------------------------------------
1 | log/
2 | tmp/
3 | db/*.sqlite3
4 | client_secrets.json
5 | Gemfile.lock
6 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | # Copyright 2015 Google, Inc
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | sudo: false
16 | language: ruby
17 | branches:
18 | only: [master]
19 | rvm:
20 | - 2.5
21 | - 2.6
22 |
23 | cache:
24 | directories:
25 | # We cache the SDK so we don't have to download it again on subsequent builds.
26 | - $HOME/google-cloud-sdk
27 |
28 | env:
29 | global:
30 | - PATH=$PATH:$HOME/google-cloud-sdk/bin
31 | - GOOGLE_APPLICATION_CREDENTIALS=$TRAVIS_BUILD_DIR/credentials.json
32 | - BUILD_ID=$TRAVIS_BUILD_ID
33 |
34 | before_install:
35 | #ENCRYPT YOUR PRIVATE KEY (If you need authentication)
36 | # 1. Install and login to the Travis CLI:
37 | # $ gem install travis
38 | # $ travis login
39 | # 2. Move your json private key to credentials.json
40 | # 3. Run:
41 | # $ travis encrypt-file credentials.json --add
42 | # 4. Commit changes:
43 | # $ git add credentials.json.enc
44 | # $ git commit credentials.json.enc .travis.yml
45 | - openssl aes-256-cbc -K $encrypted_990eecf37889_key -iv $encrypted_990eecf37889_iv
46 | -in credentials.json.enc -out credentials.json -d
47 | - gcloud auth activate-service-account --key-file credentials.json
48 | # Update to Bundler 2.0
49 | - gem update --system
50 | - gem install bundler
51 |
52 | install:
53 | - pushd bookshelf
54 | - bundle install --jobs=3 --retry=3
55 | - bash spec/setup.sh
56 | - popd
57 | - pushd sessions
58 | - bundle install --jobs=3 --retry=3
59 | - popd
60 |
61 | script:
62 | - pushd bookshelf
63 | - bundle exec rspec spec --backtrace --format documentation
64 | - popd
65 | - pushd sessions
66 | - bundle exec rake test
67 | - bundle exec rake acceptance
68 | - popd
69 |
--------------------------------------------------------------------------------
/CODEOWNERS:
--------------------------------------------------------------------------------
1 | # Code owners file.
2 | # This file controls who is tagged for review for any given pull request.
3 | #
4 | # For syntax help see:
5 | # https://help.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners#codeowners-syntax
6 |
7 | * @TheRoyalTnetennba @dazuma
8 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # How to become a contributor and submit your own code
2 |
3 | ## Contributor License Agreements
4 |
5 | We'd love to accept your patches! Before we can take them, we
6 | have to jump a couple of legal hurdles.
7 |
8 | Please fill out either the individual or corporate Contributor License Agreement
9 | (CLA).
10 |
11 | * If you are an individual writing original source code and you're sure you
12 | own the intellectual property, then you'll need to sign an [individual CLA]
13 | (https://developers.google.com/open-source/cla/individual).
14 | * If you work for a company that wants to allow you to contribute your work,
15 | then you'll need to sign a [corporate CLA]
16 | (https://developers.google.com/open-source/cla/corporate).
17 |
18 | Follow either of the two links above to access the appropriate CLA and
19 | instructions for how to sign and return it. Once we receive it, we'll be able to
20 | accept your pull requests.
21 |
22 | ## Contributing A Patch
23 |
24 | 1. Submit an issue describing your proposed change to the repo in question.
25 | 1. The repo owner will respond to your issue promptly.
26 | 1. If your proposed change is accepted, and you haven't already done so, sign a
27 | Contributor License Agreement (see details above).
28 | 1. Fork the desired repo, develop and test your code changes.
29 | 1. Ensure that your code adheres to the existing style in the sample to which
30 | you are contributing. Refer to the
31 | [Google Cloud Platform Samples Style Guide]
32 | (https://github.com/GoogleCloudPlatform/Template/wiki/style.html) for the
33 | recommended coding standards for this organization.
34 | 1. Ensure that your code has an appropriate set of unit tests which all pass.
35 | 1. Submit a pull request.
36 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Getting Started Ruby
2 |
3 | [](https://travis-ci.org/GoogleCloudPlatform/getting-started-ruby)
4 |
5 | Checkout folders to view particular steps of this sample application.
6 |
7 | - [`bookshelf/`](bookshelf/)
8 | - Code for the [Getting started with Ruby][getting-started] tutorial.
9 |
10 | [Ruby on Rails][ror] web application on [Google App Engine][gae].
11 |
12 | ### Run
13 |
14 | To run the application, first install dependencies:
15 |
16 | $ bundle install
17 |
18 | And then run the Rails web server:
19 |
20 | $ rails server
21 |
22 | ### To run the tests
23 |
24 | $ bundle install
25 | $ bundle exec rspec
26 |
27 | ### To deploy to App Engine
28 |
29 | Install the [gcloud CLI](https://cloud.google.com/cli): https://cloud.google.com/sdk/docs/install-sdk
30 |
31 | And then deploy the application:
32 |
33 | $ gcloud app deploy
34 |
35 | ## Contributing changes
36 |
37 | * See [CONTRIBUTING.md](CONTRIBUTING.md)
38 |
39 | ## Licensing
40 |
41 | * See [LICENSE](LICENSE)
42 |
43 | [getting-started]: http://cloud.google.com/ruby/getting-started/
44 | [ror]: http://rubyonrails.org/
45 | [gae]: http://cloud.google.com/appengine/docs/standard/ruby
46 |
--------------------------------------------------------------------------------
/authenticating-users/Gemfile:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | source "https://rubygems.org"
4 |
5 | git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
6 |
7 | # [START getting_started_requirements]
8 | gem "jwt", "~> 2.2"
9 | gem "sinatra", "~> 2.0"
10 | # [END getting_started_requirements]
11 |
--------------------------------------------------------------------------------
/authenticating-users/README.md:
--------------------------------------------------------------------------------
1 | # Authenticate Users with IAP
2 |
3 | * A short App Engine app, which uses [Cloud Identity-Aware Proxy](https://cloud.google.com/iap/) to serve a webpage which says `"Hello #{user_email_address}"`, where `user_email_address` is the authenticated user's email address.
4 | * To run, follow Ruby's [Authenticating Users with IAP](https://cloud.google.com/ruby/getting-started/authenticate-users-with-iap) tutorial.
5 |
6 | ## Contributing changes
7 |
8 | * See [CONTRIBUTING.md](../CONTRIBUTING.md)
9 |
10 | ## Licensing
11 |
12 | * See [LICENSE](../LICENSE)
13 |
--------------------------------------------------------------------------------
/authenticating-users/app.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 Google LLC All Rights Reserved.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | # [START getting_started_auth_all]
16 | require "base64"
17 | require "json"
18 | require "jwt"
19 | require "net/http"
20 | require "openssl"
21 | require "sinatra"
22 | require "uri"
23 |
24 | # [START getting_started_auth_certs]
25 | def certificates
26 | uri = URI.parse "https://www.gstatic.com/iap/verify/public_key"
27 | response = Net::HTTP.get_response uri
28 | JSON.parse response.body
29 | end
30 |
31 | set :certificates, certificates
32 | # [END getting_started_auth_certs]
33 |
34 | # [START getting_started_auth_metadata]
35 | def get_metadata item_name
36 | endpoint = "http://metadata.google.internal"
37 | path = "/computeMetadata/v1/project/#{item_name}"
38 | uri = URI.parse endpoint + path
39 |
40 | http = Net::HTTP.new uri.host, uri.port
41 | request = Net::HTTP::Get.new uri.request_uri
42 | request["Metadata-Flavor"] = "Google"
43 | response = http.request request
44 | response.body
45 | end
46 | # [END getting_started_auth_metadata]
47 |
48 | # [START getting_started_auth_audience]
49 | def audience
50 | project_number = get_metadata "numeric-project-id"
51 | project_id = get_metadata "project-id"
52 | "/projects/#{project_number}/apps/#{project_id}"
53 | end
54 |
55 | set :audience, audience
56 | # [END getting_started_auth_audience]
57 |
58 | # [START getting_started_auth_validate_assertion]
59 | def validate_assertion assertion
60 | a_header = Base64.decode64 assertion.split(".")[0]
61 | key_id = JSON.parse(a_header)["kid"]
62 | cert = OpenSSL::PKey::EC.new settings.certificates[key_id]
63 | info = JWT.decode assertion, cert, true, algorithm: "ES256", audience: settings.audience
64 | return info[0]["email"], info[0]["sub"]
65 |
66 | rescue StandardError => e
67 | puts "Failed to validate assertion: #{e}"
68 | [nil, nil]
69 | end
70 | # [END getting_started_auth_validate_assertion]
71 |
72 | # [START getting_started_auth_front_controller]
73 | get "/" do
74 | assertion = request.env["HTTP_X_GOOG_IAP_JWT_ASSERTION"]
75 | email, _user_id = validate_assertion assertion
76 | "
Hello #{email}
"
77 | end
78 | # [END getting_started_auth_front_controller]
79 | # [END getting_started_auth_all]
80 |
--------------------------------------------------------------------------------
/authenticating-users/app.yaml:
--------------------------------------------------------------------------------
1 | # Copyright 2019 Google LLC All Rights Reserved.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | # [START getting_started_app_yaml]
16 | runtime: ruby25
17 | entrypoint: bundle exec ruby app.rb
18 | # [END getting_started_app_yaml]
19 |
--------------------------------------------------------------------------------
/bookshelf/.gitignore:
--------------------------------------------------------------------------------
1 | # Copyright 2019 Google LLC.
2 | # Licensed under the Apache License, Version 2.0 (the "License");
3 | # you may not use this file except in compliance with the License.
4 | # You may obtain a copy of the License at
5 | #
6 | # http://www.apache.org/licenses/LICENSE-2.0
7 | #
8 | # Unless required by applicable law or agreed to in writing, software
9 | # distributed under the License is distributed on an "AS IS" BASIS,
10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 | # See the License for the specific language governing permissions and
12 | # limitations under the License.
13 |
14 | /.bundle
15 | /log/*
16 | /tmp
17 | /public/assets/
18 | /config/database.yml
19 | /gcd_dataset_directory/
20 | *.sqlite3
21 |
22 | # Ignore master key for decrypting credentials and more.
23 | /config/master.key
24 |
--------------------------------------------------------------------------------
/bookshelf/Gemfile:
--------------------------------------------------------------------------------
1 | # Copyright 2019 Google LLC.
2 | # Licensed under the Apache License, Version 2.0 (the "License");
3 | # you may not use this file except in compliance with the License.
4 | # You may obtain a copy of the License at
5 | #
6 | # http://www.apache.org/licenses/LICENSE-2.0
7 | #
8 | # Unless required by applicable law or agreed to in writing, software
9 | # distributed under the License is distributed on an "AS IS" BASIS,
10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 | # See the License for the specific language governing permissions and
12 | # limitations under the License.
13 |
14 | source "https://rubygems.org"
15 | git_source(:github) { |repo| "https://github.com/#{repo}.git" }
16 |
17 | ruby '>= 2.5'
18 |
19 | # Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
20 | gem 'rails', '~> 5.2.3'
21 | gem "google-cloud-firestore", "~> 1.0"
22 | gem "google-cloud-storage", "~> 1.10"
23 | gem "google-cloud-error_reporting"
24 |
25 | gem "jquery-rails"
26 |
27 | group :development, :test do
28 | # Call 'byebug' anywhere in the code to stop execution and get a debugger console
29 | gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
30 | end
31 |
32 | group :development do
33 | # Access an interactive console on exception pages or by calling 'console' anywhere in the code.
34 | gem 'web-console', '>= 3.3.0'
35 | gem 'listen', '>= 3.0.5', '< 3.2'
36 | end
37 |
38 |
39 | # Windows does not include zoneinfo files, so bundle the tzinfo-data gem
40 | gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
41 |
42 | group :test do
43 | gem "rspec-rails"
44 | gem "rspec-retry"
45 | gem "rack-test"
46 | gem "capybara"
47 | gem "poltergeist"
48 | gem 'phantomjs', :require => 'phantomjs/poltergeist'
49 | end
50 |
--------------------------------------------------------------------------------
/bookshelf/README.md:
--------------------------------------------------------------------------------
1 | # Ruby Getting Started
2 |
3 | Follow the [Getting started with Ruby][ruby-tutorial] tutorial to run this app.
4 |
5 | [ruby-tutorial]: https://cloud.google.com/ruby/getting-started
6 |
7 | ## Contributing changes
8 |
9 | * See [CONTRIBUTING.md](../CONTRIBUTING.md)
10 |
11 | ## Licensing
12 |
13 | * See [LICENSE](../LICENSE)
14 |
--------------------------------------------------------------------------------
/bookshelf/Rakefile:
--------------------------------------------------------------------------------
1 | # Copyright 2019 Google LLC.
2 | # Licensed under the Apache License, Version 2.0 (the "License");
3 | # you may not use this file except in compliance with the License.
4 | # You may obtain a copy of the License at
5 | #
6 | # http://www.apache.org/licenses/LICENSE-2.0
7 | #
8 | # Unless required by applicable law or agreed to in writing, software
9 | # distributed under the License is distributed on an "AS IS" BASIS,
10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 | # See the License for the specific language governing permissions and
12 | # limitations under the License.
13 |
14 | # Add your own tasks in files placed in lib/tasks ending in .rake,
15 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
16 |
17 | require_relative 'config/application'
18 |
19 | Rails.application.load_tasks
20 |
--------------------------------------------------------------------------------
/bookshelf/app.yaml:
--------------------------------------------------------------------------------
1 | # Copyright 2019 Google LLC.
2 | # Licensed under the Apache License, Version 2.0 (the "License");
3 | # you may not use this file except in compliance with the License.
4 | # You may obtain a copy of the License at
5 | #
6 | # http://www.apache.org/licenses/LICENSE-2.0
7 | #
8 | # Unless required by applicable law or agreed to in writing, software
9 | # distributed under the License is distributed on an "AS IS" BASIS,
10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 | # See the License for the specific language governing permissions and
12 | # limitations under the License.
13 |
14 | # [START bookshelf_app_yaml]
15 | runtime: ruby25
16 | entrypoint: bundle exec rackup -p $PORT
17 | instance_class: F2
18 | # [END bookshelf_app_yaml]
19 |
--------------------------------------------------------------------------------
/bookshelf/app/assets/config/manifest.js:
--------------------------------------------------------------------------------
1 | //= link_directory ../javascripts .js
2 | //= link_directory ../stylesheets .css
3 |
--------------------------------------------------------------------------------
/bookshelf/app/assets/javascripts/application.js:
--------------------------------------------------------------------------------
1 | // Copyright 2019 Google LLC.
2 | // Licensed under the Apache License, Version 2.0 (the "License");
3 | // you may not use this file except in compliance with the License.
4 | // You may obtain a copy of the License at
5 | //
6 | // http://www.apache.org/licenses/LICENSE-2.0
7 | //
8 | // Unless required by applicable law or agreed to in writing, software
9 | // distributed under the License is distributed on an "AS IS" BASIS,
10 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 | // See the License for the specific language governing permissions and
12 | // limitations under the License.
13 |
14 | // This is a manifest file that'll be compiled into application.js, which will include all the files
15 | // listed below.
16 | //
17 | // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
18 | // or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
19 | //
20 | // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
21 | // compiled file.
22 | //
23 | // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
24 | // about supported directives.
25 | //
26 | //= require jquery
27 | //= require jquery_ujs
28 | //= require_tree .
--------------------------------------------------------------------------------
/bookshelf/app/assets/stylesheets/application.css:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 Google LLC.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 |
16 | /*
17 | * This is a manifest file that'll be compiled into application.css, which will include all the files
18 | * listed below.
19 | *
20 | * Any CSS and SCSS file within this directory, lib/assets/stylesheets, or any plugin's
21 | * vendor/assets/stylesheets directory can be referenced here using a relative path.
22 | *
23 | * You're free to add application-wide styles to this file and they'll appear at the bottom of the
24 | * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
25 | * files in this directory. Styles in this file should be added after the last require_* statement.
26 | * It is generally better to create a new file per style scope.
27 | *
28 | *= require_tree .
29 | *= require_self
30 | */
31 |
--------------------------------------------------------------------------------
/bookshelf/app/controllers/application_controller.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 Google LLC.
2 | # Licensed under the Apache License, Version 2.0 (the "License");
3 | # you may not use this file except in compliance with the License.
4 | # You may obtain a copy of the License at
5 | #
6 | # http://www.apache.org/licenses/LICENSE-2.0
7 | #
8 | # Unless required by applicable law or agreed to in writing, software
9 | # distributed under the License is distributed on an "AS IS" BASIS,
10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 | # See the License for the specific language governing permissions and
12 | # limitations under the License.
13 |
14 | class ApplicationController < ActionController::Base
15 | # Prevent CSRF attacks by raising an exception.
16 | # For APIs, you may want to use :null_session instead.
17 | protect_from_forgery with: :exception
18 | end
19 |
--------------------------------------------------------------------------------
/bookshelf/app/controllers/books_controller.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 Google LLC.
2 | # Licensed under the Apache License, Version 2.0 (the "License");
3 | # you may not use this file except in compliance with the License.
4 | # You may obtain a copy of the License at
5 | #
6 | # http://www.apache.org/licenses/LICENSE-2.0
7 | #
8 | # Unless required by applicable law or agreed to in writing, software
9 | # distributed under the License is distributed on an "AS IS" BASIS,
10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 | # See the License for the specific language governing permissions and
12 | # limitations under the License.
13 |
14 | class BooksController < ApplicationController
15 |
16 | PER_PAGE = 10
17 |
18 | def index
19 | @books = Book.query limit: PER_PAGE, last_title: params[:last_title]
20 | @last_title = @books.last&.title
21 | end
22 |
23 | def new
24 | @book = Book.new
25 | end
26 |
27 | def edit
28 | @book = Book.find params[:id]
29 | end
30 |
31 | def show
32 | @book = Book.find params[:id]
33 | end
34 |
35 | def destroy
36 | @book = Book.find params[:id]
37 | @book.destroy
38 | redirect_to books_path
39 | end
40 |
41 | def update
42 | @book = Book.find params[:id]
43 |
44 | if @book.update book_params
45 | flash[:success] = "Updated Book"
46 | redirect_to book_path(@book)
47 | else
48 | render :edit
49 | end
50 | end
51 |
52 | def create
53 | @book = Book.new book_params
54 |
55 | if @book.create
56 | flash[:success] = "Added Book"
57 | redirect_to book_path(@book)
58 | else
59 | render :new
60 | end
61 | end
62 |
63 | private
64 |
65 | def book_params
66 | params.require(:book).permit :title, :author, :published_on, :description,
67 | :cover_image
68 | end
69 |
70 | end
71 |
--------------------------------------------------------------------------------
/bookshelf/app/controllers/stackdriver_controller.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019, Google, LLC.
2 | # Licensed under the Apache License, Version 2.0 (the "License");
3 | # you may not use this file except in compliance with the License.
4 | # You may obtain a copy of the License at
5 | #
6 | # http://www.apache.org/licenses/LICENSE-2.0
7 | #
8 | # Unless required by applicable law or agreed to in writing, software
9 | # distributed under the License is distributed on an "AS IS" BASIS,
10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 | # See the License for the specific language governing permissions and
12 | # limitations under the License.
13 |
14 | class StackdriverController < ApplicationController
15 | def logs
16 | Rails.logger.add(Logger::INFO, "Hey, you triggered a custom log entry. Good job!")
17 | redirect_to "/books", flash: { success: "Log message sent" }
18 | end
19 |
20 | def errors
21 | raise "This is an intentional exception."
22 | end
23 | end
24 |
--------------------------------------------------------------------------------
/bookshelf/app/models/book.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 Google LLC.
2 | # Licensed under the Apache License, Version 2.0 (the "License");
3 | # you may not use this file except in compliance with the License.
4 | # You may obtain a copy of the License at
5 | #
6 | # http://www.apache.org/licenses/LICENSE-2.0
7 | #
8 | # Unless required by applicable law or agreed to in writing, software
9 | # distributed under the License is distributed on an "AS IS" BASIS,
10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 | # See the License for the specific language governing permissions and
12 | # limitations under the License.
13 |
14 | class Book
15 | # Add Active Model support.
16 | # Provides constructor that takes a Hash of attribute values.
17 | include ActiveModel::Model
18 |
19 | # Add Active Model validation support to Book class.
20 | include ActiveModel::Validations
21 |
22 | validates :title, presence: true
23 |
24 | attr_accessor :id, :title, :author, :published_on, :description, :image_url, :cover_image
25 |
26 | # Return a Google::Cloud::Firestore::Dataset for the configured collection.
27 | # The collection is used to create, read, update, and delete entity objects.
28 | def self.collection
29 | project_id = ENV["GOOGLE_CLOUD_PROJECT"]
30 | raise "Set the GOOGLE_CLOUD_PROJECT environment variable" if project_id.nil?
31 |
32 | # [START bookshelf_firestore_client]
33 | require "google/cloud/firestore"
34 | firestore = Google::Cloud::Firestore.new project_id: project_id
35 | @collection = firestore.col "books"
36 | # [END bookshelf_firestore_client]
37 | end
38 |
39 | def self.storage_bucket
40 | project_id = ENV["GOOGLE_CLOUD_PROJECT"]
41 | raise "Set the GOOGLE_CLOUD_PROJECT environment variable" if project_id.nil?
42 |
43 | @storage_bucket = begin
44 | config = Rails.application.config.x.settings
45 | # [START bookshelf_cloud_storage_client]
46 | require "google/cloud/storage"
47 | bucket_id = project_id + "_bucket"
48 | storage = Google::Cloud::Storage.new project_id: config["project_id"],
49 | credentials: config["keyfile"]
50 | bucket = storage.bucket bucket_id
51 | # [END bookshelf_cloud_storage_client]
52 | raise "bucket does not exist" if bucket.nil?
53 | bucket
54 | end
55 | end
56 |
57 | # Query Book entities from Cloud Firestore.
58 | #
59 | # returns an array of Book query results and the last book title
60 | # that can be used to query for additional results.
61 | def self.query options = {}
62 | query = collection.order :title
63 | query = query.limit options[:limit] if options[:limit]
64 | query = query.start_after options[:last_title] if options[:last_title]
65 |
66 | books = []
67 | begin
68 | query.get do |book|
69 | books << Book.from_snapspot(book)
70 | end
71 | rescue
72 | end
73 | books
74 | end
75 |
76 | def self.requires_pagination last_title
77 | if last_title
78 | collection
79 | .order(:title)
80 | .limit(1)
81 | .start_after(last_title)
82 | .get.count > 0
83 | end
84 | end
85 |
86 | def self.from_snapspot book_snapshot
87 | book = Book.new
88 | book.id = book_snapshot.document_id
89 | book_snapshot.data.each do |name, value|
90 | book.send "#{name}=", value if book.respond_to? "#{name}="
91 | end
92 | book
93 | end
94 |
95 | # Lookup Book by ID. Returns Book or nil.
96 | def self.find id
97 | # [START bookshelf_firestore_client_get_book]
98 | book_snapshot = collection.doc(id).get
99 | Book.from_snapspot book_snapshot if book_snapshot.data
100 | # [END bookshelf_firestore_client_get_book]
101 | end
102 |
103 | # Save the book to Firestore.
104 | # @return true if valid and saved successfully, otherwise false.
105 | def save
106 | if valid?
107 | book_ref = Book.collection.doc id
108 | book_ref.set \
109 | title: title,
110 | author: author,
111 | published_on: published_on,
112 | description: description,
113 | image_url: image_url
114 | self.id = book_ref.document_id
115 | true
116 | else
117 | false
118 | end
119 | end
120 |
121 | def create
122 | upload_image if cover_image
123 | save
124 | end
125 |
126 | # Set attribute values from provided Hash and save to Firestore.
127 | def update attributes
128 | attributes.each do |name, value|
129 | send "#{name}=", value if respond_to? "#{name}="
130 | end
131 | update_image if cover_image
132 | save
133 | end
134 |
135 | def update_image
136 | delete_image if image_url
137 | upload_image
138 | end
139 |
140 | def upload_image
141 | file = Book.storage_bucket.create_file \
142 | cover_image.tempfile,
143 | "cover_images/#{id}/#{cover_image.original_filename}",
144 | content_type: cover_image.content_type,
145 | acl: "public"
146 | @image_url = file.public_url
147 | end
148 |
149 | def destroy
150 | delete_image if image_url
151 | book_ref = Book.collection.doc id
152 | book_ref.delete if book_ref
153 | end
154 |
155 | def delete_image
156 | image_uri = URI.parse image_url
157 |
158 | if image_uri.host == "#{Book.storage_bucket.name}.storage.googleapis.com"
159 | # Remove leading forward slash from image path
160 | # The result will be the image key, eg. "cover_images/:id/:filename"
161 | image_path = image_uri.path.sub "/", ""
162 |
163 | file = Book.storage_bucket.file image_path
164 | file.delete
165 | end
166 | end
167 |
168 | ##################
169 |
170 | def persisted?
171 | id.present?
172 | end
173 | end
174 |
--------------------------------------------------------------------------------
/bookshelf/app/views/books/_form.html.erb:
--------------------------------------------------------------------------------
1 | <%#
2 | Copyright 2019 Google LLC.
3 | Licensed under the Apache License, Version 2.0 (the "License");
4 | you may not use this file except in compliance with the License.
5 | You may obtain a copy of the License at
6 |
7 | http://www.apache.org/licenses/LICENSE-2.0
8 |
9 | Unless required by applicable law or agreed to in writing, software
10 | distributed under the License is distributed on an "AS IS" BASIS,
11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | See the License for the specific language governing permissions and
13 | limitations under the License.
14 | %>
15 |
16 |
Book
17 |
18 | <% if @book.errors.any? %>
19 |
20 | <% @book.errors.full_messages.each do |message| %>
21 |
47 |
48 | <% end %>
49 |
--------------------------------------------------------------------------------
/bookshelf/app/views/books/edit.html.erb:
--------------------------------------------------------------------------------
1 | <%#
2 | Copyright 2019 Google LLC.
3 | Licensed under the Apache License, Version 2.0 (the "License");
4 | you may not use this file except in compliance with the License.
5 | You may obtain a copy of the License at
6 |
7 | http://www.apache.org/licenses/LICENSE-2.0
8 |
9 | Unless required by applicable law or agreed to in writing, software
10 | distributed under the License is distributed on an "AS IS" BASIS,
11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | See the License for the specific language governing permissions and
13 | limitations under the License.
14 | %>
15 |
16 | <%= render partial: "form" %>
17 |
--------------------------------------------------------------------------------
/bookshelf/app/views/books/index.html.erb:
--------------------------------------------------------------------------------
1 | <%#
2 | Copyright 2019 Google LLC.
3 | Licensed under the Apache License, Version 2.0 (the "License");
4 | you may not use this file except in compliance with the License.
5 | You may obtain a copy of the License at
6 |
7 | http://www.apache.org/licenses/LICENSE-2.0
8 |
9 | Unless required by applicable law or agreed to in writing, software
10 | distributed under the License is distributed on an "AS IS" BASIS,
11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | See the License for the specific language governing permissions and
13 | limitations under the License.
14 | %>
15 |
16 |
Books
17 |
18 | <%= link_to new_book_path, class: "btn btn-success btn-sm" do %>
19 |
20 | Add Book
21 | <% end %>
22 |
23 | <% @books.each do |book| %>
24 |
25 | <%= link_to book_path(book) do %>
26 |
27 |
<%= book.title %>
28 |
<%= book.author %>
29 |
30 | <% end %>
31 |
32 | <% end %>
33 |
34 | <% if Book.requires_pagination @last_title %>
35 |
40 | <% end %>
41 |
42 | <% if @books.none? %>
43 |
No books found.
44 | <% end %>
45 |
--------------------------------------------------------------------------------
/bookshelf/app/views/books/new.html.erb:
--------------------------------------------------------------------------------
1 | <%#
2 | Copyright 2019 Google LLC.
3 | Licensed under the Apache License, Version 2.0 (the "License");
4 | you may not use this file except in compliance with the License.
5 | You may obtain a copy of the License at
6 |
7 | http://www.apache.org/licenses/LICENSE-2.0
8 |
9 | Unless required by applicable law or agreed to in writing, software
10 | distributed under the License is distributed on an "AS IS" BASIS,
11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | See the License for the specific language governing permissions and
13 | limitations under the License.
14 | %>
15 |
16 | <%= render partial: "form" %>
17 |
--------------------------------------------------------------------------------
/bookshelf/app/views/books/show.html.erb:
--------------------------------------------------------------------------------
1 | <%#
2 | Copyright 2019 Google LLC.
3 | Licensed under the Apache License, Version 2.0 (the "License");
4 | you may not use this file except in compliance with the License.
5 | You may obtain a copy of the License at
6 |
7 | http://www.apache.org/licenses/LICENSE-2.0
8 |
9 | Unless required by applicable law or agreed to in writing, software
10 | distributed under the License is distributed on an "AS IS" BASIS,
11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | See the License for the specific language governing permissions and
13 | limitations under the License.
14 | %>
15 |
16 |
Book
17 |
18 |
19 | <%= link_to edit_book_path(@book), class: "btn btn-primary btn-sm" do %>
20 |
21 | Edit Book
22 | <% end %>
23 | <%= link_to book_path(@book), class: "btn btn-danger btn-sm", method: :delete do %>
24 |
25 | Delete Book
26 | <% end %>
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
<%= @book.title %> | <%= @book.published_on %>
35 |
By <%= @book.author || "unknown" %>
36 |
<%= @book.description %>
37 |
38 |
39 |
--------------------------------------------------------------------------------
/bookshelf/app/views/layouts/application.html.erb:
--------------------------------------------------------------------------------
1 | <%#
2 | Copyright 2019 Google LLC.
3 | Licensed under the Apache License, Version 2.0 (the "License");
4 | you may not use this file except in compliance with the License.
5 | You may obtain a copy of the License at
6 |
7 | http://www.apache.org/licenses/LICENSE-2.0
8 |
9 | Unless required by applicable law or agreed to in writing, software
10 | distributed under the License is distributed on an "AS IS" BASIS,
11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | See the License for the specific language governing permissions and
13 | limitations under the License.
14 | %>
15 |
16 |
17 |
18 |
19 | Bookshelf - Ruby on Google Cloud Platform
20 |
21 |
22 | <%= stylesheet_link_tag "//maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css" %>
23 | <%= javascript_include_tag "application" %>
24 | <%= csrf_meta_tags %>
25 |
26 |
27 |
38 | <% if flash.any? %>
39 | <% flash.each do |type, message| %>
40 |
<%= message %>
41 | <% end %>
42 | <% end %>
43 | <%= yield %>
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/bookshelf/bin/bundle:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 |
3 | # Copyright 2019 Google LLC.
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # http://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 |
16 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
17 | load Gem.bin_path('bundler', 'bundle')
18 |
--------------------------------------------------------------------------------
/bookshelf/bin/rails:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 |
3 | # Copyright 2019 Google LLC.
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # http://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 |
16 | APP_PATH = File.expand_path('../config/application', __dir__)
17 | require_relative '../config/boot'
18 | require 'rails/commands'
19 |
--------------------------------------------------------------------------------
/bookshelf/bin/rake:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 |
3 | # Copyright 2019 Google LLC.
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # http://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 |
16 | require_relative '../config/boot'
17 | require 'rake'
18 | Rake.application.run
19 |
--------------------------------------------------------------------------------
/bookshelf/bin/setup:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 |
3 | # Copyright 2019 Google LLC.
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # http://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 |
16 | require 'fileutils'
17 | include FileUtils
18 |
19 | # path to your application root.
20 | APP_ROOT = File.expand_path('..', __dir__)
21 |
22 | def system!(*args)
23 | system(*args) || abort("\n== Command #{args} failed ==")
24 | end
25 |
26 | chdir APP_ROOT do
27 | # This script is a starting point to setup your application.
28 | # Add necessary setup steps to this file.
29 |
30 | puts '== Installing dependencies =='
31 | system! 'gem install bundler --conservative'
32 | system('bundle check') || system!('bundle install')
33 |
34 | # puts "\n== Copying sample files =="
35 | # unless File.exist?('config/database.yml')
36 | # cp 'config/database.yml.sample', 'config/database.yml'
37 | # end
38 |
39 | puts "\n== Preparing database =="
40 | system! 'bin/rails db:setup'
41 |
42 | puts "\n== Removing old logs and tempfiles =="
43 | system! 'bin/rails log:clear tmp:clear'
44 |
45 | puts "\n== Restarting application server =="
46 | system! 'bin/rails restart'
47 | end
48 |
--------------------------------------------------------------------------------
/bookshelf/config.ru:
--------------------------------------------------------------------------------
1 | # Copyright 2019 Google LLC.
2 | # Licensed under the Apache License, Version 2.0 (the "License");
3 | # you may not use this file except in compliance with the License.
4 | # You may obtain a copy of the License at
5 | #
6 | # http://www.apache.org/licenses/LICENSE-2.0
7 | #
8 | # Unless required by applicable law or agreed to in writing, software
9 | # distributed under the License is distributed on an "AS IS" BASIS,
10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 | # See the License for the specific language governing permissions and
12 | # limitations under the License.
13 |
14 | # This file is used by Rack-based servers to start the application.
15 |
16 | require_relative 'config/environment'
17 |
18 | run Rails.application
19 |
--------------------------------------------------------------------------------
/bookshelf/config/application.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 Google LLC.
2 | # Licensed under the Apache License, Version 2.0 (the "License");
3 | # you may not use this file except in compliance with the License.
4 | # You may obtain a copy of the License at
5 | #
6 | # http://www.apache.org/licenses/LICENSE-2.0
7 | #
8 | # Unless required by applicable law or agreed to in writing, software
9 | # distributed under the License is distributed on an "AS IS" BASIS,
10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 | # See the License for the specific language governing permissions and
12 | # limitations under the License.
13 |
14 | require_relative 'boot'
15 |
16 | require "rails"
17 | # Pick the frameworks you want:
18 | require "active_model/railtie"
19 | require "active_job/railtie"
20 | require "active_storage/engine"
21 | require "action_controller/railtie"
22 | require "action_view/railtie"
23 | require "sprockets/railtie"
24 | require "google/cloud/error_reporting/rails"
25 |
26 | # Require the gems listed in Gemfile, including any gems
27 | # you've limited to :test, :development, or :production.
28 | Bundler.require(*Rails.groups)
29 |
30 | module Bookshelf
31 | class Application < Rails::Application
32 | # Initialize configuration defaults for originally generated Rails version.
33 | config.load_defaults 5.2
34 |
35 | # Settings in config/environments/* take precedence over those specified here.
36 | # Application configuration can go into files in config/initializers
37 | # -- all .rb files in that directory are automatically loaded after loading
38 | # the framework and any gems in your application.
39 |
40 | # Don't generate system test files.
41 | config.generators.system_tests = nil
42 | end
43 | end
44 |
--------------------------------------------------------------------------------
/bookshelf/config/boot.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 Google LLC.
2 | # Licensed under the Apache License, Version 2.0 (the "License");
3 | # you may not use this file except in compliance with the License.
4 | # You may obtain a copy of the License at
5 | #
6 | # http://www.apache.org/licenses/LICENSE-2.0
7 | #
8 | # Unless required by applicable law or agreed to in writing, software
9 | # distributed under the License is distributed on an "AS IS" BASIS,
10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 | # See the License for the specific language governing permissions and
12 | # limitations under the License.
13 |
14 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
15 |
16 | require 'bundler/setup' # Set up gems listed in the Gemfile.
17 |
--------------------------------------------------------------------------------
/bookshelf/config/environment.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 Google LLC.
2 | # Licensed under the Apache License, Version 2.0 (the "License");
3 | # you may not use this file except in compliance with the License.
4 | # You may obtain a copy of the License at
5 | #
6 | # http://www.apache.org/licenses/LICENSE-2.0
7 | #
8 | # Unless required by applicable law or agreed to in writing, software
9 | # distributed under the License is distributed on an "AS IS" BASIS,
10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 | # See the License for the specific language governing permissions and
12 | # limitations under the License.
13 |
14 | # Load the Rails application.
15 | require_relative 'application'
16 |
17 | # Initialize the Rails application.
18 | Rails.application.initialize!
19 |
--------------------------------------------------------------------------------
/bookshelf/config/environments/development.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 Google LLC.
2 | # Licensed under the Apache License, Version 2.0 (the "License");
3 | # you may not use this file except in compliance with the License.
4 | # You may obtain a copy of the License at
5 | #
6 | # http://www.apache.org/licenses/LICENSE-2.0
7 | #
8 | # Unless required by applicable law or agreed to in writing, software
9 | # distributed under the License is distributed on an "AS IS" BASIS,
10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 | # See the License for the specific language governing permissions and
12 | # limitations under the License.
13 |
14 | Rails.application.configure do
15 | # Settings specified here will take precedence over those in config/application.rb.
16 |
17 | # In the development environment your application's code is reloaded on
18 | # every request. This slows down response time but is perfect for development
19 | # since you don't have to restart the web server when you make code changes.
20 | config.cache_classes = false
21 |
22 | # Do not eager load code on boot.
23 | config.eager_load = false
24 |
25 | # Show full error reports.
26 | config.consider_all_requests_local = true
27 |
28 | # Enable/disable caching. By default caching is disabled.
29 | # Run rails dev:cache to toggle caching.
30 | if Rails.root.join('tmp', 'caching-dev.txt').exist?
31 | config.action_controller.perform_caching = true
32 |
33 | config.cache_store = :memory_store
34 | config.public_file_server.headers = {
35 | 'Cache-Control' => "public, max-age=#{2.days.to_i}"
36 | }
37 | else
38 | config.action_controller.perform_caching = false
39 |
40 | config.cache_store = :null_store
41 | end
42 |
43 | # Store uploaded files on the local file system (see config/storage.yml for options)
44 | # config.active_storage.service = :local
45 |
46 | # Don't care if the mailer can't send.
47 | # config.action_mailer.raise_delivery_errors = false
48 |
49 | # config.action_mailer.perform_caching = false
50 |
51 | # Print deprecation notices to the Rails logger.
52 | config.active_support.deprecation = :log
53 |
54 | # Raise an error on page load if there are pending migrations.
55 | # config.active_record.migration_error = :page_load
56 |
57 | # Highlight code that triggered database queries in logs.
58 | # config.active_record.verbose_query_logs = true
59 |
60 |
61 | # Raises error for missing translations
62 | # config.action_view.raise_on_missing_translations = true
63 |
64 | # Use an evented file watcher to asynchronously detect changes in source code,
65 | # routes, locales, etc. This feature depends on the listen gem.
66 | config.file_watcher = ActiveSupport::EventedFileUpdateChecker
67 | end
68 |
--------------------------------------------------------------------------------
/bookshelf/config/environments/production.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 Google LLC.
2 | # Licensed under the Apache License, Version 2.0 (the "License");
3 | # you may not use this file except in compliance with the License.
4 | # You may obtain a copy of the License at
5 | #
6 | # http://www.apache.org/licenses/LICENSE-2.0
7 | #
8 | # Unless required by applicable law or agreed to in writing, software
9 | # distributed under the License is distributed on an "AS IS" BASIS,
10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 | # See the License for the specific language governing permissions and
12 | # limitations under the License.
13 |
14 | Rails.application.configure do
15 | # Settings specified here will take precedence over those in config/application.rb.
16 |
17 | # Code is not reloaded between requests.
18 | config.cache_classes = true
19 |
20 | # Eager load code on boot. This eager loads most of Rails and
21 | # your application in memory, allowing both threaded web servers
22 | # and those relying on copy on write to perform better.
23 | # Rake tasks automatically ignore this option for performance.
24 | config.eager_load = true
25 |
26 | # Full error reports are disabled and caching is turned on.
27 | config.consider_all_requests_local = false
28 | config.action_controller.perform_caching = true
29 |
30 | # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"]
31 | # or in config/master.key. This key is used to decrypt credentials (and other encrypted files).
32 | # config.require_master_key = true
33 |
34 | # Disable serving static files from the `/public` folder by default since
35 | # Apache or NGINX already handles this.
36 | config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present?
37 |
38 | # Enable serving of images, stylesheets, and JavaScripts from an asset server.
39 | # config.action_controller.asset_host = 'http://assets.example.com'
40 |
41 | # Specifies the header that your server uses for sending files.
42 | # config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache
43 | # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX
44 |
45 | # Store uploaded files on the local file system (see config/storage.yml for options)
46 | # config.active_storage.service = :local
47 |
48 | # Mount Action Cable outside main process or domain
49 | # config.action_cable.mount_path = nil
50 | # config.action_cable.url = 'wss://example.com/cable'
51 | # config.action_cable.allowed_request_origins = [ 'http://example.com', /http:\/\/example.*/ ]
52 |
53 | # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
54 | # config.force_ssl = true
55 |
56 | # Use the lowest log level to ensure availability of diagnostic information
57 | # when problems arise.
58 | config.log_level = :debug
59 |
60 | # Prepend all log lines with the following tags.
61 | config.log_tags = [ :request_id ]
62 |
63 | # Use a different cache store in production.
64 | # config.cache_store = :mem_cache_store
65 |
66 | # Use a real queuing backend for Active Job (and separate queues per environment)
67 | # config.active_job.queue_adapter = :resque
68 | # config.active_job.queue_name_prefix = "bookshelf_#{Rails.env}"
69 |
70 | # config.action_mailer.perform_caching = false
71 |
72 | # Ignore bad email addresses and do not raise email delivery errors.
73 | # Set this to true and configure the email server for immediate delivery to raise delivery errors.
74 | # config.action_mailer.raise_delivery_errors = false
75 |
76 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to
77 | # the I18n.default_locale when a translation cannot be found).
78 | config.i18n.fallbacks = true
79 |
80 | # Send deprecation notices to registered listeners.
81 | config.active_support.deprecation = :notify
82 |
83 | # Use default logging formatter so that PID and timestamp are not suppressed.
84 | config.log_formatter = ::Logger::Formatter.new
85 |
86 | # Use a different logger for distributed setups.
87 | # require 'syslog/logger'
88 | # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new 'app-name')
89 |
90 | if ENV["RAILS_LOG_TO_STDOUT"].present?
91 | logger = ActiveSupport::Logger.new(STDOUT)
92 | logger.formatter = config.log_formatter
93 | config.logger = ActiveSupport::TaggedLogging.new(logger)
94 | end
95 |
96 | # Do not dump schema after migrations.
97 | # config.active_record.dump_schema_after_migration = false
98 | end
99 |
--------------------------------------------------------------------------------
/bookshelf/config/environments/test.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 Google LLC.
2 | # Licensed under the Apache License, Version 2.0 (the "License");
3 | # you may not use this file except in compliance with the License.
4 | # You may obtain a copy of the License at
5 | #
6 | # http://www.apache.org/licenses/LICENSE-2.0
7 | #
8 | # Unless required by applicable law or agreed to in writing, software
9 | # distributed under the License is distributed on an "AS IS" BASIS,
10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 | # See the License for the specific language governing permissions and
12 | # limitations under the License.
13 |
14 | Rails.application.configure do
15 | # Settings specified here will take precedence over those in config/application.rb.
16 |
17 | # The test environment is used exclusively to run your application's
18 | # test suite. You never need to work with it otherwise. Remember that
19 | # your test database is "scratch space" for the test suite and is wiped
20 | # and recreated between test runs. Don't rely on the data there!
21 | config.cache_classes = true
22 |
23 | # Do not eager load code on boot. This avoids loading your whole application
24 | # just for the purpose of running a single test. If you are using a tool that
25 | # preloads Rails for running tests, you may have to set it to true.
26 | config.eager_load = false
27 |
28 | # Configure public file server for tests with Cache-Control for performance.
29 | config.public_file_server.enabled = true
30 | config.public_file_server.headers = {
31 | 'Cache-Control' => "public, max-age=#{1.hour.to_i}"
32 | }
33 |
34 | # Show full error reports and disable caching.
35 | config.consider_all_requests_local = true
36 | config.action_controller.perform_caching = false
37 |
38 | # Raise exceptions instead of rendering exception templates.
39 | config.action_dispatch.show_exceptions = false
40 |
41 | # Disable request forgery protection in test environment.
42 | config.action_controller.allow_forgery_protection = false
43 |
44 | # Store uploaded files on the local file system in a temporary directory
45 | config.active_storage.service = :test
46 |
47 | # config.action_mailer.perform_caching = false
48 |
49 | # Tell Action Mailer not to deliver emails to the real world.
50 | # The :test delivery method accumulates sent emails in the
51 | # ActionMailer::Base.deliveries array.
52 | # config.action_mailer.delivery_method = :test
53 |
54 | # Print deprecation notices to the stderr.
55 | config.active_support.deprecation = :stderr
56 |
57 | # Raises error for missing translations
58 | # config.action_view.raise_on_missing_translations = true
59 | end
60 |
--------------------------------------------------------------------------------
/bookshelf/config/initializers/cookies_serializer.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 Google LLC.
2 | # Licensed under the Apache License, Version 2.0 (the "License");
3 | # you may not use this file except in compliance with the License.
4 | # You may obtain a copy of the License at
5 | #
6 | # http://www.apache.org/licenses/LICENSE-2.0
7 | #
8 | # Unless required by applicable law or agreed to in writing, software
9 | # distributed under the License is distributed on an "AS IS" BASIS,
10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 | # See the License for the specific language governing permissions and
12 | # limitations under the License.
13 |
14 | # Be sure to restart your server when you modify this file.
15 |
16 | # Specify a serializer for the signed and encrypted cookie jars.
17 | # Valid options are :json, :marshal, and :hybrid.
18 | Rails.application.config.action_dispatch.cookies_serializer = :json
19 |
--------------------------------------------------------------------------------
/bookshelf/config/initializers/filter_parameter_logging.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 Google LLC.
2 | # Licensed under the Apache License, Version 2.0 (the "License");
3 | # you may not use this file except in compliance with the License.
4 | # You may obtain a copy of the License at
5 | #
6 | # http://www.apache.org/licenses/LICENSE-2.0
7 | #
8 | # Unless required by applicable law or agreed to in writing, software
9 | # distributed under the License is distributed on an "AS IS" BASIS,
10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 | # See the License for the specific language governing permissions and
12 | # limitations under the License.
13 |
14 | # Be sure to restart your server when you modify this file.
15 |
16 | # Configure sensitive parameters which will be filtered from the log file.
17 | Rails.application.config.filter_parameters += [:password]
18 |
--------------------------------------------------------------------------------
/bookshelf/config/initializers/inflections.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 Google LLC.
2 | # Licensed under the Apache License, Version 2.0 (the "License");
3 | # you may not use this file except in compliance with the License.
4 | # You may obtain a copy of the License at
5 | #
6 | # http://www.apache.org/licenses/LICENSE-2.0
7 | #
8 | # Unless required by applicable law or agreed to in writing, software
9 | # distributed under the License is distributed on an "AS IS" BASIS,
10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 | # See the License for the specific language governing permissions and
12 | # limitations under the License.
13 |
14 | # Be sure to restart your server when you modify this file.
15 |
16 | # Add new inflection rules using the following format. Inflections
17 | # are locale specific, and you may define rules for as many different
18 | # locales as you wish. All of these examples are active by default:
19 | # ActiveSupport::Inflector.inflections(:en) do |inflect|
20 | # inflect.plural /^(ox)$/i, '\1en'
21 | # inflect.singular /^(ox)en/i, '\1'
22 | # inflect.irregular 'person', 'people'
23 | # inflect.uncountable %w( fish sheep )
24 | # end
25 |
26 | # These inflection rules are supported but not enabled by default:
27 | # ActiveSupport::Inflector.inflections(:en) do |inflect|
28 | # inflect.acronym 'RESTful'
29 | # end
30 |
--------------------------------------------------------------------------------
/bookshelf/config/initializers/session_store.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 Google LLC.
2 | # Licensed under the Apache License, Version 2.0 (the "License");
3 | # you may not use this file except in compliance with the License.
4 | # You may obtain a copy of the License at
5 | #
6 | # http://www.apache.org/licenses/LICENSE-2.0
7 | #
8 | # Unless required by applicable law or agreed to in writing, software
9 | # distributed under the License is distributed on an "AS IS" BASIS,
10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 | # See the License for the specific language governing permissions and
12 | # limitations under the License.
13 |
14 | # Be sure to restart your server when you modify this file.
15 |
16 | Rails.application.config.session_store :cookie_store, key: '_Bookshelf_session'
17 |
--------------------------------------------------------------------------------
/bookshelf/config/initializers/wrap_parameters.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 Google LLC.
2 | # Licensed under the Apache License, Version 2.0 (the "License");
3 | # you may not use this file except in compliance with the License.
4 | # You may obtain a copy of the License at
5 | #
6 | # http://www.apache.org/licenses/LICENSE-2.0
7 | #
8 | # Unless required by applicable law or agreed to in writing, software
9 | # distributed under the License is distributed on an "AS IS" BASIS,
10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 | # See the License for the specific language governing permissions and
12 | # limitations under the License.
13 |
14 | # Be sure to restart your server when you modify this file.
15 |
16 | # This file contains settings for ActionController::ParamsWrapper which
17 | # is enabled by default.
18 |
19 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array.
20 | ActiveSupport.on_load(:action_controller) do
21 | wrap_parameters format: [:json]
22 | end
23 |
24 | # To enable root element in JSON for ActiveRecord objects.
25 | # ActiveSupport.on_load(:active_record) do
26 | # self.include_root_in_json = true
27 | # end
28 |
--------------------------------------------------------------------------------
/bookshelf/config/routes.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 Google LLC.
2 | # Licensed under the Apache License, Version 2.0 (the "License");
3 | # you may not use this file except in compliance with the License.
4 | # You may obtain a copy of the License at
5 | #
6 | # http://www.apache.org/licenses/LICENSE-2.0
7 | #
8 | # Unless required by applicable law or agreed to in writing, software
9 | # distributed under the License is distributed on an "AS IS" BASIS,
10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 | # See the License for the specific language governing permissions and
12 | # limitations under the License.
13 |
14 | Rails.application.routes.draw do
15 |
16 | # Route root of application to BooksController#index action
17 | root "books#index"
18 |
19 | # Restful routes for BooksController
20 | resources :books
21 |
22 | get "/logs", to: "stackdriver#logs"
23 | get "/errors", to: "stackdriver#errors"
24 |
25 | end
26 |
--------------------------------------------------------------------------------
/bookshelf/config/secrets.yml:
--------------------------------------------------------------------------------
1 | # Copyright 2019 Google LLC.
2 | # Licensed under the Apache License, Version 2.0 (the "License");
3 | # you may not use this file except in compliance with the License.
4 | # You may obtain a copy of the License at
5 | #
6 | # http://www.apache.org/licenses/LICENSE-2.0
7 | #
8 | # Unless required by applicable law or agreed to in writing, software
9 | # distributed under the License is distributed on an "AS IS" BASIS,
10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 | # See the License for the specific language governing permissions and
12 | # limitations under the License.
13 |
14 | # Be sure to restart your server when you modify this file.
15 |
16 | # Your secret key is used for verifying the integrity of signed cookies.
17 | # If you change this key, all old signed cookies will become invalid!
18 |
19 | # Make sure the secret is at least 30 characters and all random,
20 | # no regular words or you'll be exposed to dictionary attacks.
21 | # You can use `rake secret` to generate a secure secret key.
22 |
23 | # Make sure the secrets in this file are kept private
24 | # if you're sharing your code publicly.
25 |
26 | development:
27 | secret_key_base: db5c071ac181d90e429e9b3b9178f6ff2fbf6a9a68576dd666d85faa0aa9e3e4db59991e24a2a723524e42c1dbc61f0bf1a77451d43569d46f0e3c16b59170e3
28 |
29 | test:
30 | secret_key_base: c2b72729ddf4d841a9e2225b3233f6eb3b42fc8d2585db157161ed44e7760fbec64a694434573b5e5c7fbb20ae5969cfb13198d3dec19242e7d2eb3750406b24
31 |
32 | production:
33 | secret_key_base: 3659d9ac716f22a88f4235cae7c33e9a994492fb0dd5704350863c8bb8cc34571e568651578784185f2ea94a660769e586e72008fb801127df045b4aa4abb0ba
34 | # NOTE You should not keep production secrets in the repository,
35 | # instead read values from the environment:
36 | # secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
37 |
--------------------------------------------------------------------------------
/bookshelf/images/moby-dick.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleCloudPlatform/getting-started-ruby/c3fd0fec8b680de32bf1cee16c5106665cbcd710/bookshelf/images/moby-dick.jpg
--------------------------------------------------------------------------------
/bookshelf/public/404.html:
--------------------------------------------------------------------------------
1 |
15 |
16 |
17 |
18 |
19 | The page you were looking for doesn't exist (404)
20 |
21 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
The page you were looking for doesn't exist.
77 |
You may have mistyped the address or the page may have moved.
78 |
79 |
If you are the application owner check the logs for more information.
If you are the application owner check the logs for more information.
79 |
80 |
81 |
82 |
--------------------------------------------------------------------------------
/bookshelf/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleCloudPlatform/getting-started-ruby/c3fd0fec8b680de32bf1cee16c5106665cbcd710/bookshelf/public/favicon.ico
--------------------------------------------------------------------------------
/bookshelf/public/robots.txt:
--------------------------------------------------------------------------------
1 | # Copyright 2019 Google LLC.
2 | # Licensed under the Apache License, Version 2.0 (the "License");
3 | # you may not use this file except in compliance with the License.
4 | # You may obtain a copy of the License at
5 | #
6 | # http://www.apache.org/licenses/LICENSE-2.0
7 | #
8 | # Unless required by applicable law or agreed to in writing, software
9 | # distributed under the License is distributed on an "AS IS" BASIS,
10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 | # See the License for the specific language governing permissions and
12 | # limitations under the License.
13 |
14 | # See http://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file
15 |
--------------------------------------------------------------------------------
/bookshelf/spec/book_extensions.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 Google LLC.
2 | # Licensed under the Apache License, Version 2.0 (the "License");
3 | # you may not use this file except in compliance with the License.
4 | # You may obtain a copy of the License at
5 | #
6 | # http://www.apache.org/licenses/LICENSE-2.0
7 | #
8 | # Unless required by applicable law or agreed to in writing, software
9 | # distributed under the License is distributed on an "AS IS" BASIS,
10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 | # See the License for the specific language governing permissions and
12 | # limitations under the License.
13 |
14 | # Additional methods added to the Book class for testing only.
15 | module BookExtensions
16 |
17 | def all
18 | collection.get
19 | end
20 |
21 | def first
22 | from_snapspot(all.first)
23 | end
24 |
25 | def count
26 | all.count
27 | end
28 |
29 | def delete_all
30 | collection.get do |book_snapshot|
31 | book_snapshot.ref.delete
32 | end
33 | end
34 |
35 | def exists? id
36 | find(id).present?
37 | end
38 |
39 | def create attributes = nil
40 | book = Book.new attributes
41 | book.save
42 | book
43 | end
44 |
45 | def create! attributes = nil
46 | book = Book.new attributes
47 | raise "Book save failed" unless book.save
48 | book
49 | end
50 |
51 | end
52 |
--------------------------------------------------------------------------------
/bookshelf/spec/e2e_spec_helper.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 Google LLC.
2 | # Licensed under the Apache License, Version 2.0 (the "License");
3 | # you may not use this file except in compliance with the License.
4 | # You may obtain a copy of the License at
5 | #
6 | # http://www.apache.org/licenses/LICENSE-2.0
7 | #
8 | # Unless required by applicable law or agreed to in writing, software
9 | # distributed under the License is distributed on an "AS IS" BASIS,
10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 | # See the License for the specific language governing permissions and
12 | # limitations under the License.
13 |
14 | require "spec_helper"
15 | require "capybara/poltergeist"
16 |
17 | # use the poltergeist (phantomjs) driver for the test
18 | Capybara.current_driver = :poltergeist
19 | Capybara.server = :webrick
20 |
21 | RSpec.configure do |config|
22 | config.after :suite do
23 | if E2E.url? and ENV["E2E_URL"].nil?
24 | E2E.cleanup
25 | end
26 | end
27 | end
28 |
29 | class E2E
30 | @@sample_dir = ""
31 |
32 | class << self
33 | attr_accessor :sample_dir
34 |
35 | def url?
36 | not @url.nil?
37 | end
38 |
39 | def url
40 | deploy
41 | @url
42 | end
43 |
44 | def deploy
45 | if url? || @url = ENV["E2E_URL"]
46 | return
47 | end
48 |
49 | build_id = ENV["BUILD_ID"] || "test"
50 |
51 | version = "#{@sample_dir}-#{build_id}"
52 |
53 | # read in our credentials file
54 | project_id = ENV["GOOGLE_CLOUD_PROJECT"];
55 |
56 | # deploy this sample to gcloud
57 | # try 3 times in case of intermittent deploy error
58 | for attempt in 0..3
59 | exec "gcloud app deploy --version=#{version} -q --no-promote"
60 | break if $?.to_i == 0
61 | end
62 |
63 | # if status is not 0, we tried 3 times and failed
64 | if $?.to_i != 0
65 | puts "Failed to deploy to gcloud"
66 | return $?.to_i
67 | end
68 |
69 | # sleeping 1 to ensure URL is callable
70 | sleep 1
71 |
72 | # run the specs for the step, but use the remote URL
73 | @url = "https://#{version}-dot-#{project_id}.appspot.com"
74 |
75 | # return 0, no errors
76 | return 0
77 | end
78 |
79 | def cleanup()
80 | # determine build number
81 | version = @url.match(/https:\/\/(.+)-dot-(.+).appspot.com/)
82 | unless version
83 | puts "you must pass a build ID or define ENV[\"BUILD_ID\"]"
84 | return 1
85 | end
86 |
87 | # run gcloud command
88 | exec "gcloud app versions delete #{version[1]} -q"
89 |
90 | # return the result of the gcloud delete command
91 | if $?.to_i != 0
92 | puts "Failed to delete e2e version"
93 | return $?.to_i
94 | end
95 |
96 | # return 0, no errors
97 | return 0
98 | end
99 |
100 | def exec(cmd)
101 | puts "> #{cmd}"
102 | puts `#{cmd}`
103 | end
104 | end
105 | end
106 |
--------------------------------------------------------------------------------
/bookshelf/spec/features/book_management_e2e_spec.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 Google LLC.
2 | # Licensed under the Apache License, Version 2.0 (the "License");
3 | # you may not use this file except in compliance with the License.
4 | # You may obtain a copy of the License at
5 | #
6 | # http://www.apache.org/licenses/LICENSE-2.0
7 | #
8 | # Unless required by applicable law or agreed to in writing, software
9 | # distributed under the License is distributed on an "AS IS" BASIS,
10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 | # See the License for the specific language governing permissions and
12 | # limitations under the License.
13 |
14 | require "e2e_spec_helper"
15 |
16 | E2E.sample_dir = "bookshelf"
17 |
18 | feature "Managing Books (e2e)" do
19 |
20 | scenario "Adding a book with missing fields (e2e)", :e2e do
21 | visit E2E.url
22 | click_link "Add Book"
23 | within "form.new_book" do
24 | click_button "Save"
25 | end
26 |
27 | expect(page).to have_content "Title can't be blank"
28 | end
29 |
30 | scenario "Adding a book (e2e)", :e2e do
31 | visit E2E.url
32 |
33 | click_link "Add Book"
34 | within "form.new_book" do
35 | fill_in "Title", with: "A Tale of Two Cities"
36 | fill_in "Author", with: "Charles Dickens"
37 | fill_in "Date Published", with: "1859-04-01"
38 | fill_in "Description", with: "A novel by Charles Dickens"
39 | click_button "Save"
40 | end
41 |
42 | expect(page).to have_content "Added Book"
43 | expect(page).to have_content "A Tale of Two Cities"
44 | end
45 |
46 | scenario "Listing all books (e2e)", :e2e do
47 | visit E2E.url
48 |
49 | expect(page).to have_content "A Tale of Two Cities"
50 | expect(page).to have_content "Charles Dickens"
51 | end
52 |
53 | scenario "Deleting a book (e2e)", :e2e do
54 | visit E2E.url
55 | first(:link , "A Tale of Two Cities").click
56 | click_link "Delete Book"
57 |
58 | expect(current_path).to eq '/books'
59 | end
60 |
61 | end
62 |
--------------------------------------------------------------------------------
/bookshelf/spec/features/book_management_spec.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 Google LLC.
2 | # Licensed under the Apache License, Version 2.0 (the "License");
3 | # you may not use this file except in compliance with the License.
4 | # You may obtain a copy of the License at
5 | #
6 | # http://www.apache.org/licenses/LICENSE-2.0
7 | #
8 | # Unless required by applicable law or agreed to in writing, software
9 | # distributed under the License is distributed on an "AS IS" BASIS,
10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 | # See the License for the specific language governing permissions and
12 | # limitations under the License.
13 |
14 | require "spec_helper"
15 |
16 | feature "Managing Books" do
17 |
18 | scenario "No books have been added" do
19 | visit "/"
20 |
21 | expect(page).to have_content "No books found"
22 | end
23 |
24 | scenario "Listing all books" do
25 | Book.create! title: "A Tale of Two Cities", author: "Charles Dickens"
26 |
27 | visit "/"
28 |
29 | expect(page).to have_content "A Tale of Two Cities"
30 | expect(page).to have_content "Charles Dickens"
31 | end
32 |
33 | scenario "Paginating through list of books" do
34 | Book.delete_all
35 | Book.create! title: "Book 1"
36 | Book.create! title: "Book 2"
37 | Book.create! title: "Book 3"
38 | Book.create! title: "Book 4"
39 | Book.create! title: "Book 5"
40 |
41 | stub_const "BooksController::PER_PAGE", 2
42 |
43 | visit "/"
44 | expect(all(".book").length).to eq 2
45 |
46 | click_link "More"
47 | expect(all(".book").length).to eq 2
48 |
49 | click_link "More"
50 | expect(all(".book").length).to eq 1
51 |
52 | expect(page).not_to have_link "More"
53 | end
54 |
55 | scenario "Adding a book" do
56 | Book.delete_all
57 |
58 | visit "/"
59 | click_link "Add Book"
60 | within "form.new_book" do
61 | fill_in "Title", with: "A Tale of Two Cities"
62 | fill_in "Author", with: "Charles Dickens"
63 | fill_in "Date Published", with: "1859-04-01"
64 | fill_in "Description", with: "A novel by Charles Dickens"
65 | click_button "Save"
66 | end
67 |
68 | expect(page).to have_content "Added Book"
69 |
70 | book = Book.first
71 | expect(book.title).to eq "A Tale of Two Cities"
72 | expect(book.author).to eq "Charles Dickens"
73 | expect(book.published_on).to eq "1859-04-01"
74 | expect(book.description).to eq "A novel by Charles Dickens"
75 | end
76 |
77 | scenario "Adding a book with missing fields" do
78 | Book.delete_all
79 | visit "/"
80 | click_link "Add Book"
81 | within "form.new_book" do
82 | click_button "Save"
83 | end
84 |
85 | expect(page).to have_content "Title can't be blank"
86 |
87 | within "form.new_book" do
88 | fill_in "Title", with: "A Tale of Two Cities"
89 | click_button "Save"
90 | end
91 |
92 | expect(Book.first.title).to eq "A Tale of Two Cities"
93 | end
94 |
95 | scenario "Editing a book" do
96 | Book.delete_all
97 | book = Book.create! title: "A Tale of Two Cities", author: "Charles Dickens"
98 |
99 | visit "/"
100 | click_link "A Tale of Two Cities"
101 | click_link "Edit Book"
102 | fill_in "Title", with: "CHANGED!"
103 | click_button "Save"
104 |
105 | expect(page).to have_content "Updated Book"
106 |
107 | book = Book.find book.id
108 | expect(book.title).to eq "CHANGED!"
109 | expect(book.author).to eq "Charles Dickens"
110 | end
111 |
112 | scenario "Editing a book with missing fields" do
113 | Book.delete_all
114 | book = Book.create! title: "A Tale of Two Cities"
115 |
116 | visit "/"
117 | click_link "A Tale of Two Cities"
118 | click_link "Edit Book"
119 | fill_in "Title", with: ""
120 | click_button "Save"
121 |
122 | expect(page).to have_content "Title can't be blank"
123 | book = Book.find book.id
124 | expect(book.title).to eq "A Tale of Two Cities"
125 |
126 | within "form.edit_book" do
127 | fill_in "Title", with: "CHANGED!"
128 | click_button "Save"
129 | end
130 |
131 | book = Book.find book.id
132 | expect(book.title).to eq "CHANGED!"
133 | end
134 |
135 | scenario "Deleting a book" do
136 | Book.delete_all
137 | book = Book.create! title: "A Tale of Two Cities", author: "Charles Dickens"
138 | expect(Book.exists? book.id).to be true
139 |
140 | visit "/"
141 | click_link "A Tale of Two Cities"
142 | click_link "Delete Book"
143 |
144 | expect(Book.exists? book.id).to be false
145 | end
146 |
147 | end
148 |
--------------------------------------------------------------------------------
/bookshelf/spec/models/book_spec.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 Google LLC.
2 | # Licensed under the Apache License, Version 2.0 (the "License");
3 | # you may not use this file except in compliance with the License.
4 | # You may obtain a copy of the License at
5 | #
6 | # http://www.apache.org/licenses/LICENSE-2.0
7 | #
8 | # Unless required by applicable law or agreed to in writing, software
9 | # distributed under the License is distributed on an "AS IS" BASIS,
10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 | # See the License for the specific language governing permissions and
12 | # limitations under the License.
13 |
14 | require "spec_helper"
15 |
16 | RSpec.describe Book do
17 |
18 | it "requires a title" do
19 | expect(Book.new title: nil).not_to be_valid
20 | expect(Book.new title: "title").to be_valid
21 | end
22 |
23 | end
24 |
--------------------------------------------------------------------------------
/bookshelf/spec/setup.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 | # Copyright 2015 Google Inc.
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # http://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 |
16 | # download cloud-datastore-emulator testing tool
17 | wget -q https://storage.googleapis.com/gcd/tools/cloud-datastore-emulator-1.1.1.zip -O cloud-datastore-emulator.zip
18 | unzip -o cloud-datastore-emulator.zip
19 |
20 | # start cloud-datastore-emulator test server
21 | cloud-datastore-emulator/cloud_datastore_emulator create gcd-test-dataset-directory
22 | cloud-datastore-emulator/cloud_datastore_emulator start --testing ./gcd-test-dataset-directory/ &
23 |
24 | # compile assets directory
25 | RAILS_ENV=test bundle exec rake --rakefile=Rakefile assets:precompile
26 |
--------------------------------------------------------------------------------
/bookshelf/spec/spec_helper.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 Google LLC.
2 | # Licensed under the Apache License, Version 2.0 (the "License");
3 | # you may not use this file except in compliance with the License.
4 | # You may obtain a copy of the License at
5 | #
6 | # http://www.apache.org/licenses/LICENSE-2.0
7 | #
8 | # Unless required by applicable law or agreed to in writing, software
9 | # distributed under the License is distributed on an "AS IS" BASIS,
10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 | # See the License for the specific language governing permissions and
12 | # limitations under the License.
13 |
14 | ENV["RAILS_ENV"] ||= "test"
15 |
16 | require File.expand_path("../../config/environment", __FILE__)
17 |
18 | require "capybara/rspec"
19 | require "capybara/rails"
20 | require "book_extensions"
21 |
22 | Book.send :extend, BookExtensions
23 |
24 | RSpec.configure do |config|
25 | # Retry setup
26 | # show retry status in spec process
27 | config.verbose_retry = true
28 | # show exception that triggers a retry if verbose_retry is set to true
29 | config.display_try_failure_messages = true
30 |
31 | # set retry count and retry sleep interval to 10 seconds
32 | config.default_retry_count = 3
33 | config.default_sleep_interval = 3
34 |
35 | config.expect_with :rspec do |expectations|
36 | expectations.include_chain_clauses_in_custom_matcher_descriptions = true
37 | end
38 |
39 | config.before :all do |example|
40 | Book.delete_all
41 | end
42 | end
43 |
--------------------------------------------------------------------------------
/credentials.json.enc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleCloudPlatform/getting-started-ruby/c3fd0fec8b680de32bf1cee16c5106665cbcd710/credentials.json.enc
--------------------------------------------------------------------------------
/gce/Gemfile:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | source "https://rubygems.org"
4 |
5 | git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
6 |
7 | gem "sinatra", "~> 2.0"
8 |
--------------------------------------------------------------------------------
/gce/README.md:
--------------------------------------------------------------------------------
1 | # Running Ruby apps on Google Compute Engine
2 |
3 | * Creates a Google Compute instance which runs a simple, hello-world sinatra app behind nginx.
4 |
5 | * To run, follow Ruby's [Getting started on Compute Engine](https://cloud.google.com/ruby/tutorials/getting-started-on-compute-engine) tutorial.
6 |
7 | ## Contributing changes
8 |
9 | * See [CONTRIBUTING.md](../CONTRIBUTING.md)
10 |
11 | ## Licensing
12 |
13 | * See [LICENSE](../LICENSE)
14 |
--------------------------------------------------------------------------------
/gce/app.rb:
--------------------------------------------------------------------------------
1 | require "sinatra"
2 |
3 | get "/" do
4 | "
Hello World
"
5 | end
6 |
--------------------------------------------------------------------------------
/gce/deploy.sh:
--------------------------------------------------------------------------------
1 | # Copyright 2019 Google LLC All Rights Reserved.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | # [START getting_started_gce_create_instance]
16 | MY_INSTANCE_NAME="my-app-instance"
17 | ZONE=us-central1-a
18 |
19 | gcloud compute instances create $MY_INSTANCE_NAME \
20 | --image-family=debian-9 \
21 | --image-project=debian-cloud \
22 | --machine-type=g1-small \
23 | --scopes userinfo-email,cloud-platform \
24 | --metadata-from-file startup-script=startup-script.sh \
25 | --zone $ZONE \
26 | --tags http-server
27 | # [END getting_started_gce_create_instance]
28 |
29 | # [START getting_started_gce_allow_port]
30 | gcloud compute firewall-rules create default-allow-http-80 \
31 | --allow tcp:80 \
32 | --source-ranges 0.0.0.0/0 \
33 | --target-tags http-server \
34 | --description "Allow port 80 access to http-server"
35 | # [END getting_started_gce_allow_port]
36 |
--------------------------------------------------------------------------------
/gce/rubyapp.conf:
--------------------------------------------------------------------------------
1 | server {
2 | listen 80 default_server;
3 | listen [::]:80 default_server;
4 |
5 | location / {
6 | proxy_pass http://localhost:4567;
7 | proxy_set_header Host $host;
8 | proxy_set_header X-Real-IP $remote_addr;
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/gce/startup-script.sh:
--------------------------------------------------------------------------------
1 | # Copyright 2019 Google LLC All Rights Reserved.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | # [START getting_started_gce_startup_script]
16 | # Install Stackdriver logging agent
17 | curl -sSO https://dl.google.com/cloudagents/install-logging-agent.sh
18 | bash install-logging-agent.sh
19 |
20 | # Install dependencies
21 | apt-get update && apt-get -y upgrade && apt-get install -y autoconf bison \
22 | build-essential git libssl-dev libyaml-dev libreadline6-dev zlib1g-dev \
23 | libncurses5-dev libffi-dev libgdbm3 libgdbm-dev nginx supervisor
24 |
25 | # Account to own server process
26 | useradd -m -d /home/rubyapp rubyapp
27 |
28 | # Install Ruby and Bundler
29 | mkdir /home/rubyapp/.ruby
30 | git clone https://github.com/rbenv/ruby-build.git /home/rubyapp/.ruby-build
31 | /home/rubyapp/.ruby-build/bin/ruby-build 2.6.5 /home/rubyapp/.ruby
32 |
33 | chown -R rubyapp:rubyapp /home/rubyapp
34 |
35 | cat >/home/rubyapp/.profile << EOF
36 | export PATH="/home/rubyapp/.ruby/bin:$PATH"
37 | EOF
38 |
39 | su -l rubyapp -c "gem install bundler"
40 |
41 | # Fetch source code
42 | git clone https://github.com/GoogleCloudPlatform/getting-started-ruby.git /opt/app
43 |
44 | # Set ownership to newly created account
45 | chown -R rubyapp:rubyapp /opt/app
46 |
47 | # Install ruby dependencies
48 | su -l rubyapp -c "cd /opt/app/gce && bundle install"
49 |
50 | # Disable the default NGINX configuration
51 | rm /etc/nginx/sites-enabled/default
52 |
53 | # Enable our NGINX configuration
54 | cp /opt/app/gce/rubyapp.conf /etc/nginx/sites-available/rubyapp.conf
55 | ln -s /etc/nginx/sites-available/rubyapp.conf /etc/nginx/sites-enabled/rubyapp.conf
56 |
57 | # Start NGINX
58 | systemctl restart nginx.service
59 |
60 | # Configure supervisor to run the ruby app
61 | cat >/etc/supervisor/conf.d/rubyapp.conf << EOF
62 | [program:rubyapp]
63 | directory=/opt/app/gce
64 | command=bash -lc "bundle exec ruby app.rb"
65 | autostart=true
66 | autorestart=true
67 | user=rubyapp
68 | environment=HOME="/home/rubyapp",USER="rubyapp"
69 | stdout_logfile=syslog
70 | stderr_logfile=syslog
71 | EOF
72 |
73 | supervisorctl reread
74 | supervisorctl update
75 |
76 | # Application should now be running under supervisor
77 | # [END getting_started_gce_startup_script]
78 |
--------------------------------------------------------------------------------
/gce/teardown.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | # Copyright 2019 Google LLC All Rights Reserved.
4 | #
5 | # Licensed under the Apache License, Version 2.0 (the "License");
6 | # you may not use this file except in compliance with the License.
7 | # You may obtain a copy of the License at
8 | #
9 | # http://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing, software
12 | # distributed under the License is distributed on an "AS IS" BASIS,
13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | # See the License for the specific language governing permissions and
15 | # limitations under the License.
16 |
17 | set -x
18 |
19 | # [START getting_started_gce_teardown]
20 | MY_INSTANCE_NAME="my-app-instance"
21 | ZONE=us-central1-a
22 |
23 | gcloud compute instances delete $MY_INSTANCE_NAME \
24 | --zone=$ZONE --delete-disks=all
25 |
26 | gcloud compute firewall-rules delete default-allow-http-80
27 | # [END getting_started_gce_teardown]
28 |
--------------------------------------------------------------------------------
/sessions/Gemfile:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | source "https://rubygems.org"
4 |
5 | git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
6 |
7 | # [START getting_started_sessions_requirements]
8 | gem "google-cloud-firestore", "~> 1.2"
9 | gem "sinatra", "~> 2.0"
10 | # [END getting_started_sessions_requirements]
11 |
12 | group :development do
13 | gem "minitest", "~> 5.13"
14 | gem "rack-test", "~> 1.1"
15 | gem "rake", "~> 13.0"
16 | end
17 |
--------------------------------------------------------------------------------
/sessions/README.md:
--------------------------------------------------------------------------------
1 | # Session handling with Firestore
2 |
3 | * A short App Engine app, which uses [Firestore](https://cloud.google.com/firestore/) to serve a webpage saying `"#{session['views']} views for #{session['greeting']}"`. Here, `session["greeting"]` is one of `["Hello World", "Hallo Welt", "Ciao Mondo", "Salut le Monde", "Hola Mundo"]` which has been randomly assigned to the viewer, and `session["views"]` is the number of times that viewer has loaded the page.
4 | * To run, follow Ruby's [Handling sessions with Cloud Firestore](https://cloud.google.com/ruby/getting-started/session-handling-with-firestore) tutorial.
5 |
6 | ## Contributing changes
7 |
8 | * See [CONTRIBUTING.md](../CONTRIBUTING.md)
9 |
10 | ## Licensing
11 |
12 | * See [LICENSE](../LICENSE)
13 |
--------------------------------------------------------------------------------
/sessions/Rakefile:
--------------------------------------------------------------------------------
1 | require "rake/testtask"
2 |
3 | desc "Run tests."
4 | Rake::TestTask.new :test do |t|
5 | t.test_files = FileList["test/**/*_test.rb"]
6 | t.warning = false
7 | end
8 |
9 | Rake::TestTask.new :acceptance do |t|
10 | t.test_files = FileList["acceptance/**/*_test.rb"]
11 | t.warning = false
12 | end
13 |
--------------------------------------------------------------------------------
/sessions/acceptance/app_test.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path "../../test/test_helper.rb", __FILE__
2 |
3 | include Rack::Test::Methods
4 |
5 | def app
6 | Sinatra::Application
7 | end
8 |
9 | def firestore
10 | firestore = Google::Cloud::Firestore.new
11 | end
12 |
13 | def col
14 | col = firestore.col "sessions"
15 | end
16 |
17 | def docs
18 | docs = col.list_documents
19 | end
20 |
21 | def delete_all_sessions
22 | docs.each do |doc|
23 | firestore.batch do |b|
24 | b.delete doc.document_path
25 | end
26 | end
27 | end
28 |
29 | describe "app" do
30 | before do
31 | delete_all_sessions
32 | end
33 |
34 | after do
35 | delete_all_sessions
36 | end
37 |
38 | it "should display the number of views" do
39 | get "/"
40 | assert_match /\d+ views for /, last_response.body
41 | end
42 |
43 | it "should increment the number of views on successive views" do
44 | get "/"
45 | view_count = last_response.body.match(/(\d+)\s/)[1].to_i
46 | get "/"
47 | updated_view_count = last_response.body.match(/(\d+)\s/)[1].to_i
48 | assert_equal view_count + 1, updated_view_count
49 | end
50 |
51 | it "should not change the greeting on successive views" do
52 | get "/"
53 | greeting = last_response.body.match(/(\d|\s|\w)*(".*")/)[2]
54 | get "/"
55 | updated_greeting = last_response.body.match(/(\d|\s|\w)*(".*")/)[2]
56 | assert_equal greeting, updated_greeting
57 | end
58 |
59 | it "should store the data in firestore" do
60 | 3.times do
61 | get "/"
62 | view_count = last_response.body.match(/(\d+)\s/)[1].to_i
63 | greeting = last_response.body.match(/(\d|\s|\w)*"(.*)"/)[2]
64 | doc = col.doc(docs.first.document_id).get
65 | assert_equal doc.fields[:greeting], greeting
66 | assert_equal doc.fields[:views], view_count
67 | end
68 | end
69 | end
70 |
--------------------------------------------------------------------------------
/sessions/app.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019, Google LLC.
2 | # Licensed under the Apache License, Version 2.0 (the "License");
3 | # you may not use this file except in compliance with the License.
4 | # You may obtain a copy of the License at
5 | #
6 | # http://www.apache.org/licenses/LICENSE-2.0
7 | #
8 | # Unless required by applicable law or agreed to in writing, software
9 | # distributed under the License is distributed on an "AS IS" BASIS,
10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 | # See the License for the specific language governing permissions and
12 | # limitations under the License.
13 |
14 | # [START getting_started_session_app]
15 | require "sinatra"
16 |
17 | require_relative "firestore_session"
18 |
19 | use Rack::Session::FirestoreSession
20 |
21 | set :greetings, ["Hello World", "Hallo Welt", "Ciao Mondo", "Salut le Monde", "Hola Mundo"]
22 |
23 | get "/" do
24 | session[:greeting] ||= settings.greetings.sample
25 | session[:views] ||= 0
26 | session[:views] += 1
27 | "
#{session[:views]} views for \"#{session[:greeting]}\"
"
28 | end
29 | # [END getting_started_session_app]
30 |
--------------------------------------------------------------------------------
/sessions/app.yaml:
--------------------------------------------------------------------------------
1 | # [START getting_started_sessions_runtime]
2 | runtime: ruby25
3 | entrypoint: bundle exec ruby app.rb
4 | # [END getting_started_sessions_runtime]
5 |
--------------------------------------------------------------------------------
/sessions/firestore_session.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019, Google LLC.
2 | # Licensed under the Apache License, Version 2.0 (the "License");
3 | # you may not use this file except in compliance with the License.
4 | # You may obtain a copy of the License at
5 | #
6 | # http://www.apache.org/licenses/LICENSE-2.0
7 | #
8 | # Unless required by applicable law or agreed to in writing, software
9 | # distributed under the License is distributed on an "AS IS" BASIS,
10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 | # See the License for the specific language governing permissions and
12 | # limitations under the License.
13 |
14 | # [START getting_started_session]
15 | require "google/cloud/firestore"
16 | require "rack/session/abstract/id"
17 |
18 | module Rack
19 | module Session
20 | class FirestoreSession < Abstract::Persisted
21 | def initialize app, options = {}
22 | super
23 |
24 | @firestore = Google::Cloud::Firestore.new
25 | @col = @firestore.col "sessions"
26 | end
27 |
28 | def find_session _req, session_id
29 | return [generate_sid, {}] if session_id.nil?
30 |
31 | doc = @col.doc session_id
32 | fields = doc.get.fields || {}
33 | [session_id, stringify_keys(fields)]
34 | end
35 |
36 | def write_session _req, session_id, new_session, _opts
37 | doc = @col.doc session_id
38 | doc.set new_session, merge: true
39 | session_id
40 | end
41 |
42 | def delete_session _req, session_id, _opts
43 | doc = @col.doc session_id
44 | doc.delete
45 | generate_sid
46 | end
47 |
48 | def stringify_keys hash
49 | new_hash = {}
50 | hash.each do |k, v|
51 | new_hash[k.to_s] =
52 | if v.is_a? Hash
53 | stringify_keys v
54 | else
55 | v
56 | end
57 | end
58 | new_hash
59 | end
60 | end
61 | end
62 | end
63 | # [END getting_started_session]
64 |
--------------------------------------------------------------------------------
/sessions/test/app_test.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path "../test_helper.rb", __FILE__
2 |
3 | include Rack::Test::Methods
4 |
5 | def app
6 | Sinatra::Application
7 | end
8 |
9 | class FirestoreSessionMock < Rack::Session::Abstract::Persisted
10 | def initialize app, options = {}
11 | super
12 | @data = {}
13 | end
14 |
15 | def find_session _req, session_id
16 | return [generate_sid, {}] if session_id.nil?
17 | return session_id, @data[session_id]
18 | end
19 |
20 | def write_session _req, session_id, new_session, _opts
21 | @data[session_id] = new_session
22 | session_id
23 | end
24 |
25 | def delete_session _req, session_id, _opts
26 | @data.delete[session_id]
27 | generate_sid
28 | end
29 | end
30 |
31 | describe "app" do
32 | before do
33 | @mock_session = lambda do |app, options = {}|
34 | FirestoreSessionMock.new app, {}
35 | end
36 | end
37 |
38 | it "should display a greeting" do
39 | Rack::Session::FirestoreSession.stub :new, @mock_session do
40 | get "/"
41 | greetings = /"Hello World"|"Hallo Welt"|"Ciao Mondo"|"Salut le Monde"|"Hola Mundo"/
42 | assert_match greetings, last_response.body
43 | end
44 |
45 | end
46 |
47 | it "should display the number of views" do
48 | Rack::Session::FirestoreSession.stub :new, @mock_session do
49 | get "/"
50 | assert_match /\d+ views for /, last_response.body
51 | end
52 | end
53 |
54 | it "should increment the number of views on successive views" do
55 | Rack::Session::FirestoreSession.stub :new, @mock_session do
56 | get "/"
57 | view_count = last_response.body.match(/(\d+)\s/)[1].to_i
58 | get "/"
59 | updated_view_count = last_response.body.match(/(\d+)\s/)[1].to_i
60 | assert_equal view_count + 1, updated_view_count
61 | end
62 | end
63 |
64 | it "should not change the greeting on successive views" do
65 | Rack::Session::FirestoreSession.stub :new, @mock_session do
66 | get "/"
67 | greeting = last_response.body.match(/(\d|\s|\w)*(".*")/)[2]
68 | 4.times do
69 | get "/"
70 | updated_greeting = last_response.body.match(/(\d|\s|\w)*(".*")/)[2]
71 | assert_equal greeting, updated_greeting
72 | end
73 | end
74 | end
75 | end
76 |
--------------------------------------------------------------------------------
/sessions/test/test_helper.rb:
--------------------------------------------------------------------------------
1 | ENV["RACK_ENV"] = "test"
2 | require "minitest/autorun"
3 | require "rack/test"
4 |
5 | require File.expand_path "../../app.rb", __FILE__
6 |
--------------------------------------------------------------------------------