Skip to content

Commit 5bd8447

Browse files
Merge pull request #112 from oracle/ORDSConcertAppTemplate
feat: add the ords-concert-app template
2 parents f4cd0e2 + 3c04875 commit 5bd8447

File tree

259 files changed

+25409
-99
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

259 files changed

+25409
-99
lines changed

README.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -49,14 +49,15 @@ Next, you will be able to open the project in your favorite IDE or Code Editor a
4949

5050
## Templates
5151

52-
The package offers the following templates, which connect to the database using the [oracledb database driver](https://github.com/oracle/node-oracledb):
52+
The package offers the following templates, some of them connect to the database using the [oracledb database driver](https://github.com/oracle/node-oracledb) and other use [Oracle REST Data Services](https://www.oracle.com/database/technologies/appdev/rest.html) endpoints:
5353

5454
- `node-vanilla`: A starter template that uses Node.js, vanilla JavaScript, HTML and CSS. It is built by [vite](https://vitejs.dev/).
5555
- `node-jet`: A starter template that uses Node.js and [Oracle JET](https://www.oracle.com/webfolder/technetwork/jet/index.html). It is built using the [ojet-cli](https://www.npmjs.com/package/@oracle/ojet-cli).
5656
- `node-react`: A starter template that uses Node.js and [React](https://react.dev/). It is built by [vite](https://vitejs.dev/).
5757
- `node-vue`: A starter template that uses Node.js and [Vue.js](https://vuejs.org/). It is built by [vite](https://vitejs.dev/).
5858
- `node-angular`: A starter template that uses Node.js and [Angular](https://angular.dev/). It is built by [Angular CLI](https://github.com/angular/angular-cli). (New in `v1.2.0`)
5959
- `node-react-todo`: A simple task manager template that uses Node.js and [React](https://react.dev/). It demonstrates the use of the database for Create, Read, Update and Delete (CRUD) operations. It is built by [vite](https://vitejs.dev/).
60+
- `ords-remix-jwt-sample`: A full stack Concert Application made with [Remix](https://remix.run/) that showcases the [Oracle REST Data Services](https://www.oracle.com/database/technologies/appdev/rest.html) functionalities. Some extra configuration is required, learn more about it in the `ords-remix-jwt-sample` [Getting Started Guide](/templates/ords-remix-jwt-sample/README.md#getting-started).
6061

6162
Each of the templates include documentation for you to get started with them, as well as NPM scripts for you to use right after generating the application.
6263

@@ -89,6 +90,7 @@ DB_USER=<my-username>
8990
DB_PASSWORD=<my-password>
9091
...
9192
```
93+
Note: For the `ords-remix-jwt-sample` is expected that you will configurate your own `.env` file folowing the `ords-remix-jwt-sample` [Getting Started Guide](/templates/ords-remix-jwt-sample/README.md#getting-started).
9294

9395
## Examples
9496

generators/index.ts

+85-56
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ export default class extends Generator {
9292
const { protocol, hostname, port, serviceName } = retrieveConnectionStringDetailsFromORAFile( path.join( walletPath, 'tnsnames.ora' ) );
9393
this.options.connectionString = generateConnectionString( protocol, hostname, port, serviceName );
9494
}
95-
95+
// Copy files that are common to all of the templates.
9696
this.fs.copyTpl(
9797
this.templatePath( this.options.templateChoice ),
9898
this.destinationPath(),
@@ -101,9 +101,9 @@ export default class extends Generator {
101101
}
102102
);
103103
this.fs.copy(
104-
this.templatePath( `${this.options.templateChoice}/.gitignore.template` ),
105-
this.destinationPath( '.gitignore' ),
106-
);
104+
this.templatePath(`${ path.dirname( this.options.templateChoice ) }/app/.github`),
105+
this.destinationPath('.github')
106+
)
107107
// This copy of `eslintrc.cjs` should be removed once all templates support eslint v9
108108
this.fs.copy(
109109
this.templatePath( `${this.options.templateChoice}/.eslintrc.cjs` ),
@@ -119,63 +119,92 @@ export default class extends Generator {
119119
ignoreNoMatch: true
120120
}
121121
);
122-
this.fs.copy(
123-
this.templatePath(`${ path.dirname( this.options.templateChoice ) }/app/.github`),
124-
this.destinationPath('.github')
125-
)
126-
this.fs.copyTpl(
127-
this.templatePath( `${ path.dirname( this.options.templateChoice ) }/app/${ path.basename( this.options.templateChoice ) == 'node-jet' ? 'index-proxied' : 'index' }.cjs` ),
128-
this.destinationPath( 'server/index.cjs' ),
129-
this.options
130-
);
131-
this.fs.copy(
132-
this.templatePath( `${ path.dirname( this.options.templateChoice ) }/app/routes/${this.options.apiConfiguration}.cjs` ),
133-
this.destinationPath( `server/routes/${this.options.apiConfiguration}.cjs` ),
134-
);
135-
this.fs.copy(
136-
this.templatePath( `${ path.dirname( this.options.templateChoice ) }/app/utils/db/**/*` ),
137-
this.destinationPath( 'server/utils/db/' ),
138-
);
139-
this.fs.copy(
140-
this.templatePath( `${ path.dirname( this.options.templateChoice ) }/app/utils/rest-services/${this.options.apiConfiguration}.cjs` ),
141-
this.destinationPath( `server/utils/rest-services/${this.options.apiConfiguration}.cjs` ),
142-
);
143-
this.fs.copyTpl(
144-
this.templatePath( `${ path.dirname( this.options.templateChoice ) }/app/.env.example` ),
145-
this.destinationPath( '.env.example' ),
146-
{
147-
appName: '',
148-
connectionPassword: '',
149-
connectionString: '',
150-
connectionUsername: '',
151-
walletPassword: '',
152-
walletPath: '',
153-
}
154-
);
155-
this.fs.copyTpl(
156-
this.templatePath( `${ path.dirname( this.options.templateChoice ) }/app/.env.example.${ ( 'walletPath' in this.options ) ? 'cloud-wallet' : 'basic' }` ),
157-
this.destinationPath( '.env' ),
158-
this.options
159-
);
160-
this.fs.copy(
161-
this.templatePath( `${ path.dirname( this.options.templateChoice ) }/app/CONTRIBUTING.md` ),
162-
this.destinationPath( 'CONTRIBUTING.md' ),
163-
);
164-
165-
const readme_data = this.fs.read(this.templatePath(`${path.dirname(this.options.templateChoice)}/app/README.md`));
166-
167-
if(this.fs.exists((this.destinationPath('README.md')))){
168-
this.fs.append(this.destinationPath('README.md'), readme_data);
169-
}
170-
else{
122+
/**
123+
* The ORDS Concert App template provides:
124+
* A .gitignore file
125+
* A markdown lint configuration file (.markdownlint.json)
126+
* A .env.example file
127+
* Additionally, the sample app expects that the user configures their development
128+
* environment on their own to provide a better understanding of ords and how the
129+
* app is structured.
130+
* The rest of the files, like utils/* and db/* are also not needed since the sample
131+
* app contains their own mechanisms to talk with the db.
132+
*/
133+
if( this.options.templateChoice.includes('ords-remix-jwt-sample' )){
134+
this.fs.copy(
135+
this.templatePath( `${this.options.templateChoice}/.gitignore` ),
136+
this.destinationPath( '.gitignore' ),
137+
);
138+
this.fs.copy(
139+
this.templatePath( `${this.options.templateChoice}/.markdownlint.jsonc` ),
140+
this.destinationPath( '.markdownlint.jsonc' ),
141+
);
171142
this.fs.copy(
172-
this.templatePath( `${ path.dirname( this.options.templateChoice ) }/app/README.md` ),
173-
this.destinationPath( 'README.md' ),
143+
this.templatePath( `${this.options.templateChoice}/.env.example` ),
144+
this.destinationPath( '.env.example' ),
174145
);
146+
} else {
147+
this.fs.copy(
148+
this.templatePath( `${this.options.templateChoice}/.gitignore.template` ),
149+
this.destinationPath( '.gitignore' ),
150+
);
151+
152+
this.fs.copyTpl(
153+
this.templatePath( `${ path.dirname( this.options.templateChoice ) }/app/${ path.basename( this.options.templateChoice ) == 'node-jet' ? 'index-proxied' : 'index' }.cjs` ),
154+
this.destinationPath( 'server/index.cjs' ),
155+
this.options
156+
);
157+
this.fs.copy(
158+
this.templatePath( `${ path.dirname( this.options.templateChoice ) }/app/routes/${this.options.apiConfiguration}.cjs` ),
159+
this.destinationPath( `server/routes/${this.options.apiConfiguration}.cjs` ),
160+
);
161+
this.fs.copy(
162+
this.templatePath( `${ path.dirname( this.options.templateChoice ) }/app/utils/db/**/*` ),
163+
this.destinationPath( 'server/utils/db/' ),
164+
);
165+
this.fs.copy(
166+
this.templatePath( `${ path.dirname( this.options.templateChoice ) }/app/utils/rest-services/${this.options.apiConfiguration}.cjs` ),
167+
this.destinationPath( `server/utils/rest-services/${this.options.apiConfiguration}.cjs` ),
168+
);
169+
this.fs.copyTpl(
170+
this.templatePath( `${ path.dirname( this.options.templateChoice ) }/app/.env.example` ),
171+
this.destinationPath( '.env.example' ),
172+
{
173+
appName: '',
174+
connectionPassword: '',
175+
connectionString: '',
176+
connectionUsername: '',
177+
walletPassword: '',
178+
walletPath: '',
179+
}
180+
);
181+
this.fs.copyTpl(
182+
this.templatePath( `${ path.dirname( this.options.templateChoice ) }/app/.env.example.${ ( 'walletPath' in this.options ) ? 'cloud-wallet' : 'basic' }` ),
183+
this.destinationPath( '.env' ),
184+
this.options
185+
);
186+
this.fs.copy(
187+
this.templatePath( `${ path.dirname( this.options.templateChoice ) }/app/CONTRIBUTING.md` ),
188+
this.destinationPath( 'CONTRIBUTING.md' ),
189+
);
190+
191+
const readme_data = this.fs.read(this.templatePath(`${path.dirname(this.options.templateChoice)}/app/README.md`));
192+
193+
if(this.fs.exists((this.destinationPath('README.md')))){
194+
this.fs.append(this.destinationPath('README.md'), readme_data);
195+
}
196+
else{
197+
this.fs.copy(
198+
this.templatePath( `${ path.dirname( this.options.templateChoice ) }/app/README.md` ),
199+
this.destinationPath( 'README.md' ),
200+
);
201+
}
175202
}
176203
}
177204

178205
end() {
179-
this.log( 'Application generated successfuly. Run the following command: \n\ncd ' + path.join( process.cwd(), this.options.appName ) + '\n');
206+
this.log( 'Application generated successfully. Run the following command: \n\ncd ' + path.join( process.cwd(), this.options.appName ) + '\n');
207+
if(!this.options.templateChoice.includes('ords-remix-jwt-sample')){}
208+
this.log('Please check out the README file to learn how to configurate the ORDS Concert App')
180209
}
181210
}

package-lock.json

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@oracle/create-database-app",
3-
"version": "1.2.1",
3+
"version": "1.3.0",
44
"description": "Create an Oracle Database Application from a Template",
55
"author": "Oracle Corporation",
66
"keywords": [

src/index.ts

+46-39
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ export default class Generate extends Command {
207207
'template': Flags.string({
208208
char: 't',
209209
description: 'Template to use',
210-
options: ['node-vanilla', 'node-react', 'node-vue', 'node-react-todo', 'node-jet', 'node-angular'],
210+
options: ['node-vanilla', 'node-react', 'node-vue', 'node-react-todo', 'node-jet', 'node-angular', 'ords-remix-jwt-sample'],
211211
multiple: false
212212
}),
213213

@@ -368,13 +368,24 @@ export default class Generate extends Command {
368368
value: 'node-react-todo',
369369
description: 'This creates a simple Todo app made with ExpressJS as the backend, React as the frontend, and an Oracle Database connection that will be created from the details you provide later...',
370370
},
371+
{
372+
name: 'ords-remix-jwt-sample',
373+
value: 'ords-remix-jwt-sample',
374+
description: 'This creates a fullstack Concert Application made with Remix that leverages the Oracle REST Data Services functionalities. You will need to configurate the application yourself following the getting started guide.',
375+
},
371376
],
372377
default: 'node-vanilla'
373378
},
374379
) : template;
380+
381+
// This represents the config object that will hold all the information that the user has inputted and selected.
382+
let configObject = {
383+
appName,
384+
templateChoice: path.resolve( path.join( __dirname, '..', '..', 'templates', templateChoice ) ),
385+
};
375386

376387
// Ask the user for the database connection type (Either basic connection or a connection using a cloud wallet).
377-
const databaseConnectionType = connectionType === '' ? await select(
388+
const databaseConnectionType = connectionType === '' && templateChoice !== 'ords-remix-jwt-sample' ? await select(
378389
{
379390
message: 'Which database connection type would you like to choose?',
380391
choices: [
@@ -391,9 +402,6 @@ export default class Generate extends Command {
391402
}
392403
) : connectionType;
393404

394-
// This represents the config object that will hold all the information that the user has inputted and selected.
395-
let configObject;
396-
397405
// If the user has chosen the basic connection type, then we ask for the protocol, hostname, port and service name / SID.
398406
if ( databaseConnectionType === 'basic' ) {
399407

@@ -458,13 +466,12 @@ export default class Generate extends Command {
458466
}
459467
) : databaseServiceName;
460468
}
469+
461470
// This will be config object for the basic connection type.
462-
configObject = {
463-
appName,
464-
templateChoice: path.resolve( path.join( __dirname, '..', '..', 'templates', templateChoice ) ),
471+
Object.assign(configObject, {
465472
connectionString: generateConnectionString( protocol, hostname, port, serviceValue )
466-
};
467-
} else {
473+
});
474+
} else if( databaseConnectionType === 'walletPath' ) {
468475
let walletPath = '';
469476

470477
if(walletPathValidationResult === true){
@@ -493,38 +500,38 @@ export default class Generate extends Command {
493500

494501

495502
// This is the config object that represents the wallet connection type.
496-
configObject = {
497-
appName,
498-
templateChoice: path.resolve( path.join( __dirname, '..', '..', 'templates', templateChoice ) ),
499-
walletPath,
500-
walletPassword,
501-
};
503+
Object.assign(configObject, {
504+
walletPath: walletPath,
505+
walletPassword: walletPassword
506+
});
502507
}
503508

504-
// Ask the user for the database connection username.
505-
Object.assign( configObject, {
506-
connectionUsername: databaseUsername === '' ? await input(
507-
{
508-
message: 'What\'s your database username?',
509-
validate ( input ) {
510-
return input.trim().length === 0 ? 'This field cannot be empty!' : true;
511-
}
512-
},
513-
) : databaseUsername
514-
} );
509+
if(templateChoice !== 'ords-remix-jwt-sample'){
510+
// Ask the user for the database connection username.
511+
Object.assign( configObject, {
512+
connectionUsername: databaseUsername === '' ? await input(
513+
{
514+
message: 'What\'s your database username?',
515+
validate ( input ) {
516+
return input.trim().length === 0 ? 'This field cannot be empty!' : true;
517+
}
518+
},
519+
) : databaseUsername
520+
} );
515521

516-
// Ask the user for the database connection password.
517-
Object.assign( configObject, {
518-
connectionPassword: await password(
519-
{
520-
mask: true,
521-
message: 'What\'s your database password?',
522-
validate ( input ) {
523-
return input.trim().length === 0 ? 'This field cannot be empty!' : true;
524-
}
525-
},
526-
)
527-
} );
522+
// Ask the user for the database connection password.
523+
Object.assign( configObject, {
524+
connectionPassword: await password(
525+
{
526+
mask: true,
527+
message: 'What\'s your database password?',
528+
validate ( input ) {
529+
return input.trim().length === 0 ? 'This field cannot be empty!' : true;
530+
}
531+
},
532+
)
533+
} );
534+
}
528535

529536
generateDatabaseApp( configObject );
530537
// TODO: This is the object that holds the application name, template choice, connection details depending on the chosen connection type.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Copyright (c) 2024, Oracle and/or its affiliates.
2+
# All rights reserved
3+
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
4+
5+
# We refer to some variables as Autonomous Database specific
6+
# but you can use whichever ORDS URL you want/have as well as the user,
7+
# as long as this user is capable of creating and REST Enabling other schemas.
8+
ADB_ORDS_URL=https://example.com:8080/ords/
9+
ADB_ADMIN_USER=username
10+
ADB_ADMIN_PASSWORD=
11+
12+
# The name of the schema that will be created to host all of the
13+
# ORDS Concert App database objects.
14+
SCHEMA_NAME=ORDS_CONCERT_APP
15+
SCHEMA_PASSWORD=
16+
17+
# Your Auth0 tenant JWT credentials, used by ORDS to validate request to protected endpoints.
18+
JWT_ISSUER=https://my-domain.auth0.com/
19+
JWT_VERIFICATION_KEY=https://my-domain.auth0.com/oauth/token/.well-known/jwks.json
20+
JWT_AUDIENCE=https://concert.sample.app
21+
22+
# Auth0 Authentication app configuration parameters specific of the sample app.
23+
AUTH0_RETURN_TO_URL=http://localhost:3000
24+
AUTH0_CALLBACK_URL=http://localhost:3000/callback
25+
AUTH0_CLIENT_ID=auth0_client_id
26+
AUTH0_CLIENT_SECRET=auth0_client_secret
27+
AUTH0_DOMAIN=my-domain.auth0.com
28+
AUTH0_LOGOUT_URL=https://my-domain.auth0.com/v2/logout

0 commit comments

Comments
 (0)