Compare commits
1 Commits
1.3
...
bb8e7f359f
| Author | SHA1 | Date | |
|---|---|---|---|
| bb8e7f359f |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -5,7 +5,6 @@
|
||||
/public/bundles/
|
||||
/var/
|
||||
/vendor/
|
||||
/migrations/
|
||||
###< symfony/framework-bundle ###
|
||||
|
||||
###> phpunit/phpunit ###
|
||||
@@ -24,5 +23,3 @@
|
||||
###< symfony/asset-mapper ###
|
||||
|
||||
/references/
|
||||
composer.lock
|
||||
.continue
|
||||
42
Dockerfile
42
Dockerfile
@@ -1,4 +1,4 @@
|
||||
FROM php:8.5-apache
|
||||
FROM php:8.4-apache
|
||||
|
||||
RUN apt update && \
|
||||
apt upgrade -y && \
|
||||
@@ -11,14 +11,11 @@ RUN apt update && \
|
||||
libjpeg-dev \
|
||||
libicu-dev \
|
||||
libpq-dev \
|
||||
libsqlite3-dev \
|
||||
sqlite3 \
|
||||
curl \
|
||||
git \
|
||||
cron \
|
||||
nano
|
||||
|
||||
|
||||
RUN docker-php-ext-configure gd --with-jpeg
|
||||
RUN docker-php-ext-configure zip
|
||||
|
||||
@@ -31,8 +28,7 @@ RUN docker-php-ext-install \
|
||||
xml \
|
||||
intl \
|
||||
pdo_mysql \
|
||||
pdo_pgsql \
|
||||
pdo_sqlite
|
||||
pdo_pgsql
|
||||
|
||||
RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" && \
|
||||
php composer-setup.php --install-dir=/usr/local/bin --filename=composer && \
|
||||
@@ -41,38 +37,22 @@ RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" &&
|
||||
RUN curl -sS https://get.symfony.com/cli/installer | bash && \
|
||||
mv /root/.symfony5/bin/symfony /usr/local/bin/symfony
|
||||
|
||||
ARG CACHEBURST=1
|
||||
ARG BRANCH=master
|
||||
|
||||
WORKDIR /var/www/html
|
||||
RUN git clone -b ${BRANCH} --single-branch https://gitea.rkprather.com/ryan/sermon-notes.git ./
|
||||
RUN git config --global --add safe.directory /var/www/html
|
||||
COPY . /var/www/html/
|
||||
|
||||
RUN mv 000-default.conf /etc/apache2/sites-available/
|
||||
|
||||
RUN echo "20 1 * * 6 root cd /var/www/html && /usr/local/bin/php bin/console app:get-audio > /proc/1/fd/1 2>&1" > /etc/cron.d/get-audio
|
||||
RUN chmod 644 /etc/cron.d/get-audio
|
||||
RUN crontab /etc/cron.d/get-audio
|
||||
RUN rm /var/www/html/.env*
|
||||
RUN rm -rf /var/www/html/var/*
|
||||
RUN rm -rf /var/www/html/vendor
|
||||
RUN rm -rf /var/www/html/tests
|
||||
RUN rm -rf /var/www/html/translations
|
||||
|
||||
RUN COMPOSER_ALLOW_SUPERUSER=1 composer install --no-scripts --no-dev --optimize-autoloader
|
||||
RUN mkdir /data
|
||||
|
||||
RUN mkdir -p /var/www/html/var/cache/prod
|
||||
RUN mkdir -p /var/www/html/var/log
|
||||
RUN mkdir /var/www/html/var/cache
|
||||
RUN mkdir /var/www/html/var/log
|
||||
|
||||
RUN chown -R 33:33 /var/www/html /data
|
||||
RUN find /var/www/html -type d -exec chmod 755 '{}' \;
|
||||
RUN find /var/www/html -type f -exec chmod 644 '{}' \;
|
||||
RUN chmod 755 /data
|
||||
RUN a2enmod rewrite setenvif headers
|
||||
|
||||
COPY prod.env /var/www/html/.env
|
||||
RUN /usr/local/bin/php bin/console importmap:install
|
||||
RUN /usr/local/bin/php bin/console asset-map:compile
|
||||
RUN rm /var/www/html/.env
|
||||
RUN chmod +x /var/www/html/bin/entrypoint.sh
|
||||
RUN chmod -R 755 /var/www/html /data
|
||||
|
||||
EXPOSE 80
|
||||
|
||||
ENTRYPOINT ["/var/www/html/bin/entrypoint.sh"]
|
||||
CMD ["apache2-foreground"]
|
||||
|
||||
31
README.md
31
README.md
@@ -7,34 +7,21 @@ A program to take notes during a sermon. The web app was built with PHP and Sym
|
||||
This was my first publicly available docker container so I did not realize what some decisions would do. If you are upgrading from v1 you first need to save your database OR you will lose all your current notes!! Follow the steps below to do that
|
||||
|
||||
1. You need to make sure that you have a running SSH server on your host computer
|
||||
2. Make a directory in your `sermon-notes` folder for your database (e.g. `data`)
|
||||
3. On your host computer, `docker exec -it sermon-notes bash`
|
||||
4. `scp .env {user}@{IP}:{path}`
|
||||
2. On your host computer, `docker exec -it sermon-notes bash`
|
||||
3. `cd var/`
|
||||
4. `scp data.db {user}@{host computer IP}:{path}`
|
||||
5. Authenticate with the password
|
||||
6. `cd var/`
|
||||
7. `scp data.db {user}@{IP}:{path}/data`
|
||||
8. This will copy the file to the host computer
|
||||
9. After this then you run the `docker run...` command in Step 3 of the `Installation` instructions below
|
||||
6. This will copy the file over SFTP to the host computer
|
||||
7. After this then you run the `docker run...` command in Step 1 of the `Installation` instructions below, once the container is running you need to copy the `data.db` file into the working directory of the docker container.
|
||||
- For example, if you have `~/docker/sermon-notes` as the path for the container on the host computer, you'll copy the `data.db` to `~/docker/sermon-notes/data`
|
||||
|
||||
## Installation
|
||||
|
||||
1. Make a directory in your desired docker storage folder (e.g. `~/docker/sermon-notes`), then `cd` into it.
|
||||
2. Create a file called `.env` in that folder, no need to add anything to it right now.
|
||||
3. Download your preferred compose file (`wget -O compose.yml {link}`)
|
||||
1. [`compose.sqlite.yml`](https://gitea.rkprather.com/ryan/sermon-notes/raw/branch/main/docker/compose.sqlite.yml) - compose file for if you are planning to use SQLite
|
||||
2. [`compose.mysql.yml`](https://gitea.rkprather.com/ryan/sermon-notes/raw/branch/main/docker/compose.mysql.yml) - compose file with an integrated MYSQL database image
|
||||
3. [`compose.mariadb.yml`](https://gitea.rkprather.com/ryan/sermon-notes/raw/branch/main/docker/compose.mariadb.yml) - compose file with an integrate MariaDB database image
|
||||
4. [`compose.pgsql.yml`](https://gitea.rkprather.com/ryan/sermon-notes/raw/branch/main/docker/compose.pgsql.yml) - compose file with an integrate Postgres database image
|
||||
5. [`compose.shared-db.yml`](https://gitea.rkprather.com/ryan/sermon-notes/raw/branch/main/docker/compose.shared-db.yml) - compose file with no database image because you are planning on using an existing database container or bare metal server
|
||||
4. Pull the image `docker pull gitea.rkprather.com/ryan/sermon-notes:latest`
|
||||
5. **NOTE: IF UPGRADING SKIP THIS STEP!!!** - Run the setup script, this will setup your .env file so that when you start the container everything will be where it is supposed to be.
|
||||
- `docker run --rm -it -v ${PWD}/.env:/var/www/html/.env gitea.rkprather.com/ryan/sermon-notes:latest php /var/www/html/setup.php --{database-type} {--shared}`
|
||||
- `{database-type}` = `sqlite`, `mysql`, `mariadb`, or `pgsql`
|
||||
- If you intend on this being connected to a shared database make sure that you specify `--shared`.
|
||||
6. Start the container with compose `docker compose up -d`
|
||||
7. **NOTE: IF UPGRADING SKIP THIS STEP!!!** Run `docker exec -it sermon-notes php /var/www/html/install.php`. This will run the `php composer` to populate the database with all the desired reference material.
|
||||
- NOTE: You will see deprecation warnings, you can ignore these
|
||||
8. Once complete you have a running system that you can navigate to in your browser with `http://{ip}:{port}`|`http://{hostname}:{port}`. Then you just need to register for an account. The first account that is created is made an admin so that you can access the `Reference Editor` and update any reference material if necessary.
|
||||
3. Run `docker run -d --name sermon-notes -p 80:80 -v $PWD/data:/data -v $PWD/.env:/var/www/html/.env gitea.rkprather.com/ryan/sermon-notes:latest`, this will download and start the container and keep it running in the background. If you already have something on port 80 change the first `80` to whatever open port you'd like.
|
||||
4. Run `docker exec -it sermon-notes bash install.sh` This will run an install script to create an .env file specific to your install, populate with the beginning factors, and then run a `composer` command to download the necessary package dependancies.
|
||||
5. Once complete you have a running system that you can navigate to in your browser with `http://{ip}:{port}`|`http://{hostname}:{port}`. Then you just need to register for an account. The first account that is created is made an admin so that you can access the `Reference Editor` and update any reference material if necessary.
|
||||
|
||||
## Operation
|
||||
|
||||
|
||||
95
assets/css/fontawesome-all.min.css
vendored
95
assets/css/fontawesome-all.min.css
vendored
File diff suppressed because one or more lines are too long
@@ -1,4 +1,4 @@
|
||||
@import '../css/fontawesome-all.min.css';
|
||||
@import 'fontawesome-all.min.css';
|
||||
@import url("https://fonts.googleapis.com/css?family=Open+Sans:400,600,400italic,600italic|Roboto+Slab:400,700");
|
||||
/*
|
||||
Editorial by HTML5 UP
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
#!/bin/bash
|
||||
# Start the cron service in the background
|
||||
service cron start
|
||||
|
||||
chown -R www-data:www-data /var/www/html/var
|
||||
|
||||
# Execute the default Docker CMD (which starts Apache in the foreground)
|
||||
exec "$@"
|
||||
3656
composer.lock
generated
3656
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -1,11 +0,0 @@
|
||||
# Enable stateless CSRF protection for forms and logins/logouts
|
||||
framework:
|
||||
form:
|
||||
csrf_protection:
|
||||
token_id: submit
|
||||
|
||||
csrf_protection:
|
||||
stateless_token_ids:
|
||||
- submit
|
||||
- authenticate
|
||||
- logout
|
||||
@@ -1,40 +1,20 @@
|
||||
doctrine:
|
||||
dbal:
|
||||
connections:
|
||||
default:
|
||||
url: '%env(resolve:DATABASE_URL)%'
|
||||
profiling_collect_backtrace: '%kernel.debug%'
|
||||
use_savepoints: true
|
||||
transfer:
|
||||
url: '%env(default::XFER_DATABASE_URL)%'
|
||||
profiling_collect_backtrace: '%kernel.debug%'
|
||||
use_savepoints: true
|
||||
|
||||
# IMPORTANT: You MUST configure your server version,
|
||||
# either here or in the DATABASE_URL env var (see .env file)
|
||||
#server_version: '16'
|
||||
|
||||
profiling_collect_backtrace: '%kernel.debug%'
|
||||
use_savepoints: true
|
||||
orm:
|
||||
auto_generate_proxy_classes: true
|
||||
enable_lazy_ghost_objects: true
|
||||
# report_fields_where_declared: true
|
||||
# validate_xml_mapping: true
|
||||
# auto_mapping: true
|
||||
default_entity_manager: default
|
||||
entity_managers:
|
||||
default:
|
||||
connection: default
|
||||
naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware
|
||||
mappings:
|
||||
App:
|
||||
type: attribute
|
||||
is_bundle: false
|
||||
dir: '%kernel.project_dir%/src/Entity'
|
||||
prefix: 'App\Entity'
|
||||
alias: App
|
||||
transfer:
|
||||
connection: transfer
|
||||
report_fields_where_declared: true
|
||||
validate_xml_mapping: true
|
||||
naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware
|
||||
auto_mapping: true
|
||||
mappings:
|
||||
App:
|
||||
type: attribute
|
||||
@@ -43,7 +23,7 @@ doctrine:
|
||||
prefix: 'App\Entity'
|
||||
alias: App
|
||||
controller_resolver:
|
||||
auto_mapping: false
|
||||
auto_mapping: true
|
||||
|
||||
when@test:
|
||||
doctrine:
|
||||
@@ -70,6 +50,3 @@ when@prod:
|
||||
adapter: cache.app
|
||||
doctrine.system_cache_pool:
|
||||
adapter: cache.system
|
||||
|
||||
parameters:
|
||||
env(default_url): ''
|
||||
@@ -22,6 +22,3 @@ services:
|
||||
|
||||
# add more service definitions when explicit configuration is needed
|
||||
# please note that last definitions always *replace* previous ones
|
||||
App\Service\DatabaseTransferService:
|
||||
arguments:
|
||||
$projectDir: '%kernel.project_dir%'
|
||||
@@ -1,34 +1,22 @@
|
||||
services:
|
||||
sermon-notes:
|
||||
image: gitea.rkprather.com/ryan/sermon-notes:1.3
|
||||
image: gitea.rkprather.com/ryan/sermon-notes:latest
|
||||
container_name: sermon-notes
|
||||
hostname: sermon-notes
|
||||
restart: unless-stopped
|
||||
|
||||
env_file: .env
|
||||
|
||||
ports:
|
||||
- ${HTTP_PORT}:80
|
||||
|
||||
volumes:
|
||||
- ${PWD}/.env:/var/www/html/.env
|
||||
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
|
||||
depends_on:
|
||||
- db
|
||||
|
||||
db:
|
||||
image: mariadb:12.3
|
||||
image: mariadb
|
||||
container_name: db
|
||||
hostname: db
|
||||
restart: unless-stopped
|
||||
|
||||
env_file: .env
|
||||
|
||||
volumes:
|
||||
- ${PWD}/db_data:/var/lib/mysql
|
||||
|
||||
@@ -1,34 +1,22 @@
|
||||
services:
|
||||
sermon-notes:
|
||||
image: gitea.rkprather.com/ryan/sermon-notes:1.3
|
||||
image: gitea.rkprather.com/ryan/sermon-notes:latest
|
||||
container_name: sermon-notes
|
||||
hostname: sermon-notes
|
||||
restart: unless-stopped
|
||||
|
||||
env_file: .env
|
||||
|
||||
ports:
|
||||
- ${HTTP_PORT}:80
|
||||
|
||||
volumes:
|
||||
- ${PWD}/.env:/var/www/html/.env
|
||||
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
|
||||
depends_on:
|
||||
- db
|
||||
|
||||
db:
|
||||
image: mysql:9.6
|
||||
image: mysql
|
||||
container_name: db
|
||||
hostname: db
|
||||
restart: unless-stopped
|
||||
|
||||
env_file: .env
|
||||
|
||||
volumes:
|
||||
- ${PWD}/db-data:/var/lib/mysql
|
||||
|
||||
@@ -1,24 +1,14 @@
|
||||
services:
|
||||
sermon-notes:
|
||||
container_name: sermon-notes
|
||||
image: gitea.rkprather.com/ryan/sermon-notes:1.3
|
||||
image: gitea.rkprather.com/ryan/sermon-notes:latest
|
||||
hostname: sermon-notes
|
||||
restart: unless-stopped
|
||||
|
||||
env_file: .env
|
||||
|
||||
ports:
|
||||
- ${HTTP_PORT}:80
|
||||
|
||||
volumes:
|
||||
- ${PWD}/.env:/var/www/html/.env
|
||||
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
|
||||
depends_on:
|
||||
- db
|
||||
|
||||
@@ -27,9 +17,7 @@ services:
|
||||
container_name: db
|
||||
hostname: db
|
||||
restart: unless-stopped
|
||||
|
||||
env_file: .env
|
||||
|
||||
volumes:
|
||||
- ${PWD}/db-data:/var/lib/postgresql/data
|
||||
|
||||
@@ -1,20 +1,11 @@
|
||||
services:
|
||||
sermon-notes:
|
||||
image: gitea.rkprather.com/ryan/sermon-notes:1.3
|
||||
image: gitea.rkprather.com/ryan/sermon-notes:latest
|
||||
container_name: sermon-notes
|
||||
hostname: sermon-notes
|
||||
restart: unless-stopped
|
||||
|
||||
env_file: .env
|
||||
|
||||
ports:
|
||||
- ${HTTP_PORT}:80
|
||||
|
||||
volumes:
|
||||
- ${PWD}/.env:/var/www/html/.env
|
||||
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
|
||||
@@ -1,21 +1,12 @@
|
||||
services:
|
||||
sermon-notes:
|
||||
image: gitea.rkprather.com/ryan/sermon-notes:1.3
|
||||
image: gitea.rkprather.com/ryan/sermon-notes:latest
|
||||
container_name: sermon-notes
|
||||
hostname: sermon-notes
|
||||
restart: unless-stopped
|
||||
|
||||
env_file: .env
|
||||
|
||||
ports:
|
||||
- ${HTTP_PORT}:80
|
||||
|
||||
volumes:
|
||||
- ${PWD}/data:/data
|
||||
- ${PWD}/.env:/var/www/html/.env
|
||||
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
56
install.php
56
install.php
@@ -1,28 +1,28 @@
|
||||
#!/usr/bin/env php
|
||||
#!/usr/local/bin/php
|
||||
|
||||
<?php
|
||||
|
||||
print "Updating packages and compiling assets".PHP_EOL;
|
||||
shell_exec("COMPOSE_ALLOW_SUPERUSER=1 composer update");
|
||||
//`symfony console asset-map:compile");
|
||||
`COMPOSE_ALLOW_SUPERUSER=1 composer update`;
|
||||
`symfony console asset-map:compile`;
|
||||
|
||||
print "Creating database schema".PHP_EOL;
|
||||
shell_exec("symfony console doctrine:database:create --if-not-exists");
|
||||
`symfony console doctrine:database:create`;
|
||||
|
||||
print "Updating migrations and setting permissions for data folder".PHP_EOL;
|
||||
shell_exec("symfony console doctrine:schema:create");
|
||||
`symfony console doctrine:migrations:migrate --no-interaction`;
|
||||
|
||||
shell_exec("chown -R www-data:www-data /data /var/www/html/var/cache");
|
||||
`chown -R www-data:www-data /data`;
|
||||
|
||||
// import reference material
|
||||
|
||||
print "Importing Bible and Eccumenical Creeds".PHP_EOL;
|
||||
shell_exec("symfony console app:ingest-bible /var/www/html/references/esv-bible");
|
||||
shell_exec("symfony console app:import-ref /var/www/html/references/creeds/Apostles 'Apostles Creed' creed apc");
|
||||
shell_exec("symfony console app:import-ref /var/www/html/references/creeds/Athanasian 'Athanasian Creed' creed ath");
|
||||
shell_exec("symfony console app:import-ref /var/www/html/references/creeds/Chalcedon 'Definition of Chalcedon' creed dc");
|
||||
shell_exec("symfony console app:import-ref /var/www/html/references/creeds/French 'French Confession' creed fc");
|
||||
shell_exec("symfony console app:import-ref /var/www/html/references/creeds/Nicene 'Nicene Creed' creed nc");
|
||||
`symfony console app:ingest-bible /var/www/html/reference/esv-bible`;
|
||||
`symfony console app:import-ref /var/www/html/references/creeds/Apostles 'Apostles Creed' creed apc`;
|
||||
`symfony console app:import-ref /var/www/html/references/creeds/Athanasian 'Athanasian Creed' creed ath`;
|
||||
`symfony console app:import-ref /var/www/html/references/creeds/Chalcedon 'Definition of Chalcedon' creed dc`;
|
||||
`symfony console app:import-ref /var/www/html/references/creeds/French 'French Confession' creed fc`;
|
||||
`symfony console app:import-ref /var/www/html/references/creeds/Nicene 'Nicene Creed' creed nc`;
|
||||
|
||||
$dutchStandards = (
|
||||
strtolower(
|
||||
@@ -32,9 +32,9 @@ $dutchStandards = (
|
||||
|
||||
if ($dutchStandards) {
|
||||
print "Importing Dutch Standards".PHP_EOL;
|
||||
shell_exec("symfony console app:import-ref /var/www/html/references/bc Belgic belgic BC{\$ndx}");
|
||||
shell_exec("symfony console app:import-heidelberg");
|
||||
shell_exec("symfony console app:import-ref /var/www/html/references/cd Canons cd CD");
|
||||
`symfony console app:import-ref /var/www/html/references/bc Belgic belgic BC{\$ndx}`;
|
||||
`symfony console app:import-heidelberg`;
|
||||
`symfony console app:import-canons-of-dort`;
|
||||
}
|
||||
|
||||
$westminsterStandards = (
|
||||
@@ -45,21 +45,21 @@ $westminsterStandards = (
|
||||
|
||||
if ($westminsterStandards) {
|
||||
print "Importing Westminster Standards".PHP_EOL;
|
||||
shell_exec("symfony console app:import-ref /var/www/html/references/wcf 'Westminster Confession' wcf WCF{\$ndx}");
|
||||
shell_exec("symfony console app:import-ref /var/www/html/references/wsc 'Westminster Shorter' wsc WSC{\$ndx}");
|
||||
shell_exec("symfony console app:import-ref /var/www/html/references/wlc 'Westminster Larger' wlc WLC{\$ndx}");
|
||||
`symfony console app:import-ref /var/www/html/references/wcf 'Westminster Confession' wcf WCF{\$ndx}`;
|
||||
`symfony console app:import-ref /var/www/html/references/wsc 'Westminster Shorter' wsc WSC{\$ndx}`;
|
||||
`symfony console app:import-wlc /var/www/html/references/wlc 'Westminster Larger' wlc WLC{\$ndx}`;
|
||||
}
|
||||
|
||||
$helveticConfessions = (
|
||||
$helviticConfessions = (
|
||||
strtolower(
|
||||
readline("Do you want to import the Helvetic Confessions (1st & 2nd) (y/n)? ")
|
||||
) == 'y'
|
||||
);
|
||||
|
||||
if ($helveticConfessions) {
|
||||
if ($helviticConfessions) {
|
||||
print "Importing Helvitic standards".PHP_EOL;
|
||||
shell_exec("symfony console app:import-ref /var/www/html/references/fhc 'First Helvetic Confession' 1hc 1HC{\$ndx}");
|
||||
shell_exec("symfony console app:import-ref /var/www/html/references/shc 'Second Helvetic Confession' 2hc 2HC{\$ndx}");
|
||||
`symfony console app:import-ref /var/www/html/references/fhc 'First Helvetic Confession' 1hc 1HC{\$ndx}`;
|
||||
`symfony console app:import-ref /var/www/html/references/shc 'Second Helvetic Confession' 2hc 2HC{\$ndx}`;
|
||||
}
|
||||
|
||||
$miscStandards = (
|
||||
@@ -70,12 +70,12 @@ $miscStandards = (
|
||||
|
||||
if ($miscStandards) {
|
||||
print "Importing misc standards".PHP_EOL;
|
||||
shell_exec("symfony console app:import-ref /var/www/html/references/39a 'Thirty-Nine Articles' 39a 39A{\$ndx}");
|
||||
shell_exec("symfony console app:import-ref /var/www/html/references/ac 'Augsberg Confession' agc AGC{\$ndx}");
|
||||
shell_exec("symfony console app:import-ref /var/www/html/references/lbc 'London Baptist Confession' lbc LBC{\$ndx}");
|
||||
shell_exec("symfony console app:import-ref /var/www/html/references/lsc 'Luther\'s Small Catechism' lsc LSC");
|
||||
shell_exec("symfony console app:import-ref /var/www/html/references/llc 'Luther\'s Large Catechism' llc LLC");
|
||||
shell_exec("symfony console app:import-ref /var/www/html/references/sd 'Savoy Declaration' sd SD{\$ndx}");
|
||||
`symfony console app:import-ref /var/www/html/references/39a 'Thirty-Nine Articles' 39a 39A{\$ndx}`;
|
||||
`symfony console app:import-ref /var/www/html/references/ac 'Augsberg Confession' agc AGC{\$ndx}`;
|
||||
`symfony console app:import-ref /var/www/html/references/lbc 'London Baptist Confession' lbc LBC{\$ndx}`;
|
||||
`symfony console app:import-ref /var/www/html/references/lsc 'Luther\'s Small Catechism' lsc LSC`;
|
||||
`symfony console app:import-ref /var/www/html/references/llc 'Luther\'s Large Catechism' llc LLC`;
|
||||
`symfony console app:import-ref /var/www/html/references/sd 'Savoy Declaration' sd SD{\$ndx}`;
|
||||
}
|
||||
|
||||
print "Sermon Notes Ready".PHP_EOL.PHP_EOL;
|
||||
|
||||
0
migrations/.gitignore
vendored
Normal file
0
migrations/.gitignore
vendored
Normal file
42
migrations/Version20240505234804.php
Normal file
42
migrations/Version20240505234804.php
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DoctrineMigrations;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
/**
|
||||
* Auto-generated Migration: Please modify to your needs!
|
||||
*/
|
||||
final class Version20240505234804 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
// this up() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('CREATE TABLE user (id BLOB NOT NULL --(DC2Type:uuid)
|
||||
, email VARCHAR(180) NOT NULL, roles CLOB NOT NULL --(DC2Type:json)
|
||||
, password VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, PRIMARY KEY(id))');
|
||||
$this->addSql('CREATE UNIQUE INDEX UNIQ_IDENTIFIER_EMAIL ON user (email)');
|
||||
$this->addSql('CREATE TABLE messenger_messages (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, body CLOB NOT NULL, headers CLOB NOT NULL, queue_name VARCHAR(190) NOT NULL, created_at DATETIME NOT NULL --(DC2Type:datetime_immutable)
|
||||
, available_at DATETIME NOT NULL --(DC2Type:datetime_immutable)
|
||||
, delivered_at DATETIME DEFAULT NULL --(DC2Type:datetime_immutable)
|
||||
)');
|
||||
$this->addSql('CREATE INDEX IDX_75EA56E0FB7336F0 ON messenger_messages (queue_name)');
|
||||
$this->addSql('CREATE INDEX IDX_75EA56E0E3BD61CE ON messenger_messages (available_at)');
|
||||
$this->addSql('CREATE INDEX IDX_75EA56E016BA31DB ON messenger_messages (delivered_at)');
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
// this down() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('DROP TABLE user');
|
||||
$this->addSql('DROP TABLE messenger_messages');
|
||||
}
|
||||
}
|
||||
62
migrations/Version20240513011501.php
Normal file
62
migrations/Version20240513011501.php
Normal file
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DoctrineMigrations;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
/**
|
||||
* Auto-generated Migration: Please modify to your needs!
|
||||
*/
|
||||
final class Version20240513011501 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
// this up() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('CREATE TABLE bible (id BLOB NOT NULL --(DC2Type:uuid)
|
||||
, book VARCHAR(255) NOT NULL, chapter INTEGER NOT NULL, verse INTEGER NOT NULL, content CLOB DEFAULT NULL, book_index INTEGER NOT NULL, label VARCHAR(20) DEFAULT NULL, PRIMARY KEY(id))');
|
||||
$this->addSql('CREATE TABLE note (id BLOB NOT NULL --(DC2Type:uuid)
|
||||
, speaker_id BLOB DEFAULT NULL --(DC2Type:uuid)
|
||||
, series_id BLOB DEFAULT NULL --(DC2Type:uuid)
|
||||
, user_id BLOB DEFAULT NULL --(DC2Type:uuid)
|
||||
, title VARCHAR(255) NOT NULL, date DATE NOT NULL, passage VARCHAR(255) NOT NULL, refs CLOB DEFAULT NULL --(DC2Type:json)
|
||||
, text CLOB DEFAULT NULL, PRIMARY KEY(id), CONSTRAINT FK_CFBDFA14D04A0F27 FOREIGN KEY (speaker_id) REFERENCES speaker (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_CFBDFA145278319C FOREIGN KEY (series_id) REFERENCES series (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_CFBDFA14A76ED395 FOREIGN KEY (user_id) REFERENCES user (id) NOT DEFERRABLE INITIALLY IMMEDIATE)');
|
||||
$this->addSql('CREATE INDEX IDX_CFBDFA14D04A0F27 ON note (speaker_id)');
|
||||
$this->addSql('CREATE INDEX IDX_CFBDFA145278319C ON note (series_id)');
|
||||
$this->addSql('CREATE INDEX IDX_CFBDFA14A76ED395 ON note (user_id)');
|
||||
$this->addSql('CREATE TABLE reference (id BLOB NOT NULL --(DC2Type:uuid)
|
||||
, type VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, label VARCHAR(255) NOT NULL, ndx INTEGER NOT NULL, content CLOB DEFAULT NULL, PRIMARY KEY(id))');
|
||||
$this->addSql('CREATE TABLE series (id BLOB NOT NULL --(DC2Type:uuid)
|
||||
, user_id BLOB DEFAULT NULL --(DC2Type:uuid)
|
||||
, template_id BLOB DEFAULT NULL --(DC2Type:uuid)
|
||||
, name VARCHAR(255) NOT NULL, PRIMARY KEY(id), CONSTRAINT FK_3A10012DA76ED395 FOREIGN KEY (user_id) REFERENCES user (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_3A10012D5DA0FB8 FOREIGN KEY (template_id) REFERENCES template (id) NOT DEFERRABLE INITIALLY IMMEDIATE)');
|
||||
$this->addSql('CREATE INDEX IDX_3A10012DA76ED395 ON series (user_id)');
|
||||
$this->addSql('CREATE INDEX IDX_3A10012D5DA0FB8 ON series (template_id)');
|
||||
$this->addSql('CREATE TABLE speaker (id BLOB NOT NULL --(DC2Type:uuid)
|
||||
, user_id BLOB DEFAULT NULL --(DC2Type:uuid)
|
||||
, name VARCHAR(255) NOT NULL, PRIMARY KEY(id), CONSTRAINT FK_7B85DB61A76ED395 FOREIGN KEY (user_id) REFERENCES user (id) NOT DEFERRABLE INITIALLY IMMEDIATE)');
|
||||
$this->addSql('CREATE INDEX IDX_7B85DB61A76ED395 ON speaker (user_id)');
|
||||
$this->addSql('CREATE TABLE template (id BLOB NOT NULL --(DC2Type:uuid)
|
||||
, user_id BLOB DEFAULT NULL --(DC2Type:uuid)
|
||||
, name VARCHAR(255) NOT NULL, content CLOB NOT NULL, PRIMARY KEY(id), CONSTRAINT FK_97601F83A76ED395 FOREIGN KEY (user_id) REFERENCES user (id) NOT DEFERRABLE INITIALLY IMMEDIATE)');
|
||||
$this->addSql('CREATE INDEX IDX_97601F83A76ED395 ON template (user_id)');
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
// this down() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('DROP TABLE bible');
|
||||
$this->addSql('DROP TABLE note');
|
||||
$this->addSql('DROP TABLE reference');
|
||||
$this->addSql('DROP TABLE series');
|
||||
$this->addSql('DROP TABLE speaker');
|
||||
$this->addSql('DROP TABLE template');
|
||||
}
|
||||
}
|
||||
41
migrations/Version20240513161129.php
Normal file
41
migrations/Version20240513161129.php
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DoctrineMigrations;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
/**
|
||||
* Auto-generated Migration: Please modify to your needs!
|
||||
*/
|
||||
final class Version20240513161129 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
// this up() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('CREATE TEMPORARY TABLE __temp__reference AS SELECT id, type, name, label, ndx, content FROM reference');
|
||||
$this->addSql('DROP TABLE reference');
|
||||
$this->addSql('CREATE TABLE reference (id BLOB NOT NULL --(DC2Type:uuid)
|
||||
, type VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, label VARCHAR(255) NOT NULL, ndx INTEGER DEFAULT NULL, content CLOB DEFAULT NULL, PRIMARY KEY(id))');
|
||||
$this->addSql('INSERT INTO reference (id, type, name, label, ndx, content) SELECT id, type, name, label, ndx, content FROM __temp__reference');
|
||||
$this->addSql('DROP TABLE __temp__reference');
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
// this down() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('CREATE TEMPORARY TABLE __temp__reference AS SELECT id, type, name, label, ndx, content FROM reference');
|
||||
$this->addSql('DROP TABLE reference');
|
||||
$this->addSql('CREATE TABLE reference (id BLOB NOT NULL --(DC2Type:uuid)
|
||||
, type VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, label VARCHAR(255) NOT NULL, ndx INTEGER NOT NULL, content CLOB DEFAULT NULL, PRIMARY KEY(id))');
|
||||
$this->addSql('INSERT INTO reference (id, type, name, label, ndx, content) SELECT id, type, name, label, ndx, content FROM __temp__reference');
|
||||
$this->addSql('DROP TABLE __temp__reference');
|
||||
}
|
||||
}
|
||||
43
migrations/Version20240527010736.php
Normal file
43
migrations/Version20240527010736.php
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DoctrineMigrations;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
/**
|
||||
* Auto-generated Migration: Please modify to your needs!
|
||||
*/
|
||||
final class Version20240527010736 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
// this up() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('ALTER TABLE note ADD COLUMN recording VARCHAR(255) DEFAULT NULL');
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
// this down() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('CREATE TEMPORARY TABLE __temp__note AS SELECT id, speaker_id, series_id, user_id, title, date, passage, refs, text FROM note');
|
||||
$this->addSql('DROP TABLE note');
|
||||
$this->addSql('CREATE TABLE note (id BLOB NOT NULL --(DC2Type:uuid)
|
||||
, speaker_id BLOB DEFAULT NULL --(DC2Type:uuid)
|
||||
, series_id BLOB DEFAULT NULL --(DC2Type:uuid)
|
||||
, user_id BLOB DEFAULT NULL --(DC2Type:uuid)
|
||||
, title VARCHAR(255) NOT NULL, date DATE NOT NULL, passage VARCHAR(255) NOT NULL, refs CLOB DEFAULT NULL --(DC2Type:json)
|
||||
, text CLOB DEFAULT NULL, PRIMARY KEY(id), CONSTRAINT FK_CFBDFA14D04A0F27 FOREIGN KEY (speaker_id) REFERENCES speaker (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_CFBDFA145278319C FOREIGN KEY (series_id) REFERENCES series (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_CFBDFA14A76ED395 FOREIGN KEY (user_id) REFERENCES user (id) NOT DEFERRABLE INITIALLY IMMEDIATE)');
|
||||
$this->addSql('INSERT INTO note (id, speaker_id, series_id, user_id, title, date, passage, refs, text) SELECT id, speaker_id, series_id, user_id, title, date, passage, refs, text FROM __temp__note');
|
||||
$this->addSql('DROP TABLE __temp__note');
|
||||
$this->addSql('CREATE INDEX IDX_CFBDFA14D04A0F27 ON note (speaker_id)');
|
||||
$this->addSql('CREATE INDEX IDX_CFBDFA145278319C ON note (series_id)');
|
||||
$this->addSql('CREATE INDEX IDX_CFBDFA14A76ED395 ON note (user_id)');
|
||||
}
|
||||
}
|
||||
38
migrations/Version20240622233923.php
Normal file
38
migrations/Version20240622233923.php
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DoctrineMigrations;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
/**
|
||||
* Auto-generated Migration: Please modify to your needs!
|
||||
*/
|
||||
final class Version20240622233923 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
// this up() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('ALTER TABLE user ADD COLUMN meta_data CLOB DEFAULT NULL');
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
// this down() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('CREATE TEMPORARY TABLE __temp__user AS SELECT id, email, roles, password, name FROM user');
|
||||
$this->addSql('DROP TABLE user');
|
||||
$this->addSql('CREATE TABLE user (id BLOB NOT NULL --(DC2Type:uuid)
|
||||
, email VARCHAR(180) NOT NULL, roles CLOB NOT NULL --(DC2Type:json)
|
||||
, password VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, PRIMARY KEY(id))');
|
||||
$this->addSql('INSERT INTO user (id, email, roles, password, name) SELECT id, email, roles, password, name FROM __temp__user');
|
||||
$this->addSql('DROP TABLE __temp__user');
|
||||
$this->addSql('CREATE UNIQUE INDEX UNIQ_IDENTIFIER_EMAIL ON user (email)');
|
||||
}
|
||||
}
|
||||
43
migrations/Version20240717022017.php
Normal file
43
migrations/Version20240717022017.php
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DoctrineMigrations;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
/**
|
||||
* Auto-generated Migration: Please modify to your needs!
|
||||
*/
|
||||
final class Version20240717022017 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
// this up() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('CREATE TABLE shared_note (id BLOB NOT NULL --(DC2Type:uuid)
|
||||
, note_id BLOB NOT NULL --(DC2Type:uuid)
|
||||
, owner_id BLOB NOT NULL --(DC2Type:uuid)
|
||||
, shared_user_id BLOB NOT NULL --(DC2Type:uuid)
|
||||
, PRIMARY KEY(id), CONSTRAINT FK_754B918C26ED0855 FOREIGN KEY (note_id) REFERENCES note (id) NOT DEFERRABLE INITIALLY IMMEDIATE)');
|
||||
$this->addSql('CREATE INDEX IDX_754B918C26ED0855 ON shared_note (note_id)');
|
||||
$this->addSql('CREATE TABLE shared_series (id BLOB NOT NULL --(DC2Type:uuid)
|
||||
, series_id BLOB NOT NULL --(DC2Type:uuid)
|
||||
, owner_id BLOB NOT NULL --(DC2Type:uuid)
|
||||
, shared_user_id BLOB NOT NULL --(DC2Type:uuid)
|
||||
, PRIMARY KEY(id), CONSTRAINT FK_59E803195278319C FOREIGN KEY (series_id) REFERENCES series (id) NOT DEFERRABLE INITIALLY IMMEDIATE)');
|
||||
$this->addSql('CREATE INDEX IDX_59E803195278319C ON shared_series (series_id)');
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
// this down() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('DROP TABLE shared_note');
|
||||
$this->addSql('DROP TABLE shared_series');
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
<IfModule mod_rewrite.c>
|
||||
Options -MultiViews
|
||||
RewriteEngine On
|
||||
|
||||
SetEnvIf X-Forwarded-Proto "https" HTTPS=on
|
||||
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteRule ^(.*)$ index.php [QSA,L]
|
||||
</IfModule>
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 39 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 255 KiB |
@@ -1,35 +0,0 @@
|
||||
{
|
||||
"name": "Sermon Notes",
|
||||
"short_name": "Sermon Notes",
|
||||
"description": "A personal note-taking app for sermons with reference material",
|
||||
"start_url": "/",
|
||||
"display": "standalone",
|
||||
"orientation": "landscape",
|
||||
"background_color": "#ffffff",
|
||||
"theme_color": "#000000",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/images/Notes-icon-192x192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "/images/Notes-icon-512x512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png"
|
||||
}
|
||||
],
|
||||
"screenshots": [
|
||||
{
|
||||
"src": "/images/Notes-icon-512x512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "/images/Notes-icon-512x512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png",
|
||||
"form_factor": "wide"
|
||||
}
|
||||
]
|
||||
}
|
||||
56
public/sw.js
56
public/sw.js
@@ -1,56 +0,0 @@
|
||||
// public/sw.js
|
||||
const CACHE_NAME = 'app-cache-v1';
|
||||
const ASSETS_TO_CACHE = [
|
||||
'/',
|
||||
'/manifest.json',
|
||||
// Add paths to your main CSS and JS files here
|
||||
// e.g., '/build/app.css', '/build/app.js'
|
||||
];
|
||||
|
||||
// Install Event: Cache core static assets
|
||||
self.addEventListener('install', event => {
|
||||
event.waitUntil(
|
||||
caches.open(CACHE_NAME)
|
||||
.then(cache => {
|
||||
return cache.addAll(ASSETS_TO_CACHE);
|
||||
})
|
||||
);
|
||||
self.skipWaiting();
|
||||
});
|
||||
|
||||
// Activate Event: Clean up old caches if you change the CACHE_NAME version
|
||||
self.addEventListener('activate', event => {
|
||||
event.waitUntil(
|
||||
caches.keys().then(cacheNames => {
|
||||
return Promise.all(
|
||||
cacheNames.map(cache => {
|
||||
if (cache !== CACHE_NAME) {
|
||||
return caches.delete(cache);
|
||||
}
|
||||
})
|
||||
);
|
||||
})
|
||||
);
|
||||
self.clients.claim();
|
||||
});
|
||||
|
||||
// Fetch Event: Network First, Fallback to Cache
|
||||
self.addEventListener('fetch', event => {
|
||||
// Only cache GET requests
|
||||
if (event.request.method !== 'GET') return;
|
||||
|
||||
event.respondWith(
|
||||
fetch(event.request)
|
||||
.then(networkResponse => {
|
||||
// If the network request succeeds, clone it and put it in the cache
|
||||
return caches.open(CACHE_NAME).then(cache => {
|
||||
cache.put(event.request, networkResponse.clone());
|
||||
return networkResponse;
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
// If the network fails (offline), try to serve from cache
|
||||
return caches.match(event.request);
|
||||
})
|
||||
);
|
||||
});
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env php
|
||||
#!/usr/local/bin/php
|
||||
|
||||
<?php
|
||||
|
||||
@@ -8,7 +8,7 @@ if (!file_exists('/var/www/html/.env')) {
|
||||
|
||||
$cmd = getopt("", ["sqlite", "mysql", "mariadb", "pgsql", "shared"]);
|
||||
|
||||
$key = shell_exec("openssl rand -base64 32 | tr -d '=' | tr -d '+' | tr -d '/' | tr -d ' '");
|
||||
$key = `openssl rand -base64 32 | tr -d '=' | tr -d '+' | tr -d '/' | tr -d ' '`;
|
||||
$key = substr($key, 0, 32);
|
||||
$database_url = null;
|
||||
$getCreds = true;
|
||||
@@ -53,7 +53,7 @@ if ($getCreds) {
|
||||
$db_port = (isset($cmd['pgsql']) ? 5432 : 3306);
|
||||
$db_name = 'sermon_notes';
|
||||
$db_user = 'root';
|
||||
$pwd = shell_exec("openssl rand -base64 32 | tr -d '=' | tr -d '+' | tr -d '/' | tr -d ' '");
|
||||
$pwd = `openssl rand -base64 32 | tr -d '=' | tr -d '+' | tr -d '/' | tr -d ' '`;
|
||||
$db_password = substr($pwd, 0, 32);
|
||||
|
||||
if (isset($cmd['pgsql'])) {
|
||||
@@ -85,7 +85,7 @@ $output = <<<EOF
|
||||
APP_ENV=prod
|
||||
APP_DEBUG=0
|
||||
APP_SECRET=$key
|
||||
MESSENGER_TRANSPORT_DSN=doctrine://default?auto_setup=0
|
||||
MESSAGENER_TRANSPORT_DSN=doctrine://default?auto_setup=0
|
||||
HTTP_PORT=$http_port
|
||||
$creds$database_url
|
||||
|
||||
|
||||
@@ -1,282 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Command;
|
||||
|
||||
use App\Entity\Note;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||
|
||||
#[AsCommand(
|
||||
name: 'app:get-audio',
|
||||
description: 'Finds Notes with missing recordings and matches them to RSS feed by Date and Title.',
|
||||
)]
|
||||
class GetAudioCommand extends Command
|
||||
{
|
||||
public function __construct(
|
||||
private EntityManagerInterface $entityManager,
|
||||
private HttpClientInterface $httpClient
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this->addOption('dry-run', null, InputOption::VALUE_NONE, 'No DB changes.');
|
||||
// No specific --debug flag needed, we will output verbose logs by default for now
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
$isDryRun = $input->getOption('dry-run');
|
||||
$noteRepository = $this->entityManager->getRepository(Note::class);
|
||||
|
||||
$io->title("Starting Audio Matcher");
|
||||
|
||||
// 1. Fetch Notes
|
||||
$qb = $noteRepository->createQueryBuilder('n')
|
||||
->leftJoin('n.user', 'u')
|
||||
->addSelect('u')
|
||||
->where('n.recording IS NULL OR n.recording = :empty')
|
||||
->andWhere('u.homeChurchRSS IS NOT NULL')
|
||||
->orderBy('n.date', 'DESC') // <--- Added Sort Here
|
||||
->setParameter('empty', '');
|
||||
//$query = $qb->getQuery();
|
||||
|
||||
//print ($query->getSql());
|
||||
|
||||
$notesMissingAudio = $qb->getQuery()->getResult();
|
||||
$count = count($notesMissingAudio);
|
||||
$io->text("Found $count notes in database missing audio.");
|
||||
|
||||
if ($count === 0) {
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
// 2. Group by User
|
||||
$notesByUser = [];
|
||||
foreach ($notesMissingAudio as $note) {
|
||||
$userId = (string) $note->getUser()->getId();
|
||||
$notesByUser[$userId]['user'] = $note->getUser();
|
||||
$notesByUser[$userId]['notes'][] = $note;
|
||||
}
|
||||
|
||||
// 3. Process Per User
|
||||
foreach ($notesByUser as $userId => $data) {
|
||||
$user = $data['user'];
|
||||
$userNotes = $data['notes'];
|
||||
$rssUrl = $user->getHomeChurchRSS();
|
||||
|
||||
$io->section("User: {$user->getEmail()} (Notes: " . count($userNotes) . ")");
|
||||
$io->text("Fetching RSS: $rssUrl");
|
||||
|
||||
try {
|
||||
// Pass $io to helper for debug output
|
||||
$rssItems = $this->fetchRssItems($rssUrl, $io);
|
||||
|
||||
if (empty($rssItems)) {
|
||||
$io->warning("RSS feed was empty or failed to parse.");
|
||||
continue;
|
||||
}
|
||||
|
||||
$matchCount = 0;
|
||||
|
||||
foreach ($userNotes as $note) {
|
||||
if (!$note->getDate()) {
|
||||
$io->text(" > Note ID {$note->getId()} skipped (No Date)");
|
||||
continue;
|
||||
}
|
||||
|
||||
$noteDateString = $note->getDate()->format('Y-m-d');
|
||||
$noteTitle = $note->getTitle();
|
||||
$io->text("---------------------------------------------------");
|
||||
$io->text("Checking Note: [$noteDateString] '$noteTitle'");
|
||||
|
||||
$bestMatch = null;
|
||||
$highestConfidence = 0;
|
||||
|
||||
foreach ($rssItems as $item) {
|
||||
// DEBUG: Show Date Comparison
|
||||
if ($item['date_string'] !== $noteDateString) {
|
||||
// Uncomment the line below if you want to see EVERY failed date comparison (can be noisy)
|
||||
// $io->text(" - REJECTED: Date mismatch (RSS: {$item['date_string']})");
|
||||
continue;
|
||||
}
|
||||
|
||||
// DEBUG: Show Score Calculation
|
||||
$confidence = $this->calculateConfidence($note, $item);
|
||||
$io->text(sprintf(
|
||||
" - DATE MATCHED. Score: %d%%. RSS Title: '%s'",
|
||||
$confidence,
|
||||
$item['title']
|
||||
));
|
||||
|
||||
if ($confidence >= 80 && $confidence > $highestConfidence) {
|
||||
$highestConfidence = $confidence;
|
||||
$bestMatch = $item;
|
||||
}
|
||||
}
|
||||
|
||||
if ($bestMatch) {
|
||||
$matchCount++;
|
||||
$io->success("Match Found! ($highestConfidence%)");
|
||||
if (!$isDryRun) {
|
||||
$note->setRecording($bestMatch['url']);
|
||||
}
|
||||
} else {
|
||||
$io->text(" > No match found for this note.");
|
||||
}
|
||||
}
|
||||
|
||||
if (!$isDryRun) {
|
||||
$this->entityManager->flush();
|
||||
}
|
||||
|
||||
if ($matchCount > 0) {
|
||||
$io->success("Found $matchCount matches");
|
||||
}
|
||||
|
||||
} catch (\Exception $e) {
|
||||
$io->error("Error: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively fetches RSS items if pagination links are present.
|
||||
*/
|
||||
private function fetchRssItems(string $startUrl, SymfonyStyle $io): array
|
||||
{
|
||||
$items = [];
|
||||
$nextUrl = $startUrl;
|
||||
$pageCount = 0;
|
||||
$maxPages = 20; // Safety brake to prevent infinite loops
|
||||
|
||||
do {
|
||||
$pageCount++;
|
||||
$io->text(" > Fetching Feed Page $pageCount: $nextUrl");
|
||||
|
||||
try {
|
||||
$response = $this->httpClient->request('GET', $nextUrl);
|
||||
$content = $response->getContent();
|
||||
|
||||
// Suppress warnings for malformed XML
|
||||
$xml = @simplexml_load_string($content);
|
||||
|
||||
if ($xml === false) {
|
||||
$io->warning("XML Parsing Failed on page $pageCount");
|
||||
break;
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
$io->warning("HTTP Request Failed on page $pageCount: " . $e->getMessage());
|
||||
break;
|
||||
}
|
||||
|
||||
// 1. Parse Items on this page
|
||||
$pageItemsCount = 0;
|
||||
foreach ($xml->channel->item as $item) {
|
||||
$namespaces = $item->getNamespaces(true);
|
||||
$speaker = '';
|
||||
|
||||
// Speaker Logic
|
||||
if (isset($namespaces['itunes'])) {
|
||||
$itunes = $item->children($namespaces['itunes']);
|
||||
$speaker = (string) ($itunes->author ?? '');
|
||||
}
|
||||
if (empty($speaker) && isset($namespaces['dc'])) {
|
||||
$dc = $item->children($namespaces['dc']);
|
||||
$speaker = (string) ($dc->creator ?? '');
|
||||
}
|
||||
if (empty($speaker)) {
|
||||
$speaker = (string) ($item->author ?? '');
|
||||
}
|
||||
|
||||
// Date Parsing
|
||||
$dateString = null;
|
||||
if (isset($item->pubDate)) {
|
||||
try {
|
||||
$dt = new \DateTimeImmutable((string)$item->pubDate);
|
||||
$dateString = $dt->format('Y-m-d');
|
||||
} catch (\Exception $e) {
|
||||
// ignore bad date
|
||||
}
|
||||
}
|
||||
|
||||
$items[] = [
|
||||
'title' => (string) $item->title,
|
||||
'speaker' => $speaker,
|
||||
'url' => (string) ($item->enclosure['url'] ?? ''),
|
||||
'date_string' => $dateString,
|
||||
];
|
||||
$pageItemsCount++;
|
||||
}
|
||||
|
||||
$io->text(" Found $pageItemsCount items on this page.");
|
||||
|
||||
// 2. Look for "Next Page" link (RFC 5005 / Atom)
|
||||
$nextUrl = null;
|
||||
|
||||
// Get namespaces on the <channel> element
|
||||
$namespaces = $xml->channel->getNamespaces(true);
|
||||
|
||||
if (isset($namespaces['atom'])) {
|
||||
$atom = $xml->channel->children($namespaces['atom']);
|
||||
foreach ($atom->link as $link) {
|
||||
// We are looking for <atom:link rel="next" href="..." />
|
||||
$attributes = $link->attributes();
|
||||
if (isset($attributes['rel']) && (string)$attributes['rel'] === 'next') {
|
||||
$nextUrl = (string)$attributes['href'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: Check for raw <link rel="next"> if atom ns missing (rare but happens)
|
||||
if (!$nextUrl && property_exists($xml->channel, 'link')) {
|
||||
foreach ($xml->channel->link as $link) {
|
||||
$attributes = $link->attributes();
|
||||
if (isset($attributes['rel']) && (string)$attributes['rel'] === 'next') {
|
||||
$nextUrl = (string)$attributes['href'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} while ($nextUrl && $pageCount < $maxPages);
|
||||
|
||||
$io->success(sprintf("Finished fetching. Total items: %d (across %d pages)", count($items), $pageCount));
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
private function calculateConfidence(Note $note, array $rssItem): float
|
||||
{
|
||||
$noteTitle = $this->normalize($note->getTitle());
|
||||
$rssTitle = $this->normalize($rssItem['title']);
|
||||
|
||||
$noteSpeaker = $this->normalize($note->getSpeaker()->getName() ?? '');
|
||||
$rssSpeaker = $this->normalize($rssItem['speaker']);
|
||||
|
||||
similar_text($noteTitle, $rssTitle, $titlePercent);
|
||||
|
||||
if (!empty($noteSpeaker) && !empty($rssSpeaker)) {
|
||||
similar_text($noteSpeaker, $rssSpeaker, $speakerPercent);
|
||||
return ($titlePercent + $speakerPercent) / 2;
|
||||
}
|
||||
|
||||
return $titlePercent;
|
||||
}
|
||||
|
||||
private function normalize(string $input): string
|
||||
{
|
||||
return strtolower(trim($input));
|
||||
}
|
||||
}
|
||||
@@ -144,10 +144,6 @@ class IngestReferenceCommand extends Command
|
||||
$ref->setContent($md);
|
||||
$ref->setName($this->name);
|
||||
$ref->setType($this->type);
|
||||
|
||||
if ($this->type == 'cd') {
|
||||
$label = substr(basename($file), 0, -3);
|
||||
}
|
||||
$ref->setLabel($label);
|
||||
|
||||
$this->io->success("Ingested {$this->name} as {$this->type}:{$label}");
|
||||
|
||||
@@ -20,7 +20,6 @@ use Exception;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\Mailer\MailerInterface;
|
||||
use Symfony\Component\Mime\Address;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
@@ -454,47 +453,6 @@ class AjaxController extends AbstractController
|
||||
return $res;
|
||||
}
|
||||
|
||||
#[Route('/save-profile', name: 'app_save_profile', methods: ['POST'])]
|
||||
public function saveProfile(Request $req, EntityManagerInterface $emi): Response
|
||||
{
|
||||
$data = json_decode($req->getContent());
|
||||
/** @var App\Entity\User $user */
|
||||
$user = $this->getUser();
|
||||
|
||||
if (!$user) {
|
||||
return new JsonResponse(['msg' => 'No User']);
|
||||
}
|
||||
|
||||
if ($data->passChange) {
|
||||
if(!$data->password) {
|
||||
return new JsonResponse(['msg' => 'Blank password']);
|
||||
}
|
||||
|
||||
// @todo check that password matches current password
|
||||
if ($data->password != $user->getPassword()) {
|
||||
return new JsonResponse(['msg' => 'Invalid password']);
|
||||
}
|
||||
|
||||
if ($data->newPassword != $data->confPassword) {
|
||||
return new JsonResponse(['msg' => 'Passwords don\'t match']);
|
||||
}
|
||||
}
|
||||
|
||||
$user->setName($data->name);
|
||||
$user->setEmail($data->email);
|
||||
$user->setHomeChurchRSS($data->homeChurch);
|
||||
|
||||
$emi->persist($user);
|
||||
|
||||
try {
|
||||
$emi->flush();
|
||||
} catch (Exception $e) {
|
||||
return new JsonResponse();
|
||||
}
|
||||
|
||||
return new JsonResponse(['msg' => 'Updated']);
|
||||
}
|
||||
|
||||
#[Route('/save-settings', name: 'app_save_settings', methods: ['POST'])]
|
||||
public function saveSettings(Request $req, EntityManagerInterface $emi): Response
|
||||
{
|
||||
|
||||
@@ -7,7 +7,6 @@ use App\Entity\User;
|
||||
use App\Entity\Speaker;
|
||||
use App\Entity\Series;
|
||||
use App\Entity\SharedNote;
|
||||
use App\Service\DatabaseTransferService;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
@@ -41,7 +40,6 @@ class DefaultController extends AbstractController
|
||||
'last4Notes' => $last4Notes,
|
||||
'reverseNoteSort' => $openNotes,
|
||||
'isAdmin' => $this->isGranted('ROLE_ADMIN'),
|
||||
'xferDB' => DatabaseTransferService::isTransferEnabled(),
|
||||
'meta' => $meta,
|
||||
'speakers' => $speakers,
|
||||
'series' => $series,
|
||||
@@ -91,7 +89,7 @@ class DefaultController extends AbstractController
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route('/reference-editor', 'app_reference_editor')]
|
||||
#[Route('/reference-editor', name: 'app_reference_editor')]
|
||||
public function referenceEditor(EntityManagerInterface $emi): Response
|
||||
{
|
||||
$this->denyAccessUnlessGranted('ROLE_ADMIN');
|
||||
@@ -99,64 +97,10 @@ class DefaultController extends AbstractController
|
||||
return $this->render('editors/reference-editor.html.twig');
|
||||
}
|
||||
|
||||
#[Route('/template-editor', 'app_template_editor')]
|
||||
#[Route('/template-editor', name: 'app_template_editor')]
|
||||
public function templateEditor(): Response
|
||||
{
|
||||
$this->denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY');
|
||||
return $this->render('editors/template-editor.html.twig');
|
||||
}
|
||||
|
||||
#[Route('/xfer-database', name: 'app_admin_transfer_db')]
|
||||
public function transfer(DatabaseTransferService $service, Request $request): Response
|
||||
{
|
||||
$step = $request->query->get('step', 'init');
|
||||
$session = $request->getSession();
|
||||
|
||||
if ($step === 'init') {
|
||||
$service->createSchema();
|
||||
$session->remove('transfer_logs');
|
||||
return $this->redirectToRoute('app_admin_transfer_db', ['step' => 0]);
|
||||
}
|
||||
|
||||
if ($step === 'summary') {
|
||||
// Finalize
|
||||
$service->finalizeEnvSwap();
|
||||
|
||||
return $this->render('default/transfer_summary.html.twig', [
|
||||
'logs' => $session->get('transfer_logs', [])
|
||||
]);
|
||||
}
|
||||
|
||||
$classes = $service->getEntityClasses();
|
||||
$totalClasses = count($classes);
|
||||
|
||||
if (isset($classes[$step])) {
|
||||
$class = explode("\\", $classes[$step]);
|
||||
$className = end($class);
|
||||
|
||||
$func = "transfer{$className}Table";
|
||||
|
||||
if (method_exists($service, $func)) {
|
||||
$skippedCount = $service->{$func}();
|
||||
|
||||
if ($skippedCount > 0) {
|
||||
$logs = $session->get('transfer_logs', []);
|
||||
$logs[] = "Skipped $skippedCount orphaned records in the $className table.";
|
||||
$session->set('transfer_logs', $logs);
|
||||
}
|
||||
|
||||
$progress = round((($step+1) / $totalClasses) * 100);
|
||||
$nextStep = (($step + 1) < $totalClasses) ? ($step + 1) : 'summary';
|
||||
|
||||
return $this->render('default/transfer_progress.html.twig', [
|
||||
'current' => (isset($classes[$step+1]) ? end(explode("\\", $classes[$step+1])) : 'summary'),
|
||||
'progress' => $progress,
|
||||
'next_step' => $nextStep,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
// Step 7: Logout and redirect
|
||||
return $this->redirectToRoute('app_logout');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@ use Symfony\Component\Uid\Uuid;
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
#[ORM\Entity(repositoryClass: UserRepository::class)]
|
||||
#[ORM\Table(name: 'app_user')]
|
||||
#[ORM\UniqueConstraint(name: 'UNIQ_IDENTIFIER_EMAIL', fields: ['email'])]
|
||||
class User implements UserInterface, PasswordAuthenticatedUserInterface, JsonSerializable
|
||||
{
|
||||
@@ -72,9 +71,6 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface, JsonSer
|
||||
#[ORM\Column(nullable: true)]
|
||||
private ?array $metaData = null;
|
||||
|
||||
#[ORM\Column(length: 255, nullable: true)]
|
||||
private ?string $homeChurchRSS = null;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->series = new ArrayCollection();
|
||||
@@ -327,16 +323,4 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface, JsonSer
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getHomeChurchRSS(): ?string
|
||||
{
|
||||
return $this->homeChurchRSS;
|
||||
}
|
||||
|
||||
public function setHomeChurchRSS(?string $homeChurchRSS): static
|
||||
{
|
||||
$this->homeChurchRSS = $homeChurchRSS;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,501 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Service;
|
||||
|
||||
use App\Entity\Bible;
|
||||
use App\Entity\Note;
|
||||
use App\Entity\Reference;
|
||||
use App\Entity\Series;
|
||||
use App\Entity\Speaker;
|
||||
use App\Entity\Template;
|
||||
use App\Entity\User;
|
||||
use Doctrine\ORM\Tools\SchemaTool;
|
||||
use Doctrine\Persistence\ManagerRegistry;
|
||||
use PDO;
|
||||
use PDOException;
|
||||
use Symfony\Component\Uid\Uuid;
|
||||
|
||||
class DatabaseTransferService
|
||||
{
|
||||
private PDO $srcDB;
|
||||
private PDO $destDB;
|
||||
|
||||
public function __construct(
|
||||
private string $projectDir,
|
||||
private ManagerRegistry $doctrine
|
||||
) {
|
||||
// connect the source database
|
||||
switch (explode(":", $_ENV['DATABASE_URL'])[0]) {
|
||||
case 'pdo-sqlite';
|
||||
list($driverName, $dbFile) = explode(":/", $_ENV['DATABASE_URL']);
|
||||
$this->srcDB = new PDO('sqlite:'.$dbFile);
|
||||
break;
|
||||
case 'pdo-mysql';
|
||||
case 'pdo-pgsql';
|
||||
$dsn = $this->convertDBURLString($_ENV['DATABASE_URL']);
|
||||
$this->srcDB = new PDO($dsn['dsn'], $dsn['username'], $dsn['password']);
|
||||
}
|
||||
|
||||
// connect the destination database
|
||||
switch(explode(':', $_ENV['XFER_DATABASE_URL'])[0]) {
|
||||
case 'pdo-sqlite':
|
||||
list($driverName, $dbFile) = explode(":/", $_ENV['XFER_DATABASE']);
|
||||
$this->destDB = new PDO('sqlite:'.$dbFile);
|
||||
break;
|
||||
case 'pdo-mysql':
|
||||
case 'pdo-pgsql':
|
||||
$dsn = $this->convertDBURLString($_ENV['XFER_DATABASE_URL']);
|
||||
$this->destDB = new PDO($dsn['dsn'], $dsn['username'], $dsn['password']);
|
||||
}
|
||||
}
|
||||
|
||||
public function createSchema(): void
|
||||
{
|
||||
$destEm = $this->doctrine->getManager('transfer');
|
||||
$metadata = $destEm->getMetadataFactory()->getAllMetadata();
|
||||
$tool = new SchemaTool($destEm);
|
||||
|
||||
$tool->dropSchema($metadata);
|
||||
$tool->createSchema($metadata);
|
||||
}
|
||||
|
||||
public function getEntityClasses(): array
|
||||
{
|
||||
return [
|
||||
User::class,
|
||||
Bible::class,
|
||||
Reference::class,
|
||||
Template::class,
|
||||
Series::class,
|
||||
Speaker::class,
|
||||
Note::class
|
||||
];
|
||||
}
|
||||
|
||||
public function transferUserTable(): int
|
||||
{
|
||||
$sql = "SELECT * FROM user";
|
||||
$stmt = $this->srcDB->prepare($sql);
|
||||
$stmt->execute();
|
||||
$insQuery = "INSERT INTO user (id, email, roles, password, name, meta_data, home_church_rss) ".
|
||||
"VALUES ".
|
||||
"(:id, :email, :roles, :password, :name, :meta_data, :home_church)";
|
||||
$destStmt = $this->destDB->prepare($insQuery);
|
||||
$skippedCount = 0;
|
||||
|
||||
$this->destDB->beginTransaction();
|
||||
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
$params = [
|
||||
'id' => $row['id'],
|
||||
'email' => $row['email'],
|
||||
'roles' => $row['roles'],
|
||||
'password' => $row['password'],
|
||||
'name' => $row['name'],
|
||||
'meta_data' => $row['meta_data'],
|
||||
'home_church' => $row['home_church_rss'],
|
||||
];
|
||||
|
||||
$this->destDB->exec("SAVEPOINT row_insert");
|
||||
|
||||
try {
|
||||
$destStmt->execute($params);
|
||||
|
||||
$this->destDB->exec("RELEASE SAVEPOINT row_insert");
|
||||
} catch (PDOException $e) {
|
||||
$skipCodes = [
|
||||
'23000',
|
||||
'23503',
|
||||
'23505',
|
||||
];
|
||||
if (in_array($e->getCode(), $skipCodes, true)) {
|
||||
$this->destDB->exec("ROLLBACK TO SAVEPOINT row_insert");
|
||||
$skippedCount++; // 4. Increment the counter
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->destDB->rollBack();
|
||||
print_r($params);
|
||||
die("Critical Error: ".$e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
$this->destDB->commit();
|
||||
|
||||
return $skippedCount;
|
||||
}
|
||||
|
||||
public function transferBibleTable(): int
|
||||
{
|
||||
$sql = "SELECT * FROM bible";
|
||||
$stmt = $this->srcDB->prepare($sql);
|
||||
$stmt->execute();
|
||||
$insQuery = "INSERT INTO bible (id, book, chapter, verse, content, book_index, label) ".
|
||||
"VALUES ".
|
||||
"(:id, :book, :chapter, :verse, :content, :book_index, :label)";
|
||||
$destStmt = $this->destDB->prepare($insQuery);
|
||||
$skippedCount = 0;
|
||||
|
||||
$this->destDB->beginTransaction();
|
||||
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
$uuid = Uuid::fromString($row['id']);
|
||||
|
||||
$params = [
|
||||
'id' => $uuid->toBinary(),
|
||||
'book' => $row['book'],
|
||||
'chapter' => $row['chapter'],
|
||||
'verse' => $row['verse'],
|
||||
'content' => $row['content'],
|
||||
'book_index' => $row['book_index'],
|
||||
'label' => $row['label'],
|
||||
];
|
||||
|
||||
$this->destDB->exec("SAVEPOINT row_insert");
|
||||
|
||||
try {
|
||||
$destStmt->execute($params);
|
||||
|
||||
$this->destDB->exec("RELEASE SAVEPOINT row_insert");
|
||||
} catch (PDOException $e) {
|
||||
$skipCodes = [
|
||||
'23000',
|
||||
'23503',
|
||||
'23505',
|
||||
];
|
||||
if (in_array($e->getCode(), $skipCodes, true)) {
|
||||
$this->destDB->exec("ROLLBACK TO SAVEPOINT row_insert");
|
||||
$skippedCount++; // 4. Increment the counter
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->destDB->rollBack();
|
||||
print_r($params);
|
||||
die("Critical Error: ".$e->getMessage());
|
||||
}
|
||||
}
|
||||
$this->destDB->commit();
|
||||
|
||||
return $skippedCount;
|
||||
}
|
||||
|
||||
public function transferReferenceTable(): int
|
||||
{
|
||||
$sql = "SELECT * FROM reference";
|
||||
$stmt = $this->srcDB->prepare($sql);
|
||||
$stmt->execute();
|
||||
$insQuery = "INSERT INTO reference (id, type, name, label, ndx, content) ".
|
||||
"VALUES ".
|
||||
"(:id, :type, :name, :label, :ndx, :content)";
|
||||
$destStmt = $this->destDB->prepare($insQuery);
|
||||
$skippedCount = 0;
|
||||
|
||||
$this->destDB->beginTransaction();
|
||||
while($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
$params = [
|
||||
'id' => $row['id'],
|
||||
'type' => $row['type'],
|
||||
'name' => $row['name'],
|
||||
'label' => $row['label'],
|
||||
'ndx' => $row['ndx'],
|
||||
'content' => $row['content'],
|
||||
];
|
||||
|
||||
$this->destDB->exec("SAVEPOINT row_insert");
|
||||
|
||||
try {
|
||||
$destStmt->execute($params);
|
||||
|
||||
$this->destDB->exec("RELEASE SAVEPOINT row_insert");
|
||||
} catch (PDOException $e) {
|
||||
$skipCodes = [
|
||||
'23000',
|
||||
'23503',
|
||||
'23505',
|
||||
];
|
||||
if (in_array($e->getCode(), $skipCodes, true)) {
|
||||
$this->destDB->exec("ROLLBACK TO SAVEPOINT row_insert");
|
||||
$skippedCount++; // 4. Increment the counter
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->destDB->rollBack();
|
||||
print_r($params);
|
||||
die("Critical Error: ".$e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
$this->destDB->commit();
|
||||
|
||||
return $skippedCount;
|
||||
}
|
||||
|
||||
public function transferTemplateTable(): int
|
||||
{
|
||||
$sql = "SELECT * FROM template";
|
||||
$stmt = $this->srcDB->prepare($sql);
|
||||
$stmt->execute();
|
||||
$insQuery = "INSERT INTO template (id, user_id, name, content) ".
|
||||
"VALUES ".
|
||||
"(:id, :user_id, :name, :content)";
|
||||
$destStmt = $this->destDB->prepare($insQuery);
|
||||
$skippedCount = 0;
|
||||
|
||||
$this->destDB->beginTransaction();
|
||||
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
$params = [
|
||||
'id' => $row['id'],
|
||||
'user_id' => $row['user_id'],
|
||||
'name' => $row['name'],
|
||||
'content' => $row['content'],
|
||||
];
|
||||
|
||||
$this->destDB->exec("SAVEPOINT row_insert");
|
||||
|
||||
try {
|
||||
$destStmt->execute($params);
|
||||
|
||||
$this->destDB->exec("RELEASE SAVEPOINT row_insert");
|
||||
} catch (PDOException $e) {
|
||||
$skipCodes = [
|
||||
'23000',
|
||||
'23503',
|
||||
'23505',
|
||||
];
|
||||
if (in_array($e->getCode(), $skipCodes, true)) {
|
||||
$this->destDB->exec("ROLLBACK TO SAVEPOINT row_insert");
|
||||
$skippedCount++; // 4. Increment the counter
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->destDB->rollBack();
|
||||
print_r($params);
|
||||
die("Critical Error: ".$e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
$this->destDB->commit();
|
||||
|
||||
return $skippedCount;
|
||||
}
|
||||
|
||||
public function transferSpeakerTable(): int
|
||||
{
|
||||
$sql = "SELECT * FROM speaker";
|
||||
$stmt = $this->srcDB->prepare($sql);
|
||||
$stmt->execute();
|
||||
$insQuery = "INSERT INTO speaker (id, name, user_id) ".
|
||||
"VALUES ".
|
||||
"(:id, :name, :user_id)";
|
||||
$destStmt = $this->destDB->prepare($insQuery);
|
||||
$skippedCount = 0;
|
||||
|
||||
$this->destDB->beginTransaction();
|
||||
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
$params = [
|
||||
'id' => $row['id'],
|
||||
'name' => $row['name'],
|
||||
'user_id' => $row['user_id'],
|
||||
];
|
||||
|
||||
$this->destDB->exec("SAVEPOINT row_insert");
|
||||
|
||||
try {
|
||||
$destStmt->execute($params);
|
||||
|
||||
$this->destDB->exec("RELEASE SAVEPOINT row_insert");
|
||||
} catch (PDOException $e) {
|
||||
$skipCodes = [
|
||||
'23000',
|
||||
'23503',
|
||||
'23505',
|
||||
];
|
||||
if (in_array($e->getCode(), $skipCodes, true)) {
|
||||
$this->destDB->exec("ROLLBACK TO SAVEPOINT row_insert");
|
||||
$skippedCount++; // 4. Increment the counter
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->destDB->rollBack();
|
||||
print_r($params);
|
||||
die("Critical Error: ".$e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
$this->destDB->commit();
|
||||
|
||||
return $skippedCount;
|
||||
}
|
||||
|
||||
public function transferSeriesTable(): int
|
||||
{
|
||||
$sql = "SELECT * FROM series";
|
||||
$stmt = $this->srcDB->prepare($sql);
|
||||
$stmt->execute();
|
||||
$insQuery = "INSERT INTO series (id, name, user_id, template_id) ".
|
||||
"VALUES ".
|
||||
"(:id, :name, :user_id, :template_id)";
|
||||
$destStmt = $this->destDB->prepare($insQuery);
|
||||
$skippedCount = 0;
|
||||
|
||||
$this->destDB->beginTransaction();
|
||||
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
$params = [
|
||||
'id' => $row['id'],
|
||||
'name' => $row['name'],
|
||||
'user_id' => $row['user_id'],
|
||||
'template_id' => $row['template_id'],
|
||||
];
|
||||
|
||||
$this->destDB->exec("SAVEPOINT row_insert");
|
||||
|
||||
try {
|
||||
$destStmt->execute($params);
|
||||
|
||||
$this->destDB->exec("RELEASE SAVEPOINT row_insert");
|
||||
} catch (PDOException $e) {
|
||||
$skipCodes = [
|
||||
'23000',
|
||||
'23503',
|
||||
'23505',
|
||||
];
|
||||
if (in_array($e->getCode(), $skipCodes, true)) {
|
||||
$this->destDB->exec("ROLLBACK TO SAVEPOINT row_insert");
|
||||
$skippedCount++; // 4. Increment the counter
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->destDB->rollBack();
|
||||
print_r($params);
|
||||
die("Critical Error: ".$e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
$this->destDB->commit();
|
||||
|
||||
return $skippedCount;
|
||||
}
|
||||
|
||||
public function transferNoteTable(): int
|
||||
{
|
||||
$sql = "SELECT * FROM note";
|
||||
$stmt = $this->srcDB->prepare($sql);
|
||||
$stmt->execute();
|
||||
$insQuery = "INSERT INTO note (id, title, date, passage, refs, text, speaker_id, series_id, user_id, recording) ".
|
||||
"VALUES ".
|
||||
"(:id, :title, :date, :passage, :refs, :text, :speaker_id, :series_id, :user_id, :recording)";
|
||||
$destStmt = $this->destDB->prepare($insQuery);
|
||||
$skippedCount = 0;
|
||||
|
||||
$this->destDB->beginTransaction();
|
||||
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
$params = [
|
||||
'id' => $row['id'],
|
||||
'speaker_id' => $row['speaker_id'],
|
||||
'series_id' => $row['series_id'],
|
||||
'user_id' => $row['user_id'],
|
||||
'title' => $row['title'],
|
||||
'date' => $row['date'],
|
||||
'passage' => $row['passage'],
|
||||
'refs' => $row['refs'],
|
||||
'text' => $row['text'],
|
||||
'recording' => $row['recording'],
|
||||
];
|
||||
|
||||
$this->destDB->exec("SAVEPOINT row_insert");
|
||||
|
||||
try {
|
||||
$destStmt->execute($params);
|
||||
|
||||
$this->destDB->exec("RELEASE SAVEPOINT row_insert");
|
||||
} catch (PDOException $e) {
|
||||
$skipCodes = [
|
||||
'23000',
|
||||
'23503',
|
||||
'23505',
|
||||
];
|
||||
if (in_array($e->getCode(), $skipCodes, true)) {
|
||||
$this->destDB->exec("ROLLBACK TO SAVEPOINT row_insert");
|
||||
$skippedCount++; // 4. Increment the counter
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->destDB->rollBack();
|
||||
print_r($params);
|
||||
die("Critical Error: ".$e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
$this->destDB->commit();
|
||||
|
||||
return $skippedCount;
|
||||
}
|
||||
|
||||
public function finalizeEnvSwap(): void
|
||||
{
|
||||
$envPath = $this->projectDir . '/.env';
|
||||
|
||||
if (!file_exists($envPath)) {
|
||||
throw new \Exception(".env file not found at $envPath");
|
||||
}
|
||||
|
||||
$lines = file($envPath);
|
||||
$newLines = [];
|
||||
$xferUrlValue = null;
|
||||
|
||||
// 1. First pass: Find the value of XFER_DATABASE_URL
|
||||
foreach ($lines as $line) {
|
||||
if (preg_match('/^XFER_DATABASE_URL=(.*)/', trim($line), $matches)) {
|
||||
$xferUrlValue = $matches[1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$xferUrlValue) {
|
||||
throw new \Exception("XFER_DATABASE_URL not found in .env file.");
|
||||
}
|
||||
|
||||
// 2. Second pass: Perform the swap
|
||||
foreach ($lines as $line) {
|
||||
$trimmed = trim($line);
|
||||
|
||||
// Prepend #OLD_ to the existing DATABASE_URL
|
||||
if (preg_match('/^DATABASE_URL=/', $trimmed)) {
|
||||
$newLines[] = "# OLD_" . $line;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Rename XFER_DATABASE_URL to DATABASE_URL
|
||||
if (preg_match('/^XFER_DATABASE_URL=/', $trimmed)) {
|
||||
$newLines[] = "DATABASE_URL=" . $xferUrlValue . PHP_EOL;
|
||||
continue;
|
||||
}
|
||||
|
||||
$newLines[] = $line;
|
||||
}
|
||||
|
||||
file_put_contents($envPath, implode('', $newLines));
|
||||
}
|
||||
|
||||
public static function isTransferEnabled(): bool
|
||||
{
|
||||
return (isset($_ENV['XFER_DATABASE_URL']) && !empty($_ENV['XFER_DATABASE_URL']));
|
||||
}
|
||||
|
||||
private function convertDBURLString(string $DBURL): array
|
||||
{
|
||||
$dsn = preg_split("/[:|\/|\@]+/", $DBURL);
|
||||
if (count($dsn) > 6) {
|
||||
die('You cannot have special characters in your password for the database entry during this process. Change the database user password to just use alpha-numeric characters, then run again. You can change it back to more secure after this transfer is complete');
|
||||
}
|
||||
|
||||
$res = [
|
||||
'dsn' => substr($dsn[0], 4).':'.
|
||||
'host='.$dsn[3].';'.
|
||||
'port='.$dsn[4].';'.
|
||||
'dbname='.$dsn[5],
|
||||
'username' => $dsn[1],
|
||||
'password' => $dsn[2]
|
||||
];
|
||||
|
||||
return $res;
|
||||
}
|
||||
}
|
||||
@@ -32,58 +32,4 @@ class Utils
|
||||
// error message or try to resend the message
|
||||
}
|
||||
}
|
||||
|
||||
public static function filePerms($file): string
|
||||
{
|
||||
$perms = fileperms($file);
|
||||
|
||||
switch ($perms & 0xF000) {
|
||||
case 0xC000: // socket
|
||||
$info = 's';
|
||||
break;
|
||||
case 0xA000: // symbolic link
|
||||
$info = 'l';
|
||||
break;
|
||||
case 0x8000: // regular
|
||||
$info = 'r';
|
||||
break;
|
||||
case 0x6000: // block special
|
||||
$info = 'b';
|
||||
break;
|
||||
case 0x4000: // directory
|
||||
$info = 'd';
|
||||
break;
|
||||
case 0x2000: // character special
|
||||
$info = 'c';
|
||||
break;
|
||||
case 0x1000: // FIFO pipe
|
||||
$info = 'p';
|
||||
break;
|
||||
default: // unknown
|
||||
$info = 'u';
|
||||
}
|
||||
|
||||
// Owner
|
||||
$info .= (($perms & 0x0100) ? 'r' : '-');
|
||||
$info .= (($perms & 0x0080) ? 'w' : '-');
|
||||
$info .= (($perms & 0x0040) ?
|
||||
(($perms & 0x0800) ? 's' : 'x' ) :
|
||||
(($perms & 0x0800) ? 'S' : '-'));
|
||||
|
||||
// Group
|
||||
$info .= (($perms & 0x0020) ? 'r' : '-');
|
||||
$info .= (($perms & 0x0010) ? 'w' : '-');
|
||||
$info .= (($perms & 0x0008) ?
|
||||
(($perms & 0x0400) ? 's' : 'x' ) :
|
||||
(($perms & 0x0400) ? 'S' : '-'));
|
||||
|
||||
// World
|
||||
$info .= (($perms & 0x0004) ? 'r' : '-');
|
||||
$info .= (($perms & 0x0002) ? 'w' : '-');
|
||||
$info .= (($perms & 0x0001) ?
|
||||
(($perms & 0x0200) ? 't' : 'x' ) :
|
||||
(($perms & 0x0200) ? 'T' : '-'));
|
||||
|
||||
return $info;
|
||||
}
|
||||
}
|
||||
|
||||
33
symfony.lock
33
symfony.lock
@@ -1,13 +1,4 @@
|
||||
{
|
||||
"doctrine/deprecations": {
|
||||
"version": "1.1",
|
||||
"recipe": {
|
||||
"repo": "github.com/symfony/recipes",
|
||||
"branch": "main",
|
||||
"version": "1.0",
|
||||
"ref": "87424683adc81d7dc305eefec1fced883084aab9"
|
||||
}
|
||||
},
|
||||
"doctrine/doctrine-bundle": {
|
||||
"version": "2.12",
|
||||
"recipe": {
|
||||
@@ -100,18 +91,6 @@
|
||||
".env"
|
||||
]
|
||||
},
|
||||
"symfony/form": {
|
||||
"version": "8.0",
|
||||
"recipe": {
|
||||
"repo": "github.com/symfony/recipes",
|
||||
"branch": "main",
|
||||
"version": "7.2",
|
||||
"ref": "7d86a6723f4a623f59e2bf966b6aad2fc461d36b"
|
||||
},
|
||||
"files": [
|
||||
"config/packages/csrf.yaml"
|
||||
]
|
||||
},
|
||||
"symfony/framework-bundle": {
|
||||
"version": "7.0",
|
||||
"recipe": {
|
||||
@@ -203,18 +182,6 @@
|
||||
"tests/bootstrap.php"
|
||||
]
|
||||
},
|
||||
"symfony/property-info": {
|
||||
"version": "8.0",
|
||||
"recipe": {
|
||||
"repo": "github.com/symfony/recipes",
|
||||
"branch": "main",
|
||||
"version": "7.3",
|
||||
"ref": "dae70df71978ae9226ae915ffd5fad817f5ca1f7"
|
||||
},
|
||||
"files": [
|
||||
"config/packages/property_info.yaml"
|
||||
]
|
||||
},
|
||||
"symfony/routing": {
|
||||
"version": "7.0",
|
||||
"recipe": {
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" />
|
||||
<link rel='manifest' href='{{ asset('manifest.json') }}'>
|
||||
|
||||
<title>{% block title %}Welcome!{% endblock %}</title>
|
||||
{% block stylesheets %}{% endblock %}
|
||||
@@ -16,19 +15,5 @@
|
||||
<body class='is-preload' onload='{% if onLoad is defined %}{{ onLoad }}{% endif %}'>
|
||||
{% block body %}{% endblock %}
|
||||
{% block javascripts %}{% endblock %}
|
||||
|
||||
<script>
|
||||
if ('serviceWorker' in navigator) {
|
||||
window.addEventListener('load', () => {
|
||||
navigator.serviceWorker.register('/sw.js')
|
||||
.then(registration => {
|
||||
console.log('ServiceWorker registration successful with scope: ', registration.scope);
|
||||
})
|
||||
.catch(error => {
|
||||
console.log('ServiceWorker registration failed: ', error);
|
||||
});
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -181,7 +181,7 @@ let saveFailureCount = {{ meta.saveFailureCount }};
|
||||
<!-- The modal body -->
|
||||
<form id="emailForm" class="modal-body">
|
||||
<label for="shareEmail">Enter Friends Email:</label>
|
||||
<input type="email" id="shareEmail" name="email" autocomplete=false required />
|
||||
<input type="email" id="shareEmail" name="email" required />
|
||||
<button type='button' id="submit" class="btn btn-primary" onclick='shareNote()'>Submit</button>
|
||||
</form>
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<link href="{{ asset('css/main.css') }}" rel="stylesheet" />
|
||||
<link href="{{ asset('css/jquery-ui.theme.css') }}" rel='stylesheet' />
|
||||
<link href="{{ asset('css/jquery-ui.structure.css') }}" rel='stylesheet' />
|
||||
<link href="{{ asset('styles/style.css') }}" rel='stylesheet' />
|
||||
<link href="{{ asset('css/style.css') }}" rel='stylesheet' />
|
||||
<link href='//cdn.datatables.net/2.0.8/css/dataTables.dataTables.min.css' rel='stylesheet' />
|
||||
<style>
|
||||
.flex-container {
|
||||
@@ -80,49 +80,6 @@ $(function() {
|
||||
|
||||
});
|
||||
|
||||
function saveProfile() {
|
||||
const name = $('#name');
|
||||
const email = $('#email');
|
||||
const homeChurch = $('#home-church');
|
||||
const password = $('#password');
|
||||
const newPassword = $('#new-password');
|
||||
const confPassword = $('#conf-password');
|
||||
let passChange = false;
|
||||
|
||||
if (newPassword.val().length > 0) {
|
||||
if (password.val().length == 0) {
|
||||
alert('If you want to change your password you need to put in the current password as well');
|
||||
return;
|
||||
}
|
||||
|
||||
if (newPassword.val() != confPassword.val()) {
|
||||
alert('New password and confirm passwords do not match');
|
||||
return;
|
||||
}
|
||||
passChange = true;
|
||||
}
|
||||
|
||||
fetch('/save-profile', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
'name': name.val(),
|
||||
'email': email.val(),
|
||||
'homeChurch': homeChurch.val(),
|
||||
'passChange': passChange,
|
||||
'password': password.val(),
|
||||
'newPassword': newPassword.val(),
|
||||
'confPassword': confPassword.val()
|
||||
})
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(results => {
|
||||
alert(results.msg);
|
||||
});
|
||||
}
|
||||
|
||||
function saveSettings() {
|
||||
var saveInterval = $('#save-interval');
|
||||
var saveReferences = $('#save-references');
|
||||
@@ -171,9 +128,6 @@ function rollUp(cont) {
|
||||
<label for='email'>Email: </label>
|
||||
<input type='email' id='email' name='email' value='{{ app.user.email }}' /><br />
|
||||
|
||||
<label for='home-church'>Home Church RSS Feed: </label>
|
||||
<input type='text' id='home-church' name='home-church' value='{{ app.user.homeChurchRSS }}' /><br />
|
||||
|
||||
<label for='password'>Password: </label>
|
||||
<input type='password' id='password' name='password' /><br/>
|
||||
|
||||
|
||||
@@ -25,9 +25,6 @@
|
||||
<li><a href="#" onclick="saveNote()">Save Note</a></li>
|
||||
{% if isAdmin is defined and isAdmin %}
|
||||
<li><a href='/reference-editor'>Reference Editor</a></li>
|
||||
{% if xferDB is defined and xferDB %}
|
||||
<li><a href='/xfer-database'>Transfer Database</a></li>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
<li><a href='#' onclick="openRef()">Open Reference</a></li>
|
||||
<li><a href='/template-editor'>Template Editor</a></li>
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% block body %}
|
||||
<div class="container mt-5 text-center">
|
||||
<h2>Transferring Database...</h2>
|
||||
<p>Processing: <strong>{{ current }}</strong></p>
|
||||
|
||||
<div class="progress mb-3" style="height: 30px;">
|
||||
<div class="progress-bar progress-bar-striped progress-bar-animated"
|
||||
role="progressbar" style="width: {{ progress }}%;">
|
||||
{{ progress }}%
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p>Please do not close this window.</p>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// Automatically move to the next step after a short delay
|
||||
setTimeout(() => {
|
||||
window.location.href = "{{ path('app_admin_transfer_db', {step: next_step}) }}";
|
||||
}, 500);
|
||||
</script>
|
||||
{% endblock %}
|
||||
@@ -1,57 +0,0 @@
|
||||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% block stylesheets %}
|
||||
<link href="{{ asset('css/main.css') }}" rel="stylesheet" />
|
||||
<link href='{{ asset('css/jquery-ui.theme.css') }}' rel='stylesheet' />
|
||||
<link href='{{ asset('css/jquery-ui.structure.css') }}' rel='stylesheet' />
|
||||
<link href='{{ asset('styles/style.css') }}' rel='stylesheet' />
|
||||
<link href='//cdn.datatables.net/2.0.8/css/dataTables.dataTables.min.css' rel='stylesheet' />
|
||||
<style>
|
||||
button.button i {
|
||||
font-size: 1.5em;
|
||||
}
|
||||
.input-error {
|
||||
border: solid 2px red !important;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block javascripts %}
|
||||
<script src="{{ asset('js/jquery.min.js') }}"></script>
|
||||
<script src='{{ asset('js/jquery-ui.js') }}'></script>
|
||||
<script src="{{ asset('js/browser.min.js') }}"></script>
|
||||
<script src="{{ asset('js/breakpoints.min.js') }}"></script>
|
||||
<script src="{{ asset('js/util.js') }}"></script>
|
||||
<script src="{{ asset('js/main.js') }}"></script>
|
||||
<script src='//momentjs.com/downloads/moment-with-locales.js'></script>
|
||||
<script src="//cdnjs.cloudflare.com/ajax/libs/markdown-it/13.0.2/markdown-it.min.js" integrity="sha512-ohlWmsCxOu0bph1om5eDL0jm/83eH09fvqLDhiEdiqfDeJbEvz4FSbeY0gLJSVJwQAp0laRhTXbUQG+ZUuifUQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||
<script src='//cdn.datatables.net/2.0.8/js/dataTables.min.js'></script>
|
||||
{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<div class="container mt-5 text-center">
|
||||
<h2 class="text-success">Database Transfer Complete!</h2>
|
||||
<p>Your data has been successfully moved to the new database, and the environment variables have been updated.</p>
|
||||
|
||||
{% if logs|length > 0 %}
|
||||
<div class="alert alert-warning text-start mx-auto" style="max-width: 600px;">
|
||||
<h5 class="alert-heading">Data Clean-up Notice</h5>
|
||||
<p>During the transfer, the following orphaned records were safely ignored to maintain database integrity:</p>
|
||||
<ul>
|
||||
{% for log in logs %}
|
||||
<li>{{ log }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="alert alert-success mx-auto" style="max-width: 600px;">
|
||||
Perfect transfer! No orphaned records were found.
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="mt-4">
|
||||
<p class="text-muted">You must log in again to establish a connection with the new database.</p>
|
||||
<a href="{{ path('app_logout') }}" class="btn btn-primary btn-lg">Acknowledge & Relogin</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user