├── .gitignore ├── .reuse └── dep5 ├── LICENSE ├── LICENSES └── Apache-2.0.txt ├── README.md ├── app ├── index.cds └── risks │ ├── annotations.cds │ └── webapp │ ├── Component.js │ ├── i18n │ └── i18n.properties │ ├── index.html │ └── manifest.json ├── approuter ├── package.json └── xs-app.json ├── db ├── data │ ├── sap.ui.riskmanagement-BusinessPartners.csv │ ├── sap.ui.riskmanagement-Mitigations.csv │ └── sap.ui.riskmanagement-Risks.csv └── schema.cds ├── exercises ├── ex0 │ ├── README.md │ └── images │ │ ├── 00_00_0010.png │ │ ├── 00_00_0020.png │ │ ├── 00_00_0030.png │ │ ├── 00_00_0040.png │ │ ├── 00_00_0050.png │ │ ├── 00_00_0060.png │ │ └── 00_00_0070.png ├── ex1 │ ├── README.md │ └── images │ │ ├── 01_01_0010.png │ │ ├── 01_01_0020.png │ │ ├── 01_01_0030.png │ │ ├── 01_01_0040.png │ │ ├── 01_01_0050.png │ │ ├── 01_01_0060.png │ │ ├── 01_01_0070.png │ │ ├── 01_01_0080.png │ │ ├── 01_01_0090.png │ │ ├── 01_01_0100.png │ │ ├── 01_02_0010.png │ │ ├── 01_02_0020.png │ │ ├── 01_02_0030.png │ │ ├── 01_02_0040.png │ │ ├── 01_02_0050.png │ │ ├── 01_02_0060.png │ │ ├── 01_02_0070.png │ │ ├── 01_02_0075.png │ │ ├── 01_02_0080.png │ │ ├── 01_02_0090.png │ │ ├── 01_02_0100.png │ │ ├── 01_02_0110.png │ │ ├── 01_02_0120.png │ │ ├── 01_02_0130.png │ │ ├── 01_03_0010.png │ │ ├── 01_03_0020.png │ │ ├── 01_03_0030.png │ │ ├── 01_03_0040.png │ │ ├── 01_03_0050.png │ │ ├── 01_04_0010.png │ │ ├── 01_04_0020.png │ │ └── 01_06_0010.png ├── ex2 │ └── README.md └── ex3 │ ├── README.md │ └── images │ ├── CICD_CAP_job.png │ ├── CICD_ServiceTile.png │ ├── CICD_access.png │ ├── CICD_credentials.png │ ├── CICD_credentials_cfdeploy.png │ ├── CICD_credentials_github.png │ ├── CICD_jobs.png │ ├── CICD_running_job.png │ ├── CICD_subscribe_service.png │ ├── CICD_successful_build.png │ ├── CICD_trigger_job.png │ ├── CICD_webhook.png │ ├── CICD_webhook1.png │ ├── CICD_webhook2.png │ ├── CICD_webhook3.png │ ├── CP_API_Endpoint.png │ ├── CP_cloudfoundry.png │ ├── GH_copyGitHubURL.png │ ├── GH_createGitRepo.png │ ├── GH_newRepository.png │ ├── GH_webhook.png │ ├── GH_webhook_details.png │ ├── RiskManagement-RoleCollection.png │ ├── RiskManagement-Trust.png │ ├── RiskManagment_cpapp_running.png │ ├── RiskManagment_final.png │ ├── RiskManagment_running.png │ ├── RiskMngmt_home.png │ ├── openBizAppStudio.png │ └── openTerminal.png ├── mta.yaml ├── package.json ├── srv ├── external │ ├── API_BUSINESS_PARTNER.csn │ ├── API_BUSINESS_PARTNER.edmx │ └── data │ │ └── API_BUSINESS_PARTNER-A_BusinessPartner.csv ├── risk-service.cds ├── risk-service.js └── risks-service-ui.cds └── xs-security.json /.gitignore: -------------------------------------------------------------------------------- 1 | # CAP 2 | _out 3 | *.db 4 | connection.properties 5 | gen/ 6 | node_modules/ 7 | target/ 8 | 9 | # App Studio 10 | .che/ 11 | .gen/ 12 | 13 | # MTA 14 | *_mta_build_tmp 15 | *.mtar 16 | mta_archives/ 17 | 18 | # Other 19 | .DS_Store 20 | *.orig 21 | *.log 22 | 23 | # Source folder of SAP Fiori Tools generated project 24 | app/risks/src 25 | *.iml 26 | *.flattened-pom.xml 27 | 28 | package-lock.json -------------------------------------------------------------------------------- /.reuse/dep5: -------------------------------------------------------------------------------- 1 | Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ 2 | Upstream-Name: teched2020-DEV166 3 | Upstream-Contact: () 4 | Source: https://github.com/sap-samples/teched2020-DEV166 5 | Disclaimer: The code in this project may include calls to APIs (“API Calls”) of 6 | SAP or third-party products or services developed outside of this project 7 | (“External Products”). 8 | “APIs” means application programming interfaces, as well as their respective 9 | specifications and implementing code that allows software to communicate with 10 | other software. 11 | API Calls to External Products are not licensed under the open source license 12 | that governs this project. The use of such API Calls and related External 13 | Products are subject to applicable additional agreements with the relevant 14 | provider of the External Products. In no event shall the open source license 15 | that governs this project grant any rights in or to any External Products,or 16 | alter, expand or supersede any terms of the applicable additional agreements. 17 | If you have a valid license agreement with SAP for the use of a particular SAP 18 | External Product, then you may make use of any API Calls included in this 19 | project’s code for that SAP External Product, subject to the terms of such 20 | license agreement. If you do not have a valid license agreement for the use of 21 | a particular SAP External Product, then you may only make use of any API Calls 22 | in this project for that SAP External Product for your internal, non-productive 23 | and non-commercial test and evaluation of such API Calls. Nothing herein grants 24 | you any rights to use or access any SAP External Product, or provide any third 25 | parties the right to use of access any SAP External Product, through API Calls. 26 | 27 | Files: * 28 | Copyright: 2020 SAP SE or an SAP affiliate company and teched2020-DEV166 Contributors 29 | License: Apache-2.0 30 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /LICENSES/Apache-2.0.txt: -------------------------------------------------------------------------------- 1 | Apache License 2 | 3 | Version 2.0, January 2004 4 | 5 | http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, 6 | AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | 11 | 12 | "License" shall mean the terms and conditions for use, reproduction, and distribution 13 | as defined by Sections 1 through 9 of this document. 14 | 15 | 16 | 17 | "Licensor" shall mean the copyright owner or entity authorized by the copyright 18 | owner that is granting the License. 19 | 20 | 21 | 22 | "Legal Entity" shall mean the union of the acting entity and all other entities 23 | that control, are controlled by, or are under common control with that entity. 24 | For the purposes of this definition, "control" means (i) the power, direct 25 | or indirect, to cause the direction or management of such entity, whether 26 | by contract or otherwise, or (ii) ownership of fifty percent (50%) or more 27 | of the outstanding shares, or (iii) beneficial ownership of such entity. 28 | 29 | 30 | 31 | "You" (or "Your") shall mean an individual or Legal Entity exercising permissions 32 | granted by this License. 33 | 34 | 35 | 36 | "Source" form shall mean the preferred form for making modifications, including 37 | but not limited to software source code, documentation source, and configuration 38 | files. 39 | 40 | 41 | 42 | "Object" form shall mean any form resulting from mechanical transformation 43 | or translation of a Source form, including but not limited to compiled object 44 | code, generated documentation, and conversions to other media types. 45 | 46 | 47 | 48 | "Work" shall mean the work of authorship, whether in Source or Object form, 49 | made available under the License, as indicated by a copyright notice that 50 | is included in or attached to the work (an example is provided in the Appendix 51 | below). 52 | 53 | 54 | 55 | "Derivative Works" shall mean any work, whether in Source or Object form, 56 | that is based on (or derived from) the Work and for which the editorial revisions, 57 | annotations, elaborations, or other modifications represent, as a whole, an 58 | original work of authorship. For the purposes of this License, Derivative 59 | Works shall not include works that remain separable from, or merely link (or 60 | bind by name) to the interfaces of, the Work and Derivative Works thereof. 61 | 62 | 63 | 64 | "Contribution" shall mean any work of authorship, including the original version 65 | of the Work and any modifications or additions to that Work or Derivative 66 | Works thereof, that is intentionally submitted to Licensor for inclusion in 67 | the Work by the copyright owner or by an individual or Legal Entity authorized 68 | to submit on behalf of the copyright owner. For the purposes of this definition, 69 | "submitted" means any form of electronic, verbal, or written communication 70 | sent to the Licensor or its representatives, including but not limited to 71 | communication on electronic mailing lists, source code control systems, and 72 | issue tracking systems that are managed by, or on behalf of, the Licensor 73 | for the purpose of discussing and improving the Work, but excluding communication 74 | that is conspicuously marked or otherwise designated in writing by the copyright 75 | owner as "Not a Contribution." 76 | 77 | 78 | 79 | "Contributor" shall mean Licensor and any individual or Legal Entity on behalf 80 | of whom a Contribution has been received by Licensor and subsequently incorporated 81 | within the Work. 82 | 83 | 2. Grant of Copyright License. Subject to the terms and conditions of this 84 | License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, 85 | no-charge, royalty-free, irrevocable copyright license to reproduce, prepare 86 | Derivative Works of, publicly display, publicly perform, sublicense, and distribute 87 | the Work and such Derivative Works in Source or Object form. 88 | 89 | 3. Grant of Patent License. Subject to the terms and conditions of this License, 90 | each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, 91 | no-charge, royalty-free, irrevocable (except as stated in this section) patent 92 | license to make, have made, use, offer to sell, sell, import, and otherwise 93 | transfer the Work, where such license applies only to those patent claims 94 | licensable by such Contributor that are necessarily infringed by their Contribution(s) 95 | alone or by combination of their Contribution(s) with the Work to which such 96 | Contribution(s) was submitted. If You institute patent litigation against 97 | any entity (including a cross-claim or counterclaim in a lawsuit) alleging 98 | that the Work or a Contribution incorporated within the Work constitutes direct 99 | or contributory patent infringement, then any patent licenses granted to You 100 | under this License for that Work shall terminate as of the date such litigation 101 | is filed. 102 | 103 | 4. Redistribution. You may reproduce and distribute copies of the Work or 104 | Derivative Works thereof in any medium, with or without modifications, and 105 | in Source or Object form, provided that You meet the following conditions: 106 | 107 | (a) You must give any other recipients of the Work or Derivative Works a copy 108 | of this License; and 109 | 110 | (b) You must cause any modified files to carry prominent notices stating that 111 | You changed the files; and 112 | 113 | (c) You must retain, in the Source form of any Derivative Works that You distribute, 114 | all copyright, patent, trademark, and attribution notices from the Source 115 | form of the Work, excluding those notices that do not pertain to any part 116 | of the Derivative Works; and 117 | 118 | (d) If the Work includes a "NOTICE" text file as part of its distribution, 119 | then any Derivative Works that You distribute must include a readable copy 120 | of the attribution notices contained within such NOTICE file, excluding those 121 | notices that do not pertain to any part of the Derivative Works, in at least 122 | one of the following places: within a NOTICE text file distributed as part 123 | of the Derivative Works; within the Source form or documentation, if provided 124 | along with the Derivative Works; or, within a display generated by the Derivative 125 | Works, if and wherever such third-party notices normally appear. The contents 126 | of the NOTICE file are for informational purposes only and do not modify the 127 | License. You may add Your own attribution notices within Derivative Works 128 | that You distribute, alongside or as an addendum to the NOTICE text from the 129 | Work, provided that such additional attribution notices cannot be construed 130 | as modifying the License. 131 | 132 | You may add Your own copyright statement to Your modifications and may provide 133 | additional or different license terms and conditions for use, reproduction, 134 | or distribution of Your modifications, or for any such Derivative Works as 135 | a whole, provided Your use, reproduction, and distribution of the Work otherwise 136 | complies with the conditions stated in this License. 137 | 138 | 5. Submission of Contributions. Unless You explicitly state otherwise, any 139 | Contribution intentionally submitted for inclusion in the Work by You to the 140 | Licensor shall be under the terms and conditions of this License, without 141 | any additional terms or conditions. Notwithstanding the above, nothing herein 142 | shall supersede or modify the terms of any separate license agreement you 143 | may have executed with Licensor regarding such Contributions. 144 | 145 | 6. Trademarks. This License does not grant permission to use the trade names, 146 | trademarks, service marks, or product names of the Licensor, except as required 147 | for reasonable and customary use in describing the origin of the Work and 148 | reproducing the content of the NOTICE file. 149 | 150 | 7. Disclaimer of Warranty. Unless required by applicable law or agreed to 151 | in writing, Licensor provides the Work (and each Contributor provides its 152 | Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 153 | KIND, either express or implied, including, without limitation, any warranties 154 | or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR 155 | A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness 156 | of using or redistributing the Work and assume any risks associated with Your 157 | exercise of permissions under this License. 158 | 159 | 8. Limitation of Liability. In no event and under no legal theory, whether 160 | in tort (including negligence), contract, or otherwise, unless required by 161 | applicable law (such as deliberate and grossly negligent acts) or agreed to 162 | in writing, shall any Contributor be liable to You for damages, including 163 | any direct, indirect, special, incidental, or consequential damages of any 164 | character arising as a result of this License or out of the use or inability 165 | to use the Work (including but not limited to damages for loss of goodwill, 166 | work stoppage, computer failure or malfunction, or any and all other commercial 167 | damages or losses), even if such Contributor has been advised of the possibility 168 | of such damages. 169 | 170 | 9. Accepting Warranty or Additional Liability. While redistributing the Work 171 | or Derivative Works thereof, You may choose to offer, and charge a fee for, 172 | acceptance of support, warranty, indemnity, or other liability obligations 173 | and/or rights consistent with this License. However, in accepting such obligations, 174 | You may act only on Your own behalf and on Your sole responsibility, not on 175 | behalf of any other Contributor, and only if You agree to indemnify, defend, 176 | and hold each Contributor harmless for any liability incurred by, or claims 177 | asserted against, such Contributor by reason of your accepting any such warranty 178 | or additional liability. END OF TERMS AND CONDITIONS 179 | 180 | APPENDIX: How to apply the Apache License to your work. 181 | 182 | To apply the Apache License to your work, attach the following boilerplate 183 | notice, with the fields enclosed by brackets "[]" replaced with your own identifying 184 | information. (Don't include the brackets!) The text should be enclosed in 185 | the appropriate comment syntax for the file format. We also recommend that 186 | a file or class name and description of purpose be included on the same "printed 187 | page" as the copyright notice for easier identification within third-party 188 | archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | 194 | you may not use this file except in compliance with the License. 195 | 196 | You may obtain a copy of the License at 197 | 198 | http://www.apache.org/licenses/LICENSE-2.0 199 | 200 | Unless required by applicable law or agreed to in writing, software 201 | 202 | distributed under the License is distributed on an "AS IS" BASIS, 203 | 204 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 205 | 206 | See the License for the specific language governing permissions and 207 | 208 | limitations under the License. 209 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DEV166 - Extend SAP S/4HANA with SAP Extension Suite 2 | 3 | [![REUSE status](https://api.reuse.software/badge/github.com/SAP-samples/teched2020-DEV166)](https://api.reuse.software/info/github.com/SAP-samples/teched2020-DEV166) 4 | 5 | ## Description 6 | 7 | This repository contains the material for the SAP TechEd 2020 session called DEV166 - Extend SAP S/4HANA with SAP Extension Suite. 8 | 9 | 10 | ## Overview 11 | 12 | This session introduces attendees to an end-to-end flow to build an extension using best practices from SAP Extension Suite. 13 | 14 | This workshop will guide you step-by-step through the process of 15 | - creating new data models and a service using the SAP Cloud Application Programming Model (CAP) 16 | - integrating a service exposed on the SAP API Business Hub 17 | - creating a List Report Object Page application based on Fiori elements (FE) using the new service 18 | - configuring and running a predefined Continuous Integration and Delivery (CI/CD) pipeline that automatically tests, builds, and deploys your code changes to the SAP Business Technology Platform (BTP) 19 | 20 | Please note that the inclusion of a service displayed in the SAP API Business Hub originates from a S/4 HANA Cloud system. While large parts of the tutorial are directed to consume the service from a real S/4 HANA Cloud system, the service will eventually not be consumed from a real system but from its local copy on the SAP BTP. This is because within this tutorial and using a SAP BTP trial account, no real S/4HANA Cloud system can be provided and configured. 21 | 22 | This is what the final application will look like: 23 | 24 | ![RiskManagment Final](./exercises/ex3//images/RiskManagment_final.png) 25 | 26 | ## Requirements 27 | 28 | The requirements to follow the exercises in this repository are: 29 | - Get a free trial account on SAP BTP; see this [tutorial](https://developers.sap.com/tutorials/hcp-create-trial-account.html). Choose Europe (Frankfurt) - AWS or US East (VA) - AWS regions. Alternatively, you can also watch this [video](https://www.youtube.com/watch?v=n5luSQKYvQQ&feature=youtu.be) to set up your trial account. 30 | - Set up SAP Business Application Studio for development; see this [tutorial](https://developers.sap.com/tutorials/appstudio-onboarding.html). 31 | 32 | ## Exercises 33 | 34 | - [Getting Started](exercises/ex0/) 35 | - [Exercise 1 - Create a Cloud Application Programming Model Service and a Fiori Elements Application](exercises/ex1/) 36 | - [Exercise 1.1 - Create a CAP-Based Service](exercises/ex1#exercise-11-create-a-cap-based-service) 37 | - [Exercise 1.2 - Create an SAP Fiori Elements-Based Application](exercises/ex1#exercise-12-create-an-sap-fiori-elements-based-application) 38 | - [Exercise 1.3 - Add Business Logic to Your Application](exercises/ex1#exercise-13-add-business-logic-to-your-applicat) 39 | - [Exercise 1.4 - Add the Consumption of an External Service Exposed by SAP API](exercises/ex1#exercise-14-add-the-consumption-of-an-external-service-exposed-by-sap-api-business-hub-to-your-service) 40 | - [Exercise 1.5 - Consume the External Service in Your UI Application](exercises/ex1#exercise-15-consume-the-external-service-in-your-ui-application) 41 | - [Exercise 1.6 - Roles and Authorization Checks In CAP](exercises/ex1#exercise-16--roles-and-authorization-checks-in-cap) 42 | - [Exercise 2 - Prepare for SAP BTP Deployment](exercises/ex2/) 43 | - [Exercise 2.1 - Prepare for SAP HANA Deployment](exercises/ex2#exercise-21-prepare-for-sap-hana-deployment) 44 | - [Exercise 2.2 - Prepare User Authentication and Authorization (XSUAA) Setup](exercises/ex2#exercise-22-prepare-user-authentication-and-authorization-xsuaa-setup) 45 | - [Exercise 2.3 - Create a "Multi Target Application" (MTA) File for Deplyment](exercises/ex2#exercise-23-create-a-multi-target-application-mta-file-for-deplyment) 46 | - [Exercise 2.4 - Add Authorization and Trust Management Service (XSUAA)](exercises/ex2#exercise-24--add-authorization-and-trust-management-service-xsuaa) 47 | - [Exercise 2.5 - Add an Application Router](exercises/ex2#exercise-25--add-an-application-router) 48 | - [Exercise 2.6 - Add UI and AppRouter Module to mta.yaml](exercises/ex2#exercise-26-add-ui-and-approuter-module-to-mtayaml) 49 | - [Exercise 2.7 - Remove Access for S/4 System](exercises/ex2#exercise-27-remove-access-for-s4-system) 50 | - [Exercise 3 - Connect Your Project to SAP Continuous Integration and Delivery](exercises/ex3/) 51 | - [Exercise 3.1 - Create a GitHub Repository](exercises/ex3#exercise-31-create-a-github-repository) 52 | - [Exercise 3.2 - Create a Personal Access Token for GitHub](exercises/ex3#exercise-32-create-a-personal-access-token-for-github) 53 | - [Exercise 3.3 - Connect Your GitHub Repository with Your CAP Project](exercises/ex3#exercise-33-connect-your-github-repository-with-your-cap-project) 54 | - [Exercise 3.4 - Enable SAP Continuous Integration and Delivery](exercises/ex3#exercise-34-enable-sap-cloud-platform-continuous-integration-and-delivery) 55 | - [Exercise 3.5 - Configure Credentials in SAP Continuous Integration and Delivery](exercises/ex3#exercise-35-configure-credentials-in-sap-cloud-platform-continuous-integration-and-delivery) 56 | - [Exercise 3.6 - Configure a CI/CD Job](exercises/ex3#exercise-36-configure-a-cicd-job) 57 | - [Exercise 3.7 - Configure the Stages of Your CI/CD Pipeline](exercises/ex3#exercise-37-configure-the-stages-of-your-cicd-pipeline) 58 | - [Exercise 3.8 - Verify the Success of Your Build](exercises/ex3#exercise-38-verify-the-success-of-your-build) 59 | - [Exercise 3.9 - Assign Role Collections and Access the Deployed Application](exercises/ex3#exercise-39-assign-role-collections-and-access-the-deployed-application) 60 | 61 | ## How to obtain support 62 | 63 | Support for the content in this repository is available during the actual time of the online session for which this content has been designed. Otherwise, you may request support via the [Issues](../../issues) tab. 64 | 65 | ## License 66 | Copyright (c) 2020 SAP SE or an SAP affiliate company. All rights reserved. This file is licensed under the Apache Software License, version 2.0 except as noted otherwise in the [LICENSE](LICENSES/Apache-2.0.txt) file. 67 | -------------------------------------------------------------------------------- /app/index.cds: -------------------------------------------------------------------------------- 1 | 2 | using from './risks/annotations'; -------------------------------------------------------------------------------- /app/risks/annotations.cds: -------------------------------------------------------------------------------- 1 | using RiskService as service from '../../srv/risk-service'; -------------------------------------------------------------------------------- /app/risks/webapp/Component.js: -------------------------------------------------------------------------------- 1 | sap.ui.define(['sap/fe/core/AppComponent'], function(AppComponent) { 2 | 'use strict'; 3 | 4 | return AppComponent.extend("ns.risks.Component", { 5 | metadata: { 6 | manifest: "json" 7 | } 8 | }); 9 | }); 10 | -------------------------------------------------------------------------------- /app/risks/webapp/i18n/i18n.properties: -------------------------------------------------------------------------------- 1 | # This is the resource bundle for risks 2 | 3 | #Texts for manifest.json 4 | 5 | #XTIT: Application name 6 | appTitle=Risks 7 | 8 | #YDES: Application description 9 | appDescription=Risks 10 | -------------------------------------------------------------------------------- /app/risks/webapp/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | {{appTitle}} 8 | 9 | 24 | 25 | 26 | 34 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /app/risks/webapp/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "_version": "1.15.0", 3 | "sap.app": { 4 | "id": "ns.risks", 5 | "type": "application", 6 | "i18n": "i18n/i18n.properties", 7 | "applicationVersion": { 8 | "version": "1.0.0" 9 | }, 10 | "title": "{{appTitle}}", 11 | "description": "{{appDescription}}", 12 | "dataSources": { 13 | "mainService": { 14 | "uri": "/service/risk/", 15 | "type": "OData", 16 | "settings": { 17 | "odataVersion": "4.0" 18 | } 19 | } 20 | }, 21 | "offline": false, 22 | "resources": "resources.json", 23 | "sourceTemplate": { 24 | "id": "ui5template.fiorielements.v4.lrop", 25 | "version": "1.0.0" 26 | } 27 | }, 28 | "sap.ui": { 29 | "technology": "UI5", 30 | "icons": { 31 | "icon": "", 32 | "favIcon": "", 33 | "phone": "", 34 | "phone@2": "", 35 | "tablet": "", 36 | "tablet@2": "" 37 | }, 38 | "deviceTypes": { 39 | "desktop": true, 40 | "tablet": true, 41 | "phone": true 42 | } 43 | }, 44 | "sap.ui5": { 45 | "resources": { 46 | "js": [], 47 | "css": [] 48 | }, 49 | "dependencies": { 50 | "minUI5Version": "1.76.0", 51 | "libs": { 52 | "sap.fe.templates": {} 53 | } 54 | }, 55 | "models": { 56 | "i18n": { 57 | "type": "sap.ui.model.resource.ResourceModel", 58 | "uri": "i18n/i18n.properties" 59 | }, 60 | "": { 61 | "dataSource": "mainService", 62 | "preload": true, 63 | "settings": { 64 | "synchronizationMode": "None", 65 | "operationMode": "Server", 66 | "autoExpandSelect": true, 67 | "earlyRequests": true 68 | } 69 | } 70 | }, 71 | "routing": { 72 | "routes": [ 73 | { 74 | "pattern": ":?query:", 75 | "name": "RisksList", 76 | "target": "RisksList" 77 | }, 78 | { 79 | "pattern": "Risks({key}):?query:", 80 | "name": "RisksObjectPage", 81 | "target": "RisksObjectPage" 82 | } 83 | ], 84 | "targets": { 85 | "RisksList": { 86 | "type": "Component", 87 | "id": "RisksList", 88 | "name": "sap.fe.templates.ListReport", 89 | "options": { 90 | "settings": { 91 | "entitySet": "Risks", 92 | "variantManagement": "Page", 93 | "navigation": { 94 | "Risks": { 95 | "detail": { 96 | "route": "RisksObjectPage" 97 | } 98 | } 99 | } 100 | } 101 | } 102 | }, 103 | "RisksObjectPage": { 104 | "type": "Component", 105 | "id": "RisksObjectPage", 106 | "name": "sap.fe.templates.ObjectPage", 107 | "options": { 108 | "settings": { 109 | "entitySet": "Risks" 110 | } 111 | } 112 | } 113 | } 114 | }, 115 | "contentDensities": { 116 | "compact": true, 117 | "cozy": true 118 | } 119 | }, 120 | "sap.platform.abap": { 121 | "_version": "1.1.0", 122 | "uri": "" 123 | }, 124 | "sap.platform.hcp": { 125 | "_version": "1.1.0", 126 | "uri": "" 127 | }, 128 | "sap.fiori": { 129 | "_version": "1.1.0", 130 | "registrationIds": [], 131 | "archeType": "transactional" 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /approuter/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "approuter", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "node node_modules/@sap/approuter/approuter.js" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "@sap/approuter": "^8.6.1" 14 | }, 15 | "engines": { 16 | "node": "^12.0.0" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /approuter/xs-app.json: -------------------------------------------------------------------------------- 1 | { 2 | "welcomeFile": "/app/risks/webapp/index.html", 3 | "authenticationMethod": "route", 4 | "sessionTimeout": 30, 5 | "logout": { 6 | "logoutEndpoint": "/do/logout", 7 | "logoutPage": "/" 8 | }, 9 | "routes": [ 10 | { 11 | "source": "^/app/(.*)$", 12 | "target": "$1", 13 | "localDir": "resources", 14 | "authenticationType": "xsuaa" 15 | }, 16 | { 17 | "source": "^/service/(.*)$", 18 | "destination": "srv-binding", 19 | "authenticationType": "xsuaa" 20 | } 21 | ] 22 | } -------------------------------------------------------------------------------- /db/data/sap.ui.riskmanagement-BusinessPartners.csv: -------------------------------------------------------------------------------- 1 | BusinessPartner;LastName;FirstName 2 | 1004155;Watson;Alice 3 | 1004161;Lynotte;Phil 4 | 1004100;Masci;J -------------------------------------------------------------------------------- /db/data/sap.ui.riskmanagement-Mitigations.csv: -------------------------------------------------------------------------------- 1 | ID;createdAt;createdBy;description;owner;timeline 2 | 20466921-7d57-4e76-b14c-e53fd97dcb11;2019-10-24;tim.back@sap.com;SLA violation: authorize account manager to offer service credits for recent delivery issues;suitable BuPa;Q2 2020 3 | 20466921-7d57-4e76-b14c-e53fd97dcb12;2019-10-24;tim.back@sap.com;"SLA violation: review third party contractors to ease service delivery challenges; trigger budget review";suitable BuPa;Q3 2020 4 | 20466921-7d57-4e76-b14c-e53fd97dcb13;2019-10-24;tim.back@sap.com;Embargo violation: investigate source of shipment request, revoke authorization;SFSF Employee with link possible?;29.03.2020 5 | 20466921-7d57-4e76-b14c-e53fd97dcb14;2019-10-24;tim.back@sap.com;Embargo violation: review shipment proceedure and stop delivery until further notice;SFSF Employee with link possible?;01.03.2020 -------------------------------------------------------------------------------- /db/data/sap.ui.riskmanagement-Risks.csv: -------------------------------------------------------------------------------- 1 | ID;createdAt;createdBy;title;owner;prio;descr;miti_id;impact;bp_BusinessPartner 2 | 20466922-7d57-4e76-b14c-e53fd97dcb11;2019-10-24;tim.back@sap.com;CFR non-compliance;Fred Fish;3;Recent restructuring might violate CFR code 71;20466921-7d57-4e76-b14c-e53fd97dcb11;10000;1004155 3 | 20466922-7d57-4e76-b14c-e53fd97dcb12;2019-10-24;tim.back@sap.com;SLA violation with possible termination cause;George Gung;2;Repeated SAL violation on service delivery for two successive quarters;20466921-7d57-4e76-b14c-e53fd97dcb12;90000;1004161 4 | 20466922-7d57-4e76-b14c-e53fd97dcb13;2019-10-24;tim.back@sap.com;Shipment violating export control;Herbert Hunter;1;Violation of export and trade control with unauthorized downloads;20466921-7d57-4e76-b14c-e53fd97dcb13;200000;1004100 -------------------------------------------------------------------------------- /db/schema.cds: -------------------------------------------------------------------------------- 1 | namespace sap.ui.riskmanagement; 2 | using { managed } from '@sap/cds/common'; 3 | 4 | entity Risks : managed { 5 | key ID : UUID @(Core.Computed : true); 6 | title : String(100); 7 | owner : String; 8 | prio : String(5); 9 | descr : String; 10 | miti : Association to Mitigations; 11 | impact : Integer; 12 | bp : Association to BusinessPartners; 13 | criticality : Integer; 14 | } 15 | 16 | entity Mitigations : managed { 17 | key ID : UUID @(Core.Computed : true); 18 | description : String; 19 | owner : String; 20 | timeline : String; 21 | risks : Association to many Risks on risks.miti = $self; 22 | } 23 | 24 | // using an external service from S/4 25 | using { API_BUSINESS_PARTNER as external } from '../srv/external/API_BUSINESS_PARTNER.csn'; 26 | 27 | entity BusinessPartnerssS4 as projection on external.A_BusinessPartner { 28 | key BusinessPartner, 29 | LastName, 30 | FirstName 31 | } 32 | 33 | // using a local service instead of the S/4 one with the same type of entity 34 | entity BusinessPartners { 35 | key BusinessPartner: String(10); 36 | LastName: String(40); 37 | FirstName: String(40); 38 | } -------------------------------------------------------------------------------- /exercises/ex0/README.md: -------------------------------------------------------------------------------- 1 | # Getting Started - Setting up your Development Environment 2 | 3 | Welcome to the workshop 'Extend SAP S/4HANA with SAP Extension Suite'.\ 4 | This workshop will guide you step-by-step through the process of 5 | - creating new data models and a service using the Cloud Application Programming Model (CAP) 6 | - integrating a service from the [SAP API Business Hub](https://api.sap.com/) 7 | - creating a List Report Object Page application based on Fiori elements (FE) using the new service 8 | - configuring and running a predefined Continuous Integration and Delivery (CI/CD) pipeline that automatically tests, builds, and deploys your code changes to the SAP Business Technology Platform 9 | 10 | ## Set up Business Application Studio in a SAP BTP Trial Account 11 | 12 | If you don't have an SAP BTP account already, you can create your own [here](https://www.sap.com/products/cloud-platform/get-started.html). 13 | 14 | ### New Trial Users 15 | 16 | 1. After having registered your new user, start your trial via [this link](https://account.hanatrial.ondemand.com/register). 17 | 2. Logging in for the first time, you'll be asked to select your preferred region. To be able to perform all exercises in this tutorial, select either Europe (Frankfurt) - AWS or US East (VA) - AWS. 18 | This will start the set up of your account. 19 | 20 | ![Trial Setup](../ex0/images/00_00_0010.png) 21 | 22 | Your subaccount, org and space are created automatically, along with the necessary role configurations and subscriptions.\ 23 | When this is done, the subaccount overview page is shown. 24 | 25 | ### Existing Trial Users 26 | 27 | 1. In your subaccount, choose **Subscriptions** in the left-hand navigation. 28 | 2. Choose **SAP Business Application Studio** in the list of available subscriptions.\ 29 | Choose **Subscribe**. 30 | 3. Navigate back to your subaccount overview page. 31 | 32 | ### Access SAP Business Application Studio 33 | 34 | Click on the Quick Tool Access icon **SAP Business Application Studio**. 35 | 36 | ![Welcome SCP Trial](../ex0/images/00_00_0020.png) 37 | 38 | ## Create Dev Space 39 | 40 | Click on the button **Create Dev Space**. 41 | 42 | ![Create Dev Space](../ex0/images/00_00_0030.png) 43 | 44 | Enter a name for your dev space and select profile **SAP Cloud Business Application**. 45 | 46 | ![Select Profile](../ex0/images/00_00_0040.png) 47 | 48 | In the lower right corner of the page press button **Create Dev Space**. 49 | 50 | ![confirm](../ex0/images/00_00_0050.png)
51 | 52 | Once your dev space has status running, click on the development space name to open it. 53 | 54 | ![enter dev space](../ex0/images/00_00_0060.png) 55 | 56 | You should now see such a screen: 57 | 58 | ![bas](../ex0/images/00_00_0070.png) 59 | 60 | ## Summary 61 | 62 | With the setup procedure done, you now have completed: 63 | - Setting up the SAP BTP Trial Account 64 | - Accessing to the SAP Business Application Studio 65 | - Creation of your dev space 66 | 67 | Continue to - [Exercise 1](../ex1/README.md) 68 | -------------------------------------------------------------------------------- /exercises/ex0/images/00_00_0010.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/teched2020-DEV166/66223ca859bbd84346d4ab6ce5086209bdd65215/exercises/ex0/images/00_00_0010.png -------------------------------------------------------------------------------- /exercises/ex0/images/00_00_0020.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/teched2020-DEV166/66223ca859bbd84346d4ab6ce5086209bdd65215/exercises/ex0/images/00_00_0020.png -------------------------------------------------------------------------------- /exercises/ex0/images/00_00_0030.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/teched2020-DEV166/66223ca859bbd84346d4ab6ce5086209bdd65215/exercises/ex0/images/00_00_0030.png -------------------------------------------------------------------------------- /exercises/ex0/images/00_00_0040.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/teched2020-DEV166/66223ca859bbd84346d4ab6ce5086209bdd65215/exercises/ex0/images/00_00_0040.png -------------------------------------------------------------------------------- /exercises/ex0/images/00_00_0050.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/teched2020-DEV166/66223ca859bbd84346d4ab6ce5086209bdd65215/exercises/ex0/images/00_00_0050.png -------------------------------------------------------------------------------- /exercises/ex0/images/00_00_0060.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/teched2020-DEV166/66223ca859bbd84346d4ab6ce5086209bdd65215/exercises/ex0/images/00_00_0060.png -------------------------------------------------------------------------------- /exercises/ex0/images/00_00_0070.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/teched2020-DEV166/66223ca859bbd84346d4ab6ce5086209bdd65215/exercises/ex0/images/00_00_0070.png -------------------------------------------------------------------------------- /exercises/ex1/README.md: -------------------------------------------------------------------------------- 1 | # Exercise 1 - Create a Cloud Application Programming Model Service and a Fiori Elements Application 2 | 3 | In this exercise, we will create an application based on a data model and service created using the Cloud Application Programming Model (CAP) and a UI based on Fiori elements (FE) which in turn is based on UI5. 4 | 5 | ## ############################################################### 6 | 7 | ## Exercise 1.1 Create a CAP-Based Service 8 | 9 | In this part, you create a new CAP-based service, which exposes the OData V4 protocol. To do so, you use CAP's tooling `cds init` and `cds watch` in a terminal. 10 | 11 | ### Create and Initialize the Project 12 | 13 | 1. In the Business Application Studio click on **Start from template** 14 | ![new project](../ex1/images/01_01_0010.png) 15 | 2. Select **CAP Project** and press **Start** 16 | ![cap project](../ex1/images/01_01_0020.png) 17 | 3. Enter 'RiskManagement' as a project name. Don't tick any of the checkboxes below. 18 | ![new name](../ex1/images/01_01_0030.png) 19 | 4. After the project has been generated, click on **Finish** and **Open in New Workspace** on the pop up in the lower right corner 20 | ![new wrokspace](../ex1/images/01_01_0040.png) 21 | 5. The new workspace will open and it will show the generated 'RiskManagement' project like this: 22 | ![project view](../ex1/images/01_01_0050.png) 23 | 24 | 6. In Business Application Studio choose **Terminal -> New Terminal** from its menu. 25 | 26 | A new terminal opens in the lower right part of the Business Application Studio screen. 27 | 28 | 7. In the terminal, install the dependencies for the project 29 | ``` 30 | npm i 31 | ``` 32 | 8. In the terminal, start a CAP server by typing: 33 | ``` 34 | cds watch 35 | ``` 36 | The CAP server serves all the CAP sources from your project. It also "watches" all the files in your projects and conveniently restarts the server whenever you save a file. Changes you've made will immediately be served without you having to do anything. 37 | 38 | The screen now looks like this: 39 | ![project view](../ex1/images/01_01_0060.png) 40 | `cds watch` tells you that there’s no model yet that it can serve. You add one in the next steps. 41 | 42 | In general you can keep `cds watch` running in a terminal for the whole exercise. There is no need to restart it or try to add a second instance of it (in fact, if you do this, you get an error, described [here](#cdswatcherror)). In the follow up chapters you will open a new browser tab to see the results of `cds watch`. You can just keep this open and refresh it each time there is a change. `cds watch` notices any file change and makes sure you get the new results after a refresh in the browser. 43 | 44 | ### Add a Data Model to the Project 45 | 46 | In this part we create a data model using the Core Data Services (CDS) format from CAP. 47 | 48 | 1. In the project, go to folder **db**, representing the data model on the data base. In the context menu, select **New File** 49 | 2. Enter **schema.cds** as a name 50 | 3. Click on the new file in the explorer, an editor opens 51 | 4. Enter the following lines into the editor 52 | 53 | ```javascript 54 | namespace sap.ui.riskmanagement; 55 | using { managed } from '@sap/cds/common'; 56 | 57 | entity Risks : managed { 58 | key ID : UUID @(Core.Computed : true); 59 | title : String(100); 60 | owner : String; 61 | prio : String(5); 62 | descr : String; 63 | miti : Association to Mitigations; 64 | impact : Integer; 65 | //bp : Association to BusinessPartners; 66 | criticality : Integer; 67 | } 68 | 69 | entity Mitigations : managed { 70 | key ID : UUID @(Core.Computed : true); 71 | description : String; 72 | owner : String; 73 | timeline : String; 74 | risks : Association to many Risks on risks.miti = $self; 75 | } 76 | ``` 77 | 78 | 5. Save the file 79 | 80 | This creates 2 entities in the namespace **sap.ui.riskmanagement**, **Risks**, and **Mitigations**. Each of them has a key called **ID** and several other properties. A **Risk** has a mitigation and therefore, the property **miti** has an association to exactly one **Mitigation**. A Mitigation in turn can be used for many Risks, so it has a "too many" association. The key is automatically filled by CAP, which is exposed to the user of the service with the annotation `@(Core.Computed : true)`. 81 | 82 | At this point, you can neglect the commented property **bp** (as well as the other commented lines further down in the file and in subsequent files and chapters). All the commented lines are later used and uncommented when you introduce a reference to a Business Partner entity. For now you don't need it, though. 83 | 84 | The screen now looks like this: 85 | 86 | ![project view](../ex1/images/01_01_0070.png) 87 | 88 | 89 | Notice how `cds watch` reacted to dropping the file. It now tells you that it has a model but there are no service definitions yet and thus it still can’t serve anything. So, you will add a service definition. 90 | 91 | ### Add a Service to the Project 92 | 93 | In this part we create a new service with 2 entities, both are projections of the data models that we created in the chapter before. 94 | 95 | 1. In the project, go to folder **srv**, representing the service. In the context menu, select **New File** 96 | 2. Enter **risk-service.cds** as a name 97 | 3. Click on the new file in the explorer, an editor opens 98 | 4. Enter the following lines into the editor 99 | 100 | ```javascript 101 | using { sap.ui.riskmanagement as my } from '../db/schema'; 102 | 103 | @path: 'service/risk' 104 | service RiskService { 105 | entity Risks as projection on my.Risks; 106 | annotate Risks with @odata.draft.enabled; 107 | entity Mitigations as projection on my.Mitigations; 108 | annotate Mitigations with @odata.draft.enabled; 109 | //entity BusinessPartners as projection on my.BusinessPartners; 110 | } 111 | ``` 112 | 113 | This creates a new service **RiskService** in the namespace **sap.ui.riskmanagement**. This service exposes 2 entities (again just neglect the commented part for the business partner), **Risks** and **Mitigations**, which are both just exposing the entities of the data base schema you’ve created in the step before. 114 | 115 | If you again look at the terminal, you see that `cds watch` has noticed the new file and now tells us that it serves something: 116 | 117 | ![service](../ex1/images/01_01_0080.png) 118 | 119 | 5. Press the **Expose and Open** button 120 | 6. If you are asked to enter a name - just press return 121 | 122 | You now see this screen: 123 | 124 | ![service2](../ex1/images/01_01_0090.png) 125 | 126 | 7. Click the **$metadata** link 127 | 128 | The service already exposes a full blown OData metadata document 129 | 130 | 8. Now go back and click on the **Risks** link. 131 | 132 | This exposes the data for the Risks entity. As there is no data yet, you only see this: 133 | 134 | ```javascript 135 | { 136 | @odata.context: "$metadata#Risks", 137 | value: [ ] 138 | } 139 | ``` 140 | 141 | Don't close the window, you will need it again. 142 | 143 | ### Add Data for the Service 144 | 145 | In this part we add data to the service. It is local data that is stored in a local data base called SQLite that CAP invokes behind the scences. CAP makes it easy to add such test data to a service, all it needs is a Comma Separated Values file which contains the entities' elements as column headers. 146 | 147 | 1. In the project, go to folder **db**. In the context menu, select **New Folder** 148 | 2. Enter **data** as a name 149 | 3. On the **data** folder, in the context menu, select **New File** 150 | 2. Enter **sap.ui.riskmanagement-Risks.csv** as a name 151 | 5. Click on the new file in the explorer, an editor opens 152 | 6. Enter the following lines into the editor 153 | 154 | ```csv 155 | ID;createdAt;createdBy;title;owner;prio;descr;miti_id;impact 156 | 20466922-7d57-4e76-b14c-e53fd97dcb11;2019-10-24;tim.back@sap.com;CFR non-compliance;Fred Fish;3;Recent restructuring might violate CFR code 71;20466921-7d57-4e76-b14c-e53fd97dcb11;10000 157 | 20466922-7d57-4e76-b14c-e53fd97dcb12;2019-10-24;tim.back@sap.com;SLA violation with possible termination cause;George Gung;2;Repeated SAL violation on service delivery for two successive quarters;20466921-7d57-4e76-b14c-e53fd97dcb12;90000 158 | 20466922-7d57-4e76-b14c-e53fd97dcb13;2019-10-24;tim.back@sap.com;Shipment violating export control;Herbert Hunter;1;Violation of export and trade control with unauthorized downloads;20466921-7d57-4e76-b14c-e53fd97dcb13;200000 159 | ``` 160 | 7. Save the file 161 | 8. On the **data** folder, in the context menu, select **New File** 162 | 9. Enter **sap.ui.riskmanagement-Mitigations.csv** as a name 163 | 10. Click on the new file in the explorer, an editor opens 164 | 11. Enter the following lines into the editor 165 | 166 | ```csv 167 | ID;createdAt;createdBy;description;owner;timeline 168 | 20466921-7d57-4e76-b14c-e53fd97dcb11;2019-10-24;tim.back@sap.com;SLA violation: authorize account manager to offer service credits for recent delivery issues;suitable BuPa;Q2 2020 169 | 20466921-7d57-4e76-b14c-e53fd97dcb12;2019-10-24;tim.back@sap.com;"SLA violation: review third party contractors to ease service delivery challenges; trigger budget review";suitable BuPa;Q3 2020 170 | 20466921-7d57-4e76-b14c-e53fd97dcb13;2019-10-24;tim.back@sap.com;Embargo violation: investigate source of shipment request, revoke authorization;SFSF Employee with link possible?;29.03.2020 171 | 20466921-7d57-4e76-b14c-e53fd97dcb14;2019-10-24;tim.back@sap.com;Embargo violation: review shipment proceedure and stop delivery until further notice;SFSF Employee with link possible?;01.03.2020 172 | ``` 173 | 12. Save the file 174 | 175 | The files have the name of the namespace of the entities in the data model (e.g. **sap.ui.riskmanagement**), followed by a '-' and the name of the entity (e.g. **Risks**). When adhering to this naming convention CAP recognizes the file as data for the data model and automatically adds it to the built in SQLite data base. 176 | Looking at the contents of the file **sap.ui.riskmanagement-Risks.csv**, the first line contains all the properties from your **Risks** entity. While the other ones are straightforward, consider the **miti_id** property. In your entity, you only have a **miti** property, so where does this come from? **miti** is an association to **Mitigations**, as **Mitigations** could have several key properties, the association on the data base needs to point to all of these, therefore CAP creates a property **_** for each key. 177 | 178 | As always `cds watch` has noticed the change. 179 | 180 | 12. Return to the browser window where the service is still shown and press **refresh** in the browser. It will now show values for **Risks** 181 | 182 | ![risksdata](../ex1/images/01_01_0100.png) 183 | 184 | 185 | You’ve now got a full blown OData service, which complies to the OData standard and supports the respective queries without having to code anything but the data model and exposing the service itself. 186 | 187 | *Note:* The service is completely exposed without any authentication or authorization check. You will extend the service later with such checks. 188 | 189 | ## ############################################################### 190 | 191 | ## Exercise 1.2 Create an SAP Fiori Elements-Based Application 192 | 193 | An Fiori elements (FE) app is an application that leverages SAPUI5, its controls and its model view controller (MVC) concepts. As opposed to a plain UI5 or freestyle UI5 app, where one has all the views and controllers as part of one's projects, most of the code of an FE app is outside of the project, managed centrally be the FE team. The code inside one's project only references these central components, which take care of creating the UI according to the latest SAP Fiori design guidelines and covers all the controller logic for you out of the box. The UI can be influenced by OData annotations. They determine, for example, which properties of an OData service make up the columns of a table which displays the content of the service. 194 | 195 | ### Generate the UI with an SAP Fiori Elements Template 196 | 197 | 1. In Business Application Studio, invoke the Command Palette (```View -> Find Command``` or ```Cmd+Shift+P```) and choose ```Fiori: Open Application Generator```. 198 | 199 | ![appgen](../ex1/images/01_02_0010.png) 200 | 201 | 2. Choose `SAP Fiori Elements` and `List Report Object Page` and press **Next** 202 | 203 | ![Feapp](../ex1/images/01_02_0030.png) 204 | 205 | 206 | 3. In the next dialog, choose **Use a Local CAP Node.js Project** and point to the folder of your current ```RiskManagement``` project. Select the ``RiskService`` as the OData service and click **Next** 207 | 208 | ![Feapp](../ex1/images/01_02_0040.png) 209 | 210 | 4. Choose ```Risks``` as the main entity and click **Next** 211 | 212 | ![Feapp](../ex1/images/01_02_0050.png) 213 | 214 | 5. Enter "risks" as the module name. Enter "Risks" as the application title and the description for the application, as well as "ns" as the namespace. Choose "No" in the checkboxes and press **Finish** 215 | 216 | ![Feapp](../ex1/images/01_02_0060.png) 217 | 218 | (If you get a pop up that says "A project has been generated. What would you like to do with it?", you can ignore it and just close the pop up) 219 | 220 | The application is now generated and after a couple of seconds you can see it in the ```app``` folder of your project. It contains a ```risks``` and a ```webapp``` folder with a ```Component.js``` file, which is characteristic for a UI5 app. However, the code there’s minimal and it basically inherits its logic from the ```sap/fe/core/AppComponent```. 221 | 222 | 6. If ```cds watch``` isn't still running from the previous chapter, execute it in a terminal and press on the **Open in New Tab** button in the right lower corner. If it is still running from the last chapter, it is enough to refresh the brower page were it is running. 223 | 224 | You can now see that ```cds watch``` has discovered an HTML page in your app folder: 225 | 226 | ![Feapp](../ex1/images/01_02_0070.png) 227 | 228 | 7. Click on this link. On the launch page that now comes up, click on the **Risks** tile. 229 | 230 | You can now see the list page, it looks like this: 231 | 232 | ![EmptyLR](../ex1/images/01_02_0075.png) 233 | 234 | Unfortunately, the app looks rather empty, for example, the list has no columns yet. This is because we miss an essential part of a Fiori elements application that tells it about columns, form fields and a lot of other things: It is missing UI annotations. 235 | 236 | ### Modify the UI with OData Annotations 237 | 238 | 1. To add the OData annotations, in the project, go to folder **srv** representing the service and select **New File** in the context menu 239 | 240 | 2. Enter **risks-service-ui.cds** as a name 241 | 242 | 3. Click on the new file in the explorer, an editor opens 243 | 244 | 4. Enter the following lines into the editor 245 | 246 | ```javascript 247 | using RiskService from './risk-service'; 248 | 249 | annotate RiskService.Risks with { 250 | title @title: 'Title'; 251 | owner @title: 'Owner'; 252 | prio @title: 'Priority'; 253 | descr @title: 'Description'; 254 | miti @title: 'Mitigation'; 255 | //bp @title: 'Business Partner'; 256 | impact @title: 'Impact'; 257 | } 258 | 259 | annotate RiskService.Mitigations with { 260 | ID @( 261 | UI.Hidden, 262 | Common: { 263 | Text: description 264 | } 265 | ); 266 | description @title: 'Description'; 267 | owner @title: 'Owner'; 268 | timeline @title: 'Timeline'; 269 | risks @title: 'Risks'; 270 | } 271 | 272 | annotate RiskService.Risks with @( 273 | UI: { 274 | HeaderInfo: { 275 | TypeName: 'Risk', 276 | TypeNamePlural: 'Risks' 277 | }, 278 | SelectionFields: [prio], 279 | LineItem: [ 280 | {Value: title}, 281 | {Value: miti_ID}, 282 | {Value: owner}, 283 | //{Value: bp_BusinessPartner}, 284 | { 285 | Value: prio, 286 | Criticality: criticality 287 | } 288 | , 289 | { 290 | Value: impact, 291 | Criticality: criticality 292 | } 293 | ], 294 | Facets: [ 295 | {$Type: 'UI.ReferenceFacet', Label: 'Main', Target: '@UI.FieldGroup#Main'} 296 | ], 297 | FieldGroup#Main: { 298 | Data: [ 299 | {Value: title}, 300 | {Value: miti_ID}, 301 | {Value: descr}, 302 | {Value: owner}, 303 | { 304 | Value: prio, 305 | Criticality: criticality 306 | }, 307 | //{Value: bp_BusinessPartner}, 308 | { 309 | Value: impact, 310 | Criticality: criticality 311 | } 312 | ] 313 | } 314 | }, 315 | ) { 316 | 317 | }; 318 | 319 | annotate RiskService.Risks with { 320 | miti @( 321 | Common: { 322 | //show text, not id for mitigation in the context of risks 323 | Text: miti.description , TextArrangement: #TextOnly, 324 | ValueList: { 325 | Label: 'Mitigations', 326 | CollectionPath: 'Mitigations', 327 | Parameters: [ 328 | { $Type: 'Common.ValueListParameterInOut', 329 | LocalDataProperty: miti_ID, 330 | ValueListProperty: 'ID' 331 | }, 332 | { $Type: 'Common.ValueListParameterDisplayOnly', 333 | ValueListProperty: 'description' 334 | } 335 | ] 336 | } 337 | } 338 | ); 339 | /* 340 | bp @( 341 | Common: { 342 | Text: bp.LastName , TextArrangement: #TextOnly, 343 | ValueList: { 344 | Label: 'Business Partners', 345 | CollectionPath: 'BusinessPartners', 346 | Parameters: [ 347 | { $Type: 'Common.ValueListParameterInOut', 348 | LocalDataProperty: bp_BusinessPartner, 349 | ValueListProperty: 'BusinessPartner' 350 | }, 351 | { $Type: 'Common.ValueListParameterDisplayOnly', 352 | ValueListProperty: 'LastName' 353 | }, 354 | { $Type: 'Common.ValueListParameterDisplayOnly', 355 | ValueListProperty: 'FirstName' 356 | } 357 | ] 358 | } 359 | } 360 | ) 361 | */ 362 | } 363 | 364 | /* 365 | annotate RiskService.BusinessPartners with { 366 | BusinessPartner @( 367 | UI.Hidden, 368 | Common: { 369 | Text: LastName 370 | } 371 | ); 372 | LastName @title: 'Last Name'; 373 | FirstName @title: 'First Name'; 374 | } 375 | */ 376 | ``` 377 | 378 | 5. Save the file 379 | 380 | As in the steps before, ```cds watch``` has noticed the new file and compiled the service again, so now it contains the additional annotations. 381 | 382 | 6. In the browser, reload the test page which shows the service and the index page. Click on the index page link `/risks/webapp/index.html`. On the launch page that now comes up, click on the **Risks** tile. Click **Go**. It now shows a work list with some columns and the data from the service. 383 | 384 | ![Feapp2](../ex1/images/01_02_0080.png) 385 | 386 | You’ve now already finished a full blown service and a full blown UI application on top running locally. 387 | 388 | ### Check the Annotation Files 389 | 390 | Let's have a look at the new cds file and the annotations in there. At the beginning we see: 391 | 392 | ```javascript 393 | using RiskService from './risk-service'; 394 | 395 | annotate RiskService.Risks with { 396 | title @title: 'Title'; 397 | prio @title: 'Priority'; 398 | descr @title: 'Description'; 399 | miti @title: 'Mitigation'; 400 | //bp @title: 'Business Partner'; 401 | impact @title: 'Impact'; 402 | } 403 | ``` 404 | 405 | It's referring to the definitions of the earlier cds file that exposes the service and its ```risks``` and mitigations ```entites```. Then it annotates the ```risk``` entity with a number of texts. These should be in a translatable file normally but for now we keep them here. These texts are used as labels in form fields and column headers by FE. 406 | 407 | Next up: 408 | 409 | ```javascript 410 | annotate RiskService.Risks with @( 411 | UI: { 412 | HeaderInfo: { 413 | TypeName: 'Risk', 414 | TypeNamePlural: 'Risks' 415 | }, 416 | SelectionFields: [prio], 417 | LineItem: [ 418 | {Value: title}, 419 | {Value: miti_ID}, 420 | {Value: owner}, 421 | // {Value: bp_BusinessPartner}, 422 | { 423 | Value: prio, 424 | Criticality: criticality 425 | }, 426 | { 427 | Value: impact, 428 | Criticality: criticality 429 | } 430 | ], 431 | Facets: [ 432 | {$Type: 'UI.ReferenceFacet', Label: 'Main', Target: '@UI.FieldGroup#Main'} 433 | ], 434 | FieldGroup#Main: { 435 | Data: [ 436 | {Value: title}, 437 | {Value: miti_ID}, 438 | {Value: descr}, 439 | {Value: owner}, 440 | { 441 | Value: prio, 442 | Criticality: criticality 443 | }, 444 | // {Value: bp_BusinessPartner}, 445 | { 446 | Value: impact, 447 | Criticality: criticality 448 | } 449 | ] 450 | } 451 | }, 452 | ) { 453 | 454 | }; 455 | ``` 456 | 457 | This defines the content of the work list page and the object page, which one navigates to when clicking on a line in the work list. 458 | 459 | The ```SelectionFields``` section defines which of the properties are exposed as search fields in the header bar above the list, in this case ```prio``` is the only explicit search field. 460 | 461 | From the ```LineItem``` section all the columns and their order of the work list are derived. While in most cases the columns are defined by ```Value:``` followed by the property name of the entity, in the case of ```prio```and ```impact``` there’s also ```Criticality```, which for now you can neglect, but keep it in mind in case you go to the later modules. It currently adds a diamond icon ( ⃟ ) right left of the fields. You can just ignore it. 462 | 463 | Next up the ```Facets``` section. In this case, it defines the content of the object page. It contains only a single facet, a ```ReferenceFacet```, of the field group ```FieldGroup#Main```. This field group just shows up as a form. The properties of the ```Data``` array within ```FieldGroup#Main``` determine the fields in the form: 464 | 465 | ![FeappObjectPage](../ex1/images/01_02_0090.png) 466 | 467 | The last part is the most complicated one: 468 | ```js 469 | annotate RiskService.Risks with { 470 | miti @( 471 | Common: { 472 | //show text, not id for mitigation in the context of risks 473 | Text: miti.description , TextArrangement: #TextOnly, 474 | ValueList: { 475 | Label: 'Mitigations', 476 | CollectionPath: 'Mitigations', 477 | Parameters: [ 478 | { $Type: 'Common.ValueListParameterInOut', 479 | LocalDataProperty: miti_ID, 480 | ValueListProperty: 'ID' 481 | }, 482 | { $Type: 'Common.ValueListParameterDisplayOnly', 483 | ValueListProperty: 'description' 484 | } 485 | ] 486 | } 487 | }, 488 | UI.MultiLineText: IsActiveEntity 489 | ); 490 | } 491 | ``` 492 | 493 | Without these lines, we would see the id of the mitigations from the ```miti``` field, in both the list and the object page: 494 | 495 | ![mitinoanno](../ex1/images/01_02_0100.png) 496 | 497 | ![mitinoanno2](../ex1/images/01_02_0110.png) 498 | 499 | By introducing the annotations for the ```miti``` property, instead of just displaying the original value of ```miti```, i.e. the id, the UI shows its ```description``` property. 500 | The subsequent part ```ValueList``` introduces a value help for ```miti``` that you can see on the object page in its edit mode. The value help takes the id as an input parameter and again displays the ```description``` parameter. 501 | 502 | ![mitianno](../ex1/images/01_02_0120.png) 503 | 504 | ![mitianno2](../ex1/images/01_02_0130.png) 505 | 506 | 507 | ## ############################################################### 508 | 509 | ## Exercise 1.3 Add Business Logic to Your Application 510 | 511 | In this chapter, you add custom code to the CAP service, that changes depending on the value of the property ```impact``` and the value of the property ```criticality```, which in turn is used in OData annotations to control the color of some of the cells in the table of our work list page. 512 | 513 | ### Add Custom Code 514 | 515 | 1. In the project, go to folder **srv**, representing the service, and select **New File** in the context menu 516 | 2. Enter **risk-service.js** as a name 517 | 3. Click on the new file in the explorer, an editor opens 518 | 4. Enter the following lines into the editor 519 | 520 | ```javascript 521 | /** 522 | * Implementation for Risk Management service defined in ./risk-service.cds 523 | */ 524 | module.exports = async (srv) => { 525 | srv.after('READ', 'Risks', (risks) => { 526 | 527 | risks.forEach((risk) => { 528 | if (risk.impact >= 100000) { 529 | risk.criticality = 1; 530 | } else { 531 | risk.criticality = 2; 532 | } 533 | }); 534 | }); 535 | } 536 | ``` 537 | 538 | 5. Save the file 539 | 6. In the browser, reload the page of the Fiori Elements app 540 | 541 | It now shows our work list with the columns ```Priority``` and ```Impact``` with color and an icon, depending on the amount in ```impact```. 542 | 543 | ![FeappObjectPage](../ex1/images/01_03_0010.png) 544 | 545 | ### Explanation of the Custom Code 546 | 547 | Because your file is called ```risks-service.js``` and therefore has the same name as your service definition file ```risks-service.cds```, CAP automatically treats it as a handler file for the service defined in there. CAP exposes several [events](https://github.wdf.sap.corp/pages/cap/node.js/api#cds-event-handlers) and you can easily write handlers as the one above. 548 | 549 | In this case, the event ```after``` is triggered after a `READ` was carried out for our ```Risks``` entity. In your custom handler you get all the data, in this case all the risks that were read according to the query. You can loop over each of them and, if needed, adjust the data of the response. In this case, you change the value of the ```criticality``` when the ```impact``` is bigger than 100000. The new values for ```criticality``` are then part of the response to the read request. 550 | 551 | So, this affects the service's response, but how does this translate into a changed UI? In order to do this, you have to go back to the annotations you created in chapter 3, where you find your ```srv/risks-service-ui.cds``` file. There you had the two columns ```prio``` and ```impact``` annotated with an additional ```Criticality``` annotation. This annotation points to the ```criticality``` property of your service (*Note:* `Criticality` with an upper case `C` is the annotation, while the property name `criticality` could also be called different opposed to the annotation). As you now set different values in your custom handler for ```criticality```, the Fiori Elements application translates these into icons and colors, which you can see in the UI. 552 | 553 | ```javascript 554 | annotate RiskService.Risks with @( 555 | UI: { 556 | ... 557 | ... 558 | LineItem: [ 559 | ... 560 | ... 561 | { 562 | Value: prio, 563 | Criticality: criticality 564 | }, 565 | { 566 | Value: impact, 567 | Criticality: criticality 568 | } 569 | ], 570 | ``` 571 | 572 | You can find out more about the possible values of the ```Criticality``` annotation [here](https://github.com/SAP/odata-vocabularies/blob/master/vocabularies/UI.md#CriticalityType). This, however, is just one of the many sections of the OData Annotation vocabularies for [UI](https://github.com/SAP/odata-vocabularies/blob/master/vocabularies/UI.md) and [Common](https://github.com/SAP/odata-vocabularies/blob/master/vocabularies/Common.md) usage. 573 | 574 | 575 | ## ############################################################### 576 | 577 | ## Exercise 1.4 Add the Consumption of an External Service Exposed by SAP API Business Hub to Your Service 578 | 579 | 580 | In this chapter, you extend your CAP service with the consumption of an external Business Partner service. You get its definition from SAP's API Business Hub. Firstly, work with local data and later on get the data directly from the external SAP S/4HANA system. What you have to do is: 581 | 582 | ### Get the Business Partner EDMX File 583 | 584 | 1. Open the [SAP API Business Hub](https://api.sap.com/) page in your browser 585 | 2. Type "business partner" into the page's search field and carry out the search 586 | 3. On the left side, expand ```Products``` and mark ```SAP S/4 HANA Cloud``` 587 | 4. In the result list, choose ```Business Partner (A2X)``` 588 | 5. Choose the ```Details``` tab 589 | 590 | ![API Details](../ex1/images/01_03_0030.png) 591 | 592 | 6. Click the ```Download API Specification``` button 593 | 7. Choose the ```EDMX``` option from the list (if you’re asked to log on, log on, it works automatically) 594 | 595 | If you’re using Chrome as a browser, you now see the downloaded file in the footer bar: 596 | ![API EDMX](../ex1/images/01_03_0040.png) 597 | 598 | 599 | ### Add the EDMX File to the Project and Add Local Data 600 | 601 | 1. Make sure in your terminal ```cds watch``` is still running 602 | 2. Drag the ```API_BUSINESS_PARTNER.edmx``` file from your browser's download area/folder onto your Business Application Studio workplace and drop it into the ```srv``` folder of your ```cpapp``` app 603 | 604 | CAP has noticed the new file and automatically created a new ```external``` folder under ```srv``` and in it added a new ```API_BUSINESS_PARTNER.csn``` file. ([CSN](https://github.wdf.sap.corp/pages/cap/cds/csn) being a compact representation of CDS) 605 | 606 | 607 | 3. In your project, open the ```db/schema.cds``` file again and change the parts of the file as indicated below. 608 | 609 | From now on the exercises will mark code blocks that need to be inserted inbetween the following lines (which are not to be copied): 610 | 611 | ***//### BEGIN OF INSERT*** 612 | 613 | before the lines of code that have to be inserted and 614 | 615 | ***//### END OF OF INSERT*** 616 | 617 | after the lines to be inserted. The same is true for lines to be deleted: 618 | 619 | ***//### BEGIN OF OF DELETE*** 620 | 621 | ***//### END OF OF DELETE*** 622 | 623 | 624 | ```javascript 625 | namespace sap.ui.riskmanagement; 626 | using { managed } from '@sap/cds/common'; 627 | entity Risks : managed { 628 | key ID : UUID @(Core.Computed : true); 629 | title : String(100); 630 | prio : String(5); 631 | descr : String; 632 | miti : Association to Mitigations; 633 | impact : Integer; 634 | //bp : Association to BusinessPartners; 635 | criticality : Integer; 636 | } 637 | entity Mitigations : managed { 638 | key ID : UUID @(Core.Computed : true); 639 | description : String; 640 | owner : String; 641 | timeline : String; 642 | risks : Association to many Risks on risks.miti = $self; 643 | } 644 | 645 | //### BEGIN OF INSERT 646 | 647 | // using an external service from S/4 648 | using {  API_BUSINESS_PARTNER as external } from '../srv/external/API_BUSINESS_PARTNER.csn'; 649 | 650 | entity BusinessPartners as projection on external.A_BusinessPartner { 651 | key BusinessPartner, 652 | LastName, 653 | FirstName 654 | } 655 | 656 | //### END OF OF INSERT 657 | 658 | ``` 659 | 660 | With this code you create a so-called projection for your new service. Of the many entities and properties in these entities, that are defined in the ```API_BUSINESS_PARTNER``` service, you just look at one of the entities (```A_BusinessPartner```) and just three of its properties: ```BusinessPartner```, ```LastName```, and ```FirstName```, so your projection is using a subset of everything the original service has to offer. 661 | 662 | 4. Open the ```srv/risk-service.cds``` file 663 | 664 | 5. Uncomment the ```entity BusinessPartner``` line 665 | 666 | ```javascript 667 | using { sap.ui.riskmanagement as my } from '../db/schema'; 668 | @path: 'service/risk' 669 | service RiskService { 670 | entity Risks as projection on my.Risks; 671 | annotate Risks with @odata.draft.enabled; 672 | entity Mitigations as projection on my.Mitigations; 673 | annotate Mitigations with @odata.draft.enabled; 674 | //### BEGIN OF DELETE 675 | //entity BusinessPartners as projection on my.BusinessPartners; 676 | //### END OF DELETE 677 | //### BEGIN OF INSERT 678 | entity BusinessPartners as projection on my.BusinessPartners; 679 | //### END OF INSERT 680 | } 681 | ``` 682 | 683 | 6. In your browser, where the Fiori elements app is still running from the last chapter, press on the SAP icon on the left upper corner. This way you navigate back to the index page. Press refresh in your browser. Now press on the **Risks** tile and in the application press **Go** 684 | 685 | The browser now shows a ```BusinessPartner```service next to the ```Mitigations``` and ```Risks``` 686 | 687 | ![BPService](../ex1/images/01_03_0050.png) 688 | 689 | At this point, you have a new service exposed with a definition based on the original ```edmx``` file. However, it doesn't have any connectivity to a backend and thus, there’s no data yet. Such as with your own entities ```risks``` and ```mitigations```, you create new local data. 690 | 691 | 7. In the project, go to the folder **srv/external** and select **New Folder** from the context menu 692 | 8. Enter **data** as a name 693 | 9. In the **data** folder, select **New File** from the context menu 694 | 10. Enter **API_BUSINESS_PARTNER-A_BusinessPartner.csv** as a name 695 | 11. Click on the new file in the explorer, an editor opens 696 | 12. Enter the following lines into the editor 697 | 698 | ```csv 699 | BusinessPartner;LastName;FirstName 700 | 1004155;Watson;Alice 701 | 1004161;Lynotte;Phil 702 | 1004100;Masci;J 703 | ``` 704 | 705 | 13. Save the file 706 | 707 | 14. Open the ```srv/risk-service.js``` file 708 | 709 | 15. Add the following lines at the end of the file: 710 | 711 | ```javascript 712 | /** 713 | * Implementation for Risk Management service defined in ./risk-service.cds 714 | */ 715 | module.exports = async (srv) => { 716 | srv.after('READ', 'Risks', (risks) => { 717 | risks.forEach((risk) => { 718 | if (risk.impact >= 100000) { 719 | risk.criticality = 1; 720 | } else { 721 | risk.criticality = 2; 722 | } 723 | }); 724 | }); 725 | //### BEGIN OF INSERT 726 | 727 | const BupaService = await cds.connect.to('API_BUSINESS_PARTNER'); 728 | srv.on('READ', srv.entities.BusinessPartners, async (req) => { 729 | return await BupaService.tx(req).run(req.query); 730 | }); 731 | //### END OF INSERT 732 | } 733 | ``` 734 | 735 | You've now created a custom handler for your service. This time it called ```on``` for the ```READ``` event. 736 | 737 | It is invoked when your ```BusinessPartner``` service is called for a read, so whenever there’s a request for business partner data, this handler is called. It makes sure the request for the business partner is directed to the external business partner service. 738 | 739 | 16. Save the file 740 | 741 | 17. In your browser, open the ```BusinessPartners``` link to see the data 742 | 743 | ![API EDMX](../ex1/images/01_03_0020.png) 744 | 745 | In the next step, you change the code, so that the data is fetched from the actual service in an SAP S/4HANA Cloud system. 746 | 747 | 748 | 749 | 750 | ## ############################################################### 751 | 752 | ## Exercise 1.5 Consume the External Service in Your UI Application 753 | 754 | In this chapter, you incorporate the external service into the UI application. 755 | 756 | 1. Open the ```db/data/schema.cds``` file 757 | 2. Uncomment the ```bp``` property 758 | 759 | ```javascript 760 | namespace sap.ui.riskmanagement; 761 | using { managed } from '@sap/cds/common'; 762 | entity Risks : managed { 763 | key ID : UUID @(Core.Computed : true); 764 | title : String(100); 765 | prio : String(5); 766 | descr : String; 767 | miti : Association to Mitigations; 768 | impact : Integer; 769 | //### BEGIN OF DELETE 770 | //bp : Association to BusinessPartners; 771 | //### END OF DELETE 772 | //### BEGIN OF INSERT 773 | bp : Association to BusinessPartners; 774 | //### END OF INSERT 775 | criticality : Integer; 776 | } 777 | entity Mitigations : managed { 778 | key ID : UUID @(Core.Computed : true); 779 | description : String; 780 | owner : String; 781 | timeline : String; 782 | risks : Association to many Risks on risks.miti = $self; 783 | } 784 | // using an external service from S/4 785 | using {  API_BUSINESS_PARTNER as external } from '../srv/external/API_BUSINESS_PARTNER.csn'; 786 | entity BusinessPartners as projection on external.A_BusinessPartner { 787 | key BusinessPartner, 788 | LastName, 789 | FirstName 790 | } 791 | ``` 792 | 793 | As you got a new property in your entity, you need to add data for this property in the local data file that you've created before for the ```risk``` entity. 794 | 795 | 796 | 3. Open the file `sap.ui.riskmanagement-Risks.csv` in your `db/data` folder 797 | 4. Replace the content with the new content below which additionally includes the BP data 798 | 799 | ```csv 800 | ID;createdAt;createdBy;title;owner;prio;descr;miti_id;impact;bp_BusinessPartner 801 | 20466922-7d57-4e76-b14c-e53fd97dcb11;2019-10-24;tim.back@sap.com;CFR non-compliance;Fred Fish;3;Recent restructuring might violate CFR code 71;20466921-7d57-4e76-b14c-e53fd97dcb11;10000;1004155 802 | 20466922-7d57-4e76-b14c-e53fd97dcb12;2019-10-24;tim.back@sap.com;SLA violation with possible termination cause;George Gung;2;Repeated SAL violation on service delivery for two successive quarters;20466921-7d57-4e76-b14c-e53fd97dcb12;90000;1004161 803 | 20466922-7d57-4e76-b14c-e53fd97dcb13;2019-10-24;tim.back@sap.com;Shipment violating export control;Herbert Hunter;1;Violation of export and trade control with unauthorized downloads;20466921-7d57-4e76-b14c-e53fd97dcb13;200000;1004100 804 | ``` 805 | 806 | 5. Save the file 807 | 808 | If you check the content of the file, you see numbers like ```1004155``` at the end of the lines, representing business partners. 809 | 810 | 811 | ### Add the Business Partner Field to the UI 812 | 813 | Now, you also introduce the business partner field in the UI. For this you need to perform the following steps: 814 | 815 | - Add a label for the columns in the result list table as well as in the object page by adding a title annotation 816 | - Add the business partner as a line item to include it as a column in the result list 817 | - Add the business partner as a field to a field group, which makes it appear in a form on the object page 818 | 819 | All this happens in the cds file that has all the UI annotations. 820 | 821 | 1. Open the ```srv/risks-service-ui.cds``` file 822 | 2. Uncomment the following parts: 823 | 824 | ```javascript 825 | using RiskService from './risk-service'; 826 | 827 | annotate RiskService.Risks with { 828 | ... 829 | //### BEGIN OF DELETE 830 | //bp @title: 'Business Partner'; 831 | //### END OF DELETE 832 | //### BEGIN OF INSERT 833 | bp @title: 'Business Partner'; 834 | //### END OF INSERT 835 | ... 836 | } 837 | 838 | 839 | annotate RiskService.Risks with @( 840 | UI: { 841 | ... 842 | LineItem: [ 843 | ... 844 | //### BEGIN OF DELETE 845 | //{Value: bp_BusinessPartner}, 846 | //### END OF DELETE 847 | //### BEGIN OF INSERT 848 | {Value: bp_BusinessPartner}, 849 | //### END OF INSERT 850 | ... 851 | ], 852 | ... 853 | FieldGroup#Main: { 854 | Data: [ 855 | ... 856 | 857 | //### BEGIN OF DELETE 858 | //{Value: bp_BusinessPartner}, 859 | //### END OF DELETE 860 | //### BEGIN OF INSERT 861 | {Value: bp_BusinessPartner}, 862 | //### END OF INSERT 863 | ... 864 | ] 865 | } 866 | }, 867 | ) { 868 | 869 | }; 870 | 871 | 872 | annotate RiskService.Risks with { 873 | miti @( 874 | Common: { 875 | //show text, not id for mitigation in the context of risks 876 | Text: miti.description , TextArrangement: #TextOnly, 877 | ValueList: { 878 | Label: 'Mitigations', 879 | CollectionPath: 'Mitigations', 880 | Parameters: [ 881 | { $Type: 'Common.ValueListParameterInOut', 882 | LocalDataProperty: miti_ID, 883 | ValueListProperty: 'ID' 884 | }, 885 | { $Type: 'Common.ValueListParameterDisplayOnly', 886 | ValueListProperty: 'description' 887 | } 888 | ] 889 | } 890 | }, 891 | UI.MultiLineText: IsActiveEntity 892 | ); 893 | //### BEGIN OF DELETE 894 | /* 895 | //### END OF DELETE 896 | bp @( 897 | Common: { 898 | Text: bp.LastName , TextArrangement: #TextOnly, 899 | ValueList: { 900 | Label: 'Business Partners', 901 | CollectionPath: 'BusinessPartners', 902 | Parameters: [ 903 | { $Type: 'Common.ValueListParameterInOut', 904 | LocalDataProperty: bp_BusinessPartner, 905 | ValueListProperty: 'BusinessPartner' 906 | }, 907 | { $Type: 'Common.ValueListParameterDisplayOnly', 908 | ValueListProperty: 'LastName' 909 | }, 910 | { $Type: 'Common.ValueListParameterDisplayOnly', 911 | ValueListProperty: 'FirstName' 912 | } 913 | ] 914 | } 915 | } 916 | ) 917 | //### BEGIN OF DELETE 918 | */ 919 | 920 | /* 921 | //### END OF DELETE 922 | annotate RiskService.BusinessPartners with { 923 | BusinessPartner @( 924 | UI.Hidden, 925 | Common: { 926 | Text: LastName 927 | } 928 | ); 929 | LastName @title: 'Last Name'; 930 | FirstName @title: 'First Name'; 931 | } 932 | //### BEGIN OF DELETE 933 | */ 934 | //### END OF DELETE 935 | } 936 | ``` 937 | 938 | What does this mean? The first parts that are getting rid of the comments are easy: They just enable the title and add the business partner first as a column to the list and then as a field to the object page, just like other columns and fields were added before. 939 | 940 | The larger part of new annotations activates the same qualitites for the ```bp``` field as it happened before in exercise 1.2 for the ```miti``` field: Instead of showing the id of the business partner, its ```LastName```property is displayed. The ```ValueList``` part introduces a value list for the business partner and shows it last and first name in it. 941 | 942 | 943 | 3. Save the file 944 | 4. Open the ```srv/risk-service.js``` file 945 | 5. Add the following lines to the file: 946 | 947 | ```js 948 | module.exports = async (srv) => { 949 | srv.after('READ', 'Risks', (risks) => { 950 | 951 | risks.forEach((risk) => { 952 | if (risk.impact >= 100000) { 953 | risk.criticality = 1; 954 | } else { 955 | risk.criticality = 2; 956 | } 957 | }); 958 | }); 959 | 960 | const BupaService = await cds.connect.to('API_BUSINESS_PARTNER'); 961 | srv.on('READ', srv.entities.BusinessPartners, async (req) => { 962 | return await BupaService.tx(req).run(req.query); 963 | }); 964 | //### BEGIN OF INSERT 965 | 966 | srv.on('READ', 'Risks', async (req, next) => { 967 | /* 968 | Check whether the request want an "expand" of the business partner 969 | As this is not possible, the risk entity and the business partner entity are in different systems (Cloud Platform and S/4 HANA Cloud), 970 | if there is such an expand, remove it 971 | */ 972 | const expandIndex = req.query.SELECT.columns.findIndex(({ expand, ref }) => expand && ref[0] === 'bp'); 973 | console.log(req.query.SELECT.columns) 974 | if (expandIndex < 0) return next(); 975 | 976 | req.query.SELECT.columns.splice(expandIndex, 1); 977 | if (!req.query.SELECT.columns.find( column => column.ref.find( ref => ref == "bp_BusinessPartner" ))) { 978 | req.query.SELECT.columns.push({ ref: ["bp_BusinessPartner"] }); 979 | } 980 | 981 | /* 982 | Instead of carrying out the expand, issue a separate request for each business partner 983 | This code could be optimized, instead of having n requests for n business partners, just on bulk request could be created 984 | */ 985 | const res = await next(); 986 | await Promise.all( 987 | res.map( async risk => { 988 | const bp = await BupaService 989 | .tx(req) 990 | .run(SELECT.one(srv.entities.BusinessPartners).where({ BusinessPartner: risk.bp_BusinessPartner }) 991 | .columns([ "BusinessPartner", "LastName", "FirstName" ])); 992 | risk.bp = bp; 993 | console.dir(risk.bp) 994 | } 995 | )); 996 | return res; 997 | }); 998 | //### END OF INSERT 999 | } 1000 | ``` 1001 | 1002 | Again you have now added a custom handler, this one is called ```on``` a ```READ``` of the ```Risks``` service. It checks whether the request includes a so-called expand for business partners. This is a request that is issued by the UI when the list should be filled. While it mostly contains columns that directly belong to the ```Risks``` entity, it also contains the business partner. As we have seen in the annotation file, instead of showing the id of the business partner, the last name of the business partner will be shown. This data is in the business partner and not in the risks entity. Therefore, the UI wants to expand, i.e. for each risk the corresponing business partner is also read. 1003 | 1004 | However, there is an issue with this: The ```Risk``` entity is from the Cloud Platform, the busines partner, however, is potentially from a remote S/4 HANA Cloud system. In such a case the expand cannot be carried out. Because of this, we need to remove the expand from the request. Instead the code issues separate requests for each business partner directly to the business partner service. As the code stands, for each risk there is a separate request for a business partner. This is not optimal, it would be better if all the business partners were fetched in a bulk request. You can make this change on your own if you like! 1005 | 1006 | 6. Save the file 1007 | 7. In your tab with the application, go back to the **index.html** page and press refresh 1008 | 1009 | 8. On the launch page that now comes up, choose the **Risks** tile and then click **Go** 1010 | 1011 | You now see the ```Risks``` application with the business partner data in both the result list and the object page, which is loaded when you click on one of the rows in the table: 1012 | 1013 | ![Business Partner Data](../ex1/images/01_04_0010.png "Business Partner Data") 1014 | 1015 | ![Business Partner Data](../ex1/images/01_04_0020.png "Business Partner Data") 1016 | 1017 | 1018 | 1019 | ## ############################################################### 1020 | 1021 | ## Exercise 1.6 Roles and Authorization Checks In CAP 1022 | 1023 | In this exercise we will add authorizations to the CAP service, so that only users with the right authorization can view the data or even edit and create data. We will also add a mock user locally to test the functionality. 1024 | 1025 | ### Enable Authentication Support 1026 | 1027 | The enable authentication support in CAP, a `node.js` module called `passport` needs to be installed. 1028 | 1029 | 1. Navigate to your ```RiskManagement``` folder in a terminal in the Business Application Studio. With your `cds watch` still running in one terminal, it is the easiest to open another second terminal next to it, by invoking **Terminal** and the **New Terminal** in the menu. Alternatively, you can also suspend `cds watch` in your existing terminal by pressing **CTRL+C**. In both cases you should already be in the ```Riskmanagement``` folder 1030 | 1031 | 2. Install the ```passport``` module. (the --save part makes sure it’s also added as a dependency to your project's ```package.json```) 1032 | 1033 | ```bash 1034 | npm install --save passport 1035 | ``` 1036 | 1037 | ### Adding Cap Role Restrictions to Entities 1038 | 1039 | In this step we add the authorizations to the ```Risks``` service. 1040 | 1041 | 1. Open the file ```srv/risk-service.cds``` 1042 | 1043 | 2. Change the code in the following way and, by this, add the restrictions (`@(...)`) block to your `Risks` and `Mitigations` entities 1044 | 1045 | ```js 1046 | using { sap.ui.riskmanagement as my } from '../db/schema'; 1047 | @path: 'service/risk' 1048 | service RiskService { 1049 | //### BEGIN OF DELETE 1050 | entity Risks as projection on my.Risks; 1051 | //### END OF DELETE 1052 | //### BEGIN OF INSERT 1053 | entity Risks @(restrict : [ 1054 | { 1055 | grant : [ 'READ' ], 1056 | to : [ 'RiskViewer' ] 1057 | }, 1058 | { 1059 | grant : [ '*' ], 1060 | to : [ 'RiskManager' ] 1061 | } 1062 | ]) as projection on my.Risks; 1063 | //### END OF INSERT 1064 | annotate Risks with @odata.draft.enabled; 1065 | //### BEGIN OF DELETE 1066 | entity Mitigations as projection on my.Mitigations; 1067 | //### END OF DELETE 1068 | //### BEGIN OF INSERT 1069 | entity Mitigations @(restrict : [ 1070 | { 1071 | grant : [ 'READ' ], 1072 | to : [ 'RiskViewer' ] 1073 | }, 1074 | { 1075 | grant : [ '*' ], 1076 | to : [ 'RiskManager' ] 1077 | } 1078 | ]) as projection on my.Mitigations; 1079 | //### END OF INSERT 1080 | annotate Mitigations with @odata.draft.enabled; 1081 | entity BusinessPartners as projection on my.BusinessPartners; 1082 | } 1083 | ``` 1084 | 3. Save the file 1085 | 1086 | With this change users that have the role `RiskViewer` assigned can view ("read") risks and mitigations, and a user with role `RiskManager` can view and change risks and mitigations. They are granted all the authorizations ("*"). 1087 | 1088 | ### Add Users for Local Testing 1089 | 1090 | Since the authorization checks have been added to the CAP model, they apply not only when deployed to the cloud but also for local testing. Therefore, we need a way to log in to the application locally. 1091 | 1092 | CAP offers a possibility to add local users for testing as part of the `cds` configuration. In this tutorial, we use the `.cdsrc.json` file to add the users. 1093 | 1094 | 1095 | 1. In the project, go to the files **.cdsrc.json** and open it for editing 1096 | 2. In the editor, replace its content with the following lines 1097 | 1098 | ```json 1099 | { 1100 | "[development]": { 1101 | "auth": { 1102 | "passport": { 1103 | "strategy": "mock", 1104 | "users": { 1105 | "risk.viewer@tester.sap.com": { 1106 | "password": "initial", 1107 | "ID": "riskviewer", 1108 | "userAttributes": { 1109 | "email": "risk.viewer@tester.sap.com" 1110 | }, 1111 | "roles": [ 1112 | "RiskViewer" 1113 | ] 1114 | }, 1115 | "risk.manager@tester.sap.com": { 1116 | "password": "initial", 1117 | "ID": "riskmanager", 1118 | "userAttributes": { 1119 | "email": "risk.manager@tester.sap.com" 1120 | }, 1121 | "roles": [ 1122 | "RiskManager" 1123 | ] 1124 | } 1125 | } 1126 | } 1127 | } 1128 | } 1129 | } 1130 | ``` 1131 | 1132 | 3. Save the file 1133 | 1134 | The file defines two users `riskviewer` and `riskmanager`. Let's look at the `riskmanager` example. 1135 | 1136 | 1137 | The user is defined by an `ID`, which can be any identifier for a user. The user has an `email`, a `password` parameter, and a `roles` parameter. 1138 | 1139 | ### Access the Risk Application with a User and Password 1140 | 1141 | When accessing the `Risks` or the `Mitigations` service in the browser, you get a basic authorisation pop-up, asking for your user and password. You can use two users to log in and see that it works. 1142 | 1143 | 1. In the tab with the running application, navigate back to the launchpage, press refresh in the browser 1144 | 1145 | 2. Choose the **Risks** tile and in the app press **Go** 1146 | 1147 | 3. In the pop-up, enter the *Username*: `riskmanager` 1148 | 1149 | 4. Enter the *Password*: `initial` 1150 | 1151 | ![Authorizations](../ex1/images/01_06_0010.png) 1152 | 1153 | 5. You can now access the **Risks** application 1154 | 1155 | Unfortunately, there’s no logout functionality. However, you can use the "Clear Browser Cache" function or simply close all browser windows to get rid of the basic authentication login data in the browser. 1156 | 1157 | 1158 | This is it! You have mastered all the steps to locally run the entire application! 1159 | 1160 | Continue to - [Exercise 2](../ex2/README.md) in order to prepare everything that is needed to deploy the application to the Cloud Platform. 1161 | 1162 | 1163 | 1164 | ## Troubleshooting 1165 | 1166 | ### I get an "[ERROR] listen EADDRINUSE: address already in use :::4004" when invoking cds watch 1167 | 1168 | You have probably still got `cds watch` running in one terminal and have started a new `cds watch` in another one. CAP allows only one instance to run, this is why you get the error. You can resolve the issue by pressing ***CTRL + C*** in one of the terminal. This will stop the current instance while the other one still continues running. 1169 | Normally closing the terminal in which the current instance runs will also terminate the `cds watch` process there. In some rare cases, the process still runs but is not visible anymore. In order to stopp such a process, once again open a terminal and type: 1170 | 1171 | ``` 1172 | ps a 1173 | ``` 1174 | 1175 | In the output you will find a line like this, indicating the `cds watch` instance: 1176 | 1177 | ``` 1178 | PID TTY STAT TIME COMMAND 1179 | 7897 pts/1 S+ 0:00 node-10/node /home/user/.node_modules_global/bin/cds watch 1180 | ``` 1181 | 1182 | Copy the number under ***PID** (in the above case 7897) and carry out 1183 | 1184 | ``` 1185 | kill 1186 | ``` 1187 | 1188 | in the terminal (in this example `kill 7897`). Now you can start `cds watch` again. 1189 | 1190 | 1191 | -------------------------------------------------------------------------------- /exercises/ex1/images/01_01_0010.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/teched2020-DEV166/66223ca859bbd84346d4ab6ce5086209bdd65215/exercises/ex1/images/01_01_0010.png -------------------------------------------------------------------------------- /exercises/ex1/images/01_01_0020.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/teched2020-DEV166/66223ca859bbd84346d4ab6ce5086209bdd65215/exercises/ex1/images/01_01_0020.png -------------------------------------------------------------------------------- /exercises/ex1/images/01_01_0030.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/teched2020-DEV166/66223ca859bbd84346d4ab6ce5086209bdd65215/exercises/ex1/images/01_01_0030.png -------------------------------------------------------------------------------- /exercises/ex1/images/01_01_0040.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/teched2020-DEV166/66223ca859bbd84346d4ab6ce5086209bdd65215/exercises/ex1/images/01_01_0040.png -------------------------------------------------------------------------------- /exercises/ex1/images/01_01_0050.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/teched2020-DEV166/66223ca859bbd84346d4ab6ce5086209bdd65215/exercises/ex1/images/01_01_0050.png -------------------------------------------------------------------------------- /exercises/ex1/images/01_01_0060.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/teched2020-DEV166/66223ca859bbd84346d4ab6ce5086209bdd65215/exercises/ex1/images/01_01_0060.png -------------------------------------------------------------------------------- /exercises/ex1/images/01_01_0070.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/teched2020-DEV166/66223ca859bbd84346d4ab6ce5086209bdd65215/exercises/ex1/images/01_01_0070.png -------------------------------------------------------------------------------- /exercises/ex1/images/01_01_0080.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/teched2020-DEV166/66223ca859bbd84346d4ab6ce5086209bdd65215/exercises/ex1/images/01_01_0080.png -------------------------------------------------------------------------------- /exercises/ex1/images/01_01_0090.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/teched2020-DEV166/66223ca859bbd84346d4ab6ce5086209bdd65215/exercises/ex1/images/01_01_0090.png -------------------------------------------------------------------------------- /exercises/ex1/images/01_01_0100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/teched2020-DEV166/66223ca859bbd84346d4ab6ce5086209bdd65215/exercises/ex1/images/01_01_0100.png -------------------------------------------------------------------------------- /exercises/ex1/images/01_02_0010.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/teched2020-DEV166/66223ca859bbd84346d4ab6ce5086209bdd65215/exercises/ex1/images/01_02_0010.png -------------------------------------------------------------------------------- /exercises/ex1/images/01_02_0020.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/teched2020-DEV166/66223ca859bbd84346d4ab6ce5086209bdd65215/exercises/ex1/images/01_02_0020.png -------------------------------------------------------------------------------- /exercises/ex1/images/01_02_0030.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/teched2020-DEV166/66223ca859bbd84346d4ab6ce5086209bdd65215/exercises/ex1/images/01_02_0030.png -------------------------------------------------------------------------------- /exercises/ex1/images/01_02_0040.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/teched2020-DEV166/66223ca859bbd84346d4ab6ce5086209bdd65215/exercises/ex1/images/01_02_0040.png -------------------------------------------------------------------------------- /exercises/ex1/images/01_02_0050.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/teched2020-DEV166/66223ca859bbd84346d4ab6ce5086209bdd65215/exercises/ex1/images/01_02_0050.png -------------------------------------------------------------------------------- /exercises/ex1/images/01_02_0060.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/teched2020-DEV166/66223ca859bbd84346d4ab6ce5086209bdd65215/exercises/ex1/images/01_02_0060.png -------------------------------------------------------------------------------- /exercises/ex1/images/01_02_0070.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/teched2020-DEV166/66223ca859bbd84346d4ab6ce5086209bdd65215/exercises/ex1/images/01_02_0070.png -------------------------------------------------------------------------------- /exercises/ex1/images/01_02_0075.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/teched2020-DEV166/66223ca859bbd84346d4ab6ce5086209bdd65215/exercises/ex1/images/01_02_0075.png -------------------------------------------------------------------------------- /exercises/ex1/images/01_02_0080.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/teched2020-DEV166/66223ca859bbd84346d4ab6ce5086209bdd65215/exercises/ex1/images/01_02_0080.png -------------------------------------------------------------------------------- /exercises/ex1/images/01_02_0090.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/teched2020-DEV166/66223ca859bbd84346d4ab6ce5086209bdd65215/exercises/ex1/images/01_02_0090.png -------------------------------------------------------------------------------- /exercises/ex1/images/01_02_0100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/teched2020-DEV166/66223ca859bbd84346d4ab6ce5086209bdd65215/exercises/ex1/images/01_02_0100.png -------------------------------------------------------------------------------- /exercises/ex1/images/01_02_0110.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/teched2020-DEV166/66223ca859bbd84346d4ab6ce5086209bdd65215/exercises/ex1/images/01_02_0110.png -------------------------------------------------------------------------------- /exercises/ex1/images/01_02_0120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/teched2020-DEV166/66223ca859bbd84346d4ab6ce5086209bdd65215/exercises/ex1/images/01_02_0120.png -------------------------------------------------------------------------------- /exercises/ex1/images/01_02_0130.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/teched2020-DEV166/66223ca859bbd84346d4ab6ce5086209bdd65215/exercises/ex1/images/01_02_0130.png -------------------------------------------------------------------------------- /exercises/ex1/images/01_03_0010.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/teched2020-DEV166/66223ca859bbd84346d4ab6ce5086209bdd65215/exercises/ex1/images/01_03_0010.png -------------------------------------------------------------------------------- /exercises/ex1/images/01_03_0020.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/teched2020-DEV166/66223ca859bbd84346d4ab6ce5086209bdd65215/exercises/ex1/images/01_03_0020.png -------------------------------------------------------------------------------- /exercises/ex1/images/01_03_0030.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/teched2020-DEV166/66223ca859bbd84346d4ab6ce5086209bdd65215/exercises/ex1/images/01_03_0030.png -------------------------------------------------------------------------------- /exercises/ex1/images/01_03_0040.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/teched2020-DEV166/66223ca859bbd84346d4ab6ce5086209bdd65215/exercises/ex1/images/01_03_0040.png -------------------------------------------------------------------------------- /exercises/ex1/images/01_03_0050.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/teched2020-DEV166/66223ca859bbd84346d4ab6ce5086209bdd65215/exercises/ex1/images/01_03_0050.png -------------------------------------------------------------------------------- /exercises/ex1/images/01_04_0010.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/teched2020-DEV166/66223ca859bbd84346d4ab6ce5086209bdd65215/exercises/ex1/images/01_04_0010.png -------------------------------------------------------------------------------- /exercises/ex1/images/01_04_0020.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/teched2020-DEV166/66223ca859bbd84346d4ab6ce5086209bdd65215/exercises/ex1/images/01_04_0020.png -------------------------------------------------------------------------------- /exercises/ex1/images/01_06_0010.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/teched2020-DEV166/66223ca859bbd84346d4ab6ce5086209bdd65215/exercises/ex1/images/01_06_0010.png -------------------------------------------------------------------------------- /exercises/ex2/README.md: -------------------------------------------------------------------------------- 1 | # Exercise 2 Prepare for Business Technology Platform Deployment 2 | 3 | Up to this point, the whole application, its data model, its service and its UI application was running locally in your Business Application Studio workspace. Even though we don't cover it in this tutorial, the same would have been possible on your laptop / PC with extensions for Microsoft's Visual Code. 4 | 5 | In this exercise, we will prepare the application for a deployment to the SAP Business Technology Platform. In [Exercise 3](../ex3/README.md) a Continuous Integration / Continuous Delivery (CI/CD) Service is introduced that takes care of the deployment every time there is a change in the source code. 6 | 7 | ## ############################################################### 8 | 9 | ## Exercise 2.1 Prepare for SAP HANA Deployment 10 | 11 | While the locally running application uses an in-memory SQLite database, the deployed version will use SAP HANA. CAP helps you with the creation of the database and the deployment of the test data. At runtime it knows which database to connect to. 12 | 13 | In order for this to work, please perform these steps: 14 | 15 | 1. Open a new terminal in BAS (**Terminal**->**New Terminal**) 16 | 2. In the terminal, run the following command to install the hdb module and automatically add it as a dependency into the `package.json` file of your project: 17 | 18 | ``` 19 | npm install hdb --save 20 | ``` 21 | 22 | 3. In you project, open the `package.json` file and add the following lines: 23 | 24 | ```json 25 | { 26 | "name": "cpapp", 27 | ... 28 | "cds": { 29 | "requires": { 30 | //### BEGIN OF INSERT 31 | "db": { 32 | "kind": "sql" 33 | }, 34 | //### END OF INSERT 35 | "API_BUSINESS_PARTNER": { 36 | "kind": "odata", 37 | "model": "srv/external/API_BUSINESS_PARTNER" 38 | } 39 | //### BEGIN OF DELETE 40 | } 41 | //### END OF DELETE 42 | //### BEGIN OF INSERT 43 | }, 44 | "hana": { 45 | "deploy-format": "hdbtable" 46 | } 47 | //### END OF INSERT 48 | } 49 | } 50 | ``` 51 | 4. Save the file 52 | ## ############################################################### 53 | 54 | ## Exercise 2.2 Prepare User Authentication and Authorization (XSUAA) Setup 55 | 56 | ### Enable Authentication Support 57 | 58 | To enable authentication support in CAP for SAP Business Technology Platform, the `xssec` and `xsenv` modules need to be installed. 59 | 60 | 1. Open a new terminal in BAS (**Terminal**->**New Terminal**) 61 | 2. In the terminal, run the following command to install the hdb module and automatically add it as a dependency into the `package.json` file of your project: 62 | 63 | ```bash 64 | npm i --save @sap/xssec @sap/xsenv 65 | ``` 66 | 67 | ### Add UAA Service 68 | 69 | We need to tell CAP that the security component XSUAA (XS User Authentiation and Authorization service) is used. Please perfom these steps: 70 | 1. Open the `package.json` folder in your project and add the following lines: 71 | 72 | ```json 73 | { 74 | "name": "cpapp", 75 | ... 76 | "cds": { 77 | "requires": { 78 | "db": { 79 | "kind": "sql" 80 | }, 81 | //### BEGIN OF INSERT 82 | "uaa": { 83 | "kind": "xsuaa", 84 | "credentials": {} 85 | }, 86 | //### END OF INSERT 87 | "API_BUSINESS_PARTNER": { 88 | "kind": "odata", 89 | "model": "srv/external/API_BUSINESS_PARTNER" 90 | } 91 | } 92 | } 93 | } 94 | ``` 95 | 96 | 2. Save the file 97 | 98 | ### Roles and Scopes 99 | 100 | In the context of Cloud Foundry within the Business Technology Platform a single authorization is called scope, for example, there could be a scope "Read" and a scope "Write", that allows a user to read or write a certain business object. Scopes cannot be assigned to users directly. They are packaged into roles. For example, the role "Editor" could consist of the "Read" and "Write" scopes, while the role "Viewer" consists only of the "Read" scope. 101 | 102 | However, CAP recommends to use roles only and do a one-to-one mapping. In [Exercise 1.6 - Roles and Authorization Checks In CAP](../ex1#exercise-16--roles-and-authorization-checks-in-cap) we defined two roles. 103 | 104 | ### XSUAA Security Configuration 105 | 106 | Create the file `xs-security.json` in your `RiskManagement` project by executing the following in a terminal in BAS: 107 | 108 | ``` 109 | cds compile srv --to xsuaa >xs-security.json 110 | ``` 111 | 112 | The generated file then contains the configuration of the XSUAA. Behind the scenes, CAP has taken the authorization parts ```@(restrict ... )``` from our service definition from [here](../ex1#exercise-16--roles-and-authorization-checks-in-cap) and created scopes and role templates from it. 113 | 114 | For example, it finds the roles `RiskViewer` and `RiskManager` in the `srv/risk-service.cds` file: 115 | 116 | ```javascript 117 | entity Risks @(restrict : [ 118 | { 119 | grant : [ 'READ' ], 120 | to : [ 'RiskViewer' ] 121 | }, 122 | { 123 | grant : [ '*' ], 124 | to : [ 'RiskManager' ] 125 | } 126 | ]) as projection on my.Risks; 127 | ``` 128 | 129 | And creats scopes and roles for both in the `xs-security.json` file in your project: 130 | 131 | ```json 132 | { 133 | "xsappname": "RiskManagement", 134 | "tenant-mode": "dedicated", 135 | "scopes": [ 136 | { 137 | "name": "$XSAPPNAME.RiskViewer", 138 | "description": "Risk Viewer" 139 | }, 140 | { 141 | "name": "$XSAPPNAME.RiskManager", 142 | "description": "Risk Manager" 143 | } 144 | ], 145 | "role-templates": [ 146 | { 147 | "name": "RiskViewer", 148 | "description": "Risk Viewer", 149 | "scope-references": [ 150 | "$XSAPPNAME.RiskViewer" 151 | ], 152 | "attribute-references": [] 153 | }, 154 | { 155 | "name": "RiskManager", 156 | "description": "Risk Manager", 157 | "scope-references": [ 158 | "$XSAPPNAME.RiskManager" 159 | ], 160 | "attribute-references": [] 161 | }, 162 | { 163 | "name": "Token_Exchange", 164 | "description": "UAA", 165 | "scope-references": [ 166 | "uaa.user" 167 | ] 168 | } 169 | ] 170 | } 171 | ``` 172 | 173 | 174 | ## ############################################################### 175 | 176 | ## Exercise 2.3 Create a "Multi Target Application" (MTA) File for Deployment 177 | 178 | In this section we will create a "Multi Target Application" (MTA) file for deployment. (See the [description](https://help.sap.com/viewer/4505d0bdaf4948449b7f7379d24d0f0d/latest/en-US/ebb42efc880c4276a5f2294063fae0c3.html)). MTA is a way to create deployments consisting of multiple modules that can be implemented in different technologies. Advantages of this technology are that it comes with a build tool, automatically creates service instances, service keys and destinations, deploys content (HTML5, workflow, ...) and supports [blue-green deployment](https://help.sap.com/viewer/65de2977205c403bbc107264b8eccf4b/Cloud/en-US/7c83810c31d842938cbc39c135a2d99f.html). 179 | 180 | ### Generate MTA Deployment Descriptor (`mta.yaml`) 181 | 182 | The MTA deployment is described in the [MTA Deployment Descriptor](https://help.sap.com/viewer/4505d0bdaf4948449b7f7379d24d0f0d/2.0.03/en-US/33548a721e6548688605049792d55295.html), a file called `mta.yaml`. 183 | In the first step, let CAP generate an initial `mta.yaml` file. 184 | 185 | 1. Open a new terminal in BAS (**Terminal**->**New Terminal**) 186 | 2. In the terminal, run the following: 187 | 188 | ``` 189 | cds add mta 190 | ``` 191 | 192 | The `cds` Command Line Interface has generated the file based on your previously created settings in the `package.json` file. 193 | 194 | 3. Open the new `mta.yaml` file 195 | 196 | The `mta.yaml` file consists of different modules, that are Cloud Foundry apps, and resources, that are Cloud Foundry services. 197 | 198 | *Modules:* 199 | 200 | * `RiskManagement-srv` - OData service 201 | * `RiskManagement-db-deployer` - Deploy CAP schema and data (CSV files) to database 202 | 203 | *Resources:* 204 | 205 | The resources are generated from the `requires` section of `cds` in the `package.json`. 206 | 207 | * `RiskManagement-db` - HANA DB HDMI container 208 | * `RiskManagement-uaa` - XSUAA service 209 | 210 | The resources are Cloud Foundry service instances, that are automatically created and updated during the MTA deployment. 211 | 212 | 4. Change the following: 213 | 214 | ```yaml 215 | ... 216 | # services extracted from CAP configuration 217 | # 'service-plan' can be configured via 'cds.requires..vcap.plan' 218 | # ------------------------------------------------------------ 219 | - name: RiskManagement-db 220 | # ------------------------------------------------------------ 221 | type: com.sap.xs.hdi-container 222 | parameters: 223 | //### BEGIN OF DELETE 224 | service: hana # or 'hanatrial' on trial landscapes 225 | //### END OF DELETE 226 | //### BEGIN OF INSERT 227 | service: hanatrial 228 | //### END OF INSERT 229 | service-plan: hdi-shared 230 | properties: 231 | hdi-service-name: ${service-name} 232 | ``` 233 | 234 | 5. Save the file 235 | 236 | As the application will run on a HANA trial instance, the corresponding HANA service needs to be used. 237 | 238 | ## ############################################################### 239 | 240 | ## Exercise 2.4 Add Authorization and Trust Management Service (XSUAA) 241 | 242 | The next step is to add the Authorization and Trust Management Service to the `mta.yaml` to allow user login, authorization and authentication checks. 243 | 244 | 1. In your `mta.yaml` file change the following: 245 | 246 | 247 | ```yaml 248 | _schema-version: '3.1' 249 | ... 250 | resources: 251 | ... 252 | # ------------------------------------------------------------ 253 | - name: RiskManagement-uaa 254 | # ------------------------------------------------------------ 255 | type: org.cloudfoundry.managed-service 256 | parameters: 257 | service: xsuaa 258 | service-plan: application 259 | //### BEGIN OF INSERT 260 | path: ./xs-security.json 261 | //### END OF INSERT 262 | config: 263 | //### BEGIN OF DELETE 264 | xsappname: -${space} # name + space dependency 265 | tenant-mode: dedicated 266 | //### END OF DELETE 267 | //### BEGIN OF INSERT 268 | xsappname: 'RiskManagement-${space}' 269 | role-collections: 270 | - name: 'RiskManager-${space}' 271 | description: Manage Risks 272 | role-template-references: 273 | - $XSAPPNAME.RiskManager 274 | - name: 'RiskViewer-${space}' 275 | description: View Risks 276 | role-template-references: 277 | - $XSAPPNAME.RiskViewer 278 | //### END OF INSERT 279 | ``` 280 | 2. Save the file 281 | 282 | The configuration for XSUAA is read from the `xs-security.json` file that was created in the previous step. 283 | 284 | However in the `config` element, values can be added and overwritten. 285 | 286 | The value `xsappname` gets overwritten with a Cloud Foundry space-dependent value. The name has to be unique within a Business Technology Platform subaccount. 287 | 288 | This allows multiple deployments of this tutorial in different spaces of the same subaccount. For example, if different people of a team want to try it out and don't want to create a new subaccount for each team member. 289 | 290 | For a productive application, the `xsappname` should be explicitly set to the desired value. 291 | 292 | Further, you can add role collections using the `xs-security.json` file. Since role collections need to be unique in a subaccount like the `xsappname`, you can add it here and use the `${space}` variable to make them unique like for the `xsappname`. 293 | 294 | Alternatively, role collections can be manually added in the SAP BTP cockpit. 295 | 296 | ## ############################################################### 297 | 298 | ## Exercise 2.5 Add an Application Router 299 | 300 | In order for our application to run on the cloud, we need another component on top of the service and the UI. It will route the request from the browser either to the CAP service or to the provider of the UI sources. It also makes sure that authenticated and authorized users get a token from the XSUAA service which is also routed to the CAP service, that checks for this token. 301 | All of this is provided by another application (`module` in the MTA context). This application is a so-called AppRouter application. 302 | 303 | ### Create the AppRouter NPM Module 304 | 305 | 1. Using a terminal in BAS, create a folder `approuter` where you store all AppRouter artifacts and switch to the new folder: 306 | 307 | ``` 308 | mkdir approuter 309 | cd approuter 310 | ``` 311 | 312 | (This of course could have also be done in the BAS' file explorer instead of the terminal, but since there is a command line interface in the folder needed in the next step, we chose the terminal for creating the folder) 313 | 314 | 2. In the terminal of the new `approuter` folder, initialize `npm` and install the latest version of AppRouter NPM module: 315 | 316 | ```bash 317 | npm init --yes 318 | npm install @sap/approuter 319 | ``` 320 | 321 | The functionality of the AppRouter is provided by the `@sap/approuter` NPM module. 322 | 323 | 2. Check the required Node.js version for AppRouter 324 | 325 | This is declared in the `package.json` file of the AppRouter. You can check it with this script: 326 | 327 | ```bash 328 | cat node_modules/@sap/approuter/package.json | grep '"node"' 329 | ``` 330 | 331 | It outputs something like: 332 | 333 | ``` 334 | "node": "^10.0.0 || ^12.0.0" 335 | ``` 336 | 337 | In this example AppRouter supports Node.js 10.x.x and 12.x.x versions. 338 | 339 | 3. Add the required Node.js version to the `approuter/package.json` file. This depends on the supported versions of the AppRouter, ^12.0.0 in this example. Also add the start script for the AppRouter. 340 | 341 | ```json 342 | { 343 | "name": "approuter", 344 | ... 345 | "scripts": { 346 | //### BEGIN OF DELETE 347 | "test": "echo \"Error: no test specified\" && exit 1" 348 | //### END OF DELETE 349 | //### BEGIN OF INSERT 350 | "start": "node node_modules/@sap/approuter/approuter.js" 351 | //### END OF INSERT 352 | }, 353 | ... 354 | "dependencies": { 355 | "@sap/approuter": "^8.5.5" 356 | //### BEGIN OF DELETE 357 | } 358 | //### END OF DELETE 359 | //### BEGIN OF INSERT 360 | }, 361 | "engines": { 362 | "node": "^12.0.0" 363 | } 364 | //### END OF INSERT 365 | } 366 | ``` 367 | 4. Save the file 368 | 369 | ### AppRouter Configuration 370 | 371 | Configure the AppRouter by creating a file `xs-app.json` in the `approuter` folder with the following content: 372 | 373 | ```json 374 | { 375 | "welcomeFile": "/app/risks/webapp/index.html", 376 | "authenticationMethod": "route", 377 | "sessionTimeout": 30, 378 | "logout": { 379 | "logoutEndpoint": "/do/logout", 380 | "logoutPage": "/" 381 | }, 382 | "routes": [ 383 | { 384 | "source": "^/app/(.*)$", 385 | "target": "$1", 386 | "localDir": "resources", 387 | "authenticationType": "xsuaa" 388 | }, 389 | { 390 | "source": "^/service/(.*)$", 391 | "destination": "srv-binding", 392 | "authenticationType": "xsuaa" 393 | } 394 | ] 395 | } 396 | ``` 397 | 398 | The configration in the `routes` array tells the AppRouter how to respond to requests. 399 | 400 | - The files in the `resources` folder will be served for all requests to `/app`. Later, there’s an explanation how you get the "app" files into this resource folder. 401 | - All requests starting with `/service` will be forwarded to the CAP service based on the URL we configured in the MTA using the destination `srv_app`. Remember, the risk service is reachable via `/service/risk`. Further services are automatically routed as long as they start with `/service/` as well. 402 | 403 | Further, the AppRouter will automatically redirect to the `/app/launchpage.html` when accessed without a path, which will then serve the file `resources/launchpage.html`. 404 | 405 | ## ############################################################### 406 | 407 | ## Exercise 2.6 Add UI and AppRouter Module to `mta.yaml` 408 | 409 | The automatic creation of the `mta.yaml` file added everything that is needed from the CAP side to the `mta.yaml` file: the service, the database deployer and also the dependency to the XSUAA and HANA service. 410 | Our Fiori elements based UI application, however, is still missing, we need to manually add this module as, unfortunately, there is no automation support for this purpose. 411 | 412 | The AppRouter of the previous chapter is also an application, just as our CAP service and the UI. As these two, the AppRouter also needs to be deployed, for this we need to add a configuration to the MTA file that we created before. 413 | 414 | 1. Add the `RiskManagement-approuter` and the `RiskManagement-app` module for the AppRouter to the `mta.yaml` file: 415 | 416 | ```yaml 417 | # -------------------- SIDECAR MODULE ------------------------ 418 | - name: cpapp-db-deployer 419 | # ------------------------------------------------------------ 420 | type: hdb 421 | path: gen/db 422 | parameters: 423 | buildpack: nodejs_buildpack 424 | requires: 425 | # 'hana' and 'xsuaa' resources extracted from CAP configuration 426 | - name: RiskManagement-db 427 | - name: RiskManagement-uaa 428 | //### BEGIN OF INSERT 429 | # -------------------- APPROUTER ----------------------------- 430 | - name: RiskManagement-approuter 431 | # ------------------------------------------------------------ 432 | type: nodejs 433 | path: approuter 434 | requires: 435 | - name: RiskManagement-uaa 436 | - name: srv-api 437 | group: destinations 438 | properties: 439 | forwardAuthToken: true 440 | strictSSL: true 441 | name: srv-binding 442 | url: '~{srv-url}' 443 | build-parameters: 444 | requires: 445 | - name: RiskManagement-app 446 | artifacts: 447 | - ./* 448 | target-path: resources 449 | # -------------------- UI ----------------------------------- 450 | - name: RiskManagement-app 451 | # ------------------------------------------------------------ 452 | type: html5 453 | path: app 454 | build-parameters: 455 | supported-platforms: [] 456 | //### END OF INSERT 457 | ``` 458 | 459 | 2. Save the file 460 | 461 | The AppRouter takes the UI resources of the `RiskManagement-app` and puts it in the `resources` directory. This is where the `xs-app.json` looks for the files requested for `/app/...`. 462 | 463 | The `RiskManagement-uaa` binding adds our already existing XSUAA service instance to the AppRouter, which makes login and logout possible. Hereby the AppRouter forwards requests with the authentication token (`Authorization: Bearer `) to the CAP service. The CAP service then uses it for authentication and authorization checks. 464 | 465 | The `srv-binding` creates an environment variable `destinations` that contains a JSON array with one object containing the **destination** to the CAP service. This is required to forward requests to the CAP service. 466 | 467 | The generated environment variable looks like this: 468 | ```sh 469 | destinations='[{ "name": "srv-biding", "forwardAuthToken": true, "strictSSL": true, url: "https://..." }] 470 | ``` 471 | 472 | The URL is taken from the `RiskManagement-srv` module that needs to be enhanced to export this information. 473 | 474 | ## Exercise 2.7 Remove Access for S/4 System 475 | 476 | The previous steps have shown how to integrate a S/4 service into your application, how to run it locally with sample data and what you have to do to get the application including its access to the S/4 system deployed. However, for these exercises we don't have a real S/4 system at hand as mentioned in the [overview](../../../..#overview) of this tutorial! If you want to carry out the steps of this tutorial in your own SAP BTP account and connect it to your own S/4 HANA Cloud system, you can skip the changes of this chapater and instead follow an additional tutorial that shows how to set up the connection between your SAP BTP account and your S/4 HANA Cloud system using the Cloud Extension Factory. It will eventually create a so-called destination on your SAP BTP account which you need to add to the `API_BUSINESS_PARTNER` section of the `package.json` file. We will not cover this in this tutorial though, you might want to watch this [series of videos](https://www.youtube.com/watch?v=YI4IZbzoXO8&list=PLkzo92owKnVxiagp35AcwoxOlX0J4hLyY&index=1) to learn about the set up. 477 | 478 | If we deployed the application as it is now, the code would of course try to access a system which does not exist. Therefore, we remove the code that is necessary in a real scenario and we hope it helps you there, however in this tutorial we remove/ change some parts of the code to prevent the S/4 call. We will instead create another local service with sample data for the business partner as we have done before for risks and mitigations. 479 | 480 | 1. In your project enter the `package.json` file and remove the following part which was generated by CAP when you imported the API definiton from API Hub. 481 | 482 | ```JSON 483 | "cds": { 484 | "requires": { 485 | "db": { 486 | "kind": "sql" 487 | }, 488 | "uaa": { 489 | "kind": "xsuaa", 490 | "credentials": {} 491 | //### BEGIN OF DELETE 492 | }, 493 | "API_BUSINESS_PARTNER": { 494 | "kind": "odata", 495 | "model": "srv/external/API_BUSINESS_PARTNER" 496 | //### END OF DELETE 497 | } 498 | ``` 499 | 2. Save the file 500 | 3. In your `db` folder, open the `schema.cds` file again. Here the reference to the external service was created before. We leave this reference here, but change the name of the entity to `BusinessPartnersS4`. At the same time we add a new entity with the original name `BusinessPartners`, this is the one that is used by our service. So, you are replacing the original entity that pointed to S/4 with a local copy. 501 | 502 | ```JS 503 | namespace sap.ui.riskmanagement; 504 | using { managed } from '@sap/cds/common'; 505 | 506 | entity Risks : managed { 507 | key ID : UUID @(Core.Computed : true); 508 | title : String(100); 509 | owner : String; 510 | prio : String(5); 511 | descr : String; 512 | miti : Association to Mitigations; 513 | impact : Integer; 514 | bp : Association to BusinessPartners; 515 | criticality : Integer; 516 | } 517 | 518 | entity Mitigations : managed { 519 | key ID : UUID @(Core.Computed : true); 520 | description : String; 521 | owner : String; 522 | timeline : String; 523 | risks : Association to many Risks on risks.miti = $self; 524 | } 525 | 526 | // using an external service from S/4 527 | using { API_BUSINESS_PARTNER as external } from '../srv/external/API_BUSINESS_PARTNER.csn'; 528 | 529 | //### BEGIN OF DELETE 530 | entity BusinessPartners as projection on external.A_BusinessPartner { 531 | //### END OF DELETE 532 | //### BEGIN OF INSERT 533 | entity BusinessPartnersS4 as projection on external.A_BusinessPartner { 534 | //### END OF INSERT 535 | key BusinessPartner, 536 | LastName, 537 | FirstName 538 | } 539 | 540 | //### BEGIN OF INSERT 541 | // using a local service instead of the S/4 one with the same type of entity 542 | entity BusinessPartners { 543 | key BusinessPartner: String(10); 544 | LastName: String(40); 545 | FirstName: String(40); 546 | } 547 | //### END OF INSERT 548 | ``` 549 | 550 | 4. The last part that is missing is the bp data. Copy the `API_BUSINESS_PARTNER-A_BusinessPartner.csv` file in your `srv/external/data` folder and paste it into the `db/data` folder, next to the data files of risks and mitigations. Rename the copied file to `sap.ui.riskmanagement-BusinessPartners.csv`, reflecting the new local entity, so CAP can automatically assign this data to the entity. 551 | 552 | 5. Make sure that the application still runs locally. If `cds watch` isn't running from prior chapters, start it in a new terminal and check the application. 553 | 554 | You have now finished all the preparations to deploy the application to the SAP BTP! 555 | 556 | Continue to - [Exercise 3](../ex3/README.md) where a CI/CD service will deploy the application. 557 | 558 | -------------------------------------------------------------------------------- /exercises/ex3/README.md: -------------------------------------------------------------------------------- 1 | # Exercise 3 - Connect Your Project to SAP Continuous Integration and Delivery 2 | 3 | In this exercise, we will create a project in a public GitHub repository in which to store your source code, enable SAP Continuous Integration and Delivery and configure and run a predefined Continuous Integration and Delivery (CI/CD) pipeline that automatically tests, builds, and deploys your code changes. 4 | 5 | ## Exercise 3.1 Create a GitHub Repository 6 | 7 | After completing these steps, you will have created a public GitHub repository, in which you can store the source code of your project. **Note:** For this execise, you need to have a GitHub user. 8 | 9 | 1. Open and sign in to https://github.com/. 10 | 11 | 2. In the **Repositories** tab, choose **New** to create a new repository. 12 | ![Create Github Repo](./images/GH_newRepository.png) 13 | 14 | 3. As **Repository name**, enter *RiskManagement*. Don't tick any of the **Initialize this repository with** checkboxes. 15 | 16 | 4. Choose **Create repository**. 17 | ![Create Github Repo](./images/GH_createGitRepo.png) 18 | 19 | 5. Copy the HTTPS URL of your newly created GitHub repository. 20 | ![Copy GitHub URL](./images/GH_copyGitHubURL.png) 21 | 22 | 23 | ## Exercise 3.2 Create a Personal Access Token for GitHub 24 | 25 | After completing these steps, you will have created a personal access token to authenticate against GitHub. 26 | 27 | To create a personal access token, which you can use instead of a password, follow the steps described in [Creating a personal access token](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token). 28 | 29 | 30 | ## Exercise 3.3 Connect Your GitHub Repository with Your CAP Project 31 | 32 | After completing these steps, you will have added your CAP project sources to your GitHub repository. 33 | 34 | 1. If you have Business Application Studio still open from the former exercises, return to it. If you haven't, open your [SAP BTP Trial](https://cockpit.hanatrial.ondemand.com/) and choose the Quick Tool Access icon **SAP Business Application Studio**. 35 | 36 | ![Welcome SCP Trial](../ex0/images/00_00_0020.png) 37 | 38 | 2. Open the previously created workspace with your CAP application. 39 | 40 | 3. Open a new terminal and navigate to your project root folder. 41 | ![Open Terminal](./images/openTerminal.png) 42 | 43 | 4. Enter your email address and username. You can use the email address that you've used to register your GitHub account: 44 | ``` 45 | git config --global user.email "you@example.com" 46 | git config --global user.name "Your Name" 47 | ``` 48 | 5. To initialize a GitHub repository and add the project sources to it, execute the following commands: 49 | ``` 50 | git init 51 | git add . 52 | git commit -m "Push project content to GitHub" 53 | git branch -M main 54 | ``` 55 | 56 | 6. Now, add your copied GitHub repository URL from exercise 3.1 as remote repository (without the angle brackets '<' and '>' ): 57 | ``` 58 | git remote add origin 59 | ``` 60 | 61 | 7. Push the commit with your project content to this GitHub repository: 62 | ``` 63 | git push -u origin main 64 | ``` 65 | 66 | 8. When prompted, enter your GitHub username and the personal access token, created in exercise 3.2. 67 | 68 | 69 | ## Exercise 3.4 Enable SAP Continuous Integration and Delivery 70 | 71 | After completing these steps, you will have subscribed to SAP Continuous Integration and Delivery and assigned the *Administrator* role to your user. 72 | 73 | 74 | 1. Enter your [SAP BTP trial account](https://cockpit.hanatrial.ondemand.com/), press **Enter Your Trial Account**, press on the **trial** tile and navigate to the **Subscriptions** tab. Go to **Service Marketplace**. 75 | 76 | 2. Type **Continuous Integration & Delivery** in the search box and choose the service tile: 77 | ![Service Tile](./images/CICD_ServiceTile.png) 78 | 79 | 3. Choose **Create**. 80 | ![Service Tile](./images/CICD_subscribe_service.png) 81 | 82 | 4. In your SAP BTP subaccount, choose **Security** → **Trust Configuration**. 83 | 84 | 5. Choose the name of your identity provider (For example, 'Default identity provider' in this case). 85 | 86 | 6. Enter your email address. 87 | 88 | 7. Choose **Show Assignments**. 89 | (If your user is new to your subaccount, choose **Add User** in the confirmation dialog.) 90 | 91 | 8. Choose **Assign Role Collection**. 92 | 93 | 9. From the drop-down list, choose **CICD Service Administrator**. 94 | 95 | 96 | ## Exercise 3.5 Configure Credentials in SAP Continuous Integration and Delivery 97 | 98 | After completing these steps, you will have configured credentials for connecting SAP Continuous Integration and Delivery to other services. 99 | 100 | 1. In your SAP BTP subaccount navigate to **Services** and then to **Instances and Subscriptions**. 101 | 102 | 2. Choose the **Go to Application** icon located next to the **Continuous Integration & Delivery** subscription. 103 | 104 | ![CICD](./images/CICD_access.png) 105 | 106 | 3. Use your credentials to log in to the application. 107 | 108 | 4. If your GitHub repository is private, configure credentials for it, so that the Continuous Integration & Delivery service can connect to it. (**Note:** If your GitHub repository isn't private, you can skip this step.) 109 | 110 | - In the **Credentials** tab in SAP Continuous Integration and Delivery, choose **+** *(Create Credentials)*. 111 | ![Credentials](./images/CICD_credentials.png) 112 | - For **Name**, enter a freely chosen name for your credential, which is unique in your SAP BTP subaccount. In this example, the name of the credential is *github*. 113 | 114 | - As **Type**, select **Basic Authentication**. 115 | 116 | - For **Username**, enter your Github username. 117 | 118 | - For **Password**, use the personal access token, which you've created in GitHub in exercise 3.3. 119 | ![Credentials GitHub](./images/CICD_credentials_github.png) 120 | 121 | 5. To create credentials for deploying to the SAP Cloud Foundry environment, go to the **Credentials** tab and choose **+** *(Create Credentials)*. 122 | ![Credentials](./images/CICD_credentials.png) 123 | 124 | 6. For **Name**, enter a freely chosen name for your credentials, which is unique in your SAP BTP subaccount. In this example, the name of the credentials is *cfdeploy*. 125 | 126 | 7. As **Type**, select **Basic Authentication**. 127 | 128 | 8. For **Username**, enter your username for the SAP BTP cockpit. 129 | 130 | 9. For **Password**, use your password for the SAP BTP cockpit. 131 | ![Credentials GitHub](./images/CICD_credentials_cfdeploy.png) 132 | 133 | 134 | ## Exercise 3.6 Configure a CI/CD Job 135 | 136 | After completing these steps, you will have configured a job in SAP Continuous Integration and Delivery. 137 | 138 | 1. In the **Jobs** tab in SAP Continuous Integration and Delivery, choose **+** *(Create Job)*. 139 | ![Jobs](./images/CICD_jobs.png) 140 | 141 | 2. For **Job Name**, enter a freely chosen name for your job, which is unique in your SAP BTP subaccount. In this example, the name of the job is *RiskManagment*. 142 | 143 | 3. For **Repository**, choose **Repository** and enter a name and the URL of your GitHub repository. 144 | 145 | 4. For **Branch**, enter the GitHub branch from which you want to receive push events. In this example, the name of the branch is *main*. 146 | 147 | 5. As **Pipeline**, choose **SAP Cloud Application Programming Model**. 148 | 149 | 6. Choose **Create**. 150 | 151 | ![CAP Job](./images/CICD_CAP_job.png) 152 | 153 | If the **Webhook Creation** pop-up, which provides you with the data needed to define a webhook in GitHub, doesn't appear automatically, you can open the detailed view of an existing job in the **Jobs** tab and under **General Information**, choose **Risk Management**. 154 | ![Webhook](./images/CICD_webhook1.png) 155 | 156 | Then choose **Webhook Data**. 157 | 158 | ![Webhook](./images/CICD_webhook2.png) 159 | 160 | The following pop-up window appears: 161 | 162 | ![Webhook](./images/CICD_webhook3.png) 163 | 164 | 165 | 7. Leave it open and, in your project in GitHub, go to the **Settings** tab. 166 | 167 | 8. From the navigation pane, choose **Webhooks**. 168 | 169 | 9. Choose **Add webhook**. 170 | ![Webhook](./images/GH_webhook.png) 171 | 172 | 10. Enter the **Payload URL**, **Content type**, and **Secret** from the **Webhook Creation** pop-up in SAP Continuous Integration and Delivery. For all other settings, leave the default values. 173 | 174 | 11. Choose **Add webhook**. 175 | ![Webhook Details](./images/GH_webhook_details.png) 176 | 177 | 178 | ## Exercise 3.7 Configure the Stages of Your CI/CD Pipeline 179 | 180 | After completing these steps, you will have configured the stages of your pipeline in SAP Continuous Integration and Delivery. 181 | 182 | 1. In the GitHub repository of your project (or in your still open Business Application Studio), create a folder named `.pipeline`, which contains a file named `config.yml`. In the `config.yml` file, add the following initial configuration: 183 | 184 | ```PipelineConfiguration 185 | # Project configuration 186 | general: 187 | projectName: 'RiskManagement' 188 | productiveBranch: 'main' 189 | 190 | # Stage configuration 191 | stages: 192 | productionDeployment: 193 | cfTargets: 194 | - org: '' 195 | space: '' 196 | appName: '' 197 | apiEndpoint: '' 198 | credentialsId: '' 199 | ``` 200 | 201 | 2. Replace the placeholders with the values of the space in the Cloud Foundry environment to which you want to deploy. 202 | `` is `RiskManagement` and `credentialId` is the name of the credentials you have created before for Cloud Platform access, in the example we used `cfdeploy`. 203 | You can get the values for ``, ``, and `` from your subaccount overview in the SAP BTP cockpit: 204 | ![Cockpit](./images/CP_API_Endpoint.png) 205 | 206 | 207 | 208 | 3. Commit your changes to GitHub. If you have added the new folder and file in the Businss Application Studio, you can do so by opening a new terminal from the new `.pipeline` folder and then by typing 209 | 210 | ``` 211 | cd .pipeline 212 | git add -A 213 | git commit -m "new pipeline" 214 | git push 215 | ``` 216 | 217 | ## Exercise 3.8 Verify the Success of Your Build 218 | 219 | After completing these steps, you will have monitored the outcome of your job in SAP Continuous Integration and Delivery. 220 | 221 | 1. In the **Jobs** tab in SAP Continuous Integration and Delivery, select your job and verify that a new tile appears in the **Builds** view. This tile should be marked as running. 222 | ![Job](./images/CICD_running_job.png) 223 | **Note:** If no new tile appears, trigger the job manually by choosing the *Trigger Build* button. 224 | ![Trigger Job](./images/CICD_trigger_job.png) 225 | 226 | 2. Wait until the job has finished and verify that the build tile is marked as successful. 227 | ![Successful Build](./images/CICD_successful_build.png) 228 | 229 | 230 | ## Exercise 3.9 Assign Role Collections and Access the Deployed Application 231 | 232 | After completing these steps, you will have accessed your deployed application trough the SAP BTP cockpit. 233 | 234 | As we set it up this way, the deployed service can only be accessed when your user has a corresponing role collection assiged. If you tried to open the application without this authorization you would get a **Forbidden** pop-up. So, you need to assign the role collection to your user: 235 | 236 | 1. In your trial account in the SAP BTP cockpit, navigate to the **Security** tab and choose **Trust Configuration**. Choose the **Default Entity Provider** link. 237 | 238 | ![CP Trust](./images/RiskManagement-Trust.png) 239 | 240 | 2. Enter the email address for your SAP BTP account (the one you used to log on) and press the **Show Assignments** button. Then press the **Assign Role Collection** button and choose **RiskManager-dev** in the dropdown box. Press the **Assign Role Collection** button 241 | ![CP RoleCollection](./images/RiskManagement-RoleCollection.png) 242 | 243 | Now you are ready to access the application! 244 | 245 | 3. In the left pane of your trial accoun, navigate to the **Cloud Foundry** tab and choose **Spaces**. 246 | ![CP Spaces](./images/CP_cloudfoundry.png) 247 | 248 | 4. Select your space. 249 | 250 | 5. Verify that the *RiskManagment* application has been deployed and that the `Riskmanagement-approuter` is running (might have a `blue` or something similar in the name as well like in the picture). 251 | ![RiskManagment App](./images/RiskManagment_running.png) 252 | 253 | 6. Choose the `Riskmanagement-approuter`. 254 | 255 | 7. Choose the link under **Application Routes**. 256 | ![RiskManagment App](./images/RiskManagment_cpapp_running.png) 257 | 258 | 8. Verify that the deployed application is running and showing its home screen. 259 | ![RiskManagment Home](./images/RiskMngmt_home.png) 260 | 261 | 9. Press the **Risks** tile and then in the application the **Go** button and you should see the final deployed application with the data: 262 | 263 | ![RiskManagment Final](./images/RiskManagment_final.png) 264 | 265 | ## Summary 266 | 267 | You've created a project in GitHub to store your source code and successfully configured and run a predefined continuous integration and delivery pipeline that automatically builds, tests and deploys your code changes. 268 | 269 | -------------------------------------------------------------------------------- /exercises/ex3/images/CICD_CAP_job.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/teched2020-DEV166/66223ca859bbd84346d4ab6ce5086209bdd65215/exercises/ex3/images/CICD_CAP_job.png -------------------------------------------------------------------------------- /exercises/ex3/images/CICD_ServiceTile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/teched2020-DEV166/66223ca859bbd84346d4ab6ce5086209bdd65215/exercises/ex3/images/CICD_ServiceTile.png -------------------------------------------------------------------------------- /exercises/ex3/images/CICD_access.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/teched2020-DEV166/66223ca859bbd84346d4ab6ce5086209bdd65215/exercises/ex3/images/CICD_access.png -------------------------------------------------------------------------------- /exercises/ex3/images/CICD_credentials.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/teched2020-DEV166/66223ca859bbd84346d4ab6ce5086209bdd65215/exercises/ex3/images/CICD_credentials.png -------------------------------------------------------------------------------- /exercises/ex3/images/CICD_credentials_cfdeploy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/teched2020-DEV166/66223ca859bbd84346d4ab6ce5086209bdd65215/exercises/ex3/images/CICD_credentials_cfdeploy.png -------------------------------------------------------------------------------- /exercises/ex3/images/CICD_credentials_github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/teched2020-DEV166/66223ca859bbd84346d4ab6ce5086209bdd65215/exercises/ex3/images/CICD_credentials_github.png -------------------------------------------------------------------------------- /exercises/ex3/images/CICD_jobs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/teched2020-DEV166/66223ca859bbd84346d4ab6ce5086209bdd65215/exercises/ex3/images/CICD_jobs.png -------------------------------------------------------------------------------- /exercises/ex3/images/CICD_running_job.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/teched2020-DEV166/66223ca859bbd84346d4ab6ce5086209bdd65215/exercises/ex3/images/CICD_running_job.png -------------------------------------------------------------------------------- /exercises/ex3/images/CICD_subscribe_service.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/teched2020-DEV166/66223ca859bbd84346d4ab6ce5086209bdd65215/exercises/ex3/images/CICD_subscribe_service.png -------------------------------------------------------------------------------- /exercises/ex3/images/CICD_successful_build.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/teched2020-DEV166/66223ca859bbd84346d4ab6ce5086209bdd65215/exercises/ex3/images/CICD_successful_build.png -------------------------------------------------------------------------------- /exercises/ex3/images/CICD_trigger_job.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/teched2020-DEV166/66223ca859bbd84346d4ab6ce5086209bdd65215/exercises/ex3/images/CICD_trigger_job.png -------------------------------------------------------------------------------- /exercises/ex3/images/CICD_webhook.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/teched2020-DEV166/66223ca859bbd84346d4ab6ce5086209bdd65215/exercises/ex3/images/CICD_webhook.png -------------------------------------------------------------------------------- /exercises/ex3/images/CICD_webhook1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/teched2020-DEV166/66223ca859bbd84346d4ab6ce5086209bdd65215/exercises/ex3/images/CICD_webhook1.png -------------------------------------------------------------------------------- /exercises/ex3/images/CICD_webhook2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/teched2020-DEV166/66223ca859bbd84346d4ab6ce5086209bdd65215/exercises/ex3/images/CICD_webhook2.png -------------------------------------------------------------------------------- /exercises/ex3/images/CICD_webhook3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/teched2020-DEV166/66223ca859bbd84346d4ab6ce5086209bdd65215/exercises/ex3/images/CICD_webhook3.png -------------------------------------------------------------------------------- /exercises/ex3/images/CP_API_Endpoint.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/teched2020-DEV166/66223ca859bbd84346d4ab6ce5086209bdd65215/exercises/ex3/images/CP_API_Endpoint.png -------------------------------------------------------------------------------- /exercises/ex3/images/CP_cloudfoundry.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/teched2020-DEV166/66223ca859bbd84346d4ab6ce5086209bdd65215/exercises/ex3/images/CP_cloudfoundry.png -------------------------------------------------------------------------------- /exercises/ex3/images/GH_copyGitHubURL.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/teched2020-DEV166/66223ca859bbd84346d4ab6ce5086209bdd65215/exercises/ex3/images/GH_copyGitHubURL.png -------------------------------------------------------------------------------- /exercises/ex3/images/GH_createGitRepo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/teched2020-DEV166/66223ca859bbd84346d4ab6ce5086209bdd65215/exercises/ex3/images/GH_createGitRepo.png -------------------------------------------------------------------------------- /exercises/ex3/images/GH_newRepository.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/teched2020-DEV166/66223ca859bbd84346d4ab6ce5086209bdd65215/exercises/ex3/images/GH_newRepository.png -------------------------------------------------------------------------------- /exercises/ex3/images/GH_webhook.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/teched2020-DEV166/66223ca859bbd84346d4ab6ce5086209bdd65215/exercises/ex3/images/GH_webhook.png -------------------------------------------------------------------------------- /exercises/ex3/images/GH_webhook_details.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/teched2020-DEV166/66223ca859bbd84346d4ab6ce5086209bdd65215/exercises/ex3/images/GH_webhook_details.png -------------------------------------------------------------------------------- /exercises/ex3/images/RiskManagement-RoleCollection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/teched2020-DEV166/66223ca859bbd84346d4ab6ce5086209bdd65215/exercises/ex3/images/RiskManagement-RoleCollection.png -------------------------------------------------------------------------------- /exercises/ex3/images/RiskManagement-Trust.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/teched2020-DEV166/66223ca859bbd84346d4ab6ce5086209bdd65215/exercises/ex3/images/RiskManagement-Trust.png -------------------------------------------------------------------------------- /exercises/ex3/images/RiskManagment_cpapp_running.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/teched2020-DEV166/66223ca859bbd84346d4ab6ce5086209bdd65215/exercises/ex3/images/RiskManagment_cpapp_running.png -------------------------------------------------------------------------------- /exercises/ex3/images/RiskManagment_final.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/teched2020-DEV166/66223ca859bbd84346d4ab6ce5086209bdd65215/exercises/ex3/images/RiskManagment_final.png -------------------------------------------------------------------------------- /exercises/ex3/images/RiskManagment_running.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/teched2020-DEV166/66223ca859bbd84346d4ab6ce5086209bdd65215/exercises/ex3/images/RiskManagment_running.png -------------------------------------------------------------------------------- /exercises/ex3/images/RiskMngmt_home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/teched2020-DEV166/66223ca859bbd84346d4ab6ce5086209bdd65215/exercises/ex3/images/RiskMngmt_home.png -------------------------------------------------------------------------------- /exercises/ex3/images/openBizAppStudio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/teched2020-DEV166/66223ca859bbd84346d4ab6ce5086209bdd65215/exercises/ex3/images/openBizAppStudio.png -------------------------------------------------------------------------------- /exercises/ex3/images/openTerminal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-archive/teched2020-DEV166/66223ca859bbd84346d4ab6ce5086209bdd65215/exercises/ex3/images/openTerminal.png -------------------------------------------------------------------------------- /mta.yaml: -------------------------------------------------------------------------------- 1 | ## Generated mta.yaml based on template version 0.4.0 2 | ## appName = RiskManagement 3 | ## language=nodejs; multiTenant=false 4 | ## approuter= 5 | _schema-version: '3.1' 6 | ID: RiskManagement 7 | version: 1.0.0 8 | description: "A simple CAP project." 9 | parameters: 10 | enable-parallel-deployments: true 11 | 12 | build-parameters: 13 | before-all: 14 | - builder: custom 15 | commands: 16 | - npm install --production 17 | - npx -p @sap/cds-dk cds build --production 18 | 19 | modules: 20 | # --------------------- SERVER MODULE ------------------------ 21 | - name: RiskManagement-srv 22 | # ------------------------------------------------------------ 23 | type: nodejs 24 | path: gen/srv 25 | requires: 26 | # Resources extracted from CAP configuration 27 | - name: RiskManagement-db 28 | - name: RiskManagement-uaa 29 | provides: 30 | - name: srv-api # required by consumers of CAP services (e.g. approuter) 31 | properties: 32 | srv-url: ${default-url} 33 | 34 | # -------------------- SIDECAR MODULE ------------------------ 35 | - name: RiskManagement-db-deployer 36 | # ------------------------------------------------------------ 37 | type: hdb 38 | path: gen/db 39 | parameters: 40 | buildpack: nodejs_buildpack 41 | requires: 42 | # 'hana' and 'xsuaa' resources extracted from CAP configuration 43 | - name: RiskManagement-db 44 | - name: RiskManagement-uaa 45 | # -------------------- APPROUTER ----------------------------- 46 | - name: RiskManagement-approuter 47 | # ------------------------------------------------------------ 48 | type: nodejs 49 | path: approuter 50 | requires: 51 | - name: RiskManagement-uaa 52 | - name: srv-api 53 | group: destinations 54 | properties: 55 | forwardAuthToken: true 56 | strictSSL: true 57 | name: srv-binding 58 | url: '~{srv-url}' 59 | build-parameters: 60 | requires: 61 | - name: RiskManagement-app 62 | artifacts: 63 | - ./* 64 | target-path: resources 65 | # -------------------- UI ----------------------------------- 66 | - name: RiskManagement-app 67 | # ------------------------------------------------------------ 68 | type: html5 69 | path: app 70 | build-parameters: 71 | supported-platforms: [] 72 | 73 | resources: 74 | # services extracted from CAP configuration 75 | # 'service-plan' can be configured via 'cds.requires..vcap.plan' 76 | # ------------------------------------------------------------ 77 | - name: RiskManagement-db 78 | # ------------------------------------------------------------ 79 | type: com.sap.xs.hdi-container 80 | parameters: 81 | service: hanatrial 82 | service-plan: hdi-shared 83 | properties: 84 | hdi-service-name: ${service-name} 85 | 86 | # ------------------------------------------------------------ 87 | - name: RiskManagement-uaa 88 | # ------------------------------------------------------------ 89 | type: org.cloudfoundry.managed-service 90 | parameters: 91 | service: xsuaa 92 | service-plan: application 93 | path: ./xs-security.json 94 | config: 95 | xsappname: 'RiskManagement-${space}' 96 | role-collections: 97 | - name: 'RiskManager-${space}' 98 | description: Manage Risks 99 | role-template-references: 100 | - $XSAPPNAME.RiskManager 101 | - name: 'RiskViewer-${space}' 102 | description: View Risks 103 | role-template-references: 104 | - $XSAPPNAME.RiskViewer 105 | ## path to xs-security.json to add roles and scopes 106 | # path: ./xs-security.json 107 | ## or inline definition 108 | # scopes: 109 | # - name: $XSAPPNAME... 110 | 111 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "RiskManagement", 3 | "version": "1.0.0", 4 | "description": "A simple CAP project.", 5 | "repository": "", 6 | "license": "UNLICENSED", 7 | "private": true, 8 | "dependencies": { 9 | "@sap/cds": "^4", 10 | "@sap/xsenv": "^3.1.0", 11 | "@sap/xssec": "^3.0.10", 12 | "express": "^4", 13 | "hdb": "^0.18.2", 14 | "passport": "^0.4.1" 15 | }, 16 | "devDependencies": { 17 | "@sap/ux-specification": "^1.78.13", 18 | "sqlite3": "^5" 19 | }, 20 | "scripts": { 21 | "start": "npx cds run" 22 | }, 23 | "cds": { 24 | "requires": { 25 | "db": { 26 | "kind": "sql" 27 | }, 28 | "uaa": { 29 | "kind": "xsuaa", 30 | "credentials": {} 31 | } 32 | }, 33 | "hana": { 34 | "deploy-format": "hdbtable" 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /srv/external/data/API_BUSINESS_PARTNER-A_BusinessPartner.csv: -------------------------------------------------------------------------------- 1 | BusinessPartner;LastName;FirstName 2 | 1004155;Watson;Alice 3 | 1004161;Lynotte;Phil 4 | 1004100;Masci;J -------------------------------------------------------------------------------- /srv/risk-service.cds: -------------------------------------------------------------------------------- 1 | using { sap.ui.riskmanagement as my } from '../db/schema'; 2 | 3 | @path: 'service/risk' 4 | service RiskService { 5 | entity Risks @(restrict : [ 6 | { 7 | grant : [ 'READ' ], 8 | to : [ 'RiskViewer' ] 9 | }, 10 | { 11 | grant : [ '*' ], 12 | to : [ 'RiskManager' ] 13 | } 14 | ]) as projection on my.Risks; 15 | annotate Risks with @odata.draft.enabled; 16 | entity Mitigations @(restrict : [ 17 | { 18 | grant : [ 'READ' ], 19 | to : [ 'RiskViewer' ] 20 | }, 21 | { 22 | grant : [ '*' ], 23 | to : [ 'RiskManager' ] 24 | } 25 | ]) as projection on my.Mitigations; 26 | annotate Mitigations with @odata.draft.enabled; 27 | entity BusinessPartners as projection on my.BusinessPartners; 28 | } -------------------------------------------------------------------------------- /srv/risk-service.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Implementation for Risk Management service defined in ./risk-service.cds 3 | */ 4 | module.exports = async (srv) => { 5 | srv.after('READ', 'Risks', (risks) => { 6 | 7 | risks.forEach((risk) => { 8 | if (risk.impact >= 100000) { 9 | risk.criticality = 1; 10 | } else { 11 | risk.criticality = 2; 12 | } 13 | }); 14 | }); 15 | 16 | const BupaService = await cds.connect.to('API_BUSINESS_PARTNER'); 17 | srv.on('READ', srv.entities.BusinessPartners, async (req) => { 18 | return await BupaService.tx(req).run(req.query); 19 | }); 20 | 21 | srv.on('READ', 'Risks', async (req, next) => { 22 | /* 23 | Check whether the request want an "expand" of the business partner 24 | As this is not possible, the risk entity and the business partner entity are in different systems (Cloud Platform and S/4 HANA Cloud), 25 | if there is such an expand, remove it 26 | */ 27 | const expandIndex = req.query.SELECT.columns.findIndex(({ expand, ref }) => expand && ref[0] === 'bp'); 28 | console.log(req.query.SELECT.columns) 29 | if (expandIndex < 0) return next(); 30 | 31 | req.query.SELECT.columns.splice(expandIndex, 1); 32 | if (!req.query.SELECT.columns.find( column => column.ref.find( ref => ref == "bp_BusinessPartner" ))) { 33 | req.query.SELECT.columns.push({ ref: ["bp_BusinessPartner"] }); 34 | } 35 | 36 | /* 37 | Instead of carrying out the expand, issue a separate request for each business partner 38 | This code could be optimized, instead of having n requests for n business partners, just on bulk request could be created 39 | */ 40 | const res = await next(); 41 | await Promise.all( 42 | res.map( async risk => { 43 | const bp = await BupaService 44 | .tx(req) 45 | .run(SELECT.one(srv.entities.BusinessPartners).where({ BusinessPartner: risk.bp_BusinessPartner }) 46 | .columns([ "BusinessPartner", "LastName", "FirstName" ])); 47 | risk.bp = bp; 48 | console.dir(risk.bp) 49 | } 50 | )); 51 | return res; 52 | }); 53 | } -------------------------------------------------------------------------------- /srv/risks-service-ui.cds: -------------------------------------------------------------------------------- 1 | using RiskService from './risk-service'; 2 | 3 | annotate RiskService.Risks with { 4 | title @title: 'Title'; 5 | owner @title: 'Owner'; 6 | prio @title: 'Priority'; 7 | descr @title: 'Description'; 8 | miti @title: 'Mitigation'; 9 | bp @title: 'Business Partner'; 10 | impact @title: 'Impact'; 11 | } 12 | 13 | annotate RiskService.Mitigations with { 14 | ID @( 15 | UI.Hidden, 16 | Common: { 17 | Text: description 18 | } 19 | ); 20 | description @title: 'Description'; 21 | owner @title: 'Owner'; 22 | timeline @title: 'Timeline'; 23 | risks @title: 'Risks'; 24 | } 25 | 26 | annotate RiskService.Risks with @( 27 | UI: { 28 | HeaderInfo: { 29 | TypeName: 'Risk', 30 | TypeNamePlural: 'Risks' 31 | }, 32 | SelectionFields: [prio], 33 | LineItem: [ 34 | {Value: title}, 35 | {Value: miti_ID}, 36 | {Value: owner}, 37 | {Value: bp_BusinessPartner}, 38 | { 39 | Value: prio, 40 | Criticality: criticality 41 | } 42 | , 43 | { 44 | Value: impact, 45 | Criticality: criticality 46 | } 47 | ], 48 | Facets: [ 49 | {$Type: 'UI.ReferenceFacet', Label: 'Main', Target: '@UI.FieldGroup#Main'} 50 | ], 51 | FieldGroup#Main: { 52 | Data: [ 53 | {Value: title}, 54 | {Value: miti_ID}, 55 | {Value: descr}, 56 | {Value: owner}, 57 | { 58 | Value: prio, 59 | Criticality: criticality 60 | }, 61 | {Value: bp_BusinessPartner}, 62 | { 63 | Value: impact, 64 | Criticality: criticality 65 | } 66 | ] 67 | } 68 | }, 69 | ) { 70 | 71 | }; 72 | 73 | annotate RiskService.Risks with { 74 | miti @( 75 | Common: { 76 | //show text, not id for mitigation in the context of risks 77 | Text: miti.description , TextArrangement: #TextOnly, 78 | ValueList: { 79 | Label: 'Mitigations', 80 | CollectionPath: 'Mitigations', 81 | Parameters: [ 82 | { $Type: 'Common.ValueListParameterInOut', 83 | LocalDataProperty: miti_ID, 84 | ValueListProperty: 'ID' 85 | }, 86 | { $Type: 'Common.ValueListParameterDisplayOnly', 87 | ValueListProperty: 'description' 88 | } 89 | ] 90 | } 91 | } 92 | ); 93 | bp @( 94 | Common: { 95 | Text: bp.LastName , TextArrangement: #TextOnly, 96 | ValueList: { 97 | Label: 'Business Partners', 98 | CollectionPath: 'BusinessPartners', 99 | Parameters: [ 100 | { $Type: 'Common.ValueListParameterInOut', 101 | LocalDataProperty: bp_BusinessPartner, 102 | ValueListProperty: 'BusinessPartner' 103 | }, 104 | { $Type: 'Common.ValueListParameterDisplayOnly', 105 | ValueListProperty: 'LastName' 106 | }, 107 | { $Type: 'Common.ValueListParameterDisplayOnly', 108 | ValueListProperty: 'FirstName' 109 | } 110 | ] 111 | } 112 | } 113 | ) 114 | } 115 | 116 | 117 | annotate RiskService.BusinessPartners with { 118 | BusinessPartner @( 119 | UI.Hidden, 120 | Common: { 121 | Text: LastName 122 | } 123 | ); 124 | LastName @title: 'Last Name'; 125 | FirstName @title: 'First Name'; 126 | } -------------------------------------------------------------------------------- /xs-security.json: -------------------------------------------------------------------------------- 1 | { 2 | "xsappname": "RiskManagement", 3 | "tenant-mode": "dedicated", 4 | "scopes": [ 5 | { 6 | "name": "$XSAPPNAME.RiskViewer", 7 | "description": "RiskViewer" 8 | }, 9 | { 10 | "name": "$XSAPPNAME.RiskManager", 11 | "description": "RiskManager" 12 | } 13 | ], 14 | "attributes": [], 15 | "role-templates": [ 16 | { 17 | "name": "RiskViewer", 18 | "description": "generated", 19 | "scope-references": [ 20 | "$XSAPPNAME.RiskViewer" 21 | ], 22 | "attribute-references": [] 23 | }, 24 | { 25 | "name": "RiskManager", 26 | "description": "generated", 27 | "scope-references": [ 28 | "$XSAPPNAME.RiskManager" 29 | ], 30 | "attribute-references": [] 31 | } 32 | ] 33 | } 34 | --------------------------------------------------------------------------------