├── .env.sample
├── .github
├── dependabot.yml
└── workflows
│ ├── ci.yml
│ ├── release.yml
│ └── weekly.yml
├── .gitignore
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── Earthfile
├── LICENSE
├── README.md
├── docker-compose.yml
├── fixtures
├── api_authentication_template
│ └── expected
│ │ ├── spec
│ │ └── requests
│ │ │ └── api
│ │ │ ├── me
│ │ │ └── show_spec.cr
│ │ │ ├── sign_ins
│ │ │ └── create_spec.cr
│ │ │ └── sign_ups
│ │ │ └── create_spec.cr
│ │ └── src
│ │ ├── actions
│ │ ├── api
│ │ │ ├── me
│ │ │ │ └── show.cr
│ │ │ ├── sign_ins
│ │ │ │ └── create.cr
│ │ │ └── sign_ups
│ │ │ │ └── create.cr
│ │ └── mixins
│ │ │ └── api
│ │ │ └── auth
│ │ │ ├── helpers.cr
│ │ │ ├── require_auth_token.cr
│ │ │ └── skip_require_auth_token.cr
│ │ ├── models
│ │ └── user_token.cr
│ │ └── serializers
│ │ └── user_serializer.cr
├── app_sec_tester_template
│ └── expected
│ │ └── spec
│ │ ├── flows
│ │ └── security_spec.cr
│ │ └── setup
│ │ └── sec_tester.cr
├── app_sec_tester_template__browser
│ └── expected
│ │ └── spec
│ │ ├── flows
│ │ └── security_spec.cr
│ │ └── setup
│ │ └── sec_tester.cr
├── app_sec_tester_template__generate_auth
│ └── expected
│ │ └── spec
│ │ ├── flows
│ │ └── security_spec.cr
│ │ └── setup
│ │ └── sec_tester.cr
├── app_sec_tester_template__no_browser_auth
│ └── expected
│ │ └── spec
│ │ ├── flows
│ │ └── security_spec.cr
│ │ └── setup
│ │ └── sec_tester.cr
├── base_authentication_src_template
│ └── expected
│ │ ├── config
│ │ └── authentic.cr
│ │ ├── db
│ │ └── migrations
│ │ │ ├── .keep
│ │ │ └── 00000000000001_create_users.cr
│ │ ├── spec
│ │ └── support
│ │ │ ├── .keep
│ │ │ └── factories
│ │ │ └── user_factory.cr
│ │ └── src
│ │ ├── models
│ │ └── user.cr
│ │ ├── operations
│ │ ├── .keep
│ │ ├── mixins
│ │ │ ├── .keep
│ │ │ ├── password_validations.cr
│ │ │ └── user_from_email.cr
│ │ ├── request_password_reset.cr
│ │ ├── reset_password.cr
│ │ ├── sign_in_user.cr
│ │ └── sign_up_user.cr
│ │ └── queries
│ │ └── user_query.cr
├── browser_authentication_src_template
│ └── expected
│ │ ├── spec
│ │ ├── flows
│ │ │ ├── authentication_spec.cr
│ │ │ └── reset_password_spec.cr
│ │ └── support
│ │ │ ├── .keep
│ │ │ └── flows
│ │ │ ├── authentication_flow.cr
│ │ │ └── reset_password_flow.cr
│ │ └── src
│ │ ├── actions
│ │ ├── me
│ │ │ └── show.cr
│ │ ├── mixins
│ │ │ ├── .keep
│ │ │ └── auth
│ │ │ │ ├── allow_guests.cr
│ │ │ │ ├── password_resets
│ │ │ │ ├── base.cr
│ │ │ │ ├── find_user.cr
│ │ │ │ ├── require_token.cr
│ │ │ │ └── token_from_session.cr
│ │ │ │ ├── redirect_signed_in_users.cr
│ │ │ │ ├── require_sign_in.cr
│ │ │ │ └── test_backdoor.cr
│ │ ├── password_reset_requests
│ │ │ ├── create.cr
│ │ │ └── new.cr
│ │ ├── password_resets
│ │ │ ├── create.cr
│ │ │ ├── edit.cr
│ │ │ └── new.cr
│ │ ├── sign_ins
│ │ │ ├── create.cr
│ │ │ ├── delete.cr
│ │ │ └── new.cr
│ │ └── sign_ups
│ │ │ ├── create.cr
│ │ │ └── new.cr
│ │ ├── emails
│ │ ├── password_reset_request_email.cr
│ │ └── templates
│ │ │ └── password_reset_request_email
│ │ │ ├── html.ecr
│ │ │ └── text.ecr
│ │ └── pages
│ │ ├── auth_layout.cr
│ │ ├── main_layout.cr
│ │ ├── me
│ │ └── show_page.cr
│ │ ├── password_reset_requests
│ │ └── new_page.cr
│ │ ├── password_resets
│ │ └── new_page.cr
│ │ ├── sign_ins
│ │ └── new_page.cr
│ │ └── sign_ups
│ │ └── new_page.cr
├── browser_src_template
│ └── expected
│ │ ├── bs-config.js
│ │ ├── config
│ │ └── html_page.cr
│ │ ├── db
│ │ └── migrations
│ │ │ └── .keep
│ │ ├── package.json
│ │ ├── public
│ │ ├── assets
│ │ │ └── images
│ │ │ │ └── .keep
│ │ ├── favicon.ico
│ │ ├── mix-manifest.json
│ │ └── robots.txt
│ │ ├── spec
│ │ ├── flows
│ │ │ └── .keep
│ │ ├── setup
│ │ │ ├── .keep
│ │ │ └── configure_lucky_flow.cr
│ │ └── support
│ │ │ ├── .keep
│ │ │ ├── factories
│ │ │ └── .keep
│ │ │ └── flows
│ │ │ └── base_flow.cr
│ │ ├── src
│ │ ├── actions
│ │ │ └── browser_action.cr
│ │ ├── components
│ │ │ ├── .keep
│ │ │ ├── base_component.cr
│ │ │ └── shared
│ │ │ │ ├── field.cr
│ │ │ │ ├── field_errors.cr
│ │ │ │ ├── flash_messages.cr
│ │ │ │ └── layout_head.cr
│ │ ├── css
│ │ │ └── app.scss
│ │ ├── emails
│ │ │ └── .keep
│ │ ├── js
│ │ │ └── app.js
│ │ ├── models
│ │ │ └── mixins
│ │ │ │ └── .keep
│ │ ├── operations
│ │ │ ├── .keep
│ │ │ └── mixins
│ │ │ │ └── .keep
│ │ └── pages
│ │ │ ├── errors
│ │ │ └── show_page.cr
│ │ │ └── main_layout.cr
│ │ └── webpack.mix.js
├── browser_src_template__generate_auth
│ └── expected
│ │ ├── bs-config.js
│ │ ├── config
│ │ └── html_page.cr
│ │ ├── db
│ │ └── migrations
│ │ │ └── .keep
│ │ ├── package.json
│ │ ├── public
│ │ ├── assets
│ │ │ └── images
│ │ │ │ └── .keep
│ │ ├── favicon.ico
│ │ ├── mix-manifest.json
│ │ └── robots.txt
│ │ ├── spec
│ │ ├── flows
│ │ │ └── .keep
│ │ ├── setup
│ │ │ ├── .keep
│ │ │ └── configure_lucky_flow.cr
│ │ └── support
│ │ │ ├── .keep
│ │ │ ├── factories
│ │ │ └── .keep
│ │ │ └── flows
│ │ │ └── base_flow.cr
│ │ ├── src
│ │ ├── actions
│ │ │ └── browser_action.cr
│ │ ├── components
│ │ │ ├── .keep
│ │ │ ├── base_component.cr
│ │ │ └── shared
│ │ │ │ ├── field.cr
│ │ │ │ ├── field_errors.cr
│ │ │ │ ├── flash_messages.cr
│ │ │ │ └── layout_head.cr
│ │ ├── css
│ │ │ └── app.scss
│ │ ├── emails
│ │ │ └── .keep
│ │ ├── js
│ │ │ └── app.js
│ │ ├── models
│ │ │ └── mixins
│ │ │ │ └── .keep
│ │ ├── operations
│ │ │ ├── .keep
│ │ │ └── mixins
│ │ │ │ └── .keep
│ │ └── pages
│ │ │ ├── errors
│ │ │ └── show_page.cr
│ │ │ └── main_layout.cr
│ │ └── webpack.mix.js
├── cat.gif
├── hello_crystal.cr
├── hello_world.cr
├── shard_file_template
│ └── expected
│ │ └── shard.yml
├── shard_file_template__browser
│ └── expected
│ │ └── shard.yml
├── shard_file_template__generate_auth
│ └── expected
│ │ └── shard.yml
├── shard_file_template__with_sec_tester
│ └── expected
│ │ └── shard.yml
├── src_template
│ └── expected
│ │ ├── .crystal-version
│ │ ├── .env
│ │ ├── .github
│ │ └── workflows
│ │ │ └── ci.yml
│ │ ├── Procfile
│ │ ├── Procfile.dev
│ │ ├── README.md
│ │ ├── config
│ │ ├── application.cr
│ │ ├── colors.cr
│ │ ├── cookies.cr
│ │ ├── database.cr
│ │ ├── email.cr
│ │ ├── env.cr
│ │ ├── error_handler.cr
│ │ ├── log.cr
│ │ ├── route_helper.cr
│ │ ├── server.cr
│ │ └── watch.yml
│ │ ├── db
│ │ └── migrations
│ │ │ └── .keep
│ │ ├── docker-compose.yml
│ │ ├── docker
│ │ ├── dev_entrypoint.sh
│ │ ├── development.dockerfile
│ │ └── wait-for-it.sh
│ │ ├── script
│ │ ├── helpers
│ │ │ └── function_helpers.cr
│ │ ├── setup.cr
│ │ └── system_check.cr
│ │ ├── spec
│ │ ├── setup
│ │ │ ├── clean_database.cr
│ │ │ ├── reset_emails.cr
│ │ │ ├── setup_database.cr
│ │ │ └── start_app_server.cr
│ │ ├── spec_helper.cr
│ │ └── support
│ │ │ ├── .keep
│ │ │ ├── api_client.cr
│ │ │ └── factories
│ │ │ └── .keep
│ │ ├── src
│ │ ├── actions
│ │ │ ├── api_action.cr
│ │ │ ├── errors
│ │ │ │ └── show.cr
│ │ │ ├── home
│ │ │ │ └── index.cr
│ │ │ └── mixins
│ │ │ │ └── .keep
│ │ ├── app.cr
│ │ ├── app_database.cr
│ │ ├── app_server.cr
│ │ ├── emails
│ │ │ └── base_email.cr
│ │ ├── models
│ │ │ ├── base_model.cr
│ │ │ └── mixins
│ │ │ │ └── .keep
│ │ ├── operations
│ │ │ ├── .keep
│ │ │ └── mixins
│ │ │ │ └── .keep
│ │ ├── queries
│ │ │ ├── .keep
│ │ │ └── mixins
│ │ │ │ └── .keep
│ │ ├── serializers
│ │ │ ├── .keep
│ │ │ ├── base_serializer.cr
│ │ │ └── error_serializer.cr
│ │ ├── shards.cr
│ │ ├── start_server.cr
│ │ └── test_project.cr
│ │ ├── tasks.cr
│ │ └── tasks
│ │ ├── .keep
│ │ └── db
│ │ └── seed
│ │ ├── required_data.cr
│ │ └── sample_data.cr
├── src_template__api_only
│ └── expected
│ │ ├── .crystal-version
│ │ ├── .env
│ │ ├── .github
│ │ └── workflows
│ │ │ └── ci.yml
│ │ ├── Procfile
│ │ ├── Procfile.dev
│ │ ├── README.md
│ │ ├── config
│ │ ├── application.cr
│ │ ├── colors.cr
│ │ ├── cookies.cr
│ │ ├── database.cr
│ │ ├── email.cr
│ │ ├── env.cr
│ │ ├── error_handler.cr
│ │ ├── log.cr
│ │ ├── route_helper.cr
│ │ ├── server.cr
│ │ └── watch.yml
│ │ ├── db
│ │ └── migrations
│ │ │ └── .keep
│ │ ├── docker-compose.yml
│ │ ├── docker
│ │ ├── dev_entrypoint.sh
│ │ ├── development.dockerfile
│ │ └── wait-for-it.sh
│ │ ├── script
│ │ ├── helpers
│ │ │ └── function_helpers.cr
│ │ ├── setup.cr
│ │ └── system_check.cr
│ │ ├── spec
│ │ ├── setup
│ │ │ ├── clean_database.cr
│ │ │ ├── reset_emails.cr
│ │ │ ├── setup_database.cr
│ │ │ └── start_app_server.cr
│ │ ├── spec_helper.cr
│ │ └── support
│ │ │ ├── .keep
│ │ │ ├── api_client.cr
│ │ │ └── factories
│ │ │ └── .keep
│ │ ├── src
│ │ ├── actions
│ │ │ ├── api_action.cr
│ │ │ ├── errors
│ │ │ │ └── show.cr
│ │ │ ├── home
│ │ │ │ └── index.cr
│ │ │ └── mixins
│ │ │ │ └── .keep
│ │ ├── app.cr
│ │ ├── app_database.cr
│ │ ├── app_server.cr
│ │ ├── emails
│ │ │ └── base_email.cr
│ │ ├── models
│ │ │ ├── base_model.cr
│ │ │ └── mixins
│ │ │ │ └── .keep
│ │ ├── operations
│ │ │ ├── .keep
│ │ │ └── mixins
│ │ │ │ └── .keep
│ │ ├── queries
│ │ │ ├── .keep
│ │ │ └── mixins
│ │ │ │ └── .keep
│ │ ├── serializers
│ │ │ ├── .keep
│ │ │ ├── base_serializer.cr
│ │ │ └── error_serializer.cr
│ │ ├── shards.cr
│ │ ├── start_server.cr
│ │ └── test_project.cr
│ │ ├── tasks.cr
│ │ └── tasks
│ │ ├── .keep
│ │ └── db
│ │ └── seed
│ │ ├── required_data.cr
│ │ └── sample_data.cr
├── src_template__generate_auth
│ └── expected
│ │ ├── .crystal-version
│ │ ├── .env
│ │ ├── .github
│ │ └── workflows
│ │ │ └── ci.yml
│ │ ├── Procfile
│ │ ├── Procfile.dev
│ │ ├── README.md
│ │ ├── config
│ │ ├── application.cr
│ │ ├── colors.cr
│ │ ├── cookies.cr
│ │ ├── database.cr
│ │ ├── email.cr
│ │ ├── env.cr
│ │ ├── error_handler.cr
│ │ ├── log.cr
│ │ ├── route_helper.cr
│ │ ├── server.cr
│ │ └── watch.yml
│ │ ├── db
│ │ └── migrations
│ │ │ └── .keep
│ │ ├── docker-compose.yml
│ │ ├── docker
│ │ ├── dev_entrypoint.sh
│ │ ├── development.dockerfile
│ │ └── wait-for-it.sh
│ │ ├── script
│ │ ├── helpers
│ │ │ └── function_helpers.cr
│ │ ├── setup.cr
│ │ └── system_check.cr
│ │ ├── spec
│ │ ├── setup
│ │ │ ├── clean_database.cr
│ │ │ ├── reset_emails.cr
│ │ │ ├── setup_database.cr
│ │ │ └── start_app_server.cr
│ │ ├── spec_helper.cr
│ │ └── support
│ │ │ ├── .keep
│ │ │ ├── api_client.cr
│ │ │ └── factories
│ │ │ └── .keep
│ │ ├── src
│ │ ├── actions
│ │ │ ├── api_action.cr
│ │ │ ├── errors
│ │ │ │ └── show.cr
│ │ │ ├── home
│ │ │ │ └── index.cr
│ │ │ └── mixins
│ │ │ │ └── .keep
│ │ ├── app.cr
│ │ ├── app_database.cr
│ │ ├── app_server.cr
│ │ ├── emails
│ │ │ └── base_email.cr
│ │ ├── models
│ │ │ ├── base_model.cr
│ │ │ └── mixins
│ │ │ │ └── .keep
│ │ ├── operations
│ │ │ ├── .keep
│ │ │ └── mixins
│ │ │ │ └── .keep
│ │ ├── queries
│ │ │ ├── .keep
│ │ │ └── mixins
│ │ │ │ └── .keep
│ │ ├── serializers
│ │ │ ├── .keep
│ │ │ ├── base_serializer.cr
│ │ │ └── error_serializer.cr
│ │ ├── shards.cr
│ │ ├── start_server.cr
│ │ └── test_project.cr
│ │ ├── tasks.cr
│ │ └── tasks
│ │ ├── .keep
│ │ └── db
│ │ └── seed
│ │ ├── required_data.cr
│ │ └── sample_data.cr
├── src_template__sec_tester
│ └── expected
│ │ ├── .crystal-version
│ │ ├── .env
│ │ ├── .github
│ │ └── workflows
│ │ │ └── ci.yml
│ │ ├── Procfile
│ │ ├── Procfile.dev
│ │ ├── README.md
│ │ ├── config
│ │ ├── application.cr
│ │ ├── colors.cr
│ │ ├── cookies.cr
│ │ ├── database.cr
│ │ ├── email.cr
│ │ ├── env.cr
│ │ ├── error_handler.cr
│ │ ├── log.cr
│ │ ├── route_helper.cr
│ │ ├── server.cr
│ │ └── watch.yml
│ │ ├── db
│ │ └── migrations
│ │ │ └── .keep
│ │ ├── docker-compose.yml
│ │ ├── docker
│ │ ├── dev_entrypoint.sh
│ │ ├── development.dockerfile
│ │ └── wait-for-it.sh
│ │ ├── script
│ │ ├── helpers
│ │ │ └── function_helpers.cr
│ │ ├── setup.cr
│ │ └── system_check.cr
│ │ ├── spec
│ │ ├── setup
│ │ │ ├── clean_database.cr
│ │ │ ├── reset_emails.cr
│ │ │ ├── setup_database.cr
│ │ │ └── start_app_server.cr
│ │ ├── spec_helper.cr
│ │ └── support
│ │ │ ├── .keep
│ │ │ ├── api_client.cr
│ │ │ └── factories
│ │ │ └── .keep
│ │ ├── src
│ │ ├── actions
│ │ │ ├── api_action.cr
│ │ │ ├── errors
│ │ │ │ └── show.cr
│ │ │ ├── home
│ │ │ │ └── index.cr
│ │ │ └── mixins
│ │ │ │ └── .keep
│ │ ├── app.cr
│ │ ├── app_database.cr
│ │ ├── app_server.cr
│ │ ├── emails
│ │ │ └── base_email.cr
│ │ ├── models
│ │ │ ├── base_model.cr
│ │ │ └── mixins
│ │ │ │ └── .keep
│ │ ├── operations
│ │ │ ├── .keep
│ │ │ └── mixins
│ │ │ │ └── .keep
│ │ ├── queries
│ │ │ ├── .keep
│ │ │ └── mixins
│ │ │ │ └── .keep
│ │ ├── serializers
│ │ │ ├── .keep
│ │ │ ├── base_serializer.cr
│ │ │ └── error_serializer.cr
│ │ ├── shards.cr
│ │ ├── start_server.cr
│ │ └── test_project.cr
│ │ ├── tasks.cr
│ │ └── tasks
│ │ ├── .keep
│ │ └── db
│ │ └── seed
│ │ ├── required_data.cr
│ │ └── sample_data.cr
└── tasks.cr
├── shard.edge.yml
├── shard.override.yml
├── shard.yml
├── spec
├── integration
│ └── lucky_cli_spec.cr
├── spec_helper.cr
├── support
│ └── tempfile.cr
└── unit
│ ├── api_authentication_template_spec.cr
│ ├── app_with_sec_tester_template_spec.cr
│ ├── base_authentication_src_template_spec.cr
│ ├── browser_authentication_src_template_spec.cr
│ ├── browser_src_template_spec.cr
│ ├── project_name_spec.cr
│ ├── shard_file_generator_spec.cr
│ └── src_template_spec.cr
└── src
├── api_authentication_app_skeleton
├── spec
│ └── requests
│ │ └── api
│ │ ├── me
│ │ └── show_spec.cr.ecr
│ │ ├── sign_ins
│ │ └── create_spec.cr.ecr
│ │ └── sign_ups
│ │ └── create_spec.cr.ecr
└── src
│ ├── actions
│ ├── api
│ │ ├── me
│ │ │ └── show.cr.ecr
│ │ ├── sign_ins
│ │ │ └── create.cr.ecr
│ │ └── sign_ups
│ │ │ └── create.cr.ecr
│ └── mixins
│ │ └── api
│ │ └── auth
│ │ ├── helpers.cr.ecr
│ │ ├── require_auth_token.cr.ecr
│ │ └── skip_require_auth_token.cr.ecr
│ ├── models
│ └── user_token.cr.ecr
│ └── serializers
│ └── user_serializer.cr.ecr
├── app_with_sec_tester
└── spec
│ ├── flows
│ └── security_spec.cr.ecr
│ └── setup
│ └── sec_tester.cr.ecr
├── base_authentication_app_skeleton
├── config
│ └── authentic.cr.ecr
├── db
│ └── migrations
│ │ ├── .keep
│ │ └── 00000000000001_create_users.cr.ecr
├── spec
│ └── support
│ │ ├── .keep
│ │ └── factories
│ │ └── user_factory.cr.ecr
└── src
│ ├── models
│ └── user.cr.ecr
│ ├── operations
│ ├── .keep
│ ├── mixins
│ │ ├── .keep
│ │ ├── password_validations.cr.ecr
│ │ └── user_from_email.cr.ecr
│ ├── request_password_reset.cr.ecr
│ ├── reset_password.cr.ecr
│ ├── sign_in_user.cr.ecr
│ └── sign_up_user.cr.ecr
│ └── queries
│ └── user_query.cr.ecr
├── browser_app_skeleton
├── bs-config.js.ecr
├── config
│ └── html_page.cr.ecr
├── db
│ └── migrations
│ │ └── .keep
├── package.json.ecr
├── public
│ ├── assets
│ │ └── images
│ │ │ └── .keep
│ ├── favicon.ico.ecr
│ ├── mix-manifest.json.ecr
│ └── robots.txt.ecr
├── spec
│ ├── flows
│ │ └── .keep
│ ├── setup
│ │ ├── .keep
│ │ └── configure_lucky_flow.cr.ecr
│ └── support
│ │ ├── .keep
│ │ ├── factories
│ │ └── .keep
│ │ └── flows
│ │ └── base_flow.cr.ecr
├── src
│ ├── actions
│ │ └── browser_action.cr.ecr
│ ├── components
│ │ ├── .keep
│ │ ├── base_component.cr.ecr
│ │ └── shared
│ │ │ ├── field.cr.ecr
│ │ │ ├── field_errors.cr.ecr
│ │ │ ├── flash_messages.cr.ecr
│ │ │ └── layout_head.cr.ecr
│ ├── css
│ │ ├── app.scss.ecr
│ │ ├── components
│ │ │ └── .keep
│ │ ├── mixins
│ │ │ └── .keep
│ │ └── variables
│ │ │ └── .keep
│ ├── emails
│ │ └── .keep
│ ├── js
│ │ └── app.js.ecr
│ ├── models
│ │ └── mixins
│ │ │ └── .keep
│ ├── operations
│ │ ├── .keep
│ │ └── mixins
│ │ │ └── .keep
│ └── pages
│ │ ├── errors
│ │ └── show_page.cr.ecr
│ │ └── main_layout.cr.ecr
└── webpack.mix.js.ecr
├── browser_authentication_app_skeleton
├── spec
│ ├── flows
│ │ ├── authentication_spec.cr.ecr
│ │ └── reset_password_spec.cr.ecr
│ └── support
│ │ ├── .keep
│ │ └── flows
│ │ ├── authentication_flow.cr.ecr
│ │ └── reset_password_flow.cr.ecr
└── src
│ ├── actions
│ ├── me
│ │ └── show.cr.ecr
│ ├── mixins
│ │ ├── .keep
│ │ └── auth
│ │ │ ├── allow_guests.cr.ecr
│ │ │ ├── password_resets
│ │ │ ├── base.cr.ecr
│ │ │ ├── find_user.cr.ecr
│ │ │ ├── require_token.cr.ecr
│ │ │ └── token_from_session.cr.ecr
│ │ │ ├── redirect_signed_in_users.cr.ecr
│ │ │ ├── require_sign_in.cr.ecr
│ │ │ └── test_backdoor.cr.ecr
│ ├── password_reset_requests
│ │ ├── create.cr.ecr
│ │ └── new.cr.ecr
│ ├── password_resets
│ │ ├── create.cr.ecr
│ │ ├── edit.cr.ecr
│ │ └── new.cr.ecr
│ ├── sign_ins
│ │ ├── create.cr.ecr
│ │ ├── delete.cr.ecr
│ │ └── new.cr.ecr
│ └── sign_ups
│ │ ├── create.cr.ecr
│ │ └── new.cr.ecr
│ ├── emails
│ ├── password_reset_request_email.cr.ecr
│ └── templates
│ │ └── password_reset_request_email
│ │ ├── html.ecr.ecr
│ │ └── text.ecr.ecr
│ └── pages
│ ├── auth_layout.cr.ecr
│ ├── main_layout.cr.ecr
│ ├── me
│ └── show_page.cr.ecr
│ ├── password_reset_requests
│ └── new_page.cr.ecr
│ ├── password_resets
│ └── new_page.cr.ecr
│ ├── sign_ins
│ └── new_page.cr.ecr
│ └── sign_ups
│ └── new_page.cr.ecr
├── build_and_run_task.cr
├── dev.cr
├── generators
└── web.cr
├── init.cr
├── init_custom.cr
├── lucky.cr
├── lucky_cli.cr
├── lucky_cli
├── api_authentication_template.cr
├── app_with_sec_tester_template.cr
├── base_authentication_src_template.cr
├── browser_authentication_src_template.cr
├── browser_src_template.cr
├── generator_helpers.cr
├── project_name.cr
├── shard_file_generator.cr
├── spinner.cr
├── src_template.cr
├── version.cr
└── wizard
│ ├── labeled_yes_no_question.cr
│ ├── project_name_question.cr
│ ├── web.cr
│ └── yes_no_question.cr
└── web_app_skeleton
├── .crystal-version.ecr
├── .env.ecr
├── .github
└── workflows
│ └── ci.yml.ecr
├── Procfile.dev.ecr
├── Procfile.ecr
├── README.md.ecr
├── config
├── application.cr.ecr
├── colors.cr.ecr
├── cookies.cr.ecr
├── database.cr.ecr
├── email.cr.ecr
├── env.cr.ecr
├── error_handler.cr.ecr
├── log.cr.ecr
├── route_helper.cr.ecr
├── server.cr.ecr
└── watch.yml.ecr
├── db
└── migrations
│ └── .keep
├── docker-compose.yml.ecr
├── docker
├── dev_entrypoint.sh.ecr
├── development.dockerfile.ecr
└── wait-for-it.sh.ecr
├── script
├── helpers
│ └── function_helpers.cr.ecr
├── setup.cr.ecr
└── system_check.cr.ecr
├── spec
├── setup
│ ├── clean_database.cr.ecr
│ ├── reset_emails.cr.ecr
│ ├── setup_database.cr.ecr
│ └── start_app_server.cr.ecr
├── spec_helper.cr.ecr
└── support
│ ├── .keep
│ ├── api_client.cr.ecr
│ └── factories
│ └── .keep
├── src
├── actions
│ ├── api_action.cr.ecr
│ ├── errors
│ │ └── show.cr.ecr
│ ├── home
│ │ └── index.cr.ecr
│ └── mixins
│ │ └── .keep
├── app.cr.ecr
├── app_database.cr.ecr
├── app_server.cr.ecr
├── emails
│ └── base_email.cr.ecr
├── models
│ ├── base_model.cr.ecr
│ └── mixins
│ │ └── .keep
├── operations
│ ├── .keep
│ └── mixins
│ │ └── .keep
├── project_name.cr.ecr
├── queries
│ ├── .keep
│ └── mixins
│ │ └── .keep
├── serializers
│ ├── .keep
│ ├── base_serializer.cr.ecr
│ └── error_serializer.cr.ecr
├── shards.cr.ecr
└── start_server.cr.ecr
├── tasks.cr.ecr
└── tasks
├── .keep
└── db
└── seed
├── required_data.cr.ecr
└── sample_data.cr.ecr
/.env.sample:
--------------------------------------------------------------------------------
1 | # Change 0 -> 1 if you want to run Heroku specs
2 | RUN_HEROKU_SPECS=0
3 | HEROKU_EMAIL=foo@example.com
4 | # Get this by running -> heroku authorizations:create
5 | # Then copy the token here:
6 | HEROKU_API_KEY=fake-token
7 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 |
3 | updates:
4 | - package-ecosystem: "github-actions"
5 | directory: "/"
6 | schedule:
7 | interval: monthly
8 | target-branch: main
9 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /doc/
2 | /libs/
3 | /lib/
4 | /bin
5 | /.shards/
6 | lucky
7 | *.dwarf
8 | .env
9 | /test-project/
10 | node_modules
11 | /tmp/
12 | !/fixtures/*/expected/**/*
13 |
14 | # Libraries don't need dependency lock
15 | # Dependencies will be locked in application that uses them
16 | /shard.lock
17 | yarn.lock
18 |
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '3'
2 |
3 | services:
4 | postgres:
5 | image: postgres:16
6 | restart: always
7 | environment:
8 | POSTGRES_USER: postgres
9 | POSTGRES_PASSWORD: postgres
10 | TZ: "UTC"
11 | ports:
12 | - 5432:5432
13 | hostname: postgres
14 | healthcheck:
15 | test: ["CMD", "pg_isready"]
16 | interval: 10s
17 | timeout: 5s
18 | retries: 5
19 |
--------------------------------------------------------------------------------
/fixtures/api_authentication_template/expected/spec/requests/api/me/show_spec.cr:
--------------------------------------------------------------------------------
1 | require "../../../spec_helper"
2 |
3 | describe Api::Me::Show do
4 | it "returns the signed in user" do
5 | user = UserFactory.create
6 |
7 | response = ApiClient.auth(user).exec(Api::Me::Show)
8 |
9 | response.should send_json(200, email: user.email)
10 | end
11 |
12 | it "fails if not authenticated" do
13 | response = ApiClient.exec(Api::Me::Show)
14 |
15 | response.status_code.should eq(401)
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/fixtures/api_authentication_template/expected/spec/requests/api/sign_ins/create_spec.cr:
--------------------------------------------------------------------------------
1 | require "../../../spec_helper"
2 |
3 | describe Api::SignIns::Create do
4 | it "returns a token" do
5 | UserToken.stub_token("fake-token") do
6 | user = UserFactory.create
7 |
8 | response = ApiClient.exec(Api::SignIns::Create, user: valid_params(user))
9 |
10 | response.should send_json(200, token: "fake-token")
11 | end
12 | end
13 |
14 | it "returns an error if credentials are invalid" do
15 | user = UserFactory.create
16 | invalid_params = valid_params(user).merge(password: "incorrect")
17 |
18 | response = ApiClient.exec(Api::SignIns::Create, user: invalid_params)
19 |
20 | response.should send_json(
21 | 400,
22 | param: "password",
23 | details: "password is wrong"
24 | )
25 | end
26 | end
27 |
28 | private def valid_params(user : User)
29 | {
30 | email: user.email,
31 | password: "password",
32 | }
33 | end
34 |
--------------------------------------------------------------------------------
/fixtures/api_authentication_template/expected/src/actions/api/me/show.cr:
--------------------------------------------------------------------------------
1 | class Api::Me::Show < ApiAction
2 | get "/api/me" do
3 | json UserSerializer.new(current_user)
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/fixtures/api_authentication_template/expected/src/actions/api/sign_ins/create.cr:
--------------------------------------------------------------------------------
1 | class Api::SignIns::Create < ApiAction
2 | include Api::Auth::SkipRequireAuthToken
3 |
4 | post "/api/sign_ins" do
5 | SignInUser.run(params) do |operation, user|
6 | if user
7 | json({token: UserToken.generate(user)})
8 | else
9 | raise Avram::InvalidOperationError.new(operation)
10 | end
11 | end
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/fixtures/api_authentication_template/expected/src/actions/api/sign_ups/create.cr:
--------------------------------------------------------------------------------
1 | class Api::SignUps::Create < ApiAction
2 | include Api::Auth::SkipRequireAuthToken
3 |
4 | post "/api/sign_ups" do
5 | user = SignUpUser.create!(params)
6 | json({token: UserToken.generate(user)})
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/fixtures/api_authentication_template/expected/src/actions/mixins/api/auth/helpers.cr:
--------------------------------------------------------------------------------
1 | module Api::Auth::Helpers
2 | # The 'memoize' macro makes sure only one query is issued to find the user
3 | memoize def current_user? : User?
4 | auth_token.try do |value|
5 | user_from_auth_token(value)
6 | end
7 | end
8 |
9 | private def auth_token : String?
10 | bearer_token || token_param
11 | end
12 |
13 | private def bearer_token : String?
14 | context.request.headers["Authorization"]?
15 | .try(&.gsub("Bearer", ""))
16 | .try(&.strip)
17 | end
18 |
19 | private def token_param : String?
20 | params.get?(:auth_token)
21 | end
22 |
23 | private def user_from_auth_token(token : String) : User?
24 | UserToken.decode_user_id(token).try do |user_id|
25 | UserQuery.new.id(user_id).first?
26 | end
27 | end
28 | end
29 |
--------------------------------------------------------------------------------
/fixtures/api_authentication_template/expected/src/actions/mixins/api/auth/skip_require_auth_token.cr:
--------------------------------------------------------------------------------
1 | module Api::Auth::SkipRequireAuthToken
2 | macro included
3 | skip require_auth_token
4 | end
5 |
6 | # Since sign in is not required, current_user might be nil
7 | def current_user : User?
8 | current_user?
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/fixtures/api_authentication_template/expected/src/serializers/user_serializer.cr:
--------------------------------------------------------------------------------
1 | class UserSerializer < BaseSerializer
2 | def initialize(@user : User)
3 | end
4 |
5 | def render
6 | {email: @user.email}
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/fixtures/app_sec_tester_template/expected/spec/setup/sec_tester.cr:
--------------------------------------------------------------------------------
1 | require "lucky_sec_tester"
2 |
3 | # Signup for a `BRIGHT_TOKEN` at
4 | # [Bright Security](https://app.neuralegion.com/signup)
5 | # Read more about the SecTester on https://github.com/luckyframework/lucky_sec_tester
6 | LuckySecTester.configure do |setting|
7 | setting.bright_token = ENV["BRIGHT_TOKEN"]
8 | setting.project_id = ENV["BRIGHT_PROJECT_ID"]
9 | end
10 |
--------------------------------------------------------------------------------
/fixtures/app_sec_tester_template__browser/expected/spec/setup/sec_tester.cr:
--------------------------------------------------------------------------------
1 | require "lucky_sec_tester"
2 |
3 | # Signup for a `BRIGHT_TOKEN` at
4 | # [Bright Security](https://app.neuralegion.com/signup)
5 | # Read more about the SecTester on https://github.com/luckyframework/lucky_sec_tester
6 | LuckySecTester.configure do |setting|
7 | setting.bright_token = ENV["BRIGHT_TOKEN"]
8 | setting.project_id = ENV["BRIGHT_PROJECT_ID"]
9 | end
10 |
--------------------------------------------------------------------------------
/fixtures/app_sec_tester_template__generate_auth/expected/spec/setup/sec_tester.cr:
--------------------------------------------------------------------------------
1 | require "lucky_sec_tester"
2 |
3 | # Signup for a `BRIGHT_TOKEN` at
4 | # [Bright Security](https://app.neuralegion.com/signup)
5 | # Read more about the SecTester on https://github.com/luckyframework/lucky_sec_tester
6 | LuckySecTester.configure do |setting|
7 | setting.bright_token = ENV["BRIGHT_TOKEN"]
8 | setting.project_id = ENV["BRIGHT_PROJECT_ID"]
9 | end
10 |
--------------------------------------------------------------------------------
/fixtures/app_sec_tester_template__no_browser_auth/expected/spec/flows/security_spec.cr:
--------------------------------------------------------------------------------
1 | {% skip_file unless flag?(:with_sec_tests) %}
2 | # Run these specs with `crystal spec -Dwith_sec_tests`
3 |
4 | require "../spec_helper"
5 |
6 | describe "SecTester" do
7 | end
8 |
--------------------------------------------------------------------------------
/fixtures/app_sec_tester_template__no_browser_auth/expected/spec/setup/sec_tester.cr:
--------------------------------------------------------------------------------
1 | require "lucky_sec_tester"
2 |
3 | # Signup for a `BRIGHT_TOKEN` at
4 | # [Bright Security](https://app.neuralegion.com/signup)
5 | # Read more about the SecTester on https://github.com/luckyframework/lucky_sec_tester
6 | LuckySecTester.configure do |setting|
7 | setting.bright_token = ENV["BRIGHT_TOKEN"]
8 | setting.project_id = ENV["BRIGHT_PROJECT_ID"]
9 | end
10 |
--------------------------------------------------------------------------------
/fixtures/base_authentication_src_template/expected/config/authentic.cr:
--------------------------------------------------------------------------------
1 | require "./server"
2 |
3 | Authentic.configure do |settings|
4 | settings.secret_key = Lucky::Server.settings.secret_key_base
5 |
6 | unless LuckyEnv.production?
7 | # This value can be between 4 and 31
8 | fastest_encryption_possible = 4
9 | settings.encryption_cost = fastest_encryption_possible
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/fixtures/base_authentication_src_template/expected/db/migrations/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/base_authentication_src_template/expected/db/migrations/.keep
--------------------------------------------------------------------------------
/fixtures/base_authentication_src_template/expected/db/migrations/00000000000001_create_users.cr:
--------------------------------------------------------------------------------
1 | class CreateUsers::V00000000000001 < Avram::Migrator::Migration::V1
2 | def migrate
3 | enable_extension "citext"
4 |
5 | create table_for(User) do
6 | primary_key id : Int64
7 | add_timestamps
8 | add email : String, unique: true, case_sensitive: false
9 | add encrypted_password : String
10 | end
11 | end
12 |
13 | def rollback
14 | drop table_for(User)
15 | disable_extension "citext"
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/fixtures/base_authentication_src_template/expected/spec/support/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/base_authentication_src_template/expected/spec/support/.keep
--------------------------------------------------------------------------------
/fixtures/base_authentication_src_template/expected/spec/support/factories/user_factory.cr:
--------------------------------------------------------------------------------
1 | class UserFactory < Avram::Factory
2 | def initialize
3 | email "#{sequence("test-email")}@example.com"
4 | encrypted_password Authentic.generate_encrypted_password("password")
5 | end
6 | end
7 |
--------------------------------------------------------------------------------
/fixtures/base_authentication_src_template/expected/src/models/user.cr:
--------------------------------------------------------------------------------
1 | class User < BaseModel
2 | include Carbon::Emailable
3 | include Authentic::PasswordAuthenticatable
4 |
5 | table do
6 | column email : String
7 | column encrypted_password : String
8 | end
9 |
10 | def emailable : Carbon::Address
11 | Carbon::Address.new(email)
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/fixtures/base_authentication_src_template/expected/src/operations/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/base_authentication_src_template/expected/src/operations/.keep
--------------------------------------------------------------------------------
/fixtures/base_authentication_src_template/expected/src/operations/mixins/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/base_authentication_src_template/expected/src/operations/mixins/.keep
--------------------------------------------------------------------------------
/fixtures/base_authentication_src_template/expected/src/operations/mixins/password_validations.cr:
--------------------------------------------------------------------------------
1 | module PasswordValidations
2 | macro included
3 | before_save run_password_validations
4 | end
5 |
6 | private def run_password_validations
7 | validate_required password, password_confirmation
8 | validate_confirmation_of password, with: password_confirmation
9 | # 72 is a limitation of BCrypt
10 | validate_size_of password, min: 6, max: 72
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/fixtures/base_authentication_src_template/expected/src/operations/mixins/user_from_email.cr:
--------------------------------------------------------------------------------
1 | module UserFromEmail
2 | private def user_from_email : User?
3 | email.value.try do |value|
4 | UserQuery.new.email(value).first?
5 | end
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/fixtures/base_authentication_src_template/expected/src/operations/request_password_reset.cr:
--------------------------------------------------------------------------------
1 | class RequestPasswordReset < Avram::Operation
2 | # You can modify this in src/operations/mixins/user_from_email.cr
3 | include UserFromEmail
4 |
5 | attribute email : String
6 |
7 | # Run validations and yield the operation and the user if valid
8 | def run
9 | user = user_from_email
10 | validate(user)
11 |
12 | if valid?
13 | user
14 | else
15 | nil
16 | end
17 | end
18 |
19 | def validate(user : User?)
20 | validate_required email
21 | if user.nil?
22 | email.add_error "is not in our system"
23 | end
24 | end
25 | end
26 |
--------------------------------------------------------------------------------
/fixtures/base_authentication_src_template/expected/src/operations/reset_password.cr:
--------------------------------------------------------------------------------
1 | class ResetPassword < User::SaveOperation
2 | # Change password validations in src/operations/mixins/password_validations.cr
3 | include PasswordValidations
4 |
5 | attribute password : String
6 | attribute password_confirmation : String
7 |
8 | before_save do
9 | Authentic.copy_and_encrypt password, to: encrypted_password
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/fixtures/base_authentication_src_template/expected/src/operations/sign_up_user.cr:
--------------------------------------------------------------------------------
1 | class SignUpUser < User::SaveOperation
2 | param_key :user
3 | # Change password validations in src/operations/mixins/password_validations.cr
4 | include PasswordValidations
5 |
6 | permit_columns email
7 | attribute password : String
8 | attribute password_confirmation : String
9 |
10 | before_save do
11 | validate_uniqueness_of email
12 | Authentic.copy_and_encrypt(password, to: encrypted_password) if password.valid?
13 | end
14 | end
15 |
--------------------------------------------------------------------------------
/fixtures/base_authentication_src_template/expected/src/queries/user_query.cr:
--------------------------------------------------------------------------------
1 | class UserQuery < User::BaseQuery
2 | end
3 |
--------------------------------------------------------------------------------
/fixtures/browser_authentication_src_template/expected/spec/flows/reset_password_spec.cr:
--------------------------------------------------------------------------------
1 | require "../spec_helper"
2 |
3 | describe "Reset password flow", tags: "flow" do
4 | it "works" do
5 | user = UserFactory.create
6 | flow = ResetPasswordFlow.new(user)
7 |
8 | flow.request_password_reset
9 | flow.should_have_sent_reset_email
10 | flow.reset_password "new-password"
11 | flow.should_be_signed_in
12 | flow.sign_out
13 | flow.sign_in "wrong-password"
14 | flow.should_have_password_error
15 | flow.sign_in "new-password"
16 | flow.should_be_signed_in
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/fixtures/browser_authentication_src_template/expected/spec/support/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/browser_authentication_src_template/expected/spec/support/.keep
--------------------------------------------------------------------------------
/fixtures/browser_authentication_src_template/expected/src/actions/me/show.cr:
--------------------------------------------------------------------------------
1 | class Me::Show < BrowserAction
2 | get "/me" do
3 | html ShowPage
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/fixtures/browser_authentication_src_template/expected/src/actions/mixins/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/browser_authentication_src_template/expected/src/actions/mixins/.keep
--------------------------------------------------------------------------------
/fixtures/browser_authentication_src_template/expected/src/actions/mixins/auth/allow_guests.cr:
--------------------------------------------------------------------------------
1 | module Auth::AllowGuests
2 | macro included
3 | skip require_sign_in
4 | end
5 |
6 | # Since sign in is not required, current_user might be nil
7 | def current_user : User?
8 | current_user?
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/fixtures/browser_authentication_src_template/expected/src/actions/mixins/auth/password_resets/base.cr:
--------------------------------------------------------------------------------
1 | module Auth::PasswordResets::Base
2 | macro included
3 | include Auth::RedirectSignedInUsers
4 | include Auth::PasswordResets::FindUser
5 | include Auth::PasswordResets::RequireToken
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/fixtures/browser_authentication_src_template/expected/src/actions/mixins/auth/password_resets/find_user.cr:
--------------------------------------------------------------------------------
1 | module Auth::PasswordResets::FindUser
2 | private def user : User
3 | UserQuery.find(user_id)
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/fixtures/browser_authentication_src_template/expected/src/actions/mixins/auth/password_resets/require_token.cr:
--------------------------------------------------------------------------------
1 | module Auth::PasswordResets::RequireToken
2 | macro included
3 | before require_valid_password_reset_token
4 | end
5 |
6 | abstract def token : String
7 | abstract def user : User
8 |
9 | private def require_valid_password_reset_token
10 | if Authentic.valid_password_reset_token?(user, token)
11 | continue
12 | else
13 | flash.failure = "The password reset link is incorrect or expired. Please try again."
14 | redirect to: PasswordResetRequests::New
15 | end
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/fixtures/browser_authentication_src_template/expected/src/actions/mixins/auth/password_resets/token_from_session.cr:
--------------------------------------------------------------------------------
1 | module Auth::PasswordResets::TokenFromSession
2 | private def token : String
3 | session.get?(:password_reset_token) || raise "Password reset token not found in session"
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/fixtures/browser_authentication_src_template/expected/src/actions/mixins/auth/redirect_signed_in_users.cr:
--------------------------------------------------------------------------------
1 | module Auth::RedirectSignedInUsers
2 | macro included
3 | include Auth::AllowGuests
4 | before redirect_signed_in_users
5 | end
6 |
7 | private def redirect_signed_in_users
8 | if current_user?
9 | flash.success = "You are already signed in"
10 | redirect to: Home::Index
11 | else
12 | continue
13 | end
14 | end
15 |
16 | # current_user returns nil because signed in users are redirected.
17 | def current_user
18 | end
19 | end
20 |
--------------------------------------------------------------------------------
/fixtures/browser_authentication_src_template/expected/src/actions/mixins/auth/require_sign_in.cr:
--------------------------------------------------------------------------------
1 | module Auth::RequireSignIn
2 | macro included
3 | before require_sign_in
4 | end
5 |
6 | private def require_sign_in
7 | if current_user?
8 | continue
9 | else
10 | Authentic.remember_requested_path(self)
11 | flash.info = "Please sign in first"
12 | redirect to: SignIns::New
13 | end
14 | end
15 |
16 | # Tells the compiler that the current_user is not nil since we have checked
17 | # that the user is signed in
18 | private def current_user : User
19 | current_user?.as(User)
20 | end
21 | end
22 |
--------------------------------------------------------------------------------
/fixtures/browser_authentication_src_template/expected/src/actions/mixins/auth/test_backdoor.cr:
--------------------------------------------------------------------------------
1 | module Auth::TestBackdoor
2 | macro included
3 | before test_backdoor
4 | end
5 |
6 | private def test_backdoor
7 | if LuckyEnv.test? && (user_id = params.get?(:backdoor_user_id))
8 | user = UserQuery.find(user_id)
9 | sign_in user
10 | end
11 | continue
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/fixtures/browser_authentication_src_template/expected/src/actions/password_reset_requests/create.cr:
--------------------------------------------------------------------------------
1 | class PasswordResetRequests::Create < BrowserAction
2 | include Auth::RedirectSignedInUsers
3 |
4 | post "/password_reset_requests" do
5 | RequestPasswordReset.run(params) do |operation, user|
6 | if user
7 | PasswordResetRequestEmail.new(user).deliver
8 | flash.success = "You should receive an email on how to reset your password shortly"
9 | redirect SignIns::New
10 | else
11 | html NewPage, operation: operation
12 | end
13 | end
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/fixtures/browser_authentication_src_template/expected/src/actions/password_reset_requests/new.cr:
--------------------------------------------------------------------------------
1 | class PasswordResetRequests::New < BrowserAction
2 | include Auth::RedirectSignedInUsers
3 |
4 | get "/password_reset_requests/new" do
5 | html NewPage, operation: RequestPasswordReset.new
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/fixtures/browser_authentication_src_template/expected/src/actions/password_resets/create.cr:
--------------------------------------------------------------------------------
1 | class PasswordResets::Create < BrowserAction
2 | include Auth::PasswordResets::Base
3 | include Auth::PasswordResets::TokenFromSession
4 |
5 | post "/password_resets/:user_id" do
6 | ResetPassword.update(user, params) do |operation, user|
7 | if operation.saved?
8 | session.delete(:password_reset_token)
9 | sign_in user
10 | flash.success = "Your password has been reset"
11 | redirect to: Home::Index
12 | else
13 | html NewPage, operation: operation, user_id: user_id.to_i64
14 | end
15 | end
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/fixtures/browser_authentication_src_template/expected/src/actions/password_resets/edit.cr:
--------------------------------------------------------------------------------
1 | class PasswordResets::Edit < BrowserAction
2 | include Auth::PasswordResets::Base
3 | include Auth::PasswordResets::TokenFromSession
4 |
5 | get "/password_resets/:user_id/edit" do
6 | html NewPage, operation: ResetPassword.new, user_id: user_id.to_i64
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/fixtures/browser_authentication_src_template/expected/src/actions/password_resets/new.cr:
--------------------------------------------------------------------------------
1 | class PasswordResets::New < BrowserAction
2 | include Auth::PasswordResets::Base
3 |
4 | param token : String
5 |
6 | get "/password_resets/:user_id" do
7 | redirect_to_edit_form_without_token_param
8 | end
9 |
10 | # This is to prevent password reset tokens from being scraped in the HTTP Referer header
11 | # See more info here: https://github.com/thoughtbot/clearance/pull/707
12 | private def redirect_to_edit_form_without_token_param
13 | make_token_available_to_future_actions
14 | redirect to: PasswordResets::Edit.with(user_id)
15 | end
16 |
17 | private def make_token_available_to_future_actions
18 | session.set(:password_reset_token, token)
19 | end
20 | end
21 |
--------------------------------------------------------------------------------
/fixtures/browser_authentication_src_template/expected/src/actions/sign_ins/create.cr:
--------------------------------------------------------------------------------
1 | class SignIns::Create < BrowserAction
2 | include Auth::RedirectSignedInUsers
3 |
4 | post "/sign_in" do
5 | SignInUser.run(params) do |operation, authenticated_user|
6 | if authenticated_user
7 | sign_in(authenticated_user)
8 | flash.success = "You're now signed in"
9 | Authentic.redirect_to_originally_requested_path(self, fallback: Home::Index)
10 | else
11 | flash.failure = "Sign in failed"
12 | html NewPage, operation: operation
13 | end
14 | end
15 | end
16 | end
17 |
--------------------------------------------------------------------------------
/fixtures/browser_authentication_src_template/expected/src/actions/sign_ins/delete.cr:
--------------------------------------------------------------------------------
1 | class SignIns::Delete < BrowserAction
2 | delete "/sign_out" do
3 | sign_out
4 | flash.info = "You have been signed out"
5 | redirect to: SignIns::New
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/fixtures/browser_authentication_src_template/expected/src/actions/sign_ins/new.cr:
--------------------------------------------------------------------------------
1 | class SignIns::New < BrowserAction
2 | include Auth::RedirectSignedInUsers
3 |
4 | get "/sign_in" do
5 | html NewPage, operation: SignInUser.new
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/fixtures/browser_authentication_src_template/expected/src/actions/sign_ups/create.cr:
--------------------------------------------------------------------------------
1 | class SignUps::Create < BrowserAction
2 | include Auth::RedirectSignedInUsers
3 |
4 | post "/sign_up" do
5 | SignUpUser.create(params) do |operation, user|
6 | if user
7 | flash.info = "Thanks for signing up"
8 | sign_in(user)
9 | redirect to: Home::Index
10 | else
11 | flash.info = "Couldn't sign you up"
12 | html NewPage, operation: operation
13 | end
14 | end
15 | end
16 | end
17 |
--------------------------------------------------------------------------------
/fixtures/browser_authentication_src_template/expected/src/actions/sign_ups/new.cr:
--------------------------------------------------------------------------------
1 | class SignUps::New < BrowserAction
2 | include Auth::RedirectSignedInUsers
3 |
4 | get "/sign_up" do
5 | html NewPage, operation: SignUpUser.new
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/fixtures/browser_authentication_src_template/expected/src/emails/password_reset_request_email.cr:
--------------------------------------------------------------------------------
1 | class PasswordResetRequestEmail < BaseEmail
2 | Habitat.create { setting stubbed_token : String? }
3 | delegate stubbed_token, to: :settings
4 |
5 | def initialize(@user : User)
6 | @token = stubbed_token || Authentic.generate_password_reset_token(@user)
7 | end
8 |
9 | to @user
10 | from "myapp@support.com" # or set a default in src/emails/base_email.cr
11 | subject "Reset your password"
12 | templates html, text
13 | end
14 |
--------------------------------------------------------------------------------
/fixtures/browser_authentication_src_template/expected/src/emails/templates/password_reset_request_email/html.ecr:
--------------------------------------------------------------------------------
1 |
Please reset your password
2 |
3 | Reset password
4 |
--------------------------------------------------------------------------------
/fixtures/browser_authentication_src_template/expected/src/emails/templates/password_reset_request_email/text.ecr:
--------------------------------------------------------------------------------
1 | Please reset your password:
2 |
3 | <%= PasswordResets::New.url(@user.id, @token) %>
4 |
--------------------------------------------------------------------------------
/fixtures/browser_authentication_src_template/expected/src/pages/auth_layout.cr:
--------------------------------------------------------------------------------
1 | abstract class AuthLayout
2 | include Lucky::HTMLPage
3 |
4 | abstract def content
5 | abstract def page_title
6 |
7 | # The default page title. It is passed to `Shared::LayoutHead`.
8 | #
9 | # Add a `page_title` method to pages to override it. You can also remove
10 | # This method so every page is required to have its own page title.
11 | def page_title
12 | "Welcome"
13 | end
14 |
15 | def render
16 | html_doctype
17 |
18 | html lang: "en" do
19 | mount Shared::LayoutHead, page_title: page_title
20 |
21 | body do
22 | mount Shared::FlashMessages, context.flash
23 | content
24 | end
25 | end
26 | end
27 | end
28 |
--------------------------------------------------------------------------------
/fixtures/browser_authentication_src_template/expected/src/pages/me/show_page.cr:
--------------------------------------------------------------------------------
1 | class Me::ShowPage < MainLayout
2 | def content
3 | h1 "This is your profile"
4 | h3 "Email: #{@current_user.email}"
5 | helpful_tips
6 | end
7 |
8 | private def helpful_tips
9 | h3 "Next, you may want to:"
10 | ul do
11 | li { link_to_authentication_guides }
12 | li "Modify this page: src/pages/me/show_page.cr"
13 | li "Change where you go after sign in: src/actions/home/index.cr"
14 | end
15 | end
16 |
17 | private def link_to_authentication_guides
18 | a "Check out the authentication guides",
19 | href: "https://luckyframework.org/guides/authentication"
20 | end
21 | end
22 |
--------------------------------------------------------------------------------
/fixtures/browser_authentication_src_template/expected/src/pages/password_reset_requests/new_page.cr:
--------------------------------------------------------------------------------
1 | class PasswordResetRequests::NewPage < AuthLayout
2 | needs operation : RequestPasswordReset
3 |
4 | def content
5 | h1 "Reset your password"
6 | render_form(@operation)
7 | end
8 |
9 | private def render_form(op)
10 | form_for PasswordResetRequests::Create do
11 | mount Shared::Field, attribute: op.email, label_text: "Email", &.email_input
12 | submit "Reset Password", flow_id: "request-password-reset-button"
13 | end
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/fixtures/browser_authentication_src_template/expected/src/pages/password_resets/new_page.cr:
--------------------------------------------------------------------------------
1 | class PasswordResets::NewPage < AuthLayout
2 | needs operation : ResetPassword
3 | needs user_id : Int64
4 |
5 | def content
6 | h1 "Reset your password"
7 | render_password_reset_form(@operation)
8 | end
9 |
10 | private def render_password_reset_form(op)
11 | form_for PasswordResets::Create.with(@user_id) do
12 | mount Shared::Field, attribute: op.password, label_text: "Password", &.password_input(autofocus: "true")
13 | mount Shared::Field, attribute: op.password_confirmation, label_text: "Confirm Password", &.password_input
14 |
15 | submit "Update Password", flow_id: "update-password-button"
16 | end
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/fixtures/browser_authentication_src_template/expected/src/pages/sign_ins/new_page.cr:
--------------------------------------------------------------------------------
1 | class SignIns::NewPage < AuthLayout
2 | needs operation : SignInUser
3 |
4 | def content
5 | h1 "Sign In"
6 | render_sign_in_form(@operation)
7 | end
8 |
9 | private def render_sign_in_form(op)
10 | form_for SignIns::Create do
11 | sign_in_fields(op)
12 | submit "Sign In", flow_id: "sign-in-button"
13 | end
14 | link "Reset password", to: PasswordResetRequests::New
15 | text " | "
16 | link "Sign up", to: SignUps::New
17 | end
18 |
19 | private def sign_in_fields(op)
20 | mount Shared::Field, attribute: op.email, label_text: "Email", &.email_input(autofocus: "true")
21 | mount Shared::Field, attribute: op.password, label_text: "Password", &.password_input
22 | end
23 | end
24 |
--------------------------------------------------------------------------------
/fixtures/browser_authentication_src_template/expected/src/pages/sign_ups/new_page.cr:
--------------------------------------------------------------------------------
1 | class SignUps::NewPage < AuthLayout
2 | needs operation : SignUpUser
3 |
4 | def content
5 | h1 "Sign Up"
6 | render_sign_up_form(@operation)
7 | end
8 |
9 | private def render_sign_up_form(op)
10 | form_for SignUps::Create do
11 | sign_up_fields(op)
12 | submit "Sign Up", flow_id: "sign-up-button"
13 | end
14 | link "Sign in instead", to: SignIns::New
15 | end
16 |
17 | private def sign_up_fields(op)
18 | mount Shared::Field, attribute: op.email, label_text: "Email", &.email_input(autofocus: "true")
19 | mount Shared::Field, attribute: op.password, label_text: "Password", &.password_input
20 | mount Shared::Field, attribute: op.password_confirmation, label_text: "Confirm Password", &.password_input
21 | end
22 | end
23 |
--------------------------------------------------------------------------------
/fixtures/browser_src_template/expected/bs-config.js:
--------------------------------------------------------------------------------
1 | /*
2 | | Browser-sync config file
3 | |
4 | | For up-to-date information about the options:
5 | | http://www.browsersync.io/docs/options/
6 | |
7 | */
8 |
9 | module.exports = {
10 | snippetOptions: {
11 | rule: {
12 | match: /<\/head>/i,
13 | fn: function (snippet, match) {
14 | return snippet + match;
15 | }
16 | }
17 | },
18 | files: ["public/css/**/*.css", "public/js/**/*.js"],
19 | watchEvents: ["change"],
20 | open: false,
21 | browser: "default",
22 | ghostMode: false,
23 | ui: false,
24 | online: false,
25 | logConnections: false
26 | };
27 |
--------------------------------------------------------------------------------
/fixtures/browser_src_template/expected/config/html_page.cr:
--------------------------------------------------------------------------------
1 | Lucky::HTMLPage.configure do |settings|
2 | settings.render_component_comments = !LuckyEnv.production?
3 | end
4 |
--------------------------------------------------------------------------------
/fixtures/browser_src_template/expected/db/migrations/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/browser_src_template/expected/db/migrations/.keep
--------------------------------------------------------------------------------
/fixtures/browser_src_template/expected/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "license": "UNLICENSED",
3 | "private": true,
4 | "dependencies": {
5 | "@rails/ujs": "^7.1.0",
6 | "modern-normalize": "^2.0.0"
7 | },
8 | "scripts": {
9 | "heroku-postbuild": "yarn prod",
10 | "dev": "yarn run mix",
11 | "watch": "yarn run mix watch",
12 | "prod": "yarn run mix --production"
13 | },
14 | "devDependencies": {
15 | "@babel/compat-data": "^7.23.5",
16 | "browser-sync": "^2.29.3",
17 | "compression-webpack-plugin": "^10.0.0",
18 | "laravel-mix": "^6.0.49",
19 | "postcss": "^8.4.32",
20 | "resolve-url-loader": "^5.0.0",
21 | "sass": "^1.69.5",
22 | "sass-loader": "^13.3.2"
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/fixtures/browser_src_template/expected/public/assets/images/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/browser_src_template/expected/public/assets/images/.keep
--------------------------------------------------------------------------------
/fixtures/browser_src_template/expected/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/browser_src_template/expected/public/favicon.ico
--------------------------------------------------------------------------------
/fixtures/browser_src_template/expected/public/mix-manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "/css/app.css": "/css/app.css",
3 | "/js/app.js": "/js/app.js"
4 | }
5 |
--------------------------------------------------------------------------------
/fixtures/browser_src_template/expected/public/robots.txt:
--------------------------------------------------------------------------------
1 | # Learn more about robots.txt: https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | # 'Disallow' with an empty value allows all paths to be crawled
4 | Disallow:
5 |
--------------------------------------------------------------------------------
/fixtures/browser_src_template/expected/spec/flows/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/browser_src_template/expected/spec/flows/.keep
--------------------------------------------------------------------------------
/fixtures/browser_src_template/expected/spec/setup/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/browser_src_template/expected/spec/setup/.keep
--------------------------------------------------------------------------------
/fixtures/browser_src_template/expected/spec/support/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/browser_src_template/expected/spec/support/.keep
--------------------------------------------------------------------------------
/fixtures/browser_src_template/expected/spec/support/factories/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/browser_src_template/expected/spec/support/factories/.keep
--------------------------------------------------------------------------------
/fixtures/browser_src_template/expected/spec/support/flows/base_flow.cr:
--------------------------------------------------------------------------------
1 | # Add methods that all or most Flows need to share
2 | class BaseFlow < LuckyFlow
3 | end
4 |
--------------------------------------------------------------------------------
/fixtures/browser_src_template/expected/src/components/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/browser_src_template/expected/src/components/.keep
--------------------------------------------------------------------------------
/fixtures/browser_src_template/expected/src/components/base_component.cr:
--------------------------------------------------------------------------------
1 | abstract class BaseComponent < Lucky::BaseComponent
2 | end
3 |
--------------------------------------------------------------------------------
/fixtures/browser_src_template/expected/src/components/shared/field_errors.cr:
--------------------------------------------------------------------------------
1 | class Shared::FieldErrors(T) < BaseComponent
2 | needs attribute : Avram::PermittedAttribute(T)
3 |
4 | # Customize the markup and styles to match your application
5 | def render
6 | unless attribute.valid?
7 | div class: "error" do
8 | text "#{label_text} #{attribute.errors.first}"
9 | end
10 | end
11 | end
12 |
13 | def label_text : String
14 | Wordsmith::Inflector.humanize(attribute.name.to_s)
15 | end
16 | end
17 |
--------------------------------------------------------------------------------
/fixtures/browser_src_template/expected/src/components/shared/flash_messages.cr:
--------------------------------------------------------------------------------
1 | class Shared::FlashMessages < BaseComponent
2 | needs flash : Lucky::FlashStore
3 |
4 | def render
5 | flash.each do |flash_type, flash_message|
6 | div class: "flash-#{flash_type}", flow_id: "flash" do
7 | text flash_message
8 | end
9 | end
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/fixtures/browser_src_template/expected/src/components/shared/layout_head.cr:
--------------------------------------------------------------------------------
1 | class Shared::LayoutHead < BaseComponent
2 | needs page_title : String
3 |
4 | def render
5 | head do
6 | utf8_charset
7 | title "My App - #{@page_title}"
8 | css_link asset("css/app.css")
9 | js_link asset("js/app.js"), defer: "true"
10 | csrf_meta_tags
11 | responsive_meta_tag
12 |
13 | # Development helper used with the `lucky watch` command.
14 | # Reloads the browser when files are updated.
15 | live_reload_connect_tag if LuckyEnv.development?
16 | end
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/fixtures/browser_src_template/expected/src/emails/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/browser_src_template/expected/src/emails/.keep
--------------------------------------------------------------------------------
/fixtures/browser_src_template/expected/src/js/app.js:
--------------------------------------------------------------------------------
1 | /* eslint no-console:0 */
2 |
3 | // Rails Unobtrusive JavaScript (UJS) is *required* for links in Lucky that use DELETE, POST and PUT.
4 | // Though it says "Rails" it actually works with any framework.
5 | import Rails from "@rails/ujs";
6 | Rails.start();
7 |
8 |
--------------------------------------------------------------------------------
/fixtures/browser_src_template/expected/src/models/mixins/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/browser_src_template/expected/src/models/mixins/.keep
--------------------------------------------------------------------------------
/fixtures/browser_src_template/expected/src/operations/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/browser_src_template/expected/src/operations/.keep
--------------------------------------------------------------------------------
/fixtures/browser_src_template/expected/src/operations/mixins/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/browser_src_template/expected/src/operations/mixins/.keep
--------------------------------------------------------------------------------
/fixtures/browser_src_template/expected/src/pages/main_layout.cr:
--------------------------------------------------------------------------------
1 | abstract class MainLayout
2 | include Lucky::HTMLPage
3 |
4 | abstract def content
5 | abstract def page_title
6 |
7 | # The default page title. It is passed to `Shared::LayoutHead`.
8 | #
9 | # Add a `page_title` method to pages to override it. You can also remove
10 | # This method so every page is required to have its own page title.
11 | def page_title
12 | "Welcome"
13 | end
14 |
15 | def render
16 | html_doctype
17 |
18 | html lang: "en" do
19 | mount Shared::LayoutHead, page_title: page_title
20 |
21 | body do
22 | mount Shared::FlashMessages, context.flash
23 | content
24 | end
25 | end
26 | end
27 | end
28 |
--------------------------------------------------------------------------------
/fixtures/browser_src_template__generate_auth/expected/bs-config.js:
--------------------------------------------------------------------------------
1 | /*
2 | | Browser-sync config file
3 | |
4 | | For up-to-date information about the options:
5 | | http://www.browsersync.io/docs/options/
6 | |
7 | */
8 |
9 | module.exports = {
10 | snippetOptions: {
11 | rule: {
12 | match: /<\/head>/i,
13 | fn: function (snippet, match) {
14 | return snippet + match;
15 | }
16 | }
17 | },
18 | files: ["public/css/**/*.css", "public/js/**/*.js"],
19 | watchEvents: ["change"],
20 | open: false,
21 | browser: "default",
22 | ghostMode: false,
23 | ui: false,
24 | online: false,
25 | logConnections: false
26 | };
27 |
--------------------------------------------------------------------------------
/fixtures/browser_src_template__generate_auth/expected/config/html_page.cr:
--------------------------------------------------------------------------------
1 | Lucky::HTMLPage.configure do |settings|
2 | settings.render_component_comments = !LuckyEnv.production?
3 | end
4 |
--------------------------------------------------------------------------------
/fixtures/browser_src_template__generate_auth/expected/db/migrations/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/browser_src_template__generate_auth/expected/db/migrations/.keep
--------------------------------------------------------------------------------
/fixtures/browser_src_template__generate_auth/expected/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "license": "UNLICENSED",
3 | "private": true,
4 | "dependencies": {
5 | "@rails/ujs": "^7.1.0",
6 | "modern-normalize": "^2.0.0"
7 | },
8 | "scripts": {
9 | "heroku-postbuild": "yarn prod",
10 | "dev": "yarn run mix",
11 | "watch": "yarn run mix watch",
12 | "prod": "yarn run mix --production"
13 | },
14 | "devDependencies": {
15 | "@babel/compat-data": "^7.23.5",
16 | "browser-sync": "^2.29.3",
17 | "compression-webpack-plugin": "^10.0.0",
18 | "laravel-mix": "^6.0.49",
19 | "postcss": "^8.4.32",
20 | "resolve-url-loader": "^5.0.0",
21 | "sass": "^1.69.5",
22 | "sass-loader": "^13.3.2"
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/fixtures/browser_src_template__generate_auth/expected/public/assets/images/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/browser_src_template__generate_auth/expected/public/assets/images/.keep
--------------------------------------------------------------------------------
/fixtures/browser_src_template__generate_auth/expected/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/browser_src_template__generate_auth/expected/public/favicon.ico
--------------------------------------------------------------------------------
/fixtures/browser_src_template__generate_auth/expected/public/mix-manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "/css/app.css": "/css/app.css",
3 | "/js/app.js": "/js/app.js"
4 | }
5 |
--------------------------------------------------------------------------------
/fixtures/browser_src_template__generate_auth/expected/public/robots.txt:
--------------------------------------------------------------------------------
1 | # Learn more about robots.txt: https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | # 'Disallow' with an empty value allows all paths to be crawled
4 | Disallow:
5 |
--------------------------------------------------------------------------------
/fixtures/browser_src_template__generate_auth/expected/spec/flows/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/browser_src_template__generate_auth/expected/spec/flows/.keep
--------------------------------------------------------------------------------
/fixtures/browser_src_template__generate_auth/expected/spec/setup/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/browser_src_template__generate_auth/expected/spec/setup/.keep
--------------------------------------------------------------------------------
/fixtures/browser_src_template__generate_auth/expected/spec/support/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/browser_src_template__generate_auth/expected/spec/support/.keep
--------------------------------------------------------------------------------
/fixtures/browser_src_template__generate_auth/expected/spec/support/factories/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/browser_src_template__generate_auth/expected/spec/support/factories/.keep
--------------------------------------------------------------------------------
/fixtures/browser_src_template__generate_auth/expected/spec/support/flows/base_flow.cr:
--------------------------------------------------------------------------------
1 | # Add methods that all or most Flows need to share
2 | class BaseFlow < LuckyFlow
3 | end
4 |
--------------------------------------------------------------------------------
/fixtures/browser_src_template__generate_auth/expected/src/actions/browser_action.cr:
--------------------------------------------------------------------------------
1 | abstract class BrowserAction < Lucky::Action
2 | include Lucky::ProtectFromForgery
3 |
4 | # By default all actions are required to use underscores.
5 | # Add `include Lucky::SkipRouteStyleCheck` to your actions if you wish to ignore this check for specific routes.
6 | include Lucky::EnforceUnderscoredRoute
7 |
8 | # This module disables Google FLoC by setting the
9 | # [Permissions-Policy](https://github.com/WICG/floc) HTTP header to `interest-cohort=()`.
10 | #
11 | # This header is a part of Google's Federated Learning of Cohorts (FLoC) which is used
12 | # to track browsing history instead of using 3rd-party cookies.
13 | #
14 | # Remove this include if you want to use the FLoC tracking.
15 | include Lucky::SecureHeaders::DisableFLoC
16 |
17 | accepted_formats [:html, :json], default: :html
18 | end
19 |
--------------------------------------------------------------------------------
/fixtures/browser_src_template__generate_auth/expected/src/components/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/browser_src_template__generate_auth/expected/src/components/.keep
--------------------------------------------------------------------------------
/fixtures/browser_src_template__generate_auth/expected/src/components/base_component.cr:
--------------------------------------------------------------------------------
1 | abstract class BaseComponent < Lucky::BaseComponent
2 | end
3 |
--------------------------------------------------------------------------------
/fixtures/browser_src_template__generate_auth/expected/src/components/shared/field_errors.cr:
--------------------------------------------------------------------------------
1 | class Shared::FieldErrors(T) < BaseComponent
2 | needs attribute : Avram::PermittedAttribute(T)
3 |
4 | # Customize the markup and styles to match your application
5 | def render
6 | unless attribute.valid?
7 | div class: "error" do
8 | text "#{label_text} #{attribute.errors.first}"
9 | end
10 | end
11 | end
12 |
13 | def label_text : String
14 | Wordsmith::Inflector.humanize(attribute.name.to_s)
15 | end
16 | end
17 |
--------------------------------------------------------------------------------
/fixtures/browser_src_template__generate_auth/expected/src/components/shared/flash_messages.cr:
--------------------------------------------------------------------------------
1 | class Shared::FlashMessages < BaseComponent
2 | needs flash : Lucky::FlashStore
3 |
4 | def render
5 | flash.each do |flash_type, flash_message|
6 | div class: "flash-#{flash_type}", flow_id: "flash" do
7 | text flash_message
8 | end
9 | end
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/fixtures/browser_src_template__generate_auth/expected/src/components/shared/layout_head.cr:
--------------------------------------------------------------------------------
1 | class Shared::LayoutHead < BaseComponent
2 | needs page_title : String
3 |
4 | def render
5 | head do
6 | utf8_charset
7 | title "My App - #{@page_title}"
8 | css_link asset("css/app.css")
9 | js_link asset("js/app.js"), defer: "true"
10 | csrf_meta_tags
11 | responsive_meta_tag
12 |
13 | # Development helper used with the `lucky watch` command.
14 | # Reloads the browser when files are updated.
15 | live_reload_connect_tag if LuckyEnv.development?
16 | end
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/fixtures/browser_src_template__generate_auth/expected/src/emails/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/browser_src_template__generate_auth/expected/src/emails/.keep
--------------------------------------------------------------------------------
/fixtures/browser_src_template__generate_auth/expected/src/js/app.js:
--------------------------------------------------------------------------------
1 | /* eslint no-console:0 */
2 |
3 | // Rails Unobtrusive JavaScript (UJS) is *required* for links in Lucky that use DELETE, POST and PUT.
4 | // Though it says "Rails" it actually works with any framework.
5 | import Rails from "@rails/ujs";
6 | Rails.start();
7 |
8 |
--------------------------------------------------------------------------------
/fixtures/browser_src_template__generate_auth/expected/src/models/mixins/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/browser_src_template__generate_auth/expected/src/models/mixins/.keep
--------------------------------------------------------------------------------
/fixtures/browser_src_template__generate_auth/expected/src/operations/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/browser_src_template__generate_auth/expected/src/operations/.keep
--------------------------------------------------------------------------------
/fixtures/browser_src_template__generate_auth/expected/src/operations/mixins/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/browser_src_template__generate_auth/expected/src/operations/mixins/.keep
--------------------------------------------------------------------------------
/fixtures/browser_src_template__generate_auth/expected/src/pages/main_layout.cr:
--------------------------------------------------------------------------------
1 | abstract class MainLayout
2 | include Lucky::HTMLPage
3 |
4 | abstract def content
5 | abstract def page_title
6 |
7 | # The default page title. It is passed to `Shared::LayoutHead`.
8 | #
9 | # Add a `page_title` method to pages to override it. You can also remove
10 | # This method so every page is required to have its own page title.
11 | def page_title
12 | "Welcome"
13 | end
14 |
15 | def render
16 | html_doctype
17 |
18 | html lang: "en" do
19 | mount Shared::LayoutHead, page_title: page_title
20 |
21 | body do
22 | mount Shared::FlashMessages, context.flash
23 | content
24 | end
25 | end
26 | end
27 | end
28 |
--------------------------------------------------------------------------------
/fixtures/cat.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/cat.gif
--------------------------------------------------------------------------------
/fixtures/hello_crystal.cr:
--------------------------------------------------------------------------------
1 | puts "Hello, Crystal!"
2 |
--------------------------------------------------------------------------------
/fixtures/hello_world.cr:
--------------------------------------------------------------------------------
1 | puts "Hello World!"
2 |
--------------------------------------------------------------------------------
/fixtures/shard_file_template__browser/expected/shard.yml:
--------------------------------------------------------------------------------
1 | ---
2 | name: test-shard
3 | version: 0.1.0
4 | targets:
5 | test-shard:
6 | main: src/test-shard.cr
7 | crystal: '>= 1.16.1'
8 | dependencies:
9 | lucky:
10 | github: luckyframework/lucky
11 | version: ~> 1.4.0
12 | avram:
13 | github: luckyframework/avram
14 | version: ~> 1.4.0
15 | carbon:
16 | github: luckyframework/carbon
17 | version: ~> 0.6.0
18 | carbon_sendgrid_adapter:
19 | github: luckyframework/carbon_sendgrid_adapter
20 | version: ~> 0.6.0
21 | lucky_env:
22 | github: luckyframework/lucky_env
23 | version: ~> 0.3.0
24 | lucky_task:
25 | github: luckyframework/lucky_task
26 | version: ~> 0.3.0
27 | development_dependencies:
28 | lucky_flow:
29 | github: luckyframework/lucky_flow
30 | version: ~> 0.10.0
31 |
--------------------------------------------------------------------------------
/fixtures/shard_file_template__generate_auth/expected/shard.yml:
--------------------------------------------------------------------------------
1 | ---
2 | name: test-shard
3 | version: 0.1.0
4 | targets:
5 | test-shard:
6 | main: src/test-shard.cr
7 | crystal: '>= 1.16.1'
8 | dependencies:
9 | lucky:
10 | github: luckyframework/lucky
11 | version: ~> 1.4.0
12 | avram:
13 | github: luckyframework/avram
14 | version: ~> 1.4.0
15 | carbon:
16 | github: luckyframework/carbon
17 | version: ~> 0.6.0
18 | carbon_sendgrid_adapter:
19 | github: luckyframework/carbon_sendgrid_adapter
20 | version: ~> 0.6.0
21 | lucky_env:
22 | github: luckyframework/lucky_env
23 | version: ~> 0.3.0
24 | lucky_task:
25 | github: luckyframework/lucky_task
26 | version: ~> 0.3.0
27 | authentic:
28 | github: luckyframework/authentic
29 | version: '>= 1.0.2, < 2.0.0'
30 | jwt:
31 | github: crystal-community/jwt
32 | version: ~> 1.6.1
33 | development_dependencies: {}
34 |
--------------------------------------------------------------------------------
/fixtures/shard_file_template__with_sec_tester/expected/shard.yml:
--------------------------------------------------------------------------------
1 | ---
2 | name: test-shard
3 | version: 0.1.0
4 | targets:
5 | test-shard:
6 | main: src/test-shard.cr
7 | crystal: '>= 1.16.1'
8 | dependencies:
9 | lucky:
10 | github: luckyframework/lucky
11 | version: ~> 1.4.0
12 | avram:
13 | github: luckyframework/avram
14 | version: ~> 1.4.0
15 | carbon:
16 | github: luckyframework/carbon
17 | version: ~> 0.6.0
18 | carbon_sendgrid_adapter:
19 | github: luckyframework/carbon_sendgrid_adapter
20 | version: ~> 0.6.0
21 | lucky_env:
22 | github: luckyframework/lucky_env
23 | version: ~> 0.3.0
24 | lucky_task:
25 | github: luckyframework/lucky_task
26 | version: ~> 0.3.0
27 | development_dependencies:
28 | lucky_sec_tester:
29 | github: luckyframework/lucky_sec_tester
30 | version: ~> 0.3.3
31 |
--------------------------------------------------------------------------------
/fixtures/src_template/expected/.crystal-version:
--------------------------------------------------------------------------------
1 | 1.16.1
2 |
--------------------------------------------------------------------------------
/fixtures/src_template/expected/.env:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/src_template/expected/.env
--------------------------------------------------------------------------------
/fixtures/src_template/expected/Procfile:
--------------------------------------------------------------------------------
1 | web: bin/app
2 | release: lucky db.migrate
3 |
--------------------------------------------------------------------------------
/fixtures/src_template/expected/Procfile.dev:
--------------------------------------------------------------------------------
1 | system_check: crystal script/system_check.cr
2 | web: lucky watch
3 |
--------------------------------------------------------------------------------
/fixtures/src_template/expected/README.md:
--------------------------------------------------------------------------------
1 | # test-project
2 |
3 | This is a project written using [Lucky](https://luckyframework.org). Enjoy!
4 |
5 | ### Setting up the project
6 |
7 | 1. [Install required dependencies](https://luckyframework.org/guides/getting-started/installing#install-required-dependencies)
8 | 1. Update database settings in `config/database.cr`
9 | 1. Run `script/setup`
10 | 1. Run `lucky dev` to start the app
11 |
12 | ### Using Docker for development
13 |
14 | 1. [Install Docker](https://docs.docker.com/engine/install/)
15 | 1. Run `docker compose up`
16 |
17 | The Docker container will boot all of the necessary components needed to run your Lucky application.
18 | To configure the container, update the `docker-compose.yml` file, and the `docker/development.dockerfile` file.
19 |
20 |
21 | ### Learning Lucky
22 |
23 | Lucky uses the [Crystal](https://crystal-lang.org) programming language. You can learn about Lucky from the [Lucky Guides](https://luckyframework.org/guides/getting-started/why-lucky).
24 |
--------------------------------------------------------------------------------
/fixtures/src_template/expected/config/application.cr:
--------------------------------------------------------------------------------
1 | # This file may be used for custom Application configurations.
2 | # It will be loaded before other config files.
3 | #
4 | # Read more on configuration:
5 | # https://luckyframework.org/guides/getting-started/configuration#configuring-your-own-code
6 |
7 | # Use this code as an example:
8 | #
9 | # ```
10 | # module Application
11 | # Habitat.create do
12 | # setting support_email : String
13 | # setting lock_with_basic_auth : Bool
14 | # end
15 | # end
16 | #
17 | # Application.configure do |settings|
18 | # settings.support_email = "support@myapp.io"
19 | # settings.lock_with_basic_auth = LuckyEnv.staging?
20 | # end
21 | #
22 | # # In your application, call
23 | # # `Application.settings.support_email` anywhere you need it.
24 | # ```
25 |
--------------------------------------------------------------------------------
/fixtures/src_template/expected/config/colors.cr:
--------------------------------------------------------------------------------
1 | # This enables the color output when in development or test
2 | # Check out the Colorize docs for more information
3 | # https://crystal-lang.org/api/Colorize.html
4 | Colorize.enabled = LuckyEnv.development? || LuckyEnv.test?
5 |
--------------------------------------------------------------------------------
/fixtures/src_template/expected/config/cookies.cr:
--------------------------------------------------------------------------------
1 | require "./server"
2 |
3 | Lucky::Session.configure do |settings|
4 | settings.key = "_test_project_session"
5 | end
6 |
7 | Lucky::CookieJar.configure do |settings|
8 | settings.on_set = ->(cookie : HTTP::Cookie) {
9 | # If ForceSSLHandler is enabled, only send cookies over HTTPS
10 | cookie.secure(Lucky::ForceSSLHandler.settings.enabled)
11 |
12 | # By default, don't allow reading cookies with JavaScript
13 | cookie.http_only(true)
14 |
15 | # Restrict cookies to a first-party or same-site context
16 | cookie.samesite(:lax)
17 |
18 | # Set all cookies to the root path by default
19 | cookie.path("/")
20 |
21 | # You can set other defaults for cookies here. For example:
22 | #
23 | # cookie.expires(1.year.from_now).domain("mydomain.com")
24 | }
25 | end
26 |
--------------------------------------------------------------------------------
/fixtures/src_template/expected/config/env.cr:
--------------------------------------------------------------------------------
1 | # Environments are managed using `LuckyEnv`. By default, development, production
2 | # and test are supported. See
3 | # https://luckyframework.org/guides/getting-started/configuration for details.
4 | #
5 | # The default environment is development unless the environment variable
6 | # LUCKY_ENV is set.
7 | #
8 | # Example:
9 | # ```
10 | # LuckyEnv.environment # => "development"
11 | # LuckyEnv.development? # => true
12 | # LuckyEnv.production? # => false
13 | # LuckyEnv.test? # => false
14 | # ```
15 | #
16 | # New environments can be added using the `LuckyEnv.add_env` macro.
17 | #
18 | # Example:
19 | # ```
20 | # LuckyEnv.add_env :staging
21 | # LuckyEnv.staging? # => false
22 | # ```
23 | #
24 | # To determine whether or not a `LuckyTask` is currently running, you can use
25 | # the `LuckyEnv.task?` predicate.
26 | #
27 | # Example:
28 | # ```
29 | # LuckyEnv.task? # => false
30 | # ```
31 |
32 | # Add a staging environment.
33 | # LuckyEnv.add_env :staging
34 |
--------------------------------------------------------------------------------
/fixtures/src_template/expected/config/error_handler.cr:
--------------------------------------------------------------------------------
1 | Lucky::ErrorHandler.configure do |settings|
2 | settings.show_debug_output = !LuckyEnv.production?
3 | end
4 |
--------------------------------------------------------------------------------
/fixtures/src_template/expected/config/route_helper.cr:
--------------------------------------------------------------------------------
1 | # This is used when generating URLs for your application
2 | Lucky::RouteHelper.configure do |settings|
3 | if LuckyEnv.production?
4 | # Example: https://my_app.com
5 | settings.base_uri = ENV.fetch("APP_DOMAIN")
6 | else
7 | # Set domain to the default host/port in development/test
8 | settings.base_uri = "http://localhost:#{Lucky::ServerSettings.port}"
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/fixtures/src_template/expected/config/watch.yml:
--------------------------------------------------------------------------------
1 | host: 127.0.0.1
2 | port: 3000
3 | reload_port: 3001
4 |
--------------------------------------------------------------------------------
/fixtures/src_template/expected/db/migrations/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/src_template/expected/db/migrations/.keep
--------------------------------------------------------------------------------
/fixtures/src_template/expected/docker/development.dockerfile:
--------------------------------------------------------------------------------
1 | FROM crystallang/crystal:1.16.1
2 |
3 | # Install utilities required to make this Dockerfile run
4 | RUN apt-get update && \
5 | apt-get install -y wget
6 |
7 | # Apt installs:
8 | # - Postgres cli tools are required for lucky-cli.
9 | # - tmux is required for the Overmind process manager.
10 | RUN apt-get update && \
11 | apt-get install -y postgresql-client tmux && \
12 | rm -rf /var/lib/apt/lists/*
13 |
14 | # Install lucky cli
15 | WORKDIR /lucky/cli
16 | RUN git clone https://github.com/luckyframework/lucky_cli . && \
17 | git checkout v1.3.0 && \
18 | shards build --without-development && \
19 | cp bin/lucky /usr/bin
20 |
21 | WORKDIR /app
22 | ENV DATABASE_URL=postgres://postgres:postgres@host.docker.internal:5432/postgres
23 | EXPOSE 3000
24 | EXPOSE 3001
25 |
26 |
--------------------------------------------------------------------------------
/fixtures/src_template/expected/script/helpers/function_helpers.cr:
--------------------------------------------------------------------------------
1 | require "colorize"
2 |
3 | # These are helper methods provided to help keep your code
4 | # clean. Add new methods, or alter these as needed.
5 |
6 | def notice(message : String) : Nil
7 | puts "\n▸ #{message}"
8 | end
9 |
10 | def print_done : Nil
11 | puts "✔ Done"
12 | end
13 |
14 | def print_error(message : String) : Nil
15 | puts "There is a problem with your system setup:\n".colorize.red.bold
16 | puts "#{message}\n".colorize.red.bold
17 | Process.exit(1)
18 | end
19 |
20 | def command_not_found(command : String) : Bool
21 | Process.find_executable(command).nil?
22 | end
23 |
24 | def command_not_running(command : String, *args) : Bool
25 | output = IO::Memory.new
26 | code = Process.run(command, args, output: output).exit_code
27 | code > 0
28 | end
29 |
30 | def run_command(command : String, *args) : Nil
31 | Process.run(command, args, output: STDOUT, error: STDERR, input: STDIN)
32 | end
33 |
--------------------------------------------------------------------------------
/fixtures/src_template/expected/script/setup.cr:
--------------------------------------------------------------------------------
1 | require "./helpers/*"
2 |
3 | notice "Running System Check"
4 |
5 | require "./system_check"
6 |
7 | print_done
8 |
9 |
10 | notice "Installing shards"
11 | run_command "shards", "install"
12 |
13 | if !File.exists?(".env")
14 | notice "No .env found. Creating one."
15 | File.touch ".env"
16 | print_done
17 | end
18 |
19 | notice "Setting up the database"
20 |
21 | run_command "lucky", "db.setup"
22 |
23 | notice "Seeding the database with required and sample records"
24 | run_command "lucky", "db.seed.required_data"
25 | run_command "lucky", "db.seed.sample_data"
26 |
27 | print_done
28 | notice "Run 'lucky dev' to start the app"
29 |
--------------------------------------------------------------------------------
/fixtures/src_template/expected/script/system_check.cr:
--------------------------------------------------------------------------------
1 | require "./helpers/*"
2 |
3 | # Use this script to check the system for required tools and process that your app needs.
4 | # A few helper functions are provided to keep the code simple. See the
5 | # script/helpers/function_helpers.cr file for more examples.
6 | #
7 | # A few examples you might use here:
8 | # * 'lucky db.verify_connection' to test postgres can be connected
9 | # * Checking that elasticsearch, redis, or postgres is installed and/or booted
10 | # * Note: Booting additional processes for things like mail, background jobs, etc...
11 | # should go in your Procfile.dev.
12 |
13 |
14 | # CUSTOM PRE-BOOT CHECKS
15 | # example:
16 | # if command_not_running "redis-cli", "ping"
17 | # print_error "Redis is not running."
18 | # end
19 |
--------------------------------------------------------------------------------
/fixtures/src_template/expected/spec/setup/clean_database.cr:
--------------------------------------------------------------------------------
1 | Spec.before_each do
2 | AppDatabase.truncate
3 | end
4 |
--------------------------------------------------------------------------------
/fixtures/src_template/expected/spec/setup/reset_emails.cr:
--------------------------------------------------------------------------------
1 | Spec.before_each do
2 | Carbon::DevAdapter.reset
3 | end
4 |
--------------------------------------------------------------------------------
/fixtures/src_template/expected/spec/setup/setup_database.cr:
--------------------------------------------------------------------------------
1 | Db::Create.new(quiet: true).call
2 | Db::Migrate.new(quiet: true).call
3 |
--------------------------------------------------------------------------------
/fixtures/src_template/expected/spec/setup/start_app_server.cr:
--------------------------------------------------------------------------------
1 | app_server = AppServer.new
2 |
3 | spawn do
4 | app_server.listen
5 | end
6 |
7 | Spec.after_suite do
8 | app_server.close
9 | end
10 |
--------------------------------------------------------------------------------
/fixtures/src_template/expected/spec/spec_helper.cr:
--------------------------------------------------------------------------------
1 | ENV["LUCKY_ENV"] = "test"
2 | ENV["DEV_PORT"] = "5001"
3 | require "spec"
4 | require "../src/app"
5 | require "./support/**"
6 | require "../db/migrations/**"
7 |
8 | # Add/modify files in spec/setup to start/configure programs or run hooks
9 | #
10 | # By default there are scripts for setting up and cleaning the database,
11 | # configuring LuckyFlow, starting the app server, etc.
12 | require "./setup/**"
13 |
14 | include Carbon::Expectations
15 | include Lucky::RequestExpectations
16 |
17 | Avram::Migrator::Runner.new.ensure_migrated!
18 | Avram::SchemaEnforcer.ensure_correct_column_mappings!
19 | Habitat.raise_if_missing_settings!
20 |
--------------------------------------------------------------------------------
/fixtures/src_template/expected/spec/support/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/src_template/expected/spec/support/.keep
--------------------------------------------------------------------------------
/fixtures/src_template/expected/spec/support/api_client.cr:
--------------------------------------------------------------------------------
1 | class ApiClient < Lucky::BaseHTTPClient
2 | app AppServer.new
3 |
4 | def initialize
5 | super
6 | headers("Content-Type": "application/json")
7 | end
8 |
9 | def self.auth(user : User)
10 | new.headers("Authorization": UserToken.generate(user))
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/fixtures/src_template/expected/spec/support/factories/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/src_template/expected/spec/support/factories/.keep
--------------------------------------------------------------------------------
/fixtures/src_template/expected/src/actions/api_action.cr:
--------------------------------------------------------------------------------
1 | # Include modules and add methods that are for all API requests
2 | abstract class ApiAction < Lucky::Action
3 | # APIs typically do not need to send cookie/session data.
4 | # Remove this line if you want to send cookies in the response header.
5 | disable_cookies
6 | accepted_formats [:json]
7 |
8 | include Api::Auth::Helpers
9 |
10 | # By default all actions require sign in.
11 | # Add 'include Api::Auth::SkipRequireAuthToken' to your actions to allow all requests.
12 | include Api::Auth::RequireAuthToken
13 |
14 | # By default all actions are required to use underscores to separate words.
15 | # Add 'include Lucky::SkipRouteStyleCheck' to your actions if you wish to ignore this check for specific routes.
16 | include Lucky::EnforceUnderscoredRoute
17 | end
18 |
--------------------------------------------------------------------------------
/fixtures/src_template/expected/src/actions/home/index.cr:
--------------------------------------------------------------------------------
1 | class Home::Index < ApiAction
2 | include Api::Auth::SkipRequireAuthToken
3 |
4 | get "/" do
5 | json({hello: "Hello World from Home::Index"})
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/fixtures/src_template/expected/src/actions/mixins/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/src_template/expected/src/actions/mixins/.keep
--------------------------------------------------------------------------------
/fixtures/src_template/expected/src/app.cr:
--------------------------------------------------------------------------------
1 | require "./shards"
2 |
3 | require "../config/server"
4 | require "./app_database"
5 | require "../config/**"
6 | require "./models/base_model"
7 | require "./models/mixins/**"
8 | require "./models/**"
9 | require "./queries/mixins/**"
10 | require "./queries/**"
11 | require "./operations/mixins/**"
12 | require "./operations/**"
13 | require "./serializers/base_serializer"
14 | require "./serializers/**"
15 | require "./emails/base_email"
16 | require "./emails/**"
17 | require "./actions/mixins/**"
18 | require "./actions/**"
19 | require "../db/migrations/**"
20 | require "./app_server"
21 |
--------------------------------------------------------------------------------
/fixtures/src_template/expected/src/app_database.cr:
--------------------------------------------------------------------------------
1 | class AppDatabase < Avram::Database
2 | end
3 |
--------------------------------------------------------------------------------
/fixtures/src_template/expected/src/app_server.cr:
--------------------------------------------------------------------------------
1 | class AppServer < Lucky::BaseAppServer
2 | # Learn about middleware with HTTP::Handlers:
3 | # https://luckyframework.org/guides/http-and-routing/http-handlers
4 | def middleware : Array(HTTP::Handler)
5 | [
6 | Lucky::RequestIdHandler.new,
7 | Lucky::ForceSSLHandler.new,
8 | Lucky::HttpMethodOverrideHandler.new,
9 | Lucky::LogHandler.new,
10 | Lucky::ErrorHandler.new(action: Errors::Show),
11 | Lucky::RemoteIpHandler.new,
12 | Lucky::RouteHandler.new,
13 |
14 | # Disabled in API mode:
15 | # Lucky::StaticCompressionHandler.new("./public", file_ext: "gz", content_encoding: "gzip"),
16 | # Lucky::StaticFileHandler.new("./public", fallthrough: false, directory_listing: false),
17 | Lucky::RouteNotFoundHandler.new,
18 | ] of HTTP::Handler
19 | end
20 |
21 | def protocol
22 | "http"
23 | end
24 |
25 | def listen
26 | server.listen(host, port, reuse_port: false)
27 | end
28 | end
29 |
--------------------------------------------------------------------------------
/fixtures/src_template/expected/src/emails/base_email.cr:
--------------------------------------------------------------------------------
1 | # Learn about sending emails
2 | # https://luckyframework.org/guides/emails/sending-emails-with-carbon
3 | abstract class BaseEmail < Carbon::Email
4 | # You can add defaults using the 'inherited' hook
5 | #
6 | # Example:
7 | #
8 | # macro inherited
9 | # from default_from
10 | # end
11 | #
12 | # def default_from
13 | # Carbon::Address.new("support@app.com")
14 | # end
15 | end
16 |
--------------------------------------------------------------------------------
/fixtures/src_template/expected/src/models/base_model.cr:
--------------------------------------------------------------------------------
1 | abstract class BaseModel < Avram::Model
2 | def self.database : Avram::Database.class
3 | AppDatabase
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/fixtures/src_template/expected/src/models/mixins/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/src_template/expected/src/models/mixins/.keep
--------------------------------------------------------------------------------
/fixtures/src_template/expected/src/operations/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/src_template/expected/src/operations/.keep
--------------------------------------------------------------------------------
/fixtures/src_template/expected/src/operations/mixins/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/src_template/expected/src/operations/mixins/.keep
--------------------------------------------------------------------------------
/fixtures/src_template/expected/src/queries/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/src_template/expected/src/queries/.keep
--------------------------------------------------------------------------------
/fixtures/src_template/expected/src/queries/mixins/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/src_template/expected/src/queries/mixins/.keep
--------------------------------------------------------------------------------
/fixtures/src_template/expected/src/serializers/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/src_template/expected/src/serializers/.keep
--------------------------------------------------------------------------------
/fixtures/src_template/expected/src/serializers/base_serializer.cr:
--------------------------------------------------------------------------------
1 | abstract class BaseSerializer
2 | include Lucky::Serializable
3 |
4 | def self.for_collection(collection : Enumerable, *args, **named_args) : Array(self)
5 | collection.map do |object|
6 | new(object, *args, **named_args)
7 | end
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/fixtures/src_template/expected/src/serializers/error_serializer.cr:
--------------------------------------------------------------------------------
1 | # This is the default error serializer generated by Lucky.
2 | # Feel free to customize it in any way you like.
3 | class ErrorSerializer < BaseSerializer
4 | def initialize(
5 | @message : String,
6 | @details : String? = nil,
7 | @param : String? = nil, # so you can track which param (if any) caused the problem
8 | )
9 | end
10 |
11 | def render
12 | {message: @message, param: @param, details: @details}
13 | end
14 | end
15 |
--------------------------------------------------------------------------------
/fixtures/src_template/expected/src/shards.cr:
--------------------------------------------------------------------------------
1 | # Load .env file before any other config or app code
2 | require "lucky_env"
3 | LuckyEnv.load?(".env")
4 |
5 | # Require your shards here
6 | require "lucky"
7 | require "avram/lucky"
8 | require "carbon"
9 | require "authentic"
10 | require "jwt"
11 |
--------------------------------------------------------------------------------
/fixtures/src_template/expected/src/start_server.cr:
--------------------------------------------------------------------------------
1 | require "./app"
2 |
3 | Habitat.raise_if_missing_settings!
4 |
5 | if LuckyEnv.development?
6 | Avram::Migrator::Runner.new.ensure_migrated!
7 | Avram::SchemaEnforcer.ensure_correct_column_mappings!
8 | end
9 |
10 | app_server = AppServer.new
11 | puts "Listening on http://#{app_server.host}:#{app_server.port}"
12 |
13 | Signal::INT.trap do
14 | app_server.close
15 | end
16 |
17 | app_server.listen
18 |
--------------------------------------------------------------------------------
/fixtures/src_template/expected/src/test_project.cr:
--------------------------------------------------------------------------------
1 | # Typically you will not use or modify this file. 'shards build' and some
2 | # other crystal tools will sometimes use this.
3 | #
4 | # When this file is compiled/run it will require and run 'start_server',
5 | # which as its name implies will start the server for you app.
6 | require "./start_server"
7 |
--------------------------------------------------------------------------------
/fixtures/src_template/expected/tasks.cr:
--------------------------------------------------------------------------------
1 | # This file loads your app and all your tasks when running 'lucky'
2 | #
3 | # Run 'lucky --help' to see all available tasks.
4 | #
5 | # Learn to create your own tasks:
6 | # https://luckyframework.org/guides/command-line-tasks/custom-tasks
7 |
8 | # See `LuckyEnv#task?`
9 | ENV["LUCKY_TASK"] = "true"
10 |
11 | # Load Lucky and the app (actions, models, etc.)
12 | require "./src/app"
13 | require "lucky_task"
14 |
15 | # You can add your own tasks here in the ./tasks folder
16 | require "./tasks/**"
17 |
18 | # Load migrations
19 | require "./db/migrations/**"
20 |
21 | # Load Lucky tasks (dev, routes, etc.)
22 | require "lucky/tasks/**"
23 | require "avram/lucky/tasks"
24 |
25 | LuckyTask::Runner.run
26 |
--------------------------------------------------------------------------------
/fixtures/src_template/expected/tasks/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/src_template/expected/tasks/.keep
--------------------------------------------------------------------------------
/fixtures/src_template__api_only/expected/.crystal-version:
--------------------------------------------------------------------------------
1 | 1.16.1
2 |
--------------------------------------------------------------------------------
/fixtures/src_template__api_only/expected/.env:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/src_template__api_only/expected/.env
--------------------------------------------------------------------------------
/fixtures/src_template__api_only/expected/Procfile:
--------------------------------------------------------------------------------
1 | web: bin/app
2 | release: lucky db.migrate
3 |
--------------------------------------------------------------------------------
/fixtures/src_template__api_only/expected/Procfile.dev:
--------------------------------------------------------------------------------
1 | system_check: crystal script/system_check.cr
2 | web: lucky watch
3 |
--------------------------------------------------------------------------------
/fixtures/src_template__api_only/expected/config/application.cr:
--------------------------------------------------------------------------------
1 | # This file may be used for custom Application configurations.
2 | # It will be loaded before other config files.
3 | #
4 | # Read more on configuration:
5 | # https://luckyframework.org/guides/getting-started/configuration#configuring-your-own-code
6 |
7 | # Use this code as an example:
8 | #
9 | # ```
10 | # module Application
11 | # Habitat.create do
12 | # setting support_email : String
13 | # setting lock_with_basic_auth : Bool
14 | # end
15 | # end
16 | #
17 | # Application.configure do |settings|
18 | # settings.support_email = "support@myapp.io"
19 | # settings.lock_with_basic_auth = LuckyEnv.staging?
20 | # end
21 | #
22 | # # In your application, call
23 | # # `Application.settings.support_email` anywhere you need it.
24 | # ```
25 |
--------------------------------------------------------------------------------
/fixtures/src_template__api_only/expected/config/colors.cr:
--------------------------------------------------------------------------------
1 | # This enables the color output when in development or test
2 | # Check out the Colorize docs for more information
3 | # https://crystal-lang.org/api/Colorize.html
4 | Colorize.enabled = LuckyEnv.development? || LuckyEnv.test?
5 |
--------------------------------------------------------------------------------
/fixtures/src_template__api_only/expected/config/cookies.cr:
--------------------------------------------------------------------------------
1 | require "./server"
2 |
3 | Lucky::Session.configure do |settings|
4 | settings.key = "_test_project_session"
5 | end
6 |
7 | Lucky::CookieJar.configure do |settings|
8 | settings.on_set = ->(cookie : HTTP::Cookie) {
9 | # If ForceSSLHandler is enabled, only send cookies over HTTPS
10 | cookie.secure(Lucky::ForceSSLHandler.settings.enabled)
11 |
12 | # By default, don't allow reading cookies with JavaScript
13 | cookie.http_only(true)
14 |
15 | # Restrict cookies to a first-party or same-site context
16 | cookie.samesite(:lax)
17 |
18 | # Set all cookies to the root path by default
19 | cookie.path("/")
20 |
21 | # You can set other defaults for cookies here. For example:
22 | #
23 | # cookie.expires(1.year.from_now).domain("mydomain.com")
24 | }
25 | end
26 |
--------------------------------------------------------------------------------
/fixtures/src_template__api_only/expected/config/env.cr:
--------------------------------------------------------------------------------
1 | # Environments are managed using `LuckyEnv`. By default, development, production
2 | # and test are supported. See
3 | # https://luckyframework.org/guides/getting-started/configuration for details.
4 | #
5 | # The default environment is development unless the environment variable
6 | # LUCKY_ENV is set.
7 | #
8 | # Example:
9 | # ```
10 | # LuckyEnv.environment # => "development"
11 | # LuckyEnv.development? # => true
12 | # LuckyEnv.production? # => false
13 | # LuckyEnv.test? # => false
14 | # ```
15 | #
16 | # New environments can be added using the `LuckyEnv.add_env` macro.
17 | #
18 | # Example:
19 | # ```
20 | # LuckyEnv.add_env :staging
21 | # LuckyEnv.staging? # => false
22 | # ```
23 | #
24 | # To determine whether or not a `LuckyTask` is currently running, you can use
25 | # the `LuckyEnv.task?` predicate.
26 | #
27 | # Example:
28 | # ```
29 | # LuckyEnv.task? # => false
30 | # ```
31 |
32 | # Add a staging environment.
33 | # LuckyEnv.add_env :staging
34 |
--------------------------------------------------------------------------------
/fixtures/src_template__api_only/expected/config/error_handler.cr:
--------------------------------------------------------------------------------
1 | Lucky::ErrorHandler.configure do |settings|
2 | settings.show_debug_output = !LuckyEnv.production?
3 | end
4 |
--------------------------------------------------------------------------------
/fixtures/src_template__api_only/expected/config/route_helper.cr:
--------------------------------------------------------------------------------
1 | # This is used when generating URLs for your application
2 | Lucky::RouteHelper.configure do |settings|
3 | if LuckyEnv.production?
4 | # Example: https://my_app.com
5 | settings.base_uri = ENV.fetch("APP_DOMAIN")
6 | else
7 | # Set domain to the default host/port in development/test
8 | settings.base_uri = "http://localhost:#{Lucky::ServerSettings.port}"
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/fixtures/src_template__api_only/expected/config/watch.yml:
--------------------------------------------------------------------------------
1 | host: 127.0.0.1
2 | port: 3000
3 | reload_port: 3001
4 |
--------------------------------------------------------------------------------
/fixtures/src_template__api_only/expected/db/migrations/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/src_template__api_only/expected/db/migrations/.keep
--------------------------------------------------------------------------------
/fixtures/src_template__api_only/expected/docker/development.dockerfile:
--------------------------------------------------------------------------------
1 | FROM crystallang/crystal:1.16.1
2 |
3 | # Install utilities required to make this Dockerfile run
4 | RUN apt-get update && \
5 | apt-get install -y wget
6 |
7 | # Apt installs:
8 | # - Postgres cli tools are required for lucky-cli.
9 | # - tmux is required for the Overmind process manager.
10 | RUN apt-get update && \
11 | apt-get install -y postgresql-client tmux && \
12 | rm -rf /var/lib/apt/lists/*
13 |
14 | # Install lucky cli
15 | WORKDIR /lucky/cli
16 | RUN git clone https://github.com/luckyframework/lucky_cli . && \
17 | git checkout v1.3.0 && \
18 | shards build --without-development && \
19 | cp bin/lucky /usr/bin
20 |
21 | WORKDIR /app
22 | ENV DATABASE_URL=postgres://postgres:postgres@host.docker.internal:5432/postgres
23 | EXPOSE 3000
24 | EXPOSE 3001
25 |
26 |
--------------------------------------------------------------------------------
/fixtures/src_template__api_only/expected/script/helpers/function_helpers.cr:
--------------------------------------------------------------------------------
1 | require "colorize"
2 |
3 | # These are helper methods provided to help keep your code
4 | # clean. Add new methods, or alter these as needed.
5 |
6 | def notice(message : String) : Nil
7 | puts "\n▸ #{message}"
8 | end
9 |
10 | def print_done : Nil
11 | puts "✔ Done"
12 | end
13 |
14 | def print_error(message : String) : Nil
15 | puts "There is a problem with your system setup:\n".colorize.red.bold
16 | puts "#{message}\n".colorize.red.bold
17 | Process.exit(1)
18 | end
19 |
20 | def command_not_found(command : String) : Bool
21 | Process.find_executable(command).nil?
22 | end
23 |
24 | def command_not_running(command : String, *args) : Bool
25 | output = IO::Memory.new
26 | code = Process.run(command, args, output: output).exit_code
27 | code > 0
28 | end
29 |
30 | def run_command(command : String, *args) : Nil
31 | Process.run(command, args, output: STDOUT, error: STDERR, input: STDIN)
32 | end
33 |
--------------------------------------------------------------------------------
/fixtures/src_template__api_only/expected/script/setup.cr:
--------------------------------------------------------------------------------
1 | require "./helpers/*"
2 |
3 | notice "Running System Check"
4 |
5 | require "./system_check"
6 |
7 | print_done
8 |
9 |
10 | notice "Installing shards"
11 | run_command "shards", "install"
12 |
13 | if !File.exists?(".env")
14 | notice "No .env found. Creating one."
15 | File.touch ".env"
16 | print_done
17 | end
18 |
19 | notice "Setting up the database"
20 |
21 | run_command "lucky", "db.setup"
22 |
23 | notice "Seeding the database with required and sample records"
24 | run_command "lucky", "db.seed.required_data"
25 | run_command "lucky", "db.seed.sample_data"
26 |
27 | print_done
28 | notice "Run 'lucky dev' to start the app"
29 |
--------------------------------------------------------------------------------
/fixtures/src_template__api_only/expected/script/system_check.cr:
--------------------------------------------------------------------------------
1 | require "./helpers/*"
2 |
3 | # Use this script to check the system for required tools and process that your app needs.
4 | # A few helper functions are provided to keep the code simple. See the
5 | # script/helpers/function_helpers.cr file for more examples.
6 | #
7 | # A few examples you might use here:
8 | # * 'lucky db.verify_connection' to test postgres can be connected
9 | # * Checking that elasticsearch, redis, or postgres is installed and/or booted
10 | # * Note: Booting additional processes for things like mail, background jobs, etc...
11 | # should go in your Procfile.dev.
12 |
13 |
14 | # CUSTOM PRE-BOOT CHECKS
15 | # example:
16 | # if command_not_running "redis-cli", "ping"
17 | # print_error "Redis is not running."
18 | # end
19 |
--------------------------------------------------------------------------------
/fixtures/src_template__api_only/expected/spec/setup/clean_database.cr:
--------------------------------------------------------------------------------
1 | Spec.before_each do
2 | AppDatabase.truncate
3 | end
4 |
--------------------------------------------------------------------------------
/fixtures/src_template__api_only/expected/spec/setup/reset_emails.cr:
--------------------------------------------------------------------------------
1 | Spec.before_each do
2 | Carbon::DevAdapter.reset
3 | end
4 |
--------------------------------------------------------------------------------
/fixtures/src_template__api_only/expected/spec/setup/setup_database.cr:
--------------------------------------------------------------------------------
1 | Db::Create.new(quiet: true).call
2 | Db::Migrate.new(quiet: true).call
3 |
--------------------------------------------------------------------------------
/fixtures/src_template__api_only/expected/spec/setup/start_app_server.cr:
--------------------------------------------------------------------------------
1 | app_server = AppServer.new
2 |
3 | spawn do
4 | app_server.listen
5 | end
6 |
7 | Spec.after_suite do
8 | app_server.close
9 | end
10 |
--------------------------------------------------------------------------------
/fixtures/src_template__api_only/expected/spec/spec_helper.cr:
--------------------------------------------------------------------------------
1 | ENV["LUCKY_ENV"] = "test"
2 | ENV["DEV_PORT"] = "5001"
3 | require "spec"
4 | require "../src/app"
5 | require "./support/**"
6 | require "../db/migrations/**"
7 |
8 | # Add/modify files in spec/setup to start/configure programs or run hooks
9 | #
10 | # By default there are scripts for setting up and cleaning the database,
11 | # configuring LuckyFlow, starting the app server, etc.
12 | require "./setup/**"
13 |
14 | include Carbon::Expectations
15 | include Lucky::RequestExpectations
16 |
17 | Avram::Migrator::Runner.new.ensure_migrated!
18 | Avram::SchemaEnforcer.ensure_correct_column_mappings!
19 | Habitat.raise_if_missing_settings!
20 |
--------------------------------------------------------------------------------
/fixtures/src_template__api_only/expected/spec/support/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/src_template__api_only/expected/spec/support/.keep
--------------------------------------------------------------------------------
/fixtures/src_template__api_only/expected/spec/support/api_client.cr:
--------------------------------------------------------------------------------
1 | class ApiClient < Lucky::BaseHTTPClient
2 | app AppServer.new
3 |
4 | def initialize
5 | super
6 | headers("Content-Type": "application/json")
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/fixtures/src_template__api_only/expected/spec/support/factories/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/src_template__api_only/expected/spec/support/factories/.keep
--------------------------------------------------------------------------------
/fixtures/src_template__api_only/expected/src/actions/api_action.cr:
--------------------------------------------------------------------------------
1 | # Include modules and add methods that are for all API requests
2 | abstract class ApiAction < Lucky::Action
3 | # APIs typically do not need to send cookie/session data.
4 | # Remove this line if you want to send cookies in the response header.
5 | disable_cookies
6 | accepted_formats [:json]
7 |
8 | # By default all actions are required to use underscores to separate words.
9 | # Add 'include Lucky::SkipRouteStyleCheck' to your actions if you wish to ignore this check for specific routes.
10 | include Lucky::EnforceUnderscoredRoute
11 | end
12 |
--------------------------------------------------------------------------------
/fixtures/src_template__api_only/expected/src/actions/home/index.cr:
--------------------------------------------------------------------------------
1 | class Home::Index < ApiAction
2 | get "/" do
3 | json({hello: "Hello World from Home::Index"})
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/fixtures/src_template__api_only/expected/src/actions/mixins/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/src_template__api_only/expected/src/actions/mixins/.keep
--------------------------------------------------------------------------------
/fixtures/src_template__api_only/expected/src/app.cr:
--------------------------------------------------------------------------------
1 | require "./shards"
2 |
3 | require "../config/server"
4 | require "./app_database"
5 | require "../config/**"
6 | require "./models/base_model"
7 | require "./models/mixins/**"
8 | require "./models/**"
9 | require "./queries/mixins/**"
10 | require "./queries/**"
11 | require "./operations/mixins/**"
12 | require "./operations/**"
13 | require "./serializers/base_serializer"
14 | require "./serializers/**"
15 | require "./emails/base_email"
16 | require "./emails/**"
17 | require "./actions/mixins/**"
18 | require "./actions/**"
19 | require "../db/migrations/**"
20 | require "./app_server"
21 |
--------------------------------------------------------------------------------
/fixtures/src_template__api_only/expected/src/app_database.cr:
--------------------------------------------------------------------------------
1 | class AppDatabase < Avram::Database
2 | end
3 |
--------------------------------------------------------------------------------
/fixtures/src_template__api_only/expected/src/emails/base_email.cr:
--------------------------------------------------------------------------------
1 | # Learn about sending emails
2 | # https://luckyframework.org/guides/emails/sending-emails-with-carbon
3 | abstract class BaseEmail < Carbon::Email
4 | # You can add defaults using the 'inherited' hook
5 | #
6 | # Example:
7 | #
8 | # macro inherited
9 | # from default_from
10 | # end
11 | #
12 | # def default_from
13 | # Carbon::Address.new("support@app.com")
14 | # end
15 | end
16 |
--------------------------------------------------------------------------------
/fixtures/src_template__api_only/expected/src/models/base_model.cr:
--------------------------------------------------------------------------------
1 | abstract class BaseModel < Avram::Model
2 | def self.database : Avram::Database.class
3 | AppDatabase
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/fixtures/src_template__api_only/expected/src/models/mixins/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/src_template__api_only/expected/src/models/mixins/.keep
--------------------------------------------------------------------------------
/fixtures/src_template__api_only/expected/src/operations/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/src_template__api_only/expected/src/operations/.keep
--------------------------------------------------------------------------------
/fixtures/src_template__api_only/expected/src/operations/mixins/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/src_template__api_only/expected/src/operations/mixins/.keep
--------------------------------------------------------------------------------
/fixtures/src_template__api_only/expected/src/queries/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/src_template__api_only/expected/src/queries/.keep
--------------------------------------------------------------------------------
/fixtures/src_template__api_only/expected/src/queries/mixins/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/src_template__api_only/expected/src/queries/mixins/.keep
--------------------------------------------------------------------------------
/fixtures/src_template__api_only/expected/src/serializers/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/src_template__api_only/expected/src/serializers/.keep
--------------------------------------------------------------------------------
/fixtures/src_template__api_only/expected/src/serializers/base_serializer.cr:
--------------------------------------------------------------------------------
1 | abstract class BaseSerializer
2 | include Lucky::Serializable
3 |
4 | def self.for_collection(collection : Enumerable, *args, **named_args) : Array(self)
5 | collection.map do |object|
6 | new(object, *args, **named_args)
7 | end
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/fixtures/src_template__api_only/expected/src/serializers/error_serializer.cr:
--------------------------------------------------------------------------------
1 | # This is the default error serializer generated by Lucky.
2 | # Feel free to customize it in any way you like.
3 | class ErrorSerializer < BaseSerializer
4 | def initialize(
5 | @message : String,
6 | @details : String? = nil,
7 | @param : String? = nil, # so you can track which param (if any) caused the problem
8 | )
9 | end
10 |
11 | def render
12 | {message: @message, param: @param, details: @details}
13 | end
14 | end
15 |
--------------------------------------------------------------------------------
/fixtures/src_template__api_only/expected/src/shards.cr:
--------------------------------------------------------------------------------
1 | # Load .env file before any other config or app code
2 | require "lucky_env"
3 | LuckyEnv.load?(".env")
4 |
5 | # Require your shards here
6 | require "lucky"
7 | require "avram/lucky"
8 | require "carbon"
9 |
--------------------------------------------------------------------------------
/fixtures/src_template__api_only/expected/src/start_server.cr:
--------------------------------------------------------------------------------
1 | require "./app"
2 |
3 | Habitat.raise_if_missing_settings!
4 |
5 | if LuckyEnv.development?
6 | Avram::Migrator::Runner.new.ensure_migrated!
7 | Avram::SchemaEnforcer.ensure_correct_column_mappings!
8 | end
9 |
10 | app_server = AppServer.new
11 | puts "Listening on http://#{app_server.host}:#{app_server.port}"
12 |
13 | Signal::INT.trap do
14 | app_server.close
15 | end
16 |
17 | app_server.listen
18 |
--------------------------------------------------------------------------------
/fixtures/src_template__api_only/expected/src/test_project.cr:
--------------------------------------------------------------------------------
1 | # Typically you will not use or modify this file. 'shards build' and some
2 | # other crystal tools will sometimes use this.
3 | #
4 | # When this file is compiled/run it will require and run 'start_server',
5 | # which as its name implies will start the server for you app.
6 | require "./start_server"
7 |
--------------------------------------------------------------------------------
/fixtures/src_template__api_only/expected/tasks.cr:
--------------------------------------------------------------------------------
1 | # This file loads your app and all your tasks when running 'lucky'
2 | #
3 | # Run 'lucky --help' to see all available tasks.
4 | #
5 | # Learn to create your own tasks:
6 | # https://luckyframework.org/guides/command-line-tasks/custom-tasks
7 |
8 | # See `LuckyEnv#task?`
9 | ENV["LUCKY_TASK"] = "true"
10 |
11 | # Load Lucky and the app (actions, models, etc.)
12 | require "./src/app"
13 | require "lucky_task"
14 |
15 | # You can add your own tasks here in the ./tasks folder
16 | require "./tasks/**"
17 |
18 | # Load migrations
19 | require "./db/migrations/**"
20 |
21 | # Load Lucky tasks (dev, routes, etc.)
22 | require "lucky/tasks/**"
23 | require "avram/lucky/tasks"
24 |
25 | LuckyTask::Runner.run
26 |
--------------------------------------------------------------------------------
/fixtures/src_template__api_only/expected/tasks/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/src_template__api_only/expected/tasks/.keep
--------------------------------------------------------------------------------
/fixtures/src_template__generate_auth/expected/.crystal-version:
--------------------------------------------------------------------------------
1 | 1.16.1
2 |
--------------------------------------------------------------------------------
/fixtures/src_template__generate_auth/expected/.env:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/src_template__generate_auth/expected/.env
--------------------------------------------------------------------------------
/fixtures/src_template__generate_auth/expected/Procfile:
--------------------------------------------------------------------------------
1 | web: bin/app
2 | release: lucky db.migrate
3 |
--------------------------------------------------------------------------------
/fixtures/src_template__generate_auth/expected/Procfile.dev:
--------------------------------------------------------------------------------
1 | system_check: crystal script/system_check.cr
2 | web: lucky watch --reload-browser
3 | assets: yarn watch
4 |
--------------------------------------------------------------------------------
/fixtures/src_template__generate_auth/expected/config/application.cr:
--------------------------------------------------------------------------------
1 | # This file may be used for custom Application configurations.
2 | # It will be loaded before other config files.
3 | #
4 | # Read more on configuration:
5 | # https://luckyframework.org/guides/getting-started/configuration#configuring-your-own-code
6 |
7 | # Use this code as an example:
8 | #
9 | # ```
10 | # module Application
11 | # Habitat.create do
12 | # setting support_email : String
13 | # setting lock_with_basic_auth : Bool
14 | # end
15 | # end
16 | #
17 | # Application.configure do |settings|
18 | # settings.support_email = "support@myapp.io"
19 | # settings.lock_with_basic_auth = LuckyEnv.staging?
20 | # end
21 | #
22 | # # In your application, call
23 | # # `Application.settings.support_email` anywhere you need it.
24 | # ```
25 |
--------------------------------------------------------------------------------
/fixtures/src_template__generate_auth/expected/config/colors.cr:
--------------------------------------------------------------------------------
1 | # This enables the color output when in development or test
2 | # Check out the Colorize docs for more information
3 | # https://crystal-lang.org/api/Colorize.html
4 | Colorize.enabled = LuckyEnv.development? || LuckyEnv.test?
5 |
--------------------------------------------------------------------------------
/fixtures/src_template__generate_auth/expected/config/cookies.cr:
--------------------------------------------------------------------------------
1 | require "./server"
2 |
3 | Lucky::Session.configure do |settings|
4 | settings.key = "_test_project_session"
5 | end
6 |
7 | Lucky::CookieJar.configure do |settings|
8 | settings.on_set = ->(cookie : HTTP::Cookie) {
9 | # If ForceSSLHandler is enabled, only send cookies over HTTPS
10 | cookie.secure(Lucky::ForceSSLHandler.settings.enabled)
11 |
12 | # By default, don't allow reading cookies with JavaScript
13 | cookie.http_only(true)
14 |
15 | # Restrict cookies to a first-party or same-site context
16 | cookie.samesite(:lax)
17 |
18 | # Set all cookies to the root path by default
19 | cookie.path("/")
20 |
21 | # You can set other defaults for cookies here. For example:
22 | #
23 | # cookie.expires(1.year.from_now).domain("mydomain.com")
24 | }
25 | end
26 |
--------------------------------------------------------------------------------
/fixtures/src_template__generate_auth/expected/config/error_handler.cr:
--------------------------------------------------------------------------------
1 | Lucky::ErrorHandler.configure do |settings|
2 | settings.show_debug_output = !LuckyEnv.production?
3 | end
4 |
--------------------------------------------------------------------------------
/fixtures/src_template__generate_auth/expected/config/route_helper.cr:
--------------------------------------------------------------------------------
1 | # This is used when generating URLs for your application
2 | Lucky::RouteHelper.configure do |settings|
3 | if LuckyEnv.production?
4 | # Example: https://my_app.com
5 | settings.base_uri = ENV.fetch("APP_DOMAIN")
6 | else
7 | # Set domain to the default host/port in development/test
8 | settings.base_uri = "http://localhost:#{Lucky::ServerSettings.port}"
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/fixtures/src_template__generate_auth/expected/config/watch.yml:
--------------------------------------------------------------------------------
1 | host: 127.0.0.1
2 | port: 3000
3 | reload_port: 3001
4 |
--------------------------------------------------------------------------------
/fixtures/src_template__generate_auth/expected/db/migrations/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/src_template__generate_auth/expected/db/migrations/.keep
--------------------------------------------------------------------------------
/fixtures/src_template__generate_auth/expected/script/helpers/function_helpers.cr:
--------------------------------------------------------------------------------
1 | require "colorize"
2 |
3 | # These are helper methods provided to help keep your code
4 | # clean. Add new methods, or alter these as needed.
5 |
6 | def notice(message : String) : Nil
7 | puts "\n▸ #{message}"
8 | end
9 |
10 | def print_done : Nil
11 | puts "✔ Done"
12 | end
13 |
14 | def print_error(message : String) : Nil
15 | puts "There is a problem with your system setup:\n".colorize.red.bold
16 | puts "#{message}\n".colorize.red.bold
17 | Process.exit(1)
18 | end
19 |
20 | def command_not_found(command : String) : Bool
21 | Process.find_executable(command).nil?
22 | end
23 |
24 | def command_not_running(command : String, *args) : Bool
25 | output = IO::Memory.new
26 | code = Process.run(command, args, output: output).exit_code
27 | code > 0
28 | end
29 |
30 | def run_command(command : String, *args) : Nil
31 | Process.run(command, args, output: STDOUT, error: STDERR, input: STDIN)
32 | end
33 |
--------------------------------------------------------------------------------
/fixtures/src_template__generate_auth/expected/script/setup.cr:
--------------------------------------------------------------------------------
1 | require "./helpers/*"
2 |
3 | notice "Running System Check"
4 |
5 | require "./system_check"
6 |
7 | print_done
8 |
9 | notice "Installing node dependencies"
10 | run_command "yarn", "install", "--no-progress"
11 |
12 | notice "Compiling assets"
13 | run_command "yarn", "dev"
14 |
15 | print_done
16 |
17 | notice "Installing shards"
18 | run_command "shards", "install"
19 |
20 | if !File.exists?(".env")
21 | notice "No .env found. Creating one."
22 | File.touch ".env"
23 | print_done
24 | end
25 |
26 | notice "Setting up the database"
27 |
28 | run_command "lucky", "db.setup"
29 |
30 | notice "Seeding the database with required and sample records"
31 | run_command "lucky", "db.seed.required_data"
32 | run_command "lucky", "db.seed.sample_data"
33 |
34 | print_done
35 | notice "Run 'lucky dev' to start the app"
36 |
--------------------------------------------------------------------------------
/fixtures/src_template__generate_auth/expected/script/system_check.cr:
--------------------------------------------------------------------------------
1 | require "./helpers/*"
2 |
3 | # Use this script to check the system for required tools and process that your app needs.
4 | # A few helper functions are provided to keep the code simple. See the
5 | # script/helpers/function_helpers.cr file for more examples.
6 | #
7 | # A few examples you might use here:
8 | # * 'lucky db.verify_connection' to test postgres can be connected
9 | # * Checking that elasticsearch, redis, or postgres is installed and/or booted
10 | # * Note: Booting additional processes for things like mail, background jobs, etc...
11 | # should go in your Procfile.dev.
12 |
13 | if command_not_found "yarn"
14 | print_error "Yarn is not installed\n See https://yarnpkg.com/lang/en/docs/install/ for install instructions."
15 | end
16 |
17 | # CUSTOM PRE-BOOT CHECKS
18 | # example:
19 | # if command_not_running "redis-cli", "ping"
20 | # print_error "Redis is not running."
21 | # end
22 |
--------------------------------------------------------------------------------
/fixtures/src_template__generate_auth/expected/spec/setup/clean_database.cr:
--------------------------------------------------------------------------------
1 | Spec.before_each do
2 | AppDatabase.truncate
3 | end
4 |
--------------------------------------------------------------------------------
/fixtures/src_template__generate_auth/expected/spec/setup/reset_emails.cr:
--------------------------------------------------------------------------------
1 | Spec.before_each do
2 | Carbon::DevAdapter.reset
3 | end
4 |
--------------------------------------------------------------------------------
/fixtures/src_template__generate_auth/expected/spec/setup/setup_database.cr:
--------------------------------------------------------------------------------
1 | Db::Create.new(quiet: true).call
2 | Db::Migrate.new(quiet: true).call
3 |
--------------------------------------------------------------------------------
/fixtures/src_template__generate_auth/expected/spec/setup/start_app_server.cr:
--------------------------------------------------------------------------------
1 | app_server = AppServer.new
2 |
3 | spawn do
4 | app_server.listen
5 | end
6 |
7 | Spec.after_suite do
8 | LuckyFlow.shutdown
9 | app_server.close
10 | end
11 |
--------------------------------------------------------------------------------
/fixtures/src_template__generate_auth/expected/spec/spec_helper.cr:
--------------------------------------------------------------------------------
1 | ENV["LUCKY_ENV"] = "test"
2 | ENV["DEV_PORT"] = "5001"
3 | require "spec"
4 | require "lucky_flow"
5 | require "lucky_flow/ext/lucky"
6 | require "lucky_flow/ext/avram"
7 |
8 | require "lucky_flow/ext/authentic"
9 | require "../src/app"
10 | require "./support/flows/base_flow"
11 | require "./support/**"
12 | require "../db/migrations/**"
13 |
14 | # Add/modify files in spec/setup to start/configure programs or run hooks
15 | #
16 | # By default there are scripts for setting up and cleaning the database,
17 | # configuring LuckyFlow, starting the app server, etc.
18 | require "./setup/**"
19 |
20 | include Carbon::Expectations
21 | include Lucky::RequestExpectations
22 | include LuckyFlow::Expectations
23 |
24 | Avram::Migrator::Runner.new.ensure_migrated!
25 | Avram::SchemaEnforcer.ensure_correct_column_mappings!
26 | Habitat.raise_if_missing_settings!
27 |
--------------------------------------------------------------------------------
/fixtures/src_template__generate_auth/expected/spec/support/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/src_template__generate_auth/expected/spec/support/.keep
--------------------------------------------------------------------------------
/fixtures/src_template__generate_auth/expected/spec/support/api_client.cr:
--------------------------------------------------------------------------------
1 | class ApiClient < Lucky::BaseHTTPClient
2 | app AppServer.new
3 |
4 | def initialize
5 | super
6 | headers("Content-Type": "application/json")
7 | end
8 |
9 | def self.auth(user : User)
10 | new.headers("Authorization": UserToken.generate(user))
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/fixtures/src_template__generate_auth/expected/spec/support/factories/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/src_template__generate_auth/expected/spec/support/factories/.keep
--------------------------------------------------------------------------------
/fixtures/src_template__generate_auth/expected/src/actions/api_action.cr:
--------------------------------------------------------------------------------
1 | # Include modules and add methods that are for all API requests
2 | abstract class ApiAction < Lucky::Action
3 | # APIs typically do not need to send cookie/session data.
4 | # Remove this line if you want to send cookies in the response header.
5 | disable_cookies
6 | accepted_formats [:json]
7 |
8 | include Api::Auth::Helpers
9 |
10 | # By default all actions require sign in.
11 | # Add 'include Api::Auth::SkipRequireAuthToken' to your actions to allow all requests.
12 | include Api::Auth::RequireAuthToken
13 |
14 | # By default all actions are required to use underscores to separate words.
15 | # Add 'include Lucky::SkipRouteStyleCheck' to your actions if you wish to ignore this check for specific routes.
16 | include Lucky::EnforceUnderscoredRoute
17 | end
18 |
--------------------------------------------------------------------------------
/fixtures/src_template__generate_auth/expected/src/actions/home/index.cr:
--------------------------------------------------------------------------------
1 | class Home::Index < BrowserAction
2 | include Auth::AllowGuests
3 |
4 | get "/" do
5 | if current_user?
6 | redirect Me::Show
7 | else
8 | # When you're ready change this line to:
9 | #
10 | # redirect SignIns::New
11 | #
12 | # Or maybe show signed out users a marketing page:
13 | #
14 | # html Marketing::IndexPage
15 | html Lucky::WelcomePage
16 | end
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/fixtures/src_template__generate_auth/expected/src/actions/mixins/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/src_template__generate_auth/expected/src/actions/mixins/.keep
--------------------------------------------------------------------------------
/fixtures/src_template__generate_auth/expected/src/app.cr:
--------------------------------------------------------------------------------
1 | require "./shards"
2 |
3 | # Load the asset manifest
4 | Lucky::AssetHelpers.load_manifest "public/mix-manifest.json"
5 |
6 | require "../config/server"
7 | require "./app_database"
8 | require "../config/**"
9 | require "./models/base_model"
10 | require "./models/mixins/**"
11 | require "./models/**"
12 | require "./queries/mixins/**"
13 | require "./queries/**"
14 | require "./operations/mixins/**"
15 | require "./operations/**"
16 | require "./serializers/base_serializer"
17 | require "./serializers/**"
18 | require "./emails/base_email"
19 | require "./emails/**"
20 | require "./actions/mixins/**"
21 | require "./actions/**"
22 | require "./components/base_component"
23 | require "./components/**"
24 | require "./pages/**"
25 | require "../db/migrations/**"
26 | require "./app_server"
27 |
--------------------------------------------------------------------------------
/fixtures/src_template__generate_auth/expected/src/app_database.cr:
--------------------------------------------------------------------------------
1 | class AppDatabase < Avram::Database
2 | end
3 |
--------------------------------------------------------------------------------
/fixtures/src_template__generate_auth/expected/src/app_server.cr:
--------------------------------------------------------------------------------
1 | class AppServer < Lucky::BaseAppServer
2 | # Learn about middleware with HTTP::Handlers:
3 | # https://luckyframework.org/guides/http-and-routing/http-handlers
4 | def middleware : Array(HTTP::Handler)
5 | [
6 | Lucky::RequestIdHandler.new,
7 | Lucky::ForceSSLHandler.new,
8 | Lucky::HttpMethodOverrideHandler.new,
9 | Lucky::LogHandler.new,
10 | Lucky::ErrorHandler.new(action: Errors::Show),
11 | Lucky::RemoteIpHandler.new,
12 | Lucky::RouteHandler.new,
13 | Lucky::StaticCompressionHandler.new("./public", file_ext: "gz", content_encoding: "gzip"),
14 | Lucky::StaticFileHandler.new("./public", fallthrough: false, directory_listing: false),
15 | Lucky::RouteNotFoundHandler.new,
16 | ] of HTTP::Handler
17 | end
18 |
19 | def protocol
20 | "http"
21 | end
22 |
23 | def listen
24 | server.listen(host, port, reuse_port: false)
25 | end
26 | end
27 |
--------------------------------------------------------------------------------
/fixtures/src_template__generate_auth/expected/src/emails/base_email.cr:
--------------------------------------------------------------------------------
1 | # Learn about sending emails
2 | # https://luckyframework.org/guides/emails/sending-emails-with-carbon
3 | abstract class BaseEmail < Carbon::Email
4 | # You can add defaults using the 'inherited' hook
5 | #
6 | # Example:
7 | #
8 | # macro inherited
9 | # from default_from
10 | # end
11 | #
12 | # def default_from
13 | # Carbon::Address.new("support@app.com")
14 | # end
15 | end
16 |
--------------------------------------------------------------------------------
/fixtures/src_template__generate_auth/expected/src/models/base_model.cr:
--------------------------------------------------------------------------------
1 | abstract class BaseModel < Avram::Model
2 | def self.database : Avram::Database.class
3 | AppDatabase
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/fixtures/src_template__generate_auth/expected/src/models/mixins/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/src_template__generate_auth/expected/src/models/mixins/.keep
--------------------------------------------------------------------------------
/fixtures/src_template__generate_auth/expected/src/operations/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/src_template__generate_auth/expected/src/operations/.keep
--------------------------------------------------------------------------------
/fixtures/src_template__generate_auth/expected/src/operations/mixins/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/src_template__generate_auth/expected/src/operations/mixins/.keep
--------------------------------------------------------------------------------
/fixtures/src_template__generate_auth/expected/src/queries/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/src_template__generate_auth/expected/src/queries/.keep
--------------------------------------------------------------------------------
/fixtures/src_template__generate_auth/expected/src/queries/mixins/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/src_template__generate_auth/expected/src/queries/mixins/.keep
--------------------------------------------------------------------------------
/fixtures/src_template__generate_auth/expected/src/serializers/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/src_template__generate_auth/expected/src/serializers/.keep
--------------------------------------------------------------------------------
/fixtures/src_template__generate_auth/expected/src/serializers/base_serializer.cr:
--------------------------------------------------------------------------------
1 | abstract class BaseSerializer
2 | include Lucky::Serializable
3 |
4 | def self.for_collection(collection : Enumerable, *args, **named_args) : Array(self)
5 | collection.map do |object|
6 | new(object, *args, **named_args)
7 | end
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/fixtures/src_template__generate_auth/expected/src/serializers/error_serializer.cr:
--------------------------------------------------------------------------------
1 | # This is the default error serializer generated by Lucky.
2 | # Feel free to customize it in any way you like.
3 | class ErrorSerializer < BaseSerializer
4 | def initialize(
5 | @message : String,
6 | @details : String? = nil,
7 | @param : String? = nil, # so you can track which param (if any) caused the problem
8 | )
9 | end
10 |
11 | def render
12 | {message: @message, param: @param, details: @details}
13 | end
14 | end
15 |
--------------------------------------------------------------------------------
/fixtures/src_template__generate_auth/expected/src/shards.cr:
--------------------------------------------------------------------------------
1 | # Load .env file before any other config or app code
2 | require "lucky_env"
3 | LuckyEnv.load?(".env")
4 |
5 | # Require your shards here
6 | require "lucky"
7 | require "avram/lucky"
8 | require "carbon"
9 | require "authentic"
10 | require "jwt"
11 |
--------------------------------------------------------------------------------
/fixtures/src_template__generate_auth/expected/src/start_server.cr:
--------------------------------------------------------------------------------
1 | require "./app"
2 |
3 | Habitat.raise_if_missing_settings!
4 |
5 | if LuckyEnv.development?
6 | Avram::Migrator::Runner.new.ensure_migrated!
7 | Avram::SchemaEnforcer.ensure_correct_column_mappings!
8 | end
9 |
10 | app_server = AppServer.new
11 |
12 | Signal::INT.trap do
13 | app_server.close
14 | end
15 |
16 | app_server.listen
17 |
--------------------------------------------------------------------------------
/fixtures/src_template__generate_auth/expected/src/test_project.cr:
--------------------------------------------------------------------------------
1 | # Typically you will not use or modify this file. 'shards build' and some
2 | # other crystal tools will sometimes use this.
3 | #
4 | # When this file is compiled/run it will require and run 'start_server',
5 | # which as its name implies will start the server for you app.
6 | require "./start_server"
7 |
--------------------------------------------------------------------------------
/fixtures/src_template__generate_auth/expected/tasks.cr:
--------------------------------------------------------------------------------
1 | # This file loads your app and all your tasks when running 'lucky'
2 | #
3 | # Run 'lucky --help' to see all available tasks.
4 | #
5 | # Learn to create your own tasks:
6 | # https://luckyframework.org/guides/command-line-tasks/custom-tasks
7 |
8 | # See `LuckyEnv#task?`
9 | ENV["LUCKY_TASK"] = "true"
10 |
11 | # Load Lucky and the app (actions, models, etc.)
12 | require "./src/app"
13 | require "lucky_task"
14 |
15 | # You can add your own tasks here in the ./tasks folder
16 | require "./tasks/**"
17 |
18 | # Load migrations
19 | require "./db/migrations/**"
20 |
21 | # Load Lucky tasks (dev, routes, etc.)
22 | require "lucky/tasks/**"
23 | require "avram/lucky/tasks"
24 |
25 | LuckyTask::Runner.run
26 |
--------------------------------------------------------------------------------
/fixtures/src_template__generate_auth/expected/tasks/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/src_template__generate_auth/expected/tasks/.keep
--------------------------------------------------------------------------------
/fixtures/src_template__sec_tester/expected/.crystal-version:
--------------------------------------------------------------------------------
1 | 1.16.1
2 |
--------------------------------------------------------------------------------
/fixtures/src_template__sec_tester/expected/.env:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/src_template__sec_tester/expected/.env
--------------------------------------------------------------------------------
/fixtures/src_template__sec_tester/expected/Procfile:
--------------------------------------------------------------------------------
1 | web: bin/app
2 | release: lucky db.migrate
3 |
--------------------------------------------------------------------------------
/fixtures/src_template__sec_tester/expected/Procfile.dev:
--------------------------------------------------------------------------------
1 | system_check: crystal script/system_check.cr
2 | web: lucky watch --reload-browser
3 | assets: yarn watch
4 |
--------------------------------------------------------------------------------
/fixtures/src_template__sec_tester/expected/config/application.cr:
--------------------------------------------------------------------------------
1 | # This file may be used for custom Application configurations.
2 | # It will be loaded before other config files.
3 | #
4 | # Read more on configuration:
5 | # https://luckyframework.org/guides/getting-started/configuration#configuring-your-own-code
6 |
7 | # Use this code as an example:
8 | #
9 | # ```
10 | # module Application
11 | # Habitat.create do
12 | # setting support_email : String
13 | # setting lock_with_basic_auth : Bool
14 | # end
15 | # end
16 | #
17 | # Application.configure do |settings|
18 | # settings.support_email = "support@myapp.io"
19 | # settings.lock_with_basic_auth = LuckyEnv.staging?
20 | # end
21 | #
22 | # # In your application, call
23 | # # `Application.settings.support_email` anywhere you need it.
24 | # ```
25 |
--------------------------------------------------------------------------------
/fixtures/src_template__sec_tester/expected/config/colors.cr:
--------------------------------------------------------------------------------
1 | # This enables the color output when in development or test
2 | # Check out the Colorize docs for more information
3 | # https://crystal-lang.org/api/Colorize.html
4 | Colorize.enabled = LuckyEnv.development? || LuckyEnv.test?
5 |
--------------------------------------------------------------------------------
/fixtures/src_template__sec_tester/expected/config/cookies.cr:
--------------------------------------------------------------------------------
1 | require "./server"
2 |
3 | Lucky::Session.configure do |settings|
4 | settings.key = "_test_project_session"
5 | end
6 |
7 | Lucky::CookieJar.configure do |settings|
8 | settings.on_set = ->(cookie : HTTP::Cookie) {
9 | # If ForceSSLHandler is enabled, only send cookies over HTTPS
10 | cookie.secure(Lucky::ForceSSLHandler.settings.enabled)
11 |
12 | # By default, don't allow reading cookies with JavaScript
13 | cookie.http_only(true)
14 |
15 | # Restrict cookies to a first-party or same-site context
16 | cookie.samesite(:lax)
17 |
18 | # Set all cookies to the root path by default
19 | cookie.path("/")
20 |
21 | # You can set other defaults for cookies here. For example:
22 | #
23 | # cookie.expires(1.year.from_now).domain("mydomain.com")
24 | }
25 | end
26 |
--------------------------------------------------------------------------------
/fixtures/src_template__sec_tester/expected/config/error_handler.cr:
--------------------------------------------------------------------------------
1 | Lucky::ErrorHandler.configure do |settings|
2 | settings.show_debug_output = !LuckyEnv.production?
3 | end
4 |
--------------------------------------------------------------------------------
/fixtures/src_template__sec_tester/expected/config/route_helper.cr:
--------------------------------------------------------------------------------
1 | # This is used when generating URLs for your application
2 | Lucky::RouteHelper.configure do |settings|
3 | if LuckyEnv.production?
4 | # Example: https://my_app.com
5 | settings.base_uri = ENV.fetch("APP_DOMAIN")
6 | else
7 | # Set domain to the default host/port in development/test
8 | settings.base_uri = "http://localhost:#{Lucky::ServerSettings.port}"
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/fixtures/src_template__sec_tester/expected/config/watch.yml:
--------------------------------------------------------------------------------
1 | host: 127.0.0.1
2 | port: 3000
3 | reload_port: 3001
4 |
--------------------------------------------------------------------------------
/fixtures/src_template__sec_tester/expected/db/migrations/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/src_template__sec_tester/expected/db/migrations/.keep
--------------------------------------------------------------------------------
/fixtures/src_template__sec_tester/expected/script/helpers/function_helpers.cr:
--------------------------------------------------------------------------------
1 | require "colorize"
2 |
3 | # These are helper methods provided to help keep your code
4 | # clean. Add new methods, or alter these as needed.
5 |
6 | def notice(message : String) : Nil
7 | puts "\n▸ #{message}"
8 | end
9 |
10 | def print_done : Nil
11 | puts "✔ Done"
12 | end
13 |
14 | def print_error(message : String) : Nil
15 | puts "There is a problem with your system setup:\n".colorize.red.bold
16 | puts "#{message}\n".colorize.red.bold
17 | Process.exit(1)
18 | end
19 |
20 | def command_not_found(command : String) : Bool
21 | Process.find_executable(command).nil?
22 | end
23 |
24 | def command_not_running(command : String, *args) : Bool
25 | output = IO::Memory.new
26 | code = Process.run(command, args, output: output).exit_code
27 | code > 0
28 | end
29 |
30 | def run_command(command : String, *args) : Nil
31 | Process.run(command, args, output: STDOUT, error: STDERR, input: STDIN)
32 | end
33 |
--------------------------------------------------------------------------------
/fixtures/src_template__sec_tester/expected/script/setup.cr:
--------------------------------------------------------------------------------
1 | require "./helpers/*"
2 |
3 | notice "Running System Check"
4 |
5 | require "./system_check"
6 |
7 | print_done
8 |
9 | notice "Installing node dependencies"
10 | run_command "yarn", "install", "--no-progress"
11 |
12 | notice "Compiling assets"
13 | run_command "yarn", "dev"
14 |
15 | print_done
16 |
17 | notice "Installing shards"
18 | run_command "shards", "install"
19 |
20 | if !File.exists?(".env")
21 | notice "No .env found. Creating one."
22 | File.touch ".env"
23 | print_done
24 | end
25 |
26 | notice "Setting up the database"
27 |
28 | run_command "lucky", "db.setup"
29 |
30 | notice "Seeding the database with required and sample records"
31 | run_command "lucky", "db.seed.required_data"
32 | run_command "lucky", "db.seed.sample_data"
33 |
34 | print_done
35 | notice "Run 'lucky dev' to start the app"
36 |
--------------------------------------------------------------------------------
/fixtures/src_template__sec_tester/expected/script/system_check.cr:
--------------------------------------------------------------------------------
1 | require "./helpers/*"
2 |
3 | # Use this script to check the system for required tools and process that your app needs.
4 | # A few helper functions are provided to keep the code simple. See the
5 | # script/helpers/function_helpers.cr file for more examples.
6 | #
7 | # A few examples you might use here:
8 | # * 'lucky db.verify_connection' to test postgres can be connected
9 | # * Checking that elasticsearch, redis, or postgres is installed and/or booted
10 | # * Note: Booting additional processes for things like mail, background jobs, etc...
11 | # should go in your Procfile.dev.
12 |
13 | if command_not_found "yarn"
14 | print_error "Yarn is not installed\n See https://yarnpkg.com/lang/en/docs/install/ for install instructions."
15 | end
16 |
17 | # CUSTOM PRE-BOOT CHECKS
18 | # example:
19 | # if command_not_running "redis-cli", "ping"
20 | # print_error "Redis is not running."
21 | # end
22 |
--------------------------------------------------------------------------------
/fixtures/src_template__sec_tester/expected/spec/setup/clean_database.cr:
--------------------------------------------------------------------------------
1 | Spec.before_each do
2 | AppDatabase.truncate
3 | end
4 |
--------------------------------------------------------------------------------
/fixtures/src_template__sec_tester/expected/spec/setup/reset_emails.cr:
--------------------------------------------------------------------------------
1 | Spec.before_each do
2 | Carbon::DevAdapter.reset
3 | end
4 |
--------------------------------------------------------------------------------
/fixtures/src_template__sec_tester/expected/spec/setup/setup_database.cr:
--------------------------------------------------------------------------------
1 | Db::Create.new(quiet: true).call
2 | Db::Migrate.new(quiet: true).call
3 |
--------------------------------------------------------------------------------
/fixtures/src_template__sec_tester/expected/spec/setup/start_app_server.cr:
--------------------------------------------------------------------------------
1 | app_server = AppServer.new
2 |
3 | spawn do
4 | app_server.listen
5 | end
6 |
7 | Spec.after_suite do
8 | LuckyFlow.shutdown
9 | app_server.close
10 | end
11 |
--------------------------------------------------------------------------------
/fixtures/src_template__sec_tester/expected/spec/spec_helper.cr:
--------------------------------------------------------------------------------
1 | ENV["LUCKY_ENV"] = "test"
2 | ENV["DEV_PORT"] = "5001"
3 | require "spec"
4 | require "lucky_flow"
5 | require "lucky_flow/ext/lucky"
6 | require "lucky_flow/ext/avram"
7 | require "../src/app"
8 | require "./support/flows/base_flow"
9 | require "./support/**"
10 | require "../db/migrations/**"
11 |
12 | # Add/modify files in spec/setup to start/configure programs or run hooks
13 | #
14 | # By default there are scripts for setting up and cleaning the database,
15 | # configuring LuckyFlow, starting the app server, etc.
16 | require "./setup/**"
17 |
18 | include Carbon::Expectations
19 | include Lucky::RequestExpectations
20 | include LuckyFlow::Expectations
21 |
22 | Avram::Migrator::Runner.new.ensure_migrated!
23 | Avram::SchemaEnforcer.ensure_correct_column_mappings!
24 | Habitat.raise_if_missing_settings!
25 |
--------------------------------------------------------------------------------
/fixtures/src_template__sec_tester/expected/spec/support/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/src_template__sec_tester/expected/spec/support/.keep
--------------------------------------------------------------------------------
/fixtures/src_template__sec_tester/expected/spec/support/api_client.cr:
--------------------------------------------------------------------------------
1 | class ApiClient < Lucky::BaseHTTPClient
2 | app AppServer.new
3 |
4 | def initialize
5 | super
6 | headers("Content-Type": "application/json")
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/fixtures/src_template__sec_tester/expected/spec/support/factories/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/src_template__sec_tester/expected/spec/support/factories/.keep
--------------------------------------------------------------------------------
/fixtures/src_template__sec_tester/expected/src/actions/api_action.cr:
--------------------------------------------------------------------------------
1 | # Include modules and add methods that are for all API requests
2 | abstract class ApiAction < Lucky::Action
3 | # APIs typically do not need to send cookie/session data.
4 | # Remove this line if you want to send cookies in the response header.
5 | disable_cookies
6 | accepted_formats [:json]
7 |
8 | # By default all actions are required to use underscores to separate words.
9 | # Add 'include Lucky::SkipRouteStyleCheck' to your actions if you wish to ignore this check for specific routes.
10 | include Lucky::EnforceUnderscoredRoute
11 | end
12 |
--------------------------------------------------------------------------------
/fixtures/src_template__sec_tester/expected/src/actions/home/index.cr:
--------------------------------------------------------------------------------
1 | class Home::Index < BrowserAction
2 | get "/" do
3 | html Lucky::WelcomePage
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/fixtures/src_template__sec_tester/expected/src/actions/mixins/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/src_template__sec_tester/expected/src/actions/mixins/.keep
--------------------------------------------------------------------------------
/fixtures/src_template__sec_tester/expected/src/app.cr:
--------------------------------------------------------------------------------
1 | require "./shards"
2 |
3 | # Load the asset manifest
4 | Lucky::AssetHelpers.load_manifest "public/mix-manifest.json"
5 |
6 | require "../config/server"
7 | require "./app_database"
8 | require "../config/**"
9 | require "./models/base_model"
10 | require "./models/mixins/**"
11 | require "./models/**"
12 | require "./queries/mixins/**"
13 | require "./queries/**"
14 | require "./operations/mixins/**"
15 | require "./operations/**"
16 | require "./serializers/base_serializer"
17 | require "./serializers/**"
18 | require "./emails/base_email"
19 | require "./emails/**"
20 | require "./actions/mixins/**"
21 | require "./actions/**"
22 | require "./components/base_component"
23 | require "./components/**"
24 | require "./pages/**"
25 | require "../db/migrations/**"
26 | require "./app_server"
27 |
--------------------------------------------------------------------------------
/fixtures/src_template__sec_tester/expected/src/app_database.cr:
--------------------------------------------------------------------------------
1 | class AppDatabase < Avram::Database
2 | end
3 |
--------------------------------------------------------------------------------
/fixtures/src_template__sec_tester/expected/src/app_server.cr:
--------------------------------------------------------------------------------
1 | class AppServer < Lucky::BaseAppServer
2 | # Learn about middleware with HTTP::Handlers:
3 | # https://luckyframework.org/guides/http-and-routing/http-handlers
4 | def middleware : Array(HTTP::Handler)
5 | [
6 | Lucky::RequestIdHandler.new,
7 | Lucky::ForceSSLHandler.new,
8 | Lucky::HttpMethodOverrideHandler.new,
9 | Lucky::LogHandler.new,
10 | Lucky::ErrorHandler.new(action: Errors::Show),
11 | Lucky::RemoteIpHandler.new,
12 | Lucky::RouteHandler.new,
13 | Lucky::StaticCompressionHandler.new("./public", file_ext: "gz", content_encoding: "gzip"),
14 | Lucky::StaticFileHandler.new("./public", fallthrough: false, directory_listing: false),
15 | Lucky::RouteNotFoundHandler.new,
16 | ] of HTTP::Handler
17 | end
18 |
19 | def protocol
20 | "http"
21 | end
22 |
23 | def listen
24 | server.listen(host, port, reuse_port: false)
25 | end
26 | end
27 |
--------------------------------------------------------------------------------
/fixtures/src_template__sec_tester/expected/src/emails/base_email.cr:
--------------------------------------------------------------------------------
1 | # Learn about sending emails
2 | # https://luckyframework.org/guides/emails/sending-emails-with-carbon
3 | abstract class BaseEmail < Carbon::Email
4 | # You can add defaults using the 'inherited' hook
5 | #
6 | # Example:
7 | #
8 | # macro inherited
9 | # from default_from
10 | # end
11 | #
12 | # def default_from
13 | # Carbon::Address.new("support@app.com")
14 | # end
15 | end
16 |
--------------------------------------------------------------------------------
/fixtures/src_template__sec_tester/expected/src/models/base_model.cr:
--------------------------------------------------------------------------------
1 | abstract class BaseModel < Avram::Model
2 | def self.database : Avram::Database.class
3 | AppDatabase
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/fixtures/src_template__sec_tester/expected/src/models/mixins/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/src_template__sec_tester/expected/src/models/mixins/.keep
--------------------------------------------------------------------------------
/fixtures/src_template__sec_tester/expected/src/operations/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/src_template__sec_tester/expected/src/operations/.keep
--------------------------------------------------------------------------------
/fixtures/src_template__sec_tester/expected/src/operations/mixins/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/src_template__sec_tester/expected/src/operations/mixins/.keep
--------------------------------------------------------------------------------
/fixtures/src_template__sec_tester/expected/src/queries/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/src_template__sec_tester/expected/src/queries/.keep
--------------------------------------------------------------------------------
/fixtures/src_template__sec_tester/expected/src/queries/mixins/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/src_template__sec_tester/expected/src/queries/mixins/.keep
--------------------------------------------------------------------------------
/fixtures/src_template__sec_tester/expected/src/serializers/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/src_template__sec_tester/expected/src/serializers/.keep
--------------------------------------------------------------------------------
/fixtures/src_template__sec_tester/expected/src/serializers/base_serializer.cr:
--------------------------------------------------------------------------------
1 | abstract class BaseSerializer
2 | include Lucky::Serializable
3 |
4 | def self.for_collection(collection : Enumerable, *args, **named_args) : Array(self)
5 | collection.map do |object|
6 | new(object, *args, **named_args)
7 | end
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/fixtures/src_template__sec_tester/expected/src/serializers/error_serializer.cr:
--------------------------------------------------------------------------------
1 | # This is the default error serializer generated by Lucky.
2 | # Feel free to customize it in any way you like.
3 | class ErrorSerializer < BaseSerializer
4 | def initialize(
5 | @message : String,
6 | @details : String? = nil,
7 | @param : String? = nil, # so you can track which param (if any) caused the problem
8 | )
9 | end
10 |
11 | def render
12 | {message: @message, param: @param, details: @details}
13 | end
14 | end
15 |
--------------------------------------------------------------------------------
/fixtures/src_template__sec_tester/expected/src/shards.cr:
--------------------------------------------------------------------------------
1 | # Load .env file before any other config or app code
2 | require "lucky_env"
3 | LuckyEnv.load?(".env")
4 |
5 | # Require your shards here
6 | require "lucky"
7 | require "avram/lucky"
8 | require "carbon"
9 |
--------------------------------------------------------------------------------
/fixtures/src_template__sec_tester/expected/src/start_server.cr:
--------------------------------------------------------------------------------
1 | require "./app"
2 |
3 | Habitat.raise_if_missing_settings!
4 |
5 | if LuckyEnv.development?
6 | Avram::Migrator::Runner.new.ensure_migrated!
7 | Avram::SchemaEnforcer.ensure_correct_column_mappings!
8 | end
9 |
10 | app_server = AppServer.new
11 |
12 | Signal::INT.trap do
13 | app_server.close
14 | end
15 |
16 | app_server.listen
17 |
--------------------------------------------------------------------------------
/fixtures/src_template__sec_tester/expected/src/test_project.cr:
--------------------------------------------------------------------------------
1 | # Typically you will not use or modify this file. 'shards build' and some
2 | # other crystal tools will sometimes use this.
3 | #
4 | # When this file is compiled/run it will require and run 'start_server',
5 | # which as its name implies will start the server for you app.
6 | require "./start_server"
7 |
--------------------------------------------------------------------------------
/fixtures/src_template__sec_tester/expected/tasks.cr:
--------------------------------------------------------------------------------
1 | # This file loads your app and all your tasks when running 'lucky'
2 | #
3 | # Run 'lucky --help' to see all available tasks.
4 | #
5 | # Learn to create your own tasks:
6 | # https://luckyframework.org/guides/command-line-tasks/custom-tasks
7 |
8 | # See `LuckyEnv#task?`
9 | ENV["LUCKY_TASK"] = "true"
10 |
11 | # Load Lucky and the app (actions, models, etc.)
12 | require "./src/app"
13 | require "lucky_task"
14 |
15 | # You can add your own tasks here in the ./tasks folder
16 | require "./tasks/**"
17 |
18 | # Load migrations
19 | require "./db/migrations/**"
20 |
21 | # Load Lucky tasks (dev, routes, etc.)
22 | require "lucky/tasks/**"
23 | require "avram/lucky/tasks"
24 |
25 | LuckyTask::Runner.run
26 |
--------------------------------------------------------------------------------
/fixtures/src_template__sec_tester/expected/tasks/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/fixtures/src_template__sec_tester/expected/tasks/.keep
--------------------------------------------------------------------------------
/fixtures/tasks.cr:
--------------------------------------------------------------------------------
1 | require "../src/lucky_cli"
2 |
3 | class PlaceholderTask < LuckyTask::Task
4 | summary "placeholder"
5 | help_message "Custom help message"
6 | switch :test_mode, "Run in test mode."
7 |
8 | def call
9 | output.puts "Calling Placeholder. Test: #{test_mode?}"
10 | end
11 | end
12 |
13 | class TaskWithInput < LuckyTask::Task
14 | summary "this should be first"
15 |
16 | def call
17 | input = gets
18 | puts "input: #{input}"
19 | end
20 | end
21 |
22 | LuckyTask::Runner.run
23 |
--------------------------------------------------------------------------------
/shard.edge.yml:
--------------------------------------------------------------------------------
1 | dependencies:
2 | lucky:
3 | github: luckyframework/lucky
4 | branch: main
5 | avram:
6 | github: luckyframework/avram
7 | branch: main
8 | authentic:
9 | github: luckyframework/authentic
10 | branch: main
11 | carbon:
12 | github: luckyframework/carbon
13 | branch: main
14 | carbon_sendgrid_adapter:
15 | github: luckyframework/carbon_sendgrid_adapter
16 | branch: main
17 | lucky_env:
18 | github: luckyframework/lucky_env
19 | branch: main
20 | lucky_task:
21 | github: luckyframework/lucky_task
22 | branch: main
23 | jwt:
24 | github: crystal-community/jwt
25 | branch: master
26 |
27 | development_dependencies:
28 | lucky_flow:
29 | github: luckyframework/lucky_flow
30 | branch: main
31 |
--------------------------------------------------------------------------------
/shard.override.yml:
--------------------------------------------------------------------------------
1 | # This file is used to override the shards built by
2 | # generated Lucky apps.
3 |
4 | # Uncomment if you need to override
5 | dependencies:
6 | lucky:
7 | github: luckyframework/lucky
8 | branch: main
9 | avram:
10 | github: luckyframework/avram
11 | branch: main
12 | authentic:
13 | github: luckyframework/authentic
14 | branch: main
15 |
--------------------------------------------------------------------------------
/shard.yml:
--------------------------------------------------------------------------------
1 | name: lucky_cli
2 | version: 1.4.0
3 |
4 | authors:
5 | - Paul Smith
6 |
7 | targets:
8 | lucky:
9 | main: src/lucky.cr
10 | lucky.hello_world:
11 | main: fixtures/hello_world.cr
12 |
13 | crystal: ~> 1.16
14 |
15 | license: MIT
16 |
17 | dependencies:
18 | lucky_template:
19 | github: luckyframework/lucky_template
20 | version: ~> 0.2.0
21 | lucky_task:
22 | github: luckyframework/lucky_task
23 | version: ~> 0.3.0
24 | nox:
25 | github: crystal-loot/nox
26 | version: ~> 0.2.3
27 |
--------------------------------------------------------------------------------
/spec/unit/api_authentication_template_spec.cr:
--------------------------------------------------------------------------------
1 | require "../spec_helper"
2 |
3 | describe ApiAuthenticationTemplate do
4 | around_each do |example|
5 | with_tempfile("tmp") do |tmp|
6 | Dir.mkdir_p(tmp)
7 | Dir.cd(tmp) do
8 | example.run
9 | end
10 | end
11 | end
12 |
13 | it "generates api authentication template" do
14 | generate_snapshot("api_authentication_template") do
15 | ApiAuthenticationTemplate.new
16 | end
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/spec/unit/base_authentication_src_template_spec.cr:
--------------------------------------------------------------------------------
1 | require "../spec_helper"
2 |
3 | describe BaseAuthenticationSrcTemplate do
4 | around_each do |example|
5 | with_tempfile("tmp") do |tmp|
6 | Dir.mkdir_p(tmp)
7 | Dir.cd(tmp) do
8 | example.run
9 | end
10 | end
11 | end
12 |
13 | it "generates base authentication src template" do
14 | generate_snapshot("base_authentication_src_template") do
15 | BaseAuthenticationSrcTemplate.new
16 | end
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/spec/unit/browser_authentication_src_template_spec.cr:
--------------------------------------------------------------------------------
1 | require "../spec_helper"
2 |
3 | describe BrowserAuthenticationSrcTemplate do
4 | around_each do |example|
5 | with_tempfile("tmp") do |tmp|
6 | Dir.mkdir_p(tmp)
7 | Dir.cd(tmp) do
8 | example.run
9 | end
10 | end
11 | end
12 |
13 | it "generates browser authentication src template" do
14 | generate_snapshot("browser_authentication_src_template") do
15 | BrowserAuthenticationSrcTemplate.new
16 | end
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/spec/unit/browser_src_template_spec.cr:
--------------------------------------------------------------------------------
1 | require "../spec_helper"
2 |
3 | describe BrowserSrcTemplate do
4 | around_each do |example|
5 | with_tempfile("tmp") do |tmp|
6 | Dir.mkdir_p(tmp)
7 | Dir.cd(tmp) do
8 | example.run
9 | end
10 | end
11 | end
12 |
13 | it "generates browser src template" do
14 | generate_snapshot("browser_src_template") do
15 | BrowserSrcTemplate.new(generate_auth: true)
16 | end
17 | end
18 |
19 | it "generates browser src template without generate auth" do
20 | generate_snapshot("browser_src_template__generate_auth") do
21 | BrowserSrcTemplate.new(generate_auth: false)
22 | end
23 | end
24 | end
25 |
--------------------------------------------------------------------------------
/src/api_authentication_app_skeleton/spec/requests/api/me/show_spec.cr.ecr:
--------------------------------------------------------------------------------
1 | require "../../../spec_helper"
2 |
3 | describe Api::Me::Show do
4 | it "returns the signed in user" do
5 | user = UserFactory.create
6 |
7 | response = ApiClient.auth(user).exec(Api::Me::Show)
8 |
9 | response.should send_json(200, email: user.email)
10 | end
11 |
12 | it "fails if not authenticated" do
13 | response = ApiClient.exec(Api::Me::Show)
14 |
15 | response.status_code.should eq(401)
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/src/api_authentication_app_skeleton/spec/requests/api/sign_ins/create_spec.cr.ecr:
--------------------------------------------------------------------------------
1 | require "../../../spec_helper"
2 |
3 | describe Api::SignIns::Create do
4 | it "returns a token" do
5 | UserToken.stub_token("fake-token") do
6 | user = UserFactory.create
7 |
8 | response = ApiClient.exec(Api::SignIns::Create, user: valid_params(user))
9 |
10 | response.should send_json(200, token: "fake-token")
11 | end
12 | end
13 |
14 | it "returns an error if credentials are invalid" do
15 | user = UserFactory.create
16 | invalid_params = valid_params(user).merge(password: "incorrect")
17 |
18 | response = ApiClient.exec(Api::SignIns::Create, user: invalid_params)
19 |
20 | response.should send_json(
21 | 400,
22 | param: "password",
23 | details: "password is wrong"
24 | )
25 | end
26 | end
27 |
28 | private def valid_params(user : User)
29 | {
30 | email: user.email,
31 | password: "password",
32 | }
33 | end
34 |
--------------------------------------------------------------------------------
/src/api_authentication_app_skeleton/src/actions/api/me/show.cr.ecr:
--------------------------------------------------------------------------------
1 | class Api::Me::Show < ApiAction
2 | get "/api/me" do
3 | json UserSerializer.new(current_user)
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/src/api_authentication_app_skeleton/src/actions/api/sign_ins/create.cr.ecr:
--------------------------------------------------------------------------------
1 | class Api::SignIns::Create < ApiAction
2 | include Api::Auth::SkipRequireAuthToken
3 |
4 | post "/api/sign_ins" do
5 | SignInUser.run(params) do |operation, user|
6 | if user
7 | json({token: UserToken.generate(user)})
8 | else
9 | raise Avram::InvalidOperationError.new(operation)
10 | end
11 | end
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/src/api_authentication_app_skeleton/src/actions/api/sign_ups/create.cr.ecr:
--------------------------------------------------------------------------------
1 | class Api::SignUps::Create < ApiAction
2 | include Api::Auth::SkipRequireAuthToken
3 |
4 | post "/api/sign_ups" do
5 | user = SignUpUser.create!(params)
6 | json({token: UserToken.generate(user)})
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/src/api_authentication_app_skeleton/src/actions/mixins/api/auth/helpers.cr.ecr:
--------------------------------------------------------------------------------
1 | module Api::Auth::Helpers
2 | # The 'memoize' macro makes sure only one query is issued to find the user
3 | memoize def current_user? : User?
4 | auth_token.try do |value|
5 | user_from_auth_token(value)
6 | end
7 | end
8 |
9 | private def auth_token : String?
10 | bearer_token || token_param
11 | end
12 |
13 | private def bearer_token : String?
14 | context.request.headers["Authorization"]?
15 | .try(&.gsub("Bearer", ""))
16 | .try(&.strip)
17 | end
18 |
19 | private def token_param : String?
20 | params.get?(:auth_token)
21 | end
22 |
23 | private def user_from_auth_token(token : String) : User?
24 | UserToken.decode_user_id(token).try do |user_id|
25 | UserQuery.new.id(user_id).first?
26 | end
27 | end
28 | end
29 |
--------------------------------------------------------------------------------
/src/api_authentication_app_skeleton/src/actions/mixins/api/auth/skip_require_auth_token.cr.ecr:
--------------------------------------------------------------------------------
1 | module Api::Auth::SkipRequireAuthToken
2 | macro included
3 | skip require_auth_token
4 | end
5 |
6 | # Since sign in is not required, current_user might be nil
7 | def current_user : User?
8 | current_user?
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/src/api_authentication_app_skeleton/src/serializers/user_serializer.cr.ecr:
--------------------------------------------------------------------------------
1 | class UserSerializer < BaseSerializer
2 | def initialize(@user : User)
3 | end
4 |
5 | def render
6 | {email: @user.email}
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/src/app_with_sec_tester/spec/setup/sec_tester.cr.ecr:
--------------------------------------------------------------------------------
1 | require "lucky_sec_tester"
2 |
3 | # Signup for a `BRIGHT_TOKEN` at
4 | # [Bright Security](https://app.neuralegion.com/signup)
5 | # Read more about the SecTester on https://github.com/luckyframework/lucky_sec_tester
6 | LuckySecTester.configure do |setting|
7 | setting.bright_token = ENV["BRIGHT_TOKEN"]
8 | setting.project_id = ENV["BRIGHT_PROJECT_ID"]
9 | end
10 |
--------------------------------------------------------------------------------
/src/base_authentication_app_skeleton/config/authentic.cr.ecr:
--------------------------------------------------------------------------------
1 | require "./server"
2 |
3 | Authentic.configure do |settings|
4 | settings.secret_key = Lucky::Server.settings.secret_key_base
5 |
6 | unless LuckyEnv.production?
7 | # This value can be between 4 and 31
8 | fastest_encryption_possible = 4
9 | settings.encryption_cost = fastest_encryption_possible
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/src/base_authentication_app_skeleton/db/migrations/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/src/base_authentication_app_skeleton/db/migrations/.keep
--------------------------------------------------------------------------------
/src/base_authentication_app_skeleton/db/migrations/00000000000001_create_users.cr.ecr:
--------------------------------------------------------------------------------
1 | class CreateUsers::V00000000000001 < Avram::Migrator::Migration::V1
2 | def migrate
3 | enable_extension "citext"
4 |
5 | create table_for(User) do
6 | primary_key id : Int64
7 | add_timestamps
8 | add email : String, unique: true, case_sensitive: false
9 | add encrypted_password : String
10 | end
11 | end
12 |
13 | def rollback
14 | drop table_for(User)
15 | disable_extension "citext"
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/src/base_authentication_app_skeleton/spec/support/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/src/base_authentication_app_skeleton/spec/support/.keep
--------------------------------------------------------------------------------
/src/base_authentication_app_skeleton/spec/support/factories/user_factory.cr.ecr:
--------------------------------------------------------------------------------
1 | class UserFactory < Avram::Factory
2 | def initialize
3 | email "#{sequence("test-email")}@example.com"
4 | encrypted_password Authentic.generate_encrypted_password("password")
5 | end
6 | end
7 |
--------------------------------------------------------------------------------
/src/base_authentication_app_skeleton/src/models/user.cr.ecr:
--------------------------------------------------------------------------------
1 | class User < BaseModel
2 | include Carbon::Emailable
3 | include Authentic::PasswordAuthenticatable
4 |
5 | table do
6 | column email : String
7 | column encrypted_password : String
8 | end
9 |
10 | def emailable : Carbon::Address
11 | Carbon::Address.new(email)
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/src/base_authentication_app_skeleton/src/operations/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/src/base_authentication_app_skeleton/src/operations/.keep
--------------------------------------------------------------------------------
/src/base_authentication_app_skeleton/src/operations/mixins/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/src/base_authentication_app_skeleton/src/operations/mixins/.keep
--------------------------------------------------------------------------------
/src/base_authentication_app_skeleton/src/operations/mixins/password_validations.cr.ecr:
--------------------------------------------------------------------------------
1 | module PasswordValidations
2 | macro included
3 | before_save run_password_validations
4 | end
5 |
6 | private def run_password_validations
7 | validate_required password, password_confirmation
8 | validate_confirmation_of password, with: password_confirmation
9 | # 72 is a limitation of BCrypt
10 | validate_size_of password, min: 6, max: 72
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/src/base_authentication_app_skeleton/src/operations/mixins/user_from_email.cr.ecr:
--------------------------------------------------------------------------------
1 | module UserFromEmail
2 | private def user_from_email : User?
3 | email.value.try do |value|
4 | UserQuery.new.email(value).first?
5 | end
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/src/base_authentication_app_skeleton/src/operations/request_password_reset.cr.ecr:
--------------------------------------------------------------------------------
1 | class RequestPasswordReset < Avram::Operation
2 | # You can modify this in src/operations/mixins/user_from_email.cr
3 | include UserFromEmail
4 |
5 | attribute email : String
6 |
7 | # Run validations and yield the operation and the user if valid
8 | def run
9 | user = user_from_email
10 | validate(user)
11 |
12 | if valid?
13 | user
14 | else
15 | nil
16 | end
17 | end
18 |
19 | def validate(user : User?)
20 | validate_required email
21 | if user.nil?
22 | email.add_error "is not in our system"
23 | end
24 | end
25 | end
26 |
--------------------------------------------------------------------------------
/src/base_authentication_app_skeleton/src/operations/reset_password.cr.ecr:
--------------------------------------------------------------------------------
1 | class ResetPassword < User::SaveOperation
2 | # Change password validations in src/operations/mixins/password_validations.cr
3 | include PasswordValidations
4 |
5 | attribute password : String
6 | attribute password_confirmation : String
7 |
8 | before_save do
9 | Authentic.copy_and_encrypt password, to: encrypted_password
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/src/base_authentication_app_skeleton/src/operations/sign_up_user.cr.ecr:
--------------------------------------------------------------------------------
1 | class SignUpUser < User::SaveOperation
2 | param_key :user
3 | # Change password validations in src/operations/mixins/password_validations.cr
4 | include PasswordValidations
5 |
6 | permit_columns email
7 | attribute password : String
8 | attribute password_confirmation : String
9 |
10 | before_save do
11 | validate_uniqueness_of email
12 | Authentic.copy_and_encrypt(password, to: encrypted_password) if password.valid?
13 | end
14 | end
15 |
--------------------------------------------------------------------------------
/src/base_authentication_app_skeleton/src/queries/user_query.cr.ecr:
--------------------------------------------------------------------------------
1 | class UserQuery < User::BaseQuery
2 | end
3 |
--------------------------------------------------------------------------------
/src/browser_app_skeleton/bs-config.js.ecr:
--------------------------------------------------------------------------------
1 | /*
2 | | Browser-sync config file
3 | |
4 | | For up-to-date information about the options:
5 | | http://www.browsersync.io/docs/options/
6 | |
7 | */
8 |
9 | module.exports = {
10 | snippetOptions: {
11 | rule: {
12 | match: /<\/head>/i,
13 | fn: function (snippet, match) {
14 | return snippet + match;
15 | }
16 | }
17 | },
18 | files: ["public/css/**/*.css", "public/js/**/*.js"],
19 | watchEvents: ["change"],
20 | open: false,
21 | browser: "default",
22 | ghostMode: false,
23 | ui: false,
24 | online: false,
25 | logConnections: false
26 | };
27 |
--------------------------------------------------------------------------------
/src/browser_app_skeleton/config/html_page.cr.ecr:
--------------------------------------------------------------------------------
1 | Lucky::HTMLPage.configure do |settings|
2 | settings.render_component_comments = !LuckyEnv.production?
3 | end
4 |
--------------------------------------------------------------------------------
/src/browser_app_skeleton/db/migrations/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/src/browser_app_skeleton/db/migrations/.keep
--------------------------------------------------------------------------------
/src/browser_app_skeleton/package.json.ecr:
--------------------------------------------------------------------------------
1 | {
2 | "license": "UNLICENSED",
3 | "private": true,
4 | "dependencies": {
5 | "@rails/ujs": "^7.1.0",
6 | "modern-normalize": "^2.0.0"
7 | },
8 | "scripts": {
9 | "heroku-postbuild": "yarn prod",
10 | "dev": "yarn run mix",
11 | "watch": "yarn run mix watch",
12 | "prod": "yarn run mix --production"
13 | },
14 | "devDependencies": {
15 | "@babel/compat-data": "^7.23.5",
16 | "browser-sync": "^2.29.3",
17 | "compression-webpack-plugin": "^10.0.0",
18 | "laravel-mix": "^6.0.49",
19 | "postcss": "^8.4.32",
20 | "resolve-url-loader": "^5.0.0",
21 | "sass": "^1.69.5",
22 | "sass-loader": "^13.3.2"
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/browser_app_skeleton/public/assets/images/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/src/browser_app_skeleton/public/assets/images/.keep
--------------------------------------------------------------------------------
/src/browser_app_skeleton/public/favicon.ico.ecr:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/src/browser_app_skeleton/public/favicon.ico.ecr
--------------------------------------------------------------------------------
/src/browser_app_skeleton/public/mix-manifest.json.ecr:
--------------------------------------------------------------------------------
1 | {
2 | "/css/app.css": "/css/app.css",
3 | "/js/app.js": "/js/app.js"
4 | }
5 |
--------------------------------------------------------------------------------
/src/browser_app_skeleton/public/robots.txt.ecr:
--------------------------------------------------------------------------------
1 | # Learn more about robots.txt: https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | # 'Disallow' with an empty value allows all paths to be crawled
4 | Disallow:
5 |
--------------------------------------------------------------------------------
/src/browser_app_skeleton/spec/flows/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/src/browser_app_skeleton/spec/flows/.keep
--------------------------------------------------------------------------------
/src/browser_app_skeleton/spec/setup/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/src/browser_app_skeleton/spec/setup/.keep
--------------------------------------------------------------------------------
/src/browser_app_skeleton/spec/support/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/src/browser_app_skeleton/spec/support/.keep
--------------------------------------------------------------------------------
/src/browser_app_skeleton/spec/support/factories/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/src/browser_app_skeleton/spec/support/factories/.keep
--------------------------------------------------------------------------------
/src/browser_app_skeleton/spec/support/flows/base_flow.cr.ecr:
--------------------------------------------------------------------------------
1 | # Add methods that all or most Flows need to share
2 | class BaseFlow < LuckyFlow
3 | end
4 |
--------------------------------------------------------------------------------
/src/browser_app_skeleton/src/components/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/src/browser_app_skeleton/src/components/.keep
--------------------------------------------------------------------------------
/src/browser_app_skeleton/src/components/base_component.cr.ecr:
--------------------------------------------------------------------------------
1 | abstract class BaseComponent < Lucky::BaseComponent
2 | end
3 |
--------------------------------------------------------------------------------
/src/browser_app_skeleton/src/components/shared/field_errors.cr.ecr:
--------------------------------------------------------------------------------
1 | class Shared::FieldErrors(T) < BaseComponent
2 | needs attribute : Avram::PermittedAttribute(T)
3 |
4 | # Customize the markup and styles to match your application
5 | def render
6 | unless attribute.valid?
7 | div class: "error" do
8 | text "#{label_text} #{attribute.errors.first}"
9 | end
10 | end
11 | end
12 |
13 | def label_text : String
14 | Wordsmith::Inflector.humanize(attribute.name.to_s)
15 | end
16 | end
17 |
--------------------------------------------------------------------------------
/src/browser_app_skeleton/src/components/shared/flash_messages.cr.ecr:
--------------------------------------------------------------------------------
1 | class Shared::FlashMessages < BaseComponent
2 | needs flash : Lucky::FlashStore
3 |
4 | def render
5 | flash.each do |flash_type, flash_message|
6 | div class: "flash-#{flash_type}", flow_id: "flash" do
7 | text flash_message
8 | end
9 | end
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/src/browser_app_skeleton/src/components/shared/layout_head.cr.ecr:
--------------------------------------------------------------------------------
1 | class Shared::LayoutHead < BaseComponent
2 | needs page_title : String
3 |
4 | def render
5 | head do
6 | utf8_charset
7 | title "My App - #{@page_title}"
8 | css_link asset("css/app.css")
9 | js_link asset("js/app.js"), defer: "true"
10 | csrf_meta_tags
11 | responsive_meta_tag
12 |
13 | # Development helper used with the `lucky watch` command.
14 | # Reloads the browser when files are updated.
15 | live_reload_connect_tag if LuckyEnv.development?
16 | end
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/src/browser_app_skeleton/src/css/components/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/src/browser_app_skeleton/src/css/components/.keep
--------------------------------------------------------------------------------
/src/browser_app_skeleton/src/css/mixins/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/src/browser_app_skeleton/src/css/mixins/.keep
--------------------------------------------------------------------------------
/src/browser_app_skeleton/src/css/variables/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/src/browser_app_skeleton/src/css/variables/.keep
--------------------------------------------------------------------------------
/src/browser_app_skeleton/src/emails/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/src/browser_app_skeleton/src/emails/.keep
--------------------------------------------------------------------------------
/src/browser_app_skeleton/src/js/app.js.ecr:
--------------------------------------------------------------------------------
1 | /* eslint no-console:0 */
2 |
3 | // Rails Unobtrusive JavaScript (UJS) is *required* for links in Lucky that use DELETE, POST and PUT.
4 | // Though it says "Rails" it actually works with any framework.
5 | import Rails from "@rails/ujs";
6 | Rails.start();
7 |
8 |
--------------------------------------------------------------------------------
/src/browser_app_skeleton/src/models/mixins/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/src/browser_app_skeleton/src/models/mixins/.keep
--------------------------------------------------------------------------------
/src/browser_app_skeleton/src/operations/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/src/browser_app_skeleton/src/operations/.keep
--------------------------------------------------------------------------------
/src/browser_app_skeleton/src/operations/mixins/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/src/browser_app_skeleton/src/operations/mixins/.keep
--------------------------------------------------------------------------------
/src/browser_app_skeleton/src/pages/main_layout.cr.ecr:
--------------------------------------------------------------------------------
1 | abstract class MainLayout
2 | include Lucky::HTMLPage
3 |
4 | abstract def content
5 | abstract def page_title
6 |
7 | # The default page title. It is passed to `Shared::LayoutHead`.
8 | #
9 | # Add a `page_title` method to pages to override it. You can also remove
10 | # This method so every page is required to have its own page title.
11 | def page_title
12 | "Welcome"
13 | end
14 |
15 | def render
16 | html_doctype
17 |
18 | html lang: "en" do
19 | mount Shared::LayoutHead, page_title: page_title
20 |
21 | body do
22 | mount Shared::FlashMessages, context.flash
23 | content
24 | end
25 | end
26 | end
27 | end
28 |
--------------------------------------------------------------------------------
/src/browser_authentication_app_skeleton/spec/flows/reset_password_spec.cr.ecr:
--------------------------------------------------------------------------------
1 | require "../spec_helper"
2 |
3 | describe "Reset password flow", tags: "flow" do
4 | it "works" do
5 | user = UserFactory.create
6 | flow = ResetPasswordFlow.new(user)
7 |
8 | flow.request_password_reset
9 | flow.should_have_sent_reset_email
10 | flow.reset_password "new-password"
11 | flow.should_be_signed_in
12 | flow.sign_out
13 | flow.sign_in "wrong-password"
14 | flow.should_have_password_error
15 | flow.sign_in "new-password"
16 | flow.should_be_signed_in
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/src/browser_authentication_app_skeleton/spec/support/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/src/browser_authentication_app_skeleton/spec/support/.keep
--------------------------------------------------------------------------------
/src/browser_authentication_app_skeleton/src/actions/me/show.cr.ecr:
--------------------------------------------------------------------------------
1 | class Me::Show < BrowserAction
2 | get "/me" do
3 | html ShowPage
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/src/browser_authentication_app_skeleton/src/actions/mixins/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/src/browser_authentication_app_skeleton/src/actions/mixins/.keep
--------------------------------------------------------------------------------
/src/browser_authentication_app_skeleton/src/actions/mixins/auth/allow_guests.cr.ecr:
--------------------------------------------------------------------------------
1 | module Auth::AllowGuests
2 | macro included
3 | skip require_sign_in
4 | end
5 |
6 | # Since sign in is not required, current_user might be nil
7 | def current_user : User?
8 | current_user?
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/src/browser_authentication_app_skeleton/src/actions/mixins/auth/password_resets/base.cr.ecr:
--------------------------------------------------------------------------------
1 | module Auth::PasswordResets::Base
2 | macro included
3 | include Auth::RedirectSignedInUsers
4 | include Auth::PasswordResets::FindUser
5 | include Auth::PasswordResets::RequireToken
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/src/browser_authentication_app_skeleton/src/actions/mixins/auth/password_resets/find_user.cr.ecr:
--------------------------------------------------------------------------------
1 | module Auth::PasswordResets::FindUser
2 | private def user : User
3 | UserQuery.find(user_id)
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/src/browser_authentication_app_skeleton/src/actions/mixins/auth/password_resets/require_token.cr.ecr:
--------------------------------------------------------------------------------
1 | module Auth::PasswordResets::RequireToken
2 | macro included
3 | before require_valid_password_reset_token
4 | end
5 |
6 | abstract def token : String
7 | abstract def user : User
8 |
9 | private def require_valid_password_reset_token
10 | if Authentic.valid_password_reset_token?(user, token)
11 | continue
12 | else
13 | flash.failure = "The password reset link is incorrect or expired. Please try again."
14 | redirect to: PasswordResetRequests::New
15 | end
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/src/browser_authentication_app_skeleton/src/actions/mixins/auth/password_resets/token_from_session.cr.ecr:
--------------------------------------------------------------------------------
1 | module Auth::PasswordResets::TokenFromSession
2 | private def token : String
3 | session.get?(:password_reset_token) || raise "Password reset token not found in session"
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/src/browser_authentication_app_skeleton/src/actions/mixins/auth/redirect_signed_in_users.cr.ecr:
--------------------------------------------------------------------------------
1 | module Auth::RedirectSignedInUsers
2 | macro included
3 | include Auth::AllowGuests
4 | before redirect_signed_in_users
5 | end
6 |
7 | private def redirect_signed_in_users
8 | if current_user?
9 | flash.success = "You are already signed in"
10 | redirect to: Home::Index
11 | else
12 | continue
13 | end
14 | end
15 |
16 | # current_user returns nil because signed in users are redirected.
17 | def current_user
18 | end
19 | end
20 |
--------------------------------------------------------------------------------
/src/browser_authentication_app_skeleton/src/actions/mixins/auth/require_sign_in.cr.ecr:
--------------------------------------------------------------------------------
1 | module Auth::RequireSignIn
2 | macro included
3 | before require_sign_in
4 | end
5 |
6 | private def require_sign_in
7 | if current_user?
8 | continue
9 | else
10 | Authentic.remember_requested_path(self)
11 | flash.info = "Please sign in first"
12 | redirect to: SignIns::New
13 | end
14 | end
15 |
16 | # Tells the compiler that the current_user is not nil since we have checked
17 | # that the user is signed in
18 | private def current_user : User
19 | current_user?.as(User)
20 | end
21 | end
22 |
--------------------------------------------------------------------------------
/src/browser_authentication_app_skeleton/src/actions/mixins/auth/test_backdoor.cr.ecr:
--------------------------------------------------------------------------------
1 | module Auth::TestBackdoor
2 | macro included
3 | before test_backdoor
4 | end
5 |
6 | private def test_backdoor
7 | if LuckyEnv.test? && (user_id = params.get?(:backdoor_user_id))
8 | user = UserQuery.find(user_id)
9 | sign_in user
10 | end
11 | continue
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/src/browser_authentication_app_skeleton/src/actions/password_reset_requests/create.cr.ecr:
--------------------------------------------------------------------------------
1 | class PasswordResetRequests::Create < BrowserAction
2 | include Auth::RedirectSignedInUsers
3 |
4 | post "/password_reset_requests" do
5 | RequestPasswordReset.run(params) do |operation, user|
6 | if user
7 | PasswordResetRequestEmail.new(user).deliver
8 | flash.success = "You should receive an email on how to reset your password shortly"
9 | redirect SignIns::New
10 | else
11 | html NewPage, operation: operation
12 | end
13 | end
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/src/browser_authentication_app_skeleton/src/actions/password_reset_requests/new.cr.ecr:
--------------------------------------------------------------------------------
1 | class PasswordResetRequests::New < BrowserAction
2 | include Auth::RedirectSignedInUsers
3 |
4 | get "/password_reset_requests/new" do
5 | html NewPage, operation: RequestPasswordReset.new
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/src/browser_authentication_app_skeleton/src/actions/password_resets/create.cr.ecr:
--------------------------------------------------------------------------------
1 | class PasswordResets::Create < BrowserAction
2 | include Auth::PasswordResets::Base
3 | include Auth::PasswordResets::TokenFromSession
4 |
5 | post "/password_resets/:user_id" do
6 | ResetPassword.update(user, params) do |operation, user|
7 | if operation.saved?
8 | session.delete(:password_reset_token)
9 | sign_in user
10 | flash.success = "Your password has been reset"
11 | redirect to: Home::Index
12 | else
13 | html NewPage, operation: operation, user_id: user_id.to_i64
14 | end
15 | end
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/src/browser_authentication_app_skeleton/src/actions/password_resets/edit.cr.ecr:
--------------------------------------------------------------------------------
1 | class PasswordResets::Edit < BrowserAction
2 | include Auth::PasswordResets::Base
3 | include Auth::PasswordResets::TokenFromSession
4 |
5 | get "/password_resets/:user_id/edit" do
6 | html NewPage, operation: ResetPassword.new, user_id: user_id.to_i64
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/src/browser_authentication_app_skeleton/src/actions/password_resets/new.cr.ecr:
--------------------------------------------------------------------------------
1 | class PasswordResets::New < BrowserAction
2 | include Auth::PasswordResets::Base
3 |
4 | param token : String
5 |
6 | get "/password_resets/:user_id" do
7 | redirect_to_edit_form_without_token_param
8 | end
9 |
10 | # This is to prevent password reset tokens from being scraped in the HTTP Referer header
11 | # See more info here: https://github.com/thoughtbot/clearance/pull/707
12 | private def redirect_to_edit_form_without_token_param
13 | make_token_available_to_future_actions
14 | redirect to: PasswordResets::Edit.with(user_id)
15 | end
16 |
17 | private def make_token_available_to_future_actions
18 | session.set(:password_reset_token, token)
19 | end
20 | end
21 |
--------------------------------------------------------------------------------
/src/browser_authentication_app_skeleton/src/actions/sign_ins/create.cr.ecr:
--------------------------------------------------------------------------------
1 | class SignIns::Create < BrowserAction
2 | include Auth::RedirectSignedInUsers
3 |
4 | post "/sign_in" do
5 | SignInUser.run(params) do |operation, authenticated_user|
6 | if authenticated_user
7 | sign_in(authenticated_user)
8 | flash.success = "You're now signed in"
9 | Authentic.redirect_to_originally_requested_path(self, fallback: Home::Index)
10 | else
11 | flash.failure = "Sign in failed"
12 | html NewPage, operation: operation
13 | end
14 | end
15 | end
16 | end
17 |
--------------------------------------------------------------------------------
/src/browser_authentication_app_skeleton/src/actions/sign_ins/delete.cr.ecr:
--------------------------------------------------------------------------------
1 | class SignIns::Delete < BrowserAction
2 | delete "/sign_out" do
3 | sign_out
4 | flash.info = "You have been signed out"
5 | redirect to: SignIns::New
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/src/browser_authentication_app_skeleton/src/actions/sign_ins/new.cr.ecr:
--------------------------------------------------------------------------------
1 | class SignIns::New < BrowserAction
2 | include Auth::RedirectSignedInUsers
3 |
4 | get "/sign_in" do
5 | html NewPage, operation: SignInUser.new
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/src/browser_authentication_app_skeleton/src/actions/sign_ups/create.cr.ecr:
--------------------------------------------------------------------------------
1 | class SignUps::Create < BrowserAction
2 | include Auth::RedirectSignedInUsers
3 |
4 | post "/sign_up" do
5 | SignUpUser.create(params) do |operation, user|
6 | if user
7 | flash.info = "Thanks for signing up"
8 | sign_in(user)
9 | redirect to: Home::Index
10 | else
11 | flash.info = "Couldn't sign you up"
12 | html NewPage, operation: operation
13 | end
14 | end
15 | end
16 | end
17 |
--------------------------------------------------------------------------------
/src/browser_authentication_app_skeleton/src/actions/sign_ups/new.cr.ecr:
--------------------------------------------------------------------------------
1 | class SignUps::New < BrowserAction
2 | include Auth::RedirectSignedInUsers
3 |
4 | get "/sign_up" do
5 | html NewPage, operation: SignUpUser.new
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/src/browser_authentication_app_skeleton/src/emails/password_reset_request_email.cr.ecr:
--------------------------------------------------------------------------------
1 | class PasswordResetRequestEmail < BaseEmail
2 | Habitat.create { setting stubbed_token : String? }
3 | delegate stubbed_token, to: :settings
4 |
5 | def initialize(@user : User)
6 | @token = stubbed_token || Authentic.generate_password_reset_token(@user)
7 | end
8 |
9 | to @user
10 | from "myapp@support.com" # or set a default in src/emails/base_email.cr
11 | subject "Reset your password"
12 | templates html, text
13 | end
14 |
--------------------------------------------------------------------------------
/src/browser_authentication_app_skeleton/src/emails/templates/password_reset_request_email/html.ecr.ecr:
--------------------------------------------------------------------------------
1 | Please reset your password
2 |
3 | %= PasswordResets::New.url(@user.id, @token) %>">Reset password
4 |
--------------------------------------------------------------------------------
/src/browser_authentication_app_skeleton/src/emails/templates/password_reset_request_email/text.ecr.ecr:
--------------------------------------------------------------------------------
1 | Please reset your password:
2 |
3 | <%="<"%>%= PasswordResets::New.url(@user.id, @token) %>
4 |
--------------------------------------------------------------------------------
/src/browser_authentication_app_skeleton/src/pages/auth_layout.cr.ecr:
--------------------------------------------------------------------------------
1 | abstract class AuthLayout
2 | include Lucky::HTMLPage
3 |
4 | abstract def content
5 | abstract def page_title
6 |
7 | # The default page title. It is passed to `Shared::LayoutHead`.
8 | #
9 | # Add a `page_title` method to pages to override it. You can also remove
10 | # This method so every page is required to have its own page title.
11 | def page_title
12 | "Welcome"
13 | end
14 |
15 | def render
16 | html_doctype
17 |
18 | html lang: "en" do
19 | mount Shared::LayoutHead, page_title: page_title
20 |
21 | body do
22 | mount Shared::FlashMessages, context.flash
23 | content
24 | end
25 | end
26 | end
27 | end
28 |
--------------------------------------------------------------------------------
/src/browser_authentication_app_skeleton/src/pages/me/show_page.cr.ecr:
--------------------------------------------------------------------------------
1 | class Me::ShowPage < MainLayout
2 | def content
3 | h1 "This is your profile"
4 | h3 "Email: #{@current_user.email}"
5 | helpful_tips
6 | end
7 |
8 | private def helpful_tips
9 | h3 "Next, you may want to:"
10 | ul do
11 | li { link_to_authentication_guides }
12 | li "Modify this page: src/pages/me/show_page.cr"
13 | li "Change where you go after sign in: src/actions/home/index.cr"
14 | end
15 | end
16 |
17 | private def link_to_authentication_guides
18 | a "Check out the authentication guides",
19 | href: "https://luckyframework.org/guides/authentication"
20 | end
21 | end
22 |
--------------------------------------------------------------------------------
/src/browser_authentication_app_skeleton/src/pages/password_reset_requests/new_page.cr.ecr:
--------------------------------------------------------------------------------
1 | class PasswordResetRequests::NewPage < AuthLayout
2 | needs operation : RequestPasswordReset
3 |
4 | def content
5 | h1 "Reset your password"
6 | render_form(@operation)
7 | end
8 |
9 | private def render_form(op)
10 | form_for PasswordResetRequests::Create do
11 | mount Shared::Field, attribute: op.email, label_text: "Email", &.email_input
12 | submit "Reset Password", flow_id: "request-password-reset-button"
13 | end
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/src/browser_authentication_app_skeleton/src/pages/password_resets/new_page.cr.ecr:
--------------------------------------------------------------------------------
1 | class PasswordResets::NewPage < AuthLayout
2 | needs operation : ResetPassword
3 | needs user_id : Int64
4 |
5 | def content
6 | h1 "Reset your password"
7 | render_password_reset_form(@operation)
8 | end
9 |
10 | private def render_password_reset_form(op)
11 | form_for PasswordResets::Create.with(@user_id) do
12 | mount Shared::Field, attribute: op.password, label_text: "Password", &.password_input(autofocus: "true")
13 | mount Shared::Field, attribute: op.password_confirmation, label_text: "Confirm Password", &.password_input
14 |
15 | submit "Update Password", flow_id: "update-password-button"
16 | end
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/src/browser_authentication_app_skeleton/src/pages/sign_ins/new_page.cr.ecr:
--------------------------------------------------------------------------------
1 | class SignIns::NewPage < AuthLayout
2 | needs operation : SignInUser
3 |
4 | def content
5 | h1 "Sign In"
6 | render_sign_in_form(@operation)
7 | end
8 |
9 | private def render_sign_in_form(op)
10 | form_for SignIns::Create do
11 | sign_in_fields(op)
12 | submit "Sign In", flow_id: "sign-in-button"
13 | end
14 | link "Reset password", to: PasswordResetRequests::New
15 | text " | "
16 | link "Sign up", to: SignUps::New
17 | end
18 |
19 | private def sign_in_fields(op)
20 | mount Shared::Field, attribute: op.email, label_text: "Email", &.email_input(autofocus: "true")
21 | mount Shared::Field, attribute: op.password, label_text: "Password", &.password_input
22 | end
23 | end
24 |
--------------------------------------------------------------------------------
/src/browser_authentication_app_skeleton/src/pages/sign_ups/new_page.cr.ecr:
--------------------------------------------------------------------------------
1 | class SignUps::NewPage < AuthLayout
2 | needs operation : SignUpUser
3 |
4 | def content
5 | h1 "Sign Up"
6 | render_sign_up_form(@operation)
7 | end
8 |
9 | private def render_sign_up_form(op)
10 | form_for SignUps::Create do
11 | sign_up_fields(op)
12 | submit "Sign Up", flow_id: "sign-up-button"
13 | end
14 | link "Sign in instead", to: SignIns::New
15 | end
16 |
17 | private def sign_up_fields(op)
18 | mount Shared::Field, attribute: op.email, label_text: "Email", &.email_input(autofocus: "true")
19 | mount Shared::Field, attribute: op.password, label_text: "Password", &.password_input
20 | mount Shared::Field, attribute: op.password_confirmation, label_text: "Confirm Password", &.password_input
21 | end
22 | end
23 |
--------------------------------------------------------------------------------
/src/dev.cr:
--------------------------------------------------------------------------------
1 | class LuckyCli::Dev < LuckyTask::Task
2 | summary "Starts your app by running the processes found in Procfile.dev"
3 |
4 | def call
5 | ::Nox.run("Procfile.dev")
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/src/init.cr:
--------------------------------------------------------------------------------
1 | class LuckyCli::Init
2 | def self.run : Nil
3 | new.run
4 | end
5 |
6 | def run : Nil
7 | LuckyCli::Wizard::Web.run
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/src/lucky_cli.cr:
--------------------------------------------------------------------------------
1 | require "lucky_template"
2 | require "lucky_task"
3 | require "nox"
4 | require "ecr"
5 | require "./lucky_cli/**"
6 | require "./generators/*"
7 | require "./init"
8 | require "./init_custom"
9 |
--------------------------------------------------------------------------------
/src/lucky_cli/app_with_sec_tester_template.cr:
--------------------------------------------------------------------------------
1 | class AppWithSecTesterTemplate
2 | getter? generate_auth, browser
3 |
4 | def initialize(@generate_auth : Bool, @browser : Bool)
5 | end
6 |
7 | def render(path : Path)
8 | LuckyTemplate.write!(path, template_folder)
9 | end
10 |
11 | def template_folder
12 | LuckyTemplate.create_folder do |root_dir|
13 | root_dir.add_folder("spec") do |spec_dir|
14 | spec_dir.add_file(Path["flows/security_spec.cr"]) do |io|
15 | ECR.embed("#{__DIR__}/../app_with_sec_tester/spec/flows/security_spec.cr.ecr", io)
16 | end
17 | spec_dir.add_file(Path["setup/sec_tester.cr"]) do |io|
18 | ECR.embed("#{__DIR__}/../app_with_sec_tester/spec/setup/sec_tester.cr.ecr", io)
19 | end
20 | end
21 | end
22 | end
23 | end
24 |
--------------------------------------------------------------------------------
/src/lucky_cli/version.cr:
--------------------------------------------------------------------------------
1 | module LuckyCli
2 | VERSION = {{ `shards version #{__DIR__}`.chomp.stringify }}
3 | end
4 |
--------------------------------------------------------------------------------
/src/lucky_cli/wizard/labeled_yes_no_question.cr:
--------------------------------------------------------------------------------
1 | class LuckyCli::Wizard::LabeledYesNoQuestion
2 | getter question_text, yes_label, no_label
3 |
4 | def initialize(
5 | @question_text : String,
6 | @yes_label : String,
7 | @no_label : String,
8 | )
9 | end
10 |
11 | def self.ask(*args, **named_args) : Bool
12 | new(*args, **named_args).ask
13 | end
14 |
15 | def ask : Bool
16 | print question_text.colorize.bold.to_s +
17 | " (#{yes_label}/#{no_label}): ".colorize.green.bold.to_s
18 | answer = gets.try(&.strip.gsub("'", "").downcase)
19 | case answer
20 | when yes_label
21 | true
22 | when no_label
23 | false
24 | else
25 | puts "\nMust be '#{yes_label}' or '#{no_label}'".colorize.red
26 | ask
27 | end
28 | end
29 | end
30 |
--------------------------------------------------------------------------------
/src/lucky_cli/wizard/project_name_question.cr:
--------------------------------------------------------------------------------
1 | class LuckyCli::ProjectNameQuestion
2 | def ask : String
3 | name = ProjectName.new(prompt_for_project_name)
4 |
5 | if name.valid?
6 | name.to_s
7 | else
8 | puts "\n"
9 | puts name.validation_error_message.colorize.red
10 | ask
11 | end
12 | end
13 |
14 | private def prompt_for_project_name
15 | print "#{"Project name?".colorize.bold}: "
16 |
17 | gets.try(&.strip.gsub("'", "")) || ""
18 | end
19 | end
20 |
--------------------------------------------------------------------------------
/src/lucky_cli/wizard/yes_no_question.cr:
--------------------------------------------------------------------------------
1 | class LuckyCli::Wizard::YesNoQuestion
2 | def self.ask(question_text : String) : Bool
3 | LabeledYesNoQuestion.ask(question_text, yes_label: "y", no_label: "n")
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/src/web_app_skeleton/.crystal-version.ecr:
--------------------------------------------------------------------------------
1 | <%= crystal_version %>
2 |
--------------------------------------------------------------------------------
/src/web_app_skeleton/.env.ecr:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/src/web_app_skeleton/.env.ecr
--------------------------------------------------------------------------------
/src/web_app_skeleton/Procfile.dev.ecr:
--------------------------------------------------------------------------------
1 | system_check: crystal script/system_check.cr
2 | <%- if api_only? -%>
3 | web: lucky watch
4 | <%- else -%>
5 | web: lucky watch --reload-browser
6 | assets: yarn watch
7 | <%- end -%>
8 |
--------------------------------------------------------------------------------
/src/web_app_skeleton/Procfile.ecr:
--------------------------------------------------------------------------------
1 | web: bin/app
2 | release: lucky db.migrate
3 |
--------------------------------------------------------------------------------
/src/web_app_skeleton/config/application.cr.ecr:
--------------------------------------------------------------------------------
1 | # This file may be used for custom Application configurations.
2 | # It will be loaded before other config files.
3 | #
4 | # Read more on configuration:
5 | # https://luckyframework.org/guides/getting-started/configuration#configuring-your-own-code
6 |
7 | # Use this code as an example:
8 | #
9 | # ```
10 | # module Application
11 | # Habitat.create do
12 | # setting support_email : String
13 | # setting lock_with_basic_auth : Bool
14 | # end
15 | # end
16 | #
17 | # Application.configure do |settings|
18 | # settings.support_email = "support@myapp.io"
19 | # settings.lock_with_basic_auth = LuckyEnv.staging?
20 | # end
21 | #
22 | # # In your application, call
23 | # # `Application.settings.support_email` anywhere you need it.
24 | # ```
25 |
--------------------------------------------------------------------------------
/src/web_app_skeleton/config/colors.cr.ecr:
--------------------------------------------------------------------------------
1 | # This enables the color output when in development or test
2 | # Check out the Colorize docs for more information
3 | # https://crystal-lang.org/api/Colorize.html
4 | Colorize.enabled = LuckyEnv.development? || LuckyEnv.test?
5 |
--------------------------------------------------------------------------------
/src/web_app_skeleton/config/cookies.cr.ecr:
--------------------------------------------------------------------------------
1 | require "./server"
2 |
3 | Lucky::Session.configure do |settings|
4 | settings.key = "_<%= crystal_project_name %>_session"
5 | end
6 |
7 | Lucky::CookieJar.configure do |settings|
8 | settings.on_set = ->(cookie : HTTP::Cookie) {
9 | # If ForceSSLHandler is enabled, only send cookies over HTTPS
10 | cookie.secure(Lucky::ForceSSLHandler.settings.enabled)
11 |
12 | # By default, don't allow reading cookies with JavaScript
13 | cookie.http_only(true)
14 |
15 | # Restrict cookies to a first-party or same-site context
16 | cookie.samesite(:lax)
17 |
18 | # Set all cookies to the root path by default
19 | cookie.path("/")
20 |
21 | # You can set other defaults for cookies here. For example:
22 | #
23 | # cookie.expires(1.year.from_now).domain("mydomain.com")
24 | }
25 | end
26 |
--------------------------------------------------------------------------------
/src/web_app_skeleton/config/env.cr.ecr:
--------------------------------------------------------------------------------
1 | # Environments are managed using `LuckyEnv`. By default, development, production
2 | # and test are supported. See
3 | # https://luckyframework.org/guides/getting-started/configuration for details.
4 | #
5 | # The default environment is development unless the environment variable
6 | # LUCKY_ENV is set.
7 | #
8 | # Example:
9 | # ```
10 | # LuckyEnv.environment # => "development"
11 | # LuckyEnv.development? # => true
12 | # LuckyEnv.production? # => false
13 | # LuckyEnv.test? # => false
14 | # ```
15 | #
16 | # New environments can be added using the `LuckyEnv.add_env` macro.
17 | #
18 | # Example:
19 | # ```
20 | # LuckyEnv.add_env :staging
21 | # LuckyEnv.staging? # => false
22 | # ```
23 | #
24 | # To determine whether or not a `LuckyTask` is currently running, you can use
25 | # the `LuckyEnv.task?` predicate.
26 | #
27 | # Example:
28 | # ```
29 | # LuckyEnv.task? # => false
30 | # ```
31 |
32 | # Add a staging environment.
33 | # LuckyEnv.add_env :staging
34 |
--------------------------------------------------------------------------------
/src/web_app_skeleton/config/error_handler.cr.ecr:
--------------------------------------------------------------------------------
1 | Lucky::ErrorHandler.configure do |settings|
2 | settings.show_debug_output = !LuckyEnv.production?
3 | end
4 |
--------------------------------------------------------------------------------
/src/web_app_skeleton/config/route_helper.cr.ecr:
--------------------------------------------------------------------------------
1 | # This is used when generating URLs for your application
2 | Lucky::RouteHelper.configure do |settings|
3 | if LuckyEnv.production?
4 | # Example: https://my_app.com
5 | settings.base_uri = ENV.fetch("APP_DOMAIN")
6 | else
7 | # Set domain to the default host/port in development/test
8 | settings.base_uri = "http://localhost:#{Lucky::ServerSettings.port}"
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/src/web_app_skeleton/config/watch.yml.ecr:
--------------------------------------------------------------------------------
1 | host: 127.0.0.1
2 | port: 3000
3 | reload_port: 3001
4 |
--------------------------------------------------------------------------------
/src/web_app_skeleton/db/migrations/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/src/web_app_skeleton/db/migrations/.keep
--------------------------------------------------------------------------------
/src/web_app_skeleton/script/helpers/function_helpers.cr.ecr:
--------------------------------------------------------------------------------
1 | require "colorize"
2 |
3 | # These are helper methods provided to help keep your code
4 | # clean. Add new methods, or alter these as needed.
5 |
6 | def notice(message : String) : Nil
7 | puts "\n▸ #{message}"
8 | end
9 |
10 | def print_done : Nil
11 | puts "✔ Done"
12 | end
13 |
14 | def print_error(message : String) : Nil
15 | puts "There is a problem with your system setup:\n".colorize.red.bold
16 | puts "#{message}\n".colorize.red.bold
17 | Process.exit(1)
18 | end
19 |
20 | def command_not_found(command : String) : Bool
21 | Process.find_executable(command).nil?
22 | end
23 |
24 | def command_not_running(command : String, *args) : Bool
25 | output = IO::Memory.new
26 | code = Process.run(command, args, output: output).exit_code
27 | code > 0
28 | end
29 |
30 | def run_command(command : String, *args) : Nil
31 | Process.run(command, args, output: STDOUT, error: STDERR, input: STDIN)
32 | end
33 |
--------------------------------------------------------------------------------
/src/web_app_skeleton/script/setup.cr.ecr:
--------------------------------------------------------------------------------
1 | require "./helpers/*"
2 |
3 | notice "Running System Check"
4 |
5 | require "./system_check"
6 |
7 | print_done
8 |
9 | <%- if browser? -%>
10 | notice "Installing node dependencies"
11 | run_command "yarn", "install", "--no-progress"
12 |
13 | notice "Compiling assets"
14 | run_command "yarn", "dev"
15 |
16 | print_done
17 | <%- end -%>
18 |
19 | notice "Installing shards"
20 | run_command "shards", "install"
21 |
22 | if !File.exists?(".env")
23 | notice "No .env found. Creating one."
24 | File.touch ".env"
25 | print_done
26 | end
27 |
28 | notice "Setting up the database"
29 |
30 | run_command "lucky", "db.setup"
31 |
32 | notice "Seeding the database with required and sample records"
33 | run_command "lucky", "db.seed.required_data"
34 | run_command "lucky", "db.seed.sample_data"
35 |
36 | print_done
37 | notice "Run 'lucky dev' to start the app"
38 |
--------------------------------------------------------------------------------
/src/web_app_skeleton/script/system_check.cr.ecr:
--------------------------------------------------------------------------------
1 | require "./helpers/*"
2 |
3 | # Use this script to check the system for required tools and process that your app needs.
4 | # A few helper functions are provided to keep the code simple. See the
5 | # script/helpers/function_helpers.cr file for more examples.
6 | #
7 | # A few examples you might use here:
8 | # * 'lucky db.verify_connection' to test postgres can be connected
9 | # * Checking that elasticsearch, redis, or postgres is installed and/or booted
10 | # * Note: Booting additional processes for things like mail, background jobs, etc...
11 | # should go in your Procfile.dev.
12 |
13 | <%- if browser? -%>
14 | if command_not_found "yarn"
15 | print_error "Yarn is not installed\n See https://yarnpkg.com/lang/en/docs/install/ for install instructions."
16 | end
17 | <%- end -%>
18 |
19 | # CUSTOM PRE-BOOT CHECKS
20 | # example:
21 | # if command_not_running "redis-cli", "ping"
22 | # print_error "Redis is not running."
23 | # end
24 |
--------------------------------------------------------------------------------
/src/web_app_skeleton/spec/setup/clean_database.cr.ecr:
--------------------------------------------------------------------------------
1 | Spec.before_each do
2 | AppDatabase.truncate
3 | end
4 |
--------------------------------------------------------------------------------
/src/web_app_skeleton/spec/setup/reset_emails.cr.ecr:
--------------------------------------------------------------------------------
1 | Spec.before_each do
2 | Carbon::DevAdapter.reset
3 | end
4 |
--------------------------------------------------------------------------------
/src/web_app_skeleton/spec/setup/setup_database.cr.ecr:
--------------------------------------------------------------------------------
1 | Db::Create.new(quiet: true).call
2 | Db::Migrate.new(quiet: true).call
3 |
--------------------------------------------------------------------------------
/src/web_app_skeleton/spec/setup/start_app_server.cr.ecr:
--------------------------------------------------------------------------------
1 | app_server = AppServer.new
2 |
3 | spawn do
4 | app_server.listen
5 | end
6 |
7 | Spec.after_suite do
8 | <%- if browser? -%>
9 | LuckyFlow.shutdown
10 | <%- end -%>
11 | app_server.close
12 | end
13 |
--------------------------------------------------------------------------------
/src/web_app_skeleton/spec/support/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/src/web_app_skeleton/spec/support/.keep
--------------------------------------------------------------------------------
/src/web_app_skeleton/spec/support/api_client.cr.ecr:
--------------------------------------------------------------------------------
1 | class ApiClient < Lucky::BaseHTTPClient
2 | app AppServer.new
3 |
4 | def initialize
5 | super
6 | headers("Content-Type": "application/json")
7 | end
8 | <%- if generate_auth? -%>
9 |
10 | def self.auth(user : User)
11 | new.headers("Authorization": UserToken.generate(user))
12 | end
13 | <%- end -%>
14 | end
15 |
--------------------------------------------------------------------------------
/src/web_app_skeleton/spec/support/factories/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/src/web_app_skeleton/spec/support/factories/.keep
--------------------------------------------------------------------------------
/src/web_app_skeleton/src/actions/api_action.cr.ecr:
--------------------------------------------------------------------------------
1 | # Include modules and add methods that are for all API requests
2 | abstract class ApiAction < Lucky::Action
3 | # APIs typically do not need to send cookie/session data.
4 | # Remove this line if you want to send cookies in the response header.
5 | disable_cookies
6 | accepted_formats [:json]
7 | <%- if generate_auth? -%>
8 |
9 | include Api::Auth::Helpers
10 |
11 | # By default all actions require sign in.
12 | # Add 'include Api::Auth::SkipRequireAuthToken' to your actions to allow all requests.
13 | include Api::Auth::RequireAuthToken
14 | <%- end -%>
15 |
16 | # By default all actions are required to use underscores to separate words.
17 | # Add 'include Lucky::SkipRouteStyleCheck' to your actions if you wish to ignore this check for specific routes.
18 | include Lucky::EnforceUnderscoredRoute
19 | end
20 |
--------------------------------------------------------------------------------
/src/web_app_skeleton/src/actions/home/index.cr.ecr:
--------------------------------------------------------------------------------
1 | <%- if api_only? -%>
2 | class Home::Index < ApiAction
3 | <%- if generate_auth? -%>
4 | include Api::Auth::SkipRequireAuthToken
5 |
6 | <%- end -%>
7 | get "/" do
8 | json({hello: "Hello World from Home::Index"})
9 | end
10 | end
11 | <%- else -%>
12 | class Home::Index < BrowserAction
13 | <%- if generate_auth? -%>
14 | include Auth::AllowGuests
15 |
16 | get "/" do
17 | if current_user?
18 | redirect Me::Show
19 | else
20 | # When you're ready change this line to:
21 | #
22 | # redirect SignIns::New
23 | #
24 | # Or maybe show signed out users a marketing page:
25 | #
26 | # html Marketing::IndexPage
27 | html Lucky::WelcomePage
28 | end
29 | end
30 | <%- else -%>
31 | get "/" do
32 | html Lucky::WelcomePage
33 | end
34 | <%- end -%>
35 | end
36 | <%- end -%>
37 |
--------------------------------------------------------------------------------
/src/web_app_skeleton/src/actions/mixins/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/src/web_app_skeleton/src/actions/mixins/.keep
--------------------------------------------------------------------------------
/src/web_app_skeleton/src/app.cr.ecr:
--------------------------------------------------------------------------------
1 | require "./shards"
2 |
3 | <%- if browser? -%>
4 | # Load the asset manifest
5 | Lucky::AssetHelpers.load_manifest "public/mix-manifest.json"
6 |
7 | <%- end -%>
8 | require "../config/server"
9 | require "./app_database"
10 | require "../config/**"
11 | require "./models/base_model"
12 | require "./models/mixins/**"
13 | require "./models/**"
14 | require "./queries/mixins/**"
15 | require "./queries/**"
16 | require "./operations/mixins/**"
17 | require "./operations/**"
18 | require "./serializers/base_serializer"
19 | require "./serializers/**"
20 | require "./emails/base_email"
21 | require "./emails/**"
22 | require "./actions/mixins/**"
23 | require "./actions/**"
24 | <%- if browser? -%>
25 | require "./components/base_component"
26 | require "./components/**"
27 | require "./pages/**"
28 | <%- end -%>
29 | require "../db/migrations/**"
30 | require "./app_server"
31 |
--------------------------------------------------------------------------------
/src/web_app_skeleton/src/app_database.cr.ecr:
--------------------------------------------------------------------------------
1 | class AppDatabase < Avram::Database
2 | end
3 |
--------------------------------------------------------------------------------
/src/web_app_skeleton/src/emails/base_email.cr.ecr:
--------------------------------------------------------------------------------
1 | # Learn about sending emails
2 | # https://luckyframework.org/guides/emails/sending-emails-with-carbon
3 | abstract class BaseEmail < Carbon::Email
4 | # You can add defaults using the 'inherited' hook
5 | #
6 | # Example:
7 | #
8 | # macro inherited
9 | # from default_from
10 | # end
11 | #
12 | # def default_from
13 | # Carbon::Address.new("support@app.com")
14 | # end
15 | end
16 |
--------------------------------------------------------------------------------
/src/web_app_skeleton/src/models/base_model.cr.ecr:
--------------------------------------------------------------------------------
1 | abstract class BaseModel < Avram::Model
2 | def self.database : Avram::Database.class
3 | AppDatabase
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/src/web_app_skeleton/src/models/mixins/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/src/web_app_skeleton/src/models/mixins/.keep
--------------------------------------------------------------------------------
/src/web_app_skeleton/src/operations/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/src/web_app_skeleton/src/operations/.keep
--------------------------------------------------------------------------------
/src/web_app_skeleton/src/operations/mixins/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/src/web_app_skeleton/src/operations/mixins/.keep
--------------------------------------------------------------------------------
/src/web_app_skeleton/src/project_name.cr.ecr:
--------------------------------------------------------------------------------
1 | # Typically you will not use or modify this file. 'shards build' and some
2 | # other crystal tools will sometimes use this.
3 | #
4 | # When this file is compiled/run it will require and run 'start_server',
5 | # which as its name implies will start the server for you app.
6 | require "./start_server"
7 |
--------------------------------------------------------------------------------
/src/web_app_skeleton/src/queries/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/src/web_app_skeleton/src/queries/.keep
--------------------------------------------------------------------------------
/src/web_app_skeleton/src/queries/mixins/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/src/web_app_skeleton/src/queries/mixins/.keep
--------------------------------------------------------------------------------
/src/web_app_skeleton/src/serializers/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/src/web_app_skeleton/src/serializers/.keep
--------------------------------------------------------------------------------
/src/web_app_skeleton/src/serializers/base_serializer.cr.ecr:
--------------------------------------------------------------------------------
1 | abstract class BaseSerializer
2 | include Lucky::Serializable
3 |
4 | def self.for_collection(collection : Enumerable, *args, **named_args) : Array(self)
5 | collection.map do |object|
6 | new(object, *args, **named_args)
7 | end
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/src/web_app_skeleton/src/serializers/error_serializer.cr.ecr:
--------------------------------------------------------------------------------
1 | # This is the default error serializer generated by Lucky.
2 | # Feel free to customize it in any way you like.
3 | class ErrorSerializer < BaseSerializer
4 | def initialize(
5 | @message : String,
6 | @details : String? = nil,
7 | @param : String? = nil, # so you can track which param (if any) caused the problem
8 | )
9 | end
10 |
11 | def render
12 | {message: @message, param: @param, details: @details}
13 | end
14 | end
15 |
--------------------------------------------------------------------------------
/src/web_app_skeleton/src/shards.cr.ecr:
--------------------------------------------------------------------------------
1 | # Load .env file before any other config or app code
2 | require "lucky_env"
3 | LuckyEnv.load?(".env")
4 |
5 | # Require your shards here
6 | require "lucky"
7 | require "avram/lucky"
8 | require "carbon"
9 | <%- if generate_auth? -%>
10 | require "authentic"
11 | require "jwt"
12 | <%- end -%>
13 |
--------------------------------------------------------------------------------
/src/web_app_skeleton/src/start_server.cr.ecr:
--------------------------------------------------------------------------------
1 | require "./app"
2 |
3 | Habitat.raise_if_missing_settings!
4 |
5 | if LuckyEnv.development?
6 | Avram::Migrator::Runner.new.ensure_migrated!
7 | Avram::SchemaEnforcer.ensure_correct_column_mappings!
8 | end
9 |
10 | app_server = AppServer.new
11 | <%- if !proxied_through_browsersync? -%>
12 | puts "Listening on http://#{app_server.host}:#{app_server.port}"
13 | <%- end -%>
14 |
15 | Signal::INT.trap do
16 | app_server.close
17 | end
18 |
19 | app_server.listen
20 |
--------------------------------------------------------------------------------
/src/web_app_skeleton/tasks.cr.ecr:
--------------------------------------------------------------------------------
1 | # This file loads your app and all your tasks when running 'lucky'
2 | #
3 | # Run 'lucky --help' to see all available tasks.
4 | #
5 | # Learn to create your own tasks:
6 | # https://luckyframework.org/guides/command-line-tasks/custom-tasks
7 |
8 | # See `LuckyEnv#task?`
9 | ENV["LUCKY_TASK"] = "true"
10 |
11 | # Load Lucky and the app (actions, models, etc.)
12 | require "./src/app"
13 | require "lucky_task"
14 |
15 | # You can add your own tasks here in the ./tasks folder
16 | require "./tasks/**"
17 |
18 | # Load migrations
19 | require "./db/migrations/**"
20 |
21 | # Load Lucky tasks (dev, routes, etc.)
22 | require "lucky/tasks/**"
23 | require "avram/lucky/tasks"
24 |
25 | LuckyTask::Runner.run
26 |
--------------------------------------------------------------------------------
/src/web_app_skeleton/tasks/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckyframework/lucky_cli/ccaa571765582086d437efe0da4f439a19929d64/src/web_app_skeleton/tasks/.keep
--------------------------------------------------------------------------------