├── .devcontainer ├── .env ├── Dockerfile ├── README.md ├── devcontainer.json └── docker-compose.yml ├── .github ├── CODE_OF_CONDUCT.md ├── ISSUE_TEMPLATE.md └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE.md ├── README.md ├── app.js ├── azure.yaml ├── bin └── www ├── infra ├── README.md ├── main.bicep ├── main.parameters.json └── resources.bicep ├── models └── task.js ├── package-lock.json ├── package.json ├── public ├── images │ └── Azure-A-48px-product.svg └── stylesheets │ └── style.css ├── routes ├── index.js └── users.js └── views ├── error.pug ├── index.pug └── layout.pug /.devcontainer/.env: -------------------------------------------------------------------------------- 1 | ENV_DB_DATABASE=app 2 | ENV_DB_USER=root 3 | ENV_DB_PASSWORD=example -------------------------------------------------------------------------------- /.devcontainer/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/devcontainers/javascript-node:20-bookworm 2 | 3 | # Install MongoDB command line tools - though mongo-database-tools not available on arm64 4 | ARG MONGO_TOOLS_VERSION=6.0 5 | RUN . /etc/os-release \ 6 | && curl -sSL "https://www.mongodb.org/static/pgp/server-${MONGO_TOOLS_VERSION}.asc" | gpg --dearmor > /usr/share/keyrings/mongodb-archive-keyring.gpg \ 7 | && echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/mongodb-archive-keyring.gpg] http://repo.mongodb.org/apt/debian ${VERSION_CODENAME}/mongodb-org/${MONGO_TOOLS_VERSION} main" | tee /etc/apt/sources.list.d/mongodb-org-${MONGO_TOOLS_VERSION}.list \ 8 | && apt-get update && export DEBIAN_FRONTEND=noninteractive \ 9 | && apt-get install -y mongodb-mongosh \ 10 | && if [ "$(dpkg --print-architecture)" = "amd64" ]; then apt-get install -y mongodb-database-tools; fi \ 11 | && apt-get clean -y && rm -rf /var/lib/apt/lists/* 12 | 13 | # [Optional] Uncomment this section to install additional OS packages. 14 | # RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ 15 | # && apt-get -y install --no-install-recommends 16 | 17 | # [Optional] Uncomment if you want to install an additional version of node using nvm 18 | # ARG EXTRA_NODE_VERSION=10 19 | # RUN su node -c "source /usr/local/share/nvm/nvm.sh && nvm install ${EXTRA_NODE_VERSION}" 20 | 21 | # [Optional] Uncomment if you want to install more global node modules 22 | # RUN su node -c "npm install -g " 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /.devcontainer/README.md: -------------------------------------------------------------------------------- 1 | # .devcontainer directory 2 | 3 | This `.devcontainer` directory contains the configuration for a [dev container](https://docs.github.com/codespaces/setting-up-your-project-for-codespaces/adding-a-dev-container-configuration/introduction-to-dev-containers) and isn't used by the sample application. 4 | 5 | The dev container configuration lets you open the repository in a [GitHub codespace](https://docs.github.com/codespaces/overview) or a dev container in Visual Studio Code. For your convenience, the dev container is configured with the following: 6 | 7 | - Node.js 8 | - MongoDB 9 | - [Azure Developer CLI](https://learn.microsoft.com/azure/developer/azure-developer-cli/overview) (so you can run `azd` commands directly). -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | // For format details, see https://aka.ms/devcontainer.json. For config options, see the 2 | // README at: https://github.com/devcontainers/templates/tree/main/src/javascript-node-mongo 3 | { 4 | "name": "Node.js & Mongo DB", 5 | "dockerComposeFile": "docker-compose.yml", 6 | "service": "app", 7 | "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}", 8 | 9 | // Features to add to the dev container. More info: https://containers.dev/features. 10 | "features": { 11 | "ghcr.io/devcontainers/features/azure-cli:1": {}, 12 | "ghcr.io/azure/azure-dev/azd:0": {} 13 | }, 14 | 15 | // Configure tool-specific properties. 16 | "customizations": { 17 | // Configure properties specific to VS Code. 18 | "vscode": { 19 | // Add the IDs of extensions you want installed when the container is created. 20 | "extensions": [ 21 | "github.copilot" 22 | ] 23 | } 24 | } 25 | 26 | // Use 'forwardPorts' to make a list of ports inside the container available locally. 27 | // "forwardPorts": [3000, 27017], 28 | 29 | // Use 'postCreateCommand' to run commands after the container is created. 30 | // "postCreateCommand": "yarn install", 31 | 32 | // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. 33 | // "remoteUser": "root" 34 | } 35 | -------------------------------------------------------------------------------- /.devcontainer/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.8' 2 | 3 | services: 4 | app: 5 | build: 6 | context: . 7 | dockerfile: Dockerfile 8 | volumes: 9 | - ../..:/workspaces:cached 10 | 11 | environment: 12 | MONGODB_URI: mongodb://${ENV_DB_USER}:${ENV_DB_PASSWORD}@db:27017/${ENV_DB_DATABASE}?authSource=admin 13 | 14 | # Overrides default command so things don't shut down after the process ends. 15 | command: sleep infinity 16 | 17 | # Runs app on the same network as the database container, allows "forwardPorts" in devcontainer.json function. 18 | network_mode: service:db 19 | 20 | # Use "forwardPorts" in **devcontainer.json** to forward an app port locally. 21 | # (Adding the "ports" property to this file will not forward from a Codespace.) 22 | 23 | db: 24 | image: mongo:latest 25 | restart: unless-stopped 26 | volumes: 27 | - mongodb-data:/data/db 28 | 29 | environment: 30 | MONGO_INITDB_ROOT_USERNAME: ${ENV_DB_USER} 31 | MONGO_INITDB_ROOT_PASSWORD: ${ENV_DB_PASSWORD} 32 | 33 | # Add "forwardPorts": ["27017"] to **devcontainer.json** to forward MongoDB locally. 34 | # (Adding the "ports" property to this file will not forward from a Codespace.) 35 | 36 | redis: 37 | image: redis 38 | restart: unless-stopped 39 | 40 | volumes: 41 | mongodb-data: -------------------------------------------------------------------------------- /.github/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Microsoft Open Source Code of Conduct 2 | 3 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 4 | 5 | Resources: 6 | 7 | - [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/) 8 | - [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) 9 | - Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns 10 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 4 | > Please provide us with the following information: 5 | > --------------------------------------------------------------- 6 | 7 | ### This issue is for a: (mark with an `x`) 8 | ``` 9 | - [ ] bug report -> please search issues before submitting 10 | - [ ] feature request 11 | - [ ] documentation issue or request 12 | - [ ] regression (a behavior that used to work and stopped in a new release) 13 | ``` 14 | 15 | ### Minimal steps to reproduce 16 | > 17 | 18 | ### Any log messages given by the failure 19 | > 20 | 21 | ### Expected/desired behavior 22 | > 23 | 24 | ### OS and Version? 25 | > Windows 7, 8 or 10. Linux (which distribution). macOS (Yosemite? El Capitan? Sierra?) 26 | 27 | ### Versions 28 | > 29 | 30 | ### Mention any other details that might be useful 31 | 32 | > --------------------------------------------------------------- 33 | > Thanks! We'll be in touch soon. 34 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Purpose 2 | 3 | * ... 4 | 5 | ## Does this introduce a breaking change? 6 | 7 | ``` 8 | [ ] Yes 9 | [ ] No 10 | ``` 11 | 12 | ## Pull Request Type 13 | What kind of change does this Pull Request introduce? 14 | 15 | 16 | ``` 17 | [ ] Bugfix 18 | [ ] Feature 19 | [ ] Code style update (formatting, local variables) 20 | [ ] Refactoring (no functional changes, no api changes) 21 | [ ] Documentation content changes 22 | [ ] Other... Please describe: 23 | ``` 24 | 25 | ## How to Test 26 | * Get the code 27 | 28 | ``` 29 | git clone [repo-address] 30 | cd [repo-name] 31 | git checkout [branch-name] 32 | npm install 33 | ``` 34 | 35 | * Test the code 36 | 37 | ``` 38 | ``` 39 | 40 | ## What to Check 41 | Verify that the following are valid 42 | * ... 43 | 44 | ## Other Information 45 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Aa][Rr][Mm]/ 27 | [Aa][Rr][Mm]64/ 28 | bld/ 29 | [Bb]in/ 30 | [Oo]bj/ 31 | [Ll]og/ 32 | [Ll]ogs/ 33 | 34 | # Visual Studio 2015/2017 cache/options directory 35 | .vs/ 36 | # Uncomment if you have tasks that create the project's static files in wwwroot 37 | #wwwroot/ 38 | 39 | # Visual Studio 2017 auto generated files 40 | Generated\ Files/ 41 | 42 | # MSTest test Results 43 | [Tt]est[Rr]esult*/ 44 | [Bb]uild[Ll]og.* 45 | 46 | # NUnit 47 | *.VisualState.xml 48 | TestResult.xml 49 | nunit-*.xml 50 | 51 | # Build Results of an ATL Project 52 | [Dd]ebugPS/ 53 | [Rr]eleasePS/ 54 | dlldata.c 55 | 56 | # Benchmark Results 57 | BenchmarkDotNet.Artifacts/ 58 | 59 | # .NET Core 60 | project.lock.json 61 | project.fragment.lock.json 62 | artifacts/ 63 | 64 | # StyleCop 65 | StyleCopReport.xml 66 | 67 | # Files built by Visual Studio 68 | *_i.c 69 | *_p.c 70 | *_h.h 71 | *.ilk 72 | *.meta 73 | *.obj 74 | *.iobj 75 | *.pch 76 | *.pdb 77 | *.ipdb 78 | *.pgc 79 | *.pgd 80 | *.rsp 81 | *.sbr 82 | *.tlb 83 | *.tli 84 | *.tlh 85 | *.tmp 86 | *.tmp_proj 87 | *_wpftmp.csproj 88 | *.log 89 | *.vspscc 90 | *.vssscc 91 | .builds 92 | *.pidb 93 | *.svclog 94 | *.scc 95 | 96 | # Chutzpah Test files 97 | _Chutzpah* 98 | 99 | # Visual C++ cache files 100 | ipch/ 101 | *.aps 102 | *.ncb 103 | *.opendb 104 | *.opensdf 105 | *.sdf 106 | *.cachefile 107 | *.VC.db 108 | *.VC.VC.opendb 109 | 110 | # Visual Studio profiler 111 | *.psess 112 | *.vsp 113 | *.vspx 114 | *.sap 115 | 116 | # Visual Studio Trace Files 117 | *.e2e 118 | 119 | # TFS 2012 Local Workspace 120 | $tf/ 121 | 122 | # Guidance Automation Toolkit 123 | *.gpState 124 | 125 | # ReSharper is a .NET coding add-in 126 | _ReSharper*/ 127 | *.[Rr]e[Ss]harper 128 | *.DotSettings.user 129 | 130 | # TeamCity is a build add-in 131 | _TeamCity* 132 | 133 | # DotCover is a Code Coverage Tool 134 | *.dotCover 135 | 136 | # AxoCover is a Code Coverage Tool 137 | .axoCover/* 138 | !.axoCover/settings.json 139 | 140 | # Visual Studio code coverage results 141 | *.coverage 142 | *.coveragexml 143 | 144 | # NCrunch 145 | _NCrunch_* 146 | .*crunch*.local.xml 147 | nCrunchTemp_* 148 | 149 | # MightyMoose 150 | *.mm.* 151 | AutoTest.Net/ 152 | 153 | # Web workbench (sass) 154 | .sass-cache/ 155 | 156 | # Installshield output folder 157 | [Ee]xpress/ 158 | 159 | # DocProject is a documentation generator add-in 160 | DocProject/buildhelp/ 161 | DocProject/Help/*.HxT 162 | DocProject/Help/*.HxC 163 | DocProject/Help/*.hhc 164 | DocProject/Help/*.hhk 165 | DocProject/Help/*.hhp 166 | DocProject/Help/Html2 167 | DocProject/Help/html 168 | 169 | # Click-Once directory 170 | publish/ 171 | 172 | # Publish Web Output 173 | *.[Pp]ublish.xml 174 | *.azurePubxml 175 | # Note: Comment the next line if you want to checkin your web deploy settings, 176 | # but database connection strings (with potential passwords) will be unencrypted 177 | *.pubxml 178 | *.publishproj 179 | 180 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 181 | # checkin your Azure Web App publish settings, but sensitive information contained 182 | # in these scripts will be unencrypted 183 | PublishScripts/ 184 | 185 | # NuGet Packages 186 | *.nupkg 187 | # NuGet Symbol Packages 188 | *.snupkg 189 | # The packages folder can be ignored because of Package Restore 190 | **/[Pp]ackages/* 191 | # except build/, which is used as an MSBuild target. 192 | !**/[Pp]ackages/build/ 193 | # Uncomment if necessary however generally it will be regenerated when needed 194 | #!**/[Pp]ackages/repositories.config 195 | # NuGet v3's project.json files produces more ignorable files 196 | *.nuget.props 197 | *.nuget.targets 198 | 199 | # Microsoft Azure Build Output 200 | csx/ 201 | *.build.csdef 202 | 203 | # Microsoft Azure Emulator 204 | ecf/ 205 | rcf/ 206 | 207 | # Windows Store app package directories and files 208 | AppPackages/ 209 | BundleArtifacts/ 210 | Package.StoreAssociation.xml 211 | _pkginfo.txt 212 | *.appx 213 | *.appxbundle 214 | *.appxupload 215 | 216 | # Visual Studio cache files 217 | # files ending in .cache can be ignored 218 | *.[Cc]ache 219 | # but keep track of directories ending in .cache 220 | !?*.[Cc]ache/ 221 | 222 | # Others 223 | ClientBin/ 224 | ~$* 225 | *~ 226 | *.dbmdl 227 | *.dbproj.schemaview 228 | *.jfm 229 | *.pfx 230 | *.publishsettings 231 | orleans.codegen.cs 232 | 233 | # Including strong name files can present a security risk 234 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 235 | #*.snk 236 | 237 | # Since there are multiple workflows, uncomment next line to ignore bower_components 238 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 239 | #bower_components/ 240 | 241 | # RIA/Silverlight projects 242 | Generated_Code/ 243 | 244 | # Backup & report files from converting an old project file 245 | # to a newer Visual Studio version. Backup files are not needed, 246 | # because we have git ;-) 247 | _UpgradeReport_Files/ 248 | Backup*/ 249 | UpgradeLog*.XML 250 | UpgradeLog*.htm 251 | ServiceFabricBackup/ 252 | *.rptproj.bak 253 | 254 | # SQL Server files 255 | *.mdf 256 | *.ldf 257 | *.ndf 258 | 259 | # Business Intelligence projects 260 | *.rdl.data 261 | *.bim.layout 262 | *.bim_*.settings 263 | *.rptproj.rsuser 264 | *- [Bb]ackup.rdl 265 | *- [Bb]ackup ([0-9]).rdl 266 | *- [Bb]ackup ([0-9][0-9]).rdl 267 | 268 | # Microsoft Fakes 269 | FakesAssemblies/ 270 | 271 | # GhostDoc plugin setting file 272 | *.GhostDoc.xml 273 | 274 | # Node.js Tools for Visual Studio 275 | .ntvs_analysis.dat 276 | node_modules/ 277 | 278 | # Visual Studio 6 build log 279 | *.plg 280 | 281 | # Visual Studio 6 workspace options file 282 | *.opt 283 | 284 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 285 | *.vbw 286 | 287 | # Visual Studio LightSwitch build output 288 | **/*.HTMLClient/GeneratedArtifacts 289 | **/*.DesktopClient/GeneratedArtifacts 290 | **/*.DesktopClient/ModelManifest.xml 291 | **/*.Server/GeneratedArtifacts 292 | **/*.Server/ModelManifest.xml 293 | _Pvt_Extensions 294 | 295 | # Paket dependency manager 296 | .paket/paket.exe 297 | paket-files/ 298 | 299 | # FAKE - F# Make 300 | .fake/ 301 | 302 | # CodeRush personal settings 303 | .cr/personal 304 | 305 | # Python Tools for Visual Studio (PTVS) 306 | __pycache__/ 307 | *.pyc 308 | 309 | # Cake - Uncomment if you are using it 310 | # tools/** 311 | # !tools/packages.config 312 | 313 | # Tabs Studio 314 | *.tss 315 | 316 | # Telerik's JustMock configuration file 317 | *.jmconfig 318 | 319 | # BizTalk build output 320 | *.btp.cs 321 | *.btm.cs 322 | *.odx.cs 323 | *.xsd.cs 324 | 325 | # OpenCover UI analysis results 326 | OpenCover/ 327 | 328 | # Azure Stream Analytics local run output 329 | ASALocalRun/ 330 | 331 | # MSBuild Binary and Structured Log 332 | *.binlog 333 | 334 | # NVidia Nsight GPU debugger configuration file 335 | *.nvuser 336 | 337 | # MFractors (Xamarin productivity tool) working folder 338 | .mfractor/ 339 | 340 | # Local History for Visual Studio 341 | .localhistory/ 342 | 343 | # BeatPulse healthcheck temp database 344 | healthchecksdb 345 | 346 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 347 | MigrationBackup/ 348 | 349 | # Ionide (cross platform F# VS Code tools) working folder 350 | .ionide/ 351 | 352 | .azure/ -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## [project-title] Changelog 2 | 3 | 4 | # x.y.z (yyyy-mm-dd) 5 | 6 | *Features* 7 | * ... 8 | 9 | *Bug Fixes* 10 | * ... 11 | 12 | *Breaking Changes* 13 | * ... 14 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to [project-title] 2 | 3 | This project welcomes contributions and suggestions. Most contributions require you to agree to a 4 | Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us 5 | the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com. 6 | 7 | When you submit a pull request, a CLA bot will automatically determine whether you need to provide 8 | a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions 9 | provided by the bot. You will only need to do this once across all repos using our CLA. 10 | 11 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 12 | For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or 13 | contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. 14 | 15 | - [Code of Conduct](#coc) 16 | - [Issues and Bugs](#issue) 17 | - [Feature Requests](#feature) 18 | - [Submission Guidelines](#submit) 19 | 20 | ## Code of Conduct 21 | Help us keep this project open and inclusive. Please read and follow our [Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 22 | 23 | ## Found an Issue? 24 | If you find a bug in the source code or a mistake in the documentation, you can help us by 25 | [submitting an issue](#submit-issue) to the GitHub Repository. Even better, you can 26 | [submit a Pull Request](#submit-pr) with a fix. 27 | 28 | ## Want a Feature? 29 | You can *request* a new feature by [submitting an issue](#submit-issue) to the GitHub 30 | Repository. If you would like to *implement* a new feature, please submit an issue with 31 | a proposal for your work first, to be sure that we can use it. 32 | 33 | * **Small Features** can be crafted and directly [submitted as a Pull Request](#submit-pr). 34 | 35 | ## Submission Guidelines 36 | 37 | ### Submitting an Issue 38 | Before you submit an issue, search the archive, maybe your question was already answered. 39 | 40 | If your issue appears to be a bug, and hasn't been reported, open a new issue. 41 | Help us to maximize the effort we can spend fixing issues and adding new 42 | features, by not reporting duplicate issues. Providing the following information will increase the 43 | chances of your issue being dealt with quickly: 44 | 45 | * **Overview of the Issue** - if an error is being thrown a non-minified stack trace helps 46 | * **Version** - what version is affected (e.g. 0.1.2) 47 | * **Motivation for or Use Case** - explain what are you trying to do and why the current behavior is a bug for you 48 | * **Browsers and Operating System** - is this a problem with all browsers? 49 | * **Reproduce the Error** - provide a live example or a unambiguous set of steps 50 | * **Related Issues** - has a similar issue been reported before? 51 | * **Suggest a Fix** - if you can't fix the bug yourself, perhaps you can point to what might be 52 | causing the problem (line of code or commit) 53 | 54 | You can file new issues by providing the above information at the corresponding repository's issues link: https://github.com/[organization-name]/[repository-name]/issues/new]. 55 | 56 | ### Submitting a Pull Request (PR) 57 | Before you submit your Pull Request (PR) consider the following guidelines: 58 | 59 | * Search the repository (https://github.com/[organization-name]/[repository-name]/pulls) for an open or closed PR 60 | that relates to your submission. You don't want to duplicate effort. 61 | 62 | * Make your changes in a new git fork: 63 | 64 | * Commit your changes using a descriptive commit message 65 | * Push your fork to GitHub: 66 | * In GitHub, create a pull request 67 | * If we suggest changes then: 68 | * Make the required updates. 69 | * Rebase your fork and force push to your GitHub repository (this will update your Pull Request): 70 | 71 | ```shell 72 | git rebase master -i 73 | git push -f 74 | ``` 75 | 76 | That's it! Thank you for your contribution! 77 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Microsoft Corporation. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | --- 2 | page_type: sample 3 | languages: 4 | - azdeveloper 5 | - javascript 6 | - bicep 7 | products: 8 | - azure 9 | - azure-app-service 10 | - azure-cosmos-db 11 | - azure-virtual-network 12 | - azure-key-vault 13 | - azure-cache-redis 14 | urlFragment: msdocs-nodejs-mongodb-azure-sample-app 15 | name: Deploy a Express.js web app with MongoDB in Azure 16 | description: This is a CRUD web app that uses Express.js and Azure Cosmos DB. 17 | --- 18 | 19 | 20 | # Deploy a Express.js web app with MongoDB in Azure 21 | 22 | This is a CRUD (create-read-update-delete) web app that uses Express.js and Azure Cosmos DB. The Node.js app is hosted in a fully managed Azure App Service. This app is designed to be be run locally Linux Node.js container in Azure App Service. You can either deploy this project by following the tutorial [*Tutorial: Deploy a Node.js + MongoDB web app to Azure*](https://learn.microsoft.com/azure/app-service/tutorial-nodejs-mongodb-app) or by using the [Azure Developer CLI (azd)](https://learn.microsoft.com/azure/developer/azure-developer-cli/overview) according to the instructions below. 23 | 24 | ## Run the sample 25 | 26 | This project has a [dev container configuration](.devcontainer/), which makes it easier to develop apps locally, deploy them to Azure, and monitor them. The easiest way to run this sample application is inside a GitHub codespace. Follow these steps: 27 | 28 | 1. Fork this repository to your account. For instructions, see [Fork a repo](https://docs.github.com/get-started/quickstart/fork-a-repo). 29 | 30 | 1. From the repository root of your fork, select **Code** > **Codespaces** > **+**. 31 | 32 | 1. In the codespace terminal, run the following command: 33 | 34 | ```shell 35 | npm install && npm start 36 | ``` 37 | 38 | 1. When you see the message `Your application running on port 3000 is available.`, click **Open in Browser**. 39 | 40 | ### Quick deploy 41 | 42 | This project is designed to work well with the [Azure Developer CLI](https://learn.microsoft.com/azure/developer/azure-developer-cli/overview), which makes it easier to develop apps locally, deploy them to Azure, and monitor them. 43 | 44 | 🎥 Watch a deployment of the code in [this screencast](https://www.youtube.com/watch?v=JDlZ4TgPKYc). 45 | 46 | Steps for deployment: 47 | 48 | 1. Sign up for a [free Azure account](https://azure.microsoft.com/free/) 49 | 2. Install the [Azure Dev CLI](https://learn.microsoft.com/azure/developer/azure-developer-cli/install-azd). (If you opened this repository in a Dev Container, it's already installed for you.) 50 | 3. Log in to Azure. 51 | 52 | ```shell 53 | azd auth login 54 | ``` 55 | 56 | 4. Provision and deploy all the resources: 57 | 58 | ```shell 59 | azd up 60 | ``` 61 | 62 | It will prompt you to create a deployment environment name, pick a subscription, and provide a location (like `westeurope`). Then it will provision the resources in your account and deploy the latest code. If you get an error with deployment, changing the location (like to "centralus") can help, as there may be availability constraints for some of the resources. 63 | 64 | 5. When `azd` has finished deploying, you'll see an endpoint URI in the command output. Visit that URI, and you should see the CRUD app! 🎉 If you see an error, open the Azure Portal from the URL in the command output, navigate to the App Service, select Logstream, and check the logs for any errors. 65 | 66 | 6. When you've made any changes to the app code, you can just run: 67 | 68 | ```shell 69 | azd deploy 70 | ``` 71 | 72 | ## Getting help 73 | 74 | If you're working with this project and running into issues, please post in [Issues](/issues). 75 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | var createError = require("http-errors"); 2 | var express = require("express"); 3 | var mongoose = require("mongoose"); 4 | var path = require("path"); 5 | var cookieParser = require("cookie-parser"); 6 | var logger = require("morgan"); 7 | const { format } = require("date-fns"); 8 | 9 | // 1st party dependencies 10 | var indexRouter = require("./routes/index"); 11 | 12 | async function getApp() { 13 | 14 | // Database 15 | // Use AZURE_COSMOS_CONNECTIONSTRING if available, otherwise fall back to MONGODB_URI 16 | const mongoUri = process.env.AZURE_COSMOS_CONNECTIONSTRING || process.env.MONGODB_URI; 17 | 18 | mongoose.connect(mongoUri).then(() => { 19 | console.log('Connected to database'); 20 | }).catch((err) => { 21 | console.error('Error connecting to database:', err); 22 | }); 23 | 24 | var app = express(); 25 | 26 | var port = normalizePort(process.env.PORT || '3000'); 27 | app.set('port', port); 28 | 29 | // view engine setup 30 | app.set("views", path.join(__dirname, "views")); 31 | app.set("view engine", "pug"); 32 | 33 | app.use(logger("dev")); 34 | app.use(express.json()); 35 | app.use(express.urlencoded({ extended: false })); 36 | app.use(cookieParser()); 37 | app.use(express.static(path.join(__dirname, "public"))); 38 | 39 | app.locals.format = format; 40 | 41 | app.use("/", indexRouter); 42 | app.use("/js", express.static(__dirname + "/node_modules/bootstrap/dist/js")); // redirect bootstrap JS 43 | app.use( 44 | "/css", 45 | express.static(__dirname + "/node_modules/bootstrap/dist/css") 46 | ); // redirect CSS bootstrap 47 | 48 | // catch 404 and forward to error handler 49 | app.use(function (req, res, next) { 50 | next(createError(404)); 51 | }); 52 | 53 | // error handler 54 | app.use(function (err, req, res, next) { 55 | // set locals, only providing error in development 56 | res.locals.message = err.message; 57 | res.locals.error = req.app.get("env") === "development" ? err : {}; 58 | 59 | // render the error page 60 | res.status(err.status || 500); 61 | res.render("error"); 62 | }); 63 | 64 | return app; 65 | } 66 | /** 67 | * Normalize a port into a number, string, or false. 68 | */ 69 | 70 | function normalizePort(val) { 71 | var port = parseInt(val, 10); 72 | 73 | if (isNaN(port)) { 74 | // named pipe 75 | return val; 76 | } 77 | 78 | if (port >= 0) { 79 | // port number 80 | return port; 81 | } 82 | 83 | return false; 84 | } 85 | module.exports = { 86 | getApp 87 | }; 88 | -------------------------------------------------------------------------------- /azure.yaml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=https://raw.githubusercontent.com/Azure/azure-dev/main/schemas/v1.0/azure.yaml.json 2 | # azure.yaml is an azd configuration file and isn't used by the sample application. 3 | 4 | name: node-app-service-mongodb-redis-infra 5 | metadata: 6 | template: node-app-service-mongodb-redis-infra@0.0.1-beta 7 | services: 8 | web: 9 | project: . 10 | language: js 11 | host: appservice 12 | hooks: 13 | postprovision: 14 | posix: 15 | shell: sh 16 | run: printf '\nApp Service app has the following app settings:\n' && printf "$CONNECTION_SETTINGS" | jq -r '.[]' | sed 's/\(.*\)/\t- \1/' && printf "\nSee the settings in the portal:\033[1;36m $WEB_APP_CONFIG\n" 17 | interactive: true 18 | continueOnError: true 19 | windows: 20 | shell: pwsh 21 | run: Write-Host "`n`nApp Service app has the following app settings:`n" $CONNECTION_SETTINGS | ConvertFrom-Json | ForEach-Object { Write-Host "\t- $_" } 22 | interactive: true 23 | continueOnError: true 24 | postdeploy: 25 | posix: 26 | shell: sh 27 | run: printf "Open SSH session to App Service container at:\033[1;36m $WEB_APP_SSH\033[0m\nStream App Service logs at:\033[1;36m $WEB_APP_LOG_STREAM\n" 28 | interactive: true 29 | continueOnError: true 30 | windows: 31 | shell: pwsh 32 | run: Write-Host "`n`nOpen SSH session to App Service container at:`n" $WEB_APP_SSH; Write-Host "Stream App Service logs at:`n" $WEB_APP_LOG_STREAM 33 | interactive: true 34 | continueOnError: true -------------------------------------------------------------------------------- /bin/www: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | /** 4 | * Module dependencies. 5 | */ 6 | 7 | var { getApp } = require("../app"); 8 | var debug = require("debug")("todolist:server"); 9 | var http = require("http"); 10 | 11 | /** 12 | * Create HTTP server. 13 | */ 14 | getApp().then((app) => { 15 | var port = app.get("port"); 16 | var server = http.createServer(app); 17 | 18 | /** 19 | * Listen on provided port, on all network interfaces. 20 | */ 21 | 22 | server.listen(port); 23 | server.on("error", onError); 24 | server.on("listening", onListening); 25 | 26 | /** 27 | * Event listener for HTTP server "error" event. 28 | */ 29 | 30 | function onError(error) { 31 | if (error.syscall !== "listen") { 32 | throw error; 33 | } 34 | 35 | var bind = typeof port === "string" ? "Pipe " + port : "Port " + port; 36 | 37 | // handle specific listen errors with friendly messages 38 | switch (error.code) { 39 | case "EACCES": 40 | console.error(bind + " requires elevated privileges"); 41 | process.exit(1); 42 | break; 43 | case "EADDRINUSE": 44 | console.error(bind + " is already in use"); 45 | process.exit(1); 46 | break; 47 | default: 48 | throw error; 49 | } 50 | } 51 | 52 | /** 53 | * Event listener for HTTP server "listening" event. 54 | */ 55 | 56 | function onListening() { 57 | var addr = server.address(); 58 | var bind = typeof addr === "string" ? "pipe " + addr : "port " + addr.port; 59 | debug("Listening on " + bind); 60 | } 61 | }); 62 | -------------------------------------------------------------------------------- /infra/README.md: -------------------------------------------------------------------------------- 1 | # infra directory 2 | 3 | This `infra` directory contains azd files used for `azd provision` and isn't used by the sample application. -------------------------------------------------------------------------------- /infra/main.bicep: -------------------------------------------------------------------------------- 1 | targetScope = 'subscription' 2 | 3 | @minLength(1) 4 | @maxLength(64) 5 | @description('Name which is used to generate a short unique hash for each resource') 6 | param name string 7 | 8 | @minLength(1) 9 | @description('Primary location for all resources') 10 | param location string 11 | 12 | var resourceToken = toLower(uniqueString(subscription().id, name, location)) 13 | 14 | resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { 15 | name: '${name}_group' 16 | location: location 17 | tags: { 'azd-env-name': name } 18 | } 19 | 20 | module resources 'resources.bicep' = { 21 | name: 'resources' 22 | scope: resourceGroup 23 | params: { 24 | name: name 25 | location: location 26 | resourceToken: resourceToken 27 | } 28 | } 29 | 30 | output AZURE_LOCATION string = location 31 | output WEB_URI string = resources.outputs.WEB_URI 32 | output CONNECTION_SETTINGS array = resources.outputs.CONNECTION_SETTINGS 33 | output WEB_APP_LOG_STREAM string = resources.outputs.WEB_APP_LOG_STREAM 34 | output WEB_APP_SSH string = resources.outputs.WEB_APP_SSH 35 | output WEB_APP_CONFIG string = resources.outputs.WEB_APP_CONFIG 36 | -------------------------------------------------------------------------------- /infra/main.parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "name": { 6 | "value": "${AZURE_ENV_NAME}" 7 | }, 8 | "location": { 9 | "value": "${AZURE_LOCATION}" 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /infra/resources.bicep: -------------------------------------------------------------------------------- 1 | param name string 2 | param location string 3 | param resourceToken string 4 | 5 | var appName = '${name}-${resourceToken}' 6 | 7 | resource virtualNetwork 'Microsoft.Network/virtualNetworks@2024-01-01' = { 8 | location: location 9 | name: '${appName}Vnet' 10 | properties: { 11 | addressSpace: { 12 | addressPrefixes: ['10.0.0.0/16'] 13 | } 14 | subnets: [ 15 | { 16 | name: 'cache-subnet' 17 | properties: { 18 | addressPrefix: '10.0.0.0/24' 19 | privateEndpointNetworkPolicies: 'Disabled' 20 | } 21 | } 22 | { 23 | name: 'vault-subnet' 24 | properties: { 25 | addressPrefix: '10.0.3.0/24' 26 | privateEndpointNetworkPolicies: 'Disabled' 27 | } 28 | } 29 | { 30 | name: 'database-subnet' 31 | properties: { 32 | addressPrefix: '10.0.2.0/24' 33 | privateEndpointNetworkPolicies: 'Disabled' 34 | } 35 | } 36 | { 37 | name: 'webapp-subnet' 38 | properties: { 39 | addressPrefix: '10.0.1.0/24' 40 | delegations: [ 41 | { 42 | name: 'dlg-appServices' 43 | properties: { 44 | serviceName: 'Microsoft.Web/serverfarms' 45 | } 46 | } 47 | ] 48 | } 49 | } 50 | ] 51 | } 52 | resource subnetForDb 'subnets' existing = { 53 | name: 'database-subnet' 54 | } 55 | resource subnetForVault 'subnets' existing = { 56 | name: 'vault-subnet' 57 | } 58 | resource subnetForApp 'subnets' existing = { 59 | name: 'webapp-subnet' 60 | } 61 | resource subnetForCache 'subnets' existing = { 62 | name: 'cache-subnet' 63 | } 64 | } 65 | 66 | // Resources needed to secure Key Vault behind a private endpoint 67 | resource privateDnsZoneKeyVault 'Microsoft.Network/privateDnsZones@2020-06-01' = { 68 | name: 'privatelink.vaultcore.azure.net' 69 | location: 'global' 70 | resource vnetLink 'virtualNetworkLinks@2020-06-01' = { 71 | location: 'global' 72 | name: '${appName}-vaultlink' 73 | properties: { 74 | virtualNetwork: { 75 | id: virtualNetwork.id 76 | } 77 | registrationEnabled: false 78 | } 79 | } 80 | } 81 | resource vaultPrivateEndpoint 'Microsoft.Network/privateEndpoints@2023-04-01' = { 82 | name: '${appName}-vault-privateEndpoint' 83 | location: location 84 | properties: { 85 | subnet: { 86 | id: virtualNetwork::subnetForVault.id 87 | } 88 | privateLinkServiceConnections: [ 89 | { 90 | name: '${appName}-vault-privateEndpoint' 91 | properties: { 92 | privateLinkServiceId: keyVault.id 93 | groupIds: ['vault'] 94 | } 95 | } 96 | ] 97 | } 98 | resource privateDnsZoneGroup 'privateDnsZoneGroups@2024-01-01' = { 99 | name: 'default' 100 | properties: { 101 | privateDnsZoneConfigs: [ 102 | { 103 | name: 'vault-config' 104 | properties: { 105 | privateDnsZoneId: privateDnsZoneKeyVault.id 106 | } 107 | } 108 | ] 109 | } 110 | } 111 | } 112 | 113 | // Resources needed to secure Cosmos DB behind a private endpoint 114 | resource dbPrivateEndpoint 'Microsoft.Network/privateEndpoints@2023-04-01' = { 115 | name: '${appName}-db-privateEndpoint' 116 | location: location 117 | properties: { 118 | subnet: { 119 | id: virtualNetwork::subnetForDb.id 120 | } 121 | privateLinkServiceConnections: [ 122 | { 123 | name: '${appName}-db-privateEndpoint' 124 | properties: { 125 | privateLinkServiceId: dbaccount.id 126 | groupIds: ['MongoDB'] 127 | } 128 | } 129 | ] 130 | } 131 | resource privateDnsZoneGroup 'privateDnsZoneGroups@2024-01-01' = { 132 | name: 'default' 133 | properties: { 134 | privateDnsZoneConfigs: [ 135 | { 136 | name: 'database-config' 137 | properties: { 138 | privateDnsZoneId: privateDnsZoneDB.id 139 | } 140 | } 141 | ] 142 | } 143 | } 144 | } 145 | resource privateDnsZoneDB 'Microsoft.Network/privateDnsZones@2020-06-01' = { 146 | name: 'privatelink.mongo.cosmos.azure.com' 147 | location: 'global' 148 | dependsOn: [ 149 | virtualNetwork 150 | ] 151 | resource privateDnsZoneLinkDB 'virtualNetworkLinks@2020-06-01' = { 152 | name: '${appName}-dblink' 153 | location: 'global' 154 | properties: { 155 | virtualNetwork: { 156 | id: virtualNetwork.id 157 | } 158 | registrationEnabled: false 159 | } 160 | } 161 | } 162 | 163 | // Resources needed to secure Redis Cache behind a private endpoint 164 | resource cachePrivateEndpoint 'Microsoft.Network/privateEndpoints@2023-04-01' = { 165 | name: '${appName}-cache-privateEndpoint' 166 | location: location 167 | properties: { 168 | subnet: { 169 | id: virtualNetwork::subnetForCache.id 170 | } 171 | privateLinkServiceConnections: [ 172 | { 173 | name: '${appName}-cache-privateEndpoint' 174 | properties: { 175 | privateLinkServiceId: redisCache.id 176 | groupIds: ['redisCache'] 177 | } 178 | } 179 | ] 180 | } 181 | resource privateDnsZoneGroup 'privateDnsZoneGroups' = { 182 | name: 'default' 183 | properties: { 184 | privateDnsZoneConfigs: [ 185 | { 186 | name: 'cache-config' 187 | properties: { 188 | privateDnsZoneId: privateDnsZoneCache.id 189 | } 190 | } 191 | ] 192 | } 193 | } 194 | } 195 | resource privateDnsZoneCache 'Microsoft.Network/privateDnsZones@2020-06-01' = { 196 | name: 'privatelink.redis.cache.windows.net' 197 | location: 'global' 198 | dependsOn: [ 199 | virtualNetwork 200 | ] 201 | resource privateDnsZoneLinkCache 'virtualNetworkLinks@2020-06-01' = { 202 | name: '${appName}-cachelink' 203 | location: 'global' 204 | properties: { 205 | virtualNetwork: { 206 | id: virtualNetwork.id 207 | } 208 | registrationEnabled: false 209 | } 210 | } 211 | } 212 | 213 | // The Key Vault is used to manage connection secrets. 214 | resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' = { 215 | name: '${take(replace(appName, '-', ''), 17)}-vault' 216 | location: location 217 | properties: { 218 | enableRbacAuthorization: true 219 | tenantId: subscription().tenantId 220 | sku: { family: 'A', name: 'standard' } 221 | publicNetworkAccess: 'Disabled' 222 | networkAcls: { 223 | defaultAction: 'Deny' 224 | bypass: 'AzureServices' 225 | ipRules: [] 226 | virtualNetworkRules: [] 227 | } 228 | } 229 | } 230 | 231 | // The Cosmos DB account is configured to be the minimum pricing tier 232 | resource dbaccount 'Microsoft.DocumentDB/databaseAccounts@2024-05-15' = { 233 | location: location 234 | name: '${appName}-server' 235 | kind: 'MongoDB' 236 | tags:{ 237 | defaultExperience: 'Azure Cosmos DB for MongoDB API' 238 | } 239 | properties: { 240 | publicNetworkAccess: 'Disabled' 241 | enableAutomaticFailover: false 242 | enableMultipleWriteLocations: false 243 | isVirtualNetworkFilterEnabled: false 244 | disableKeyBasedMetadataWriteAccess: false 245 | enableFreeTier: false 246 | analyticalStorageConfiguration: { 247 | schemaType: 'FullFidelity' 248 | } 249 | databaseAccountOfferType: 'Standard' 250 | defaultIdentity: 'FirstPartyIdentity' 251 | networkAclBypass: 'None' 252 | disableLocalAuth: false 253 | enablePartitionMerge: false 254 | enableBurstCapacity: false 255 | minimalTlsVersion: 'Tls12' 256 | consistencyPolicy: { 257 | defaultConsistencyLevel: 'Session' 258 | maxIntervalInSeconds: 5 259 | maxStalenessPrefix: 100 260 | } 261 | apiProperties: { 262 | serverVersion: '4.0' 263 | } 264 | locations: [ 265 | { 266 | locationName: location 267 | failoverPriority: 0 268 | isZoneRedundant: false 269 | } 270 | ] 271 | capabilities: [ 272 | { 273 | name: 'EnableMongo' 274 | } 275 | { 276 | name: 'DisableRateLimitingResponses' 277 | } 278 | { 279 | name: 'EnableServerless' 280 | } 281 | ] 282 | } 283 | 284 | resource db 'mongodbDatabases@2024-05-15' = { 285 | name: '${appName}-database' 286 | properties: { 287 | resource: { 288 | id: '${appName}-database' 289 | } 290 | } 291 | } 292 | } 293 | 294 | // The Redis cache is configured to the minimum pricing tier 295 | resource redisCache 'Microsoft.Cache/Redis@2023-08-01' = { 296 | name: '${appName}-cache' 297 | location: location 298 | properties: { 299 | sku: { 300 | name: 'Basic' 301 | family: 'C' 302 | capacity: 0 303 | } 304 | redisConfiguration: {} 305 | enableNonSslPort: false 306 | redisVersion: '6' 307 | publicNetworkAccess: 'Disabled' 308 | } 309 | } 310 | 311 | // The App Service plan is configured to the B1 pricing tier 312 | resource appServicePlan 'Microsoft.Web/serverfarms@2022-09-01' = { 313 | name: '${appName}-plan' 314 | location: location 315 | kind: 'linux' 316 | properties: { 317 | reserved: true 318 | } 319 | sku: { 320 | name: 'B1' 321 | } 322 | } 323 | 324 | resource web 'Microsoft.Web/sites@2022-09-01' = { 325 | name: appName 326 | location: location 327 | tags: {'azd-service-name': 'web'} // Needed by AZD 328 | properties: { 329 | siteConfig: { 330 | linuxFxVersion: 'NODE|20-lts' // Set to Node 20 LTS 331 | vnetRouteAllEnabled: true // Route outbound traffic to the VNET 332 | ftpsState: 'Disabled' 333 | appSettings: [ 334 | { 335 | name: 'SCM_DO_BUILD_DURING_DEPLOYMENT' // By default, azd up doesn't include node_modules for node. Enable deployment build automation on App Service 336 | value: 'true' 337 | } 338 | ] 339 | } 340 | serverFarmId: appServicePlan.id 341 | httpsOnly: true 342 | } 343 | 344 | // Disable basic authentication for FTP and SCM 345 | resource ftp 'basicPublishingCredentialsPolicies@2023-12-01' = { 346 | name: 'ftp' 347 | properties: { 348 | allow: false 349 | } 350 | } 351 | resource scm 'basicPublishingCredentialsPolicies@2023-12-01' = { 352 | name: 'scm' 353 | properties: { 354 | allow: false 355 | } 356 | } 357 | 358 | // Enable App Service native logs 359 | resource logs 'config' = { 360 | name: 'logs' 361 | properties: { 362 | applicationLogs: { 363 | fileSystem: { 364 | level: 'Verbose' 365 | } 366 | } 367 | detailedErrorMessages: { 368 | enabled: true 369 | } 370 | failedRequestsTracing: { 371 | enabled: true 372 | } 373 | httpLogs: { 374 | fileSystem: { 375 | enabled: true 376 | retentionInDays: 1 377 | retentionInMb: 35 378 | } 379 | } 380 | } 381 | } 382 | 383 | // Enable VNET integration 384 | resource webappVnetConfig 'networkConfig' = { 385 | name: 'virtualNetwork' 386 | properties: { 387 | subnetResourceId: virtualNetwork::subnetForApp.id 388 | } 389 | } 390 | 391 | dependsOn: [virtualNetwork] 392 | } 393 | 394 | // Service Connector from the app to the key vault, which generates the connection settings for the Node.js application 395 | // The application code doesn't make any direct connections to the key vault, but the setup expedites the managed identity access 396 | // so that the database and cache connectors can be configured with key vault references. 397 | resource vaultConnector 'Microsoft.ServiceLinker/linkers@2024-04-01' = { 398 | scope: web 399 | name: 'vaultConnector' 400 | properties: { 401 | clientType: 'nodejs' 402 | targetService: { 403 | type: 'AzureResource' 404 | id: keyVault.id 405 | } 406 | authInfo: { 407 | authType: 'systemAssignedIdentity' // Use a system-assigned managed identity. No password is used. 408 | } 409 | vNetSolution: { 410 | type: 'privateLink' 411 | } 412 | } 413 | dependsOn: [ 414 | vaultPrivateEndpoint 415 | ] 416 | } 417 | 418 | // Service Connector from the app to the database, which generates the connection settings for the Node.js application 419 | resource dbConnector 'Microsoft.ServiceLinker/linkers@2024-04-01' = { 420 | scope: web 421 | name: 'defaultConnector' 422 | properties: { 423 | clientType: 'nodejs' 424 | targetService: { 425 | type: 'AzureResource' 426 | id: dbaccount::db.id 427 | } 428 | authInfo: { 429 | authType: 'accessKey' // Configure secrets as Key Vault references. No secret is exposed in App Service. 430 | } 431 | secretStore: { 432 | keyVaultId: keyVault.id 433 | } 434 | vNetSolution: { 435 | type: 'privateLink' 436 | } 437 | } 438 | dependsOn: [ 439 | dbPrivateEndpoint 440 | ] 441 | } 442 | 443 | // Service Connector from the app to the cache, which generates the connection settings for the Node.js application 444 | resource cacheConnector 'Microsoft.ServiceLinker/linkers@2024-04-01' = { 445 | scope: web 446 | name: 'RedisConnector' 447 | properties: { 448 | clientType: 'nodejs' 449 | targetService: { 450 | type: 'AzureResource' 451 | id: resourceId('Microsoft.Cache/Redis/Databases', redisCache.name, '0') 452 | } 453 | authInfo: { 454 | authType: 'accessKey' // Configure secrets as Key Vault references. No secret is exposed in App Service. 455 | } 456 | secretStore: { 457 | keyVaultId: keyVault.id 458 | } 459 | vNetSolution: { 460 | type: 'privateLink' 461 | } 462 | } 463 | dependsOn: [ 464 | cachePrivateEndpoint 465 | ] 466 | } 467 | 468 | resource logAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2020-03-01-preview' = { 469 | name: '${appName}-workspace' 470 | location: location 471 | properties: any({ 472 | retentionInDays: 30 473 | features: { 474 | searchVersion: 1 475 | } 476 | sku: { 477 | name: 'PerGB2018' 478 | } 479 | }) 480 | } 481 | 482 | // Enable log shipping from the App Service app to the Log Analytics workspace. 483 | resource webdiagnostics 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = { 484 | name: 'AllLogs' 485 | scope: web 486 | properties: { 487 | workspaceId: logAnalyticsWorkspace.id 488 | logs: [ 489 | { 490 | category: 'AppServiceHTTPLogs' 491 | enabled: true 492 | } 493 | { 494 | category: 'AppServiceConsoleLogs' 495 | enabled: true 496 | } 497 | { 498 | category: 'AppServiceAppLogs' 499 | enabled: true 500 | } 501 | { 502 | category: 'AppServiceAuditLogs' 503 | enabled: true 504 | } 505 | { 506 | category: 'AppServiceIPSecAuditLogs' 507 | enabled: true 508 | } 509 | { 510 | category: 'AppServicePlatformLogs' 511 | enabled: true 512 | } 513 | ] 514 | metrics: [ 515 | { 516 | category: 'AllMetrics' 517 | enabled: true 518 | } 519 | ] 520 | } 521 | } 522 | 523 | output WEB_URI string = 'https://${web.properties.defaultHostName}' 524 | 525 | output CONNECTION_SETTINGS array = map(concat(dbConnector.listConfigurations().configurations, cacheConnector.listConfigurations().configurations, vaultConnector.listConfigurations().configurations), config => config.name) 526 | output WEB_APP_LOG_STREAM string = format('https://portal.azure.com/#@/resource{0}/logStream', web.id) 527 | output WEB_APP_SSH string = format('https://{0}.scm.azurewebsites.net/webssh/host', web.name) 528 | output WEB_APP_CONFIG string = format('https://portal.azure.com/#@/resource{0}/environmentVariablesAppSettings', web.id) 529 | -------------------------------------------------------------------------------- /models/task.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose'); 2 | 3 | const taskSchema = new mongoose.Schema({ 4 | taskName: { 5 | type: String, 6 | trim: true, 7 | }, 8 | createDate: Date, 9 | completedDate: Date, 10 | completed: Boolean 11 | }); 12 | 13 | module.exports = mongoose.model('Task', taskSchema); -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "todolist", 3 | "version": "0.0.0", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "todolist", 9 | "version": "0.0.0", 10 | "dependencies": { 11 | "bootstrap": "^5.3.3", 12 | "cookie-parser": "~1.4.6", 13 | "date-fns": "^4.1.0", 14 | "debug": "~4.3.7", 15 | "express": "^4.21.0", 16 | "http-errors": "~2.0.0", 17 | "mongoose": "^8.6.3", 18 | "morgan": "~1.10.0", 19 | "pug": "^3.0.3" 20 | } 21 | }, 22 | "node_modules/@babel/helper-string-parser": { 23 | "version": "7.24.8", 24 | "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz", 25 | "integrity": "sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==", 26 | "license": "MIT", 27 | "engines": { 28 | "node": ">=6.9.0" 29 | } 30 | }, 31 | "node_modules/@babel/helper-validator-identifier": { 32 | "version": "7.24.7", 33 | "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", 34 | "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", 35 | "license": "MIT", 36 | "engines": { 37 | "node": ">=6.9.0" 38 | } 39 | }, 40 | "node_modules/@babel/parser": { 41 | "version": "7.25.6", 42 | "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.6.tgz", 43 | "integrity": "sha512-trGdfBdbD0l1ZPmcJ83eNxB9rbEax4ALFTF7fN386TMYbeCQbyme5cOEXQhbGXKebwGaB/J52w1mrklMcbgy6Q==", 44 | "license": "MIT", 45 | "dependencies": { 46 | "@babel/types": "^7.25.6" 47 | }, 48 | "bin": { 49 | "parser": "bin/babel-parser.js" 50 | }, 51 | "engines": { 52 | "node": ">=6.0.0" 53 | } 54 | }, 55 | "node_modules/@babel/types": { 56 | "version": "7.25.6", 57 | "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.6.tgz", 58 | "integrity": "sha512-/l42B1qxpG6RdfYf343Uw1vmDjeNhneUXtzhojE7pDgfpEypmRhI6j1kr17XCVv4Cgl9HdAiQY2x0GwKm7rWCw==", 59 | "license": "MIT", 60 | "dependencies": { 61 | "@babel/helper-string-parser": "^7.24.8", 62 | "@babel/helper-validator-identifier": "^7.24.7", 63 | "to-fast-properties": "^2.0.0" 64 | }, 65 | "engines": { 66 | "node": ">=6.9.0" 67 | } 68 | }, 69 | "node_modules/@mongodb-js/saslprep": { 70 | "version": "1.1.9", 71 | "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.9.tgz", 72 | "integrity": "sha512-tVkljjeEaAhCqTzajSdgbQ6gE6f3oneVwa3iXR6csiEwXXOFsiC6Uh9iAjAhXPtqa/XMDHWjjeNH/77m/Yq2dw==", 73 | "license": "MIT", 74 | "dependencies": { 75 | "sparse-bitfield": "^3.0.3" 76 | } 77 | }, 78 | "node_modules/@popperjs/core": { 79 | "version": "2.11.8", 80 | "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", 81 | "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", 82 | "license": "MIT", 83 | "peer": true, 84 | "funding": { 85 | "type": "opencollective", 86 | "url": "https://opencollective.com/popperjs" 87 | } 88 | }, 89 | "node_modules/@types/webidl-conversions": { 90 | "version": "7.0.3", 91 | "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz", 92 | "integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==", 93 | "license": "MIT" 94 | }, 95 | "node_modules/@types/whatwg-url": { 96 | "version": "11.0.5", 97 | "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-11.0.5.tgz", 98 | "integrity": "sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ==", 99 | "license": "MIT", 100 | "dependencies": { 101 | "@types/webidl-conversions": "*" 102 | } 103 | }, 104 | "node_modules/accepts": { 105 | "version": "1.3.8", 106 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", 107 | "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", 108 | "license": "MIT", 109 | "dependencies": { 110 | "mime-types": "~2.1.34", 111 | "negotiator": "0.6.3" 112 | }, 113 | "engines": { 114 | "node": ">= 0.6" 115 | } 116 | }, 117 | "node_modules/acorn": { 118 | "version": "7.4.1", 119 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", 120 | "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", 121 | "license": "MIT", 122 | "bin": { 123 | "acorn": "bin/acorn" 124 | }, 125 | "engines": { 126 | "node": ">=0.4.0" 127 | } 128 | }, 129 | "node_modules/array-flatten": { 130 | "version": "1.1.1", 131 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", 132 | "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", 133 | "license": "MIT" 134 | }, 135 | "node_modules/asap": { 136 | "version": "2.0.6", 137 | "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", 138 | "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", 139 | "license": "MIT" 140 | }, 141 | "node_modules/assert-never": { 142 | "version": "1.3.0", 143 | "resolved": "https://registry.npmjs.org/assert-never/-/assert-never-1.3.0.tgz", 144 | "integrity": "sha512-9Z3vxQ+berkL/JJo0dK+EY3Lp0s3NtSnP3VCLsh5HDcZPrh0M+KQRK5sWhUeyPPH+/RCxZqOxLMR+YC6vlviEQ==", 145 | "license": "MIT" 146 | }, 147 | "node_modules/babel-walk": { 148 | "version": "3.0.0-canary-5", 149 | "resolved": "https://registry.npmjs.org/babel-walk/-/babel-walk-3.0.0-canary-5.tgz", 150 | "integrity": "sha512-GAwkz0AihzY5bkwIY5QDR+LvsRQgB/B+1foMPvi0FZPMl5fjD7ICiznUiBdLYMH1QYe6vqu4gWYytZOccLouFw==", 151 | "license": "MIT", 152 | "dependencies": { 153 | "@babel/types": "^7.9.6" 154 | }, 155 | "engines": { 156 | "node": ">= 10.0.0" 157 | } 158 | }, 159 | "node_modules/basic-auth": { 160 | "version": "2.0.1", 161 | "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", 162 | "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", 163 | "license": "MIT", 164 | "dependencies": { 165 | "safe-buffer": "5.1.2" 166 | }, 167 | "engines": { 168 | "node": ">= 0.8" 169 | } 170 | }, 171 | "node_modules/basic-auth/node_modules/safe-buffer": { 172 | "version": "5.1.2", 173 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 174 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", 175 | "license": "MIT" 176 | }, 177 | "node_modules/body-parser": { 178 | "version": "1.20.3", 179 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", 180 | "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", 181 | "license": "MIT", 182 | "dependencies": { 183 | "bytes": "3.1.2", 184 | "content-type": "~1.0.5", 185 | "debug": "2.6.9", 186 | "depd": "2.0.0", 187 | "destroy": "1.2.0", 188 | "http-errors": "2.0.0", 189 | "iconv-lite": "0.4.24", 190 | "on-finished": "2.4.1", 191 | "qs": "6.13.0", 192 | "raw-body": "2.5.2", 193 | "type-is": "~1.6.18", 194 | "unpipe": "1.0.0" 195 | }, 196 | "engines": { 197 | "node": ">= 0.8", 198 | "npm": "1.2.8000 || >= 1.4.16" 199 | } 200 | }, 201 | "node_modules/body-parser/node_modules/debug": { 202 | "version": "2.6.9", 203 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 204 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 205 | "license": "MIT", 206 | "dependencies": { 207 | "ms": "2.0.0" 208 | } 209 | }, 210 | "node_modules/body-parser/node_modules/ms": { 211 | "version": "2.0.0", 212 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 213 | "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", 214 | "license": "MIT" 215 | }, 216 | "node_modules/bootstrap": { 217 | "version": "5.3.3", 218 | "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.3.tgz", 219 | "integrity": "sha512-8HLCdWgyoMguSO9o+aH+iuZ+aht+mzW0u3HIMzVu7Srrpv7EBBxTnrFlSCskwdY1+EOFQSm7uMJhNQHkdPcmjg==", 220 | "funding": [ 221 | { 222 | "type": "github", 223 | "url": "https://github.com/sponsors/twbs" 224 | }, 225 | { 226 | "type": "opencollective", 227 | "url": "https://opencollective.com/bootstrap" 228 | } 229 | ], 230 | "license": "MIT", 231 | "peerDependencies": { 232 | "@popperjs/core": "^2.11.8" 233 | } 234 | }, 235 | "node_modules/bson": { 236 | "version": "6.8.0", 237 | "resolved": "https://registry.npmjs.org/bson/-/bson-6.8.0.tgz", 238 | "integrity": "sha512-iOJg8pr7wq2tg/zSlCCHMi3hMm5JTOxLTagf3zxhcenHsFp+c6uOs6K7W5UE7A4QIJGtqh/ZovFNMP4mOPJynQ==", 239 | "license": "Apache-2.0", 240 | "engines": { 241 | "node": ">=16.20.1" 242 | } 243 | }, 244 | "node_modules/bytes": { 245 | "version": "3.1.2", 246 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", 247 | "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", 248 | "license": "MIT", 249 | "engines": { 250 | "node": ">= 0.8" 251 | } 252 | }, 253 | "node_modules/call-bind": { 254 | "version": "1.0.7", 255 | "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", 256 | "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", 257 | "license": "MIT", 258 | "dependencies": { 259 | "es-define-property": "^1.0.0", 260 | "es-errors": "^1.3.0", 261 | "function-bind": "^1.1.2", 262 | "get-intrinsic": "^1.2.4", 263 | "set-function-length": "^1.2.1" 264 | }, 265 | "engines": { 266 | "node": ">= 0.4" 267 | }, 268 | "funding": { 269 | "url": "https://github.com/sponsors/ljharb" 270 | } 271 | }, 272 | "node_modules/character-parser": { 273 | "version": "2.2.0", 274 | "resolved": "https://registry.npmjs.org/character-parser/-/character-parser-2.2.0.tgz", 275 | "integrity": "sha512-+UqJQjFEFaTAs3bNsF2j2kEN1baG/zghZbdqoYEDxGZtJo9LBzl1A+m0D4n3qKx8N2FNv8/Xp6yV9mQmBuptaw==", 276 | "license": "MIT", 277 | "dependencies": { 278 | "is-regex": "^1.0.3" 279 | } 280 | }, 281 | "node_modules/constantinople": { 282 | "version": "4.0.1", 283 | "resolved": "https://registry.npmjs.org/constantinople/-/constantinople-4.0.1.tgz", 284 | "integrity": "sha512-vCrqcSIq4//Gx74TXXCGnHpulY1dskqLTFGDmhrGxzeXL8lF8kvXv6mpNWlJj1uD4DW23D4ljAqbY4RRaaUZIw==", 285 | "license": "MIT", 286 | "dependencies": { 287 | "@babel/parser": "^7.6.0", 288 | "@babel/types": "^7.6.1" 289 | } 290 | }, 291 | "node_modules/content-disposition": { 292 | "version": "0.5.4", 293 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", 294 | "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", 295 | "license": "MIT", 296 | "dependencies": { 297 | "safe-buffer": "5.2.1" 298 | }, 299 | "engines": { 300 | "node": ">= 0.6" 301 | } 302 | }, 303 | "node_modules/content-type": { 304 | "version": "1.0.5", 305 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", 306 | "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", 307 | "license": "MIT", 308 | "engines": { 309 | "node": ">= 0.6" 310 | } 311 | }, 312 | "node_modules/cookie": { 313 | "version": "0.4.1", 314 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", 315 | "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==", 316 | "license": "MIT", 317 | "engines": { 318 | "node": ">= 0.6" 319 | } 320 | }, 321 | "node_modules/cookie-parser": { 322 | "version": "1.4.6", 323 | "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.6.tgz", 324 | "integrity": "sha512-z3IzaNjdwUC2olLIB5/ITd0/setiaFMLYiZJle7xg5Fe9KWAceil7xszYfHHBtDFYLSgJduS2Ty0P1uJdPDJeA==", 325 | "license": "MIT", 326 | "dependencies": { 327 | "cookie": "0.4.1", 328 | "cookie-signature": "1.0.6" 329 | }, 330 | "engines": { 331 | "node": ">= 0.8.0" 332 | } 333 | }, 334 | "node_modules/cookie-signature": { 335 | "version": "1.0.6", 336 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", 337 | "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", 338 | "license": "MIT" 339 | }, 340 | "node_modules/date-fns": { 341 | "version": "4.1.0", 342 | "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz", 343 | "integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==", 344 | "license": "MIT", 345 | "funding": { 346 | "type": "github", 347 | "url": "https://github.com/sponsors/kossnocorp" 348 | } 349 | }, 350 | "node_modules/debug": { 351 | "version": "4.3.7", 352 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", 353 | "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", 354 | "license": "MIT", 355 | "dependencies": { 356 | "ms": "^2.1.3" 357 | }, 358 | "engines": { 359 | "node": ">=6.0" 360 | }, 361 | "peerDependenciesMeta": { 362 | "supports-color": { 363 | "optional": true 364 | } 365 | } 366 | }, 367 | "node_modules/define-data-property": { 368 | "version": "1.1.4", 369 | "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", 370 | "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", 371 | "license": "MIT", 372 | "dependencies": { 373 | "es-define-property": "^1.0.0", 374 | "es-errors": "^1.3.0", 375 | "gopd": "^1.0.1" 376 | }, 377 | "engines": { 378 | "node": ">= 0.4" 379 | }, 380 | "funding": { 381 | "url": "https://github.com/sponsors/ljharb" 382 | } 383 | }, 384 | "node_modules/depd": { 385 | "version": "2.0.0", 386 | "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", 387 | "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", 388 | "license": "MIT", 389 | "engines": { 390 | "node": ">= 0.8" 391 | } 392 | }, 393 | "node_modules/destroy": { 394 | "version": "1.2.0", 395 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", 396 | "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", 397 | "license": "MIT", 398 | "engines": { 399 | "node": ">= 0.8", 400 | "npm": "1.2.8000 || >= 1.4.16" 401 | } 402 | }, 403 | "node_modules/doctypes": { 404 | "version": "1.1.0", 405 | "resolved": "https://registry.npmjs.org/doctypes/-/doctypes-1.1.0.tgz", 406 | "integrity": "sha512-LLBi6pEqS6Do3EKQ3J0NqHWV5hhb78Pi8vvESYwyOy2c31ZEZVdtitdzsQsKb7878PEERhzUk0ftqGhG6Mz+pQ==", 407 | "license": "MIT" 408 | }, 409 | "node_modules/ee-first": { 410 | "version": "1.1.1", 411 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", 412 | "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", 413 | "license": "MIT" 414 | }, 415 | "node_modules/encodeurl": { 416 | "version": "2.0.0", 417 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", 418 | "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", 419 | "license": "MIT", 420 | "engines": { 421 | "node": ">= 0.8" 422 | } 423 | }, 424 | "node_modules/es-define-property": { 425 | "version": "1.0.0", 426 | "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", 427 | "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", 428 | "license": "MIT", 429 | "dependencies": { 430 | "get-intrinsic": "^1.2.4" 431 | }, 432 | "engines": { 433 | "node": ">= 0.4" 434 | } 435 | }, 436 | "node_modules/es-errors": { 437 | "version": "1.3.0", 438 | "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", 439 | "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", 440 | "license": "MIT", 441 | "engines": { 442 | "node": ">= 0.4" 443 | } 444 | }, 445 | "node_modules/escape-html": { 446 | "version": "1.0.3", 447 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", 448 | "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", 449 | "license": "MIT" 450 | }, 451 | "node_modules/etag": { 452 | "version": "1.8.1", 453 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", 454 | "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", 455 | "license": "MIT", 456 | "engines": { 457 | "node": ">= 0.6" 458 | } 459 | }, 460 | "node_modules/express": { 461 | "version": "4.21.0", 462 | "resolved": "https://registry.npmjs.org/express/-/express-4.21.0.tgz", 463 | "integrity": "sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng==", 464 | "license": "MIT", 465 | "dependencies": { 466 | "accepts": "~1.3.8", 467 | "array-flatten": "1.1.1", 468 | "body-parser": "1.20.3", 469 | "content-disposition": "0.5.4", 470 | "content-type": "~1.0.4", 471 | "cookie": "0.6.0", 472 | "cookie-signature": "1.0.6", 473 | "debug": "2.6.9", 474 | "depd": "2.0.0", 475 | "encodeurl": "~2.0.0", 476 | "escape-html": "~1.0.3", 477 | "etag": "~1.8.1", 478 | "finalhandler": "1.3.1", 479 | "fresh": "0.5.2", 480 | "http-errors": "2.0.0", 481 | "merge-descriptors": "1.0.3", 482 | "methods": "~1.1.2", 483 | "on-finished": "2.4.1", 484 | "parseurl": "~1.3.3", 485 | "path-to-regexp": "0.1.10", 486 | "proxy-addr": "~2.0.7", 487 | "qs": "6.13.0", 488 | "range-parser": "~1.2.1", 489 | "safe-buffer": "5.2.1", 490 | "send": "0.19.0", 491 | "serve-static": "1.16.2", 492 | "setprototypeof": "1.2.0", 493 | "statuses": "2.0.1", 494 | "type-is": "~1.6.18", 495 | "utils-merge": "1.0.1", 496 | "vary": "~1.1.2" 497 | }, 498 | "engines": { 499 | "node": ">= 0.10.0" 500 | } 501 | }, 502 | "node_modules/express/node_modules/cookie": { 503 | "version": "0.6.0", 504 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", 505 | "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", 506 | "license": "MIT", 507 | "engines": { 508 | "node": ">= 0.6" 509 | } 510 | }, 511 | "node_modules/express/node_modules/debug": { 512 | "version": "2.6.9", 513 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 514 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 515 | "license": "MIT", 516 | "dependencies": { 517 | "ms": "2.0.0" 518 | } 519 | }, 520 | "node_modules/express/node_modules/ms": { 521 | "version": "2.0.0", 522 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 523 | "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", 524 | "license": "MIT" 525 | }, 526 | "node_modules/finalhandler": { 527 | "version": "1.3.1", 528 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", 529 | "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", 530 | "license": "MIT", 531 | "dependencies": { 532 | "debug": "2.6.9", 533 | "encodeurl": "~2.0.0", 534 | "escape-html": "~1.0.3", 535 | "on-finished": "2.4.1", 536 | "parseurl": "~1.3.3", 537 | "statuses": "2.0.1", 538 | "unpipe": "~1.0.0" 539 | }, 540 | "engines": { 541 | "node": ">= 0.8" 542 | } 543 | }, 544 | "node_modules/finalhandler/node_modules/debug": { 545 | "version": "2.6.9", 546 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 547 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 548 | "license": "MIT", 549 | "dependencies": { 550 | "ms": "2.0.0" 551 | } 552 | }, 553 | "node_modules/finalhandler/node_modules/ms": { 554 | "version": "2.0.0", 555 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 556 | "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", 557 | "license": "MIT" 558 | }, 559 | "node_modules/forwarded": { 560 | "version": "0.2.0", 561 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", 562 | "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", 563 | "license": "MIT", 564 | "engines": { 565 | "node": ">= 0.6" 566 | } 567 | }, 568 | "node_modules/fresh": { 569 | "version": "0.5.2", 570 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", 571 | "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", 572 | "license": "MIT", 573 | "engines": { 574 | "node": ">= 0.6" 575 | } 576 | }, 577 | "node_modules/function-bind": { 578 | "version": "1.1.2", 579 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", 580 | "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", 581 | "license": "MIT", 582 | "funding": { 583 | "url": "https://github.com/sponsors/ljharb" 584 | } 585 | }, 586 | "node_modules/get-intrinsic": { 587 | "version": "1.2.4", 588 | "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", 589 | "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", 590 | "license": "MIT", 591 | "dependencies": { 592 | "es-errors": "^1.3.0", 593 | "function-bind": "^1.1.2", 594 | "has-proto": "^1.0.1", 595 | "has-symbols": "^1.0.3", 596 | "hasown": "^2.0.0" 597 | }, 598 | "engines": { 599 | "node": ">= 0.4" 600 | }, 601 | "funding": { 602 | "url": "https://github.com/sponsors/ljharb" 603 | } 604 | }, 605 | "node_modules/gopd": { 606 | "version": "1.0.1", 607 | "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", 608 | "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", 609 | "license": "MIT", 610 | "dependencies": { 611 | "get-intrinsic": "^1.1.3" 612 | }, 613 | "funding": { 614 | "url": "https://github.com/sponsors/ljharb" 615 | } 616 | }, 617 | "node_modules/has-property-descriptors": { 618 | "version": "1.0.2", 619 | "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", 620 | "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", 621 | "license": "MIT", 622 | "dependencies": { 623 | "es-define-property": "^1.0.0" 624 | }, 625 | "funding": { 626 | "url": "https://github.com/sponsors/ljharb" 627 | } 628 | }, 629 | "node_modules/has-proto": { 630 | "version": "1.0.3", 631 | "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", 632 | "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", 633 | "license": "MIT", 634 | "engines": { 635 | "node": ">= 0.4" 636 | }, 637 | "funding": { 638 | "url": "https://github.com/sponsors/ljharb" 639 | } 640 | }, 641 | "node_modules/has-symbols": { 642 | "version": "1.0.3", 643 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", 644 | "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", 645 | "license": "MIT", 646 | "engines": { 647 | "node": ">= 0.4" 648 | }, 649 | "funding": { 650 | "url": "https://github.com/sponsors/ljharb" 651 | } 652 | }, 653 | "node_modules/has-tostringtag": { 654 | "version": "1.0.2", 655 | "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", 656 | "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", 657 | "license": "MIT", 658 | "dependencies": { 659 | "has-symbols": "^1.0.3" 660 | }, 661 | "engines": { 662 | "node": ">= 0.4" 663 | }, 664 | "funding": { 665 | "url": "https://github.com/sponsors/ljharb" 666 | } 667 | }, 668 | "node_modules/hasown": { 669 | "version": "2.0.2", 670 | "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", 671 | "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", 672 | "license": "MIT", 673 | "dependencies": { 674 | "function-bind": "^1.1.2" 675 | }, 676 | "engines": { 677 | "node": ">= 0.4" 678 | } 679 | }, 680 | "node_modules/http-errors": { 681 | "version": "2.0.0", 682 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", 683 | "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", 684 | "license": "MIT", 685 | "dependencies": { 686 | "depd": "2.0.0", 687 | "inherits": "2.0.4", 688 | "setprototypeof": "1.2.0", 689 | "statuses": "2.0.1", 690 | "toidentifier": "1.0.1" 691 | }, 692 | "engines": { 693 | "node": ">= 0.8" 694 | } 695 | }, 696 | "node_modules/iconv-lite": { 697 | "version": "0.4.24", 698 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", 699 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", 700 | "license": "MIT", 701 | "dependencies": { 702 | "safer-buffer": ">= 2.1.2 < 3" 703 | }, 704 | "engines": { 705 | "node": ">=0.10.0" 706 | } 707 | }, 708 | "node_modules/inherits": { 709 | "version": "2.0.4", 710 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 711 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", 712 | "license": "ISC" 713 | }, 714 | "node_modules/ipaddr.js": { 715 | "version": "1.9.1", 716 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", 717 | "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", 718 | "license": "MIT", 719 | "engines": { 720 | "node": ">= 0.10" 721 | } 722 | }, 723 | "node_modules/is-core-module": { 724 | "version": "2.15.1", 725 | "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", 726 | "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==", 727 | "license": "MIT", 728 | "dependencies": { 729 | "hasown": "^2.0.2" 730 | }, 731 | "engines": { 732 | "node": ">= 0.4" 733 | }, 734 | "funding": { 735 | "url": "https://github.com/sponsors/ljharb" 736 | } 737 | }, 738 | "node_modules/is-expression": { 739 | "version": "4.0.0", 740 | "resolved": "https://registry.npmjs.org/is-expression/-/is-expression-4.0.0.tgz", 741 | "integrity": "sha512-zMIXX63sxzG3XrkHkrAPvm/OVZVSCPNkwMHU8oTX7/U3AL78I0QXCEICXUM13BIa8TYGZ68PiTKfQz3yaTNr4A==", 742 | "license": "MIT", 743 | "dependencies": { 744 | "acorn": "^7.1.1", 745 | "object-assign": "^4.1.1" 746 | } 747 | }, 748 | "node_modules/is-promise": { 749 | "version": "2.2.2", 750 | "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", 751 | "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", 752 | "license": "MIT" 753 | }, 754 | "node_modules/is-regex": { 755 | "version": "1.1.4", 756 | "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", 757 | "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", 758 | "license": "MIT", 759 | "dependencies": { 760 | "call-bind": "^1.0.2", 761 | "has-tostringtag": "^1.0.0" 762 | }, 763 | "engines": { 764 | "node": ">= 0.4" 765 | }, 766 | "funding": { 767 | "url": "https://github.com/sponsors/ljharb" 768 | } 769 | }, 770 | "node_modules/js-stringify": { 771 | "version": "1.0.2", 772 | "resolved": "https://registry.npmjs.org/js-stringify/-/js-stringify-1.0.2.tgz", 773 | "integrity": "sha512-rtS5ATOo2Q5k1G+DADISilDA6lv79zIiwFd6CcjuIxGKLFm5C+RLImRscVap9k55i+MOZwgliw+NejvkLuGD5g==", 774 | "license": "MIT" 775 | }, 776 | "node_modules/jstransformer": { 777 | "version": "1.0.0", 778 | "resolved": "https://registry.npmjs.org/jstransformer/-/jstransformer-1.0.0.tgz", 779 | "integrity": "sha512-C9YK3Rf8q6VAPDCCU9fnqo3mAfOH6vUGnMcP4AQAYIEpWtfGLpwOTmZ+igtdK5y+VvI2n3CyYSzy4Qh34eq24A==", 780 | "license": "MIT", 781 | "dependencies": { 782 | "is-promise": "^2.0.0", 783 | "promise": "^7.0.1" 784 | } 785 | }, 786 | "node_modules/kareem": { 787 | "version": "2.6.3", 788 | "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.6.3.tgz", 789 | "integrity": "sha512-C3iHfuGUXK2u8/ipq9LfjFfXFxAZMQJJq7vLS45r3D9Y2xQ/m4S8zaR4zMLFWh9AsNPXmcFfUDhTEO8UIC/V6Q==", 790 | "license": "Apache-2.0", 791 | "engines": { 792 | "node": ">=12.0.0" 793 | } 794 | }, 795 | "node_modules/media-typer": { 796 | "version": "0.3.0", 797 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", 798 | "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", 799 | "license": "MIT", 800 | "engines": { 801 | "node": ">= 0.6" 802 | } 803 | }, 804 | "node_modules/memory-pager": { 805 | "version": "1.5.0", 806 | "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", 807 | "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", 808 | "license": "MIT" 809 | }, 810 | "node_modules/merge-descriptors": { 811 | "version": "1.0.3", 812 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", 813 | "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", 814 | "license": "MIT", 815 | "funding": { 816 | "url": "https://github.com/sponsors/sindresorhus" 817 | } 818 | }, 819 | "node_modules/methods": { 820 | "version": "1.1.2", 821 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", 822 | "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", 823 | "license": "MIT", 824 | "engines": { 825 | "node": ">= 0.6" 826 | } 827 | }, 828 | "node_modules/mime": { 829 | "version": "1.6.0", 830 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", 831 | "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", 832 | "license": "MIT", 833 | "bin": { 834 | "mime": "cli.js" 835 | }, 836 | "engines": { 837 | "node": ">=4" 838 | } 839 | }, 840 | "node_modules/mime-db": { 841 | "version": "1.52.0", 842 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", 843 | "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", 844 | "license": "MIT", 845 | "engines": { 846 | "node": ">= 0.6" 847 | } 848 | }, 849 | "node_modules/mime-types": { 850 | "version": "2.1.35", 851 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", 852 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", 853 | "license": "MIT", 854 | "dependencies": { 855 | "mime-db": "1.52.0" 856 | }, 857 | "engines": { 858 | "node": ">= 0.6" 859 | } 860 | }, 861 | "node_modules/mongodb": { 862 | "version": "6.8.0", 863 | "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.8.0.tgz", 864 | "integrity": "sha512-HGQ9NWDle5WvwMnrvUxsFYPd3JEbqD3RgABHBQRuoCEND0qzhsd0iH5ypHsf1eJ+sXmvmyKpP+FLOKY8Il7jMw==", 865 | "license": "Apache-2.0", 866 | "dependencies": { 867 | "@mongodb-js/saslprep": "^1.1.5", 868 | "bson": "^6.7.0", 869 | "mongodb-connection-string-url": "^3.0.0" 870 | }, 871 | "engines": { 872 | "node": ">=16.20.1" 873 | }, 874 | "peerDependencies": { 875 | "@aws-sdk/credential-providers": "^3.188.0", 876 | "@mongodb-js/zstd": "^1.1.0", 877 | "gcp-metadata": "^5.2.0", 878 | "kerberos": "^2.0.1", 879 | "mongodb-client-encryption": ">=6.0.0 <7", 880 | "snappy": "^7.2.2", 881 | "socks": "^2.7.1" 882 | }, 883 | "peerDependenciesMeta": { 884 | "@aws-sdk/credential-providers": { 885 | "optional": true 886 | }, 887 | "@mongodb-js/zstd": { 888 | "optional": true 889 | }, 890 | "gcp-metadata": { 891 | "optional": true 892 | }, 893 | "kerberos": { 894 | "optional": true 895 | }, 896 | "mongodb-client-encryption": { 897 | "optional": true 898 | }, 899 | "snappy": { 900 | "optional": true 901 | }, 902 | "socks": { 903 | "optional": true 904 | } 905 | } 906 | }, 907 | "node_modules/mongodb-connection-string-url": { 908 | "version": "3.0.1", 909 | "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-3.0.1.tgz", 910 | "integrity": "sha512-XqMGwRX0Lgn05TDB4PyG2h2kKO/FfWJyCzYQbIhXUxz7ETt0I/FqHjUeqj37irJ+Dl1ZtU82uYyj14u2XsZKfg==", 911 | "license": "Apache-2.0", 912 | "dependencies": { 913 | "@types/whatwg-url": "^11.0.2", 914 | "whatwg-url": "^13.0.0" 915 | } 916 | }, 917 | "node_modules/mongoose": { 918 | "version": "8.6.3", 919 | "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.6.3.tgz", 920 | "integrity": "sha512-++yRmm7hjMbqVA/8WeiygTnEfrFbiy+OBjQi49GFJIvCQuSYE56myyQWo4j5hbpcHjhHQU8NukMNGTwAWFWjIw==", 921 | "license": "MIT", 922 | "dependencies": { 923 | "bson": "^6.7.0", 924 | "kareem": "2.6.3", 925 | "mongodb": "6.8.0", 926 | "mpath": "0.9.0", 927 | "mquery": "5.0.0", 928 | "ms": "2.1.3", 929 | "sift": "17.1.3" 930 | }, 931 | "engines": { 932 | "node": ">=16.20.1" 933 | }, 934 | "funding": { 935 | "type": "opencollective", 936 | "url": "https://opencollective.com/mongoose" 937 | } 938 | }, 939 | "node_modules/morgan": { 940 | "version": "1.10.0", 941 | "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz", 942 | "integrity": "sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==", 943 | "license": "MIT", 944 | "dependencies": { 945 | "basic-auth": "~2.0.1", 946 | "debug": "2.6.9", 947 | "depd": "~2.0.0", 948 | "on-finished": "~2.3.0", 949 | "on-headers": "~1.0.2" 950 | }, 951 | "engines": { 952 | "node": ">= 0.8.0" 953 | } 954 | }, 955 | "node_modules/morgan/node_modules/debug": { 956 | "version": "2.6.9", 957 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 958 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 959 | "license": "MIT", 960 | "dependencies": { 961 | "ms": "2.0.0" 962 | } 963 | }, 964 | "node_modules/morgan/node_modules/ms": { 965 | "version": "2.0.0", 966 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 967 | "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", 968 | "license": "MIT" 969 | }, 970 | "node_modules/morgan/node_modules/on-finished": { 971 | "version": "2.3.0", 972 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", 973 | "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", 974 | "license": "MIT", 975 | "dependencies": { 976 | "ee-first": "1.1.1" 977 | }, 978 | "engines": { 979 | "node": ">= 0.8" 980 | } 981 | }, 982 | "node_modules/mpath": { 983 | "version": "0.9.0", 984 | "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.9.0.tgz", 985 | "integrity": "sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew==", 986 | "license": "MIT", 987 | "engines": { 988 | "node": ">=4.0.0" 989 | } 990 | }, 991 | "node_modules/mquery": { 992 | "version": "5.0.0", 993 | "resolved": "https://registry.npmjs.org/mquery/-/mquery-5.0.0.tgz", 994 | "integrity": "sha512-iQMncpmEK8R8ncT8HJGsGc9Dsp8xcgYMVSbs5jgnm1lFHTZqMJTUWTDx1LBO8+mK3tPNZWFLBghQEIOULSTHZg==", 995 | "license": "MIT", 996 | "dependencies": { 997 | "debug": "4.x" 998 | }, 999 | "engines": { 1000 | "node": ">=14.0.0" 1001 | } 1002 | }, 1003 | "node_modules/ms": { 1004 | "version": "2.1.3", 1005 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 1006 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", 1007 | "license": "MIT" 1008 | }, 1009 | "node_modules/negotiator": { 1010 | "version": "0.6.3", 1011 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", 1012 | "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", 1013 | "license": "MIT", 1014 | "engines": { 1015 | "node": ">= 0.6" 1016 | } 1017 | }, 1018 | "node_modules/object-assign": { 1019 | "version": "4.1.1", 1020 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", 1021 | "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", 1022 | "license": "MIT", 1023 | "engines": { 1024 | "node": ">=0.10.0" 1025 | } 1026 | }, 1027 | "node_modules/object-inspect": { 1028 | "version": "1.13.2", 1029 | "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", 1030 | "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", 1031 | "license": "MIT", 1032 | "engines": { 1033 | "node": ">= 0.4" 1034 | }, 1035 | "funding": { 1036 | "url": "https://github.com/sponsors/ljharb" 1037 | } 1038 | }, 1039 | "node_modules/on-finished": { 1040 | "version": "2.4.1", 1041 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", 1042 | "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", 1043 | "license": "MIT", 1044 | "dependencies": { 1045 | "ee-first": "1.1.1" 1046 | }, 1047 | "engines": { 1048 | "node": ">= 0.8" 1049 | } 1050 | }, 1051 | "node_modules/on-headers": { 1052 | "version": "1.0.2", 1053 | "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", 1054 | "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", 1055 | "license": "MIT", 1056 | "engines": { 1057 | "node": ">= 0.8" 1058 | } 1059 | }, 1060 | "node_modules/parseurl": { 1061 | "version": "1.3.3", 1062 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", 1063 | "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", 1064 | "license": "MIT", 1065 | "engines": { 1066 | "node": ">= 0.8" 1067 | } 1068 | }, 1069 | "node_modules/path-parse": { 1070 | "version": "1.0.7", 1071 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", 1072 | "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", 1073 | "license": "MIT" 1074 | }, 1075 | "node_modules/path-to-regexp": { 1076 | "version": "0.1.10", 1077 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", 1078 | "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==", 1079 | "license": "MIT" 1080 | }, 1081 | "node_modules/promise": { 1082 | "version": "7.3.1", 1083 | "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", 1084 | "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", 1085 | "license": "MIT", 1086 | "dependencies": { 1087 | "asap": "~2.0.3" 1088 | } 1089 | }, 1090 | "node_modules/proxy-addr": { 1091 | "version": "2.0.7", 1092 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", 1093 | "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", 1094 | "license": "MIT", 1095 | "dependencies": { 1096 | "forwarded": "0.2.0", 1097 | "ipaddr.js": "1.9.1" 1098 | }, 1099 | "engines": { 1100 | "node": ">= 0.10" 1101 | } 1102 | }, 1103 | "node_modules/pug": { 1104 | "version": "3.0.3", 1105 | "resolved": "https://registry.npmjs.org/pug/-/pug-3.0.3.tgz", 1106 | "integrity": "sha512-uBi6kmc9f3SZ3PXxqcHiUZLmIXgfgWooKWXcwSGwQd2Zi5Rb0bT14+8CJjJgI8AB+nndLaNgHGrcc6bPIB665g==", 1107 | "license": "MIT", 1108 | "dependencies": { 1109 | "pug-code-gen": "^3.0.3", 1110 | "pug-filters": "^4.0.0", 1111 | "pug-lexer": "^5.0.1", 1112 | "pug-linker": "^4.0.0", 1113 | "pug-load": "^3.0.0", 1114 | "pug-parser": "^6.0.0", 1115 | "pug-runtime": "^3.0.1", 1116 | "pug-strip-comments": "^2.0.0" 1117 | } 1118 | }, 1119 | "node_modules/pug-attrs": { 1120 | "version": "3.0.0", 1121 | "resolved": "https://registry.npmjs.org/pug-attrs/-/pug-attrs-3.0.0.tgz", 1122 | "integrity": "sha512-azINV9dUtzPMFQktvTXciNAfAuVh/L/JCl0vtPCwvOA21uZrC08K/UnmrL+SXGEVc1FwzjW62+xw5S/uaLj6cA==", 1123 | "license": "MIT", 1124 | "dependencies": { 1125 | "constantinople": "^4.0.1", 1126 | "js-stringify": "^1.0.2", 1127 | "pug-runtime": "^3.0.0" 1128 | } 1129 | }, 1130 | "node_modules/pug-code-gen": { 1131 | "version": "3.0.3", 1132 | "resolved": "https://registry.npmjs.org/pug-code-gen/-/pug-code-gen-3.0.3.tgz", 1133 | "integrity": "sha512-cYQg0JW0w32Ux+XTeZnBEeuWrAY7/HNE6TWnhiHGnnRYlCgyAUPoyh9KzCMa9WhcJlJ1AtQqpEYHc+vbCzA+Aw==", 1134 | "license": "MIT", 1135 | "dependencies": { 1136 | "constantinople": "^4.0.1", 1137 | "doctypes": "^1.1.0", 1138 | "js-stringify": "^1.0.2", 1139 | "pug-attrs": "^3.0.0", 1140 | "pug-error": "^2.1.0", 1141 | "pug-runtime": "^3.0.1", 1142 | "void-elements": "^3.1.0", 1143 | "with": "^7.0.0" 1144 | } 1145 | }, 1146 | "node_modules/pug-error": { 1147 | "version": "2.1.0", 1148 | "resolved": "https://registry.npmjs.org/pug-error/-/pug-error-2.1.0.tgz", 1149 | "integrity": "sha512-lv7sU9e5Jk8IeUheHata6/UThZ7RK2jnaaNztxfPYUY+VxZyk/ePVaNZ/vwmH8WqGvDz3LrNYt/+gA55NDg6Pg==", 1150 | "license": "MIT" 1151 | }, 1152 | "node_modules/pug-filters": { 1153 | "version": "4.0.0", 1154 | "resolved": "https://registry.npmjs.org/pug-filters/-/pug-filters-4.0.0.tgz", 1155 | "integrity": "sha512-yeNFtq5Yxmfz0f9z2rMXGw/8/4i1cCFecw/Q7+D0V2DdtII5UvqE12VaZ2AY7ri6o5RNXiweGH79OCq+2RQU4A==", 1156 | "license": "MIT", 1157 | "dependencies": { 1158 | "constantinople": "^4.0.1", 1159 | "jstransformer": "1.0.0", 1160 | "pug-error": "^2.0.0", 1161 | "pug-walk": "^2.0.0", 1162 | "resolve": "^1.15.1" 1163 | } 1164 | }, 1165 | "node_modules/pug-lexer": { 1166 | "version": "5.0.1", 1167 | "resolved": "https://registry.npmjs.org/pug-lexer/-/pug-lexer-5.0.1.tgz", 1168 | "integrity": "sha512-0I6C62+keXlZPZkOJeVam9aBLVP2EnbeDw3An+k0/QlqdwH6rv8284nko14Na7c0TtqtogfWXcRoFE4O4Ff20w==", 1169 | "license": "MIT", 1170 | "dependencies": { 1171 | "character-parser": "^2.2.0", 1172 | "is-expression": "^4.0.0", 1173 | "pug-error": "^2.0.0" 1174 | } 1175 | }, 1176 | "node_modules/pug-linker": { 1177 | "version": "4.0.0", 1178 | "resolved": "https://registry.npmjs.org/pug-linker/-/pug-linker-4.0.0.tgz", 1179 | "integrity": "sha512-gjD1yzp0yxbQqnzBAdlhbgoJL5qIFJw78juN1NpTLt/mfPJ5VgC4BvkoD3G23qKzJtIIXBbcCt6FioLSFLOHdw==", 1180 | "license": "MIT", 1181 | "dependencies": { 1182 | "pug-error": "^2.0.0", 1183 | "pug-walk": "^2.0.0" 1184 | } 1185 | }, 1186 | "node_modules/pug-load": { 1187 | "version": "3.0.0", 1188 | "resolved": "https://registry.npmjs.org/pug-load/-/pug-load-3.0.0.tgz", 1189 | "integrity": "sha512-OCjTEnhLWZBvS4zni/WUMjH2YSUosnsmjGBB1An7CsKQarYSWQ0GCVyd4eQPMFJqZ8w9xgs01QdiZXKVjk92EQ==", 1190 | "license": "MIT", 1191 | "dependencies": { 1192 | "object-assign": "^4.1.1", 1193 | "pug-walk": "^2.0.0" 1194 | } 1195 | }, 1196 | "node_modules/pug-parser": { 1197 | "version": "6.0.0", 1198 | "resolved": "https://registry.npmjs.org/pug-parser/-/pug-parser-6.0.0.tgz", 1199 | "integrity": "sha512-ukiYM/9cH6Cml+AOl5kETtM9NR3WulyVP2y4HOU45DyMim1IeP/OOiyEWRr6qk5I5klpsBnbuHpwKmTx6WURnw==", 1200 | "license": "MIT", 1201 | "dependencies": { 1202 | "pug-error": "^2.0.0", 1203 | "token-stream": "1.0.0" 1204 | } 1205 | }, 1206 | "node_modules/pug-runtime": { 1207 | "version": "3.0.1", 1208 | "resolved": "https://registry.npmjs.org/pug-runtime/-/pug-runtime-3.0.1.tgz", 1209 | "integrity": "sha512-L50zbvrQ35TkpHwv0G6aLSuueDRwc/97XdY8kL3tOT0FmhgG7UypU3VztfV/LATAvmUfYi4wNxSajhSAeNN+Kg==", 1210 | "license": "MIT" 1211 | }, 1212 | "node_modules/pug-strip-comments": { 1213 | "version": "2.0.0", 1214 | "resolved": "https://registry.npmjs.org/pug-strip-comments/-/pug-strip-comments-2.0.0.tgz", 1215 | "integrity": "sha512-zo8DsDpH7eTkPHCXFeAk1xZXJbyoTfdPlNR0bK7rpOMuhBYb0f5qUVCO1xlsitYd3w5FQTK7zpNVKb3rZoUrrQ==", 1216 | "license": "MIT", 1217 | "dependencies": { 1218 | "pug-error": "^2.0.0" 1219 | } 1220 | }, 1221 | "node_modules/pug-walk": { 1222 | "version": "2.0.0", 1223 | "resolved": "https://registry.npmjs.org/pug-walk/-/pug-walk-2.0.0.tgz", 1224 | "integrity": "sha512-yYELe9Q5q9IQhuvqsZNwA5hfPkMJ8u92bQLIMcsMxf/VADjNtEYptU+inlufAFYcWdHlwNfZOEnOOQrZrcyJCQ==", 1225 | "license": "MIT" 1226 | }, 1227 | "node_modules/punycode": { 1228 | "version": "2.3.1", 1229 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", 1230 | "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", 1231 | "license": "MIT", 1232 | "engines": { 1233 | "node": ">=6" 1234 | } 1235 | }, 1236 | "node_modules/qs": { 1237 | "version": "6.13.0", 1238 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", 1239 | "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", 1240 | "license": "BSD-3-Clause", 1241 | "dependencies": { 1242 | "side-channel": "^1.0.6" 1243 | }, 1244 | "engines": { 1245 | "node": ">=0.6" 1246 | }, 1247 | "funding": { 1248 | "url": "https://github.com/sponsors/ljharb" 1249 | } 1250 | }, 1251 | "node_modules/range-parser": { 1252 | "version": "1.2.1", 1253 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", 1254 | "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", 1255 | "license": "MIT", 1256 | "engines": { 1257 | "node": ">= 0.6" 1258 | } 1259 | }, 1260 | "node_modules/raw-body": { 1261 | "version": "2.5.2", 1262 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", 1263 | "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", 1264 | "license": "MIT", 1265 | "dependencies": { 1266 | "bytes": "3.1.2", 1267 | "http-errors": "2.0.0", 1268 | "iconv-lite": "0.4.24", 1269 | "unpipe": "1.0.0" 1270 | }, 1271 | "engines": { 1272 | "node": ">= 0.8" 1273 | } 1274 | }, 1275 | "node_modules/resolve": { 1276 | "version": "1.22.8", 1277 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", 1278 | "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", 1279 | "license": "MIT", 1280 | "dependencies": { 1281 | "is-core-module": "^2.13.0", 1282 | "path-parse": "^1.0.7", 1283 | "supports-preserve-symlinks-flag": "^1.0.0" 1284 | }, 1285 | "bin": { 1286 | "resolve": "bin/resolve" 1287 | }, 1288 | "funding": { 1289 | "url": "https://github.com/sponsors/ljharb" 1290 | } 1291 | }, 1292 | "node_modules/safe-buffer": { 1293 | "version": "5.2.1", 1294 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 1295 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", 1296 | "funding": [ 1297 | { 1298 | "type": "github", 1299 | "url": "https://github.com/sponsors/feross" 1300 | }, 1301 | { 1302 | "type": "patreon", 1303 | "url": "https://www.patreon.com/feross" 1304 | }, 1305 | { 1306 | "type": "consulting", 1307 | "url": "https://feross.org/support" 1308 | } 1309 | ], 1310 | "license": "MIT" 1311 | }, 1312 | "node_modules/safer-buffer": { 1313 | "version": "2.1.2", 1314 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 1315 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", 1316 | "license": "MIT" 1317 | }, 1318 | "node_modules/send": { 1319 | "version": "0.19.0", 1320 | "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", 1321 | "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", 1322 | "license": "MIT", 1323 | "dependencies": { 1324 | "debug": "2.6.9", 1325 | "depd": "2.0.0", 1326 | "destroy": "1.2.0", 1327 | "encodeurl": "~1.0.2", 1328 | "escape-html": "~1.0.3", 1329 | "etag": "~1.8.1", 1330 | "fresh": "0.5.2", 1331 | "http-errors": "2.0.0", 1332 | "mime": "1.6.0", 1333 | "ms": "2.1.3", 1334 | "on-finished": "2.4.1", 1335 | "range-parser": "~1.2.1", 1336 | "statuses": "2.0.1" 1337 | }, 1338 | "engines": { 1339 | "node": ">= 0.8.0" 1340 | } 1341 | }, 1342 | "node_modules/send/node_modules/debug": { 1343 | "version": "2.6.9", 1344 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 1345 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 1346 | "license": "MIT", 1347 | "dependencies": { 1348 | "ms": "2.0.0" 1349 | } 1350 | }, 1351 | "node_modules/send/node_modules/debug/node_modules/ms": { 1352 | "version": "2.0.0", 1353 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 1354 | "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", 1355 | "license": "MIT" 1356 | }, 1357 | "node_modules/send/node_modules/encodeurl": { 1358 | "version": "1.0.2", 1359 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", 1360 | "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", 1361 | "license": "MIT", 1362 | "engines": { 1363 | "node": ">= 0.8" 1364 | } 1365 | }, 1366 | "node_modules/serve-static": { 1367 | "version": "1.16.2", 1368 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", 1369 | "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", 1370 | "license": "MIT", 1371 | "dependencies": { 1372 | "encodeurl": "~2.0.0", 1373 | "escape-html": "~1.0.3", 1374 | "parseurl": "~1.3.3", 1375 | "send": "0.19.0" 1376 | }, 1377 | "engines": { 1378 | "node": ">= 0.8.0" 1379 | } 1380 | }, 1381 | "node_modules/set-function-length": { 1382 | "version": "1.2.2", 1383 | "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", 1384 | "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", 1385 | "license": "MIT", 1386 | "dependencies": { 1387 | "define-data-property": "^1.1.4", 1388 | "es-errors": "^1.3.0", 1389 | "function-bind": "^1.1.2", 1390 | "get-intrinsic": "^1.2.4", 1391 | "gopd": "^1.0.1", 1392 | "has-property-descriptors": "^1.0.2" 1393 | }, 1394 | "engines": { 1395 | "node": ">= 0.4" 1396 | } 1397 | }, 1398 | "node_modules/setprototypeof": { 1399 | "version": "1.2.0", 1400 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", 1401 | "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", 1402 | "license": "ISC" 1403 | }, 1404 | "node_modules/side-channel": { 1405 | "version": "1.0.6", 1406 | "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", 1407 | "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", 1408 | "license": "MIT", 1409 | "dependencies": { 1410 | "call-bind": "^1.0.7", 1411 | "es-errors": "^1.3.0", 1412 | "get-intrinsic": "^1.2.4", 1413 | "object-inspect": "^1.13.1" 1414 | }, 1415 | "engines": { 1416 | "node": ">= 0.4" 1417 | }, 1418 | "funding": { 1419 | "url": "https://github.com/sponsors/ljharb" 1420 | } 1421 | }, 1422 | "node_modules/sift": { 1423 | "version": "17.1.3", 1424 | "resolved": "https://registry.npmjs.org/sift/-/sift-17.1.3.tgz", 1425 | "integrity": "sha512-Rtlj66/b0ICeFzYTuNvX/EF1igRbbnGSvEyT79McoZa/DeGhMyC5pWKOEsZKnpkqtSeovd5FL/bjHWC3CIIvCQ==", 1426 | "license": "MIT" 1427 | }, 1428 | "node_modules/sparse-bitfield": { 1429 | "version": "3.0.3", 1430 | "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", 1431 | "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", 1432 | "license": "MIT", 1433 | "dependencies": { 1434 | "memory-pager": "^1.0.2" 1435 | } 1436 | }, 1437 | "node_modules/statuses": { 1438 | "version": "2.0.1", 1439 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", 1440 | "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", 1441 | "license": "MIT", 1442 | "engines": { 1443 | "node": ">= 0.8" 1444 | } 1445 | }, 1446 | "node_modules/supports-preserve-symlinks-flag": { 1447 | "version": "1.0.0", 1448 | "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", 1449 | "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", 1450 | "license": "MIT", 1451 | "engines": { 1452 | "node": ">= 0.4" 1453 | }, 1454 | "funding": { 1455 | "url": "https://github.com/sponsors/ljharb" 1456 | } 1457 | }, 1458 | "node_modules/to-fast-properties": { 1459 | "version": "2.0.0", 1460 | "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", 1461 | "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", 1462 | "license": "MIT", 1463 | "engines": { 1464 | "node": ">=4" 1465 | } 1466 | }, 1467 | "node_modules/toidentifier": { 1468 | "version": "1.0.1", 1469 | "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", 1470 | "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", 1471 | "license": "MIT", 1472 | "engines": { 1473 | "node": ">=0.6" 1474 | } 1475 | }, 1476 | "node_modules/token-stream": { 1477 | "version": "1.0.0", 1478 | "resolved": "https://registry.npmjs.org/token-stream/-/token-stream-1.0.0.tgz", 1479 | "integrity": "sha512-VSsyNPPW74RpHwR8Fc21uubwHY7wMDeJLys2IX5zJNih+OnAnaifKHo+1LHT7DAdloQ7apeaaWg8l7qnf/TnEg==", 1480 | "license": "MIT" 1481 | }, 1482 | "node_modules/tr46": { 1483 | "version": "4.1.1", 1484 | "resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz", 1485 | "integrity": "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==", 1486 | "license": "MIT", 1487 | "dependencies": { 1488 | "punycode": "^2.3.0" 1489 | }, 1490 | "engines": { 1491 | "node": ">=14" 1492 | } 1493 | }, 1494 | "node_modules/type-is": { 1495 | "version": "1.6.18", 1496 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", 1497 | "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", 1498 | "license": "MIT", 1499 | "dependencies": { 1500 | "media-typer": "0.3.0", 1501 | "mime-types": "~2.1.24" 1502 | }, 1503 | "engines": { 1504 | "node": ">= 0.6" 1505 | } 1506 | }, 1507 | "node_modules/unpipe": { 1508 | "version": "1.0.0", 1509 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", 1510 | "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", 1511 | "license": "MIT", 1512 | "engines": { 1513 | "node": ">= 0.8" 1514 | } 1515 | }, 1516 | "node_modules/utils-merge": { 1517 | "version": "1.0.1", 1518 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", 1519 | "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", 1520 | "license": "MIT", 1521 | "engines": { 1522 | "node": ">= 0.4.0" 1523 | } 1524 | }, 1525 | "node_modules/vary": { 1526 | "version": "1.1.2", 1527 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", 1528 | "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", 1529 | "license": "MIT", 1530 | "engines": { 1531 | "node": ">= 0.8" 1532 | } 1533 | }, 1534 | "node_modules/void-elements": { 1535 | "version": "3.1.0", 1536 | "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", 1537 | "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==", 1538 | "license": "MIT", 1539 | "engines": { 1540 | "node": ">=0.10.0" 1541 | } 1542 | }, 1543 | "node_modules/webidl-conversions": { 1544 | "version": "7.0.0", 1545 | "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", 1546 | "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", 1547 | "license": "BSD-2-Clause", 1548 | "engines": { 1549 | "node": ">=12" 1550 | } 1551 | }, 1552 | "node_modules/whatwg-url": { 1553 | "version": "13.0.0", 1554 | "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-13.0.0.tgz", 1555 | "integrity": "sha512-9WWbymnqj57+XEuqADHrCJ2eSXzn8WXIW/YSGaZtb2WKAInQ6CHfaUUcTyyver0p8BDg5StLQq8h1vtZuwmOig==", 1556 | "license": "MIT", 1557 | "dependencies": { 1558 | "tr46": "^4.1.1", 1559 | "webidl-conversions": "^7.0.0" 1560 | }, 1561 | "engines": { 1562 | "node": ">=16" 1563 | } 1564 | }, 1565 | "node_modules/with": { 1566 | "version": "7.0.2", 1567 | "resolved": "https://registry.npmjs.org/with/-/with-7.0.2.tgz", 1568 | "integrity": "sha512-RNGKj82nUPg3g5ygxkQl0R937xLyho1J24ItRCBTr/m1YnZkzJy1hUiHUJrc/VlsDQzsCnInEGSg3bci0Lmd4w==", 1569 | "license": "MIT", 1570 | "dependencies": { 1571 | "@babel/parser": "^7.9.6", 1572 | "@babel/types": "^7.9.6", 1573 | "assert-never": "^1.2.1", 1574 | "babel-walk": "3.0.0-canary-5" 1575 | }, 1576 | "engines": { 1577 | "node": ">= 10.0.0" 1578 | } 1579 | } 1580 | } 1581 | } 1582 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "todolist", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "start": "node ./bin/www" 7 | }, 8 | "dependencies": { 9 | "bootstrap": "^5.3.3", 10 | "cookie-parser": "~1.4.6", 11 | "date-fns": "^4.1.0", 12 | "debug": "~4.3.7", 13 | "express": "^4.21.0", 14 | "http-errors": "~2.0.0", 15 | "mongoose": "^8.6.3", 16 | "morgan": "~1.10.0", 17 | "pug": "^3.0.3" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /public/images/Azure-A-48px-product.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /public/stylesheets/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding: 50px; 3 | font: 14px "Lucida Grande", Helvetica, Arial, sans-serif; 4 | } 5 | 6 | a { 7 | color: #00B7FF; 8 | } 9 | 10 | .text-azure-blue { 11 | color: #0078D4 12 | } 13 | 14 | .bg-azure-light-gray { 15 | background-color: #EBEBEB; 16 | } -------------------------------------------------------------------------------- /routes/index.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var Task = require('../models/task'); 3 | 4 | var router = express.Router(); 5 | 6 | /* GET home page. */ 7 | router.get('/', function(req, res, next) { 8 | Task.find() 9 | .then((tasks) => { 10 | const currentTasks = tasks.filter(task => !task.completed); 11 | const completedTasks = tasks.filter(task => task.completed === true); 12 | 13 | console.log(`Total tasks: ${tasks.length} Current tasks: ${currentTasks.length} Completed tasks: ${completedTasks.length}`) 14 | res.render('index', { currentTasks: currentTasks, completedTasks: completedTasks }); 15 | }) 16 | .catch((err) => { 17 | console.log(err); 18 | res.send('Sorry! Something went wrong.'); 19 | }); 20 | }); 21 | 22 | 23 | router.post('/addTask', function(req, res, next) { 24 | const taskName = req.body.taskName; 25 | const createDate = Date.now(); 26 | 27 | var task = new Task({ 28 | taskName: taskName, 29 | createDate: createDate 30 | }); 31 | console.log(`Adding a new task ${taskName} - createDate ${createDate}`) 32 | 33 | task.save() 34 | .then(() => { 35 | console.log(`Added new task ${taskName} - createDate ${createDate}`) 36 | res.redirect('/'); }) 37 | .catch((err) => { 38 | console.log(err); 39 | res.send('Sorry! Something went wrong.'); 40 | }); 41 | }); 42 | 43 | router.post('/completeTask', function(req, res, next) { 44 | console.log("I am in the PUT method") 45 | const taskId = req.body._id; 46 | const completedDate = Date.now(); 47 | 48 | Task.findByIdAndUpdate(taskId, { completed: true, completedDate: Date.now()}) 49 | .then(() => { 50 | console.log(`Completed task ${taskId}`) 51 | res.redirect('/'); } ) 52 | .catch((err) => { 53 | console.log(err); 54 | res.send('Sorry! Something went wrong.'); 55 | }); 56 | }); 57 | 58 | 59 | router.post('/deleteTask', function(req, res, next) { 60 | const taskId = req.body._id; 61 | const completedDate = Date.now(); 62 | Task.findByIdAndDelete(taskId) 63 | .then(() => { 64 | console.log(`Deleted task $(taskId)`) 65 | res.redirect('/'); } ) 66 | .catch((err) => { 67 | console.log(err); 68 | res.send('Sorry! Something went wrong.'); 69 | }); 70 | }); 71 | 72 | 73 | module.exports = router; 74 | -------------------------------------------------------------------------------- /routes/users.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var router = express.Router(); 3 | 4 | /* GET users listing. */ 5 | router.get('/', function(req, res, next) { 6 | res.send('respond with a resource'); 7 | }); 8 | 9 | module.exports = router; 10 | -------------------------------------------------------------------------------- /views/error.pug: -------------------------------------------------------------------------------- 1 | extends layout 2 | 3 | block content 4 | h1= message 5 | h2= error.status 6 | pre #{error.stack} 7 | -------------------------------------------------------------------------------- /views/index.pug: -------------------------------------------------------------------------------- 1 | extends layout 2 | 3 | block content 4 | 5 | form(action='./addTask' method='POST' class='form-registration') 6 | div(class='row my-3') 7 | div(class='col-md-2 align-bottom') 8 | label(for="taskName" class='fs-5') New task 9 | div(class='col-md-8') 10 | input(class="form-control form-control-sm" type="text" name='taskName', placeholder="Enter new task here" ) 11 | div(class='col-md-2 text-end') 12 | button(class='btn btn-success btn-sm' type='submit') Add task 13 | 14 | 15 | h5(class='my-2') Current tasks 16 | 17 | div(class='row mb-3 border-bottom border-3') 18 | div(class='col-md-6 fw-bold') Task 19 | div(class='col-md-2 fw-bold') Created 20 | div(class='col-md-4 fw-bold') Action 21 | 22 | each task in currentTasks 23 | div(class='row mb-2') 24 | div(class='col-sm-6') #{task.taskName} 25 | div(class='col-sm-2') #{format(task.createDate, "yyyy-MM-dd")} 26 | div(class='col-sm-2') 27 | form(action='./completeTask' method='POST' class='form-registration') 28 | input(type='hidden' name='_id' value=`${task._id}`) 29 | button(class='btn btn-primary btn-sm mx-1' type='submit') Complete 30 | div(class='col-sm-2') 31 | form(action='./deleteTask' method='POST' class='form-registration') 32 | input(type='hidden' name='_id' value=`${task._id}`) 33 | button(class='btn btn-danger btn-sm mx-1') Delete 34 | 35 | h5(class='my-2') Completed tasks 36 | div(class='row mb-3 border-bottom border-3') 37 | div(class='col-sm-8 fw-bold') Task 38 | div(class='col-sm-2 fw-bold') Created 39 | div(class='col-sm-2 fw-bold') Completed 40 | each task in completedTasks 41 | div(class='row mb-3') 42 | div(class='col-sm-8') #{task.taskName} 43 | div(class='col-sm-2') #{format(task.createDate, "yyyy-MM-dd")} 44 | div(class='col-sm-2') #{format(task.completedDate, "yyyy-MM-dd")} 45 | -------------------------------------------------------------------------------- /views/layout.pug: -------------------------------------------------------------------------------- 1 | doctype html 2 | html 3 | head 4 | title= title 5 | link(rel='stylesheet', href='/css/bootstrap.css') 6 | link(rel='stylesheet', href='/stylesheets/style.css') 7 | body(class='p-2') 8 | 9 | main(class='container' style='max-width: 720px') 10 | div(class='d-flex align-items-center p-3 my-1 bg-azure-light-gray rounded shadow-sm') 11 | img(class='me-3', src='/images/Azure-A-48px-product.svg', alt='', width='48', height='48') 12 | div(class='1h-1') 13 | h1(class='h3 mb-0 text-azure-blue lh-1') Azure Todo List 14 | small(class='text-black') ExpressJS/MongoDB Sample Application 15 | 16 | 17 | block content 18 | script(src='/js/bootstrap.min.js') 19 | 20 | 21 | --------------------------------------------------------------------------------