diff --git a/engelsystem.yml b/engelsystem.yml new file mode 100644 index 0000000..9b47a31 --- /dev/null +++ b/engelsystem.yml @@ -0,0 +1,9 @@ +--- +- name: Set up Engelsystem + hosts: uberspace + vars_files: + - general_vars.yml + - engelsystem_vars.yml + remote_user: "{{ uberspace_user }}" + roles: + - engelsystem \ No newline at end of file diff --git a/engelsystem_vars.yml.example b/engelsystem_vars.yml.example new file mode 100644 index 0000000..0b651db --- /dev/null +++ b/engelsystem_vars.yml.example @@ -0,0 +1,3 @@ +--- +engelsystem_contact_email: contactEmailForYourEngelsystem +engelsystem_faq: 'faqInMarkdownOrNull' \ No newline at end of file diff --git a/general_vars.yml.example b/general_vars.yml.example index 6f5ba86..0afd5ba 100644 --- a/general_vars.yml.example +++ b/general_vars.yml.example @@ -3,5 +3,7 @@ uberspace_user: yourUberspaceUser domain: domainToService node_version: 12 php_version: 7.4 +mail_host: yourHostname.uberspace.de +mail_password: yourMailPassword mysql_user: yourMysqlUser mysql_password: yourMysqlPassword diff --git a/roles/common/defaults/main.yml b/roles/common/defaults/main.yml new file mode 100644 index 0000000..505e83e --- /dev/null +++ b/roles/common/defaults/main.yml @@ -0,0 +1,3 @@ +--- +mail_encryption: 'tls' +mail_driver: 'smtp' \ No newline at end of file diff --git a/roles/engelsystem/defaults/main.yml b/roles/engelsystem/defaults/main.yml new file mode 100644 index 0000000..8170f52 --- /dev/null +++ b/roles/engelsystem/defaults/main.yml @@ -0,0 +1,13 @@ +--- +engelsystem_version: 3.2.0 +engelsystem_environment: 'production' # development +engelsystem_system_email: 'noreply@{{ domain }}' +engelsystem_faq: null +engelsystem_theme: 1 +engelsystem_home_site: 'news' # news, meetings, user_shifts, angeltypes, questions +engelsystem_angel_autoarrive: true # false +engelsystem_enable_tshirt: false # true +engelsystem_enable_pronoun: true # false +engelsystem_enable_username: true # false +engelsystem_enable_dect: false # true +engelsystem_planned_arrival: false # true \ No newline at end of file diff --git a/roles/engelsystem/meta/main.yml b/roles/engelsystem/meta/main.yml new file mode 100644 index 0000000..1c5dc7b --- /dev/null +++ b/roles/engelsystem/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - role: common \ No newline at end of file diff --git a/roles/engelsystem/tasks/config.yml b/roles/engelsystem/tasks/config.yml new file mode 100644 index 0000000..2c2fbae --- /dev/null +++ b/roles/engelsystem/tasks/config.yml @@ -0,0 +1,11 @@ +--- +- name: Disable directory listing + ansible.builtin.template: + src: htaccess.j2 + dest: ~/html/.htaccess + mode: 0644 +- name: Use custom config file + ansible.builtin.template: + src: config.php.j2 + dest: /var/www/virtual/{{ uberspace_user }}/config/config.php + mode: 0644 diff --git a/roles/engelsystem/tasks/download.yml b/roles/engelsystem/tasks/download.yml new file mode 100644 index 0000000..980f573 --- /dev/null +++ b/roles/engelsystem/tasks/download.yml @@ -0,0 +1,59 @@ +--- +- name: delete nocontent + ansible.builtin.file: + path: ~/html/nocontent.html + state: absent +- name: create directory for download + ansible.builtin.file: + path: ~/engelsystem + state: directory + mode: 0755 +- name: download Engelsystem + ansible.builtin.unarchive: + src: https://github.com/engelsystem/engelsystem/releases/download/v{{ engelsystem_version }}/engelsystem-v{{ engelsystem_version }}.zip + dest: ~/engelsystem + remote_src: yes + creates: ~/engelsystem/release + register: engelsystem_archive +- name: check web root + ansible.builtin.stat: + path: /var/www/virtual/{{ uberspace_user }}/engelsystem/storage + register: storage +- name: ensure correct mode for web directory + when: storage.stat.isdir is not defined + ansible.builtin.file: + path: /var/www/virtual/{{ uberspace_user }}/engelsystem + mode: 0755 + state: directory +- name: copy to web root + when: storage.stat.isdir is not defined + ansible.builtin.copy: + src: ~/engelsystem/release/ + dest: /var/www/virtual/{{ uberspace_user }}/engelsystem + remote_src: yes + directory_mode: 0755 + mode: 0644 +- name: ensure correct mode for web directory + ansible.builtin.file: + path: /var/www/virtual/{{ uberspace_user }} + mode: 0750 + state: directory +- name: point html directory to engelsystem public directory + block: + - name: remove old html directory + ansible.builtin.file: + path: /var/www/virtual/{{ uberspace_user }}/html + state: absent + - name: create symlink to public directory + ansible.builtin.file: + path: /var/www/virtual/{{ uberspace_user }}/html + src: /var/www/virtual/{{ uberspace_user }}/engelsystem/public + state: link +- name: ensure correct SE settings + ansible.builtin.shell: + cmd: /usr/sbin/restorecon -R -v /var/www/virtual/{{ uberspace_user|quote }}/html +- name: download database install script + ansible.builtin.get_url: + url: https://github.com/engelsystem/engelsystem/releases/download/v{{ engelsystem_version }}/install-v{{ engelsystem_version }}.sql + dest: ~/engelsystem/install.sql + mode: 0644 diff --git a/roles/engelsystem/tasks/main.yml b/roles/engelsystem/tasks/main.yml new file mode 100644 index 0000000..2752eba --- /dev/null +++ b/roles/engelsystem/tasks/main.yml @@ -0,0 +1,4 @@ +--- +- include: download.yml +- include: mysql.yml +- include: config.yml \ No newline at end of file diff --git a/roles/engelsystem/tasks/mysql.yml b/roles/engelsystem/tasks/mysql.yml new file mode 100644 index 0000000..fc5af4e --- /dev/null +++ b/roles/engelsystem/tasks/mysql.yml @@ -0,0 +1,13 @@ +--- +- name: create MySQL database + community.mysql.mysql_db: + name: "{{ uberspace_user }}_engelsystem" + encoding: utf8 + register: create_database +- name: import initial database contents + when: create_database.changed + community.mysql.mysql_db: + name: "{{ uberspace_user }}_engelsystem" + state: import + target: ~/engelsystem/install.sql + encoding: utf8 \ No newline at end of file diff --git a/roles/engelsystem/templates/config.php.j2 b/roles/engelsystem/templates/config.php.j2 new file mode 100644 index 0000000..3764534 --- /dev/null +++ b/roles/engelsystem/templates/config.php.j2 @@ -0,0 +1,266 @@ + [ + 'host' => env('MYSQL_HOST', (env('CI', false) ? 'mariadb' : 'localhost')), + 'database' => env('MYSQL_DATABASE', '{{ uberspace_user }}_engelsystem'), + 'username' => env('MYSQL_USER', '{{ mysql_user }}'), + 'password' => env('MYSQL_PASSWORD', '{{ mysql_password }}'), + ], + + // For accessing stats + 'api_key' => '', + + // Enable maintenance mode (show a static page) + 'maintenance' => (bool)env('MAINTENANCE', false), + + // Application name (not the event name!) + 'app_name' => env('APP_NAME', 'Engelsystem'), + + // Set to development to enable debugging messages + 'environment' => env('ENVIRONMENT', '{{ engelsystem_environment }}'), + + // Application URL and base path to use instead of the auto detected one + 'url' => env('APP_URL', null), + + // Header links + // Available link placeholders: %lang% + 'header_items' => [ + //'Foo' => 'https://foo.bar/batz-%lang%.html', + ], + + // Footer links + 'footer_items' => [ + // URL to the angel faq and job description + 'FAQ' => env('FAQ_URL', '/faq'), + + // Contact email address, linked on every page + 'Contact' => env('CONTACT_EMAIL', 'mailto:{{ engelsystem_contact_email }}'), + ], + + // Text displayed on the FAQ page, rendered as markdown + 'faq_text' => env('FAQ_TEXT', {{ engelsystem_faq }}), + + // Link to documentation/help + 'documentation_url' => 'https://engelsystem.de/doc/', + + // Email config + 'email' => [ + // Can be mail, smtp, sendmail or log + 'driver' => env('MAIL_DRIVER', '{{ mail_driver }}'), + 'from' => [ + // From address of all emails + 'address' => env('MAIL_FROM_ADDRESS', '{{ engelsystem_system_email }}'), + 'name' => env('MAIL_FROM_NAME', env('APP_NAME', 'Engelsystem')), + ], + + 'host' => env('MAIL_HOST', '{{ mail_host }}'), + 'port' => env('MAIL_PORT', 587), + // Transport encryption like tls (for starttls) or ssl + 'encryption' => env('MAIL_ENCRYPTION', '{{ mail_encryption }}'), + 'username' => env('MAIL_USERNAME', '{{ uberspace_user }}@uber.space'), + 'password' => env('MAIL_PASSWORD', '{{ mail_password }}'), + 'sendmail' => env('MAIL_SENDMAIL', '/usr/sbin/sendmail -bs'), + ], + + 'oauth' => [ + // '[name]' => [config] + /* + '[name]' => [ + // Name shown to the user (optional) + 'name' => 'Some Provider', + // Auth client ID + 'client_id' => 'engelsystem', + // Auth client secret + 'client_secret' => '[generated by provider]', + // Authentication URL + 'url_auth' => '[generated by provider]', + // Token URL + 'url_token' => '[generated by provider]', + // User info URL which provides userdata + 'url_info' => '[generated by provider]', + // Info unique user id field + 'id' => 'uuid', + // The following fields are used for registration + // Info username field (optional) + 'username' => 'nickname', + // Info email field (optional) + 'email' => 'email', + // Info first name field (optional) + 'first_name' => 'first-name', + // Info last name field (optional) + 'last_name' => 'last-name', + // User URL to provider, shown on provider settings page (optional) + 'url' => '[provider page]', + // Only show after clicking the page title (optional) + 'hidden' => false, + // Mark user as arrived when using this provider (optional) + 'mark_arrived' => false, + ], + */ + ], + + // Default theme, 1=style1.css + 'theme' => env('THEME', {{ engelsystem_theme }}), + + // Available themes + 'available_themes' => [ + '14' => 'Engelsystem rC3 teal (2020)', + '13' => 'Engelsystem rC3 violet (2020)', + '12' => 'Engelsystem 36c3 (2019)', + '10' => 'Engelsystem cccamp19 green (2019)', + '9' => 'Engelsystem cccamp19 yellow (2019)', + '8' => 'Engelsystem cccamp19 blue (2019)', + '7' => 'Engelsystem 35c3 dark (2018)', + '6' => 'Engelsystem 34c3 dark (2017)', + '5' => 'Engelsystem 34c3 light (2017)', + '4' => 'Engelsystem 33c3 (2016)', + '3' => 'Engelsystem 32c3 (2015)', + '2' => 'Engelsystem cccamp15', + '11' => 'Engelsystem high contrast', + '0' => 'Engelsystem light', + '1' => 'Engelsystem dark', + ], + + // Redirect to this site after logging in or when pressing the top-left button + // Must be one of news, meetings, user_shifts, angeltypes, questions + 'home_site' => env('HOME_SITE', '{{ engelsystem_home_site }}'), + + // Number of News shown on one site + 'display_news' => env('DISPLAY_NEWS', 10), + + // Users are able to sign up + 'registration_enabled' => (bool)env('REGISTRATION_ENABLED', true), + + // Only arrived angels can sign up for shifts + 'signup_requires_arrival' => (bool)env('SIGNUP_REQUIRES_ARRIVAL', false), + + // Whether newly-registered user should automatically be marked as arrived + 'autoarrive' => (bool)env('ANGEL_AUTOARRIVE', {{ engelsystem_angel_autoarrive }}), + + // Only allow shift signup this number of hours in advance + // Setting this to 0 disables the feature + 'signup_advance_hours' => env('SIGNUP_ADVANCE_HOURS', 0), + + // Allow signup this many minutes after the start of the shift + 'signup_post_minutes' => env('SIGNUP_POST_MINUTES', 0), + + // Number of hours that an angel has to sign out own shifts + 'last_unsubscribe' => env('LAST_UNSUBSCRIBE', 3), + + // Define the algorithm to use for `password_verify()` + // If the user uses an old algorithm the password will be converted to the new format + // See https://secure.php.net/manual/en/password.constants.php for a complete list + 'password_algorithm' => PASSWORD_DEFAULT, + + // The minimum length for passwords + 'min_password_length' => env('PASSWORD_MINIMUM_LENGTH', 8), + + // Whether the DECT field should be enabled + 'enable_dect' => (bool)env('ENABLE_DECT', {{ engelsystem_enable_dect }}), + + // Enables prename and lastname + 'enable_user_name' => (bool)env('ENABLE_USER_NAME', {{ engelsystem_enable_username }}), + + // Enable displaying the pronoun fields + 'enable_pronoun' => (bool)env('ENABLE_PRONOUN', {{ engelsystem_enable_pronoun }}), + + // Enables the planned arrival/leave date + 'enable_planned_arrival' => (bool)env('ENABLE_PLANNED_ARRIVAL', {{ engelsystem_planned_arrival }}), + + // Enables the T-Shirt configuration on signup and profile + 'enable_tshirt_size' => (bool)env('ENABLE_TSHIRT_SIZE', {{ engelsystem_enable_tshirt }}), + + // Number of shifts to freeload until angel is locked for shift signup. + 'max_freeloadable_shifts' => env('MAX_FREELOADABLE_SHIFTS', 2), + + // Local timezone + 'timezone' => env('TIMEZONE', ini_get('date.timezone') ?: 'Europe/Berlin'), + + // Multiply 'night shifts' and freeloaded shifts (start or end between 2 and 6 exclusive) by 2 + 'night_shifts' => [ + 'enabled' => (bool)env('NIGHT_SHIFTS', true), // Disable to weigh every shift the same + 'start' => env('NIGHT_SHIFTS_START', 2), + 'end' => env('NIGHT_SHIFTS_END', 6), + 'multiplier' => env('NIGHT_SHIFTS_MULTIPLIER', 2), + ], + + // Voucher calculation + 'voucher_settings' => [ + 'initial_vouchers' => env('INITIAL_VOUCHERS', 0), + 'shifts_per_voucher' => env('SHIFTS_PER_VOUCHER', 0), + 'hours_per_voucher' => env('HOURS_PER_VOUCHER', 2), + // 'Y-m-d' formatted + 'voucher_start' => env('VOUCHER_START', null) ?: null, + ], + + // Available locales in /resources/lang/ + 'locales' => [ + 'de_DE' => 'Deutsch', + 'en_US' => 'English', + ], + + // The default locale to use + 'default_locale' => env('DEFAULT_LOCALE', 'en_US'), + + // Available T-Shirt sizes, set value to null if not available + 'tshirt_sizes' => [ + 'S' => 'Small Straight-Cut', + 'S-G' => 'Small Fitted-Cut', + 'M' => 'Medium Straight-Cut', + 'M-G' => 'Medium Fitted-Cut', + 'L' => 'Large Straight-Cut', + 'L-G' => 'Large Fitted-Cut', + 'XL' => 'XLarge Straight-Cut', + 'XL-G' => 'XLarge Fitted-Cut', + '2XL' => '2XLarge Straight-Cut', + '3XL' => '3XLarge Straight-Cut', + '4XL' => '4XLarge Straight-Cut', + ], + + 'metrics' => [ + // User work buckets in seconds + 'work' => [1 * 60 * 60, 1.5 * 60 * 60, 2 * 60 * 60, 3 * 60 * 60, 5 * 60 * 60, 10 * 60 * 60, 20 * 60 * 60], + 'voucher' => [0, 1, 2, 3, 5, 10, 15, 20], + ], + + // Shifts overview + // Set max number of hours that can be shown at once + // 0 means no limit + 'filter_max_duration' => env('FILTER_MAX_DURATION', 0), + + // Session config + 'session' => [ + // Supported: pdo or native + 'driver' => env('SESSION_DRIVER', 'pdo'), + + // Cookie name + 'name' => env('SESSION_NAME', 'session'), + ], + + // IP addresses of reverse proxies that are trusted, can be an array or a comma separated list + 'trusted_proxies' => env('TRUSTED_PROXIES', ['127.0.0.0/8', '::ffff:127.0.0.0/8', '::1/128']), + + // Add additional headers + 'add_headers' => (bool)env('ADD_HEADERS', true), + 'headers' => [ + 'X-Content-Type-Options' => 'nosniff', + 'X-Frame-Options' => 'sameorigin', + 'Referrer-Policy' => 'strict-origin-when-cross-origin', + 'Content-Security-Policy' => 'default-src \'self\' \'unsafe-inline\' \'unsafe-eval\'', + 'X-XSS-Protection' => '1; mode=block', + 'Feature-Policy' => 'autoplay \'none\'', + //'Strict-Transport-Security' => 'max-age=7776000', + //'Expect-CT' => 'max-age=7776000,enforce,report-uri="[uri]"', + ], + + // A list of credits + 'credits' => [ + 'Contribution' => 'Please visit [engelsystem/engelsystem](https://github.com/engelsystem/engelsystem) if ' + . 'you want to to contribute, have found any [bugs](https://github.com/engelsystem/engelsystem/issues) ' + . 'or need help.' + ], +]; \ No newline at end of file diff --git a/roles/engelsystem/templates/htaccess.j2 b/roles/engelsystem/templates/htaccess.j2 new file mode 100644 index 0000000..e64510d --- /dev/null +++ b/roles/engelsystem/templates/htaccess.j2 @@ -0,0 +1,8 @@ +Options -Indexes + + RewriteEngine on + + RewriteCond %{REQUEST_FILENAME} !-d + RewriteCond %{REQUEST_FILENAME} !-f + RewriteRule ^ index.php [L] + \ No newline at end of file diff --git a/roles/nextcloud/tasks/download.yml b/roles/nextcloud/tasks/download.yml index 2f2d54e..3af5c56 100644 --- a/roles/nextcloud/tasks/download.yml +++ b/roles/nextcloud/tasks/download.yml @@ -11,7 +11,7 @@ src: ~/nextcloud/ dest: ~/html remote_src: yes - when: nextcloud_archive is successful + when: nextcloud_archive.changed - name: remove nocontent.html file: path: ~/html/nocontent.html