diff --git a/.github/workflows/docker-base.yml b/.github/workflows/docker-base.yml
index 9a25b7a61..beee770d7 100644
--- a/.github/workflows/docker-base.yml
+++ b/.github/workflows/docker-base.yml
@@ -13,10 +13,10 @@ jobs:
packages: write
strategy:
matrix:
- php_version: [8.2, 8.3, 8.4]
+ php_version: [8.2, 8.3, 8.4, 8.5]
steps:
- name: Checkout
- uses: actions/checkout@v5
+ uses: actions/checkout@v6
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
@@ -26,7 +26,7 @@ jobs:
uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub
- uses: docker/login-action@v3.5.0
+ uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
@@ -45,6 +45,7 @@ jobs:
org.opencontainers.image.vendor=BMLT
org.opencontainers.image.created={{date 'YYYY-MM-DDTHH:mm:ssZ'}}
org.opencontainers.image.version=${{ matrix.php_version }}
+ org.opencontainers.image.revision=${{ github.sha }}
php.version=${{ matrix.php_version }}
- name: Build and push Base
@@ -66,7 +67,7 @@ jobs:
packages: write
steps:
- name: Checkout
- uses: actions/checkout@v5
+ uses: actions/checkout@v6
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
@@ -76,7 +77,7 @@ jobs:
uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub
- uses: docker/login-action@v3.1.0
+ uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index ded5c2c14..d190e1953 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -37,10 +37,10 @@ jobs:
- name: php ${{ matrix.php }} 🐘
id: setup-php
- uses: shivammathur/setup-php@2.35.4
+ uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
- tools: composer:v2.8.8
+ tools: composer:v2.8.12
- name: make composer 🎼
run: |
@@ -58,7 +58,7 @@ jobs:
- name: Send coverage data to codecov.io 📀
if: matrix.db == 'latest' && matrix.php == '8.4'
- uses: codecov/codecov-action@v5.5.0
+ uses: codecov/codecov-action@v5
with:
files: src/coverage.xml
token: ${{ secrets.CODECOV_TOKEN }}
@@ -69,10 +69,10 @@ jobs:
- name: checkout 🛒
uses: actions/checkout@v5
- - name: node 20 ❇️
- uses: actions/setup-node@v4.4.0
+ - name: node 22 ❇️
+ uses: actions/setup-node@v6
with:
- node-version: 20
+ node-version: 22
- name: make npm ♦️
run: |
@@ -98,32 +98,28 @@ jobs:
contents: write
steps:
- name: Checkout 🛒
- uses: actions/checkout@v4
+ uses: actions/checkout@v5
- name: php 8.2 🐘
id: setup-php
- uses: shivammathur/setup-php@2.35.4
+ uses: shivammathur/setup-php@v2
with:
php-version: '8.2'
- tools: composer:v2.8.8
+ tools: composer:v2.8.12
- name: make composer 🎼
run: |
make composer
- - name: setup node 20 ❇️
- uses: actions/setup-node@v4.4.0
+ - name: setup node 22 ❇️
+ uses: actions/setup-node@v6
with:
- node-version: 20
+ node-version: 22
- name: make frontend 🐥
run: |
make frontend
- - name: make crouton 🍞
- run: |
- make crouton
-
- name: Write .env with APP_VERSION and COMMIT_SHA 🧃
shell: bash
run: |
@@ -137,7 +133,7 @@ jobs:
make zip
- name: Configure S3 AWS Credentials 🪪
- uses: aws-actions/configure-aws-credentials@v4
+ uses: aws-actions/configure-aws-credentials@v5
with:
role-to-assume: arn:aws:iam::${{ secrets.AWS_ACCOUNT_ID }}:role/github-actions/gh-ci-s3-artifact
role-session-name: gh-actions
@@ -149,7 +145,7 @@ jobs:
- name: Configure AWS Credentials 🪪
if: contains(github.ref_name, 'main') || contains(github.ref_name, 'unstable')
- uses: aws-actions/configure-aws-credentials@v4
+ uses: aws-actions/configure-aws-credentials@v5
with:
role-to-assume: arn:aws:iam::${{ secrets.AWS_ACCOUNT_ID }}:role/github-actions/gh-ci-tf-bmlt-rs
role-session-name: gh-actions-bmlt
@@ -182,7 +178,7 @@ jobs:
echo "RELEASE_TYPE=${RELEASE_TYPE}" >> $GITHUB_ENV
- name: Create Release 🎉
- uses: ncipollo/release-action@v1.18.0
+ uses: ncipollo/release-action@v1
if: github.ref_type == 'tag'
with:
artifacts: "build/bmlt-server.zip"
@@ -208,7 +204,7 @@ jobs:
uses: actions/checkout@v5
- name: Configure AWS Credentials 🪪
- uses: aws-actions/configure-aws-credentials@v4
+ uses: aws-actions/configure-aws-credentials@v5
with:
role-to-assume: arn:aws:iam::${{ secrets.AWS_ACCOUNT_ID }}:role/github-actions/gh-ci-tf-bmlt-rs
role-session-name: gh-actions-bmlt
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 16054c191..2631dbde2 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -29,11 +29,11 @@ jobs:
options: --health-cmd="${{ (matrix.db == 'latest') && 'mariadb-admin' || 'mysqladmin' }} ping" --health-interval=5s --health-timeout=2s --health-retries=3
steps:
- name: checkout 🛒
- uses: actions/checkout@v4
+ uses: actions/checkout@v5
- name: php ${{ matrix.php }} 🐘
id: setup-php
- uses: shivammathur/setup-php@2.35.4
+ uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
tools: composer:v2.6.5
@@ -58,10 +58,10 @@ jobs:
- name: checkout 🛒
uses: actions/checkout@v5
- - name: node 20 ❇️
- uses: actions/setup-node@v4.0.0
+ - name: node 22 ❇️
+ uses: actions/setup-node@v6
with:
- node-version: 20
+ node-version: 22
- name: make npm ♦️
run: |
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a02277a07..89609698d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,7 +1,42 @@
-## 4.0.0 (UNRELEASED)
-* Added new user interface implemented in Svelte. This includes a brand-new UI code base and various improvements. It is mostly backward compatible, except as noted here:
+## 4.1.0 (UNRELEASED)
+* Settings Management UI:
+ * All server settings (except database credentials) are now fully configurable through the
+ Admin UI's Settings page. Settings are stored in the database and can also be managed via the Admin API (/api/v1/settings).
+ * A migration was added to automatically seed settings from legacy `auto-config.inc.php` file on upgrade.
+* Fix location map errors when auto geocoding is disabled.
+* Fix duplicate format keys in the initial migrations schema and in existing databases
+
+## 4.0.4 (November 26, 2025)
+* Modified the UI to hide the New Meeting button and show a helpful message when a user does not have editing privileges on any service bodies.
+* Fixed an issue that prevented users from logging in to Yap servers that use this BMLT server.
+
+## 4.0.3 (November 23, 2025)
+* Fixed an issue that prevented the UI from loading on servers with a `RewriteOptions inherit` configuration.
+* Fixed `$format_lang_names` setting to work with the new UI.
+* Fixed a geocoding issue -- if the county and/or zip code is automatically computed by the geocoder, we don't want to feed old and possibly incorrect values to the geocoder if the user edits an address.
+* Fixed problems with format key validation.
+* Added Portuguese translations.
+* Strip legacy `#@-@#` separator from custom field values in UI display.
+
+## 4.0.2 (November 11, 2025)
+* Added Italian translations.
+* Updated German translations.
+* Fix favicon.
+* Mask visibility=1 fields with asterisks in GetChanges json_data for unauthorized users.
+* Fixed an issue where a service body couldn't be edited if one of its meeting editor users had been deleted.
+* Fixed admin routes failing to load when accessed via direct URL or bookmark.
+* Added database migrations to trim user fields whitespace and to remove nonexistent users from service body assignments.
+
+## 4.0.1 (November 5, 2025)
+* Fixed longitude/latitude fields to be read-only when auto-geocoding is enabled
+
+## 4.0.0 (November 4, 2025)
+* Added new user interface implemented in Svelte. This includes a brand-new UI code base and various improvements, including support for mobile devices and dark mode. It is mostly backward compatible, except as noted here:
- Dropped support for the installer wizard -- see `installation/README.md` for new directions.
- Deprecated the auto-config parameter `$default_minute_interval` (now just set to 5 minutes).
+* The new UI is mobile-friendly and includes dark mode support.
+* Added newly rewritten semantic workshop.
+* Added new `$bmlt_notice` setting for `auto-config.inc.php` to display custom notices on the login screen. Example: `$bmlt_notice = 'We've upgraded the BMLT to 4.0.0 with a new interface! Please report any issues to bmlt@example.org';`
* Fixed a bug that prevented the NAWS Export from working with newer versions of MySQL.
## 3.1.2 (May 2, 2025)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 3713f05d9..83bfba6bb 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -3,65 +3,68 @@
For general information about BMLT, including ways to contribute to the project, please see
[the BMLT website](https://bmlt.app).
-This file contains information specifically about how to set up a development environment to work on the server.
-We want the server code (as well as code for the other project core elements) to continue to be of high quality, so
-prospective developers should have a solid grounding in good software engineering practice. In other words, making
-changes to the server code with the intent to contribute them back to
-the main repository wouldn't be the best place to start for folks new to software development -- there are, on
-the other hand, lots of other parts of the project that could very much use your time and energy! (An exception is
-that we do frequently need fluent speakers of languages other than English to translate localization strings -- even
-if the initial translation has already been done, there are often new strings added in subsequent development work
-that need translation.)
-
-There are various ways you can set up your development environment; in the directions here we use
-[Docker](https://www.docker.com). If you don't have them already, clone the server repo from github, and install
-[Docker Desktop](https://www.docker.com/products/docker-desktop). The make file assumes docker-compose v2.
-
-## Running the server under docker
-1. You will need to make sure you are using docker-compose v2. You can do this by opening the docker dashboard and going
-to preferences then general then scroll to the bottom and check the box that says `Use Docker Compose V2`, then hit apply &
-restart.
-1. Copy `docker/docker-compose.dev.yml.example` to `docker/docker-compose.dev.yml` and edit it to set the `GKEY` variable to your google api key.
-1. Run the command `make dev` in the top-level `bmlt-server` directory. If something isn't working (for example,
+This file contains information specifically about how to set up a development environment for work on the server. There are various ways you can do this; in the directions here we use
+[Docker](https://www.docker.com). If you don't have them already, clone the
+[BMLT server repo](https://github.com/bmlt-enabled/bmlt-server) from github, and install
+[Docker Desktop](https://www.docker.com/products/docker-desktop). These directions were tested with Docker Desktop v4.53.0.
+
+## Running the Server under Docker
+1. If you want to use Google Maps for displaying meeting locations, copy `docker/docker-compose.dev.yml.example` to `docker/docker-compose.dev.yml` and edit it to set the `GOOGLE_API_KEY` variable to your google api key. If you want to use OpenStreetMap, omit this step. You can also provide values for other environment variables using this file (see below).
+2. Run the command `make dev` in the top-level `bmlt-server` directory. If something isn't working (for example,
mising packages), try running `make clean` first and then `make dev`.
-1. Browse to `http://localhost:8000/main_server/`.
-1. Login with username "serveradmin" and password "CoreysGoryStory".
-1. When finished, exit by pressing ctrl+c. You may also wish to delete the containers in the Docker Dashboard.
+3. Browse to `http://localhost:8000/main_server/`.
+4. Login with username "serveradmin" and password "CoreysGoryStory".
+5. When finished, exit by pressing ctrl+c in the terminal window where you ran `make dev`. You may also wish to delete the containers in the Docker Dashboard.
-### Supported environment variables
-This is an example `docker-compose.dev.yml` file. The value for each of these variables, on start of the container, is automatically
-written to the appropriate line in `auto-config.inc.php`.
-```
-version: '3'
+### Environment Variables and Settings
+
+When running a production server, there is a file `auto-config.inc.php` that is used to initialize a set of environment variables used by the server. Other server settings are read from a table in the database.
+
+For development work, Docker takes care of initializing these environment variables. You can also specify other server settings that will override the values in the database. This is done by adding key/value pairs to the file `docker/docker-compose.dev.yml`. The sample file `docker/docker-compose.dev.yml.example` has just one variable listed (`GOOGLE_API_KEY` for the Google API key). You can add others as needed. The keys should be in SCREAMING_SNAKE_CASE. See the `SETTING_DEFAULTS` constant in `src/database/migrations/2025_11_20_133800_seed_settings_from_legacy_config.php` for a list of possibilities. There are also a few database options: `DB_PREFIX`, `DB_DATABASE`, `DB_USERNAME`, `DB_PASSWORD`, and `DB_HOST`. Of these `DB_PREFIX` is probably the only one you might want to override.
+
+Server settings that are overridden by entries in `docker/docker-compose.dev.yml` will show up correctly in the Server Settings pane in the UI, but won't necessarily be reflected in the `settings` table in the database. However, if you make a change to the settings in the UI and save, then all the values (including ones from entries in `docker/docker-compose.dev.yml`) will be written to the database.
+### Switching PHP Versions
+
+To test with a different PHP version, add this to `docker/docker-compose.dev.yml`:
+```yaml
services:
bmlt:
- environment:
- GKEY: ''
- DB_DATABASE: rootserver
- DB_USER: rootserver
- DB_PASSWORD: rootserver
- DB_HOST: db
- DB_PREFIX: na
- NEW_UI_ENABLED: 'true'
- AGGREGATOR_MODE_ENABLED: 'false'
+ build:
+ args:
+ PHP_VERSION: 8.4
```
-## Developing the New UI
-The new UI is developed using [Svelte](https://svelte.dev/), and the code is located in the `resources/js` directory.
+Then rebuild without cache:
+```bash
+docker compose -f docker/docker-compose.yml -f docker/docker-compose.dev.yml build --no-cache bmlt
+make dev
+```
-You can enable the new UI in the docker container by setting the `NEW_UI_ENABLED` environment variable to `'true'` in `docker/docker-compose.dev.yml`.
+## Loading a Different Sample Database
+
+If your database uses a table prefix other than `na` (say `myprefix`), add this line to `docker/docker-compose.dev.yml`:
+```
+DB_PREFIX: 'myprefix'
+```
+Then use the following command to load your database:
+```
+docker exec -i docker-db-1 sh -c 'exec mariadb -uroot -prootserver rootserver' < mydb.sql
+```
+
+## UI Development
+The UI is now written using [Svelte](https://svelte.dev/), and the code is located in the `resources/js` directory. (The previous UI has now been removed from the current code base.)
To install the UI's dependencies, run the `npm install` command from the `src` directory.
When working on the UI, you'll need to have the [Vite](https://vitejs.dev/) dev server running. To start the dev server, run `npm run dev` from the `src` directory. While the dev server is running, the UI is served out of the `resources/js` directory instead of the normal `public` directory, and [hot module replacement](https://vitejs.dev/guide/features.html#hot-module-replacement) is enabled.
-### Debugging the New UI
-This assumes you are using [VS Code](https://code.visualstudio.com) to develop the new UI.
+### Debugging the UI
+This assumes you are using [VS Code](https://code.visualstudio.com) to develop the UI.
-#### Debugging the Browser
-First, follow the instructions above for running the server under Docker with `NEW_UI_ENABLED` set to `'true'`. This mostly just involves running `make dev`.
+#### Debugging Using a Browser
+First, follow the instructions above for running the server under Docker. This mostly just involves running `make dev`.
Then, create `.vscode/launch.json` with a `chrome` debug configuration:
@@ -82,75 +85,187 @@ Then, create `.vscode/launch.json` with a `chrome` debug configuration:
You should now be able to set breakpoints, launch this debug configuration, and step through the code.
-#### Debugging the Tests
+#### Debugging Tests
This works exactly as described in the [vitest documentation](https://v0.vitest.dev/guide/debugging.html). Set any breakpoints, launch a new JavaScript Debug Terminal, and run `npm run test`.
-## Some useful `make` commands
+## Developing with the TypeScript Client
+
+When developing Admin API features alongside the TypeScript client, you can use [npm link](https://docs.npmjs.com/cli/v11/commands/npm-link/) to work with both repositories locally without publishing to npm.
+
+### Prerequisites
+Clone the BMLT TypeScript client repository:
+```bash
+git clone https://github.com/bmlt-enabled/bmlt-server-typescript-client.git
+```
-- `make help` Describe all of the make commands.
+### One-time Setup
+1. Link the TypeScript client globally:
+ ```bash
+ cd /path/to/bmlt-server-typescript-client
+ npm link
+ ```
+
+2. Link the client in the BMLT server frontend:
+ ```bash
+ cd /path/to/bmlt-server/src
+ npm link ../../bmlt-server-typescript-client
+ ```
+
+### Development Workflow
+After making API changes, regenerate the TypeScript client:
+
+1. Generate updated OpenAPI documentation:
+ ```bash
+ cd /path/to/bmlt-server
+ make generate-api-json
+ ```
+
+2. Regenerate the TypeScript client:
+ ```bash
+ cd /path/to/bmlt-server-typescript-client
+ rm openapi.json
+ make generate
+ ```
+
+This allows you to develop the API without changing your configs or imports.
+
+## Some Useful `make` Commands
+
+- `make help` Describe all the make commands.
- `make clean` Clean the build by removing all build artifacts and downloaded dependencies.
- `make docker` Builds the docker image. You really only need to run this when first getting set up or after a change
has been made to the Dockerfile or its base image.
- `make dev` Run the server under docker (see above).
- `make bash` Open a bash shell on the container's file system. This will start in the directory `/var/www/html/main_server`
-- `make mysql` Start the mysql command-line client with the database `rootserver`, which holds the server's tables.
+- `make mysql` Start the mysql command-line client with the database `rootserver`, which holds the server's tables. (Well, actually it uses the MariaDB command-line client now rather than mysql, but the `make` command still has the old name.)
- `make test` Run PHP tests.
There are some additional commands as well; `make help` will list them.
-## Loading a different sample database
-
-Use this command to replace the supplied test database with your own:
-```
-docker exec -i docker-db-1 sh -c 'exec mariadb -uroot -prootserver rootserver' < mydb.sql
-```
-
-## Running tests
+## Running PHP Tests
Start the server using `make dev` (see above). Then in a separate terminal, run the tests using `make test`.
-Somewhat annoyingly, `make test` will clobber your current database, so you'll need to restore it if you want to go
-back to running the server.
-
## Running lint
You can run the linter by running `make lint` in the top-level directory.
It doesn't work when xdebug is listening, so make sure xdebug is off first.
-## Testing the install wizard
-The Docker files automatically set up an `auto-config.inc.php` file for you. Usually this is great since it saves you
-the bother of going through the install wizard each time you restart the server. However, if you want to test or
-change the install wizard, you can start with the install wizard instead of the login screen by deleting this file.
-Here are modified steps to do that.
-1. Edit `docker-compose.dev.yml` to set your google maps api key, `GKEY: API_KEY`.
-1. Run the command `make dev` in the top-level `bmlt-server` directory.
-1. In another window, run `make bash` to open a bash shell accessing the container's file system. The shell should
-start in the directory `cd /var/www/html/main_server`.
-1. In the bash shell, `cd ..` to get to the parent directory, then `rm auto-config.inc.php`.
-1. Leave the shell open so that you can check whether the installer generated a new `auto-config.inc.php` and if so what it contains.
-1. Browse to `http://localhost:8000/main_server/`.
-1. In the browser you will now be in the Install Wizard. Start by filling in the Database Connection Settings screen as follows.
-```
-Database Type: mysql
-Database Host: db
-Table Prefix: na2
-Database Name: rootserver
-Database User: rootserver
-Database Password: rootserver
-```
-Note that the Database Host is `db` rather than the usual `localhost`. If you start with the install wizard, normally
-you need an empty database, but the `rootserver` database already contains sample data. A convenient alternative to dropping
-and (re) creating `rootserver` is to use the provided `rootserver` database, and to change the Table Prefix to `na2`, as
-above. If you need to run the installer again, just use a new Table Prefix each time (`na3` etc).
-
-Finally, as with the earlier directions, when finished exit by pressing ctrl+c or by running `docker-compose down`.
-
-## To debug in IntelliJ or PhpStorm (see screenshots below for more detail)
-
-1. Open IntelliJ Preferences. Go to `Languages & Frameworks -> PHP -> Debug`. Under the `Xdebug` section, set the `Debug port` to `10000,9003`. Close IntelliJ Preferences. 
-1. Add a new `PHP Remote Debug` debug configuration.
-1. In the new debug configuration, make click the three dots `...` next to the Server field, and add a new Server. Set the server's `Host` to `0.0.0.0`, and set the `Port` to `8000`. Check the `Use path mappings` checkbox, and set the `Absolute path on the server` for the `Project files` to `/var/www/html/main_server`. 
-1. Check `Filter debug connection by IDE key` and set the `IDE Key(session id)` to `ROOT_SERVER_DEBUG`. 
-1. To start debugging, select your new debug configuration and click the `Start Listening for PHP Debug Connections` icon. 
-1. Then, click the `Debug` icon to open your web browser and start the XDebug session. 
-1. Then, browse to `http://0.0.0.0:8000/main_server/`
+## Utility Commands to Help with Localization
+The strings that the UI displays are localized using files in the `src/resources/js/lang` directory. So if you add a new string, normally the programmer would need to add it to 11 or more files (one file per language). There are some utility commands to make this easer. If you are running under Docker, a convenient way to run them is to open a bash shell using `make bash`, connect to the `src` directory, and run the desired command.
+
+### Adding a new key/value pair or updating an existing one
+This adds a new key/value pair to all language files, respecting alphabetical order. For languages other than English, the new key/value pair will also have a comment `// TODO: translate`.
+````
+php artisan translation:add meetingName "Meeting Name"
+````
+To update an existing key use `--force`.
+````
+php artisan translation:add cancel "Cancelled" --force
+````
+
+### Deleing a Key/Value Pair
+This deletes a key and its value from all language files.
+````
+php artisan translation:delete oldKey
+````
+
+### Updating the Translations for One Language from a Spreadsheet
+A convenient starting point for the spreadsheet file is to use the button `Download Translations Spreadsheet` under the Administration tab.
+````
+php artisan translation:update-from-spreadsheet /path/to/italian-translations.xlsx it
+````
+
+## Adding a New Language to the Server
+
+To add a new language (for example, Norwegian, which has [ISO 639-1](https://en.wikipedia.org/wiki/List_of_ISO_639_language_codes) code `no`):
+
+### Backend Translation Files
+
+1. Copy the English translation directory:
+ ```bash
+ cp -r src/lang/en/ src/lang/no/
+ ```
+
+2. Edit `src/lang/no/language_name.php` to set the native language name:
+ ```php
+ 'Norsk',
+ ];
+ ```
+
+3. Translate the strings in the other PHP files (`main_prompts.php`, `change_detail.php`, `change_type.php`, `weekdays.php`, etc.).
+
+### Frontend Translation Files
+
+1. Copy the English translation file:
+ ```bash
+ cp src/resources/js/lang/en.ts src/resources/js/lang/no.ts
+ ```
+
+2. Translate the strings in the file `src/resources/js/lang/no.ts` and rename the two constants that it exports:
+ `enYupLocale` => `noYupLocale`, `enTranslations` => `noTranslations`.
+
+
+3. Export the new language in `src/resources/js/lang/index.ts`:
+ ```typescript
+ export { noTranslations, noYupLocale } from './no';
+ ```
+
+4. Import and add the new language to `src/resources/js/stores/localization.ts`:
+ - Add to imports (maintain alphabetical order):
+ ```typescript
+ noTranslations,
+ noYupLocale,
+ ```
+ - Add to the `strings` object (maintain alphabetical order):
+ ```typescript
+ no: noTranslations,
+ ```
+ - Add to the `yupLocales` object (maintain alphabetical order):
+ ```typescript
+ no: noYupLocale,
+ ```
+
+### Format Translations
+
+The server will actually run without any format translations for the new language, but you will almost certainly want to add some to provide a reasonable experience for users and service body administrators. There are two options for adding format translations for the new language:
+1. add them using a database migration
+2. add them by logging in as the server admin and using the editor available on the Formats tab
+
+Option 1 puts the format translations into the code base, and is how all the formats that come with a fresh out-of-the-box server are defined.
+
+Option 2 is much simpler -- just use the format translation editor in the UI -- but they won't be in the code base and someone who spins up a new server in your new language won't get them automatically. You can also do some of both: start with a set of basic format translations defined using a database migration, and then add some additional ones using the UI.
+
+For historical reasons, the meeting's venue type (in-person, hybrid, or virtual) is specified in the server database using the `HY` (hybrid) and `VM` (virtual meeting) formats. The UI for service body administrators doesn't expose these to the administrator however; they get set using the Venue Type menu on the meeting editor Location tab. `TC` (Temporarily Closed) has been deprecated -- it was used a lot during the pandemic -- but you may still encounter it if you start with a database containing some older data. However, these formats **are** visible in crouton and bread for hybrid, virtual, or temporarily closed meetings, so you should provide translations for them.
+
+The migration `src/database/migrations/1902_01_01_000000_create_initial_schema.php` includes translations for the formats shipped with the server. You can use these as suggestions for other translations you might want to provide for the new language.
+
+## Debugging in IntelliJ or PhpStorm
+
+See screenshots below for more detail.
+
+1. Open IntelliJ Settings. Go to `Languages & Frameworks -> PHP -> Debug`. Under the `Xdebug` section, set the `Debug port` to `10000,9003`. Click OK and close IntelliJ Preferences.
+
+
+
+2. Pick `Run -> Edit Configurations...` Add a new `PHP Remote Debug` debug configuration.
+3. In the new debug configuration, check `Filter debug connection by IDE key`. Click the three dots `...` next to the Server field, and add a new Server. Set the server's `Host` to `0.0.0.0`, and set the `Port` to `8000`. Check the `Use path mappings` checkbox, and set the `Absolute path on the server` for the `src` directory under `Project files` to `/var/www/html/main_server`. Click OK.
+
+ 
+
+4. Back in the debug configuration, set the `IDE Key(session id)` to `ROOT_SERVER_DEBUG`.
+
+
+
+5. To start debugging, select your new debug configuration and click the `Start Listening for PHP Debug Connections` icon.
+
+
+
+6. Then, click the `Debug` icon to open your web browser and start the XDebug session.
+
+
+
+7. Finally, browse to `http://0.0.0.0:8000/main_server/`
diff --git a/Makefile b/Makefile
index eb9ee9ef6..2bf1e5e57 100644
--- a/Makefile
+++ b/Makefile
@@ -2,10 +2,8 @@ COMMIT := $(shell git rev-parse --short=8 HEAD)
BASE_IMAGE := bmltenabled/bmlt-server-base
BASE_IMAGE_TAG := 8.2
BASE_IMAGE_BUILD_TAG := $(COMMIT)-$(shell date +%s)
-CROUTON_JS := src/public/client_interface/html/croutonjs/crouton.js
SEMANTIC_HTML := src/public/semantic/index.html
TIMEZONE_ASSETS := src/public/timezones-1970.geojson.index.json
-LEGACY_STATIC_FILES := src/public/local_server/styles.css
VENDOR_AUTOLOAD := src/vendor/autoload.php
NODE_MODULES := src/node_modules/.package-lock.json
FRONTEND := src/public/build/manifest.json
@@ -19,14 +17,14 @@ ifeq ($(CI)x, x)
NPM_FLAG := install
COMPOSER_PREFIX := docker run --pull=always -t --rm -v '$(shell pwd)':/code -w /code $(BASE_IMAGE):$(BASE_IMAGE_TAG)
LINT_PREFIX := docker run -t --rm -v '$(shell pwd)':/code -w /code/src $(IMAGE):$(TAG)
- TEST_PREFIX := docker run -e XDEBUG_MODE=coverage,debug -t --rm -v '$(shell pwd)/src:/var/www/html/main_server' -v '$(shell pwd)/docker/test-auto-config.inc.php:/var/www/html/auto-config.inc.php' -w /var/www/html/main_server --network host $(IMAGE):$(TAG)
+ TEST_PREFIX := docker run -e XDEBUG_MODE=coverage,debug -t --rm -v '$(shell pwd)/src:/var/www/html/main_server' -w /var/www/html/main_server --network host $(IMAGE):$(TAG)
ifneq (,$(wildcard docker/docker-compose.dev.yml))
EXTRA_DOCKER_COMPOSE_ARGS := -f docker/docker-compose.dev.yml
endif
else
DOCKERFILE := Dockerfile
IMAGE := bmltenabled/bmlt-server
- TAG := 3.0.0-$(COMMIT)
+ TAG := 4.0.0-$(COMMIT)
ifeq ($(strip $(GITHUB_REF_NAME)),main)
TAG := latest
endif
@@ -49,15 +47,6 @@ help: ## Print the help documentation
$(VENDOR_AUTOLOAD):
$(COMPOSER_PREFIX) composer install --working-dir=src $(COMPOSER_ARGS)
-$(CROUTON_JS):
- curl -sLO https://github.com/bmlt-enabled/crouton/releases/latest/download/croutonjs.zip
- mkdir -p src/public/client_interface/html/croutonjs
- unzip croutonjs.zip -d src/public/client_interface/html/croutonjs
- rm -f croutonjs.zip
- rm -f src/public/client_interface/html/croutonjs/*.html
- rm -f src/public/client_interface/html/croutonjs/*.json
- rm -rf src/public/client_interface/html/croutonjs/examples
-
$(SEMANTIC_HTML):
curl -sLO https://github.com/bmlt-enabled/semantic-workshop/releases/latest/download/semantic-workshop.zip
mkdir -p src/public/semantic
@@ -74,26 +63,29 @@ $(NODE_MODULES):
$(FRONTEND): $(NODE_MODULES)
cd src && npm run build
-$(LEGACY_STATIC_FILES):
- rsync -a -m \
- --include='**/*.js' \
- --include='**/*.css' \
- --include='**/*.png' \
- --include='**/*.svg' \
- --include='**/*.ttf' \
- --include='**/*.woff' \
- --include='**/*.woff2' \
- --include='**/*.eot' \
- --include='**/*.json' \
- --include='**/*.gif' \
- --include='*/' \
- --exclude='*' \
- src/legacy/ src/public
-
-$(ZIP_FILE): $(VENDOR_AUTOLOAD) $(FRONTEND) $(CROUTON_JS) $(SEMANTIC_HTML) $(TIMEZONE_ASSETS) $(LEGACY_STATIC_FILES)
+$(ZIP_FILE): $(VENDOR_AUTOLOAD) $(FRONTEND) $(SEMANTIC_HTML) $(TIMEZONE_ASSETS)
mkdir -p build
cp -r src build/main_server
- cd build && zip -r $(shell basename $(ZIP_FILE)) main_server -x main_server/node_modules/\*
+ cd build && zip -r $(shell basename $(ZIP_FILE)) main_server \
+ -x main_server/.gitattributes \
+ -x main_server/.gitignore \
+ -x main_server/.nvmrc \
+ -x main_server/.phpcs.xml \
+ -x main_server/.phpstan.neon \
+ -x main_server/app.html \
+ -x main_server/coverage.xml \
+ -x main_server/eslint.config.js \
+ -x main_server/node_modules/\* \
+ -x main_server/package.json \
+ -x main_server/package-lock.json \
+ -x main_server/phpunit.xml \
+ -x main_server/.phpunit.result.cache \
+ -x main_server/prettier.config.js \
+ -x main_server/resources/js/\* \
+ -x main_server/svelte.config.js \
+ -x main_server/tests/\* \
+ -x main_server/tsconfig.json \
+ -x main_server/vite.config.ts
rm -rf build/main_server
.PHONY: composer
@@ -102,9 +94,6 @@ composer: $(VENDOR_AUTOLOAD) ## Runs composer install
.PHONY: npm
npm: $(NODE_MODULES) ## Runs npm install
-.PHONY: crouton
-crouton: $(CROUTON_JS) ## Installs crouton
-
.PHONY: semantic
semantic: $(SEMANTIC_HTML) ## Installs semantic workshop
@@ -119,7 +108,7 @@ zip: $(ZIP_FILE) ## Builds zip file
.PHONY: docker
docker: zip ## Builds Docker Image
- docker build --pull --build-arg PHP_VERSION=$(BASE_IMAGE_TAG) -f docker/$(DOCKERFILE) . -t $(IMAGE):$(TAG)
+ docker build --pull --build-arg PHP_VERSION=$(BASE_IMAGE_TAG) --label "org.opencontainers.image.revision=$(COMMIT)" --label "org.opencontainers.image.created=$(shell date -u +'%Y-%m-%dT%H:%M:%SZ')" -f docker/$(DOCKERFILE) . -t $(IMAGE):$(TAG)
.PHONY: docker-push
docker-push: ## Pushes docker image to Dockerhub
@@ -149,7 +138,7 @@ coverage-serve: ## Serves HTML Coverage Report
.PHONY: generate-api-json
generate-api-json: ## Generates Open API JSON
- $(LINT_PREFIX) php artisan l5-swagger:generate
+ $(TEST_PREFIX) php artisan l5-swagger:generate
.PHONY: lint
lint: ## PHP Lint
@@ -169,7 +158,7 @@ phpstan: ## PHP Larastan Code Analysis
.PHONY: docker-publish-base
docker-publish-base: ## Builds Base Docker Image
- docker buildx build --platform linux/amd64,linux/arm64/v8 -f docker/Dockerfile-base docker/ -t $(BASE_IMAGE):$(BASE_IMAGE_TAG) --push
+ docker buildx build --platform linux/amd64,linux/arm64/v8 --label "org.opencontainers.image.revision=$(COMMIT)" --label "org.opencontainers.image.created=$(shell date -u +'%Y-%m-%dT%H:%M:%SZ')" -f docker/Dockerfile-base docker/ -t $(BASE_IMAGE):$(BASE_IMAGE_TAG) --push
.PHONY: mysql
mysql: ## Runs mysql cli in mysql container
@@ -182,8 +171,6 @@ bash: ## Runs bash shell in apache container
.PHONY: clean
clean: ## Clean build
rm -rf src/public/build
- rm -rf src/public/client_interface
- rm -rf src/public/local_server
rm -rf src/public/semantic
rm -rf src/node_modules
rm -rf src/vendor
diff --git a/docker/Dockerfile b/docker/Dockerfile
index 6df2a3c2a..c6ff8e75d 100644
--- a/docker/Dockerfile
+++ b/docker/Dockerfile
@@ -11,9 +11,4 @@ RUN \
# Handle mod_dir redirect using X-Forwarded headers
COPY docker/.htaccess /var/www/html/main_server/.htaccess
-COPY docker/write-config.sh /tmp/write-config.sh
-COPY docker/start-bmlt.sh /tmp/start-bmlt.sh
-COPY docker/aggregator-initialize-database.sh /tmp/aggregator-initialize-database.sh
-COPY docker/aggregator-import-servers.sh /tmp/aggregator-import-servers.sh
-
-CMD ["/bin/bash", "/tmp/start-bmlt.sh"]
+CMD ["apachectl", "-D", "FOREGROUND"]
diff --git a/docker/Dockerfile-base b/docker/Dockerfile-base
index 8cd5f13d7..ee8e6a2d2 100644
--- a/docker/Dockerfile-base
+++ b/docker/Dockerfile-base
@@ -1,4 +1,4 @@
-FROM ubuntu:jammy
+FROM ubuntu:noble
ARG PHP_VERSION=8.2
@@ -60,7 +60,7 @@ RUN ln -sf /proc/self/fd/1 /var/log/apache2/access.log && \
RUN a2enmod rewrite
# Disable default PHP modules
-RUN for ver in 7.4 8.0 8.1 8.2 8.3 8.4; do \
+RUN for ver in 8.1 8.2 8.3 8.4 8.5; do \
if [ -f "/etc/apache2/mods-enabled/php$ver.conf" ] && [ "$ver" != "${PHP_VERSION}" ]; then \
a2dismod php$ver; \
fi; \
diff --git a/docker/Dockerfile-debug b/docker/Dockerfile-debug
index e54998052..3f55d2a98 100644
--- a/docker/Dockerfile-debug
+++ b/docker/Dockerfile-debug
@@ -6,6 +6,9 @@ ENV PHP_INI_PATH=/etc/php/${PHP_VERSION}/apache2/php.ini
ENV PHP_CLI_INI_PATH=/etc/php/${PHP_VERSION}/cli/php.ini
ENV PHP_XDEBUG_ENABLED=1
+RUN echo "opcache.revalidate_freq=0" >> ${PHP_INI_PATH}
+RUN echo "opcache.revalidate_freq=0" >> ${PHP_CLI_INI_PATH}
+
RUN echo "zend_extension=$(find /usr/lib/php/ -name xdebug.so)" >> ${PHP_INI_PATH} \
&& echo "xdebug.mode=coverage,debug" >> ${PHP_INI_PATH} \
&& echo "xdebug.client_port=9003" >> ${PHP_INI_PATH} \
@@ -22,9 +25,4 @@ RUN echo "zend_extension=$(find /usr/lib/php/ -name xdebug.so)" >> ${PHP_CLI_INI
&& echo "xdebug.log=/tmp/xdebug.log" >> ${PHP_CLI_INI_PATH} \
&& echo "xdebug.idekey=ROOT_SERVER_DEBUG" >> ${PHP_CLI_INI_PATH}
-COPY docker/write-config.sh /tmp/write-config.sh
-COPY docker/start-bmlt.sh /tmp/start-bmlt.sh
-COPY docker/aggregator-initialize-database.sh /tmp/aggregator-initialize-database.sh
-COPY docker/aggregator-import-servers.sh /tmp/aggregator-import-servers.sh
-
-CMD ["/bin/bash", "/tmp/start-bmlt.sh"]
+CMD ["apachectl", "-D", "FOREGROUND"]
diff --git a/docker/aggregator-import-servers.sh b/docker/aggregator-import-servers.sh
deleted file mode 100644
index 8f9362e23..000000000
--- a/docker/aggregator-import-servers.sh
+++ /dev/null
@@ -1,6 +0,0 @@
-#!/bin/bash
-set -o xtrace
-set -e
-
-/bin/bash /tmp/write-config.sh
-/usr/bin/php /var/www/html/main_server/artisan aggregator:ImportRootServers
diff --git a/docker/aggregator-initialize-database.sh b/docker/aggregator-initialize-database.sh
deleted file mode 100644
index bd2743c4a..000000000
--- a/docker/aggregator-initialize-database.sh
+++ /dev/null
@@ -1,6 +0,0 @@
-#!/bin/bash
-set -o xtrace
-set -e
-
-/bin/bash /tmp/write-config.sh
-/usr/bin/php /var/www/html/main_server/artisan aggregator:InitializeDatabase
diff --git a/docker/auto-config.inc.php b/docker/auto-config.inc.php
index 5e3d50bd9..58f71f31e 100644
--- a/docker/auto-config.inc.php
+++ b/docker/auto-config.inc.php
@@ -1,40 +1,5 @@
-79.793701171875, 'latitude' => 36.06575205170711, 'zoom' => 10 ); // This is the default map location for new meetings.
-$comdef_distance_units = 'mi';
-
-// Display settings:
-$bmlt_title = 'BMLT Administration'; // This is the page title and heading for the main administration login page.
-$banner_text = 'Administration Login'; // This is text that is displayed just above the login box on the main login page.
-
-// Miscellaneous settings:
-$comdef_global_language ='en'; // This is the 2-letter code for the default root server localization (will default to 'en' -English, if the localization is not available).
-$min_pw_len = 10; // The minimum number of characters in a user account password for this root server.
-$number_of_meetings_for_auto = 10; // This is an approximation of the number of meetings to search for in the auto-search feature. The higher the number, the wider the radius.
-$change_depth_for_meetings = 5; // This is how many changes should be recorded for each meeting. The higher the number, the larger the database will grow, as this can become quite substantial.
-$default_duration_time = '1:00:00'; // This is the default duration for meetings that have no duration specified.
-$g_enable_language_selector = TRUE; // Set this to TRUE (or 1) to enable a popup on the login screen that allows the administrator to select their language.
-$g_enable_email_contact = FALSE; // If this is TRUE (or 1), then this will enable the ability to contact meeting list contacts via a secure email form.
-
-// These are 'hard-coded,' but can be changed later.
-
-// These reflect the way that we handle contact emails.
-
-$include_service_body_admin_on_emails = FALSE; // If this is TRUE (or 1), then any emails sent using the meeting contact will include the Service Body Admin contact for the meeting Service body (ignored, if $g_enable_email_contact is FALSE).
-
-$include_every_admin_on_emails = FALSE; // If this is TRUE (or 1), then any emails sent using the meeting contact will include all Service Body Admin contacts (including the Server Administrator) for the meeting (ignored, if $g_enable_email_contact or $include_service_body_admin_on_emails is FALSE).
-
-
-$time_format = 'g:i A'; // The PHP date() format for the times displayed.
-$change_date_format = 'g:i A, n/j/Y'; // The PHP date() format for times/dates displayed in the change records.
-$admin_session_name = 'BMLT_Admin'; // This is merely the 'tag' used to identify the BMLT admin session.
-$g_enable_semantic_admin = TRUE;
-$default_minute_interval = 5; // This sets the minutes interval for Start Time and Duration.
diff --git a/docker/bmlt.env b/docker/bmlt.env
deleted file mode 100644
index c4e81bb09..000000000
--- a/docker/bmlt.env
+++ /dev/null
@@ -1,8 +0,0 @@
-GKEY=
-DB_DATABASE=rootserver
-DB_USER=rootserver
-DB_PASSWORD=rootserver
-DB_HOST=db
-DB_PREFIX=na
-NEW_UI_ENABLED=false
-AGGREGATOR_MODE_ENABLED=false
diff --git a/docker/docker-compose.dev.yml.example b/docker/docker-compose.dev.yml.example
index 81cdffe78..2113bf24c 100644
--- a/docker/docker-compose.dev.yml.example
+++ b/docker/docker-compose.dev.yml.example
@@ -1,5 +1,4 @@
services:
bmlt:
environment:
- GKEY: ''
- NEW_UI_ENABLED: 'false'
+ GOOGLE_API_KEY: ''
diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml
index 4a65d669c..b845689ef 100644
--- a/docker/docker-compose.yml
+++ b/docker/docker-compose.yml
@@ -8,11 +8,13 @@ services:
- PHP_VERSION=${PHP_VERSION:-8.2}
ports:
- "8000:8000"
- env_file:
- - bmlt.env
environment:
APP_DEBUG: "true"
DB_HOST: db
+ DB_DATABASE: rootserver
+ DB_USERNAME: rootserver
+ DB_PASSWORD: rootserver
+ DB_PREFIX: na
depends_on:
- db
volumes:
diff --git a/docker/start-bmlt.sh b/docker/start-bmlt.sh
deleted file mode 100644
index 5046e8074..000000000
--- a/docker/start-bmlt.sh
+++ /dev/null
@@ -1,6 +0,0 @@
-#!/bin/bash
-set -o xtrace
-set -e
-
-/bin/bash /tmp/write-config.sh
-apachectl -D FOREGROUND
diff --git a/docker/test-auto-config.inc.php b/docker/test-auto-config.inc.php
deleted file mode 100644
index 2fbc399d3..000000000
--- a/docker/test-auto-config.inc.php
+++ /dev/null
@@ -1,2 +0,0 @@
-> /var/www/html/auto-config.inc.php
-fi
-
-if [ ! -z $DB_DATABASE ]
-then
- echo "\$dbName = \"$DB_DATABASE\";" >> /var/www/html/auto-config.inc.php
-fi
-
-if [ ! -z $DB_USER ]
-then
- echo "\$dbUser = \"$DB_USER\";" >> /var/www/html/auto-config.inc.php
-fi
-
-if [ ! -z $DB_PASSWORD ]
-then
- echo "\$dbPassword = \"$DB_PASSWORD\";" >> /var/www/html/auto-config.inc.php
-fi
-
-if [ ! -z $DB_HOST ]
-then
- echo "\$dbServer = \"$DB_HOST\";" >> /var/www/html/auto-config.inc.php
-fi
-
-if [ ! -z $DB_PREFIX ]
-then
- echo "\$dbPrefix = \"$DB_PREFIX\";" >> /var/www/html/auto-config.inc.php
-fi
-
-if [ ! -z "$DO_NOT_FORCE_PORT" -a "$DO_NOT_FORCE_PORT" == "true" ]
-then
- echo "\$g_do_not_force_port = true;" >> /var/www/html/auto-config.inc.php
-fi
-
-if [ ! -z "$NEW_UI_ENABLED" -a "$NEW_UI_ENABLED" == "true" ]
-then
- echo "\$new_ui_enabled = true;" >> /var/www/html/auto-config.inc.php
-fi
-
-if [ ! -z "$AGGREGATOR_MODE_ENABLED" -a "$AGGREGATOR_MODE_ENABLED" == "true" ]
-then
- echo "\$aggregator_mode_enabled = true;" >> /var/www/html/auto-config.inc.php
-fi
-
-if [ ! -z "$AGGREGATOR_MAX_GEO_WIDTH_KM" ]
-then
- echo "\$aggregator_max_geo_width_km = ${AGGREGATOR_MAX_GEO_WIDTH_KM};" >> /var/www/html/auto-config.inc.php
-fi
-
-if [ ! -z "$MEETING_STATES_AND_PROVINCES" ]
-then
- echo "\$meeting_states_and_provinces = \"${MEETING_STATES_AND_PROVINCES}\";" >> /var/www/html/auto-config.inc.php
-fi
-
-if [ ! -z "$MEETING_COUNTIES_AND_SUB_PROVINCES" ]
-then
- echo "\$meeting_counties_and_sub_provinces = \"${MEETING_COUNTIES_AND_SUB_PROVINCES}\";" >> /var/www/html/auto-config.inc.php
-fi
-
-echo "\$default_duration_time = \"${DEFAULT_DURATION_TIME:-01:00:00}\";" >> /var/www/html/auto-config.inc.php
-echo "\$bmlt_title = \"${BMLT_TITLE:-BMLT Administration}\";" >> /var/www/html/auto-config.inc.php
-echo "\$bmlt_notice = \"${BMLT_NOTICE:-}\";" >> /var/www/html/auto-config.inc.php
-
-if [ "$ENABLE_LANGUAGE_SELECTOR" == "false" ]; then
- echo "\$g_enable_language_selector = false;" >> /var/www/html/auto-config.inc.php
-else
- echo "\$g_enable_language_selector = true;" >> /var/www/html/auto-config.inc.php
-fi
diff --git a/installation/README.md b/installation/README.md
index 0e77ce8db..c802e8785 100644
--- a/installation/README.md
+++ b/installation/README.md
@@ -1,6 +1,6 @@
# Setting Up a BMLT Server
-As of version 4.0.0 of the server, we are dropping support for the Installer Wizard. Setting up a completely new server
+We dropped support for the Installer Wizard as of version 4.0.0 of the server. Setting up a completely new server
is at this point an infrequent event, and hopefully these directions will be clear enough.
For a more detailed but older tutorial please see https://bmlt.app/setting-up-the-bmlt/. That tutorial is based on the Installer Wizard, so you'll need to adapt it accordingly. But it may be useful to explain some of the steps. Differences are noted below.
@@ -11,21 +11,15 @@ Set up an empty MySQL database, along with a MySQL user that has access to it.
## Uploading the BMLT Server Zip File
-Get the latest version of the server from https://github.com/bmlt-enabled/bmlt-server/releases, and upload it to your web hosting provider's server. (The directions for this step in the older tutorial are also still valid.) For this part of the step, upload the zip file *without* unzipping it on your local machine. Then unzip it on your server. You should end up with a directory `main_server` under the directory that holds the files that show up on your website. Thus, if your web hosting server has a directory `public_html` for the files that show up on your website, put `main_server` in that directory, like this: `public_html/main_server`.
-
-In addition, unzip the file on your laptop or desktop machine -- you'll need to get a couple of files from it in the following steps. But don't try to upload the unzipped file -- that can result in problems with dropped files and such.
-
-## Initializing the MySQL Database
-
-This step is different from the old tutorial.
-
-In the unzipped version of the BMLT Server on your local machine, locate the directory `installation` and find the file `initial-database.sql` in that directory. Import the contents of this file into the empty MySQL database that you set up in the first step. (If you are using cPanel, find the `phpMyAdmin` tool under `Databases`, select your new database, and then click `Import`.)
+Get the latest version of the server from https://github.com/bmlt-enabled/bmlt-server/releases using the link labeled `bmlt-server.zip`, and upload it to your web hosting provider's server. (The directions for this step in the older tutorial are also still valid.) For this part of the step, upload `bmlt-server.zip` *without* unzipping it on your local machine. Then unzip it on your server. You should end up with a directory `main_server` under the directory that holds the files that show up on your website. Thus, if your web hosting server has a directory `public_html` for the files that show up on your website, put `main_server` in that directory, like this: `public_html/main_server`. (Again, don't try to upload the unzipped directory from your local machine -- that can result in problems with dropped files and such.)
## Adding the auto-config File
This step is also different from the old tutorial.
-In the unzipped version of the BMLT Server, look again in the directory `installation` and find the file `initial-auto-config.txt`. Upload this file to your server, put it in the directory that holds your `main_server` directory, and rename it to `auto-config.inc.php`. This file should have the permissions `-rw-r--r--` (`0644` in octal). This means that the owner of the file can read and write it, and the owning group and others can read it.
+Download the file `initial-auto-config.txt` from GitHub at https://github.com/bmlt-enabled/bmlt-server/blob/main/installation/initial-auto-config.txt.
+
+Upload this file to your server, put it in the directory that holds your `main_server` directory, and rename it to `auto-config.inc.php`. This file should have the permissions `-rw-r--r--` (`0644` in octal). This means that the owner of the file can read and write it, and the owning group and others can read it.
Note that the file `auto-config.inc.php` is not inside `main_server`, but rather at the same level. This is a little weird, but does have the advantage that you can upload a new version of the server easily without touching the `auto-config.inc.php` file. So your directory structure should look something like this:
```
@@ -37,9 +31,7 @@ public_html
......
```
-Now edit the `auto-config.inc.php` file with new parameters as needed. You can do this using the `edit` command on cPanel. There are two parameters you definitely need to update, namely `$dbUser` and `$dbPassword` (the user and password for your server database). You also need to either update the parameter `$gkey` if you are using Google Maps, or else delete this parameter altogether if you are using OSM (Open Street Maps) for maps and nominatim for geocoding.
-
-There are various other parameters in the file, but the default values may well be what you want.
+Now edit the `auto-config.inc.php` file with new parameters as needed. You can do this using the `edit` command on cPanel. There are two parameters you definitely need to update, namely `$dbUser` and `$dbPassword` (the user and password for your server database). There are a few other parameters in the file, but the default values may well be what you want.
Alternatively, you can edit the `initial-auto-config.txt` file on your local machine, and then upload the edited file, thus avoiding needing to edit it on your web host. If you do that, be sure and use an editor intended for editing source code and not something like Microsoft Word.
@@ -50,3 +42,11 @@ Now you should be able to go to the website for your new server (which might be
## Adding Users and Service Bodies
At this point you can set up one or more Service Body Administrators and Service Bodies, and start adding meetings. We are now back to steps that are unchanged from the old tutorial, so refer to that for details.
+
+## Changing Server Settings
+
+To change server settings, go to the Server Settings item under the Administration tab when logged in as the server admin. One in particular that you may want to change is `Google Maps API Key`. The meeting location map can be displayed using either Google Maps or OpenStreetMap. To use Google maps, set `Google Maps API Key` to your Google api key. To use OpenStreetMap, just skip this step -- the system will default to it if there isn't a Google api key.
+
+If you export a database to share with others, you should probably set Google Maps API Key to the empty string first.
+
+For versions of the BMLT server prior to 4.1.0, `auto-config.inc.php` could also contain a large number of additional variable definitions. In 4.1.0, these are moved to the database, and can be inspected or updated using Server Settings. If you are migrating from an older version of the server, there is a migration that runs once when upgrading to 4.1.0 that will copy these values out of `auto-config.inc.php` and into the database. After the migration is run, these other variables in `auto-config.inc.php` will no longer have any effect on the server, and you can simplify `auto-config.inc.php` if you wish.
diff --git a/installation/initial-auto-config.txt b/installation/initial-auto-config.txt
index a40154a59..ef2b5d146 100644
--- a/installation/initial-auto-config.txt
+++ b/installation/initial-auto-config.txt
@@ -8,9 +8,6 @@ defined('BMLT_EXEC') or die ('Cannot Execute Directly');
// SETTINGS THAT MUST BE UPDATED
$dbUser = 'USERNAME'; // This is the SQL user that is authorized for the above database.
$dbPassword = 'USERPASSWORD'; // This is the password for the above authorized user. Make it a big, ugly hairy one. It is powerful, and there is no need to remember it.
-$gkey = 'a long string of random characters'; // This is the Google Maps JavaScript API Key, necessary for using Google Maps.
-// $gkey is optional -- if you just omit it, the server will use OSM for maps and nominatim for geocoding.
-// But if present, it must be a valid Google key.
// OTHER DATABASE SETTINGS (CHANGE IF NEEDED, BUT THE DEFAULTS MAY BE OK AS IS)
$dbType = 'mysql'; // This is the PHP PDO driver name for your database.
@@ -18,39 +15,4 @@ $dbName = 'rootserver'; // This is the name of the database.
$dbServer = 'localhost'; // This is the host/server for accessing the database.
$dbPrefix = 'na'; // This is a table name prefix that can be used to differentiate tables used by different root server instances that share the same database.
-// OTHER SETTINGS FOLLOW (CHANGE IF NEEDED, BUT THE DEFAULTS MAY BE OK AS IS)
-
-// Location and Map settings:
-$region_bias = 'us'; // This is a 2-letter country code for a 'region bias,' which helps figure out ambiguous search queries.
-// The default above is for the United States; other examples are 'au' (Australia), 'de' (Germany), 'fr' (France), 'jp' (Japan), etc.
-$search_spec_map_center = array('longitude' => -118.563659, 'latitude' => 34.235918, 'zoom' => 6);
-// The above coordinates are for the NAWS office in Los Angeles -- change as appropriate
-$comdef_distance_units = 'mi'; // the other option is 'km'
-
-// Display settings:
-$bmlt_title = 'Basic Meeting List Toolbox Administration';
-$banner_text = 'Administration Login';
-
-// Miscellaneous settings:
-$comdef_global_language = 'en'; // This is the 2-letter code for the default root server localization (will default to 'en' -English, if the localization is not available).
-$min_pw_len = 10; // The minimum number of characters in a user account password for this root server.
-$number_of_meetings_for_auto = 10; // This is an approximation of the number of meetings to search for in the auto-search feature. The higher the number, the wider the radius.
-$change_depth_for_meetings = 5; // This is how many changes should be recorded for each meeting. The higher the number, the larger the database will grow, as this can become quite substantial.";
-$default_duration_time = '01:30'; // This is the default duration for meetings that have no duration specified.
-$g_enable_language_selector = FALSE; // Set this to TRUE (or 1) to enable a popup on the login screen that allows the administrator to select their language.
-$g_enable_semantic_admin = TRUE; // If this is TRUE (or 1), then Semantic Administration for this Server is enabled (Administrators can log in using apps).
-$g_defaultClosedStatus = TRUE; // If this is FALSE (or 0), then the default (unspecified) Open/Closed format for meetings reported to NAWS is OPEN. Otherwise, it is CLOSED.
-// These reflect the way that we handle contact emails.
-$g_enable_email_contact = FALSE; // If this is TRUE (or 1), then this will enable the ability to contact meeting list contacts via a secure email form.
-$include_service_body_admin_on_emails = FALSE; // If this is TRUE (or 1), then any emails sent using the meeting contact will include the Service Body Admin contact for the meeting Service body (ignored, if $g_enable_email_contact is FALSE).
-$include_every_admin_on_emails = FALSE; // If this is TRUE (or 1), then any emails sent using the meeting contact will include all Service Body Admin contacts (including the Server Administrator) for the meeting (ignored, if $g_enable_email_contact or $include_service_body_admin_on_emails is FALSE).
-
-//The server languages are supported by default, the langs specified here add to them
-$format_lang_names = array(
-);
-// These are 'hard-coded,' but can be changed later:
-$time_format = 'g:i A'; // The PHP date() format for the times displayed.
-$change_date_format = 'g:i A, n/j/Y'; // The PHP date() format for times/dates displayed in the change records.
-$admin_session_name = 'BMLT_Admin'; // This is merely the 'tag' used to identify the BMLT admin session.
-
?>
diff --git a/installation/initial-database.sql b/installation/initial-database.sql
deleted file mode 100644
index 5c61fce9b..000000000
--- a/installation/initial-database.sql
+++ /dev/null
@@ -1,1080 +0,0 @@
-/*M!999999\- enable the sandbox mode */
--- MariaDB dump 10.19-11.6.2-MariaDB, for debian-linux-gnu (aarch64)
---
--- Host: localhost Database: rootserver
--- ------------------------------------------------------
--- Server version 11.6.2-MariaDB-ubu2404
-
-/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
-/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
-/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
-/*!40101 SET NAMES utf8mb4 */;
-/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
-/*!40103 SET TIME_ZONE='+00:00' */;
-/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
-/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
-/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
-/*M!100616 SET @OLD_NOTE_VERBOSITY=@@NOTE_VERBOSITY, NOTE_VERBOSITY=0 */;
-
---
--- Table structure for table `na_comdef_changes`
---
-
-DROP TABLE IF EXISTS `na_comdef_changes`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `na_comdef_changes` (
- `id_bigint` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
- `user_id_bigint` bigint(20) unsigned DEFAULT NULL,
- `service_body_id_bigint` bigint(20) unsigned NOT NULL,
- `lang_enum` varchar(7) NOT NULL,
- `change_date` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
- `object_class_string` varchar(64) NOT NULL,
- `change_name_string` varchar(255) DEFAULT NULL,
- `change_description_text` text DEFAULT NULL,
- `before_id_bigint` bigint(20) unsigned DEFAULT NULL,
- `before_lang_enum` varchar(7) DEFAULT NULL,
- `after_id_bigint` bigint(20) unsigned DEFAULT NULL,
- `after_lang_enum` varchar(7) DEFAULT NULL,
- `change_type_enum` varchar(32) NOT NULL,
- `before_object` blob DEFAULT NULL,
- `after_object` blob DEFAULT NULL,
- PRIMARY KEY (`id_bigint`),
- KEY `user_id_bigint` (`user_id_bigint`),
- KEY `service_body_id_bigint` (`service_body_id_bigint`),
- KEY `lang_enum` (`lang_enum`),
- KEY `change_type_enum` (`change_type_enum`),
- KEY `change_date` (`change_date`),
- KEY `before_id_bigint` (`before_id_bigint`),
- KEY `after_id_bigint` (`after_id_bigint`),
- KEY `before_lang_enum` (`before_lang_enum`),
- KEY `after_lang_enum` (`after_lang_enum`),
- KEY `object_class_string` (`object_class_string`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Dumping data for table `na_comdef_changes`
---
-
-LOCK TABLES `na_comdef_changes` WRITE;
-/*!40000 ALTER TABLE `na_comdef_changes` DISABLE KEYS */;
-/*!40000 ALTER TABLE `na_comdef_changes` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
--- Table structure for table `na_comdef_db_version`
---
-
-DROP TABLE IF EXISTS `na_comdef_db_version`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `na_comdef_db_version` (
- `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
- `version` int(11) NOT NULL,
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Dumping data for table `na_comdef_db_version`
---
-
-LOCK TABLES `na_comdef_db_version` WRITE;
-/*!40000 ALTER TABLE `na_comdef_db_version` DISABLE KEYS */;
-INSERT INTO `na_comdef_db_version` VALUES
-(1,21);
-/*!40000 ALTER TABLE `na_comdef_db_version` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
--- Table structure for table `na_comdef_format_types`
---
-
-DROP TABLE IF EXISTS `na_comdef_format_types`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `na_comdef_format_types` (
- `key_string` varchar(10) NOT NULL,
- `api_enum` varchar(256) NOT NULL,
- `position_int` int(11) NOT NULL,
- UNIQUE KEY `na_comdef_format_types_key_string_unique` (`key_string`),
- UNIQUE KEY `na_comdef_format_types_api_enum_unique` (`api_enum`),
- KEY `na_comdef_format_types_key_string_index` (`key_string`),
- KEY `na_comdef_format_types_api_enum_index` (`api_enum`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Dumping data for table `na_comdef_format_types`
---
-
-LOCK TABLES `na_comdef_format_types` WRITE;
-/*!40000 ALTER TABLE `na_comdef_format_types` DISABLE KEYS */;
-INSERT INTO `na_comdef_format_types` VALUES
-('FC1','MEETING_FORMAT',1),
-('FC2','LOCATION',2),
-('FC3','COMMON_NEEDS_OR_RESTRICTION',3),
-('LANG','LANGUAGE',5),
-('O','OPEN_OR_CLOSED',4);
-/*!40000 ALTER TABLE `na_comdef_format_types` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
--- Table structure for table `na_comdef_formats`
---
-
-DROP TABLE IF EXISTS `na_comdef_formats`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `na_comdef_formats` (
- `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
- `shared_id_bigint` bigint(20) unsigned NOT NULL,
- `root_server_id` bigint(20) unsigned DEFAULT NULL,
- `source_id` bigint(20) unsigned DEFAULT NULL,
- `key_string` varchar(255) DEFAULT NULL,
- `icon_blob` blob DEFAULT NULL,
- `worldid_mixed` varchar(255) DEFAULT NULL,
- `lang_enum` varchar(7) NOT NULL DEFAULT 'en',
- `name_string` varchar(255) DEFAULT NULL,
- `description_string` text DEFAULT NULL,
- `format_type_enum` varchar(7) DEFAULT 'FC1',
- PRIMARY KEY (`id`),
- KEY `shared_id_bigint` (`shared_id_bigint`),
- KEY `worldid_mixed` (`worldid_mixed`),
- KEY `format_type_enum` (`format_type_enum`),
- KEY `lang_enum` (`lang_enum`),
- KEY `key_string` (`key_string`),
- KEY `root_server_id_source_id` (`root_server_id`,`source_id`),
- CONSTRAINT `na_comdef_formats_root_server_id_foreign` FOREIGN KEY (`root_server_id`) REFERENCES `na_root_servers` (`id`) ON DELETE CASCADE
-) ENGINE=InnoDB AUTO_INCREMENT=500 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Dumping data for table `na_comdef_formats`
---
-
-LOCK TABLES `na_comdef_formats` WRITE;
-/*!40000 ALTER TABLE `na_comdef_formats` DISABLE KEYS */;
-INSERT INTO `na_comdef_formats` VALUES
-(1,1,NULL,NULL,'B',NULL,'BEG','de','Beginners','This meeting is focused on the needs of new members of NA.','FC3'),
-(2,2,NULL,NULL,'BL',NULL,'LANG','de','Bi-Lingual','This Meeting can be attended by speakers of English and another language.','LANG'),
-(3,3,NULL,NULL,'BT',NULL,'BT','de','Basic Text','This meeting is focused on discussion of the Basic Text of Narcotics Anonymous.','FC1'),
-(4,4,NULL,NULL,'C',NULL,'CLOSED','de','Closed','This meeting is closed to non-addicts. You should attend only if you believe that you may have a problem with substance abuse.','O'),
-(5,5,NULL,NULL,'CH',NULL,'CH','de','Closed Holidays','This meeting gathers in a facility that is usually closed on holidays.','FC3'),
-(6,6,NULL,NULL,'CL',NULL,'CAN','de','Candlelight','This meeting is held by candlelight.','FC2'),
-(7,7,NULL,NULL,'CS',NULL,'','de','Children under Supervision','Well-behaved, supervised children are welcome.','FC3'),
-(8,8,NULL,NULL,'D',NULL,'DISC','de','Discussion','This meeting invites participation by all attendees.','FC1'),
-(9,9,NULL,NULL,'ES',NULL,'LANG','de','Español','This meeting is conducted in Spanish.','LANG'),
-(10,10,NULL,NULL,'GL',NULL,'GL','de','Gay/Lesbian/Transgender','This meeting is focused on the needs of gay, lesbian and transgender members of NA.','FC3'),
-(11,11,NULL,NULL,'IL',NULL,NULL,'de','Illness','This meeting is focused on the needs of NA members with chronic illness.','FC1'),
-(12,12,NULL,NULL,'IP',NULL,'IP','de','Informational Pamphlet','This meeting is focused on discussion of one or more Informational Pamphlets.','FC1'),
-(13,13,NULL,NULL,'IW',NULL,'IW','de','It Works -How and Why','This meeting is focused on discussion of the It Works -How and Why text.','FC1'),
-(14,14,NULL,NULL,'JT',NULL,'JFT','de','Just for Today','This meeting is focused on discussion of the Just For Today text.','FC1'),
-(15,15,NULL,NULL,'M',NULL,'M','de','Men','This meeting is meant to be attended by men only.','FC3'),
-(16,16,NULL,NULL,'NC',NULL,'NC','de','No Children','Please do not bring children to this meeting.','FC3'),
-(17,17,NULL,NULL,'O',NULL,'OPEN','de','Open','This meeting is open to addicts and non-addicts alike. All are welcome.','O'),
-(18,18,NULL,NULL,'Pi',NULL,NULL,'de','Pitch','This meeting has a format that consists of each person who shares picking the next person.','FC1'),
-(19,19,NULL,NULL,'RF',NULL,'VAR','de','Rotating Format','This meeting has a format that changes for each meeting.','FC1'),
-(20,20,NULL,NULL,'Rr',NULL,NULL,'de','Round Robin','This meeting has a fixed sharing order (usually a circle.)','FC1'),
-(21,21,NULL,NULL,'SC',NULL,NULL,'de','Security Cameras','This meeting is held in a facility that has security cameras.','FC2'),
-(22,22,NULL,NULL,'SD',NULL,'S-D','de','Speaker/Discussion','This meeting is lead by a speaker, then opened for participation by attendees.','FC1'),
-(23,23,NULL,NULL,'SG',NULL,'SWG','de','Step Working Guide','This meeting is focused on discussion of the Step Working Guide text.','FC1'),
-(24,24,NULL,NULL,'SL',NULL,NULL,'de','ASL','This meeting provides an American Sign Language (ASL) interpreter for the deaf.','FC2'),
-(25,26,NULL,NULL,'So',NULL,'SPK','de','Speaker Only','This meeting is a speaker-only meeting. Other attendees do not participate in the discussion.','FC1'),
-(26,27,NULL,NULL,'St',NULL,'STEP','de','Step','This meeting is focused on discussion of the Twelve Steps of NA.','FC1'),
-(27,28,NULL,NULL,'Ti',NULL,NULL,'de','Timer','This meeting has sharing time limited by a timer.','FC1'),
-(28,29,NULL,NULL,'To',NULL,'TOP','de','Topic','This meeting is based upon a topic chosen by a speaker or by group conscience.','FC1'),
-(29,30,NULL,NULL,'Tr',NULL,'TRAD','de','Tradition','This meeting is focused on discussion of the Twelve Traditions of NA.','FC1'),
-(30,31,NULL,NULL,'TW',NULL,'TRAD','de','Traditions Workshop','This meeting engages in detailed discussion of one or more of the Twelve Traditions of N.A.','FC1'),
-(31,32,NULL,NULL,'W',NULL,'W','de','Women','This meeting is meant to be attended by women only.','FC3'),
-(32,33,NULL,NULL,'WC',NULL,'WCHR','de','Wheelchair','This meeting is wheelchair accessible.','FC2'),
-(33,34,NULL,NULL,'YP',NULL,'Y','de','Young People','This meeting is focused on the needs of younger members of NA.','FC3'),
-(34,35,NULL,NULL,'OE',NULL,NULL,'de','Open-Ended','No fixed duration. The meeting continues until everyone present has had a chance to share.','FC1'),
-(35,36,NULL,NULL,'BK',NULL,'LIT','de','Book Study','Approved N.A. Books','FC1'),
-(36,37,NULL,NULL,'NS',NULL,'NS','de','No Smoking','Smoking is not allowed at this meeting.','FC1'),
-(37,38,NULL,NULL,'Ag',NULL,NULL,'de','Agnostic','Intended for people with varying degrees of Faith.','FC1'),
-(38,39,NULL,NULL,'FD',NULL,NULL,'de','Five and Dime','Discussion of the Fifth Step and the Tenth Step','FC1'),
-(39,40,NULL,NULL,'AB',NULL,'QA','de','Ask-It-Basket','A topic is chosen from suggestions placed into a basket.','FC1'),
-(40,41,NULL,NULL,'ME',NULL,'MED','de','Meditation','This meeting encourages its participants to engage in quiet meditation.','FC1'),
-(41,42,NULL,NULL,'RA',NULL,'RA','de','Restricted Attendance','This facility places restrictions on attendees.','FC3'),
-(42,43,NULL,NULL,'QA',NULL,'QA','de','Question and Answer','Attendees may ask questions and expect answers from Group members.','FC1'),
-(43,44,NULL,NULL,'CW',NULL,'CW','de','Children Welcome','Children are welcome at this meeting.','FC3'),
-(44,45,NULL,NULL,'CP',NULL,'CPT','de','Concepts','This meeting is focused on discussion of the twelve concepts of NA.','FC1'),
-(45,46,NULL,NULL,'FIN',NULL,'LANG','de','Finnish','Finnish speaking meeting','LANG'),
-(46,47,NULL,NULL,'ENG',NULL,'LANG','de','English speaking','This Meeting can be attended by speakers of English.','LANG'),
-(47,48,NULL,NULL,'PER',NULL,'LANG','de','Persian','Persian speaking meeting','LANG'),
-(48,49,NULL,NULL,'L/R',NULL,'LANG','de','Lithuanian/Russian','Lithuanian/Russian Speaking Meeting','LANG'),
-(49,51,NULL,NULL,'LC',NULL,'LC','de','Living Clean','This is a discussion of the NA book Living Clean -The Journey Continues.','FC1'),
-(50,52,NULL,NULL,'GP',NULL,'GP','de','Guiding Principles','This is a discussion of the NA book Guiding Principles - The Spirit of Our Traditions.','FC1'),
-(51,54,NULL,NULL,'VM',NULL,'VM','de','Virtual Meeting','Meets Virtually','FC2'),
-(52,55,NULL,NULL,'TC',NULL,'TC','de','Temporarily Closed Facility','Facility is Temporarily Closed','FC2'),
-(53,56,NULL,NULL,'HY',NULL,'HYBR','de','Hybrid Meeting','Meets Virtually and In-person','FC2'),
-(54,57,NULL,NULL,'SPAD',NULL,'SPAD','de','Ein spirituelles Prinzip pro Tag','Lesen aus dem Buch Ein spirituelles Prinzip pro Tag','FC1'),
-(55,1,NULL,NULL,'B',NULL,'BEG','dk','Beginners','This meeting is focused on the needs of new members of NA.','FC3'),
-(56,2,NULL,NULL,'BL',NULL,'LANG','dk','Bi-Lingual','This Meeting can be attended by speakers of English and another language.','LANG'),
-(57,3,NULL,NULL,'BT',NULL,'BT','dk','Basic Text','This meeting is focused on discussion of the Basic Text of Narcotics Anonymous.','FC1'),
-(58,4,NULL,NULL,'C',NULL,'CLOSED','dk','Closed','This meeting is closed to non-addicts. You should attend only if you believe that you may have a problem with substance abuse.','O'),
-(59,5,NULL,NULL,'CH',NULL,'CH','dk','Closed Holidays','This meeting gathers in a facility that is usually closed on holidays.','FC3'),
-(60,6,NULL,NULL,'CL',NULL,'CAN','dk','Candlelight','This meeting is held by candlelight.','FC2'),
-(61,7,NULL,NULL,'CS',NULL,'','dk','Children under Supervision','Well-behaved, supervised children are welcome.','FC3'),
-(62,8,NULL,NULL,'D',NULL,'DISC','dk','Discussion','This meeting invites participation by all attendees.','FC1'),
-(63,9,NULL,NULL,'ES',NULL,'LANG','dk','Español','This meeting is conducted in Spanish.','LANG'),
-(64,10,NULL,NULL,'GL',NULL,'GL','dk','Gay/Lesbian/Transgender','This meeting is focused on the needs of gay, lesbian and transgender members of NA.','FC3'),
-(65,11,NULL,NULL,'IL',NULL,NULL,'dk','Illness','This meeting is focused on the needs of NA members with chronic illness.','FC1'),
-(66,12,NULL,NULL,'IP',NULL,'IP','dk','Informational Pamphlet','This meeting is focused on discussion of one or more Informational Pamphlets.','FC1'),
-(67,13,NULL,NULL,'IW',NULL,'IW','dk','It Works -How and Why','This meeting is focused on discussion of the It Works -How and Why text.','FC1'),
-(68,14,NULL,NULL,'JT',NULL,'JFT','dk','Just for Today','This meeting is focused on discussion of the Just For Today text.','FC1'),
-(69,15,NULL,NULL,'M',NULL,'M','dk','Men','This meeting is meant to be attended by men only.','FC3'),
-(70,16,NULL,NULL,'NC',NULL,'NC','dk','No Children','Please do not bring children to this meeting.','FC3'),
-(71,17,NULL,NULL,'O',NULL,'OPEN','dk','Open','This meeting is open to addicts and non-addicts alike. All are welcome.','O'),
-(72,18,NULL,NULL,'Pi',NULL,NULL,'dk','Pitch','This meeting has a format that consists of each person who shares picking the next person.','FC1'),
-(73,19,NULL,NULL,'RF',NULL,'VAR','dk','Rotating Format','This meeting has a format that changes for each meeting.','FC1'),
-(74,20,NULL,NULL,'Rr',NULL,NULL,'dk','Round Robin','This meeting has a fixed sharing order (usually a circle.)','FC1'),
-(75,21,NULL,NULL,'SC',NULL,NULL,'dk','Security Cameras','This meeting is held in a facility that has security cameras.','FC2'),
-(76,22,NULL,NULL,'SD',NULL,'S-D','dk','Speaker/Discussion','This meeting is lead by a speaker, then opened for participation by attendees.','FC1'),
-(77,23,NULL,NULL,'SG',NULL,'SWG','dk','Step Working Guide','This meeting is focused on discussion of the Step Working Guide text.','FC1'),
-(78,24,NULL,NULL,'SL',NULL,NULL,'dk','ASL','This meeting provides an American Sign Language (ASL) interpreter for the deaf.','FC2'),
-(79,26,NULL,NULL,'So',NULL,'SPK','dk','Speaker Only','This meeting is a speaker-only meeting. Other attendees do not participate in the discussion.','FC1'),
-(80,27,NULL,NULL,'St',NULL,'STEP','dk','Step','This meeting is focused on discussion of the Twelve Steps of NA.','FC1'),
-(81,28,NULL,NULL,'Ti',NULL,NULL,'dk','Timer','This meeting has sharing time limited by a timer.','FC1'),
-(82,29,NULL,NULL,'To',NULL,'TOP','dk','Topic','This meeting is based upon a topic chosen by a speaker or by group conscience.','FC1'),
-(83,30,NULL,NULL,'Tr',NULL,'TRAD','dk','Tradition','This meeting is focused on discussion of the Twelve Traditions of NA.','FC1'),
-(84,31,NULL,NULL,'TW',NULL,'TRAD','dk','Traditions Workshop','This meeting engages in detailed discussion of one or more of the Twelve Traditions of N.A.','FC1'),
-(85,32,NULL,NULL,'W',NULL,'W','dk','Women','This meeting is meant to be attended by women only.','FC3'),
-(86,33,NULL,NULL,'WC',NULL,'WCHR','dk','Wheelchair','This meeting is wheelchair accessible.','FC2'),
-(87,34,NULL,NULL,'YP',NULL,'Y','dk','Young People','This meeting is focused on the needs of younger members of NA.','FC3'),
-(88,35,NULL,NULL,'OE',NULL,NULL,'dk','Open-Ended','No fixed duration. The meeting continues until everyone present has had a chance to share.','FC1'),
-(89,36,NULL,NULL,'BK',NULL,'LIT','dk','Book Study','Approved N.A. Books','FC1'),
-(90,37,NULL,NULL,'NS',NULL,'NS','dk','No Smoking','Smoking is not allowed at this meeting.','FC1'),
-(91,38,NULL,NULL,'Ag',NULL,NULL,'dk','Agnostic','Intended for people with varying degrees of Faith.','FC1'),
-(92,39,NULL,NULL,'FD',NULL,NULL,'dk','Five and Dime','Discussion of the Fifth Step and the Tenth Step','FC1'),
-(93,40,NULL,NULL,'AB',NULL,'QA','dk','Ask-It-Basket','A topic is chosen from suggestions placed into a basket.','FC1'),
-(94,41,NULL,NULL,'ME',NULL,'MED','dk','Meditation','This meeting encourages its participants to engage in quiet meditation.','FC1'),
-(95,42,NULL,NULL,'RA',NULL,'RA','dk','Restricted Attendance','This facility places restrictions on attendees.','FC3'),
-(96,43,NULL,NULL,'QA',NULL,'QA','dk','Question and Answer','Attendees may ask questions and expect answers from Group members.','FC1'),
-(97,44,NULL,NULL,'CW',NULL,'CW','dk','Children Welcome','Children are welcome at this meeting.','FC3'),
-(98,45,NULL,NULL,'CP',NULL,'CPT','dk','Concepts','This meeting is focused on discussion of the twelve concepts of NA.','FC1'),
-(99,46,NULL,NULL,'FIN',NULL,'LANG','dk','Finnish','Finnish speaking meeting','LANG'),
-(100,47,NULL,NULL,'ENG',NULL,'LANG','dk','English speaking','This Meeting can be attended by speakers of English.','LANG'),
-(101,48,NULL,NULL,'PER',NULL,'LANG','dk','Persian','Persian speaking meeting','LANG'),
-(102,49,NULL,NULL,'L/R',NULL,'LANG','dk','Lithuanian/Russian','Lithuanian/Russian Speaking Meeting','LANG'),
-(103,51,NULL,NULL,'LC',NULL,'LC','dk','Living Clean','This is a discussion of the NA book Living Clean -The Journey Continues.','FC1'),
-(104,52,NULL,NULL,'GP',NULL,'GP','dk','Guiding Principles','This is a discussion of the NA book Guiding Principles - The Spirit of Our Traditions.','FC1'),
-(105,54,NULL,NULL,'VM',NULL,'VM','dk','Virtual Meeting','Meets Virtually','FC2'),
-(106,55,NULL,NULL,'TC',NULL,'TC','dk','Temporarily Closed Facility','Facility is Temporarily Closed','FC2'),
-(107,56,NULL,NULL,'HY',NULL,'HYBR','dk','Hybrid Meeting','Meets Virtually and In-person','FC2'),
-(108,1,NULL,NULL,'B',NULL,'BEG','en','Beginners','This meeting is focused on the needs of new members of NA.','FC3'),
-(109,2,NULL,NULL,'BL',NULL,'LANG','en','Bi-Lingual','This Meeting can be attended by speakers of English and another language.','LANG'),
-(110,3,NULL,NULL,'BT',NULL,'BT','en','Basic Text','This meeting is focused on discussion of the Basic Text of Narcotics Anonymous.','FC1'),
-(111,4,NULL,NULL,'C',NULL,'CLOSED','en','Closed','This meeting is closed to non-addicts. You should attend only if you believe that you may have a problem with substance abuse.','O'),
-(112,5,NULL,NULL,'CH',NULL,'CH','en','Closed Holidays','This meeting gathers in a facility that is usually closed on holidays.','FC3'),
-(113,6,NULL,NULL,'CL',NULL,'CAN','en','Candlelight','This meeting is held by candlelight.','FC2'),
-(114,7,NULL,NULL,'CS',NULL,'','en','Children under Supervision','Well-behaved, supervised children are welcome.','FC3'),
-(115,8,NULL,NULL,'D',NULL,'DISC','en','Discussion','This meeting invites participation by all attendees.','FC1'),
-(116,9,NULL,NULL,'ES',NULL,'LANG','en','Español','This meeting is conducted in Spanish.','LANG'),
-(117,10,NULL,NULL,'GL',NULL,'GL','en','Gay/Lesbian/Transgender','This meeting is focused on the needs of gay, lesbian and transgender members of NA.','FC3'),
-(118,11,NULL,NULL,'IL',NULL,NULL,'en','Illness','This meeting is focused on the needs of NA members with chronic illness.','FC1'),
-(119,12,NULL,NULL,'IP',NULL,'IP','en','Informational Pamphlet','This meeting is focused on discussion of one or more Informational Pamphlets.','FC1'),
-(120,13,NULL,NULL,'IW',NULL,'IW','en','It Works -How and Why','This meeting is focused on discussion of the It Works -How and Why text.','FC1'),
-(121,14,NULL,NULL,'JT',NULL,'JFT','en','Just for Today','This meeting is focused on discussion of the Just For Today text.','FC1'),
-(122,15,NULL,NULL,'M',NULL,'M','en','Men','This meeting is meant to be attended by men only.','FC3'),
-(123,16,NULL,NULL,'NC',NULL,'NC','en','No Children','Please do not bring children to this meeting.','FC3'),
-(124,17,NULL,NULL,'O',NULL,'OPEN','en','Open','This meeting is open to addicts and non-addicts alike. All are welcome.','O'),
-(125,18,NULL,NULL,'Pi',NULL,NULL,'en','Pitch','This meeting has a format that consists of each person who shares picking the next person.','FC1'),
-(126,19,NULL,NULL,'RF',NULL,'VAR','en','Rotating Format','This meeting has a format that changes for each meeting.','FC1'),
-(127,20,NULL,NULL,'Rr',NULL,NULL,'en','Round Robin','This meeting has a fixed sharing order (usually a circle.)','FC1'),
-(128,21,NULL,NULL,'SC',NULL,NULL,'en','Security Cameras','This meeting is held in a facility that has security cameras.','FC2'),
-(129,22,NULL,NULL,'SD',NULL,'S-D','en','Speaker/Discussion','This meeting is lead by a speaker, then opened for participation by attendees.','FC1'),
-(130,23,NULL,NULL,'SG',NULL,'SWG','en','Step Working Guide','This meeting is focused on discussion of the Step Working Guide text.','FC1'),
-(131,24,NULL,NULL,'SL',NULL,NULL,'en','ASL','This meeting provides an American Sign Language (ASL) interpreter for the deaf.','FC2'),
-(132,26,NULL,NULL,'So',NULL,'SPK','en','Speaker Only','This meeting is a speaker-only meeting. Other attendees do not participate in the discussion.','FC1'),
-(133,27,NULL,NULL,'St',NULL,'STEP','en','Step','This meeting is focused on discussion of the Twelve Steps of NA.','FC1'),
-(134,28,NULL,NULL,'Ti',NULL,NULL,'en','Timer','This meeting has sharing time limited by a timer.','FC1'),
-(135,29,NULL,NULL,'To',NULL,'TOP','en','Topic','This meeting is based upon a topic chosen by a speaker or by group conscience.','FC1'),
-(136,30,NULL,NULL,'Tr',NULL,'TRAD','en','Tradition','This meeting is focused on discussion of the Twelve Traditions of NA.','FC1'),
-(137,31,NULL,NULL,'TW',NULL,'TRAD','en','Traditions Workshop','This meeting engages in detailed discussion of one or more of the Twelve Traditions of N.A.','FC1'),
-(138,32,NULL,NULL,'W',NULL,'W','en','Women','This meeting is meant to be attended by women only.','FC3'),
-(139,33,NULL,NULL,'WC',NULL,'WCHR','en','Wheelchair','This meeting is wheelchair accessible.','FC2'),
-(140,34,NULL,NULL,'YP',NULL,'Y','en','Young People','This meeting is focused on the needs of younger members of NA.','FC3'),
-(141,35,NULL,NULL,'OE',NULL,NULL,'en','Open-Ended','No fixed duration. The meeting continues until everyone present has had a chance to share.','FC1'),
-(142,36,NULL,NULL,'BK',NULL,'LIT','en','Book Study','Approved N.A. Books','FC1'),
-(143,37,NULL,NULL,'NS',NULL,'NS','en','No Smoking','Smoking is not allowed at this meeting.','FC1'),
-(144,38,NULL,NULL,'Ag',NULL,NULL,'en','Agnostic','Intended for people with varying degrees of Faith.','FC1'),
-(145,39,NULL,NULL,'FD',NULL,NULL,'en','Five and Dime','Discussion of the Fifth Step and the Tenth Step','FC1'),
-(146,40,NULL,NULL,'AB',NULL,'QA','en','Ask-It-Basket','A topic is chosen from suggestions placed into a basket.','FC1'),
-(147,41,NULL,NULL,'ME',NULL,'MED','en','Meditation','This meeting encourages its participants to engage in quiet meditation.','FC1'),
-(148,42,NULL,NULL,'RA',NULL,'RA','en','Restricted Attendance','This facility places restrictions on attendees.','FC3'),
-(149,43,NULL,NULL,'QA',NULL,'QA','en','Question and Answer','Attendees may ask questions and expect answers from Group members.','FC1'),
-(150,44,NULL,NULL,'CW',NULL,'CW','en','Children Welcome','Children are welcome at this meeting.','FC3'),
-(151,45,NULL,NULL,'CP',NULL,'CPT','en','Concepts','This meeting is focused on discussion of the twelve concepts of NA.','FC1'),
-(152,46,NULL,NULL,'FIN',NULL,'LANG','en','Finnish','Finnish speaking meeting','LANG'),
-(153,47,NULL,NULL,'ENG',NULL,'LANG','en','English speaking','This Meeting can be attended by speakers of English.','LANG'),
-(154,48,NULL,NULL,'PER',NULL,'LANG','en','Persian','Persian speaking meeting','LANG'),
-(155,49,NULL,NULL,'L/R',NULL,'LANG','en','Lithuanian/Russian','Lithuanian/Russian Speaking Meeting','LANG'),
-(156,51,NULL,NULL,'LC',NULL,'LC','en','Living Clean','This is a discussion of the NA book Living Clean -The Journey Continues.','FC1'),
-(157,52,NULL,NULL,'GP',NULL,'GP','en','Guiding Principles','This is a discussion of the NA book Guiding Principles - The Spirit of Our Traditions.','FC1'),
-(158,54,NULL,NULL,'VM',NULL,'VM','en','Virtual Meeting','Meets Virtually','FC2'),
-(159,55,NULL,NULL,'TC',NULL,'TC','en','Temporarily Closed Facility','Facility is Temporarily Closed','FC2'),
-(160,56,NULL,NULL,'HY',NULL,'HYBR','en','Hybrid Meeting','Meets Virtually and In-person','FC2'),
-(161,57,NULL,NULL,'SPAD',NULL,'SPAD','en','A Spiritual Principle a Day','This meeting is focused on discussion of the book A Spiritual Principle a Day.','FC1'),
-(162,1,NULL,NULL,'B',NULL,'BEG','es','Para el recién llegado','Esta reunión se centra en las necesidades de los nuevos miembros de NA.','FC3'),
-(163,2,NULL,NULL,'BL',NULL,'LANG','es','Bilingüe','Esta reunión se pueden asistir personas de que hablen inglés y otro idioma.','LANG'),
-(164,3,NULL,NULL,'BT',NULL,'BT','es','Texto Básico','Esta reunión se centra en la discusión del texto básico de Narcóticos Anónimos.','FC1'),
-(165,4,NULL,NULL,'C',NULL,'CLOSED','es','Cerrado','Esta reunión está cerrada a los no adictos. Usted debe asistir solamente si cree que puede tener un problema con abuso de drogas.','O'),
-(166,5,NULL,NULL,'CH',NULL,NULL,'es','Cerrado en Días de fiesta','Esta reunión tiene lugar en una localidad que esta generalmente cerrada los días de fiesta.','FC3'),
-(167,6,NULL,NULL,'CL',NULL,'CAN','es','Luz de vela','Esta reunión se celebra a luz de vela.','FC2'),
-(168,7,NULL,NULL,'CS',NULL,'','es','Niños bajo Supervisión','Los niños de buen comportamiento y supervisados son bienvenidos.','FC3'),
-(169,8,NULL,NULL,'D',NULL,'DISC','es','Discusión','Esta reunión invita la participación de todos los asistentes.','FC1'),
-(170,10,NULL,NULL,'GL',NULL,'GL','es','Gay/Lesbiana','Esta reunión se centra en las necesidades de miembros gay y lesbianas de NA.','FC3'),
-(171,11,NULL,NULL,'IL',NULL,NULL,'es','Enfermedad','Esta reunión se centra en las necesidades de los miembros de NA con enfermedades crónicas.','FC1'),
-(172,12,NULL,NULL,'IP',NULL,'IP','es','Folleto Informativo','Esta reunión se centra en la discusión de unos o más folletos informativos.','FC1'),
-(173,13,NULL,NULL,'IW',NULL,'IW','es','Functiona - Cómo y Porqué','Esta reunión se centra en la discusión del texto Funciona - Cómo y Porqué.','FC1'),
-(174,14,NULL,NULL,'JT',NULL,'JFT','es','Solo por Hoy','Esta reunión se centra en la discusión del texto Solo por Hoy.','FC1'),
-(175,15,NULL,NULL,'M',NULL,'M','es','Hombres','A esta reunión se supone que aistan hombres solamente.','FC3'),
-(176,16,NULL,NULL,'NC',NULL,NULL,'es','No niños','Por favor no traer niños a esta reunión.','FC3'),
-(177,17,NULL,NULL,'O',NULL,'OPEN','es','Abierta','Esta reunión está abierta a los adictos y a los no adictos por igual. Todos son bienvenidos.','O'),
-(178,18,NULL,NULL,'Pi',NULL,NULL,'es','Echada','Esta reunión tiene un formato que consiste en que cada persona que comparta escoja a la persona siguiente.','FC1'),
-(179,19,NULL,NULL,'RF',NULL,'VAR','es','Formato que Rota','Esta reunión tiene un formato que cambia para cada reunión.','FC1'),
-(180,20,NULL,NULL,'Rr',NULL,NULL,'es','Round Robin','Esta reunión tiene un orden fijo de compartir (generalmente un círculo).','FC1'),
-(181,21,NULL,NULL,'SC',NULL,NULL,'es','Cámaras de Vigilancia','Esta reunión se celebra en una localidad que tenga cámaras de vigilancia.','FC2'),
-(182,22,NULL,NULL,'SD',NULL,'S-D','es','Orador/Discusión','Esta reunión es conducida por un orador, después es abierta para la participación de los asistentes.','FC1'),
-(183,23,NULL,NULL,'SG',NULL,'SWG','es','Guia Para Trabajar los Pasos','Esta reunión se centra en la discusión del texto Guia Para Trabajar los Pasos.','FC1'),
-(184,24,NULL,NULL,'SL',NULL,NULL,'es','ASL','Esta reunión proporciona intérprete (ASL) para los sordos.','FC2'),
-(185,26,NULL,NULL,'So',NULL,'SPK','es','Solamente Orador','Esta reunión es de orador solamente. Otros asistentes no participan en la discusión.','FC1'),
-(186,27,NULL,NULL,'St',NULL,'STEP','es','Paso','Esta reunión se centra en la discusión de los doce pasos de NA.','FC1'),
-(187,28,NULL,NULL,'Ti',NULL,NULL,'es','Contador de Tiempo','Esta reunión tiene el tiempo de compartir limitado por un contador de tiempo.','FC1'),
-(188,29,NULL,NULL,'To',NULL,'TOP','es','Tema','Esta reunión se basa en un tema elegido por el orador o por la conciencia del grupo.','FC1'),
-(189,30,NULL,NULL,'Tr',NULL,'TRAD','es','Tradición','Esta reunión se centra en la discusión de las Doce Tradiciones de NA.','FC1'),
-(190,31,NULL,NULL,'TW',NULL,'TRAD','es','Taller de las Tradiciones','Esta reunión consiste en la discusión detallada de una o más de las Doce Tradiciones de N.A.','FC1'),
-(191,32,NULL,NULL,'W',NULL,'W','es','Mujeres','A esta reunión se supone que asistan mujeres solamente.','FC3'),
-(192,33,NULL,NULL,'WC',NULL,'WCHR','es','Silla de Ruedas','Esta reunión es accesible por silla de ruedas.','FC2'),
-(193,34,NULL,NULL,'YP',NULL,'Y','es','Jovenes','Esta reunión se centra en las necesidades de los miembros más jóvenes de NA.','FC3'),
-(194,35,NULL,NULL,'OE',NULL,NULL,'es','Sin Tiempo Fijo','No tiene tiempo fijo. Esta reunión continua hasta que cada miembro haya tenido la oportunidad de compartir.','FC1'),
-(195,54,NULL,NULL,'VM',NULL,'VM','es','Virtual Meeting','Meets Virtually','FC2'),
-(196,55,NULL,NULL,'TC',NULL,'TC','es','Temporarily Closed Facility','Facility is Temporarily Closed','FC2'),
-(197,56,NULL,NULL,'HY',NULL,'HYBR','es','Hybrid Meeting','Meets Virtually and In-person','FC2'),
-(198,54,NULL,NULL,'VM',NULL,'VM','fa','Virtual Meeting','Meets Virtually','FC2'),
-(199,55,NULL,NULL,'TC',NULL,'TC','fa','Temporarily Closed Facility','Facility is Temporarily Closed','FC2'),
-(200,56,NULL,NULL,'HY',NULL,'HYBR','fa','Hybrid Meeting','Meets Virtually and In-person','FC2'),
-(201,1,NULL,NULL,'B',NULL,'BEG','fr','Débutants','Cette réunion est axée sur les besoins des nouveaux membres de NA.','FC3'),
-(202,2,NULL,NULL,'BL',NULL,'LANG','fr','bilingue','Cette réunion peut aider les personnes qui parlent l\'anglais et une autre langue.','LANG'),
-(203,3,NULL,NULL,'BT',NULL,'BT','fr','Texte de Base','Cette réunion est axée sur la discussion du texte de base de Narcotiques Anonymes.','FC1'),
-(204,4,NULL,NULL,'C',NULL,'CLOSED','fr','Fermée','Cette réunion est fermée aux non-toxicomanes. Vous pouvez y assister que si vous pensez que vous pouvez avoir un problème avec l\'abus de drogues.','O'),
-(205,5,NULL,NULL,'CH',NULL,NULL,'fr','Fermé durant les jours fériés.','Cette réunion a lieu dans une local qui est généralement fermé durant les jours fériés.','FC3'),
-(206,6,NULL,NULL,'CL',NULL,'CAN','fr','Chandelle','Cette réunion se déroule à la chandelle.','FC2'),
-(207,7,NULL,NULL,'CS',NULL,'','fr','Enfants sous Supervision','Les enfants bien élevés sont les bienvenus et supervisés.','FC3'),
-(208,8,NULL,NULL,'D',NULL,'DISC','fr','Discussion','Cette réunion invite tous les participants à la discussion.','FC1'),
-(209,10,NULL,NULL,'GL',NULL,'GL','fr','Gais, lesbiennes, transsexuel(le)s, bisexuel(le)s','Cette réunion est axée sur les besoins des membres gais, lesbiennes, transsexuel(le)s et bisexuel(le)s de NA.','FC3'),
-(210,11,NULL,NULL,'IL',NULL,NULL,'fr','Chroniques','Cette réunion est axée sur les besoins des membres de NA comportant des troubles de maladies chroniques.','FC1'),
-(211,12,NULL,NULL,'IP',NULL,'IP','fr','Brochures','Cette réunion est axée sur la discussion d\'une ou plusieurs brochures.','FC1'),
-(212,13,NULL,NULL,'IW',NULL,'IW','fr','Ça marche, Comment et Pourquoi','Cette session met l\'accent sur la discussion de texte Ça marche, Comment et Pourquoi.','FC1'),
-(213,14,NULL,NULL,'JT',NULL,'JFT','fr','Juste pour aujourd\'hui','Cette session met l\'accent sur la discussion du texte Juste pour aujourd\'hui.','FC1'),
-(214,15,NULL,NULL,'M',NULL,'M','fr','Hommes','Cette réunion est destinée à être assisté par seulement que des hommes.','FC3'),
-(215,16,NULL,NULL,'NC',NULL,NULL,'fr','Pas d\'enfant','S\'il vous plaît, ne pas amener les enfants à cette réunion.','FC3'),
-(216,17,NULL,NULL,'O',NULL,'OPEN','fr','Ouvert','Cette réunion est ouverte aux toxicomanes et non-toxicomanes de même. Tous sont les bienvenus.','O'),
-(217,18,NULL,NULL,'Pi',NULL,NULL,'fr','À la pige','Cette réunion a un format de discussion est que chaque personne qui discute invite la personne suivante à discuter.','FC1'),
-(218,19,NULL,NULL,'RF',NULL,'VAR','fr','Format varié','Cette réunion a un format qui varie à toutes les réunions.','FC1'),
-(219,20,NULL,NULL,'Rr',NULL,NULL,'fr','À la ronde','Cette réunion a un ordre de partage fixe (généralement un cercle).','FC1'),
-(220,21,NULL,NULL,'SC',NULL,NULL,'fr','Caméra de surveillance','Cette réunion se tient dans un emplacement qui a des caméras de surveillance.','FC2'),
-(221,22,NULL,NULL,'SD',NULL,'S-D','fr','Partage et ouvert','Cette réunion a un conférencier, puis ouvert au public.','FC1'),
-(222,23,NULL,NULL,'SG',NULL,'SWG','fr','Guides des Étapes','Cette réunion est axée sur la discussion sur le Guide des Étapes.','FC1'),
-(223,24,NULL,NULL,'SL',NULL,NULL,'fr','Malentendants','Cette rencontre permet l\'interprète pour les personnes malentendantes.','FC2'),
-(224,26,NULL,NULL,'So',NULL,'SPK','fr','Partage seulement','Cette réunion a seulement un conférencier. Les autres participants ne participent pas à la discussion.','FC1'),
-(225,27,NULL,NULL,'St',NULL,'STEP','fr','Étapes NA','Cette réunion est axée sur la discussion des Douze Étapes de NA.','FC1'),
-(226,28,NULL,NULL,'Ti',NULL,NULL,'fr','Discussion chronométrée','Cette réunion a une durée de discussion limitée par une minuterie pour chaque personne.','FC1'),
-(227,29,NULL,NULL,'To',NULL,'TOP','fr','Thématique','Cette réunion est basée sur un thème choisi par la personne qui anime ou la conscience de groupe.','FC1'),
-(228,30,NULL,NULL,'Tr',NULL,'TRAD','fr','Traditions','Cette réunion est axée sur la discussion des Douze Traditions de NA.','FC1'),
-(229,31,NULL,NULL,'TW',NULL,'TRAD','fr','Atelier sur les traditions','Cette réunion est une discussion détaillée d\'une ou de plusieurs des Douze Traditions de NA','FC1'),
-(230,32,NULL,NULL,'W',NULL,'W','fr','Femmes','Seulement les femmes sont admises.','FC3'),
-(231,33,NULL,NULL,'WC',NULL,'WCHR','fr','Fauteuil Roulant','Cette réunion est accessible en fauteuil roulant.','FC2'),
-(232,34,NULL,NULL,'YP',NULL,'Y','fr','Jeunes','Cette réunion est axée sur les besoins des plus jeunes membres de NA.','FC3'),
-(233,35,NULL,NULL,'OE',NULL,NULL,'fr','Marathon','Il n\'y a pas de durée fixe. Cette réunion se poursuit jusqu\'à ce que chaque membre a eu l\'occasion de partager.','FC1'),
-(234,36,NULL,NULL,'BK',NULL,'LIT','fr','Études de livres NA','Livres N.A. Approuvés','FC1'),
-(235,37,NULL,NULL,'NS',NULL,'NS','fr','Non-fumeurs','Fumer n\'est pas permis à cette réunion.','FC1'),
-(236,38,NULL,NULL,'Ag',NULL,NULL,'fr','Agnostique','Destiné aux personnes ayant divers degrés de la foi.','FC1'),
-(237,39,NULL,NULL,'FD',NULL,NULL,'fr','Cinq et dix','Discussion de la cinquième étape et la dixième étape.','FC1'),
-(238,40,NULL,NULL,'AB',NULL,'QA','fr','Panier','Un sujet est choisi parmi les suggestions placées dans un panier.','FC1'),
-(239,41,NULL,NULL,'ME',NULL,'MED','fr','Méditation','Cette réunion encourage ses participants à s\'engager dans la méditation tranquille.','FC1'),
-(240,42,NULL,NULL,'RA',NULL,'RA','fr','Accés limités','Cet emplacement impose des restrictions sur les participants.','FC3'),
-(241,43,NULL,NULL,'QA',NULL,'QA','fr','Questions et Réponses','Les participants peuvent poser des questions et attendre des réponses des membres du groupe.','FC1'),
-(242,44,NULL,NULL,'CW',NULL,'CW','fr','Enfants bienvenus','Les enfants sont les bienvenus à cette réunion.','FC3'),
-(243,45,NULL,NULL,'CP',NULL,'CPT','fr','Concepts','Cette réunion est axée sur la discussion des douze concepts de NA.','FC1'),
-(244,46,NULL,NULL,'Finlandais',NULL,NULL,'fr','Finlandais','Cette réunion se déroule en langue finlandaisè','FC3'),
-(245,47,NULL,NULL,'ENG',NULL,NULL,'fr','Anglais','Cette réunion se déroule de langues anglais.','FC3'),
-(246,54,NULL,NULL,'VM',NULL,'VM','fr','Virtual Meeting','Meets Virtually','FC2'),
-(247,55,NULL,NULL,'TC',NULL,'TC','fr','Temporarily Closed Facility','Facility is Temporarily Closed','FC2'),
-(248,56,NULL,NULL,'HY',NULL,'HYBR','fr','Hybrid Meeting','Meets Virtually and In-person','FC2'),
-(249,1,NULL,NULL,'NV',NULL,NULL,'it','Nuovi venuti','Riunione concentrata principalmente sulle necessità dei nuovi membri di NA.','FC3'),
-(250,2,NULL,NULL,'BL',NULL,'LANG','it','Bilingue','Questa riunione può essere frequentata da membri che parlano italiano e/o inglese.','LANG'),
-(251,3,NULL,NULL,'TB',NULL,NULL,'it','Testo base','Riunione concentrata sulla discussione del testo base di NA.','FC1'),
-(252,4,NULL,NULL,'Ch.',NULL,NULL,'it','Chiusa','Riunione chiusa ai non dipendenti. Dovrebbe frequentarla soltanto chi crede di avere un problema con le sostanze d\'abuso.','O'),
-(253,5,NULL,NULL,'SF',NULL,NULL,'it','Sospesa nei giorni festivi','Questa riunione si tiene in locali che di solito sono chiusi nei giorni festivi e di vacanza.','FC3'),
-(254,6,NULL,NULL,'LC',NULL,NULL,'it','Lume di candela','Questa riunione si tiene a lume di candela per favorire la meditazione.','FC2'),
-(255,7,NULL,NULL,'BS',NULL,NULL,'it','Bambini sotto supervisione','Sono ammessi bambini senza problemi di comportamento e sotto supervisione.','FC3'),
-(256,8,NULL,NULL,'Disc.',NULL,NULL,'it','Discussione','Tutti i partecipanti sono invitati a condividere.','FC1'),
-(257,9,NULL,NULL,'ES',NULL,'LANG','it','Spagnolo','Riunione in lingua spagnolo.','FC3'),
-(258,14,NULL,NULL,'SPO',NULL,NULL,'it','Solo per oggi','Riunione in cui si discutono i temi delle meditazioni quotidiane del libro \"Solo per oggi\".','FC1'),
-(259,15,NULL,NULL,'U',NULL,NULL,'it','Uomini','Riunioni per soli uomini.','FC3'),
-(260,17,NULL,NULL,'Ap.',NULL,NULL,'it','Aperta','Riunione aperta ai non dipendenti. Parenti, amici, professionisti e altri membri della società, sono benvenuti.','O'),
-(261,23,NULL,NULL,'GLP',NULL,NULL,'it','Guida al lavoro sui passi','Riunione basata sulla discussione della Guida al lavoro sui Dodici passi di NA.','FC1'),
-(262,28,NULL,NULL,'Temp.',NULL,NULL,'it','Condivisioni temporizzate','In queste riunioni il tempo di condivisione è limitato da un cronometro.','FC1'),
-(263,27,NULL,NULL,'P',NULL,NULL,'it','Passi','Riunione di discussione sui Dodici passi.','FC1'),
-(264,29,NULL,NULL,'Arg.',NULL,NULL,'it','Riunioni a tema','Queste riunioni si basano su un argomento prescelto.','FC1'),
-(265,30,NULL,NULL,'T',NULL,NULL,'it','Tradizioni','Riunione di discussione sulle Dodici tradizioni.','FC1'),
-(266,31,NULL,NULL,'TW',NULL,NULL,'it','Workshop sulle Dodici tradizioni','Riunioni in cui si discute dettagliatamente su una o più delle Dodici tradizioni.','FC1'),
-(267,32,NULL,NULL,'D',NULL,NULL,'it','Donne','Riunione solo donne.','FC3'),
-(268,33,NULL,NULL,'SR',NULL,NULL,'it','Sedia a rotelle','Riunione accessibile per chi ha la sedia a rotelle.','FC2'),
-(269,35,NULL,NULL,'M',NULL,NULL,'it','Maratona','Durata non prestabilita. La riunione prosegue finché tutti i presenti hanno da condividere.','FC1'),
-(270,37,NULL,NULL,'NF',NULL,NULL,'it','Non fumatori','In queste riunioni non è consentito fumare.','FC1'),
-(271,40,NULL,NULL,'TS',NULL,NULL,'it','Tema a sorpresa','L\'argomento su cui condividere è scritto su un biglietto o altro supporto (es. un bastoncino di legno) ed estratto a caso da ciascun membro.','FC1'),
-(272,42,NULL,NULL,'M',NULL,NULL,'it','Meditazione','In questa riunione sono poste restrizioni alle modalità di partecipazione.','FC3'),
-(273,43,NULL,NULL,'D/R',NULL,NULL,'it','Domande e risposteq','I partecipanti possono fare domande e attenderne la risposta dagli altri membri del gruppo.','FC1'),
-(274,44,NULL,NULL,'Ba',NULL,NULL,'it','Bambini','I bambini sono benvenuti in queste riunioni.','FC3'),
-(275,45,NULL,NULL,'C',NULL,NULL,'it','Concetti di servizio','Riunioni basate sulla discussione dei Dodici concetti per il servizio in NA.','FC1'),
-(276,51,NULL,NULL,'VP',NULL,NULL,'it','Vivere puliti','Riunioni di discussione sul libro \"Vivere puliti - Il viaggio continua\".','FC1'),
-(277,54,NULL,NULL,'VM',NULL,'VM','it','Virtual Meeting','Meets Virtually','FC2'),
-(278,55,NULL,NULL,'TC',NULL,'TC','it','Temporarily Closed Facility','Facility is Temporarily Closed','FC2'),
-(279,56,NULL,NULL,'HY',NULL,'HYBR','it','Hybrid Meeting','Meets Virtually and In-person','FC2'),
-(280,1,NULL,NULL,'B',NULL,'BEG','pl','Nowoprzybyli','Mityng koncentruje się na potrzebach nowyh członków NA.','FC3'),
-(281,2,NULL,NULL,'BL',NULL,'LANG','pl','Wielojęzykowość','Na tym mityngu mogą uczęszczać osoby posługujące się językiem angielskim i innymi.','LANG'),
-(282,3,NULL,NULL,'BT',NULL,'BT','pl','Tekst Podstawowy','Mityng koncentruje się na dyskusjach o Tekście Podstawowym Anonimowych Narkomanów.','FC1'),
-(283,4,NULL,NULL,'C',NULL,'CLOSED','pl','Mityng zamknięty','Mityng zamknięty. Wyłącznie dla osób uzależnionych i tych, które chcą przestać brać.','O'),
-(284,5,NULL,NULL,'CH',NULL,'CH','pl','Zamknięty w święta','Mityng odbywa się w miejscu, które zwykle jest zamknięte w dni wolne od pracy/wakacje.','FC3'),
-(285,6,NULL,NULL,'CL',NULL,'CAN','pl','Świeczka','Ten mityng odbywa się przy blasku świecy.','FC2'),
-(286,7,NULL,NULL,'CS',NULL,'','pl','Dzieci pod opieką','Dzieci uzależnionych mile widziane pod warunkiem odpowiedniego zachowania.','FC3'),
-(287,8,NULL,NULL,'D',NULL,'DISC','pl','Dyskusja','Mityng dla wszystkich chętnych.','FC1'),
-(288,9,NULL,NULL,'ES',NULL,'LANG','pl','Hiszpański','Mityng odbywa się w języku hiszpańskim.','LANG'),
-(289,10,NULL,NULL,'GL',NULL,'GL','pl','LGBTQ','Mityng koncentruje się na członkach wspólnoty należących do społeczności LGBT.','FC3'),
-(290,11,NULL,NULL,'IL',NULL,NULL,'pl','Choroba','Mityng koncentruje się na potrzebach przewlekle chorych członków NA.','FC1'),
-(291,12,NULL,NULL,'IP',NULL,'IP','pl','Broszura Informacyjna','Mityng koncentruje się na dyskusji nad jedną z Broszur Międzynarodowych.','FC1'),
-(292,13,NULL,NULL,'IW',NULL,'IW','pl','To Działa - Jak i Dlaczego','Mityng koncentruje się na dyskusji nad tekstem z \"To Działa - Jak i Dlaczego\".','FC1'),
-(293,14,NULL,NULL,'JT',NULL,'JFT','pl','Właśnie Dzisiaj','Mityng koncentruje się na dyskusji nad tekstem z \"Właśnie dzisiaj\".','FC1'),
-(294,15,NULL,NULL,'M',NULL,'M','pl','Mężczyźni','Mityng wyłącznie dla mężczyzn.','FC3'),
-(295,16,NULL,NULL,'NC',NULL,'NC','pl','Bez Dzieci','Prosimy, by nie przyprowadzać dzieci na ten mityng.','FC3'),
-(296,17,NULL,NULL,'O',NULL,'OPEN','pl','Otwarty','Mityng otwarty dla uzależnionych i nieuzależnionych. Wszyscy są mile widziani.','O'),
-(297,18,NULL,NULL,'Pi',NULL,NULL,'pl','Pitch','Na tym mityngu obowiązuje format, w którym osoba, dzieląca się doświadczeniem, wybiera kolejną osobę.','FC1'),
-(298,19,NULL,NULL,'RF',NULL,'VAR','pl','Zmienny format','Format tego mityngu zmienia się co mityng.','FC1'),
-(299,20,NULL,NULL,'Rr',NULL,NULL,'pl','Round Robin','Na tym mityngu jest ustalona kolejność dzielenia się doświadczeniem (zwykle w koło)','FC1'),
-(300,21,NULL,NULL,'SC',NULL,NULL,'pl','Kamery bezpieczeństwa','Mityng odbywa się w miejscu, w którym zamontowane są kamery bezpieczeństwa.','FC2'),
-(301,22,NULL,NULL,'SD',NULL,'S-D','pl','Spikerka/dyskusja','Mityng rozpoczynany jest wypowiedzią spikera, a następnie jest otwarty do dzielenia się przez resztę uczestników.','FC1'),
-(302,23,NULL,NULL,'SG',NULL,'SWG','pl','Przewodnik pracy nad Krokami','Mityng koncentruje się na dyskusji nad tekstem z \"Przewodnika do pracy nad Krokami\".','FC1'),
-(303,24,NULL,NULL,'SL',NULL,NULL,'pl','ASL','W tym mityngu bierze udział tłumacz języka migowego dla osób niesłyszących.','FC2'),
-(304,26,NULL,NULL,'So',NULL,'SPK','pl','Tylko spikerka','Mityng składa się tylko z wypowiedzi spikera. Inni uczestnicy nie dzielą się doświadczeniem.','FC1'),
-(305,27,NULL,NULL,'St',NULL,'STEP','pl','Kroki','Mityng koncentruje się na dyskusji nad Dwunastoma Krokami Anonimowych Narkomanów.','FC1'),
-(306,28,NULL,NULL,'Ti',NULL,NULL,'pl','Licznik czasu','Na tym mitngu czas wypowiedzi jest kontrolowany przez licznik czasu.','FC1'),
-(307,29,NULL,NULL,'To',NULL,'TOP','pl','Dowolny temat','Temat tego mityngu jest wybierany przez spikera lub przez sumienie grupy.','FC1'),
-(308,30,NULL,NULL,'Tr',NULL,'TRAD','pl','Tradycje','Mityng koncentruje się na dyskusji nad Dwunastoma Tradycjami NA.','FC1'),
-(309,31,NULL,NULL,'TW',NULL,'TRAD','pl','Warsztaty z tradycji','Mityng koncentruje się na wnikliwej analizje jednej lub wielu z Dwunastu Tradycji Anonimowych Narkomanów','FC1'),
-(310,32,NULL,NULL,'W',NULL,'W','pl','Kobiety','Mityng przeznaczony jedynie dla kobiet.','FC3'),
-(311,33,NULL,NULL,'WC',NULL,'WCHR','pl','Wózki inwalidzkie','Mityng wyposażony w łatwy dostęp dla wózków inwalidzkich.','FC2'),
-(312,34,NULL,NULL,'YP',NULL,'Y','pl','Młodzi ludzie','Mityng koncentruje się na dyskusjach nad potrzebami najmłodszych członków NA.','FC3'),
-(313,35,NULL,NULL,'OE',NULL,NULL,'pl','Bez końca','Mityng bez ustalonej długości. Trwa tak długo, jak długo są na nim uczestnicy.','FC1'),
-(314,36,NULL,NULL,'BK',NULL,'LIT','pl','Analiza książek','Analiza oficjalnych książek Anonimowych Narkomanów','FC1'),
-(315,37,NULL,NULL,'NS',NULL,'NS','pl','Zakac palenia','Palenie w trakcie tego mityngu jest zabronione.','FC1'),
-(316,38,NULL,NULL,'Ag',NULL,NULL,'pl','Agnostycy','Mityng dla ludzi o zróżnicowanych stopniach wiary.','FC1'),
-(317,39,NULL,NULL,'FD',NULL,NULL,'pl','Piąty i dziesiąty krok','Dyskusja nad piątym i dziesiątym krokiem Anonimowych Narkomanów','FC1'),
-(318,40,NULL,NULL,'AB',NULL,'QA','pl','Temat z koszyka','Temat mityngu wybierany jest spośród zaproponowanych niejawnie przez grupę.','FC1'),
-(319,41,NULL,NULL,'ME',NULL,'MED','pl','Medytacja','Uczestnicy tego mityngu zachęcani są do wzięcia udziału w cichej medytacji.','FC1'),
-(320,42,NULL,NULL,'RA',NULL,'RA','pl','Ograniczone uczestnictwo','Miejsce odbywania się mityngu nakłada ograniczenia na to, kto może wziąć udział w mityngu.','FC3'),
-(321,43,NULL,NULL,'QA',NULL,'QA','pl','Pytania i odpowiedzi','Uczestnicy mogą zadawać pytania i oczekiwać odpowiedzi od innych uczestników.','FC1'),
-(322,44,NULL,NULL,'CW',NULL,'CW','pl','Dzieci mile widziane','Dzieci są mile widziane.','FC3'),
-(323,45,NULL,NULL,'CP',NULL,'CPT','pl','Koncepcje','Mityng koncentruje się na dyskusji nad Dwunastoma Koncepcjami Anonimowych Narkomanów.','FC1'),
-(324,46,NULL,NULL,'FIN',NULL,'LANG','pl','Fiński','Mityng odbywa się w języku fińskim','LANG'),
-(325,47,NULL,NULL,'ENG',NULL,'LANG','pl','Anglojęzyczny','Mityng odbywa się w języku angielskim.','LANG'),
-(326,48,NULL,NULL,'PER',NULL,'LANG','pl','Perski','Mityng odbywa się w języku perskim','LANG'),
-(327,49,NULL,NULL,'L/R',NULL,'LANG','pl','Litewski/rosyjski','Mityng odbywa się w języku litewskim/rosyjskim','LANG'),
-(328,51,NULL,NULL,'LC',NULL,'LC','pl','Życie w czystości','Mityng koncentruje się na dyskusji nad tekstem z \"Życie w czystości: Podróż trwa nadal\".','FC1'),
-(329,52,NULL,NULL,'GP',NULL,'GP','pl','Guiding Principles','Mityng koncentruje się na dyskusji nad tekstem z \"Guiding Principles - The Spirit of Our Traditions\".','FC1'),
-(330,54,NULL,NULL,'VM',NULL,'VM','pl','Virtual Meeting','Meets Virtually','FC2'),
-(331,55,NULL,NULL,'TC',NULL,'TC','pl','Temporarily Closed Facility','Facility is Temporarily Closed','FC2'),
-(332,56,NULL,NULL,'HY',NULL,'HYBR','pl','Hybrid Meeting','Meets Virtually and In-person','FC2'),
-(333,1,NULL,NULL,'RC',NULL,'BEG','pt','Recém-chegados','Esta reunião tem foco nas necessidades de novos membros em NA.','FC3'),
-(334,2,NULL,NULL,'BL',NULL,'LANG','pt','Bilíngue','Reunião pode acontecer em duas línguas além de Português.','LANG'),
-(335,3,NULL,NULL,'TB',NULL,'BT','pt','Texto Básico','Esta reunião tem foco no debate sobre o Texto Básico de Narcóticos Anônimos.','FC1'),
-(336,4,NULL,NULL,'F',NULL,'CLOSED','pt','Fechada','Esta reunião fechada para não adictos. Você deve ir apenas se acredita ter problemas com abuso de substâncias.','O'),
-(337,5,NULL,NULL,'FF',NULL,'CH','pt','Fechada em feriados','Esta reunião acontece em local que geralmente é fechado em feirados.','FC3'),
-(338,6,NULL,NULL,'VL',NULL,'CAN','pt','Luz de velas','Esta reunião acontece à luz de velas.','FC2'),
-(339,7,NULL,NULL,'CA',NULL,'','pt','Criança sob supervisão','Bem-comportadas, crianças sob supervisão são bem-vindas.','FC3'),
-(340,8,NULL,NULL,'D',NULL,'DISC','pt','Discussão','Esta reunião convida a participação de todos.','FC1'),
-(341,9,NULL,NULL,'ES',NULL,'LANG','pt','Espanhol','Esta reunião acontece em Espanhol.','LANG'),
-(342,10,NULL,NULL,'LGBT',NULL,'GL','pt','LGBTQ+','Reunião de interesse LGBTQ+ em NA.','FC3'),
-(343,11,NULL,NULL,'DC',NULL,NULL,'pt','Doença Crônica','Esta reunião tem foco nos interesses especiais de pessoas sofrendo de doenças crônicas.','FC1'),
-(344,12,NULL,NULL,'IP',NULL,'PI','pt','Panfleto Informativo','Esta reunião tem foco na discussão sobre um ou mais IPs ou Panfletos Informativos.','FC1'),
-(345,13,NULL,NULL,'FUN',NULL,'IW','pt','Funciona - Como e Por quê','Esta reunião tem foco na discussão do texto do livro Funciona - Como e Por quê.','FC1'),
-(346,14,NULL,NULL,'SPH',NULL,'JFT','pt','Só Por Hoje','Esta reunião tem foco na discussão do texto do livro Só Por Hoje.','FC1'),
-(347,15,NULL,NULL,'H',NULL,'M','pt','Homens','Reunião de interesse masculino em NA','FC3'),
-(348,16,NULL,NULL,'PC',NULL,'NC','pt','Proibido crianças','Por gentileza não trazer crianças a essa reunião.','FC3'),
-(349,17,NULL,NULL,'A',NULL,'OPEN','pt','Aberta','Esta reunião é aberta para adictos e não-adictos. Todos são bem-vindos.','O'),
-(350,18,NULL,NULL,'Ind',NULL,NULL,'pt','Indicação','Esta reunião tem um formato que consiste que cada pessoa que partilha escolhe a próxima pessoa a partilhar.','FC1'),
-(351,19,NULL,NULL,'FR',NULL,'VAR','pt','Formato Rotativo','Esta reunião muda seu formato a cada reunião.','FC1'),
-(352,20,NULL,NULL,'Rr',NULL,NULL,'pt','Round Robin','Esta reunião tem um formato fixo de partilha (geralmente em círculo.)','FC1'),
-(353,21,NULL,NULL,'CV',NULL,NULL,'pt','Câmera de vigilância','Esta reunião acontece em ambiente que tem câmeras de vigilância.','FC2'),
-(354,22,NULL,NULL,'TD',NULL,'S-D','pt','Temática/Discussão','Esta reunião tem um orador, em seguida é aberta a participação dos membros','FC1'),
-(355,23,NULL,NULL,'EP',NULL,'SWG','pt','Estudo de Passos','Esta reunião é de estudo dos passos através do Guia Para Trabalhar os Passos de NA.','FC1'),
-(356,24,NULL,NULL,'LS',NULL,NULL,'pt','LSB','Esta reunião acontece com ajuda de intérprete de LIBRAS (Língua Brasileira de Sinais).','FC2'),
-(357,26,NULL,NULL,'TM',NULL,'SPK','pt','Temática','Esta reunião é do tipo temática. Não há participação dos membros na discussão.','FC1'),
-(358,27,NULL,NULL,'PS',NULL,'STEP','pt','Passos','Esta reunião é de discussão dos 12 Passos de NA.','FC1'),
-(359,28,NULL,NULL,'TP',NULL,NULL,'pt','Tempo de Partilha','Esta reunião tem seu tempo de partilha controlado por relógio.','FC1'),
-(360,29,NULL,NULL,'To',NULL,'TOP','pt','Tópico','Esta reunião é baseada em tópico escolhida por um orador ou por consciência de grupo.','FC1'),
-(361,30,NULL,NULL,'Tr',NULL,'TRAD','pt','Tradições','Esta reunião tem foco em discussão das 12 Tradições de NA.','FC1'),
-(362,31,NULL,NULL,'TW',NULL,'TRAD','pt','Workshop de Tradições','Esta reunião envolve uma discussão mais detalhada de uma ou mais das Tradições de N.A.','FC1'),
-(363,32,NULL,NULL,'M',NULL,'W','pt','Mulheres','Reunião de interesse feminino em NA.','FC3'),
-(364,33,NULL,NULL,'CadT',NULL,'WCHR','pt','Cadeirante Total','Esta reunião tem acesso total a cadeirantes.','FC2'),
-(365,34,NULL,NULL,'Jv',NULL,'Y','pt','Jovens','Esta reunião tem foco nos interesses de membros jovens em NA.','FC3'),
-(366,35,NULL,NULL,'UP',NULL,NULL,'pt','Último Partilhar','Sem duração fixa. A reunião continua até todos os presentes partilharem.','FC1'),
-(367,36,NULL,NULL,'EL',NULL,'LIT','pt','Estudo de Literatura','Reunião de estudo de literaturas aprovadas de NA','FC1'),
-(368,37,NULL,NULL,'NF',NULL,'NS','pt','Proibido Fumar','Não é permitido fumar nessa reunião.','FC1'),
-(369,38,NULL,NULL,'Ag',NULL,NULL,'pt','Agnóstico','Destinada a pessoas com diferentes graus de fé.','FC1'),
-(370,39,NULL,NULL,'QD',NULL,NULL,'pt','Quinto e Décimo','Reunião de discussão sobre o Quinto e Décimo Passos','FC1'),
-(371,40,NULL,NULL,'ST',NULL,'QA','pt','Sorteio de Tópico','Um tópico é escolhido através de sugestões sorteadas.','FC1'),
-(372,41,NULL,NULL,'ME',NULL,'MED','pt','Meditação','Esta reunião incentiva seus participantes a se envolverem em meditação silenciosa.','FC1'),
-(373,42,NULL,NULL,'AR',NULL,'RA','pt','Acesso Restrito','Esta reunião esta em local que impõe restrição de acesso às pessoas.','FC3'),
-(374,43,NULL,NULL,'PR',NULL,'QA','pt','Perguntas e Respostas','Os participantes podem fazer perguntas e esperar respostas dos membros do grupo.','FC1'),
-(375,44,NULL,NULL,'PC',NULL,'CW','pt','Permitido Crianças','Crianças são bem-vindas a essa reunião.','FC3'),
-(376,45,NULL,NULL,'Con',NULL,'CPT','pt','Conceitos','Esta reunião tem foco na discussão dos Doze Conceitos de NA.','FC1'),
-(377,46,NULL,NULL,'FIN',NULL,'LANG','pt','Filandês','Reunião em língua filandesa','LANG'),
-(378,47,NULL,NULL,'ENG',NULL,'LANG','pt','Inglês','Reunião em língua inglesa.','LANG'),
-(379,48,NULL,NULL,'PER',NULL,'LANG','pt','Persa','Reunião em língua persa','LANG'),
-(380,49,NULL,NULL,'L/R',NULL,'LANG','pt','Lituano/Russo','Reunião em Lituano/Russo','LANG'),
-(381,51,NULL,NULL,'VL',NULL,'LC','pt','Vivendo Limpo','Esta é uma reunião de discussão do livro Vivendo Limpo-A Jornada Continua.','FC1'),
-(382,52,NULL,NULL,'GP',NULL,'GP','pt','Guia de Princípios','Esta é uma reunião baseada no livro Guia de Princípios - O Espírito das Nossas Tradições .','FC1'),
-(383,53,NULL,NULL,'CadP',NULL,'WCHR','pt','Cadeirante Parcial','Esta reunião tem acesso parcial a cadeirante.','FC2'),
-(384,54,NULL,NULL,'VM',NULL,'VM','pt','Virtual Meeting','Meets Virtually','FC2'),
-(385,55,NULL,NULL,'TC',NULL,'TC','pt','Temporarily Closed Facility','Facility is Temporarily Closed','FC2'),
-(386,56,NULL,NULL,'HY',NULL,'HYBR','pt','Hybrid Meeting','Meets Virtually and In-person','FC2'),
-(387,1,NULL,NULL,'B',NULL,'BEG','ru','Начинающие','Эта встреча посвящена потребностям новых членов NA.','FC3'),
-(388,2,NULL,NULL,'BL',NULL,'LANG','ru','Двуязычное','На этом совещании могут присутствов Базового Текста Анонимных Наркоманов','LANG'),
-(389,4,NULL,NULL,'C',NULL,'CLOSED','ru','Закрытая','Эта встреча закрыта для не наркоманов. Вам следует присутствовать только в том случае, если вы считаете, что у вас могут быть проблемы со злоупотреблением психоактивными веществами.','O'),
-(390,5,NULL,NULL,'CH',NULL,'CH','ru','Закрыто по праздникам','Эта встреча собирается в учреждении, которое обычно закрыто в праздничные дни.','FC3'),
-(391,6,NULL,NULL,'CL',NULL,'CAN','ru','Искусственное освещение','Эта встреча проводится при свечах.','FC2'),
-(392,7,NULL,NULL,'CS',NULL,'','ru','Дети под присмотром','Добро пожаловать, хорошо воспитанные дети приветствуются.','FC3'),
-(393,8,NULL,NULL,'D',NULL,'DISC','ru','Обсуждение','Эта встреча приглашает к участию всех участников.','FC1'),
-(394,9,NULL,NULL,'ES',NULL,'LANG','ru','Испанский','Эта встреча проводится на испанском языке.','LANG'),
-(395,10,NULL,NULL,'GL',NULL,'GL','ru','Геи / Лесбиянки / трансгендеры','Эта встреча посвящена потребностям геев, лесбиянок и транссексуальных членов АН.','FC3'),
-(396,11,NULL,NULL,'IL',NULL,NULL,'ru','Болезнь','Эта встреча посвящена потребностям членов АН с хроническим заболеванием.','FC1'),
-(397,12,NULL,NULL,'IP',NULL,'IP','ru','Информационная брошюра','Эта встреча посвящена обсуждению одной или нескольких информационных брошюр.','FC1'),
-(398,13,NULL,NULL,'IW',NULL,'IW','ru','Это работает - как и почему','Эта встреча посвящена обсуждению текста «Как это работает - как и почему».','FC1'),
-(399,14,NULL,NULL,'JT',NULL,'JFT','ru','Только сегодня','Эта встреча посвящена обсуждению текста \"Только Сегодня\"','FC1'),
-(400,15,NULL,NULL,'M',NULL,'M','ru','Мужчины','Эта встреча предназначена только для мужчин.','FC3'),
-(401,16,NULL,NULL,'NC',NULL,'NC','ru','Без детей','Пожалуйста, не приводите детей на эту встречу.','FC3'),
-(402,17,NULL,NULL,'O',NULL,'OPEN','ru','Открытая','Эта встреча открыта как для наркоманов, так и для не наркоманов. Все приветствуются.','O'),
-(403,18,NULL,NULL,'Pi',NULL,NULL,'ru','Питч','Эта встреча имеет формат, который состоит из каждого участника, который разделяет выбор следующего участника.','FC1'),
-(404,19,NULL,NULL,'RF',NULL,'VAR','ru','Ротация','Эта встреча имеет формат, который изменяется для каждой встречи.','FC1'),
-(405,20,NULL,NULL,'Rr',NULL,NULL,'ru','Говорим по кругу','Эта встреча имеет фиксированный порядок обмена опытом (высказывания по кругу.)','FC1'),
-(406,21,NULL,NULL,'SC',NULL,NULL,'ru','Камеры наблюдения','Эта встреча проводится в учреждении с камерами наблюдения.','FC2'),
-(407,22,NULL,NULL,'SD',NULL,'S-D','ru','Спикерская / Обсуждение','Это спикерская, а затем время для обсуждений.','FC1'),
-(408,23,NULL,NULL,'SG',NULL,'SWG','ru','Руководство по Шагам АН','Эта встреча посвящена обсуждению текста руководства по шагам АН.','FC1'),
-(409,24,NULL,NULL,'SL',NULL,NULL,'ru','Для глухих','Эта встреча предоставляет переводчика американского языка жестов (ASL) для глухих.','FC2'),
-(410,26,NULL,NULL,'So',NULL,'SPK','ru','Только спикерская','Только спикерская. Другие участники не участвуют в обсуждении.','FC1'),
-(411,27,NULL,NULL,'St',NULL,'STEP','ru','Шаги','Эта встреча посвящена обсуждению Двенадцати Шагов АН.','FC1'),
-(412,28,NULL,NULL,'Ti',NULL,NULL,'ru','Таймер','Время этой встречи ограничено таймером.','FC1'),
-(413,29,NULL,NULL,'To',NULL,'TOP','ru','Тема','Эта встреча основана на теме, выбранной ведущим или групповым.','FC1'),
-(414,30,NULL,NULL,'Tr',NULL,'TRAD','ru','Традиции','Эта встреча посвящена обсуждению Двенадцати Традиций АН.','FC1'),
-(415,31,NULL,NULL,'TW',NULL,'TRAD','ru','Мастерская Традиций','Эта встреча включает в себя подробное обсуждение одной или нескольких из двенадцати традиций А.Н.','FC1'),
-(416,32,NULL,NULL,'W',NULL,'W','ru','Женская','Эта встреча предназначена для участия только женщин.','FC3'),
-(417,33,NULL,NULL,'WC',NULL,'WCHR','ru','Инвалидное кресло','Эта встреча доступна для инвалидов.','FC2'),
-(418,34,NULL,NULL,'YP',NULL,'Y','ru','Молодые люди','Эта встреча ориентирована на потребности молодых членов АН.','FC3'),
-(419,35,NULL,NULL,'OE',NULL,NULL,'ru','Неограниченная','Нет фиксированной продолжительности. Встреча продолжается до тех пор, пока все присутствующие не смогут поделиться опытом.','FC1'),
-(420,36,NULL,NULL,'BK',NULL,'LIT','ru','Книжное обучение','Утвержденные книги А.Н.','FC1'),
-(421,37,NULL,NULL,'NS',NULL,'NS','ru','Не курить','Курение запрещено на этой встрече.','FC1'),
-(422,38,NULL,NULL,'Ag',NULL,NULL,'ru','Агностики','Предназначен для людей с разной степенью веры.','FC1'),
-(423,39,NULL,NULL,'FD',NULL,NULL,'ru','Пятый и Десятый','Обсуждение пятого шага и десятого шага','FC1'),
-(424,40,NULL,NULL,'AB',NULL,'QA','ru','Коробочка','Тема выбирается из предложений, помещенных в коробочку.','FC1'),
-(425,41,NULL,NULL,'ME',NULL,'MED','ru','Медитация','Эта встреча поощряет ее участников заниматься тихой медитацией.','FC1'),
-(426,42,NULL,NULL,'RA',NULL,'RA','ru','Ограниченная Посещаемость','Эта встреча накладывает ограничения на посетителей.','FC3'),
-(427,43,NULL,NULL,'QA',NULL,'QA','ru','Вопрос и ответ','Участники могут задавать вопросы и ожидать ответов от членов группы.','FC1'),
-(428,44,NULL,NULL,'CW',NULL,'CW','ru','Дети - добро пожаловать','Дети приветствуются на этой встрече.','FC3'),
-(429,45,NULL,NULL,'CP',NULL,'CPT','ru','Концепции','Эта встреча посвящена обсуждению двенадцати концепций А.Н.','FC1'),
-(430,46,NULL,NULL,'FIN',NULL,'LANG','ru','Финский','финноязычная встреча','LANG'),
-(431,47,NULL,NULL,'ENG',NULL,'LANG','ru','Англогоязычный','На его собрании могут присутствовать носители английского языка.','LANG'),
-(432,48,NULL,NULL,'PER',NULL,'LANG','ru','Персидский','Собрание проводится на Персидском языке','LANG'),
-(433,49,NULL,NULL,'L/R',NULL,'LANG','ru','Русский\\литовский','Русскоговорящие собрания АН','LANG'),
-(434,51,NULL,NULL,'LC',NULL,'LC','ru','Жить Чистыми','Это обсуждение книги АН «Живи чисто - путешествие продолжается».','FC1'),
-(435,52,NULL,NULL,'GP',NULL,'GP','ru','Руководящие принципы','Это обсуждение книги АН «Руководящие принципы - дух наших традиций».','FC1'),
-(436,54,NULL,NULL,'VM',NULL,'VM','ru','Виртуальная встреча','Собираемся онлайн','FC2'),
-(437,55,NULL,NULL,'TC',NULL,'TC','ru','Временно закрыто','Объект временно закрыт','FC2'),
-(438,56,NULL,NULL,'HY',NULL,'HYBR','ru','Hybrid Meeting','Meets Virtually and In-person','FC2'),
-(439,4,NULL,NULL,'S',NULL,'CLOSED','sv','Slutet möte','Ett slutet NA möte är för de individer som identifierar sig som beroende eller för de som är osäkra och tror att de kanske har drogproblem.','FC3'),
-(440,15,NULL,NULL,'M',NULL,'M','sv','Mansmöte','Detta möte är endast öppet för män.','FC3'),
-(441,17,NULL,NULL,'Ö',NULL,'OPEN','sv','Öppet möte','Ett öppet möte är ett NA-möte där vem som helst som är intresserad av hur vi har funnit tillfrisknande från beroendesjukdomen kan närvara.','FC3'),
-(442,47,NULL,NULL,'ENG',NULL,NULL,'sv','Engelska','Engelsktalande möte','FC3'),
-(443,48,NULL,NULL,'PER',NULL,NULL,'sv','Persiskt','Persiskt möte','FC1'),
-(444,32,NULL,NULL,'K',NULL,'W','sv','Kvinnomöte','Detta möte är endast öppet för kvinnor.','FC3'),
-(445,33,NULL,NULL,'RL',NULL,'WCHR','sv','Rullstolsvänlig lokal','Detta möte är tillgängligt för rullstolsbundna.','FC2'),
-(446,47,NULL,NULL,'ENG',NULL,NULL,'sv','Engelska','Engelsktalande möte','FC3'),
-(447,54,NULL,NULL,'VM',NULL,'VM','sv','Virtual Meeting','Meets Virtually','FC2'),
-(448,55,NULL,NULL,'TC',NULL,'TC','sv','Temporarily Closed Facility','Facility is Temporarily Closed','FC2'),
-(449,56,NULL,NULL,'HY',NULL,'HYBR','sv','Hybrid Meeting','Meets Virtually and In-person','FC2'),
-(450,1,NULL,NULL,'B',NULL,'BEG','fa','تازه واردان','این جلسه بر روی نیازهای تازه واردان در معتادان گمنام متمرکز میباشد','FC3'),
-(451,2,NULL,NULL,'BL',NULL,'LANG','fa','دو زبانه','این جلسه پذیرای شرکت کنندگان انگلیسی زبان و دیگر زبان ها میباشد','LANG'),
-(452,3,NULL,NULL,'BT',NULL,'BT','fa','کتاب پایه','این جلسه متمرکز بر روی بحث درباره کتاب پایه معتادان گمنام میباشد','FC1'),
-(453,4,NULL,NULL,'C',NULL,'CLOSED','fa','بسته','این جلسه برای افراد غیر معتاد بسته میباشد. شما تنها اگر فکر میکنید با مواد خدر مشکل دارید میتوانید شرکت کنید','O'),
-(454,5,NULL,NULL,'CH',NULL,'CH','fa','بسته در روزهای تعطیل','این جلسات در روزهای تعطیل برگزار نمیگردد','FC3'),
-(455,6,NULL,NULL,'CL',NULL,'CAN','fa','شمع روشن','این جلسه بهمراه شمع روشن برگزار میگردد','FC2'),
-(456,7,NULL,NULL,'CS',NULL,'','fa','کودکان بی سرپرست','خوش رفتاری','FC3'),
-(457,8,NULL,NULL,'D',NULL,'DISC','fa','بحث و گفتگو','این جلسه از تمامی شرکت کنندگان دعوت به بحث میکند','FC1'),
-(458,9,NULL,NULL,'ES',NULL,'LANG','fa','اسپانیایی','این جلسه به زبان اسپانیایی برگزار میگردد','LANG'),
-(459,10,NULL,NULL,'GL',NULL,'GL','fa','مردان همجنس باز/زنان همجنس باز/تغییر جنسیتی ها','این جلسه به نیازهای همجنس بازان/همجنس خواهان میپردازد','FC3'),
-(460,11,NULL,NULL,'IL',NULL,NULL,'fa','بیماران','این جلسه به نیازهای اعضا با بیماری های مزمن متمرکز میباشد','FC1'),
-(461,12,NULL,NULL,'IP',NULL,'IP','fa','پمفلت های اطلاعاتی','این جلسه به بررسی و بحث در مورد یک یا چند پمفلت متمرکز میباشد','FC1'),
-(462,13,NULL,NULL,'IW',NULL,'IW','fa','چگونگی عملکرد','این جلسه با موضوع بحث در مورد کتاب چگونگی عملکرد برگزار میگردد','FC1'),
-(463,14,NULL,NULL,'JT',NULL,'JFT','fa','فقط برای امروز','این جلسه با موضوع بحث درمورد کتاب فقط برای امروز متمرکز میباشد','FC1'),
-(464,15,NULL,NULL,'M',NULL,'M','fa','مردان','این جلسه فقط مخصوص آقایان مباشد','FC3'),
-(465,16,NULL,NULL,'NC',NULL,'NC','fa','ممنوعیت ورود کودکان','لطفاً کودکان را به این جلسه نیاورید','FC3'),
-(466,17,NULL,NULL,'O',NULL,'OPEN','fa','باز','این جلسه برای کلیه اعضا معتاد و همچنین غیر معتادان باز میباشد','O'),
-(467,18,NULL,NULL,'Pi',NULL,NULL,'fa','انتخابی','فورمت این جلسه بصورتیست که هر مشارکت کننده میتواند نفر بعدی را جهت مشارکت انتخاب نماید','FC1'),
-(468,19,NULL,NULL,'RF',NULL,'VAR','fa','فورمت چرخشی','فورمت این جلسه در هر جلسه متغیر میباشد','FC1'),
-(469,20,NULL,NULL,'Rr',NULL,NULL,'fa','مشارکت موضوع دار','این جلسه دارای یکسری موضوعات خاص میباشد (معمولاً بصورت چرخشی)','FC1'),
-(470,21,NULL,NULL,'SC',NULL,NULL,'fa','دوربین مداربسته','این جلسه در مکانهای مجهز به دوربین مدار بسته برگزار میگردد','FC2'),
-(471,22,NULL,NULL,'SD',NULL,'S-D','fa','سخنرانی/بحث','این جلسه توسط یک سخنران گردانندگی میگردد','FC1'),
-(472,23,NULL,NULL,'SG',NULL,'SWG','fa','راهنمای کارکرد قدم','این جلسه با موضوع بررسی و بحث در مورد کتاب راهنمای کاکرد قدم برگزار میگردد','FC1'),
-(473,24,NULL,NULL,'SL',NULL,NULL,'fa','تفسیر به زبان انگلیسی برای ناشنوایان','این جلسه بهمراه مفسر انگلیسی برای ناشنوایان برگزار میگردد','FC2'),
-(474,26,NULL,NULL,'So',NULL,'SPK','fa','فقط سخنرانی','این جلسه فقط یک سخنران دارد. دیگر شرکت کنندگان حق مشارکت ندارند','FC1'),
-(475,27,NULL,NULL,'St',NULL,'STEP','fa','قدم','این جلسه با موضوع بحث درمورد قدم های دوازده گانه معتادان گمنام برگزار میگردد','FC1'),
-(476,28,NULL,NULL,'Ti',NULL,NULL,'fa','زمان سنج','در این جلسه زمان مشارکت توسط زمان سنج محاسبه و کنترل میگردد','FC1'),
-(477,29,NULL,NULL,'To',NULL,'TOP','fa','موضوع','این جلسه برپایه موضوع انتخابی توسط یک سخنران یا وجدان گروهی برگزار میگردد','FC1'),
-(478,30,NULL,NULL,'Tr',NULL,'TRAD','fa','سنت ها','این جلسه با موضوع بحث درمورد سنت های دوازده گانه معتادان گمنام برگزار میگردد','FC1'),
-(479,31,NULL,NULL,'TW',NULL,'TRAD','fa','کارگاه سنت ها','این جلسه با موضوع بررسی جزئیاتی یک یاچند سنت معتادان گمنام برگزار میگردد','FC1'),
-(480,32,NULL,NULL,'W',NULL,'W','fa','بانوان','این جلسه فقط مخصوص خانم ها مباشد','FC3'),
-(481,33,NULL,NULL,'WC',NULL,'WCHR','fa','ویلچر','در این جلسه ویلچر در دسترس میباشد','FC2'),
-(482,34,NULL,NULL,'YP',NULL,'Y','fa','جوانان','این جلسه بر روی نیازهای اعضا جوان متمرکز میباشد','FC3'),
-(483,35,NULL,NULL,'OE',NULL,NULL,'fa','بی پایان','بدون مدت زمان ثابت. این جلسه تا زمانی که تمامی اعضا درخواست کننده مشارکت، مشارکت نکرده باشند به اتمام نمیرسد','FC1'),
-(484,36,NULL,NULL,'BK',NULL,'LIT','fa','کتاب خوانی','کتابخوانی نشریات معتادان گمنام','FC1'),
-(485,37,NULL,NULL,'NS',NULL,'NS','fa','مصرف دخانیات ممنوع','مصرف دخانیات در این جلسه ممنوع میباشد','FC1'),
-(486,38,NULL,NULL,'Ag',NULL,NULL,'fa','بی اعتقادان','جلسه مخصوص اعضا باهر میزان درجه از اعتقاد','FC1'),
-(487,39,NULL,NULL,'FD',NULL,NULL,'fa','پنج و ده','جلسه بحث و بررسی قدم های پنج و ده','FC1'),
-(488,40,NULL,NULL,'AB',NULL,'QA','fa','انتخاب موضوع از سبد','انتخاب یک موضوع توسط پیشنهادات ارائه شده در سبد','FC1'),
-(489,41,NULL,NULL,'ME',NULL,'MED','fa','مراقبه','این جلسه اعضا شرکت کننده را به مراقبه کامل تشویق مینماید','FC1'),
-(490,42,NULL,NULL,'RA',NULL,'RA','fa','محدودیت شرکت کننده','این جلسه دارای محدودیت شرکت کنندگان میباشد','FC3'),
-(491,43,NULL,NULL,'QA',NULL,'QA','fa','پرسش و پاسخ','اعضا میتوانند سوالات خود را مطرح نموده و منتظر دریافت پاسخ از دیگر اعضا باشند','FC1'),
-(492,44,NULL,NULL,'CW',NULL,'CW','fa','با حضور کودکان','حضور کودکان در این جلسه بلامانع میباشد','FC3'),
-(493,45,NULL,NULL,'CP',NULL,'CPT','fa','مفاهیم','این جلسه با موضوع بحث درمورد مفاهیم دوازده گانه معتادان گمنام برگزار میگردد','FC1'),
-(494,46,NULL,NULL,'FIN',NULL,'LANG','fa','فنلاندی','جلسه به زبان فنلاندی','LANG'),
-(495,47,NULL,NULL,'ENG',NULL,'LANG','fa','انگلیسی','این جلسه میتواند با حضور اعضا انگلیسی زبان نیز برگزار گردد','LANG'),
-(496,48,NULL,NULL,'PER',NULL,'LANG','fa','فارسی','جلسه به زبان فارسی','LANG'),
-(497,49,NULL,NULL,'L/R',NULL,'LANG','fa','لیتوانیایی/روسی','جلسه به زبان های لیتوانیایی/روسی','LANG'),
-(498,51,NULL,NULL,'LC',NULL,'LC','fa','پاک زیستن','این جلسه با موضوع بررسی و بحث در مورد کتاب پاک زیستن - سفر ادامه دارد، برگزار میگردد','FC1'),
-(499,52,NULL,NULL,'GP',NULL,'GP','fa','روح سنت ها','این جلسه با موضوع بررسی و بحث در مورد کتاب روح سنت ها برگزار میگردد','FC1');
-/*!40000 ALTER TABLE `na_comdef_formats` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
--- Table structure for table `na_comdef_meetings_data`
---
-
-DROP TABLE IF EXISTS `na_comdef_meetings_data`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `na_comdef_meetings_data` (
- `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
- `meetingid_bigint` bigint(20) unsigned NOT NULL,
- `key` varchar(32) NOT NULL,
- `field_prompt` varchar(255) DEFAULT NULL,
- `lang_enum` varchar(7) DEFAULT NULL,
- `visibility` int(11) DEFAULT NULL,
- `data_string` varchar(255) DEFAULT NULL,
- `data_bigint` bigint(20) DEFAULT NULL,
- `data_double` double DEFAULT NULL,
- PRIMARY KEY (`id`),
- KEY `data_bigint` (`data_bigint`),
- KEY `data_double` (`data_double`),
- KEY `meetingid_bigint` (`meetingid_bigint`),
- KEY `lang_enum` (`lang_enum`),
- KEY `key` (`key`),
- KEY `visibility` (`visibility`),
- FULLTEXT KEY `na_comdef_meetings_data_data_string_fulltext` (`data_string`)
-) ENGINE=InnoDB AUTO_INCREMENT=24 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Dumping data for table `na_comdef_meetings_data`
---
-
-LOCK TABLES `na_comdef_meetings_data` WRITE;
-/*!40000 ALTER TABLE `na_comdef_meetings_data` DISABLE KEYS */;
-INSERT INTO `na_comdef_meetings_data` VALUES
-(1,0,'meeting_name','Meeting Name','en',0,'Meeting Name',NULL,NULL),
-(2,0,'location_text','Location Name','en',0,'Location Name',NULL,NULL),
-(3,0,'location_info','Additional Location Information','en',0,'Additional Location Information',NULL,NULL),
-(4,0,'location_street','Street Address','en',0,'Street Address',NULL,NULL),
-(5,0,'location_city_subsection','Borough','en',0,'Borough',NULL,NULL),
-(6,0,'location_neighborhood','Neighborhood','en',0,'Neighborhood',NULL,NULL),
-(7,0,'location_municipality','Town','en',0,'Town',NULL,NULL),
-(8,0,'location_sub_province','County','en',0,'County',NULL,NULL),
-(9,0,'location_province','State','en',0,'State',NULL,NULL),
-(10,0,'location_postal_code_1','Zip Code','en',0,NULL,0,NULL),
-(11,0,'location_nation','Nation','en',0,'Nation',NULL,NULL),
-(12,0,'comments','Comments','en',0,'Comments',NULL,NULL),
-(13,0,'train_lines','Train Lines','en',0,NULL,NULL,NULL),
-(14,0,'bus_lines','Bus Lines','en',0,NULL,NULL,NULL),
-(15,0,'contact_phone_2','Contact 2 Phone','en',1,'Contact 2 Phone',NULL,NULL),
-(16,0,'contact_email_2','Contact 2 Email','en',1,'Contact 2 Email',NULL,NULL),
-(17,0,'contact_name_2','Contact 2 Name','en',1,'Contact 2 Name',NULL,NULL),
-(18,0,'contact_phone_1','Contact 1 Phone','en',1,'Contact 1 Phone',NULL,NULL),
-(19,0,'contact_email_1','Contact 1 Email','en',1,'Contact 1 Email',NULL,NULL),
-(20,0,'contact_name_1','Contact 1 Name','en',1,'Contact 1 Name',NULL,NULL),
-(21,0,'phone_meeting_number','Phone Meeting Dial-in Number','en',0,'Phone Meeting Dial-in Number',NULL,NULL),
-(22,0,'virtual_meeting_link','Virtual Meeting Link','en',0,'Virtual Meeting Link',NULL,NULL),
-(23,0,'virtual_meeting_additional_info','Virtual Meeting Additional Info','en',0,'Virtual Meeting Additional Info',NULL,NULL);
-/*!40000 ALTER TABLE `na_comdef_meetings_data` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
--- Table structure for table `na_comdef_meetings_longdata`
---
-
-DROP TABLE IF EXISTS `na_comdef_meetings_longdata`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `na_comdef_meetings_longdata` (
- `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
- `meetingid_bigint` bigint(20) unsigned NOT NULL,
- `key` varchar(32) NOT NULL,
- `field_prompt` varchar(255) DEFAULT NULL,
- `lang_enum` varchar(7) DEFAULT NULL,
- `visibility` int(11) DEFAULT NULL,
- `data_blob` text DEFAULT NULL,
- PRIMARY KEY (`id`),
- KEY `meetingid_bigint` (`meetingid_bigint`),
- KEY `lang_enum` (`lang_enum`),
- KEY `field_prompt` (`field_prompt`),
- KEY `key` (`key`),
- KEY `visibility` (`visibility`),
- FULLTEXT KEY `na_comdef_meetings_longdata_data_blob_fulltext` (`data_blob`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Dumping data for table `na_comdef_meetings_longdata`
---
-
-LOCK TABLES `na_comdef_meetings_longdata` WRITE;
-/*!40000 ALTER TABLE `na_comdef_meetings_longdata` DISABLE KEYS */;
-/*!40000 ALTER TABLE `na_comdef_meetings_longdata` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
--- Table structure for table `na_comdef_meetings_main`
---
-
-DROP TABLE IF EXISTS `na_comdef_meetings_main`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `na_comdef_meetings_main` (
- `id_bigint` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
- `root_server_id` bigint(20) unsigned DEFAULT NULL,
- `source_id` bigint(20) unsigned DEFAULT NULL,
- `worldid_mixed` varchar(255) DEFAULT NULL,
- `shared_group_id_bigint` bigint(20) DEFAULT NULL,
- `service_body_bigint` bigint(20) unsigned NOT NULL,
- `weekday_tinyint` tinyint(3) unsigned DEFAULT NULL,
- `venue_type` tinyint(3) unsigned DEFAULT NULL,
- `start_time` time DEFAULT NULL,
- `duration_time` time DEFAULT NULL,
- `time_zone` varchar(40) DEFAULT NULL,
- `formats` varchar(255) DEFAULT NULL,
- `lang_enum` varchar(7) DEFAULT NULL,
- `longitude` double DEFAULT NULL,
- `latitude` double DEFAULT NULL,
- `published` tinyint(4) NOT NULL DEFAULT 0,
- `email_contact` varchar(255) DEFAULT NULL,
- PRIMARY KEY (`id_bigint`),
- KEY `weekday_tinyint` (`weekday_tinyint`),
- KEY `venue_type` (`venue_type`),
- KEY `service_body_bigint` (`service_body_bigint`),
- KEY `start_time` (`start_time`),
- KEY `duration_time` (`duration_time`),
- KEY `time_zone` (`time_zone`),
- KEY `formats` (`formats`),
- KEY `lang_enum` (`lang_enum`),
- KEY `worldid_mixed` (`worldid_mixed`),
- KEY `shared_group_id_bigint` (`shared_group_id_bigint`),
- KEY `longitude` (`longitude`),
- KEY `latitude` (`latitude`),
- KEY `published` (`published`),
- KEY `email_contact` (`email_contact`),
- KEY `root_server_id_source_id` (`root_server_id`,`source_id`),
- CONSTRAINT `na_comdef_meetings_main_root_server_id_foreign` FOREIGN KEY (`root_server_id`) REFERENCES `na_root_servers` (`id`) ON DELETE CASCADE
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Dumping data for table `na_comdef_meetings_main`
---
-
-LOCK TABLES `na_comdef_meetings_main` WRITE;
-/*!40000 ALTER TABLE `na_comdef_meetings_main` DISABLE KEYS */;
-/*!40000 ALTER TABLE `na_comdef_meetings_main` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
--- Table structure for table `na_comdef_service_bodies`
---
-
-DROP TABLE IF EXISTS `na_comdef_service_bodies`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `na_comdef_service_bodies` (
- `id_bigint` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
- `root_server_id` bigint(20) unsigned DEFAULT NULL,
- `source_id` bigint(20) unsigned DEFAULT NULL,
- `name_string` varchar(255) NOT NULL,
- `description_string` text NOT NULL,
- `lang_enum` varchar(7) NOT NULL DEFAULT 'en',
- `worldid_mixed` varchar(255) DEFAULT NULL,
- `kml_file_uri_string` varchar(255) DEFAULT NULL,
- `principal_user_bigint` bigint(20) unsigned DEFAULT NULL,
- `editors_string` varchar(255) DEFAULT NULL,
- `uri_string` varchar(255) DEFAULT NULL,
- `sb_type` varchar(32) DEFAULT NULL,
- `sb_owner` bigint(20) unsigned DEFAULT NULL,
- `sb_owner_2` bigint(20) unsigned DEFAULT NULL,
- `sb_meeting_email` varchar(255) NOT NULL,
- PRIMARY KEY (`id_bigint`),
- KEY `worldid_mixed` (`worldid_mixed`),
- KEY `kml_file_uri_string` (`kml_file_uri_string`),
- KEY `principal_user_bigint` (`principal_user_bigint`),
- KEY `editors_string` (`editors_string`),
- KEY `lang_enum` (`lang_enum`),
- KEY `uri_string` (`uri_string`),
- KEY `sb_type` (`sb_type`),
- KEY `sb_owner` (`sb_owner`),
- KEY `sb_owner_2` (`sb_owner_2`),
- KEY `sb_meeting_email` (`sb_meeting_email`),
- KEY `root_server_id_source_id` (`root_server_id`,`source_id`),
- CONSTRAINT `na_comdef_service_bodies_root_server_id_foreign` FOREIGN KEY (`root_server_id`) REFERENCES `na_root_servers` (`id`) ON DELETE CASCADE
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Dumping data for table `na_comdef_service_bodies`
---
-
-LOCK TABLES `na_comdef_service_bodies` WRITE;
-/*!40000 ALTER TABLE `na_comdef_service_bodies` DISABLE KEYS */;
-/*!40000 ALTER TABLE `na_comdef_service_bodies` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
--- Table structure for table `na_comdef_users`
---
-
-DROP TABLE IF EXISTS `na_comdef_users`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `na_comdef_users` (
- `id_bigint` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
- `user_level_tinyint` tinyint(3) unsigned NOT NULL DEFAULT 0,
- `name_string` varchar(255) NOT NULL,
- `description_string` text NOT NULL,
- `email_address_string` varchar(255) NOT NULL,
- `login_string` varchar(255) NOT NULL,
- `password_string` varchar(255) NOT NULL,
- `last_access_datetime` datetime NOT NULL DEFAULT '1970-01-01 00:00:00',
- `lang_enum` varchar(7) NOT NULL DEFAULT 'en',
- `owner_id_bigint` bigint(20) NOT NULL DEFAULT -1,
- PRIMARY KEY (`id_bigint`),
- UNIQUE KEY `login_string` (`login_string`),
- KEY `user_level_tinyint` (`user_level_tinyint`),
- KEY `email_address_string` (`email_address_string`),
- KEY `last_access_datetime` (`last_access_datetime`),
- KEY `lang_enum` (`lang_enum`),
- KEY `owner_id_bigint` (`owner_id_bigint`)
-) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Dumping data for table `na_comdef_users`
---
-
-LOCK TABLES `na_comdef_users` WRITE;
-/*!40000 ALTER TABLE `na_comdef_users` DISABLE KEYS */;
-INSERT INTO `na_comdef_users` VALUES
-(1,1,'Server Administrator','Main Server Administrator','','serveradmin','$2y$10$wwu/pk1IUY3X3ppzoJvDJ.EWqIgZ1A4qyZHCrFNaN0r9RLHagTZGG','1970-01-01 00:00:00','en',-1);
-/*!40000 ALTER TABLE `na_comdef_users` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
--- Table structure for table `na_migrations`
---
-
-DROP TABLE IF EXISTS `na_migrations`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `na_migrations` (
- `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
- `migration` varchar(255) NOT NULL,
- `batch` int(11) NOT NULL,
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB AUTO_INCREMENT=17 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Dumping data for table `na_migrations`
---
-
-LOCK TABLES `na_migrations` WRITE;
-/*!40000 ALTER TABLE `na_migrations` DISABLE KEYS */;
-INSERT INTO `na_migrations` VALUES
-(1,'1900_01_01_000000_create_sessions_table',1),
-(2,'1901_01_01_000000_legacy_migrations',1),
-(3,'1902_01_01_000000_create_initial_schema',1),
-(4,'1903_01_01_000000_innodb_db_version',1),
-(5,'1904_01_01_000000_innodb_meetings_data',1),
-(6,'1905_01_01_000000_innodb_meetings_longdata',1),
-(7,'1906_01_01_000000_innodb_formats',1),
-(8,'1907_01_01_000000_innodb_meetings_main',1),
-(9,'1908_01_01_000000_innodb_service_bodies',1),
-(10,'1909_01_01_000000_innodb_users',1),
-(11,'1910_01_01_000000_innodb_changes',1),
-(12,'1911_01_01_000000_trim_whitespace',1),
-(13,'2019_12_14_000001_create_personal_access_tokens_table',1),
-(14,'2023_05_16_223943_format_types',1),
-(15,'2024_06_12_164303_fix_meeting_lang_enum',1),
-(16,'2024_07_20_203802_fix_admin_user_owners',1);
-/*!40000 ALTER TABLE `na_migrations` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
--- Table structure for table `na_personal_access_tokens`
---
-
-DROP TABLE IF EXISTS `na_personal_access_tokens`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `na_personal_access_tokens` (
- `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
- `tokenable_type` varchar(255) NOT NULL,
- `tokenable_id` bigint(20) unsigned NOT NULL,
- `name` varchar(255) NOT NULL,
- `token` varchar(64) NOT NULL,
- `abilities` text DEFAULT NULL,
- `last_used_at` timestamp NULL DEFAULT NULL,
- `expires_at` timestamp NULL DEFAULT NULL,
- `created_at` timestamp NULL DEFAULT NULL,
- `updated_at` timestamp NULL DEFAULT NULL,
- PRIMARY KEY (`id`),
- UNIQUE KEY `na_personal_access_tokens_token_unique` (`token`),
- KEY `na_personal_access_tokens_tokenable_type_tokenable_id_index` (`tokenable_type`,`tokenable_id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Dumping data for table `na_personal_access_tokens`
---
-
-LOCK TABLES `na_personal_access_tokens` WRITE;
-/*!40000 ALTER TABLE `na_personal_access_tokens` DISABLE KEYS */;
-/*!40000 ALTER TABLE `na_personal_access_tokens` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
--- Table structure for table `na_root_server_statistics`
---
-
-DROP TABLE IF EXISTS `na_root_server_statistics`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `na_root_server_statistics` (
- `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
- `root_server_id` bigint(20) unsigned NOT NULL,
- `num_zones` int(10) unsigned NOT NULL,
- `num_regions` int(10) unsigned NOT NULL,
- `num_areas` int(10) unsigned NOT NULL,
- `num_groups` int(10) unsigned NOT NULL,
- `num_total_meetings` int(10) unsigned NOT NULL,
- `num_in_person_meetings` int(10) unsigned NOT NULL,
- `num_virtual_meetings` int(10) unsigned NOT NULL,
- `num_hybrid_meetings` int(10) unsigned NOT NULL,
- `num_unknown_meetings` int(10) unsigned NOT NULL,
- `is_latest` tinyint(1) NOT NULL,
- `created_at` timestamp NULL DEFAULT NULL,
- `updated_at` timestamp NULL DEFAULT NULL,
- PRIMARY KEY (`id`),
- KEY `na_root_server_statistics_root_server_id_foreign` (`root_server_id`),
- KEY `is_latest` (`is_latest`),
- KEY `is_latest_root_server_id` (`is_latest`,`root_server_id`),
- CONSTRAINT `na_root_server_statistics_root_server_id_foreign` FOREIGN KEY (`root_server_id`) REFERENCES `na_root_servers` (`id`) ON DELETE CASCADE
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Dumping data for table `na_root_server_statistics`
---
-
-LOCK TABLES `na_root_server_statistics` WRITE;
-/*!40000 ALTER TABLE `na_root_server_statistics` DISABLE KEYS */;
-/*!40000 ALTER TABLE `na_root_server_statistics` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
--- Table structure for table `na_root_servers`
---
-
-DROP TABLE IF EXISTS `na_root_servers`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `na_root_servers` (
- `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
- `source_id` bigint(20) unsigned NOT NULL,
- `name` varchar(255) NOT NULL,
- `url` varchar(255) NOT NULL,
- `server_info` text DEFAULT NULL,
- `last_successful_import` datetime DEFAULT NULL,
- `created_at` timestamp NULL DEFAULT NULL,
- `updated_at` timestamp NULL DEFAULT NULL,
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Dumping data for table `na_root_servers`
---
-
-LOCK TABLES `na_root_servers` WRITE;
-/*!40000 ALTER TABLE `na_root_servers` DISABLE KEYS */;
-/*!40000 ALTER TABLE `na_root_servers` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
--- Table structure for table `na_sessions`
---
-
-DROP TABLE IF EXISTS `na_sessions`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `na_sessions` (
- `id` varchar(255) NOT NULL,
- `user_id` bigint(20) unsigned DEFAULT NULL,
- `ip_address` varchar(45) DEFAULT NULL,
- `user_agent` text DEFAULT NULL,
- `payload` text NOT NULL,
- `last_activity` int(11) NOT NULL,
- PRIMARY KEY (`id`),
- KEY `na_sessions_user_id_index` (`user_id`),
- KEY `na_sessions_last_activity_index` (`last_activity`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Dumping data for table `na_sessions`
---
-
-LOCK TABLES `na_sessions` WRITE;
-/*!40000 ALTER TABLE `na_sessions` DISABLE KEYS */;
-INSERT INTO `na_sessions` VALUES
-('4lISohRRKEYSvJpxRYMw94j06dw6WNagcbJB9Gmo',NULL,'192.168.65.1','Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.6 Safari/605.1.15','YTo0OntzOjY6Il90b2tlbiI7czo0MDoiVk5Lc1BCUG9pNjJENXUxU0YwQXljYjFZbUJJdzlEajJFZTdNZzhxRyI7czo5OiJsYW5nX2VudW0iO3M6MjoiZW4iO3M6OToiX3ByZXZpb3VzIjthOjE6e3M6MzoidXJsIjtzOjMzOiJodHRwOi8vbG9jYWxob3N0OjgwMDAvbWFpbl9zZXJ2ZXIiO31zOjY6Il9mbGFzaCI7YToyOntzOjM6Im9sZCI7YTowOnt9czozOiJuZXciO2E6MDp7fX19',1732564880);
-/*!40000 ALTER TABLE `na_sessions` ENABLE KEYS */;
-UNLOCK TABLES;
-/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
-
-/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
-/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
-/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
-/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
-/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
-/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
-/*M!100616 SET NOTE_VERBOSITY=@OLD_NOTE_VERBOSITY */;
-
--- Dump completed on 2024-11-25 20:02:57
diff --git a/src/.nvmrc b/src/.nvmrc
index f203ab89b..2bd5a0a98 100644
--- a/src/.nvmrc
+++ b/src/.nvmrc
@@ -1 +1 @@
-20.13.1
+22
diff --git a/src/.phpcs.xml b/src/.phpcs.xml
index 4c3e1c9bd..f3f267b47 100644
--- a/src/.phpcs.xml
+++ b/src/.phpcs.xml
@@ -45,8 +45,5 @@
You can add specific global ignores to different
rules here.
-->
-
-
-
-
+
diff --git a/src/app.html b/src/app.html
index af5bd9a22..71a963859 100644
--- a/src/app.html
+++ b/src/app.html
@@ -2,7 +2,7 @@
-
+
%sveltekit.head%
diff --git a/src/app/ConfigBase.php b/src/app/ConfigBase.php
new file mode 100644
index 000000000..6598fd398
--- /dev/null
+++ b/src/app/ConfigBase.php
@@ -0,0 +1,51 @@
+ (int)$value,
+ Setting::TYPE_FLOAT => (float)$value,
+ Setting::TYPE_BOOL => filter_var($value, FILTER_VALIDATE_BOOLEAN),
+ Setting::TYPE_ARRAY => static::parseEnvArray($value),
+ default => $value,
+ };
+ }
+
+ private static function parseEnvArray($value): array
+ {
+ if (is_array($value)) {
+ return $value;
+ }
+
+ $decoded = json_decode($value, true);
+ if (is_array($decoded)) {
+ return $decoded;
+ }
+
+ if (is_string($value) && $value !== '') {
+ return array_map('trim', explode(',', $value));
+ }
+
+ return [];
+ }
+}
diff --git a/src/app/Console/Commands/AddTranslationKey.php b/src/app/Console/Commands/AddTranslationKey.php
new file mode 100644
index 000000000..d05c66572
--- /dev/null
+++ b/src/app/Console/Commands/AddTranslationKey.php
@@ -0,0 +1,251 @@
+argument('key');
+ $value = $this->argument('value');
+
+ if (!preg_match('/^[a-z][a-zA-Z0-9]*$/', $key)) {
+ $this->error("Invalid key format. Key must be in camelCase (start with lowercase letter, no underscores or spaces).");
+ return 1;
+ }
+
+ $langPath = resource_path('js/lang');
+ $files = File::glob($langPath . '/*.ts');
+
+ $files = array_filter($files, fn($file) => basename($file) !== 'index.ts');
+
+ if (empty($files)) {
+ $this->error("No translation files found in {$langPath}");
+ return 1;
+ }
+
+ $this->info("Adding translation key '{$key}' to all language files...");
+
+ foreach ($files as $file) {
+ $this->processFile($file, $key, $value);
+ }
+
+ $this->info("\n✓ Translation key '{$key}' added to all language files.");
+ if (!$this->option('force')) {
+ $this->info("Note: Non-English files have been marked with '// TODO: translate' comments.");
+ }
+
+ return 0;
+ }
+
+ private function processFile(string $filePath, string $key, string $value): void
+ {
+ $fileName = basename($filePath);
+ $content = File::get($filePath);
+
+ $isEnglish = str_starts_with($fileName, 'en.');
+
+ $translationValue = $isEnglish ? $value : $value;
+ $comment = $isEnglish ? '' : ', // TODO: translate';
+
+ // Find the translations export (e.g., export const enTranslations = {)
+ if (!preg_match('/export const \w+Translations = \{/', $content, $matches, PREG_OFFSET_CAPTURE)) {
+ $this->error("Could not find translations export in {$fileName}");
+ return;
+ }
+
+ $exportStart = $matches[0][1] + strlen($matches[0][0]);
+
+ $closingBracePos = $this->findClosingBrace($content, $exportStart);
+
+ if ($closingBracePos === false) {
+ $this->error("Could not find closing brace for translations in {$fileName}");
+ return;
+ }
+
+ // Extract the translations section
+ $translationsContent = substr($content, $exportStart, $closingBracePos - $exportStart);
+
+ // Parse existing keys
+ preg_match_all('/^\s*(\w+):/m', $translationsContent, $keyMatches);
+ $existingKeys = $keyMatches[1];
+
+ // Check if key already exists
+ if (in_array($key, $existingKeys)) {
+ if (!$this->option('force')) {
+ $this->warn(" {$fileName}: Key '{$key}' already exists, skipping. Use --force to overwrite.");
+ return;
+ }
+ // Remove the existing key so we can replace it
+ $this->removeExistingKey($translationsContent, $key, $exportStart, $closingBracePos, $content, $filePath, $value, $fileName, $isEnglish);
+ return;
+ }
+
+ // Find insertion point (alphabetically, case-insensitive)
+ $insertAfterKey = null;
+ $insertBeforeKey = null;
+
+ foreach ($existingKeys as $existingKey) {
+ if (strcasecmp($existingKey, $key) < 0) {
+ $insertAfterKey = $existingKey;
+ } else {
+ $insertBeforeKey = $existingKey;
+ break;
+ }
+ }
+
+ // Create the new line
+ // escape single quotes and backslashes
+ $escapedValue = str_replace(['\\', "'"], ['\\\\', "\\'"], $translationValue);
+
+ // Determine if we're inserting at the end (after last key)
+ // If so, don't add comma since it will be the new last item
+ $isLastItem = ($insertAfterKey && !$insertBeforeKey);
+ $commentForNewLine = $isLastItem && !$isEnglish ? ' // TODO: translate' : $comment;
+
+ $newLine = " {$key}: '{$escapedValue}'{$commentForNewLine}";
+
+ // Find the position to insert
+ if ($insertBeforeKey) {
+ // Insert before the next key (add comma after if English, otherwise comment includes comma)
+ if (preg_match('/^\s*' . preg_quote($insertBeforeKey, '/') . ':/m', $translationsContent, $match, PREG_OFFSET_CAPTURE)) {
+ $insertPos = $match[0][1];
+ $comma = $isEnglish ? ',' : '';
+ $before = substr($translationsContent, 0, $insertPos);
+ $after = substr($translationsContent, $insertPos);
+
+ if (trim($before) === '') {
+ // At the start - keep structure but ensure newline before first key
+ if (substr($after, 0, 1) === "\n") {
+ $after = substr($after, 1);
+ }
+ $updatedContent = "\n" . $newLine . $comma . "\n" . $after;
+ } else {
+ $updatedContent = $before . $newLine . $comma . "\n" . $after;
+ }
+ } else {
+ return;
+ }
+ } elseif ($insertAfterKey) {
+ // Insert after the previous key (at the end)
+ if (preg_match('/^\s*' . preg_quote($insertAfterKey, '/') . ':.*$/m', $translationsContent, $match, PREG_OFFSET_CAPTURE)) {
+ $lineStart = $match[0][1];
+ $lineLen = strlen($match[0][0]);
+ $before = substr($translationsContent, 0, $lineStart);
+ $lastLine = substr($translationsContent, $lineStart, $lineLen);
+ $after = substr($translationsContent, $lineStart + $lineLen);
+
+ // Ensure previous last line has trailing comma before any comment
+ if (!preg_match('/,\s*(?:\/\/.*)?$/', $lastLine)) {
+ if (preg_match('/(.*?)(\s*\/\/.*)$/', $lastLine, $m2)) {
+ $beforeComment = rtrim($m2[1]);
+ $commentPart = ltrim($m2[2]);
+ $lastLine = $beforeComment . ', ' . $commentPart;
+ } else {
+ $lastLine = rtrim($lastLine) . ',';
+ }
+ }
+
+ $updatedContent = $before . $lastLine . "\n" . $newLine . $after;
+ } else {
+ return;
+ }
+ } else {
+ // No existing keys, add as first key
+ $updatedContent = "\n" . $newLine . "\n";
+ }
+
+ $newContent = substr($content, 0, $exportStart)
+ . $updatedContent
+ . substr($content, $closingBracePos);
+
+ File::put($filePath, $newContent);
+ $this->info(" ✓ {$fileName}");
+ }
+
+ private function findClosingBrace(string $content, int $startPos): int|false
+ {
+ $depth = 1;
+ $length = strlen($content);
+
+ for ($i = $startPos; $i < $length; $i++) {
+ if ($content[$i] === '{') {
+ $depth++;
+ } elseif ($content[$i] === '}') {
+ $depth--;
+ if ($depth === 0) {
+ return $i;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ private function removeExistingKey(
+ string $translationsContent,
+ string $key,
+ int $exportStart,
+ int $closingBracePos,
+ string $content,
+ string $filePath,
+ string $value,
+ string $fileName,
+ bool $isEnglish
+ ): void {
+ // Find the line with the existing key and extract its value
+ $pattern = '/^(\s*)' . preg_quote($key, '/') . ':\s*([\'"])(.*?)\2(,?)(.*?)$/m';
+ if (preg_match($pattern, $translationsContent, $match, PREG_OFFSET_CAPTURE)) {
+ $lineStart = $match[0][1];
+ $indent = $match[1][0];
+ $trailingComma = $match[4][0];
+
+ // Escape the new value
+ $escapedValue = str_replace(['\\', "'"], ['\\\\', "\\'"], $value);
+
+ // Add TODO comment for non-English files
+ $comment = $isEnglish ? '' : ', // TODO: translate';
+
+ // If there's no comma, we need to add one (or use the comment's comma)
+ if (!$trailingComma && !$comment) {
+ $trailingComma = ',';
+ } elseif ($trailingComma && $comment) {
+ // Comment already has comma, don't duplicate
+ $trailingComma = '';
+ }
+
+ $newLine = "{$indent}{$key}: '{$escapedValue}'{$trailingComma}{$comment}";
+
+ // Replace the entire line
+ $beforeLine = substr($translationsContent, 0, $lineStart);
+ $lineEnd = $lineStart + strlen($match[0][0]);
+ $afterLine = substr($translationsContent, $lineEnd);
+
+ $updatedContent = $beforeLine . $newLine . $afterLine;
+
+ // Rebuild the full content
+ $newContent = substr($content, 0, $exportStart)
+ . $updatedContent
+ . substr($content, $closingBracePos);
+
+ File::put($filePath, $newContent);
+ $this->info(" ✓ {$fileName} (updated)");
+ }
+ }
+}
diff --git a/src/app/Console/Commands/DeleteTranslationKey.php b/src/app/Console/Commands/DeleteTranslationKey.php
new file mode 100644
index 000000000..0ef4d1de7
--- /dev/null
+++ b/src/app/Console/Commands/DeleteTranslationKey.php
@@ -0,0 +1,152 @@
+argument('key');
+
+ $langPath = resource_path('js/lang');
+ $files = File::glob($langPath . '/*.ts');
+
+ $files = array_filter($files, fn($file) => basename($file) !== 'index.ts');
+
+ if (empty($files)) {
+ $this->error("No translation files found in {$langPath}");
+ return 1;
+ }
+
+ $this->info("Deleting translation key '{$key}' from all language files...");
+
+ $deletedCount = 0;
+ $notFoundCount = 0;
+
+ foreach ($files as $file) {
+ $result = $this->deleteKeyFromFile($file, $key);
+ if ($result) {
+ $deletedCount++;
+ } else {
+ $notFoundCount++;
+ }
+ }
+
+ if ($deletedCount > 0) {
+ $this->info("\n✓ Translation key '{$key}' deleted from {$deletedCount} file(s).");
+ }
+
+ if ($notFoundCount > 0) {
+ $this->warn("Key not found in {$notFoundCount} file(s).");
+ }
+
+ return 0;
+ }
+
+ private function deleteKeyFromFile(string $filePath, string $key): bool
+ {
+ $fileName = basename($filePath);
+ $content = File::get($filePath);
+
+ // Find the translations export (e.g., export const enTranslations = {)
+ if (!preg_match('/export const \w+Translations = \{/', $content, $matches, PREG_OFFSET_CAPTURE)) {
+ $this->error("Could not find translations export in {$fileName}");
+ return false;
+ }
+
+ $exportStart = $matches[0][1] + strlen($matches[0][0]);
+
+ $closingBracePos = $this->findClosingBrace($content, $exportStart);
+
+ if ($closingBracePos === false) {
+ $this->error("Could not find closing brace for translations in {$fileName}");
+ return false;
+ }
+
+ // Extract the translations section
+ $translationsContent = substr($content, $exportStart, $closingBracePos - $exportStart);
+
+ // Find the line with the key
+ $pattern = '/^(\s*)' . preg_quote($key, '/') . ':.*?(?:,\s*(?:\/\/.*)?)?$/m';
+ if (!preg_match($pattern, $translationsContent, $match, PREG_OFFSET_CAPTURE)) {
+ $this->warn(" {$fileName}: Key '{$key}' not found");
+ return false;
+ }
+
+ $lineStart = $match[0][1];
+ $lineLength = strlen($match[0][0]);
+
+ // Remove the line including the newline
+ $beforeLine = substr($translationsContent, 0, $lineStart);
+ $afterLine = substr($translationsContent, $lineStart + $lineLength);
+
+ // Remove the newline after the key
+ if (substr($afterLine, 0, 1) === "\n") {
+ $afterLine = substr($afterLine, 1);
+ }
+
+ // Check if we need to fix comma on the previous line
+ // If the deleted line had no comma and the previous line exists,
+ // and the next content is not the closing brace, we may need to add a comma
+ $hasComma = preg_match('/,\s*(?:\/\/.*)?$/', $match[0][0]);
+
+ if (!$hasComma && trim($afterLine) !== '' && !preg_match('/^\s*}/', $afterLine)) {
+ // The deleted line didn't have a comma, but there's more content after
+ // We need to ensure the previous line has a comma
+ if (preg_match('/^(.*?)(\s*(?:\/\/.*)?)\s*$/s', rtrim($beforeLine, "\n"), $prevMatch)) {
+ $beforeContent = $prevMatch[1];
+ $trailingComment = $prevMatch[2] ?? '';
+
+ // Check if the last line already has a comma
+ if (!preg_match('/,\s*$/', $beforeContent)) {
+ // Add comma before any trailing comment
+ $beforeLine = rtrim($beforeContent, " \t") . ',' . $trailingComment . "\n";
+ }
+ }
+ }
+
+ $updatedContent = $beforeLine . $afterLine;
+
+ // Rebuild the full content
+ $newContent = substr($content, 0, $exportStart)
+ . $updatedContent
+ . substr($content, $closingBracePos);
+
+ File::put($filePath, $newContent);
+ $this->info(" ✓ {$fileName}");
+
+ return true;
+ }
+
+ private function findClosingBrace(string $content, int $startPos): int|false
+ {
+ $depth = 1;
+ $length = strlen($content);
+
+ for ($i = $startPos; $i < $length; $i++) {
+ if ($content[$i] === '{') {
+ $depth++;
+ } elseif ($content[$i] === '}') {
+ $depth--;
+ if ($depth === 0) {
+ return $i;
+ }
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/src/app/Console/Commands/ImportRootServers.php b/src/app/Console/Commands/ImportRootServers.php
index 322a994b1..5ea4b3889 100644
--- a/src/app/Console/Commands/ImportRootServers.php
+++ b/src/app/Console/Commands/ImportRootServers.php
@@ -19,6 +19,9 @@
use App\Repositories\External\ExternalRootServer;
use App\Repositories\External\ExternalServiceBody;
use App\Repositories\External\InvalidObjectException;
+use App\Repositories\Import\FormatImportResult;
+use App\Repositories\Import\MeetingImportResult;
+use App\Repositories\Import\ServiceBodyImportResult;
use Carbon\Carbon;
use Illuminate\Console\Command;
use Illuminate\Database\Query\Builder;
@@ -27,7 +30,7 @@
class ImportRootServers extends Command
{
- protected $signature = 'aggregator:ImportRootServers {--list-url=https://raw.githubusercontent.com/bmlt-enabled/aggregator/main/rootServerList.json}';
+ protected $signature = 'aggregator:ImportRootServers {--list-url=https://raw.githubusercontent.com/bmlt-enabled/aggregator/main/serverList.json}';
protected $description = 'Import root servers';
@@ -42,7 +45,7 @@ public function handle(
MeetingRepositoryInterface $meetingRepository,
ServiceBodyRepositoryInterface $serviceBodyRepository
) {
- if (!legacy_config('aggregator_mode_enabled')) {
+ if (!file_config('aggregator_mode_enabled')) {
$this->error('aggregator mode is not enabled');
return;
}
@@ -84,21 +87,16 @@ private function importRootServersList(RootServerRepositoryInterface $rootServer
{
try {
$url = $this->option('list-url');
- $response = $this->httpGet($url);
- $externalRootServers = collect($response)
- ->map(function ($rootServer) {
- try {
- return new ExternalRootServer($rootServer);
- } catch (InvalidObjectException) {
- return null;
- }
- })
- ->reject(fn($e) => is_null($e));
- $rootServerRepository->import($externalRootServers);
+ $response = $this->httpGet($url, true);
+ $externalRootServers = collect($response)->map(fn ($rs) => new ExternalRootServer($rs));
+ $result = $rootServerRepository->import($externalRootServers);
} catch (\Exception $e) {
$this->error($e->getMessage());
throw $e;
}
+ $this->info("created $result->numCreated");
+ $this->info("updated $result->numUpdated");
+ $this->info("deleted $result->numDeleted");
}
private function importRootServer(
@@ -110,9 +108,24 @@ private function importRootServer(
): void {
$this->info("importing root server $rootServer->id:$rootServer->url");
$this->importServerInfo($rootServer, $rootServerRepository);
- $this->importServiceBodies($rootServer, $serviceBodyRepository);
- $this->importFormats($rootServer, $formatRepository);
- $this->importMeetings($rootServer, $meetingRepository);
+
+ $serviceBodiesResult = $this->importServiceBodies($rootServer, $serviceBodyRepository);
+ $this->info(" created $serviceBodiesResult->numCreated");
+ $this->info(" updated $serviceBodiesResult->numUpdated");
+ $this->info(" reassigned $serviceBodiesResult->numReassigned");
+ $this->info(" deleted $serviceBodiesResult->numDeleted");
+
+ $formatsResult = $this->importFormats($rootServer, $formatRepository);
+ $this->info(" created $formatsResult->numCreated");
+ $this->info(" updated $formatsResult->numUpdated");
+ $this->info(" deleted $formatsResult->numDeleted");
+
+ $meetingsResult = $this->importMeetings($rootServer, $meetingRepository);
+ $this->info(" created $meetingsResult->numCreated");
+ $this->info(" updated $meetingsResult->numUpdated");
+ $this->info(" deleted $meetingsResult->numDeleted");
+ $this->info(" orphaned and deleted $meetingsResult->numOrphaned");
+
$this->updateStatistics($rootServer);
$rootServerRepository->update($rootServer->id, ['last_successful_import' => Carbon::now()]);
}
@@ -126,7 +139,7 @@ private function importServerInfo(RootServer $rootServer, RootServerRepositoryIn
$rootServer->refresh();
}
- private function importServiceBodies(RootServer $rootServer, ServiceBodyRepositoryInterface $serviceBodyRepository)
+ private function importServiceBodies(RootServer $rootServer, ServiceBodyRepositoryInterface $serviceBodyRepository): ServiceBodyImportResult
{
$this->info('importing service bodies');
$url = rtrim($rootServer->url, '/') . '/client_interface/json/?switcher=GetServiceBodies';
@@ -141,10 +154,10 @@ private function importServiceBodies(RootServer $rootServer, ServiceBodyReposito
}
})
->reject(fn($e) => is_null($e));
- $serviceBodyRepository->import($rootServer->id, $externalServiceBodies);
+ return $serviceBodyRepository->import($rootServer->id, $externalServiceBodies);
}
- private function importFormats(RootServer $rootServer, FormatRepositoryInterface $formatRepository)
+ private function importFormats(RootServer $rootServer, FormatRepositoryInterface $formatRepository): FormatImportResult
{
$this->info('importing formats');
$serverInfo = json_decode($rootServer->server_info);
@@ -153,7 +166,7 @@ private function importFormats(RootServer $rootServer, FormatRepositoryInterface
$url = rtrim($rootServer->url, '/') . '/client_interface/json/?switcher=GetFormats';
$externalFormats = collect([]);
foreach ($languages as $language) {
- $this->info("importing formats:$language");
+ $this->info(" retrieving $language");
$response = $this->httpGet($url . "&lang_enum=$language");
$externalFormats = $externalFormats->concat(
collect($response)
@@ -170,10 +183,10 @@ private function importFormats(RootServer $rootServer, FormatRepositoryInterface
);
}
- $formatRepository->import($rootServer->id, $externalFormats);
+ return $formatRepository->import($rootServer->id, $externalFormats);
}
- private function importMeetings(RootServer $rootServer, MeetingRepositoryInterface $meetingRepository)
+ private function importMeetings(RootServer $rootServer, MeetingRepositoryInterface $meetingRepository): MeetingImportResult
{
$this->info('importing meetings');
$url = rtrim($rootServer->url, '/') . '/client_interface/json/?switcher=GetSearchResults';
@@ -188,7 +201,7 @@ private function importMeetings(RootServer $rootServer, MeetingRepositoryInterfa
}
})
->reject(fn($e) => is_null($e));
- $meetingRepository->import($rootServer->id, $externalMeetings);
+ return $meetingRepository->import($rootServer->id, $externalMeetings);
}
private function updateStatistics(RootServer $rootServer)
@@ -227,7 +240,7 @@ private function getNumGroups(RootServer $rootServer): int
->whereIn('meetingid_bigint', function ($query) use ($serviceBody) {
$query
->select('id_bigint')
- ->from((new Meeting)->getTable())
+ ->from((new Meeting())->getTable())
->where('service_body_bigint', $serviceBody->id_bigint)
->where(function (Builder $query) {
$query
@@ -247,13 +260,13 @@ private function analyzeTables(): void
$this->info('analyzing tables');
$prefix = DB::connection()->getTablePrefix();
$tableNames = [
- $prefix . (new Meeting)->getTable(),
- $prefix . (new MeetingData)->getTable(),
- $prefix . (new MeetingLongData)->getTable(),
- $prefix . (new ServiceBody)->getTable(),
- $prefix . (new Format)->getTable(),
- $prefix . (new RootServer)->getTable(),
- $prefix . (new RootServerStatistics)->getTable(),
+ $prefix . (new Meeting())->getTable(),
+ $prefix . (new MeetingData())->getTable(),
+ $prefix . (new MeetingLongData())->getTable(),
+ $prefix . (new ServiceBody())->getTable(),
+ $prefix . (new Format())->getTable(),
+ $prefix . (new RootServer())->getTable(),
+ $prefix . (new RootServerStatistics())->getTable(),
];
foreach ($tableNames as $tableName) {
$sql = DB::raw("ANALYZE TABLE $tableName;")->getValue(DB::connection()->getQueryGrammar());
@@ -261,13 +274,17 @@ private function analyzeTables(): void
}
}
- private function httpGet(string $url): array
+ private function httpGet(string $url, bool $shouldLogResponse = false): array
{
sleep(self::$requestDelaySeconds);
- $headers = ['User-Agent' => 'Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Firefox/52.0 +aggregator'];
+ $headers = ['User-Agent' => file_config('aggregator_user_agent')];
$response = Http::withHeaders($headers)->retry(3, self::$retryDelaySeconds * 1000)->get($url);
+ if ($shouldLogResponse) {
+ $this->info("response from $url: $response");
+ }
+
if (!$response->ok()) {
throw new \Exception("Got bad status code {$response->status()} from $url");
}
diff --git a/src/app/Console/Commands/InitializeDatabase.php b/src/app/Console/Commands/InitializeDatabase.php
index c53d01e08..1109e7908 100644
--- a/src/app/Console/Commands/InitializeDatabase.php
+++ b/src/app/Console/Commands/InitializeDatabase.php
@@ -14,7 +14,7 @@ class InitializeDatabase extends Command
public function handle()
{
- if (!legacy_config('aggregator_mode_enabled')) {
+ if (!file_config('aggregator_mode_enabled')) {
$this->error('aggregator mode is not enabled');
return;
}
diff --git a/src/app/Console/Commands/PrimeDatabaseFromLegacyTomato.php b/src/app/Console/Commands/PrimeDatabaseFromLegacyTomato.php
index 338ffcd68..4c61d7cdf 100644
--- a/src/app/Console/Commands/PrimeDatabaseFromLegacyTomato.php
+++ b/src/app/Console/Commands/PrimeDatabaseFromLegacyTomato.php
@@ -26,7 +26,7 @@ class PrimeDatabaseFromLegacyTomato extends Command
public function handle(RootServerRepository $rootServerRepository)
{
- if (!legacy_config('aggregator_mode_enabled')) {
+ if (!file_config('aggregator_mode_enabled')) {
$this->error('aggregator mode is not enabled');
return;
}
@@ -68,7 +68,7 @@ private function importRootServers(RootServerRepositoryInterface $rootServerRepo
->map(fn ($o) => [
'id' => $o['source_id'],
'name' => $o['name'],
- 'rootURL' => rtrim($o['root_server_url']) . '/',
+ 'url' => rtrim($o['root_server_url']) . '/',
])
->map(function ($rootServer) {
try {
@@ -172,11 +172,11 @@ private function analyzeTables(): void
$this->info('analyzing tables');
$prefix = DB::connection()->getTablePrefix();
$tableNames = [
- $prefix . (new Meeting)->getTable(),
- $prefix . (new MeetingData)->getTable(),
- $prefix . (new MeetingLongData)->getTable(),
- $prefix . (new ServiceBody)->getTable(),
- $prefix . (new Format)->getTable(),
+ $prefix . (new Meeting())->getTable(),
+ $prefix . (new MeetingData())->getTable(),
+ $prefix . (new MeetingLongData())->getTable(),
+ $prefix . (new ServiceBody())->getTable(),
+ $prefix . (new Format())->getTable(),
];
foreach ($tableNames as $tableName) {
DB::statement("ANALYZE TABLE $tableName;");
diff --git a/src/app/Console/Commands/UpdateTranslationsFromSpreadsheet.php b/src/app/Console/Commands/UpdateTranslationsFromSpreadsheet.php
new file mode 100644
index 000000000..d2c2b2ab4
--- /dev/null
+++ b/src/app/Console/Commands/UpdateTranslationsFromSpreadsheet.php
@@ -0,0 +1,160 @@
+argument('spreadsheet');
+ $languageCode = $this->argument('language');
+
+ if ($languageCode === 'en') {
+ $this->error("Cannot update English translations from spreadsheet.");
+ $this->info("English translations should be updated directly in the source file or using 'translation:add' command.");
+ return 1;
+ }
+
+ if (!file_exists($spreadsheetPath)) {
+ $this->error("Spreadsheet file not found: {$spreadsheetPath}");
+ return 1;
+ }
+
+ $langPath = resource_path("js/lang/{$languageCode}.ts");
+ if (!File::exists($langPath)) {
+ $this->error("Translation file not found: {$langPath}");
+ $this->info("Available languages: " . implode(', ', $this->getAvailableLanguages()));
+ return 1;
+ }
+
+ try {
+ $this->info("Reading spreadsheet: {$spreadsheetPath}");
+ $translations = $this->parseSpreadsheet($spreadsheetPath);
+
+ if (empty($translations)) {
+ $this->error("No translations found in spreadsheet");
+ return 1;
+ }
+
+ $this->info("Found " . count($translations) . " translations in spreadsheet");
+
+ $backupFile = "{$langPath}.backup." . time();
+ File::copy($langPath, $backupFile);
+ $this->info("Created backup: {$backupFile}");
+
+ $this->info("Updating {$languageCode}.ts...");
+ $result = $this->updateTranslationFile($langPath, $translations);
+
+ $this->info("\n📊 Translation summary:");
+ $this->info(" • Keys found in spreadsheet: " . count($translations));
+ $this->info(" • Updated existing keys: {$result['updated']}");
+ $this->info(" • Keys not found in file: {$result['notFound']}");
+
+ if ($result['notFound'] > 0) {
+ $this->warn("\nKeys not found in {$languageCode}.ts:");
+ foreach ($result['notFoundKeys'] as $key) {
+ $this->warn(" • {$key}");
+ }
+ $this->warn("\nUse 'translation:add' command to add new keys first");
+ }
+
+ $this->info("\n✅ Translation file updated successfully!");
+ $this->info("📁 Backup created at: {$backupFile}");
+
+ return 0;
+ } catch (\Exception $e) {
+ $this->error("Error: " . $e->getMessage());
+ return 1;
+ }
+ }
+
+ private function parseSpreadsheet(string $filePath): array
+ {
+ $spreadsheet = IOFactory::load($filePath);
+ $sheet = $spreadsheet->getActiveSheet();
+ $highestRow = $sheet->getHighestRow();
+
+ $translations = [];
+
+ // Start from row 2 (skip header: Key, English, Target Language)
+ for ($row = 2; $row <= $highestRow; $row++) {
+ $key = trim((string) $sheet->getCell("A{$row}")->getValue());
+ // Column C contains the target language translation
+ $value = trim((string) $sheet->getCell("C{$row}")->getValue());
+
+ if ($key && $value) {
+ $translations[$key] = $value;
+ }
+ }
+
+ return $translations;
+ }
+
+ private function updateTranslationFile(string $filePath, array $newTranslations): array
+ {
+ $content = File::get($filePath);
+ $updated = 0;
+ $notFound = 0;
+ $notFoundKeys = [];
+
+ foreach ($newTranslations as $key => $newValue) {
+ // Escape the new value for single quotes
+ $escapedValue = str_replace(['\\', "'"], ['\\\\', "\\'"], $newValue);
+
+ // Match the key with its current value (both single and double quotes)
+ $pattern = '/^(\s*)' . preg_quote($key, '/') . ':\s*([\'"])(.*)\\2(,?)(.*?)$/m';
+
+ if (preg_match($pattern, $content, $match)) {
+ $indent = $match[1];
+ $comma = $match[4];
+ $restOfLine = $match[5]; // This captures comments like // TODO: translate
+
+ // Build the replacement line with single quotes
+ $replacement = "{$indent}{$key}: '{$escapedValue}'{$comma}{$restOfLine}";
+
+ $content = preg_replace($pattern, $replacement, $content, 1);
+ $updated++;
+ } else {
+ $notFound++;
+ $notFoundKeys[] = $key;
+ }
+ }
+
+ File::put($filePath, $content);
+
+ return [
+ 'updated' => $updated,
+ 'notFound' => $notFound,
+ 'notFoundKeys' => $notFoundKeys,
+ ];
+ }
+
+ private function getAvailableLanguages(): array
+ {
+ $langPath = resource_path('js/lang');
+ $files = File::glob($langPath . '/*.ts');
+
+ return array_map(function ($file) {
+ $basename = basename($file, '.ts');
+ return $basename !== 'index' ? $basename : null;
+ }, array_filter($files, fn($file) => basename($file) !== 'index.ts'));
+ }
+}
diff --git a/src/app/Console/Kernel.php b/src/app/Console/Kernel.php
index e06a58fc9..30b73104c 100644
--- a/src/app/Console/Kernel.php
+++ b/src/app/Console/Kernel.php
@@ -29,7 +29,7 @@ protected function schedule(Schedule $schedule)
*/
protected function commands()
{
- $this->load(__DIR__.'/Commands');
+ $this->load(__DIR__ . '/Commands');
// require base_path('routes/console.php');
}
diff --git a/src/app/FromDatabaseConfig.php b/src/app/FromDatabaseConfig.php
new file mode 100644
index 000000000..02328a91c
--- /dev/null
+++ b/src/app/FromDatabaseConfig.php
@@ -0,0 +1,66 @@
+get($name);
+ }
+
+ public static function get(string $name = null, $default = null)
+ {
+ if (!static::$configLoaded) {
+ static::loadConfig();
+ }
+
+ if (is_null($name)) {
+ return static::$config;
+ }
+
+ return static::$config[$name] ?? $default;
+ }
+
+ public static function set(string $name, $value)
+ {
+ // should only be used in testing
+ $repository = app(SettingRepository::class);
+ $repository->update($name, $value);
+ $setting = $repository->getByName($name);
+ static::$config[$name] = $setting->value;
+ }
+
+ public static function reset(): void
+ {
+ // should only be used in testing
+ static::$config = null;
+ static::$settingTypes = null;
+ static::$configLoaded = false;
+ }
+
+ private static function loadConfig(): void
+ {
+ static::$configLoaded = true; // we set this first thing to prevent infinite looping when calling into fromEnv
+ $repository = app(SettingRepository::class);
+ $settings = $repository->getAll();
+ static::$settingTypes = $settings->mapWithKeys(fn ($s) => [$s->name => $s->type]);
+ static::$config = $settings
+ ->mapWithKeys(function ($setting) {
+ $value = static::fromEnv($setting->name) ?? $setting->value;
+ return [$setting->name => $value];
+ })
+ ->toArray();
+ }
+}
diff --git a/src/app/FromFileConfig.php b/src/app/FromFileConfig.php
new file mode 100644
index 000000000..13fbe1791
--- /dev/null
+++ b/src/app/FromFileConfig.php
@@ -0,0 +1,82 @@
+ Setting::TYPE_STRING,
+ 'db_username' => Setting::TYPE_STRING,
+ 'db_password' => Setting::TYPE_STRING,
+ 'db_host' => Setting::TYPE_STRING,
+ 'db_prefix' => Setting::TYPE_STRING,
+ 'aggregator_mode_enabled' => Setting::TYPE_BOOL,
+ 'aggregator_max_geo_width_km' => Setting::TYPE_FLOAT,
+ 'aggregator_user_agent' => Setting::TYPE_STRING,
+ ];
+ return $types[$name];
+ }
+
+ public static function get(?string $name = null, $default = null)
+ {
+ if (!static::$configLoaded) {
+ self::loadConfig();
+ }
+
+ if (is_null(static::$config)) {
+ return null;
+ }
+
+ if (is_null($name)) {
+ return static::$config;
+ }
+
+ return static::$config[$name] ?? $default;
+ }
+
+ public static function set(string $name, $value)
+ {
+ // should only be used in testing
+ if (!static::$configLoaded) {
+ static::loadConfig();
+ }
+
+ static::$config[$name] = $value;
+ }
+
+ public static function reset(): void
+ {
+ // should only be used in testing
+ static::$config = null;
+ static::$configLoaded = false;
+ }
+
+ private static function loadConfig(): void
+ {
+ $configFile = base_path() . '/../auto-config.inc.php';
+ if (file_exists($configFile)) {
+ defined('BMLT_EXEC') or define('BMLT_EXEC', 1);
+ require($configFile);
+ }
+
+ static::$config = [
+ 'db_database' => static::fromEnv('db_database') ?? $dbName ?? null,
+ 'db_username' => static::fromEnv('db_username') ?? $dbUser ?? null,
+ 'db_password' => static::fromEnv('db_password') ?? $dbPassword ?? null,
+ 'db_host' => static::fromEnv('db_host') ?? $dbServer ?? null,
+ 'db_prefix' => static::fromEnv('db_prefix') ?? $dbPrefix ?? null,
+ 'aggregator_mode_enabled' => static::fromEnv('aggregator_mode_enabled') ?? $aggregator_mode_enabled ?? false,
+ 'aggregator_max_geo_width_km' => static::fromEnv('aggregator_max_geo_width_km') ?? $aggregator_max_geo_width_km ?? null,
+ 'aggregator_user_agent' => static::fromEnv('aggregator_user_agent') ?? $aggregator_user_agent ?? 'Mozilla/5.0 (X11; Linux x86_64; rv:146.0) Gecko/20100101 Firefox/146.0 +aggregator',
+ ];
+
+ static::$configLoaded = true;
+ }
+}
diff --git a/src/app/Http/Controllers/Admin/FormatController.php b/src/app/Http/Controllers/Admin/FormatController.php
index 224276e80..24f9f9869 100644
--- a/src/app/Http/Controllers/Admin/FormatController.php
+++ b/src/app/Http/Controllers/Admin/FormatController.php
@@ -7,6 +7,8 @@
use App\Interfaces\FormatRepositoryInterface;
use App\Models\Format;
use App\Models\FormatType;
+use App\Rules\FormatTranslationKey;
+use App\Rules\FormatTranslations;
use Illuminate\Http\Request;
use Illuminate\Support\Collection;
use Illuminate\Validation\Rule;
@@ -21,20 +23,17 @@ public function __construct(FormatRepositoryInterface $formatRepository)
$this->authorizeResource(Format::class);
}
-
public function index(Request $request)
{
$formats = $this->formatRepository->getAsTranslations();
return FormatResource::collection($formats);
}
-
public function show(Format $format)
{
return new FormatResource($format);
}
-
public function store(Request $request)
{
$validated = $this->validateInputs($request);
@@ -45,7 +44,7 @@ public function store(Request $request)
public function update(Request $request, Format $format)
{
- $validated = $this->validateInputs($request);
+ $validated = $this->validateInputs($request, $format->shared_id_bigint);
$sharedFormatsValues = $this->buildValuesArray($validated);
$this->formatRepository->update($format->shared_id_bigint, $sharedFormatsValues);
return response()->noContent();
@@ -59,7 +58,7 @@ public function partialUpdate(Request $request, Format $format)
if ($fieldName == 'worldId') {
return [$fieldName => $request->has($fieldName) ? $request->input($fieldName) : $format->worldid_mixed];
} elseif ($fieldName == 'type') {
- return [$fieldName => $request->has($fieldName) ? $request->input($fieldName) : (!is_null($format->format_type_enum) ? FormatType::getApiEnumFromKey($format->format_type_enum): null)];
+ return [$fieldName => $request->has($fieldName) ? $request->input($fieldName) : (!is_null($format->format_type_enum) ? FormatType::getApiEnumFromKey($format->format_type_enum) : null)];
} else {
return [$fieldName => $request->has($fieldName) ? $request->input($fieldName) : $format->translations->map(function ($translation) {
return [
@@ -74,13 +73,12 @@ public function partialUpdate(Request $request, Format $format)
->toArray()
);
- $validated = $this->validateInputs($request);
+ $validated = $this->validateInputs($request, $format->shared_id_bigint);
$sharedFormatsValues = $this->buildValuesArray($validated);
$this->formatRepository->update($format->shared_id_bigint, $sharedFormatsValues);
return response()->noContent();
}
-
public function destroy(Request $request, Format $format)
{
$request->merge(['id' => $format->shared_id_bigint]);
@@ -100,7 +98,7 @@ public function destroy(Request $request, Format $format)
return response()->noContent();
}
- private function validateInputs(Request $request)
+ private function validateInputs(Request $request, int $formatId = null): Collection
{
return collect($request->validate([
'worldId' => 'nullable|string|max:30',
@@ -114,9 +112,10 @@ function ($attribute, $value, $fail) {
$fail(':attribute may have only one translation per language.');
}
}
- }
+ },
+ new FormatTranslations($this->formatRepository, $formatId)
],
- 'translations.*.key' => ['required', 'string', 'max:10', Rule::notIn(['VM', 'HY', 'TC'])],
+ 'translations.*.key' => ['required', 'string', 'max:10', new FormatTranslationKey($this->formatRepository, $formatId)],
'translations.*.name' => 'required|string|max:255',
'translations.*.description' => 'required|string|max:255',
'translations.*.language' => 'required|string|max:7',
diff --git a/src/app/Http/Controllers/Admin/MeetingController.php b/src/app/Http/Controllers/Admin/MeetingController.php
index abbfaf273..e09c9c0bf 100644
--- a/src/app/Http/Controllers/Admin/MeetingController.php
+++ b/src/app/Http/Controllers/Admin/MeetingController.php
@@ -59,12 +59,20 @@ public function index(Request $request)
return MeetingResource::collection($meetings);
}
-
+ public function searchTranslations(Request $request)
+ {
+ $this->meetingRepository->setTargetLanguage($request->lang);
+ return $this->index($request);
+ }
public function show(Meeting $meeting)
{
return new MeetingResource($meeting);
}
-
+ public function getTranslation(Request $request, Meeting $meeting)
+ {
+ $this->meetingRepository->setTargetLanguage($request->lang);
+ return new MeetingResource($meeting);
+ }
public function store(Request $request)
{
$validated = $this->validateInputs($request);
@@ -80,7 +88,23 @@ public function update(Request $request, Meeting $meeting)
$this->meetingRepository->update($meeting->id_bigint, $values);
return response()->noContent();
}
-
+ public function translate(Request $request, Meeting $meeting)
+ {
+ $this->meetingRepository->setTargetLanguage($request->lang);
+ $validated = $this->validateTranslationInputs($request);
+ if (isset($validated['customFields'])) {
+ foreach ($validated['customFields'] as $key => $value) {
+ $validated[$key] = $value;
+ }
+ unset($validated['customFields']);
+ }
+ if (isset($validated['name'])) {
+ $validated['meeting_name'] = $validated['name'];
+ unset($validated['name']);
+ }
+ $this->meetingRepository->translate($meeting->id_bigint, $validated);
+ return response()->noContent();
+ }
public function partialUpdate(Request $request, Meeting $meeting)
{
$meetingData = $meeting->data
@@ -169,7 +193,12 @@ private function getCustomFields(): Collection
}
return $customFields;
}
-
+ private function validateTranslationInputs(Request $request)
+ {
+ return $request->validate(
+ array_merge(['name' => 'nullable|string|max:128'], $this->getDataFieldValidators(true))
+ );
+ }
private function validateInputs(Request $request, $skipVenueTypeLocationValidation = false)
{
return collect($request->validate(
@@ -188,7 +217,7 @@ private function validateInputs(Request $request, $skipVenueTypeLocationValidati
'email' => 'nullable|email|max:255',
'worldId' => 'nullable|string|max:30',
'name' => 'required|string|max:128',
- 'timeZone' => ['nullable', 'string', 'max:40', new IANATimeZone],
+ 'timeZone' => ['nullable', 'string', 'max:40', new IANATimeZone()],
], $this->getDataFieldValidators($skipVenueTypeLocationValidation))
));
}
@@ -200,7 +229,7 @@ private function getDataFieldValidators($skipVenueTypeLocationValidation = false
->reject(fn ($_, $fieldName) => $fieldName == 'meeting_name' || $customFields->contains($fieldName))
->mapWithKeys(function ($_, $fieldName) use ($skipVenueTypeLocationValidation) {
if (!$skipVenueTypeLocationValidation && in_array($fieldName, VenueTypeLocation::FIELDS)) {
- return [$fieldName => ['max:512', new VenueTypeLocation]];
+ return [$fieldName => ['max:512', new VenueTypeLocation()]];
} else {
return [$fieldName => 'nullable|string|max:512'];
}
diff --git a/src/app/Http/Controllers/Admin/RootServerController.php b/src/app/Http/Controllers/Admin/RootServerController.php
index 2084dccbe..a804a8048 100644
--- a/src/app/Http/Controllers/Admin/RootServerController.php
+++ b/src/app/Http/Controllers/Admin/RootServerController.php
@@ -19,7 +19,7 @@ public function __construct(RootServerRepositoryInterface $rootServerRepository)
public function index(Request $request)
{
- if (!legacy_config('aggregator_mode_enabled')) {
+ if (!file_config('aggregator_mode_enabled')) {
return new JsonResponse(['message' => 'Endpoint is unavailable when aggregator mode is disabled.'], 404);
}
@@ -29,7 +29,7 @@ public function index(Request $request)
public function show(RootServer $rootServer)
{
- if (!legacy_config('aggregator_mode_enabled')) {
+ if (!file_config('aggregator_mode_enabled')) {
return new JsonResponse(['message' => 'Endpoint is unavailable when aggregator mode is disabled.'], 404);
}
diff --git a/src/app/Http/Controllers/Admin/SettingController.php b/src/app/Http/Controllers/Admin/SettingController.php
new file mode 100644
index 000000000..f9552662b
--- /dev/null
+++ b/src/app/Http/Controllers/Admin/SettingController.php
@@ -0,0 +1,52 @@
+settingRepository = $settingRepository;
+ }
+
+ public function index(Request $request)
+ {
+ $this->authorize('viewAny', Setting::class);
+
+ $settings = $this->settingRepository->getAll()->map(function ($setting) {
+ $setting->value = FromDatabaseConfig::fromEnv($setting->name) ?? $setting->value;
+ return $setting;
+ });
+ return response()->json(SettingResource::collection($settings));
+ }
+
+ public function update(Request $request)
+ {
+ $this->authorize('update', Setting::class);
+ $settingTypes = $this->settingRepository->getAll()->mapWithKeys(fn ($s) => [$s->name => $s->type]);
+ $rules = array_merge(
+ ['*' => Rule::in($settingTypes->keys())],
+ $settingTypes->mapWithKeys(function ($type, $name) {
+ return [$name => match ($type) {
+ Setting::TYPE_STRING => 'nullable|string|max:65535',
+ Setting::TYPE_INT => 'nullable|integer',
+ Setting::TYPE_FLOAT => 'nullable|numeric',
+ Setting::TYPE_BOOL => 'nullable|boolean',
+ Setting::TYPE_ARRAY => 'nullable|array',
+ }];
+ })->toArray()
+ );
+ $validated = $request->validate($rules);
+ $this->settingRepository->updateMultiple($validated);
+ return response()->noContent();
+ }
+}
diff --git a/src/app/Http/Controllers/Admin/Swagger/FormatController.php b/src/app/Http/Controllers/Admin/Swagger/FormatController.php
index a1479cb00..ae0857fe1 100644
--- a/src/app/Http/Controllers/Admin/Swagger/FormatController.php
+++ b/src/app/Http/Controllers/Admin/Swagger/FormatController.php
@@ -35,7 +35,6 @@
*/
class FormatController extends Controller
{
-
/**
* @OA\Get(path="/api/v1/formats", summary="Retrieves formats", description="Retrieve formats", operationId="getFormats", tags={"rootServer"}, security={{"bmltToken":{}}},
* @OA\Response(response=200, description="Returns when user is authenticated.",
diff --git a/src/app/Http/Controllers/Admin/Swagger/MeetingController.php b/src/app/Http/Controllers/Admin/Swagger/MeetingController.php
index 73b7ecd09..86f2726e8 100644
--- a/src/app/Http/Controllers/Admin/Swagger/MeetingController.php
+++ b/src/app/Http/Controllers/Admin/Swagger/MeetingController.php
@@ -67,7 +67,6 @@
class MeetingController extends Controller
{
-
/**
* @OA\Get(path="/api/v1/meetings", summary="Retrieves meetings", description="Retrieve meetings for authenticated user.", operationId="getMeetings", tags={"rootServer"}, security={{"bmltToken":{}}},
* @OA\Parameter(description="comma delimited meeting ids", in="query", name="meetingIds", required=false, example="1,2",
@@ -96,7 +95,37 @@ class MeetingController extends Controller
public function index()
{
}
-
+ /**
+ * @OA\Get(path="/api/v1/translations/meetings/{lang}", summary="Retrieves meetings with translated values", description="Retrieve meetings for authenticated user.", operationId="getTranslatedMeetings", tags={"rootServer"}, security={{"bmltToken":{}}},
+ * @OA\Parameter(description="language", in="path", name="lang", required=true, example="en",
+ * @OA\Schema(type="string")
+ * ),
+ * @OA\Parameter(description="comma delimited meeting ids", in="query", name="meetingIds", required=false, example="1,2",
+ * @OA\Schema(type="string")
+ * ),
+ * @OA\Parameter(description="comma delimited day ids between 0-6", in="query", name="days", required=false, example="0,1",
+ * @OA\Schema(type="string")
+ * ),
+ * @OA\Parameter(description="comma delimited service body ids", in="query", name="serviceBodyIds", required=false, example="3,4",
+ * @OA\Schema(type="string")
+ * ),
+ * @OA\Parameter(description="string", in="query", name="searchString", required=false, example="Just for Today",
+ * @OA\Schema(type="string")
+ * ),
+ * @OA\Response(response=200, description="List of meetings.",
+ * @OA\JsonContent(ref="#/components/schemas/MeetingCollection")
+ * ),
+ * @OA\Response(response=401, description="Returns when user is not authenticated.",
+ * @OA\JsonContent(ref="#/components/schemas/AuthenticationError")
+ * ),
+ * @OA\Response(response=422, description="Validation error.",
+ * @OA\JsonContent(ref="#/components/schemas/ValidationError")
+ * ),
+ * )
+ */
+ public function translateIndex()
+ {
+ }
/**
* @OA\Get(path="/api/v1/meetings/{meetingId}", summary="Retrieves a meeting", description="Retrieve a meeting.", operationId="getMeeting", tags={"rootServer"}, security={{"bmltToken":{}}},
* @OA\Parameter(description="ID of meeting", in="path", name="meetingId", required=true, example="1",
@@ -116,7 +145,28 @@ public function index()
public function show()
{
}
-
+ /**
+ * @OA\Get(path="/api/v1/translations/meetings/{meetingId}/{lang}", summary="Retrieves a meeting translation", description="Retrieve a meeting.", operationId="getMeetingTranslation", tags={"rootServer"}, security={{"bmltToken":{}}},
+ * @OA\Parameter(description="language", in="path", name="lang", required=true, example="en",
+ * @OA\Schema(type="string")
+ * ),
+ * @OA\Parameter(description="ID of meeting", in="path", name="meetingId", required=true, example="1",
+ * @OA\Schema(type="integer",format="int64")
+ * ),
+ * @OA\Response(response=200, description="Returns when user is authenticated.",
+ * @OA\JsonContent(ref="#/components/schemas/Meeting")
+ * ),
+ * @OA\Response(response=401, description="Returns when user is not authenticated.",
+ * @OA\JsonContent(ref="#/components/schemas/AuthenticationError")
+ * ),
+ * @OA\Response(response=404, description="Returns when no meeting exists.",
+ * @OA\JsonContent(ref="#/components/schemas/NotFoundError")
+ * ),
+ * )
+ */
+ public function showTranslation()
+ {
+ }
/**
* @OA\Post(path="/api/v1/meetings", summary="Creates a meeting", description="Creates a meeting.", operationId="createMeeting", tags={"rootServer"}, security={{"bmltToken":{}}},
* @OA\RequestBody(required=true, description="Pass in meeting object",
@@ -199,6 +249,34 @@ public function update()
public function partialUpdate()
{
}
+ /** @OA\Patch(path="/api/v1/translations/meetings/{meetingId}/{lang}", summary="Translates the a meeting data", description="Provide tranlations for a meeting by id", operationId="translateMeeting", tags={"rootServer"}, security={{"bmltToken":{}}},
+ * @OA\Parameter(description="language", in="path", name="lang", required=true, example="en",
+ * @OA\Schema(type="string")
+ * ),
+ * @OA\Parameter(description="ID of meeting", in="path", name="meetingId", required=true, example="1",
+ * @OA\Schema(type="integer", format="int64")
+ * ),
+ * @OA\RequestBody(required=true, description="Pass in fields you want to update.",
+ * @OA\JsonContent(ref="#/components/schemas/MeetingPartialUpdate"),
+ * ),
+ * @OA\Response(response=204, description="Success."),
+ * @OA\Response(response=401, description="Returns when user is not authenticated.",
+ * @OA\JsonContent(ref="#/components/schemas/AuthenticationError")
+ * ),
+ * @OA\Response(response=403, description="Returns when user is unauthorized to perform action.",
+ * @OA\JsonContent(ref="#/components/schemas/AuthorizationError")
+ * ),
+ * @OA\Response(response=404, description="Returns when no meeting exists.",
+ * @OA\JsonContent(ref="#/components/schemas/NotFoundError")
+ * ),
+ * @OA\Response(response=422, description="Validation error.",
+ * @OA\JsonContent(ref="#/components/schemas/ValidationError")
+ * ),
+ * )
+ */
+ public function translate()
+ {
+ }
/**
* @OA\Delete(path="/api/v1/meetings/{meetingId}", summary="Deletes a meeting", description="Deletes a meeting by id.", operationId="deleteMeeting", tags={"rootServer"}, security={{"bmltToken":{}}},
diff --git a/src/app/Http/Controllers/Admin/Swagger/RootServerController.php b/src/app/Http/Controllers/Admin/Swagger/RootServerController.php
index d131d2859..e576899b2 100644
--- a/src/app/Http/Controllers/Admin/Swagger/RootServerController.php
+++ b/src/app/Http/Controllers/Admin/Swagger/RootServerController.php
@@ -35,7 +35,6 @@
*/
class RootServerController extends Controller
{
-
/**
* @OA\Get(path="/api/v1/rootservers", summary="Retrieves root servers", description="Retrieve root servers.", operationId="getRootServers", tags={"rootServer"},
* @OA\Response(response=200, description="Successful response.",
diff --git a/src/app/Http/Controllers/Admin/Swagger/ServiceBodyController.php b/src/app/Http/Controllers/Admin/Swagger/ServiceBodyController.php
index 499ca709b..d19e44c02 100644
--- a/src/app/Http/Controllers/Admin/Swagger/ServiceBodyController.php
+++ b/src/app/Http/Controllers/Admin/Swagger/ServiceBodyController.php
@@ -36,7 +36,6 @@
*/
class ServiceBodyController extends Controller
{
-
/**
* @OA\Get(path="/api/v1/servicebodies", summary="Retrieves service bodies", description="Retrieve service bodies for authenticated user.", operationId="getServiceBodies", tags={"rootServer"}, security={{"bmltToken":{}}},
* @OA\Response(response=200, description="Returns when user is authenticated.",
diff --git a/src/app/Http/Controllers/Admin/Swagger/SettingController.php b/src/app/Http/Controllers/Admin/Swagger/SettingController.php
new file mode 100644
index 000000000..426085429
--- /dev/null
+++ b/src/app/Http/Controllers/Admin/Swagger/SettingController.php
@@ -0,0 +1,99 @@
+url = rtrim(url('/'), '/') . '/';
$server->description = 'this server';
diff --git a/src/app/Http/Controllers/Admin/TokenController.php b/src/app/Http/Controllers/Admin/TokenController.php
index d08eb77d0..b5db0064c 100644
--- a/src/app/Http/Controllers/Admin/TokenController.php
+++ b/src/app/Http/Controllers/Admin/TokenController.php
@@ -75,8 +75,13 @@ private function createToken(User $user)
$expiresAt = 60 * config('sanctum.expiration', 0);
$expiresAt += time();
+ $token = $user->createToken(Str::random(20));
+
+ $user->last_access_datetime = $token->accessToken->created_at;
+ $user->save();
+
return [
- 'access_token' => $user->createToken(Str::random(20))->plainTextToken,
+ 'access_token' => $token->plainTextToken,
'expires_at' => $expiresAt,
'token_type' => 'bearer',
'user_id' => $user->id_bigint,
diff --git a/src/app/Http/Controllers/Admin/UserController.php b/src/app/Http/Controllers/Admin/UserController.php
index 3cbebf14b..9fe684029 100644
--- a/src/app/Http/Controllers/Admin/UserController.php
+++ b/src/app/Http/Controllers/Admin/UserController.php
@@ -56,6 +56,7 @@ public function store(Request $request)
'displayName' => 'required|string|max:255',
'description' => 'nullable|string|max:1024',
'email' => 'nullable|email',
+ 'targetLanguage' => 'required_if:type,' . User::USER_TYPE_TRANSLATOR . '|string|max:10',
'ownerId' => 'nullable|present|int|exists:comdef_users,id_bigint',
]);
@@ -72,6 +73,7 @@ public function store(Request $request)
'description_string' => $validated['description'] ?? '',
'email_address_string' => $validated['email'] ?? '',
'owner_id_bigint' => $validated['ownerId'] ?? -1,
+ 'target_language' => $validated['targetLanguage'] ?? '',
]);
return new UserResource($user);
}
@@ -97,6 +99,8 @@ public function partialUpdate(Request $request, User $user)
return ['displayName' => $request->has('displayName') ? $request->input('displayName') : $user->name_string];
} elseif ($fieldName == 'description_string') {
return ['description' => $request->has('description') ? $request->input('description') : $user->description_string];
+ } elseif ($fieldName == 'target_language') {
+ return ['description' => $request->has('targetLanguage') ? $request->input('targetLanguage') : $user->target_language];
} elseif ($fieldName == 'email_address_string') {
return ['email' => $request->has('email') ? $request->input('email') : $user->email_address_string];
} elseif ($fieldName == 'password_string') {
@@ -137,6 +141,7 @@ private function validateForUpdate(Request $request, User $user): Collection
'description' => 'nullable|string|max:1024',
'email' => 'nullable|email',
'ownerId' => 'nullable|present|int|exists:comdef_users,id_bigint',
+ 'targetLanguage' => 'required_if:type,' . User::USER_TYPE_TRANSLATOR . '|string|max:10',
]));
$ownerId = $validated->get('ownerId');
@@ -174,6 +179,8 @@ private function buildValuesArrayForUpdate(Request $request, User $user, Collect
return [$fieldName => $validated['description'] ?? ''];
} elseif ($fieldName == 'email_address_string') {
return [$fieldName => $validated['email'] ?? ''];
+ } elseif ($fieldName == 'target_language') {
+ return [$fieldName => $validated['targetLanguage'] ?? ''];
} else {
return [null => null];
}
diff --git a/src/app/Http/Controllers/CatchAllController.php b/src/app/Http/Controllers/CatchAllController.php
deleted file mode 100644
index 79e9f5c7c..000000000
--- a/src/app/Http/Controllers/CatchAllController.php
+++ /dev/null
@@ -1,116 +0,0 @@
-path)) {
- return self::legacyResponse($pathInfo);
- }
- return response('"the aggregator formerly known as tomato"');
- }
-
- if (legacy_config('new_ui_enabled')) {
- if (self::isAllowedLegacyPath($pathInfo) && file_exists($pathInfo->path)) {
- return self::legacyResponse($pathInfo);
- }
-
- return response()->view('frontend', [
- 'autoGeocodingEnabled' => legacy_config('auto_geocoding_enabled'),
- 'baseUrl' => $request->getBaseurl(),
- 'bmltTitle' => legacy_config('bmlt_title'),
- 'bmltNotice' => legacy_config('bmlt_notice'),
- 'centerLongitude' => legacy_config('search_spec_map_center_longitude'),
- 'centerLatitude' => legacy_config('search_spec_map_center_latitude'),
- 'centerZoom' => legacy_config('search_spec_map_center_zoom'),
- 'countyAutoGeocodingEnabled' => legacy_config('county_auto_geocoding_enabled'),
- 'customFields' => self::getCustomFields(),
- 'defaultClosedStatus' => legacy_config('default_closed_status'),
- 'defaultDuration' => legacy_config('default_duration_time'),
- 'defaultLanguage' => legacy_config('language'),
- 'distanceUnits' => legacy_config('distance_units'),
- 'googleApiKey' => legacy_config('google_api_key', ''),
- 'isLanguageSelectorEnabled' => legacy_config('enable_language_selector'),
- 'languageMapping' => self::getLanguageMapping(),
- 'meetingStatesAndProvinces' => implode(',', legacy_config('meeting_states_and_provinces', [])),
- 'meetingCountiesAndSubProvinces' => implode(',', legacy_config('meeting_counties_and_sub_provinces', [])),
- 'regionBias' => legacy_config('region_bias'),
- 'version' => config('app.version'),
- 'zipAutoGeocodingEnabled' => legacy_config('zip_auto_geocoding_enabled'),
- ]);
- }
-
- if (file_exists($pathInfo->path)) {
- return self::legacyResponse($pathInfo);
- }
-
- abort(404);
- }
-
- private static function getLanguageMapping(): array
- {
- return collect(scandir(base_path('lang')))
- ->reject(fn ($dir) => str_starts_with($dir, '.'))
- ->sort()
- ->mapWithKeys(function ($langAbbreviation, $_) {
- $langName = $langAbbreviation == 'dk' ? 'da' : $langAbbreviation;
- $langName = \Locale::getDisplayLanguage($langName, $langName);
- $langName = mb_str_split($langName);
- $langName = mb_strtoupper($langName[0]) . implode('', array_slice($langName, 1));
- return [$langAbbreviation => $langName];
- })
- ->toArray();
- }
-
- private static function getCustomFields(): Collection
- {
- $meetingRepository = resolve(MeetingRepositoryInterface::class);
- $customFields = $meetingRepository->getCustomFields();
- return $meetingRepository->getDataTemplates()
- ->reject(fn ($t) => !$customFields->contains($t->key))
- ->map(fn ($t) => [
- 'name' => $t->key,
- 'displayName' => $t->field_prompt,
- 'language' => $t->lang_enum
- ])
- ->values();
- }
-
- private static function isAllowedLegacyPath(LegacyPathInfo $pathInfo): bool
- {
- foreach (self::$allowedLegacyPathEndings as $allowedPathEnding) {
- if (str_ends_with($pathInfo->path, $allowedPathEnding)) {
- return true;
- }
- }
-
- return false;
- }
-
- private static function legacyResponse(LegacyPathInfo $pathInfo): Response
- {
- return response()
- ->view('legacy', ['includePath' => $pathInfo->path])
- ->header('Content-Type', $pathInfo->contentType);
- }
-}
diff --git a/src/app/Http/Controllers/Controller.php b/src/app/Http/Controllers/Controller.php
index a0a2a8a34..ce1176ddb 100644
--- a/src/app/Http/Controllers/Controller.php
+++ b/src/app/Http/Controllers/Controller.php
@@ -9,5 +9,7 @@
class Controller extends BaseController
{
- use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
+ use AuthorizesRequests;
+ use DispatchesJobs;
+ use ValidatesRequests;
}
diff --git a/src/app/Http/Controllers/Legacy/LegacyAdminController.php b/src/app/Http/Controllers/Legacy/LegacyAdminController.php
index 543d406e7..363a30c08 100644
--- a/src/app/Http/Controllers/Legacy/LegacyAdminController.php
+++ b/src/app/Http/Controllers/Legacy/LegacyAdminController.php
@@ -3,7 +3,7 @@
namespace App\Http\Controllers\Legacy;
use App\Http\Controllers\Controller;
-use App\Http\Controllers\CatchAllController;
+use App\Http\Controllers\UserInterfaceController;
use App\Interfaces\ServiceBodyRepositoryInterface;
use App\Interfaces\UserRepositoryInterface;
use App\Models\User;
@@ -39,7 +39,7 @@ public function handle(Request $request)
return $this->handleGetUserInfo($request);
}
- return CatchAllController::handle($request);
+ return UserInterfaceController::handle($request);
}
private function handleLogin(Request $request)
diff --git a/src/app/Http/Controllers/Legacy/LegacyPathInfo.php b/src/app/Http/Controllers/Legacy/LegacyPathInfo.php
index d64736eb3..462db9079 100644
--- a/src/app/Http/Controllers/Legacy/LegacyPathInfo.php
+++ b/src/app/Http/Controllers/Legacy/LegacyPathInfo.php
@@ -1,4 +1,5 @@
input('meeting_ids') ?? [];
$meetingIds = is_string($meetingIds) ? array_map(fn ($id) => trim($id), explode(',', $meetingIds)) : $meetingIds;
$meetingIds = ensure_integer_array($meetingIds);
@@ -178,7 +180,7 @@ private function getSearchResults(Request $request, ?string $dataFormat = null):
$geoWidthMiles = is_numeric($geoWidthMiles) ? floatval($geoWidthMiles) : null;
if ($isAggregatorMode) {
- $maxGeoWidthKilometers = legacy_config('aggregator_max_geo_width_km');
+ $maxGeoWidthKilometers = file_config('aggregator_max_geo_width_km');
$maxGeoWidthMiles = $maxGeoWidthKilometers * 0.621371;
$geoWidthKilometers = !is_null($geoWidthKilometers) && $geoWidthKilometers > $maxGeoWidthKilometers ? $maxGeoWidthKilometers : $geoWidthKilometers;
$geoWidthMiles = !is_null($geoWidthMiles) && $geoWidthMiles > $maxGeoWidthMiles ? $maxGeoWidthMiles : $geoWidthMiles;
@@ -195,15 +197,17 @@ private function getSearchResults(Request $request, ?string $dataFormat = null):
$searchString = $request->input('SearchString');
$searchString = !is_null($searchString) ? trim($searchString) : null;
- $searchString = strlen($searchString) > 2 || is_numeric($searchString) ? $searchString : null;
+ if (!is_null($searchString)) {
+ $searchString = mb_strlen($searchString) > 2 || is_numeric($searchString) ? $searchString : null;
+ }
$searchStringIsAddress = !is_null($searchString) && $request->input('StringSearchIsAnAddress') == '1';
if (!is_null($searchString) && $searchStringIsAddress) {
- $googleApiKey = legacy_config('google_api_key');
+ $googleApiKey = bmlt_config('googleApiKey');
if (is_null($googleApiKey)) {
abort(400, 'A google api key must be configured to use StringSearchIsAnAddress.');
}
- $regionBias = legacy_config('region_bias');
+ $regionBias = bmlt_config('regionBias');
if (is_string($regionBias) && is_numeric($searchString)) {
// when it's numeric, like a postcode, add $regionBias directly
$searchString .= ' ' . $regionBias;
@@ -235,12 +239,12 @@ private function getSearchResults(Request $request, ?string $dataFormat = null):
$searchStringRadius = $request->input('SearchStringRadius');
if (is_null($searchStringRadius) || !is_numeric($searchStringRadius)) {
- $nNearestAuto = abs(legacy_config('number_of_meetings_for_auto')) * -1;
- $geoWidthMiles = legacy_config('distance_units') == 'mi' ? $nNearestAuto : null;
- $geoWidthKilometers = legacy_config('distance_units') != 'mi' ? $nNearestAuto : null;
+ $nNearestAuto = abs(bmlt_config('numberOfMeetingsForAuto')) * -1;
+ $geoWidthMiles = bmlt_config('distanceUnits') == 'mi' ? $nNearestAuto : null;
+ $geoWidthKilometers = bmlt_config('distanceUnits') != 'mi' ? $nNearestAuto : null;
} else {
- $geoWidthMiles = legacy_config('distance_units') == 'mi' ? floatval($searchStringRadius) : null;
- $geoWidthKilometers = legacy_config('distance_units') != 'mi' ? floatval($searchStringRadius) : null;
+ $geoWidthMiles = bmlt_config('distanceUnits') == 'mi' ? floatval($searchStringRadius) : null;
+ $geoWidthKilometers = bmlt_config('distanceUnits') != 'mi' ? floatval($searchStringRadius) : null;
}
$searchString = null;
@@ -258,7 +262,7 @@ private function getSearchResults(Request $request, ?string $dataFormat = null):
$sortKeys = $request->input('sort_keys');
$sortKeys = empty($sortKeys) ? null : explode(',', $sortKeys);
if (is_null($sortKeys)) {
- $sortAlias = $request->input('sort_key') ?? legacy_config('default_sort_key');
+ $sortAlias = $request->input('sort_key') ?? bmlt_config('defaultSortKey');
if (!is_null($sortAlias)) {
if ($sortAlias == 'weekday') {
$sortKeys = ['weekday_tinyint', 'location_municipality', 'location_city_subsection', 'start_time', 'location_neighborhood'];
@@ -355,7 +359,7 @@ private function getSearchResults(Request $request, ?string $dataFormat = null):
// This code to calculate the formats fields is really inefficient, but necessary because
// we don't have foreign keys between the meetings and formats tables.
- $langEnum = $request->input('lang_enum', config('app.locale'));
+ $langEnum = $request->input('lang_enum', App::currentLocale());
$formats = $this->formatRepository->search(
rootServersInclude: $rootServersInclude,
rootServersExclude: $rootServersExclude,
@@ -391,7 +395,7 @@ private function getSearchResults(Request $request, ?string $dataFormat = null):
private function getFormats(Request $request): BaseJsonResponse
{
- $isAggregatorMode = (bool)legacy_config('aggregator_mode_enabled');
+ $isAggregatorMode = (bool)file_config('aggregator_mode_enabled');
$rootServersInclude = null;
$rootServersExclude = null;
@@ -414,7 +418,7 @@ private function getFormats(Request $request): BaseJsonResponse
$formatsExclude = collect($formatIds)->filter(fn($r) => $r < 0)->map(fn($r) => abs($r))->toArray();
$formatsExclude = count($formatsExclude) ? $formatsExclude : null;
- $langEnums = $request->input('lang_enum', config('app.locale'));
+ $langEnums = $request->input('lang_enum', App::currentLocale());
if (!is_array($langEnums)) {
$langEnums = [$langEnums];
}
@@ -461,7 +465,7 @@ private function getServiceBodies(Request $request): BaseJsonResponse
$rootServersInclude = null;
$rootServersExclude = null;
- if (legacy_config('aggregator_mode_enabled')) {
+ if (file_config('aggregator_mode_enabled')) {
$rootServerIds = $request->input('root_server_ids', []);
$rootServerIds = ensure_integer_array($rootServerIds);
$rootServersInclude = collect($rootServerIds)->filter(fn($r) => $r > 0)->map(fn($r) => $r)->toArray();
@@ -541,32 +545,29 @@ private function getServerInfo($request): BaseJsonResponse
'version' => config('app.version'),
'versionInt' => strval((intval($versionArray[0]) * 1000000) + (intval($versionArray[1]) * 1000) + intval(strstr($versionArray[2], '-', true) ?: $versionArray[2])),
'langs' => collect(scandir(base_path('lang')))->reject(fn ($dir) => str_starts_with($dir, '.'))->sort()->join(','),
- 'nativeLang' => config('app.locale'),
- 'centerLongitude' => strval(legacy_config('search_spec_map_center_longitude')),
- 'centerLatitude' => strval(legacy_config('search_spec_map_center_latitude')),
- 'centerZoom' => strval(legacy_config('search_spec_map_center_zoom')),
- 'defaultDuration' => legacy_config('default_duration_time'),
- 'regionBias' => legacy_config('region_bias'),
+ 'nativeLang' => App::currentLocale(),
+ 'centerLongitude' => strval(bmlt_config('searchSpecMapCenterLongitude')),
+ 'centerLatitude' => strval(bmlt_config('searchSpecMapCenterLatitude')),
+ 'centerZoom' => strval(bmlt_config('searchSpecMapCenterZoom')),
+ 'defaultDuration' => bmlt_config('defaultDurationTime'),
+ 'regionBias' => bmlt_config('regionBias'),
'charSet' => 'UTF-8',
- 'distanceUnits' => legacy_config('distance_units'),
- 'semanticAdmin' => legacy_config('enable_semantic_admin') ? '1' : '0',
- 'emailEnabled' => legacy_config('enable_email_contact') ? '1' : '0',
- 'emailIncludesServiceBodies' => legacy_config('include_service_body_admin_on_emails') ? '1' : '0',
- 'changesPerMeeting' => strval(legacy_config('change_depth_for_meetings')),
- 'meeting_states_and_provinces' => implode(',', legacy_config('meeting_states_and_provinces', [])),
- 'meeting_counties_and_sub_provinces' => implode(',', legacy_config('meeting_counties_and_sub_provinces', [])),
+ 'distanceUnits' => bmlt_config('distanceUnits'),
+ 'semanticAdmin' => '1', // Yap uses this flag to determine legacy auth so we must keep it.
+ 'changesPerMeeting' => strval(bmlt_config('changeDepthForMeetings')),
+ 'meeting_states_and_provinces' => implode(',', bmlt_config('meetingStatesAndProvinces', [])),
+ 'meeting_counties_and_sub_provinces' => implode(',', bmlt_config('meetingCountiesAndSubProvinces', [])),
'available_keys' => $this->meetingRepository->getFieldKeys()->map(fn ($value) => $value['key'])->merge(['root_server_uri', 'format_shared_id_list'])->join(','),
- 'google_api_key' => legacy_config('aggregator_mode_enabled') ? null : legacy_config('google_api_key', ''),
+ 'google_api_key' => file_config('aggregator_mode_enabled') ? null : bmlt_config('googleApiKey', ''),
'dbVersion' => $this->migrationRepository->getLastMigration()['migration'],
- 'dbPrefix' => legacy_config('db_prefix'),
- 'meeting_time_zones_enabled' => legacy_config('meeting_time_zones_enabled') ? '1' : '0',
+ 'dbPrefix' => file_config('db_prefix'),
'phpVersion' => phpversion(),
- 'auto_geocoding_enabled' => legacy_config('auto_geocoding_enabled'),
- 'county_auto_geocoding_enabled' => legacy_config('county_auto_geocoding_enabled'),
- 'zip_auto_geocoding_enabled' => legacy_config('zip_auto_geocoding_enabled'),
+ 'auto_geocoding_enabled' => bmlt_config('autoGeocodingEnabled'),
+ 'county_auto_geocoding_enabled' => bmlt_config('countyAutoGeocodingEnabled'),
+ 'zip_auto_geocoding_enabled' => bmlt_config('zipAutoGeocodingEnabled'),
'commit' => config('app.commit'),
- 'default_closed_status' => legacy_config('default_closed_status'),
- 'aggregator_mode_enabled' => legacy_config('aggregator_mode_enabled')
+ 'default_closed_status' => bmlt_config('defaultClosedStatus'),
+ 'aggregator_mode_enabled' => file_config('aggregator_mode_enabled')
]]);
}
@@ -693,7 +694,7 @@ private function getNawsDump($request): StreamedResponse
})
->reject(fn ($meeting) => is_null($meeting));
$meetings = $meetings->concat($deletedMeetings);
- $allFormats = $this->formatRepository->search(langEnums: [legacy_config('language')], showAll: true)
+ $allFormats = $this->formatRepository->search(langEnums: [App::currentLocale()], showAll: true)
->reject(fn ($fmt) => is_null($fmt->key_string) || empty(trim($fmt->key_string)));
$formatIdToWorldId = $allFormats->mapWithKeys(fn ($fmt, $_) => [$fmt->shared_id_bigint => $fmt->worldid_mixed]);
$formatIdToKeyString = $allFormats->mapWithKeys(fn ($fmt, $_) => [$fmt->shared_id_bigint => $fmt->key_string]);
@@ -937,7 +938,7 @@ private function getNawsClosed($meetingFormats)
if (in_array('OPEN', $meetingFormats)) {
return 'OPEN';
}
- return legacy_config('default_closed_status') ? 'CLOSED' : 'OPEN';
+ return bmlt_config('defaultClosedStatus') ? 'CLOSED' : 'OPEN';
}
// Meeting times will be of the form 19:30:00. Convert to 1930 (which is what this format expects).
@@ -945,7 +946,7 @@ private function getNawsTime($meeting)
{
$t = explode(':', $meeting->start_time);
if (is_array($t) && count($t) > 1) {
- return $t[0].$t[1];
+ return $t[0] . $t[1];
} else {
return $t;
}
diff --git a/src/app/Http/Controllers/UserInterfaceController.php b/src/app/Http/Controllers/UserInterfaceController.php
new file mode 100644
index 000000000..027ba2c77
--- /dev/null
+++ b/src/app/Http/Controllers/UserInterfaceController.php
@@ -0,0 +1,72 @@
+view('frontend', [
+ 'autoGeocodingEnabled' => bmlt_config('autoGeocodingEnabled'),
+ 'baseUrl' => $request->getBaseurl(),
+ 'bmltTitle' => bmlt_config('bmltTitle'),
+ 'bmltNotice' => bmlt_config('bmltNotice'),
+ 'centerLongitude' => bmlt_config('searchSpecMapCenterLongitude'),
+ 'centerLatitude' => bmlt_config('searchSpecMapCenterLatitude'),
+ 'centerZoom' => bmlt_config('searchSpecMapCenterZoom'),
+ 'countyAutoGeocodingEnabled' => bmlt_config('countyAutoGeocodingEnabled'),
+ 'customFields' => self::getCustomFields(),
+ 'defaultClosedStatus' => bmlt_config('defaultClosedStatus'),
+ 'defaultDuration' => bmlt_config('defaultDurationTime'),
+ 'defaultLanguage' => App::currentLocale(),
+ 'distanceUnits' => bmlt_config('distanceUnits'),
+ 'googleApiKey' => bmlt_config('googleApiKey', ''),
+ 'isLanguageSelectorEnabled' => bmlt_config('enableLanguageSelector'),
+ 'languageMapping' => self::getLanguageMapping(),
+ 'formatLangNames' => bmlt_config('formatLangNames', []),
+ 'meetingStatesAndProvinces' => bmlt_config('meetingStatesAndProvinces', []),
+ 'meetingCountiesAndSubProvinces' => bmlt_config('meetingCountiesAndSubProvinces', []),
+ 'regionBias' => bmlt_config('regionBias'),
+ 'version' => config('app.version'),
+ 'zipAutoGeocodingEnabled' => bmlt_config('zipAutoGeocodingEnabled'),
+ ]);
+ }
+
+ private static function getLanguageMapping(): array
+ {
+ return collect(scandir(base_path('lang')))
+ ->reject(fn($dir) => str_starts_with($dir, '.'))
+ ->sort()
+ ->mapWithKeys(fn($langCode) => [$langCode => __('language_name.name', [], $langCode)])
+ ->toArray();
+ }
+
+ private static function getCustomFields(): Collection
+ {
+ $meetingRepository = resolve(MeetingRepositoryInterface::class);
+ $customFields = $meetingRepository->getCustomFields();
+ return $meetingRepository->getDataTemplates()
+ ->reject(fn ($t) => !$customFields->contains($t->key))
+ ->map(fn ($t) => [
+ 'name' => $t->key,
+ 'displayName' => $t->field_prompt,
+ 'language' => $t->lang_enum
+ ])
+ ->values();
+ }
+}
diff --git a/src/app/Http/Kernel.php b/src/app/Http/Kernel.php
index 899664162..43fd6dcbd 100644
--- a/src/app/Http/Kernel.php
+++ b/src/app/Http/Kernel.php
@@ -17,6 +17,7 @@ class Kernel extends HttpKernel
protected $middleware = [
// \App\Http\Middleware\TrustHosts::class,
\App\Http\Middleware\DatabaseMigrations::class,
+ \App\Http\Middleware\SetLocale::class,
\App\Http\Middleware\TrustProxies::class,
\Illuminate\Http\Middleware\HandleCors::class,
\App\Http\Middleware\PreventRequestsDuringMaintenance::class,
diff --git a/src/app/Http/Middleware/DatabaseMigrations.php b/src/app/Http/Middleware/DatabaseMigrations.php
index a1da89061..c74b43253 100644
--- a/src/app/Http/Middleware/DatabaseMigrations.php
+++ b/src/app/Http/Middleware/DatabaseMigrations.php
@@ -46,13 +46,13 @@ public function handle(Request $request, Closure $next)
return $next($request);
}
- private function migrationsShouldRun(): bool
+ public function migrationsShouldRun(): bool
{
if (!Schema::hasTable('migrations')) {
return true;
}
- if (!$this->migrationRepository->migrationExists('2024_07_20_203802_fix_admin_user_owners')) {
+ if (!$this->migrationRepository->migrationExists('2025_12_31_233709_clean_orphaned_format_ids')) {
return true;
}
diff --git a/src/app/Http/Middleware/SetLocale.php b/src/app/Http/Middleware/SetLocale.php
new file mode 100644
index 000000000..6a0a1db19
--- /dev/null
+++ b/src/app/Http/Middleware/SetLocale.php
@@ -0,0 +1,17 @@
+setLocale(bmlt_config('language', 'en'));
+ return $next($request);
+ }
+}
diff --git a/src/app/Http/Resources/Admin/MeetingChangeResource.php b/src/app/Http/Resources/Admin/MeetingChangeResource.php
index d9d1f6d3d..2103b87c3 100644
--- a/src/app/Http/Resources/Admin/MeetingChangeResource.php
+++ b/src/app/Http/Resources/Admin/MeetingChangeResource.php
@@ -11,6 +11,7 @@
class MeetingChangeResource extends JsonResource
{
use ChangeDetailsTrait;
+
private static bool $isRequestInitialized = false;
private static Collection $allFormats;
private static Collection $allServiceBodies;
@@ -32,7 +33,7 @@ public function toArray($request): array
'dateString' => date('g:i A, n/j/Y', strtotime($this->change_date)),
'userName' => $this->user?->name_string ?? '',
'serviceBodyName' => $this->serviceBody?->name_string ?? '',
- 'details' => $this->getChangeDetails(true),
+ 'details' => $this->getChangeDetails(asArray: true, ignoreVisibility: true),
];
}
diff --git a/src/app/Http/Resources/Admin/MeetingResource.php b/src/app/Http/Resources/Admin/MeetingResource.php
index 070289e3c..54a050ead 100644
--- a/src/app/Http/Resources/Admin/MeetingResource.php
+++ b/src/app/Http/Resources/Admin/MeetingResource.php
@@ -2,6 +2,7 @@
namespace App\Http\Resources\Admin;
+use Illuminate\Support\Facades\App;
use App\Http\Resources\JsonResource;
use App\Models\Meeting;
use App\Repositories\MeetingRepository;
@@ -30,7 +31,20 @@ public static function resetStaticVariables()
self::$hiddenFormatIds = null;
self::$temporarilyClosedFormatId = null;
}
-
+ private function languagePriority($langEnum, $requestedLangEnum)
+ {
+ if ($langEnum === $requestedLangEnum) {
+ return 3;
+ }
+ if ($langEnum === (file_config('language') ?: App::currentLocale())) {
+ return 2;
+ }
+ return 1;
+ }
+ private function getTargetLanguage($request)
+ {
+ return $request->lang;
+ }
public function toArray($request)
{
if (!self::$isRequestInitialized) {
@@ -47,9 +61,17 @@ public function toArray($request)
self::$hiddenFormatIds = collect([self::$virtualFormatId, self::$hybridFormatId, self::$temporarilyClosedFormatId]);
self::$isRequestInitialized = true;
}
-
- $meetingData = $this->data
- ->mapWithKeys(fn ($data, $_) => [$data->key => $data->data_string])
+ $requestedLangEnum = $this->getTargetLanguage($request) ?? (file_config('language') ?: App::currentLocale());
+ $meetingData = collect($this->data->reduce(function ($carry, $item) use ($requestedLangEnum) {
+ if (!isset($carry[0][$item->key])) {
+ $carry[0][$item->key] = $item->data_string;
+ $carry[1][$item->key] = $item->lang_enum;
+ } elseif ($this->languagePriority($item->lang_enum, $requestedLangEnum) > $this->languagePriority($carry[0][$item->key], $requestedLangEnum)) {
+ $carry[0][$item->key] = $item->data_string;
+ $carry[1][$item->key] = $item->lang_enum;
+ }
+ return $carry;
+ }, [[], []])[0])
->toBase()
->merge(
$this->longdata
diff --git a/src/app/Http/Resources/Admin/SettingResource.php b/src/app/Http/Resources/Admin/SettingResource.php
new file mode 100644
index 000000000..2abfe6e64
--- /dev/null
+++ b/src/app/Http/Resources/Admin/SettingResource.php
@@ -0,0 +1,26 @@
+name] = $setting->value;
+ }
+
+ return $settings;
+ }
+}
diff --git a/src/app/Http/Resources/Admin/UserResource.php b/src/app/Http/Resources/Admin/UserResource.php
index 8810031f6..afab69a30 100644
--- a/src/app/Http/Resources/Admin/UserResource.php
+++ b/src/app/Http/Resources/Admin/UserResource.php
@@ -24,6 +24,8 @@ public function toArray($request)
'description' => $this->description_string,
'email' => $this->email_address_string,
'ownerId' => $this->owner_id_bigint == -1 ? null : $this->owner_id_bigint,
+ 'targetLanguage' => $this->target_language ?? '',
+ 'lastLoginAt' => $this->last_access_datetime?->year > 1970 ? $this->last_access_datetime : null,
];
}
}
diff --git a/src/app/Http/Resources/Query/FormatResource.php b/src/app/Http/Resources/Query/FormatResource.php
index 0f891fb20..52acbfb03 100644
--- a/src/app/Http/Resources/Query/FormatResource.php
+++ b/src/app/Http/Resources/Query/FormatResource.php
@@ -14,7 +14,7 @@ class FormatResource extends JsonResource
*/
public function toArray($request)
{
- $isAggregatorModeEnabled = (bool)legacy_config('aggregator_mode_enabled');
+ $isAggregatorModeEnabled = (bool)file_config('aggregator_mode_enabled');
return [
'key_string' => $this->key_string,
diff --git a/src/app/Http/Resources/Query/MeetingChangeResource.php b/src/app/Http/Resources/Query/MeetingChangeResource.php
index 3a8326093..11331c4bd 100644
--- a/src/app/Http/Resources/Query/MeetingChangeResource.php
+++ b/src/app/Http/Resources/Query/MeetingChangeResource.php
@@ -3,6 +3,7 @@
namespace App\Http\Resources\Query;
use App\Http\Resources\JsonResource;
+use App\Models\User;
use App\Repositories\FormatRepository;
use App\Repositories\ServiceBodyRepository;
use App\Http\Resources\Traits\ChangeDetailsTrait;
@@ -11,9 +12,13 @@
class MeetingChangeResource extends JsonResource
{
use ChangeDetailsTrait;
+
private static bool $isRequestInitialized = false;
private static Collection $allFormats;
private static Collection $allServiceBodies;
+ private static ?Collection $serviceBodyPermissions = null;
+ private static bool $userIsAuthenticated = false;
+ private static bool $userIsAdmin = false;
private bool $isBeforeObjectLoaded = false;
private ?array $cachedBeforeObject;
@@ -25,7 +30,7 @@ class MeetingChangeResource extends JsonResource
'c_comdef_meeting' => 'meeting',
'c_comdef_format' => 'format',
'c_comdef_user' => 'user',
- 'c_comdef_service_body'=> 'service_body',
+ 'c_comdef_service_body' => 'service_body',
];
private static array $changeTypeToStrMap = [
@@ -39,6 +44,9 @@ class MeetingChangeResource extends JsonResource
public static function resetStaticVariables()
{
self::$isRequestInitialized = false;
+ self::$serviceBodyPermissions = null;
+ self::$userIsAuthenticated = false;
+ self::$userIsAdmin = false;
}
public function toArray($request)
@@ -65,13 +73,26 @@ public function toArray($request)
];
}
- private function initializeRequest()
+ private function initializeRequest($request)
{
$formatRepository = new FormatRepository();
self::$allFormats = $formatRepository->search(showAll: true)->groupBy(['shared_id_bigint', 'lang_enum'], preserveKeys: true);
$serviceBodyRepository = new ServiceBodyRepository();
self::$allServiceBodies = $serviceBodyRepository->search()->mapWithKeys(fn ($sb) => [$sb->id_bigint => $sb]);
+
+ // Permissions
+ $user = $request->user();
+ if (!is_null($user) && $user->user_level_tinyint != User::USER_LEVEL_DEACTIVATED) {
+ self::$userIsAuthenticated = true;
+ if ($user->user_level_tinyint == User::USER_LEVEL_ADMIN) {
+ self::$userIsAdmin = true;
+ } else {
+ self::$serviceBodyPermissions = $serviceBodyRepository
+ ->getAssignedServiceBodyIds($user->id_bigint)
+ ->mapWithKeys(fn ($sbId, $_) => [$sbId => null]);
+ }
+ }
}
private function getJsonDataArray(): array
@@ -94,6 +115,7 @@ private function getJsonDataArray(): array
private function convertObjectToArray($meetingObject): array
{
$ret = collect([]);
+ $serviceBodyBigint = null;
$mainValues = $meetingObject['main_table_values'] ?? null;
if ($mainValues) {
@@ -166,6 +188,8 @@ private function convertObjectToArray($meetingObject): array
}
$dataTableValues = $meetingObject['data_table_values'] ?? [];
+ $userHasPermission = self::$userIsAuthenticated && (self::$userIsAdmin || self::$serviceBodyPermissions?->has($serviceBodyBigint));
+
foreach ($dataTableValues as $data) {
if (isset($data['key']) && $data['key'] == 'root_server_uri') {
continue;
@@ -173,7 +197,13 @@ private function convertObjectToArray($meetingObject): array
if (!isset($data['data_string'])) {
continue;
}
- $ret->put($data['key'], $data['data_string']);
+
+ // Check visibility field - if visibility is 1 (protected) and user doesn't have permission, mask with asterisks
+ if (isset($data['visibility']) && $data['visibility'] == 1 && !$userHasPermission && !empty($data['data_string'])) {
+ $ret->put($data['key'], '********');
+ } else {
+ $ret->put($data['key'], $data['data_string']);
+ }
}
return $ret->toArray();
diff --git a/src/app/Http/Resources/Query/MeetingResource.php b/src/app/Http/Resources/Query/MeetingResource.php
index b7b3e307e..cfee711c8 100644
--- a/src/app/Http/Resources/Query/MeetingResource.php
+++ b/src/app/Http/Resources/Query/MeetingResource.php
@@ -37,6 +37,16 @@ public static function resetStaticVariables()
self::$defaultDurationTime = null;
self::$isAggregatorModeEnabled = false;
}
+ private function languagePriority($langEnum, $requestedLangEnum)
+ {
+ if ($langEnum === $requestedLangEnum) {
+ return 3;
+ }
+ if ($langEnum === config('app.locale')) {
+ return 2;
+ }
+ return 1;
+ }
/**
* Transform the resource into an array.
@@ -75,13 +85,21 @@ public function toArray($request)
'format_shared_id_list' => $this->getFormatSharedIdList(),
'root_server_id' => $this->getRootServerId(),
];
-
+ $requestedLangEnum = $request->lang_enum ?? config('app.locale');
// data table keys
- $meetingData = $this->data->mapWithKeys(fn ($data, $_) => [$data->key => $data->data_string])->toBase()
+ $meetingData = collect($this->data->reduce(function ($carry, $item) use ($requestedLangEnum) {
+ if (!isset($carry[0][$item->key])) {
+ $carry[0][$item->key] = $item->data_string;
+ $carry[1][$item->key] = $item->lang_enum;
+ } elseif ($this->languagePriority($item->lang_enum, $requestedLangEnum) > $this->languagePriority($carry[0][$item->key], $requestedLangEnum)) {
+ $carry[0][$item->key] = $item->data_string;
+ $carry[1][$item->key] = $item->lang_enum;
+ }
+ return $carry;
+ }, [[], []])[0])->toBase()
->merge(
- $this->longdata->mapWithKeys(fn ($data, $_) => [$data->key => $data->data_blob])->toBase()
+ $this->longdata->mapWithKeys(fn ($data, $_) => [$data->key.'|'.$data->lang_enum => $data->data_blob])->toBase()
);
-
foreach (self::$meetingDataTemplates as $meetingDataTemplate) {
if (self::$hasDataFieldKeys && !self::$dataFieldKeys->has($meetingDataTemplate->key)) {
continue;
@@ -106,10 +124,10 @@ private function initializeRequest($request)
$serviceBodyRepository = new ServiceBodyRepository();
// Default duration time
- self::$defaultDurationTime = legacy_config('default_duration_time');
+ self::$defaultDurationTime = bmlt_config('defaultDurationTime');
// Aggregator mode
- self::$isAggregatorModeEnabled = (bool)legacy_config('aggregator_mode_enabled');
+ self::$isAggregatorModeEnabled = (bool)file_config('aggregator_mode_enabled');
// Preload meeting data templates
self::$meetingDataTemplates = $meetingRepository->getDataTemplates();
diff --git a/src/app/Http/Resources/Query/ServiceBodyResource.php b/src/app/Http/Resources/Query/ServiceBodyResource.php
index e1d0ef879..a383bf863 100644
--- a/src/app/Http/Resources/Query/ServiceBodyResource.php
+++ b/src/app/Http/Resources/Query/ServiceBodyResource.php
@@ -23,8 +23,8 @@ public function toArray($request)
'url' => $this->uri_string ?? '',
'helpline' => $this->kml_file_uri_string ?? '',
'world_id' => $this->worldid_mixed ?? '',
- 'contact_email' => $this->when(legacy_config('include_service_body_email_in_semantic'), $this->sb_meeting_email ?? ''),
- 'root_server_id' => $this->when(legacy_config('aggregator_mode_enabled'), $this->root_server_id ?? '')
+ 'contact_email' => $this->when(bmlt_config('includeServiceBodyEmailInSemantic'), $this->sb_meeting_email ?? ''),
+ 'root_server_id' => $this->when(file_config('aggregator_mode_enabled'), $this->root_server_id ?? '')
];
}
}
diff --git a/src/app/Http/Resources/Query/TsmlMeetingResource.php b/src/app/Http/Resources/Query/TsmlMeetingResource.php
index d1dacf8e8..0d4ea8c92 100644
--- a/src/app/Http/Resources/Query/TsmlMeetingResource.php
+++ b/src/app/Http/Resources/Query/TsmlMeetingResource.php
@@ -90,11 +90,12 @@ public function toArray($request): array
->filter()
->values()
->toArray(),
- 'notes' => $allData['location_info'] ?? '',
+ 'location_notes' => $allData['location_info'] ?? '',
+ 'notes' => $allData['comments'] ?? '',
'coordinates' => $this->venue_type == 2
? null
: (($this->latitude && $this->longitude) ? "{$this->latitude},{$this->longitude}" : null),
- 'slug' => \Str::slug($allData['meeting_name']),
+ 'slug' => \Str::slug($allData['meeting_name']) . '-' . $this->id_bigint,
'updated' => $this->updated_at ?? null,
'region' => $this->serviceBody->name_string ?? '',
'regions' => [$this->serviceBody->name_string ?? ''],
diff --git a/src/app/Http/Resources/Traits/ChangeDetailsTrait.php b/src/app/Http/Resources/Traits/ChangeDetailsTrait.php
index a1da3b09d..83efe0920 100644
--- a/src/app/Http/Resources/Traits/ChangeDetailsTrait.php
+++ b/src/app/Http/Resources/Traits/ChangeDetailsTrait.php
@@ -13,7 +13,7 @@ trait ChangeDetailsTrait
'c_comdef_meeting' => 'meeting',
'c_comdef_format' => 'format',
'c_comdef_user' => 'user',
- 'c_comdef_service_body'=> 'service_body',
+ 'c_comdef_service_body' => 'service_body',
];
private static array $changeTypeToStrMap = [
@@ -23,7 +23,7 @@ trait ChangeDetailsTrait
'comdef_change_type_rollback' => 'rolled_back',
];
- public function getChangeDetails(bool $asArray = false): string|array
+ public function getChangeDetails(bool $asArray = false, bool $ignoreVisibility = false): string|array
{
$objectType = self::$objectClassToStrMap[$this->object_class_string];
$changeType = self::$changeTypeToStrMap[$this->change_type_enum];
@@ -69,12 +69,12 @@ public function getChangeDetails(bool $asArray = false): string|array
$beforeValue = $beforeValues->get($key);
$afterValue = $afterValues->get($key);
if (is_array($afterValue)) {
- $isVisible = $afterValue['visibility'] !== 1;
+ $isVisible = $ignoreVisibility || $afterValue['visibility'] !== 1;
$fieldPrompt = $afterValue['field_prompt'] ?? $fieldName;
$afterValue = $afterValue['data_string'] ?? null;
}
if (is_array($beforeValue)) {
- if ($isVisible) {
+ if ($isVisible && !$ignoreVisibility) {
$isVisible = $beforeValue['visibility'] !== 1;
}
if ($fieldPrompt == $key) {
@@ -158,9 +158,9 @@ public function getChangeDetails(bool $asArray = false): string|array
$afterValue = floatval($afterValue);
} elseif ($key == 'start_time' || $key == 'duration_time') {
$beforeValue = explode(':', $beforeValue);
- $beforeValue = strval(intval($beforeValue[0])).':'.(intval($beforeValue[1]) < 10 ? '0' : '').strval(intval($beforeValue[1]));
+ $beforeValue = strval(intval($beforeValue[0])) . ':' . (intval($beforeValue[1]) < 10 ? '0' : '') . strval(intval($beforeValue[1]));
$afterValue = explode(':', $afterValue);
- $afterValue = strval(intval($afterValue[0])).':'.(intval($afterValue[1]) < 10 ? '0' : '').strval(intval($afterValue[1]));
+ $afterValue = strval(intval($afterValue[0])) . ':' . (intval($afterValue[1]) < 10 ? '0' : '') . strval(intval($afterValue[1]));
if ($beforeValue == $afterValue) {
continue;
}
diff --git a/src/app/Interfaces/FormatRepositoryInterface.php b/src/app/Interfaces/FormatRepositoryInterface.php
index 568b7c2bf..22ee83813 100644
--- a/src/app/Interfaces/FormatRepositoryInterface.php
+++ b/src/app/Interfaces/FormatRepositoryInterface.php
@@ -3,6 +3,7 @@
namespace App\Interfaces;
use App\Models\Format;
+use App\Repositories\Import\FormatImportResult;
use Illuminate\Support\Collection;
interface FormatRepositoryInterface
@@ -25,5 +26,5 @@ public function getTemporarilyClosedFormat(): Format;
public function create(array $sharedFormatsValues): Format;
public function update(int $sharedId, array $sharedFormatsValues): bool;
public function delete(int $sharedId): bool;
- public function import(int $rootServerId, Collection $externalObjects): void;
+ public function import(int $rootServerId, Collection $externalObjects): FormatImportResult;
}
diff --git a/src/app/Interfaces/MeetingRepositoryInterface.php b/src/app/Interfaces/MeetingRepositoryInterface.php
index ea7992f04..878fa70fc 100644
--- a/src/app/Interfaces/MeetingRepositoryInterface.php
+++ b/src/app/Interfaces/MeetingRepositoryInterface.php
@@ -3,6 +3,7 @@
namespace App\Interfaces;
use App\Models\Meeting;
+use App\Repositories\Import\MeetingImportResult;
use Illuminate\Support\Collection;
interface MeetingRepositoryInterface
@@ -50,6 +51,8 @@ public function getDataTemplates(): Collection;
public function getBoundingBox(): array;
public function create(array $values): Meeting;
public function update(int $id, array $values): bool;
+ public function translate(int $id, array $values): bool;
+ public function setTargetLanguage(string $lang);
public function delete(int $id): bool;
- public function import(int $rootServerId, Collection $externalObjects): void;
+ public function import(int $rootServerId, Collection $externalObjects): MeetingImportResult;
}
diff --git a/src/app/Interfaces/RootServerRepositoryInterface.php b/src/app/Interfaces/RootServerRepositoryInterface.php
index 58c21d477..eed96277f 100644
--- a/src/app/Interfaces/RootServerRepositoryInterface.php
+++ b/src/app/Interfaces/RootServerRepositoryInterface.php
@@ -3,6 +3,7 @@
namespace App\Interfaces;
use App\Models\RootServer;
+use App\Repositories\Import\RootServerImportResult;
use Illuminate\Support\Collection;
interface RootServerRepositoryInterface
@@ -11,5 +12,5 @@ public function search(bool $eagerStatistics = false): Collection;
public function create(array $values): RootServer;
public function update(int $id, array $values): bool;
public function delete(int $id): bool;
- public function import(Collection $externalObjects): void;
+ public function import(Collection $externalObjects): RootServerImportResult;
}
diff --git a/src/app/Interfaces/ServiceBodyRepositoryInterface.php b/src/app/Interfaces/ServiceBodyRepositoryInterface.php
index 2c1a603a4..346730aba 100644
--- a/src/app/Interfaces/ServiceBodyRepositoryInterface.php
+++ b/src/app/Interfaces/ServiceBodyRepositoryInterface.php
@@ -3,6 +3,7 @@
namespace App\Interfaces;
use App\Models\ServiceBody;
+use App\Repositories\Import\ServiceBodyImportResult;
use Illuminate\Support\Collection;
interface ServiceBodyRepositoryInterface
@@ -23,5 +24,5 @@ public function getAdminServiceBodyIds(int $userId): Collection;
public function getChildren(array $parents): array;
public function getParents(array $children): array;
public function removeUser(int $userId);
- public function import(int $rootServerId, Collection $externalObjects): void;
+ public function import(int $rootServerId, Collection $externalObjects): ServiceBodyImportResult;
}
diff --git a/src/app/Interfaces/SettingRepositoryInterface.php b/src/app/Interfaces/SettingRepositoryInterface.php
new file mode 100644
index 000000000..bfad91426
--- /dev/null
+++ b/src/app/Interfaces/SettingRepositoryInterface.php
@@ -0,0 +1,14 @@
+map(fn($id) => trim($id))->toArray()
- : ($meeting_states_and_provinces ?? []);
- $config['meeting_counties_and_sub_provinces'] = isset($meeting_counties_and_sub_provinces) && is_string($meeting_counties_and_sub_provinces)
- ? collect(explode(',', $meeting_counties_and_sub_provinces))->map(fn($id) => trim($id))->toArray()
- : ($meeting_counties_and_sub_provinces ?? []);
- $config['meeting_time_zones_enabled'] = isset($meeting_time_zones_enabled) && $meeting_time_zones_enabled;
- $config['search_spec_map_center_longitude'] = isset($search_spec_map_center) && is_array($search_spec_map_center) && isset($search_spec_map_center['longitude']) ? $search_spec_map_center['longitude'] : -118.563659;
- $config['search_spec_map_center_latitude'] = isset($search_spec_map_center) && is_array($search_spec_map_center) && isset($search_spec_map_center['latitude']) ? $search_spec_map_center['latitude'] : 34.235918;
- $config['search_spec_map_center_zoom'] = isset($search_spec_map_center) && is_array($search_spec_map_center) && isset($search_spec_map_center['zoom']) ? $search_spec_map_center['zoom'] : 6;
- $config['number_of_meetings_for_auto'] = isset($number_of_meetings_for_auto) && is_numeric($number_of_meetings_for_auto) ? intval($number_of_meetings_for_auto) : 10;
- $config['auto_geocoding_enabled'] = isset($auto_geocoding_enabled) ? boolval($auto_geocoding_enabled) : true;
- $config['county_auto_geocoding_enabled'] = isset($county_auto_geocoding_enabled) ? boolval($county_auto_geocoding_enabled) : false;
- $config['zip_auto_geocoding_enabled'] = isset($zip_auto_geocoding_enabled) ? boolval($zip_auto_geocoding_enabled) : false;
- $config['new_ui_enabled'] = $new_ui_enabled ?? true;
- // If default_closed_status is TRUE, meetings that don't explicitly have an OPEN or CLOSED format are assumed CLOSED for the NAWS export.
- $config['default_closed_status'] = $g_defaultClosedStatus ?? true;
- $config['enable_language_selector'] = $g_enable_language_selector ?? false;
- $config['aggregator_mode_enabled'] = $aggregator_mode_enabled ?? false;
- $config['aggregator_max_geo_width_km'] = isset($aggregator_max_geo_width_km) && is_numeric($aggregator_max_geo_width_km) ? floatval($aggregator_max_geo_width_km) : 1000;
- $config['include_service_body_email_in_semantic'] = $g_include_service_body_email_in_semantic ?? false;
- $config['bmlt_title'] = $bmlt_title ?? '';
- $config['bmlt_notice'] = $bmlt_notice ?? '';
-
- self::$config = $config;
- self::$configLoaded = true;
- }
-}
diff --git a/src/app/Models/Setting.php b/src/app/Models/Setting.php
new file mode 100644
index 000000000..14c7b235c
--- /dev/null
+++ b/src/app/Models/Setting.php
@@ -0,0 +1,55 @@
+ is_null($value) ? null : json_decode($value, true),
+ set: fn ($value) => is_null($value) ? null : json_encode($this->cast($value, $this->type)),
+ );
+ }
+
+ private function cast($value, string $type): mixed
+ {
+ switch ($type) {
+ case self::TYPE_ARRAY:
+ if (is_array($value)) {
+ return $value;
+ }
+ if (is_string($value)) {
+ return $value === '' ? [] : array_map('trim', explode(',', $value));
+ }
+ return [];
+
+ case self::TYPE_BOOL:
+ return (bool) $value;
+
+ case self::TYPE_INT:
+ return (int) $value;
+
+ case self::TYPE_FLOAT:
+ return (float) $value;
+
+ case self::TYPE_STRING:
+ default:
+ return (string) $value;
+ }
+ }
+}
diff --git a/src/app/Models/User.php b/src/app/Models/User.php
index 92edbd3d5..65f9b3dd3 100644
--- a/src/app/Models/User.php
+++ b/src/app/Models/User.php
@@ -9,23 +9,27 @@
class User extends Model implements AuthenticatableContract
{
- use Authenticatable, HasApiTokens;
+ use Authenticatable;
+ use HasApiTokens;
public const USER_LEVEL_ADMIN = 1;
public const USER_LEVEL_SERVICE_BODY_ADMIN = 2;
public const USER_LEVEL_DEACTIVATED = 4;
public const USER_LEVEL_OBSERVER = 5;
+ public const USER_LEVEL_TRANSLATOR = 6;
public const USER_TYPE_DEACTIVATED = 'deactivated';
public const USER_TYPE_ADMIN = 'admin';
public const USER_TYPE_SERVICE_BODY_ADMIN = 'serviceBodyAdmin';
public const USER_TYPE_OBSERVER = 'observer';
+ public const USER_TYPE_TRANSLATOR = 'translator';
public const USER_LEVEL_TO_USER_TYPE_MAP = [
self::USER_LEVEL_DEACTIVATED => self::USER_TYPE_DEACTIVATED,
self::USER_LEVEL_ADMIN => self::USER_TYPE_ADMIN,
self::USER_LEVEL_SERVICE_BODY_ADMIN => self::USER_TYPE_SERVICE_BODY_ADMIN,
self::USER_LEVEL_OBSERVER => self::USER_TYPE_OBSERVER,
+ self::USER_LEVEL_TRANSLATOR => self::USER_TYPE_TRANSLATOR,
];
public const USER_TYPE_TO_USER_LEVEL_MAP = [
@@ -33,6 +37,7 @@ class User extends Model implements AuthenticatableContract
self::USER_TYPE_ADMIN => self::USER_LEVEL_ADMIN,
self::USER_TYPE_SERVICE_BODY_ADMIN => self::USER_LEVEL_SERVICE_BODY_ADMIN,
self::USER_TYPE_OBSERVER => self::USER_LEVEL_OBSERVER,
+ self::USER_TYPE_TRANSLATOR => self::USER_LEVEL_TRANSLATOR,
];
public const FIELDS = [
@@ -43,6 +48,7 @@ class User extends Model implements AuthenticatableContract
'login_string',
'password_string',
'owner_id_bigint',
+ 'target_language'
];
protected $table = 'comdef_users';
@@ -50,6 +56,10 @@ class User extends Model implements AuthenticatableContract
public $timestamps = false;
protected $fillable = self::FIELDS;
+ protected $casts = [
+ 'last_access_datetime' => 'datetime',
+ ];
+
public function getAuthPassword()
{
return $this->password_string;
@@ -70,6 +80,11 @@ public function isServiceBodyAdmin(): bool
return $this->user_level_tinyint == self::USER_LEVEL_SERVICE_BODY_ADMIN;
}
+ public function isTranslator(): bool
+ {
+ return $this->user_level_tinyint == self::USER_LEVEL_TRANSLATOR;
+ }
+
public function isDeactivated(): bool
{
return $this->user_level_tinyint == self::USER_LEVEL_DEACTIVATED;
diff --git a/src/app/Policies/ChangePolicy.php b/src/app/Policies/ChangePolicy.php
index fef091aa3..c255b99ab 100644
--- a/src/app/Policies/ChangePolicy.php
+++ b/src/app/Policies/ChangePolicy.php
@@ -9,7 +9,8 @@
class ChangePolicy
{
- use DeniesDeactivatedUser, HandlesAuthorization;
+ use DeniesDeactivatedUser;
+ use HandlesAuthorization;
private ServiceBodyRepositoryInterface $serviceBodyRepository;
diff --git a/src/app/Policies/DeniesDeactivatedUser.php b/src/app/Policies/DeniesDeactivatedUser.php
index 12ede58e5..81933f4c2 100644
--- a/src/app/Policies/DeniesDeactivatedUser.php
+++ b/src/app/Policies/DeniesDeactivatedUser.php
@@ -1,4 +1,5 @@
update($user, $meeting);
}
+ public function translate(User $user, Meeting $meeting)
+ {
+ if (file_config('aggregator_mode_enabled')) {
+ return false;
+ }
+
+ if ($user->isAdmin()) {
+ return true;
+ }
+
+ if ($user->isTranslator() || $user->isServiceBodyAdmin()) {
+ return $this->serviceBodyRepository->getAssignedServiceBodyIds($user->id_bigint)->contains($meeting->service_body_bigint);
+ }
+ return false;
+ }
public function delete(User $user, Meeting $meeting)
{
- if (legacy_config('aggregator_mode_enabled')) {
+ if (file_config('aggregator_mode_enabled')) {
return false;
}
diff --git a/src/app/Policies/ServiceBodyPolicy.php b/src/app/Policies/ServiceBodyPolicy.php
index d03a3cfc6..448ab7d8a 100644
--- a/src/app/Policies/ServiceBodyPolicy.php
+++ b/src/app/Policies/ServiceBodyPolicy.php
@@ -9,7 +9,8 @@
class ServiceBodyPolicy
{
- use DeniesDeactivatedUser, HandlesAuthorization;
+ use DeniesDeactivatedUser;
+ use HandlesAuthorization;
private ServiceBodyRepositoryInterface $serviceBodyRepository;
@@ -34,7 +35,7 @@ public function view(User $user, ServiceBody $serviceBody)
public function create(User $user)
{
- if (legacy_config('aggregator_mode_enabled')) {
+ if (file_config('aggregator_mode_enabled')) {
return false;
}
@@ -43,7 +44,7 @@ public function create(User $user)
public function update(User $user, ServiceBody $serviceBody)
{
- if (legacy_config('aggregator_mode_enabled')) {
+ if (file_config('aggregator_mode_enabled')) {
return false;
}
@@ -65,7 +66,7 @@ public function partialUpdate(User $user, ServiceBody $serviceBody)
public function delete(User $user, ServiceBody $serviceBody)
{
- if (legacy_config('aggregator_mode_enabled')) {
+ if (file_config('aggregator_mode_enabled')) {
return false;
}
diff --git a/src/app/Policies/SettingPolicy.php b/src/app/Policies/SettingPolicy.php
new file mode 100644
index 000000000..a24f7666d
--- /dev/null
+++ b/src/app/Policies/SettingPolicy.php
@@ -0,0 +1,22 @@
+isAdmin();
+ }
+
+ public function update(User $user)
+ {
+ return $user->isAdmin();
+ }
+}
diff --git a/src/app/Policies/UserPolicy.php b/src/app/Policies/UserPolicy.php
index c60ba364a..58bc2aa57 100644
--- a/src/app/Policies/UserPolicy.php
+++ b/src/app/Policies/UserPolicy.php
@@ -7,7 +7,8 @@
class UserPolicy
{
- use DeniesDeactivatedUser, HandlesAuthorization;
+ use DeniesDeactivatedUser;
+ use HandlesAuthorization;
public function viewAny(User $user)
{
diff --git a/src/app/Providers/AppServiceProvider.php b/src/app/Providers/AppServiceProvider.php
index 84e2c731d..34bd4f181 100644
--- a/src/app/Providers/AppServiceProvider.php
+++ b/src/app/Providers/AppServiceProvider.php
@@ -3,7 +3,6 @@
namespace App\Providers;
use Illuminate\Http\Resources\Json\JsonResource;
-use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\ServiceProvider;
diff --git a/src/app/Providers/RepositoryServiceProvider.php b/src/app/Providers/RepositoryServiceProvider.php
index 195d92ceb..3ad8ec03b 100644
--- a/src/app/Providers/RepositoryServiceProvider.php
+++ b/src/app/Providers/RepositoryServiceProvider.php
@@ -8,6 +8,7 @@
use App\Interfaces\MigrationRepositoryInterface;
use App\Interfaces\RootServerRepositoryInterface;
use App\Interfaces\ServiceBodyRepositoryInterface;
+use App\Interfaces\SettingRepositoryInterface;
use App\Interfaces\UserRepositoryInterface;
use App\Models\RootServer;
use App\Repositories\ChangeRepository;
@@ -16,6 +17,7 @@
use App\Repositories\MigrationRepository;
use App\Repositories\RootServerRepository;
use App\Repositories\ServiceBodyRepository;
+use App\Repositories\SettingRepository;
use App\Repositories\UserRepository;
use Illuminate\Support\ServiceProvider;
@@ -34,6 +36,7 @@ public function register()
$this->app->bind(MigrationRepositoryInterface::class, MigrationRepository::class);
$this->app->bind(RootServerRepositoryInterface::class, RootServerRepository::class);
$this->app->bind(ServiceBodyRepositoryInterface::class, ServiceBodyRepository::class);
+ $this->app->bind(SettingRepositoryInterface::class, SettingRepository::class);
$this->app->bind(UserRepositoryInterface::class, UserRepository::class);
}
diff --git a/src/app/Repositories/External/ExternalRootServer.php b/src/app/Repositories/External/ExternalRootServer.php
index 9b90db6ff..181c7db5e 100644
--- a/src/app/Repositories/External/ExternalRootServer.php
+++ b/src/app/Repositories/External/ExternalRootServer.php
@@ -14,7 +14,7 @@ public function __construct(array $values)
{
$this->id = $this->validateInt($values, 'id');
$this->name = $this->validateString($values, 'name');
- $this->url = $this->validateUrl($values, 'rootURL');
+ $this->url = $this->validateUrl($values, 'url');
}
public function isEqual(RootServer $rootServer): bool
diff --git a/src/app/Repositories/FormatRepository.php b/src/app/Repositories/FormatRepository.php
index 18eae92bb..e2cfd167c 100644
--- a/src/app/Repositories/FormatRepository.php
+++ b/src/app/Repositories/FormatRepository.php
@@ -7,6 +7,7 @@
use App\Models\Format;
use App\Models\Meeting;
use App\Repositories\External\ExternalFormat;
+use App\Repositories\Import\FormatImportResult;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
@@ -112,7 +113,7 @@ public function create(array $sharedFormatsValues): Format
foreach ($sharedFormatsValues as $values) {
$values['shared_id_bigint'] = $sharedIdBigint;
$format = Format::create($values);
- if (!legacy_config('aggregator_mode_enabled')) {
+ if (!file_config('aggregator_mode_enabled')) {
$this->saveChange(null, $format);
}
}
@@ -136,7 +137,7 @@ public function update(int $sharedId, array $sharedFormatsValues): bool
->filter(fn ($values) => $values['lang_enum'] == $oldFormat->lang_enum)
->isEmpty();
if ($isDeleted) {
- if (!legacy_config('aggregator_mode_enabled')) {
+ if (!file_config('aggregator_mode_enabled')) {
$this->saveChange($oldFormat, null);
}
}
@@ -146,7 +147,7 @@ public function update(int $sharedId, array $sharedFormatsValues): bool
$values['shared_id_bigint'] = $sharedId;
$newFormat = Format::create($values);
$oldFormat = $oldFormats->get($newFormat->lang_enum);
- if (!legacy_config('aggregator_mode_enabled')) {
+ if (!file_config('aggregator_mode_enabled')) {
if (is_null($oldFormat)) {
$this->saveChange(null, $newFormat);
} else {
@@ -166,7 +167,7 @@ public function delete(int $sharedId): bool
if ($formats->isNotEmpty()) {
foreach ($formats as $format) {
$format->delete();
- if (!legacy_config('aggregator_mode_enabled')) {
+ if (!file_config('aggregator_mode_enabled')) {
$this->saveChange($format, null);
}
}
@@ -229,11 +230,13 @@ private function serializeForChange(Format $format): string
]);
}
- public function import(int $rootServerId, Collection $externalObjects): void
+ public function import(int $rootServerId, Collection $externalObjects): FormatImportResult
{
+ $result = new FormatImportResult();
+
// deleted formats
$sourceIds = $externalObjects->pluck('id');
- Format::query()
+ $result->numDeleted = Format::query()
->where('root_server_id', $rootServerId)
->whereNotIn('source_id', $sourceIds)
->delete();
@@ -242,7 +245,7 @@ public function import(int $rootServerId, Collection $externalObjects): void
foreach ($bySourceIdByLanguage as $sourceId => $byLanguage) {
// deleted languages
$languages = $byLanguage->keys();
- Format::query()
+ $result->numDeleted += Format::query()
->where('root_server_id', $rootServerId)
->where('source_id', $sourceId)
->whereNotIn('lang_enum', $languages)
@@ -258,6 +261,7 @@ public function import(int $rootServerId, Collection $externalObjects): void
if ($existingFormats->isEmpty()) {
$values = $this->externalFormatToValuesArray($rootServerId, $sourceId, $externalFormats);
$this->create($values);
+ $result->numCreated++;
} else {
$isDirty = $existingFormats->count() != $externalFormats->count();
if (!$isDirty) {
@@ -274,9 +278,12 @@ public function import(int $rootServerId, Collection $externalObjects): void
$sharedId = $existingFormats->first()->shared_id_bigint;
$values = $this->externalFormatToValuesArray($rootServerId, $sourceId, $externalFormats);
$this->update($sharedId, $values);
+ $result->numUpdated++;
}
}
}
+
+ return $result;
}
private function externalFormatToValuesArray(int $rootServerId, int $sourceId, Collection $externalFormats): array
diff --git a/src/app/Repositories/Import/FormatImportResult.php b/src/app/Repositories/Import/FormatImportResult.php
new file mode 100644
index 000000000..f7f63007c
--- /dev/null
+++ b/src/app/Repositories/Import/FormatImportResult.php
@@ -0,0 +1,10 @@
+ $meeting->id_bigint,
'key' => $t->key,
'field_prompt' => $t->field_prompt,
- 'lang_enum' => $t->lang_enum,
+ 'lang_enum' => file_config('language') ?: App::currentLocale(),
'data_blob' => $fieldValue,
'visibility' => $t->visibility,
]);
@@ -643,19 +645,70 @@ public function create(array $values): Meeting
'meetingid_bigint' => $meeting->id_bigint,
'key' => $t->key,
'field_prompt' => $t->field_prompt,
- 'lang_enum' => $t->lang_enum,
+ 'lang_enum' => file_config('language') ?: App::currentLocale(),
'data_string' => $fieldValue,
'visibility' => $t->visibility,
]);
}
}
- if (!legacy_config('aggregator_mode_enabled')) {
+ if (!file_config('aggregator_mode_enabled')) {
$this->saveChange(null, $meeting);
}
return $meeting;
});
}
-
+ private function getSystemLanguage(): string
+ {
+ return file_config('language') ?: config('app.locale');
+ }
+ public function setTargetLanguage($lang)
+ {
+ $this->targetLanguage = $lang;
+ }
+ private function getTargetLanguage(): string
+ {
+ return $this->targetLanguage ?? $this->getSystemLanguage();
+ }
+ public function translate(int $id, array $values): bool
+ {
+ $dataTemplates = $this->getDataTemplates();
+ return DB::transaction(function () use ($id, $values, $dataTemplates) {
+ $meeting = Meeting::find($id);
+ if (is_null($meeting)) {
+ return false;
+ }
+ MeetingData::query()->where('meetingid_bigint', $id)
+ ->where('lang_enum', $this->getTargetLanguage())
+ ->whereIn('key', array_keys($values))->delete();
+ MeetingLongData::query()->where('meetingid_bigint', $id)
+ ->where('lang_enum', $this->getTargetLanguage())
+ ->whereIn('key', array_keys($values))->delete();
+ foreach ($values as $fieldName => $fieldValue) {
+ $t = $dataTemplates->get($fieldName);
+ if (strlen($fieldValue) > 255) {
+ MeetingLongData::create([
+ 'meetingid_bigint' => $meeting->id_bigint,
+ 'key' => $t->key,
+ 'field_prompt' => $t->field_prompt,
+ 'lang_enum' => $this->getTargetLanguage(),
+ 'data_blob' => $fieldValue,
+ 'visibility' => $t->visibility,
+ ]);
+ } else {
+ MeetingData::create([
+ 'meetingid_bigint' => $meeting->id_bigint,
+ 'key' => $t->key,
+ 'field_prompt' => $t->field_prompt,
+ 'lang_enum' => $this->getTargetLanguage(),
+ 'data_string' => $fieldValue,
+ 'visibility' => $t->visibility,
+ ]);
+ }
+ }
+ return true;
+ });
+ return false;
+ }
public function update(int $id, array $values): bool
{
$values = collect($values);
@@ -665,19 +718,37 @@ public function update(int $id, array $values): bool
return DB::transaction(function () use ($id, $mainValues, $dataValues, $dataTemplates) {
$meeting = Meeting::find($id);
- $meeting->loadMissing(['data', 'longdata']);
+ //TODO: re-enable if needed
+ //$meeting->loadMissing(['data', 'longdata']);
+
if (!is_null($meeting)) {
+ $meetingDataValues = collect($meeting)->reject(fn ($_, $fieldName) => empty($value) || !$dataTemplates->has($fieldName))
+ ->toBase();
Meeting::query()->where('id_bigint', $id)->update($mainValues);
- MeetingData::query()->where('meetingid_bigint', $id)->delete();
- MeetingLongData::query()->where('meetingid_bigint', $id)->delete();
+
+ $oldData = MeetingData::query()->where('meetingid_bigint', $id)
+ ->where('lang_enum', $this->getSystemLanguage())
+ ->whereIn('key', array_keys($dataValues->toArray()))->get()
+ ->merge(
+ MeetingLongData::query()->where('meetingid_bigint', $id)
+ ->where('lang_enum', $this->getSystemLanguage())
+ ->whereIn('key', array_keys($dataValues->toArray()))->get()
+ )->keyby('key');
+ MeetingData::query()->where('meetingid_bigint', $id)->where('lang_enum', $this->getSystemLanguage())->delete();
+ MeetingLongData::query()->where('meetingid_bigint', $id)->where('lang_enum', $this->getSystemLanguage())->delete();
foreach ($dataValues as $fieldName => $fieldValue) {
+ if ($oldData->get($fieldName) != $fieldValue) {
+ $meetingDataValues->forget($fieldName);
+ MeetingData::query()->where('meetingid_bigint', $id)->where('key', $fieldName)->delete();
+ MeetingLongData::query()->where('meetingid_bigint', $id)->where('key', $fieldName)->delete();
+ }
$t = $dataTemplates->get($fieldName);
if (strlen($fieldValue) > 255) {
MeetingLongData::create([
'meetingid_bigint' => $meeting->id_bigint,
'key' => $t->key,
'field_prompt' => $t->field_prompt,
- 'lang_enum' => $t->lang_enum,
+ 'lang_enum' => $this->getTargetLanguage(),
'data_blob' => $fieldValue,
'visibility' => $t->visibility,
]);
@@ -686,13 +757,17 @@ public function update(int $id, array $values): bool
'meetingid_bigint' => $meeting->id_bigint,
'key' => $t->key,
'field_prompt' => $t->field_prompt,
- 'lang_enum' => $t->lang_enum,
+ 'lang_enum' => $this->getTargetLanguage(),
'data_string' => $fieldValue,
'visibility' => $t->visibility,
]);
}
}
- if (!legacy_config('aggregator_mode_enabled')) {
+ foreach ($meetingDataValues as $fieldName => $fieldValue) {
+ MeetingData::query()->where('meetingid_bigint', $id)->where('key', $fieldName)->delete();
+ MeetingLongData::query()->where('meetingid_bigint', $id)->where('key', $fieldName)->delete();
+ }
+ if (!file_config('aggregator_mode_enabled')) {
$this->saveChange($meeting, Meeting::find($id));
}
return true;
@@ -710,7 +785,7 @@ public function delete(int $id): bool
MeetingData::query()->where('meetingid_bigint', $meeting->id_bigint)->delete();
MeetingLongData::query()->where('meetingid_bigint', $meeting->id_bigint)->delete();
Meeting::query()->where('id_bigint', $meeting->id_bigint)->delete();
- if (!legacy_config('aggregator_mode_enabled')) {
+ if (!file_config('aggregator_mode_enabled')) {
$this->saveChange($meeting, null);
}
return true;
@@ -733,18 +808,18 @@ private function saveChange(?Meeting $beforeMeeting, ?Meeting $afterMeeting): vo
// http request there will be a user, which will have a numeric ID.
'user_id_bigint' => request()?->user()?->id_bigint,
'service_body_id_bigint' => $afterMeeting?->service_body_bigint ?? $beforeMeeting->service_body_bigint,
- 'lang_enum' => $beforeMeeting?->lang_enum ?: $afterMeeting?->lang_enum ?: legacy_config('language') ?: App::currentLocale(),
+ 'lang_enum' => $beforeMeeting?->lang_enum ?: $afterMeeting?->lang_enum ?: App::currentLocale(),
'object_class_string' => 'c_comdef_meeting',
'before_id_bigint' => $beforeMeeting?->id_bigint,
- 'before_lang_enum' => !is_null($beforeMeeting) ? $beforeMeeting?->lang_enum ?: legacy_config('language') ?: App::currentLocale() : null,
+ 'before_lang_enum' => !is_null($beforeMeeting) ? $beforeMeeting?->lang_enum ?: App::currentLocale() : null,
'after_id_bigint' => $afterMeeting?->id_bigint,
- 'after_lang_enum' => !is_null($afterMeeting) ? $afterMeeting?->lang_enum ?: legacy_config('language') ?: App::currentLocale() : null,
+ 'after_lang_enum' => !is_null($afterMeeting) ? $afterMeeting?->lang_enum ?: App::currentLocale() : null,
'change_type_enum' => is_null($beforeMeeting) ? 'comdef_change_type_new' : (is_null($afterMeeting) ? 'comdef_change_type_delete' : 'comdef_change_type_change'),
'before_object' => $beforeObject,
'after_object' => $afterObject,
]);
- $changeLimit = legacy_config('change_depth_for_meetings');
+ $changeLimit = bmlt_config('changeDepthForMeetings');
if (is_integer($changeLimit) && $changeLimit > 0) {
$meetingId = $beforeMeeting?->id_bigint ?? $afterMeeting?->id_bigint;
if (!is_null($meetingId)) {
@@ -819,15 +894,16 @@ private function serializeForChange(Meeting $meeting): string
]);
}
- public function import(int $rootServerId, Collection $externalObjects): void
+ public function import(int $rootServerId, Collection $externalObjects): MeetingImportResult
{
+ $result = new MeetingImportResult();
$sourceIds = $externalObjects->map(fn (ExternalMeeting $ex) => $ex->id);
$meetingIds = Meeting::query()
->where('root_server_id', $rootServerId)
->whereNotIn('source_id', $sourceIds)
->pluck('id_bigint');
- Meeting::query()->whereIn('id_bigint', $meetingIds)->delete();
+ $result->numDeleted = Meeting::query()->whereIn('id_bigint', $meetingIds)->delete();
MeetingData::query()->whereIn('meetingid_bigint', $meetingIds)->delete();
MeetingLongData::query()->whereIn('meetingid_bigint', $meetingIds)->delete();
@@ -852,18 +928,23 @@ public function import(int $rootServerId, Collection $externalObjects): void
if (is_null($serviceBodyId)) {
if (!is_null($db)) {
$db->delete();
+ $result->numOrphaned++;
}
continue;
}
if (is_null($db)) {
$values = $this->externalMeetingToValuesArray($rootServerId, $serviceBodyId, $external, $formatSourceIdToSharedIdMap);
- $this->create($values);
+ $this->create($values, 'en');
+ $result->numCreated++;
} else if (!$external->isEqual($db, $serviceBodyIdToSourceIdMap, $formatSharedIdToSourceIdMap)) {
$values = $this->externalMeetingToValuesArray($rootServerId, $serviceBodyId, $external, $formatSourceIdToSharedIdMap);
- $this->update($db->id_bigint, $values);
+ $this->update($db->id_bigint, $values, 'en');
+ $result->numUpdated++;
}
}
+
+ return $result;
}
private function castExternal($obj): ExternalMeeting
diff --git a/src/app/Repositories/RootServerRepository.php b/src/app/Repositories/RootServerRepository.php
index 9247ad382..7d7243f3f 100644
--- a/src/app/Repositories/RootServerRepository.php
+++ b/src/app/Repositories/RootServerRepository.php
@@ -8,6 +8,7 @@
use App\Models\MeetingLongData;
use App\Models\RootServer;
use App\Repositories\External\ExternalRootServer;
+use App\Repositories\Import\RootServerImportResult;
use Illuminate\Support\Collection;
class RootServerRepository implements RootServerRepositoryInterface
@@ -49,24 +50,25 @@ public function delete(int $id): bool
return false;
}
- public function import(Collection $externalObjects): void
+ public function import(Collection $externalObjects): RootServerImportResult
{
+ $result = new RootServerImportResult();
$ignoreRootServerUrls = config('aggregator.ignore_root_servers');
$externalObjects = $externalObjects->reject(fn (ExternalRootServer $ex) => in_array($ex->url, $ignoreRootServerUrls));
$sourceIds = $externalObjects->map(fn (ExternalRootServer $ex) => $ex->id);
- RootServer::query()->whereNotIn('source_id', $sourceIds)->delete();
+ $result->numDeleted = RootServer::query()->whereNotIn('source_id', $sourceIds)->delete();
// TODO test these
MeetingData::query()
->whereNot('meetingid_bigint', 0)
->whereNotIn('meetingid_bigint', function ($query) {
- $query->select('id_bigint')->from((new Meeting)->getTable());
+ $query->select('id_bigint')->from((new Meeting())->getTable());
})->delete();
MeetingLongData::query()
->whereNot('meetingid_bigint', 0)
->whereNotIn('meetingid_bigint', function ($query) {
- $query->select('id_bigint')->from((new Meeting)->getTable());
+ $query->select('id_bigint')->from((new Meeting())->getTable());
})->delete();
foreach ($externalObjects as $externalRoot) {
@@ -75,10 +77,14 @@ public function import(Collection $externalObjects): void
$values = ['source_id' => $externalRoot->id, 'name' => $externalRoot->name, 'url' => $externalRoot->url];
if (is_null($dbRoot)) {
$this->create($values);
+ $result->numCreated++;
} else if (!$externalRoot->isEqual($dbRoot)) {
$this->update($dbRoot->id, $values);
+ $result->numUpdated++;
}
}
+
+ return $result;
}
private function castExternalRootServer($obj): ExternalRootServer
diff --git a/src/app/Repositories/ServiceBodyRepository.php b/src/app/Repositories/ServiceBodyRepository.php
index 7c6d2abdc..c7515e051 100644
--- a/src/app/Repositories/ServiceBodyRepository.php
+++ b/src/app/Repositories/ServiceBodyRepository.php
@@ -7,6 +7,7 @@
use App\Models\RootServer;
use App\Models\ServiceBody;
use App\Repositories\External\ExternalServiceBody;
+use App\Repositories\Import\ServiceBodyImportResult;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\App;
@@ -56,7 +57,7 @@ public function create(array $values): ServiceBody
{
return DB::transaction(function () use ($values) {
$serviceBody = ServiceBody::create($values);
- if (!legacy_config('aggregator_mode_enabled')) {
+ if (!file_config('aggregator_mode_enabled')) {
$this->saveChange(null, $serviceBody);
}
return $serviceBody;
@@ -69,7 +70,7 @@ public function update(int $id, array $values): bool
$serviceBody = ServiceBody::find($id);
if (!is_null($serviceBody)) {
ServiceBody::query()->where('id_bigint', $id)->update($values);
- if (!legacy_config('aggregator_mode_enabled')) {
+ if (!file_config('aggregator_mode_enabled')) {
$this->saveChange($serviceBody, ServiceBody::find($id));
}
return true;
@@ -84,7 +85,7 @@ public function delete(int $id): bool
$serviceBody = ServiceBody::find($id);
if (!is_null($serviceBody)) {
$serviceBody->delete();
- if (!legacy_config('aggregator_mode_enabled')) {
+ if (!file_config('aggregator_mode_enabled')) {
$this->saveChange($serviceBody, null);
}
return true;
@@ -105,12 +106,12 @@ private function saveChange(?ServiceBody $beforeServiceBody, ?ServiceBody $after
Change::create([
'user_id_bigint' => request()->user()->id_bigint,
'service_body_id_bigint' => $afterServiceBody?->id_bigint ?? $beforeServiceBody->id_bigint,
- 'lang_enum' => $beforeServiceBody?->lang_enum ?: $afterServiceBody?->lang_enum ?: legacy_config('language') ?: App::currentLocale(),
+ 'lang_enum' => $beforeServiceBody?->lang_enum ?: $afterServiceBody?->lang_enum ?: App::currentLocale(),
'object_class_string' => 'c_comdef_service_body',
'before_id_bigint' => $beforeServiceBody?->id_bigint,
- 'before_lang_enum' => !is_null($beforeServiceBody) ? $beforeServiceBody?->lang_enum ?: legacy_config('language') ?: App::currentLocale() : null,
+ 'before_lang_enum' => !is_null($beforeServiceBody) ? $beforeServiceBody?->lang_enum ?: App::currentLocale() : null,
'after_id_bigint' => $afterServiceBody?->id_bigint,
- 'after_lang_enum' => !is_null($afterServiceBody) ? $afterServiceBody?->lang_enum ?: legacy_config('language') ?: App::currentLocale() : null,
+ 'after_lang_enum' => !is_null($afterServiceBody) ? $afterServiceBody?->lang_enum ?: App::currentLocale() : null,
'change_type_enum' => is_null($beforeServiceBody) ? 'comdef_change_type_new' : (is_null($afterServiceBody) ? 'comdef_change_type_delete' : 'comdef_change_type_change'),
'before_object' => $beforeObject,
'after_object' => $afterObject,
@@ -128,7 +129,7 @@ private function serializeForChange(ServiceBody $serviceBody): string
$serviceBody->worldid_mixed ?? '',
$serviceBody->name_string,
$serviceBody->description_string,
- $serviceBody->lang_enum ?? legacy_config('language') ?? App::currentLocale(),
+ $serviceBody->lang_enum ?? App::currentLocale(),
$serviceBody->sb_type ?? '',
$serviceBody->sb_owner ?? '',
$serviceBody->sb_owner_2 ?? '',
@@ -235,14 +236,15 @@ public function removeUser(int $userId)
}
}
- public function import(int $rootServerId, Collection $externalObjects): void
+ public function import(int $rootServerId, Collection $externalObjects): ServiceBodyImportResult
{
+ $result = new ServiceBodyImportResult();
$rootServer = RootServer::query()->where('id', $rootServerId)->firstOrFail();
$ignoreServiceBodyIds = collect(config('aggregator.ignore_service_bodies'))->get($rootServer->source_id, []);
$externalObjects = $externalObjects->reject(fn ($ex) => in_array($ex->id, $ignoreServiceBodyIds));
$sourceIds = $externalObjects->map(fn (ExternalServiceBody $ex) => $ex->id);
- ServiceBody::query()
+ $result->numDeleted = ServiceBody::query()
->where('root_server_id', $rootServerId)
->whereNotIn('source_id', $sourceIds)
->delete();
@@ -258,11 +260,13 @@ public function import(int $rootServerId, Collection $externalObjects): void
if (is_null($db)) {
$values = $this->externalServiceBodyToValuesArray($rootServerId, $external);
$bySourceId->put($external->id, $this->create($values));
+ $result->numCreated++;
} else if (!$external->isEqual($db)) {
$values = $this->externalServiceBodyToValuesArray($rootServerId, $external);
$this->update($db->id_bigint, $values);
$db->refresh();
$bySourceId->put($external->id, $db);
+ $result->numUpdated++;
}
}
@@ -276,6 +280,7 @@ public function import(int $rootServerId, Collection $externalObjects): void
if ($db->sb_owner !== 0) {
$db->sb_owner = 0;
$db->save();
+ $result->numReassigned++;
}
continue;
}
@@ -287,8 +292,11 @@ public function import(int $rootServerId, Collection $externalObjects): void
if ($db->sb_owner != $parent->id_bigint) {
$db->sb_owner = $parent->id_bigint;
$db->save();
+ $result->numReassigned++;
}
}
+
+ return $result;
}
private function castExternal($obj): ExternalServiceBody
diff --git a/src/app/Repositories/SettingRepository.php b/src/app/Repositories/SettingRepository.php
new file mode 100644
index 000000000..edde71cc9
--- /dev/null
+++ b/src/app/Repositories/SettingRepository.php
@@ -0,0 +1,46 @@
+where('name', $name)->first();
+ }
+
+ public function getAll(): Collection
+ {
+ return Setting::all();
+ }
+
+ public function update(string $key, $value): bool
+ {
+ $setting = Setting::updateOrCreate(
+ ['name' => $key],
+ ['value' => $value]
+ );
+
+ return $setting->wasRecentlyCreated || $setting->wasChanged();
+ }
+
+ public function updateMultiple(array $keyValuePairs): bool
+ {
+ return DB::transaction(function () use ($keyValuePairs) {
+ $success = true;
+
+ foreach ($keyValuePairs as $key => $value) {
+ if (!$this->update($key, $value)) {
+ $success = false;
+ }
+ }
+
+ return $success;
+ });
+ }
+}
diff --git a/src/app/Repositories/UserRepository.php b/src/app/Repositories/UserRepository.php
index 869fbb668..977a522fe 100644
--- a/src/app/Repositories/UserRepository.php
+++ b/src/app/Repositories/UserRepository.php
@@ -90,7 +90,6 @@ public function delete(int $id): bool
return false;
});
}
-
private function saveChange(?User $beforeUser, ?User $afterUser): void
{
$beforeObject = !is_null($beforeUser) ? $this->serializeForChange($beforeUser) : null;
@@ -103,12 +102,12 @@ private function saveChange(?User $beforeUser, ?User $afterUser): void
Change::create([
'user_id_bigint' => request()->user()?->id_bigint ?? $beforeUser?->id_bigint ?? $afterUser?->id_bigint,
'service_body_id_bigint' => $afterUser?->id_bigint ?? $beforeUser->id_bigint,
- 'lang_enum' => $beforeUser?->lang_enum ?: $afterUser?->lang_enum ?: legacy_config('language') ?: App::currentLocale(),
+ 'lang_enum' => $beforeUser?->lang_enum ?: $afterUser?->lang_enum ?: App::currentLocale(),
'object_class_string' => 'c_comdef_user',
'before_id_bigint' => $beforeUser?->id_bigint,
- 'before_lang_enum' => !is_null($beforeUser) ? $beforeUser?->lang_enum ?: legacy_config('language') ?: App::currentLocale() : null,
+ 'before_lang_enum' => !is_null($beforeUser) ? $beforeUser?->lang_enum ?: App::currentLocale() : null,
'after_id_bigint' => $afterUser?->id_bigint,
- 'after_lang_enum' => !is_null($afterUser) ? $afterUser?->lang_enum ?: legacy_config('language') ?: App::currentLocale() : null,
+ 'after_lang_enum' => !is_null($afterUser) ? $afterUser?->lang_enum ?: App::currentLocale() : null,
'change_type_enum' => is_null($beforeUser) ? 'comdef_change_type_new' : (is_null($afterUser) ? 'comdef_change_type_delete' : 'comdef_change_type_change'),
'before_object' => $beforeObject,
'after_object' => $afterObject,
diff --git a/src/app/Rules/FormatTranslationKey.php b/src/app/Rules/FormatTranslationKey.php
new file mode 100644
index 000000000..caa6566be
--- /dev/null
+++ b/src/app/Rules/FormatTranslationKey.php
@@ -0,0 +1,69 @@
+formatRepository = $formatRepository;
+ $this->formatId = $formatId;
+ }
+
+ public function validate(string $attribute, mixed $value, Closure $fail): void
+ {
+ $translation = $this->data['translations'][intval(explode('.', $attribute)[1])];
+ if (!isset($translation['language'])) {
+ // we can trust that another validator will fail this
+ return;
+ }
+
+ if ($translation['language'] == 'en') {
+ if (is_null($this->formatId)) {
+ if ($value == 'VM' || $value == 'HY' || $value == 'TC') {
+ $fail(':attribute cannot be VM, HY, or TC for the english translation.');
+ }
+ } else {
+ $existingFormat = $this->formatRepository->search(formatsInclude: [$this->formatId], langEnums: ['en'], showAll: true)->first();
+ if (is_null($existingFormat)) {
+ if ($value == 'VM' || $value == 'HY' || $value == 'TC') {
+ $fail(':attribute cannot be VM, HY, or TC for the english translation.');
+ }
+ } else {
+ if ($existingFormat->key_string == 'VM' && $value != 'VM') {
+ $fail(':attribute cannot be changed for the english VM format.');
+ } elseif ($existingFormat->key_string == 'HY' && $value != 'HY') {
+ $fail(':attribute cannot be changed for the english HY format.');
+ } elseif ($existingFormat->key_string == 'TC' && $value != 'TC') {
+ $fail(':attribute cannot be changed for the english TC format.');
+ }
+ }
+ }
+ }
+
+ $duplicates = $this->formatRepository->search(
+ formatsExclude: is_null($this->formatId) ? null : [$this->formatId],
+ langEnums: [$translation['language']],
+ keyStrings: [$value],
+ showAll: true
+ );
+ if ($duplicates->isNotEmpty()) {
+ $fail(':attribute cannot be the same as another format\'s for the same language.');
+ }
+ }
+
+ public function setData(array $data): static
+ {
+ $this->data = $data;
+ return $this;
+ }
+}
diff --git a/src/app/Rules/FormatTranslations.php b/src/app/Rules/FormatTranslations.php
new file mode 100644
index 000000000..93f4e679f
--- /dev/null
+++ b/src/app/Rules/FormatTranslations.php
@@ -0,0 +1,39 @@
+formatRepository = $formatRepository;
+ $this->formatId = $formatId;
+ }
+
+ public function validate(string $attribute, mixed $value, Closure $fail): void
+ {
+ if (is_null($this->formatId)) {
+ return;
+ }
+
+ $virtualFormatId = $this->formatRepository->getVirtualFormat()->shared_id_bigint;
+ $hybridFormatId = $this->formatRepository->getHybridFormat()->shared_id_bigint;
+ $tempClosedFormatId = $this->formatRepository->getTemporarilyClosedFormat()->shared_id_bigint;
+ $reservedFormatIds = [$virtualFormatId, $hybridFormatId, $tempClosedFormatId];
+ if (!in_array($this->formatId, $reservedFormatIds)) {
+ return;
+ }
+
+ $translations = collect($value);
+ if ($translations->filter(fn ($t) => $t['language'] == 'en')->isEmpty()) {
+ $fail("the english translation of a reserved format cannot be deleted.");
+ }
+ }
+}
diff --git a/src/app/helpers.php b/src/app/helpers.php
index bc0ee3674..6c2bc5b8d 100644
--- a/src/app/helpers.php
+++ b/src/app/helpers.php
@@ -1,11 +1,19 @@
=7.4",
+ "phpstan/phpdoc-parser": "^2.0",
"psr/log": "^1.1 || ^2.0 || ^3.0",
"symfony/deprecation-contracts": "^2 || ^3",
"symfony/finder": "^5.0 || ^6.0 || ^7.0",
- "symfony/yaml": "^5.0 || ^6.0 || ^7.0"
+ "symfony/yaml": "^5.4 || ^6.0 || ^7.0"
},
"conflict": {
"symfony/process": ">=6, <6.4.14"
@@ -7015,7 +7070,8 @@
"vimeo/psalm": "^4.30 || ^5.0"
},
"suggest": {
- "doctrine/annotations": "^2.0"
+ "doctrine/annotations": "^2.0",
+ "radebatz/type-info-extras": "^1.0.2"
},
"bin": [
"bin/openapi"
@@ -7061,9 +7117,9 @@
],
"support": {
"issues": "https://github.com/zircote/swagger-php/issues",
- "source": "https://github.com/zircote/swagger-php/tree/5.3.0"
+ "source": "https://github.com/zircote/swagger-php/tree/5.7.0"
},
- "time": "2025-08-14T23:31:27+00:00"
+ "time": "2025-11-11T03:41:35+00:00"
}
],
"packages-dev": [
@@ -7509,16 +7565,16 @@
},
{
"name": "larastan/larastan",
- "version": "v3.6.0",
+ "version": "v3.8.0",
"source": {
"type": "git",
"url": "https://github.com/larastan/larastan.git",
- "reference": "6431d010dd383a9279eb8874a76ddb571738564a"
+ "reference": "d13ef96d652d1b2a8f34f1760ba6bf5b9c98112e"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/larastan/larastan/zipball/6431d010dd383a9279eb8874a76ddb571738564a",
- "reference": "6431d010dd383a9279eb8874a76ddb571738564a",
+ "url": "https://api.github.com/repos/larastan/larastan/zipball/d13ef96d652d1b2a8f34f1760ba6bf5b9c98112e",
+ "reference": "d13ef96d652d1b2a8f34f1760ba6bf5b9c98112e",
"shasum": ""
},
"require": {
@@ -7532,7 +7588,7 @@
"illuminate/pipeline": "^11.44.2 || ^12.4.1",
"illuminate/support": "^11.44.2 || ^12.4.1",
"php": "^8.2",
- "phpstan/phpstan": "^2.1.11"
+ "phpstan/phpstan": "^2.1.29"
},
"require-dev": {
"doctrine/coding-standard": "^13",
@@ -7545,7 +7601,8 @@
"phpunit/phpunit": "^10.5.35 || ^11.5.15"
},
"suggest": {
- "orchestra/testbench": "Using Larastan for analysing a package needs Testbench"
+ "orchestra/testbench": "Using Larastan for analysing a package needs Testbench",
+ "phpmyadmin/sql-parser": "Install to enable Larastan's optional phpMyAdmin-based SQL parser automatically"
},
"type": "phpstan-extension",
"extra": {
@@ -7586,7 +7643,7 @@
],
"support": {
"issues": "https://github.com/larastan/larastan/issues",
- "source": "https://github.com/larastan/larastan/tree/v3.6.0"
+ "source": "https://github.com/larastan/larastan/tree/v3.8.0"
},
"funding": [
{
@@ -7594,20 +7651,20 @@
"type": "github"
}
],
- "time": "2025-07-11T06:52:52+00:00"
+ "time": "2025-10-27T23:09:14+00:00"
},
{
"name": "laravel/pint",
- "version": "v1.24.0",
+ "version": "v1.25.1",
"source": {
"type": "git",
"url": "https://github.com/laravel/pint.git",
- "reference": "0345f3b05f136801af8c339f9d16ef29e6b4df8a"
+ "reference": "5016e263f95d97670d71b9a987bd8996ade6d8d9"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/laravel/pint/zipball/0345f3b05f136801af8c339f9d16ef29e6b4df8a",
- "reference": "0345f3b05f136801af8c339f9d16ef29e6b4df8a",
+ "url": "https://api.github.com/repos/laravel/pint/zipball/5016e263f95d97670d71b9a987bd8996ade6d8d9",
+ "reference": "5016e263f95d97670d71b9a987bd8996ade6d8d9",
"shasum": ""
},
"require": {
@@ -7618,9 +7675,9 @@
"php": "^8.2.0"
},
"require-dev": {
- "friendsofphp/php-cs-fixer": "^3.82.2",
- "illuminate/view": "^11.45.1",
- "larastan/larastan": "^3.5.0",
+ "friendsofphp/php-cs-fixer": "^3.87.2",
+ "illuminate/view": "^11.46.0",
+ "larastan/larastan": "^3.7.1",
"laravel-zero/framework": "^11.45.0",
"mockery/mockery": "^1.6.12",
"nunomaduro/termwind": "^2.3.1",
@@ -7631,9 +7688,6 @@
],
"type": "project",
"autoload": {
- "files": [
- "overrides/Runner/Parallel/ProcessFactory.php"
- ],
"psr-4": {
"App\\": "app/",
"Database\\Seeders\\": "database/seeders/",
@@ -7663,20 +7717,20 @@
"issues": "https://github.com/laravel/pint/issues",
"source": "https://github.com/laravel/pint"
},
- "time": "2025-07-10T18:09:32+00:00"
+ "time": "2025-09-19T02:57:12+00:00"
},
{
"name": "laravel/sail",
- "version": "v1.44.0",
+ "version": "v1.48.0",
"source": {
"type": "git",
"url": "https://github.com/laravel/sail.git",
- "reference": "a09097bd2a8a38e23ac472fa6a6cf5b0d1c1d3fe"
+ "reference": "1bf3b8870b72a258a3b6b5119435835ece522e8a"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/laravel/sail/zipball/a09097bd2a8a38e23ac472fa6a6cf5b0d1c1d3fe",
- "reference": "a09097bd2a8a38e23ac472fa6a6cf5b0d1c1d3fe",
+ "url": "https://api.github.com/repos/laravel/sail/zipball/1bf3b8870b72a258a3b6b5119435835ece522e8a",
+ "reference": "1bf3b8870b72a258a3b6b5119435835ece522e8a",
"shasum": ""
},
"require": {
@@ -7689,7 +7743,7 @@
},
"require-dev": {
"orchestra/testbench": "^7.0|^8.0|^9.0|^10.0",
- "phpstan/phpstan": "^1.10"
+ "phpstan/phpstan": "^2.0"
},
"bin": [
"bin/sail"
@@ -7726,20 +7780,20 @@
"issues": "https://github.com/laravel/sail/issues",
"source": "https://github.com/laravel/sail"
},
- "time": "2025-07-04T16:17:06+00:00"
+ "time": "2025-11-09T14:46:21+00:00"
},
{
"name": "league/csv",
- "version": "9.24.1",
+ "version": "9.27.1",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/csv.git",
- "reference": "e0221a3f16aa2a823047d59fab5809d552e29bc8"
+ "reference": "26de738b8fccf785397d05ee2fc07b6cd8749797"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/thephpleague/csv/zipball/e0221a3f16aa2a823047d59fab5809d552e29bc8",
- "reference": "e0221a3f16aa2a823047d59fab5809d552e29bc8",
+ "url": "https://api.github.com/repos/thephpleague/csv/zipball/26de738b8fccf785397d05ee2fc07b6cd8749797",
+ "reference": "26de738b8fccf785397d05ee2fc07b6cd8749797",
"shasum": ""
},
"require": {
@@ -7755,7 +7809,7 @@
"phpstan/phpstan-deprecation-rules": "^1.2.1",
"phpstan/phpstan-phpunit": "^1.4.2",
"phpstan/phpstan-strict-rules": "^1.6.2",
- "phpunit/phpunit": "^10.5.16 || ^11.5.22",
+ "phpunit/phpunit": "^10.5.16 || ^11.5.22 || ^12.3.6",
"symfony/var-dumper": "^6.4.8 || ^7.3.0"
},
"suggest": {
@@ -7817,7 +7871,7 @@
"type": "github"
}
],
- "time": "2025-06-25T14:53:51+00:00"
+ "time": "2025-10-25T08:35:20+00:00"
},
{
"name": "mockery/mockery",
@@ -8181,16 +8235,11 @@
},
{
"name": "phpstan/phpstan",
- "version": "2.1.22",
- "source": {
- "type": "git",
- "url": "https://github.com/phpstan/phpstan.git",
- "reference": "41600c8379eb5aee63e9413fe9e97273e25d57e4"
- },
+ "version": "2.1.32",
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpstan/phpstan/zipball/41600c8379eb5aee63e9413fe9e97273e25d57e4",
- "reference": "41600c8379eb5aee63e9413fe9e97273e25d57e4",
+ "url": "https://api.github.com/repos/phpstan/phpstan/zipball/e126cad1e30a99b137b8ed75a85a676450ebb227",
+ "reference": "e126cad1e30a99b137b8ed75a85a676450ebb227",
"shasum": ""
},
"require": {
@@ -8235,20 +8284,20 @@
"type": "github"
}
],
- "time": "2025-08-04T19:17:37+00:00"
+ "time": "2025-11-11T15:18:17+00:00"
},
{
"name": "phpunit/php-code-coverage",
- "version": "11.0.10",
+ "version": "11.0.11",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
- "reference": "1a800a7446add2d79cc6b3c01c45381810367d76"
+ "reference": "4f7722aa9a7b76aa775e2d9d4e95d1ea16eeeef4"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/1a800a7446add2d79cc6b3c01c45381810367d76",
- "reference": "1a800a7446add2d79cc6b3c01c45381810367d76",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/4f7722aa9a7b76aa775e2d9d4e95d1ea16eeeef4",
+ "reference": "4f7722aa9a7b76aa775e2d9d4e95d1ea16eeeef4",
"shasum": ""
},
"require": {
@@ -8305,7 +8354,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
"security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
- "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/show"
+ "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/11.0.11"
},
"funding": [
{
@@ -8325,7 +8374,7 @@
"type": "tidelift"
}
],
- "time": "2025-06-18T08:56:18+00:00"
+ "time": "2025-08-27T14:37:49+00:00"
},
{
"name": "phpunit/php-file-iterator",
@@ -8574,16 +8623,16 @@
},
{
"name": "phpunit/phpunit",
- "version": "11.5.33",
+ "version": "11.5.44",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
- "reference": "5965e9ff57546cb9137c0ff6aa78cb7442b05cf6"
+ "reference": "c346885c95423eda3f65d85a194aaa24873cda82"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/5965e9ff57546cb9137c0ff6aa78cb7442b05cf6",
- "reference": "5965e9ff57546cb9137c0ff6aa78cb7442b05cf6",
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c346885c95423eda3f65d85a194aaa24873cda82",
+ "reference": "c346885c95423eda3f65d85a194aaa24873cda82",
"shasum": ""
},
"require": {
@@ -8597,7 +8646,7 @@
"phar-io/manifest": "^2.0.4",
"phar-io/version": "^3.2.1",
"php": ">=8.2",
- "phpunit/php-code-coverage": "^11.0.10",
+ "phpunit/php-code-coverage": "^11.0.11",
"phpunit/php-file-iterator": "^5.1.0",
"phpunit/php-invoker": "^5.0.1",
"phpunit/php-text-template": "^4.0.1",
@@ -8607,7 +8656,7 @@
"sebastian/comparator": "^6.3.2",
"sebastian/diff": "^6.0.2",
"sebastian/environment": "^7.2.1",
- "sebastian/exporter": "^6.3.0",
+ "sebastian/exporter": "^6.3.2",
"sebastian/global-state": "^7.0.2",
"sebastian/object-enumerator": "^6.0.1",
"sebastian/type": "^5.1.3",
@@ -8655,7 +8704,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
- "source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.33"
+ "source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.44"
},
"funding": [
{
@@ -8679,7 +8728,7 @@
"type": "tidelift"
}
],
- "time": "2025-08-16T05:19:02+00:00"
+ "time": "2025-11-13T07:17:35+00:00"
},
{
"name": "sebastian/cli-parser",
@@ -9146,16 +9195,16 @@
},
{
"name": "sebastian/exporter",
- "version": "6.3.0",
+ "version": "6.3.2",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/exporter.git",
- "reference": "3473f61172093b2da7de1fb5782e1f24cc036dc3"
+ "reference": "70a298763b40b213ec087c51c739efcaa90bcd74"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/3473f61172093b2da7de1fb5782e1f24cc036dc3",
- "reference": "3473f61172093b2da7de1fb5782e1f24cc036dc3",
+ "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/70a298763b40b213ec087c51c739efcaa90bcd74",
+ "reference": "70a298763b40b213ec087c51c739efcaa90bcd74",
"shasum": ""
},
"require": {
@@ -9169,7 +9218,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-main": "6.1-dev"
+ "dev-main": "6.3-dev"
}
},
"autoload": {
@@ -9212,15 +9261,27 @@
"support": {
"issues": "https://github.com/sebastianbergmann/exporter/issues",
"security": "https://github.com/sebastianbergmann/exporter/security/policy",
- "source": "https://github.com/sebastianbergmann/exporter/tree/6.3.0"
+ "source": "https://github.com/sebastianbergmann/exporter/tree/6.3.2"
},
"funding": [
{
"url": "https://github.com/sebastianbergmann",
"type": "github"
+ },
+ {
+ "url": "https://liberapay.com/sebastianbergmann",
+ "type": "liberapay"
+ },
+ {
+ "url": "https://thanks.dev/u/gh/sebastianbergmann",
+ "type": "thanks_dev"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/sebastian/exporter",
+ "type": "tidelift"
}
],
- "time": "2024-12-05T09:17:50+00:00"
+ "time": "2025-09-24T06:12:51+00:00"
},
{
"name": "sebastian/global-state",
@@ -9657,16 +9718,16 @@
},
{
"name": "spatie/backtrace",
- "version": "1.7.4",
+ "version": "1.8.1",
"source": {
"type": "git",
"url": "https://github.com/spatie/backtrace.git",
- "reference": "cd37a49fce7137359ac30ecc44ef3e16404cccbe"
+ "reference": "8c0f16a59ae35ec8c62d85c3c17585158f430110"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/spatie/backtrace/zipball/cd37a49fce7137359ac30ecc44ef3e16404cccbe",
- "reference": "cd37a49fce7137359ac30ecc44ef3e16404cccbe",
+ "url": "https://api.github.com/repos/spatie/backtrace/zipball/8c0f16a59ae35ec8c62d85c3c17585158f430110",
+ "reference": "8c0f16a59ae35ec8c62d85c3c17585158f430110",
"shasum": ""
},
"require": {
@@ -9704,7 +9765,8 @@
"spatie"
],
"support": {
- "source": "https://github.com/spatie/backtrace/tree/1.7.4"
+ "issues": "https://github.com/spatie/backtrace/issues",
+ "source": "https://github.com/spatie/backtrace/tree/1.8.1"
},
"funding": [
{
@@ -9716,7 +9778,7 @@
"type": "other"
}
],
- "time": "2025-05-08T15:41:09+00:00"
+ "time": "2025-08-26T08:22:30+00:00"
},
{
"name": "spatie/error-solutions",
@@ -10037,16 +10099,16 @@
},
{
"name": "squizlabs/php_codesniffer",
- "version": "3.13.2",
+ "version": "3.13.5",
"source": {
"type": "git",
"url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git",
- "reference": "5b5e3821314f947dd040c70f7992a64eac89025c"
+ "reference": "0ca86845ce43291e8f5692c7356fccf3bcf02bf4"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/5b5e3821314f947dd040c70f7992a64eac89025c",
- "reference": "5b5e3821314f947dd040c70f7992a64eac89025c",
+ "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/0ca86845ce43291e8f5692c7356fccf3bcf02bf4",
+ "reference": "0ca86845ce43291e8f5692c7356fccf3bcf02bf4",
"shasum": ""
},
"require": {
@@ -10063,11 +10125,6 @@
"bin/phpcs"
],
"type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "3.x-dev"
- }
- },
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
@@ -10117,7 +10174,7 @@
"type": "thanks_dev"
}
],
- "time": "2025-06-17T22:17:01+00:00"
+ "time": "2025-11-04T16:30:35+00:00"
},
{
"name": "staabm/side-effects-detector",
diff --git a/src/config/aggregator.php b/src/config/aggregator.php
index 8ad900296..558fc3160 100644
--- a/src/config/aggregator.php
+++ b/src/config/aggregator.php
@@ -3,13 +3,13 @@
return [
'ignore_root_servers' => json_decode(env('AGGREGATOR_IGNORE_ROOT_SERVERS') ?? 'null') ?? [],
'ignore_service_bodies' => json_decode(env('AGGREGATOR_IGNORE_SERVICE_BODIES') ?? 'null') ?? [
- 120 => [ # {"id":"120","name":"NA New Jersey","rootURL":"https://www.narcoticsanonymousnj.org/main_server/"}
+ 120 => [ # {"id":"120","name":"NA New Jersey","url":"https://www.narcoticsanonymousnj.org/main_server/"}
31, 32, # Duplicated Eastern New York Region
27, 28 # Duplicated Greater Philadelphia Region
],
],
'rate_limit_root_servers' => json_decode(env('AGGREGATOR_RATE_LIMIT_ROOT_SERVERS') ?? 'null') ?? [
- # {"id":"139","name":"NA Argentina","rootURL":"https://www.na.org.ar/main_server/"},
+ # {"id":"139","name":"NA Argentina","url":"https://www.na.org.ar/main_server/"},
139 => ['request_delay' => 10, 'retry_delay' => 300],
],
];
diff --git a/src/config/app.php b/src/config/app.php
index 055a7c8f5..2085482a1 100644
--- a/src/config/app.php
+++ b/src/config/app.php
@@ -15,7 +15,7 @@
|
*/
- 'name' => env('APP_NAME', 'BMLT Root Server'),
+ 'name' => env('APP_NAME', 'BMLT Server'),
/*
@@ -28,7 +28,7 @@
| or any other location as required by the application or its packages.
*/
- 'version' => env('APP_VERSION', '4.0.0'),
+ 'version' => env('APP_VERSION', '4.1.0'),
/*
|--------------------------------------------------------------------------
@@ -106,7 +106,10 @@
|
*/
- 'locale' => legacy_config('language', 'en'),
+ // Note: Cannot load from database because config files are loaded before DB connection.
+ // This is just a fallback, actual language comes from setting in database.
+ // Note that language specific translations for things like server error messages probably wont work.
+ 'locale' => 'en',
/*
|--------------------------------------------------------------------------
diff --git a/src/config/broadcasting.php b/src/config/broadcasting.php
index 168824244..3fe737e3e 100644
--- a/src/config/broadcasting.php
+++ b/src/config/broadcasting.php
@@ -36,7 +36,7 @@
'secret' => env('PUSHER_APP_SECRET'),
'app_id' => env('PUSHER_APP_ID'),
'options' => [
- 'host' => env('PUSHER_HOST', 'api-'.env('PUSHER_APP_CLUSTER', 'mt1').'.pusher.com') ?: 'api-'.env('PUSHER_APP_CLUSTER', 'mt1').'.pusher.com',
+ 'host' => env('PUSHER_HOST', 'api-' . env('PUSHER_APP_CLUSTER', 'mt1') . '.pusher.com') ?: 'api-' . env('PUSHER_APP_CLUSTER', 'mt1') . '.pusher.com',
'port' => env('PUSHER_PORT', 443),
'scheme' => env('PUSHER_SCHEME', 'https'),
'encrypted' => true,
diff --git a/src/config/cache.php b/src/config/cache.php
index 33bb29546..daf5e68be 100644
--- a/src/config/cache.php
+++ b/src/config/cache.php
@@ -105,6 +105,6 @@
|
*/
- 'prefix' => env('CACHE_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_cache_'),
+ 'prefix' => env('CACHE_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_') . '_cache_'),
];
diff --git a/src/config/database.php b/src/config/database.php
index 26ce537b2..92f3c16c7 100644
--- a/src/config/database.php
+++ b/src/config/database.php
@@ -2,6 +2,13 @@
use Illuminate\Support\Str;
+$dbPrefix = file_config('db_prefix', '');
+if ($dbPrefix) {
+ $dbPrefix = $dbPrefix . '_';
+} elseif (env('APP_ENV') === 'testing') {
+ $dbPrefix = 'test_';
+}
+
return [
/*
@@ -38,15 +45,15 @@
'mysql' => [
'driver' => 'mysql',
'url' => env('DATABASE_URL'),
- 'host' => legacy_config('db_host', '0.0.0.0'),
+ 'host' => file_config('db_host', '0.0.0.0'),
'port' => env('DB_PORT', '3306'),
- 'database' => legacy_config('db_database'),
- 'username' => legacy_config('db_username'),
- 'password' => legacy_config('db_password'),
+ 'database' => file_config('db_database'),
+ 'username' => file_config('db_username'),
+ 'password' => file_config('db_password'),
'unix_socket' => env('DB_SOCKET', ''),
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
- 'prefix' => legacy_config('db_prefix') ? legacy_config('db_prefix') . '_' : 'test_',
+ 'prefix' => $dbPrefix,
'prefix_indexes' => true,
'strict' => true,
'engine' => 'InnoDB',
@@ -58,15 +65,15 @@
'test' => [
'driver' => 'mysql',
'url' => env('DATABASE_URL'),
- 'host' => legacy_config('db_host', '0.0.0.0'),
+ 'host' => file_config('db_host', '0.0.0.0'),
'port' => env('DB_PORT', '3306'),
- 'database' => legacy_config('db_database', 'rootserver'),
- 'username' => legacy_config('db_username', 'root'),
- 'password' => legacy_config('db_password', 'rootserver'),
+ 'database' => file_config('db_database', 'rootserver'),
+ 'username' => file_config('db_username', 'root'),
+ 'password' => file_config('db_password', 'rootserver'),
'unix_socket' => env('DB_SOCKET', ''),
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
- 'prefix' => legacy_config('db_prefix') ? legacy_config('db_prefix') . '_' : 'test_',
+ 'prefix' => $dbPrefix,
'prefix_indexes' => true,
'strict' => true,
'engine' => 'InnoDB',
@@ -106,7 +113,7 @@
'options' => [
'cluster' => env('REDIS_CLUSTER', 'redis'),
- 'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_database_'),
+ 'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_') . '_database_'),
],
'default' => [
diff --git a/src/config/filesystems.php b/src/config/filesystems.php
index fefc24464..6b55fbe23 100644
--- a/src/config/filesystems.php
+++ b/src/config/filesystems.php
@@ -45,7 +45,7 @@
'public' => [
'driver' => 'local',
'root' => storage_path('app/public'),
- 'url' => env('APP_URL').'/storage',
+ 'url' => env('APP_URL') . '/storage',
'visibility' => 'public',
'throw' => false,
],
diff --git a/src/config/logging.php b/src/config/logging.php
index 5aa1dbb78..752af7110 100644
--- a/src/config/logging.php
+++ b/src/config/logging.php
@@ -85,7 +85,7 @@
'handler_with' => [
'host' => env('PAPERTRAIL_URL'),
'port' => env('PAPERTRAIL_PORT'),
- 'connectionString' => 'tls://'.env('PAPERTRAIL_URL').':'.env('PAPERTRAIL_PORT'),
+ 'connectionString' => 'tls://' . env('PAPERTRAIL_URL') . ':' . env('PAPERTRAIL_PORT'),
],
],
diff --git a/src/config/session.php b/src/config/session.php
index 749008183..b271aa8a5 100644
--- a/src/config/session.php
+++ b/src/config/session.php
@@ -128,7 +128,7 @@
'cookie' => env(
'SESSION_COOKIE',
- Str::slug(env('APP_NAME', 'laravel'), '_').'_session'
+ Str::slug(env('APP_NAME', 'laravel'), '_') . '_session'
),
/*
diff --git a/src/database/migrations/1901_01_01_000000_legacy_migrations.php b/src/database/migrations/1901_01_01_000000_legacy_migrations.php
index 98a06450d..824ee4f5a 100644
--- a/src/database/migrations/1901_01_01_000000_legacy_migrations.php
+++ b/src/database/migrations/1901_01_01_000000_legacy_migrations.php
@@ -25,8 +25,6 @@ public function up()
$dbName = config('database.connections.mysql.database');
$dbPrefix = rtrim(config('database.connections.mysql.prefix'), '_');
- require_once(__DIR__."/../../legacy/server/shared/classes/VenueType.php");
-
// Make sure version table exists
$versionTableName = $dbPrefix . "_comdef_db_version";
$sql = "SELECT COUNT(*) as count FROM information_schema.tables WHERE TABLE_SCHEMA = '$dbName' AND TABLE_NAME = '$versionTableName'";
@@ -459,9 +457,9 @@ function getFormatStrFilter($formatId, $hasFormat)
return $filter . ")";
}
- $VENUE_TYPE_HYBRID = VenueType::HYBRID;
- $VENUE_TYPE_VIRTUAL = VenueType::VIRTUAL;
- $VENUE_TYPE_IN_PERSON = VenueType::IN_PERSON;
+ $VENUE_TYPE_HYBRID = 3;
+ $VENUE_TYPE_VIRTUAL = 2;
+ $VENUE_TYPE_IN_PERSON = 1;
$vmFormatId = getFormatId($this, "VM");
$hyFormatId = getFormatId($this, "HY");
$tcFormatId = getFormatId($this, "TC");
diff --git a/src/database/migrations/1902_01_01_000000_create_initial_schema.php b/src/database/migrations/1902_01_01_000000_create_initial_schema.php
index 658bcbd91..17876c283 100644
--- a/src/database/migrations/1902_01_01_000000_create_initial_schema.php
+++ b/src/database/migrations/1902_01_01_000000_create_initial_schema.php
@@ -182,7 +182,7 @@ public function up()
$table->index('key_string', 'key_string');
$table->index(['root_server_id', 'source_id'], 'root_server_id_source_id');
});
- if (!legacy_config('aggregator_mode_enabled')) {
+ if (!file_config('aggregator_mode_enabled')) {
// aggregator mode does not need any stock data
DB::table('comdef_formats')->insert([
['shared_id_bigint' => 1, 'key_string' => 'B', 'worldid_mixed' => 'BEG', 'lang_enum' => 'de', 'name_string' => 'Beginners', 'description_string' => 'This meeting is focused on the needs of new members of NA.', 'format_type_enum' => 'FC3'],
@@ -456,7 +456,7 @@ public function up()
['shared_id_bigint' => 35, 'key_string' => 'M', 'worldid_mixed' => null, 'lang_enum' => 'it', 'name_string' => 'Maratona', 'description_string' => 'Durata non prestabilita. La riunione prosegue finché tutti i presenti hanno da condividere.', 'format_type_enum' => 'FC1'],
['shared_id_bigint' => 37, 'key_string' => 'NF', 'worldid_mixed' => null, 'lang_enum' => 'it', 'name_string' => 'Non fumatori', 'description_string' => 'In queste riunioni non è consentito fumare.', 'format_type_enum' => 'FC1'],
['shared_id_bigint' => 40, 'key_string' => 'TS', 'worldid_mixed' => null, 'lang_enum' => 'it', 'name_string' => 'Tema a sorpresa', 'description_string' => 'L\'argomento su cui condividere è scritto su un biglietto o altro supporto (es. un bastoncino di legno) ed estratto a caso da ciascun membro.', 'format_type_enum' => 'FC1'],
- ['shared_id_bigint' => 42, 'key_string' => 'M', 'worldid_mixed' => null, 'lang_enum' => 'it', 'name_string' => 'Meditazione', 'description_string' => 'In questa riunione sono poste restrizioni alle modalità di partecipazione.', 'format_type_enum' => 'FC3'],
+ ['shared_id_bigint' => 42, 'key_string' => 'AR', 'worldid_mixed' => null, 'lang_enum' => 'it', 'name_string' => 'Accesso ristretto', 'description_string' => 'In questa riunione sono poste restrizioni alle modalità di partecipazione.', 'format_type_enum' => 'FC3'],
['shared_id_bigint' => 43, 'key_string' => 'D/R', 'worldid_mixed' => null, 'lang_enum' => 'it', 'name_string' => 'Domande e risposteq', 'description_string' => 'I partecipanti possono fare domande e attenderne la risposta dagli altri membri del gruppo.', 'format_type_enum' => 'FC1'],
['shared_id_bigint' => 44, 'key_string' => 'Ba', 'worldid_mixed' => null, 'lang_enum' => 'it', 'name_string' => 'Bambini', 'description_string' => 'I bambini sono benvenuti in queste riunioni.', 'format_type_enum' => 'FC3'],
['shared_id_bigint' => 45, 'key_string' => 'C', 'worldid_mixed' => null, 'lang_enum' => 'it', 'name_string' => 'Concetti di servizio', 'description_string' => 'Riunioni basate sulla discussione dei Dodici concetti per il servizio in NA.', 'format_type_enum' => 'FC1'],
@@ -522,7 +522,7 @@ public function up()
['shared_id_bigint' => 3, 'key_string' => 'TB', 'worldid_mixed' => 'BT', 'lang_enum' => 'pt', 'name_string' => 'Texto Básico', 'description_string' => 'Esta reunião tem foco no debate sobre o Texto Básico de Narcóticos Anônimos.', 'format_type_enum' => 'FC1'],
['shared_id_bigint' => 4, 'key_string' => 'F', 'worldid_mixed' => 'CLOSED', 'lang_enum' => 'pt', 'name_string' => 'Fechada', 'description_string' => 'Esta reunião fechada para não adictos. Você deve ir apenas se acredita ter problemas com abuso de substâncias.', 'format_type_enum' => 'O'],
['shared_id_bigint' => 5, 'key_string' => 'FF', 'worldid_mixed' => 'CH', 'lang_enum' => 'pt', 'name_string' => 'Fechada em feriados', 'description_string' => 'Esta reunião acontece em local que geralmente é fechado em feirados.', 'format_type_enum' => 'FC3'],
- ['shared_id_bigint' => 6, 'key_string' => 'VL', 'worldid_mixed' => 'CAN', 'lang_enum' => 'pt', 'name_string' => 'Luz de velas', 'description_string' => 'Esta reunião acontece à luz de velas.', 'format_type_enum' => 'FC2'],
+ ['shared_id_bigint' => 6, 'key_string' => 'LV', 'worldid_mixed' => 'CAN', 'lang_enum' => 'pt', 'name_string' => 'Luz de velas', 'description_string' => 'Esta reunião acontece à luz de velas.', 'format_type_enum' => 'FC2'],
['shared_id_bigint' => 7, 'key_string' => 'CA', 'worldid_mixed' => '', 'lang_enum' => 'pt', 'name_string' => 'Criança sob supervisão', 'description_string' => 'Bem-comportadas, crianças sob supervisão são bem-vindas.', 'format_type_enum' => 'FC3'],
['shared_id_bigint' => 8, 'key_string' => 'D', 'worldid_mixed' => 'DISC', 'lang_enum' => 'pt', 'name_string' => 'Discussão', 'description_string' => 'Esta reunião convida a participação de todos.', 'format_type_enum' => 'FC1'],
['shared_id_bigint' => 9, 'key_string' => 'ES', 'worldid_mixed' => 'LANG', 'lang_enum' => 'pt', 'name_string' => 'Espanhol', 'description_string' => 'Esta reunião acontece em Espanhol.', 'format_type_enum' => 'LANG'],
@@ -559,7 +559,7 @@ public function up()
['shared_id_bigint' => 41, 'key_string' => 'ME', 'worldid_mixed' => 'MED', 'lang_enum' => 'pt', 'name_string' => 'Meditação', 'description_string' => 'Esta reunião incentiva seus participantes a se envolverem em meditação silenciosa.', 'format_type_enum' => 'FC1'],
['shared_id_bigint' => 42, 'key_string' => 'AR', 'worldid_mixed' => 'RA', 'lang_enum' => 'pt', 'name_string' => 'Acesso Restrito', 'description_string' => 'Esta reunião esta em local que impõe restrição de acesso às pessoas.', 'format_type_enum' => 'FC3'],
['shared_id_bigint' => 43, 'key_string' => 'PR', 'worldid_mixed' => 'QA', 'lang_enum' => 'pt', 'name_string' => 'Perguntas e Respostas', 'description_string' => 'Os participantes podem fazer perguntas e esperar respostas dos membros do grupo.', 'format_type_enum' => 'FC1'],
- ['shared_id_bigint' => 44, 'key_string' => 'PC', 'worldid_mixed' => 'CW', 'lang_enum' => 'pt', 'name_string' => 'Permitido Crianças', 'description_string' => 'Crianças são bem-vindas a essa reunião.', 'format_type_enum' => 'FC3'],
+ ['shared_id_bigint' => 44, 'key_string' => 'CBV', 'worldid_mixed' => 'CW', 'lang_enum' => 'pt', 'name_string' => 'Crianças são bem-vindas', 'description_string' => 'Crianças são bem-vindas a essa reunião.', 'format_type_enum' => 'FC3'],
['shared_id_bigint' => 45, 'key_string' => 'Con', 'worldid_mixed' => 'CPT', 'lang_enum' => 'pt', 'name_string' => 'Conceitos', 'description_string' => 'Esta reunião tem foco na discussão dos Doze Conceitos de NA.', 'format_type_enum' => 'FC1'],
['shared_id_bigint' => 46, 'key_string' => 'FIN', 'worldid_mixed' => 'LANG', 'lang_enum' => 'pt', 'name_string' => 'Filandês', 'description_string' => 'Reunião em língua filandesa', 'format_type_enum' => 'LANG'],
['shared_id_bigint' => 47, 'key_string' => 'ENG', 'worldid_mixed' => 'LANG', 'lang_enum' => 'pt', 'name_string' => 'Inglês', 'description_string' => 'Reunião em língua inglesa.', 'format_type_enum' => 'LANG'],
@@ -630,7 +630,6 @@ public function up()
['shared_id_bigint' => 48, 'key_string' => 'PER', 'worldid_mixed' => null, 'lang_enum' => 'sv', 'name_string' => 'Persiskt', 'description_string' => 'Persiskt möte', 'format_type_enum' => 'FC1'],
['shared_id_bigint' => 32, 'key_string' => 'K', 'worldid_mixed' => 'W', 'lang_enum' => 'sv', 'name_string' => 'Kvinnomöte', 'description_string' => 'Detta möte är endast öppet för kvinnor.', 'format_type_enum' => 'FC3'],
['shared_id_bigint' => 33, 'key_string' => 'RL', 'worldid_mixed' => 'WCHR', 'lang_enum' => 'sv', 'name_string' => 'Rullstolsvänlig lokal', 'description_string' => 'Detta möte är tillgängligt för rullstolsbundna.', 'format_type_enum' => 'FC2'],
- ['shared_id_bigint' => 47, 'key_string' => 'ENG', 'worldid_mixed' => null, 'lang_enum' => 'sv', 'name_string' => 'Engelska', 'description_string' => 'Engelsktalande möte', 'format_type_enum' => 'FC3'],
['shared_id_bigint' => 54, 'key_string' => 'VM', 'worldid_mixed' => 'VM', 'lang_enum' => 'sv', 'name_string' => 'Virtual Meeting', 'description_string' => 'Meets Virtually', 'format_type_enum' => 'FC2'],
['shared_id_bigint' => 55, 'key_string' => 'TC', 'worldid_mixed' => 'TC', 'lang_enum' => 'sv', 'name_string' => 'Temporarily Closed Facility', 'description_string' => 'Facility is Temporarily Closed', 'format_type_enum' => 'FC2'],
['shared_id_bigint' => 56, 'key_string' => 'HY', 'worldid_mixed' => 'HYBR', 'lang_enum' => 'sv', 'name_string' => 'Hybrid Meeting', 'description_string' => 'Meets Virtually and In-person', 'format_type_enum' => 'FC2'],
diff --git a/src/database/migrations/2023_05_16_223943_format_types.php b/src/database/migrations/2023_05_16_223943_format_types.php
index f2afa46f4..4bb0f0f58 100644
--- a/src/database/migrations/2023_05_16_223943_format_types.php
+++ b/src/database/migrations/2023_05_16_223943_format_types.php
@@ -26,7 +26,7 @@ public function up()
$table->index('key_string');
$table->index('api_enum');
});
- if (!legacy_config('aggregator_mode_enabled')) {
+ if (!file_config('aggregator_mode_enabled')) {
// aggregator mode does not need any stock data
DB::table('comdef_format_types')->insert([
['key_string' => 'FC1', 'api_enum' => 'MEETING_FORMAT', 'position_int' => '1'],
diff --git a/src/database/migrations/2024_06_12_164303_fix_meeting_lang_enum.php b/src/database/migrations/2024_06_12_164303_fix_meeting_lang_enum.php
index ab90968bd..d6ffc4bd2 100644
--- a/src/database/migrations/2024_06_12_164303_fix_meeting_lang_enum.php
+++ b/src/database/migrations/2024_06_12_164303_fix_meeting_lang_enum.php
@@ -12,7 +12,7 @@
*/
public function up()
{
- if (!legacy_config('aggregator_mode_enabled')) {
+ if (!file_config('aggregator_mode_enabled')) {
DB::table('comdef_meetings_main')
->whereNull('lang_enum')
->update(['lang_enum' => config('app.locale')]);
diff --git a/src/database/migrations/2024_07_20_203802_fix_admin_user_owners.php b/src/database/migrations/2024_07_20_203802_fix_admin_user_owners.php
index cb7a2bda9..3c0b0a882 100644
--- a/src/database/migrations/2024_07_20_203802_fix_admin_user_owners.php
+++ b/src/database/migrations/2024_07_20_203802_fix_admin_user_owners.php
@@ -10,7 +10,7 @@
*/
public function up(): void
{
- if (!legacy_config('aggregator_mode_enabled')) {
+ if (!file_config('aggregator_mode_enabled')) {
$adminUserIds = DB::table('comdef_users')->where('user_level_tinyint', 1)->pluck('id_bigint');
DB::table('comdef_users')->whereIn('owner_id_bigint', $adminUserIds)->update(['owner_id_bigint' => -1]);
}
diff --git a/src/database/migrations/2025_09_25_123352_set_langenum_to_app_locale.php b/src/database/migrations/2025_09_25_123352_set_langenum_to_app_locale.php
new file mode 100644
index 000000000..73b96d336
--- /dev/null
+++ b/src/database/migrations/2025_09_25_123352_set_langenum_to_app_locale.php
@@ -0,0 +1,26 @@
+update(['lang_enum' => config('app.locale')]);
+ Schema::table('comdef_users', function ($table) {
+ $table->string('target_language', 10)->nullable();
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ */
+ public function down(): void
+ {
+ }
+};
diff --git a/src/database/migrations/2025_10_09_160510_add_serveradmin_if_needed.php b/src/database/migrations/2025_10_09_160510_add_serveradmin_if_needed.php
new file mode 100644
index 000000000..4b7fcab31
--- /dev/null
+++ b/src/database/migrations/2025_10_09_160510_add_serveradmin_if_needed.php
@@ -0,0 +1,36 @@
+where('user_level_tinyint', 1)->count();
+ if ($n == 0) {
+ DB::table('comdef_users')->insert([
+ 'user_level_tinyint' => 1,
+ 'name_string' => 'Server Administrator',
+ 'description_string' => 'Main Server Administrator',
+ 'email_address_string' => '',
+ 'login_string' => 'serveradmin',
+ 'password_string' => Hash::make('change-this-password-first-thing')
+ ]);
+ };
+ }
+
+ /**
+ * Reverse the migrations.
+ */
+ public function down(): void
+ {
+ //
+ }
+};
diff --git a/src/database/migrations/2025_11_10_014000_remove_nonexistent_assigned_users_from_service_bodies.php b/src/database/migrations/2025_11_10_014000_remove_nonexistent_assigned_users_from_service_bodies.php
new file mode 100644
index 000000000..e46c49f82
--- /dev/null
+++ b/src/database/migrations/2025_11_10_014000_remove_nonexistent_assigned_users_from_service_bodies.php
@@ -0,0 +1,58 @@
+pluck('id_bigint');
+ $serviceBodies = DB::table('comdef_service_bodies')
+ ->whereNotNull('editors_string')
+ ->whereNot('editors_string', '')
+ ->get(['id_bigint', 'editors_string']);
+
+ foreach ($serviceBodies as $serviceBody) {
+ $oldUserIds = collect(explode(',', trim($serviceBody->editors_string)))
+ ->map(fn($userId) => trim($userId))
+ ->filter(fn($userId) => !empty($userId) && is_numeric($userId))
+ ->map(fn($userId) => intval($userId));
+
+ $newUserIds = $oldUserIds->filter(fn($userId) => $allUserIds->contains($userId));
+ if ($oldUserIds->count() == $newUserIds->count()) {
+ continue;
+ }
+
+ DB::table('comdef_service_bodies')
+ ->where('id_bigint', $serviceBody->id_bigint)
+ ->update(['editors_string' => $newUserIds->isEmpty() ? null : $newUserIds->implode(',')]);
+
+ Log::info('Removed non-existent assigned users from service body', [
+ 'service_body_id' => $serviceBody->id_bigint,
+ 'old_editors_string' => $serviceBody->editors_string,
+ 'new_editors_string' => $newUserIds->isEmpty() ? null : $newUserIds->implode(','),
+ 'removed_count' => $oldUserIds->count() - $newUserIds->count()
+ ]);
+ }
+ }
+
+ /**
+ * Reverse the migrations.
+ */
+ public function down(): void
+ {
+ //
+ }
+};
diff --git a/src/database/migrations/2025_11_11_174719_trim_user_whitespace.php b/src/database/migrations/2025_11_11_174719_trim_user_whitespace.php
new file mode 100644
index 000000000..e8ffaa065
--- /dev/null
+++ b/src/database/migrations/2025_11_11_174719_trim_user_whitespace.php
@@ -0,0 +1,40 @@
+whereNotNull('name_string')
+ ->update(['name_string' => DB::raw('TRIM(name_string)')]);
+
+ DB::table('comdef_users')
+ ->whereNotNull('description_string')
+ ->update(['description_string' => DB::raw('TRIM(description_string)')]);
+
+ DB::table('comdef_users')
+ ->whereNotNull('login_string')
+ ->update(['login_string' => DB::raw('TRIM(login_string)')]);
+
+ DB::table('comdef_users')
+ ->whereNotNull('email_address_string')
+ ->update(['email_address_string' => DB::raw('TRIM(email_address_string)')]);
+ }
+
+ /**
+ * Reverse the migrations.
+ *
+ * @return void
+ */
+ public function down()
+ {
+ }
+};
diff --git a/src/database/migrations/2025_11_20_133700_create_settings_table.php b/src/database/migrations/2025_11_20_133700_create_settings_table.php
new file mode 100644
index 000000000..03714662b
--- /dev/null
+++ b/src/database/migrations/2025_11_20_133700_create_settings_table.php
@@ -0,0 +1,34 @@
+bigIncrements('id');
+ $table->string('name', 255)->unique();
+ $table->string('type', 50)->default('string');
+ $table->text('value')->nullable();
+ $table->timestamps();
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ *
+ * @return void
+ */
+ public function down()
+ {
+ Schema::dropIfExists('settings');
+ }
+};
diff --git a/src/database/migrations/2025_11_20_133800_seed_settings_from_legacy_config.php b/src/database/migrations/2025_11_20_133800_seed_settings_from_legacy_config.php
new file mode 100644
index 000000000..370483a85
--- /dev/null
+++ b/src/database/migrations/2025_11_20_133800_seed_settings_from_legacy_config.php
@@ -0,0 +1,154 @@
+ self::TYPE_STRING,
+ 'changeDepthForMeetings' => self::TYPE_INT,
+ 'defaultSortKey' => self::TYPE_STRING,
+ 'language' => self::TYPE_STRING,
+ 'defaultDurationTime' => self::TYPE_STRING,
+ 'regionBias' => self::TYPE_STRING,
+ 'distanceUnits' => self::TYPE_STRING,
+ 'meetingStatesAndProvinces' => self::TYPE_ARRAY,
+ 'meetingCountiesAndSubProvinces' => self::TYPE_ARRAY,
+ 'searchSpecMapCenterLongitude' => self::TYPE_FLOAT,
+ 'searchSpecMapCenterLatitude' => self::TYPE_FLOAT,
+ 'searchSpecMapCenterZoom' => self::TYPE_INT,
+ 'numberOfMeetingsForAuto' => self::TYPE_INT,
+ 'autoGeocodingEnabled' => self::TYPE_BOOL,
+ 'countyAutoGeocodingEnabled' => self::TYPE_BOOL,
+ 'zipAutoGeocodingEnabled' => self::TYPE_BOOL,
+ 'defaultClosedStatus' => self::TYPE_BOOL,
+ 'enableLanguageSelector' => self::TYPE_BOOL,
+ 'includeServiceBodyEmailInSemantic' => self::TYPE_BOOL,
+ 'bmltTitle' => self::TYPE_STRING,
+ 'bmltNotice' => self::TYPE_STRING,
+ 'formatLangNames' => self::TYPE_ARRAY,
+ ];
+
+ private const SETTING_DEFAULTS = [
+ 'googleApiKey' => '',
+ 'changeDepthForMeetings' => 0,
+ 'defaultSortKey' => null,
+ 'language' => 'en',
+ 'defaultDurationTime' => '01:00',
+ 'regionBias' => 'us',
+ 'distanceUnits' => 'mi',
+ 'meetingStatesAndProvinces' => [],
+ 'meetingCountiesAndSubProvinces' => [],
+ 'searchSpecMapCenterLongitude' => -118.563659,
+ 'searchSpecMapCenterLatitude' => 34.235918,
+ 'searchSpecMapCenterZoom' => 6,
+ 'numberOfMeetingsForAuto' => 10,
+ 'autoGeocodingEnabled' => true,
+ 'countyAutoGeocodingEnabled' => false,
+ 'zipAutoGeocodingEnabled' => false,
+ 'defaultClosedStatus' => true,
+ 'enableLanguageSelector' => false,
+ 'includeServiceBodyEmailInSemantic' => false,
+ 'bmltTitle' => 'BMLT Administration',
+ 'bmltNotice' => '',
+ 'formatLangNames' => [],
+ ];
+
+ public function up()
+ {
+ $config = $this->getConfig();
+ $settingNames = array_keys(self::SETTING_TYPES);
+ foreach ($settingNames as $name) {
+ $type = self::SETTING_TYPES[$name];
+ $value = $config[$name];
+ if (!is_null($value)) {
+ $value = $this->cast($value, $type);
+ $value = json_encode($value);
+ }
+ DB::table('settings')->insert(['name' => $name, 'type' => $type, 'value' => $value]);
+ }
+ }
+
+ private function cast($value, string $type): mixed
+ {
+ switch ($type) {
+ case self::TYPE_ARRAY:
+ if (is_array($value)) {
+ return $value;
+ }
+ if (is_string($value)) {
+ return $value === '' ? [] : array_map('trim', explode(',', $value));
+ }
+ return [];
+
+ case self::TYPE_BOOL:
+ return (bool)$value;
+
+ case self::TYPE_INT:
+ return (int)$value;
+
+ case self::TYPE_FLOAT:
+ return (float)$value;
+
+ case self::TYPE_STRING:
+ default:
+ return (string)$value;
+ }
+ }
+
+ private function getConfig(): array
+ {
+ // Declare all possible global variables so they're accessible
+ global $gkey, $gKey, $change_depth_for_meetings, $default_sort_key, $comdef_global_language;
+ global $default_duration_time, $region_bias, $comdef_distance_units;
+ global $meeting_states_and_provinces, $meeting_counties_and_sub_provinces;
+ global $search_spec_map_center, $number_of_meetings_for_auto;
+ global $auto_geocoding_enabled, $county_auto_geocoding_enabled, $zip_auto_geocoding_enabled;
+ global $g_defaultClosedStatus, $g_enable_language_selector;
+ global $g_include_service_body_email_in_semantic, $bmlt_title, $bmlt_notice, $format_lang_names;
+
+ // If not in testing and file exists, load it
+ $legacyConfigFile = base_path() . '/../auto-config.inc.php';
+ if (env('APP_ENV') !== 'testing' && file_exists($legacyConfigFile)) {
+ defined('BMLT_EXEC') or define('BMLT_EXEC', 1);
+ require($legacyConfigFile);
+ }
+
+ return [
+ 'googleApiKey' => $gkey ?? $gKey ?? self::SETTING_DEFAULTS['googleApiKey'],
+ 'changeDepthForMeetings' => $change_depth_for_meetings ?? self::SETTING_DEFAULTS['changeDepthForMeetings'],
+ 'defaultSortKey' => $default_sort_key ?? self::SETTING_DEFAULTS['defaultSortKey'],
+ 'language' => $comdef_global_language ?? self::SETTING_DEFAULTS['language'],
+ 'defaultDurationTime' => $default_duration_time ?? self::SETTING_DEFAULTS['defaultDurationTime'],
+ 'regionBias' => $region_bias ?? self::SETTING_DEFAULTS['regionBias'],
+ 'distanceUnits' => $comdef_distance_units ?? self::SETTING_DEFAULTS['distanceUnits'],
+ 'meetingStatesAndProvinces' => $meeting_states_and_provinces ?? self::SETTING_DEFAULTS['meetingStatesAndProvinces'],
+ 'meetingCountiesAndSubProvinces' => $meeting_counties_and_sub_provinces ?? self::SETTING_DEFAULTS['meetingCountiesAndSubProvinces'],
+ 'searchSpecMapCenterLongitude' => (isset($search_spec_map_center) ? ($search_spec_map_center['longitude'] ?? null) : null) ?? self::SETTING_DEFAULTS['searchSpecMapCenterLongitude'],
+ 'searchSpecMapCenterLatitude' => (isset($search_spec_map_center) ? ($search_spec_map_center['latitude'] ?? null) : null) ?? self::SETTING_DEFAULTS['searchSpecMapCenterLatitude'],
+ 'searchSpecMapCenterZoom' => (isset($search_spec_map_center) ? ($search_spec_map_center['zoom'] ?? null) : null) ?? self::SETTING_DEFAULTS['searchSpecMapCenterZoom'],
+ 'numberOfMeetingsForAuto' => $number_of_meetings_for_auto ?? self::SETTING_DEFAULTS['numberOfMeetingsForAuto'],
+ 'autoGeocodingEnabled' => $auto_geocoding_enabled ?? self::SETTING_DEFAULTS['autoGeocodingEnabled'],
+ 'countyAutoGeocodingEnabled' => $county_auto_geocoding_enabled ?? self::SETTING_DEFAULTS['countyAutoGeocodingEnabled'],
+ 'zipAutoGeocodingEnabled' => $zip_auto_geocoding_enabled ?? self::SETTING_DEFAULTS['zipAutoGeocodingEnabled'],
+ 'defaultClosedStatus' => $g_defaultClosedStatus ?? self::SETTING_DEFAULTS['defaultClosedStatus'],
+ 'enableLanguageSelector' => $g_enable_language_selector ?? self::SETTING_DEFAULTS['enableLanguageSelector'],
+ 'includeServiceBodyEmailInSemantic' => $g_include_service_body_email_in_semantic ?? self::SETTING_DEFAULTS['includeServiceBodyEmailInSemantic'],
+ 'bmltTitle' => $bmlt_title ?? self::SETTING_DEFAULTS['bmltTitle'],
+ 'bmltNotice' => $bmlt_notice ?? self::SETTING_DEFAULTS['bmltNotice'],
+ 'formatLangNames' => $format_lang_names ?? self::SETTING_DEFAULTS['formatLangNames'],
+ ];
+ }
+
+ public function down()
+ {
+ DB::table('settings')->truncate();
+ }
+};
diff --git a/src/database/migrations/2025_12_12_201931_fix_formats.php b/src/database/migrations/2025_12_12_201931_fix_formats.php
new file mode 100644
index 000000000..d8d4c9da1
--- /dev/null
+++ b/src/database/migrations/2025_12_12_201931_fix_formats.php
@@ -0,0 +1,98 @@
+where('lang_enum', 'it')
+ ->where('key_string', 'AR')
+ ->doesntExist();
+ if ($available) {
+ DB::table('comdef_formats')
+ ->where('lang_enum', 'it')
+ ->where('key_string', 'M')
+ ->where('name_string', 'Meditazione')
+ ->where('description_string', 'In questa riunione sono poste restrizioni alle modalità di partecipazione.')
+ ->update(['key_string' => 'AR', 'name_string' => 'Accesso ristretto']);
+ }
+
+ // update the key and name for Children Welcome format in Portuguese
+ $available = DB::table('comdef_formats')
+ ->where('lang_enum', 'pt')
+ ->where('key_string', 'CBM')
+ ->doesntExist();
+ if ($available) {
+ DB::table('comdef_formats')
+ ->where('lang_enum', 'pt')
+ ->where('key_string', 'PC')
+ ->where('name_string', 'Permitido Crianças')
+ ->where('description_string', 'Crianças são bem-vindas a essa reunião.')
+ ->update(['key_string' => 'CBM', 'name_string' => 'Crianças são bem-vindas']);
+ }
+
+ // update the key for Candlelight format in Portuguese
+ $available = DB::table('comdef_formats')
+ ->where('lang_enum', 'pt')
+ ->where('key_string', 'LV')
+ ->doesntExist();
+ if ($available) {
+ DB::table('comdef_formats')
+ ->where('lang_enum', 'pt')
+ ->where('key_string', 'VL')
+ ->where('name_string', 'Luz de velas')
+ ->where('description_string', 'Esta reunião acontece à luz de velas.')
+ ->update(['key_string' => 'LV']);
+ }
+
+ // delete the duplicate ENG format for Swedish
+ $formats = DB::table('comdef_formats')
+ ->where('lang_enum', 'sv')
+ ->where('key_string', 'ENG')
+ ->where('name_string', 'Engelska')
+ ->where('description_string', 'Engelsktalande möte');
+ $n = $formats->count();
+ if ($n == 2) {
+ $dupId = $formats->max('id');
+ DB::table('comdef_formats')
+ ->where('id', $dupId)
+ ->delete();
+ }
+ }
+
+ /**
+ * Reverse the migrations.
+ */
+ public function down(): void
+ {
+ //
+ }
+};
diff --git a/src/database/migrations/2025_12_27_112435_update_danish_language_code.php b/src/database/migrations/2025_12_27_112435_update_danish_language_code.php
new file mode 100644
index 000000000..bb011393e
--- /dev/null
+++ b/src/database/migrations/2025_12_27_112435_update_danish_language_code.php
@@ -0,0 +1,67 @@
+where('lang_enum', 'dk')
+ ->update(['lang_enum' => 'da']);
+
+ DB::table('comdef_service_bodies')
+ ->where('lang_enum', 'dk')
+ ->update(['lang_enum' => 'da']);
+
+ DB::table('comdef_users')
+ ->where('lang_enum', 'dk')
+ ->update(['lang_enum' => 'da']);
+
+ DB::table('comdef_meetings_data')
+ ->where('lang_enum', 'dk')
+ ->update(['lang_enum' => 'da']);
+
+ DB::table('comdef_meetings_longdata')
+ ->where('lang_enum', 'dk')
+ ->update(['lang_enum' => 'da']);
+
+ DB::table('comdef_meetings_main')
+ ->where('lang_enum', 'dk')
+ ->update(['lang_enum' => 'da']);
+ }
+
+ /**
+ * Reverse the migrations.
+ */
+ public function down(): void
+ {
+ DB::table('comdef_formats')
+ ->where('lang_enum', 'da')
+ ->update(['lang_enum' => 'dk']);
+
+ DB::table('comdef_service_bodies')
+ ->where('lang_enum', 'da')
+ ->update(['lang_enum' => 'dk']);
+
+ DB::table('comdef_users')
+ ->where('lang_enum', 'da')
+ ->update(['lang_enum' => 'dk']);
+
+ DB::table('comdef_meetings_data')
+ ->where('lang_enum', 'da')
+ ->update(['lang_enum' => 'dk']);
+
+ DB::table('comdef_meetings_longdata')
+ ->where('lang_enum', 'da')
+ ->update(['lang_enum' => 'dk']);
+
+ DB::table('comdef_meetings_main')
+ ->where('lang_enum', 'da')
+ ->update(['lang_enum' => 'dk']);
+ }
+};
diff --git a/src/database/migrations/2025_12_31_233709_clean_orphaned_format_ids.php b/src/database/migrations/2025_12_31_233709_clean_orphaned_format_ids.php
new file mode 100644
index 000000000..66e18c0fa
--- /dev/null
+++ b/src/database/migrations/2025_12_31_233709_clean_orphaned_format_ids.php
@@ -0,0 +1,75 @@
+pluck('id')
+ ->map(fn($id) => (string)$id)
+ ->flip();
+
+ $minId = DB::table('comdef_meetings_main')->min('id_bigint');
+ $maxId = DB::table('comdef_meetings_main')->max('id_bigint');
+
+ if (is_null($minId) || is_null($maxId)) {
+ return;
+ }
+
+ $chunkSize = 500;
+ $startId = $minId;
+
+ while ($startId <= $maxId) {
+ $endId = min($startId + $chunkSize, $maxId);
+
+ $meetings = DB::table('comdef_meetings_main')
+ ->whereBetween('id_bigint', [$startId, $endId])
+ ->whereNotNull('formats')
+ ->whereNot('formats', '')
+ ->select('id_bigint', 'formats')
+ ->get();
+
+ foreach ($meetings as $meeting) {
+ $formatIds = collect(explode(',', $meeting->formats))
+ ->map(fn($id) => trim($id))
+ ->filter(fn($id) => $id !== '');
+
+ $validIds = $formatIds->filter(fn($id) => $validFormatIds->has($id));
+ $cleanedFormats = $validIds->implode(',');
+
+ if ($cleanedFormats !== $meeting->formats) {
+ DB::table('comdef_meetings_main')
+ ->where('id_bigint', $meeting->id_bigint)
+ ->update(['formats' => $cleanedFormats]);
+ }
+ }
+
+ $startId = $endId + 1;
+ }
+ }
+
+ /**
+ * Reverse the migrations.
+ *
+ * Note: This migration cannot be reliably reversed because we don't know
+ * which format IDs were removed. The down() method is intentionally left empty.
+ */
+ public function down(): void
+ {
+ // Cannot reverse this migration - we don't know which format IDs were orphaned
+ }
+};
diff --git a/src/database/migrations/2026_01_04_123352_set_langenum_to_app_locale.php b/src/database/migrations/2026_01_04_123352_set_langenum_to_app_locale.php
new file mode 100644
index 000000000..73b96d336
--- /dev/null
+++ b/src/database/migrations/2026_01_04_123352_set_langenum_to_app_locale.php
@@ -0,0 +1,26 @@
+update(['lang_enum' => config('app.locale')]);
+ Schema::table('comdef_users', function ($table) {
+ $table->string('target_language', 10)->nullable();
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ */
+ public function down(): void
+ {
+ }
+};
diff --git a/src/index.php b/src/index.php
index e5d477e7b..bcdb1cad9 100644
--- a/src/index.php
+++ b/src/index.php
@@ -16,7 +16,7 @@
|
*/
-if (file_exists($maintenance = __DIR__.'/storage/framework/maintenance.php')) {
+if (file_exists($maintenance = __DIR__ . '/storage/framework/maintenance.php')) {
require $maintenance;
}
diff --git a/src/lang/dk/change_detail.php b/src/lang/da/change_detail.php
similarity index 100%
rename from src/lang/dk/change_detail.php
rename to src/lang/da/change_detail.php
diff --git a/src/lang/dk/change_type.php b/src/lang/da/change_type.php
similarity index 100%
rename from src/lang/dk/change_type.php
rename to src/lang/da/change_type.php
diff --git a/src/lang/da/language_name.php b/src/lang/da/language_name.php
new file mode 100644
index 000000000..120546be5
--- /dev/null
+++ b/src/lang/da/language_name.php
@@ -0,0 +1,5 @@
+ 'Dansk',
+];
diff --git a/src/lang/dk/main_prompts.php b/src/lang/da/main_prompts.php
similarity index 100%
rename from src/lang/dk/main_prompts.php
rename to src/lang/da/main_prompts.php
diff --git a/src/lang/dk/weekdays.php b/src/lang/da/weekdays.php
similarity index 100%
rename from src/lang/dk/weekdays.php
rename to src/lang/da/weekdays.php
diff --git a/src/lang/de/language_name.php b/src/lang/de/language_name.php
new file mode 100644
index 000000000..1c523bc09
--- /dev/null
+++ b/src/lang/de/language_name.php
@@ -0,0 +1,5 @@
+ 'Deutsch',
+];
diff --git a/src/lang/en/language_name.php b/src/lang/en/language_name.php
new file mode 100644
index 000000000..41a720cbb
--- /dev/null
+++ b/src/lang/en/language_name.php
@@ -0,0 +1,5 @@
+ 'English',
+];
diff --git a/src/lang/es/language_name.php b/src/lang/es/language_name.php
new file mode 100644
index 000000000..4357b18be
--- /dev/null
+++ b/src/lang/es/language_name.php
@@ -0,0 +1,5 @@
+ 'Español',
+];
diff --git a/src/lang/fa/language_name.php b/src/lang/fa/language_name.php
new file mode 100644
index 000000000..f4c72a29a
--- /dev/null
+++ b/src/lang/fa/language_name.php
@@ -0,0 +1,5 @@
+ 'فارسی',
+];
diff --git a/src/lang/fr/language_name.php b/src/lang/fr/language_name.php
new file mode 100644
index 000000000..2e9f0e208
--- /dev/null
+++ b/src/lang/fr/language_name.php
@@ -0,0 +1,5 @@
+ 'Français',
+];
diff --git a/src/lang/it/language_name.php b/src/lang/it/language_name.php
new file mode 100644
index 000000000..1c2f6d7df
--- /dev/null
+++ b/src/lang/it/language_name.php
@@ -0,0 +1,5 @@
+ 'Italiano',
+];
diff --git a/src/lang/pl/language_name.php b/src/lang/pl/language_name.php
new file mode 100644
index 000000000..2875e4de7
--- /dev/null
+++ b/src/lang/pl/language_name.php
@@ -0,0 +1,5 @@
+ 'Polski',
+];
diff --git a/src/lang/pt/language_name.php b/src/lang/pt/language_name.php
new file mode 100644
index 000000000..5c943b21c
--- /dev/null
+++ b/src/lang/pt/language_name.php
@@ -0,0 +1,5 @@
+ 'Português',
+];
diff --git a/src/lang/ru/language_name.php b/src/lang/ru/language_name.php
new file mode 100644
index 000000000..5368e24cf
--- /dev/null
+++ b/src/lang/ru/language_name.php
@@ -0,0 +1,5 @@
+ 'Русский',
+];
diff --git a/src/lang/sv/language_name.php b/src/lang/sv/language_name.php
new file mode 100644
index 000000000..6ab0d8e16
--- /dev/null
+++ b/src/lang/sv/language_name.php
@@ -0,0 +1,5 @@
+ 'Svenska',
+];
diff --git a/src/legacy/client_interface/contact.php b/src/legacy/client_interface/contact.php
deleted file mode 100644
index c3a3cf151..000000000
--- a/src/legacy/client_interface/contact.php
+++ /dev/null
@@ -1,435 +0,0 @@
- The ID of the meeting being referenced.
- service_body_id= The ID of the Service body associated with the meeting.
- from_address= A validly-formatted email address to be used as the "FROM:" line.
- message= The message text.
-
- All of these must be supplied, and the Service body ID needs to jive with the one associated with the meeting ID.
- That's not something that spammers will be easily able to determine; especially when you consider how worthless the recipient will be to them.
-
- The contacts are tiered in this manner:
- - If a contact is provided for the meeting itself (email_contact field, or contact_email_1), then that contact is used.
- - If there are multiple contacts using the default contact structure (contact_email_1, contact_email_2), then we will send to both of them.
- - If no individual contacts are provided for a meeting, then we will use the email contact for the Service body for that meeting.
- - If no Service body contact is provided, then the email will be sent to the Server Administrator.
- - If no email contacts are provided anywhere, the email will not be sent.
-
- A simple integer response is returned. 1, if the email was successfully sent, 0 if email contacts are disallowed, -1, if no email contacts are available for this meeting, -2, if the from email address is invalid, -3 if the email was flagged as spam, and -4 if there was some error encountered while sending.
-
- If the meeting ID is 0 (or there is no input), then the message text and from are ignored, and this is considered a test to see if email is supported. A response of 1 is yes, 0, otherwise.
-
- This won't work if the $g_enable_email_contact = TRUE; line is not in the auto-config.inc.php file.
-
- If you want to include all the Service body contacts (multiple recipients are possible), then set $include_service_body_admin_on_emails = TRUE; in the config file.
-
- This file is part of the Basic Meeting List Toolbox (BMLT).
-
- Find out more at: https://bmlt.app
-
- BMLT is free software: you can redistribute it and/or modify
- it under the terms of the MIT License.
-
- BMLT is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- MIT License for more details.
-
- You should have received a copy of the MIT License along with this code.
- If not, see .
-*/
-
-global $g_mail_debug;
-
-$g_mail_debug = false; ///< Set this to TRUE to output the email as an echo, instead of sending it.
-
-if (preg_match("/localhost/", $_SERVER['SERVER_NAME'])) {
- $g_mail_debug = true; // We always debug for localhost testing.
-}
-
-/***********************************************************************/
-/** \brief This analyzes an input string for obvious spam signatures.
- This looks for attempts to insert headers into the From: line.
-
- \returns a Boolean. TRUE if the message appears to be spam.
-*/
-function analyzeFromLine(
- $inFrom ///< The message from line as a text string.
-) {
- $inFrom = strtolower($inFrom);
-
- $ret = !((false == strpos($inFrom, "\r")) && (false == strpos($inFrom, "\n")) && (false == strpos($inFrom, ";")) && (false == strpos($inFrom, "to:")) && (false == strpos($inFrom, "cc:")) && (false == strpos($inFrom, "bc:")));
-
- return $ret;
-}
-
-/***********************************************************************/
-/** \brief This analyzes an input string for obvious spam signatures (mostly checking for URLs).
- This is VERY basic, but it will catch 99% of the usual spam types.
- Cribbed from here: http://wcetdesigns.com/tutorials/2011/11/30/detect-url-in-string.html
-
- \returns a Boolean. TRUE if the message appears to be spam.
-*/
-function analyzeMessageContent(
- $inMessage ///< The message as a text string.
-) {
- $ret = false;
- $count = 0;
-
- $p = '#^(http(s)?|ftp)://([a-z0-9_-]+.)+([a-z]{2,}){1}((:|/)(.*))?$#';
-
- $w = preg_split("/\s+/", $inMessage, -1, PREG_SPLIT_NO_EMPTY);
-
- foreach ($w as $s) {
- if (preg_match($p, $s)) {
- if (1 < $count++) { // More than 2 is spam.
- $ret = true;
- break;
- }
- }
- }
-
- return $ret;
-}
-
-/***********************************************************************/
-/** \brief This analyzes email address (or a list of them), and returns TRUE if they are OK (as formatted).
- \returns a Boolean. TRUE if the emails are OK.
-*/
-function isValidEmailAddress(
- $in_test_address ///< The email address (or a list or array) to be checked.
-) {
- $valid = false;
- if (isset($in_test_address)) {
- if (!is_array($in_test_address)) {
- $in_test_address = explode(",", $in_test_address); // See if we have a list.
- }
-
- // Start off optimistic.
- $valid = true;
-
- // If we have more than one address, we iterate through each one.
- foreach ($in_test_address as $addr_elem) {
- // This splits any name/address pair (ex: "Jack Schidt" )
- $addr_temp = preg_split("/ ", strtolower($addr_elem));
-
- if (count($addr_temp) > 1) { // We also want to trim off address brackets.
- $addr_elem = trim($addr_temp[1], "<>");
- } else {
- $addr_elem = trim($addr_temp[0], "<>");
- }
-
- // Test for valid email address.
- $regexp = "/^([a-z0-9\_\.\-]+?)@([a-z0-9\-]+)(\.[a-z0-9\-]+)*(\.[a-z]{2,6})$/";
-
- if (!preg_match($regexp, strtolower($addr_elem))) {
- $valid = false;
- break;
- }
- }
- }
-
- return $valid;
-}
-
-/***********************************************************************/
-/** \brief This simplifies one single email address, by stripping away cruft.
-
- \returns a "cleaned" email address.
-*/
-function simplifyEmailAddress($in_orig_address)
-{
- $addr_temp = preg_split("/ ", $in_orig_address);
-
- if (count($addr_temp) > 1) { // We also want to trim off address brackets.
- $addr_elem = trim($addr_temp[1], " <>");
- } else {
- $addr_elem = trim($addr_temp[0], " <>");
- }
-
- if (isValidEmailAddress($addr_elem)) {
- return $addr_elem;
- }
-
- return "";
-}
-
-/***********************************************************************/
-/** \brief This actually sends the email.
-
- \returns a Boolean. TRUE if successful.
-*/
-function sendEMail(
- $in_to_address,
- $in_from_address,
- $in_subject = "",
- $in_body = ""
-) {
- $success = false;
-
- $addlParam = $in_from_address;
-
- if ($addlParam) {
- $addlParam = "-f $addlParam";
- }
-
- // The body is not sent in the plain text portion of the
- // mail() function. Instead, it is put in the headers.
-
- $headers = "";
- $headers .= "From: $in_from_address\n";
- // Make sure our endlines are correct, and unescape any escaped quotes.
- $in_body = preg_replace("/\r\n/", "\n", $in_body);
- $in_body = stripslashes(preg_replace("/\r/", "\n", $in_body));
- $in_body = stripslashes(preg_replace("/\n+/", "\n", $in_body));
- $subject = stripslashes($in_subject);
-
- // Headers precede the body.
- $headers .= $in_body;
-
- global $g_mail_debug;
-
- if ($g_mail_debug) {
- $disp = "To: ".htmlspecialchars($in_to_address)."\n";
- $disp .= "Subject: ".htmlspecialchars($subject)."\n";
- $disp .= htmlspecialchars($headers);
- echo "
$disp
";
- $success = true;
- } else {
- // The "Message" parameter is blank, because we are using
- // the headers to send the body. Bit more technical, but
- // more effective.
- $success = mail($in_to_address, $subject, "", $headers, $addlParam);
- }
-
- return $success;
-}
-
-/***********************************************************************/
-/* MAIN CONTEXT */
-/***********************************************************************/
-
-$ret = 0; // We start off assuming that email contact is disabled.
-$meeting_id = 0;
-
-if (isset($_GET['meeting_id'])) {
- $meeting_id = intval($_GET['meeting_id']);
-}
-
-// If this is just a test, we respond with the capability.
-if (0 == $meeting_id) {
- if (file_exists(dirname(dirname(dirname(__FILE__))).'/../auto-config.inc.php')) {
- defined('BMLT_EXEC') or define('BMLT_EXEC', 1);
- // We check to make sure that we are supporting the capability.
- require_once(dirname(dirname(dirname(__FILE__))).'/../auto-config.inc.php');
- $ret = $g_enable_email_contact ? 1 : 0;
- }
-} else {
- if (isset($_GET['service_body_id'])) {
- $service_body_id = intval($_GET['service_body_id']);
- if (!$service_body_id) {
- $service_body_id = intval($_GET['service_body_bigint']);
- }
- }
-
- if (isset($_GET['message'])) {
- $message_text = $_GET['message'];
- }
-
- if (isset($_GET['from_address'])) {
- $from_address = $_GET['from_address'];
- }
-
- $isspam = false;
-
- foreach ($_GET as $key => $value) {
- $key = strtolower(strval($key));
-
- // Any attempt to sneak in extra fields automatically marks this as spam.
- if (($key != 'meeting_id') && ($key != 'service_body_id') && ($key != 'service_body_bigint') && ($key != 'from_address') && ($key != 'message')) {
- if ($g_mail_debug) {
- echo ( "$key is invalid " );
- }
-
- $isspam = true;
- break;
- }
- }
-
- if (!$isspam) {
- $isspam = isset($from_address) ? analyzeFromLine($from_address) : false;
-
- if (!$isspam) {
- if (isset($from_address) ? isValidEmailAddress($from_address) : true) {
- $isspam = isset($message_text) ? analyzeMessageContent($message_text) : false;
-
- if (!$isspam) {
- if (file_exists(dirname(dirname(dirname(__FILE__))).'/../auto-config.inc.php')) {
- defined('BMLT_EXEC') or define('BMLT_EXEC', 1);
-
- // We check to make sure that we are supporting the capability.
- require_once(dirname(dirname(dirname(__FILE__))).'/../auto-config.inc.php');
-
- if ($g_enable_email_contact && $meeting_id) {
- require_once(dirname(dirname(__FILE__)).'/server/c_comdef_server.class.php');
- $server = c_comdef_server::MakeServer();
-
- if ($server instanceof c_comdef_server) {
- $email_contacts = array(); // This will contain our meeting email contact list.
-
- $meeting_object = c_comdef_server::GetOneMeeting($meeting_id);
-
- if ($meeting_object instanceof c_comdef_meeting) { // We must have a valid meeting.
- // This is a pretty good spamtrap. The submission must have both the meeting ID and the valid Service body ID.
- if (isset($service_body_id) && $service_body_id && ($service_body_id == $meeting_object->GetServiceBodyID())) {
- if ($meeting_object->GetEmailContact()) { // The direct contact is placed first in the queue.
- $email = simplifyEmailAddress($meeting_object->GetEmailContact());
-
- if ($email) {
- $email_contacts[] = $email;
- }
- }
-
- // We now walk up the hierarchy, and add contacts as we find them. We use the emails set in the Service body admin, not individual accounts.
-
- $service_body = $meeting_object->GetServiceBodyObj();
-
- do {
- if ($service_body && $service_body->GetContactEmail()) {
- $email = simplifyEmailAddress($service_body->GetContactEmail());
-
- if ($email && !in_array($email, $email_contacts)) { // Make sure we don't already have it.
- $email_contacts[] = $email;
- }
- }
-
- // We don't recurse if we aren't supposed to
- $service_body = isset($include_every_admin_on_emails) && $include_every_admin_on_emails ? $service_body->GetOwnerIDObject() : null;
- } while ($service_body);
-
- // The one exception is the Server Administrator, and we get that email from the individual account.
-
- if (isset($include_every_admin_on_emails) && $include_every_admin_on_emails) { // The Server admin is not involved unless we are cascading.
- $server_admin_user = c_comdef_server::GetUserByIDObj(1);
-
- if ($server_admin_user && $server_admin_user->GetEmailAddress()) {
- $email = simplifyEmailAddress($server_admin_user->GetEmailAddress());
-
- if ($email) {
- $email_contacts[] = $email;
- }
- }
- }
-
- // At this point, we have one or more email addresses in our $email_contacts array. It's possible that the Server Admin may be the only contact.
-
- if (count($email_contacts)) { // Make sure that we have something.
- $to_line = null;
-
- if ((1 < count($email_contacts)) && $include_service_body_admin_on_emails) { // See if we are including anyone else.
- $to_line = implode(",", $email_contacts);
- } else {
- $to_line = $email_contacts[0]; // Otherwise, just the primary contact.
- }
-
- if ($to_line) { // Assuming all went well, we have a nice to line, here.
- if (isValidEmailAddress($to_line)) { // Make sure our email addresses are valid.
- $local_strings = c_comdef_server::GetLocalStrings();
-
- $subject = sprintf($local_strings['email_contact_strings']['meeting_contact_form_subject_format'], $meeting_object->GetLocalName());
- $dirn = dirname(( dirname($_SERVER['PHP_SELF'])));
- if ('/' == $dirn) {
- $dirn = '';
- }
- $start_time = explode(':', $meeting_object->GetMeetingDataValue('start_time'));
- unset($start_time[2]);
- $start_time = implode(':', $start_time);
- $root_dirname = 'http://'.$_SERVER['SERVER_NAME'].(($_SERVER['SERVER_PORT'] != 80) ? ':'.$_SERVER['SERVER_PORT'] : '').$dirn;
- $url1 = $root_dirname.'/?single_meeting_id='.$meeting_id;
- $url2 = $root_dirname.'/?edit_meeting='.$meeting_id;
- $body = sprintf(
- $local_strings['email_contact_strings']['meeting_contact_message_format'],
- $message_text,
- $meeting_object->GetLocalName(),
- $start_time,
- $local_strings['weekdays'][$meeting_object->GetMeetingDataValue('weekday_tinyint')],
- $url1,
- $url2
- );
- if (sendEMail($to_line, $from_address, $subject, $body)) {
- $ret = 1;
- } else {
- $ret = -4;
- }
- } else {
- $ret = -1;
- }
- } else {
- $ret = -1; // Should never happen.
- }
- } else {
- $ret = -1;
- }
- } else {
- if ($g_mail_debug) {
- die("Content Considered Spam (Service body check failed)");
- }
-
- $ret = -3;
- }
- }
- }
- }
-
- // If this is just a test, we respond with the capability.
- if (0 == $meeting_id) {
- $ret = $g_enable_email_contact ? 1 : 0;
- }
- } else {
- die("SERVER NOT INITIALIZED");
- }
- } else {
- if ($g_mail_debug) {
- die("Content Considered Spam");
- }
-
- $ret = -3;
- }
- } else {
- if ($g_mail_debug) {
- die("From Address Invalid");
- }
-
- $ret = -2;
- }
- } else {
- if ($g_mail_debug) {
- die("From Address Considered Spam");
- }
-
- $ret = -3;
- }
- } else {
- if ($g_mail_debug) {
- die("Extra parameters (considered spam)");
- }
-
- $ret = -3;
- }
-}
-
-echo intval($ret);
diff --git a/src/legacy/client_interface/csv/c_comdef_meeting_search_manager.class.php b/src/legacy/client_interface/csv/c_comdef_meeting_search_manager.class.php
deleted file mode 100755
index 5c36991fa..000000000
--- a/src/legacy/client_interface/csv/c_comdef_meeting_search_manager.class.php
+++ /dev/null
@@ -1,1567 +0,0 @@
-.
-*/
-
-defined('BMLT_EXEC') or die('Cannot Execute Directly'); // Makes sure that this file is in the correct context.
-
-require_once(dirname(__FILE__)."/../../server/c_comdef_server.class.php");
-require_once(dirname(__FILE__)."/../../server/shared/classes/VenueType.php");
-
-/// A class to control the basic common functionality of all meeting searches.
-// phpcs:disable PSR1.Classes.ClassDeclaration.MissingNamespace
-// phpcs:disable Squiz.Classes.ValidClassName.NotCamelCaps
-class c_comdef_meeting_search_manager
-// phpcs:emable PSR1.Classes.ClassDeclaration.MissingNamespace
-// phpcs:enable Squiz.Classes.ValidClassName.NotCamelCaps
-{
- /// These fields are used to specify the search criteria.
- protected $_formats = null; /**< An array of integers. These are formats. The filtering will be an "AND" filtering, so qualified meetings
- must have all of the given formats. The key is the format's shared ID, and the value will be one of these:
- - -1 NOT (exclude all meetings that contain this format from the search).
- - 0 No preference (This format will not be a consideration in the search).
- - 1 Return meetings that contain this format.
-
- Default is 0 for all. If no formats are specified (either 1 or -1), then formats will not be a consideration
- in the meeting search. If any format is specified as 1, then ONLY meetings with the given format will be
- considered in the search, and you must explicitly set any other formats you wish found.
- */
- protected $_formats_comparison_operator = "AND"; /**< A string, controls the comparison operator used for included formats. Valid values are AND and OR.
- * */
-
- protected $_service_bodies = null; /**< An array of integers. The key is the ID for a Service Body, and the value is one of these:
- - -1 NOT (exclude all meetings that contain this Service Body from the search).
- - 0 No preference (This Service Body will not be a consideration in the search).
- - 1 Return meetings that contain this Service Body.
-
- Default is 0 for all. If no Service Bodies are specified (either 1 or -1), then Service Bodies will not be a
- consideration in the meeting search. If any Service Body is specified as 1, then ONLY meetings with the given
- Service Body will be considered in the search, and you must explicitly set any other Service Bodies you wish found.
- */
- protected $_languages = null; /**< An array of integers. The key is the language enum, and the value is as follows:
- - -1 NOT (exclude all meetings that have this language from the search).
- - 0 No preference (This language will not be a consideration in the search).
- - 1 Return meetings that have this language.
-
- Default is 0 for all. If no languages are specified (either 1 or -1), then language will not be a
- consideration in the meeting search. If any language is specified as 1, then ONLY meetings with the given
- language will be considered in the search, and you must explicitly set any other language you wish found.
- */
- protected $_weekdays = null; /**< An array of integers. The key is the weekday (1 = Sunday, 7 = Saturday), and the value is as follows:
- - -1 NOT (exclude all meetings that occur on this weekday from the search).
- - 0 No preference (This weekday will not be a consideration in the search).
- - 1 Return meetings that occur on this weekday.
-
- Default is 0 for all. If no weekdays are specified (either 1 or -1), then the weekday will not be a
- consideration in the meeting search. If any weekday is specified as 1, then ONLY meetings that occur on
- the given weekday will be considered in the search, and you must explicitly set any other weekday you wish found.
- */
-
- protected $_venue_types = null; // An array of Venue types, positive or negative. Negative venue types are excluded.
-
- /// These specify the start time and duration of the meeting. The start time can be specified as a "window."
- protected $_start_after = null; ///< An epoch time (seconds, as returned by time()), that denotes the earliest starting time allowed.
- protected $_start_before = null; ///< An epoch time (seconds, as returned by time()), that denotes the latest starting time allowed.
- protected $_end_before = null; ///< An epoch time (seconds, as returned by time()), that denotes the latest ending time allowed.
- protected $_min_duration = null; ///< The number of seconds a meeting should last as a minimum.
- protected $_max_duration = null; ///< The number of seconds a meeting can last, at most.
-
- /// These specify the search radius (We store it in kilometers).
- protected $_search_radius = null; ///< If this is not null, it needs to be a positive, floating-point number, indicating the radius, in Kilometers.
- protected $_search_radius_count = null; ///< If this is not null, it needs to be a positive integer, indicating the number of meetings to find automatically.
- protected $_search_center_long = null; ///< If $_search_radius is not null, this needs to be a floating-point number that indicates the longitude, in degrees, of the search center.
- protected $_search_center_lat = null; ///< If $_search_radius is not null, this needs to be a floating-point number that indicates the latitude, in degrees, of the search center.
-
- /// We allow a broad string search that goes through all the text items. In English and Spanish, it uses metaphone, which is a "sounds like" phonetic search.
- protected $_search_string = null; ///< A string to be located from within the results. This search is done after all of the previous ones. This is applied at the end.
- protected $_search_string_all_words = false; ///< A Boolean. If this is true, then all of the words in a phrase must be present.
- protected $_search_string_literal = false; ///< A Boolean. If this is true, then the spelling must be literal.
-
- /// This allows you to filter out a particular value for a key
- protected $_meeting_key = null; /**< A string. This is the xact name of the key to match.
- NOTE: As of Version 1.5, this can be an array of strings (it can still be a single string). The array should contain the names of string fields.
- */
- protected $_meeting_key_value = null; /**< A string. The value to match.
- NOTE: As of Version 1.5, this is matched with a metaphone match, as well as the RegEx match.
- */
- protected $_meeting_key_match_case = false; /**< If true, the case must match. Default is false.
- NOTE: As of Version 1.5, setting this to TRUE also stops the metaphone search.
- */
- protected $_meeting_key_contains = false; ///< If this is false, then the string must be complete. Default is false (literal).
-
- /// This contains a list of IDs of individual meetings. If it is set, then all other search parameters are ignored.
- protected $_meeting_id_array = null; ///< An array of positive integers. The Ids of meetings to find. If this is set, all other search criteria are ignored.
-
- /// This indicates whether the search should include, exclude, or focus on "published" meetings.
- protected $_published_search = 0; /**< This only counts if the searcher is a logged-in admin. The value can be:
- - -1 Search for ONLY unpublished meetings
- - 0 Search for published and unpublished meetings.
- - 1 Search for ONLY published meetings.
- */
- protected $_sort_search_by_distance = false; ///< If this is true, then the search results may be sorted by distance from the geo center.
-
- /// This contains the search results.
- protected $_search_results = null; ///< A c_comdef_meetings object. If this is null, a new search is performed. This contains the entire search results.
-
- private $sort_array = null; ///< This contains an array of strings that represent the sort keys.
- private $sort_desc = false; ///< This is set to true if the sort is a reverse sort.
- private $sort_depth = 3; ///< An integer. This is how far back a staged sort goes. Default is 3. 0 is forever.
-
- /// This refers to portions of a larger search (pages).
- private $_results_per_page = 0; ///< The number of meetings to list per page.
- private $_pageno = 0; ///< An integer. The page number represented by this object. If $_results_per_page is 0, this is ignored.
-
- /// If this isn't the root, then this will be a reference to the root.
- private $_my_root = null; ///< A reference to an instance of c_comdef_meeting_search_manager -The root object.
-
- private $_my_server = null; ///< A reference to a c_comdef_server object. This is the server to be used for the search.
-
- /*******************************************************************/
- /** \brief Constructor.
- */
- public function __construct(
- $in_results_per_page = 0, ///< An integer that defines how many results per page you want to see. 0 (default) is all in one page.
- c_comdef_meeting_search_manager &$in_parent = null, ///< A reference to an existing c_comdef_meeting_search_manager object.
- c_comdef_meetings &$in_search_results = null, ///< A reference to some pre-parsed search results.
- $in_pageno = 0 ///< An integer. The page of the main search this is from.
- ) {
- // If this is a page of results, we set up the object to reference the root.
- if ($in_parent instanceof c_comdef_meeting_search_manager) {
- $this->_my_root = $in_parent;
- // These all reference the root object's values.
- $this->_formats = $in_parent->_formats;
- $this->_formats_comparison_operator = $in_parent->_formats_comparison_operator;
- $this->_service_bodies = $in_parent->_service_bodies;
- $this->_languages = $in_parent->_languages;
- $this->_weekdays = $in_parent->_weekdays;
- $this->_venue_types = $in_parent->_venue_types;
- $this->_start_after = $in_parent->_start_after;
- $this->_start_before = $in_parent->_start_before;
- $this->_end_before = $in_parent->_end_before;
- $this->_min_duration = $in_parent->_min_duration;
- $this->_max_duration = $in_parent->_max_duration;
- $this->_search_radius = $in_parent->_search_radius;
- $this->_search_center_long = $in_parent->_search_center_long;
- $this->_search_center_lat = $in_parent->_search_center_lat;
- $this->_search_string = $in_parent->_search_string;
- $this->_meeting_id_array = $in_parent->_meeting_id_array;
- $this->_published_search = $in_parent->_published_search;
-
- $this->_my_server = $in_parent->_my_server;
-
- // These may get changed by this instance.
- $this->sort_array = $in_parent->sort_array;
- $this->sort_desc = $in_parent->sort_desc;
-
- // These are passed in and set at construction
- $this->_pageno = $in_pageno;
- $this->_search_results = $in_search_results;
- } else // If we are the root object, we start clean.
- {
- // See if the caller has requested a number of results per page.
- if ($in_results_per_page) {
- $this->_results_per_page = $in_results_per_page;
- }
-
- $this->_my_server = c_comdef_server::MakeServer(); // We initialize the server.
-
- $this->SetUpFormats(); // We set the formats array.
- $this->SetUpServiceBodies(); // We set the Service Bodies array.
- $this->SetUpLanguages(); // We set the Languages array.
-
- // Set up the weekday array (1 = Sunday, 7 = Saturday ).
- $this->_weekdays = null;
- for ($wd = 1; $wd < 8; $wd++) {
- $this->_weekdays[$wd] = 0;
- }
-
- $this->_venue_types = null;
- $this->_venue_types[VenueType::IN_PERSON] = 0;
- $this->_venue_types[VenueType::VIRTUAL] = 0;
- $this->_venue_types[VenueType::HYBRID] = 0;
-
- // This is the default sort.
- $this->sort_array = array ( "lang_enum", "weekday_tinyint", "start_time", "id_bigint" );
-
- // We have no search parameters or results at this point.
- }
- }
-
- /*******************************************************************/
- /** \brief Sets an internal array of integers, containing the Shared IDs for
- all available formats on the server. They are initialized to 0 (neutral).
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function SetUpFormats()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $this->_formats = null;
-
- $formats = $this->GetAvailableFormats();
-
- // Basic error checking.
- if (is_array($formats) && count($formats)) {
- // We look in the server's local language (in case there are no other translations).
- $my_lang = $this->_my_server->GetLocalLang();
-
- $er = $formats[$my_lang];
-
- if (is_array($er) && count($er)) {
- foreach ($er as $key => $value) { // We ignore the value.
- $this->_formats[$key] = 0;
- }
- }
- }
- }
-
- /*******************************************************************/
- /** \brief Accessor -Get a reference to the $_formats field.
-
- \returns a reference to the $_formats field, which is an array of integers.
- The key is the format's shared ID, and the value will be one of these:
- - -1 NOT (exclude all meetings that contain this format from the search).
- - 0 No preference (This format will not be a consideration in the search).
- - 1 Return meetings that contain this format.
-
- Default is 0 for all. If no formats are specified (either 1 or -1), then formats will not be a consideration
- in the meeting search. If any format is specified as 1, then ONLY meetings with the given format will be
- considered in the search, and you must explicitly set any other formats you wish found.
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function &GetFormats()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- return $this->_formats;
- }
-
- /*******************************************************************/
- /** \brief Sets a key/value search.
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function SetKeyValueSearch(
- $in_meeting_key, ///< A string. This is the exact name of the key to match.
- $in_meeting_key_value, ///< A string. The value to match.
- $in_meeting_key_match_case = false, ///< If true, the case must match. Default is false.
- $in_meeting_key_contains = true ///< If this is false, then the string must be complete. Default is true (contains).
- ) {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $this->_meeting_key = $in_meeting_key;
- $this->_meeting_key_value = $in_meeting_key_value;
- $this->_meeting_key_match_case = $in_meeting_key_match_case;
- $this->_meeting_key_contains = $in_meeting_key_contains;
- }
-
- /*******************************************************************/
- /** \brief Sets the sort by distance flag.
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function SetSortByDistance(
- $in_sort_search_by_distance = false ///< A Boolean. False is default.
- ) {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $this->_sort_search_by_distance = ($in_sort_search_by_distance != false);
- }
-
- /*******************************************************************/
- /** \brief Sets an internal array of integers, containing the IDs for
- all available service bodies on the server. They are initialized
- to 0 (neutral).
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function SetUpServiceBodies()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $this->_service_bodies = array();
-
- // Basic error checking.
- if ($this->_my_server instanceof c_comdef_server) {
- // Start by getting the service bodies aggregator object.
- $bodies = $this->_my_server->GetServiceBodyArray();
- if (is_array($bodies) && count($bodies)) {
- foreach ($bodies as $body) {
- $key = $body->GetID();
- $this->_service_bodies[$key] = 0;
- }
- }
- }
- }
-
- /*******************************************************************/
- /** \brief Accessor -Get the number of results per page.
-
- \returns an integer.
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function GetResultsPerPage()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $ret = 0;
-
- // This is kept in the root object.
- if (!$this->_my_root) {
- $ret = $this->_results_per_page;
- } elseif ($this->GetRootObject() instanceof c_comdef_meeting_search_manager) {
- $ret = $this->GetRootObject()->GetResultsPerPage();
- }
-
- return $ret;
- }
-
- /*******************************************************************/
- /** \brief Accessor -Set the number of results per page.
- This will only work on the root object.
-
- \returns a boolean. If the operation was successful, it is true. False otherwise.
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function SetResultsPerPage(
- $in_results_per_page ///< A positive integer. If it is 0, then all results will be returned in one page.
- ) {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $ret = false;
-
- if (!$this->_my_root) {
- $this->_results_per_page = $in_results_per_page;
- $ret = true;
- }
-
- return $ret;
- }
-
- /*******************************************************************/
- /** \brief Accessor -Get the page number of this set.
-
- \returns an integer.
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function GetPageNo()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- return $this->_pageno;
- }
-
- /*******************************************************************/
- /** \brief Accessor -Get the index (1 - based) of the first meeting in this page.
-
- \returns an integer.
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function GetFirstIndexInPage()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- return ($this->GetResultsPerPage() * ($this->GetPageNo() - 1)) + 1;
- }
-
- /*******************************************************************/
- /** \brief Accessor -Get the index (1 - based) of the last meeting in this page.
-
- \returns an integer.
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function GetLastIndexInPage()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- return ($this->GetFirstIndexInPage() + $this->GetNumberOfResultsInThisPage()) - 1;
- }
-
- /*******************************************************************/
- /** \brief Accessor -Get the page number of this set.
-
- \returns an integer.
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function GetNumberOfPages()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $ret = 0;
-
- $respp = $this->GetResultsPerPage();
- $resnum = $this->GetNumberOfResults();
-
- if ($respp > 0) {
- $ret = intval(($resnum + ($respp - 1)) / $respp);
- } elseif ($resnum > 0) {
- $ret = 1;
- }
-
- return $ret;
- }
-
- /*******************************************************************/
- /** \brief Accessor -Get the total number of meetings found.
- This gives the TOTAL number found, not just the subset in this page.
-
- \returns an integer.
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function GetNumberOfResults()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $ret = 0;
-
- if (!$this->_my_root && $this->_search_results instanceof c_comdef_meetings) {
- $ret = $this->_search_results->GetNumMeetings();
- } elseif ($this->_my_root instanceof c_comdef_meeting_search_manager) {
- $ret = $this->_my_root->GetNumberOfResults();
- }
-
- return $ret;
- }
-
- /*******************************************************************/
- /** \brief Accessor -Get the number of meetings in this page.
-
- \returns an integer.
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function GetNumberOfResultsInThisPage()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $ret = 0;
-
- if ($this->_search_results instanceof c_comdef_meetings) {
- $ret = $this->_search_results->GetNumMeetings();
- }
-
- return $ret;
- }
-
- /*******************************************************************/
- /** \brief Accessor -Get the number of meetings in this page.
-
- This system allows each page to be treated independently, like allowing
- different sorts without re-sorting the entire search.
-
- This object needs to be the "root" object to return a page.
-
- \returns a new instance (not a reference) to a c_comdef_meeting_search_manager
- object, containing a subset of the meetings to fill this one page.
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function GetPageOfResults(
- $in_page_no = 1 ///< A positive integer. This should be 1 to $this->GetNumberOfPages() (1-based)
- ) {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- if ($in_page_no < 1) { // Can't be less than 1.
- $in_page_no = 1;
- }
-
- if ($in_page_no > $this->GetNumberOfPages()) { // Can't be greater than the last page.
- $in_page_no = $this->GetNumberOfPages();
- }
-
- $ret = null;
-
- // We get pages from the root at all times.
- if (!$this->_my_root && $this->_search_results instanceof c_comdef_meetings) {
- // This is the starting index for our page of results.
- $main_array_1 = $this->_search_results->GetMeetingObjects();
- $main_array = array();
- foreach ($main_array_1 as $meeting) {
- array_push($main_array, $meeting);
- }
-
- $ret_array = array();
- $min = $this->GetResultsPerPage() * ($in_page_no - 1);
- $actual = intval($this->GetResultsPerPage());
- if ($actual > 0) {
- $max = min(count($main_array), $min + $this->GetResultsPerPage());
- } else {
- $max = $this->GetNumberOfResults();
- }
-
- for ($index = intval($min); $index < intval($max); $index++) {
- if ($main_array[$index] instanceof c_comdef_meeting) {
- $data = $main_array[$index]->GetMeetingData();
- if (is_array($data) && count($data)) {
- $ret_array[$data['id_bigint']] = $main_array[$index];
- }
- }
- }
-
- if (count($ret_array)) {
- $resultsObj = new c_comdef_meetings($this->_search_results->GetParentObj(), $ret_array);
-
- if ($resultsObj instanceof c_comdef_meetings) {
- $ret = new c_comdef_meeting_search_manager(0, $this, $resultsObj, $in_page_no);
- }
- }
- } elseif ($this->_my_root instanceof c_comdef_meeting_search_manager) {
- $ret = $this->_my_root->GetPageOfResults($in_page_no);
- }
-
- return $ret;
- }
-
- /*******************************************************************/
- /** \brief Accessor -Get a reference to the $_service_bodies field.
-
- \returns a reference to the $_service_bodies field.
- The key is the Service Body ID. The value is as follows:
- - -1 NOT (exclude all meetings that contain this Service Body from the search).
- - 0 No preference (This Service Body will not be a consideration in the search).
- - 1 Return meetings that contain this Service Body.
-
- Default is 0 for all. If no Service Bodies are specified (either 1 or -1), then Service Bodies will not be a
- consideration in the meeting search. If any Service Body is specified as 1, then ONLY meetings with the given
- Service Body will be considered in the search, and you must explicitly set any other Service Bodies you wish found.
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function &GetServiceBodies()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- return $this->_service_bodies;
- }
-
- /*******************************************************************/
- /** \brief Sets up an internal array of languages.
- The array uses the language enum as the key, and the -1->0->1
- form as the selector.
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function SetUpLanguages()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $this->_languages = null;
-
- // Basic error checking.
- if ($this->_my_server instanceof c_comdef_server) {
- $langs = $this->_my_server->GetServerLangs();
-
- if (is_array($langs) && count($langs)) {
- foreach ($langs as $key => $value) {
- $this->_languages[$key] = 0;
- }
- }
- }
- }
-
- /*******************************************************************/
- /** \brief Accessor -Get a reference to the $_languages field.
-
- \returns a reference to the $_languages field.
- The key is the language enum, and the value is as follows:
- - -1 NOT (exclude all meetings that have this language from the search).
- - 0 No preference (This language will not be a consideration in the search).
- - 1 Return meetings that have this language.
-
- Default is 0 for all. If no languages are specified (either 1 or -1), then language will not be a
- consideration in the meeting search. If any language is specified as 1, then ONLY meetings with the given
- language will be considered in the search, and you must explicitly set any other language you wish found.
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function &GetLanguages()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- return $this->_languages;
- }
-
- /*******************************************************************/
- /** \brief Accessor -Get a reference to the $_weekdays field.
-
- \returns a reference to the $_weekdays field.
- The key is the weekday (1 = Sunday, 7 = Saturday), and the value is as follows:
- - -1 NOT (exclude all meetings that occur on this weekday from the search).
- - 0 No preference (This weekday will not be a consideration in the search).
- - 1 Return meetings that occur on this weekday.
-
- Default is 0 for all. If no weekdays are specified (either 1 or -1), then the weekday will not be a
- consideration in the meeting search. If any weekday is specified as 1, then ONLY meetings that occur on
- the given weekday will be considered in the search, and you must explicitly set any other weekday you wish found.
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function &GetWeekdays()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- return $this->_weekdays;
- }
-
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function &GetVenueTypes()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- return $this->_venue_types;
- }
-
- /*******************************************************************/
- /** \brief Accessor -Get a reference to the c_comdef_server object.
-
- \returns a reference to the c_comdef_server object instantiated by
- this object.
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function GetServer()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- return $this->_my_server;
- }
-
- /*******************************************************************/
- /** \brief Accessor -Get a reference to the root object.
-
- \returns a reference to the c_comdef_meeting_search_manager object.
- If this is the root object, it will return a reference to itself.
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function GetRootObject()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $ret = null;
-
- if ($this->_my_root instanceof c_comdef_meeting_search_manager) {
- $ret = $this->_my_root;
- } else {
- $ret = $this;
- }
-
- return $ret;
- }
-
- /*******************************************************************/
- /** \brief Set a search radius and center, with the Radius in miles.
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function SetSearchRadiusAndCenterInMiles(
- $in_search_radius_in_miles, ///< The radius as specified in miles, not Km.
- $in_long_in_degrees, ///< The longitude needs to be specified in degrees.
- $in_lat_in_degrees ///< The latitude needs to be specified in degrees.
- ) {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $this->SetSearchRadiusAndCenterInKm(1.609344 * $in_search_radius_in_miles, $in_long_in_degrees, $in_lat_in_degrees);
- }
-
- /*******************************************************************/
- /** \brief Set a search radius and center, with the radius in Km.
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function SetSearchRadiusAndCenterInKm(
- $in_search_radius_in_km, ///< The radius needs to be specified in kilometers, not miles.
- $in_long_in_degrees, ///< The longitude needs to be specified in degrees.
- $in_lat_in_degrees ///< The latitude needs to be specified in degrees.
- ) {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $this->_search_radius = $in_search_radius_in_km;
- $this->_search_center_long = $in_long_in_degrees;
- $this->_search_center_lat = $in_lat_in_degrees;
- }
-
- /*******************************************************************/
- /** \brief Set a search center, and a count for an auto radius hunt.
- The way this works is that the center is set, and the optimal
- radius is selected in kilometers to deliver that many meetings.
- The radius starts at 25 Km (about 10 miles), and goes up or
- down in 5Km "clicks." Under 5Km, it reduces to 0.5Km "clicks."
- It will not go out more than 100Km.
-
- When it passes the threshold for the number of meetings in the
- square, the radius is selected, and the _search_radius is set
- to the number of Kilometers.
-
- We are not looking for an exact meeting count. It should select the
- first radius that contains AT LEAST the number of meetings requested.
-
- If not enough meetings are found, the radius ends up at 0.
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function SetSearchRadiusAndCenterAuto(
- $in_search_result_count, ///< A positive integer. It specifies the number of meetings to find.
- $in_long_in_degrees, ///< The longitude needs to be specified in degrees.
- $in_lat_in_degrees ///< The latitude needs to be specified in degrees.
- ) {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $this->_search_radius_count = $in_search_result_count;
- $this->_search_radius = 0;
- $this->_search_center_long = $in_long_in_degrees;
- $this->_search_center_lat = $in_lat_in_degrees;
- }
-
- /*******************************************************************/
- /** \brief Get the search radius.
-
- \returns a floating-point number. If the $in_miles parameter is false,
- the returned value is kilometers. If it is true, the returned value
- is in miles.
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function GetRadius(
- $in_miles = false ///< A boolean. If true, the returned value will be in miles. Otherwise, it is returned in kilometers.
- ) {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- return $in_miles ? ($this->_search_radius / 1.609344) : $this->_search_radius;
- }
-
- /*******************************************************************/
- /** \brief Get the longitude.
-
- \returns a floating-point number. The return is in degrees.
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function GetLongitude()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- return $this->_search_center_long;
- }
-
- /*******************************************************************/
- /** \brief Get the latitude.
-
- \returns a floating-point number. The return is in degrees.
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function GetLatitude()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- return $this->_search_center_lat;
- }
-
- /*******************************************************************/
- /** \brief Get the search for published value
-
- \returns an integer.
- - -1 Search for ONLY unpublished meetings
- - 0 Search for published and unpublished meetings.
- - 1 Search for ONLY published meetings.
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function GetPublished()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- return $this->_published_search;
- }
-
- /*******************************************************************/
- /** \brief Sets the search for published value
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function SetPublished(
- $in_published_search
- // The value to set. It can be:
- // - -1 Search for ONLY unpublished meetings
- // - 0 Search for published and unpublished meetings.
- // - 1 Search for ONLY published meetings.
- ) {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $this->_published_search = $in_published_search;
- }
-
- /*******************************************************************/
- /** \brief Set a start time window.
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function SetStartTime(
- $in_starts_after, ///< An epoch time, defining when the meeting should start (or after)
- $in_starts_before = null ///< If defined, the meeting must start no later than this.
- ) {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $this->_start_after = $in_starts_after;
-
- // We don't let this be less than, or equal to, the start time.
- if ((null != $in_starts_after) && (null != $in_starts_before)
- && (intval($in_starts_after) >= intval($in_starts_before))) {
- $in_starts_before = null;
- }
-
- // We don't let this be less than, or equal to, the start time.
- if ((null != $in_starts_after) && (null != $in_starts_before)
- && (intval($in_starts_after) >= intval($in_starts_before))) {
- $in_starts_before = null;
- }
-
- $this->_start_before = $in_starts_before;
- }
-
- /*******************************************************************/
- /** \brief Set a maximum end time.
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function SetEndTime(
- $in_ends_before ///< An epoch time, defining that the meeting must end no later than this.
- ) {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $this->_end_before = $in_ends_before;
- }
-
- /*******************************************************************/
- /** \brief Get the "ends before" value
-
- \returns an integer, containing the epoch time for the value.
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function GetEndsBefore()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- return $this->_end_before;
- }
-
- /*******************************************************************/
- /** \brief Get the "starts after" value
-
- \returns an integer, containing the epoch time for the value.
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function GetStartTime_Min()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- return $this->_start_after;
- }
-
- /*******************************************************************/
- /** \brief Get the "starts before" value
-
- \returns an integer, containing the epoch time for the value.
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function GetStartTime_Max()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- return $this->_start_before;
- }
-
- /*******************************************************************/
- /** \brief Set a duration time window.
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function SetDuration(
- $in_max_duration, ///< An epoch time, defining the maximum duration of a meeting.
- $in_min_duration = null ///< If defined, the minimum duration of the meeting.
- ) {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $this->_max_duration = $in_max_duration;
-
- // We don't let this be less than, or equal to, the start time.
- if (((null != $in_max_duration) && (null != $in_min_duration)) && intval($in_min_duration) >= intval($in_max_duration)) {
- $in_min_duration = null;
- }
-
- $this->_min_duration = $in_min_duration;
- }
-
- /*******************************************************************/
- /** \brief Get the Maximum Duration value
-
- \returns an integer, containing the epoch time for the value.
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function GetDuration_Max()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- return $this->_max_duration;
- }
-
- /*******************************************************************/
- /** \brief Get the Minimum Duration value
-
- \returns an integer, containing the epoch time for the value.
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function GetDuration_Min()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- return $this->_min_duration;
- }
-
- /*******************************************************************/
- /** \brief Set a search string.
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function SetSearchString(
- $in_search_string, ///< A string. This is a string for which to search.
- $in_all_words = false, ///< A Boolean. If this is true, then all of the words in a phrase must be present.
- $in_literal = false ///< A Boolean. If this is true, then the spelling must be literal.
- ) {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $this->_search_string = $in_search_string;
- $this->_search_string_all_words = $in_all_words;
- $this->_search_string_literal = $in_literal;
- }
-
- /*******************************************************************/
- /** \brief Get the current search string.
-
- \returns a reference to the search string.
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function GetSearchString()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- return $this->_search_string;
- }
-
- /*******************************************************************/
- /** \brief Set the current search string.
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function SetMeetingIDArray(
- $in_meeting_id_array ///< An array of positive integers. These are the IDs of individual meetings to find.
- ) {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $this->_meeting_id_array = $in_meeting_id_array;
- }
-
- /*******************************************************************/
- /** \brief Get the current search string.
-
- \returns a reference to the meeting ID array.
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function GetMeetingIDArray()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- return $this->_meeting_id_array;
- }
-
- /*******************************************************************/
- /** \brief Get the current search string "all words" flag.
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function StringSearchForAllWords()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- return $this->_search_string_all_words;
- }
-
- /*******************************************************************/
- /** \brief Get the current search string literal flag.
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function StringSearchIsLiteral()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- return $this->_search_string_literal;
- }
-
- /// These functions will help the caller to get information from the server. You can use them to build a search form.
-
- /*******************************************************************/
- /** \brief Returns an array of language enums and names.
-
- \returns a reference to an array of strings, containing the server
- languages in human-readable, local form. The key will be the enum,
- and the value will be the name of the language.
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function GetAvailableLanguages()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $ret = null;
-
- // Basic error checking.
- if ($this->_my_server instanceof c_comdef_server) {
- $ret = $this->_my_server->GetServerLangs();
- }
-
- return $ret;
- }
-
- /*******************************************************************/
- /** \brief Returns an array of references to c_comdef_service_body objects.
-
- This returns ALL Service bodies; whether or not they contain meetings.
-
- \returns a reference to an array of c_comdef_service_body objects.
- The key will be the ID of the Service body, and the value will be a reference
- to the object. Null, if the function fails for any reason.
-
- This will reference the actual objects controlled by the server.
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function GetAvailableServiceBodies()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $ret = null;
-
- // Basic error checking.
- if ($this->_my_server instanceof c_comdef_server) {
- $ret = $this->_my_server->GetServiceBodyArray();
- }
-
- return $ret;
- }
-
- /*******************************************************************/
- /** \brief Returns a multi-dimensional array of references to c_comdef_format objects.
-
- This returns ALL formats; whether or not they are used in meetings.
-
- \returns a reference to a multi-dimensional array of c_comdef_format objects.
- The key will be the language enum, and the value will be another array,
- which will have its key as the Shared ID of the format, and the value will be
- a reference to the object. Null, if the function fails for any reason.
-
- This will reference the actual objects controlled by the server.
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function GetAvailableFormats()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $ret = null;
-
- // Basic error checking.
- if ($this->_my_server instanceof c_comdef_server) {
- // Start by getting the format aggregator object.
- $formats_obj = $this->_my_server->GetFormatsObj();
-
- if ($formats_obj instanceof c_comdef_formats) {
- $ret = $formats_obj->GetFormatsArray();
- }
- }
-
- return $ret;
- }
-
- /*******************************************************************/
- /** \brief Returns an array of all possible field keys to be used for sorting.
-
- \returns an array of strings, with the key being the same as the value.
- NOTE: This contains ALL possible keys, including ones that may not be
- used in the found set.
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public static function GetAllAvailableSortKeys()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- return c_comdef_meeting::GetAllMeetingKeys();
- }
-
- /// These functions deal with the search itself.
-
- /*******************************************************************/
- /** \brief Returns an array of field keys to be used for sorting.
- This function is not static, and searches the found set for keys.
- As a result, it takes longer.
-
- \returns an array of strings, with the key being the same as the value.
- NOTE: This contains only the keys used in this found set.
-
- As a result, this will return null until after a search has been performed.
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function GetSpecificSortKeys()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $ret = null;
-
- if ($this->_search_results instanceof c_comdef_meetings) {
- $ret = $this->_search_results->GetMeetingKeys();
- }
-
- return $ret;
- }
-
- /*******************************************************************/
- /** \brief Executes a new search. It will always force a new search.
-
- \returns an integer that indicates the number of meetings found.
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function DoSearch()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $this->GetSearchResults_Obj(true);
-
- $ret = $this->GetNumberOfResults();
-
- return $ret;
- }
-
- /*******************************************************************/
- /** \brief Returns a reference to the c_comdef_meetings object that
- contains the results of the search. If this is null, or if the
- $in_new_search parameter is set to true, the search will be
- executed, otherwise, this just returns a reference to the existing
- search results.
-
- \returns a reference to the internal $_search_results field (an
- instance of c_comdef_search_results).
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function GetSearchResults_Obj(
- $in_new_search = false ///< If this is set to true, the search is done anew.
- ) {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- // See if we need to make a new search. Only the root can do a new search.
- if ((null == $this->_my_root) && (true == $in_new_search) || (null == $this->_search_results)) {
- $this->_search_results = null;
-
- // Basic error checking.
- if ($this->_my_server instanceof c_comdef_server) {
- // If we have an ID array, then we skip everything else, and just search for those IDs.
- if (is_array($this->_meeting_id_array) && count($this->_meeting_id_array)) {
- $this->_search_results = c_comdef_server::GetMeetingsByID($this->_meeting_id_array);
-
- if ($this->_search_results instanceof c_comdef_meetings) {
- $this->_search_results->RemoveInvalidMeetings();
-
- // Force a new sort.
- $this->SortMeetingObjects();
- }
- } else {
- // We start by specifying a search using the main criteria. We need to interpret the current state into search criteria.
-
- // Set up our Service Bodies Array.
- $service_bodies = null;
-
- if (is_array($this->_service_bodies) && count($this->_service_bodies)) {
- $service_bodies = array();
- foreach ($this->_service_bodies as $key => $value) {
- // If the value of the Service Body is 1 or -1, we add it to the list.
- if (abs($value) == 1) {
- array_push($service_bodies, intval($key) * $value);
- }
- }
- }
-
- // Set up our weekday array.
- $weekdays = null;
-
- if (is_array($this->_weekdays) && count($this->_weekdays)) {
- $weekdays = array();
- foreach ($this->_weekdays as $key => $value) {
- // If the value of the Weekday is 1 or -1, we add it to the list.
- if (abs($value) != 0) {
- array_push($weekdays, intval($key) * $value);
- }
- }
- }
-
- // Venue Types
- $venueTypes = null;
- if (is_array($this->_venue_types) && count($this->_venue_types)) {
- $venueTypes = array();
- foreach ($this->_venue_types as $key => $value) {
- if (abs($value) != 0) {
- // I have no idea why we are multiplying here... just following the pattern
- array_push($venueTypes, intval($key) * $value);
- }
- }
- }
-
- // Set up our formats array.
- $formats = null;
-
- if (is_array($this->_formats) && count($this->_formats)) {
- $formats = array();
- foreach ($this->_formats as $key => $value) {
- // If the value of the format is 1 or -1, we add it to the list.
- if (abs($value) == 1) {
- array_push($formats, intval($key) * $value);
- }
- }
- }
-
- $languages = null;
-
- if (is_array($this->_languages) && count($this->_languages)) {
- $languages = array();
- foreach ($this->_languages as $key => $value) {
- // If the value of the format is 1 or -1, we add it to the list.
- if (abs($value) == 1) {
- array_push($languages, ($value == -1) ? "-$key" : $key);
- }
- }
- }
-
- // If we will specify a search radius, we specify a restricted area for the search.
- $search_rect = $this->GetSquareForRadius($weekdays, $service_bodies);
-
- // Do the main database search first.
- $null_me = null;
- $this->_search_results = c_comdef_server::GetMeetings(
- $service_bodies,
- $languages,
- $weekdays,
- $venueTypes,
- $formats,
- $this->_start_after,
- $this->_start_before,
- $this->_end_before,
- $this->_min_duration,
- $this->_max_duration,
- $search_rect,
- null,
- $null_me,
- $this->_published_search,
- $this->_formats_comparison_operator
- );
- if (isset($this->_search_results) && $this->_search_results && ($this->_search_results instanceof c_comdef_meetings)) {
- $this->_search_results->RemoveInvalidMeetings();
-
- // Force a new sort.
- $this->SortMeetingObjects();
-
- // These are two "post-database" searches that we do.
- if (null != $this->_search_radius) {
- $this->_search_results = $this->_search_results->GetMeetingsByDistance($this->_search_center_long, $this->_search_center_lat, $this->_search_radius, true, $this->_sort_search_by_distance);
- }
-
- if (null != $this->_search_string) {
- $_search_results = $this->_search_results->GetMeetingsByString($this->_search_string, null, $this->_search_string_all_words, $this->_search_string_literal);
- $this->_search_results = null;
- $this->_search_results = $_search_results;
- }
-
- if ($this->_meeting_key) {
- $key_array = (is_array($this->_meeting_key) && count($this->_meeting_key)) ? $this->_meeting_key : array ( $this->_meeting_key );
- $_search_results = $this->_search_results->GetMeetingsByKeyValue($key_array, $this->_meeting_key_value, $this->_meeting_key_contains, $this->_meeting_key_match_case);
- $this->_search_results = null;
- $this->_search_results = $_search_results;
- }
- }
- }
- }
- }
-
- return $this->_search_results;
- }
-
- /*******************************************************************/
- /** \brief Clears the search results, so the next access will redo the search.
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function ClearSearch()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- // Only the root can clear its search results.
- if (null == $this->_my_root) {
- $this->_search_results = null;
- }
- }
-
- /*******************************************************************/
- /** \brief This will return the search results as an array of c_comdef_meeting
- objects.
-
- \returns a reference to an array of references to c_comdef_meeting objects.
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function GetSearchResultsAsArray()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $ret = null;
-
- if ($this->GetSearchResults_Obj() instanceof c_comdef_meetings) {
- $s_array = $this->GetSearchResults_Obj()->GetMeetingObjects();
-
- if (is_array($s_array) && count($s_array)) {
- $ret = $s_array;
- }
- }
-
- return $ret;
- }
-
- /// These are sorting functions.
-
- /*******************************************************************/
- /** \brief Simply clears out the sort array, so the search is unsorted.
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function ClearSort()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- // Only the root can do this.
- if (null == $this->_my_root) {
- $this->sort_array = null;
- }
- }
-
- /*******************************************************************/
- /** \brief Accessor. Set the maximum number of sorts to maintain.
- If the current number is more than the new value, then we remove any
- beyond that.
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function SetSortDepth(
- $in_new_depth = 0 ///< A positive integer. If nothing is provided, we set to endless (0).
- ) {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- // Only the root can do this.
- if (null == $this->_my_root) {
- $this->sort_depth = $in_new_depth;
- if (0 < $this->sort_depth) { // Only if a depth is defined.
- while (count($this->sort_array) > $this->sort_depth) {
- array_shift($this->sort_array); // Take off the bottommost one.
- }
- }
-
- // Force a new sort, based on the new depth.
- $this->SortMeetingObjects();
- }
- }
-
- /*******************************************************************/
- /** \brief Set a new "top" sort priority.
-
- The prior "top" sort priority will be made secondary. If the key
- was previously "lower" in the sort priority, it is removed from there.
-
- It will trigger a sort after the new key has been established.
-
- This allows a very "natural" type of sorting, where the user goes
- from one field to another.
-
- This will always reset the sort direction to the given one (or will
- reset to ascending). We could save the direction with each column,
- but that is likely to result in a confusing mess. It's a better idea
- to just apply the same direction to every column.
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function SetTopSortPriority(
- $in_new_top_sort_key, ///< A string. This should be the database table column name for the new "top" sort key.
- $in_desc = false ///< If this is set to true, the sort will be highest to lowest. Default is false.
- ) {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- // Only the root can do this.
- if (null == $this->_my_root) {
- // We first remove any previous mention of this key.
- for ($i = 0; $i < count($this->sort_array); $i++) {
- if ($this->sort_array[$i] == $in_new_top_sort_key) {
- unset($this->sort_array[$i]);
- break;
- }
- }
-
- // The new key goes in as the first item.
- if (!is_array($this->sort_array) || (1 > count($this->sort_array))) {
- $this->sort_array = array( $in_new_top_sort_key );
- } else {
- // We first see if we are at the limit for sort depth.
-
- if (0 < $this->sort_depth) { // Only if a depth is defined.
- while (count($this->sort_array) >= $this->sort_depth) {
- array_shift($this->sort_array); // Take off the bottommost one.
- }
- }
-
- array_unshift($this->sort_array, $in_new_top_sort_key);
- }
-
- // Make sure the new array direction is recorded.
- $this->sort_desc = $in_desc;
-
- // Force a new sort.
- $this->SortMeetingObjects();
- }
- }
-
- /*******************************************************************/
- /** \brief Sets up the sort array and direction. This replaces the
- entire array and direction. If the array is longer than the
- maximum number of sort keys, only that number of keys are used.
-
- It will reset the sort direction, so you need to explicitly indicate
- the sort direction if you want it descending, as opposed to ascending.
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function SetSort(
- $in_sort_fields_array = null,
- // An array of strings. The array will deliniate the sort order, by field name.
- // Array element [0] will be the highest priority, and it will descend from there.
- // If this is not specified, the sort will be cleared.
- $in_desc = false, ///< If this is set to true, the sort will be highest to lowest. Default is false.
- $in_max_sort_keys = 0 ///< A positive integer, specifying a new maximum sort depth. If it is not specified, the max will not be changed.
- ) {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- // Only the root can do this.
- if (null == $this->_my_root) {
- if (false != $in_desc) {
- $in_desc = true;
- }
-
- $this->sort_desc = $in_desc;
-
- if (0 < $in_max_sort_keys) {
- $this->sort_depth = $in_max_sort_keys;
- }
-
- if (null != $in_sort_fields_array) {
- $max = min($this->sort_depth, count($in_sort_fields_array));
-
- if ($max > 0) {
- $this->sort_array = array_slice($in_sort_fields_array, 0, $max);
- } else {
- $this->sort_array = null;
- }
- }
- }
- }
-
- /*******************************************************************/
- /** \brief Sorts the meetings.
- This will apply a sort, dependent upon the given fields.
- The given array contains the field names (SQL columns and keys)
- for the data to be sorted.
-
- If you don't specify any parameters, the ones from the last sort
- will be used.
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function SortMeetingObjects(
- $in_sort_fields_array = null,
- // An array of strings. The array will deliniate the sort order, by field name.
- // Array element [0] will be the highest priority, and it will descend from there.
- $in_desc = null ///< If this is set to true, the sort will be highest to lowest. Default is false.
- ) {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- // Only the root can do this.
- if (null == $this->_my_root) {
- if (null != $this->_search_results) {
- if (null != $in_sort_fields_array) {
- $this->sort_array = $in_sort_fields_array;
- } else {
- $in_sort_fields_array = $this->sort_array;
- }
-
- if (null != $in_desc) {
- $this->sort_desc = $in_desc;
- } else {
- $in_desc = $this->sort_desc;
- }
-
- if (is_array($in_sort_fields_array) && count($in_sort_fields_array)) {
- // This is simply a "pass-through" to the object we have on hand.
- $this->_search_results->SortMeetingObjects($in_sort_fields_array, $in_desc, $this->_sort_search_by_distance);
- }
- }
- }
- }
-
- /// These are various utility functions.
-
- /*******************************************************************/
- /** \brief This is an internal utility function that takes a specified
- radius and center point and calculates a square, in longitude and
- latitude points, that encompasses that radius. This greatly narrows
- the scope of the search, so the radius calculation will simply eliminate
- any meetings that are "in the corners."
-
- If the setting is for auto-radius, the auto-radius is first resolved, then
- the main radius value is set. Remember that auto-radius is for all meetings,
- all days of the week. It is really a "density test," as opposed to an
- accurate selector.
-
- \returns an array of floating-point values, in the following form:
- - ['east'] = longitude of the Eastern side of the rectangle
- - ['west'] = longitude of the Western side of the rectangle
- - ['north'] = latitude of the Northern side of the rectangle
- - ['south'] = latitude of the Southern side of the rectangle
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function GetSquareForRadius(
- $in_weekday_tinyint_array, ///< An array of weekdays in which to filter for.
- $in_service_bodies_array = null ///< An array of service bodies in which to filter for.
- ) {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $loc = array ();
-
- if ($this->_search_radius_count) {
- $this->_search_radius = c_comdef_server::HuntForRadius($this->_search_radius_count, $this->_search_center_long, $this->_search_center_lat, $in_weekday_tinyint_array, $in_service_bodies_array);
- $this->_search_radius_count = null;
- }
-
- if ($this->_search_radius > 0) {
- $loc = c_comdef_server::GetSquareForRadius($this->_search_radius, $this->_search_center_long, $this->_search_center_lat);
- }
-
- return $loc;
- }
-
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function SetFormatsComparisonOperator($operator)
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- if ($operator == "OR") {
- $this->_formats_comparison_operator = "OR";
- } else {
- $this->_formats_comparison_operator = "AND";
- }
- }
-
- /// These are static functions for directly accessing meetings via ID.
-
- /*******************************************************************/
- /** \brief This is a static utility function that will return one single
- instance of c_comdef_meeting, based upon the ID of that meeting.
-
- \returns a new (not reference) c_comdef_meeting instance. Null if it fails.
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public static function GetSingleMeetingByID(
- $in_id ///< An integer. The ID of the meeting.
- ) {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- return c_comdef_server::GetOneMeeting($in_id);
- }
-
- /*******************************************************************/
- /** \brief This is a static utility function that will return multiple
- instances of c_comdef_meeting, based upon the IDs of the meetings.
- It will create an array to hold these instances
-
- NOTE: This is NOT the same as the c_comdef_server::GetMeetingsByID()
- function, as that function returns an instance of c_comdef_meetings.
-
- \returns an array of new (not reference) c_comdef_meeting instances.
- Null if it fails.
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public static function GetMultipleMeetingsByID(
- $in_id_array ///< An array of integers. The IDs of the meetings.
- ) {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $ret = null;
-
- if (is_array($in_id_array) && count($in_id_array)) {
- foreach ($in_id_array as $id) {
- $ret[$id] = c_comdef_search_manager::GetSingleMeetingByID($id);
- }
- }
-
- return $ret;
- }
-}
diff --git a/src/legacy/client_interface/csv/common_search.inc.php b/src/legacy/client_interface/csv/common_search.inc.php
deleted file mode 100755
index 1a9fbaa7d..000000000
--- a/src/legacy/client_interface/csv/common_search.inc.php
+++ /dev/null
@@ -1,779 +0,0 @@
-.
-*/
-
-/*******************************************************************/
-/** \brief This function sets up the search manager to do the specified
- search. It does not actually do the search.
-*/
-function SetUpSearch(
- &$in_search_manager, ///< A reference to an instance of c_comdef_search_manager. The search manager to set up.
- &$in_http_vars
- // The various HTTP GET and POST parameters.
- // The values that are important to the search are:
- // - 'services'
- // This is an array of positive integers.
- // This is interpreted as an array of integers. Each integer represents the ID of a Service Body.
- // A positive integer means that the search will look specifically for meetings that contain that
- // Service Body ID.
- // If the integer is negative (preceded by a minus sign -), then the criteria will be to look
- // for meetings that don't contain that ID.
- // If no 'services' values are given, then the search will not use the Service Body field as a
- // search criteria.
- //
- // - 'recursive'
- // If this is set to '1', then the 'services' key will recursively follow Service bodies.
- //
- // - 'venue_types'
- // This is an array of integers.
- // This is interpreted as an array of integers. Each integer represents a Venue Type.
- // A positive integer means that the search will look specifically for meetings that have that Venue Type.
- // If the integer is negative (preceded by a minus sign -), then the criteria will be to look
- // for meetings that don't have that Venue Type.
- // If no 'venue_type' values are given, then the search will not use the Venue Type field as a
- // search criteria.
- //
- // - 'weekdays'
- // This is an array of negative or positive nonzero integers (-7 - -1, 1 - 7).
- // This is interpreted as an array of integers. Each integer represents a weekday (1 -> Sunday, 7 -> Saturday).
- // A positive integer means that the search will look specifically for meetings that occur on that weekday.
- // If the integer is negative (preceded by a minus sign -), then the criteria will be to look
- // for meetings that don't occur on that weekday.
- // If no 'weekdays' values are given, then the search will not use the weekday field as a
- // search criteria.
- //
- // - 'bmlt_search_type'
- // This is set to 'advanced' if the search is an advanced one (we need to take more criteria into consideration).
- //
- // - 'advanced_search_mode'
- // This is set if the call was made from the advanced search page.
- //
- // - 'advanced_formats'
- // This is the formats array, but is only counted if the bmlt_search_type is set to 'advanced'.
- //
- // - 'advanced_service_bodies'
- // This is the same, but for Service Bodies.
- //
- // - 'advanced_weekdays'
- // ...and weekdays.
- //
- // - 'advanced_radius'
- // ...and radius (in degrees)
- //
- // - advanced_mapmode
- // If this is true (1), then the Advanced form is using its map.
- //
- // - 'advanced_published'
- // This is a switch to indicate whether or not to display published or unpublished meetings.
- // It is only viable for logged-in users, and can have these values:
- // - -1 Search for ONLY unpublished meetings
- // - 0 Search for published and unpublished meetings.
- // - 1 Search for ONLY published meetings.
- //
- // - 'formats'
- // This is an array of positive integers.
- // This is interpreted as an array of integers. Each integer represents a format shared ID.
- // A format ID means that the search will look specifically for meetings that have that format.
- // If the format is negative (preceded by a minus sign -), then the criteria will be to look
- // for meetings that don't have that format.
- // If no 'formats' values are given, then the search will not use the formats field as a
- // search criteria.
- //
- // - 'formats_comparison_operator'
- // This is a string used to set the operator used to compare included (positive integer) formats. Valid values
- // and AND and OR.
- //
- // - 'langs'
- // This is an array of 2-character strings.
- // This is interpreted as an array of strings. Each string represents a language code, and is a 2-character string.
- // A language string means that the search will look specifically for meetings that are in that language.
- // If the language is preceded by a minus sign -, then the criteria will be to look
- // for meetings that are not in that language.
- // If no 'langs' values are given, then the search will not use the lang_enum field as a
- // search criteria.
- //
- // The following values specify a start time "window." The meeting must start on, or after StartsAfterH/M, and
- // can start no later than StartsBeforeH/M
- //
- // - 'StartsAfterH'
- // A positive integer between 0 and 23. The hour of the minimal start time for meetings, in military time.
- // - 'StartsAfterM'
- // A positive integer between 0 and 59. The minute of the minimal start time for meetings, in military time.
- // - 'StartsBeforeH'
- // A positive integer between 0 and 23. The hour of the maximal start time for meetings, in military time.
- // - 'StartsBeforeM'
- // A positive integer between 0 and 59. The minute of the maximal start time for meetings, in military time.
- //
- // The following values specify a time duration "window." The meeting can last no longer than MaxDurationH/M,
- // and no less than MinDurationH/M.
- //
- // - 'MinDurationH'
- // A positive integer. This is the number of hours in the minimal duration.
- // - 'MinDurationM'
- // A positive integer. This is the number of minutes in the minimal duration.
- // - 'MaxDurationH'
- // A positive integer. This is the number of hours in the maximal duration.
- // - 'MaxDurationM'
- // A positive integer. This is the number of minutes in the maximal duration.
- //
- // This is how meetings are located. We don't use address lookups. Instead, we geolocate the meetings via the
- // longitude and latitude fields in each record. If you don't specify a geolocation, then the entire database
- // is searched. If you do specify one, then only the portion within the radius is searched.
- //
- // - 'geo_width'
- // A floating point number. This is the radius (not diameter) of the search, in MILES (not Kilometers).
- // If this is negative, then it should be an integer, and that indicates an auto-radius is requested to
- // find the number of meetings in the integer.
- //
- // - 'geo_width_km'
- // A floating point number. This is the radius (not diameter) of the search, in KILOMETERS (not Miles).
- // If this is negative, then it should be an integer, and that indicates an auto-radius is requested to
- // find the number of meetings in the integer.
- //
- // - 'long_val'
- // If one of the three radius specifiers is zero or undefined, this is ignored.
- // This is a floating point number that specifies the longitude, in degrees, of the center of the search radius.
- //
- // - 'lat_val'
- // If one of the three radius specifiers is zero or undefined, this is ignored.
- // This is a floating point number that specifies the latitude, in degrees, of the center of the search radius.
- //
- // - 'SearchString'
- // A string. If this is specified, then all the string fields of the meetings specified by the above criteria
- // will be searched for the string. By default, if the language supports metaphone (sound like search), then
- // that is used.
- //
- // - 'StringSearchIsAnAddress'
- // A boolean. Nonzero means that the given string should not be checked against any of the fields in the meeting
- // data. Instead, it is to be considered a submission to the Google Maps geocode, and will be used to determine
- // a cernter point in a local search.
- //
- // - 'SearchStringAll'
- // If nonzero, then all of the words in the search string will have to be matched for a meetings to qualify.
- //
- // - 'SearchStringExact'
- // If nonzero, metaphone will not be used, and the spelling must be exact.
- //
- // - 'SearchStringRadius'
- // If specified, the radius of the search around the address (ignored if StringSearchIsAnAddress is false).
- // The units are in whatever the server units are for this language (can be miles or kilometers).
- // Negative numbers must always be integers, and specify a rough target number of meetings for auto-radius.
- //
- // - 'meeting_ids'
- // An array of positive integers. Each integer is an ID of an individual meeting. If this is set, all other
- // search criteria are ignored.
- //
- // - 'meeting_key'
- // A string. This is the exact name of the key to match. If this is null (Default), the following three are ignored.
- // NOTE: As of 1.5, the behavior of this field has changed.
- // If it is an array, then the string search is done via metaphone, unless meeting_key_match_case is true.
- // If it is an array, then the search is done on all the fields in the array, assuming they are all text.
- // Non-string fields are ignored.
- //
- // - 'meeting_key_value'
- // A string. The value to match.
- // NOTE: As of Version 1.5, this is matched with a metaphone match, as well as the RegEx match.
- //
- // - 'meeting_key_match_case'
- // If true, the case must match. Default is false.
- // NOTE: As of Version 1.5, setting this to TRUE also stops the metaphone search.
- //
- // - 'meeting_key_contains'
- // If this is true, then the string can have partial matches. Default is false (literal).
- //
- // - 'sort_results_by_distance'
- // If this is true, then, if possible, the search results will be sorted by distance from the radius center.
- // If this is set, then the 'sort_keys' parameter below will be ignored.
- //
- // - 'sort_keys'
- // This is a comma-separated list of sort keys. The leftmost one will be the top priority, and the rightmost the lowest.
- // The sort depth will be the number of keys.
- // The direction will be assumed 'asc', unless 'desc' is one of the keys (it can be anywhere in the list).
-) {
- $search_string = isset($in_http_vars['SearchString']) ? trim($in_http_vars['SearchString']) : '';
-
- if ($search_string && !(isset($in_http_vars['StringSearchIsAnAddress']) && $in_http_vars['StringSearchIsAnAddress']) && intval($search_string) && (preg_match('|\d+|', $search_string) || preg_match('(|\d+|,)+', $search_string))) {
- $temp_ids = explode(',', $search_string);
-
- if (is_array($temp_ids) && count($temp_ids)) {
- $first = true;
-
- foreach ($temp_ids as $id) {
- $id = intval(trim($id));
-
- if ($id) {
- if ($first) {
- $in_http_vars['meeting_ids'] = null;
- $first = false;
- }
-
- $in_http_vars['meeting_ids'][] = $id;
- }
- }
- } else {
- $id = intval($search_string);
-
- if ($id) {
- $in_http_vars['meeting_ids'] = array ( intval($id) );
- }
- }
- }
-
- // If we have a meeting ID array, then that defines the entire search. We ignore everything else
- if (isset($in_http_vars['meeting_ids']) && is_array($in_http_vars['meeting_ids']) && count($in_http_vars['meeting_ids'])) {
- $in_search_manager->SetMeetingIDArray($in_http_vars['meeting_ids']);
- } else {
- if (isset($in_http_vars['sort_results_by_distance'])) {
- $in_search_manager->SetSortByDistance($in_http_vars['sort_results_by_distance']);
- } elseif (isset($in_http_vars['sort_keys']) && $in_http_vars['sort_keys']) {
- $sort_fields = array();
- $keys = explode(',', $in_http_vars['sort_keys']);
- $dir = 'asc';
- foreach ($keys as $key) {
- if (strtolower(trim($key)) == 'desc') {
- $dir = 'desc';
- } else {
- $templates = c_comdef_meeting::GetDataTableTemplate();
- if ($templates && count($templates)) {
- $additional = array ();
-
- foreach ($templates as $template) {
- $value = $template['key'];
- array_push($additional, $value);
- }
-
- $standards = array ( 'weekday_tinyint', 'venue_type', 'id_bigint', 'worldid_mixed', 'service_body_bigint', 'lang_enum', 'duration_time', 'start_time', 'longitude', 'latitude' );
- $templates = array_merge($standards, $additional);
-
- if (in_array($key, $templates)) {
- array_push($sort_fields, $key);
- }
- }
- }
- }
-
- $in_search_manager->SetSort($sort_fields, $dir == 'desc', count($sort_fields));
- }
-
- // The first thing we do is try to resolve any address lookups.
- if ($search_string && isset($in_http_vars['StringSearchIsAnAddress']) && $in_http_vars['StringSearchIsAnAddress']) {
- $geo_search = (isset($in_http_vars['geo_width']) && $in_http_vars['geo_width']) ? true : ((isset($in_http_vars['geo_width_km']) && $in_http_vars['geo_width_km']) ? true : false);
-
- // We do a geocode to find out if this is an address.
- if (!$geo_search) {
- $search_string = preg_replace('|,(\s*?)|', ', ', $search_string); // This works around a bug caused by too-tight commas.
- $geo = GetGeocodeFromString($search_string, $in_http_vars['advanced_weekdays'] ?? null);
- if (is_array($geo) && count($geo)) {
- $localized_strings = c_comdef_server::GetLocalStrings();
-
- $in_http_vars['long_val'] = $geo['longitude'];
- $in_http_vars['lat_val'] = $geo['latitude'];
-
- if (isset($in_http_vars['SearchStringRadius']) && floatval($in_http_vars['SearchStringRadius']) != 0.0) {
- if (intval($in_http_vars['SearchStringRadius']) < 0) {
- $geo['radius'] = intval($in_http_vars['SearchStringRadius']);
- } else {
- $geo['radius'] = floatval($in_http_vars['SearchStringRadius']);
- }
- }
-
- if ($localized_strings['dist_units'] == 'mi') {
- if (isset($in_http_vars['geo_width_km'])) {
- unset($in_http_vars['geo_width_km']);
- }
- $in_http_vars['geo_width'] = $geo['radius'];
- } else {
- unset($in_http_vars['geo_width']);
- $in_http_vars['geo_width_km'] = $geo['radius'];
- }
-
- /* We need to undef these, because they can step on the long/lat. */
- unset($search_string);
- unset($in_http_vars['StringSearchIsAnAddress']);
- unset($in_http_vars['SearchStringRadius']);
- }
- }
- }
-
- // First, set up the services.
- if (isset($in_http_vars['bmlt_search_type']) && ($in_http_vars['bmlt_search_type'] == 'advanced') && isset($in_http_vars['advanced_service_bodies']) && is_array($in_http_vars['advanced_service_bodies']) && count($in_http_vars['advanced_service_bodies'])) {
- $in_http_vars['services'] = $in_http_vars['advanced_service_bodies'];
- }
-
- if (isset($in_http_vars['services']) && !is_array($in_http_vars['services'])) {
- $in_http_vars['services'] = array ( $in_http_vars['services'] );
- }
-
- // Look for Service bodies.
- if (isset($in_http_vars['services']) && is_array($in_http_vars['services']) && count($in_http_vars['services'])) {
- $services = array();
-
- if (isset($in_http_vars['recursive']) && $in_http_vars['recursive']) {
- foreach ($in_http_vars['services'] as $service) {
- $nested = GetAllContainedServiceBodyIDs(intval($service));
-
- if (isset($nested) && is_array($nested) && count($nested)) {
- foreach ($nested as $sb_i) {
- $sb_i = intval($sb_i);
- $services[$sb_i] = $sb_i;
- }
- }
- }
- } else {
- $services = $in_http_vars['services'];
- }
-
- $sb =& $in_search_manager->GetServiceBodies();
-
- foreach ($services as $service) {
- $sb[intval($service)] = 1;
- }
- } else {
- unset($in_http_vars['services']);
- }
-
- if (!( isset($in_http_vars['geo_width_km']) && $in_http_vars['geo_width_km'] )
- && !( isset($in_http_vars['geo_width']) && $in_http_vars['geo_width'] )
- && isset($in_http_vars['bmlt_search_type'])
- && ($in_http_vars['bmlt_search_type'] == 'advanced')
- && isset($in_http_vars['advanced_radius'])
- && isset($in_http_vars['advanced_mapmode'])
- && $in_http_vars['advanced_mapmode']
- && ( floatval($in_http_vars['advanced_radius'] != 0.0) )
- && isset($in_http_vars['lat_val'])
- && isset($in_http_vars['long_val'])
- && ( (floatval($in_http_vars['lat_val']) != 0.0) || (floatval($in_http_vars['long_val']) != 0.0) )
- ) {
- if ($localized_strings['dist_units'] == 'mi') {
- $in_http_vars['geo_width'] = $in_http_vars['advanced_radius'];
- unset($in_http_vars['geo_width_km']);
- } else {
- $in_http_vars['geo_width_km'] = $in_http_vars['advanced_radius'];
- unset($in_http_vars['geo_width']);
- }
- }
-
- // If we aren't doing any geographic searches, then we won't have a search center.
- if (!( isset($in_http_vars['geo_width']) && $in_http_vars['geo_width'] ) && !( isset($in_http_vars['geo_width_km']) && $in_http_vars['geo_width_km'] )) {
- unset($in_http_vars['lat_val']);
- unset($in_http_vars['long_val']);
- }
-
- // Next, set up the weekdays.
- if (isset($in_http_vars['bmlt_search_type']) && ($in_http_vars['bmlt_search_type'] == 'advanced') && isset($in_http_vars['advanced_weekdays']) && ((is_array($in_http_vars['advanced_weekdays']) && count($in_http_vars['advanced_weekdays'])) || isset($in_http_vars['advanced_weekdays']))) {
- $in_http_vars['weekdays'] = $in_http_vars['advanced_weekdays'];
- }
-
- if (isset($in_http_vars['weekdays']) && !is_array($in_http_vars['weekdays']) && (intval(abs($in_http_vars['weekdays'])) > 0) && (intval(abs($in_http_vars['weekdays'])) < 8)) {
- $in_http_vars['weekdays'] = array ( intval($in_http_vars['weekdays']) );
- }
-
- if (isset($in_http_vars['weekdays']) && is_array($in_http_vars['weekdays']) && count($in_http_vars['weekdays'])) {
- $wd =& $in_search_manager->GetWeekdays();
- foreach ($in_http_vars['weekdays'] as $weekday) {
- $wd[abs(intval($weekday))] = intval($weekday) > 0 ? 1 : -1;
- }
- } elseif (isset($in_http_vars['weekdays'])) {
- $wd =& $in_search_manager->GetWeekdays();
- $wd[abs(intval($in_http_vars['weekdays']))] = intval(intval($in_http_vars['weekdays'])) > 0 ? 1 : -1;
- }
-
- // Venue Types
- if (isset($in_http_vars['venue_types']) && is_array($in_http_vars['venue_types']) && count($in_http_vars['venue_types'])) {
- $vt =& $in_search_manager->GetVenueTypes();
- foreach ($in_http_vars['venue_types'] as $venueType) {
- $vt[abs(intval($venueType))] = intval($venueType) > 0 ? 1 : -1;
- }
- } else if (isset($in_http_vars['venue_types'])) {
- $vt =& $in_search_manager->GetVenueTypes();
- $vt[abs(intval($in_http_vars['venue_types']))] = intval($in_http_vars['venue_types']) > 0 ? 1 : -1;
- }
-
- // Next, set up the formats.
- if (isset($in_http_vars['bmlt_search_type']) && ($in_http_vars['bmlt_search_type'] == 'advanced') && isset($in_http_vars['advanced_formats']) && is_array($in_http_vars['advanced_formats']) && count($in_http_vars['advanced_formats'])) {
- $in_http_vars['formats'] = $in_http_vars['advanced_formats'];
- }
-
- if (isset($in_http_vars['formats'])) {
- if (!is_array($in_http_vars['formats'])) {
- $in_http_vars['formats'] = array ( intval($in_http_vars['formats']) );
- }
-
- $fm =& $in_search_manager->GetFormats();
- foreach ($in_http_vars['formats'] as $format) {
- $key = abs(intval($format));
- $fm[$key] = (intval($format) > 0) ? 1 : -1;
- }
- }
-
- if (isset($in_http_vars['formats_comparison_operator']) && $in_http_vars['formats_comparison_operator'] == "OR") {
- $in_search_manager->SetFormatsComparisonOperator("OR");
- }
-
- // Next, set up the languages.
- if (isset($in_http_vars['langs']) && is_array($in_http_vars['langs']) && count($in_http_vars['langs'])) {
- $lan =& $in_search_manager->GetLanguages();
- foreach ($in_http_vars['langs'] as $lng) {
- $lan[$lng] = 1;
- }
- }
-
- // Next, set up the advanced published option.
- if (isset($in_http_vars['advanced_published'])) {
- $in_search_manager->SetPublished(intval($in_http_vars['advanced_published']));
- } else {
- $in_search_manager->SetPublished(1);
- }
-
- // Set the start window.
- $start_time = null;
- $end_time = null;
-
- // Next, the minimum start time..
- if (isset($in_http_vars['StartsAfterH']) || isset($in_http_vars['StartsAfterM'])) {
- $start_hour = min(23, max(0, intval($in_http_vars['StartsAfterH'])));
- $start_minute = min(59, max(0, intval($in_http_vars['StartsAfterM'])));
- $start_time = mktime($start_hour, $start_minute);
- }
-
- // Next, the maximum start time..
- if (isset($in_http_vars['StartsBeforeH']) || isset($in_http_vars['StartsBeforeM'])) {
- $end_hour = min(23, max(0, intval($in_http_vars['StartsBeforeH'])));
- $end_minute = min(59, max(0, intval($in_http_vars['StartsBeforeM'])));
- $end_time = mktime($end_hour, $end_minute);
- }
-
- $in_search_manager->SetStartTime($start_time, $end_time);
-
- $end_time = null;
-
- // Next, the maximum end time..
- if (isset($in_http_vars['EndsBeforeH']) || isset($in_http_vars['EndsBeforeM'])) {
- $end_hour = min(23, max(0, intval($in_http_vars['EndsBeforeH'])));
- $end_minute = min(59, max(0, intval($in_http_vars['EndsBeforeM'])));
- $end_time = ($end_hour * 3600) + ($end_minute * 60);
- }
-
- $in_search_manager->SetEndTime($end_time);
-
- // Set the duration window.
- $max_duration_time = null;
- $min_duration_time = null;
-
- // Next, the minimum start time..
- if (isset($in_http_vars['MaxDurationH']) || isset($in_http_vars['MaxDurationM'])) {
- $max_duration_hour = min(23, max(0, intval($in_http_vars['MaxDurationH'])));
- $max_duration_minute = min(59, max(0, intval($in_http_vars['MaxDurationM'])));
- $max_duration_time = mktime($max_duration_hour, $max_duration_minute);
- }
-
- // Next, the maximum start time..
- if (isset($in_http_vars['MinDurationH']) || isset($in_http_vars['MinDurationM'])) {
- $min_duration_hour = min(23, max(0, intval($in_http_vars['MinDurationH'])));
- $min_duration_minute = min(59, max(0, intval($in_http_vars['MinDurationM'])));
- $min_duration_time = mktime($min_duration_hour, $min_duration_minute);
- }
-
- $in_search_manager->SetDuration($max_duration_time, $min_duration_time);
-
- // Next, we deal with a geolocated search radius.
-
- if ((isset($in_http_vars['geo_width']) && ($in_http_vars['geo_width'] != 0))
- || (isset($in_http_vars['geo_width_km']) && ($in_http_vars['geo_width_km'] != 0) )) {
- $long = isset($in_http_vars['long_val']) ? floatval($in_http_vars['long_val']) : 0;
- $lat = isset($in_http_vars['lat_val']) ? floatval($in_http_vars['lat_val']) : 0;
- $radius_in_miles = 0;
- $radius_in_km = 0;
- $local_strings = c_comdef_server::GetLocalStrings();
- $radius_auto = $local_strings['number_of_meetings_for_auto'];
-
- if (isset($in_http_vars['geo_width']) && ( $in_http_vars['geo_width'] != 0 )) {
- if ($in_http_vars['geo_width'] < 0) {
- $radius_auto = 0 - intval($in_http_vars['geo_width']);
- } else {
- $radius_in_miles = floatval($in_http_vars['geo_width']);
- }
- } elseif (isset($in_http_vars['geo_width_km']) && ( $in_http_vars['geo_width_km'] != 0 )) {
- if ($in_http_vars['geo_width_km'] < 0) {
- $radius_auto = 0 - intval($in_http_vars['geo_width_km']);
- } else {
- $radius_in_km = floatval($in_http_vars['geo_width_km']);
- }
- }
-
- if ($radius_in_miles > 0) {
- $in_search_manager->SetSearchRadiusAndCenterInMiles($radius_in_miles, $long, $lat);
- } elseif ($radius_in_km > 0) {
- $in_search_manager->SetSearchRadiusAndCenterInKm($radius_in_km, $long, $lat);
- } elseif ($radius_auto > 0) {
- $in_search_manager->SetSearchRadiusAndCenterAuto($radius_auto, $long, $lat);
- }
- }
-
- if (isset($search_string) && (!isset($in_http_vars['meeting_key']) || !(is_array($in_http_vars['meeting_key']) && count($in_http_vars['meeting_key'])))) {
- // And last, but not least, a string search:
- $find_all = (isset($in_http_vars['SearchStringAll']) && $in_http_vars['SearchStringAll']) ? true :false;
- $literal = (isset($in_http_vars['SearchStringExact']) && $in_http_vars['SearchStringExact']) ? true :false;
- $in_search_manager->SetSearchString($search_string, $find_all, $literal);
- }
-
- if (isset($in_http_vars['meeting_key']) && $in_http_vars['meeting_key']) {
- // This is true by default.
- if (!isset($in_http_vars['meeting_key_contains'])) {
- $in_http_vars['meeting_key_contains'] = false;
- }
-
- // This is false by default.
- if (!isset($in_http_vars['meeting_key_match_case'])) {
- $in_http_vars['meeting_key_match_case'] = false;
- }
- $in_search_manager->SetKeyValueSearch($in_http_vars['meeting_key'], $in_http_vars['meeting_key_value'], $in_http_vars['meeting_key_match_case'], $in_http_vars['meeting_key_contains']);
- }
- }
-}
-
-/*******************************************************************/
-/** \brief This gets all the Service bodies, and returns a one-dimensional
- arry, containing its ID, and the IDs of all the Service bodies
- that are contained in the array.
-
- \returns an array of integers.
-*/
-function GetAllContainedServiceBodyIDs(
- $in_parent_id = 0 ///< This is the ID of the top Service body (will not be included in the reponse).
-) {
- $in_parent_id = intval($in_parent_id);
- $ret = array( $in_parent_id );
-
- $service_bodies = c_comdef_server::GetServer()->GetServiceBodyArray();
-
- foreach ($service_bodies as $service_body) {
- $sb_id = intval($service_body->GetID());
- $parent_id = intval($service_body->GetOwnerID());
-
- if ($in_parent_id == $parent_id) {
- $ret2 = GetAllContainedServiceBodyIDs($sb_id);
- $ret = array_merge($ret, $ret2);
- }
- }
-
- return $ret;
-}
-
-/*******************************************************************/
-/** \brief This displays the format keys, along with abbreviations to
- display when the cursor is over them.
-
- \returns a string, containing the HTML rendered by the function, or,
- if the $lite parameter is set to true, an associative, multidimensional
- array, containing the information.
-*/
-function BuildFormats(
- $in_mtg_obj, ///< A reference to an instance of c_comdef_meeting.
- $lite = false ///< If this is set to true, then the formats will be returned in an associative array, instead of as HTML. Default is false.
-) {
- $formats = "";
-
- $formats_obj = $in_mtg_obj->GetMeetingDataValue('formats');
-
- if (is_array($formats_obj) && count($formats_obj)) {
- foreach ($formats_obj as $format) {
- if ($format instanceof c_comdef_format) {
- $key = htmlspecialchars($format->GetKey());
- $name = c_comdef_htmlspecialchars($format->GetLocalName());
- $desc = c_comdef_htmlspecialchars($format->GetLocalDescription());
- if ($lite) {
- $formats[$key]['name'] = $name;
- $formats[$key]['desc'] = $desc;
- } else {
- $formatspacer = '';
- if ($formats) {
- $formatspacer = ' ';
- }
-
- $formats .= "$formatspacer$key";
- }
- }
- }
- }
-
- return $formats;
-}
-
-/*******************************************************************/
-/** \brief Combines the town, borough and neighborhood into one string.
-
- \returns a string, containing the HTML rendered by the function.
-*/
-function BuildTown(
- $in_mtg_obj ///< A reference to an instance of c_comdef_meeting.
-) {
- $location_borough = c_comdef_htmlspecialchars(trim(stripslashes($in_mtg_obj->GetMeetingDataValue('location_city_subsection'))));
- $location_town = c_comdef_htmlspecialchars(trim(stripslashes($in_mtg_obj->GetMeetingDataValue('location_municipality'))));
- $location_neighborhood = c_comdef_htmlspecialchars(trim(stripslashes($in_mtg_obj->GetMeetingDataValue('location_neighborhood'))));
- $location_province = c_comdef_htmlspecialchars(trim(stripslashes($in_mtg_obj->GetMeetingDataValue('location_province'))));
-
- if ($location_province) {
- $location_town .= ', '.$location_province;
- }
-
- if ($location_borough) {
- $location_town = "$location_borough, $location_town";
- }
-
- if ($location_neighborhood) {
- $location_town = "$location_town ($location_neighborhood)";
- }
-
- return $location_town;
-}
-
-/*******************************************************************/
-/** \brief This creates a time string to be displayed for the meeting.
- The display is done in non-military time, and "midnight" and
- "noon" are substituted for 12:59:00, 00:00:00 and 12:00:00
-
- \returns a string, containing the HTML rendered by the function.
-*/
-function BuildTime(
- $in_time, ///< A string. The value of the time field.
- $in_integer = false ///< If true, the time is returned as an integer (Military time).
-) {
- $localized_strings = c_comdef_server::GetLocalStrings();
-
- $time = null;
-
- if ($in_integer) {
- $time = intval(str_replace(':', '', $in_time)) / 100;
- } else {
- if (($in_time == "00:00:00") || ($in_time == "23:59:00")) {
- $time = c_comdef_htmlspecialchars($localized_strings['comdef_server_admin_strings']['meeting_editor_screen_meeting_noon_label']);
- } elseif ($in_time == "12:00:00") {
- $time = c_comdef_htmlspecialchars($localized_strings['comdef_server_admin_strings']['meeting_editor_screen_meeting_midnight_label']);
- } else {
- $time = c_comdef_htmlspecialchars(date($localized_strings['time_format'], strtotime($in_time)));
- }
- }
-
- return $time;
-}
-
-/*******************************************************************/
-/** \brief This combines the location and street address fields.
-
- \returns a string, containing the HTML rendered by the function.
-*/
-function BuildLocation(
- $in_mtg_obj ///< A reference to an instance of c_comdef_meeting.
-) {
- $ret = "";
-
- if ($in_mtg_obj instanceof c_comdef_meeting) {
- $location_text = c_comdef_htmlspecialchars(trim(stripslashes($in_mtg_obj->GetMeetingDataValue('location_text'))));
- $street = c_comdef_htmlspecialchars(trim(stripslashes($in_mtg_obj->GetMeetingDataValue('location_street'))));
- $info = c_comdef_htmlspecialchars(trim(stripslashes($in_mtg_obj->GetMeetingDataValue('location_info'))));
-
- if ($location_text) {
- $ret .= $location_text;
- }
-
- if ($street) {
- if ($ret) {
- $ret .= ", ";
- }
- $ret .= $street;
- }
-
- if ($info) {
- if ($ret) {
- $ret .= " ";
- }
- $ret .= "($info)";
- }
- }
-
- return $ret;
-}
-
-/*******************************************************************/
-/** \brief This function uses the server-level Google Maps API to
- try to geocode an address from the string passed in. A instance
- of c_comdef_server needs to have been instantiated by the time
- this is called.
-
- \returns an associative array of two floating-point numbers,
- representing the longitude and latitude, in degrees, of any
- geocoded result. Null, if no valid result was returned.
-*/
-
-function GetGeocodeFromString(
- $in_string, ///< The string to be checked.
- $in_weekday_tinyint_array ///< An array of weekdays in which to filter for.
-) {
- $ret = null;
- $localized_strings = c_comdef_server::GetLocalStrings();
-
- $geo_uri = $localized_strings['comdef_server_admin_strings']['ServerMapsURL'];
-
- if ($localized_strings['region_bias']) {
- $geo_uri .= '®ion='.$localized_strings['region_bias'];
- }
-
- if ($localized_strings['google_api_key']) {
- $geo_uri .= '&key='.$localized_strings['google_api_key'];
- }
-
- // Bit of a kludge. If the string is just a number (a postcode), then we add the region bias directly to it.
- if (is_numeric($in_string) && $localized_strings['region_bias']) {
- $in_string .= " ".$localized_strings['region_bias'];
- }
-
- $geo_uri = str_replace('##SEARCH_STRING##', urlencode($in_string), $geo_uri);
-
- // We set up a 200-mile bounds, in order to encourage Google to look in the proper place.
- $m_p_deg = 100 / (111.321 * cos(deg2rad($localized_strings['search_spec_map_center']['latitude'])) * 1.609344); // Degrees for 100 miles.
- $bounds_ar = strval($localized_strings['search_spec_map_center']['latitude'] - $m_p_deg).",". strval($localized_strings['search_spec_map_center']['longitude'] - $m_p_deg); // Southwest corner
- $bounds_ar .= "|";
- $bounds_ar .= strval($localized_strings['search_spec_map_center']['latitude'] + $m_p_deg).",".strval($localized_strings['search_spec_map_center']['longitude'] + $m_p_deg); // Northeast corner
-
- $xml = simplexml_load_file($geo_uri);
-
- if ($xml->status == 'OK') {
- $ret['longitude'] = floatval($xml->result->geometry->location->lng);
- $ret['latitude'] = floatval($xml->result->geometry->location->lat);
- $radius = c_comdef_server::HuntForRadius($localized_strings['number_of_meetings_for_auto'], $ret['longitude'], $ret['latitude'], $in_weekday_tinyint_array);
- if ($radius) {
- // The native units for the radius search is km. We need to convert to miles, if we are in miles.
- if ($localized_strings['dist_units'] == 'mi') {
- $radius /= 1.609344;
- }
-
- $ret['radius'] = $radius;
- } else {
- $ret = null;
- }
- }
-
- return $ret;
-}
diff --git a/src/legacy/client_interface/csv/csv.php b/src/legacy/client_interface/csv/csv.php
deleted file mode 100755
index 44202a3f3..000000000
--- a/src/legacy/client_interface/csv/csv.php
+++ /dev/null
@@ -1,1592 +0,0 @@
-/client_interface/csv/
- with the same parameters that you would send to an advanced search. The results
- will be returned as a CSV file.
-
- This file can be called from other servers.
-
- This file is part of the Basic Meeting List Toolbox (BMLT).
-
- Find out more at: https://bmlt.app
-
- BMLT is free software: you can redistribute it and/or modify
- it under the terms of the MIT License.
-
- BMLT is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- MIT License for more details.
-
- You should have received a copy of the MIT License along with this code.
- If not, see .
-*/
-
-require_once(dirname(__FILE__).'/../../server/shared/classes/comdef_utilityclasses.inc.php');
-require_once(dirname(__FILE__).'/../../server/c_comdef_server.class.php');
-require_once(dirname(__FILE__).'/../../server/shared/Array2Json.php');
-require_once(dirname(__FILE__).'/../../server/shared/Array2XML.php');
-
-/*******************************************************************/
-/**
- \brief Queries the local server, and returns processed CSV data
-
- This requires that the "switcher=" parameter be set in the GET or
- POST parameters:
- - 'GetSearchResults'
- This returns the search results.
-
- \returns CSV data, with the first row a key header.
-*/
-function parse_redirect(
- &$server ///< A reference to an instance of c_comdef_server
-) {
- $result = null;
- $http_vars = array_merge_recursive($_GET, $_POST);
-
- $port = $_SERVER['SERVER_PORT'] ;
- // IIS puts "off" in the HTTPS field, so we need to test for that.
- $https = (!empty($_SERVER['HTTPS']) && (($_SERVER['HTTPS'] !== 'off') || ($port == 443)));
- $server_path = $_SERVER['SERVER_NAME'];
- $my_path = dirname(dirname(dirname($_SERVER['SCRIPT_NAME'])));
- $server_path .= trim((($https && ($port != 443)) || (!$https && ($port != 80))) ? ':'.$port : '', '/');
- $http_vars['bmlt_root'] = 'http'.($https ? 's' : '').'://'.$server_path.$my_path;
-
- $langs = array ( $server->GetLocalLang() );
- $localized_strings = c_comdef_server::GetLocalStrings();
-
- if (isset($http_vars['lang_enum'])) {
- if (!is_array($http_vars['lang_enum'])) {
- $langs = array ( trim($http_vars['lang_enum']) );
- } else {
- $langs = $http_vars['lang_enum'];
- }
- }
-
- if (!isset($http_vars['switcher'])) {
- $http_vars['switcher'] = '';
- }
-
- switch ($http_vars['switcher']) {
- case 'GetSearchResults':
- $meanLocationData = array();
- $formats_ar = array();
-
- if (isset($http_vars['xml_data'])) {
- $result2 = GetSearchResults($http_vars, $formats_ar, $meanLocationData);
- $result = "\n";
-
- $blueMeanieXML = '';
- $blueMeanieXML .= '';
- $blueMeanieXML .= ''.$meanLocationData['search_average']['location']['latitude'].'';
- $blueMeanieXML .= ''.$meanLocationData['search_average']['location']['longitude'].'';
- $blueMeanieXML .= '';
- $blueMeanieXML .= '';
- $blueMeanieXML .= ''.$meanLocationData['search_average']['radius']['miles'].'';
- $blueMeanieXML .= ''.$meanLocationData['search_average']['radius']['kilometers'].'';
- $blueMeanieXML .= '';
- $blueMeanieXML .= '';
- $blueMeanieXML .= '';
- $blueMeanieXML .= '';
- $blueMeanieXML .= ''.$meanLocationData['search_center']['location']['latitude'].'';
- $blueMeanieXML .= ''.$meanLocationData['search_center']['location']['longitude'].'';
- $blueMeanieXML .= '';
- $blueMeanieXML .= '';
- $blueMeanieXML .= ''.$meanLocationData['search_center']['radius']['miles'].'';
- $blueMeanieXML .= ''.$meanLocationData['search_center']['radius']['kilometers'].'';
- $blueMeanieXML .= '';
- $blueMeanieXML .= '';
-
- if (!isset($http_vars['getMeanLocationData'])) {
- $xsd_uri = 'http://'.htmlspecialchars(str_replace('/client_interface/xml', '/client_interface/xsd', trim(strtolower($_SERVER['SERVER_NAME'])).(($_SERVER['SERVER_PORT'] != 80) ? ':'.$_SERVER['SERVER_PORT'] : '').dirname($_SERVER['SCRIPT_NAME']).'/GetSearchResults.php'));
- $result .= "";
- $result .= TranslateToXML($result2);
- if ((isset($http_vars['get_used_formats']) || isset($http_vars['get_formats_only'])) && $formats_ar && is_array($formats_ar) && count($formats_ar)) {
- if (isset($http_vars['get_formats_only'])) {
- $result = "";
- $xsd_uri = 'http://'.htmlspecialchars(str_replace('/client_interface/xml', '/client_interface/xsd', trim(strtolower($_SERVER['SERVER_NAME'])).(($_SERVER['SERVER_PORT'] != 80) ? ':'.$_SERVER['SERVER_PORT'] : '').dirname($_SERVER['SCRIPT_NAME']).'/GetFormats.php'));
- $result .= "";
- } else {
- $result .= "";
- }
- $result3 = GetFormats($server, $langs, null, $formats_ar);
- $result .= TranslateToXML($result3);
- $result .= "";
- }
-
- if (!isset($http_vars['get_formats_only'])) {
- $result .= "";
- $result .= $blueMeanieXML;
- $result .= "";
- $result .= "";
- }
- } else {
- $xsd_uri = 'http://'.htmlspecialchars(str_replace('/client_interface/xml', '/client_interface/xsd', trim(strtolower($_SERVER['SERVER_NAME'])).(($_SERVER['SERVER_PORT'] != 80) ? ':'.$_SERVER['SERVER_PORT'] : '').dirname($_SERVER['SCRIPT_NAME']).'/GetMeetingLocationInfo.php'));
- $result .= "";
- $result .= $blueMeanieXML;
- $result .= "";
- }
- } elseif (isset($http_vars['gpx_data'])) {
- $result2 = GetSearchResults($http_vars, $formats_ar);
- $result2 = returnArrayFromCSV(explode("\n", $result2));
- if (is_array($result2) && count($result2)) {
- $result = "";
- $result .= "";
-
- $minlng = 361;
- $minlat = 361;
- $maxlng = -361;
- $maxlat = -361;
-
- foreach ($result2 as $meeting) {
- $lng = floatval($meeting['longitude']);
- $lat = floatval($meeting['latitude']);
-
- if ($lng || $lat) {
- $minlng = min($minlng, $lng);
- $minlat = min($minlat, $lat);
- $maxlng = max($maxlng, $lng);
- $maxlat = max($maxlat, $lat);
- }
- }
-
- $result .= '';
-
- foreach ($result2 as $meeting) {
- $desc = prepareSimpleLine($meeting);
-
- $name = c_comdef_htmlspecialchars(trim(stripslashes($meeting['meeting_name'])));
- if (!$name) {
- $name = "NA Meeting";
- }
-
- $lng = floatval($meeting['longitude']);
- $lat = floatval($meeting['latitude']);
- $type = 'NA Meeting';
-
- if ($lng || $lat) {
- $result .= '';
- $result .= '';
- if ($desc) {
- $result .= '';
- }
-
- $result .= '';
- $result .= 'Diamond, Blue';
- $result .= '';
- }
- }
-
- $result .= '';
- }
- } elseif (isset($http_vars['kml_data'])) {
- $result2 = GetSearchResults($http_vars, $formats_ar);
- $result2 = returnArrayFromCSV(explode("\n", $result2));
- if (is_array($result2) && count($result2)) {
- $result = "";
- $result .= '';
- $result .= '';
-
- foreach ($result2 as $meeting) {
- $desc = prepareSimpleLine($meeting);
- $address = prepareSimpleLine($meeting, false);
-
- $name = c_comdef_htmlspecialchars(trim(stripslashes($meeting['meeting_name'])));
-
- if (!$name) {
- $name = "NA Meeting";
- }
-
- $lng = floatval($meeting['longitude']);
- $lat = floatval($meeting['latitude']);
-
- if ($lng || $lat) {
- $result .= '';
- $result .= ''.htmlspecialchars($name).'';
-
- if ($address) {
- $result .= ''.$address.'';
- }
-
- if ($desc) {
- $result .= ''.$desc.'';
- }
-
- $result .= '';
- $result .= '';
- $result .= htmlspecialchars($lng).','.htmlspecialchars($lat).',0';
- $result .= '';
- $result .= '';
- $result .= '';
- }
- }
-
- $result .= '';
- $result .= '';
- }
- } elseif (isset($http_vars['poi_data'])) {
- $result2 = GetSearchResults($http_vars, $formats_ar);
- $result2 = returnArrayFromCSV(explode("\n", $result2));
- if (is_array($result2) && count($result2)) {
- $result = "lon,lat,name,desc\n";
- foreach ($result2 as $meeting) {
- $desc = htmlspecialchars_decode(prepareSimpleLine($meeting));
-
- $name = trim(stripslashes($meeting['meeting_name']));
-
- if (!$name) {
- $name = "NA Meeting";
- }
-
- $name = addcslashes($name, '"');
- $desc = addcslashes($desc, '"');
-
- $lng = floatval($meeting['longitude']);
- $lat = floatval($meeting['latitude']);
-
- if ($lng || $lat) {
- $result .= '"'.$lng.'","'.$lat.'","'.$name.'","'.$desc.'"'."\n";
- }
- }
- }
- } elseif (isset($http_vars['json_data'])) {
- $result = TranslateToJSON(GetSearchResults($http_vars, $formats_ar, $meanLocationData));
- if ((isset($http_vars['get_used_formats']) || isset($http_vars['get_formats_only']))) {
- if (isset($http_vars['get_formats_only'])) {
- $format_list = '[]';
- if (isset($formats_ar) && is_array($formats_ar) && count($formats_ar)) {
- $format_list = TranslateToJSON(GetFormats($server, $langs, null, $formats_ar));
- }
-
- $result = '{"formats":'.$format_list.'}';
- } else {
- if (isset($http_vars['appendMeanLocationData'])) {
- $result = '{"meetings":'.$result.',"formats":'.TranslateToJSON(GetFormats($server, $langs, null, $formats_ar)).',"locationInfo":'.array2json($meanLocationData).'}';
- } else {
- $format_list = '[]';
- if (isset($formats_ar) && is_array($formats_ar) && count($formats_ar)) {
- $format_list = TranslateToJSON(GetFormats($server, $langs, null, $formats_ar));
- }
-
- $result = '{"meetings":'.$result.',"formats":'.$format_list.'}';
- }
- }
- } else {
- if (isset($http_vars['getMeanLocationData']) && is_array($meanLocationData) && count($meanLocationData)) {
- if (isset($http_vars['appendMeanLocationData'])) {
- $result = '{"meetings":'.$result.',"locationInfo":'.array2json($meanLocationData).'}';
- } else {
- $result = array2json(array ( 'locationInfo' => $meanLocationData ));
- }
- }
- }
- } else {
- $result2 = GetSearchResults($http_vars, $formats_ar);
-
- if (isset($http_vars['get_formats_only'])) {
- $result2 = GetFormats($server, $langs, null, $formats_ar);
-
- if (!$result2) {
- $result2 = '[]';
- }
- }
-
- $result = $result2;
- }
- break;
-
- case 'GetFormats':
- $show_all_formats = isset($http_vars['show_all']) && $http_vars['show_all'] == '1';
- $formatKeyStrings = null;
- if (isset($http_vars['key_strings']) && is_array($http_vars['key_strings']) && count($http_vars['key_strings'])) {
- $formatKeyStrings = $http_vars['key_strings'];
- } else if (isset($http_vars['key_strings'])) {
- $formatKeyStrings = [$http_vars['key_strings']];
- }
-
- $result2 = GetFormats($server, $langs, $formatKeyStrings, null, $show_all_formats);
-
- if (isset($http_vars['xml_data'])) {
- $result = "";
- $xsd_uri = 'http://'.htmlspecialchars(str_replace('/client_interface/xml', '/client_interface/xsd', $_SERVER['SERVER_NAME'].(($_SERVER['SERVER_PORT'] != 80) ? ':'.$_SERVER['SERVER_PORT'] : '').dirname($_SERVER['SCRIPT_NAME']).'/GetFormats.php'));
- $result .= "";
- $result .= TranslateToXML($result2);
- $result .= "";
- } elseif (isset($http_vars['json_data'])) {
- $result = TranslateToJSON($result2);
- if (!$result) {
- $result = '[]';
- }
- } else {
- $result = $result2;
- }
- break;
-
- case 'GetServiceBodies':
- $recursive = isset($http_vars['recursive']) && $http_vars['recursive'] == '1';
- $parents = isset($http_vars['parents']) && $http_vars['parents'] == '1';
-
- $services = null;
- if (isset($http_vars['services'])) {
- $services = is_array($http_vars['services']) ? $http_vars['services'] : array($http_vars['services']);
- }
- $result2 = GetServiceBodies($server, $services, $recursive, $parents);
-
- if (isset($http_vars['xml_data'])) {
- $result = "";
- $xsd_uri = 'http://'.htmlspecialchars(str_replace('/client_interface/xml', '/client_interface/xsd', $_SERVER['SERVER_NAME'].(($_SERVER['SERVER_PORT'] != 80) ? ':'.$_SERVER['SERVER_PORT'] : '').dirname($_SERVER['SCRIPT_NAME']).'/GetServiceBodies.php'));
- $result .= "";
- $result .= TranslateToXML($result2);
- $result .= "";
- } elseif (isset($http_vars['json_data'])) {
- $result = TranslateToJSON($result2);
- if (!$result) {
- $result = '[]';
- }
- } else {
- $result = $result2;
- }
- break;
-
- case 'GetChanges':
- $start_date = null;
- $end_date = null;
- $meeting_id = null;
- $service_body_id = null;
- $meetings_only = true;
-
- if (isset($http_vars['start_date'])) {
- $start_date = strtotime(trim($http_vars['start_date']));
- }
-
- if (isset($http_vars['end_date'])) {
- $end_date = strtotime(trim($http_vars['end_date']));
- }
-
- if (isset($http_vars['meeting_id'])) {
- $meeting_id = intval($http_vars['meeting_id']);
- }
-
- if (isset($http_vars['service_body_id'])) {
- $service_body_id = intval($http_vars['service_body_id']);
- }
-
- $result2 = GetChanges($http_vars, $start_date, $end_date, $meeting_id, $service_body_id);
-
- if (isset($http_vars['xml_data'])) {
- $xsd_uri = 'http://'.htmlspecialchars(str_replace('/client_interface/xml', '/client_interface/xsd', $_SERVER['SERVER_NAME'].(($_SERVER['SERVER_PORT'] != 80) ? ':'.$_SERVER['SERVER_PORT'] : '').dirname($_SERVER['SCRIPT_NAME']).'/GetChanges.php'));
- $result = "".TranslateToXML($result2)."";
- } elseif (isset($http_vars['json_data'])) {
- $result = TranslateToJSON($result2);
- if (!$result) {
- $result = '[]';
- }
- } else {
- $result = $result2;
- }
- break;
-
- case 'GetServerInfo':
- $result2 = GetServerInfo();
- if (isset($http_vars['xml_data'])) {
- $result = "";
- $xsd_uri = 'http://'.htmlspecialchars(str_replace('/client_interface/xml', '/client_interface/xsd', $_SERVER['SERVER_NAME'].(($_SERVER['SERVER_PORT'] != 80) ? ':'.$_SERVER['SERVER_PORT'] : '').dirname($_SERVER['SCRIPT_NAME']).'/ServerInfo.php'));
- $result .= "";
- $result .= TranslateToXML($result2);
- $result .= "";
- } elseif (isset($http_vars['json_data'])) {
- $result = TranslateToJSON($result2);
- } else {
- $result = $result2;
- }
- break;
-
- case 'GetNAWSDump':
- $result = CSVHandleNawsDump($http_vars, $server);
- break;
-
- case 'GetCoverageArea':
- $result2 = GetCoverageArea();
- if (isset($http_vars['xml_data'])) {
- $result = "";
- $xsd_uri = 'http://'.htmlspecialchars(str_replace('/client_interface/xml', '/client_interface/xsd', $_SERVER['SERVER_NAME'].(($_SERVER['SERVER_PORT'] != 80) ? ':'.$_SERVER['SERVER_PORT'] : '').dirname($_SERVER['SCRIPT_NAME']).'/GetCoverageArea.php'));
- $result .= "";
- $result .= TranslateToXML($result2);
- $result .= "";
- } elseif (isset($http_vars['json_data'])) {
- $result = TranslateToJSON($result2);
- } else {
- $result = $result2;
- }
- break;
-
- case 'GetFieldKeys':
- $keys = c_comdef_meeting::GetFullTemplate();
-
- if (isset($keys) && is_array($keys) && count($keys)) {
- $result2 = array ('"key","description"');
-
- foreach ($keys as $key) {
- if (($key['visibility'] != 1) && ($key['key'] != 'published') && ($key['key'] != 'shared_group_id_bigint')) {
- $result2[] = '"'.$key['key'].'","'.$key['field_prompt'].'"';
- }
- }
-
- $result2 = implode("\n", $result2);
-
- if (isset($http_vars['xml_data'])) {
- $result = "";
- $xsd_uri = 'http://'.htmlspecialchars(str_replace('/client_interface/xml', '/client_interface/xsd', $_SERVER['SERVER_NAME'].(($_SERVER['SERVER_PORT'] != 80) ? ':'.$_SERVER['SERVER_PORT'] : '').dirname($_SERVER['SCRIPT_NAME']).'/GetFieldKeys.php'));
- $result .= "";
- $result .= TranslateToXML($result2);
- $result .= "";
- } elseif (isset($http_vars['json_data'])) {
- $result = TranslateToJSON($result2);
- } else {
- $result = $result2;
- }
- }
- break;
-
- case 'GetFieldValues':
- $meeting_key = trim($http_vars['meeting_key']);
- $values = c_comdef_meeting::GetAllValuesForKey($meeting_key);
- if (isset($values) && is_array($values) && count($values)) {
- $result2 = array ('"'.$meeting_key.'","ids"');
-
- foreach ($values as $value => $ids) {
- if (($meeting_key == 'formats') && isset($http_vars['specific_formats']) && trim($http_vars['specific_formats'])) {
- $targeted_formats = explode(',', trim($http_vars['specific_formats']));
- if (is_array($targeted_formats) && count($targeted_formats)) {
- $targeted_formats = array_map(intval, $targeted_formats);
- $these_formats = explode("\t", $value);
-
- if (is_array($these_formats) && count($these_formats)) {
- $these_formats = array_map(intval, $these_formats);
- $value = array_intersect($these_formats, $targeted_formats);
- if (isset($http_vars['all_formats'])) {
- $diff = array_diff($targeted_formats, $value);
- if (isset($diff) && is_array($diff) && count($diff)) {
- continue;
- }
- }
-
- if (!count($value)) {
- continue;
- } else {
- $value = implode("\t", $value);
- }
- } else {
- continue;
- }
- } else {
- break;
- }
- } elseif ($meeting_key == 'worldid_mixed') {
- if ($value != 'NULL') {
- $value = trim($value);
- }
- }
-
- $ids = explode('\t', $ids);
- $ids = trim(implode("\t", $ids));
- $result2[] = '"'.$value.'","'.$ids.'"';
- }
-
- $result3 = array();
-
- foreach ($result2 as $resultRow) {
- list ( $key, $value ) = explode(',', $resultRow);
-
- $value = explode("\t", trim($value, '"'));
- $oldValue = explode("\t", array_key_exists($key, $result3) ? $result3[$key] : "");
- $value = array_unique(array_merge($value, $oldValue));
- asort($value);
- $value = trim(implode("\t", $value));
- $result3[$key] = $value;
- }
-
- $result2 = array();
- foreach ($result3 as $key => $value) {
- $key = str_replace('&APOS&', ',', trim($key, '"'));
-
- $result2[] = "\"$key\",\"$value\"";
- }
-
- $result2 = implode("\n", $result2);
- }
-
- if (isset($http_vars['xml_data'])) {
- $result = "";
- $xsd_uri = 'http://'.htmlspecialchars(str_replace('/client_interface/xml', '/client_interface/xsd', $_SERVER['SERVER_NAME'].(($_SERVER['SERVER_PORT'] != 80) ? ':'.$_SERVER['SERVER_PORT'] : '').dirname($_SERVER['SCRIPT_NAME']).'/GetFieldValues.php'));
- $result .= "";
- $result .= str_replace("\t", ',', TranslateToXML($result2));
- $result .= "";
- } elseif (isset($http_vars['json_data'])) {
- $result = TranslateToJSON($result2);
- } else {
- $result = str_replace("\t", ',', $result2);
- }
- break;
-
- default:
- $result = HandleDefault($http_vars);
- break;
- }
-
- return $result;
-}
-
-/*******************************************************************/
-/**
- \brief This returns a string, with the meeting's daya, time and location data in a simple string.
-
- \returns a string, containing the meeting day, time and location summary.
-*/
-function prepareSimpleLine(
- $meeting, /**< An associative array of meeting data */
- $withDate = true /**< If false (default is true), the weekday and time will not be added. */
-) {
- $localized_strings = c_comdef_server::GetLocalStrings();
-
- $location_borough = array_key_exists('location_city_subsection', $meeting) ? c_comdef_htmlspecialchars(trim(stripslashes($meeting['location_city_subsection']))) : "";
- $location_neighborhood = array_key_exists('location_neighborhood', $meeting) ? c_comdef_htmlspecialchars(trim(stripslashes($meeting['location_neighborhood']))) : "";
- $location_province = array_key_exists('location_province', $meeting) ? c_comdef_htmlspecialchars(trim(stripslashes($meeting['location_province']))) : "";
- $location_nation = array_key_exists('location_nation', $meeting) ? c_comdef_htmlspecialchars(trim(stripslashes($meeting['location_nation']))) : "";
- $location_postal_code_1 = array_key_exists('location_postal_code_1', $meeting) ? c_comdef_htmlspecialchars(trim(stripslashes($meeting['location_postal_code_1']))) : "";
- $location_text = array_key_exists('location_text', $meeting) ? c_comdef_htmlspecialchars(trim(stripslashes($meeting['location_text']))) : "";
- $street = array_key_exists('location_street', $meeting) ? c_comdef_htmlspecialchars(trim(stripslashes($meeting['location_street']))) : "";
- $info = array_key_exists('location_info', $meeting) ? c_comdef_htmlspecialchars(trim(stripslashes($meeting['location_info']))) : "";
- $town = array_key_exists('location_municipality', $meeting) ? c_comdef_htmlspecialchars(trim(stripslashes($meeting['location_municipality']))) : "";
- $desc = $withDate ? '' : $location_text;
-
- if ($location_borough) {
- $town = $location_borough;
- }
-
- if ($location_province) {
- $town = "$town, $location_province";
- }
-
- if ($location_postal_code_1) {
- $town = "$town, $location_postal_code_1";
- }
-
- if ($location_nation) {
- $town = "$town, $location_nation";
- }
-
- if ($withDate && $location_neighborhood) {
- $town = "$town ($location_neighborhood)";
- }
-
- if ($street) {
- if ($desc) {
- $desc .= ", ";
- }
- $desc .= $street;
- }
-
- if ($town) {
- if ($desc) {
- $desc .= ", ";
- }
- $desc .= $town;
- }
-
- if ($withDate && $info) {
- if ($desc) {
- $desc .= " ($info)";
- } else {
- $desc = $info;
- }
- }
-
- $weekday = intval(trim(stripslashes($meeting['weekday_tinyint'])));
- $time = date($localized_strings['time_format'], strtotime($meeting['start_time']));
- $weekday = $localized_strings['comdef_server_admin_strings']['meeting_search_weekdays_names'][$weekday];
-
- $ret = null;
-
- if ($withDate && $weekday) {
- $ret = $weekday;
- }
-
- if ($withDate && $time) {
- if ($ret) {
- $ret .= ', ';
- }
-
- $ret .= $time;
- }
-
- if ($ret) {
- $ret .= ', ';
- }
-
- $ret .= $desc;
-
- return $ret;
-}
-
-/*******************************************************************/
-/**
- \brief
-*/
-function CSVHandleNawsDump(
- $in_http_Vars, ///< The ID of the Service Body to dump
- $in_server ///< The Root Server instance
-) {
- $sb = $in_server->GetServiceBodyByIDObj(intval($in_http_Vars['sb_id']));
-
- if ($sb) {
- require_once(dirname(__FILE__).'/search_results_csv.php');
- $service_bodies = array ( 'services' => c_comdef_server::GetServiceBodyHierarchyIDs(intval($in_http_Vars['sb_id'])) );
-
- $cc = preg_replace('|[\W]|', '_', strtoupper(trim($sb->GetWorldID())));
-
- if (preg_match('|^_+$|', $cc)) {
- $cc = '';
- }
-
- $filename = preg_replace('|[\W]|', '_', strtolower(trim($sb->GetLocalName())));
-
- if (preg_match('|^_+$|', $filename)) {
- $filename = '';
- }
-
- $filename .= date('_Y_m_d_H_i_s');
-
- if ($cc) {
- $filename = "$cc"."_$filename";
- }
-
- $sb_array = array("services" => array(), "advanced_published" => 0);
-
- // Make sure we all have NAWS IDs.
- foreach ($service_bodies["services"] as $sbID) {
- $service_body_object = $in_server->GetServiceBodyByIDObj($sbID);
- if ($service_body_object && $service_body_object->GetWorldID()) {
- $sb_array["services"][] = $sbID;
- }
- }
- header("Content-Disposition: attachment; filename=BMLT_$filename.csv");
- return ReturnNAWSFormatCSV($sb_array, $in_server);
- }
-}
-
-/*******************************************************************/
-/**
- \brief This returns an associative array from the given CSV, which is an array of lines, and the top line is the field names.
-
- \returns an associative array. Each main element will be one line, and each line will be an associative array of fields. If a field is not present in the line, it is not included.
-*/
-function returnArrayFromCSV(
- $inCSVArray ///< A array of CSV data, split as lines (each element is a single text line of CSV data). the first line is the header (array keys).
-) {
- $ret = null;
-
- $desc_line = $inCSVArray[0]; // Get the field names.
- $desc_line = explode('","', trim($desc_line, '"'));
-
- for ($index = 1; $index < count($inCSVArray); $index++) {
- $interim_line = explode('","', trim($inCSVArray[$index], '"'));
-
- if ($interim_line && count($interim_line)) {
- $result = null;
-
- $interim_line = array_combine($desc_line, $interim_line);
-
- foreach ($interim_line as $key => $value) {
- $value = trim($value);
-
- if ($value) {
- $result[$key] = $value;
- }
- }
-
- if (is_array($result) && count($result)) {
- $ret[] = $result;
- }
- }
- }
-
- return $ret;
-}
-
-/*******************************************************************/
-/**
- \brief Calculates the distance, in Km, between two long/lat pairs.
- This uses the Haversine formula.
- Cribbed from here: http://blog.voltampmedia.com/2011/12/17/php-implementation-of-haversine-computation/
-
- \returns A floating-point, positive number. The distance, in miles.
-*/
-function calcDistanceInMiles(
- $lat_1, ///< The latitude of the first point, in degrees.
- $long_1, ///< The longitude of the first point, in degrees.
- $lat_2, ///< The latitude of the second point, in degrees.
- $long_2 ///< The longitude of the second point, in degrees.
-) {
- $sin_lat = sin(deg2rad($lat_2 - $lat_1) / 2.0);
- $sin2_lat = $sin_lat * $sin_lat;
-
- $sin_long = sin(deg2rad($long_2 - $long_1) / 2.0);
- $sin2_long = $sin_long * $sin_long;
-
- $cos_lat_1 = cos($lat_1);
- $cos_lat_2 = cos($lat_2);
-
- $sqrt = sqrt($sin2_lat + ($cos_lat_1 * $cos_lat_2 * $sin2_long));
-
- $earth_radius = 3963.1676; // in miles
-
- $distance = 2.0 * $earth_radius * asin($sqrt);
-
- return $distance;
-}
-
-/*******************************************************************/
-/**
- \brief This returns the search results, in whatever form was requested.
-
- \returns CSV data, with the first row a key header.
-*/
-function GetSearchResults(
- $in_http_vars, ///< The HTTP GET and POST parameters.
- &$formats_ar = null, ///< This will return the formats used in this search.
- &$meanLocationData = null ///< This is a passed in receptacle for some location data calculations.
-) {
- if (!( isset($in_http_vars['geo_width']) && $in_http_vars['geo_width'] ) && isset($in_http_vars['bmlt_search_type']) && ($in_http_vars['bmlt_search_type'] == 'advanced') && isset($in_http_vars['advanced_radius']) && isset($in_http_vars['advanced_mapmode']) && $in_http_vars['advanced_mapmode'] && ( floatval($in_http_vars['advanced_radius'] != 0.0) ) && isset($in_http_vars['lat_val']) && isset($in_http_vars['long_val']) && ( (floatval($in_http_vars['lat_val']) != 0.0) || (floatval($in_http_vars['long_val']) != 0.0) )) {
- $in_http_vars['geo_width'] = $in_http_vars['advanced_radius'];
- } elseif (!( isset($in_http_vars['geo_width']) && $in_http_vars['geo_width'] ) && isset($in_http_vars['bmlt_search_type']) && ($in_http_vars['bmlt_search_type'] == 'advanced')) {
- $in_http_vars['lat_val'] = null;
- $in_http_vars['long_val'] = null;
- } elseif (!isset($in_http_vars['geo_loc']) || $in_http_vars['geo_loc'] != 'yes') {
- if (!isset($in_http_vars['geo_width'])) {
- $in_http_vars['geo_width'] = 0;
- }
- }
-
- require_once(dirname(__FILE__).'/search_results_csv.php');
- $geocode_results = null;
- $ignore_me = null;
- $meeting_objects = array();
- $result = DisplaySearchResultsCSV($in_http_vars, $ignore_me, $geocode_results, $meeting_objects);
- $locationData = array ( );
-
- if (is_array($meeting_objects) && count($meeting_objects)) {
- foreach ($meeting_objects as $one_meeting) {
- if (isset($in_http_vars['getMeanLocationData']) || (isset($meanLocationData)&& is_array($meanLocationData))) {
- $locationData[] = array ( 'long' => floatval($one_meeting->GetMeetingDataValue('longitude')), 'lat' => floatval($one_meeting->GetMeetingDataValue('latitude')) );
- }
-
- if (is_array($formats_ar)) {
- $formats = $one_meeting->GetMeetingDataValue('formats');
-
- foreach ($formats as $format) {
- if ($format && ($format instanceof c_comdef_format)) {
- $format_shared_id = $format->GetSharedID();
- $formats_ar[$format_shared_id] = $format;
- }
- }
- }
- }
- }
-
- if (count($locationData)) { // If the caller just wants an average location report, then give them that.
- $avgLong = 0.0;
- $avgLat = 0.0;
- $minLong = 1000.0;
- $maxLong = -1000.0;
- $minLat = 1000.0;
- $maxLat = -1000.0;
-
- foreach ($locationData as $location) {
- $avgLong += $location['long'];
- $avgLat += $location['lat'];
- $minLong = min($minLong, $location['long']);
- $maxLong = max($maxLong, $location['long']);
- $minLat = min($minLat, $location['lat']);
- $maxLat = max($maxLat, $location['lat']);
- }
-
- $avgLong = $avgLong / floatVal(count($locationData));
- $avgLat = $avgLat / floatVal(count($locationData));
- $centerLat = ($maxLat + $minLat) / 2.0;
- $centerLong = ($maxLong + $minLong) / 2.0;
-
- $d1 = calcDistanceInMiles($avgLat, $avgLong, $maxLat, $maxLong);
- $d2 = calcDistanceInMiles($avgLat, $avgLong, $minLat, $minLong);
- $d3 = calcDistanceInMiles($avgLat, $avgLong, $minLat, $maxLong);
- $d4 = calcDistanceInMiles($avgLat, $avgLong, $maxLat, $minLong);
-
- $avg_radiusMi = max($d1, $d2, $d3, $d4);
- $avg_radiusKm = $avg_radiusMi * 1.60934;
-
- $hard_radiusMi = calcDistanceInMiles($centerLat, $centerLong, $maxLat, $maxLong);
- $hard_radiusKm = $hard_radiusMi * 1.60934;
-
- if (isset($meanLocationData) && is_array($meanLocationData)) {
- $meanLocationData = array ( 'search_average' => array ( 'location' => array ( 'latitude' => $avgLat, 'longitude' => $avgLong, ), 'radius' => array ( 'miles' => $avg_radiusMi, 'kilometers' => $avg_radiusKm ) ),
- 'search_center' => array ( 'location' => array ( 'latitude' => $centerLat, 'longitude' => $centerLong, ), 'radius' => array ( 'miles' => $hard_radiusMi, 'kilometers' => $hard_radiusKm ) ));
- }
-
- if (isset($in_http_vars['getMeanLocationData'])) {
- $result = '"average_center_latitude","average_center_longitude","average_radius_mi","average_radius_km","search_center_latitude","search_center_longitude","search_center_radius_mi","search_center_radius_km"'."\n";
- $result .= '"'.$avgLat.'","'.$avgLong.'","'.$avg_radiusMi.'","'.$avg_radiusKm.'","'.$centerLat.'","'.$centerLong.'","'.$hard_radiusMi.'","'.$hard_radiusKm.'"';
- }
- }
-
- if (!isset($in_http_vars['getMeanLocationData']) && isset($in_http_vars['data_field_key']) && $in_http_vars['data_field_key']) {
- // At this point, we have everything in a CSV. We separate out just the field we want.
- $temp_keyed_array = array();
- $result = explode("\n", $result);
- $keys = array_shift($result);
- $keys = explode("\",\"", trim($keys, '"'));
- $the_keys = explode(',', $in_http_vars['data_field_key']);
-
- $result2 = array();
- foreach ($result as $row) {
- if ($row) {
- $index = 0;
- $row = explode('","', trim($row, '",'));
- $row_columns = array();
- foreach ($row as $column) {
- if (!$column) {
- $column = ' ';
- }
- if (in_array($keys[$index++], $the_keys)) {
- array_push($row_columns, $column);
- }
- }
- $result2[$row[0]] = '"'.implode('","', $row_columns).'"';
- }
- }
-
- $the_keys = array_intersect($keys, $the_keys);
- $result = '"'.implode('","', $the_keys)."\"\n".implode("\n", $result2);
- }
- return $result;
-}
-
-/*******************************************************************/
-/** \brief Returns a set of two coordinates that define a rectangle
- that encloses all of the meetings.
-
- \returns a dictionary, with the two coordinates.
-*/
-function GetCoverageArea()
-{
- $result = c_comdef_server::GetCoverageArea();
- $ret = null;
-
- if (isset($result) && is_array($result) && count($result)) {
- $ret = array ( '"nw_corner_longitude","nw_corner_latitude","se_corner_longitude","se_corner_latitude"' );
- $ret[1] = '"'.strval($result["nw_corner"]["longitude"]).'","'.strval($result["nw_corner"]["latitude"]).'","'.strval($result["se_corner"]["longitude"]).'","'.strval($result["se_corner"]["latitude"]).'"';
- $ret = implode("\n", $ret);
- }
-
- return $ret;
-}
-
-/*******************************************************************/
-/**
- \brief This returns the complete formats table.
-
- \returns CSV data, with the first row a key header.
-*/
-function GetFormats(
- &$server, ///< A reference to an instance of c_comdef_server
- $in_lang = null, ///< The language of the formats to be returned.
- $in_key_strings = null, ///< If supplied, an array of format key strings to be returned.
- $in_formats = null, //< If supplied, an already-fetched array of formats.
- $show_all = false //< If true return all formats regardless of if they are used or not.
-) {
- $my_keys = array ( 'key_string',
- 'name_string',
- 'description_string',
- 'lang',
- 'id',
- 'world_id',
- 'root_server_uri',
- 'format_type_enum',
- );
-
- $ret = null;
-
- $formats_obj = $server->GetFormatsObj();
- if ($formats_obj instanceof c_comdef_formats) {
- $langs = $server->GetFormatLangs();
- $used_formats = $server->GetUsedFormatIDs();
- if (isset($in_lang) && is_array($in_lang) && count($in_lang)) {
- $langs2 = array();
- foreach ($in_lang as $key) {
- if (array_key_exists($key, $langs)) {
- $langs2[$key] = $langs[$key];
- }
- }
-
- $langs = $langs2;
- } elseif (array_key_exists($in_lang, $langs)) {
- $langs = array ( $in_lang => $langs[$in_lang] );
- }
-
- $ret .= '"'.implode('","', $my_keys)."\"\n";
- foreach ($langs as $key => $value) {
- if ($in_formats) {
- $format_array = $in_formats;
- } else {
- $format_array = $formats_obj->GetFormatsByLanguage($key);
- }
-
- if (is_array($format_array) && count($format_array)) {
- foreach ($format_array as $format) {
- if ($format instanceof c_comdef_format) {
- $localized_format = $server->GetOneFormat($format->GetSharedID(), $key);
-
- if (isset($in_key_strings) && is_array($in_key_strings) && count($in_key_strings)) {
- if (!in_array($localized_format->GetKey(), $in_key_strings)) {
- continue;
- }
- }
-
- if ($localized_format instanceof c_comdef_format) {
- $line = '';
- foreach ($my_keys as $ky) {
- if ($line) {
- $line .= ',';
- }
-
- $val = '';
-
- switch ($ky) {
- case 'lang':
- $val = $key;
- break;
-
- case 'id':
- $val = $localized_format->GetSharedID();
- break;
-
- case 'key_string':
- $val = $localized_format->GetKey();
- break;
-
- case 'name_string':
- $val = $localized_format->GetLocalName();
- break;
-
- case 'description_string':
- $val = $localized_format->GetLocalDescription();
- break;
-
- case 'world_id':
- $val = $localized_format->GetWorldID();
- break;
-
- case 'root_server_uri':
- $val = dirname(dirname(GetURLToMainServerDirectory(true)));
- break;
-
- case 'format_type_enum':
- $val = $localized_format->GetFormatType();
- break;
- }
-
- $line .= '"'.str_replace('"', '\"', trim($val)).'"';
- }
- if ($show_all || in_array($localized_format->GetSharedID(), $used_formats)) {
- $ret .= "$line\n";
- }
- }
- }
- }
- }
- }
- }
-
- return $ret;
-}
-
-/*******************************************************************/
-/**
- \brief This returns the complete Service bodies table.
-
- \returns CSV data, with the first row a key header.
-*/
-function GetServiceBodies(
- &$server, ///< A reference to an instance of c_comdef_server
- $services = null,
- $recursive = false,
- $parents = false
-) {
- $ret = array ();
- $localized_strings = c_comdef_server::GetLocalStrings();
-
- $ret[0] = '"id","parent_id","name","description","type","url","helpline","world_id"';
-
- if ($localized_strings['include_service_body_email_in_semantic']) {
- $ret[0] .= ',"contact_email"';
- }
-
- $servicesInclude = array();
- $servicesExclude = array();
- if ($services) {
- foreach ($services as $id) {
- if (substr($id, 0, 1) == "-") {
- array_push($servicesExclude, substr($id, 1));
- } else {
- array_push($servicesInclude, $id);
- }
- }
- }
-
- if ($recursive) {
- $servicesInclude = array_merge($servicesInclude, GetChildServiceBodies($server, $servicesInclude));
- $servicesExclude = array_merge($servicesExclude, GetChildServiceBodies($server, $servicesExclude));
- }
-
- if ($parents) {
- $servicesInclude = array_merge($servicesInclude, GetParentServiceBodies($server, $servicesInclude));
- }
-
- try {
- $array_obj = $server->GetServiceBodyArray();
- if (is_array($array_obj) && count($array_obj)) {
- foreach ($array_obj as &$sb) {
- if ($sb instanceof c_comdef_service_body) {
- if (count($servicesInclude) && !in_array($sb->GetID(), $servicesInclude)) {
- continue;
- }
- if (count($servicesExclude) && in_array($sb->GetID(), $servicesExclude)) {
- continue;
- }
- $row = array();
- $row[] = $sb->GetID();
- $row[] = $sb->GetOwnerID();
- $row[] = $sb->GetLocalName();
- $description = preg_replace('|[^\S]+?|', " ", $sb->GetLocalDescription());
- $row[] = $description;
- $row[] = $sb->GetSBType();
- $row[] = $sb->GetURI();
- $row[] = trim($sb->GetHelpline());
- $row[] = $sb->GetWorldID();
- if ($localized_strings['include_service_body_email_in_semantic']) {
- $row[] = trim($sb->GetContactEmail());
- }
- $row = '"'.implode('","', $row).'"';
- $ret[] = $row;
- }
- }
- }
- } catch (Exception $e) {
- }
-
- return implode("\n", $ret);
-}
-
-function GetParentServiceBodies($server, $serviceBodyIds)
-{
- $ret = array();
- $serviceBodyArray = $server->GetServiceBodyArray();
- $parents = $serviceBodyIds;
- while (count($parents)) {
- $newParents = array();
- foreach ($serviceBodyArray as $serviceBody) {
- if (in_array($serviceBody->GetID(), $parents) && !in_array($serviceBody->GetOwnerID(), $ret)) {
- array_push($newParents, $serviceBody->GetOwnerID());
- array_push($ret, $serviceBody->GetOwnerID());
- }
- }
- $parents = $newParents;
- }
- return $ret;
-}
-
-function GetChildServiceBodies($server, $parents)
-{
- $ret = array();
- $children = $parents;
- $serviceBodyArray = $server->GetServiceBodyArray();
- while (count($children)) {
- $newChildren = array();
- foreach ($serviceBodyArray as $serviceBody) {
- if (in_array($serviceBody->GetOwnerID(), $children) && !in_array($serviceBody->GetID(), $ret)) {
- array_push($newChildren, $serviceBody->GetID());
- array_push($ret, $serviceBody->GetID());
- }
- }
- $children = $newChildren;
- }
- return $ret;
-}
-
-/*******************************************************************/
-/**
- \brief This returns a line of server info.
-
- \returns CSV data, with the first row a key header.
-*/
-function GetServerInfo()
-{
- require(dirname(__FILE__).'/../../server/config/get-config.php');
- $ret = '';
- $version_array = GetServerVersion();
- $version_num = (intval($version_array[0]) * 1000000) + (intval($version_array[1]) * 1000) + intval($version_array[2]);
- $version_string = strval($version_array[0]).'.'.strval($version_array[1]).'.'.strval($version_array[2]);
- $lang_array = c_comdef_server::GetServerLangs();
- $lang_string = implode(',', array_keys($lang_array));
- $localStrings = c_comdef_server::GetLocalStrings();
- $default_lang = strval($localStrings['enum']);
- $canAdmin = isset($g_enable_semantic_admin) && $g_enable_semantic_admin ? '1' : '0';
- $centerLongLatZoom = implode(',', $localStrings['search_spec_map_center']);
- $canEmail = isset($g_enable_email_contact) && $g_enable_email_contact ? '1' : '0';
- $includeServiceBodiesOnEmails = isset($include_service_body_admin_on_emails) && $include_service_body_admin_on_emails ? '1' : '0';
- $changeDepth = strVal(intval($change_depth_for_meetings));
- $dbVersion = c_comdef_server::GetDatabaseVersion();
- $availableFields = "";
- $keys = c_comdef_meeting::GetFullTemplate();
- $meeting_time_zones_enabled = $localStrings['meeting_time_zones_enabled'] ? '1' : '0';
- $phpVersion = phpversion();
-
- foreach ($keys as $key) {
- if (($key['visibility'] != 1) && ($key['key'] != 'published') && ($key['key'] != 'shared_group_id_bigint')) {
- if ($availableFields != "") {
- $availableFields .= ',';
- }
-
- $availableFields .= $key['key'];
- }
- }
-
- $ret = '"version","versionInt","langs","nativeLang","centerLongitude","centerLatitude","centerZoom","defaultDuration","regionBias","charSet","distanceUnits","semanticAdmin","emailEnabled","emailIncludesServiceBodies","changesPerMeeting","meeting_states_and_provinces","meeting_counties_and_sub_provinces","available_keys","google_api_key","dbVersion","dbPrefix","meeting_time_zones_enabled","phpVersion"'."\n";
- $ret .= '"'.$version_string.'","'.strval($version_num).'","'.$lang_string.'","'.$default_lang.'",';
- $ret .= '"'.strval($localStrings['search_spec_map_center']['longitude']).'","'.strval($localStrings['search_spec_map_center']['latitude']).'",';
- $ret .= '"'.strval($localStrings['search_spec_map_center']['zoom']).'","'.$localStrings['default_duration_time'].'",';
- $ret .= '"'.$localStrings['region_bias'].'","'.$localStrings['charset'].'","'.$localStrings['dist_units'].'","'.$canAdmin.'",';
- $ret .= '"'.$canEmail.'","'.$includeServiceBodiesOnEmails.'","'.$changeDepth.'","'.implode(',', $localStrings['meeting_states_and_provinces']).'","'.implode(',', $localStrings['meeting_counties_and_sub_provinces']).'","'.str_replace('"', '\"', $availableFields).',root_server_uri,format_shared_id_list","'.$localStrings['google_api_key'].'","'.$dbVersion.'","'.$localStrings['dbPrefix'].'","'.$meeting_time_zones_enabled.'","'.$phpVersion.'"';
-
- return $ret;
-}
-
-/*******************************************************************/
-/**
- \brief Returns the server version in an array.
-
- \returns an array of integers, with [0] being the main version, [1] being the minor version, and [2] being the fix version.
-*/
-function GetServerVersion()
-{
-
- $ret = explode('.', config()->get('app.version'));
-
- if (!isset($ret[1])) {
- $ret[1] = '0';
- }
-
- if (!isset($ret[2])) {
- $ret[1] = '0';
- }
-
- $ret[0] = intval($ret[0]);
- $ret[1] = intval($ret[1]);
- $ret[2] = intval($ret[2]);
-
- return $ret;
-}
-
-/*******************************************************************/
-/**
- \brief This returns change records.
-
- \returns CSV data, with the first row a key header.
-*/
-function GetChanges(
- $in_http_vars, ///< The HTTP GET/POST query.
- $in_start_date = null, ///< Optional. A start date (In PHP time() format). If supplied, then only changes on, or after this date will be returned.
- $in_end_date = null, ///< Optional. An end date (In PHP time() format). If supplied, then only changes that occurred on, or before this date will be returned.
- $in_meeting_id = null, ///< Optional. If supplied, an ID for a particular meeting. Only changes for that meeting will be returned.
- $in_sb_id = null ///< Optional. If supplied, an ID for a particular Service body. Only changes for that Service body will be returned.
-) {
- $ret = null;
-
- try {
- $change_objects = c_comdef_server::GetChangesFromIDAndType('c_comdef_meeting', null, $in_start_date, $in_end_date);
- if ($change_objects instanceof c_comdef_changes) {
- $obj_array = $change_objects->GetChangesObjects();
-
- if (is_array($obj_array) && count($obj_array)) {
- set_time_limit(max(30, intval(count($obj_array) / 20))); // Change requests can take a loooong time...
- $localized_strings = c_comdef_server::GetLocalStrings();
- include(dirname(__FILE__).'/../../server/config/get-config.php');
- $ret = '"date_int","date_string","change_type","change_id","meeting_id","meeting_name","user_id","user_name","service_body_id","service_body_name","meeting_exists","details","json_data"'."\n";
-
- // If they specify a Service body, we also look in "child" Service bodies, so we need to produce a flat array of IDs.
- if (isset($in_sb_id) && $in_sb_id) {
- global $bmlt_array_gather;
-
- $bmlt_array_gather = array();
-
- /************************************************//**
- * This little internal function will simply fill *
- * the $bmlt_array_gather array with a linear set of *
- * Service body IDs that can be used for a quick *
- * comparison, later on. It is a callback function. *
- ****************************************************/
- function bmlt_at_at(
- $in_value,
- $in_key
- ) {
- global $bmlt_array_gather;
-
- if ($in_value instanceof c_comdef_service_body) {
- array_push($bmlt_array_gather, $in_value->GetID());
- }
- }
- $tmp = c_comdef_server::GetServer()->GetNestedServiceBodyArray($in_sb_id);
- array_walk_recursive($tmp, 'bmlt_at_at');
-
- if (is_array($bmlt_array_gather) && count($bmlt_array_gather)) {
- $in_sb_id = $bmlt_array_gather;
- } else {
- $in_sb_id = array ( $in_sb_id );
- }
- }
-
- foreach ($obj_array as $change) {
- $change_type = $change->GetChangeType();
- $date_int = intval($change->GetChangeDate());
- $change_id = intval($change->GetID());
- $date_string = date($change_date_format, $date_int);
- $json_data = '';
-
- if ($change instanceof c_comdef_change) {
- $b_obj = $change->GetBeforeObject();
- $a_obj = $change->GetAfterObject();
- $meeting_id = intval($change->GetBeforeObjectID());
- $sb_a = intval(($a_obj instanceof c_comdef_meeting) ? $a_obj->GetServiceBodyID() : 0);
- $sb_b = intval(($b_obj instanceof c_comdef_meeting) ? $b_obj->GetServiceBodyID() : 0);
- $sb_c = intval($change->GetServiceBodyID());
-
- if (!$meeting_id) {
- $meeting_id = intval($change->GetAfterObjectID());
- }
-
- if ((intval($in_meeting_id) && intval($in_meeting_id) == intval($meeting_id)) || !intval($in_meeting_id)) {
- $meeting_name = '';
- $user_name = '';
-
- if (!is_array($in_sb_id) || !count($in_sb_id) || in_array($sb_a, $in_sb_id) || in_array($sb_b, $in_sb_id) || in_array($sb_c, $in_sb_id)) {
- $sb_id = (intval($sb_c) ? $sb_c : (intval($sb_b) ? $sb_b : $sb_a));
- $meeting = (null != $b_obj) ? $b_obj : $a_obj;
-
- // Using str_replace, because preg_replace is pretty expensive. However, I don't think this buys us much.
- if ($b_obj instanceof c_comdef_meeting) {
- $meeting_name = str_replace('"', "'", str_replace("\n", " ", str_replace("\r", " ", $b_obj->GetMeetingDataValue('meeting_name'))));
- } elseif ($a_obj instanceof c_comdef_meeting) {
- $meeting_name = str_replace('"', "'", str_replace("\n", " ", str_replace("\r", " ", $a_obj->GetMeetingDataValue('meeting_name'))));
- }
-
- $user_id = intval($change->GetUserID());
-
- $user = c_comdef_server::GetUserByIDObj($user_id);
-
- if ($user instanceof c_comdef_user) {
- $user_name = htmlspecialchars($user->GetLocalName());
- }
-
- $sb = c_comdef_server::GetServiceBodyByIDObj($sb_id);
-
- if ($sb instanceof c_comdef_service_body) {
- $sb_name = htmlspecialchars($sb->GetLocalName());
- }
-
- $meeting_exists = 0;
-
- if (c_comdef_server::GetOneMeeting($meeting_id, true)) {
- $meeting_exists = 1;
- }
-
- $details = '';
- $desc = $change->DetailedChangeDescription();
-
- if ($desc && isset($desc['details']) && is_array($desc['details'])) {
- // We need to prevent double-quotes, as they are the string delimiters, so we replace them with single-quotes.
- $details = str_replace('"', "'", str_replace("\n", " ", str_replace("\r", " ", implode(" ", $desc['details']))));
- }
-
- $change_line = array();
-
- if ($date_int) {
- $change_line['date_int'] = $date_int;
- } else {
- $change_line['date_int'] = 0;
- }
-
- if ($date_string) {
- $change_line['date_string'] = $date_string;
- } else {
- $change_line['date_string'] = '';
- }
-
- if ($change_type) {
- $change_line['change_type'] = $change_type;
- } else {
- $change_line['change_type'] = '';
- }
-
- if ($change_id) {
- $change_line['change_id'] = $change_id;
- } else {
- $change_line['change_id'] = 0;
- }
-
- if ($meeting_id) {
- $change_line['meeting_id'] = $meeting_id;
- } else {
- $change_line['meeting_id'] = 0;
- }
-
- if ($meeting_name) {
- $change_line['meeting_name'] = $meeting_name;
- } else {
- $change_line['meeting_name'] = '';
- }
-
- if ($user_id) {
- $change_line['user_id'] = $user_id;
- } else {
- $change_line['user_id'] = 0;
- }
-
- if ($user_name) {
- $change_line['user_name'] = $user_name;
- } else {
- $change_line['user_name'] = '';
- }
-
- if ($sb_id) {
- $change_line['service_body_id'] = $sb_id;
- } else {
- $change_line['service_body_id'] = '';
- }
-
- if ($sb_name) {
- $change_line['service_body_name'] = $sb_name;
- } else {
- $change_line['service_body_name'] = '';
- }
-
- $change_line['meeting_exists'] = $meeting_exists;
-
- if ($details) {
- $change_line['details'] = $details;
- } else {
- $change_line['details'] = '';
- }
-
- $json_data = MakeJSONDataObject($b_obj, 'before');
-
- if (($json_data != '') && ($a_obj instanceof c_comdef_meeting)) {
- $json_data .= ',';
- }
-
- $json_data .= MakeJSONDataObject($a_obj, 'after');
-
- $change_line['json_data'] = '{'.str_replace('"', '"', $json_data).'}';
-
- $ret .= '"'.implode('","', $change_line)."\"\n";
- }
- }
- }
- }
- }
- }
- } catch (Exception $e) {
- }
-
- return $ret;
-}
-
-/*******************************************************************/
-/**
- \brief Converts a given c_comdef_meeting object to a JSON object string.
-
- \returns A string, containing the JSON Data. It is blank if no JSON Data.
-*/
-function MakeJSONDataObject(
- $in_meeting_object, ///< The c_comdef_meeting object to be converted.
- $in_object_name ///< A name for the returned object.
-) {
- $json_data = '';
-
- if ($in_meeting_object instanceof c_comdef_meeting) {
- $keys = $in_meeting_object->GetMeetingDataKeys();
-
- foreach ($keys as $key) {
- if ($key) {
- $value = $in_meeting_object->GetMeetingDataValue($key);
-
- if ($value) {
- if ($key == 'formats') {
- $val_temp = array();
- $values = $value;
-
- foreach ($values as $format) {
- if ($format instanceof c_comdef_format) {
- $val_temp[] = $format->GetKey();
- }
- }
-
- $value = $val_temp;
- }
-
- if (is_array($value)) {
- if (count($value)) {
- for ($c = 0; $c < count($value); $c++) {
- $val = json_encode(trim($value[$c], '"'));
- $val = str_replace('"', '"', $val);
- $val = str_replace('&', '&', $val);
- $val = trim(preg_replace("|\s+|", ' ', $val), '"');
- $value[$c] = trim($val, "\\");
- }
-
- if ($json_data) {
- $json_data .= ',';
- }
-
- $json_data .= '"'.$key.'":'.'["'.implode('","', $value).'"]';
- }
- } else {
- $value = trim($value, "\\");
- $value = preg_replace("|^\"\"|", "\""", $value);
- $value = trim(json_encode($value), '"');
- $value = str_replace('"', '"', $value);
- $value = str_replace('&', '&', $value);
- $value = trim(preg_replace("|\s+|", ' ', $value), '\\');
- $value = trim($value, '"');
- if ($json_data) {
- $json_data .= ',';
- }
- $json_data .= '"'.$key.'":"'.$value.'"';
- }
- }
- }
- }
-
- if ($json_data && $in_object_name) {
- $json_data = '"'.$in_object_name.'":{'.$json_data.'}';
- }
- }
-
- return $json_data;
-}
-
-/*******************************************************************/
-/**
- \brief Handles no command supplied (error)
-
- \returns English error string (not XML).
-*/
-function HandleDefault(
- $in_http_vars ///< The HTTP GET and POST parameters.
-) {
- return "You must supply one of the following: 'switcher=GetSearchResults', 'switcher=GetFormats', 'switcher=GetChanges', 'switcher=GetNAWSDump', 'switcher=GetFieldKeys', 'switcher=GetFieldValues' or 'switcher=GetServiceBodies'.";
-}
-
-/*******************************************************************/
-/**
- \brief Handles no server available (error).
-
- \returns null;
-*/
-function HandleNoServer()
-{
- return null;
-}
-
-/*******************************************************************/
-/**
- \brief Translates CSV to JSON.
-
- \returns a JSON string, with all the data in the CSV.
-*/
-function TranslateToJSON(
- $in_csv_data ///< An array of CSV data, with the first element being the field names.
-) {
- $temp_keyed_array = array();
- $in_csv_data = explode("\n", $in_csv_data);
- $keys = array_shift($in_csv_data);
- $keys = explode("\",\"", trim($keys, '"'));
-
- foreach ($in_csv_data as $row) {
- if ($row) {
- $line = null;
- $index = 0;
- $row = explode('","', trim($row, '",'));
- foreach ($row as $column) {
- if (isset($column)) {
- $key = $keys[$index++];
- $value = str_replace("\t", ',', trim($column));
-
- if ($key == "json_data") {
- $value = trim($value, '"');
- $value = str_replace('"', '"', $value);
- }
-
- $line[$key] = $value;
- }
- }
- array_push($temp_keyed_array, $line);
- }
- }
-
- $out_json_data = str_replace('\\\\"', '"', array2json($temp_keyed_array)); // HACK ALERT: TranslateToJSON does whacky things with my escaped quotes, so I undo that here.
-
- return $out_json_data;
-}
-
-/*******************************************************************/
-/**
- \brief Translates CSV to XML.
-
- \returns an XML string, with all the data in the CSV.
-*/
-function TranslateToXML(
- $in_csv_data ///< An array of CSV data, with the first element being the field names.
-) {
- $temp_keyed_array = array();
- $in_csv_data = explode("\n", $in_csv_data);
- $keys = array_shift($in_csv_data);
- $keys = rtrim(ltrim($keys, '"'), '",');
- $keys = preg_split('/","/', $keys);
-
- foreach ($in_csv_data as $row) {
- if ($row) {
- $line = null;
- $index = 0;
- $row_t = rtrim(ltrim($row, '"'), '",');
- $row_t = preg_split('/","/', $row_t);
- foreach ($row_t as $column) {
- if (isset($column)) {
- $line[$keys[$index++]] = trim($column);
- }
- }
- array_push($temp_keyed_array, $line);
- }
- }
-
- $out_xml_data = array2xml($temp_keyed_array, 'not_used', false);
- // HACK ALERT: Undoing the poopiness done by TranslateToXML.
- $out_xml_data = str_replace("&aamp;quot;", """, $out_xml_data);
- $out_xml_data = str_replace(""", """, $out_xml_data);
- $out_xml_data = str_replace("\\"", """, $out_xml_data);
- $out_xml_data = str_replace("&ququot;", """, $out_xml_data);
-
- return $out_xml_data;
-}
diff --git a/src/legacy/client_interface/csv/index.php b/src/legacy/client_interface/csv/index.php
deleted file mode 100755
index c4ba991e4..000000000
--- a/src/legacy/client_interface/csv/index.php
+++ /dev/null
@@ -1,60 +0,0 @@
-/client_interface/csv/
- with the same parameters that you would send to an advanced search. The results
- will be returned as a CSV file.
-
- This file can be called from other servers.
-
- This file is part of the Basic Meeting List Toolbox (BMLT).
-
- Find out more at: https://bmlt.app
-
- BMLT is free software: you can redistribute it and/or modify
- it under the terms of the MIT License.
-
- BMLT is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- MIT License for more details.
-
- You should have received a copy of the MIT License along with this code.
- If not, see .
-*/
-
-defined('BMLT_EXEC') or define('BMLT_EXEC', true); // This is a security verifier. Keeps files from being executed outside of the context
-require_once(dirname(__FILE__).'/csv.php');
-try {
- $server = c_comdef_server::MakeServer();
- $ret = null;
-
- if ($server instanceof c_comdef_server) {
-// if ( !isset ( $_GET['dump_ind_formats'] ) )
-// {
-// $_GET['dump_ind_formats'] = true;
-// }
-
- $ret = parse_redirect($server);
- if (isset($_GET['compress_output']) || isset($_POST['compress_output'])) {
- if (zlib_get_coding_type() === false) {
- ob_start("ob_gzhandler");
- } else {
- header('Content-Type:text/csv; charset=UTF-8');
- ob_start();
- }
- } else {
- header('Content-Type:text/csv; charset=UTF-8');
- ob_start();
- }
- echo $ret;
- ob_end_flush();
- } else {
- echo HandleNoServer();
- }
-} catch (Exception $e) {
- echo HandleNoServer();
-}
diff --git a/src/legacy/client_interface/csv/search_results_csv.php b/src/legacy/client_interface/csv/search_results_csv.php
deleted file mode 100755
index 921932934..000000000
--- a/src/legacy/client_interface/csv/search_results_csv.php
+++ /dev/null
@@ -1,1360 +0,0 @@
-.
-*/
-
-defined('BMLT_EXEC') or die('Cannot Execute Directly'); // Makes sure that this file is in the correct context.
-
-require_once(dirname(__FILE__).'/common_search.inc.php');
-require(dirname(__FILE__).'/../../server/config/get-config.php'); // Just to make sure we have an early copy.
-
-global $g_format_dictionary; ///< This is a dictionary used to translate formats to NAWS format. It uses the format shared IDs in the server's language.
-
-bmlt_populate_format_dictionary();
-
-/// If you wish to override this, simply set this up in your /get-config.php file. That will supersede this.
-/// Actually... this block of code never, ever gets hit because the above call to bmlt_populate_format_dictionary
-/// will always set $g_format_dictionary. We should... probably remove it?
-if (!isset($g_format_dictionary) || !is_array($g_format_dictionary) || !count($g_format_dictionary)) {
- /// This is the default set.
- /// The right side is the BMLT side, and the left side is the NAWS code. The left side should not be changed.
- $g_format_dictionary = array (
- 'CPT' => null,
- 'MED' => null,
- 'QA' => null,
- 'RA' => null,
- 'BEG' => array(1),
- 'BT' => array(3),
- 'OPEN' => array(4),
- 'CAN' => array(6),
- 'CH' => array(5),
- 'CW' => array(7),
- 'DISC' => array(8),
- 'GL' => array(10),
- 'GP' => array(52),
- 'IP' => array(12),
- 'IW' => array(13),
- 'JFT' => array(14),
- 'LIT' => array(36),
- 'M' => array(15),
- 'CLOSED' => array(17),
- 'NC' => array(16),
- 'NS' => array(37),
- 'SMOK' => array(25),
- 'SPK' => array(22),
- 'STEP' => array(27),
- 'SWG' => array(23),
- 'TOP' => array(29),
- 'TRAD' => array(30),
- 'VAR' => array(19),
- 'W' => array(32),
- 'WCHR' => array(33),
- 'Y' => array(34)
- );
-}
-
-/*******************************************************************/
-/** \brief This reads in the server format codes, and populates the
- format dictionary with the NAWS IDs.
-*/
-function bmlt_populate_format_dictionary()
-{
- global $g_format_dictionary; ///< This is a dictionary used to translate formats to NAWS format. It uses the format shared IDs in the server's language.
-
- // first accumulate a local array of formats in $dict
- $dict = [];
- $server = c_comdef_server::MakeServer();
- $localized_strings = c_comdef_server::GetLocalStrings();
- $formats_array = c_comdef_server::GetServer()->GetFormatsObj()->GetFormatsArray();
-
- foreach ($formats_array['en'] as $format) {
- if ($format instanceof c_comdef_format) {
- $world_id = $format->GetWorldID();
- $shared_id = $format->GetSharedID();
- if ($world_id && $shared_id) {
- if (array_key_exists($world_id, $dict)) {
- array_push($dict[$world_id], $shared_id);
- } else {
- $dict[$world_id] = array( $shared_id );
- }
- }
- }
- }
- // add all the formats in $dict to $g_format_dictionary, putting the preferred formats first (in the same
- // order as in naws_export_formats_at_front)
- $g_format_dictionary = [];
- $local_strings = c_comdef_server::GetLocalStrings();
- $preferred = $local_strings['naws_export_formats_at_front'];
- foreach ($preferred as $id) {
- if (array_key_exists($id, $dict)) {
- $g_format_dictionary[$id] = $dict[$id];
- }
- }
- foreach ($dict as $id => $val) {
- if (!in_array($id, $preferred)) {
- $g_format_dictionary[$id] = $dict[$id];
- }
- }
-}
-
-/*******************************************************************/
-/** \brief This function does a search, then builds a CSV result,
- with each row being a meeting. The first row is a row of keys.
-
- \returns a string, containing CSV data, with the first row a key header.
-*/
-function DisplaySearchResultsCSV(
- $in_http_vars,
- // The various HTTP GET and POST parameters.
- // If this is defined and set to 'yes', then that means the client supports AJAX.
- // - 'supports_ajax'
- // We serve non-JavaScript content to clients that don't support AJAX, even if they support JavaScript.
- //
- // The values that are important to the list paging are:
- // - 'page_num'
- // This is a positive integer, specifying which page of results to display.
- //
- // - 'page_size'
- // This is the number of meetings to list on one "page" of results.
- // The search results are paged, so that a large search is broken
- // into multiple pages of page_display_size results.
- //
- // - 'sort_key'
- // This is the key to use for sorting. There are three possible values:
- // - 'town'
- // This is sorted by town, borough and neighborhood first, weekday and time second.
- // - 'weekday'
- // This is sorted by weekday first, town, borough and neighborhood second, then time
- // - 'time'
- // This is sorted by weekday first, time, second, then town, borough and neighborhood.
- //
- // - 'sort_dir'
- // This is the direction of the sort. It can be one of the following:
- // - 'asc'
- // Ascending, from least to greatest.
- // - 'desc'
- // Descending, from greatest to least.
- //
- // These are used to specify a search:
- //
- // - 'services'
- // This is an array of positive integers.
- // This is interpreted as an array of integers. Each integer represents the ID of a Service Body.
- // A positive integer means that the search will look specifically for meetings that contain that
- // Service Body ID.
- // If the integer is negative (preceded by a minus sign -), then the criteria will be to look
- // for meetings that don't contain that ID.
- // If no 'services' values are given, then the search will not use the Service Body field as a
- // search criteria.
- //
- // - 'venue_types'
- // This is an array of integers.
- // This is interpreted as an array of integers. Each integer represents a Venue Type.
- // A positive integer means that the search will look specifically for meetings that have that Venue Type.
- // If the integer is negative (preceded by a minus sign -), then the criteria will be to look
- // for meetings that don't have that Venue Type.
- // If no 'venue_type' values are given, then the search will not use the Venue Type field as a
- // search criteria.
- //
- // - 'weekdays'
- // This is an array of positive integers ( 1-7).
- // This is interpreted as an array of integers. Each integer represents a weekday (1 -> Sunday, 7 -> Saturday).
- // A positive integer means that the search will look specifically for meetings that occur on that weekday.
- // If the integer is negative (preceded by a minus sign -), then the criteria will be to look
- // for meetings that don't occur on that weekday.
- // If no 'weekdays' values are given, then the search will not use the weekday field as a
- // search criteria.
- //
- // - 'formats'
- // This is an array of positive integers.
- // This is interpreted as an array of integers. Each integer represents a format shared ID.
- // A format ID means that the search will look specifically for meetings that have that format.
- // If the format is negative (preceded by a minus sign -), then the criteria will be to look
- // for meetings that don't have that format.
- // If no 'formats' values are given, then the search will not use the formats field as a
- // search criteria.
- //
- // - 'langs'
- // This is an array of 2-character strings.
- // This is interpreted as an array of strings. Each string represents a language code, and is a 2-character string.
- // A language string means that the search will look specifically for meetings that are in that language.
- // If the language is preceded by a minus sign -, then the criteria will be to look
- // for meetings that are not in that language.
- // If no 'langs' values are given, then the search will not use the lang_enum field as a
- // search criteria.
- //
- // - 'bmlt_search_type'
- // This is set to 'advanced' if the search is an advanced one (we need to take more criteria into consideration).
- //
- // - 'advanced_formats'
- // This is the formats array, but is only counted if the bmlt_search_type is set to 'advanced'.
- //
- // - 'advanced_service_bodies'
- // This is the same, but for Service Bodies.
- //
- // - 'advanced_weekdays'
- // ...and weekdays.
- //
- // - 'advanced_radius'
- // ...and radius (in degrees)
- //
- // - advanced_mapmode
- // If this is true (1), then the Advanced form is using its map.
- //
- // The following values specify a start time "window." The meeting must start on, or after StartsAfterH/M, and
- // can start no later than StartsBeforeH/M
- //
- // - 'StartsAfterH'
- // A positive integer between 0 and 23. The hour of the minimal start time for meetings, in military time.
- // - 'StartsAfterM'
- // A positive integer between 0 and 59. The minute of the minimal start time for meetings, in military time.
- // - 'StartsBeforeH'
- // A positive integer between 0 and 23. The hour of the maximal start time for meetings, in military time.
- // - 'StartsBeforeM'
- // A positive integer between 0 and 59. The minute of the maximal start time for meetings, in military time.
- //
- // The following values specify a time duration "window." The meeting can last no longer than MaxDurationH/M,
- // and no less than MinDurationH/M.
- //
- // - 'MinDurationH'
- // A positive integer. This is the number of hours in the minimal duration.
- // - 'MinDurationM'
- // A positive integer. This is the number of minutes in the minimal duration.
- // - 'MaxDurationH'
- // A positive integer. This is the number of hours in the maximal duration.
- // - 'MaxDurationM'
- // A positive integer. This is the number of minutes in the maximal duration.
- //
- // This is how meetings are located. We don't use address lookups. Instead, we geolocate the meetings via the
- // longitude and latitude fields in each record. If you don't specify a geolocation, then the entire database
- // is searched. If you do specify one, then only the portion within the radius is searched.
- //
- // - 'geo_width'
- // A floating point number. This is the radius (not diameter) of the search, in MILES (not Kilometers).
- // If this is negative, then it should be an integer, and that indicates an auto-radius is requested to
- // find the number of meetings in the integer.
- //
- // - 'geo_width_km'
- // A floating point number. This is the radius (not diameter) of the search, in KILOMETERS (not Miles).
- // If this is negative, then it should be an integer, and that indicates an auto-radius is requested to
- // find the number of meetings in the integer.
- //
- // - 'long_val'
- // If one of the three radius specifiers is zero or undefined, this is ignored.
- // This is a floating point number that specifies the longitude, in degrees, of the center of the search radius.
- //
- // - 'lat_val'
- // If one of the three radius specifiers is zero or undefined, this is ignored.
- // This is a floating point number that specifies the latitude, in degrees, of the center of the search radius.
- //
- // - 'SearchString'
- // A string. If this is specified, then all the string fields of the meetings specified by the above criteria
- // will be searched for the string. By default, if the language supports metaphone (sound like search), then
- // that is used.
- //
- // - 'StringSearchIsAnAddress'
- // A boolean. Nonzero means that the given string should not be checked against any of the fields in the meeting
- // data. Instead, it is to be considered a submission to the Google Maps geocode, and will be used to determine
- // a cernter point in a local search.
- //
- // - 'SearchStringAll'
- // If nonzero, then all of the words in the search string will have to be matched for a meetings to qualify.
- //
- // - 'SearchStringExact'
- // If nonzero, metaphone will not be used, and the spelling must be exact.
- //
- // - 'meeting_ids'
- // An array of positive integers. Each integer is an ID of an individual meeting. If this is set, all other
- // search criteria are ignored.
- //
- // - 'sort_keys'
- // This is a comma-separated list of sort keys. The leftmost one will be the top priority, and the rightmost the lowest.
- // The sort depth will be the number of keys.
- // The direction will be assumed 'asc', unless 'desc' is one of the keys (it can be anywhere in the list).
- //
- // - 'simple_other_fields'
- // Set this to '1' in order to prevent the server from separating values with the prompt separator.
- &$return_array = null, ///< If this is supplied, then the result will be saved in this as an array. It must be an empty array, supplied by reference.
- &$return_geocode = null,
- // If this is supplied, the response will be an associative array, with the search center and radius.
- // It will return:
- // - 'radius' The radius of the search, in Km
- // - 'longitude' The longitude of the search center
- // - 'latitude' Th latitude of the search center
- &$return_results = null, ///< If supplied, should point to an array that will be filled with the actual meeting objects that comprise the result.
- $in_supress_hidden_concat = false, ///< If true, then hidden fields will not have their prompts encoded
- $in_editor_only = false ///< If true, then only meetings for which the current logged-in user can edit/observe are returned.
-) {
- $ret = null;
- require_once(dirname(__FILE__).'/c_comdef_meeting_search_manager.class.php');
-
- $search_manager = new c_comdef_meeting_search_manager;
-
- if ($search_manager instanceof c_comdef_meeting_search_manager) {
- $localized_strings = c_comdef_server::GetLocalStrings();
-
- $lang_enum = c_comdef_server::GetServer()->GetLocalLang();
-
- // This can be changed in the auto config.
- include(dirname(__FILE__).'/../../server/config/get-config.php');
-
- if (isset($in_http_vars['lang_enum']) && $in_http_vars['lang_enum']) {
- $lang_enum = $in_http_vars['lang_enum'];
- }
-
- if (!isset($in_http_vars['results_per_page'])) {
- $in_http_vars['results_per_page'] = 0;
- }
-
- if (isset($default_sort_key) && !isset($in_http_vars['sort_key']) && !isset($in_http_vars['sort_keys'])) {
- $in_http_vars['sort_key'] = $default_sort_key;
- }
-
- if ((!isset($in_http_vars['sort_dir']) || ( ($in_http_vars['sort_dir'] != 'desc') && ($in_http_vars['sort_dir'] != 'asc') ) ) && !isset($in_http_vars['sort_keys'])) {
- $in_http_vars['sort_dir'] = 'asc';
- }
-
- SetUpSearch($search_manager, $in_http_vars);
-
- if (isset($in_http_vars['page_size'])) {
- $search_manager->SetResultsPerPage($in_http_vars['page_size']);
- }
-
- if (isset($in_http_vars['sort_dir'])) {
- $sort_dir_desc = ($in_http_vars['sort_dir'] == "desc") ? true : false;
-
- if (isset($localized_strings['default_sorts']) && isset($in_http_vars['sort_key']) && isset($sort_dir_desc) && !isset($in_http_vars['sort_keys'])) {
- $search_manager->SetSort($localized_strings['default_sorts'][$in_http_vars['sort_key']], $sort_dir_desc, 0);
- }
- }
-
- $search_manager->DoSearch();
-
- $long = null;
- $lat = null;
-
- if (isset($in_http_vars['long_val'])) {
- $long = $in_http_vars['long_val'];
- }
-
- if (isset($in_http_vars['lat_val'])) {
- $lat = $in_http_vars['lat_val'];
- }
-
- if (isset($in_http_vars['geo_width'])) {
- $my_radius = $in_http_vars['geo_width'];
- } elseif (isset($in_http_vars['geo_width_km'])) {
- $my_radius = $in_http_vars['geo_width_km'];
- }
-
- if (isset($my_radius) && ($my_radius < 0)) {
- $my_radius = $search_manager->GetRadius($localized_strings['dist_units'] == 'mi');
- }
-
- if (isset($return_geocode)) {
- $return_geocode = nil;
-
- if ($search_manager->GetRadius(false)) {
- $return_geocode['radius'] = $search_manager->GetRadius(false);
- $return_geocode['longitude'] = $search_manager->GetLongitude();
- $return_geocode['latitude'] = $search_manager->GetLatitude();
- }
- }
-
- $num_pages = $search_manager->GetNumberOfPages();
- $num_results = $search_manager->GetNumberOfResults();
-
- $page_no = 1;
-
- if (isset($in_http_vars['page_num']) && (0 < intval($in_http_vars['page_num']))) {
- $page_no = intval($in_http_vars['page_num']);
- }
-
- if (1 > intval($page_no)) {
- $page_no = 1;
- }
-
- if ($page_no > $num_pages) {
- $page_no = $num_pages;
- }
-
- $page_data = $search_manager->GetPageOfResults($page_no);
-
- if ($page_data instanceof c_comdef_meeting_search_manager) {
- $keys = c_comdef_meeting::GetAllMeetingKeys();
- // This is a required one for data export.
- if (!in_array('meeting_name', $keys)) {
- $keys[] = 'meeting_name';
- }
-
- $keys[] = 'root_server_uri';
- $keys[] = 'format_shared_id_list';
-
- $ret = '"'.join('","', $keys).'"';
-
- $formats = c_comdef_server::GetServer()->GetFormatsObj();
- $formats_keys = array();
- $formats_keys_header = array();
-
- $ret .= "\n";
-
- $in_ar = $page_data->GetSearchResultsAsArray();
-
- if (isset($return_results) && is_array($return_results)) {
- $return_results = $in_ar;
- }
-
- foreach ($in_ar as &$mtg_obj) {
- $line = array();
- $formats_ar = $formats_keys;
-
- if ($mtg_obj instanceof c_comdef_meeting) {
- if (!$in_editor_only || $mtg_obj->UserCanObserve()) {
- $format_shared_id_list = array();
- $first = true;
- foreach ($keys as $key) {
- if (trim($key)) {
- $val = $mtg_obj->GetMeetingDataValue($key);
-
- if (($key == 'meeting_name') && !$val) { // No meeting name results in a generic "NA Meeting" as the name.
- $val = $localized_strings['comdef_server_admin_strings']['Value_Prompts']['generic'];
- }
-
- if ($key == 'lang_enum' && isset($in_http_vars['lang_enum']) && $in_http_vars['lang_enum']) {
- // Override the native lang_enum for the meeting with the requested language if present in http_vars
- // (Does this ever matter??)
- $val = $in_http_vars['lang_enum'];
- }
-
- if (isset($val)) {
- if (($key == 'formats')) {
- if (is_array($val) && count($val)) {
- $v_ar = array();
- foreach ($val as $format) {
- if ($format instanceof c_comdef_format) {
- // $format will be one of the meeting's formats in the native server language. If it's already
- // in the correct language, just add its key to $v_ar and its id to $format_shared_id_list.
- // Otherwise see if there is a version of the format in the other language (stored in $lang_enum). If there is,
- // push the key for the format in the other language onto $v_ar instead. Note that the key might be different
- // in different languages. If there isn't a version of the format in the other language, just skip it.
- $id = $format->GetSharedID();
- if ($format->GetLocalLang() == $lang_enum) {
- array_push($v_ar, $format->GetKey());
- array_push($format_shared_id_list, $id);
- } else {
- $fs = $formats->GetFormatsBySharedIDCode($id);
- if (array_key_exists($lang_enum, $fs)) {
- $localized_format = $fs[$lang_enum];
- array_push($v_ar, $localized_format->GetKey());
- array_push($format_shared_id_list, $id);
- }
- }
- }
- }
- $val = join(',', $v_ar);
- $val = preg_replace('|"|', '\\"', preg_replace('|[\r\n\t]+|', ' ', $val));
- } elseif (is_string($val)) {
- $val = preg_replace('|"|', '\\"', preg_replace('|[\r\n\t]+|', ' ', $val));
- }
- }
-
- if (($key == 'formats') && $val) {
- $f_list = explode(',', $val);
-
- if (is_array($f_list) && count($f_list)) {
- foreach ($f_list as $format) {
- $formats_ar[$format] = 1;
- }
- }
- }
-
- if ($val) {
- if ($mtg_obj->IsItemHidden($key)) {
- if ($mtg_obj->UserCanObserve()) {
- if (!$in_supress_hidden_concat && !isset($in_http_vars['simple_other_fields'])) {
- $val = preg_replace('|.*?\#\@\-\@\#|', '', $mtg_obj->GetMeetingDataValue($key)); // Strip out any old accidentally introduced separators.
- $val = 'observer_only#@-@#'.$mtg_obj->GetMeetingDataPrompt($key).'#@-@#'.$val;
- }
- } else {
- $val = '';
- }
- } else {
- switch ($key) {
- // We don't do anything for the standard fields.
- case 'distance_in_miles':
- case 'distance_in_km':
- case 'id_bigint':
- case 'worldid_mixed':
- case 'shared_group_id_bigint':
- case 'service_body_bigint':
- case 'weekday_tinyint':
- case 'venue_type':
- case 'start_time':
- case 'duration_time':
- case 'time_zone':
- case 'formats':
- case 'lang_enum':
- case 'longitude':
- case 'latitude':
- case 'published':
- case 'email_contact':
- case 'meeting_name':
- case 'location_text':
- case 'location_info':
- case 'location_street':
- case 'location_city_subsection':
- case 'location_neighborhood':
- case 'location_municipality':
- case 'location_sub_province':
- case 'location_province':
- case 'location_postal_code_1':
- case 'location_nation':
- case 'comments':
- case 'virtual_meeting_link':
- case 'virtual_meeting_additional_info':
- case 'phone_meeting_number':
- break;
-
- // The rest get the prompt/value treatment, unless otherwise requested.
- default:
- if ($val && !isset($in_http_vars['simple_other_fields'])) {
- $val = preg_replace('|.*?\#\@\-\@\#|', '', $val); // Strip out any old accidentally introduced separators.
- $val = $mtg_obj->GetMeetingDataPrompt($key).'#@-@#'.$val;
- }
- break;
- }
- }
- }
- } else {
- $val = '';
- }
-
- $val = trim(preg_replace("|[\n\r]+|", "; ", $val));
-
- $line[$key] = $val;
- }
- }
-
- if (!isset($line['duration_time']) || !$line['duration_time'] || ($line['duration_time'] == '00:00:00')) {
- $line['duration_time'] = $localized_strings['default_duration_time'];
- }
-
- if (isset($format_shared_id_list) && is_array($format_shared_id_list) && count($format_shared_id_list)) {
- sort($format_shared_id_list);
- $line['format_shared_id_list'] = implode(',', $format_shared_id_list);
- }
-
- $line['root_server_uri'] = dirname(dirname(GetURLToMainServerDirectory(true)));
-
- if (is_array($line) && count($line)) {
- if (is_array($return_array)) {
- array_push($return_array, $line);
- }
-
- $ret .= '"'.join('","', $line).'"';
-
- $ret .= "\n";
- }
- }
- }
- }
- }
- }
-
- return $ret;
-}
-
-/********************************************************************/
-/* NAWS LIST GENERATION */
-/* The following functions are used to generate a CSV file that is */
-/* in a format suitable for NA World Services (NAWS). Because they */
-/* often change their format, it needs to be extremely flexible. */
-/* The heart is a "translator dictionary," that matches fields in a */
-/* standard meeting object to the fields expected by NAWS. If the */
-/* content of a dictionary entry is a function, then a translation */
-/* is done by calling a function. Otherwise, if the content is a */
-/* field name, the contents of that field are simply transferred */
-/* without interpretation. */
-/********************************************************************/
-
-/*******************************************************************/
-/**
- \brief Returns the CSV file in NAWS format
-
- \returns A string, consisting of a CSV file, in the format required by NAWS.
-*/
-function ReturnNAWSFormatCSV(
- $in_http_vars, ///< The HTTP GET and POST parameters.
- &$server ///< A reference to an instance of c_comdef_server
-) {
- // This is a dictionary that is used to translate the meeting data from the BMLT format to the NAWS format.
- $transfer_dictionary = array( 'Committee' => 'BMLT_FuncNAWSReturnMeetingNAWSID',
- 'CommitteeName' => 'meeting_name',
- 'AddDate' => null,
- 'AreaRegion' => 'BMLT_FuncNAWSReturnMeetingServiceBodyNAWSID',
- 'ParentName' => 'BMLT_FuncNAWSReturnMeetingServiceBodyName',
- 'ComemID' => null,
- 'ContactID' => null,
- 'ContactName' => null,
- 'CompanyName' => null,
- 'ContactAddrID' => null,
- 'ContactAddress1' => null,
- 'ContactAddress2' => null,
- 'ContactCity' => null,
- 'ContactState' => null,
- 'ContactZip' => null,
- 'ContactCountry' => null,
- 'ContactPhone' => null,
- 'MeetingID' => null,
- 'Room' => 'BMLT_FuncNAWSReturnNonNawsFormats',
- 'Closed' => 'BMLT_FuncNAWSReturnOpenOrClosed',
- 'WheelChr' => 'BMLT_FuncNAWSReturnWheelchair',
- 'Day' => 'BMLT_FuncNAWSReturnWeekday',
- 'Time' => 'BMLT_FuncNAWSReturnTime',
- 'Language1' => 'BMLT_FuncNAWSReturnLanguage1',
- 'Language2' => null,
- 'Language3' => null,
- 'LocationId' => null,
- 'Place' => 'location_text',
- 'Address' => 'location_street',
- 'City' => 'BMLT_FuncNAWSReturnMeetingTown',
- 'LocBorough' => 'location_neighborhood',
- 'State' => 'location_province',
- 'Zip' => 'location_postal_code_1',
- 'Country' => 'location_nation',
- 'Directions' => 'BMLT_FuncNAWSReturnDirections',
- 'Institutional' => 'BMLT_FuncNAWSReturnInst',
- 'Format1' => 'BMLT_FuncNAWSReturnFormat1',
- 'Format2' => 'BMLT_FuncNAWSReturnFormat2',
- 'Format3' => 'BMLT_FuncNAWSReturnFormat3',
- 'Format4' => 'BMLT_FuncNAWSReturnFormat4',
- 'Format5' => 'BMLT_FuncNAWSReturnFormat5',
- 'Delete' => null,
- 'LastChanged' => 'BMLT_FuncNAWSReturnLastMeetingChangeTime',
- 'Longitude' => 'longitude',
- 'Latitude' => 'latitude',
- 'ContactGP' => null,
- 'PhoneMeetingNumber' => 'phone_meeting_number',
- 'VirtualMeetingLink' => 'virtual_meeting_link',
- 'VirtualMeetingInfo' => 'virtual_meeting_additional_info',
- 'TimeZone' => 'time_zone',
- 'bmlt_id' => 'id_bigint',
- 'unpublished' => 'BMLT_FuncNAWSReturnPublishedStatus'
- );
-
- $ret = null;
-
- if (!( isset($in_http_vars['geo_width']) && $in_http_vars['geo_width'] ) && isset($in_http_vars['bmlt_search_type']) && ($in_http_vars['bmlt_search_type'] == 'advanced') && isset($in_http_vars['advanced_radius']) && isset($in_http_vars['advanced_mapmode']) && $in_http_vars['advanced_mapmode'] && ( floatval($in_http_vars['advanced_radius'] != 0.0) ) && isset($in_http_vars['lat_val']) && isset($in_http_vars['long_val']) && ( (floatval($in_http_vars['lat_val']) != 0.0) || (floatval($in_http_vars['long_val']) != 0.0) )) {
- $in_http_vars['geo_width'] = $in_http_vars['advanced_radius'];
- } elseif (!( isset($in_http_vars['geo_width']) && $in_http_vars['geo_width'] ) && isset($in_http_vars['bmlt_search_type']) && ($in_http_vars['bmlt_search_type'] == 'advanced')) {
- $in_http_vars['lat_val'] = null;
- $in_http_vars['long_val'] = null;
- } elseif (!isset($in_http_vars['geo_loc']) || $in_http_vars['geo_loc'] != 'yes') {
- if (!isset($in_http_vars['geo_width'])) {
- $in_http_vars['geo_width'] = 0;
- }
- }
- $ret_array = array (); // If we supply an array as a second parameter, we will get the dump returned in a two-dimensional array.
- DisplaySearchResultsCSV($in_http_vars, $ret_array); // Start off by getting the CSV dump in the same manner as the normal CSV dump.
-
- if (is_array($ret_array) && count($ret_array)) {
- $ret = '"'.join('","', array_keys($transfer_dictionary)).'"'; // This is the header line.
- foreach ($ret_array as $one_meeting) {
- if (is_array($one_meeting) && count($one_meeting)) {
- $line = array();
- foreach ($transfer_dictionary as $key => $value) {
- // See if this is a function.
- if (function_exists($value) && is_callable($value) && preg_match('|^BMLT_FuncNAWSReturn|', $value)) {
- $value = $value($one_meeting['id_bigint'], $server);
- } elseif (isset($one_meeting[$value])) { // See if we just transfer the value with no change.
- $value = $one_meeting[$value];
- }
- array_push($line, $value);
- }
-
- if (is_array($line) && count($line)) {
- $ret .= "\n".'"'.join('","', $line).'"';
- }
- }
- }
- }
-
- $del_meetings = ReturnNAWSDeletedMeetings($server, $transfer_dictionary, $in_http_vars['services']); // We append deleted meetings to the end.
-
- if (is_array($del_meetings) && count($del_meetings)) {
- foreach ($del_meetings as $one_meeting) {
- if (is_array($one_meeting) && count($one_meeting)) {
- $ret .= "\n".'"'.join('","', $one_meeting).'"';
- }
- }
- }
-
- return $ret;
-}
-
-/*******************************************************************/
-/**
- \brief Returns deleted meetings with NAWS IDs.
-
- \description This queries every deleted meeting. The meetings returned are not restricted to the search parameters,
- and may repeat from previous dumps. Only meetings that had World IDs, and that don't have the World ID 'deleted'
- in their most recent change record, are returned. (The special World ID 'deleted' indicates a meeting that NAWS
- has already processed, and so they don't need to see it again.)
-
- \returns An array of World IDs and change dates. These each represent deleted meetings.
-*/
-function ReturnNAWSDeletedMeetings(
- &$server, ///< A reference to an instance of c_comdef_server
- $in_transfer_dictionary, ///< The transfer dictionary
- $in_services ///< Any Service body IDs
-) {
- $ret = null;
- $ids_to_ignore = []; // these are the IDs of meetings that NAWS has already processed, and so we don't output them
-
- // We start by getting all the meetings that have been deleted (Could be quite a few).
- // These are returned in reverse chronological order, with the most recent change first.
- $changes = $server->GetChangesFromOTypeAndCType('c_comdef_meeting', 'comdef_change_type_delete');
-
- if ($changes instanceof c_comdef_changes) {
- $ret = array();
- $c_array = $changes->GetChangesObjects();
-
- if (is_array($c_array) && count($c_array)) {
- foreach ($c_array as &$change) {
- $b_obj = $change->GetBeforeObject();
- if ($b_obj instanceof c_comdef_meeting) {
- $line = null;
- if (!$server->GetOneMeeting($b_obj->GetID())) { // Must be currently deleted.
- if (is_array($in_services) && count($in_services)) {
- $found = false;
- reset($in_services);
- foreach ($in_services as $sb_id) {
- if (!$found) {
- if (intval($b_obj->GetServiceBodyID()) == intval($sb_id)) {
- $found = true;
- }
- }
- }
- }
- // If the meeting's ID is in $ids_to_ignore, we don't output it (not surprisingly).
- // If the world_id for the meeting is 'deleted', that means that NAWS has already processed it,
- // and we don't output it either; in addition, we add it to the $ids_to_ignore so that any earlier
- // deletion change records for this meeting don't have anything output either.
- if (in_array($b_obj->GetID(), $ids_to_ignore)) {
- $value = false;
- } else if (strtolower($b_obj->GetMeetingDataValue('worldid_mixed')) === 'deleted') {
- array_push($ids_to_ignore, $b_obj->GetID());
- $value = false;
- } else {
- $value = intval(preg_replace('|\D*?|', '', $b_obj->GetMeetingDataValue('worldid_mixed')));
- }
-
- if ($value && $found) {
- foreach ($in_transfer_dictionary as $key => $value2) {
- if (($key != 'Delete')) {
- $value1 = null;
- // See if this is a function.
- if (function_exists($value2) && is_callable($value2) && preg_match('|^BMLT_FuncNAWSReturn|', $value2)) {
- if ($value2 == 'BMLT_FuncNAWSReturnLastMeetingChangeTime') {
- $value1 = date('n/j/y', $change->GetChangeDate());
- } else {
- $value1 = $value2($b_obj, $server);
- }
- } else // See if we just transfer the value with no change.
- {
- $value1 = $b_obj->GetMeetingDataValue($value2);
- }
- } else {
- $value1 = 'D';
- }
-
- $line[$key] = $value1;
- }
- }
- }
-
- array_push($ret, $line);
- }
- }
- }
- }
- return $ret;
-}
-
-/*******************************************************************/
-/**
- \brief Returns '' or '1', if the meeting is unpublished or not (used for the NAWS format)
-
- \returns A string, '' or '1'.
-*/
-function BMLT_FuncNAWSReturnPublishedStatus(
- $in_meeting_id, ///< The ID of the meeting (internal DB ID). This can also be a meeting object.
- &$server ///< A reference to an instance of c_comdef_server
-) {
- $ret = '';
-
- if ($in_meeting_id instanceof c_comdef_meeting) {
- $the_meeting = $in_meeting_id;
- } else {
- $the_meeting = $server->GetOneMeeting($in_meeting_id);
- }
-
- if ($the_meeting instanceof c_comdef_meeting) {
- $ret = $the_meeting->IsPublished() ? '' : '1';
- }
-
- return $ret;
-}
-
-/*******************************************************************/
-/**
- \brief Returns 'OPEN' or 'CLOSED', if the meeting is open or closed (used for the NAWS format)
-
- \returns A string, 'OPEN' or 'CLOSED'.
-*/
-function BMLT_FuncNAWSReturnOpenOrClosed(
- $in_meeting_id, ///< The ID of the meeting (internal DB ID). This can also be a meeting object.
- &$server ///< A reference to an instance of c_comdef_server
-) {
- global $g_format_dictionary;
-
- $localized_strings = c_comdef_server::GetLocalStrings();
-
- $ret = $localized_strings['default_closed_status'] ? 'CLOSED' : 'OPEN'; // This is the default closed/open status.
- $opposite = $localized_strings['default_closed_status'] ? 'OPEN' : 'CLOSED';
-
- if ($in_meeting_id instanceof c_comdef_meeting) {
- $the_meeting = $in_meeting_id;
- } else {
- $the_meeting = $server->GetOneMeeting($in_meeting_id);
- }
-
- $ids = $g_format_dictionary[$opposite];
-
- if ($the_meeting instanceof c_comdef_meeting) {
- $formats = $the_meeting->GetMeetingDataValue('formats');
-
- if (is_array($formats) && count($formats) && is_array($ids)) {
- foreach ($ids as $id) {
- if (isset($formats[$id])) {
- $ret = $opposite;
- break;
- }
- }
- }
- }
-
- return $ret;
-}
-
-/*******************************************************************/
-/**
- \brief Returns 'TRUE' or 'FALSE', if the meeting is or is not wheelchair-accessible (used for the NAWS format)
-
- \returns A string, 'TRUE' or 'FALSE'.
-*/
-function BMLT_FuncNAWSReturnWheelchair(
- $in_meeting_id, ///< The ID of the meeting (internal DB ID) This can also be a meeting object.
- &$server ///< A reference to an instance of c_comdef_server
-) {
- global $g_format_dictionary;
-
- $ret = 'FALSE';
-
- if ($in_meeting_id instanceof c_comdef_meeting) {
- $the_meeting = $in_meeting_id;
- } else {
- $the_meeting = $server->GetOneMeeting($in_meeting_id);
- }
-
- $ids = $g_format_dictionary['WCHR'];
-
- if ($the_meeting instanceof c_comdef_meeting) {
- $formats = $the_meeting->GetMeetingDataValue('formats');
-
- if (is_array($formats) && count($formats) && is_array($ids)) {
- foreach ($ids as $id) {
- if (isset($formats[$id])) {
- $ret = 'TRUE';
- break;
- }
- }
- }
- }
-
- return $ret;
-}
-
-/*******************************************************************/
-/**
- \brief Returns 'TRUE' or 'FALSE', if the meeting is or is not an institution meeting (used for the NAWS format)
-
- \returns A string, 'TRUE' or 'FALSE' (It will always be FALSE).
-*/
-function BMLT_FuncNAWSReturnInst(
- $in_meeting_id, ///< The ID of the meeting (internal DB ID) This can also be a meeting object.
- &$server ///< A reference to an instance of c_comdef_server
-) {
- $ret = 'FALSE';
-
- return $ret;
-}
-
-/*******************************************************************/
-/**
- \brief Returns the string for the weekday the meeting gathers (used for the NAWS format)
-
- \returns A string ('Monday' - 'Friday').
-*/
-function BMLT_FuncNAWSReturnWeekday(
- $in_meeting_id, ///< The ID of the meeting (internal DB ID) This can also be a meeting object.
- &$server ///< A reference to an instance of c_comdef_server
-) {
- $ret = null;
-
- $weekdays = array ( null, 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday' );
-
- if ($in_meeting_id instanceof c_comdef_meeting) {
- $the_meeting = $in_meeting_id;
- } else {
- $the_meeting = $server->GetOneMeeting($in_meeting_id);
- }
-
- if ($the_meeting instanceof c_comdef_meeting) {
- $ret = $weekdays[$the_meeting->GetMeetingDataValue('weekday_tinyint')];
- }
-
- return $ret;
-}
-
-/*******************************************************************/
-/**
- \brief Returns the string for the weekday the meeting gathers (used for the NAWS format)
-
- \returns A string (the time, in pure military time - no seconds).
-*/
-function BMLT_FuncNAWSReturnTime(
- $in_meeting_id, ///< The ID of the meeting (internal DB ID) This can also be a meeting object.
- &$server ///< A reference to an instance of c_comdef_server
-) {
- $ret = null;
-
- if ($in_meeting_id instanceof c_comdef_meeting) {
- $the_meeting = $in_meeting_id;
- } else {
- $the_meeting = $server->GetOneMeeting($in_meeting_id);
- }
-
- if ($the_meeting instanceof c_comdef_meeting) {
- $ret = explode(':', $the_meeting->GetMeetingDataValue('start_time'));
- if (is_array($ret) && count($ret) > 1) {
- $ret = $ret[0].$ret[1];
- }
- }
-
- return $ret;
-}
-
-/*******************************************************************/
-/**
- \brief Returns the string for the first alternative language (if any)
-
- \returns A string.
-*/
-function BMLT_FuncNAWSReturnLanguage1(
- $in_meeting_id, ///< The ID of the meeting (internal DB ID) This can also be a meeting object.
- &$server ///< A reference to an instance of c_comdef_server
-) {
- $ret = '';
-
- if ($in_meeting_id instanceof c_comdef_meeting) {
- $the_meeting = $in_meeting_id;
- } else {
- $the_meeting = $server->GetOneMeeting($in_meeting_id);
- }
-
- if ($the_meeting instanceof c_comdef_meeting) {
- $formats = $the_meeting->GetMeetingDataValue('formats');
- $lang = $server->GetLocalLang();
-
- if (is_array($formats) && count($formats)) {
- foreach ($formats as $format) {
- if ($format instanceof c_comdef_format) {
- if ('LANG' == $format->GetWorldID()) {
- $ret = strtoupper(trim($format->GetKey()));
- break;
- }
- }
- }
- }
- }
-
- return $ret;
-}
-
-/*******************************************************************/
-/**
- \brief Returns the string for the NAWS ID for the meeting (used for the NAWS format)
-
- \returns A string The meeting ID, in NAWS form (G0000000).
-*/
-function BMLT_FuncNAWSReturnMeetingNAWSID(
- $in_meeting_id, ///< The ID of the meeting (internal DB ID) This can also be a meeting object.
- &$server ///< A reference to an instance of c_comdef_server
-) {
- $ret = null;
- if ($in_meeting_id instanceof c_comdef_meeting) {
- $the_meeting = $in_meeting_id;
- } else {
- $the_meeting = $server->GetOneMeeting($in_meeting_id);
- }
-
- if ($the_meeting instanceof c_comdef_meeting) {
- $ret = trim($the_meeting->GetMeetingDataValue('worldid_mixed'));
- }
-
- return $ret;
-}
-
-/*******************************************************************/
-/**
- \brief Returns the string for the town field the meeting (used for the NAWS format). This may use the borough name, instead.
-
- \returns A string The meeting town.
-*/
-function BMLT_FuncNAWSReturnMeetingTown(
- $in_meeting_id, ///< The ID of the meeting (internal DB ID) This can also be a meeting object.
- &$server ///< A reference to an instance of c_comdef_server
-) {
- $ret = null;
- if ($in_meeting_id instanceof c_comdef_meeting) {
- $the_meeting = $in_meeting_id;
- } else {
- $the_meeting = $server->GetOneMeeting($in_meeting_id);
- }
-
- if ($the_meeting instanceof c_comdef_meeting) {
- // Our first choice is the borough/ku.
- $ret = trim($the_meeting->GetMeetingDataValue('location_city_subsection'));
-
- if (!$ret) {
- $ret = trim($the_meeting->GetMeetingDataValue('location_municipality'));
- }
-
- // If all else fails, we use the neighborhood.
- if (!$ret) {
- $ret = trim($the_meeting->GetMeetingDataValue('location_neighborhood'));
- }
- }
-
- return $ret;
-}
-
-/*******************************************************************/
-/**
- \brief Returns the latest changed date for the given meeting.
-
- \returns a date in ISO form ('2013-01-31').
-*/
-function BMLT_FuncNAWSReturnLastMeetingChangeTime(
- $in_meeting_id, ///< The ID of the meeting (internal DB ID) This can also be a meeting object.
- &$server ///< A reference to an instance of c_comdef_server
-) {
- $ret = null;
-
- $changes_obj = $server->GetChangesFromIDAndType('c_comdef_meeting', $in_meeting_id);
-
- if ($changes_obj instanceof c_comdef_changes) {
- $changes_objects = $changes_obj->GetChangesObjects();
-
- if (is_array($changes_objects) && count($changes_objects)) {
- $last_date = 0;
- foreach ($changes_objects as $change) {
- $last_date = max($last_date, $change->GetChangeDate());
- }
-
- if ($last_date) {
- $ret = date('n/j/y', $last_date);
- }
- }
- }
-
- return $ret;
-}
-
-/*******************************************************************/
-/**
- \brief Returns the string for the NAWS ID for the meeting's Service Body (used for the NAWS format)
-
- \returns A string The Service Body ID, in NAWS form (RG/AR0000000).
-*/
-function BMLT_FuncNAWSReturnMeetingServiceBodyNAWSID(
- $in_meeting_id, ///< The ID of the meeting (internal DB ID) This can also be a meeting object.
- &$server ///< A reference to an instance of c_comdef_server
-) {
- $ret = null;
-
- if ($in_meeting_id instanceof c_comdef_meeting) {
- $the_meeting = $in_meeting_id;
- } else {
- $the_meeting = $server->GetOneMeeting($in_meeting_id);
- }
-
- if ($the_meeting instanceof c_comdef_meeting) {
- $service_body = $the_meeting->GetServiceBodyObj();
-
- $ret2 = intval(preg_replace('|\D*?|', '', trim($service_body->GetWorldID())));
-
- if ($service_body instanceof c_comdef_service_body) {
- if ($service_body->GetSBType() == c_comdef_service_body__ASC__) {
- if ($ret2) {
- $ret = sprintf('AR%05d', $ret2);
- }
- } elseif ($service_body->GetSBType() == c_comdef_service_body__RSC__) {
- if ($ret2) {
- $ret = sprintf('RG%03d', $ret2);
- }
- }
- }
- }
-
- return $ret;
-}
-
-/*******************************************************************/
-/**
-\brief Returns a string of all formats that don't map to NAWS codes.
-
-\returns A string The format codes name_string.
- */
-function BMLT_FuncNAWSReturnNonNawsFormats(
- $in_meeting_id, ///< The ID of the meeting (internal DB ID) This can also be a meeting object.
- &$server ///< A reference to an instance of c_comdef_server
-) {
-
- $ret = "";
-
- if ($in_meeting_id instanceof c_comdef_meeting) {
- $the_meeting = $in_meeting_id;
- } else {
- $the_meeting = $server->GetOneMeeting($in_meeting_id);
- }
-
- if ($the_meeting instanceof c_comdef_meeting) {
- $formats = $the_meeting->GetMeetingDataValue('formats');
-
- if (is_array($formats) && count($formats)) {
- foreach ($formats as $format) {
- if ($format != null && !$format->GetWorldID()) {
- $ret .= $format->GetLocalName();
- $ret .= ',';
- }
- }
-
- $ret = rtrim($ret, ',');
- }
- }
-
- return $ret;
-}
-
-/*******************************************************************/
-/**
-\brief Returns a string of location_info and comments fields.
-
-\returns A string The location_info and comments fields.
- */
-function BMLT_FuncNAWSReturnDirections(
- $in_meeting_id, ///< The ID of the meeting (internal DB ID) This can also be a meeting object.
- &$server ///< A reference to an instance of c_comdef_server
-) {
-
- $ret = "";
-
- if ($in_meeting_id instanceof c_comdef_meeting) {
- $the_meeting = $in_meeting_id;
- } else {
- $the_meeting = $server->GetOneMeeting($in_meeting_id);
- }
-
- if ($the_meeting instanceof c_comdef_meeting) {
- $ret = trim($the_meeting->GetMeetingDataValue('location_info'));
-
- if ($the_meeting->GetMeetingDataValue('comments')) {
- if ($ret) {
- $ret .= ", ";
- }
- $ret .= trim($the_meeting->GetMeetingDataValue('comments'));
- }
- }
-
- return $ret;
-}
-
-/*******************************************************************/
-/**
- \brief Returns the string for the first format (used for the NAWS format)
-
- \returns A string The format code, in NAWS form.
-*/
-function BMLT_FuncNAWSReturnFormat1(
- $in_meeting_id, ///< The ID of the meeting (internal DB ID) This can also be a meeting object.
- &$server ///< A reference to an instance of c_comdef_server
-) {
- return BMLT_FuncNAWSReturnFormat(1, $in_meeting_id, $server);
-}
-
-/*******************************************************************/
-/**
- \brief Returns the string for the second format (used for the NAWS format)
-
- \returns A string The format code, in NAWS form.
-*/
-function BMLT_FuncNAWSReturnFormat2(
- $in_meeting_id, ///< The ID of the meeting (internal DB ID) This can also be a meeting object.
- &$server ///< A reference to an instance of c_comdef_server
-) {
- return BMLT_FuncNAWSReturnFormat(2, $in_meeting_id, $server);
-}
-
-/*******************************************************************/
-/**
- \brief Returns the string for the third format (used for the NAWS format)
-
- \returns A string The format code, in NAWS form.
-*/
-function BMLT_FuncNAWSReturnFormat3(
- $in_meeting_id, ///< The ID of the meeting (internal DB ID) This can also be a meeting object.
- &$server ///< A reference to an instance of c_comdef_server
-) {
- return BMLT_FuncNAWSReturnFormat(3, $in_meeting_id, $server);
-}
-
-/*******************************************************************/
-/**
- \brief Returns the string for the fourth format (used for the NAWS format)
-
- \returns A string The format code, in NAWS form.
-*/
-function BMLT_FuncNAWSReturnFormat4(
- $in_meeting_id, ///< The ID of the meeting (internal DB ID) This can also be a meeting object.
- &$server ///< A reference to an instance of c_comdef_server
-) {
- return BMLT_FuncNAWSReturnFormat(4, $in_meeting_id, $server);
-}
-
-/*******************************************************************/
-/**
- \brief Returns the string for the fifth format (used for the NAWS format)
-
- \returns A string The format code, in NAWS form.
-*/
-function BMLT_FuncNAWSReturnFormat5(
- $in_meeting_id, ///< The ID of the meeting (internal DB ID) This can also be a meeting object.
- &$server ///< A reference to an instance of c_comdef_server
-) {
- return BMLT_FuncNAWSReturnFormat(5, $in_meeting_id, $server);
-}
-
-/*******************************************************************/
-/**
- \brief Returns the string for the n-th format (used for the NAWS format)
-
- \returns A string The format code, in NAWS form.
- */
-function BMLT_FuncNAWSReturnFormat(
- $n, ///< which format
- $in_meeting_id, ///< The ID of the meeting (internal DB ID) This can also be a meeting object.
- &$server ///< A reference to an instance of c_comdef_server
-) {
- global $g_format_dictionary;
- if ($in_meeting_id instanceof c_comdef_meeting) {
- $the_meeting = $in_meeting_id;
- } else {
- $the_meeting = $server->GetOneMeeting($in_meeting_id);
- }
- if ($the_meeting instanceof c_comdef_meeting) {
- // $formats is an array of the formats for this meeting as they are stored in the BMLT database.
- // $naws_formats is an array of the NAWS versions of these formats - note that not everything in $formats
- // will have a corresponding NAWS versions. Also there can also be several BMLT formats that map
- // to the same NAWS format -- in this case, only include one NAWS format.
- // This function is a bit stupid, since it gets called up to 5 times for the 5 possible NAWS formats --
- // more aesthetic (and slightly more efficient) would be to just call it once. However, efficiency is not
- // terribly important here since this just gets called when producing an export spreadsheet.
- $formats = $the_meeting->GetMeetingDataValue('formats');
- $naws_formats = [];
- if (is_array($formats) && count($formats)) {
- foreach ($g_format_dictionary as $n_format => $b_formats) {
- if (($n_format != 'OPEN') && ($n_format != 'CLOSED') && ($n_format != 'WCHR')) {
- foreach ($b_formats as $b_format) {
- if (isset($formats[$b_format]) && !in_array($n_format, $naws_formats)) {
- array_push($naws_formats, $n_format);
- }
- }
- }
- }
- }
- if ($n > count($naws_formats)) {
- return null;
- } else {
- return $naws_formats[$n-1];
- }
- }
-}
-
-/*******************************************************************/
-/**
- \brief Returns the string for the name for the meeting's Service Body (used for the NAWS format)
-
- \returns A string The Service Body name.
-*/
-function BMLT_FuncNAWSReturnMeetingServiceBodyName(
- $in_meeting_id, ///< The ID of the meeting (internal DB ID) This can also be a meeting object.
- &$server ///< A reference to an instance of c_comdef_server
-) {
- $ret = null;
-
- if ($in_meeting_id instanceof c_comdef_meeting) {
- $the_meeting = $in_meeting_id;
- } else {
- $the_meeting = $server->GetOneMeeting($in_meeting_id);
- }
-
- if ($the_meeting instanceof c_comdef_meeting) {
- $service_body = $the_meeting->GetServiceBodyObj();
-
- while (!$ret && ($service_body instanceof c_comdef_service_body)) {
- if (($service_body->GetSBType() == c_comdef_service_body__ASC__) || ($service_body->GetSBType() == c_comdef_service_body__RSC__)) {
- $ret = $service_body->GetLocalName();
- } else {
- $service_body = $service_body->GetOwnerIDObject();
- }
- }
- }
-
- return $ret;
-}
diff --git a/src/legacy/client_interface/gpx/index.php b/src/legacy/client_interface/gpx/index.php
deleted file mode 100755
index 63f366057..000000000
--- a/src/legacy/client_interface/gpx/index.php
+++ /dev/null
@@ -1,64 +0,0 @@
-/client_interface/gpx/
- with the same parameters that you would send to an advanced search. The results
- will be returned as an GPX file.
-
- This file can be called from other servers.
-
- This file is part of the Basic Meeting List Toolbox (BMLT).
-
- Find out more at: https://bmlt.app
-
- BMLT is free software: you can redistribute it and/or modify
- it under the terms of the MIT License.
-
- BMLT is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- MIT License for more details.
-
- You should have received a copy of the MIT License along with this code.
- If not, see .
-*/
-
-defined('BMLT_EXEC') or define('BMLT_EXEC', true); // This is a security verifier. Keeps files from being executed outside of the context
-require_once(dirname(__FILE__).'/../csv/csv.php');
-
-try {
- $server = c_comdef_server::MakeServer();
- $ret = null;
-
- if ($server instanceof c_comdef_server) {
- $_GET['switcher'] = 'GetSearchResults';
- unset($_GET['xml_data']);
- $_GET['gpx_data'] = true;
- $_GET['data_field_key'] = 'longitude,latitude,location_city_subsection,location_neighborhood,location_province,location_nation,location_postal_code_1,location_text,location_street,location_info,location_municipality,meeting_name,weekday_tinyint,start_time';
- $ret = parse_redirect($server);
- // The caller can request compression. Not all clients can deal with compressed replies.
- if (isset($_GET['compress_output']) || isset($_POST['compress_output'])) {
- if (zlib_get_coding_type() === false) {
- ob_start("ob_gzhandler");
- } else {
- header('Content-Type:application/xml; charset=UTF-8');
- header('Content-Disposition: attachment; filename="SearchResults.gpx"');
- ob_start();
- }
- } else {
- header('Content-Type:application/xml; charset=UTF-8');
- header('Content-Disposition: attachment; filename="SearchResults.gpx"');
- ob_start();
- }
-
- echo $ret;
- ob_end_flush();
- } else {
- echo HandleNoServer();
- }
-} catch (Exception $e) {
- echo HandleNoServer();
-}
diff --git a/src/legacy/client_interface/html/index.php b/src/legacy/client_interface/html/index.php
deleted file mode 100755
index 38778c7e4..000000000
--- a/src/legacy/client_interface/html/index.php
+++ /dev/null
@@ -1,83 +0,0 @@
-my_server->GetLocalStrings();
-$user_obj = $console_object->my_server->GetCurrentUserObj();
-if ($user_obj instanceof c_comdef_user && $user_obj->GetUserLevel() != _USER_LEVEL_DEACTIVATED) {
- $service_body_ids = [];
- $service_body_set = [];
- $user_level = intval($user_obj->GetUserLevel());
- if ($user_level === _USER_LEVEL_OBSERVER) {
- $service_body_set = $console_object->my_observable_service_bodies;
- } else if ($user_level === _USER_LEVEL_SERVICE_BODY_ADMIN) {
- $service_body_set = $console_object->my_service_bodies;
- } else if ($user_level === _USER_LEVEL_SERVER_ADMIN) {
- $service_body_set = $console_object->my_all_service_bodies;
- }
-
- foreach ($service_body_set as $service_body_id) {
- array_push($service_body_ids, intval($service_body_id->GetID()));
- }
-
- function getBCP47TagForISO631Language($code)
- {
- $default = 'en-US';
-
- $iso630tobcp47 = [
- 'de' => 'de-DE',
- 'dk' => 'da-DK',
- 'es' => 'es-US',
- 'fa' => 'fa-IR',
- 'fr' => 'fr-CA',
- 'it' => 'it-IT',
- 'pl' => 'pl-PL',
- 'pt' => 'pt-BR',
- 'sv' => 'sv-SE'
- ];
-
- return array_key_exists($code, $iso630tobcp47) ? $iso630tobcp47[$code] : $default;
- }?>
-
-
-
-
-
- cookie('bmlt_admin_lang_pref', 'en');
- ?>
- " />
- " />
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/legacy/client_interface/index.htm b/src/legacy/client_interface/index.htm
deleted file mode 100755
index e69de29bb..000000000
diff --git a/src/legacy/client_interface/json/GetLangs.php b/src/legacy/client_interface/json/GetLangs.php
deleted file mode 100755
index 78923799a..000000000
--- a/src/legacy/client_interface/json/GetLangs.php
+++ /dev/null
@@ -1,66 +0,0 @@
-.
-********************************************************************************************/
-
-defined('BMLT_EXEC') or define('BMLT_EXEC', true); // This is a security verifier. Keeps files from being executed outside of the context
-$file_dir = str_replace('/client_interface/json', '', dirname(__FILE__)).'/server/c_comdef_server.class.php';
-require_once($file_dir);
-$server = c_comdef_server::MakeServer();
-$ret = null;
-
-if ($server instanceof c_comdef_server) {
- $langs = $server->GetServerLangs();
-
- if ($langs) {
- // The caller can request compression. Not all clients can deal with compressed replies.
- if (isset($_GET['compress_json']) || isset($_POST['compress_json'])) {
- ob_start('ob_gzhandler');
- } else {
- header('Content-Type:application/json; charset=UTF-8');
- ob_start();
- }
-
- echo '{"languages":[';
-
- $first = true;
-
- foreach ($langs as $key_string => $name_string) {
- if (!$first) {
- echo ",";
- } else {
- $first = false;
- }
-
- echo '{"key":'.json_encode($key_string);
- echo ',"name":'.json_encode($name_string);
- if (!strcmp($key_string, $server->GetLocalLang())) {
- echo ',"default":true';
- }
- echo '}';
- }
-
- echo "]}";
- ob_end_flush();
- } else {
- echo ( 'No Languages' );
- }
-} else {
- echo ( 'No Server' );
-}
diff --git a/src/legacy/client_interface/json/index.php b/src/legacy/client_interface/json/index.php
deleted file mode 100755
index 52cdc51af..000000000
--- a/src/legacy/client_interface/json/index.php
+++ /dev/null
@@ -1,58 +0,0 @@
-/client_interface/json/
- with the same parameters that you would send to an advanced search. The results
- will be returned as a JSON file.
-
- This file can be called from other servers.
-
- This file is part of the Basic Meeting List Toolbox (BMLT).
-
- Find out more at: https://bmlt.app
-
- BMLT is free software: you can redistribute it and/or modify
- it under the terms of the MIT License.
-
- BMLT is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- MIT License for more details.
-
- You should have received a copy of the MIT License along with this code.
- If not, see .
-*/
-
-defined('BMLT_EXEC') or define('BMLT_EXEC', true); // This is a security verifier. Keeps files from being executed outside of the context
-
-require_once(dirname(__FILE__).'/../csv/csv.php');
-
-try {
- $server = c_comdef_server::MakeServer();
- $ret = null;
-
- if ($server instanceof c_comdef_server) {
- $_GET['json_data'] = true;
- $ret = parse_redirect($server);
- if (isset($_GET['compress_output']) || isset($_POST['compress_output'])) {
- if (zlib_get_coding_type() === false) {
- ob_start("ob_gzhandler");
- } else {
- ob_start();
- }
- } else {
- header('Content-Type:application/json; charset=UTF-8');
- ob_start();
- }
-
- echo $ret;
- ob_end_flush();
- } else {
- echo HandleNoServer();
- }
-} catch (Exception $e) {
- echo HandleNoServer();
-}
diff --git a/src/legacy/client_interface/jsonp/GetLangs.php b/src/legacy/client_interface/jsonp/GetLangs.php
deleted file mode 100755
index 3701b314b..000000000
--- a/src/legacy/client_interface/jsonp/GetLangs.php
+++ /dev/null
@@ -1,66 +0,0 @@
-.
-********************************************************************************************/
-
-defined('BMLT_EXEC') or define('BMLT_EXEC', true); // This is a security verifier. Keeps files from being executed outside of the context
-$file_dir = str_replace('/client_interface/jsonp', '', dirname(__FILE__)).'/server/c_comdef_server.class.php';
-require_once($file_dir);
-$server = c_comdef_server::MakeServer();
-$ret = null;
-
-if ($server instanceof c_comdef_server) {
- $langs = $server->GetServerLangs();
-
- if ($langs) {
- // The caller can request compression. Not all clients can deal with compressed replies.
- if (isset($_GET['compress_json']) || isset($_POST['compress_json'])) {
- ob_start('ob_gzhandler');
- } else {
- header('Content-Type:application/javascript; charset=UTF-8');
- ob_start();
- }
-
- echo $_GET['callback'] . '({"languages":[';
-
- $first = true;
-
- foreach ($langs as $key_string => $name_string) {
- if (!$first) {
- echo ",";
- } else {
- $first = false;
- }
-
- echo '{"key":'.json_encode($key_string);
- echo ',"name":'.json_encode($name_string);
- if (!strcmp($key_string, $server->GetLocalLang())) {
- echo ',"default":true';
- }
- echo '}';
- }
-
- echo "]});";
- ob_end_flush();
- } else {
- echo ( 'No Languages' );
- }
-} else {
- echo ( 'No Server' );
-}
diff --git a/src/legacy/client_interface/jsonp/index.php b/src/legacy/client_interface/jsonp/index.php
deleted file mode 100755
index 3c286dbc3..000000000
--- a/src/legacy/client_interface/jsonp/index.php
+++ /dev/null
@@ -1,60 +0,0 @@
-/client_interface/jsonp/
- with the same parameters that you would send to an advanced search. The results
- will be returned as a JSONP file.
-
- This file can be called from other servers.
-
- This file is part of the Basic Meeting List Toolbox (BMLT).
-
- Find out more at: https://bmlt.app
-
- BMLT is free software: you can redistribute it and/or modify
- it under the terms of the MIT License.
-
- BMLT is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- MIT License for more details.
-
- You should have received a copy of the MIT License along with this code.
- If not, see .
-*/
-
-defined('BMLT_EXEC') or define('BMLT_EXEC', true); // This is a security verifier. Keeps files from being executed outside of the context
-
-require_once(dirname(__FILE__).'/../csv/csv.php');
-
-try {
- $server = c_comdef_server::MakeServer();
- $ret = null;
-
- if ($server instanceof c_comdef_server) {
- $_GET['json_data'] = true;
- $ret = parse_redirect($server);
- if (isset($_GET['compress_output']) || isset($_POST['compress_output'])) {
- if (zlib_get_coding_type() === false) {
- ob_start("ob_gzhandler");
- } else {
- ob_start();
- }
- } else {
- header('Content-Type:application/javascript; charset=UTF-8');
- ob_start();
- }
-
- echo $_GET['callback'] . '(';
- echo $ret;
- echo ');';
- ob_end_flush();
- } else {
- echo HandleNoServer();
- }
-} catch (Exception $e) {
- echo HandleNoServer();
-}
diff --git a/src/legacy/client_interface/kml/index.php b/src/legacy/client_interface/kml/index.php
deleted file mode 100755
index 7943032e7..000000000
--- a/src/legacy/client_interface/kml/index.php
+++ /dev/null
@@ -1,65 +0,0 @@
-/client_interface/kml/
- with the same parameters that you would send to an advanced search. The results
- will be returned as an KML file.
-
- This file can be called from other servers.
-
- This file is part of the Basic Meeting List Toolbox (BMLT).
-
- Find out more at: https://bmlt.app
-
- BMLT is free software: you can redistribute it and/or modify
- it under the terms of the MIT License.
-
- BMLT is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- MIT License for more details.
-
- You should have received a copy of the MIT License along with this code.
- If not, see .
-*/
-
-defined('BMLT_EXEC') or define('BMLT_EXEC', true); // This is a security verifier. Keeps files from being executed outside of the context
-require_once(dirname(__FILE__).'/../csv/csv.php');
-
-try {
- $server = c_comdef_server::MakeServer();
- $ret = null;
-
- if ($server instanceof c_comdef_server) {
- $_GET['switcher'] = 'GetSearchResults';
- unset($_GET['xml_data']);
- unset($_GET['gpx_data']);
- $_GET['kml_data'] = true;
- $_GET['data_field_key'] = 'longitude,latitude,location_city_subsection,location_neighborhood,location_province,location_nation,location_postal_code_1,location_text,location_street,location_info,location_municipality,meeting_name,weekday_tinyint,start_time';
- $ret = parse_redirect($server);
- // The caller can request compression. Not all clients can deal with compressed replies.
- if (isset($_GET['compress_output']) || isset($_POST['compress_output'])) {
- if (zlib_get_coding_type() === false) {
- ob_start("ob_gzhandler");
- } else {
- header('Content-Type:application/xml; charset=UTF-8');
- header('Content-Disposition: attachment; filename="SearchResults.kml"');
- ob_start();
- }
- } else {
- header('Content-Type:application/xml; charset=UTF-8');
- header('Content-Disposition: attachment; filename="SearchResults.kml"');
- ob_start();
- }
-
- echo $ret;
- ob_end_flush();
- } else {
- echo HandleNoServer();
- }
-} catch (Exception $e) {
- echo HandleNoServer();
-}
diff --git a/src/legacy/client_interface/poi/index.php b/src/legacy/client_interface/poi/index.php
deleted file mode 100755
index de68ab482..000000000
--- a/src/legacy/client_interface/poi/index.php
+++ /dev/null
@@ -1,66 +0,0 @@
-/client_interface/poi/
- with the same parameters that you would send to an advanced search. The results
- will be returned as an POI CSV file.
-
- This file can be called from other servers.
-
- This file is part of the Basic Meeting List Toolbox (BMLT).
-
- Find out more at: https://bmlt.app
-
- BMLT is free software: you can redistribute it and/or modify
- it under the terms of the MIT License.
-
- BMLT is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- MIT License for more details.
-
- You should have received a copy of the MIT License along with this code.
- If not, see .
-*/
-
-defined('BMLT_EXEC') or define('BMLT_EXEC', true); // This is a security verifier. Keeps files from being executed outside of the context
-require_once(dirname(__FILE__).'/../csv/csv.php');
-
-try {
- $server = c_comdef_server::MakeServer();
- $ret = null;
-
- if ($server instanceof c_comdef_server) {
- $_GET['switcher'] = 'GetSearchResults';
- unset($_GET['xml_data']);
- unset($_GET['gpx_data']);
- unset($_GET['kml_data']);
- $_GET['poi_data'] = true;
- $_GET['data_field_key'] = 'longitude,latitude,location_city_subsection,location_neighborhood,location_province,location_nation,location_postal_code_1,location_text,location_street,location_info,location_municipality,meeting_name,weekday_tinyint,start_time';
- $ret = parse_redirect($server);
- // The caller can request compression. Not all clients can deal with compressed replies.
- if (isset($_GET['compress_output']) || isset($_POST['compress_output'])) {
- if (zlib_get_coding_type() === false) {
- ob_start("ob_gzhandler");
- } else {
- header('Content-Type:text/csv; charset=UTF-8');
- header('Content-Disposition: attachment; filename="SearchResultsPOI.csv"');
- ob_start();
- }
- } else {
- header('Content-Type:text/csv; charset=UTF-8');
- header('Content-Disposition: attachment; filename="SearchResultsPOI.csv"');
- ob_start();
- }
-
- echo $ret;
- ob_end_flush();
- } else {
- echo HandleNoServer();
- }
-} catch (Exception $e) {
- echo HandleNoServer();
-}
diff --git a/src/legacy/client_interface/simple/index.php b/src/legacy/client_interface/simple/index.php
deleted file mode 100755
index 37e651f57..000000000
--- a/src/legacy/client_interface/simple/index.php
+++ /dev/null
@@ -1,515 +0,0 @@
-/client_interface/simple/
- with the same parameters that you would send to an advanced search. The results
- will be returned as XHTML data.
-
- This file can be called from other servers.
-
- This file is part of the Basic Meeting List Toolbox (BMLT).
-
- Find out more at: https://bmlt.app
-
- BMLT is free software: you can redistribute it and/or modify
- it under the terms of the MIT License.
-
- BMLT is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- MIT License for more details.
-
- You should have received a copy of the MIT License along with this code.
- If not, see .
-*/
-defined('BMLT_EXEC') or define('BMLT_EXEC', true); // This is a security verifier. Keeps files from being executed outside of the context
-require_once(dirname(__FILE__).'/../../server/shared/classes/comdef_utilityclasses.inc.php');
-require_once(dirname(__FILE__).'/../csv/csv.php');
-
-$server = c_comdef_server::MakeServer();
-$ret = null;
-
-if ($server instanceof c_comdef_server) {
- /*******************************************************************/
- /**
- \brief Queries the local server, and returns processes XHTML.
-
- This requires that the "switcher=" parameter be set in the GET or
- POST parameters:
- - 'GetSearchResults'
- This returns the search results.
-
- \returns CSV data, with the first row a key header.
- */
- function parse_redirect_simple(
- &$server ///< A reference to an instance of c_comdef_server
- ) {
- $result = null;
- $http_vars = array_merge_recursive($_GET, $_POST);
-
- if (!isset($http_vars['lang_enum']) || !$http_vars['lang_enum']) {
- $http_vars['lang_enum'] = $server->GetLocalLang();
- }
-
- // Just to be safe, we override any root passed in. We know where our root is, and we don't need to be told.
- $http_vars['bmlt_root'] = 'http://'.$_SERVER['SERVER_NAME'].(($_SERVER['SERVER_PORT'] != 80) ? ':'.$_SERVER['SERVER_PORT'] : '').dirname($_SERVER['SCRIPT_NAME'])."/../../";
-
- switch ($http_vars['switcher']) {
- case 'GetSearchResults':
- $container = (isset($http_vars['container_id']) && $http_vars['container_id']) ? $http_vars['container_id'] : null;
- $result = GetSimpleSearchResults($http_vars, isset($http_vars['block_mode']), $container);
- break;
-
- case 'GetFormats':
- $lang = null;
-
- if (isset($http_vars['lang_enum'])) {
- $lang = $http_vars['lang_enum'];
- }
-
- $formatKeyStrings = null;
- if (isset($http_vars['key_strings']) && is_array($http_vars['key_strings']) && count($http_vars['key_strings'])) {
- $formatKeyStrings = $http_vars['key_strings'];
- } else if (isset($http_vars['key_strings'])) {
- $formatKeyStrings = [$http_vars['key_strings']];
- }
-
- unset($http_vars['lang_enum']);
- unset($http_vars['key_strings']);
- unset($http_vars['switcher']);
- $container = (isset($http_vars['container_id']) && $http_vars['container_id']) ? $http_vars['container_id'] : null;
- $result = GetSimpleFormats($server, isset($http_vars['block_mode']), $container, $lang, $formatKeyStrings, $http_vars);
- break;
-
- default:
- $result = HandleSimpleDefault($http_vars);
- break;
- }
-
- return $result;
- }
-
- /*******************************************************************/
- /**
- \brief This returns the search results, in whatever form was requested.
-
- \returns XHTML data. It will either be a table, or block elements.
- */
- function GetSimpleSearchResults(
- $in_http_vars, ///< The HTTP GET and POST parameters.
- $in_block = false, ///< If this is true, the results will be sent back as block elements (div tags), as opposed to a table. Default is false.
- $in_container_id = null ///< This is an optional ID for the "wrapper."
- ) {
- $localized_strings = c_comdef_server::GetLocalStrings();
- $original_weekday = -1;
- $current_weekday = -1;
-
- if (!( isset($in_http_vars['geo_width']) && $in_http_vars['geo_width'] ) && isset($in_http_vars['bmlt_search_type']) && ($in_http_vars['bmlt_search_type'] == 'advanced') && isset($in_http_vars['advanced_radius']) && isset($in_http_vars['advanced_mapmode']) && $in_http_vars['advanced_mapmode'] && ( floatval($in_http_vars['advanced_radius'] != 0.0) ) && isset($in_http_vars['lat_val']) && isset($in_http_vars['long_val']) && ( (floatval($in_http_vars['lat_val']) != 0.0) || (floatval($in_http_vars['long_val']) != 0.0) )) {
- $in_http_vars['geo_width'] = $in_http_vars['advanced_radius'];
- } elseif (!( isset($in_http_vars['geo_width']) && $in_http_vars['geo_width'] ) && isset($in_http_vars['bmlt_search_type']) && ($in_http_vars['bmlt_search_type'] == 'advanced')) {
- $in_http_vars['lat_val'] = null;
- $in_http_vars['long_val'] = null;
- } elseif (!isset($in_http_vars['geo_loc']) || $in_http_vars['geo_loc'] != 'yes') {
- if (!isset($in_http_vars['geo_width'])) {
- $in_http_vars['geo_width'] = 0;
- }
- }
-
- if (!(isset($in_http_vars['sort_key']) && $in_http_vars['sort_key']) && !(isset($in_http_vars['sort_keys']) && $in_http_vars['sort_keys'])) {
- $in_http_vars['sort_key'] = 'time';
- }
-
- require_once(dirname(__FILE__).'/../csv/search_results_csv.php');
- $results = DisplaySearchResultsCSV($in_http_vars);
-
- $ret = '';
-
- // What we do, is to parse the CSV return. We'll pick out certain fields, and format these into a table or block element return.
- if ($results) {
- if (isset($in_http_vars['single_uri']) && $in_http_vars['single_uri']) {
- $single_uri = $in_http_vars['single_uri'];
- }
-
- // Start by turning the CSV into an array of meeting lines.
- $results = explode("\n", $results);
-
- if (is_array($results) && count($results)) {
- $ret = $in_block ? '
' : '
';
- $keys = preg_replace('|^"|', '', preg_replace('|"$|', '', explode('","', $results[0])));
- $weekday_div = false;
-
- $alt = 1; // This is used to provide an alternating class.
- // We skip the first line, because that is the field header.
- for ($count = 1; $count < count($results); $count++) {
- $meeting = $results[$count];
-
- if ($meeting) {
- if ($alt == 1) {
- $alt = 0;
- } else {
- $alt = 1;
- }
-
- $meeting = preg_replace('|^"|', '', preg_replace('|"$|', '', explode('","', $meeting)));
- if (is_array($meeting) && count($meeting)) {
- if (count($meeting) > count($keys)) {
- $keys[] = 'unused';
- }
-
- // This is for convenience. We turn the meeting array into an associative one by adding the keys.
- $meeting = array_combine($keys, $meeting);
- $location_borough = c_comdef_htmlspecialchars(trim(stripslashes($meeting['location_city_subsection'])));
- $location_neighborhood = c_comdef_htmlspecialchars(trim(stripslashes($meeting['location_neighborhood'])));
- $location_province = c_comdef_htmlspecialchars(trim(stripslashes($meeting['location_province'])));
- $location_nation = c_comdef_htmlspecialchars(trim(stripslashes($meeting['location_nation'])));
- $location_postal_code_1 = c_comdef_htmlspecialchars(trim(stripslashes($meeting['location_postal_code_1'])));
- $location_municipality = c_comdef_htmlspecialchars(trim(stripslashes($meeting['location_municipality'])));
- $town = '';
-
- if ($location_municipality) {
- if ($location_borough) {
- // We do it this verbose way, so we will scrag the comma if we want to hide the town.
- $town = "$location_borough, $location_municipality";
- } else {
- $town = "$location_municipality";
- }
- } elseif ($location_borough) {
- $town = "$location_borough";
- }
-
- if ($location_province) {
- if ($town) {
- $town .= ', ';
- }
-
- $town .= "$location_province";
- }
-
- if ($location_postal_code_1) {
- if ($town) {
- $town .= ', ';
- }
-
- $town .= "$location_postal_code_1";
- }
-
- if ($location_nation) {
- if ($town) {
- $town .= ', ';
- }
-
- $town .= "$location_nation";
- }
-
- if ($location_neighborhood) {
- $town_temp = '';
-
- if ($town) {
- $town_temp = ' (';
- }
-
- $town_temp .= "$location_neighborhood";
-
- if ($town) {
- $town_temp .= ')';
- }
-
- $town .= $town_temp;
- }
-
- $weekday = c_comdef_htmlspecialchars($localized_strings['weekdays'][intval($meeting['weekday_tinyint'])]);
- $time = BuildMeetingTime($meeting['start_time']);
-
- $address = '';
- $location_text = c_comdef_htmlspecialchars(trim(stripslashes($meeting['location_text'])));
- $street = c_comdef_htmlspecialchars(trim(stripslashes($meeting['location_street'])));
- $info = c_comdef_htmlspecialchars(trim(stripslashes($meeting['location_info'])));
-
- if ($location_text) {
- $address = "$location_text";
- }
-
- if ($street) {
- if ($address) {
- $address .= ', ';
- }
-
- $address .= "$street";
- }
-
- if ($info) {
- if ($address) {
- $address .= '';
- }
-
- $address .= "($info)";
- }
-
- $name = c_comdef_htmlspecialchars(trim(stripslashes($meeting['meeting_name'])));
- $format = c_comdef_htmlspecialchars(trim(stripslashes($meeting['formats'])));
-
- $name_uri = urlencode(htmlspecialchars_decode($name));
-
- $map_uri = str_replace("##LONG##", c_comdef_htmlspecialchars($meeting['longitude']), str_replace("##LAT##", c_comdef_htmlspecialchars($meeting['latitude']), str_replace("##NAME##", $name_uri, $localized_strings['comdef_server_admin_strings']['MapsURL'])));
-
- if ($time && $weekday && $address) {
- $meeting_weekday = $meeting['weekday_tinyint'];
-
- if (7 < $meeting_weekday) {
- $meeting_weekday = 1;
- }
-
- if (($current_weekday != $meeting_weekday) && $in_block) {
- if ($current_weekday != -1) {
- $weekday_div = false;
- $ret .= '';
- }
-
- $current_weekday = $meeting_weekday;
-
- $ret .= '
';
- }
- }
-
- return $ret;
- }
-
- /*******************************************************************/
- /** \brief This creates a time string to be displayed for the meeting.
- The display is done in non-military time, and "midnight" and
- "noon" are substituted for 12:59:00, 00:00:00 and 12:00:00
-
- \returns a string, containing the HTML rendered by the function.
- */
- function BuildMeetingTime(
- $in_time ///< A string. The value of the time field.
- ) {
- $localized_strings = c_comdef_server::GetLocalStrings();
-
- $time = null;
-
- if (($in_time == "00:00:00") || ($in_time >= "23:55:00")) {
- $time = c_comdef_htmlspecialchars($localized_strings['comdef_server_admin_strings']['meeting_editor_screen_meeting_midnight_label']);
- } elseif ($in_time == "12:00:00") {
- $time = c_comdef_htmlspecialchars($localized_strings['comdef_server_admin_strings']['meeting_editor_screen_meeting_noon_label']);
- } else {
- include(dirname(__FILE__).'/../../server/config/get-config.php');
-
- $time = c_comdef_htmlspecialchars(date($time_format, strtotime($in_time)));
- }
-
- return $time;
- }
-
- /*******************************************************************/
- /**
- \brief This returns the complete formats table.
-
- \returns XHTML data, with the first row a key header.
- */
- function GetSimpleFormats(
- &$server, ///< A reference to an instance of c_comdef_server
- $in_block = false, ///< If this is true, the results will be sent back as block elements (div tags), as opposed to a table. Default is false.
- $in_container_id = null, ///< This is an optional ID for the "wrapper."
- $in_lang = null, ///< The language of the formats to be returned. Default is null (server language). Can be an array.
- $in_key_strings = null, ///< If supplied, an array of format key strings to be returned.
- $in_search_params = null ///< If this is supplied, then it is a search parameter list. The idea is that only the formats used in the returned meetings will be displayed.
- ) {
- $my_keys = array ( 'key_string',
- 'name_string',
- 'description_string'
- );
-
- $ret = $in_block ? '
';
-
- return $ret;
- }
-
- /*******************************************************************/
- /**
- \brief Handles no command supplied (error)
-
- \returns English error string (not XML).
- */
- function HandleSimpleDefault(
- $in_http_vars ///< The HTTP GET and POST parameters.
- ) {
- return "You must supply either 'switcher=GetSearchResults' or 'switcher=GetFormats'";
- }
-
- $ret = parse_redirect_simple($server);
-} else {
- $ret = HandleNoServer();
-}
-
-$handler = 'ob_gzhandler';
-
-// Server-side includes (and some other implementations) can't handle compressed data in the response. If "nocompress" is specified, then the GZIP handler isn't used.
-if (isset($_GET['nocompress']) || isset($_POST['nocompress'])) {
- $handler = null;
-}
-
-ob_start($handler);
- $ret = preg_replace('//', '', $ret);
- $ret = preg_replace('/\/\*(.|\s)*?\*\//', '', $ret);
- $ret = preg_replace("|\s+\/\/.*|", " ", $ret);
- $ret = preg_replace("/\s+/", " ", $ret);
- echo $ret;
-ob_end_flush();
diff --git a/src/legacy/client_interface/xml/GetLangs.php b/src/legacy/client_interface/xml/GetLangs.php
deleted file mode 100755
index a36c63da6..000000000
--- a/src/legacy/client_interface/xml/GetLangs.php
+++ /dev/null
@@ -1,68 +0,0 @@
-.
-********************************************************************************************/
-
-defined('BMLT_EXEC') or define('BMLT_EXEC', true); // This is a security verifier. Keeps files from being executed outside of the context
-$file_dir = str_replace('/client_interface/xml', '', dirname(__FILE__)).'/server/c_comdef_server.class.php';
-require_once($file_dir);
-$server = c_comdef_server::MakeServer();
-$ret = null;
-
-if ($server instanceof c_comdef_server) {
- $langs = $server->GetServerLangs();
-
- if ($langs) {
- // The caller can request compression. Not all clients can deal with compressed replies.
- if (isset($_GET['compress_xml']) || isset($_POST['compress_xml'])) {
- ob_start('ob_gzhandler');
- } else {
- header('Content-Type:application/xml; charset=UTF-8');
- ob_start();
- }
- echo '<'.'?'.'xml version="1.0" encoding="UTF-8"'.'?'.'>';
-
- $port = $_SERVER['SERVER_PORT'] ;
- // IIS puts "off" in the HTTPS field, so we need to test for that.
- $https = (!empty($_SERVER['HTTPS']) && (($_SERVER['HTTPS'] !== 'off') || ($port == 443)));
- $server_path = $_SERVER['SERVER_NAME'];
- $my_path = dirname(dirname($_SERVER['SCRIPT_NAME'])).'/xsd/GetLangs.php';
- $server_path .= trim((($https && ($port != 443)) || (!$https && ($port != 80))) ? ':'.$port : '', '/');
- $xsd_uri = 'http'.($https ? 's' : '').'://'.$server_path.$my_path;
-
- echo "";
-
- foreach ($langs as $key_string => $name_string) {
- echo 'GetLocalLang())) {
- echo ' default="1"';
- }
- echo '>';
- echo htmlspecialchars($name_string);
- echo '';
- }
-
- echo "";
- ob_end_flush();
- } else {
- echo ( 'No Languages' );
- }
-} else {
- echo ( 'No Server' );
-}
diff --git a/src/legacy/client_interface/xml/GetServiceBodies.php b/src/legacy/client_interface/xml/GetServiceBodies.php
deleted file mode 100755
index 34323a019..000000000
--- a/src/legacy/client_interface/xml/GetServiceBodies.php
+++ /dev/null
@@ -1,31 +0,0 @@
-/client_interface/json/
- with the same parameters that you would send to an advanced search. The results
- will be returned as an XML file.
-
- This file can be called from other servers.
-
- This file is part of the Basic Meeting List Toolbox (BMLT).
-
- Find out more at: https://bmlt.app
-
- BMLT is free software: you can redistribute it and/or modify
- it under the terms of the MIT License.
-
- BMLT is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- MIT License for more details.
-
- You should have received a copy of the MIT License along with this code.
- If not, see .
-*/
-
-defined('BMLT_EXEC') or define('BMLT_EXEC', true); // This is a security verifier. Keeps files from being executed outside of the context
-$_GET['switcher'] = 'GetServiceBodies';
-require_once(dirname(__FILE__).'/index.php');
diff --git a/src/legacy/client_interface/xml/index.php b/src/legacy/client_interface/xml/index.php
deleted file mode 100755
index e83934659..000000000
--- a/src/legacy/client_interface/xml/index.php
+++ /dev/null
@@ -1,59 +0,0 @@
-/client_interface/xml/
- with the same parameters that you would send to an advanced search. The results
- will be returned as an XML file.
-
- This file can be called from other servers.
-
- This file is part of the Basic Meeting List Toolbox (BMLT).
-
- Find out more at: https://bmlt.app
-
- BMLT is free software: you can redistribute it and/or modify
- it under the terms of the MIT License.
-
- BMLT is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- MIT License for more details.
-
- You should have received a copy of the MIT License along with this code.
- If not, see .
-*/
-
-defined('BMLT_EXEC') or define('BMLT_EXEC', true); // This is a security verifier. Keeps files from being executed outside of the context
-require_once(dirname(__FILE__).'/../csv/csv.php');
-
-try {
- $server = c_comdef_server::MakeServer();
- $ret = null;
-
- if ($server instanceof c_comdef_server) {
- $_GET['xml_data'] = true;
- $ret = parse_redirect($server);
- // The caller can request compression. Not all clients can deal with compressed replies.
- if (isset($_GET['compress_output']) || isset($_POST['compress_output'])) {
- if (zlib_get_coding_type() === false) {
- ob_start("ob_gzhandler");
- } else {
- header('Content-Type:application/xml; charset=UTF-8');
- ob_start();
- }
- } else {
- header('Content-Type:application/xml; charset=UTF-8');
- ob_start();
- }
-
- echo $ret;
- ob_end_flush();
- } else {
- echo HandleNoServer();
- }
-} catch (Exception $e) {
- echo HandleNoServer();
-}
diff --git a/src/legacy/client_interface/xsd/AdminPermissions.php b/src/legacy/client_interface/xsd/AdminPermissions.php
deleted file mode 100644
index e53371ab6..000000000
--- a/src/legacy/client_interface/xsd/AdminPermissions.php
+++ /dev/null
@@ -1,52 +0,0 @@
-.
-********************************************************************************************/
-
-// The caller can request compression. Not all clients can deal with compressed replies.
-if (isset($_GET['compress_xml']) || isset($_POST['compress_xml'])) {
- if (zlib_get_coding_type() === false) {
- ob_start("ob_gzhandler");
- } else {
- header('Content-Type:application/xml; charset=UTF-8');
- ob_start();
- }
-} else {
- header('Content-Type:application/xml; charset=UTF-8');
- ob_start();
-}
-echo "<"."?xml version=\"1.0\" encoding=\"UTF-8\"?".">\n"; ?>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/legacy/client_interface/xsd/ChangeResponse.php b/src/legacy/client_interface/xsd/ChangeResponse.php
deleted file mode 100755
index c19a9bc8c..000000000
--- a/src/legacy/client_interface/xsd/ChangeResponse.php
+++ /dev/null
@@ -1,75 +0,0 @@
-.
-********************************************************************************************/
-
-// The caller can request compression. Not all clients can deal with compressed replies.
-if (isset($_GET['compress_xml']) || isset($_POST['compress_xml'])) {
- if (zlib_get_coding_type() === false) {
- ob_start("ob_gzhandler");
- } else {
- header('Content-Type:application/xml; charset=UTF-8');
- ob_start();
- }
-} else {
- header('Content-Type:application/xml; charset=UTF-8');
- ob_start();
-}
-echo "<"."?xml version=\"1.0\" encoding=\"UTF-8\"?".">\n"; ?>
-' elementFormDefault='qualified' targetNamespace='http://'>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/legacy/client_interface/xsd/DeletedMeeting.php b/src/legacy/client_interface/xsd/DeletedMeeting.php
deleted file mode 100755
index 07d01e833..000000000
--- a/src/legacy/client_interface/xsd/DeletedMeeting.php
+++ /dev/null
@@ -1,53 +0,0 @@
-.
-********************************************************************************************/
-
-// The caller can request compression. Not all clients can deal with compressed replies.
-if (isset($_GET['compress_xml']) || isset($_POST['compress_xml'])) {
- if (zlib_get_coding_type() === false) {
- ob_start("ob_gzhandler");
- } else {
- header('Content-Type:application/xml; charset=UTF-8');
- ob_start();
- }
-} else {
- header('Content-Type:application/xml; charset=UTF-8');
- ob_start();
-}
-echo "<"."?xml version=\"1.0\" encoding=\"UTF-8\"?".">\n"; ?>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/legacy/client_interface/xsd/FieldTemplates.php b/src/legacy/client_interface/xsd/FieldTemplates.php
deleted file mode 100755
index 5c8680560..000000000
--- a/src/legacy/client_interface/xsd/FieldTemplates.php
+++ /dev/null
@@ -1,63 +0,0 @@
-.
-********************************************************************************************/
-
-// The caller can request compression. Not all clients can deal with compressed replies.
-if (isset($_GET['compress_xml']) || isset($_POST['compress_xml'])) {
- if (zlib_get_coding_type() === false) {
- ob_start("ob_gzhandler");
- } else {
- header('Content-Type:application/xml; charset=UTF-8');
- ob_start();
- }
-} else {
- header('Content-Type:application/xml; charset=UTF-8');
- ob_start();
-}
-echo "\n"; ?>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/legacy/client_interface/xsd/GetChanges.php b/src/legacy/client_interface/xsd/GetChanges.php
deleted file mode 100755
index b22c124fd..000000000
--- a/src/legacy/client_interface/xsd/GetChanges.php
+++ /dev/null
@@ -1,73 +0,0 @@
-.
-********************************************************************************************/
-
-// The caller can request compression. Not all clients can deal with compressed replies.
-if (isset($_GET['compress_xml']) || isset($_POST['compress_xml'])) {
- if (zlib_get_coding_type() === false) {
- ob_start("ob_gzhandler");
- } else {
- header('Content-Type:application/xml; charset=UTF-8');
- ob_start();
- }
-} else {
- header('Content-Type:application/xml; charset=UTF-8');
- ob_start();
-}
-echo "<"."?xml version=\"1.0\" encoding=\"UTF-8\"?".">\n"; ?>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/legacy/client_interface/xsd/GetCoverageArea.php b/src/legacy/client_interface/xsd/GetCoverageArea.php
deleted file mode 100755
index caee5a752..000000000
--- a/src/legacy/client_interface/xsd/GetCoverageArea.php
+++ /dev/null
@@ -1,57 +0,0 @@
-.
-********************************************************************************************/
-
-// The caller can request compression. Not all clients can deal with compressed replies.
-if (isset($_GET['compress_xml']) || isset($_POST['compress_xml'])) {
- if (zlib_get_coding_type() === false) {
- ob_start("ob_gzhandler");
- } else {
- header('Content-Type:application/xml; charset=UTF-8');
- ob_start();
- }
-} else {
- header('Content-Type:application/xml; charset=UTF-8');
- ob_start();
-}
-echo "\n"; ?>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/legacy/client_interface/xsd/GetDeletedMeetings.php b/src/legacy/client_interface/xsd/GetDeletedMeetings.php
deleted file mode 100755
index 2d1ec419a..000000000
--- a/src/legacy/client_interface/xsd/GetDeletedMeetings.php
+++ /dev/null
@@ -1,68 +0,0 @@
-.
-********************************************************************************************/
-
-// The caller can request compression. Not all clients can deal with compressed replies.
-if (isset($_GET['compress_xml']) || isset($_POST['compress_xml'])) {
- if (zlib_get_coding_type() === false) {
- ob_start("ob_gzhandler");
- } else {
- header('Content-Type:application/xml; charset=UTF-8');
- ob_start();
- }
-} else {
- header('Content-Type:application/xml; charset=UTF-8');
- ob_start();
-}
-echo "<"."?xml version=\"1.0\" encoding=\"UTF-8\"?".">\n"; ?>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/legacy/client_interface/xsd/GetFieldKeys.php b/src/legacy/client_interface/xsd/GetFieldKeys.php
deleted file mode 100755
index 94b37445f..000000000
--- a/src/legacy/client_interface/xsd/GetFieldKeys.php
+++ /dev/null
@@ -1,55 +0,0 @@
-.
-********************************************************************************************/
-
-// The caller can request compression. Not all clients can deal with compressed replies.
-if (isset($_GET['compress_xml']) || isset($_POST['compress_xml'])) {
- if (zlib_get_coding_type() === false) {
- ob_start("ob_gzhandler");
- } else {
- header('Content-Type:application/xml; charset=UTF-8');
- ob_start();
- }
-} else {
- header('Content-Type:application/xml; charset=UTF-8');
- ob_start();
-}
-echo "\n"; ?>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/legacy/client_interface/xsd/GetFieldValues.php b/src/legacy/client_interface/xsd/GetFieldValues.php
deleted file mode 100755
index adc1c518d..000000000
--- a/src/legacy/client_interface/xsd/GetFieldValues.php
+++ /dev/null
@@ -1,55 +0,0 @@
-.
-********************************************************************************************/
-
-// The caller can request compression. Not all clients can deal with compressed replies.
-if (isset($_GET['compress_xml']) || isset($_POST['compress_xml'])) {
- if (zlib_get_coding_type() === false) {
- ob_start("ob_gzhandler");
- } else {
- header('Content-Type:application/xml; charset=UTF-8');
- ob_start();
- }
-} else {
- header('Content-Type:application/xml; charset=UTF-8');
- ob_start();
-}
-echo "\n"; ?>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/legacy/client_interface/xsd/GetFormats.php b/src/legacy/client_interface/xsd/GetFormats.php
deleted file mode 100755
index 3ee303472..000000000
--- a/src/legacy/client_interface/xsd/GetFormats.php
+++ /dev/null
@@ -1,62 +0,0 @@
-.
-********************************************************************************************/
-
-// The caller can request compression. Not all clients can deal with compressed replies.
-if (isset($_GET['compress_xml']) || isset($_POST['compress_xml'])) {
- if (zlib_get_coding_type() === false) {
- ob_start("ob_gzhandler");
- } else {
- header('Content-Type:application/xml; charset=UTF-8');
- ob_start();
- }
-} else {
- header('Content-Type:application/xml; charset=UTF-8');
- ob_start();
-}
-echo "\n"; ?>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/legacy/client_interface/xsd/GetLangs.php b/src/legacy/client_interface/xsd/GetLangs.php
deleted file mode 100755
index 6a371575e..000000000
--- a/src/legacy/client_interface/xsd/GetLangs.php
+++ /dev/null
@@ -1,55 +0,0 @@
-.
-********************************************************************************************/
-
-// The caller can request compression. Not all clients can deal with compressed replies.
-if (isset($_GET['compress_xml']) || isset($_POST['compress_xml'])) {
- if (zlib_get_coding_type() === false) {
- ob_start("ob_gzhandler");
- } else {
- header('Content-Type:application/xml; charset=UTF-8');
- ob_start();
- }
-} else {
- header('Content-Type:application/xml; charset=UTF-8');
- ob_start();
-}
-echo "<"."?xml version=\"1.0\" encoding=\"UTF-8\"?".">\n"; ?>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/legacy/client_interface/xsd/GetMeetingLocationInfo.php b/src/legacy/client_interface/xsd/GetMeetingLocationInfo.php
deleted file mode 100755
index 6d05f8667..000000000
--- a/src/legacy/client_interface/xsd/GetMeetingLocationInfo.php
+++ /dev/null
@@ -1,84 +0,0 @@
-.
-********************************************************************************************/
-
-// The caller can request compression. Not all clients can deal with compressed replies.
-if (isset($_GET['compress_xml']) || isset($_POST['compress_xml'])) {
- if (zlib_get_coding_type() === false) {
- ob_start("ob_gzhandler");
- } else {
- header('Content-Type:application/xml; charset=UTF-8');
- ob_start();
- }
-} else {
- header('Content-Type:application/xml; charset=UTF-8');
- ob_start();
-}
-echo "\n"; ?>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/legacy/client_interface/xsd/GetSearchResults.php b/src/legacy/client_interface/xsd/GetSearchResults.php
deleted file mode 100755
index 628aa6976..000000000
--- a/src/legacy/client_interface/xsd/GetSearchResults.php
+++ /dev/null
@@ -1,160 +0,0 @@
-.
-********************************************************************************************/
-
-defined('BMLT_EXEC') or define('BMLT_EXEC', true); // This is a security verifier. Keeps files from being executed outside of the context
-$file_dir = str_replace('/client_interface/xsd', '', dirname(__FILE__)).'/server/c_comdef_server.class.php';
-require_once($file_dir);
-$server = c_comdef_server::MakeServer();
-$ret = null;
-
-if ($server instanceof c_comdef_server) {
- // The caller can request compression. Not all clients can deal with compressed replies.
- if (isset($_GET['compress_xml']) || isset($_POST['compress_xml'])) {
- if (zlib_get_coding_type() === false) {
- ob_start("ob_gzhandler");
- } else {
- header('Content-Type:application/xml; charset=UTF-8');
- ob_start();
- }
- } else {
- header('Content-Type:application/xml; charset=UTF-8');
- ob_start();
- }
- echo "\n"; ?>
-
-
-
-
-
-
-
- \n";
- }
- ?>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/legacy/client_interface/xsd/GetServiceBodies.php b/src/legacy/client_interface/xsd/GetServiceBodies.php
deleted file mode 100755
index db2a5197c..000000000
--- a/src/legacy/client_interface/xsd/GetServiceBodies.php
+++ /dev/null
@@ -1,62 +0,0 @@
-.
-********************************************************************************************/
-
-// The caller can request compression. Not all clients can deal with compressed replies.
-if (isset($_GET['compress_xml']) || isset($_POST['compress_xml'])) {
- if (zlib_get_coding_type() === false) {
- ob_start("ob_gzhandler");
- } else {
- header('Content-Type:application/xml; charset=UTF-8');
- ob_start();
- }
-} else {
- header('Content-Type:application/xml; charset=UTF-8');
- ob_start();
-}
-echo "\n"; ?>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/legacy/client_interface/xsd/HierServiceBodies.php b/src/legacy/client_interface/xsd/HierServiceBodies.php
deleted file mode 100644
index 5e187707f..000000000
--- a/src/legacy/client_interface/xsd/HierServiceBodies.php
+++ /dev/null
@@ -1,146 +0,0 @@
-.
-********************************************************************************************/
-
-// The caller can request compression. Not all clients can deal with compressed replies.
-if (isset($_GET['compress_xml']) || isset($_POST['compress_xml'])) {
- if (zlib_get_coding_type() === false) {
- ob_start("ob_gzhandler");
- } else {
- header('Content-Type:application/xml; charset=UTF-8');
- ob_start();
- }
-} else {
- header('Content-Type:application/xml; charset=UTF-8');
- ob_start();
-}
-echo "<"."?xml version=\"1.0\" encoding=\"UTF-8\"?".">\n"; ?>
-' elementFormDefault='qualified' targetNamespace='http://'>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/legacy/client_interface/xsd/RestoreDeletedMeeting.php b/src/legacy/client_interface/xsd/RestoreDeletedMeeting.php
deleted file mode 100755
index 6da4d5fef..000000000
--- a/src/legacy/client_interface/xsd/RestoreDeletedMeeting.php
+++ /dev/null
@@ -1,61 +0,0 @@
-.
-********************************************************************************************/
-
-// The caller can request compression. Not all clients can deal with compressed replies.
-if (isset($_GET['compress_xml']) || isset($_POST['compress_xml'])) {
- if (zlib_get_coding_type() === false) {
- ob_start("ob_gzhandler");
- } else {
- header('Content-Type:application/xml; charset=UTF-8');
- ob_start();
- }
-} else {
- header('Content-Type:application/xml; charset=UTF-8');
- ob_start();
-}
-echo "<"."?xml version=\"1.0\" encoding=\"UTF-8\"?".">\n"; ?>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/legacy/client_interface/xsd/ServerInfo.php b/src/legacy/client_interface/xsd/ServerInfo.php
deleted file mode 100755
index f55903517..000000000
--- a/src/legacy/client_interface/xsd/ServerInfo.php
+++ /dev/null
@@ -1,74 +0,0 @@
-.
-********************************************************************************************/
-
-// The caller can request compression. Not all clients can deal with compressed replies.
-if (isset($_GET['compress_xml']) || isset($_POST['compress_xml'])) {
- if (zlib_get_coding_type() === false) {
- ob_start("ob_gzhandler");
- } else {
- header('Content-Type:application/xml; charset=UTF-8');
- ob_start();
- }
-} else {
- header('Content-Type:application/xml; charset=UTF-8');
- ob_start();
-}
-echo "<"."?xml version=\"1.0\" encoding=\"UTF-8\"?".">\n"; ?>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/legacy/client_interface/xsd/UserInfo.php b/src/legacy/client_interface/xsd/UserInfo.php
deleted file mode 100644
index 5e45b5509..000000000
--- a/src/legacy/client_interface/xsd/UserInfo.php
+++ /dev/null
@@ -1,52 +0,0 @@
-.
-********************************************************************************************/
-
-// The caller can request compression. Not all clients can deal with compressed replies.
-if (isset($_GET['compress_xml']) || isset($_POST['compress_xml'])) {
- if (zlib_get_coding_type() === false) {
- ob_start("ob_gzhandler");
- } else {
- header('Content-Type:application/xml; charset=UTF-8');
- ob_start();
- }
-} else {
- header('Content-Type:application/xml; charset=UTF-8');
- ob_start();
-}
-echo "<"."?xml version=\"1.0\" encoding=\"UTF-8\"?".">\n"; ?>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/legacy/client_interface/xsd/index.htm b/src/legacy/client_interface/xsd/index.htm
deleted file mode 100755
index e69de29bb..000000000
diff --git a/src/legacy/index.php b/src/legacy/index.php
deleted file mode 100755
index 88450484e..000000000
--- a/src/legacy/index.php
+++ /dev/null
@@ -1,22 +0,0 @@
-.
-*/
-ob_start();
-define('__DEBUG_MODE__', 1); // Uncomment to make the CSS and JavaScript easier to trace (and less efficient).
-defined('BMLT_EXEC') or define('BMLT_EXEC', 1);
-include(dirname(__FILE__).'/local_server/index.php');
-ob_end_flush();
diff --git a/src/legacy/local_server/bmlt.js b/src/legacy/local_server/bmlt.js
deleted file mode 100644
index 20c91c7f6..000000000
--- a/src/legacy/local_server/bmlt.js
+++ /dev/null
@@ -1,122 +0,0 @@
-var bmltbaseURL;
-var recurseServiceBodies;
-
-var bmltClientInit = function (host, recurse) {
- this.bmltbaseURL = host + "/client_interface/jsonp/?switcher=";
- this.recurseServiceBodies = recurse == null ? false : recurse;
-};
-
-var getDayOfWeek = function (dayint) {
- return ["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"][dayint];
-};
-
-var getTodayDayOfWeek = function () {
- return (new Date()).getDay() + 1;
-};
-
-var militaryToStandard = function (value) {
- if (value !== null && value !== undefined) { //If value is passed in
- if (value.indexOf('AM') > -1 || value.indexOf('PM') > -1) { //If time is already in standard time then don't format.
- return value;
- } else {
- if (value.length === 8) { //If value is the expected length for military time then process to standard time.
- var valueconv = value.split(':'); // convert to array
- // fetch
- var hours = Number(valueconv[0]);
-
- // calculate
- var timeValue;
- if (hours > 0 && hours <= 12) { // If hour is less than or equal to 12 then convert to standard 12 hour format
- timeValue= "" + hours;
- } else if (hours > 12) { //If hour is greater than 12 then convert to standard 12 hour format
- timeValue= "" + (hours - 12);
- } else if (hours === 0) { //If hour is 0 then set to 12 for standard time 12 AM
- timeValue= "12";
- }
-
- timeValue += ":" + valueconv[1]; // get minutes
- timeValue += (hours >= 12) ? " PM" : " AM"; // get AM/PM
- // show
- return timeValue;
- } else { //If value is not the expected length than just return the value as is
- return valueconv;
- }
- }
- }
-};
-
-var getMeetingsByCity = function (city, callback) {
- getJSON(bmltbaseURL + "GetSearchResults&meeting_key=location_municipality&meeting_key_value=" + city + "&callback=?", callback);
-};
-
-var getMeetingsByServiceBodyId = function (serviceBodyId, callback) {
- getJSON(bmltbaseURL + "GetSearchResults" + getServiceBodyIdQueryString(serviceBodyId) + "&callback=?", callback);
-};
-
-var getMeetingsByServiceBodyIdAndWeekdayId = function (serviceBodyId, weekdayId, callback) {
- getJSON(bmltbaseURL + "GetSearchResults" + getServiceBodyIdQueryString(serviceBodyId) + "&weekdays=" + weekdayId + "&callback=?", callback);
-};
-
-var getMeetingsByServiceBodyIdAndCity = function (serviceBodyId, city, callback) {
- getJSON(bmltbaseURL + "GetSearchResults" + getServiceBodyIdQueryString(serviceBodyId) + "&meeting_key=location_municipality&meeting_key_value=" + city + "&callback=?", callback);
-};
-
-var getMeetingsByLocation = function (day, geoWidth, position, callback) {
- getJSON(bmltbaseURL + "GetSearchResults&weekdays=" + day + "&geo_width=" + geoWidth + "&long_val=" + position.longitude + "&lat_val=" + position.latitude + "&callback=?", callback);
-};
-
-var getFormats = function (callback) {
- getJSON(bmltbaseURL + "GetFormats&callback=?", callback);
-};
-
-var getUniqueValuesByServiceBody = function (serviceBodyId, field, callback) {
- getMeetingsByServiceBodyId(serviceBodyId, function (data) {
- var valuesArray = [];
- for (i = 0; i < data.length; i++) {
- valuesArray.push(data[i][field]);
- }
-
- callback(valuesArray.unique())
- });
-};
-
-var getServiceBodyIdQueryString = function (serviceBodyIds) {
- var serviceBodyIdString = "";
- if (Array.isArray(serviceBodyIds)) {
- for (var i = 0; i < serviceBodyIds.length; i++) {
- serviceBodyIdString += "&services[]=" + serviceBodyIds[i];
- }
- } else {
- serviceBodyIdString = "&services=" + serviceBodyIds;
- }
-
- return serviceBodyIdString;
-};
-
-var getJSON = function (url, callback) {
- var random = Math.floor(Math.random() * 999999);
- var callbackFunctionName = "cb_" + random;
- if (this.recurseServiceBodies) {
- url += "&recursive=1";
- }
- url = url.replace("callback=?", "callback=" + callbackFunctionName);
-
- window[callbackFunctionName] = function (data) {
- callback(data);
- };
-
- var scriptItem = document.createElement('script');
- scriptItem.setAttribute('src', url);
- document.body.appendChild(scriptItem);
-};
-
-Array.prototype.unique = function () {
- var o = {}, a = [];
- for (var i = 0; i < this.length; i++) {
- o[this[i]] = 1
- for (var e in o) {
- a.push(e)
- return a
- }
- }
-};
diff --git a/src/legacy/local_server/db_connect.php b/src/legacy/local_server/db_connect.php
deleted file mode 100644
index 2cbf26f52..000000000
--- a/src/legacy/local_server/db_connect.php
+++ /dev/null
@@ -1,42 +0,0 @@
-.
-*/
-/**
- \brief This function checks to make sure the database is correct for the current version.
-*/
-function DB_Connect_and_Upgrade()
-{
- global $dbPrefix;
-
- include(dirname(__FILE__)."/../server/config/get-config.php");
-
- if (!isset($dbType)) {
- $dbType = 'mysql';
- }
-
- if (!isset($dbServer)) {
- $dbServer = 'localhost';
- }
-
- if (!isset($dbPrefix)) {
- $dbPrefix = 'na';
- }
-
- c_comdef_dbsingleton::init($dbType, $dbServer, $dbName, $dbUser, $dbPassword, 'utf8');
-
- // Migration code that used to be here was moved to a laravel migration
-}
diff --git a/src/legacy/local_server/index.php b/src/legacy/local_server/index.php
deleted file mode 100755
index 791a9ae8b..000000000
--- a/src/legacy/local_server/index.php
+++ /dev/null
@@ -1,102 +0,0 @@
-.
-*/
-defined('BMLT_EXEC') or die('Cannot Execute Directly'); // Makes sure that this file is in the correct context.
-define('_LANG_COOKIE_NAME', 'bmlt_admin_lang_pref');
-
-global $http_vars;
-$http_vars = array_merge($_GET, $_POST);
-$lang_enum = '';
-
-// We use a cookie to store the language pref.
-$lang_enum = request()->cookie(_LANG_COOKIE_NAME, $lang_enum);
-
-if (isset($http_vars['lang_enum']) && $http_vars['lang_enum']) {
- $lang_enum = $http_vars['lang_enum'];
-}
-
-$http_vars['lang_enum'] = $lang_enum; // Quick and dirty way to ensure that this gets properly propagated.
-
-$file_loc = dirname(__FILE__).'/install_wizard/index.php';
-
-require_once($file_loc); // We test for the install wizard, first.
-
-if (isset($g_enable_language_selector) && $g_enable_language_selector) {
- cookie()->queue(_LANG_COOKIE_NAME, $lang_enum, 60 * 24 * 365);
-}
-
-if (isset($http_vars ['bmlt_ajax_callback'])) {
- require_once(dirname(__FILE__).'/server_admin/c_comdef_admin_ajax_handler.class.php');
-} else {
- ?>
-
-
-
-
-
-
-
-
-
-
-
- Basic Meeting List Toolbox Administration Console
-
-
- GetCurrentUserObj();
- if (($user_obj instanceof c_comdef_user) && ($user_obj->GetUserLevel() != _USER_LEVEL_DEACTIVATED)) {
- echo '
';
- // OK. If they make it in here, it means they are legit, so display the logged-in console.
- require_once(dirname(__FILE__).'/server_admin/main_console.php');
- echo '
';
- }
- } else {
- ?>
-
ERROR: NO SERVER!
-
-
-
-
diff --git a/src/legacy/local_server/install_wizard/auto-config.inc.php.example.txt b/src/legacy/local_server/install_wizard/auto-config.inc.php.example.txt
deleted file mode 100644
index 6ee5106b6..000000000
--- a/src/legacy/local_server/install_wizard/auto-config.inc.php.example.txt
+++ /dev/null
@@ -1,51 +0,0 @@
-'; // This is the name of the database.
- $dbUser = ''; // This is the SQL user that is authorized for the above database.
- $dbPassword = ''; // This is the password for the above authorized user. Make it a big, ugly hairy one. It is powerful, and there is no need to remember it.
- $dbServer = 'localhost'; // This is the host/server for accessing the database.
- $dbPrefix = 'na'; // This is a table name prefix that can be used to differentiate tables used by different root server instances that share the same database.
-
- // Location and Map settings:
- $region_bias = 'us'; // This is a 2-letter code for a 'region bias,' which helps Google Maps to figure out ambiguous search queries.
- $gkey = ''; // This is the Google Maps JavaScript API Key, necessary for using Google Maps.
- $search_spec_map_center = array ( 'longitude' => -118.563659, 'latitude' => 34.235918, 'zoom' => 6 ); // This is the default map location for new meetings.
- $comdef_distance_units = 'mi';
-
- // Display settings:
- $bmlt_title = 'Basic Meeting List Toolbox Administration'; // This is the page title and heading for the main administration login page.
- $banner_text = 'Administration Login'; // This is text that is displayed just above the login box on the main login page.
-
- // Miscellaneous settings:
- $comdef_global_language ='en'; // This is the 2-letter code for the default root server localization (will default to 'en' -English, if the localization is not available).
- $min_pw_len = 10; // The minimum number of characters in a user account password for this root server.
- $number_of_meetings_for_auto = 10; // This is an approximation of the number of meetings to search for in the auto-search feature. The higher the number, the wider the radius.
- $change_depth_for_meetings = 5; // This is how many changes should be recorded for each meeting.
- // The higher the number, the larger the database will grow, as this can become quite substantial.
- $default_duration_time = '1:30:00'; // This is the default duration for meetings that have no duration specified.
- $g_enable_language_selector = FALSE; // Set this to TRUE (or 1) to enable a popup on the login screen that allows the administrator to select their language.
- $g_enable_semantic_admin = FALSE; // If this is TRUE (or 1), then Semantic Administration for this Server is enabled (Administrators can log in using apps).
- $g_defaultClosedStatus = TRUE; // If this is FALSE (or 0), then the default (unspecified) Open/Closed format for meetings reported to NAWS is OPEN. Otherwise, it is CLOSED.
-
- // These reflect the way that we handle contact emails.
- $g_enable_email_contact = FALSE; // If this is TRUE (or 1), then this will enable the ability to contact meeting list contacts via a secure email form.
- $include_service_body_admin_on_emails = FALSE; // If this is TRUE (or 1), then any emails sent using the meeting contact will include the nearest Service Body Admin
- // contact for the meeting Service body (ignored, if $g_enable_email_contact is FALSE).
- $include_every_admin_on_emails = FALSE; // If this is TRUE (or 1), then any emails sent using the meeting contact will include all Service Body Admin contacts
- // (including the Server Administrator) for the meeting.
- // (ignored, if $g_enable_email_contact or $include_service_body_admin_on_emails is FALSE)
-
- // Add any languages for which formats will be given
- // The server languages are supported by default, the langs specified here add to them
- // $format_lang_names = ['fa'=>'Farsi'];
- // These are 'hard-coded,' but can be changed later.
-
- $time_format = 'g:i A'; // The PHP date() format for the times displayed.
- $change_date_format = 'g:i A, n/j/Y'; // The PHP date() format for times/dates displayed in the change records.
- $admin_session_name = 'BMLT_Admin'; // This is merely the 'tag' used to identify the BMLT admin session.
-?>
\ No newline at end of file
diff --git a/src/legacy/local_server/install_wizard/country_names_and_code_elements.txt b/src/legacy/local_server/install_wizard/country_names_and_code_elements.txt
deleted file mode 100644
index 13984676d..000000000
--- a/src/legacy/local_server/install_wizard/country_names_and_code_elements.txt
+++ /dev/null
@@ -1,250 +0,0 @@
-AFGHANISTAN AF
-ÅLAND ISLANDS AX
-ALBANIA AL
-ALGERIA DZ
-AMERICAN SAMOA AS
-ANDORRA AD
-ANGOLA AO
-ANGUILLA AI
-ANTARCTICA AQ
-ANTIGUA AND BARBUDA AG
-ARGENTINA AR
-ARMENIA AM
-ARUBA AW
-AUSTRALIA AU
-AUSTRIA AT
-AZERBAIJAN AZ
-BAHAMAS BS
-BAHRAIN BH
-BANGLADESH BD
-BARBADOS BB
-BELARUS BY
-BELGIUM BE
-BELIZE BZ
-BENIN BJ
-BERMUDA BM
-BHUTAN BT
-BOLIVIA, PLURINATIONAL STATE OF BO
-BONAIRE, SINT EUSTATIUS AND SABA BQ
-BOSNIA AND HERZEGOVINA BA
-BOTSWANA BW
-BOUVET ISLAND BV
-BRAZIL BR
-BRITISH INDIAN OCEAN TERRITORY IO
-BRUNEI DARUSSALAM BN
-BULGARIA BG
-BURKINA FASO BF
-BURUNDI BI
-CAMBODIA KH
-CAMEROON CM
-CANADA CA
-CAPE VERDE CV
-CAYMAN ISLANDS KY
-CENTRAL AFRICAN REPUBLIC CF
-CHAD TD
-CHILE CL
-CHINA CN
-CHRISTMAS ISLAND CX
-COCOS (KEELING) ISLANDS CC
-COLOMBIA CO
-COMOROS KM
-CONGO CG
-CONGO, THE DEMOCRATIC REPUBLIC OF THE CD
-COOK ISLANDS CK
-COSTA RICA CR
-CÔTE D'IVOIRE CI
-CROATIA HR
-CUBA CU
-CURAÇAO CW
-CYPRUS CY
-CZECH REPUBLIC CZ
-DENMARK DK
-DJIBOUTI DJ
-DOMINICA DM
-DOMINICAN REPUBLIC DO
-ECUADOR EC
-EGYPT EG
-EL SALVADOR SV
-EQUATORIAL GUINEA GQ
-ERITREA ER
-ESTONIA EE
-ETHIOPIA ET
-FALKLAND ISLANDS (MALVINAS) FK
-FAROE ISLANDS FO
-FIJI FJ
-FINLAND FI
-FRANCE FR
-FRENCH GUIANA GF
-FRENCH POLYNESIA PF
-FRENCH SOUTHERN TERRITORIES TF
-GABON GA
-GAMBIA GM
-GEORGIA GE
-GERMANY DE
-GHANA GH
-GIBRALTAR GI
-GREECE GR
-GREENLAND GL
-GRENADA GD
-GUADELOUPE GP
-GUAM GU
-GUATEMALA GT
-GUERNSEY GG
-GUINEA GN
-GUINEA-BISSAU GW
-GUYANA GY
-HAITI HT
-HEARD ISLAND AND MCDONALD ISLANDS HM
-HOLY SEE (VATICAN CITY STATE) VA
-HONDURAS HN
-HONG KONG HK
-HUNGARY HU
-ICELAND IS
-INDIA IN
-INDONESIA ID
-IRAN, ISLAMIC REPUBLIC OF IR
-IRAQ IQ
-IRELAND IE
-ISLE OF MAN IM
-ISRAEL IL
-ITALY IT
-JAMAICA JM
-JAPAN JP
-JERSEY JE
-JORDAN JO
-KAZAKHSTAN KZ
-KENYA KE
-KIRIBATI KI
-KOREA, DEMOCRATIC PEOPLE'S REPUBLIC OF KP
-KOREA, REPUBLIC OF KR
-KUWAIT KW
-KYRGYZSTAN KG
-LAO PEOPLE'S DEMOCRATIC REPUBLIC LA
-LATVIA LV
-LEBANON LB
-LESOTHO LS
-LIBERIA LR
-LIBYA LY
-LIECHTENSTEIN LI
-LITHUANIA LT
-LUXEMBOURG LU
-MACAO MO
-MACEDONIA, THE FORMER YUGOSLAV REPUBLIC OF MK
-MADAGASCAR MG
-MALAWI MW
-MALAYSIA MY
-MALDIVES MV
-MALI ML
-MALTA MT
-MARSHALL ISLANDS MH
-MARTINIQUE MQ
-MAURITANIA MR
-MAURITIUS MU
-MAYOTTE YT
-MEXICO MX
-MICRONESIA, FEDERATED STATES OF FM
-MOLDOVA, REPUBLIC OF MD
-MONACO MC
-MONGOLIA MN
-MONTENEGRO ME
-MONTSERRAT MS
-MOROCCO MA
-MOZAMBIQUE MZ
-MYANMAR MM
-NAMIBIA NA
-NAURU NR
-NEPAL NP
-NETHERLANDS NL
-NEW CALEDONIA NC
-NEW ZEALAND NZ
-NICARAGUA NI
-NIGER NE
-NIGERIA NG
-NIUE NU
-NORFOLK ISLAND NF
-NORTHERN MARIANA ISLANDS MP
-NORWAY NO
-OMAN OM
-PAKISTAN PK
-PALAU PW
-PALESTINE, STATE OF PS
-PANAMA PA
-PAPUA NEW GUINEA PG
-PARAGUAY PY
-PERU PE
-PHILIPPINES PH
-PITCAIRN PN
-POLAND PL
-PORTUGAL PT
-PUERTO RICO PR
-QATAR QA
-RÉUNION RE
-ROMANIA RO
-RUSSIAN FEDERATION RU
-RWANDA RW
-SAINT BARTHÉLEMY BL
-SAINT HELENA, ASCENSION AND TRISTAN DA CUNHA SH
-SAINT KITTS AND NEVIS KN
-SAINT LUCIA LC
-SAINT MARTIN (FRENCH PART) MF
-SAINT PIERRE AND MIQUELON PM
-SAINT VINCENT AND THE GRENADINES VC
-SAMOA WS
-SAN MARINO SM
-SAO TOME AND PRINCIPE ST
-SAUDI ARABIA SA
-SENEGAL SN
-SERBIA RS
-SEYCHELLES SC
-SIERRA LEONE SL
-SINGAPORE SG
-SINT MAARTEN (DUTCH PART) SX
-SLOVAKIA SK
-SLOVENIA SI
-SOLOMON ISLANDS SB
-SOMALIA SO
-SOUTH AFRICA ZA
-SOUTH GEORGIA AND THE SOUTH SANDWICH ISLANDS GS
-SOUTH SUDAN SS
-SPAIN ES
-SRI LANKA LK
-SUDAN SD
-SURINAME SR
-SVALBARD AND JAN MAYEN SJ
-SWAZILAND SZ
-SWEDEN SE
-SWITZERLAND CH
-SYRIAN ARAB REPUBLIC SY
-TAIWAN, PROVINCE OF CHINA TW
-TAJIKISTAN TJ
-TANZANIA, UNITED REPUBLIC OF TZ
-THAILAND TH
-TIMOR-LESTE TL
-TOGO TG
-TOKELAU TK
-TONGA TO
-TRINIDAD AND TOBAGO TT
-TUNISIA TN
-TURKEY TR
-TURKMENISTAN TM
-TURKS AND CAICOS ISLANDS TC
-TUVALU TV
-UGANDA UG
-UKRAINE UA
-UNITED ARAB EMIRATES AE
-UNITED KINGDOM GB
-UNITED STATES US
-UNITED STATES MINOR OUTLYING ISLANDS UM
-URUGUAY UY
-UZBEKISTAN UZ
-VANUATU VU
-VENEZUELA, BOLIVARIAN REPUBLIC OF VE
-VIET NAM VN
-VIRGIN ISLANDS, BRITISH VG
-VIRGIN ISLANDS, U.S. VI
-WALLIS AND FUTUNA WF
-WESTERN SAHARA EH
-YEMEN YE
-ZAMBIA ZM
-ZIMBABWE ZW
-
diff --git a/src/legacy/local_server/install_wizard/index.php b/src/legacy/local_server/install_wizard/index.php
deleted file mode 100644
index 615d238b2..000000000
--- a/src/legacy/local_server/install_wizard/index.php
+++ /dev/null
@@ -1,67 +0,0 @@
-.
-*/
-defined('BMLT_EXEC') or die('Cannot Execute Directly'); // Makes sure that this file is in the correct context.
-
-$config_file_path = dirname(dirname(dirname(__FILE__))).'/server/config/get-config.php';
-
-if (file_exists($config_file_path)) {
- require_once($config_file_path);
-} else {
- die('The Config File Is Missing!');
-}
-
-// These are defaults for some of the newer fields.
-if (!isset($region_bias) || (null === $region_bias)) {
- $region_bias = 'us';
-}
-
-if (!isset($banner_text) || (null === $banner_text)) {
- $banner_text = '';
-}
-
-if (!isset($comdef_global_language) || !$comdef_global_language) {
- $comdef_global_language = 'en';
-}
-
-// We only invoke the wizard if the configuration has not been done.
-if (!(
- isset($dbType) && $dbType
- && isset($dbName) && $dbName
- && isset($dbServer) && $dbServer
- && isset($dbUser) && $dbUser
- && isset($dbPassword) && $dbPassword
- && isset($dbPrefix) && $dbPrefix
- && isset($bmlt_title) && $bmlt_title
- && isset($min_pw_len) && $min_pw_len
- && isset($search_spec_map_center) && is_array($search_spec_map_center) && count($search_spec_map_center)
- && isset($number_of_meetings_for_auto) && $number_of_meetings_for_auto
- && isset($time_format) && $time_format
- && isset($change_date_format) && $change_date_format
- && isset($change_depth_for_meetings) && $change_depth_for_meetings
- && isset($admin_session_name)
- && isset($comdef_distance_units) && $comdef_distance_units
- )
- ) {
- if (isset($http_vars['lang_enum']) && $http_vars['lang_enum']) {
- $lang = $http_vars['lang_enum'];
- } else {
- $lang = isset($comdef_global_language) && $comdef_global_language ? $comdef_global_language : 'en';
- }
-
- require_once(dirname(__FILE__).'/installer.php');
-}
diff --git a/src/legacy/local_server/install_wizard/installer.js b/src/legacy/local_server/install_wizard/installer.js
deleted file mode 100644
index 44b4e4870..000000000
--- a/src/legacy/local_server/install_wizard/installer.js
+++ /dev/null
@@ -1,924 +0,0 @@
-/*
- This file is part of the Basic Meeting List Toolbox (BMLT).
-
- Find out more at: https://bmlt.app
-
- BMLT is free software: you can redistribute it and/or modify
- it under the terms of the MIT License.
-
- BMLT is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- MIT License for more details.
-
- You should have received a copy of the MIT License along with this code.
- If not, see .
-*/
-function BMLTInstaller( in_prefs ///< A JSON object with the initial prefs.
- )
-{
- var m_installer_wrapper_object;
- var m_map_object;
- var m_map_center;
- var m_installer_state;
- var m_ajax_uri;
- var m_ajax_request_in_progress;
- var m_google_api_key = "";
- var m_google_maps_script = null;
- var m_google_api_key_is_good = false;
- var m_database_credentials_are_good = false;
- var m_server_admin_password_is_good = false;
-
- // #mark -
- // #mark Page Selection Handlers
- // #mark -
-
- /************************************************************************************//**
- * \brief Shows Page 1 of the installer wizard. It does this by setting the wrapper *
- * className to the first page, which uses CSS to hide the other two pages. *
- ****************************************************************************************/
- this.selectPage1 = function () {
- if ( this.m_installer_wrapper_object.className != 'page_1_wrapper' ) {
- this.m_installer_wrapper_object.className = 'page_1_wrapper';
- };
- };
-
- /************************************************************************************//**
- * \brief Shows Page 2 of the installer wizard. It does this by setting the wrapper *
- * className to the first page, which uses CSS to hide the other two pages. *
- ****************************************************************************************/
- this.selectPage2 = function () {
- if ( this.m_installer_wrapper_object.className != 'page_2_wrapper' ) {
- this.m_installer_wrapper_object.className = 'page_2_wrapper';
- };
- };
-
- /************************************************************************************//**
- * \brief Shows Page 3 of the installer wizard. It does this by setting the wrapper *
- * className to the first page, which uses CSS to hide the other two pages. *
- ****************************************************************************************/
- this.selectPage3 = function () {
- if ( this.m_installer_wrapper_object.className != 'page_3_wrapper' ) {
- this.m_installer_wrapper_object.className = 'page_3_wrapper';
- this.testForDatabaseSetup();
- };
- };
-
- /************************************************************************************//**
- * \brief Shows Page 4 of the installer wizard. It does this by setting the wrapper *
- * className to the first page, which uses CSS to hide the other two pages. *
- ****************************************************************************************/
- this.selectPage4 = function () {
- if ( this.m_installer_wrapper_object.className != 'page_4_wrapper' ) {
- this.m_installer_wrapper_object.className = 'page_4_wrapper';
- document.getElementById('database_install_stuff_div').className = 'item_hidden';
- document.getElementById('file_text_pre').innerHTML = this.createFileData();
- var apiKeyWarningDiv = document.getElementById('admin_google_api_key_warning');
- var testForDatabaseSetup = this.testForDatabaseSetup;
- if (apiKeyWarningDiv) {
- this.testMapsApiKey(function (message) {
- if (message) {
- apiKeyWarningDiv.innerHTML = g_maps_api_key_warning + ' ' + message + ' ' + g_maps_api_key_click_here + '';
- this.m_google_api_key_is_good = false;
- } else {
- apiKeyWarningDiv.innerHTML = '';
- this.m_google_api_key_is_good = true;
- }
- testForDatabaseSetup.call(g_installer_object);
- });
- }
- }
- };
-
- // #mark -
- // #mark Text Item Handlers
- // #mark -
-
- /************************************************************************************//**
- * \brief When a text input (either or
';
-
- return $ret;
-}
-
-/*******************************************************************/
-/** \brief Creates the select element for the Server default language.
-
- \returns a string, containing the select element HTML.
-*/
-function bmlt_create_lang_select()
-{
- $ret = '';
-
- $basedir = dirname(dirname(__FILE__)).'/server_admin/lang/';
-
- $ret .= '';
-
- return $ret;
-}
-
-/*******************************************************************/
-/** \brief This is a callback to sort the server languages.
- The default server language will always be first, and
- the rest will be sorted alphabetically.
- \returns an integer. -1 if goes before b, 1 if otherwise, 0 if neither.
-*/
-function ServerLangSortCallback(
- $in_lang_a,
- $in_lang_b
-) {
- global $default_lang;
-
- $ret = 0;
-
- if ($in_lang_a == $default_lang) {
- $ret = -1;
- } elseif ($in_lang_b == $default_lang) {
- $ret = 1;
- } else {
- $ret = strncasecmp($in_lang_a, $in_lang_b, strlen($in_lang_a));
- }
-
- return $ret;
-}
-
-/*******************************************************************/
-/** \brief Creates the select element for the Region bias.
-
- \returns a string, containing the select element HTML.
-*/
-function bmlt_create_region_bias_select()
-{
- global $prefs_array;
- $ret = '';
-
- $file_path = dirname(__FILE__).'/country_names_and_code_elements.txt';
- $cc_array = explode("\n", file_get_contents($file_path));
-
- $ret .= '';
-
- return $ret;
-}
-
-/*******************************************************************/
-/** \brief Creates the select element for the PDO driver selector.
-
- \returns a string, containing the select element HTML.
-*/
-function bmlt_create_pdo_driver_select()
-{
- global $prefs_array;
- $ret = '';
-
- $ret .= '';
- } else {
- $ret = '
ERROR!
';
- }
-
- return $ret;
-}
-?>
diff --git a/src/legacy/local_server/install_wizard/sql_files/InitialFormatsData-de.sql b/src/legacy/local_server/install_wizard/sql_files/InitialFormatsData-de.sql
deleted file mode 100644
index aff70a025..000000000
--- a/src/legacy/local_server/install_wizard/sql_files/InitialFormatsData-de.sql
+++ /dev/null
@@ -1,55 +0,0 @@
--- TODO: translate strings to German
-INSERT INTO `%%PREFIX%%_comdef_formats` (`shared_id_bigint`, `key_string`, `icon_blob`, `worldid_mixed`, `lang_enum`, `name_string`, `description_string`, `format_type_enum`) VALUES
-(1, 'B', NULL, 'BEG', 'de', 'Beginners', 'This meeting is focused on the needs of new members of NA.', 'FC3'),
-(2, 'BL', NULL, 'LANG', 'de', 'Bi-Lingual', 'This Meeting can be attended by speakers of English and another language.', 'LANG'),
-(3, 'BT', NULL, 'BT', 'de', 'Basic Text', 'This meeting is focused on discussion of the Basic Text of Narcotics Anonymous.', 'FC1'),
-(4, 'C', NULL, 'CLOSED', 'de', 'Closed', 'This meeting is closed to non-addicts. You should attend only if you believe that you may have a problem with substance abuse.', 'O'),
-(5, 'CH', NULL, 'CH', 'de', 'Closed Holidays', 'This meeting gathers in a facility that is usually closed on holidays.', 'FC3'),
-(6, 'CL', NULL, 'CAN', 'de', 'Candlelight', 'This meeting is held by candlelight.', 'FC2'),
-(7, 'CS', NULL, '', 'de', 'Children under Supervision', 'Well-behaved, supervised children are welcome.', 'FC3'),
-(8, 'D', NULL, 'DISC', 'de', 'Discussion', 'This meeting invites participation by all attendees.', 'FC1'),
-(9, 'ES', NULL, 'LANG', 'de', 'Español', 'This meeting is conducted in Spanish.', 'LANG'),
-(10, 'GL', NULL, 'GL', 'de', 'Gay/Lesbian/Transgender', 'This meeting is focused on the needs of gay, lesbian and transgender members of NA.', 'FC3'),
-(11, 'IL', NULL, NULL, 'de', 'Illness', 'This meeting is focused on the needs of NA members with chronic illness.', 'FC1'),
-(12, 'IP', NULL, 'IP', 'de', 'Informational Pamphlet', 'This meeting is focused on discussion of one or more Informational Pamphlets.', 'FC1'),
-(13, 'IW', NULL, 'IW', 'de', 'It Works -How and Why', 'This meeting is focused on discussion of the It Works -How and Why text.', 'FC1'),
-(14, 'JT', NULL, 'JFT', 'de', 'Just for Today', 'This meeting is focused on discussion of the Just For Today text.', 'FC1'),
-(15, 'M', NULL, 'M', 'de', 'Men', 'This meeting is meant to be attended by men only.', 'FC3'),
-(16, 'NC', NULL, 'NC', 'de', 'No Children', 'Please do not bring children to this meeting.', 'FC3'),
-(17, 'O', NULL, 'OPEN', 'de', 'Open', 'This meeting is open to addicts and non-addicts alike. All are welcome.', 'O'),
-(18, 'Pi', NULL, NULL, 'de', 'Pitch', 'This meeting has a format that consists of each person who shares picking the next person.', 'FC1'),
-(19, 'RF', NULL, 'VAR', 'de', 'Rotating Format', 'This meeting has a format that changes for each meeting.', 'FC1'),
-(20, 'Rr', NULL, NULL, 'de', 'Round Robin', 'This meeting has a fixed sharing order (usually a circle.)', 'FC1'),
-(21, 'SC', NULL, NULL, 'de', 'Security Cameras', 'This meeting is held in a facility that has security cameras.', 'FC2'),
-(22, 'SD', NULL, 'S-D', 'de', 'Speaker/Discussion', 'This meeting is lead by a speaker, then opened for participation by attendees.', 'FC1'),
-(23, 'SG', NULL, 'SWG', 'de', 'Step Working Guide', 'This meeting is focused on discussion of the Step Working Guide text.', 'FC1'),
-(24, 'SL', NULL, NULL, 'de', 'ASL', 'This meeting provides an American Sign Language (ASL) interpreter for the deaf.', 'FC2'),
-(26, 'So', NULL, 'SPK', 'de', 'Speaker Only', 'This meeting is a speaker-only meeting. Other attendees do not participate in the discussion.', 'FC1'),
-(27, 'St', NULL, 'STEP', 'de', 'Step', 'This meeting is focused on discussion of the Twelve Steps of NA.', 'FC1'),
-(28, 'Ti', NULL, NULL, 'de', 'Timer', 'This meeting has sharing time limited by a timer.', 'FC1'),
-(29, 'To', NULL, 'TOP', 'de', 'Topic', 'This meeting is based upon a topic chosen by a speaker or by group conscience.', 'FC1'),
-(30, 'Tr', NULL, 'TRAD', 'de', 'Tradition', 'This meeting is focused on discussion of the Twelve Traditions of NA.', 'FC1'),
-(31, 'TW', NULL, 'TRAD', 'de', 'Traditions Workshop', 'This meeting engages in detailed discussion of one or more of the Twelve Traditions of N.A.', 'FC1'),
-(32, 'W', NULL, 'W', 'de', 'Women', 'This meeting is meant to be attended by women only.', 'FC3'),
-(33, 'WC', NULL, 'WCHR', 'de', 'Wheelchair', 'This meeting is wheelchair accessible.', 'FC2'),
-(34, 'YP', NULL, 'Y', 'de', 'Young People', 'This meeting is focused on the needs of younger members of NA.', 'FC3'),
-(35, 'OE', NULL, NULL, 'de', 'Open-Ended', 'No fixed duration. The meeting continues until everyone present has had a chance to share.', 'FC1'),
-(36, 'BK', NULL, 'LIT', 'de', 'Book Study', 'Approved N.A. Books', 'FC1'),
-(37, 'NS', NULL, 'NS', 'de', 'No Smoking', 'Smoking is not allowed at this meeting.', 'FC1'),
-(38, 'Ag', NULL, NULL, 'de', 'Agnostic', 'Intended for people with varying degrees of Faith.', 'FC1'),
-(39, 'FD', NULL, NULL, 'de', 'Five and Dime', 'Discussion of the Fifth Step and the Tenth Step', 'FC1'),
-(40, 'AB', NULL, 'QA', 'de', 'Ask-It-Basket', 'A topic is chosen from suggestions placed into a basket.', 'FC1'),
-(41, 'ME', NULL, 'MED', 'de', 'Meditation', 'This meeting encourages its participants to engage in quiet meditation.', 'FC1'),
-(42, 'RA', NULL, 'RA', 'de', 'Restricted Attendance', 'This facility places restrictions on attendees.', 'FC3'),
-(43, 'QA', NULL, 'QA', 'de', 'Question and Answer', 'Attendees may ask questions and expect answers from Group members.', 'FC1'),
-(44, 'CW', NULL, 'CW', 'de', 'Children Welcome', 'Children are welcome at this meeting.', 'FC3'),
-(45, 'CP', NULL, 'CPT', 'de', 'Concepts', 'This meeting is focused on discussion of the twelve concepts of NA.', 'FC1'),
-(46, 'FIN', NULL, 'LANG', 'de', 'Finnish', 'Finnish speaking meeting', 'LANG'),
-(47, 'ENG', NULL, 'LANG', 'de', 'English speaking', 'This Meeting can be attended by speakers of English.', 'LANG'),
-(48, 'PER', NULL, 'LANG', 'de', 'Persian', 'Persian speaking meeting', 'LANG'),
-(49, 'L/R', NULL, 'LANG', 'de', 'Lithuanian/Russian', 'Lithuanian/Russian Speaking Meeting', 'LANG'),
-(51, 'LC', NULL, 'LC', 'de', 'Living Clean', 'This is a discussion of the NA book Living Clean -The Journey Continues.', 'FC1'),
-(52, 'GP', NULL, 'GP', 'de', 'Guiding Principles', 'This is a discussion of the NA book Guiding Principles - The Spirit of Our Traditions.', 'FC1'),
-(54, 'VM', NULL, 'VM', 'de', 'Virtual Meeting', 'Meets Virtually', 'FC2'),
-(55, 'TC', NULL, 'TC', 'de', 'Temporarily Closed Facility', 'Facility is Temporarily Closed', 'FC2'),
-(56, 'HY', NULL, 'HYBR', 'de', 'Hybrid Meeting', 'Meets Virtually and In-person', 'FC2');
diff --git a/src/legacy/local_server/install_wizard/sql_files/InitialFormatsData-dk.sql b/src/legacy/local_server/install_wizard/sql_files/InitialFormatsData-dk.sql
deleted file mode 100644
index 3f20d0030..000000000
--- a/src/legacy/local_server/install_wizard/sql_files/InitialFormatsData-dk.sql
+++ /dev/null
@@ -1,55 +0,0 @@
--- TODO: translate strings to Danish
-INSERT INTO `%%PREFIX%%_comdef_formats` (`shared_id_bigint`, `key_string`, `icon_blob`, `worldid_mixed`, `lang_enum`, `name_string`, `description_string`, `format_type_enum`) VALUES
-(1, 'B', NULL, 'BEG', 'dk', 'Beginners', 'This meeting is focused on the needs of new members of NA.', 'FC3'),
-(2, 'BL', NULL, 'LANG', 'dk', 'Bi-Lingual', 'This Meeting can be attended by speakers of English and another language.', 'LANG'),
-(3, 'BT', NULL, 'BT', 'dk', 'Basic Text', 'This meeting is focused on discussion of the Basic Text of Narcotics Anonymous.', 'FC1'),
-(4, 'C', NULL, 'CLOSED', 'dk', 'Closed', 'This meeting is closed to non-addicts. You should attend only if you believe that you may have a problem with substance abuse.', 'O'),
-(5, 'CH', NULL, 'CH', 'dk', 'Closed Holidays', 'This meeting gathers in a facility that is usually closed on holidays.', 'FC3'),
-(6, 'CL', NULL, 'CAN', 'dk', 'Candlelight', 'This meeting is held by candlelight.', 'FC2'),
-(7, 'CS', NULL, '', 'dk', 'Children under Supervision', 'Well-behaved, supervised children are welcome.', 'FC3'),
-(8, 'D', NULL, 'DISC', 'dk', 'Discussion', 'This meeting invites participation by all attendees.', 'FC1'),
-(9, 'ES', NULL, 'LANG', 'dk', 'Español', 'This meeting is conducted in Spanish.', 'LANG'),
-(10, 'GL', NULL, 'GL', 'dk', 'Gay/Lesbian/Transgender', 'This meeting is focused on the needs of gay, lesbian and transgender members of NA.', 'FC3'),
-(11, 'IL', NULL, NULL, 'dk', 'Illness', 'This meeting is focused on the needs of NA members with chronic illness.', 'FC1'),
-(12, 'IP', NULL, 'IP', 'dk', 'Informational Pamphlet', 'This meeting is focused on discussion of one or more Informational Pamphlets.', 'FC1'),
-(13, 'IW', NULL, 'IW', 'dk', 'It Works -How and Why', 'This meeting is focused on discussion of the It Works -How and Why text.', 'FC1'),
-(14, 'JT', NULL, 'JFT', 'dk', 'Just for Today', 'This meeting is focused on discussion of the Just For Today text.', 'FC1'),
-(15, 'M', NULL, 'M', 'dk', 'Men', 'This meeting is meant to be attended by men only.', 'FC3'),
-(16, 'NC', NULL, 'NC', 'dk', 'No Children', 'Please do not bring children to this meeting.', 'FC3'),
-(17, 'O', NULL, 'OPEN', 'dk', 'Open', 'This meeting is open to addicts and non-addicts alike. All are welcome.', 'O'),
-(18, 'Pi', NULL, NULL, 'dk', 'Pitch', 'This meeting has a format that consists of each person who shares picking the next person.', 'FC1'),
-(19, 'RF', NULL, 'VAR', 'dk', 'Rotating Format', 'This meeting has a format that changes for each meeting.', 'FC1'),
-(20, 'Rr', NULL, NULL, 'dk', 'Round Robin', 'This meeting has a fixed sharing order (usually a circle.)', 'FC1'),
-(21, 'SC', NULL, NULL, 'dk', 'Security Cameras', 'This meeting is held in a facility that has security cameras.', 'FC2'),
-(22, 'SD', NULL, 'S-D', 'dk', 'Speaker/Discussion', 'This meeting is lead by a speaker, then opened for participation by attendees.', 'FC1'),
-(23, 'SG', NULL, 'SWG', 'dk', 'Step Working Guide', 'This meeting is focused on discussion of the Step Working Guide text.', 'FC1'),
-(24, 'SL', NULL, NULL, 'dk', 'ASL', 'This meeting provides an American Sign Language (ASL) interpreter for the deaf.', 'FC2'),
-(26, 'So', NULL, 'SPK', 'dk', 'Speaker Only', 'This meeting is a speaker-only meeting. Other attendees do not participate in the discussion.', 'FC1'),
-(27, 'St', NULL, 'STEP', 'dk', 'Step', 'This meeting is focused on discussion of the Twelve Steps of NA.', 'FC1'),
-(28, 'Ti', NULL, NULL, 'dk', 'Timer', 'This meeting has sharing time limited by a timer.', 'FC1'),
-(29, 'To', NULL, 'TOP', 'dk', 'Topic', 'This meeting is based upon a topic chosen by a speaker or by group conscience.', 'FC1'),
-(30, 'Tr', NULL, 'TRAD', 'dk', 'Tradition', 'This meeting is focused on discussion of the Twelve Traditions of NA.', 'FC1'),
-(31, 'TW', NULL, 'TRAD', 'dk', 'Traditions Workshop', 'This meeting engages in detailed discussion of one or more of the Twelve Traditions of N.A.', 'FC1'),
-(32, 'W', NULL, 'W', 'dk', 'Women', 'This meeting is meant to be attended by women only.', 'FC3'),
-(33, 'WC', NULL, 'WCHR', 'dk', 'Wheelchair', 'This meeting is wheelchair accessible.', 'FC2'),
-(34, 'YP', NULL, 'Y', 'dk', 'Young People', 'This meeting is focused on the needs of younger members of NA.', 'FC3'),
-(35, 'OE', NULL, NULL, 'dk', 'Open-Ended', 'No fixed duration. The meeting continues until everyone present has had a chance to share.', 'FC1'),
-(36, 'BK', NULL, 'LIT', 'dk', 'Book Study', 'Approved N.A. Books', 'FC1'),
-(37, 'NS', NULL, 'NS', 'dk', 'No Smoking', 'Smoking is not allowed at this meeting.', 'FC1'),
-(38, 'Ag', NULL, NULL, 'dk', 'Agnostic', 'Intended for people with varying degrees of Faith.', 'FC1'),
-(39, 'FD', NULL, NULL, 'dk', 'Five and Dime', 'Discussion of the Fifth Step and the Tenth Step', 'FC1'),
-(40, 'AB', NULL, 'QA', 'dk', 'Ask-It-Basket', 'A topic is chosen from suggestions placed into a basket.', 'FC1'),
-(41, 'ME', NULL, 'MED', 'dk', 'Meditation', 'This meeting encourages its participants to engage in quiet meditation.', 'FC1'),
-(42, 'RA', NULL, 'RA', 'dk', 'Restricted Attendance', 'This facility places restrictions on attendees.', 'FC3'),
-(43, 'QA', NULL, 'QA', 'dk', 'Question and Answer', 'Attendees may ask questions and expect answers from Group members.', 'FC1'),
-(44, 'CW', NULL, 'CW', 'dk', 'Children Welcome', 'Children are welcome at this meeting.', 'FC3'),
-(45, 'CP', NULL, 'CPT', 'dk', 'Concepts', 'This meeting is focused on discussion of the twelve concepts of NA.', 'FC1'),
-(46, 'FIN', NULL, 'LANG', 'dk', 'Finnish', 'Finnish speaking meeting', 'LANG'),
-(47, 'ENG', NULL, 'LANG', 'dk', 'English speaking', 'This Meeting can be attended by speakers of English.', 'LANG'),
-(48, 'PER', NULL, 'LANG', 'dk', 'Persian', 'Persian speaking meeting', 'LANG'),
-(49, 'L/R', NULL, 'LANG', 'dk', 'Lithuanian/Russian', 'Lithuanian/Russian Speaking Meeting', 'LANG'),
-(51, 'LC', NULL, 'LC', 'dk', 'Living Clean', 'This is a discussion of the NA book Living Clean -The Journey Continues.', 'FC1'),
-(52, 'GP', NULL, 'GP', 'dk', 'Guiding Principles', 'This is a discussion of the NA book Guiding Principles - The Spirit of Our Traditions.', 'FC1'),
-(54, 'VM', NULL, 'VM', 'dk', 'Virtual Meeting', 'Meets Virtually', 'FC2'),
-(55, 'TC', NULL, 'TC', 'dk', 'Temporarily Closed Facility', 'Facility is Temporarily Closed', 'FC2'),
-(56, 'HY', NULL, 'HYBR', 'dk', 'Hybrid Meeting', 'Meets Virtually and In-person', 'FC2');
diff --git a/src/legacy/local_server/install_wizard/sql_files/InitialFormatsData-en.sql b/src/legacy/local_server/install_wizard/sql_files/InitialFormatsData-en.sql
deleted file mode 100644
index 8b1fe70ee..000000000
--- a/src/legacy/local_server/install_wizard/sql_files/InitialFormatsData-en.sql
+++ /dev/null
@@ -1,54 +0,0 @@
-INSERT INTO `%%PREFIX%%_comdef_formats` (`shared_id_bigint`, `key_string`, `icon_blob`, `worldid_mixed`, `lang_enum`, `name_string`, `description_string`, `format_type_enum`) VALUES
-(1, 'B', NULL, 'BEG', 'en', 'Beginners', 'This meeting is focused on the needs of new members of NA.', 'FC3'),
-(2, 'BL', NULL, 'LANG', 'en', 'Bi-Lingual', 'This Meeting can be attended by speakers of English and another language.', 'LANG'),
-(3, 'BT', NULL, 'BT', 'en', 'Basic Text', 'This meeting is focused on discussion of the Basic Text of Narcotics Anonymous.', 'FC1'),
-(4, 'C', NULL, 'CLOSED', 'en', 'Closed', 'This meeting is closed to non-addicts. You should attend only if you believe that you may have a problem with substance abuse.', 'O'),
-(5, 'CH', NULL, 'CH', 'en', 'Closed Holidays', 'This meeting gathers in a facility that is usually closed on holidays.', 'FC3'),
-(6, 'CL', NULL, 'CAN', 'en', 'Candlelight', 'This meeting is held by candlelight.', 'FC2'),
-(7, 'CS', NULL, '', 'en', 'Children under Supervision', 'Well-behaved, supervised children are welcome.', 'FC3'),
-(8, 'D', NULL, 'DISC', 'en', 'Discussion', 'This meeting invites participation by all attendees.', 'FC1'),
-(9, 'ES', NULL, 'LANG', 'en', 'Español', 'This meeting is conducted in Spanish.', 'LANG'),
-(10, 'GL', NULL, 'GL', 'en', 'Gay/Lesbian/Transgender', 'This meeting is focused on the needs of gay, lesbian and transgender members of NA.', 'FC3'),
-(11, 'IL', NULL, NULL, 'en', 'Illness', 'This meeting is focused on the needs of NA members with chronic illness.', 'FC1'),
-(12, 'IP', NULL, 'IP', 'en', 'Informational Pamphlet', 'This meeting is focused on discussion of one or more Informational Pamphlets.', 'FC1'),
-(13, 'IW', NULL, 'IW', 'en', 'It Works -How and Why', 'This meeting is focused on discussion of the It Works -How and Why text.', 'FC1'),
-(14, 'JT', NULL, 'JFT', 'en', 'Just for Today', 'This meeting is focused on discussion of the Just For Today text.', 'FC1'),
-(15, 'M', NULL, 'M', 'en', 'Men', 'This meeting is meant to be attended by men only.', 'FC3'),
-(16, 'NC', NULL, 'NC', 'en', 'No Children', 'Please do not bring children to this meeting.', 'FC3'),
-(17, 'O', NULL, 'OPEN', 'en', 'Open', 'This meeting is open to addicts and non-addicts alike. All are welcome.', 'O'),
-(18, 'Pi', NULL, NULL, 'en', 'Pitch', 'This meeting has a format that consists of each person who shares picking the next person.', 'FC1'),
-(19, 'RF', NULL, 'VAR', 'en', 'Rotating Format', 'This meeting has a format that changes for each meeting.', 'FC1'),
-(20, 'Rr', NULL, NULL, 'en', 'Round Robin', 'This meeting has a fixed sharing order (usually a circle.)', 'FC1'),
-(21, 'SC', NULL, NULL, 'en', 'Security Cameras', 'This meeting is held in a facility that has security cameras.', 'FC2'),
-(22, 'SD', NULL, 'S-D', 'en', 'Speaker/Discussion', 'This meeting is lead by a speaker, then opened for participation by attendees.', 'FC1'),
-(23, 'SG', NULL, 'SWG', 'en', 'Step Working Guide', 'This meeting is focused on discussion of the Step Working Guide text.', 'FC1'),
-(24, 'SL', NULL, NULL, 'en', 'ASL', 'This meeting provides an American Sign Language (ASL) interpreter for the deaf.', 'FC2'),
-(26, 'So', NULL, 'SPK', 'en', 'Speaker Only', 'This meeting is a speaker-only meeting. Other attendees do not participate in the discussion.', 'FC1'),
-(27, 'St', NULL, 'STEP', 'en', 'Step', 'This meeting is focused on discussion of the Twelve Steps of NA.', 'FC1'),
-(28, 'Ti', NULL, NULL, 'en', 'Timer', 'This meeting has sharing time limited by a timer.', 'FC1'),
-(29, 'To', NULL, 'TOP', 'en', 'Topic', 'This meeting is based upon a topic chosen by a speaker or by group conscience.', 'FC1'),
-(30, 'Tr', NULL, 'TRAD', 'en', 'Tradition', 'This meeting is focused on discussion of the Twelve Traditions of NA.', 'FC1'),
-(31, 'TW', NULL, 'TRAD', 'en', 'Traditions Workshop', 'This meeting engages in detailed discussion of one or more of the Twelve Traditions of N.A.', 'FC1'),
-(32, 'W', NULL, 'W', 'en', 'Women', 'This meeting is meant to be attended by women only.', 'FC3'),
-(33, 'WC', NULL, 'WCHR', 'en', 'Wheelchair', 'This meeting is wheelchair accessible.', 'FC2'),
-(34, 'YP', NULL, 'Y', 'en', 'Young People', 'This meeting is focused on the needs of younger members of NA.', 'FC3'),
-(35, 'OE', NULL, NULL, 'en', 'Open-Ended', 'No fixed duration. The meeting continues until everyone present has had a chance to share.', 'FC1'),
-(36, 'BK', NULL, 'LIT', 'en', 'Book Study', 'Approved N.A. Books', 'FC1'),
-(37, 'NS', NULL, 'NS', 'en', 'No Smoking', 'Smoking is not allowed at this meeting.', 'FC1'),
-(38, 'Ag', NULL, NULL, 'en', 'Agnostic', 'Intended for people with varying degrees of Faith.', 'FC1'),
-(39, 'FD', NULL, NULL, 'en', 'Five and Dime', 'Discussion of the Fifth Step and the Tenth Step', 'FC1'),
-(40, 'AB', NULL, 'QA', 'en', 'Ask-It-Basket', 'A topic is chosen from suggestions placed into a basket.', 'FC1'),
-(41, 'ME', NULL, 'MED', 'en', 'Meditation', 'This meeting encourages its participants to engage in quiet meditation.', 'FC1'),
-(42, 'RA', NULL, 'RA', 'en', 'Restricted Attendance', 'This facility places restrictions on attendees.', 'FC3'),
-(43, 'QA', NULL, 'QA', 'en', 'Question and Answer', 'Attendees may ask questions and expect answers from Group members.', 'FC1'),
-(44, 'CW', NULL, 'CW', 'en', 'Children Welcome', 'Children are welcome at this meeting.', 'FC3'),
-(45, 'CP', NULL, 'CPT', 'en', 'Concepts', 'This meeting is focused on discussion of the twelve concepts of NA.', 'FC1'),
-(46, 'FIN', NULL, 'LANG', 'en', 'Finnish', 'Finnish speaking meeting', 'LANG'),
-(47, 'ENG', NULL, 'LANG', 'en', 'English speaking', 'This Meeting can be attended by speakers of English.', 'LANG'),
-(48, 'PER', NULL, 'LANG', 'en', 'Persian', 'Persian speaking meeting', 'LANG'),
-(49, 'L/R', NULL, 'LANG', 'en', 'Lithuanian/Russian', 'Lithuanian/Russian Speaking Meeting', 'LANG'),
-(51, 'LC', NULL, 'LC', 'en', 'Living Clean', 'This is a discussion of the NA book Living Clean -The Journey Continues.', 'FC1'),
-(52, 'GP', NULL, 'GP', 'en', 'Guiding Principles', 'This is a discussion of the NA book Guiding Principles - The Spirit of Our Traditions.', 'FC1'),
-(54, 'VM', NULL, 'VM', 'en', 'Virtual Meeting', 'Meets Virtually', 'FC2'),
-(55, 'TC', NULL, 'TC', 'en', 'Temporarily Closed Facility', 'Facility is Temporarily Closed', 'FC2'),
-(56, 'HY', NULL, 'HYBR', 'en', 'Hybrid Meeting', 'Meets Virtually and In-person', 'FC2');
diff --git a/src/legacy/local_server/install_wizard/sql_files/InitialFormatsData-es.sql b/src/legacy/local_server/install_wizard/sql_files/InitialFormatsData-es.sql
deleted file mode 100644
index c8770be95..000000000
--- a/src/legacy/local_server/install_wizard/sql_files/InitialFormatsData-es.sql
+++ /dev/null
@@ -1,37 +0,0 @@
-INSERT INTO `%%PREFIX%%_comdef_formats` (`shared_id_bigint`, `key_string`, `icon_blob`, `worldid_mixed`, `lang_enum`, `name_string`, `description_string`, `format_type_enum`) VALUES
-(1, 'B', NULL, 'BEG', 'es', 'Para el recién llegado', 'Esta reunión se centra en las necesidades de los nuevos miembros de NA.', 'FC3'),
-(2, 'BL', NULL, 'LANG', 'es', 'Bilingüe', 'Esta reunión se pueden asistir personas de que hablen inglés y otro idioma.', 'LANG'),
-(3, 'BT', NULL, 'BT', 'es', 'Texto Básico', 'Esta reunión se centra en la discusión del texto básico de Narcóticos Anónimos.', 'FC1'),
-(4, 'C', NULL, 'CLOSED', 'es', 'Cerrado', 'Esta reunión está cerrada a los no adictos. Usted debe asistir solamente si cree que puede tener un problema con abuso de drogas.', 'O'),
-(5, 'CH', NULL, NULL, 'es', 'Cerrado en Días de fiesta', 'Esta reunión tiene lugar en una localidad que esta generalmente cerrada los días de fiesta.', 'FC3'),
-(6, 'CL', NULL, 'CAN', 'es', 'Luz de vela', 'Esta reunión se celebra a luz de vela.', 'FC2'),
-(7, 'CS', NULL, '', 'es', 'Niños bajo Supervisión', 'Los niños de buen comportamiento y supervisados son bienvenidos.', 'FC3'),
-(8, 'D', NULL, 'DISC', 'es', 'Discusión', 'Esta reunión invita la participación de todos los asistentes.', 'FC1'),
-(10, 'GL', NULL, 'GL', 'es', 'Gay/Lesbiana', 'Esta reunión se centra en las necesidades de miembros gay y lesbianas de NA.', 'FC3'),
-(11, 'IL', NULL, NULL, 'es', 'Enfermedad', 'Esta reunión se centra en las necesidades de los miembros de NA con enfermedades crónicas.', 'FC1'),
-(12, 'IP', NULL, 'IP', 'es', 'Folleto Informativo', 'Esta reunión se centra en la discusión de unos o más folletos informativos.', 'FC1'),
-(13, 'IW', NULL, 'IW', 'es', 'Functiona - Cómo y Porqué', 'Esta reunión se centra en la discusión del texto Funciona - Cómo y Porqué.', 'FC1'),
-(14, 'JT', NULL, 'JFT', 'es', 'Solo por Hoy', 'Esta reunión se centra en la discusión del texto Solo por Hoy.', 'FC1'),
-(15, 'M', NULL, 'M', 'es', 'Hombres', 'A esta reunión se supone que aistan hombres solamente.', 'FC3'),
-(16, 'NC', NULL, NULL, 'es', 'No niños', 'Por favor no traer niños a esta reunión.', 'FC3'),
-(17, 'O', NULL, 'OPEN', 'es', 'Abierta', 'Esta reunión está abierta a los adictos y a los no adictos por igual. Todos son bienvenidos.', 'O'),
-(18, 'Pi', NULL, NULL, 'es', 'Echada', 'Esta reunión tiene un formato que consiste en que cada persona que comparta escoja a la persona siguiente.', 'FC1'),
-(19, 'RF', NULL, 'VAR', 'es', 'Formato que Rota', 'Esta reunión tiene un formato que cambia para cada reunión.', 'FC1'),
-(20, 'Rr', NULL, NULL, 'es', 'Round Robin', 'Esta reunión tiene un orden fijo de compartir (generalmente un círculo).', 'FC1'),
-(21, 'SC', NULL, NULL, 'es', 'Cámaras de Vigilancia', 'Esta reunión se celebra en una localidad que tenga cámaras de vigilancia.', 'FC2'),
-(22, 'SD', NULL, 'S-D', 'es', 'Orador/Discusión', 'Esta reunión es conducida por un orador, después es abierta para la participación de los asistentes.', 'FC1'),
-(23, 'SG', NULL, 'SWG', 'es', 'Guia Para Trabajar los Pasos', 'Esta reunión se centra en la discusión del texto Guia Para Trabajar los Pasos.', 'FC1'),
-(24, 'SL', NULL, NULL, 'es', 'ASL', 'Esta reunión proporciona intérprete (ASL) para los sordos.', 'FC2'),
-(26, 'So', NULL, 'SPK', 'es', 'Solamente Orador', 'Esta reunión es de orador solamente. Otros asistentes no participan en la discusión.', 'FC1'),
-(27, 'St', NULL, 'STEP', 'es', 'Paso', 'Esta reunión se centra en la discusión de los doce pasos de NA.', 'FC1'),
-(28, 'Ti', NULL, NULL, 'es', 'Contador de Tiempo', 'Esta reunión tiene el tiempo de compartir limitado por un contador de tiempo.', 'FC1'),
-(29, 'To', NULL, 'TOP', 'es', 'Tema', 'Esta reunión se basa en un tema elegido por el orador o por la conciencia del grupo.', 'FC1'),
-(30, 'Tr', NULL, 'TRAD', 'es', 'Tradición', 'Esta reunión se centra en la discusión de las Doce Tradiciones de NA.', 'FC1'),
-(31, 'TW', NULL, 'TRAD', 'es', 'Taller de las Tradiciones', 'Esta reunión consiste en la discusión detallada de una o más de las Doce Tradiciones de N.A.', 'FC1'),
-(32, 'W', NULL, 'W', 'es', 'Mujeres', 'A esta reunión se supone que asistan mujeres solamente.', 'FC3'),
-(33, 'WC', NULL, 'WCHR', 'es', 'Silla de Ruedas', 'Esta reunión es accesible por silla de ruedas.', 'FC2'),
-(34, 'YP', NULL, 'Y', 'es', 'Jovenes', 'Esta reunión se centra en las necesidades de los miembros más jóvenes de NA.', 'FC3'),
-(35, 'OE', NULL, NULL, 'es', 'Sin Tiempo Fijo', 'No tiene tiempo fijo. Esta reunión continua hasta que cada miembro haya tenido la oportunidad de compartir.', 'FC1'),
-(54, 'VM', NULL, 'VM', 'es', 'Virtual Meeting', 'Meets Virtually', 'FC2'),
-(55, 'TC', NULL, 'TC', 'es', 'Temporarily Closed Facility', 'Facility is Temporarily Closed', 'FC2'),
-(56, 'HY', NULL, 'HYBR', 'es', 'Hybrid Meeting', 'Meets Virtually and In-person', 'FC2');
\ No newline at end of file
diff --git a/src/legacy/local_server/install_wizard/sql_files/InitialFormatsData-fa.sql b/src/legacy/local_server/install_wizard/sql_files/InitialFormatsData-fa.sql
deleted file mode 100644
index 2368b573d..000000000
--- a/src/legacy/local_server/install_wizard/sql_files/InitialFormatsData-fa.sql
+++ /dev/null
@@ -1,54 +0,0 @@
-INSERT INTO `%%PREFIX%%_comdef_formats` (`shared_id_bigint`, `key_string`, `icon_blob`, `worldid_mixed`, `lang_enum`, `name_string`, `description_string`, `format_type_enum`) VALUES
-(1, 'B', NULL, 'BEG', 'fa', 'تازه واردان','این جلسه بر روی نیازهای تازه واردان در معتادان گمنام متمرکز میباشد', 'FC3'),
-(2, 'BL', NULL, 'LANG', 'fa', 'دو زبانه','این جلسه پذیرای شرکت کنندگان انگلیسی زبان و دیگر زبان ها میباشد', 'LANG'),
-(3, 'BT', NULL, 'BT', 'fa', 'کتاب پایه','این جلسه متمرکز بر روی بحث درباره کتاب پایه معتادان گمنام میباشد', 'FC1'),
-(4, 'C', NULL, 'CLOSED', 'fa', 'بسته','این جلسه برای افراد غیر معتاد بسته میباشد. شما تنها اگر فکر میکنید با مواد خدر مشکل دارید میتوانید شرکت کنید', 'O'),
-(5, 'CH', NULL, 'CH', 'fa', 'بسته در روزهای تعطیل','این جلسات در روزهای تعطیل برگزار نمیگردد', 'FC3'),
-(6, 'CL', NULL, 'CAN', 'fa', 'شمع روشن','این جلسه بهمراه شمع روشن برگزار میگردد', 'FC2'),
-(7, 'CS', NULL, '', 'fa', 'کودکان بی سرپرست','خوش رفتاری', 'FC3'),
-(8, 'D', NULL, 'DISC', 'fa', 'بحث و گفتگو','این جلسه از تمامی شرکت کنندگان دعوت به بحث میکند', 'FC1'),
-(9, 'ES', NULL, 'LANG', 'fa', 'اسپانیایی','این جلسه به زبان اسپانیایی برگزار میگردد', 'LANG'),
-(10, 'GL', NULL, 'GL', 'fa', 'مردان همجنس باز/زنان همجنس باز/تغییر جنسیتی ها','این جلسه به نیازهای همجنس بازان/همجنس خواهان میپردازد', 'FC3'),
-(11, 'IL', NULL, NULL, 'fa', 'بیماران','این جلسه به نیازهای اعضا با بیماری های مزمن متمرکز میباشد', 'FC1'),
-(12, 'IP', NULL, 'IP', 'fa', 'پمفلت های اطلاعاتی','این جلسه به بررسی و بحث در مورد یک یا چند پمفلت متمرکز میباشد', 'FC1'),
-(13, 'IW', NULL, 'IW', 'fa', 'چگونگی عملکرد ','این جلسه با موضوع بحث در مورد کتاب چگونگی عملکرد برگزار میگردد', 'FC1'),
-(14, 'JT', NULL, 'JFT', 'fa', 'فقط برای امروز','این جلسه با موضوع بحث درمورد کتاب فقط برای امروز متمرکز میباشد', 'FC1'),
-(15, 'M', NULL, 'M', 'fa', 'مردان','این جلسه فقط مخصوص آقایان مباشد', 'FC3'),
-(16, 'NC', NULL, 'NC', 'fa', 'ممنوعیت ورود کودکان','لطفاً کودکان را به این جلسه نیاورید', 'FC3'),
-(17, 'O', NULL, 'OPEN', 'fa', 'باز','این جلسه برای کلیه اعضا معتاد و همچنین غیر معتادان باز میباشد', 'O'),
-(18, 'Pi', NULL, NULL, 'fa', 'انتخابی','فورمت این جلسه بصورتیست که هر مشارکت کننده میتواند نفر بعدی را جهت مشارکت انتخاب نماید', 'FC1'),
-(19, 'RF', NULL, 'VAR', 'fa', 'فورمت چرخشی','فورمت این جلسه در هر جلسه متغیر میباشد', 'FC1'),
-(20, 'Rr', NULL, NULL, 'fa', 'مشارکت موضوع دار','این جلسه دارای یکسری موضوعات خاص میباشد (معمولاً بصورت چرخشی)', 'FC1'),
-(21, 'SC', NULL, NULL, 'fa', 'دوربین مداربسته','این جلسه در مکانهای مجهز به دوربین مدار بسته برگزار میگردد', 'FC2'),
-(22, 'SD', NULL, 'S-D', 'fa', 'سخنرانی/بحث','این جلسه توسط یک سخنران گردانندگی میگردد', 'FC1'),
-(23, 'SG', NULL, 'SWG', 'fa', 'راهنمای کارکرد قدم','این جلسه با موضوع بررسی و بحث در مورد کتاب راهنمای کاکرد قدم برگزار میگردد', 'FC1'),
-(24, 'SL', NULL, NULL, 'fa', 'تفسیر به زبان انگلیسی برای ناشنوایان','این جلسه بهمراه مفسر انگلیسی برای ناشنوایان برگزار میگردد', 'FC2'),
-(26, 'So', NULL, 'SPK', 'fa', 'فقط سخنرانی','این جلسه فقط یک سخنران دارد. دیگر شرکت کنندگان حق مشارکت ندارند', 'FC1'),
-(27, 'St', NULL, 'STEP', 'fa', 'قدم','این جلسه با موضوع بحث درمورد قدم های دوازده گانه معتادان گمنام برگزار میگردد', 'FC1'),
-(28, 'Ti', NULL, NULL, 'fa', 'زمان سنج','در این جلسه زمان مشارکت توسط زمان سنج محاسبه و کنترل میگردد', 'FC1'),
-(29, 'To', NULL, 'TOP', 'fa', 'موضوع','این جلسه برپایه موضوع انتخابی توسط یک سخنران یا وجدان گروهی برگزار میگردد', 'FC1'),
-(30, 'Tr', NULL, 'TRAD', 'fa', 'سنت ها','این جلسه با موضوع بحث درمورد سنت های دوازده گانه معتادان گمنام برگزار میگردد', 'FC1'),
-(31, 'TW', NULL, 'TRAD', 'fa', 'کارگاه سنت ها','این جلسه با موضوع بررسی جزئیاتی یک یاچند سنت معتادان گمنام برگزار میگردد', 'FC1'),
-(32, 'W', NULL, 'W', 'fa', 'بانوان','این جلسه فقط مخصوص خانم ها مباشد', 'FC3'),
-(33, 'WC', NULL, 'WCHR', 'fa', 'ویلچر','در این جلسه ویلچر در دسترس میباشد', 'FC2'),
-(34, 'YP', NULL, 'Y', 'fa', 'جوانان','این جلسه بر روی نیازهای اعضا جوان متمرکز میباشد', 'FC3'),
-(35, 'OE', NULL, NULL, 'fa', 'بی پایان','بدون مدت زمان ثابت. این جلسه تا زمانی که تمامی اعضا درخواست کننده مشارکت، مشارکت نکرده باشند به اتمام نمیرسد', 'FC1'),
-(36, 'BK', NULL, 'LIT', 'fa', 'کتاب خوانی','کتابخوانی نشریات معتادان گمنام', 'FC1'),
-(37, 'NS', NULL, 'NS', 'fa', 'مصرف دخانیات ممنوع','مصرف دخانیات در این جلسه ممنوع میباشد', 'FC1'),
-(38, 'Ag', NULL, NULL, 'fa', 'بی اعتقادان','جلسه مخصوص اعضا باهر میزان درجه از اعتقاد', 'FC1'),
-(39, 'FD', NULL, NULL, 'fa', 'پنج و ده','جلسه بحث و بررسی قدم های پنج و ده', 'FC1'),
-(40, 'AB', NULL, 'QA', 'fa', 'انتخاب موضوع از سبد','انتخاب یک موضوع توسط پیشنهادات ارائه شده در سبد', 'FC1'),
-(41, 'ME', NULL, 'MED', 'fa', 'مراقبه','این جلسه اعضا شرکت کننده را به مراقبه کامل تشویق مینماید', 'FC1'),
-(42, 'RA', NULL, 'RA', 'fa', 'محدودیت شرکت کننده','این جلسه دارای محدودیت شرکت کنندگان میباشد', 'FC3'),
-(43, 'QA', NULL, 'QA', 'fa', 'پرسش و پاسخ','اعضا میتوانند سوالات خود را مطرح نموده و منتظر دریافت پاسخ از دیگر اعضا باشند', 'FC1'),
-(44, 'CW', NULL, 'CW', 'fa', 'با حضور کودکان','حضور کودکان در این جلسه بلامانع میباشد', 'FC3'),
-(45, 'CP', NULL, 'CPT', 'fa', 'مفاهیم','این جلسه با موضوع بحث درمورد مفاهیم دوازده گانه معتادان گمنام برگزار میگردد', 'FC1'),
-(46, 'FIN', NULL, 'LANG', 'fa', 'فنلاندی','جلسه به زبان فنلاندی', 'LANG'),
-(47, 'ENG', NULL, 'LANG', 'fa', ' انگلیسی','این جلسه میتواند با حضور اعضا انگلیسی زبان نیز برگزار گردد', 'LANG'),
-(48, 'PER', NULL, 'LANG', 'fa', 'فارسی','جلسه به زبان فارسی', 'LANG'),
-(49, 'L/R', NULL, 'LANG', 'fa', 'لیتوانیایی/روسی','جلسه به زبان های لیتوانیایی/روسی', 'LANG'),
-(51, 'LC', NULL, 'LC', 'fa', 'پاک زیستن','این جلسه با موضوع بررسی و بحث در مورد کتاب پاک زیستن - سفر ادامه دارد، برگزار میگردد', 'FC1'),
-(52, 'GP', NULL, 'GP', 'fa', 'روح سنت ها','این جلسه با موضوع بررسی و بحث در مورد کتاب روح سنت ها برگزار میگردد', 'FC1'),
-(54, 'VM', NULL, 'VM', 'fa', 'Virtual Meeting', 'Meets Virtually', 'FC2'),
-(55, 'TC', NULL, 'TC', 'fa', 'Temporarily Closed Facility', 'Facility is Temporarily Closed', 'FC2'),
-(56, 'HY', NULL, 'HYBR', 'fa', 'Hybrid Meeting', 'Meets Virtually and In-person', 'FC2');
\ No newline at end of file
diff --git a/src/legacy/local_server/install_wizard/sql_files/InitialFormatsData-fr.sql b/src/legacy/local_server/install_wizard/sql_files/InitialFormatsData-fr.sql
deleted file mode 100644
index 27e6c13e2..000000000
--- a/src/legacy/local_server/install_wizard/sql_files/InitialFormatsData-fr.sql
+++ /dev/null
@@ -1,49 +0,0 @@
-INSERT INTO `%%PREFIX%%_comdef_formats` (`shared_id_bigint`, `key_string`, `icon_blob`, `worldid_mixed`, `lang_enum`, `name_string`, `description_string`, `format_type_enum`) VALUES
-(1, 'B', NULL, 'BEG', 'fr', 'Débutants', 'Cette réunion est axée sur les besoins des nouveaux membres de NA.', 'FC3'),
-(2, 'BL', NULL, 'LANG', 'fr', 'bilingue', 'Cette réunion peut aider les personnes qui parlent l\'anglais et une autre langue.', 'LANG'),
-(3, 'BT', NULL, 'BT', 'fr', 'Texte de Base', 'Cette réunion est axée sur la discussion du texte de base de Narcotiques Anonymes.', 'FC1'),
-(4, 'C', NULL, 'CLOSED', 'fr', 'Fermée', 'Cette réunion est fermée aux non-toxicomanes. Vous pouvez y assister que si vous pensez que vous pouvez avoir un problème avec l\'abus de drogues.', 'O'),
-(5, 'CH', NULL, NULL, 'fr', 'Fermé durant les jours fériés.', 'Cette réunion a lieu dans une local qui est généralement fermé durant les jours fériés.', 'FC3'),
-(6, 'CL', NULL, 'CAN', 'fr', 'Chandelle', 'Cette réunion se déroule à la chandelle.', 'FC2'),
-(7, 'CS', NULL, '', 'fr', 'Enfants sous Supervision', 'Les enfants bien élevés sont les bienvenus et supervisés.', 'FC3'),
-(8, 'D', NULL, 'DISC', 'fr', 'Discussion', 'Cette réunion invite tous les participants à la discussion.', 'FC1'),
-(10, 'GL', NULL, 'GL', 'fr', 'Gais, lesbiennes, transsexuel(le)s, bisexuel(le)s', 'Cette réunion est axée sur les besoins des membres gais, lesbiennes, transsexuel(le)s et bisexuel(le)s de NA.', 'FC3'),
-(11, 'IL', NULL, NULL, 'fr', 'Chroniques', 'Cette réunion est axée sur les besoins des membres de NA comportant des troubles de maladies chroniques.', 'FC1'),
-(12, 'IP', NULL, 'IP', 'fr', 'Brochures', 'Cette réunion est axée sur la discussion d\'une ou plusieurs brochures.', 'FC1'),
-(13, 'IW', NULL, 'IW', 'fr', 'Ça marche, Comment et Pourquoi', 'Cette session met l\'accent sur la discussion de texte Ça marche, Comment et Pourquoi.', 'FC1'),
-(14, 'JT', NULL, 'JFT', 'fr', 'Juste pour aujourd\'hui', 'Cette session met l\'accent sur la discussion du texte Juste pour aujourd\'hui.', 'FC1'),
-(15, 'M', NULL, 'M', 'fr', 'Hommes', 'Cette réunion est destinée à être assisté par seulement que des hommes.', 'FC3'),
-(16, 'NC', NULL, NULL, 'fr', 'Pas d\'enfant', 'S\'il vous plaît, ne pas amener les enfants à cette réunion.', 'FC3'),
-(17, 'O', NULL, 'OPEN', 'fr', 'Ouvert', 'Cette réunion est ouverte aux toxicomanes et non-toxicomanes de même. Tous sont les bienvenus.', 'O'),
-(18, 'Pi', NULL, NULL, 'fr', 'À la pige', 'Cette réunion a un format de discussion est que chaque personne qui discute invite la personne suivante à discuter.', 'FC1'),
-(19, 'RF', NULL, 'VAR', 'fr', 'Format varié', 'Cette réunion a un format qui varie à toutes les réunions.', 'FC1'),
-(20, 'Rr', NULL, NULL, 'fr', 'À la ronde', 'Cette réunion a un ordre de partage fixe (généralement un cercle).', 'FC1'),
-(21, 'SC', NULL, NULL, 'fr', 'Caméra de surveillance', 'Cette réunion se tient dans un emplacement qui a des caméras de surveillance.', 'FC2'),
-(22, 'SD', NULL, 'S-D', 'fr', 'Partage et ouvert', 'Cette réunion a un conférencier, puis ouvert au public.', 'FC1'),
-(23, 'SG', NULL, 'SWG', 'fr', 'Guides des Étapes', 'Cette réunion est axée sur la discussion sur le Guide des Étapes.', 'FC1'),
-(24, 'SL', NULL, NULL, 'fr', 'Malentendants', 'Cette rencontre permet l\'interprète pour les personnes malentendantes.', 'FC2'),
-(26, 'So', NULL, 'SPK', 'fr', 'Partage seulement', 'Cette réunion a seulement un conférencier. Les autres participants ne participent pas à la discussion.', 'FC1'),
-(27, 'St', NULL, 'STEP', 'fr', 'Étapes NA', 'Cette réunion est axée sur la discussion des Douze Étapes de NA.', 'FC1'),
-(28, 'Ti', NULL, NULL, 'fr', 'Discussion chronométrée', 'Cette réunion a une durée de discussion limitée par une minuterie pour chaque personne.', 'FC1'),
-(29, 'To', NULL, 'TOP', 'fr', 'Thématique', 'Cette réunion est basée sur un thème choisi par la personne qui anime ou la conscience de groupe.', 'FC1'),
-(30, 'Tr', NULL, 'TRAD', 'fr', 'Traditions', 'Cette réunion est axée sur la discussion des Douze Traditions de NA.', 'FC1'),
-(31, 'TW', NULL, 'TRAD', 'fr', 'Atelier sur les traditions', 'Cette réunion est une discussion détaillée d\'une ou de plusieurs des Douze Traditions de NA', 'FC1'),
-(32, 'W', NULL, 'W', 'fr', 'Femmes', 'Seulement les femmes sont admises.', 'FC3'),
-(33, 'WC', NULL, 'WCHR', 'fr', 'Fauteuil Roulant', 'Cette réunion est accessible en fauteuil roulant.', 'FC2'),
-(34, 'YP', NULL, 'Y', 'fr', 'Jeunes', 'Cette réunion est axée sur les besoins des plus jeunes membres de NA.', 'FC3'),
-(35, 'OE', NULL, NULL, 'fr', 'Marathon', 'Il n\'y a pas de durée fixe. Cette réunion se poursuit jusqu\'à ce que chaque membre a eu l\'occasion de partager.', 'FC1'),
-(36, 'BK', NULL, 'LIT', 'fr', 'Études de livres NA', 'Livres N.A. Approuvés', 'FC1'),
-(37, 'NS', NULL, 'NS', 'fr', 'Non-fumeurs', 'Fumer n\'est pas permis à cette réunion.', 'FC1'),
-(38, 'Ag', NULL, NULL, 'fr', 'Agnostique', 'Destiné aux personnes ayant divers degrés de la foi.', 'FC1'),
-(39, 'FD', NULL, NULL, 'fr', 'Cinq et dix', 'Discussion de la cinquième étape et la dixième étape.', 'FC1'),
-(40, 'AB', NULL, 'QA', 'fr', 'Panier', 'Un sujet est choisi parmi les suggestions placées dans un panier.', 'FC1'),
-(41, 'ME', NULL, 'MED', 'fr', 'Méditation', 'Cette réunion encourage ses participants à s\'engager dans la méditation tranquille.', 'FC1'),
-(42, 'RA', NULL, 'RA', 'fr', 'Accés limités', 'Cet emplacement impose des restrictions sur les participants.', 'FC3'),
-(43, 'QA', NULL, 'QA', 'fr', 'Questions et Réponses', 'Les participants peuvent poser des questions et attendre des réponses des membres du groupe.', 'FC1'),
-(44, 'CW', NULL, 'CW', 'fr', 'Enfants bienvenus', 'Les enfants sont les bienvenus à cette réunion.', 'FC3'),
-(45, 'CP', NULL, 'CPT', 'fr', 'Concepts', 'Cette réunion est axée sur la discussion des douze concepts de NA.', 'FC1'),
-(46, 'Finlandais', NULL, NULL, 'fr', 'Finlandais', 'Cette réunion se déroule en langue finlandaisè', 'FC3'),
-(47, 'ENG', NULL, NULL, 'fr', 'Anglais', 'Cette réunion se déroule de langues anglais.', 'FC3'),
-(54, 'VM', NULL, 'VM', 'fr', 'Virtual Meeting', 'Meets Virtually', 'FC2'),
-(55, 'TC', NULL, 'TC', 'fr', 'Temporarily Closed Facility', 'Facility is Temporarily Closed', 'FC2'),
-(56, 'HY', NULL, 'HYBR', 'fr', 'Hybrid Meeting', 'Meets Virtually and In-person', 'FC2');
diff --git a/src/legacy/local_server/install_wizard/sql_files/InitialFormatsData-it.sql b/src/legacy/local_server/install_wizard/sql_files/InitialFormatsData-it.sql
deleted file mode 100644
index bd9ded305..000000000
--- a/src/legacy/local_server/install_wizard/sql_files/InitialFormatsData-it.sql
+++ /dev/null
@@ -1,32 +0,0 @@
-INSERT INTO `%%PREFIX%%_comdef_formats` (`shared_id_bigint`, `key_string`, `icon_blob`, `worldid_mixed`, `lang_enum`, `name_string`, `description_string`, `format_type_enum`) VALUES
-(1, 'NV', NULL, NULL, 'it', 'Nuovi venuti', 'Riunione concentrata principalmente sulle necessità dei nuovi membri di NA.', 'FC3'),
-(2, 'BL', NULL, 'LANG', 'it', 'Bilingue', 'Questa riunione può essere frequentata da membri che parlano italiano e/o inglese.', 'LANG'),
-(3, 'TB', NULL, NULL, 'it', 'Testo base', 'Riunione concentrata sulla discussione del testo base di NA.', 'FC1'),
-(4, 'Ch.', NULL, NULL, 'it', 'Chiusa', 'Riunione chiusa ai non dipendenti. Dovrebbe frequentarla soltanto chi crede di avere un problema con le sostanze d\'abuso.', 'O'),
-(5, 'SF', NULL, NULL, 'it', 'Sospesa nei giorni festivi', 'Questa riunione si tiene in locali che di solito sono chiusi nei giorni festivi e di vacanza.', 'FC3'),
-(6, 'LC', NULL, NULL, 'it', 'Lume di candela', 'Questa riunione si tiene a lume di candela per favorire la meditazione.', 'FC2'),
-(7, 'BS', NULL, NULL, 'it', 'Bambini sotto supervisione', 'Sono ammessi bambini senza problemi di comportamento e sotto supervisione.', 'FC3'),
-(8, 'Disc.', NULL, NULL, 'it', 'Discussione', 'Tutti i partecipanti sono invitati a condividere.', 'FC1'),
-(9, 'ES', NULL, 'LANG', 'it', 'Spagnolo', 'Riunione in lingua spagnolo.', 'FC3'),
-(14, 'SPO', NULL, NULL, 'it', 'Solo per oggi', 'Riunione in cui si discutono i temi delle meditazioni quotidiane del libro "Solo per oggi".', 'FC1'),
-(15, 'U', NULL, NULL, 'it', 'Uomini', 'Riunioni per soli uomini.', 'FC3'),
-(17, 'Ap.', NULL, NULL, 'it', 'Aperta', 'Riunione aperta ai non dipendenti. Parenti, amici, professionisti e altri membri della società, sono benvenuti.', 'O'),
-(23, 'GLP', NULL, NULL, 'it', 'Guida al lavoro sui passi', 'Riunione basata sulla discussione della Guida al lavoro sui Dodici passi di NA.', 'FC1'),
-(28, 'Temp.', NULL, NULL, 'it', 'Condivisioni temporizzate', 'In queste riunioni il tempo di condivisione è limitato da un cronometro.', 'FC1'),
-(27, 'P', NULL, NULL, 'it', 'Passi', 'Riunione di discussione sui Dodici passi.', 'FC1'),
-(29, 'Arg.', NULL, NULL, 'it', 'Riunioni a tema', 'Queste riunioni si basano su un argomento prescelto.', 'FC1'),
-(30, 'T', NULL, NULL, 'it', 'Tradizioni', 'Riunione di discussione sulle Dodici tradizioni.', 'FC1'),
-(31, 'TW', NULL, NULL, 'it', 'Workshop sulle Dodici tradizioni', 'Riunioni in cui si discute dettagliatamente su una o più delle Dodici tradizioni.', 'FC1'),
-(32, 'D', NULL, NULL, 'it', 'Donne', 'Riunione solo donne.', 'FC3'),
-(33, 'SR', NULL, NULL, 'it', 'Sedia a rotelle', 'Riunione accessibile per chi ha la sedia a rotelle.', 'FC2'),
-(35, 'M', NULL, NULL, 'it', 'Maratona', 'Durata non prestabilita. La riunione prosegue finché tutti i presenti hanno da condividere.', 'FC1'),
-(37, 'NF', NULL, NULL, 'it', 'Non fumatori', 'In queste riunioni non è consentito fumare.', 'FC1'),
-(40, 'TS', NULL, NULL, 'it', 'Tema a sorpresa', 'L\'argomento su cui condividere è scritto su un biglietto o altro supporto (es. un bastoncino di legno) ed estratto a caso da ciascun membro.', 'FC1'),
-(42, 'M', NULL, NULL, 'it', 'Meditazione', 'In questa riunione sono poste restrizioni alle modalità di partecipazione.', 'FC3'),
-(43, 'D/R', NULL, NULL, 'it', 'Domande e risposteq', 'I partecipanti possono fare domande e attenderne la risposta dagli altri membri del gruppo.', 'FC1'),
-(44, 'Ba', NULL, NULL, 'it', 'Bambini', 'I bambini sono benvenuti in queste riunioni.', 'FC3'),
-(45, 'C', NULL, NULL, 'it', 'Concetti di servizio', 'Riunioni basate sulla discussione dei Dodici concetti per il servizio in NA.', 'FC1'),
-(51, 'VP', NULL, NULL, 'it', 'Vivere puliti', 'Riunioni di discussione sul libro "Vivere puliti - Il viaggio continua".', 'FC1'),
-(54, 'VM', NULL, 'VM', 'it', 'Virtual Meeting', 'Meets Virtually', 'FC2'),
-(55, 'TC', NULL, 'TC', 'it', 'Temporarily Closed Facility', 'Facility is Temporarily Closed', 'FC2'),
-(56, 'HY', NULL, 'HYBR', 'it', 'Hybrid Meeting', 'Meets Virtually and In-person', 'FC2');
\ No newline at end of file
diff --git a/src/legacy/local_server/install_wizard/sql_files/InitialFormatsData-pl.sql b/src/legacy/local_server/install_wizard/sql_files/InitialFormatsData-pl.sql
deleted file mode 100644
index 8616bb289..000000000
--- a/src/legacy/local_server/install_wizard/sql_files/InitialFormatsData-pl.sql
+++ /dev/null
@@ -1,54 +0,0 @@
-INSERT INTO `%%PREFIX%%_comdef_formats` (`shared_id_bigint`, `key_string`, `icon_blob`, `worldid_mixed`, `lang_enum`, `name_string`, `description_string`, `format_type_enum`) VALUES
-(1, 'B', NULL, 'BEG', 'pl', 'Nowoprzybyli', 'Mityng koncentruje się na potrzebach nowyh członków NA.', 'FC3'),
-(2, 'BL', NULL, 'LANG', 'pl', 'Wielojęzykowość', 'Na tym mityngu mogą uczęszczać osoby posługujące się językiem angielskim i innymi.', 'LANG'),
-(3, 'BT', NULL, 'BT', 'pl', 'Tekst Podstawowy', 'Mityng koncentruje się na dyskusjach o Tekście Podstawowym Anonimowych Narkomanów.', 'FC1'),
-(4, 'C', NULL, 'CLOSED', 'pl', 'Mityng zamknięty', 'Mityng zamknięty. Wyłącznie dla osób uzależnionych i tych, które chcą przestać brać.', 'O'),
-(5, 'CH', NULL, 'CH', 'pl', 'Zamknięty w święta', 'Mityng odbywa się w miejscu, które zwykle jest zamknięte w dni wolne od pracy/wakacje.', 'FC3'),
-(6, 'CL', NULL, 'CAN', 'pl', 'Świeczka', 'Ten mityng odbywa się przy blasku świecy.', 'FC2'),
-(7, 'CS', NULL, '', 'pl', 'Dzieci pod opieką', 'Dzieci uzależnionych mile widziane pod warunkiem odpowiedniego zachowania.', 'FC3'),
-(8, 'D', NULL, 'DISC', 'pl', 'Dyskusja', 'Mityng dla wszystkich chętnych.', 'FC1'),
-(9, 'ES', NULL, 'LANG', 'pl', 'Hiszpański', 'Mityng odbywa się w języku hiszpańskim.', 'LANG'),
-(10, 'GL', NULL, 'GL', 'pl', 'LGBTQ', 'Mityng koncentruje się na członkach wspólnoty należących do społeczności LGBT.', 'FC3'),
-(11, 'IL', NULL, NULL, 'pl', 'Choroba', 'Mityng koncentruje się na potrzebach przewlekle chorych członków NA.', 'FC1'),
-(12, 'IP', NULL, 'IP', 'pl', 'Broszura Informacyjna', 'Mityng koncentruje się na dyskusji nad jedną z Broszur Międzynarodowych.', 'FC1'),
-(13, 'IW', NULL, 'IW', 'pl', 'To Działa - Jak i Dlaczego', 'Mityng koncentruje się na dyskusji nad tekstem z "To Działa - Jak i Dlaczego".', 'FC1'),
-(14, 'JT', NULL, 'JFT', 'pl', 'Właśnie Dzisiaj', 'Mityng koncentruje się na dyskusji nad tekstem z "Właśnie dzisiaj".', 'FC1'),
-(15, 'M', NULL, 'M', 'pl', 'Mężczyźni', 'Mityng wyłącznie dla mężczyzn.', 'FC3'),
-(16, 'NC', NULL, 'NC', 'pl', 'Bez Dzieci', 'Prosimy, by nie przyprowadzać dzieci na ten mityng.', 'FC3'),
-(17, 'O', NULL, 'OPEN', 'pl', 'Otwarty', 'Mityng otwarty dla uzależnionych i nieuzależnionych. Wszyscy są mile widziani.', 'O'),
-(18, 'Pi', NULL, NULL, 'pl', 'Pitch', 'Na tym mityngu obowiązuje format, w którym osoba, dzieląca się doświadczeniem, wybiera kolejną osobę.', 'FC1'),
-(19, 'RF', NULL, 'VAR', 'pl', 'Zmienny format', 'Format tego mityngu zmienia się co mityng.', 'FC1'),
-(20, 'Rr', NULL, NULL, 'pl', 'Round Robin', 'Na tym mityngu jest ustalona kolejność dzielenia się doświadczeniem (zwykle w koło)', 'FC1'),
-(21, 'SC', NULL, NULL, 'pl', 'Kamery bezpieczeństwa', 'Mityng odbywa się w miejscu, w którym zamontowane są kamery bezpieczeństwa.', 'FC2'),
-(22, 'SD', NULL, 'S-D', 'pl', 'Spikerka/dyskusja', 'Mityng rozpoczynany jest wypowiedzią spikera, a następnie jest otwarty do dzielenia się przez resztę uczestników.', 'FC1'),
-(23, 'SG', NULL, 'SWG', 'pl', 'Przewodnik pracy nad Krokami', 'Mityng koncentruje się na dyskusji nad tekstem z "Przewodnika do pracy nad Krokami".', 'FC1'),
-(24, 'SL', NULL, NULL, 'pl', 'ASL', 'W tym mityngu bierze udział tłumacz języka migowego dla osób niesłyszących.', 'FC2'),
-(26, 'So', NULL, 'SPK', 'pl', 'Tylko spikerka', 'Mityng składa się tylko z wypowiedzi spikera. Inni uczestnicy nie dzielą się doświadczeniem.', 'FC1'),
-(27, 'St', NULL, 'STEP', 'pl', 'Kroki', 'Mityng koncentruje się na dyskusji nad Dwunastoma Krokami Anonimowych Narkomanów.', 'FC1'),
-(28, 'Ti', NULL, NULL, 'pl', 'Licznik czasu', 'Na tym mitngu czas wypowiedzi jest kontrolowany przez licznik czasu.', 'FC1'),
-(29, 'To', NULL, 'TOP', 'pl', 'Dowolny temat', 'Temat tego mityngu jest wybierany przez spikera lub przez sumienie grupy.', 'FC1'),
-(30, 'Tr', NULL, 'TRAD', 'pl', 'Tradycje', 'Mityng koncentruje się na dyskusji nad Dwunastoma Tradycjami NA.', 'FC1'),
-(31, 'TW', NULL, 'TRAD', 'pl', 'Warsztaty z tradycji', 'Mityng koncentruje się na wnikliwej analizje jednej lub wielu z Dwunastu Tradycji Anonimowych Narkomanów', 'FC1'),
-(32, 'W', NULL, 'W', 'pl', 'Kobiety', 'Mityng przeznaczony jedynie dla kobiet.', 'FC3'),
-(33, 'WC', NULL, 'WCHR', 'pl', 'Wózki inwalidzkie', 'Mityng wyposażony w łatwy dostęp dla wózków inwalidzkich.', 'FC2'),
-(34, 'YP', NULL, 'Y', 'pl', 'Młodzi ludzie', 'Mityng koncentruje się na dyskusjach nad potrzebami najmłodszych członków NA.', 'FC3'),
-(35, 'OE', NULL, NULL, 'pl', 'Bez końca', 'Mityng bez ustalonej długości. Trwa tak długo, jak długo są na nim uczestnicy.', 'FC1'),
-(36, 'BK', NULL, 'LIT', 'pl', 'Analiza książek', 'Analiza oficjalnych książek Anonimowych Narkomanów', 'FC1'),
-(37, 'NS', NULL, 'NS', 'pl', 'Zakac palenia', 'Palenie w trakcie tego mityngu jest zabronione.', 'FC1'),
-(38, 'Ag', NULL, NULL, 'pl', 'Agnostycy', 'Mityng dla ludzi o zróżnicowanych stopniach wiary.', 'FC1'),
-(39, 'FD', NULL, NULL, 'pl', 'Piąty i dziesiąty krok', 'Dyskusja nad piątym i dziesiątym krokiem Anonimowych Narkomanów', 'FC1'),
-(40, 'AB', NULL, 'QA', 'pl', 'Temat z koszyka', 'Temat mityngu wybierany jest spośród zaproponowanych niejawnie przez grupę.', 'FC1'),
-(41, 'ME', NULL, 'MED', 'pl', 'Medytacja', 'Uczestnicy tego mityngu zachęcani są do wzięcia udziału w cichej medytacji.', 'FC1'),
-(42, 'RA', NULL, 'RA', 'pl', 'Ograniczone uczestnictwo', 'Miejsce odbywania się mityngu nakłada ograniczenia na to, kto może wziąć udział w mityngu.', 'FC3'),
-(43, 'QA', NULL, 'QA', 'pl', 'Pytania i odpowiedzi', 'Uczestnicy mogą zadawać pytania i oczekiwać odpowiedzi od innych uczestników.', 'FC1'),
-(44, 'CW', NULL, 'CW', 'pl', 'Dzieci mile widziane', 'Dzieci są mile widziane.', 'FC3'),
-(45, 'CP', NULL, 'CPT', 'pl', 'Koncepcje', 'Mityng koncentruje się na dyskusji nad Dwunastoma Koncepcjami Anonimowych Narkomanów.', 'FC1'),
-(46, 'FIN', NULL, 'LANG', 'pl', 'Fiński', 'Mityng odbywa się w języku fińskim', 'LANG'),
-(47, 'ENG', NULL, 'LANG', 'pl', 'Anglojęzyczny', 'Mityng odbywa się w języku angielskim.', 'LANG'),
-(48, 'PER', NULL, 'LANG', 'pl', 'Perski', 'Mityng odbywa się w języku perskim', 'LANG'),
-(49, 'L/R', NULL, 'LANG', 'pl', 'Litewski/rosyjski', 'Mityng odbywa się w języku litewskim/rosyjskim', 'LANG'),
-(51, 'LC', NULL, 'LC', 'pl', 'Życie w czystości', 'Mityng koncentruje się na dyskusji nad tekstem z "Życie w czystości: Podróż trwa nadal".', 'FC1'),
-(52, 'GP', NULL, 'GP', 'pl', 'Guiding Principles', 'Mityng koncentruje się na dyskusji nad tekstem z "Guiding Principles - The Spirit of Our Traditions".', 'FC1'),
-(54, 'VM', NULL, 'VM', 'pl', 'Virtual Meeting', 'Meets Virtually', 'FC2'),
-(55, 'TC', NULL, 'TC', 'pl', 'Temporarily Closed Facility', 'Facility is Temporarily Closed', 'FC2'),
-(56, 'HY', NULL, 'HYBR', 'pl', 'Hybrid Meeting', 'Meets Virtually and In-person', 'FC2');
\ No newline at end of file
diff --git a/src/legacy/local_server/install_wizard/sql_files/InitialFormatsData-pt.sql b/src/legacy/local_server/install_wizard/sql_files/InitialFormatsData-pt.sql
deleted file mode 100644
index 5391796d6..000000000
--- a/src/legacy/local_server/install_wizard/sql_files/InitialFormatsData-pt.sql
+++ /dev/null
@@ -1,55 +0,0 @@
-INSERT INTO `%%PREFIX%%_comdef_formats` (`shared_id_bigint`, `key_string`, `icon_blob`, `worldid_mixed`, `lang_enum`, `name_string`, `description_string`, `format_type_enum`) VALUES
-(1, 'RC', NULL, 'BEG', 'pt', 'Recém-chegados', 'Esta reunião tem foco nas necessidades de novos membros em NA.', 'FC3'),
-(2, 'BL', NULL, 'LANG', 'pt', 'Bilíngue', 'Reunião pode acontecer em duas línguas além de Português.', 'LANG'),
-(3, 'TB', NULL, 'BT', 'pt', 'Texto Básico', 'Esta reunião tem foco no debate sobre o Texto Básico de Narcóticos Anônimos.', 'FC1'),
-(4, 'F', NULL, 'CLOSED', 'pt', 'Fechada', 'Esta reunião fechada para não adictos. Você deve ir apenas se acredita ter problemas com abuso de substâncias.', 'O'),
-(5, 'FF', NULL, 'CH', 'pt', 'Fechada em feriados', 'Esta reunião acontece em local que geralmente é fechado em feirados.', 'FC3'),
-(6, 'VL', NULL, 'CAN', 'pt', 'Luz de velas', 'Esta reunião acontece à luz de velas.', 'FC2'),
-(7, 'CA', NULL, '', 'pt', 'Criança sob supervisão', 'Bem-comportadas, crianças sob supervisão são bem-vindas.', 'FC3'),
-(8, 'D', NULL, 'DISC', 'pt', 'Discussão', 'Esta reunião convida a participação de todos.', 'FC1'),
-(9, 'ES', NULL, 'LANG', 'pt', 'Espanhol', 'Esta reunião acontece em Espanhol.', 'LANG'),
-(10, 'LGBT', NULL, 'GL', 'pt', 'LGBTQ+', 'Reunião de interesse LGBTQ+ em NA.', 'FC3'),
-(11, 'DC', NULL, NULL, 'pt', 'Doença Crônica', 'Esta reunião tem foco nos interesses especiais de pessoas sofrendo de doenças crônicas.', 'FC1'),
-(12, 'IP', NULL, 'PI', 'pt', 'Panfleto Informativo', 'Esta reunião tem foco na discussão sobre um ou mais IPs ou Panfletos Informativos.', 'FC1'),
-(13, 'FUN', NULL, 'IW', 'pt', 'Funciona - Como e Por quê', 'Esta reunião tem foco na discussão do texto do livro Funciona - Como e Por quê.', 'FC1'),
-(14, 'SPH', NULL, 'JFT', 'pt', 'Só Por Hoje', 'Esta reunião tem foco na discussão do texto do livro Só Por Hoje.', 'FC1'),
-(15, 'H', NULL, 'M', 'pt', 'Homens', 'Reunião de interesse masculino em NA', 'FC3'),
-(16, 'PC', NULL, 'NC', 'pt', 'Proibido crianças', 'Por gentileza não trazer crianças a essa reunião.', 'FC3'),
-(17, 'A', NULL, 'OPEN', 'pt', 'Aberta', 'Esta reunião é aberta para adictos e não-adictos. Todos são bem-vindos.', 'O'),
-(18, 'Ind', NULL, NULL, 'pt', 'Indicação', 'Esta reunião tem um formato que consiste que cada pessoa que partilha escolhe a próxima pessoa a partilhar.', 'FC1'),
-(19, 'FR', NULL, 'VAR', 'pt', 'Formato Rotativo', 'Esta reunião muda seu formato a cada reunião.', 'FC1'),
-(20, 'Rr', NULL, NULL, 'pt', 'Round Robin', 'Esta reunião tem um formato fixo de partilha (geralmente em círculo.)', 'FC1'),
-(21, 'CV', NULL, NULL, 'pt', 'Câmera de vigilância', 'Esta reunião acontece em ambiente que tem câmeras de vigilância.', 'FC2'),
-(22, 'TD', NULL, 'S-D', 'pt', 'Temática/Discussão', 'Esta reunião tem um orador, em seguida é aberta a participação dos membros', 'FC1'),
-(23, 'EP', NULL, 'SWG', 'pt', 'Estudo de Passos', 'Esta reunião é de estudo dos passos através do Guia Para Trabalhar os Passos de NA.', 'FC1'),
-(24, 'LS', NULL, NULL, 'pt', 'LSB', 'Esta reunião acontece com ajuda de intérprete de LIBRAS (Língua Brasileira de Sinais).', 'FC2'),
-(26, 'TM', NULL, 'SPK', 'pt', 'Temática', 'Esta reunião é do tipo temática. Não há participação dos membros na discussão.', 'FC1'),
-(27, 'PS', NULL, 'STEP', 'pt', 'Passos', 'Esta reunião é de discussão dos 12 Passos de NA.', 'FC1'),
-(28, 'TP', NULL, NULL, 'pt', 'Tempo de Partilha', 'Esta reunião tem seu tempo de partilha controlado por relógio.', 'FC1'),
-(29, 'To', NULL, 'TOP', 'pt', 'Tópico', 'Esta reunião é baseada em tópico escolhida por um orador ou por consciência de grupo.', 'FC1'),
-(30, 'Tr', NULL, 'TRAD', 'pt', 'Tradições', 'Esta reunião tem foco em discussão das 12 Tradições de NA.', 'FC1'),
-(31, 'TW', NULL, 'TRAD', 'pt', 'Workshop de Tradições', 'Esta reunião envolve uma discussão mais detalhada de uma ou mais das Tradições de N.A.', 'FC1'),
-(32, 'M', NULL, 'W', 'pt', 'Mulheres', 'Reunião de interesse feminino em NA.', 'FC3'),
-(33, 'CadT', NULL, 'WCHR', 'pt', 'Cadeirante Total', 'Esta reunião tem acesso total a cadeirantes.', 'FC2'),
-(34, 'Jv', NULL, 'Y', 'pt', 'Jovens', 'Esta reunião tem foco nos interesses de membros jovens em NA.', 'FC3'),
-(35, 'UP', NULL, NULL, 'pt', 'Último Partilhar', 'Sem duração fixa. A reunião continua até todos os presentes partilharem.', 'FC1'),
-(36, 'EL', NULL, 'LIT', 'pt', 'Estudo de Literatura', 'Reunião de estudo de literaturas aprovadas de NA', 'FC1'),
-(37, 'NF', NULL, 'NS', 'pt', 'Proibido Fumar', 'Não é permitido fumar nessa reunião.', 'FC1'),
-(38, 'Ag', NULL, NULL, 'pt', 'Agnóstico', 'Destinada a pessoas com diferentes graus de fé.', 'FC1'),
-(39, 'QD', NULL, NULL, 'pt', 'Quinto e Décimo', 'Reunião de discussão sobre o Quinto e Décimo Passos', 'FC1'),
-(40, 'ST', NULL, 'QA', 'pt', 'Sorteio de Tópico', 'Um tópico é escolhido através de sugestões sorteadas.', 'FC1'),
-(41, 'ME', NULL, 'MED', 'pt', 'Meditação', 'Esta reunião incentiva seus participantes a se envolverem em meditação silenciosa.', 'FC1'),
-(42, 'AR', NULL, 'RA', 'pt', 'Acesso Restrito', 'Esta reunião esta em local que impõe restrição de acesso às pessoas.', 'FC3'),
-(43, 'PR', NULL, 'QA', 'pt', 'Perguntas e Respostas', 'Os participantes podem fazer perguntas e esperar respostas dos membros do grupo.', 'FC1'),
-(44, 'PC', NULL, 'CW', 'pt', 'Permitido Crianças', 'Crianças são bem-vindas a essa reunião.', 'FC3'),
-(45, 'Con', NULL, 'CPT', 'pt', 'Conceitos', 'Esta reunião tem foco na discussão dos Doze Conceitos de NA.', 'FC1'),
-(46, 'FIN', NULL, 'LANG', 'pt', 'Filandês', 'Reunião em língua filandesa', 'LANG'),
-(47, 'ENG', NULL, 'LANG', 'pt', 'Inglês', 'Reunião em língua inglesa.', 'LANG'),
-(48, 'PER', NULL, 'LANG', 'pt', 'Persa', 'Reunião em língua persa', 'LANG'),
-(49, 'L/R', NULL, 'LANG', 'pt', 'Lituano/Russo', 'Reunião em Lituano/Russo', 'LANG'),
-(51, 'VL', NULL, 'LC', 'pt', 'Vivendo Limpo', 'Esta é uma reunião de discussão do livro Vivendo Limpo-A Jornada Continua.', 'FC1'),
-(52, 'GP', NULL, 'GP', 'pt', 'Guia de Princípios', 'Esta é uma reunião baseada no livro Guia de Princípios - O Espírito das Nossas Tradições .', 'FC1'),
-(53, 'CadP', NULL, 'WCHR', 'pt', 'Cadeirante Parcial', 'Esta reunião tem acesso parcial a cadeirante.', 'FC2'),
-(54, 'VM', NULL, 'VM', 'pt', 'Virtual Meeting', 'Meets Virtually', 'FC2'),
-(55, 'TC', NULL, 'TC', 'pt', 'Temporarily Closed Facility', 'Facility is Temporarily Closed', 'FC2'),
-(56, 'HY', NULL, 'HYBR', 'pt', 'Hybrid Meeting', 'Meets Virtually and In-person', 'FC2');
\ No newline at end of file
diff --git a/src/legacy/local_server/install_wizard/sql_files/InitialFormatsData-ru.sql b/src/legacy/local_server/install_wizard/sql_files/InitialFormatsData-ru.sql
deleted file mode 100644
index fefeb085d..000000000
--- a/src/legacy/local_server/install_wizard/sql_files/InitialFormatsData-ru.sql
+++ /dev/null
@@ -1,53 +0,0 @@
-INSERT INTO `%%PREFIX%%_comdef_formats` (`shared_id_bigint`, `key_string`, `icon_blob`, `worldid_mixed`, `lang_enum`, `name_string`, `description_string`, `format_type_enum`) VALUES
-(1, 'B', NULL, 'BEG', 'ru', 'Начинающие', 'Эта встреча посвящена потребностям новых членов NA.', 'FC3'),
-(2, 'BL', NULL, 'LANG', 'ru', 'Двуязычное ',' На этом совещании могут присутствов Базового Текста Анонимных Наркоманов', 'LANG'),
-(4, 'C', NULL, 'CLOSED', 'ru', 'Закрытая', 'Эта встреча закрыта для не наркоманов. Вам следует присутствовать только в том случае, если вы считаете, что у вас могут быть проблемы со злоупотреблением психоактивными веществами.', 'O'),
-(5, 'CH', NULL, 'CH', 'ru', 'Закрыто по праздникам', 'Эта встреча собирается в учреждении, которое обычно закрыто в праздничные дни.', 'FC3'),
-(6, 'CL', NULL, 'CAN', 'ru', 'Искусственное освещение', 'Эта встреча проводится при свечах.', 'FC2'),
-(7, 'CS', NULL, '', 'ru', 'Дети под присмотром', 'Добро пожаловать, хорошо воспитанные дети приветствуются.', 'FC3'),
-(8, 'D', NULL, 'DISC', 'ru', 'Обсуждение', 'Эта встреча приглашает к участию всех участников.', 'FC1'),
-(9, 'ES', NULL, 'LANG', 'ru', 'Испанский', 'Эта встреча проводится на испанском языке.', 'LANG'),
-(10, 'GL', NULL, 'GL', 'ru', 'Геи / Лесбиянки / трансгендеры', 'Эта встреча посвящена потребностям геев, лесбиянок и транссексуальных членов АН.', 'FC3'),
-(11, 'IL', NULL, NULL, 'ru', 'Болезнь', 'Эта встреча посвящена потребностям членов АН с хроническим заболеванием.', 'FC1'),
-(12, 'IP', NULL, 'IP', 'ru', 'Информационная брошюра', 'Эта встреча посвящена обсуждению одной или нескольких информационных брошюр.', 'FC1'),
-(13, 'IW', NULL, 'IW', 'ru', 'Это работает - как и почему', 'Эта встреча посвящена обсуждению текста «Как это работает - как и почему».', 'FC1'),
-(14, 'JT', NULL, 'JFT', 'ru', 'Только сегодня', 'Эта встреча посвящена обсуждению текста "Только Сегодня"', 'FC1'),
-(15, 'M', NULL, 'M', 'ru', 'Мужчины', 'Эта встреча предназначена только для мужчин.', 'FC3'),
-(16, 'NC', NULL, 'NC', 'ru', 'Без детей', 'Пожалуйста, не приводите детей на эту встречу.', 'FC3'),
-(17, 'O', NULL, 'OPEN', 'ru', 'Открытая', 'Эта встреча открыта как для наркоманов, так и для не наркоманов. Все приветствуются.', 'O'),
-(18, 'Pi', NULL, NULL, 'ru', 'Питч', 'Эта встреча имеет формат, который состоит из каждого участника, который разделяет выбор следующего участника.', 'FC1'),
-(19, 'RF', NULL, 'VAR', 'ru', 'Ротация', 'Эта встреча имеет формат, который изменяется для каждой встречи.', 'FC1'),
-(20, 'Rr', NULL, NULL, 'ru', 'Говорим по кругу', 'Эта встреча имеет фиксированный порядок обмена опытом (высказывания по кругу.)', 'FC1'),
-(21, 'SC', NULL, NULL, 'ru', 'Камеры наблюдения', 'Эта встреча проводится в учреждении с камерами наблюдения.', 'FC2'),
-(22, 'SD', NULL, 'S-D', 'ru', 'Спикерская / Обсуждение', 'Это спикерская, а затем время для обсуждений.', 'FC1'),
-(23, 'SG', NULL, 'SWG', 'ru', 'Руководство по Шагам АН', 'Эта встреча посвящена обсуждению текста руководства по шагам АН.', 'FC1'),
-(24, 'SL', NULL, NULL, 'ru', 'Для глухих', 'Эта встреча предоставляет переводчика американского языка жестов (ASL) для глухих.', 'FC2'),
-(26, 'So', NULL, 'SPK', 'ru', 'Только спикерская', 'Только спикерская. Другие участники не участвуют в обсуждении.', 'FC1'),
-(27, 'St', NULL, 'STEP', 'ru', 'Шаги', 'Эта встреча посвящена обсуждению Двенадцати Шагов АН.', 'FC1'),
-(28, 'Ti', NULL, NULL, 'ru', 'Таймер', 'Время этой встречи ограничено таймером.', 'FC1'),
-(29, 'To', NULL, 'TOP', 'ru', 'Тема', 'Эта встреча основана на теме, выбранной ведущим или групповым.', 'FC1'),
-(30, 'Tr', NULL, 'TRAD', 'ru', 'Традиции', 'Эта встреча посвящена обсуждению Двенадцати Традиций АН.', 'FC1'),
-(31, 'TW', NULL, 'TRAD', 'ru', 'Мастерская Традиций', 'Эта встреча включает в себя подробное обсуждение одной или нескольких из двенадцати традиций А.Н.', 'FC1'),
-(32, 'W', NULL, 'W', 'ru', 'Женская', 'Эта встреча предназначена для участия только женщин.', 'FC3'),
-(33, 'WC', NULL, 'WCHR', 'ru', 'Инвалидное кресло', 'Эта встреча доступна для инвалидов.', 'FC2'),
-(34, 'YP', NULL, 'Y', 'ru', 'Молодые люди', 'Эта встреча ориентирована на потребности молодых членов АН.', 'FC3'),
-(35, 'OE', NULL, NULL, 'ru', 'Неограниченная', 'Нет фиксированной продолжительности. Встреча продолжается до тех пор, пока все присутствующие не смогут поделиться опытом.', 'FC1'),
-(36, 'BK', NULL, 'LIT', 'ru', 'Книжное обучение', 'Утвержденные книги А.Н.', 'FC1'),
-(37, 'NS', NULL, 'NS', 'ru', 'Не курить', 'Курение запрещено на этой встрече.', 'FC1'),
-(38, 'Ag', NULL, NULL, 'ru', 'Агностики', 'Предназначен для людей с разной степенью веры.', 'FC1'),
-(39, 'FD', NULL, NULL, 'ru', 'Пятый и Десятый', 'Обсуждение пятого шага и десятого шага', 'FC1'),
-(40, 'AB', NULL, 'QA', 'ru', 'Коробочка', 'Тема выбирается из предложений, помещенных в коробочку.', 'FC1'),
-(41, 'ME', NULL, 'MED', 'ru', 'Медитация', 'Эта встреча поощряет ее участников заниматься тихой медитацией.', 'FC1'),
-(42, 'RA', NULL, 'RA', 'ru', 'Ограниченная Посещаемость', 'Эта встреча накладывает ограничения на посетителей.', 'FC3'),
-(43, 'QA', NULL, 'QA', 'ru', 'Вопрос и ответ', 'Участники могут задавать вопросы и ожидать ответов от членов группы.', 'FC1'),
-(44, 'CW', NULL, 'CW', 'ru', 'Дети - добро пожаловать', 'Дети приветствуются на этой встрече.', 'FC3'),
-(45, 'CP', NULL, 'CPT', 'ru', 'Концепции', 'Эта встреча посвящена обсуждению двенадцати концепций А.Н.', 'FC1'),
-(46, 'FIN', NULL, 'LANG', 'ru', 'Финский', 'финноязычная встреча', 'LANG'),
-(47, 'ENG', NULL, 'LANG', 'ru', 'Англогоязычный', 'На его собрании могут присутствовать носители английского языка.', 'LANG'),
-(48, 'PER', NULL, 'LANG', 'ru', 'Персидский', 'Собрание проводится на Персидском языке', 'LANG'),
-(49, 'L/R', NULL, 'LANG', 'ru', 'Русский\литовский', 'Русскоговорящие собрания АН', 'LANG'),
-(51, 'LC', NULL, 'LC', 'ru', 'Жить Чистыми', 'Это обсуждение книги АН «Живи чисто - путешествие продолжается».', 'FC1'),
-(52, 'GP', NULL, 'GP', 'ru', 'Руководящие принципы', 'Это обсуждение книги АН «Руководящие принципы - дух наших традиций».', 'FC1'),
-(54, 'VM', NULL, 'VM', 'ru', 'Виртуальная встреча', 'Собираемся онлайн', 'FC2'),
-(55, 'TC', NULL, 'TC', 'ru', 'Временно закрыто', 'Объект временно закрыт', 'FC2'), -- TODO: change name to Temporarily Closed Facility (translated)
-(56, 'HY', NULL, 'HYBR', 'ru', 'Hybrid Meeting', 'Meets Virtually and In-person', 'FC2');
\ No newline at end of file
diff --git a/src/legacy/local_server/install_wizard/sql_files/InitialFormatsData-sv.sql b/src/legacy/local_server/install_wizard/sql_files/InitialFormatsData-sv.sql
deleted file mode 100644
index f8a97824c..000000000
--- a/src/legacy/local_server/install_wizard/sql_files/InitialFormatsData-sv.sql
+++ /dev/null
@@ -1,12 +0,0 @@
-INSERT INTO `%%PREFIX%%_comdef_formats` (`shared_id_bigint`, `key_string`, `icon_blob`, `worldid_mixed`, `lang_enum`, `name_string`, `description_string`, `format_type_enum`) VALUES
-(4, 'S', NULL, 'CLOSED', 'sv', 'Slutet möte', 'Ett slutet NA möte är för de individer som identifierar sig som beroende eller för de som är osäkra och tror att de kanske har drogproblem.', 'FC3'),
-(15, 'M', NULL, 'M', 'sv', 'Mansmöte', 'Detta möte är endast öppet för män.', 'FC3'),
-(17, 'Ö', NULL, 'OPEN', 'sv', 'Öppet möte', 'Ett öppet möte är ett NA-möte där vem som helst som är intresserad av hur vi har funnit tillfrisknande från beroendesjukdomen kan närvara.', 'FC3'),
-(47, 'ENG', NULL, NULL, 'sv', 'Engelska', 'Engelsktalande möte', 'FC3'),
-(48, 'PER', NULL, NULL, 'sv', 'Persiskt', 'Persiskt möte', 'FC1'),
-(32, 'K', NULL, 'W', 'sv', 'Kvinnomöte', 'Detta möte är endast öppet för kvinnor.', 'FC3'),
-(33, 'RL', NULL, 'WCHR', 'sv', 'Rullstolsvänlig lokal', 'Detta möte är tillgängligt för rullstolsbundna.', 'FC2'),
-(47, 'ENG', NULL, NULL, 'sv', 'Engelska', 'Engelsktalande möte', 'FC3'),
-(54, 'VM', NULL, 'VM', 'sv', 'Virtual Meeting', 'Meets Virtually', 'FC2'),
-(55, 'TC', NULL, 'TC', 'sv', 'Temporarily Closed Facility', 'Facility is Temporarily Closed', 'FC2'),
-(56, 'HY', NULL, 'HYBR', 'sv', 'Hybrid Meeting', 'Meets Virtually and In-person', 'FC2');
\ No newline at end of file
diff --git a/src/legacy/local_server/install_wizard/sql_files/InitialMeetingsData.sql b/src/legacy/local_server/install_wizard/sql_files/InitialMeetingsData.sql
deleted file mode 100644
index 432154c26..000000000
--- a/src/legacy/local_server/install_wizard/sql_files/InitialMeetingsData.sql
+++ /dev/null
@@ -1,24 +0,0 @@
-INSERT INTO `%%PREFIX%%_comdef_meetings_data` (`meetingid_bigint`, `key`, `field_prompt`, `lang_enum`, `visibility`, `data_string`, `data_bigint`, `data_double`) VALUES
-(0, 'meeting_name', 'Meeting Name', 'en', 0, 'Meeting Name', NULL, NULL),
-(0, 'location_text', 'Location Name', 'en', 0, 'Location Name', NULL, NULL),
-(0, 'location_info', 'Additional Location Information', 'en', 0, 'Additional Location Information', NULL, NULL),
-(0, 'location_street', 'Street Address', 'en', 0, 'Street Address', NULL, NULL),
-(0, 'location_city_subsection', 'Borough', 'en', 0, 'Borough', NULL, NULL),
-(0, 'location_neighborhood', 'Neighborhood', 'en', 0, 'Neighborhood', NULL, NULL),
-(0, 'location_municipality', 'Town', 'en', 0, 'Town', NULL, NULL),
-(0, 'location_sub_province', 'County', 'en', 0, 'County', NULL, NULL),
-(0, 'location_province', 'State', 'en', 0, 'State', NULL, NULL),
-(0, 'location_postal_code_1', 'Zip Code', 'en', 0, NULL, 0, NULL),
-(0, 'location_nation', 'Nation', 'en', 0, 'Nation', NULL, NULL),
-(0, 'comments', 'Comments', 'en', 0, 'Comments', NULL, NULL),
-(0, 'train_lines', 'Train Lines', 'en', 0, NULL, NULL, NULL),
-(0, 'bus_lines', 'Bus Lines', 'en', 0, NULL, NULL, NULL),
-(0, 'contact_phone_2', 'Contact 2 Phone', 'en', 1, 'Contact 2 Phone', NULL, NULL),
-(0, 'contact_email_2', 'Contact 2 Email', 'en', 1, 'Contact 2 Email', NULL, NULL),
-(0, 'contact_name_2', 'Contact 2 Name', 'en', 1, 'Contact 2 Name', NULL, NULL),
-(0, 'contact_phone_1', 'Contact 1 Phone', 'en', 1, 'Contact 1 Phone', NULL, NULL),
-(0, 'contact_email_1', 'Contact 1 Email', 'en', 1, 'Contact 1 Email', NULL, NULL),
-(0, 'contact_name_1', 'Contact 1 Name', 'en', 1, 'Contact 1 Name', NULL, NULL),
-(0, 'phone_meeting_number', 'Phone Meeting Dial-in Number', 'en', 0, 'Phone Meeting Dial-in Number', NULL, NULL),
-(0, 'virtual_meeting_link', 'Virtual Meeting Link', 'en', 0, 'Virtual Meeting Link', NULL, NULL),
-(0, 'virtual_meeting_additional_info', 'Virtual Meeting Additional Info', 'en', 0, 'Virtual Meeting Additional Info', NULL, NULL);
diff --git a/src/legacy/local_server/install_wizard/sql_files/InitialUsersStructure.sql b/src/legacy/local_server/install_wizard/sql_files/InitialUsersStructure.sql
deleted file mode 100644
index 0f838b73d..000000000
--- a/src/legacy/local_server/install_wizard/sql_files/InitialUsersStructure.sql
+++ /dev/null
@@ -1,19 +0,0 @@
-CREATE TABLE `%%PREFIX%%_comdef_users` (
- `id_bigint` bigint(20) unsigned NOT NULL auto_increment,
- `user_level_tinyint` tinyint(4) unsigned NOT NULL default '0',
- `name_string` tinytext NOT NULL,
- `description_string` text NOT NULL,
- `email_address_string` varchar(255) NOT NULL,
- `login_string` varchar(255) NOT NULL,
- `password_string` varchar(255) NOT NULL,
- `last_access_datetime` datetime NOT NULL default '1970-01-01 00:00:00',
- `lang_enum` varchar(7) NOT NULL default 'en',
- `owner_id_bigint` BIGINT(20) NOT NULL default -1,
- PRIMARY KEY (`id_bigint`),
- UNIQUE KEY `login_string` (`login_string`),
- KEY `user_level_tinyint` (`user_level_tinyint`),
- KEY `email_address_string` (`email_address_string`),
- KEY `last_access_datetime` (`last_access_datetime`),
- KEY `lang_enum` (`lang_enum`),
- KEY `owner_id_bigint` (`owner_id_bigint`)
-) DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;
diff --git a/src/legacy/local_server/install_wizard/sql_files/dropEverything.sql b/src/legacy/local_server/install_wizard/sql_files/dropEverything.sql
deleted file mode 100644
index fab3b8c9d..000000000
--- a/src/legacy/local_server/install_wizard/sql_files/dropEverything.sql
+++ /dev/null
@@ -1,11 +0,0 @@
-DROP TABLE `%%PREFIX%%_comdef_changes`;
-DROP TABLE `%%PREFIX%%_comdef_db_version`;
-DROP TABLE `%%PREFIX%%_comdef_formats`;
-DROP TABLE `%%PREFIX%%_comdef_meetings_main`;
-DROP TABLE `%%PREFIX%%_comdef_meetings_data`;
-DROP TABLE `%%PREFIX%%_comdef_meetings_longdata`;
-DROP TABLE `%%PREFIX%%_comdef_service_bodies`;
-DROP TABLE `%%PREFIX%%_comdef_users`;
-DROP TABLE `%%PREFIX%%_migrations`;
-DROP TABLE `%%PREFIX%%_sessions`;
-DROP TABLE `%%PREFIX%%_personal_access_tokens`;
diff --git a/src/legacy/local_server/install_wizard/sql_files/initialChangesStructure.sql b/src/legacy/local_server/install_wizard/sql_files/initialChangesStructure.sql
deleted file mode 100644
index af95df8c3..000000000
--- a/src/legacy/local_server/install_wizard/sql_files/initialChangesStructure.sql
+++ /dev/null
@@ -1,28 +0,0 @@
-CREATE TABLE `%%PREFIX%%_comdef_changes` (
- `id_bigint` bigint(20) unsigned NOT NULL auto_increment,
- `user_id_bigint` bigint(20) unsigned NOT NULL,
- `service_body_id_bigint` bigint(20) unsigned NOT NULL,
- `lang_enum` varchar(7) NOT NULL,
- `change_date` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,
- `object_class_string` varchar(64) NOT NULL,
- `change_name_string` tinytext,
- `change_description_text` text,
- `before_id_bigint` bigint(20) unsigned default NULL,
- `before_lang_enum` varchar(7) default NULL,
- `after_id_bigint` bigint(20) unsigned default NULL,
- `after_lang_enum` varchar(7) default NULL,
- `change_type_enum` varchar(32) NOT NULL,
- `before_object` blob,
- `after_object` blob,
- PRIMARY KEY (`id_bigint`),
- KEY `user_id_bigint` (`user_id_bigint`),
- KEY `service_body_id_bigint` (`service_body_id_bigint`),
- KEY `lang_enum` (`lang_enum`),
- KEY `change_type_enum` (`change_type_enum`),
- KEY `change_date` (`change_date`),
- KEY `before_id_bigint` (`before_id_bigint`),
- KEY `after_id_bigint` (`after_id_bigint`),
- KEY `before_lang_enum` (`before_lang_enum`),
- KEY `after_lang_enum` (`after_lang_enum`),
- KEY `object_class_string` (`object_class_string`)
-) DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;
diff --git a/src/legacy/local_server/install_wizard/sql_files/initialDbVersionData.sql b/src/legacy/local_server/install_wizard/sql_files/initialDbVersionData.sql
deleted file mode 100644
index aa902db4a..000000000
--- a/src/legacy/local_server/install_wizard/sql_files/initialDbVersionData.sql
+++ /dev/null
@@ -1 +0,0 @@
-INSERT INTO `%%PREFIX%%_comdef_db_version` VALUES (21);
diff --git a/src/legacy/local_server/install_wizard/sql_files/initialDbVersionStructure.sql b/src/legacy/local_server/install_wizard/sql_files/initialDbVersionStructure.sql
deleted file mode 100644
index 8b3c1833d..000000000
--- a/src/legacy/local_server/install_wizard/sql_files/initialDbVersionStructure.sql
+++ /dev/null
@@ -1 +0,0 @@
-CREATE TABLE `%%PREFIX%%_comdef_db_version` (version INT);
diff --git a/src/legacy/local_server/install_wizard/sql_files/initialFormatsStructure.sql b/src/legacy/local_server/install_wizard/sql_files/initialFormatsStructure.sql
deleted file mode 100644
index 1ebc2e1ee..000000000
--- a/src/legacy/local_server/install_wizard/sql_files/initialFormatsStructure.sql
+++ /dev/null
@@ -1,15 +0,0 @@
-CREATE TABLE `%%PREFIX%%_comdef_formats` (
- `shared_id_bigint` bigint(20) unsigned NOT NULL,
- `key_string` varchar(255) default NULL,
- `icon_blob` longblob,
- `worldid_mixed` varchar(255) default NULL,
- `lang_enum` varchar(7) NOT NULL default 'en',
- `name_string` tinytext,
- `description_string` text,
- `format_type_enum` varchar(7) default 'FC1',
- KEY `shared_id_bigint` (`shared_id_bigint`),
- KEY `worldid_mixed` (`worldid_mixed`),
- KEY `format_type_enum` (`format_type_enum`),
- KEY `lang_enum` (`lang_enum`),
- KEY `key_string` (`key_string`)
-) DEFAULT CHARSET=utf8;
diff --git a/src/legacy/local_server/install_wizard/sql_files/initialMeetingsStructure.sql b/src/legacy/local_server/install_wizard/sql_files/initialMeetingsStructure.sql
deleted file mode 100644
index 21694e8a5..000000000
--- a/src/legacy/local_server/install_wizard/sql_files/initialMeetingsStructure.sql
+++ /dev/null
@@ -1,62 +0,0 @@
-CREATE TABLE `%%PREFIX%%_comdef_meetings_main` (
- `id_bigint` bigint(20) unsigned NOT NULL auto_increment,
- `worldid_mixed` varchar(255) default NULL,
- `shared_group_id_bigint` bigint(20) default NULL,
- `service_body_bigint` bigint(20) unsigned NOT NULL,
- `weekday_tinyint` tinyint(4) unsigned default NULL,
- `venue_type` tinyint(4) unsigned default NULL,
- `start_time` time default NULL,
- `duration_time` time default NULL,
- `time_zone` varchar(40) default NULL,
- `formats` varchar(255) default NULL,
- `lang_enum` varchar(7) default NULL,
- `longitude` double default NULL,
- `latitude` double default NULL,
- `published` tinyint(4) NOT NULL default '0',
- `email_contact` varchar(255) default NULL,
- PRIMARY KEY (`id_bigint`),
- KEY `weekday_tinyint` (`weekday_tinyint`),
- KEY `venue_type` (`venue_type`),
- KEY `service_body_bigint` (`service_body_bigint`),
- KEY `start_time` (`start_time`),
- KEY `duration_time` (`duration_time`),
- KEY `time_zone` (`time_zone`),
- KEY `formats` (`formats`),
- KEY `lang_enum` (`lang_enum`),
- KEY `worldid_mixed` (`worldid_mixed`),
- KEY `shared_group_id_bigint` (`shared_group_id_bigint`),
- KEY `longitude` (`longitude`),
- KEY `latitude` (`latitude`),
- KEY `published` (`published`),
- KEY `email_contact` (`email_contact`)
-) DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;
-CREATE TABLE `%%PREFIX%%_comdef_meetings_data` (
- `meetingid_bigint` bigint(20) unsigned NOT NULL,
- `key` varchar(32) NOT NULL,
- `field_prompt` tinytext,
- `lang_enum` varchar(7) default NULL,
- `visibility` int(1) default NULL,
- `data_string` tinytext,
- `data_bigint` bigint(20) default NULL,
- `data_double` double default NULL,
- KEY `data_bigint` (`data_bigint`),
- KEY `data_double` (`data_double`),
- KEY `meetingid_bigint` (`meetingid_bigint`),
- KEY `lang_enum` (`lang_enum`),
- KEY `key` (`key`),
- KEY `visibility` (`visibility`)
-) DEFAULT CHARSET=utf8;
-CREATE TABLE `%%PREFIX%%_comdef_meetings_longdata` (
- `meetingid_bigint` bigint(20) unsigned NOT NULL,
- `key` varchar(32) NOT NULL,
- `field_prompt` varchar(255) default NULL,
- `lang_enum` varchar(7) default NULL,
- `visibility` int(1) default NULL,
- `data_longtext` text,
- `data_blob` blob,
- KEY `meetingid_bigint` (`meetingid_bigint`),
- KEY `lang_enum` (`lang_enum`),
- KEY `field_prompt` (`field_prompt`),
- KEY `key` (`key`),
- KEY `visibility` (`visibility`)
-) DEFAULT CHARSET=utf8;
diff --git a/src/legacy/local_server/install_wizard/sql_files/initialServiceBodiesStructure.sql b/src/legacy/local_server/install_wizard/sql_files/initialServiceBodiesStructure.sql
deleted file mode 100644
index 52fe8f864..000000000
--- a/src/legacy/local_server/install_wizard/sql_files/initialServiceBodiesStructure.sql
+++ /dev/null
@@ -1,26 +0,0 @@
-CREATE TABLE `%%PREFIX%%_comdef_service_bodies` (
- `id_bigint` bigint(20) unsigned NOT NULL auto_increment,
- `name_string` tinytext NOT NULL,
- `description_string` text NOT NULL,
- `lang_enum` varchar(7) NOT NULL default 'en',
- `worldid_mixed` varchar(255) default NULL,
- `kml_file_uri_string` varchar(255) default NULL,
- `principal_user_bigint` bigint(20) unsigned default NULL,
- `editors_string` varchar(255) default NULL,
- `uri_string` varchar(255) default NULL,
- `sb_type` varchar(32) default NULL,
- `sb_owner` bigint(20) unsigned default NULL,
- `sb_owner_2` bigint(20) unsigned default NULL,
- `sb_meeting_email` varchar(255) NOT NULL default '',
- PRIMARY KEY (`id_bigint`),
- KEY `worldid_mixed` (`worldid_mixed`),
- KEY `kml_file_uri_string` (`kml_file_uri_string`),
- KEY `principal_user_bigint` (`principal_user_bigint`),
- KEY `editors_string` (`editors_string`),
- KEY `lang_enum` (`lang_enum`),
- KEY `uri_string` (`uri_string`),
- KEY `sb_type` (`sb_type`),
- KEY `sb_owner` (`sb_owner`),
- KEY `sb_owner_2` (`sb_owner_2`),
- KEY `sb_meeting_email` (`sb_meeting_email`)
-) DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;
diff --git a/src/legacy/local_server/install_wizard/sql_files/serverAdmin.sql b/src/legacy/local_server/install_wizard/sql_files/serverAdmin.sql
deleted file mode 100644
index 277bc29a5..000000000
--- a/src/legacy/local_server/install_wizard/sql_files/serverAdmin.sql
+++ /dev/null
@@ -1 +0,0 @@
-INSERT INTO `%%PREFIX%%_comdef_users` (`id_bigint`, `user_level_tinyint`, `name_string`, `description_string`, `email_address_string`, `login_string`, `password_string`, `lang_enum`) VALUES ( 1, 1, ?, ?, '', ?, ?, ? );
\ No newline at end of file
diff --git a/src/legacy/local_server/server_admin/NAWSImport.php b/src/legacy/local_server/server_admin/NAWSImport.php
deleted file mode 100644
index 55cea27b6..000000000
--- a/src/legacy/local_server/server_admin/NAWSImport.php
+++ /dev/null
@@ -1,458 +0,0 @@
-load($importFilePath);
- $this->nawsExportRows = $spreadsheet->getActiveSheet()->toArray(null, true, true, true);
- $this->initialValueForPublished = $initialValueForPublished;
-
- // If the last row is all nulls, remove it
- $lastRow = $this->nawsExportRows[count($this->nawsExportRows)];
- $allNulls = true;
- foreach ($lastRow as $columnValue) {
- if ($columnValue != null) {
- $allNulls = false;
- break;
- }
- }
- if ($allNulls) {
- array_pop($this->nawsExportRows);
- }
- } catch (Exception $e) {
- throw new Exception('There was a problem reading the spreadsheet: ' . $e->getMessage());
- }
-
-
- // Lowercase all of the headings for case insensitive string matching
- foreach ($this->nawsExportRows[1] as $key => $value) {
- if ($value) {
- $this->nawsExportRows[1][$key] = strtolower($value);
- }
- }
-
- // Validate there are no missing columns, and set the $this->columnNames map
- $missingValues = array();
- foreach ($this->expectedColumns as $expectedColumnName) {
- $idx = array_search($expectedColumnName, $this->nawsExportRows[1]);
- if (is_bool($idx)) {
- array_push($missingValues, $expectedColumnName);
- } else {
- $this->columnNames[$idx] = $expectedColumnName;
- }
- }
- if (count($missingValues) > 0) {
- throw new Exception('NAWS export is missing required columns: ' . implode(', ', $missingValues));
- }
-
- // Store the column index for these important columns
- $this->deleteIndex = array_search('delete', $this->columnNames);
- $this->areaNameIndex = array_search('parentname', $this->columnNames);
- $this->areaWorldIdIndex = array_search('arearegion', $this->columnNames);
- $this->worldIdIndex = array_search('committee', $this->columnNames);
- }
-
- public function import($failOnDuplicates = false)
- {
- set_time_limit(1200); // 20 minutes
- require_once(__DIR__ . '/../../server/classes/c_comdef_meeting.class.php');
- require_once(__DIR__ . '/../../server/classes/c_comdef_service_body.class.php');
- require_once(__DIR__ . '/../../server/classes/c_comdef_user.class.php');
- $this->server = c_comdef_server::MakeServer();
- c_comdef_dbsingleton::beginTransaction();
- try {
- if ($failOnDuplicates) {
- $this->throwIfDuplicateServiceBodies();
- $this->throwIfDuplicateMeetings();
- }
- $this->createServiceBodiesAndUsers();
- $this->createMeetings();
- } catch (NAWSImportServiceBodiesExistException $e) {
- c_comdef_dbsingleton::rollBack();
- throw $e;
- } catch (NAWSImportMeetingsExistException $e) {
- c_comdef_dbsingleton::rollBack();
- throw $e;
- } catch (Exception $e) {
- c_comdef_dbsingleton::rollBack();
- throw new Exception($e->getMessage());
- }
- c_comdef_dbsingleton::commit();
- }
-
- private function createServiceBodiesAndUsers()
- {
- // Create the service bodies
- for ($i = 1; $i <= count($this->nawsExportRows); $i++) {
- $row = $this->nawsExportRows[$i];
-
- if ($i == 1) {
- continue;
- }
-
- if ($row[$this->deleteIndex] == 'D') {
- continue;
- }
-
- $areaName = trim($row[$this->areaNameIndex]);
- $areaWorldId = trim($row[$this->areaWorldIdIndex]);
- if (!$areaName) {
- continue;
- }
- $this->areas[$areaWorldId] = $areaName;
- }
-
- foreach ($this->areas as $areaWorldId => $areaName) {
- $userName = preg_replace("/[^A-Za-z0-9]/", '', $areaName);
- $user = new c_comdef_user(
- null,
- 0,
- _USER_LEVEL_SERVICE_BODY_ADMIN,
- '',
- $userName,
- '',
- $this->server->GetLocalLang(),
- $userName,
- 'User automatically created for ' . $areaName,
- 1
- );
- $user->SetPassword($this->generateRandomString(30));
- $user->UpdateToDB();
- $this->numUsersCreated++;
-
- $serviceBody = new c_comdef_service_body;
- $serviceBody->SetLocalName($areaName);
- $serviceBody->SetWorldID($areaWorldId);
- $serviceBody->SetLocalDescription($areaName);
- $serviceBody->SetPrincipalUserID($user->GetID());
- $serviceBody->SetEditors(array($user->GetID()));
- if (substr($areaWorldId, 0, 2) == 'AR') {
- $serviceBody->SetSBType(c_comdef_service_body__ASC__);
- } else {
- $serviceBody->SetSBType(c_comdef_service_body__RSC__);
- }
- $serviceBody->UpdateToDB();
- $this->numServiceBodiesCreated++;
- $this->areas[$areaWorldId] = $serviceBody;
- }
-
- reset($this->nawsExportRows);
- }
-
- private function createMeetings()
- {
- $defaultDurationTime = $this->server->GetLocalStrings()['default_duration_time'];
-
- $formats = array();
- foreach ($this->server->GetFormatsObj()->GetFormatsArray()['en'] as $format) {
- if ($format instanceof c_comdef_format) {
- $world_id = $format->GetWorldID();
- $shared_id = $format->GetSharedID();
- if ($world_id && $shared_id) {
- if (is_array($formats) && array_key_exists($world_id, $formats)) {
- array_push($formats[$world_id], $shared_id);
- } else {
- $formats[$world_id] = array($shared_id);
- }
- }
- }
- }
-
- $ajaxHandler = new c_comdef_admin_ajax_handler(null);
- $nawsDays = array(null, 'sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday');
- // State is not a required column, because it is not always filled out for foreign countries
- // to allow importing virtual meetings, also drop address and city as required columns
- $requiredColumns = array('committeename', 'arearegion', 'day', 'time');
- for ($i = 1; $i <= count($this->nawsExportRows); $i++) {
- $row = $this->nawsExportRows[$i];
- if ($i == 1) {
- continue;
- }
-
- if ($row[$this->deleteIndex] == 'D') {
- continue;
- }
-
- $meetingData = array();
- $meetingData['published'] = $this->initialValueForPublished;
- $meetingData['lang_enum'] = $this->server->GetLocalLang();
- $meetingData['duration_time'] = $defaultDurationTime;
- $meetingData['format_shared_id_list'] = array();
- $skipMeeting = false;
- foreach ($this->columnNames as $columnIndex => $columnName) {
- $value = trim($row[$columnIndex]);
-
- // NAWS exports sometimes contain deleted meetings, and will have empty cells
- // for those meetings. Just skip them.
- if (!is_bool(array_search($columnName, $requiredColumns)) && !$value) {
- $skipMeeting = true;
- break;
- }
-
- switch ($columnName) {
- case 'committee':
- $meetingData['worldid_mixed'] = $value;
- break;
- case 'committeename':
- $meetingData['meeting_name'] = $value;
- break;
- case 'arearegion':
- $meetingData['service_body_bigint'] = $this->areas[$row[$this->areaWorldIdIndex]]->GetID();
- break;
- case 'day':
- $value = strtolower($value);
- $value = array_search($value, $nawsDays);
- if ($value == false) {
- throw new Exception('Invalid value in column \'' . $columnName . '\'');
- }
- $meetingData['weekday_tinyint'] = $value;
- break;
- case 'time':
- $time = abs(intval($value));
- $hours = min(23, $time / 100);
- $minutes = min(59, ($time - (intval($time / 100) * 100)));
- $meetingData['start_time'] = sprintf("%d:%02d:00", $hours, $minutes);
- break;
- case 'place':
- $meetingData['location_text'] = $value;
- break;
- case 'address':
- $meetingData['location_street'] = $value;
- break;
- case 'city':
- $meetingData['location_municipality'] = $value;
- break;
- case 'locborough':
- $meetingData['location_neighborhood'] = $value;
- break;
- case 'state':
- $meetingData['location_province'] = $value;
- break;
- case 'zip':
- $meetingData['location_postal_code_1'] = $value;
- break;
- case 'country':
- $meetingData['location_nation'] = $value;
- break;
- case 'room':
- case 'directions':
- if ($meetingData['location_info'] ?? false) {
- if ($value) {
- if ($columnName == 'directions') {
- $meetingData['location_info'] .= ', ' . $value;
- } else {
- $meetingData['location_info'] = $value . ', ' . $meetingData['location_info'];
- }
- }
- } else {
- $meetingData['location_info'] = $value;
- }
- break;
- case 'wheelchr':
- $value = strtolower($value);
- if ($value == 'true' || $value == '1') {
- $value = $formats['WCHR'];
- if ($value) {
- $meetingData['format_shared_id_list'] = array_merge($meetingData['format_shared_id_list'], $value);
- }
- }
- break;
- case 'closed':
- case 'format1':
- case 'format2':
- case 'format3':
- case 'format4':
- case 'format5':
- $value = $formats[$value] ?? false;
- if ($value) {
- $meetingData['format_shared_id_list'] = array_merge($meetingData['format_shared_id_list'], $value);
- }
- break;
- case 'longitude':
- $meetingData['longitude'] = $value;
- break;
- case 'latitude':
- $meetingData['latitude'] = $value;
- break;
- case 'phonemeetingnumber':
- $meetingData['phone_meeting_number'] = $value;
- break;
- case 'virtualmeetinglink':
- $meetingData['virtual_meeting_link'] = $value;
- break;
- case 'virtualmeetinginfo':
- $meetingData['virtual_meeting_additional_info'] = $value;
- break;
- case 'timezone':
- $meetingData['time_zone'] = $value;
- break;
- case 'unpublished':
- if ($value == '1') {
- $meetingData['published'] = false;
- }
- break;
- }
- }
-
- if ($skipMeeting) {
- continue;
- }
-
- $meetingData['format_shared_id_list'] = implode(',', $meetingData['format_shared_id_list']);
- $ajaxHandler->SetMeetingDataValues($meetingData, false);
- $this->numMeetingsCreated++;
- }
- }
-
- private function throwIfDuplicateServiceBodies()
- {
- $duplicates = array();
- $existingWorldIds = array();
- $select = "SELECT DISTINCT `worldid_mixed` FROM `" . c_comdef_server::GetServiceBodiesTableName_obj() . "`;";
- $rows = c_comdef_dbsingleton::preparedQuery($select);
- if (is_array($rows) && count($rows)) {
- foreach ($rows as $row) {
- if (!$row['worldid_mixed']) {
- continue;
- }
- $worldId = strtoupper(trim($row['worldid_mixed']));
- if ($worldId) {
- $existingWorldIds[$worldId] = null;
- }
- }
- }
-
- for ($i = 1; $i <= count($this->nawsExportRows); $i++) {
- $row = $this->nawsExportRows[$i];
- if ($i == 1) {
- continue;
- }
-
- if ($row[$this->deleteIndex] == 'D') {
- continue;
- }
-
- $worldId = $row[$this->areaWorldIdIndex];
- if (!$worldId) {
- continue;
- }
-
- $worldId = strtoupper(trim($worldId));
- if (!$worldId) {
- continue;
- }
-
- if (array_key_exists($worldId, $existingWorldIds)) {
- $duplicates[$worldId] = null;
- }
- }
-
- $duplicates = array_keys($duplicates);
- if (count($duplicates)) {
- throw new NAWSImportServiceBodiesExistException($duplicates);
- }
-
- reset($this->nawsExportRows);
- }
-
- private function throwIfDuplicateMeetings()
- {
- $duplicates = array();
- $existingWorldIds = array();
- $select = "SELECT DISTINCT `worldid_mixed` FROM `" . c_comdef_server::GetMeetingTableName_obj() . "_main`;";
- $rows = c_comdef_dbsingleton::preparedQuery($select);
- if (is_array($rows) && count($rows)) {
- foreach ($rows as $row) {
- if (!$row['worldid_mixed']) {
- continue;
- }
- $worldId = strtoupper(trim($row['worldid_mixed']));
- if ($worldId) {
- $existingWorldIds[$worldId] = null;
- }
- }
- }
-
- for ($i = 1; $i <= count($this->nawsExportRows); $i++) {
- $row = $this->nawsExportRows[$i];
- if ($i == 1) {
- continue;
- }
-
- if ($row[$this->deleteIndex] == 'D') {
- continue;
- }
-
- $worldId = $row[$this->worldIdIndex];
- if (!$worldId) {
- continue;
- }
-
- $worldId = strtoupper(trim($worldId));
- if (!$worldId) {
- continue;
- }
-
- if (array_key_exists($worldId, $existingWorldIds)) {
- $duplicates[$worldId] = null;
- }
- }
-
- $duplicates = array_keys($duplicates);
- if (count($duplicates)) {
- throw new NAWSImportMeetingsExistException($duplicates);
- }
-
- reset($this->nawsExportRows);
- }
-
- private function generateRandomString($length = 10)
- {
- return substr(str_shuffle(str_repeat($x = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', ceil($length/strlen($x)))), 1, $length);
- }
-
- public function getNumServiceBodiesCreated()
- {
- return $this->numServiceBodiesCreated;
- }
-
- public function getNumUsersCreated()
- {
- return $this->numUsersCreated;
- }
-
- public function getNumMeetingsCreated()
- {
- return $this->numMeetingsCreated;
- }
-}
diff --git a/src/legacy/local_server/server_admin/NAWSImportMeetingsExistException.php b/src/legacy/local_server/server_admin/NAWSImportMeetingsExistException.php
deleted file mode 100644
index b8806e46f..000000000
--- a/src/legacy/local_server/server_admin/NAWSImportMeetingsExistException.php
+++ /dev/null
@@ -1,19 +0,0 @@
-worldIds = $worldIds;
- parent::__construct();
- }
-
- public function getWorldIds()
- {
- return $this->worldIds;
- }
-}
diff --git a/src/legacy/local_server/server_admin/NAWSImportServiceBodiesExistException.php b/src/legacy/local_server/server_admin/NAWSImportServiceBodiesExistException.php
deleted file mode 100644
index 1fd26ca98..000000000
--- a/src/legacy/local_server/server_admin/NAWSImportServiceBodiesExistException.php
+++ /dev/null
@@ -1,19 +0,0 @@
-worldIds = $worldIds;
- parent::__construct();
- }
-
- public function getWorldIds()
- {
- return $this->worldIds;
- }
-}
diff --git a/src/legacy/local_server/server_admin/PhpJsonXmlArrayStringInterchanger.inc.php b/src/legacy/local_server/server_admin/PhpJsonXmlArrayStringInterchanger.inc.php
deleted file mode 100644
index 23fd05b31..000000000
--- a/src/legacy/local_server/server_admin/PhpJsonXmlArrayStringInterchanger.inc.php
+++ /dev/null
@@ -1,273 +0,0 @@
-errorLog);
- if ($c>0) {
- $i=$c-1;
- $return="
".$this->errorLog[$i]."
";
- }
- echo $return;
- }
-
- /**
- * Function to display complete error log for debugging purpose
- *
- * @access public
- * @return string
- */
- public function displayErrorLog()
- {
- $return="No errors were encountered.";
- $c=count($this->errorLog);
- if ($c>0) {
- $return="";
- for ($i=0; $i<$c; $i++) {
- $return.="
".$this->errorLog[$i]."
";
- }
- }
- echo $return;
- }
-
- /**
- * Function to recursivly parse Xml Content
- *
- * @param mixed $ret
- * @access private
- * @return array on success and false on failure
- */
- private function parseXml($ret)
- {
- $return=false;
- if (is_object($ret)) {
- $ret=(array)$ret;
- $this->parseXml($ret);
- }
- if (is_array($ret)) {
- foreach ($ret as $k => $v) {
- if (is_object($v)) {
- $return[$k]=$this->parseXml($v);
- } else {
- $return[$k]=$v ;
- }
- }
- }
- return $return;
- }
-
- /**
- * Function to convert XML into Array
- *
- * @param string $xmlContent
- * @access public
- * @return array on success and false on failure
- */
- public function convertXmlToArray($xmlContent)
- {
- $return=false;
- $ret=simplexml_load_string($xmlContent);
- if ($ret===false) {
- $this->errorLog[]="Invalid XML content: $xmlContent in function: ".__FUNCTION__." on line: ".__LINE__." in filename= ".__FILE__;
- return false;
- } else {
- $return=$this->parseXml($ret);
- if ($return===false) {
- $this->errorLog[]="Failed to parse XML content in function: ".__FUNCTION__." on line: ".__LINE__." in filename= ".__FILE__;
- return false;
- }
- }
- return $return;
- }
-
- /**
- * Function to recursivly parse Array Content
- *
- * @param mixed $ret
- * @access private
- * @return string(xml) on success and false on failure
- */
- private function parseArray($array)
- {
- if (is_array($array)) {
- foreach ($array as $k => $v) {
- if (trim($k)=="") {
- $this->errorLog[]="Array needs to be associative as parameter in function: ".__FUNCTION__." on line: ".__LINE__." in filename= ".__FILE__;
- return false;
- } else {
- if (is_numeric($k)) {
- $k="nodeValue$k";
- }
- if (is_array($v)) {
- $return.="<$k>".$this->parseArray($v)."$k>";
- } else {
- $return.="<$k>$v$k>";
- }
- }
- }
- } else {
- $this->errorLog[]="Invalid array in function: ".__FUNCTION__." on line: ".__LINE__." in filename= ".__FILE__;
- return false;
- }
- return $return;
- }
-
- /**
- * Function to convert an associative array into XML
- *
- * @param string $array
- * @access public
- * @return string(xml) on success and false on failure
- */
- public function convertArrayToXML($array)
- {
- $return="";
- $return.=$this->parseArray($array);
- $return.="";
- return $return;
- }
-
- /**
- * Function to convert an JSON into XML
- *
- * @param string $json
- * @access public
- * @return string(xml) on success and false on failure
- */
- public function convertJsonToXML($json)
- {
- if (!is_string($json)) {
- $this->errorLog[]="The first parameter should to be string in function: ".__FUNCTION__." on line: ".__LINE__." in filename= ".__FILE__;
- return false;
- }
- $array=json_decode($json, true);
- if ($array===false) {
- $this->errorLog[]="Failed to decode JSON in function: ".__FUNCTION__." on line: ".__LINE__." in filename= ".__FILE__;
- return false;
- } else {
- return $this->convertArrayToXML($array);
- }
- }
-
- /**
- * Function to convert an JSON into array
- *
- * @param string $json
- * @access public
- * @return array on success and false on failure
- */
- public function convertJsonToArray($json)
- {
- if (!is_string($json)) {
- $this->errorLog[]="The first parameter should to be string in function: ".__FUNCTION__." on line: ".__LINE__." in filename= ".__FILE__;
- return false;
- }
- $json=str_replace("\\'", "'", $json);
- $json=str_replace('\\"', '"', $json);
- $array=json_decode($json, true);
- if ($array===false) {
- $this->errorLog[]="Failed to decode JSON in function: ".__FUNCTION__." on line: ".__LINE__." in filename= ".__FILE__;
- return false;
- } else {
- return $array;
- }
- }
-
-
- /**
- * Function to parse String and convert it into array
- *
- * @param array $array
- * @access public
- * @return array on success and false on failure
- * @todo refactor the code from line 205-222 (automate it)
- */
- public function convertStringToArray($string, &$myarray = "")
- {
- $lines = explode(LINE_SEPERATOR, $string);
- foreach ($lines as $value) {
- $items = explode(NODE_SEPERATOR, $value);
- if (sizeof($items) == 2) {
- $myarray[$items[0]] = $items[1];
- } elseif (sizeof($items) == 3) {
- $myarray[$items[0]][$items[1]] = $items[2];
- } elseif (sizeof($items) == 4) {
- $myarray[$items[0]][$items[1]] [$items[2]] = $items[3];
- } elseif (sizeof($items) == 5) {
- $myarray[$items[0]][$items[1]] [$items[2]][$items[3]] = $items[4];
- } elseif (sizeof($items) == 6) {
- $myarray[$items[0]][$items[1]] [$items[2]][$items[3]][$items[4]] = $items[5];
- } elseif (sizeof($items) == 7) {
- $myarray[$items[0]][$items[1]] [$items[2]][$items[3]][$items[4]][$items[5]] = $items[6];
- }
- }
- return $myarray;
- }
-
- /**
- * Function to parse Array and convert it into string
- *
- * @param array $array
- * @access private
- * @return string on success and false on failure
- */
- private function convertArrayToString($myarray, &$output = "", &$parentkey = "")
- {
- if (is_array($myarray)) {
- if (trim($parentkey)=="") {
- $parentkey=LINE_SEPERATOR;
- }
- foreach ($myarray as $key => $value) {
- if (is_array($value)) {
- $parentkey .= $key.NODE_SEPERATOR;
- $this->convertArrayToString($value, $output, $parentkey);
- $parentkey = "";
- } else {
- $output .= $parentkey.$key.NODE_SEPERATOR.$value.LINE_SEPERATOR;
- }
- }
- } else {
- $this->errorLog[]="Invalid array in function: ".__FUNCTION__." on line: ".__LINE__." in filename= ".__FILE__;
- return false;
- }
- return $output;
- }
-
- /**
- * Function to convert XML into string
- *
- * @param string $xml
- * @return string on success and false on failure
- */
- public function convertXmltoString($xml)
- {
- $array=$this->convertXmlToArray($xml);
- if ($array===false) {
- return false;
- } else {
- return $this->convertArrayToString($array);
- }
- }
-}
diff --git a/src/legacy/local_server/server_admin/c_comdef_admin_ajax_handler.class.php b/src/legacy/local_server/server_admin/c_comdef_admin_ajax_handler.class.php
deleted file mode 100755
index 314941863..000000000
--- a/src/legacy/local_server/server_admin/c_comdef_admin_ajax_handler.class.php
+++ /dev/null
@@ -1,1525 +0,0 @@
-.
-*/
-defined('BMLT_EXEC') or die('Cannot Execute Directly'); // Makes sure that this file is in the correct context.
-require_once(dirname(__FILE__).'/../../server/c_comdef_server.class.php');
-require_once(dirname(__FILE__).'/../../server/shared/classes/comdef_utilityclasses.inc.php');
-require_once(dirname(__FILE__).'/../../server/shared/Array2Json.php');
-require_once(dirname(__FILE__).'/../../server/shared/Array2XML.php');
-require_once(dirname(__FILE__).'/../../client_interface/csv/search_results_csv.php');
-require_once(dirname(__FILE__).'/PhpJsonXmlArrayStringInterchanger.inc.php');
-require_once(dirname(__FILE__) . '/../../server/shared/classes/VenueType.php');
-
-/***********************************************************************************************************//**
- \class c_comdef_admin_main_console
- \brief Controls display of the main BMLT administration console.
-***************************************************************************************************************/
-// phpcs:disable PSR1.Classes.ClassDeclaration.MissingNamespace
-// phpcs:disable Squiz.Classes.ValidClassName.NotCamelCaps
-class c_comdef_admin_ajax_handler
-// phpcs:enable PSR1.Classes.ClassDeclaration.MissingNamespace
-// phpcs:enable Squiz.Classes.ValidClassName.NotCamelCaps
-{
- public $my_localized_strings; ///< This will contain the localized strings and whatnot for display.
- public $my_server; ///< This hold the server object.
- public $my_user; ///< This holds the instance of the logged-in user.
- public $my_http_vars; ///< Contains the HTTP vars sent in.
-
- /*******************************************************************************************************//**
- \brief
- ***********************************************************************************************************/
- public function __construct(
- $in_http_vars ///< The HTTP transaction parameters
- ) {
- $this->my_http_vars = $in_http_vars;
- $this->my_localized_strings = c_comdef_server::GetLocalStrings();
- $this->my_server = c_comdef_server::MakeServer();
- $this->my_user = $this->my_server->GetCurrentUserObj();
-
- // We check this every chance that we get.
- if (!$this->my_user || ($this->my_user->GetUserLevel() == _USER_LEVEL_DEACTIVATED)) {
- die('NOT AUTHORIZED');
- }
- }
-
- /*******************************************************************************************************//**
- \brief
- \returns
- ***********************************************************************************************************/
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function parse_ajax_call()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $returned_text = '';
-
- $account_changed = false;
-
- if (isset($this->my_http_vars['set_format_change']) && $this->my_http_vars['set_format_change']) {
- $this->HandleFormatChange($this->my_http_vars['set_format_change']);
- }
- if (isset($this->my_http_vars['delete_format']) && $this->my_http_vars['delete_format']) {
- $this->HandleDeleteFormat($this->my_http_vars['delete_format']);
- } elseif (isset($this->my_http_vars['create_new_user']) && $this->my_http_vars['create_new_user']) {
- $this->HandleUserCreate($this->my_http_vars['create_new_user']);
- } elseif (isset($this->my_http_vars['set_user_change']) && $this->my_http_vars['set_user_change']) {
- $this->HandleUserChange($this->my_http_vars['set_user_change']);
- } elseif (isset($this->my_http_vars['delete_user']) && $this->my_http_vars['delete_user']) {
- $this->HandleDeleteUser($this->my_http_vars['delete_user'], isset($this->my_http_vars['permanently']));
- } elseif (isset($this->my_http_vars['create_new_service_body']) && $this->my_http_vars['create_new_service_body']) {
- $this->HandleServiceBodyCreate($this->my_http_vars['create_new_service_body']);
- } elseif (isset($this->my_http_vars['set_service_body_change']) && $this->my_http_vars['set_service_body_change']) {
- $this->HandleServiceBodyChange($this->my_http_vars['set_service_body_change']);
- } elseif (isset($this->my_http_vars['delete_service_body']) && $this->my_http_vars['delete_service_body']) {
- $this->HandleDeleteServiceBody($this->my_http_vars['delete_service_body'], isset($this->my_http_vars['permanently']));
- } elseif (isset($this->my_http_vars['set_meeting_change']) && $this->my_http_vars['set_meeting_change']) {
- $this->HandleMeetingUpdate($this->my_http_vars['set_meeting_change']);
- } elseif (isset($this->my_http_vars['delete_meeting']) && $this->my_http_vars['delete_meeting']) {
- $returned_text = $this->HandleDeleteMeeting($this->my_http_vars['delete_meeting']);
- } elseif (isset($this->my_http_vars['get_meeting_history']) && $this->my_http_vars['get_meeting_history']) {
- $returned_text = $this->GetMeetingHistory($this->my_http_vars['get_meeting_history']);
- } elseif (isset($this->my_http_vars['do_meeting_search'])) {
- $used_formats = array();
- $returned_text = $this->TranslateToJSON($this->GetSearchResults($this->my_http_vars, $used_formats));
- header('Content-Type:application/json; charset=UTF-8');
- } elseif (isset($this->my_http_vars['do_update_world_ids'])) {
- $returned_text = $this->HandleMeetingWorldIDsUpdate();
- } elseif (isset($this->my_http_vars['do_naws_import'])) {
- $returned_text = $this->HandleNAWSImport();
- } else {
- $this->HandleAccountChange();
- }
-
- return $returned_text;
- }
-
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function HandleNAWSImport()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- if (!c_comdef_server::IsUserServerAdmin(null, true)) {
- return 'NOT AUTHORIZED';
- }
-
- $ret = array(
- 'success' => false,
- 'errors' => null,
- 'report' => array(
- 'num_service_bodies_created' => 0,
- 'num_users_created' => 0,
- 'num_meetings_created' => 0
- )
- );
-
- if (empty($_FILES)) {
- $ret['errors'] = $this->my_localized_strings['comdef_server_admin_strings']['server_admin_error_no_files_uploaded'];
- return json_encode($ret);
- }
-
- require_once(__DIR__.'/NAWSImport.php');
- require_once(__DIR__.'/NAWSImportServiceBodiesExistException.php');
- require_once(__DIR__.'/NAWSImportMeetingsExistException.php');
-
- try {
- $nawsImport = new NAWSImport($_FILES['thefile']['tmp_name'], $this->my_http_vars['initialValueForPublished'] == 'TRUE');
- $nawsImport->import(true);
- } catch (NAWSImportServiceBodiesExistException $e) {
- $ret['errors'] = $this->my_localized_strings['comdef_server_admin_strings']['server_admin_error_service_bodies_already_exist'] . implode(', ', $e->getWorldIds());
- return json_encode($ret);
- } catch (NAWSImportMeetingsExistException $e) {
- $ret['errors'] = $this->my_localized_strings['comdef_server_admin_strings']['server_admin_error_meetings_already_exist'] . implode(', ', $e->getWorldIds());
- return json_encode($ret);
- } catch (Exception $e) {
- $ret['errors'] = $e->getMessage();
- return json_encode($ret);
- }
-
- $ret['success'] = true;
- $ret['report']['num_service_bodies_created'] = $nawsImport->getNumServiceBodiesCreated();
- $ret['report']['num_users_created'] = $nawsImport->getNumUsersCreated();
- $ret['report']['num_meetings_created'] = $nawsImport->getNumMeetingsCreated();
-
- return json_encode($ret);
- }
-
- /* Method to handle updating World ID codes. These are provided in a spreadsheet, usually sent by NAWS, with new world_id
- codes to be entered. The only thing that will be changed doing this are world_id codes for meetings, nothing else.
- In addition to new codes, NAWS can also provide a new world_id 'deleted'. This is for meetings that are already
- deleted and so noted by NAWS. The code that produces a NAWS export file knows it can skip deleted meetings with
- this special world_id, just as it skips deleted meetings with a blank world_id. (Otherwise NAWS keeps seeing these
- deleted meetings on the export file.) The method will only update meetings that the current logged-in user has
- permission to edit. For deleted meetings, the method checks that the current logged-in user could edit the meeting
- if it were restored. The server admin can edit any meeting. Note that deleted meetings exist only in the changes
- table of the database, not the meetings table; so to mark them, the code temporarily restores them, changes the world_ids,
- and deletes them again. Here is the logic for handling the various cases of meetings in the spreadsheet read in.
- These are all based on the bmlt_id for the meeting.
- * if the meeting is in the meetings table in the database:
- + if user has edit rights to this meeting:
- - if the world_id is changing, update the world_id, and report it as 'updated'
- - if the world_id remains the same, don't change it, and report it as 'not_updated'
- + if user doesn't have edit rights to this meeting, don't change it, and report it as 'problem'
- * if the meeting is not in the meetings table in the database but is in the changes table:
- + if the new world_id is 'deleted':
- - if user had edit rights to this meeting:
- - if the world_id wasn't already 'deleted', change it to 'deleted', and report it as 'marked'
- - if the world_id was already 'deleted', don't change it, and report it as 'not_updated'
- - if user didn't have edit rights to this meeting, don't change it, and report it as 'problem'
- + if the new world_id anything else, report it as 'problem'
- * if the meeting is neither in the meetings table nor in the changes table, report it as 'problem'
- The results of doing the updates are returned in a json-encoded array. */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function HandleMeetingWorldIDsUpdate()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- // $ret holds the results from updating the world_ids.
- // TODO sometime: it would be better to encapsulate this functionality in a class MeetingWorldIDsUpdateResult.
- $ret = array(
- 'success' => false,
- 'errors' => array(),
- 'report' => array(
- 'updated' => array(),
- 'not_updated' => array(),
- 'marked' => array(),
- 'problem' => array()
- )
- );
-
- $isServerAdmin = c_comdef_server::IsUserServerAdmin(null, true);
- if (!$isServerAdmin && !c_comdef_server::IsUserServiceBodyAdmin(null, true)) {
- return 'NOT AUTHORIZED';
- }
-
- if (empty($_FILES)) {
- $ret['errors'][] = $this->my_localized_strings['comdef_server_admin_strings']['server_admin_error_no_files_uploaded'];
- return json_encode($ret);
- }
-
- require_once(__DIR__ .'/../../../vendor/autoload.php');
-
- $file = $_FILES['thefile'];
- try {
- $reader = \PhpOffice\PhpSpreadsheet\IOFactory::createReaderForFile($file['tmp_name']);
- $spreadsheet = $reader->load($file['tmp_name']);
- $rows = $spreadsheet->getActiveSheet()->toArray(null, true, true, true);
- } catch (Exception $e) {
- $ret['errors'][] = $this->my_localized_strings['comdef_server_admin_strings']['server_admin_error_could_not_create_reader'] . $e->getMessage();
- return json_encode($ret);
- }
-
- // $userServiceBodyIDs is an array of service body IDs of meetings that the current user is allowed to edit.
- // $userServiceBodyIDs is empty if the user is the serveradmin and can edit any meeting.
- $userServiceBodyIDs = [];
- if (!$isServerAdmin) {
- $ids = c_comdef_server::GetUserServiceBodies();
- if (is_array($ids)) {
- $userServiceBodyIDs = array_keys($ids);
- }
- }
-
- $bmltIdx = "";
- $worldIdx = "";
- $meetingMap = array();
- for ($i = 1; $i <= count($rows); $i++) {
- $row = $rows[$i];
- if ($i == 1) {
- foreach ($row as $key => $value) {
- if ($value == "bmlt_id") {
- $bmltIdx = $key;
- } elseif ($value == "Committee") {
- $worldIdx = $key;
- }
- if ($bmltIdx && $worldIdx) {
- break;
- }
- }
-
- if (!$bmltIdx || !$worldIdx) {
- if (!$bmltIdx) {
- $ret['errors'][] = $this->my_localized_strings['comdef_server_admin_strings']['server_admin_error_required_spreadsheet_column'] . "bmlt_id";
- }
- if (!$worldIdx) {
- $ret['errors'][] = $this->my_localized_strings['comdef_server_admin_strings']['server_admin_error_required_spreadsheet_column'] . "Committee";
- }
- return json_encode($ret);
- }
-
- continue;
- }
-
- $bmltId = trim(strval($row[$bmltIdx]));
- $worldId = trim($row[$worldIdx]);
- if (empty($bmltId) && empty($worldId)) {
- continue;
- } elseif (!is_numeric($bmltId)) {
- $ret['errors'][] = $this->my_localized_strings['comdef_server_admin_strings']['server_admin_error_bmlt_id_not_integer'] . $bmltId;
- } else {
- $meetingMap[$bmltId] = $worldId;
- }
- }
-
- if (empty($meetingMap)) {
- $ret['errors'][] = $this->my_localized_strings['comdef_server_admin_strings']['server_admin_error_no_world_ids_updated'];
- }
-
- if (!empty($ret['errors'])) {
- return json_encode($ret);
- }
-
- // Attempt to save some memory, as many servers will be memory restricted
- unset($rows);
- unset($spreadsheet);
- unset($reader);
-
- $json_tool = new PhpJsonXmlArrayStringInterchanger;
- $used_formats = array();
- $meetings = $this->GetSearchResults(array('meeting_ids' => array_keys($meetingMap)), $used_formats);
- $meetings = $this->TranslateToJSON($meetings);
- $meetings = $json_tool->convertJsonToArray($meetings, true);
- $map = array();
- foreach ($meetings as $meeting) {
- $bmltId = strval($meeting['id_bigint']);
- $map[$bmltId] = $meeting;
- }
- $meetings = $map;
-
- c_comdef_dbsingleton::beginTransaction();
- try {
- foreach ($meetingMap as $bmltId => $newWorldId) {
- if (!array_key_exists($bmltId, $meetings)) {
- $this->UpdatePossiblyDeletedMeeting($bmltId, $newWorldId, $ret, $isServerAdmin, $userServiceBodyIDs);
- continue;
- }
- $meeting = $meetings[$bmltId];
- if (!$isServerAdmin && !in_array(intval($meeting['service_body_bigint']), $userServiceBodyIDs)) {
- $ret['report']['problem'][] = $bmltId;
- continue;
- }
- $oldWorldId = $meeting['worldid_mixed'];
- if ($oldWorldId == $newWorldId) {
- $ret['report']['not_updated'][] = $bmltId;
- continue;
- }
- $meeting['worldid_mixed'] = $newWorldId;
- $this->SetMeetingDataValues($meeting, false);
- $ret['report']['updated'][] = $bmltId;
- }
- } catch (Exception $e) {
- c_comdef_dbsingleton::rollBack();
- throw $e;
- }
- c_comdef_dbsingleton::commit();
-
- $ret['success'] = empty($ret['errors']);
- return json_encode($ret);
- }
-
- /* Helper method for HandleMeetingWorldIDsUpdate for updating deleted meetings. These meetings exist only in the
- changes table, if at all. The normal use for this method is to set the world_id to 'deleted', which is used by NAWS
- to indicate that they've recorded this deletion. The NAWS export facility doesn't export meetings whose world_id is
- 'deleted', so that NAWS doesn't have to keep looking at the same deleted meeting over and over. If the world_id was
- already 'deleted' or if we're trying to set it to its current world_id, report no change. This method doesn't try
- to be to be clever about working around problems: if something is wrong, it just reports the meeting as a problem
- meeting and doesn't make any changes. Obscure case: it's also OK to update the world_id of a deleted meeting to a
- different world_id as well, not just to 'deleted'. This is useful for avoiding a synchronization problem that would
- arise if a new meeting is deleted before its NAWS code can be uploaded. (The sequence of events in that case would
- be a meeting is created with no world_id, gets picked up in a NAWS export, and then gets deleted, still with no
- world_id recorded. Then if NAWS sees the new meeting in the export and enters it in their database, it will get a
- world_id on the next import. This will set the world_id on the next import. Then the next export will include it
- as deleted, since it now has a world_id, so that NAWS knows that the meeting with that world_id no longer exists.
- As a final wrinkle, you could also change the world_id of a deleted meeting that already had a world_id.
- There doesn't seem to be a use case for this, but it would not be a problem to do so. In that case, there is a
- "feature" of the NAWS export code that causes 2 entries in the spreadsheet for the deleted meeting, one for each
- world_id under which it was deleted. I'm going to declare that this is in fact a feature rather than a bug, since
- it's probably good if NAWS sees both world_ids in case something weird is going on. Once it's set to 'deleted' that
- meeting will no longer appear.) */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- private function UpdatePossiblyDeletedMeeting($bmltId, $newWorldId, &$ret, $isServerAdmin, $userServiceBodyIDs)
- {
- $change_objects = c_comdef_server::GetChangesFromIDAndType('c_comdef_meeting', $bmltId);
- if ($change_objects instanceof c_comdef_changes) {
- $obj_array = $change_objects->GetChangesObjects();
- if (is_array($obj_array)) {
- // The changes are returned in reverse chronological order. Ideally the last change would be a delete; but it seems
- // that there can be race conditions in which there are several changes with the same time stamp (but only one of these
- // will be a delete). So get the most recent delete, rather than just $obj_array[0]
- foreach ($obj_array as $change) {
- if ($change instanceof c_comdef_change && $change->GetChangeType() === 'comdef_change_type_delete' && !$change->GetAfterObject()) {
- $meeting = $change->GetBeforeObject();
- if (!$isServerAdmin && !in_array(intval($meeting->GetServiceBodyID()), $userServiceBodyIDs)) {
- // Meeting was under some other service body that this user isn't allowed to change.
- $ret['report']['problem'][] = $bmltId;
- } elseif ($newWorldId === $meeting->GetWorldID()) {
- // We aren't trying to change its world_id.
- $ret['report']['not_updated'][] = $bmltId;
- } else {
- // Found a deleted meeting whose world_id should be changed (could be to 'deleted' or to another world_id). Do that.
- $meeting->SetWorldID($newWorldId);
- $meeting->UpdateToDB();
- $meeting->DeleteFromDB();
- if (strtolower($newWorldId) == 'deleted') {
- $ret['report']['marked'][] = $bmltId;
- } else {
- $ret['report']['updated'][] = $bmltId;
- }
- }
- return;
- }
- }
- }
- }
- // meeting not found in the changes table
- $ret['report']['problem'][] = $bmltId;
- }
-
- /*******************************************************************/
- /**
- \brief
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function HandleAccountChange()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $response_text = array();
-
- $t_user = isset($this->my_http_vars['target_user']) ? intval($this->my_http_vars['target_user']) : 0;
-
- if ((intval($this->my_user->GetID()) == $t_user) && isset($this->my_http_vars['account_email_value'])) {
- $this->my_user->SetEmailAddress($this->my_http_vars['account_email_value']);
- $success = $this->my_user->UpdateToDB();
- $response_text['EMAIL_CHANGED'] = ($success ? true : false);
- }
-
- if ((intval($this->my_user->GetID()) == $t_user) && isset($this->my_http_vars['account_description_value'])) {
- $this->my_user->SetLocalDescription($this->my_http_vars['account_description_value']);
- $success = $this->my_user->UpdateToDB();
- $response_text['DESCRIPTION_CHANGED'] = ($success ? true : false);
- }
-
- $login = $this->my_user->GetLogin();
- $login_changed = false;
- $password = (isset($this->my_http_vars['account_password_value']) ? $this->my_http_vars['account_password_value'] : '');
-
- if ($this->my_user->GetUserLevel() == _USER_LEVEL_SERVER_ADMIN) {
- if ((intval($this->my_user->GetID()) == $t_user) && isset($this->my_http_vars['account_name_value'])) {
- $this->my_user->SetLocalName($this->my_http_vars['account_name_value']);
- $success = $this->my_user->UpdateToDB();
- $response_text['NAME_CHANGED'] = ($success ? true : false);
- }
-
- if ((intval($this->my_user->GetID()) == $t_user) && isset($this->my_http_vars['account_login_value'])) {
- $login = $this->my_http_vars['account_login_value'];
- $login_changed = true;
- }
- } else {
- unset($this->my_http_vars['account_login_value']);
- }
-
- if ((intval($this->my_user->GetID()) == $t_user) && (isset($this->my_http_vars['account_login_value']) || isset($this->my_http_vars['account_password_value']))) {
- $success = $this->my_user->UpdateToDB(false, $login, $password);
- $response_text['PASSWORD_CHANGED'] = ($success ? true : false);
- if ($login_changed) {
- $response_text['LOGIN_CHANGED'] = ($success ? true : false);
- }
- }
-
- if (is_array($response_text) && count($response_text)) {
- header('Content-Type:application/json; charset=UTF-8');
- echo ( array2json(array ( 'ACCOUNT_CHANGED' => $response_text )));
- }
- }
-
- /*******************************************************************/
- /**
- \brief
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function HandleFormatChange(
- $in_new_format_data ///< A JSON string with the new format data.
- ) {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- if (c_comdef_server::IsUserServerAdmin(null, true)) {
- $json_tool = new PhpJsonXmlArrayStringInterchanger;
-
- $the_processed_formats = $json_tool->convertJsonToArray($in_new_format_data, true);
-
- $the_changed_formats = array();
- foreach ($the_processed_formats as $the_format) {
- if (trim($the_format['key']) || trim($the_format['name']) || trim($the_format['description'])) {
- $the_changed_formats[$the_format['lang_key']] = $the_format;
- }
- }
-
- $the_objects_to_be_changed = array();
-
- $ret_data = '';
- $shared_id = '';
- $format_type = 'FC1';
-
- // The first thing that we do, is go through the incoming data, and make sure that we create or modify c_comdef_format objects to match the input.
- foreach ($the_changed_formats as $format_data) {
- if ($format_data) {
- if (isset($format_data['key'])) {
- $format_data['key'] = trim($format_data['key']);
- }
-
- if (isset($format_data['name'])) {
- $format_data['name'] = trim($format_data['name']);
- }
-
- if (isset($format_data['description'])) {
- $format_data['description'] = trim($format_data['description']);
- }
-
- foreach ($format_data as &$data_val) { // This removes double-slashes, added by the JSON encoding.
- $data_val = str_replace('\\\\', '\\', $data_val);
- }
-
- if (!$shared_id) {
- $shared_id = intval($format_data['shared_id']);
- $format_type = $format_data['type'];
- } else {
- if ($shared_id != intval($format_data['shared_id'])) { // This should never happen.
- $the_objects_to_be_changed = null;
- break;
- }
- }
-
- $lang_key = $format_data['lang_key'];
-
- $server_format = null;
-
- if ($format_data['shared_id']) {
- $this->my_server->GetOneFormat($format_data['shared_id'], $format_data['lang_key']);
- }
- if (!($server_format instanceof c_comdef_format)) {
- $parent = null;
- $server_format = new c_comdef_format($parent, $format_data['shared_id'], $format_type, $format_data['key'], null, null, $format_data['lang_key'], $format_data['name'], $format_data['description']);
- } else {
- $server_format->SetKey($format_data['key']);
- $server_format->SetLocalName($format_data['name']);
- $server_format->SetLocalDescription($format_data['description']);
- }
-
- if (isset($format_data['worldid_mixed']) && $format_data['worldid_mixed']) {
- $server_format->SetWorldID($format_data['worldid_mixed']);
- }
-
- array_push($the_objects_to_be_changed, $server_format);
- }
- }
-
- $the_changed_objects = array();
-
- if ($the_objects_to_be_changed && is_array($the_objects_to_be_changed) && count($the_objects_to_be_changed)) {
- $new_shared_id = 0;
- $langs = $this->my_server->GetFormatLangs();
-
- foreach ($the_objects_to_be_changed as $one_format) {
- if (!(($one_format instanceof c_comdef_format) && $one_format->UpdateToDB())) {
- $the_objects_to_be_changed = null;
- $ret_data = json_prepare($this->my_localized_strings['comdef_server_admin_strings']['format_change_fader_change_fail_text']);
- break;
- }
-
- if (!$one_format->GetSharedID()) {
- $one_format->SetSharedID($new_shared_id);
- }
-
- $saved_format_object = array (
- 'shared_id' => $one_format->GetSharedID(),
- 'lang_key' => $one_format->GetLocalLang(),
- 'lang_name' => $langs[$one_format->GetLocalLang()],
- 'key' => $one_format->GetKey(),
- 'name' => $one_format->GetLocalName(),
- 'description' => $one_format->GetLocalDescription(),
- 'type' => $one_format->GetFormatType(),
- 'worldid_mixed' => $one_format->GetWorldID()
- );
-
- $new_shared_id = $saved_format_object['shared_id'];
-
- $the_changed_objects[$one_format->GetLocalLang()] = $saved_format_object;
- }
-
- // Now, we go through the server's formats, and delete any that aren't reflected in the incoming data.
- foreach ($langs as $lang_key => $lang_name) {
- $server_format = $this->my_server->GetOneFormat($shared_id, $lang_key);
-
- if ($server_format && !isset($the_changed_formats[$lang_key])) {
- $server_format->DeleteFromDB();
- }
- }
- } else {
- $ret_data = json_prepare($this->my_localized_strings['comdef_server_admin_strings']['format_change_fader_change_fail_text']);
- }
-
- header('Content-Type:application/json; charset=UTF-8');
- if ($ret_data) {
- echo "{'success':false,'report':'$ret_data'}";
- } else {
- echo "{'success':true,'report':".array2json($the_changed_objects)."}";
- }
- } else {
- echo 'NOT AUTHORIZED';
- }
- }
-
- /*******************************************************************/
- /**
- \brief
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function HandleDeleteFormat(
- $in_format_shared_id ///< The shared ID of the formats to delete.
- ) {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- if (c_comdef_server::IsUserServerAdmin(null, true)) {
- $ret_data = '';
-
- $langs = $this->my_server->GetFormatLangs();
-
- foreach ($langs as $lang_key => $lang_name) {
- $server_format = $this->my_server->GetOneFormat($in_format_shared_id, $lang_key);
-
- if ($server_format instanceof c_comdef_format) {
- $server_format->DeleteFromDB();
- }
- }
-
- header('Content-Type:application/json; charset=UTF-8');
- if ($ret_data) {
- echo "{'success':false,'report':'$ret_data'}";
- } else {
- echo "{'success':true,'report':$in_format_shared_id}";
- }
- } else {
- echo 'NOT AUTHORIZED';
- }
- }
-
- /*******************************************************************/
- /**
- \brief
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function HandleUserCreate(
- $in_user_data ///< A JSON object, containing the new User data.
- ) {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- if (c_comdef_server::IsUserServerAdmin(null, true)) {
- $json_tool = new PhpJsonXmlArrayStringInterchanger;
-
- $the_new_user = $json_tool->convertJsonToArray($in_user_data, true);
-
- if (is_array($the_new_user) && count($the_new_user)) {
- $id = $the_new_user[0];
- $login = $the_new_user[1];
- $name = $the_new_user[2];
- $description = $the_new_user[3];
- $email = $the_new_user[4];
- $user_level = intval($the_new_user[5]);
- $password = trim($the_new_user[6]);
- $user_owner = intval($the_new_user[7]);
-
- $user_owner_user = $this->my_server->GetUserByIDObj($user_owner);
- if (is_null($user_owner_user) || $user_owner_user->GetUserLevel() == _USER_LEVEL_SERVER_ADMIN) {
- $user_owner = -1;
- }
-
- if (!$this->my_server->GetUserByLogin($login)) {
- $user_to_create = new c_comdef_user(null, 0, $user_level, $email, $login, "", $this->my_server->GetLocalLang(), $name, $description, $user_owner, null);
-
- if ($user_to_create instanceof c_comdef_user) {
- if ($password) {
- $user_to_create->SetNewPassword($password);
- }
-
- if ($user_to_create->UpdateToDB()) {
- // Get whatever ID was assigned to this User.
- $the_new_user[0] = intval($user_to_create->GetID());
- header('Content-Type:application/json; charset=UTF-8');
- echo "{'success':true,'user':".array2json($the_new_user)."}";
- } else {
- $err_string = json_prepare($this->my_localized_strings['comdef_server_admin_strings']['user_change_fader_create_fail_text']);
- header('Content-Type:application/json; charset=UTF-8');
- echo "{'success':false,'report':'$err_string'}";
- }
- } else {
- $err_string = json_prepare($this->my_localized_strings['comdef_server_admin_strings']['user_change_fader_create_fail_text']);
- header('Content-Type:application/json; charset=UTF-8');
- echo "{'success':false,'report':'$err_string'}";
- }
- } else {
- $err_string = json_prepare($this->my_localized_strings['comdef_server_admin_strings']['user_change_fader_create_fail_already_exists']);
- header('Content-Type:application/json; charset=UTF-8');
- echo "{'success':false,'report':'$err_string'}";
- }
- } else {
- $err_string = json_prepare($this->my_localized_strings['comdef_server_admin_strings']['user_change_fader_create_fail_text']);
- header('Content-Type:application/json; charset=UTF-8');
- echo "{'success':false,'report':'$err_string'}";
- }
- } else {
- echo 'NOT AUTHORIZED';
- }
- }
-
- /*******************************************************************/
- /**
- \brief
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function HandleUserChange(
- $in_user_data ///< A JSON object, containing the new User data.
- ) {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $isServerAdmin = c_comdef_server::IsUserServerAdmin(null, true);
- $isServiceBodyAdmin = c_comdef_server::IsUserServiceBodyAdmin(null, true);
- if ($isServerAdmin || $isServiceBodyAdmin) {
- $json_tool = new PhpJsonXmlArrayStringInterchanger;
-
- $the_changed_user = $json_tool->convertJsonToArray($in_user_data, true);
-
- if (is_array($the_changed_user) && count($the_changed_user)) {
- $id = $the_changed_user[0];
- $login = $the_changed_user[1];
- $name = $the_changed_user[2];
- $description = $the_changed_user[3];
- $email = $the_changed_user[4];
- $user_level = intval($the_changed_user[5]);
- $password = trim($the_changed_user[6]);
- $user_owner = intval($the_changed_user[7]);
- $user_to_change = $this->my_server->GetUserByIDObj($id);
-
- $user_owner_user = $this->my_server->GetUserByIDObj($user_owner);
- if (is_null($user_owner_user) || $user_owner_user->GetUserLevel() == _USER_LEVEL_SERVER_ADMIN) {
- $user_owner = -1;
- }
-
- if ($user_to_change instanceof c_comdef_user) {
- // Don't allow service body admins to make changes to users they don't own
- if ($isServiceBodyAdmin && $user_to_change->GetOwnerID() != c_comdef_server::GetCurrentUserObj()->GetID()) {
- echo 'NOT AUTHORIZED';
- return;
- }
-
- $user_to_change->SetLogin($login);
- $user_to_change->SetLocalName($name);
- $user_to_change->SetLocalDescription($description);
- $user_to_change->SetEmailAddress($email);
- // Only allow server admins to set user level and user owner
- if ($isServerAdmin) {
- $user_to_change->SetUserLevel($user_level);
- $user_to_change->SetOwnerID($user_owner);
- }
-
- if ($password) {
- if (!$user_to_change->SetNewPassword($password)) {
- $err_string = json_prepare($this->my_localized_strings['comdef_server_admin_strings']['user_change_fader_fail_cant_update_text']);
- header('Content-Type:application/json; charset=UTF-8');
- echo "{\"success\":false,\"report\":\"$err_string\"}";
- return;
- }
- }
-
- if ($user_to_change->UpdateToDB()) {
- header('Content-Type:application/json; charset=UTF-8');
- echo '{"success":true,"user":'.array2json($the_changed_user)."}";
- } else {
- $err_string = json_prepare($this->my_localized_strings['comdef_server_admin_strings']['user_change_fader_fail_cant_update_text']);
- header('Content-Type:application/json; charset=UTF-8');
- echo "{\"success\":false,\"report\":\"$err_string\"}";
- }
- } else {
- $err_string = json_prepare($this->my_localized_strings['comdef_server_admin_strings']['user_change_fader_fail_cant_find_sb_text']);
- header('Content-Type:application/json; charset=UTF-8');
- echo "{\"success\":false,\"report\":\"$err_string\"}";
- }
- } else {
- $err_string = json_prepare($this->my_localized_strings['comdef_server_admin_strings']['user_change_fader_fail_no_data_text']);
- header('Content-Type:application/json; charset=UTF-8');
- echo "{\"success\":false,\"report\":\"$err_string\"}";
- }
- } else {
- echo 'NOT AUTHORIZED';
- }
- }
-
- /*******************************************************************/
- /**
- \brief
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function HandleDeleteUser(
- $in_user_id, ///< The ID of the user to be deleted.
- $in_delete_permanently = false
- ) {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $err_string = json_prepare($this->my_localized_strings['comdef_server_admin_strings']['user_change_fader_delete_fail_text']);
- if (c_comdef_server::IsUserServerAdmin(null, true)) {
- try {
- $user_to_delete = $this->my_server->GetUserByIDObj($in_user_id);
-
- if ($user_to_delete instanceof c_comdef_user) {
- if ($user_to_delete->DeleteFromDB()) {
- $user_to_delete->ResetChildUsers();
- if ($in_delete_permanently) {
- $this->DeleteUserChanges($in_user_id);
- }
-
- header('Content-Type:application/json; charset=UTF-8');
- echo "{'success':true,'report':'$in_user_id'}";
- } else {
- header('Content-Type:application/json; charset=UTF-8');
- echo "{'success':false,'report':'$ierr_string'}";
- }
- } else {
- header('Content-Type:application/json; charset=UTF-8');
- echo "{'success':false,'report':'$ierr_string'}";
- }
- } catch (Exception $e) {
- header('Content-Type:application/json; charset=UTF-8');
- echo "{'success':false,'report':'$ierr_string'}";
- }
- } else {
- echo 'NOT AUTHORIZED';
- }
- }
-
- /*******************************************************************/
- /**
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function DeleteUserChanges($in_user_id)
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- if (c_comdef_server::IsUserServerAdmin(null, true)) {
- $changes = $this->my_server->GetChangesFromIDAndType('c_comdef_user', $in_user_id);
-
- if ($changes instanceof c_comdef_changes) {
- $obj_array = $changes->GetChangesObjects();
-
- if (is_array($obj_array) && count($obj_array)) {
- foreach ($obj_array as $change) {
- $change->DeleteFromDB();
- }
- }
- }
- }
- }
-
- /*******************************************************************/
- /**
- \brief This handles updating an existing Service body.
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function HandleServiceBodyChange(
- $in_service_body_data ///< A JSON object, containing the new Service Body data.
- ) {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $json_tool = new PhpJsonXmlArrayStringInterchanger;
-
- $the_new_service_body = $json_tool->convertJsonToArray($in_service_body_data, true);
-
- if (is_array($the_new_service_body) && count($the_new_service_body)) {
- $id = $the_new_service_body[0];
- $parent_service_body_id = $the_new_service_body[1];
- $name = trim($the_new_service_body[2]);
- $description = trim($the_new_service_body[3]);
- $main_user_id = $the_new_service_body[4];
- $editor_ids = explode(',', $the_new_service_body[5]);
- $email = trim($the_new_service_body[6]);
- $uri = trim($the_new_service_body[7]);
- $helpline = trim($the_new_service_body[8]);
- $type = $the_new_service_body[9];
- $worldid = trim($the_new_service_body[12]);
-
- $sb_to_change = $this->my_server->GetServiceBodyByIDObj($id);
-
- if ($sb_to_change instanceof c_comdef_service_body) {
- $sb_to_change->SetOwnerID($parent_service_body_id);
- $sb_to_change->SetLocalName($name);
- $description = preg_replace('|[^\S]+?|', " ", $description);
- $sb_to_change->SetLocalDescription($description);
- $sb_to_change->SetPrincipalUserID($main_user_id);
- $sb_to_change->SetEditors($editor_ids);
- $sb_to_change->SetContactEmail($email);
- $sb_to_change->SetURI($uri);
- $sb_to_change->SetHelpline($helpline);
- $sb_to_change->SetSBType($type);
- $sb_to_change->SetWorldID($worldid);
-
- if ($sb_to_change->UpdateToDB()) {
- header('Content-Type:application/json; charset=UTF-8');
- echo "{'success':true,'service_body':".array2json($the_new_service_body)."}";
- } else {
- $err_string = json_prepare($this->my_localized_strings['comdef_server_admin_strings']['service_body_change_fader_fail_cant_update_text']);
- header('Content-Type:application/json; charset=UTF-8');
- echo "{'success':false,'report':'$err_string'}";
- }
- } else {
- $err_string = json_prepare($this->my_localized_strings['comdef_server_admin_strings']['service_body_change_fader_fail_cant_find_sb_text']);
- header('Content-Type:application/json; charset=UTF-8');
- echo "{'success':false,'report':'$err_string'}";
- }
- } else {
- $err_string = json_prepare($this->my_localized_strings['comdef_server_admin_strings']['service_body_change_fader_fail_no_data_text']);
- header('Content-Type:application/json; charset=UTF-8');
- echo "{'success':false,'report':'$err_string'}";
- }
- }
-
- /*******************************************************************/
- /**
- \brief This handles creating a new Service body.
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function HandleServiceBodyCreate(
- $in_service_body_data ///< A JSON object, containing the new Service Body data.
- ) {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- if (c_comdef_server::IsUserServerAdmin(null, true)) {
- $json_tool = new PhpJsonXmlArrayStringInterchanger;
-
- $the_new_service_body = $json_tool->convertJsonToArray($in_service_body_data, true);
-
- if (is_array($the_new_service_body) && count($the_new_service_body)) {
- $id = $the_new_service_body[0];
- $parent_service_body_id = $the_new_service_body[1];
- $name = trim($the_new_service_body[2]);
- $description = trim($the_new_service_body[3]);
- $main_user_id = $the_new_service_body[4];
- $editor_ids = explode(',', $the_new_service_body[5]);
- $email = trim($the_new_service_body[6]);
- $uri = trim($the_new_service_body[7]);
- $helpline = trim($the_new_service_body[8]);
- $type = $the_new_service_body[9];
- $worldid = trim($the_new_service_body[12]);
-
- $sb_to_create = new c_comdef_service_body;
-
- if ($sb_to_create instanceof c_comdef_service_body) {
- $sb_to_create->SetOwnerID($parent_service_body_id);
- $sb_to_create->SetLocalName($name);
- $sb_to_create->SetLocalDescription($description);
- $sb_to_create->SetPrincipalUserID($main_user_id);
- $sb_to_create->SetEditors($editor_ids);
- $sb_to_create->SetContactEmail($email);
- $sb_to_create->SetURI($uri);
- $sb_to_create->SetHelpline($helpline);
- $sb_to_create->SetSBType($type);
- $sb_to_create->SetWorldID($worldid);
-
- if ($sb_to_create->UpdateToDB()) {
- // Get whatever ID was assigned to this Service Body.
- $the_new_service_body[0] = $sb_to_create->GetID();
- header('Content-Type:application/json; charset=UTF-8');
- echo "{'success':true,'service_body':".array2json($the_new_service_body)."}";
- } else {
- $err_string = json_prepare($this->my_localized_strings['comdef_server_admin_strings']['service_body_change_fader_fail_cant_update_text']);
- header('Content-Type:application/json; charset=UTF-8');
- echo "{'success':false,'report':'$err_string'}";
- }
- } else {
- $err_string = json_prepare($this->my_localized_strings['comdef_server_admin_strings']['service_body_change_fader_fail_cant_find_sb_text']);
- header('Content-Type:application/json; charset=UTF-8');
- echo "{'success':false,'report':'$err_string'}";
- }
- } else {
- $err_string = json_prepare($this->my_localized_strings['comdef_server_admin_strings']['service_body_change_fader_fail_no_data_text']);
- header('Content-Type:application/json; charset=UTF-8');
- echo "{'success':false,'report':'$err_string'}";
- }
- } else {
- echo 'NOT AUTHORIZED';
- }
- }
-
- /*******************************************************************/
- /**
- \brief
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function HandleDeleteServiceBody(
- $in_sb_id,
- $in_delete_permanently = false
- ) {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $err_string = json_prepare($this->my_localized_strings['comdef_server_admin_strings']['service_body_change_fader_delete_fail_text']);
-
- if (c_comdef_server::IsUserServerAdmin(null, true)) {
- try {
- $service_body = $this->my_server->GetServiceBodyByIDObj($in_sb_id);
-
- if ($service_body instanceof c_comdef_service_body) {
- if ($service_body->DeleteFromDB()) {
- if ($in_delete_permanently) {
- $this->DeleteServiceBodyChanges($in_sb_id);
- }
-
- header('Content-Type:application/json; charset=UTF-8');
- echo "{'success':true, 'id':$in_sb_id}";
- } else {
- header('Content-Type:application/json; charset=UTF-8');
- echo "{'success':false,'report':'$err_string'}";
- }
- } else {
- header('Content-Type:application/json; charset=UTF-8');
- echo "{'success':false,'report':'$err_string'}";
- }
- } catch (Exception $e) {
- header('Content-Type:application/json; charset=UTF-8');
- echo "{'success':false,'report':'$err_string'}";
- }
- } else {
- echo 'NOT AUTHORIZED';
- }
- }
-
- /*******************************************************************/
- /**
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function DeleteServiceBodyChanges($in_sb_id)
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- if (c_comdef_server::IsUserServerAdmin(null, true)) {
- $changes = $this->my_server->GetChangesFromIDAndType('c_comdef_service_body', $in_sb_id);
-
- if ($changes instanceof c_comdef_changes) {
- $obj_array = $changes->GetChangesObjects();
-
- if (is_array($obj_array) && count($obj_array)) {
- foreach ($obj_array as $change) {
- $change->DeleteFromDB();
- }
- }
- }
- }
- }
-
- /*******************************************************************/
- /**
- \brief
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function GetMeetingHistory($in_meeting_id)
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $ret = '[';
- $changes = $this->my_server->GetChangesFromIDAndType('c_comdef_meeting', $in_meeting_id);
-
- if ($changes instanceof c_comdef_changes) {
- $obj_array = $changes->GetChangesObjects();
-
- if (is_array($obj_array) && count($obj_array)) {
- $first = true;
-
- foreach ($obj_array as $change) {
- if (!$first) {
- $ret .= ',';
- } else {
- $first = false;
- }
-
- $ret .= '{';
- $change_id = $change->GetID();
- $user_id = $change->GetUserID();
- if ($user_id) {
- $user_object = $this->my_server->GetUserByIDObj($change->GetUserID());
- if ($user_object) {
- $user_name = json_prepare($user_object->GetLocalName());
- }
- }
- $change_description = json_prepare($change->DetailedChangeDescription());
- $change_date = json_prepare(date('g:i A, F j Y', $change->GetChangeDate()));
-
- $ret .= '"id":'.$change_id.',';
- $ret .= '"user":"'.$user_name.'",';
- $ret .= '"description":["'.implode('","', str_replace('&', '&', $change_description['details'] ?? [''])).'"],';
- $ret .= '"date":"'.$change_date.'"';
-
- $ret .= '}';
- }
- }
- }
-
- $ret .= ']';
-
- return $ret;
- }
-
- /*******************************************************************/
- /**
- \brief
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function HandleDeleteMeeting(
- $in_meeting_id
- ) {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- try {
- $meeting = $this->my_server->GetOneMeeting($in_meeting_id);
-
- if ($meeting instanceof c_comdef_meeting) {
- if ($meeting->UserCanEdit()) {
- if ($meeting->DeleteFromDB()) {
- header('Content-Type:application/json; charset=UTF-8');
- echo "{'success':true,'report':'$in_meeting_id'}";
- } else {
- header('Content-Type:application/json; charset=UTF-8');
- echo "{'success':false,'report':'$in_meeting_id'}";
- }
- } else {
- header('Content-Type:application/json; charset=UTF-8');
- echo "{'success':false,'report':'$in_meeting_id'}";
- }
- } else {
- header('Content-Type:application/json; charset=UTF-8');
- echo "{'success':false,'report':'$in_meeting_id'}";
- }
- } catch (Exception $e) {
- header('Content-Type:application/json; charset=UTF-8');
- echo "{'success':false,'report':'$in_meeting_id'}";
- }
- }
-
- /*******************************************************************/
- /**
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function DeleteMeetingChanges($in_meeting_id)
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- if (c_comdef_server::IsUserServerAdmin(null, true)) {
- $changes = $this->my_server->GetChangesFromIDAndType('c_comdef_meeting', $in_meeting_id);
-
- if ($changes instanceof c_comdef_changes) {
- $obj_array = $changes->GetChangesObjects();
-
- if (is_array($obj_array) && count($obj_array)) {
- foreach ($obj_array as $change) {
- $change->DeleteFromDB();
- }
- }
- }
- }
- }
-
- /*******************************************************************/
- /**
- \brief This handles updating an existing meeting, or adding a new one.
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function HandleMeetingUpdate(
- $in_meeting_data ///< A JSON object, containing the new meeting data.
- ) {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $json_tool = new PhpJsonXmlArrayStringInterchanger;
-
- $the_new_meeting = $json_tool->convertJsonToArray($in_meeting_data, true);
-
- if (is_array($the_new_meeting) && count($the_new_meeting)) {
- c_comdef_dbsingleton::beginTransaction();
- try {
- $this->SetMeetingDataValues($the_new_meeting);
- } catch (Exception $e) {
- c_comdef_dbsingleton::rollback();
- throw $e;
- }
- c_comdef_dbsingleton::commit();
- }
- }
-
- /*******************************************************************/
- /**
- \brief
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function SetMeetingDataValues($in_meeting_data, $print_result = true)
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- try {
- if ($in_meeting_data['id_bigint'] ?? false) {
- $meeting = $this->my_server->GetOneMeeting($in_meeting_data['id_bigint']);
- } else {
- $data = array ( 'service_body_bigint' => intval($in_meeting_data['service_body_bigint']),
- 'weekday_tinyint' => intval($in_meeting_data['weekday_tinyint']),
- 'start_time' => $in_meeting_data['start_time'],
- 'lang_enum' => (isset($in_meeting_data['lang_enum']) && $in_meeting_data['lang_enum']) ? $in_meeting_data['lang_enum'] : $this->my_server->GetLocalLang()
- );
- $meeting = new c_comdef_meeting($this->my_server, $data);
- }
-
- if ($meeting instanceof c_comdef_meeting) {
- // Security precaution: We check the session to make sure that the user is authorized for this meeting.
- if ($meeting->UserCanEdit()) {
- if (array_key_exists('id_bigint', $in_meeting_data)) {
- $result_data = array ( 'meeting_id' => $in_meeting_data['id_bigint'] );
- } else {
- $result_data = [];
- }
- $data =& $meeting->GetMeetingData();
-
- // We prepare the "template" array. These are the data values for meeting 0 in the two tables.
- // We will use them to provide default visibility values. Only the server admin can override these.
- // This is where we get a list of the available "optional" fields to put in a popup for adding a new one.
- $template_data = c_comdef_meeting::GetDataTableTemplate();
- $template_longdata = c_comdef_meeting::GetLongDataTableTemplate();
-
- // We merge the two tables (data and longdata).
- if (is_array($template_data) && count($template_data) && is_array($template_longdata) && count($template_longdata)) {
- $template_data = array_merge($template_data, $template_longdata);
- }
-
- foreach ($in_meeting_data as $key => $value) {
- if ($key == 'formats') {
- continue;
- }
-
- if ($key == 'format_shared_id_list') {
- $vals = array();
- $value = explode(",", $value);
- $lang = $this->my_server->GetLocalLang();
- foreach ($value as $sharedID) {
- $sharedID = intval($sharedID);
- $object = c_comdef_server::GetServer()->GetFormatsObj()->GetFormatBySharedIDCodeAndLanguage($sharedID, $lang);
- if ($object) {
- $vals[$sharedID] = $object;
- }
- }
- uksort($vals, array ( 'c_comdef_meeting','format_sorter_simple' ));
- $value = $vals;
- $key = 'formats';
- }
-
- switch ($key) {
- case 'zoom':
- case 'distance_in_km': // These are ignored.
- case 'distance_in_miles':
- break;
-
- // These are the "fixed" or "core" data values.
- case 'worldid_mixed':
- case 'start_time':
- case 'lang_enum':
- case 'duration_time':
- case 'time_zone':
- $data[$key] = trim($value);
- break;
-
- case 'formats':
- $data[$key] = $value;
- $data["venue_type"] = $this->GetVenueTypeForFormats($value);
- break;
-
- case 'longitude':
- case 'latitude':
- $data[$key] = floatval($value);
- break;
-
- case 'id_bigint':
- case 'service_body_bigint':
- case 'weekday_tinyint':
- $data[$key] = intval($value);
- break;
-
- case 'email_contact':
- $value = trim($value);
- if ($value) {
- if (c_comdef_vet_email_address($value)) {
- $data[$key] = $value;
- } else {
- $err_string = json_prepare($this->my_localized_strings['comdef_server_admin_strings']['email_format_bad']);
- header('Content-Type:application/json; charset=UTF-8');
- die("{'error':true,'type':'email_format_bad','report':'$err_string','id':'".$in_meeting_data['id_bigint']."'}");
- }
- } else {
- $data[$key] = $value;
- }
- break;
-
- // We only accept a 1 or a 0.
- case 'published':
- // Meeting list editors can't publish meetings.
- if (c_comdef_server::GetCurrentUserObj(true)->GetUserLevel() != _USER_LEVEL_EDITOR) {
- $data[$key] = $value ? 1 : 0;
- }
- break;
-
- case 'root_server_uri':
- case 'venue_type':
- break; // This should just be a calculated field, so don't save it
-
- // These are the various "optional" fields.
- default:
- if (isset($data[$key])) {
- $data[$key]['meetingid_bigint'] = $in_meeting_data['id_bigint'];
- $data[$key]['value'] = trim($value);
- } else {
- $value = trim($value);
- $template_field_prompt = array_key_exists($key, $template_data) ? $template_data[$key]['field_prompt'] : null;
- $template_visibility = array_key_exists($key, $template_data) ? $template_data[$key]['visibility'] : null;
- $result_data['new_data']['key'] = $key;
- $result_data['new_data']['field_prompt'] = $template_field_prompt;
- $result_data['new_data']['value'] = $value;
- $meeting->AddDataField($key, $template_field_prompt, $value, null, intval($template_visibility));
- }
- break;
- }
- }
- if ($meeting->UpdateToDB()) {
- $used_formats = array();
- $result = $this->TranslateToJSON($this->GetSearchResults(array ( 'meeting_ids' => array ( $meeting->GetID() ) ), $used_formats));
- if ($print_result) {
- header('Content-Type:application/json; charset=UTF-8');
- echo $result;
- } else {
- return $result;
- }
- } else {
- $in_meeting_data['id_bigint'] = json_prepare($this->my_localized_strings['comdef_server_admin_strings']['edit_Meeting_meeting_id']).$in_meeting_data['id_bigint'];
- $err_string = json_prepare($this->my_localized_strings['comdef_server_admin_strings']['edit_Meeting_auth_failure']);
- $result = "{'error':true,'type':'auth_failure','report':'$err_string','info':'".$in_meeting_data['id_bigint']."'}";
- if ($print_result) {
- header('Content-Type:application/json; charset=UTF-8');
- echo $result;
- } else {
- return $result;
- }
- }
- } else {
- $in_meeting_data['id_bigint'] = json_prepare($this->my_localized_strings['comdef_server_admin_strings']['edit_Meeting_meeting_id']).$in_meeting_data['id_bigint'];
- $err_string = json_prepare($this->my_localized_strings['comdef_server_admin_strings']['edit_Meeting_auth_failure']);
- $result = "{'error':true,'type':'auth_failure','report':'$err_string','info':'".$in_meeting_data['id_bigint']."'}";
- if ($print_result) {
- header('Content-Type:application/json; charset=UTF-8');
- echo $result;
- } else {
- return $result;
- }
- }
- } else {
- $in_meeting_data['id_bigint'] = json_prepare($this->my_localized_strings['comdef_server_admin_strings']['edit_Meeting_meeting_id']).$in_meeting_data['id_bigint'];
- $err_string = json_prepare($this->my_localized_strings['comdef_server_admin_strings']['edit_Meeting_object_not_found']);
- $result = "{'error':true,'type':'object_not_found','report':'$err_string','info':'".$in_meeting_data['id_bigint']."'}";
- if ($print_result) {
- header('Content-Type:application/json; charset=UTF-8');
- echo $result;
- } else {
- return $result;
- }
- }
- } catch (Exception $e) {
- $in_meeting_data['id_bigint'] = json_prepare($this->my_localized_strings['comdef_server_admin_strings']['edit_Meeting_meeting_id']).$in_meeting_data['id_bigint'];
- $err_string = json_prepare($this->my_localized_strings['comdef_server_admin_strings']['edit_Meeting_object_not_changed']);
- $result = "{'error':true,'type':'object_not_changed','report':'$err_string','info':'".$in_meeting_data['id_bigint']."'}";
- if ($print_result) {
- header('Content-Type:application/json; charset=UTF-8');
- echo $result;
- } else {
- return $result;
- }
- }
- }
-
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- private function GetVenueTypeForFormats($formatsArray)
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- // Get the format ID for each of the venue type formats
- $vmFormatId = 0;
- $hyFormatId = 0;
- $tcFormatId = 0;
- foreach ($this->my_server->GetFormatsArray()["en"] as $format) {
- if ($format->GetKey() == "VM") {
- $vmFormatId = $format->GetSharedID();
- } else if ($format->GetKey() == "HY") {
- $hyFormatId = $format->GetSharedID();
- } else if ($format->GetKey() == "TC") {
- $tcFormatId = $format->GetSharedID();
- }
- if ($vmFormatId && $hyFormatId && $tcFormatId) {
- break;
- }
- }
-
- // if (!$vmFormatId || !$hyFormatId || !$tcFormatId) {
- // I think this can only happen if someone manually messed with their database, and
- // I am not really sure what we should do in this situation.
- //}
-
- // Set helper bools indicating whether or not the formats array has these formats
- $hasVM = false;
- $hasHY = false;
- $hasTC = false;
- foreach ($formatsArray as $format) {
- if ($format->GetSharedID() == $vmFormatId) {
- $hasVM = true;
- } else if ($format->GetSharedID() == $hyFormatId) {
- $hasHY = true;
- } else if ($format->GetSharedID() == $tcFormatId) {
- $hasTC = true;
- }
- if ($hasVM && $hasHY && $hasTC) {
- break;
- }
- }
-
- // This logic is copied from setFormatCheckboxes in server_admin_javascript.js
- if (!$hasVM && !$hasTC && $hasHY) {
- return VenueType::HYBRID;
- } else if ($hasVM && $hasTC && !$hasHY) {
- // This is Virtual TC in the UI, but that doesn't seem like a useful designation for filtering,
- // so we are just going to set it to virtual. I suspect virtual TC as a venue type will go away
- // eventually.
- return VenueType::VIRTUAL;
- } else if ($hasVM && !$hasTC && !$hasHY) {
- return VenueType::VIRTUAL;
- } else {
- return VenueType::IN_PERSON;
- }
- }
-
- /*******************************************************************/
- /**
- \brief This returns the search results, in whatever form was requested.
-
- \returns CSV data, with the first row a key header.
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function GetSearchResults(
- $in_http_vars, ///< The HTTP GET and POST parameters.
- &$formats_ar ///< This will return the formats used in this search.
- ) {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- if (!( isset($in_http_vars['geo_width']) && $in_http_vars['geo_width'] ) && isset($in_http_vars['bmlt_search_type']) && ($in_http_vars['bmlt_search_type'] == 'advanced') && isset($in_http_vars['advanced_radius']) && isset($in_http_vars['advanced_mapmode']) && $in_http_vars['advanced_mapmode'] && ( floatval($in_http_vars['advanced_radius'] != 0.0) ) && isset($in_http_vars['lat_val']) && isset($in_http_vars['long_val']) && ( (floatval($in_http_vars['lat_val']) != 0.0) || (floatval($in_http_vars['long_val']) != 0.0) )) {
- $in_http_vars['geo_width'] = $in_http_vars['advanced_radius'];
- } elseif (!( isset($in_http_vars['geo_width']) && $in_http_vars['geo_width'] ) && isset($in_http_vars['bmlt_search_type']) && ($in_http_vars['bmlt_search_type'] == 'advanced')) {
- $in_http_vars['lat_val'] = null;
- $in_http_vars['long_val'] = null;
- } elseif (!isset($in_http_vars['geo_loc']) || $in_http_vars['geo_loc'] != 'yes') {
- if (!isset($in_http_vars['geo_width'])) {
- $in_http_vars['geo_width'] = 0;
- }
- }
-
- $geocode_results = null;
- $ignore_me = null;
- $meeting_objects = array();
-
- $result = DisplaySearchResultsCSV($in_http_vars, $ignore_me, $geocode_results, $meeting_objects, true, true);
-
- if (isset($meeting_objects) && is_array($meeting_objects) && count($meeting_objects) && isset($formats_ar) && is_array($formats_ar)) {
- foreach ($meeting_objects as $one_meeting) {
- $formats = $one_meeting->GetMeetingDataValue('formats');
-
- foreach ($formats as $format) {
- if ($format && ($format instanceof c_comdef_format)) {
- $format_shared_id = $format->GetSharedID();
- $formats_ar[$format_shared_id] = $format;
- }
- }
- }
- }
-
- if (isset($in_http_vars['data_field_key']) && $in_http_vars['data_field_key']) {
- // At this point, we have everything in a CSV. We separate out just the field we want.
- $temp_keyed_array = array();
- $result = explode("\n", $result);
- $keys = array_shift($result);
- $keys = explode("\",\"", trim($keys, '"'));
- $the_keys = explode(',', $in_http_vars['data_field_key']);
-
- $result2 = array();
- foreach ($result as $row) {
- if ($row) {
- $index = 0;
- $row = explode('","', trim($row, '",'));
- $row_columns = array();
- foreach ($row as $column) {
- if (isset($column)) {
- if (in_array($keys[$index++], $the_keys)) {
- array_push($row_columns, $column);
- }
- }
- }
- $result2[$row[0]] = '"'.implode('","', $row_columns).'"';
- }
- }
-
- $the_keys = array_intersect($keys, $the_keys);
- $result = '"'.implode('","', $the_keys)."\"\n".implode("\n", $result2);
- }
-
- return $result;
- }
-
- /*******************************************************************/
- /**
- \brief Translates CSV to JSON.
-
- \returns a JSON string, with all the data in the CSV.
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function TranslateToJSON(
- $in_csv_data ///< An array of CSV data, with the first element being the field names.
- ) {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $temp_keyed_array = array();
- $in_csv_data = explode("\n", $in_csv_data);
- $keys = array_shift($in_csv_data);
- $keys = explode("\",\"", trim($keys, '"'));
-
- foreach ($in_csv_data as $row) {
- if ($row) {
- $line = null;
- $index = 0;
- $row = trim($row);
- if (substr($row, 0, 1) == '"') { // Strip first double quote
- $row = substr($row, 1, strlen($row) - 1);
- }
- if (substr($row, strlen($row) - 1, 1) == ',') { // Strip last comma, just in case
- $row = substr($row, 0, strlen($row) - 1);
- }
- if (substr($row, strlen($row) - 1, 1) == '"') { // Strip last double quote
- $row = substr($row, 0, strlen($row) - 1);
- }
- $row = explode('","', $row);
- if (is_array($row)) {
- foreach ($row as $column) {
- if (isset($column)) {
- $line[$keys[$index++]] = $column;
- }
- }
- array_push($temp_keyed_array, $line);
- }
- }
- }
-
- return array2json($temp_keyed_array);
- }
-}
-
-$handler = new c_comdef_admin_ajax_handler($http_vars);
-
-$ret = 'ERROR';
-
-if ($handler instanceof c_comdef_admin_ajax_handler) {
- $ret = $handler->parse_ajax_call();
-}
-
-echo $ret;
diff --git a/src/legacy/local_server/server_admin/c_comdef_admin_main_console.class.php b/src/legacy/local_server/server_admin/c_comdef_admin_main_console.class.php
deleted file mode 100644
index ba3c7aa61..000000000
--- a/src/legacy/local_server/server_admin/c_comdef_admin_main_console.class.php
+++ /dev/null
@@ -1,2259 +0,0 @@
-.
-*/
-defined('BMLT_EXEC') or die('Cannot Execute Directly'); // Makes sure that this file is in the correct context.
-require_once(dirname(__FILE__).'/../../server/c_comdef_server.class.php');
-require_once(dirname(__FILE__).'/../../server/shared/Array2Json.php');
-
-// #define ( '__NAWS_IMPORT__', 1 ) /* Uncomment to enable the NAWS import functionality. */
-
-/************************************************************************************************************//**
- \class c_comdef_admin_main_console
- \brief Controls display of the main BMLT administration console.
-****************************************************************************************************************/
-// phpcs:disable PSR1.Classes.ClassDeclaration.MissingNamespace
-// phpcs:disable Squiz.Classes.ValidClassName.NotCamelCaps
-class c_comdef_admin_main_console
-// phpcs:enable PSR1.Classes.ClassDeclaration.MissingNamespace
-// phpcs:enable Squiz.Classes.ValidClassName.NotCamelCaps
-{
- public $my_localized_strings; ///< This will contain the localized strings and whatnot for display.
- public $my_server; ///< This hold the server object.
- public $my_user; ///< This holds the instance of the logged-in user.
- public $my_ajax_uri; ///< This will be the URI for AJAX calls.
- public $my_http_vars; ///< Contains the HTTP vars sent in.
- public $my_service_bodies; ///< This will be an array that contains all the Service bodies this user can edit.
- public $my_users; ///< This will be an array of all the user objects.
- public $my_formats; ///< The format objects that are available for meetings.
- public $my_format_types; ///< The format objects that are available for meetings.
- public $my_data_field_templates; ///< This holds the keys for all the possible data fields for this server.
- public $my_editable_service_bodies; ///< This will contain all the Service bodies that we can actually directly edit.
- public $my_all_service_bodies; ///< This contains all Service bodies, cleaned for orphans.
- public $my_observable_service_bodies; ///< This contains all observable service bodies.
- public $my_lang_ids; ///< Contains the enumerations for all the server langs.
-
- /********************************************************************************************************//**
- \brief
- ************************************************************************************************************/
- public function __construct(
- $in_http_vars ///< The HTTP transaction parameters
- ) {
- $this->my_http_vars = $in_http_vars;
- $this->my_localized_strings = c_comdef_server::GetLocalStrings();
- $this->my_server = c_comdef_server::MakeServer();
- $this->my_user = $this->my_server->GetCurrentUserObj();
-
- // We check this every chance that we get.
- if (!$this->my_user || ($this->my_user->GetUserLevel() == _USER_LEVEL_DEACTIVATED)) {
- die('NOT AUTHORIZED');
- }
-
- $this->my_users = array_values($this->my_server->GetServerUsersObj()->GetUsersArray());
- usort($this->my_users, array("c_comdef_admin_main_console", "compare_names"));
- $url_path = GetURLToMainServerDirectory();
- $this->my_ajax_uri = $url_path.'?bmlt_ajax_callback=1';
-
- $this->my_formats = array();
- $langs = $this->my_server->GetFormatLangs();
- $this->my_lang_ids = array_keys($langs);
- $server_format_array = $this->my_server->GetFormatsArray();
- $format_ids = array();
- usort($server_format_array[$this->my_server->GetLocalLang()], function ($a, $b) {
- return strnatcasecmp($a->GetKey(), $b->GetKey());
- });
- // We will build an array of formats in the structure we'll need for our editor. We start by gathering all of the shared IDs.
- foreach ($langs as $lang_key => $lang_name) {
- if (isset($server_format_array[$lang_key])) {
- $the_format_object_array = $server_format_array[$lang_key];
- foreach ($the_format_object_array as $format) {
- $format_ids['format_'.$format->GetSharedID()] = $format->GetSharedID();
- }
- }
- }
-
- // OK, we have a sorted array of unique format IDs. Now, we assign each one an array of format data per language.
-
- foreach ($format_ids as $id) {
- $single_format = array();
- // Walk through the server languages...
- foreach ($langs as $lang_key => $lang_name) {
- // Then through all the formats with data in each language...
- if (isset($server_format_array[$lang_key])) {
- $the_format_object_array = $server_format_array[$lang_key];
- foreach ($the_format_object_array as $format) {
- // If the format is available with data in this language, we add it to our ID.
- if ($format->GetSharedID() == $id) {
- $single_format[$lang_key]['shared_id'] = $id;
- $single_format[$lang_key]['lang_key'] = $lang_key;
- $single_format[$lang_key]['lang_name'] = $lang_name;
- $single_format[$lang_key]['key'] = $format->GetKey();
- $single_format[$lang_key]['name'] = $format->GetLocalName();
- $single_format[$lang_key]['description'] = $format->GetLocalDescription();
- $single_format[$lang_key]['type'] = $format->GetFormatType();
- $single_format[$lang_key]['worldid_mixed'] = $format->GetWorldID();
- }
- }
- }
- }
-
- $this->my_formats[] = array ( 'id' => $id, 'formats' => $single_format );
- }
-
- /* Now get the format types */
- $this->my_format_types = $this->my_server->GetFormatTypesArray();
- usort($this->my_format_types, function ($a, $b) {
- return $a->GetPosition() <=> $b->GetPosition();
- });
- $service_bodies = $this->my_server->GetServiceBodyArray();
- usort($service_bodies, array("c_comdef_admin_main_console", "compare_names"));
- $this->my_service_bodies = array();
- $this->my_editable_service_bodies = array();
- $this->my_all_service_bodies = array();
- $this->my_observable_service_bodies = array();
-
- for ($c = 0; $c < count($service_bodies); $c++) {
- $service_body = $service_bodies[$c];
- if ($service_body->UserCanEditMeetings()) {
- array_push($this->my_service_bodies, $service_body);
- }
-
- if ($service_body->UserCanEdit()) {
- array_push($this->my_editable_service_bodies, $service_body);
- }
-
- if ($service_body->UserCanObserve()) {
- array_push($this->my_observable_service_bodies, $service_body);
- }
-
- array_push($this->my_all_service_bodies, $service_body);
- }
-
- // We get all the available data fields, and create a local data member for their keys.
- $this->my_data_field_templates = c_comdef_meeting::GetDataTableTemplate();
- $longdata_obj = c_comdef_meeting::GetLongDataTableTemplate();
-
- // We merge the two tables (data and longdata).
- if (is_array($this->my_data_field_templates) && count($this->my_data_field_templates) && is_array($longdata_obj) && count($longdata_obj)) {
- $this->my_data_field_templates = array_merge($this->my_data_field_templates, $longdata_obj);
- }
-
- // Sort them by their field keys, so we have a consistent order.
- $flags = ( defined('SORT_NATURAL') && defined('SORT_FLAG_CASE') ) ? intval(SORT_NATURAL | SORT_FLAG_CASE) : null;
- ksort($this->my_data_field_templates, $flags);
- }
-
- /********************************************************************************************************//**
- \brief Returns the HTML for the main admin console.
- \returns HTML code.
- ************************************************************************************************************/
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function return_main_console_html()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $ret = '
'.(defined('__DEBUG_MODE__') ? "\n" : '');
- // We actually include the JS directly into the HTML. This gives us a lot more flexibility as to how we deploy and gatekeep this file.
- $ret .= '';
- $ret .= ''.(defined('__DEBUG_MODE__') ? "\n" : '');
- $ret .= ''.(defined('__DEBUG_MODE__') ? "\n" : '');
- $ret .= ''.(defined('__DEBUG_MODE__') ? "\n" : '');
- $ret .= '';
- $ret .= ''.(defined('__DEBUG_MODE__') ? "\n" : '');
- // Belt and suspenders. Just make sure the user is legit.
- if (($this->my_user instanceof c_comdef_user) && ($this->my_user->GetUserLevel() != _USER_LEVEL_DEACTIVATED)) {
- // Figure out which output will be sent, according to the user level.
- switch ($this->my_user->GetUserLevel()) {
- case _USER_LEVEL_SERVER_ADMIN:
- $ret .= $this->return_format_editor_panel();
- // Intentional fallthrough
- case _USER_LEVEL_SERVICE_BODY_ADMIN:
- $ret .= $this->return_server_admin_panel();
- $ret .= $this->return_user_admin_panel();
- if ((count($this->my_editable_service_bodies) > 0) || ($this->my_user->GetUserLevel() == _USER_LEVEL_SERVER_ADMIN)) {
- $ret .= $this->return_service_body_admin_panel();
- }
- // Intentional fallthrough
- case _USER_LEVEL_EDITOR:
- $ret .= $this->return_meeting_editor_panel();
- // Intentional fallthrough
- case _USER_LEVEL_OBSERVER:
- $ret .= '
'.(defined('__DEBUG_MODE__') ? "\n" : '');
- $ret .= ''.(defined('__DEBUG_MODE__') ? "\n" : '');
-
- return $ret;
- }
-
- /********************************************************************************************************//**
- \brief This creates the HTML for a user selection popup menu.
- \returns The HTML and JavaScript for the popup menu (select element).
- ************************************************************************************************************/
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function create_user_popup($users)
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $ret = ''.(defined('__DEBUG_MODE__') ? "\n" : '');
-
- return $ret;
- }
-
- /********************************************************************************************************//**
- \brief This creates the HTML for a user level popup menu.
- \returns The HTML and JavaScript for the popup menu (select element).
- ************************************************************************************************************/
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function create_user_level_popup()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $disabled = $this->my_user->GetUserLevel() == _USER_LEVEL_SERVER_ADMIN ? '' : ' disabled';
- $ret = '';
-
- return $ret;
- }
-
- /********************************************************************************************************//**
- \brief This creates the HTML for a user owner selection popup menu.
- \returns The HTML and JavaScript for the popup menu (select element).
- ************************************************************************************************************/
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function create_user_owner_popup($users)
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $disabled = $this->my_user->GetUserLevel() == _USER_LEVEL_SERVER_ADMIN ? '' : ' disabled';
- $ret = ''.(defined('__DEBUG_MODE__') ? "\n" : '');
-
- return $ret;
- }
-
- /********************************************************************************************************//**
- \brief This constructs the User editor buttons as a div.
- \returns The HTML and JavaScript for the button panel.
- ************************************************************************************************************/
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function return_user_editor_button_panel()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $ret = '
';
-
- return $ret;
- }
-
- /********************************************************************************************************//**
- \brief This constructs the Service body editor panel. Only Server Admins and Service Body Admins get this one.
- \returns The HTML and JavaScript for the "Service Body Administration" section.
- ************************************************************************************************************/
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function return_service_body_admin_panel()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $ret = '';
- $full_editors = $this->get_full_editor_users();
-
- if (count($full_editors)) { // Have to have at least one Service body admin
- $ret = '
';
- $ret .= '';
- }
-
- return $ret;
- }
-
- /********************************************************************************************************//**
- \brief This constructs a window for the Service Body administrator.
- \returns The HTML and JavaScript for the "Service Body Administration" section.
- ************************************************************************************************************/
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function return_single_service_body_editor_panel()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $ret = '
'.(defined('__DEBUG_MODE__') ? "\n" : '');
-
- return $ret;
- }
-
- /********************************************************************************************************//**
- \brief This gets just the Service Body Admin Users, and returns their objects in an array.
- \returns An array with the user objects (instances of c_comdef_user)
- ************************************************************************************************************/
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function get_full_editor_users()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $ret = array ();
-
- for ($c = 0; $c < count($this->my_users); $c++) {
- $user = $this->my_users[$c];
- if ($user->GetUserLevel() == _USER_LEVEL_SERVICE_BODY_ADMIN) {
- array_push($ret, $user);
- }
- }
-
- return $ret;
- }
-
- /********************************************************************************************************//**
- \brief This gets just the Service Body Editor (Trainee) Users, and returns their objects in an array.
- \returns An array with the user objects (instances of c_comdef_user)
- ************************************************************************************************************/
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function get_basic_editor_users()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $ret = array ();
-
- for ($c = 0; $c < count($this->my_users); $c++) {
- $user = $this->my_users[$c];
- if ($user->GetUserLevel() == _USER_LEVEL_EDITOR) {
- array_push($ret, $user);
- }
- }
-
- return $ret;
- }
-
- /********************************************************************************************************//**
- \brief This gets just the Observer Users, and returns their objects in an array.
- \returns An array with the user objects (instances of c_comdef_user)
- ************************************************************************************************************/
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function get_observer_users()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $ret = array ();
-
- for ($c = 0; $c < count($this->my_users); $c++) {
- $user = $this->my_users[$c];
- if ($user->GetUserLevel() == _USER_LEVEL_OBSERVER) {
- array_push($ret, $user);
- }
- }
-
- return $ret;
- }
-
- /********************************************************************************************************//**
- \brief This creates the HTML for a Service body parent selection popup menu.
- \returns The HTML and JavaScript for the popup menu (select element).
- ************************************************************************************************************/
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function create_service_body_parent_popup()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $ret = ''.(defined('__DEBUG_MODE__') ? "\n" : '');
-
- return $ret;
- }
-
- /********************************************************************************************************//**
- \brief This creates the HTML for a Service body selection popup menu.
- \returns The HTML and JavaScript for the popup menu (select element).
- ************************************************************************************************************/
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function create_service_body_popup()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $ret = ''.(defined('__DEBUG_MODE__') ? "\n" : '');
-
- return $ret;
- }
-
- /********************************************************************************************************//**
- \brief This creates the HTML for a Service body selection popup menu.
- \returns The HTML and JavaScript for the popup menu (select element).
- ************************************************************************************************************/
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function create_service_body_type_popup()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $ret = '';
-
- return $ret;
- }
-
- /********************************************************************************************************//**
- \brief This returns the user name for a given user ID.
- \returns a string, containing the name.
- ************************************************************************************************************/
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function get_user_name_from_id(
- $in_user_id ///< The ID to look up.
- ) {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $ret = null;
-
- for ($index = 0; $index < count($this->my_users); $index++) {
- $user = $this->my_users[$index];
- if ($user->GetID() == $in_user_id) {
- $ret = $user->GetLocalName();
- break;
- }
- }
-
- return $ret;
- }
-
- /********************************************************************************************************//**
- \brief This creates the HTML for a Service body selection popup menu.
- \returns The HTML and JavaScript for the popup menu (select element).
- ************************************************************************************************************/
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function create_service_body_user_popup()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $ret = '';
-
- return $ret;
- }
-
- /********************************************************************************************************//**
- \brief This constructs the Service body editor buttons as a div.
- \returns The HTML and JavaScript for the button panel.
- ************************************************************************************************************/
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function return_service_body_editor_button_panel()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $ret = '
';
- }
-
- return $ret;
- }
-
- /********************************************************************************************************//**
- \brief This constructs the tab div that allows the user to select between a search and results.
- \returns The HTML and JavaScript for the Meeting Editor Tabs
- ************************************************************************************************************/
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function return_meeting_editor_tab_div()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $ret ='
';
-
- return $ret;
- }
-
- /********************************************************************************************************//**
- \brief This constructs a panel that displays a choice of Service bodies for the user to choose.
- \returns The HTML and JavaScript for the Edit Meetings Search Specifier section.
- ************************************************************************************************************/
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function return_meeting_start_time_selection_panel()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $ret = '
';
-
- return $ret;
- }
-
- /********************************************************************************************************//**
- \brief This constructs a panel that displays a choice of Service bodies for the user to choose.
- \returns The HTML and JavaScript for the Edit Meetings Search Specifier section.
- ************************************************************************************************************/
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function return_meeting_service_body_selection_panel()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $ret = 'NOT AUTHORIZED';
-
- if (count($this->my_service_bodies)) {
- $ret = '
';
- }
-
- return $ret;
- }
-
- /************************************************************************************//**
- \brief Build the content for the Advanced Service Bodies section.
- ****************************************************************************************/
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function populate_service_bodies(
- $in_id ///< The ID of the Service body.
- ) {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $service_body_content = '';
- $child_content = '';
-
- foreach ($this->my_all_service_bodies as $service_body) {
- if ($in_id == $service_body->GetID()) {
- if ($service_body->UserCanEditMeetings()) {
- $service_body_content = '';
- $service_body_content .= '';
- $service_body_content .= '';
- $service_body_content .= '';
- }
- } elseif ($in_id == $service_body->GetOwnerID()) {
- $child_content .= $this->populate_service_bodies($service_body->GetID());
- }
- }
-
- // At this point, we have the main Service body, as well as any child content.
-
- if ($service_body_content) {
- $service_body_content = '
';
- } else {
- die('THIS USER NOT AUTHORIZED TO EDIT MEETINGS');
- }
-
- return $ret;
- }
-
- /********************************************************************************************************//**
- \brief This constructs a panel for creating new meetings that goes above the results.
- \returns The HTML and JavaScript for the New Meetings section.
- ************************************************************************************************************/
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function return_new_meeting_panel()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $ret = '
';
-
- return $ret;
- }
-
- /********************************************************************************************************//**
- \brief This constructs the meeting search results panel of the meeting editor.
- \returns The HTML and JavaScript for the Search Results section.
- ************************************************************************************************************/
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function return_meeting_results_panel()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $ret = '
';
- $ret .= '
';
- $ret .= '
';
- $ret .= '
';
- $ret .= '
';
-
- return $ret;
- }
-
- /********************************************************************************************************//**
- \brief This constructs a template to be filled in for a single meeting that will be edited.
- \returns The HTML and JavaScript for the "Edit Meetings" section.
- ************************************************************************************************************/
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function return_single_meeting_editor_template()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $ret = '
';
-
- return $ret;
- }
-
- /********************************************************************************************************//**
- \brief This constructs the meeting editor buttons as a div.
- \returns The HTML and JavaScript for the button panel.
- ************************************************************************************************************/
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function return_meeting_editor_button_panel()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $ret = '
';
-
- return $ret;
- }
-
- /********************************************************************************************************//**
- \brief This constructs a template to be filled in for the basic options tab.
- \returns The HTML and JavaScript for the option sheet.
- ************************************************************************************************************/
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function return_single_meeting_basic_template()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- if (($this->my_user->GetUserLevel() == _USER_LEVEL_EDITOR) || ($this->my_user->GetUserLevel() == _USER_LEVEL_SERVICE_BODY_ADMIN) || ($this->my_user->GetUserLevel() == _USER_LEVEL_SERVER_ADMIN)) {
- $ret = '
';
- }
-
- return $ret;
- }
-
- /********************************************************************************************************//**
- \brief This constructs a template to be filled in for the location options tab.
- \returns The HTML and JavaScript for the option sheet.
- ************************************************************************************************************/
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function return_single_meeting_location_template()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $ret = '
';
- }
- return $ret;
- }
- /********************************************************************************************************//**
- \brief
- \returns The HTML and JavaScript for the option sheet.
- ************************************************************************************************************/
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function return_single_meeting_other_template()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $ret = '
';
- foreach ($this->my_data_field_templates as $data_field) {
- $key = $data_field['key'];
- $prompt = $data_field['field_prompt'];
- switch ($key) {
- case 'id_bigint': // All of these are ignored, as they are taken care of in other option sheets.
- case 'worldid_mixed':
- case 'shared_group_id_bigint':
- case 'service_body_bigint':
- case 'weekday_tinyint':
- case 'venue_type':
- case 'start_time':
- case 'formats':
- case 'lang_enum':
- case 'longitude':
- case 'latitude':
- case 'email_contact':
- case 'meeting_name':
- case 'location_text':
- case 'location_info':
- case 'location_street':
- case 'location_neighborhood':
- case 'location_city_subsection':
- case 'location_municipality':
- case 'location_sub_province':
- case 'location_province':
- case 'location_postal_code_1':
- case 'location_nation':
- case 'phone_meeting_number':
- case 'virtual_meeting_link':
- case 'virtual_meeting_additional_info':
- break;
-
- default: // We display these ones.
- if (array_key_exists('meeting_editor_screen_meeting_' . $key . '_label', $this->my_localized_strings['comdef_server_admin_strings'])) {
- $prompt = $this->my_localized_strings['comdef_server_admin_strings']['meeting_editor_screen_meeting_' . $key . '_label'];
- }
- $ret .= '
';
-
- return $ret;
- }
-
- /********************************************************************************************************//**
- \brief
- \returns The HTML and JavaScript for the option sheet.
- ************************************************************************************************************/
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function return_single_meeting_history_template()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $ret = '
';
- $ret .= '
';
- $ret .= '
';
-
- return $ret;
- }
-
- /********************************************************************************************************//**
- \brief This constructs the "Server Administration" section of the console. Server Admins and Service Body admins can see this.
- \returns The HTML and JavaScript for the "Server Administration" section.
- ************************************************************************************************************/
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function return_server_admin_panel()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $ret = '
';
-
- return $ret;
- }
-
- /********************************************************************************************************//**
- \brief This constructs the "My Account" section of the console. All user levels will have this.
- \returns The HTML and JavaScript for the "My Account" section.
- ************************************************************************************************************/
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function return_user_account_settings_panel()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $ret = '
';
-
- return $ret;
- }
-
- /************************************************************************************//**
- \brief Used to sort users and service body names.
- ****************************************************************************************/
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function compare_names($a, $b)
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- return strnatcasecmp($a->GetLocalName(), $b->GetLocalName());
- }
-}
diff --git a/src/legacy/local_server/server_admin/c_comdef_admin_xml_handler.class.php b/src/legacy/local_server/server_admin/c_comdef_admin_xml_handler.class.php
deleted file mode 100644
index 0346d8011..000000000
--- a/src/legacy/local_server/server_admin/c_comdef_admin_xml_handler.class.php
+++ /dev/null
@@ -1,1880 +0,0 @@
-.
-*/
-defined('BMLT_EXEC') or die('Cannot Execute Directly'); // Makes sure that this file is in the correct context.
-/***********************************************************************************************************//**
- \class c_comdef_admin_xml_handler
- \brief Controls handling of the admin semantic interface.
-
- This class should not even be instantiated unless the user has been authorized, and an authorized seesion
- is in progress.
-***************************************************************************************************************/
-// phpcs:disable PSR1.Classes.ClassDeclaration.MissingNamespace
-// phpcs:disable Squiz.Classes.ValidClassName.NotCamelCaps
-class c_comdef_admin_xml_handler
-// phpcs:enable PSR1.Classes.ClassDeclaration.MissingNamespace
-// phpcs:enable Squiz.Classes.ValidClassName.NotCamelCaps
-{
- public $http_vars; ///< This will hold the combined GET and POST parameters for this call.
- public $server; ///< The BMLT server model instance.
- public $my_localized_strings; ///< An array of localized strings.
- public $handled_service_body_ids; ///< This is used to ensure that we respect the hierarchy when doing a hierarchical Service body request.
-
- /********************************************************************************************************//**
- \brief The class constructor.
- ************************************************************************************************************/
- public function __construct(
- $in_http_vars, ///< The combined GET and POST parameters.
- $in_server ///< The BMLT server instance.
- ) {
- $this->http_vars = $in_http_vars;
- $this->server = $in_server;
- $this->my_localized_strings = c_comdef_server::GetLocalStrings();
- $this->handled_service_body_ids = array();
- }
-
- /********************************************************************************************************//**
- \brief This returns the URL to the main server. It needs extra stripping, because we're depper than usual.
-
- \returns the URL.
- ************************************************************************************************************/
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function getMainURL()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- return dirname(dirname(GetURLToMainServerDirectory(false))).'/';
- }
-
- /********************************************************************************************************//**
- \brief This extracts a meeting's essential data as XML.
-
- \returns the XML for the meeting data.
- ************************************************************************************************************/
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function get_meeting_data($meeting_id)
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $ret = '';
-
- $meeting_object = c_comdef_server::GetOneMeeting($meeting_id);
-
- if (($meeting_object instanceof c_comdef_meeting) && (intval($meeting_object->GetID()) == intval($meeting_id))) {
- $localized_strings = c_comdef_server::GetLocalStrings();
- $meeting_id = $meeting_object->GetID();
- $weekday_tinyint = intval($meeting_object->GetMeetingDataValue('weekday_tinyint'));
- $weekday_name = $localized_strings["comdef_server_admin_strings"]["meeting_search_weekdays_names"][$weekday_tinyint];
- $start_time = $meeting_object->GetMeetingDataValue('start_time');
- $meeting_name = str_replace('"', "'", str_replace("\n", " ", str_replace("\r", " ", $meeting_object->GetMeetingDataValue('meeting_name'))));
- $meeting_borough = str_replace('"', "'", str_replace("\n", " ", str_replace("\r", " ", $meeting_object->GetMeetingDataValue('location_city_subsection'))));
- $meeting_town = str_replace('"', "'", str_replace("\n", " ", str_replace("\r", " ", $meeting_object->GetMeetingDataValue('location_municipality'))));
- $meeting_state = str_replace('"', "'", str_replace("\n", " ", str_replace("\r", " ", $meeting_object->GetMeetingDataValue('location_province'))));
-
- $ret = '"meeting_id","meeting_name","weekday_tinyint","weekday_name","start_time","location_city_subsection","location_municipality","location_province"'."\n";
-
- if ($meeting_id) {
- $change_line['meeting_id'] = $meeting_id;
- } else {
- $change_line['meeting_id'] = 0;
- }
-
- if ($meeting_name) {
- $change_line['meeting_name'] = $meeting_name;
- } else {
- $change_line['meeting_name'] = '';
- }
-
- if ($weekday_tinyint) {
- $change_line['weekday_tinyint'] = $weekday_tinyint;
- } else {
- $change_line['weekday_tinyint'] = '';
- }
-
- if ($weekday_name) {
- $change_line['weekday_name'] = $weekday_name;
- } else {
- $change_line['weekday_name'] = '';
- }
-
- if ($start_time) {
- $change_line['start_time'] = $start_time;
- } else {
- $change_line['start_time'] = '';
- }
-
- if ($meeting_borough) {
- $change_line['location_city_subsection'] = $meeting_borough;
- } else {
- $change_line['location_city_subsection'] = '';
- }
-
- if ($meeting_town) {
- $change_line['location_municipality'] = $meeting_town;
- } else {
- $change_line['location_municipality'] = '';
- }
-
- if ($meeting_state) {
- $change_line['location_province'] = $meeting_state;
- } else {
- $change_line['location_province'] = '';
- }
-
- $ret .= '"'.implode('","', $change_line).'"'."\n";
- $ret = $this->TranslateCSVToXML($ret);
- $ret = "\ngetMainURL()."client_interface/xsd/RestoreDeletedMeeting.php\">$ret";
- } else {
- $ret = '
PROGRAM ERROR (MEETING FETCH FAILED)
';
- }
-
- return $ret;
- }
-
- /********************************************************************************************************//**
- \brief This is called to process the input and generate the output. It is the "heart" of the class.
-
- \returns XML to be returned.
- ************************************************************************************************************/
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function process_commands()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $ret = null;
- // We make sure that we are allowed to access this level of functionality.
- // This is "belt and suspenders." We will constantly check user credentials.
- if ($this->basic_user_validation()) {
- if (isset($this->http_vars['admin_action']) && trim($this->http_vars['admin_action'])) {
- set_time_limit(120); // Some requests can take a loooong time...
- switch (strtolower(trim($this->http_vars['admin_action']))) {
- case 'get_permissions':
- $ret = $this->process_capabilities_request();
- break;
-
- case 'get_service_body_info':
- $ret = $this->process_service_bodies_info_request();
- break;
-
- case 'get_format_info':
- $ret = $this->process_format_info();
- break;
-
- case 'get_field_templates':
- $ret = $this->process_get_field_templates();
- break;
-
- case 'get_meetings':
- $ret = $this->process_meeting_search();
- break;
-
- case 'get_deleted_meetings':
- $ret = $this->process_deleted_meetings();
- break;
-
- case 'get_changes':
- $ret = $this->process_changes();
- break;
-
- case 'add_meeting':
- $this->http_vars['meeting_id'] = 0;
- unset($this->http_vars['meeting_id']); // Make sure that we have no meeting ID. This forces an add.
- $ret = $this->process_meeting_modify();
- break;
-
- case 'rollback_meeting_to_before_change':
- if (intval($this->http_vars['meeting_id']) && intval($this->http_vars['change_id'])) { // Make sure that we are referring to a meeting and a change.
- $ret = $this->process_rollback_meeting();
- } else {
- $ret = '
BAD ADMIN ACTION
';
- }
- break;
-
- case 'restore_deleted_meeting':
- if (intval($this->http_vars['meeting_id'])) { // Make sure that we are referring to a meeting
- $ret = $this->process_restore_deleted_meeting();
- } else {
- $ret = '
BAD ADMIN ACTION
';
- }
- break;
-
- case 'modify_meeting':
- if (intval($this->http_vars['meeting_id'])) { // Make sure that we are referring to a meeting.
- $ret = $this->process_meeting_modify();
- } else {
- $ret = '
BAD ADMIN ACTION
';
- }
- break;
-
- case 'delete_meeting':
- if (intval($this->http_vars['meeting_id'])) { // Make sure that we are referring to a meeting
- $ret = $this->process_meeting_delete();
- } else {
- $ret = '
';
- }
-
- return $ret;
- }
-
- /********************************************************************************************************//**
- \brief This is a basic funtion that tests the current user, to see if they are basically valid.
-
- \returns TRUE, if the user is valid.
- ************************************************************************************************************/
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function basic_user_validation()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $ret = false;
-
- $user_obj = $this->server->GetCurrentUserObj();
- // First, make sure the use is of the correct general type.
- if (isset($user_obj) && ($user_obj instanceof c_comdef_user) && ($user_obj->GetUserLevel() != _USER_LEVEL_DEACTIVATED) && ($user_obj->GetUserLevel() != _USER_LEVEL_SERVER_ADMIN) && ($user_obj->GetID() > 1)) {
- $ret = true;
- }
-
- return $ret;
- }
-
- /********************************************************************************************************//**
- \brief This fulfills a user request to get change records.
-
- \returns the XML for the change data.
- ************************************************************************************************************/
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function process_changes()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $ret = '
NOT AUTHORIZED
';
-
- // First, make sure the use is of the correct general type.
- if ($this->basic_user_validation()) {
- $start_date = (isset($this->http_vars['from_date']) && $this->http_vars['from_date']) ? strtotime($this->http_vars['from_date']) : (isset($this->http_vars['start_date']) && intval($this->http_vars['start_date']) ? intval($this->http_vars['start_date']) : null);
- $end_date = (isset($this->http_vars['to_date']) && $this->http_vars['to_date']) ? strtotime($this->http_vars['to_date']) : (isset($this->http_vars['end_date']) && intval($this->http_vars['end_date']) ? intval($this->http_vars['end_date']) : null);
- $meeting_id = isset($this->http_vars['meeting_id']) && intval($this->http_vars['meeting_id']) ? intval($this->http_vars['meeting_id']) : null;
- $user_id = isset($this->http_vars['user_id']) && intval($this->http_vars['user_id']) ? intval($this->http_vars['user_id']) : null;
- $service_body_id = null;
-
- if (isset($this->http_vars['service_body_id'])) {
- $service_body_array = explode(",", $this->http_vars['service_body_id']);
-
- foreach ($service_body_array as $sb) {
- $sb_int = intval($sb);
-
- if ($sb_int > 0) {
- $sb_obj = c_comdef_server::GetServiceBodyByIDObj($sb_int);
-
- if ($sb_obj instanceof c_comdef_service_body) {
- if ($sb_obj->UserCanObserve()) {
- if (!isset($service_body_id)) {
- $service_body_id = $sb_int;
- } elseif (!is_array($service_body_id)) {
- $service_body_id = array ( $service_body_id, $sb_int );
- } else {
- $service_body_id[] = $sb_int;
- }
- }
- }
- }
- }
- }
-
- // We get the changes as CSV, then immediately turn them into XML.
- $ret = $this->TranslateCSVToXML($this->get_changes_as_csv($start_date, $end_date, $meeting_id, $user_id, $service_body_id));
- $ret = "\ngetMainURL()."client_interface/xsd/GetChanges.php\">$ret";
- }
-
- return $ret;
- }
-
- /********************************************************************************************************//**
- \brief This fulfills a user request to restore a single deleted meeting.
-
- \returns the current meeting XML, if the rollback was successful.
- ************************************************************************************************************/
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function process_rollback_meeting()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $ret = '
NOT AUTHORIZED
';
-
- // First, make sure the user is of the correct general type.
- if ($this->basic_user_validation()) {
- $ret = '
PROGRAM ERROR (ROLLBACK FAILED)
';
-
- $meeting_id = isset($this->http_vars['meeting_id']) && intval($this->http_vars['meeting_id']) ? intval($this->http_vars['meeting_id']) : null;
- $change_id = isset($this->http_vars['change_id']) && intval($this->http_vars['change_id']) ? intval($this->http_vars['change_id']) : null;
-
- if ($meeting_id && $change_id) {
- $change_objects = c_comdef_server::GetChangesFromIDAndType('c_comdef_meeting', $meeting_id);
-
- if ($change_objects instanceof c_comdef_changes) {
- $obj_array = $change_objects->GetChangesObjects();
-
- if (is_array($obj_array) && count($obj_array)) {
- foreach ($obj_array as $change) {
- if ($change->GetID() == $change_id) {
- $beforeMeetingObject = $change->GetBeforeObject();
- if ($beforeMeetingObject) {
- $currentMeetingObject = c_comdef_server::GetOneMeeting($meeting_id);
-
- if (($beforeMeetingObject instanceof c_comdef_meeting) && ($currentMeetingObject instanceof c_comdef_meeting)) {
- if ($currentMeetingObject->UserCanEdit() && $beforeMeetingObject->UserCanEdit()) {
- if ($change->Rollback()) {
- $meeting_object = c_comdef_server::GetOneMeeting($meeting_id);
-
- $ret = $this->get_meeting_data($meeting_id);
- }
- }
- }
- }
-
- break;
- }
- }
- }
- }
- }
- }
-
- return $ret;
- }
-
- /********************************************************************************************************//**
- \brief This fulfills a user request to restore a single deleted meeting.
-
- \returns the XML for the meeting data.
- ************************************************************************************************************/
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function process_restore_deleted_meeting()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $ret = '';
-
- // First, make sure the user is of the correct general type.
- if ($this->basic_user_validation()) {
- $meeting_id = isset($this->http_vars['meeting_id']) && intval($this->http_vars['meeting_id']) ? intval($this->http_vars['meeting_id']) : null;
-
- if ($meeting_id) {
- $change_objects = c_comdef_server::GetChangesFromIDAndType('c_comdef_meeting', $meeting_id);
-
- if ($change_objects instanceof c_comdef_changes) {
- $obj_array = $change_objects->GetChangesObjects();
-
- if (is_array($obj_array) && count($obj_array)) {
- foreach ($obj_array as $change) {
- if ($change instanceof c_comdef_change) {
- if ($change->GetAfterObject()) {
- continue;
- }
-
- $unrestored_meeting_object = $change->GetBeforeObject();
-
- if ($unrestored_meeting_object->UserCanEdit()) {
- $unrestored_meeting_object->SetPublished(false); // Newly restored meetings are always unpublished.
- $unrestored_meeting_object->UpdateToDB();
- $ret = $this->get_meeting_data($meeting_id);
- } else {
- $ret = '
NOT AUTHORIZED
';
- }
- } else {
- $ret = '
PROGRAM ERROR (NO VALID CHANGE RECORD)
';
- }
- }
- } else {
- $ret = '
NO MEETING AVAILABLE
';
- }
- } else {
- $ret = '
NO MEETING AVAILABLE
';
- }
- } else {
- $ret = '
NO MEETING SPECIFIED
';
- }
- } else {
- $ret = '
NOT AUTHORIZED
';
- }
-
-
- return $ret;
- }
-
- /********************************************************************************************************//**
- \brief This fulfills a user request to delete a meeting.
-
- \returns the XML for the meeting data.
- ************************************************************************************************************/
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function process_deleted_meetings()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $ret = '';
-
- // First, make sure the user is of the correct general type.
- if ($this->basic_user_validation()) {
- $start_date = (isset($this->http_vars['from_date']) && $this->http_vars['from_date']) ? strtotime($this->http_vars['from_date']) : (isset($this->http_vars['start_date']) && intval($this->http_vars['start_date']) ? intval($this->http_vars['start_date']) : null);
- $end_date = (isset($this->http_vars['to_date']) && $this->http_vars['to_date']) ? strtotime($this->http_vars['to_date']) : (isset($this->http_vars['end_date']) && intval($this->http_vars['end_date']) ? intval($this->http_vars['end_date']) : null);
- $meeting_id = isset($this->http_vars['meeting_id']) && intval($this->http_vars['meeting_id']) ? intval($this->http_vars['meeting_id']) : null;
- $user_id = isset($this->http_vars['user_id']) && intval($this->http_vars['user_id']) ? intval($this->http_vars['user_id']) : null;
- $service_body_id = null;
-
- if (isset($this->http_vars['service_body_id'])) {
- $service_body_array = explode(",", $this->http_vars['service_body_id']);
-
- foreach ($service_body_array as $sb) {
- $sb_int = intval($sb);
-
- if ($sb_int > 0) {
- $sb_obj = c_comdef_server::GetServiceBodyByIDObj($sb_int);
-
- if ($sb_obj instanceof c_comdef_service_body) {
- if ($sb_obj->UserCanObserve()) {
- if (!isset($service_body_id)) {
- $service_body_id = $sb_int;
- } elseif (!is_array($service_body_id)) {
- $service_body_id = array ( $service_body_id, $sb_int );
- } else {
- $service_body_id[] = $sb_int;
- }
- }
- }
- }
- }
- }
-
- // We get the deleted meetings as CSV, then immediately turn them into XML.
- $ret = $this->get_deleted_meetings_as_csv($start_date, $end_date, $meeting_id, $user_id, $service_body_id);
- $ret = $this->TranslateCSVToXML($ret);
- $ret = "\ngetMainURL()."client_interface/xsd/GetDeletedMeetings.php\">$ret";
- } else {
- $ret = '
NOT AUTHORIZED
';
- }
-
- return $ret;
- }
-
- /*******************************************************************/
- /**
- \brief This returns deleted meeting records in CSV form (which we turn into XML).
-
- \returns CSV data, with the first row a key header.
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function get_deleted_meetings_as_csv(
- $in_start_date = null, ///< Optional. A start date (In PHP time() format). If supplied, then only deletions on, or after this date will be returned.
- $in_end_date = null, ///< Optional. An end date (In PHP time() format). If supplied, then only deletions that occurred on, or before this date will be returned.
- $in_meeting_id = null, ///< Optional. If supplied, an ID for a particular meeting. Only deletion for that meeting will be returned.
- $in_user_id = null, ///< Optional. If supplied, an ID for a particular user. Only deletions made by that user will be returned.
- $in_sb_id = null ///< Optional. If supplied, an ID for a particular Service body. Only deletions for meetings in that Service body will be returned. If this is an array, then multiple Service bodies will be searched.
- ) {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $ret = null;
- try {
- $change_objects = c_comdef_server::GetChangesFromIDAndType('c_comdef_meeting', null, $in_start_date, $in_end_date);
- if ($change_objects instanceof c_comdef_changes) {
- $obj_array = $change_objects->GetChangesObjects();
-
- if (is_array($obj_array) && count($obj_array)) {
- set_time_limit(max(30, intval(count($obj_array) / 20))); // Change requests can take a loooong time...
- $localized_strings = c_comdef_server::GetLocalStrings();
- require_once(dirname(dirname(dirname(__FILE__))).'/server/config/get-config.php');
- // These are our columns. This will be our header line.
- $ret = '"deletion_date_int","deletion_date_string","user_id","user_name","service_body_id","service_body_name","meeting_id","meeting_name","weekday_tinyint","weekday_name","start_time","location_city_subsection","location_municipality","location_province"'."\n";
-
- // If they specify a Service body, we also look in "child" Service bodies, so we need to produce a flat array of IDs.
- if (isset($in_sb_id) && $in_sb_id) {
- // If this is not an array, then we check for children. If it is an array, then we just do exactly what is in the array, regardless of children.
- if (!is_array($in_sb_id) || !count($in_sb_id)) {
- global $bmlt_array_gather;
-
- $bmlt_array_gather = array();
-
- /************************************************//**
- * This little internal function will simply fill *
- * the $bmlt_array_gather array with a linear set of *
- * Service body IDs that can be used for a quick *
- * comparison, later on. It is a callback function. *
- ****************************************************/
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- function bmlt_at_at(
- $in_value,
- $in_key
- ) {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- global $bmlt_array_gather;
-
- if ($in_value instanceof c_comdef_service_body) {
- array_push($bmlt_array_gather, $in_value->GetID());
- }
- }
-
- $array_to_walk = c_comdef_server::GetServer()->GetNestedServiceBodyArray($in_sb_id);
- array_walk_recursive($array_to_walk, 'bmlt_at_at');
-
- if (is_array($bmlt_array_gather) && count($bmlt_array_gather)) {
- $in_sb_id = $bmlt_array_gather;
- } else {
- $in_sb_id = array ( $in_sb_id );
- }
- }
- }
-
- $fetched_ids_array = array();
-
- foreach ($obj_array as $change) {
- $date_int = intval($change->GetChangeDate());
- $date_string = date("Y-m-d H:m:s", $date_int);
-
- if ($change instanceof c_comdef_change) {
- $b_obj = $change->GetBeforeObject();
-
- if ($change->GetAfterObject()) { // We are only interested in deleted meetings. If After exists, it was not a deletion.
- continue;
- }
-
- $meeting_id = intval($change->GetBeforeObjectID()); // By default, we get the meeting ID from the "before" object.
- $sb_b = intval(($b_obj instanceof c_comdef_meeting) ? $b_obj->GetServiceBodyID() : 0);
-
- $sb_obj = c_comdef_server::GetServiceBodyByIDObj($sb_b);
- if (($sb_obj instanceof c_comdef_service_body) && $sb_obj->UserCanObserve()) {
- $sb_c = intval($change->GetServiceBodyID());
-
- if (in_array($meeting_id, $fetched_ids_array)) {
- continue;
- }
-
- // If this meeting currently exists, then it doesn't qualify.
- if (c_comdef_server::GetMeetingsByID(array ( $meeting_id ))) {
- continue;
- }
-
- $fetched_ids_array[] = $meeting_id;
-
- // If we are looking for a particular meeting, and this is it, or we don't care, then go ahead.
- if ((intval($in_meeting_id) && intval($in_meeting_id) == intval($meeting_id)) || !intval($in_meeting_id)) {
- $meeting_name = '';
- $user_name = '';
- $meeting_town = '';
- $meeting_state = '';
-
- // If we are looking for a particular Service body, and this is it, or we don't caer about the Service body, then go ahead.
- if (!is_array($in_sb_id) || !count($in_sb_id) || in_array($sb_b, $in_sb_id) || in_array($sb_c, $in_sb_id)) {
- $sb_id = (intval($sb_c) ? $sb_c : $sb_b);
-
- $user_id = intval($change->GetUserID());
-
- // If the user was specified, we look for changes by that user only. Otherwise, we don't care.
- if ((isset($in_user_id) && $in_user_id && ($in_user_id == $user_id)) || !isset($in_user_id) || !$in_user_id) {
- // Get the user that created this change.
- $user = c_comdef_server::GetUserByIDObj($user_id);
-
- if ($user instanceof c_comdef_user) {
- $user_name = $user->GetLocalName();
- } else {
- $user_name = '????'; // Otherwise, it's a mystery.
- }
-
- // Using str_replace, because preg_replace is pretty expensive. However, I don't think this buys us much.
- if ($b_obj instanceof c_comdef_meeting) {
- $meeting_name = str_replace('"', "'", str_replace("\n", " ", str_replace("\r", " ", $b_obj->GetMeetingDataValue('meeting_name'))));
- $meeting_borough = str_replace('"', "'", str_replace("\n", " ", str_replace("\r", " ", $b_obj->GetMeetingDataValue('location_city_subsection'))));
- $meeting_town = str_replace('"', "'", str_replace("\n", " ", str_replace("\r", " ", $b_obj->GetMeetingDataValue('location_municipality'))));
- $meeting_state = str_replace('"', "'", str_replace("\n", " ", str_replace("\r", " ", $b_obj->GetMeetingDataValue('location_province'))));
- }
-
- $weekday_tinyint = intval($b_obj->GetMeetingDataValue('weekday_tinyint'));
- $weekday_name = $localized_strings["comdef_server_admin_strings"]["meeting_search_weekdays_names"][$weekday_tinyint];
-
- $start_time = $b_obj->GetMeetingDataValue('start_time');
-
- $sb = c_comdef_server::GetServiceBodyByIDObj($sb_id);
-
- if ($sb instanceof c_comdef_service_body) {
- $sb_name = $sb->GetLocalName();
- } else {
- $sb_name = '????';
- }
-
- // We create an array, which we'll implode after we're done. Easy way to create a CSV row.
- $change_line = array();
-
- // Create each column for this row.
- if ($date_int) {
- $change_line['deletion_date_int'] = $date_int;
- } else {
- $change_line['deletion_date_int'] = 0;
- }
-
- if ($date_string) {
- $change_line['deletion_date_string'] = $date_string;
- } else {
- $change_line['deletion_date_string'] = '';
- }
-
- if ($user_id) {
- $change_line['user_id'] = $user_id;
- } else {
- $change_line['user_id'] = 0;
- }
-
- if ($user_name) {
- $change_line['user_name'] = $user_name;
- } else {
- $change_line['user_name'] = '';
- }
-
- if ($sb_id) {
- $change_line['service_body_id'] = $sb_id;
- } else {
- $change_line['service_body_id'] = '';
- }
-
- if ($sb_name) {
- $change_line['service_body_name'] = $sb_name;
- } else {
- $change_line['service_body_name'] = '';
- }
-
- if ($meeting_id) {
- $change_line['meeting_id'] = $meeting_id;
- } else {
- $change_line['meeting_id'] = 0;
- }
-
- if ($meeting_name) {
- $change_line['meeting_name'] = $meeting_name;
- } else {
- $change_line['meeting_name'] = '';
- }
-
- if ($weekday_tinyint) {
- $change_line['weekday_tinyint'] = $weekday_tinyint;
- } else {
- $change_line['weekday_tinyint'] = '';
- }
-
- if ($weekday_name) {
- $change_line['weekday_name'] = $weekday_name;
- } else {
- $change_line['weekday_name'] = '';
- }
-
- if ($start_time) {
- $change_line['start_time'] = $start_time;
- } else {
- $change_line['start_time'] = '';
- }
-
- if ($meeting_borough) {
- $change_line['location_city_subsection'] = $meeting_borough;
- } else {
- $change_line['location_city_subsection'] = '';
- }
-
- if ($meeting_town) {
- $change_line['location_municipality'] = $meeting_town;
- } else {
- $change_line['location_municipality'] = '';
- }
-
- if ($meeting_state) {
- $change_line['location_province'] = $meeting_state;
- } else {
- $change_line['location_province'] = '';
- }
-
- $ret .= '"'.implode('","', $change_line).'"'."\n";
- }
- }
- }
- }
- }
- }
- }
- }
- } catch (Exception $e) {
- $ret = '
ERROR
';
- }
-
- return $ret;
- }
-
- /*******************************************************************/
- /**
- \brief This returns change records in CSV form (which we turn into XML).
-
- \returns CSV data, with the first row a key header.
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function get_changes_as_csv(
- $in_start_date = null, ///< Optional. A start date (In PHP time() format). If supplied, then only changes on, or after this date will be returned.
- $in_end_date = null, ///< Optional. An end date (In PHP time() format). If supplied, then only changes that occurred on, or before this date will be returned.
- $in_meeting_id = null, ///< Optional. If supplied, an ID for a particular meeting. Only changes for that meeting will be returned.
- $in_user_id = null, ///< Optional. If supplied, an ID for a particular user. Only changes made by that user will be returned.
- $in_sb_id = null, ///< Optional. If supplied, an ID for a particular Service body. Only changes for that Service body will be returned.
- $in_change_type = 'c_comdef_meeting' ///< This is the change type. Default is meeting change (NOTE: This function needs work to handle other types, but I figured I'd put in a hook for later).
- ) {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $ret = null;
- try {
- // Start by getting every meeting change between the given dates.
- $change_objects = c_comdef_server::GetChangesFromIDAndType($in_change_type, null, $in_start_date, $in_end_date);
- if ($change_objects instanceof c_comdef_changes) {
- $obj_array = $change_objects->GetChangesObjects();
-
- if (is_array($obj_array) && count($obj_array)) {
- set_time_limit(max(30, intval(count($obj_array) / 20))); // Change requests can take a loooong time...
- $localized_strings = c_comdef_server::GetLocalStrings();
- require_once(dirname(dirname(dirname(__FILE__))).'/server/config/get-config.php');
- // These are our columns. This will be our header line.
- $ret = '"new_meeting","change_id","date_int","date_string","change_type","meeting_id","meeting_name","user_id","user_name","service_body_id","service_body_name","meeting_exists","details"'."\n";
-
- // If they specify a Service body, we also look in "child" Service bodies, so we need to produce a flat array of IDs.
- if (isset($in_sb_id) && $in_sb_id) {
- // If this is not an array, then we check for children. If it is an array, then we just do exactly what is in the array, regardless of children.
- if (!is_array($in_sb_id) || !count($in_sb_id)) {
- global $bmlt_array_gather;
-
- $bmlt_array_gather = array();
-
- /************************************************//**
- * This little internal function will simply fill *
- * the $bmlt_array_gather array with a linear set of *
- * Service body IDs that can be used for a quick *
- * comparison, later on. It is a callback function. *
- ****************************************************/
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- function bmlt_at_at(
- $in_value,
- $in_key
- ) {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- global $bmlt_array_gather;
-
- if ($in_value instanceof c_comdef_service_body) {
- array_push($bmlt_array_gather, $in_value->GetID());
- }
- }
-
- $array_to_walk = c_comdef_server::GetServer()->GetNestedServiceBodyArray($in_sb_id);
- array_walk_recursive($array_to_walk, 'bmlt_at_at');
-
- if (is_array($bmlt_array_gather) && count($bmlt_array_gather)) {
- $in_sb_id = $bmlt_array_gather;
- } else {
- $in_sb_id = array ( $in_sb_id );
- }
- }
- }
-
- foreach ($obj_array as $change) {
- $change_type = $change->GetChangeType();
- $date_int = intval($change->GetChangeDate());
- $date_string = date("Y-m-d H:m:s", $date_int);
-
- if ($change instanceof c_comdef_change) {
- $b_obj = $change->GetBeforeObject();
- $a_obj = $change->GetAfterObject();
- $meeting_id = intval($change->GetBeforeObjectID()); // By default, we get the meeting ID from the "before" object.
- $sb_a = intval(($a_obj instanceof c_comdef_meeting) ? $a_obj->GetServiceBodyID() : 0);
- $sb_b = intval(($b_obj instanceof c_comdef_meeting) ? $b_obj->GetServiceBodyID() : 0);
- $sb_c = intval($change->GetServiceBodyID());
-
- // If the meeting was newly created, then we get the ID from the "after" object.
- if (!$meeting_id) {
- $meeting_id = intval($change->GetAfterObjectID());
- }
-
- // If we are looking for a particular meeting, and this is it, or we don't care, then go ahead.
- if ((intval($in_meeting_id) && intval($in_meeting_id) == intval($meeting_id)) || !intval($in_meeting_id)) {
- $meeting_name = '';
- $user_name = '';
-
- // If we are looking for a particular Service body, and this is it, or we don't caer about the Service body, then go ahead.
- if (!is_array($in_sb_id) || !count($in_sb_id) || in_array($sb_a, $in_sb_id) || in_array($sb_b, $in_sb_id) || in_array($sb_c, $in_sb_id)) {
- $sb_id = (intval($sb_c) ? $sb_c : (intval($sb_b) ? $sb_b : $sb_a));
-
- $user_id = intval($change->GetUserID());
-
- // If the user was specified, we look for changes by that user only. Otherwise, we don't care.
- if ((isset($in_user_id) && $in_user_id && ($in_user_id == $user_id)) || !isset($in_user_id) || !$in_user_id) {
- // Get the user that created this change.
- $user = c_comdef_server::GetUserByIDObj($user_id);
-
- if ($user instanceof c_comdef_user) {
- $user_name = $user->GetLocalName();
- } else {
- $user_name = '????'; // Otherwise, it's a mystery.
- }
-
- // Using str_replace, because preg_replace is pretty expensive. However, I don't think this buys us much.
- if ($b_obj instanceof c_comdef_meeting) {
- $meeting_name = str_replace('"', "'", str_replace("\n", " ", str_replace("\r", " ", $b_obj->GetMeetingDataValue('meeting_name'))));
- } elseif ($a_obj instanceof c_comdef_meeting) {
- $meeting_name = str_replace('"', "'", str_replace("\n", " ", str_replace("\r", " ", $a_obj->GetMeetingDataValue('meeting_name'))));
- }
-
- $sb = c_comdef_server::GetServiceBodyByIDObj($sb_id);
-
- if ($sb instanceof c_comdef_service_body) {
- $sb_name = $sb->GetLocalName();
- } else {
- $sb_name = '????';
- }
-
- // We see if the meeting currently exists.
- $meeting_exists = 0;
-
- if (c_comdef_server::GetOneMeeting($meeting_id, true)) {
- $meeting_exists = 1;
- }
-
- // Get the details of the change.
- $details = '';
- $desc = $change->DetailedChangeDescription();
-
- if ($desc && isset($desc['details']) && is_array($desc['details'])) {
- // We need to prevent double-quotes, as they are the string delimiters, so we replace them with single-quotes.
- $details = htmlspecialchars_decode(str_replace('"', "'", str_replace("\n", " ", str_replace("\r", " ", implode(" ", $desc['details'])))), ENT_COMPAT);
- } elseif ($desc && isset($desc['details'])) {
- // We need to prevent double-quotes, as they are the string delimiters, so we replace them with single-quotes.
- $details = htmlspecialchars_decode(str_replace('"', "'", str_replace("\n", " ", str_replace("\r", " ", $desc['details']))), ENT_COMPAT);
- } else {
- $details = htmlspecialchars_decode(str_replace('"', "'", str_replace("\n", " ", str_replace("\r", " ", $desc['overall']))), ENT_COMPAT);
- }
-
- // We create an array, which we'll implode after we're done. Easy way to create a CSV row.
- $change_line = array();
-
- // Create each column for this row.
- $change_line["new_meeting"] = ($b_obj instanceof c_comdef_meeting) ? 0 : 1;
-
- $change_line['change_id'] = $change->GetID();
-
- if ($date_int) {
- $change_line['date_int'] = $date_int;
- } else {
- $change_line['date_int'] = 0;
- }
-
- if ($date_string) {
- $change_line['date_string'] = $date_string;
- } else {
- $change_line['date_string'] = '';
- }
-
- if ($change_type) {
- $change_line['change_type'] = $change_type;
- } else {
- $change_line['change_type'] = '';
- }
-
- if ($meeting_id) {
- $change_line['meeting_id'] = $meeting_id;
- } else {
- $change_line['meeting_id'] = 0;
- }
-
- if ($meeting_name) {
- $change_line['meeting_name'] = $meeting_name;
- } else {
- $change_line['meeting_name'] = '';
- }
-
- if ($user_id) {
- $change_line['user_id'] = $user_id;
- } else {
- $change_line['user_id'] = 0;
- }
-
- if ($user_name) {
- $change_line['user_name'] = $user_name;
- } else {
- $change_line['user_name'] = '';
- }
-
- if ($sb_id) {
- $change_line['service_body_id'] = $sb_id;
- } else {
- $change_line['service_body_id'] = '';
- }
-
- if ($sb_name) {
- $change_line['service_body_name'] = $sb_name;
- } else {
- $change_line['service_body_name'] = '';
- }
-
- $change_line['meeting_exists'] = $meeting_exists;
-
- if ($details) {
- $change_line['details'] = $details;
- } else {
- $change_line['details'] = '';
- }
-
- $ret .= '"'.implode('","', $change_line).'"'."\n";
- }
- }
- }
- }
- }
- }
- }
- } catch (Exception $e) {
- $ret = '
ERROR
';
- }
-
- return $ret;
- }
-
- /********************************************************************************************************//**
- \brief This fulfills a user request to get all the available fields for adding/modifying meeting data.
-
- \returns the XML for the template data.
- ************************************************************************************************************/
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function process_get_field_templates()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $ret = '';
-
- // First, make sure the use is of the correct general type.
- if ($this->basic_user_validation()) {
- // Get the template data from the database.
- $template_data = array_merge(c_comdef_meeting::GetMainDataTemplate(), c_comdef_meeting::GetDataTableTemplate());
- $template_longdata = c_comdef_meeting::GetLongDataTableTemplate();
-
- // We merge the two tables (data and longdata).
- if (is_array($template_data) && count($template_data) && is_array($template_longdata) && count($template_longdata)) {
- $template_data = array_merge($template_data, $template_longdata);
- }
-
- // $template_data now contains the templates for the meeting data. These are the available "slots" for new values. We need to convert to XML.
-
- foreach ($template_data as $template) {
- $ret .= '';
- $ret .= ''.c_comdef_htmlspecialchars($template['key']).'';
- $ret .= ''.c_comdef_htmlspecialchars($template['field_prompt']).'';
- $ret .= ''.c_comdef_htmlspecialchars($template['lang_enum']).'';
- $ret .= ''.intval($template['visibility']).'';
-
- if (isset($template['data_string'])) {
- $ret .= ''.c_comdef_htmlspecialchars($template['data_string']).'';
- }
-
- if (isset($template['data_bigint'])) {
- $ret .= ''.intval($template['data_bigint']).'';
- }
-
- if (isset($template['data_double'])) {
- $ret .= ''.intval($template['data_double']).'';
- }
-
- if (isset($template['data_longtext'])) {
- $ret .= ''.c_comdef_htmlspecialchars($template['data_longtext']).'';
- }
-
- if (isset($template['data_blob'])) {
- $ret .= ''.c_comdef_htmlspecialchars(base64_encode($template['data_blob'])).'';
- }
- $ret .= '';
- }
-
- $ret = "\ngetMainURL()."client_interface/xsd/FieldTemplates.php\">$ret";
- } else {
- $ret = '
NOT AUTHORIZED
';
- }
-
- return $ret;
- }
-
- /********************************************************************************************************//**
- \brief This fulfills a user request to delete an existing meeting. $this->http_vars['meeting_id'] must be set to the meeting ID.
-
- \returns A very simple XML Report.
- ************************************************************************************************************/
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function process_meeting_delete()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $ret = null;
-
- // First, make sure the use is of the correct general type.
- if ($this->basic_user_validation()) {
- $meeting_obj = $this->server->GetOneMeeting(intval($this->http_vars['meeting_id']));
- if ($meeting_obj instanceof c_comdef_meeting) { // Make sure we got a meeting.
- if ($meeting_obj->UserCanEdit($this->server->GetCurrentUserObj())) { // Make sure that we are allowed to edit this meeting.
- // Before we say goodbye, we take down the relevant details for the next of kin...
- $id = intval($meeting_obj->GetID());
- $service_body_id = intval($meeting_obj->GetServiceBodyID());
- $name = c_comdef_htmlspecialchars(str_replace('"', "'", str_replace("\n", " ", str_replace("\r", " ", $meeting_obj->GetMeetingDataValue('meeting_name')))));
- $weekday = intval($meeting_obj->GetMeetingDataValue('weekday_tinyint'));
- $start_time = c_comdef_htmlspecialchars($meeting_obj->GetMeetingDataValue('start_time'));
-
- $meeting_obj->DeleteFromDB(); // Delete the meeting.
-
- // Write out the death certificate.
- $ret = ''.$id.''.$id.''.$name.''.$service_body_id.''.$start_time.''.$weekday.'';
- $ret = "\ngetMainURL()."client_interface/xsd/DeletedMeeting.php\" id=\"$id\">$ret";
- } else {
- $ret = '
NOT AUTHORIZED
';
- }
- } else {
- $ret = '
ERROR
';
- }
- } else {
- $ret = '
NOT AUTHORIZED
';
- }
-
- return $ret;
- }
-
- /********************************************************************************************************//**
- \brief This fulfills a user request to modify fields in a meeting (or create a new meeting).
- This requires that the following HTTP parameters be set:
- - meeting_id This is an integer that is the BMLT ID of the meeting being modified (the user must have edit rights to this meeting). If this is 0 (or unset), then we will be creating a new meeting.
- If we are creating a new meeting, the new meeting will start at 8:30PM on Sunday, unless new values for the 'weekday' and 'start_time' fields are provided.
- Once the meeting is created, we can set any of its fields as given.
- - meeting_field This is a string, or array of string, with the field name in the meeting search response.
- - new_value This is a string, or array of string, with the new value for the field. If the meeting_field parameter is an array, then each value here needs to be specified to correspond with the field.
-
- \returns XML, containing the fields modified.
- ************************************************************************************************************/
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function process_meeting_modify()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $ret = null;
-
- $user_obj = $this->server->GetCurrentUserObj();
- // First, make sure the use is of the correct general type.
- if ($this->basic_user_validation()) {
- $closing_tag = ''; // We will usually be changing existing meetings.
- $my_editable_service_bodies = array();
- $thisIsANewMeeting = false; // Set to true for new meetings.
-
- $service_bodies = $this->server->GetServiceBodyArray();
-
- if ($user_obj->GetUserLevel() == _USER_LEVEL_SERVICE_BODY_ADMIN) { // Must be a Service Body Admin.
- // We cycle through all the Service bodies, and look for ones in which we have permissions.
- // We use the Service body IDs to key them in associative arrays.
- foreach ($service_bodies as $service_body) {
- if ($service_body->UserCanEditMeetings()) { // We are a full Service body editor, with rights to edit the Service body itself (as well as all its meetings).
- $my_editable_service_bodies['sb_'.$service_body->GetID()] = $service_body;
- }
- }
- }
-
- $new_meeting_id = 0;
- // Get the meeting object, itself.
- if (!intval($this->http_vars['meeting_id'])) { // Will we be creating a new meeting?
- $service_bodies = $this->server->GetServiceBodyArray();
-
- if ($user_obj->GetUserLevel() == _USER_LEVEL_SERVICE_BODY_ADMIN) { // Must be a Service Body Admin.
- if (isset($my_editable_service_bodies) && is_array($my_editable_service_bodies) && count($my_editable_service_bodies)) {
- $service_body_id = 0;
-
- // If we are allowed to edit more than one Service body, then we are given a choice. We must supply an ID for the new meeting.
- if (count($my_editable_service_bodies) > 1) {
- if (isset($this->http_vars['service_body_id']) && intval($this->http_vars['service_body_id'])) {
- $service_body_id = intval($this->http_vars['service_body_id']);
- } else {
- $meeting_fields = $this->http_vars['meeting_field'];
-
- foreach ($meeting_fields as $field) {
- list ( $key, $value ) = explode(',', $field);
-
- if ($key == 'service_body_bigint') {
- $service_body_id = intval($value);
- break;
- }
- }
- }
- } else // Otherwise, it is picked for us.
- {
- // We have to do this odd dance, because it's an associative array.
- $keys_1 = array_keys($my_editable_service_bodies);
-
- $service_body = $my_editable_service_bodies[$keys_1[0]];
-
- if ($service_body instanceof c_comdef_service_body) {
- $service_body_id = $service_body->GetID();
- }
- }
-
- $weekday = 1; // Default is Sunday
- $start_time = '20:30:00'; // Default is 8:30 PM
- $lang = c_comdef_server::GetServer()->GetLocalLang(); // We use whatever the server language is.
- if ($service_body_id) { // Can't create a new meeting without a Service body.
- $service_body = c_comdef_server::GetServer()->GetServiceBodyByIDObj($service_body_id);
-
- if ($service_body instanceof c_comdef_service_body) {
- if ($service_body->UserCanEditMeetings($user_obj)) {
- $new_meeting_id = c_comdef_server::AddNewMeeting($service_body_id, $weekday, $start_time, $lang);
- $meeting_obj = $this->server->GetOneMeeting(intval($new_meeting_id));
- $meeting_obj->SetPublished(false); // New meetings are always unpublished.
- $meeting_id = $new_meeting_id;
- $ret = '';
- $thisIsANewMeeting = true;
- $closing_tag = '';
- } else {
- $ret = '
NOT AUTHORIZED
';
- }
- } else {
- $ret = '
ERROR
';
- }
- } else {
- $ret = '
ERROR
';
- }
- } else {
- $ret = '
NOT AUTHORIZED
';
- }
- } else {
- $ret = '
NOT AUTHORIZED
';
- }
- } else {
- $meeting_obj = $this->server->GetOneMeeting(intval($this->http_vars['meeting_id']));
- $ret = '';
- }
-
- if ($meeting_obj instanceof c_comdef_meeting) {
- if ($meeting_obj->UserCanEdit($user_obj)) { // We next make sure that we are allowed to make changes to this meeting.
- $keys = c_comdef_meeting::GetAllMeetingKeys(); // Get all the available keys. The one passed in needs to match one of these.
- $localized_strings = c_comdef_server::GetLocalStrings();
-
- // In case we need to add a new field, we get the meeting data template.
- $template_data = c_comdef_meeting::GetDataTableTemplate();
- $template_longdata = c_comdef_meeting::GetLongDataTableTemplate();
-
- // We merge the two tables (data and longdata).
- if (is_array($template_data) && count($template_data) && is_array($template_longdata) && count($template_longdata)) {
- $template_data = array_merge($template_data, $template_longdata);
- }
-
- // If so, we take the field, and tweak its value.
- $meeting_fields = $this->http_vars['meeting_field'];
-
- if (!is_array($meeting_fields)) {
- $meeting_fields = array ( $meeting_fields );
- }
-
- // We change each of the fields passed in to the new values passed in.
- foreach ($meeting_fields as $field) {
- list ( $meeting_field, $value ) = explode(',', $field, 2);
- if (strpos($value, "##-##")) { // Look for our special flagged items.
- $temp = explode("##-##", $value);
- $value = $temp[count($temp) - 1];
- }
-
- if (isset($meeting_field) && in_array($meeting_field, $keys)) {
- switch ($meeting_field) {
- case 'id_bigint': // We don't currently let these get changed.
- case 'lang_enum':
- $value = null;
- $old_value = null;
- break;
-
- case 'service_body_bigint':
- if (isset($my_editable_service_bodies) && is_array($my_editable_service_bodies) && count($my_editable_service_bodies)) {
- $before_id = intval($meeting_obj->GetServiceBodyID());
- $after_id = intval($value);
-
- // Have to be allowed to edit both.
- if ($my_editable_service_bodies['sb_'.$before_id] && $my_editable_service_bodies['sb_'.$after_id]) {
- $old_value = $meeting_obj->GetServiceBodyID();
- $meeting_obj->SetServiceBodyID(intval($value));
- } else {
- $ret = '
NOT AUTHORIZED
';
- }
- } else {
- $ret = '
NOT AUTHORIZED
';
- }
- break;
-
- case 'email_contact':
- $old_value = $meeting_obj->GetEmailContact();
- $meeting_obj->SetEmailContact(intval($value));
- break;
-
- case 'published':
- if (!$new_meeting_id) { // New meetings are always unpublished.
- $old_value = $meeting_obj->IsPublished();
- $meeting_obj->SetPublished(intval($value) != 0 ? true : false);
- } else {
- $old_value = 0;
- $value = 0;
- }
- break;
-
- case 'weekday_tinyint':
- if ((intval($value) > 0) && (intval($value) < 8)) {
- $old_value = $meeting_obj->GetMeetingDataValue($meeting_field);
- $data =& $meeting_obj->GetMeetingData();
- $data[$meeting_field] = intval($value);
- }
- break;
-
- case 'longitude':
- case 'latitude':
- if (floatval($value) != 0.0) {
- $old_value = $meeting_obj->GetMeetingDataValue($meeting_field);
- $data =& $meeting_obj->GetMeetingData();
- $data[$meeting_field] = floatval($value);
- }
- break;
-
- case 'start_time':
- case 'duration_time':
- case 'time_zone':
- $old_value = $meeting_obj->GetMeetingDataValue($meeting_field);
- $data =& $meeting_obj->GetMeetingData();
- $data[$meeting_field] = $value;
- break;
-
- case 'formats':
- // Formats take some extra work, because we store them in the meeting as individual objects, so we create, sort and apply those objects.
- $old_value_array = $meeting_obj->GetMeetingDataValue($meeting_field);
- $lang = $this->server->GetLocalLang();
- $vals = array();
-
- foreach ($old_value_array as $format) {
- if ($format) {
- $vals[$format->GetSharedID()] = $format;
- }
- }
-
- uksort($vals, array ( 'c_comdef_meeting','format_sorter_simple' ));
-
- $keys_2 = array();
- foreach ($vals as $format) {
- $keys_2[] = $format->GetKey();
- }
-
- $old_value = implode(",", $keys_2);
-
- $formats = explode(",", $value);
- $formats_object = $this->server->GetFormatsObj();
-
- $newVals = array();
- foreach ($formats as $key) {
- $object = $formats_object->GetFormatByKeyAndLanguage($key, $lang);
- if ($object instanceof c_comdef_format) {
- $newVals[$object->GetSharedID()] = $object;
- }
- }
-
- uksort($newVals, array ( 'c_comdef_meeting','format_sorter_simple' ));
- $data =& $meeting_obj->GetMeetingData();
- $data[$meeting_field] = $newVals;
- break;
-
- case 'worldid_mixed':
- $old_value = $meeting_obj->GetMeetingDataValue($meeting_field);
- $data =& $meeting_obj->GetMeetingData();
- $data[$meeting_field] = $value;
- break;
-
- case 'meeting_name':
- $old_value = $meeting_obj->GetMeetingDataValue($meeting_field);
- if (!isset($value) || !$value) {
- $value = $localized_strings["comdef_server_admin_strings"]["Value_Prompts"]["generic"];
- }
- // Assuming fallthrough is intentional here, due to lack of break statement?
-
- default:
- $old_value = $meeting_obj->GetMeetingDataValue($meeting_field);
- $data =& $meeting_obj->GetMeetingData();
- $prompt = isset($data[$meeting_field]['field_prompt']) ? $data[$meeting_field]['field_prompt'] : $template_data[$meeting_field]['field_prompt'];
- $visibility = intval(isset($data[$meeting_field]['visibility']) ? $data[$meeting_field]['visibility'] : $template_data[$meeting_field]['visibility']);
- $meeting_obj->AddDataField($meeting_field, $prompt, $value, null, $visibility, true);
- break;
- }
-
- // We only indicate changes.
- if (isset($meeting_field) && $meeting_field && !($thisIsANewMeeting && !(isset($value) && $value)) && ((isset($old_value) && $old_value) || (isset($value) && $value)) && ($old_value != $value)) {
- $ret_temp = '';
- $ret_temp_internal = '';
- // New meetings have no old data.
- if (!$thisIsANewMeeting && isset($old_value) && $old_value) {
- $ret_temp_internal .= ''.c_comdef_htmlspecialchars($old_value).'';
- }
-
- if (isset($value) && $value) {
- $ret_temp_internal .= ''.c_comdef_htmlspecialchars($value).'';
- }
-
- $ret_temp .= ''.$ret_temp_internal.'';
-
- // We only send back changes that were actually made. This reduces empty response data.
- if ($ret_temp_internal) {
- $ret .= $ret_temp;
- }
- }
-
- $meeting_field = null;
- }
- }
-
- // This can short-circuit the operation.
- if ($ret != '
NOT AUTHORIZED
') {
- $meeting_obj->UpdateToDB(); // Save the new data. After this, the meeting has been changed.
-
- $ret .= $closing_tag;
-
- $ret = "\ngetMainURL()."client_interface/xsd/ChangeResponse.php\">$ret";
- }
- } else {
- $ret = '
NOT AUTHORIZED
';
- }
- } else {
- $ret = '
ERROR
';
- }
- } else {
- $ret = '
NOT AUTHORIZED
';
- }
-
- return $ret;
- }
-
- /********************************************************************************************************//**
- \brief This fulfills a user request to return meeting information from a search.
-
- \returns XML, containing the answer.
- ************************************************************************************************************/
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function process_meeting_search()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- if (!( isset($this->http_vars['geo_width']) && $this->http_vars['geo_width'] ) && isset($this->http_vars['bmlt_search_type']) && ($this->http_vars['bmlt_search_type'] == 'advanced') && isset($this->http_vars['advanced_radius']) && isset($this->http_vars['advanced_mapmode']) && $this->http_vars['advanced_mapmode'] && ( floatval($this->http_vars['advanced_radius'] != 0.0) ) && isset($this->http_vars['lat_val']) && isset($this->http_vars['long_val']) && ( (floatval($this->http_vars['lat_val']) != 0.0) || (floatval($this->http_vars['long_val']) != 0.0) )) {
- $this->http_vars['geo_width'] = $this->http_vars['advanced_radius'];
- } elseif (!( isset($this->http_vars['geo_width']) && $this->http_vars['geo_width'] ) && isset($this->http_vars['bmlt_search_type']) && ($this->http_vars['bmlt_search_type'] == 'advanced')) {
- $this->http_vars['lat_val'] = null;
- $this->http_vars['long_val'] = null;
- } elseif (!isset($this->http_vars['geo_loc']) || $this->http_vars['geo_loc'] != 'yes') {
- if (!isset($this->http_vars['geo_width'])) {
- $this->http_vars['geo_width'] = 0;
- }
- }
-
- require_once(dirname(dirname(dirname(__FILE__))).'/client_interface/csv/search_results_csv.php');
-
- $geocode_results = null;
- $ignore_me = null;
- $meeting_objects = array();
- $formats_ar = array ();
- $result2 = DisplaySearchResultsCSV($this->http_vars, $ignore_me, $geocode_results, $meeting_objects);
-
- if (is_array($meeting_objects) && count($meeting_objects) && is_array($formats_ar)) {
- foreach ($meeting_objects as $one_meeting) {
- $formats = $one_meeting->GetMeetingDataValue('formats');
-
- foreach ($formats as $format) {
- if ($format && ($format instanceof c_comdef_format)) {
- $format_shared_id = $format->GetSharedID();
- $formats_ar[$format_shared_id] = $format;
- }
- }
- }
- }
-
- if (isset($this->http_vars['data_field_key']) && $this->http_vars['data_field_key']) {
- // At this point, we have everything in a CSV. We separate out just the field we want.
- $temp_keyed_array = array();
- $result = explode("\n", $result);
- $keys = array_shift($result);
- $keys = explode("\",\"", trim($keys, '"'));
- $the_keys = explode(',', $this->http_vars['data_field_key']);
-
- $result = array();
- foreach ($result2 as $row) {
- if ($row) {
- $index = 0;
- $row = explode('","', trim($row, '",'));
- $row_columns = array();
- foreach ($row as $column) {
- if (!$column) {
- $column = ' ';
- }
- if (in_array($keys[$index++], $the_keys)) {
- array_push($row_columns, $column);
- }
- }
- $result[$row[0]] = '"'.implode('","', $row_columns).'"';
- }
- }
-
- $the_keys = array_intersect($keys, $the_keys);
- $result2 = '"'.implode('","', $the_keys)."\"\n".implode("\n", $result);
- }
-
-
- $result = "\ngetMainURL()."client_interface/xsd/GetSearchResults.php\">";
- $result .= $this->TranslateCSVToXML($result2);
- if ((isset($http_vars['get_used_formats']) || isset($http_vars['get_formats_only'])) && $formats_ar && is_array($formats_ar) && count($formats_ar)) {
- if (isset($http_vars['get_formats_only'])) {
- $result = "\ngetMainURL()."client_interface/xsd/GetFormats.php\">";
- } else {
- $result .= "";
- }
- $result3 = GetFormats($server, $langs, null, $formats_ar);
- $result .= TranslateToXML($result3);
-
- $result .= "";
- }
-
- $result .= isset($http_vars['get_formats_only']) ? "" : "";
-
- return $result;
- }
-
- /********************************************************************************************************//**
- \brief This fulfills a user request to return format information.
-
- \returns XML, containing the answer.
- ************************************************************************************************************/
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function process_format_info()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $ret = '';
-
- if ($this->basic_user_validation()) {
- $format_ids = array();
-
- // See if we are receiving a request for just specific formats, or if we are being asked for all of them.
- if (isset($this->http_vars['format_id']) && intval(trim($this->http_vars['format_id']))) {
- $format_ids[] = intval(trim($this->http_vars['format_id']));
- } elseif (isset($this->http_vars['format_id']) && is_array($this->http_vars['format_id']) && count($this->http_vars['format_id'])) {
- foreach ($this->http_vars['format_id'] as $format) {
- $format_ids[] = intval(trim($format));
- }
- } else {
- $format_ids = null;
- }
-
- $lang = $this->server->GetLocalLang();
- if (isset($this->http_vars['lang']) && trim($this->http_vars['lang'])) {
- $lang = strtolower(trim($this->http_vars['lang']));
- }
-
- $returned_formats = array(); // We will be returning our formats in this.
- $format_objects = $this->server->GetFormatsObj()->GetFormatsByLanguage($lang); // Get all the formats (not just the ones used, but ALL of them).
-
- // Filter for requested formats in the requested language.
- foreach ($format_objects as $format) {
- if (!$format_ids || in_array(intval($format->GetSharedID()), $format_ids)) {
- $returned_formats[] = $format;
- }
- }
-
- // At this point, we have a complete array of just the format[s] that will be returned. Time to make some XML...
- $index = 0;
-
- // We will find out which formats actually appear, somewhere in the DB, and indicate that when we give the info.
- $used_formats = $this->server->GetUsedFormatsArray();
- $used_ids = array();
-
- foreach ($used_formats as $format) {
- $used_ids[] = intval($format->GetSharedID());
- }
-
- foreach ($returned_formats as $format) {
- $ret .= '';
- $id = intval($format->GetSharedID());
- $ret.= ''.c_comdef_htmlspecialchars($format->GetKey()).'';
- $ret.= ''.c_comdef_htmlspecialchars($format->GetLocalName()).'';
- $ret.= ''.c_comdef_htmlspecialchars($format->GetLocalDescription()).'';
- $ret.= ''.c_comdef_htmlspecialchars($lang).'';
- $ret.= ''.$id.'';
- $world_id = trim($format->GetWorldID());
- if (isset($world_id) && $world_id) {
- $ret.= ''.c_comdef_htmlspecialchars($world_id).'';
- }
-
- // If this is used somewehere, we indicate it here.
- if (in_array($id, $used_ids)) {
- $ret.= '1';
- }
-
- $ret .= '';
- }
- $ret = "\ngetMainURL()."client_interface/xsd/GetFormats.php\">$ret";
- } else {
- $ret = '
NOT AUTHORIZED
';
- }
-
- return $ret;
- }
-
- /********************************************************************************************************//**
- \brief This fulfills a user request to return Service Body information for multiple Service bodies.
-
- \returns XML, containing the answer.
- ************************************************************************************************************/
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function process_service_bodies_info_request()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $ret = '';
-
- if ($this->basic_user_validation()) {
- $service_body_ids = array();
-
- // Look to see if the caller is asking for particular Service bodies.
- if (isset($this->http_vars['sb_id']) && $this->http_vars['sb_id']) {
- if (!is_array($this->http_vars['sb_id'])) {
- $service_body_ids[] = intval(trim($this->http_vars['sb_id']));
- } else {
- foreach ($this->http_vars['sb_id'] as $id) {
- if (intval(trim($id))) {
- $service_body_ids[] = intval(trim($id));
- }
- }
- }
- }
-
- // If we have a request for individual Service bodies, then we just return those ones.
- if (isset($service_body_ids) && is_array($service_body_ids) && count($service_body_ids)) {
- foreach ($service_body_ids as $id) {
- $ret .= $this->process_service_body_info_request($id);
- }
- } else // If they are not looking for particular bodies, then we return the whole kit & kaboodle.
- {
- $service_bodies = $this->server->GetServiceBodyArray();
-
- foreach ($service_bodies as $service_body) {
- if (isset($this->http_vars['flat']) || !$service_body->GetOwnerIDObject()) { // We automatically include top-level Service bodies here, and let ones with parents sort themselves out.
- $ret .= $this->process_service_body_info_request($service_body->GetID());
- }
- }
- }
-
- $ret = "\ngetMainURL()."client_interface/xsd/HierServiceBodies.php\">$ret";
- } else {
- $ret = '
NOT AUTHORIZED
';
- }
-
- return $ret;
- }
-
- /********************************************************************************************************//**
- \brief This fulfills a user request to return Service Body information.
-
- \returns XML, containing the answer.
- ************************************************************************************************************/
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function process_service_body_info_request(
- $in_service_body_id ///< The ID of the Service body being requested.
- ) {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $ret = '';
- // Belt and suspenders. We need to make sure the user is authorized.
- if ($this->basic_user_validation()) {
- if (!in_array($in_service_body_id, $this->handled_service_body_ids)) {
- $this->handled_service_body_ids[] = $in_service_body_id;
- $service_body = $this->server->GetServiceBodyByIDObj($in_service_body_id);
-
- if (isset($service_body) && ($service_body instanceof c_comdef_service_body)) {
- // Everyone gets the type, URI, name, description and parent Service body.
- $name = $service_body->GetLocalName();
- $description = $service_body->GetLocalDescription();
- $uri = $service_body->GetURI();
- $helpline = $service_body->GetHelpline();
- $type = $service_body->GetSBType();
-
- $parent_service_body_id = 0;
- $parent_service_body_name = "";
- $parent_service_body_type = "";
-
- $parent_service_body = $service_body->GetOwnerIDObject();
-
- if (isset($parent_service_body) && $parent_service_body) {
- $parent_service_body_id = intval($parent_service_body->GetID());
- $parent_service_body_name = $parent_service_body->GetLocalName();
- $parent_service_body_type = $parent_service_body->GetSBType();
- }
-
- $principal_user = $service_body->GetPrincipalUserObj();
- $principal_user_id = intval($principal_user->GetID());
-
- // Scan for our various editors.
- $guest_editors = $this->server->GetUsersByLevelObj(_USER_LEVEL_OBSERVER, true); // Observer or greater.
- $service_body_editors = array();
- $meeting_list_editors = array();
- $observers = array();
-
- foreach ($guest_editors as $editor) {
- if ($service_body->UserCanEdit($editor)) { // We will have at least one of these, as the principal user needs to be listed.
- array_push($service_body_editors, $editor);
- } elseif ($service_body->UserCanEditMeetings($editor)) {
- array_push($meeting_list_editors, $editor);
- } elseif ($service_body->UserCanObserve($editor)) {
- array_push($observers, $editor);
- }
- }
-
- // Scan for direct descendant child Service bodies.
- $children = array();
- $service_bodies = $this->server->GetServiceBodyArray();
-
- foreach ($service_bodies as $child) {
- if ($child->IsOwnedBy($in_service_body_id, true)) {
- $children[] = $child;
- }
- }
-
- // We check to see which editors are mentioned in this Service body.
- $guest_editors = $service_body->GetEditors();
-
- // See if we have rights to edit this Service body. Just for the heck of it, we check the user level (not really necessary, but belt and suspenders).
- $this_user_can_edit_the_body = ($this->server->GetCurrentUserObj()->GetUserLevel() == _USER_LEVEL_SERVICE_BODY_ADMIN) && $service_body->UserCanEdit();
-
- $contact_email = null;
-
- // Service Body Admins (with permission for the body) get more info.
- if ($this_user_can_edit_the_body) {
- $contact_email = $service_body->GetContactEmail();
- }
-
- // At this point, we have all the information we need to build the response XML.
- $ret = '';
- $ret .= ''.c_comdef_htmlspecialchars($this->my_localized_strings['service_body_types'][$type]).'';
- if (isset($description) && $description) {
- $ret .= ''.c_comdef_htmlspecialchars($description).'';
- }
- if (isset($uri) && $uri) {
- $ret .= ''.c_comdef_htmlspecialchars($uri).'';
- }
- if (isset($helpline) && $helpline) {
- $ret .= ''.c_comdef_htmlspecialchars($helpline).'';
- }
- if (isset($parent_service_body) && $parent_service_body) {
- $ret .= ''.c_comdef_htmlspecialchars($parent_service_body_name).'';
- }
- if ($this_user_can_edit_the_body && isset($contact_email) && $contact_email) {
- $ret .= ''.c_comdef_htmlspecialchars($contact_email).'';
- }
-
- $ret .= '';
- if (isset($service_body_editors) && is_array($service_body_editors) && count($service_body_editors)) {
- // We will have at least one of these (the principal user).
- // These are the users that can directly manipulate the Service body.
- $ret .= '';
- foreach ($service_body_editors as $editor) {
- $editor_id = intval($editor->GetID());
- $ret .= '';
- }
- $ret .= '';
- }
-
- // These are users that can't manipulate the Service body, but can edit meetings.
- if (isset($meeting_list_editors) && is_array($meeting_list_editors) && count($meeting_list_editors)) {
- $ret .= '';
- foreach ($meeting_list_editors as $editor) {
- $editor_id = intval($editor->GetID());
- $ret .= '';
- }
- $ret .= '';
- }
-
- // These are users that can only see hidden fields in meetings.
- if (isset($observers) && is_array($observers) && count($observers)) {
- $ret .= '';
- foreach ($observers as $editor) {
- $editor_id = intval($editor->GetID());
- $ret .= '';
- }
- $ret .= '';
- }
- $ret .= '';
-
- // If this is a hierarchical response, we embed the children as XML service_body elements. Otherwise, we list them as simple catalog elements.
- if (!isset($this->http_vars['flat']) && isset($children) && is_array($children) && count($children)) {
- $ret .= "";
- foreach ($children as $child) {
- $ret .= $this->process_service_body_info_request($child->GetID());
- }
- $ret .= "";
- } elseif (isset($children) && is_array($children) && count($children)) {
- $ret .= '';
- foreach ($children as $child) {
- $ret .= ''.c_comdef_htmlspecialchars($child->GetLocalName()).'';
- }
- $ret .= '';
- }
-
- $ret .= '';
- }
- }
- } else {
- $ret = '
NOT AUTHORIZED
';
- }
-
- return $ret;
- }
-
- /********************************************************************************************************//**
- \brief This fulfills a user request to report the rights for the logged-in user.
-
- \returns XML, containing the answer.
- ************************************************************************************************************/
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function process_capabilities_request()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $ret = '';
- $service_bodies = $this->server->GetServiceBodyArray();
-
- // We will fill these three arrays, depending on the users' rights for a given Service body.
- $my_meeting_observer_service_bodies = array();
- $my_meeting_editor_service_bodies = array();
- $my_editable_service_bodies = array();
-
- $user_obj = $this->server->GetCurrentUserObj();
- if ($this->basic_user_validation()) {
- // We cycle through all the Service bodies, and look for ones in which we have permissions.
- // We use the Service body IDs to key them in associative arrays.
- foreach ($service_bodies as $service_body) {
- if (($user_obj->GetUserLevel() == _USER_LEVEL_SERVICE_BODY_ADMIN) && $service_body->UserCanEdit()) { // We are a full Service body editor, with rights to edit the Service body itself (as well as all its meetings).
- $my_editable_service_bodies['sb_'.$service_body->GetID()] = $service_body;
- } elseif ((($user_obj->GetUserLevel() == _USER_LEVEL_SERVICE_BODY_ADMIN) || ($user_obj->GetUserLevel() == _USER_LEVEL_OBSERVER)) && $service_body->UserCanObserve()) { // We are a "guest" editor, or an observer (depends on our user level).
- // Again, we keep checking credentials, over and over again.
- if ($user_obj->GetUserLevel() == _USER_LEVEL_OBSERVER) {
- $my_meeting_observer_service_bodies['sb_'.$service_body->GetID()] = $service_body;
- } elseif ($service_body->UserCanEditMeetings()) {
- $my_meeting_editor_service_bodies['sb_'.$service_body->GetID()] = $service_body;
- }
- }
- }
- // Now, we grant rights to Service bodies that are implicit from other rights (for example, a Service Body Admin can also observe and edit meetings).
-
- // A full Service Body Admin can edit meetings in that Service body.
- foreach ($my_editable_service_bodies as $service_body) {
- $my_meeting_editor_service_bodies['sb_'.$service_body->GetID()] = $service_body;
- }
-
- // An editor (whether an admin or a "guest") also has observe rights.
- foreach ($my_meeting_editor_service_bodies as $service_body) {
- $my_meeting_observer_service_bodies['sb_'.$service_body->GetID()] = $service_body;
- }
-
- // At this point, we have 3 arrays (or fewer), filled with Service bodies that we have rights on. It is entirely possible that only one of them could be filled, and it may only have one member.
-
- // We start to construct the XML filler.
- foreach ($service_bodies as $service_body) {
- // If we can observe, then we have at least one permission for this Service body.
- if (isset($my_meeting_observer_service_bodies['sb_'.$service_body->GetID()]) && $my_meeting_observer_service_bodies['sb_'.$service_body->GetID()]) {
- $ret .= '';
- }
- }
- // Create a proper XML wrapper for the response data.
- $ret = "\ngetMainURL()."client_interface/xsd/AdminPermissions.php\">$ret";
- // We now have XML that states the current user's permission levels in all Service bodies.
- } else {
- $ret = '
NOT AUTHORIZED
';
- }
-
- return $ret;
- }
-
- /********************************************************************************************************//**
- \brief This fulfills a user request to return the current users info.
-
- \returns XML, containing the answer.
- ************************************************************************************************************/
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function process_user_info()
- {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- $ret = '';
- $user_obj = $this->server->GetCurrentUserObj();
-
- if ($this->basic_user_validation()) {
- $ret = '';
- // Create a proper XML wrapper for the response data.
- $ret = "\ngetMainURL()."client_interface/xsd/UserInfo.php\">$ret";
- // We now have XML that states the current user's permission levels in all Service bodies.
- } else {
- $ret = '
NOT AUTHORIZED
';
- }
-
- return $ret;
- }
-
- /*******************************************************************/
- /**
- \brief Translates CSV to XML.
-
- \returns an XML string, with all the data in the CSV.
- */
- // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- public function TranslateCSVToXML(
- $in_csv_data ///< An array of CSV data, with the first element being the field names.
- ) {
- // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
- require_once(dirname(dirname(dirname(__FILE__))).'/server/shared/Array2XML.php');
- $temp_keyed_array = array();
- $in_csv_data = explode("\n", $in_csv_data);
- $keys = array_shift($in_csv_data);
- $keys = rtrim(ltrim($keys, '"'), '",');
- $keys = preg_split('/","/', $keys);
-
- foreach ($in_csv_data as $row) {
- if ($row) {
- $line = null;
- $index = 0;
- $row_t = rtrim(ltrim($row, '"'), '",');
- $row_t = preg_split('/","/', $row_t);
- foreach ($row_t as $column) {
- if (isset($column)) {
- $line[$keys[$index++]] = trim($column);
- }
- }
- array_push($temp_keyed_array, $line);
- }
- }
-
- $out_xml_data = array2xml($temp_keyed_array, 'not_used', false);
-
- return $out_xml_data;
- }
-}
diff --git a/src/legacy/local_server/server_admin/c_comdef_login.php b/src/legacy/local_server/server_admin/c_comdef_login.php
deleted file mode 100755
index aa0a459ce..000000000
--- a/src/legacy/local_server/server_admin/c_comdef_login.php
+++ /dev/null
@@ -1,270 +0,0 @@
-.
-*/
-defined('BMLT_EXEC') or die('Cannot Execute Directly'); // Makes sure that this file is in the correct context.
-
-require_once(dirname(dirname(dirname(__FILE__)))."/server/c_comdef_server.class.php");
-require_once(dirname(dirname(dirname(__FILE__)))."/server/shared/classes/comdef_utilityclasses.inc.php");
-
-include(dirname(dirname(dirname(__FILE__))).'/server/config/get-config.php');
-
-$t_server = c_comdef_server::MakeServer(); // We initialize the server.
-
-$lang_enum = $t_server->GetServer()->GetLocalLang();
-
-// We use a cookie to store the language pref.
-$lang_enum = request()->cookie('bmlt_admin_lang_pref', $lang_enum);
-
-if (isset($http_vars['lang_enum']) && $http_vars['lang_enum']) {
- $lang_enum = $http_vars['lang_enum'];
-}
-
-if (isset($g_enable_language_selector) && $g_enable_language_selector) {
- cookie()->queue('bmlt_admin_lang_pref', $lang_enum, 60 * 24 * 365);
-}
-
-if (isset($_GET['bad_login_form'])) {
- $localized_strings = c_comdef_server::GetLocalStrings();
- die('
'.c_comdef_LoginForm($server).'');
-}
-
-$user_obj = $t_server->GetCurrentUserObj();
-if (is_null($user_obj)) {
- echo c_comdef_LoginForm($t_server);
-} elseif (!($user_obj instanceof c_comdef_user) || ($user_obj->GetUserLevel() == _USER_LEVEL_DEACTIVATED)) {
- // If the login is invalid, we terminate the whole kit and kaboodle, and inform the user they are persona non grata.
- $localized_strings = c_comdef_server::GetLocalStrings();
- die('