From 5fcd33e294972379d9234c3290f1eb8e75601da9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Schw=C3=B6rer?= Date: Sat, 22 Sep 2018 01:35:41 +0200 Subject: [PATCH] webshit --- .../inspectionProfiles/profiles_settings.xml | 7 - .idea/vcs.xml | 6 - .gitignore => android/.gitignore | 0 .../.idea}/codeStyles/Project.xml | 0 .../inspectionProfiles/Project_Default.xml | 10 + .../.idea}/runConfigurations.xml | 0 {app => android/app}/.gitignore | 0 {app => android/app}/build.gradle | 0 {app => android/app}/google-services.json | 0 {app => android/app}/proguard-rules.pro | 0 .../app}/src/main/AndroidManifest.xml | 0 .../simplecloudnotifier/FBMService.java | 7 +- .../simplecloudnotifier/MainActivity.java | 0 .../drawable-v24/ic_launcher_foreground.xml | 0 .../res/drawable/ic_launcher_background.xml | 0 .../app}/src/main/res/drawable/icon.png | Bin .../src/main/res/layout/activity_main.xml | 0 .../res/mipmap-anydpi-v26/ic_launcher.xml | 0 .../mipmap-anydpi-v26/ic_launcher_round.xml | 0 .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin .../res/mipmap-hdpi/ic_launcher_round.png | Bin .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin .../res/mipmap-mdpi/ic_launcher_round.png | Bin .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin .../res/mipmap-xhdpi/ic_launcher_round.png | Bin .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin .../res/mipmap-xxhdpi/ic_launcher_round.png | Bin .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin .../res/mipmap-xxxhdpi/ic_launcher_round.png | Bin .../app}/src/main/res/values/colors.xml | 0 .../app}/src/main/res/values/strings.xml | 0 .../app}/src/main/res/values/styles.xml | 0 build.gradle => android/build.gradle | 0 .../gradle.properties | 0 .../gradle}/wrapper/gradle-wrapper.jar | Bin .../gradle}/wrapper/gradle-wrapper.properties | 0 gradlew => android/gradlew | 0 gradlew.bat => android/gradlew.bat | 0 settings.gradle => android/settings.gradle | 0 web/.gitignore | 183 ++++++++++++++++++ web/lib/httpful.phar | Bin 0 -> 64034 bytes web/model.php | 73 +++++++ web/register.php | 17 ++ web/schema.sql | 10 + web/send.php | 72 +++++++ web/update.php | 46 +++++ 46 files changed, 415 insertions(+), 16 deletions(-) delete mode 100644 .idea/inspectionProfiles/profiles_settings.xml delete mode 100644 .idea/vcs.xml rename .gitignore => android/.gitignore (100%) rename {.idea => android/.idea}/codeStyles/Project.xml (100%) create mode 100644 android/.idea/inspectionProfiles/Project_Default.xml rename {.idea => android/.idea}/runConfigurations.xml (100%) rename {app => android/app}/.gitignore (100%) rename {app => android/app}/build.gradle (100%) rename {app => android/app}/google-services.json (100%) rename {app => android/app}/proguard-rules.pro (100%) rename {app => android/app}/src/main/AndroidManifest.xml (100%) rename {app => android/app}/src/main/java/com/blackforestbytes/simplecloudnotifier/FBMService.java (85%) rename {app => android/app}/src/main/java/com/blackforestbytes/simplecloudnotifier/MainActivity.java (100%) rename {app => android/app}/src/main/res/drawable-v24/ic_launcher_foreground.xml (100%) rename {app => android/app}/src/main/res/drawable/ic_launcher_background.xml (100%) rename {app => android/app}/src/main/res/drawable/icon.png (100%) rename {app => android/app}/src/main/res/layout/activity_main.xml (100%) rename {app => android/app}/src/main/res/mipmap-anydpi-v26/ic_launcher.xml (100%) rename {app => android/app}/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml (100%) rename {app => android/app}/src/main/res/mipmap-hdpi/ic_launcher.png (100%) rename {app => android/app}/src/main/res/mipmap-hdpi/ic_launcher_round.png (100%) rename {app => android/app}/src/main/res/mipmap-mdpi/ic_launcher.png (100%) rename {app => android/app}/src/main/res/mipmap-mdpi/ic_launcher_round.png (100%) rename {app => android/app}/src/main/res/mipmap-xhdpi/ic_launcher.png (100%) rename {app => android/app}/src/main/res/mipmap-xhdpi/ic_launcher_round.png (100%) rename {app => android/app}/src/main/res/mipmap-xxhdpi/ic_launcher.png (100%) rename {app => android/app}/src/main/res/mipmap-xxhdpi/ic_launcher_round.png (100%) rename {app => android/app}/src/main/res/mipmap-xxxhdpi/ic_launcher.png (100%) rename {app => android/app}/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png (100%) rename {app => android/app}/src/main/res/values/colors.xml (100%) rename {app => android/app}/src/main/res/values/strings.xml (100%) rename {app => android/app}/src/main/res/values/styles.xml (100%) rename build.gradle => android/build.gradle (100%) rename gradle.properties => android/gradle.properties (100%) rename {gradle => android/gradle}/wrapper/gradle-wrapper.jar (100%) rename {gradle => android/gradle}/wrapper/gradle-wrapper.properties (100%) rename gradlew => android/gradlew (100%) rename gradlew.bat => android/gradlew.bat (100%) rename settings.gradle => android/settings.gradle (100%) create mode 100644 web/.gitignore create mode 100644 web/lib/httpful.phar create mode 100644 web/model.php create mode 100644 web/register.php create mode 100644 web/schema.sql create mode 100644 web/send.php create mode 100644 web/update.php diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml deleted file mode 100644 index dd4c951..0000000 --- a/.idea/inspectionProfiles/profiles_settings.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 94a25f7..0000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.gitignore b/android/.gitignore similarity index 100% rename from .gitignore rename to android/.gitignore diff --git a/.idea/codeStyles/Project.xml b/android/.idea/codeStyles/Project.xml similarity index 100% rename from .idea/codeStyles/Project.xml rename to android/.idea/codeStyles/Project.xml diff --git a/android/.idea/inspectionProfiles/Project_Default.xml b/android/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..146ab09 --- /dev/null +++ b/android/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,10 @@ + + + + \ No newline at end of file diff --git a/.idea/runConfigurations.xml b/android/.idea/runConfigurations.xml similarity index 100% rename from .idea/runConfigurations.xml rename to android/.idea/runConfigurations.xml diff --git a/app/.gitignore b/android/app/.gitignore similarity index 100% rename from app/.gitignore rename to android/app/.gitignore diff --git a/app/build.gradle b/android/app/build.gradle similarity index 100% rename from app/build.gradle rename to android/app/build.gradle diff --git a/app/google-services.json b/android/app/google-services.json similarity index 100% rename from app/google-services.json rename to android/app/google-services.json diff --git a/app/proguard-rules.pro b/android/app/proguard-rules.pro similarity index 100% rename from app/proguard-rules.pro rename to android/app/proguard-rules.pro diff --git a/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml similarity index 100% rename from app/src/main/AndroidManifest.xml rename to android/app/src/main/AndroidManifest.xml diff --git a/app/src/main/java/com/blackforestbytes/simplecloudnotifier/FBMService.java b/android/app/src/main/java/com/blackforestbytes/simplecloudnotifier/FBMService.java similarity index 85% rename from app/src/main/java/com/blackforestbytes/simplecloudnotifier/FBMService.java rename to android/app/src/main/java/com/blackforestbytes/simplecloudnotifier/FBMService.java index bdeadfe..dd9c996 100644 --- a/app/src/main/java/com/blackforestbytes/simplecloudnotifier/FBMService.java +++ b/android/app/src/main/java/com/blackforestbytes/simplecloudnotifier/FBMService.java @@ -35,16 +35,17 @@ public class FBMService extends FirebaseMessagingService // TODO(developer): Handle FCM messages here. // Not getting messages here? See why this may be: https://goo.gl/39bRNJ - Log.i("FB::MessageReceived<1>", "From: " + remoteMessage.getFrom()); + Log.i("FB::MessageReceived", "From: " + remoteMessage.getFrom()); // Check if message contains a data payload. if (remoteMessage.getData().size() > 0) { - Log.i("FB::MessageReceived<3>", "Payload: " + remoteMessage.getData()); + Log.i("FB::MessageReceived", "Payload: " + remoteMessage.getData()); } // Check if message contains a notification payload. if (remoteMessage.getNotification() != null) { - Log.i("FB::MessageReceived<2>", "Payload: " + remoteMessage.getNotification().getBody()); + Log.i("FB::MessageReceived", "Notify_Title: " + remoteMessage.getNotification().getTitle()); + Log.i("FB::MessageReceived", "Notify_Body: " + remoteMessage.getNotification().getBody()); } // Also if you intend on generating your own notifications as a result of a received FCM diff --git a/app/src/main/java/com/blackforestbytes/simplecloudnotifier/MainActivity.java b/android/app/src/main/java/com/blackforestbytes/simplecloudnotifier/MainActivity.java similarity index 100% rename from app/src/main/java/com/blackforestbytes/simplecloudnotifier/MainActivity.java rename to android/app/src/main/java/com/blackforestbytes/simplecloudnotifier/MainActivity.java diff --git a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml similarity index 100% rename from app/src/main/res/drawable-v24/ic_launcher_foreground.xml rename to android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/android/app/src/main/res/drawable/ic_launcher_background.xml similarity index 100% rename from app/src/main/res/drawable/ic_launcher_background.xml rename to android/app/src/main/res/drawable/ic_launcher_background.xml diff --git a/app/src/main/res/drawable/icon.png b/android/app/src/main/res/drawable/icon.png similarity index 100% rename from app/src/main/res/drawable/icon.png rename to android/app/src/main/res/drawable/icon.png diff --git a/app/src/main/res/layout/activity_main.xml b/android/app/src/main/res/layout/activity_main.xml similarity index 100% rename from app/src/main/res/layout/activity_main.xml rename to android/app/src/main/res/layout/activity_main.xml diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml similarity index 100% rename from app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml rename to android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml similarity index 100% rename from app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml rename to android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png similarity index 100% rename from app/src/main/res/mipmap-hdpi/ic_launcher.png rename to android/app/src/main/res/mipmap-hdpi/ic_launcher.png diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png similarity index 100% rename from app/src/main/res/mipmap-hdpi/ic_launcher_round.png rename to android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png similarity index 100% rename from app/src/main/res/mipmap-mdpi/ic_launcher.png rename to android/app/src/main/res/mipmap-mdpi/ic_launcher.png diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png similarity index 100% rename from app/src/main/res/mipmap-mdpi/ic_launcher_round.png rename to android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png similarity index 100% rename from app/src/main/res/mipmap-xhdpi/ic_launcher.png rename to android/app/src/main/res/mipmap-xhdpi/ic_launcher.png diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png similarity index 100% rename from app/src/main/res/mipmap-xhdpi/ic_launcher_round.png rename to android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png similarity index 100% rename from app/src/main/res/mipmap-xxhdpi/ic_launcher.png rename to android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png similarity index 100% rename from app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png rename to android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png similarity index 100% rename from app/src/main/res/mipmap-xxxhdpi/ic_launcher.png rename to android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png similarity index 100% rename from app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png rename to android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png diff --git a/app/src/main/res/values/colors.xml b/android/app/src/main/res/values/colors.xml similarity index 100% rename from app/src/main/res/values/colors.xml rename to android/app/src/main/res/values/colors.xml diff --git a/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml similarity index 100% rename from app/src/main/res/values/strings.xml rename to android/app/src/main/res/values/strings.xml diff --git a/app/src/main/res/values/styles.xml b/android/app/src/main/res/values/styles.xml similarity index 100% rename from app/src/main/res/values/styles.xml rename to android/app/src/main/res/values/styles.xml diff --git a/build.gradle b/android/build.gradle similarity index 100% rename from build.gradle rename to android/build.gradle diff --git a/gradle.properties b/android/gradle.properties similarity index 100% rename from gradle.properties rename to android/gradle.properties diff --git a/gradle/wrapper/gradle-wrapper.jar b/android/gradle/wrapper/gradle-wrapper.jar similarity index 100% rename from gradle/wrapper/gradle-wrapper.jar rename to android/gradle/wrapper/gradle-wrapper.jar diff --git a/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties similarity index 100% rename from gradle/wrapper/gradle-wrapper.properties rename to android/gradle/wrapper/gradle-wrapper.properties diff --git a/gradlew b/android/gradlew similarity index 100% rename from gradlew rename to android/gradlew diff --git a/gradlew.bat b/android/gradlew.bat similarity index 100% rename from gradlew.bat rename to android/gradlew.bat diff --git a/settings.gradle b/android/settings.gradle similarity index 100% rename from settings.gradle rename to android/settings.gradle diff --git a/web/.gitignore b/web/.gitignore new file mode 100644 index 0000000..d692dff --- /dev/null +++ b/web/.gitignore @@ -0,0 +1,183 @@ + +# Created by https://www.gitignore.io/api/git,windows,intellij,phpstorm+all + +### Git ### +# Created by git for backups. To disable backups in Git: +# $ git config --global mergetool.keepBackup false +*.orig + +# Created by git when using merge tools for conflicts +*.BACKUP.* +*.BASE.* +*.LOCAL.* +*.REMOTE.* +*_BACKUP_*.txt +*_BASE_*.txt +*_LOCAL_*.txt +*_REMOTE_*.txt + +### Intellij ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/modules.xml +# .idea/*.iml +# .idea/modules + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### Intellij Patch ### +# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 + +# *.iml +# modules.xml +# .idea/misc.xml +# *.ipr + +# Sonarlint plugin +.idea/sonarlint + +### PhpStorm+all ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff + +# Generated files + +# Sensitive or high-churn files + +# Gradle + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/modules.xml +# .idea/*.iml +# .idea/modules + +# CMake + +# Mongo Explorer plugin + +# File-based project format + +# IntelliJ + +# mpeltonen/sbt-idea plugin + +# JIRA plugin + +# Cursive Clojure plugin + +# Crashlytics plugin (for Android Studio and IntelliJ) + +# Editor-based Rest Client + +# Android studio 3.1+ serialized cache file + +### PhpStorm+all Patch ### +# Ignores the whole .idea folder and all .iml files +# See https://github.com/joeblau/gitignore.io/issues/186 and https://github.com/joeblau/gitignore.io/issues/360 + +.idea/ + +# Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023 + +*.iml +modules.xml +.idea/misc.xml +*.ipr + +### Windows ### +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + + +# End of https://www.gitignore.io/api/git,windows,intellij,phpstorm+all + + + +################# + +config.php \ No newline at end of file diff --git a/web/lib/httpful.phar b/web/lib/httpful.phar new file mode 100644 index 0000000000000000000000000000000000000000..87fb39283751c0478ba5e99c70c45fe4a5c94ce5 GIT binary patch literal 64034 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 PDO::ERRMODE_EXCEPTION, + PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, + PDO::ATTR_EMULATE_PREPARES => false, + ]; + + return Statics::$DB = new PDO($dsn, $_config['user'], $_config['password'], $opt); +} + +function generateRandomAuthKey() +{ + $random = ''; + for ($i = 0; $i < 64; $i++) + + try { + switch (random_int(1, 3)) { + case 1: + $random .= chr(random_int(ord('0'), ord('9'))); + break; + case 2: + $random .= chr(random_int(ord('A'), ord('Z'))); + break; + case 3: + $random .= chr(random_int(ord('a'), ord('z'))); + break; + + } + } + catch (Exception $e) + { + die(json_encode(['success' => false, 'message' => 'Internal error - no randomness'])); + } + return $random; +} + +function sendPOST($url, $body, $header) +{ + $builder = \Httpful\Request::post($url); + + $builder->body($body); + + foreach ($header as $k => $v) $builder->addHeader($k, $v); + + $response = $builder->send(); + + if ($response->code != 200) throw new Exception("Repsponse code: " . $response->code); + + return $response->body; +} diff --git a/web/register.php b/web/register.php new file mode 100644 index 0000000..cd6a99c --- /dev/null +++ b/web/register.php @@ -0,0 +1,17 @@ + false, 'message' => 'Missing parameter [[fcm_token]]'])); + +$fcmtoken = $_GET['fcm_token']; +$user_key = generateRandomAuthKey(); + +$pdo = getDatabase(); + +$stmt = $pdo->prepare('INSERT INTO users (user_key, fcm_token, timestamp_accessed) VALUES (:key, :token, NOW())'); +$stmt->execute(['key' => $user_key, 'token' => $fcmtoken]); +$user_id = $pdo->lastInsertId('user_id'); + +echo json_encode(['success' => true, 'user_id' => $user_id, 'user_key' => $user_key, 'message' => 'new user registered']); +return 0; \ No newline at end of file diff --git a/web/schema.sql b/web/schema.sql new file mode 100644 index 0000000..048e43d --- /dev/null +++ b/web/schema.sql @@ -0,0 +1,10 @@ +CREATE TABLE `users` +( + `id` INT(11) NOT NULL AUTO_INCREMENT, + `auth_token` VARCHAR(64) NOT NULL, + `fcm_token` VARCHAR(256) NULL DEFAULT NULL, + `messages_sent` INT(11) NOT NULL DEFAULT '0', + `timestamp_created` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + `timestamp_accessed` DATETIME NULL DEFAULT NULL, + PRIMARY KEY (`id`) +); diff --git a/web/send.php b/web/send.php new file mode 100644 index 0000000..7259dfb --- /dev/null +++ b/web/send.php @@ -0,0 +1,72 @@ + false, 'message' => 'Missing parameter [[user_id]]'])); +if (!isset($_GET['user_key'])) die(json_encode(['success' => false, 'message' => 'Missing parameter [[user_token]]'])); +if (!isset($_GET['message_title'])) die(json_encode(['success' => false, 'message' => 'Missing parameter [[message_title]]'])); + +$user_id = $_GET['user_id']; +$user_key = $_GET['user_key']; +$message = $_GET['message_title']; +$content = isset($_POST['message_content']) ? $_POST['message_content'] : ''; + +//---------------------- + +$pdo = getDatabase(); + +$stmt = $pdo->prepare('SELECT user_id, user_key, fcm_token FROM users WHERE user_id = :uid LIMIT 1'); +$stmt->execute(['uid' => $user_id]); + +$datas = $stmt->fetchAll(PDO::FETCH_ASSOC); +if (count($datas)<=0) die(json_encode(['success' => false, 'message' => 'No User found'])); +$data = $datas[0]; + +if ($data === null) die(json_encode(['success' => false, 'message' => 'User not found'])); +if ($data['user_id'] !== (int)$user_id) die(json_encode(['success' => false, 'message' => 'UserID not found'])); +if ($data['user_key'] !== $user_key) die(json_encode(['success' => false, 'message' => 'Authentification failed'])); + +$fcm = $data['fcm_token']; + + +$url = "https://fcm.googleapis.com/fcm/send"; +$payload = json_encode( +[ + 'to' => $fcm, + //'dry_run' => true, + 'notification' => + [ + 'title' => $message, + 'body' => $content, + ], + 'data' => + [ + 'title' => $message, + 'body' => $content, + ] +]); +$header= +[ + 'Authorization' => 'key=' . getConfig()['firebase']['server_key'], + 'Content-Type' => 'application/json', +]; + +try +{ + $httpresult = sendPOST($url, $payload, $header); +} +catch (Exception $e) +{ + die(json_encode(['success' => false, 'message' => 'Exception: ' . $e->getMessage()])); +} + +var_dump($httpresult); + + +$stmt = $pdo->prepare('UPDATE users SET timestamp_accessed=NOW(), messages_sent=messages_sent+1 WHERE user_id = :uid'); +$stmt->execute(['uid' => $user_id]); + + +echo (json_encode(['success' => true, 'message' => 'Message sent'])); +return 0; \ No newline at end of file diff --git a/web/update.php b/web/update.php new file mode 100644 index 0000000..bf29a15 --- /dev/null +++ b/web/update.php @@ -0,0 +1,46 @@ + false, 'message' => 'Missing parameter [[user_id]]'])); +if (!isset($_GET['user_key'])) die(json_encode(['success' => false, 'message' => 'Missing parameter [[user_key]]'])); +if (!isset($_GET['message'])) die(json_encode(['success' => false, 'message' => 'Missing parameter [[message]]'])); + +$user_id = $_GET['user_id']; +$user_key = $_GET['token']; +$fcm_token = isset($_GET['token']) ? $_GET['token'] : null; + +//---------------------- + +$pdo = getDatabase(); + +$stmt = $pdo->prepare('SELECT user_id, user_key FROM users WHERE user_id = :uid LIMIT 1'); +$stmt->execute(['uid' => $user_id]); + +$datas = $stmt->fetchAll(PDO::FETCH_ASSOC); +if (count($datas)<=0) die(json_encode(['success' => false, 'message' => 'No User found'])); +$data = $datas[0]; + +if ($data === null) die(json_encode(['success' => false, 'message' => 'User not found'])); +if ($data['user_id'] !== (int)$user_id) die(json_encode(['success' => false, 'message' => 'UserID not found'])); +if ($data['user_key'] !== $user_key) die(json_encode(['success' => false, 'message' => 'Authentification failed'])); + +$new_userkey = generateRandomAuthKey(); + +if ($fcm_token === null) +{ + $stmt = $pdo->prepare('UPDATE users SET timestamp_accessed=NOW(), user_key=:at WHERE user_id = :uid'); + $stmt->execute(['uid' => $user_id, 'at' => $new_userkey]); + + echo json_encode(['success' => true, 'user_id' => $user_id, 'user_key' => $new_userkey, 'message' => 'user updated']); + return 0; +} +else +{ + $stmt = $pdo->prepare('UPDATE users SET timestamp_accessed=NOW(), fcm_token=:ft, user_key=:at WHERE user_id = :uid'); + $stmt->execute(['uid' => $user_id, 'ft' => $fcm_token, 'at' => $new_userkey]); + + echo json_encode(['success' => true, 'user_id' => $user_id, 'user_key' => $new_userkey, 'message' => 'user updated']); + return 0; +} \ No newline at end of file