Compare commits
No commits in common. "master" and "2.0.2" have entirely different histories.
@ -12,13 +12,9 @@ SRC_DIR=`dirname $0`"/.."
|
|||||||
RELEASE_VERSION=${1}
|
RELEASE_VERSION=${1}
|
||||||
echo "Release version set to ${RELEASE_VERSION}"
|
echo "Release version set to ${RELEASE_VERSION}"
|
||||||
|
|
||||||
#which npm > /dev/null
|
|
||||||
#which gulp > /dev/null
|
|
||||||
#which wget > /dev/null
|
|
||||||
|
|
||||||
sed -ri 's/(.*)<version>(.+)<\/version>/\1<version>'${RELEASE_VERSION}'<\/version>/g' ${SRC_DIR}/appinfo/info.xml
|
sed -ri 's/(.*)<version>(.+)<\/version>/\1<version>'${RELEASE_VERSION}'<\/version>/g' ${SRC_DIR}/appinfo/info.xml
|
||||||
npm install
|
npm install
|
||||||
node_modules/gulp/bin/gulp.js uglify
|
gulp uglify
|
||||||
git commit -am "Release "${RELEASE_VERSION}
|
git commit -am "Release "${RELEASE_VERSION}
|
||||||
git tag ${RELEASE_VERSION}
|
git tag ${RELEASE_VERSION}
|
||||||
git push
|
git push
|
||||||
@ -39,8 +35,7 @@ rm -Rf \
|
|||||||
ocsms/gulpfile.js \
|
ocsms/gulpfile.js \
|
||||||
ocsms/package.json \
|
ocsms/package.json \
|
||||||
ocsms/.ci \
|
ocsms/.ci \
|
||||||
ocsms/.tx \
|
ocsms/.tx
|
||||||
ocsms/doc
|
|
||||||
|
|
||||||
tar cfz ocsms-${RELEASE_VERSION}.tar.gz ocsms
|
tar cfz ocsms-${RELEASE_VERSION}.tar.gz ocsms
|
||||||
echo "Release version "${RELEASE_VERSION}" is now ready."
|
echo "Release version "${RELEASE_VERSION}" is now ready."
|
||||||
|
70
.github/workflows/codeql-analysis.yml
vendored
@ -1,70 +0,0 @@
|
|||||||
# For most projects, this workflow file will not need changing; you simply need
|
|
||||||
# to commit it to your repository.
|
|
||||||
#
|
|
||||||
# You may wish to alter this file to override the set of languages analyzed,
|
|
||||||
# or to provide custom queries or build logic.
|
|
||||||
#
|
|
||||||
# ******** NOTE ********
|
|
||||||
# We have attempted to detect the languages in your repository. Please check
|
|
||||||
# the `language` matrix defined below to confirm you have the correct set of
|
|
||||||
# supported CodeQL languages.
|
|
||||||
#
|
|
||||||
name: "CodeQL"
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [ master ]
|
|
||||||
pull_request:
|
|
||||||
# The branches below must be a subset of the branches above
|
|
||||||
branches: [ master ]
|
|
||||||
schedule:
|
|
||||||
- cron: '20 1 * * 4'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
analyze:
|
|
||||||
name: Analyze
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
permissions:
|
|
||||||
actions: read
|
|
||||||
contents: read
|
|
||||||
security-events: write
|
|
||||||
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
language: [ 'javascript' ]
|
|
||||||
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
|
|
||||||
# Learn more about CodeQL language support at https://git.io/codeql-language-support
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
|
|
||||||
# Initializes the CodeQL tools for scanning.
|
|
||||||
- name: Initialize CodeQL
|
|
||||||
uses: github/codeql-action/init@v1
|
|
||||||
with:
|
|
||||||
languages: ${{ matrix.language }}
|
|
||||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
|
||||||
# By default, queries listed here will override any specified in a config file.
|
|
||||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
|
||||||
# queries: ./path/to/local/query, your-org/your-repo/queries@main
|
|
||||||
|
|
||||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
|
||||||
# If this step fails, then you should remove it and run the build manually (see below)
|
|
||||||
- name: Autobuild
|
|
||||||
uses: github/codeql-action/autobuild@v1
|
|
||||||
|
|
||||||
# ℹ️ Command-line programs to run using the OS shell.
|
|
||||||
# 📚 https://git.io/JvXDl
|
|
||||||
|
|
||||||
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
|
||||||
# and modify them (or add more) to build your code if your project
|
|
||||||
# uses a compiled language
|
|
||||||
|
|
||||||
#- run: |
|
|
||||||
# make bootstrap
|
|
||||||
# make release
|
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
|
||||||
uses: github/codeql-action/analyze@v1
|
|
11
.l10nignore
@ -1,11 +0,0 @@
|
|||||||
doc/swagger-ui-bundle.js
|
|
||||||
doc/swagger-ui-bundle.js.map
|
|
||||||
doc/swagger-ui.css
|
|
||||||
doc/swagger-ui.css.map
|
|
||||||
doc/swagger-ui.js
|
|
||||||
doc/swagger-ui.js.map
|
|
||||||
doc/swagger-ui-standalone-preset.js
|
|
||||||
doc/swagger-ui-standalone-preset.js.map
|
|
||||||
doc/swagger.yml
|
|
||||||
doc/index.html
|
|
||||||
doc/oauth2-redirect.html
|
|
@ -1,10 +1,9 @@
|
|||||||
[main]
|
[main]
|
||||||
host = https://www.transifex.com
|
host = https://www.transifex.com
|
||||||
lang_map = sk_SK: sk, th_TH: th, ja_JP: ja, bg_BG: bg, cs_CZ: cs, fi_FI: fi, hu_HU: hu, nb_NO: nb
|
lang_map = bg_BG: bg, cs_CZ: cs, fi_FI: fi, hu_HU: hu, nb_NO: nb, sk_SK: sk, th_TH: th, ja_JP: ja
|
||||||
|
|
||||||
[o:nextcloud:p:nextcloud:r:ocsms]
|
[nextcloud.ocsms]
|
||||||
file_filter = translationfiles/<lang>/ocsms.po
|
file_filter = translationfiles/<lang>/ocsms.po
|
||||||
source_file = translationfiles/templates/ocsms.pot
|
source_file = translationfiles/templates/ocsms.pot
|
||||||
source_lang = en
|
source_lang = en
|
||||||
type = PO
|
type = PO
|
||||||
|
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
FROM nextcloud:15.0.0-rc-apache
|
FROM nextcloud:14.0.3-apache
|
||||||
|
|
||||||
COPY . /usr/src/nextcloud/apps/ocsms
|
COPY . /usr/src/nextcloud/apps/ocsms
|
||||||
|
15
README.md
@ -1,14 +1,15 @@
|
|||||||
# Phone Sync (for Nextcloud & ownCloud)
|
# Phone Sync (for Nextcloud & ownCloud)
|
||||||
|
|
||||||
Phone Sync provides a webinterface to display your SMS conversations. SMS conversations are pushed by your Android devices using the [Android client](https://github.com/nerzhul/ownCloud-SMS-App), available on [F-Droid](https://f-droid.org/repository/browse/?fdid=fr.unix_experience.owncloud_sms).
|
Phone Sync provides a webinterface to display your SMS conversations. SMS conversations are pushed by your Android devices using the [Android client](https://github.com/nerzhul/ownCloud-SMS-App), available on [Google Play Store](https://play.google.com/store/apps/details?id=fr.unix_experience.owncloud_sms).
|
||||||
|
|
||||||
## :arrow_forward: Access
|
## :arrow_forward: Access
|
||||||
|
|
||||||
The app is available on the [Nextcloud App Store](https://apps.nextcloud.com/apps/ocsms), so installing is as easy as:
|
The app is available in both, [Nextcloud appstore](https://apps.nextcloud.com/apps/ocsms) and [ownCloud appstore](https://apps.owncloud.com/content/show.php/ownCloud+SMS?content=167289). So installing is as easy as
|
||||||
|
|
||||||
1. Navigate in your Nextcloud instance to the "Apps"
|
1. Navigate in your Nextcloud / ownCloud instance to the "apps"
|
||||||
2. Select the category "Multimedia"
|
2. Enable "experimental apps" in the settings
|
||||||
3. Click "activate"
|
3. Select the category "Multimedia"
|
||||||
|
4. Click "activate"
|
||||||
|
|
||||||
## :question: Solve encoding errors on MySQL
|
## :question: Solve encoding errors on MySQL
|
||||||
If you are on MySQL or MariaDB and have the following issue with the database:
|
If you are on MySQL or MariaDB and have the following issue with the database:
|
||||||
@ -58,7 +59,3 @@ If you've enabled 2FA (Two Factor Authentication) logins you may be hit with an
|
|||||||
|
|
||||||
## :notebook: License
|
## :notebook: License
|
||||||
Phone Sync web application is currently licensed under [AGPL license](https://github.com/nextcloud/ocsms/blob/master/LICENSE.md).
|
Phone Sync web application is currently licensed under [AGPL license](https://github.com/nextcloud/ocsms/blob/master/LICENSE.md).
|
||||||
|
|
||||||
## :notebook: External Libraries
|
|
||||||
[Twemoji](https://github.com/twitter/twemoji) Code licensed under the [MIT License](http://opensource.org/licenses/MIT), Graphics licensed under [CC-BY 4.0](https://creativecommons.org/licenses/by/4.0/).
|
|
||||||
[libphonenumber-for-php](https://github.com/giggsey/libphonenumber-for-php) Code licensed under the [Apache 2.0 License](http://www.apache.org/licenses/LICENSE-2.0).
|
|
||||||
|
37
appinfo/app.php
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Nextcloud - Phone Sync
|
||||||
|
*
|
||||||
|
* This file is licensed under the Affero General Public License version 3 or
|
||||||
|
* later. See the COPYING file.
|
||||||
|
*
|
||||||
|
* @author Loic Blot <loic.blot@unix-experience.fr>
|
||||||
|
* @copyright Loic Blot 2014-2017
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace OCA\OcSms\AppInfo;
|
||||||
|
|
||||||
|
if (class_exists('\OCP\AppFramework\App')) {
|
||||||
|
\OC::$server->getNavigationManager()->add(array(
|
||||||
|
// the string under which your app will be referenced in owncloud
|
||||||
|
'id' => 'ocsms',
|
||||||
|
|
||||||
|
// sorting weight for the navigation. The higher the number, the higher
|
||||||
|
// will it be listed in the navigation
|
||||||
|
'order' => 10,
|
||||||
|
|
||||||
|
// the route that will be shown on startup
|
||||||
|
'href' => \OC::$server->getURLGenerator()->linkToRoute('ocsms.sms.index'),
|
||||||
|
|
||||||
|
// the icon that will be shown in the navigation
|
||||||
|
// this file needs to exist in img/
|
||||||
|
'icon' => \OC::$server->getURLGenerator()->imagePath('ocsms', 'app.svg'),
|
||||||
|
|
||||||
|
// the title of your application. This will be used in the
|
||||||
|
// navigation or on the settings page of your app
|
||||||
|
'name' => \OCP\Util::getL10N('ocsms')->t('Phone Sync')
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
$msg = 'Can not enable the OcSms app because the App Framework App is disabled';
|
||||||
|
\OC::$server->getLogger()->error($msg, array('ocsms'));
|
||||||
|
}
|
268
appinfo/database.xml
Normal file
@ -0,0 +1,268 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<database>
|
||||||
|
<name>*dbname*</name>
|
||||||
|
<create>true</create>
|
||||||
|
<overwrite>false</overwrite>
|
||||||
|
<charset>utf8</charset>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<name>*dbprefix*ocsms_user_datas</name>
|
||||||
|
<declaration>
|
||||||
|
<field>
|
||||||
|
<name>user_id</name>
|
||||||
|
<type>text</type>
|
||||||
|
<notnull>true</notnull>
|
||||||
|
<length>64</length>
|
||||||
|
</field>
|
||||||
|
<field>
|
||||||
|
<name>datakey</name>
|
||||||
|
<type>text</type>
|
||||||
|
<notnull>true</notnull>
|
||||||
|
<length>64</length>
|
||||||
|
</field>
|
||||||
|
<field>
|
||||||
|
<name>datavalue</name>
|
||||||
|
<type>text</type>
|
||||||
|
<length>64</length>
|
||||||
|
<notnull>true</notnull>
|
||||||
|
</field>
|
||||||
|
<index>
|
||||||
|
<name>user_datas_user_datakey</name>
|
||||||
|
<field>
|
||||||
|
<name>user_id</name>
|
||||||
|
</field>
|
||||||
|
<field>
|
||||||
|
<name>datakey</name>
|
||||||
|
</field>
|
||||||
|
</index>
|
||||||
|
</declaration>
|
||||||
|
</table>
|
||||||
|
<table>
|
||||||
|
<name>*dbprefix*ocsms_smsdatas</name>
|
||||||
|
<declaration>
|
||||||
|
<field>
|
||||||
|
<name>id</name>
|
||||||
|
<type>integer</type>
|
||||||
|
<default>0</default>
|
||||||
|
<notnull>true</notnull>
|
||||||
|
<autoincrement>1</autoincrement>
|
||||||
|
<length>10</length>
|
||||||
|
<primary>true</primary>
|
||||||
|
</field>
|
||||||
|
<field>
|
||||||
|
<name>user_id</name>
|
||||||
|
<type>text</type>
|
||||||
|
<notnull>true</notnull>
|
||||||
|
<length>64</length>
|
||||||
|
</field>
|
||||||
|
<field>
|
||||||
|
<name>added</name>
|
||||||
|
<type>timestamp</type>
|
||||||
|
<notnull>true</notnull>
|
||||||
|
<default>1970-01-01 00:00:00</default>
|
||||||
|
</field>
|
||||||
|
<field>
|
||||||
|
<name>lastmodified</name>
|
||||||
|
<type>timestamp</type>
|
||||||
|
<notnull>true</notnull>
|
||||||
|
<default>1970-01-01 00:00:00</default>
|
||||||
|
</field>
|
||||||
|
<field>
|
||||||
|
<name>sms_id</name>
|
||||||
|
<type>integer</type>
|
||||||
|
<notnull>true</notnull>
|
||||||
|
<length>5</length>
|
||||||
|
</field>
|
||||||
|
<field>
|
||||||
|
<name>sms_address</name>
|
||||||
|
<type>text</type>
|
||||||
|
<notnull>true</notnull>
|
||||||
|
<length>512</length>
|
||||||
|
</field>
|
||||||
|
<field>
|
||||||
|
<name>sms_msg</name>
|
||||||
|
<type>text</type>
|
||||||
|
<notnull>true</notnull>
|
||||||
|
<length>10240</length>
|
||||||
|
</field>
|
||||||
|
<field>
|
||||||
|
<name>sms_date</name>
|
||||||
|
<type>integer</type>
|
||||||
|
<notnull>true</notnull>
|
||||||
|
<length>10</length>
|
||||||
|
</field>
|
||||||
|
<field>
|
||||||
|
<name>sms_flags</name>
|
||||||
|
<type>text</type>
|
||||||
|
<notnull>true</notnull>
|
||||||
|
<default>00</default>
|
||||||
|
<length>2</length>
|
||||||
|
</field>
|
||||||
|
<field>
|
||||||
|
<name>sms_mailbox</name>
|
||||||
|
<type>integer</type>
|
||||||
|
<notnull>true</notnull>
|
||||||
|
<length>1</length>
|
||||||
|
</field>
|
||||||
|
<field>
|
||||||
|
<name>sms_type</name>
|
||||||
|
<type>integer</type>
|
||||||
|
<notnull>true</notnull>
|
||||||
|
<length>1</length>
|
||||||
|
</field>
|
||||||
|
<index>
|
||||||
|
<name>smsdata_user_mailbox</name>
|
||||||
|
<field>
|
||||||
|
<name>user_id</name>
|
||||||
|
</field>
|
||||||
|
<field>
|
||||||
|
<name>sms_mailbox</name>
|
||||||
|
</field>
|
||||||
|
</index>
|
||||||
|
<index>
|
||||||
|
<name>smsdata_user_smsid</name>
|
||||||
|
<field>
|
||||||
|
<name>user_id</name>
|
||||||
|
</field>
|
||||||
|
<field>
|
||||||
|
<name>sms_id</name>
|
||||||
|
</field>
|
||||||
|
</index>
|
||||||
|
<index>
|
||||||
|
<name>smsdata_user_mailbox_date</name>
|
||||||
|
<field>
|
||||||
|
<name>user_id</name>
|
||||||
|
</field>
|
||||||
|
<field>
|
||||||
|
<name>sms_mailbox</name>
|
||||||
|
</field>
|
||||||
|
<field>
|
||||||
|
<name>sms_date</name>
|
||||||
|
</field>
|
||||||
|
</index>
|
||||||
|
<index>
|
||||||
|
<name>smsdata_user_mailbox_address</name>
|
||||||
|
<field>
|
||||||
|
<name>user_id</name>
|
||||||
|
</field>
|
||||||
|
<field>
|
||||||
|
<name>sms_mailbox</name>
|
||||||
|
</field>
|
||||||
|
<field>
|
||||||
|
<name>sms_address</name>
|
||||||
|
</field>
|
||||||
|
</index>
|
||||||
|
<index>
|
||||||
|
<name>smsdata_user_mailbox_address_date</name>
|
||||||
|
<field>
|
||||||
|
<name>user_id</name>
|
||||||
|
</field>
|
||||||
|
<field>
|
||||||
|
<name>sms_mailbox</name>
|
||||||
|
</field>
|
||||||
|
<field>
|
||||||
|
<name>sms_address</name>
|
||||||
|
</field>
|
||||||
|
<field>
|
||||||
|
<name>sms_date</name>
|
||||||
|
</field>
|
||||||
|
</index>
|
||||||
|
</declaration>
|
||||||
|
</table>
|
||||||
|
<table>
|
||||||
|
<name>*dbprefix*ocsms_sendmessage_queue</name>
|
||||||
|
<declaration>
|
||||||
|
<field>
|
||||||
|
<name>id</name>
|
||||||
|
<type>integer</type>
|
||||||
|
<default>0</default>
|
||||||
|
<notnull>true</notnull>
|
||||||
|
<autoincrement>1</autoincrement>
|
||||||
|
<length>10</length>
|
||||||
|
<primary>true</primary>
|
||||||
|
</field>
|
||||||
|
<field>
|
||||||
|
<name>user_id</name>
|
||||||
|
<type>text</type>
|
||||||
|
<notnull>true</notnull>
|
||||||
|
<length>64</length>
|
||||||
|
</field>
|
||||||
|
<field>
|
||||||
|
<name>sms_address</name>
|
||||||
|
<type>text</type>
|
||||||
|
<notnull>true</notnull>
|
||||||
|
<length>64</length>
|
||||||
|
</field>
|
||||||
|
<field>
|
||||||
|
<name>sms_msg</name>
|
||||||
|
<type>text</type>
|
||||||
|
<notnull>true</notnull>
|
||||||
|
<length>2048</length>
|
||||||
|
</field>
|
||||||
|
</declaration>
|
||||||
|
</table>
|
||||||
|
<table>
|
||||||
|
<name>*dbprefix*ocsms_conversation_read_states</name>
|
||||||
|
<declaration>
|
||||||
|
<field>
|
||||||
|
<name>user_id</name>
|
||||||
|
<type>text</type>
|
||||||
|
<notnull>true</notnull>
|
||||||
|
<length>64</length>
|
||||||
|
</field>
|
||||||
|
<field>
|
||||||
|
<name>phone_number</name>
|
||||||
|
<type>text</type>
|
||||||
|
<notnull>true</notnull>
|
||||||
|
<length>64</length>
|
||||||
|
</field>
|
||||||
|
<field>
|
||||||
|
<name>int_date</name>
|
||||||
|
<type>integer</type>
|
||||||
|
<length>32</length>
|
||||||
|
<notnull>true</notnull>
|
||||||
|
</field>
|
||||||
|
<index>
|
||||||
|
<name>sms_conversation_rs_pkey</name>
|
||||||
|
<field>
|
||||||
|
<name>user_id</name>
|
||||||
|
</field>
|
||||||
|
<field>
|
||||||
|
<name>phone_number</name>
|
||||||
|
</field>
|
||||||
|
</index>
|
||||||
|
</declaration>
|
||||||
|
</table>
|
||||||
|
<table>
|
||||||
|
<name>*dbprefix*ocsms_config</name>
|
||||||
|
<declaration>
|
||||||
|
<field>
|
||||||
|
<name>user</name>
|
||||||
|
<type>text</type>
|
||||||
|
<notnull>true</notnull>
|
||||||
|
<length>255</length>
|
||||||
|
</field>
|
||||||
|
<field>
|
||||||
|
<name>key</name>
|
||||||
|
<type>text</type>
|
||||||
|
<notnull>true</notnull>
|
||||||
|
<length>255</length>
|
||||||
|
</field>
|
||||||
|
<field>
|
||||||
|
<name>value</name>
|
||||||
|
<type>text</type>
|
||||||
|
<notnull>false</notnull>
|
||||||
|
<length>10240</length>
|
||||||
|
</field>
|
||||||
|
<index>
|
||||||
|
<name>config_user_key</name>
|
||||||
|
<field>
|
||||||
|
<name>user</name>
|
||||||
|
</field>
|
||||||
|
<field>
|
||||||
|
<name>key</name>
|
||||||
|
</field>
|
||||||
|
</index>
|
||||||
|
</declaration>
|
||||||
|
</table>
|
||||||
|
</database>
|
@ -5,35 +5,26 @@
|
|||||||
<name>Phone Sync</name>
|
<name>Phone Sync</name>
|
||||||
<summary>An app to sync SMS with your cloud</summary>
|
<summary>An app to sync SMS with your cloud</summary>
|
||||||
<description>An app to sync SMS with your cloud</description>
|
<description>An app to sync SMS with your cloud</description>
|
||||||
<author>Loic Blot</author>
|
<licence>agpl</licence>
|
||||||
<author>e-alfred</author>
|
<author homepage="https://www.unix-experience.fr">Loic Blot</author>
|
||||||
<version>2.2.0</version>
|
<version>2.0.2</version>
|
||||||
<licence>agpl</licence>
|
|
||||||
<category>multimedia</category>
|
<category>multimedia</category>
|
||||||
<category>tools</category>
|
<category>tools</category>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<nextcloud min-version="18" max-version="20" />
|
<php min-version="5.6" min-int-size="32"/>
|
||||||
|
<nextcloud min-version="14.0" max-version="14.0" />
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
<ocsid>167289</ocsid>
|
||||||
|
|
||||||
<website>https://github.com/nextcloud/ocsms</website>
|
<website>https://github.com/nextcloud/ocsms</website>
|
||||||
<bugs>https://github.com/nextcloud/ocsms/issues</bugs>
|
<bugs>https://github.com/nextcloud/ocsms/issues</bugs>
|
||||||
<repository type="git">https://github.com/nextcloud/ocsms</repository>
|
<repository type="git">https://github.com/nextcloud/ocsms</repository>
|
||||||
<screenshot small-thumbnail="https://raw.githubusercontent.com/nextcloud/ocsms/master/appinfo/screenshots/1-small.png">https://raw.githubusercontent.com/nextcloud/ocsms/master/appinfo/screenshots/1.png</screenshot>
|
<screenshot small-thumbnail="https://raw.githubusercontent.com/nextcloud/ocsms/master/appinfo/screenshots/1-small.png">https://raw.githubusercontent.com/nextcloud/ocsms/master/appinfo/screenshots/1.png</screenshot>
|
||||||
|
|
||||||
<fulltextsearch>
|
|
||||||
<provider>OCA\OcSms\Provider\FullTextSearchProvider</provider>
|
|
||||||
</fulltextsearch>
|
|
||||||
<repair-steps>
|
<repair-steps>
|
||||||
<post-migration>
|
<post-migration>
|
||||||
<step>OCA\OcSms\Migration\FixConversationReadStates</step>
|
<step>OCA\OcSms\Migration\FixConversationReadStates</step>
|
||||||
</post-migration>
|
</post-migration>
|
||||||
</repair-steps>
|
</repair-steps>
|
||||||
<navigations>
|
|
||||||
<navigation>
|
|
||||||
<id>ocsms</id>
|
|
||||||
<name>Phone Sync</name>
|
|
||||||
<route>ocsms.sms.index</route>
|
|
||||||
<icon>app.svg</icon>
|
|
||||||
</navigation>
|
|
||||||
</navigations>
|
|
||||||
</info>
|
</info>
|
||||||
|
@ -43,7 +43,7 @@ $application->registerRoutes($this, array('routes' => array(
|
|||||||
array('name' => 'api#fetch_messages_count', 'url' => '/api/v2/messages/count', 'verb' => 'GET'), // Android APIv2
|
array('name' => 'api#fetch_messages_count', 'url' => '/api/v2/messages/count', 'verb' => 'GET'), // Android APIv2
|
||||||
|
|
||||||
// Android API v3
|
// Android API v3
|
||||||
array('name' => 'api#generate_sms_test_data', 'url' => '/api/v3/test/generate_sms_data', 'verb' => 'POST'), // Android APIv3
|
// @TODO
|
||||||
|
|
||||||
// Android API v4
|
// Android API v4
|
||||||
// @TODO future calls to sending calls recorded on the phone
|
// @TODO future calls to sending calls recorded on the phone
|
||||||
|
@ -229,25 +229,4 @@ class ApiController extends Controller {
|
|||||||
// @TODO
|
// @TODO
|
||||||
return new JSONResponse(array("messages" => array()));
|
return new JSONResponse(array("messages" => array()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @NoAdminRequired
|
|
||||||
* @NoCSRFRequired
|
|
||||||
*
|
|
||||||
* @param $smsCount
|
|
||||||
* @param $smsDatas
|
|
||||||
* @return JSONResponse
|
|
||||||
*
|
|
||||||
* produce a bunch of data to test application
|
|
||||||
*/
|
|
||||||
public function generateSmsTestData () {
|
|
||||||
return $this->push(2, array(
|
|
||||||
array("_id" => 702, "type" => 1, "mbox" => 2, "read" => "true",
|
|
||||||
"seen" => "true", "date" => 1654777747, "address" => "+33123456789",
|
|
||||||
"body" => "hello dude"),
|
|
||||||
array("_id" => 685, "type" => 1, "mbox" => 1, "read" => "true",
|
|
||||||
"seen" => "true", "date" => 1654777777, "address" => "+33123456789",
|
|
||||||
"body" => "😀🌍⭐🌎🌔🌒🐕🍖🥂🍻🎮🤸♂️🚇🈲❕📘📚📈🇸🇨🇮🇲"),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -80,21 +80,7 @@ class SmsController extends Controller {
|
|||||||
$params = array('user' => $this->userId,
|
$params = array('user' => $this->userId,
|
||||||
'mailboxes' => $mboxes
|
'mailboxes' => $mboxes
|
||||||
);
|
);
|
||||||
$response = new TemplateResponse($this->appName, 'main', $params);
|
return new TemplateResponse($this->appName, 'main', $params);
|
||||||
$this->addContentSecurityToResponse($response);
|
|
||||||
return $response;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds the domain "data:" to the allowed image domains
|
|
||||||
* this function is called by reference
|
|
||||||
*
|
|
||||||
* @param TemplateResponse $response
|
|
||||||
*/
|
|
||||||
private function addContentSecurityToResponse($response) {
|
|
||||||
$csp = new Http\ContentSecurityPolicy();
|
|
||||||
$csp->allowEvalScript(true);
|
|
||||||
$response->setContentSecurityPolicy($csp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3,10 +3,6 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
body.dark #app {
|
|
||||||
color: var(--color-background-dark);
|
|
||||||
}
|
|
||||||
|
|
||||||
#app-navigation {
|
#app-navigation {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
border-left: 1px solid #ddd;
|
border-left: 1px solid #ddd;
|
||||||
@ -170,10 +166,6 @@ body.dark #app {
|
|||||||
float: left;
|
float: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
.msg-sent a:link, .msg-sent a:visited, .msg-recv a:link, .msg-recv a:visited {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
.msg-date {
|
.msg-date {
|
||||||
color: #666;
|
color: #666;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
@ -289,13 +281,6 @@ label {
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
img.emoji {
|
|
||||||
height: 1em;
|
|
||||||
width: 1em;
|
|
||||||
margin: 0 .05em 0 .1em;
|
|
||||||
vertical-align: -0.1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.contact-list-no-contact {
|
.contact-list-no-contact {
|
||||||
padding: 1em;
|
padding: 1em;
|
||||||
font-size: 1.5em;
|
font-size: 1.5em;
|
||||||
|
@ -26,7 +26,7 @@ class ConversationStateMapper extends Mapper {
|
|||||||
public function getLast ($userId) {
|
public function getLast ($userId) {
|
||||||
$qb = $this->db->getQueryBuilder();
|
$qb = $this->db->getQueryBuilder();
|
||||||
$qb->selectAlias($qb->createFunction('MAX(int_date)'), 'mx')
|
$qb->selectAlias($qb->createFunction('MAX(int_date)'), 'mx')
|
||||||
->from('ocsms_conv_r_states')
|
->from('ocsms_conversation_read_states')
|
||||||
->where($qb->expr()->andX(
|
->where($qb->expr()->andX(
|
||||||
$qb->expr()->eq('user_id', $qb->createNamedParameter($userId))
|
$qb->expr()->eq('user_id', $qb->createNamedParameter($userId))
|
||||||
));
|
));
|
||||||
@ -42,7 +42,7 @@ class ConversationStateMapper extends Mapper {
|
|||||||
public function getLastForPhoneNumber ($userId, $phoneNumber) {
|
public function getLastForPhoneNumber ($userId, $phoneNumber) {
|
||||||
$qb = $this->db->getQueryBuilder();
|
$qb = $this->db->getQueryBuilder();
|
||||||
$qb->selectAlias($qb->createFunction('MAX(int_date)'), 'mx')
|
$qb->selectAlias($qb->createFunction('MAX(int_date)'), 'mx')
|
||||||
->from('ocsms_conv_r_states')
|
->from('ocsms_conversation_read_states')
|
||||||
->where($qb->expr()->andX(
|
->where($qb->expr()->andX(
|
||||||
$qb->expr()->eq('user_id', $qb->createNamedParameter($userId)),
|
$qb->expr()->eq('user_id', $qb->createNamedParameter($userId)),
|
||||||
$qb->expr()->eq('phone_number', $qb->createNamedParameter($phoneNumber))
|
$qb->expr()->eq('phone_number', $qb->createNamedParameter($phoneNumber))
|
||||||
@ -59,7 +59,7 @@ class ConversationStateMapper extends Mapper {
|
|||||||
public function setLast ($userId, $phoneNumber, $lastDate) {
|
public function setLast ($userId, $phoneNumber, $lastDate) {
|
||||||
$this->db->beginTransaction();
|
$this->db->beginTransaction();
|
||||||
$qb = $this->db->getQueryBuilder();
|
$qb = $this->db->getQueryBuilder();
|
||||||
$qb->delete('ocsms_conv_r_states')
|
$qb->delete('ocsms_conversation_read_states')
|
||||||
->where($qb->expr()->andX(
|
->where($qb->expr()->andX(
|
||||||
$qb->expr()->eq('user_id', $qb->createNamedParameter($userId)),
|
$qb->expr()->eq('user_id', $qb->createNamedParameter($userId)),
|
||||||
$qb->expr()->eq('phone_number', $qb->createNamedParameter($phoneNumber))
|
$qb->expr()->eq('phone_number', $qb->createNamedParameter($phoneNumber))
|
||||||
@ -67,7 +67,7 @@ class ConversationStateMapper extends Mapper {
|
|||||||
$qb->execute();
|
$qb->execute();
|
||||||
|
|
||||||
$qb = $this->db->getQueryBuilder();
|
$qb = $this->db->getQueryBuilder();
|
||||||
$qb->insert('ocsms_conv_r_states')
|
$qb->insert('ocsms_conversation_read_states')
|
||||||
->values(array(
|
->values(array(
|
||||||
'user_id' => $qb->createNamedParameter($userId),
|
'user_id' => $qb->createNamedParameter($userId),
|
||||||
'phone_number' => $qb->createNamedParameter($phoneNumber),
|
'phone_number' => $qb->createNamedParameter($phoneNumber),
|
||||||
|
@ -132,17 +132,13 @@ class SmsMapper extends Mapper {
|
|||||||
}
|
}
|
||||||
$phoneList[$fmtPN][$pn] += 1;
|
$phoneList[$fmtPN][$pn] += 1;
|
||||||
}
|
}
|
||||||
$fpn = $phoneNumber;
|
$fpn = PhoneNumberFormatter::format($country, $phoneNumber);
|
||||||
if(isset($phoneList[$fpn])) {
|
if(isset($phoneList[$fpn])){
|
||||||
return $phoneList[$fpn];
|
return $phoneList[$fpn];
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
$fpn = PhoneNumberFormatter::format($country, $fpn);
|
return array();
|
||||||
if (isset($phoneList[$fpn])) {
|
|
||||||
return $phoneList[$fpn];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return array();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getAllMessagesForPhoneNumber ($userId, $phoneNumber, $country, $minDate = 0) {
|
public function getAllMessagesForPhoneNumber ($userId, $phoneNumber, $country, $minDate = 0) {
|
||||||
|
Before Width: | Height: | Size: 445 B |
Before Width: | Height: | Size: 1.1 KiB |
@ -1,60 +0,0 @@
|
|||||||
<!-- HTML for static distribution bundle build -->
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>Swagger UI</title>
|
|
||||||
<link rel="stylesheet" type="text/css" href="./swagger-ui.css" >
|
|
||||||
<link rel="icon" type="image/png" href="./favicon-32x32.png" sizes="32x32" />
|
|
||||||
<link rel="icon" type="image/png" href="./favicon-16x16.png" sizes="16x16" />
|
|
||||||
<style>
|
|
||||||
html
|
|
||||||
{
|
|
||||||
box-sizing: border-box;
|
|
||||||
overflow: -moz-scrollbars-vertical;
|
|
||||||
overflow-y: scroll;
|
|
||||||
}
|
|
||||||
|
|
||||||
*,
|
|
||||||
*:before,
|
|
||||||
*:after
|
|
||||||
{
|
|
||||||
box-sizing: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
body
|
|
||||||
{
|
|
||||||
margin:0;
|
|
||||||
background: #fafafa;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<div id="swagger-ui"></div>
|
|
||||||
|
|
||||||
<script src="./swagger-ui-bundle.js"> </script>
|
|
||||||
<script src="./swagger-ui-standalone-preset.js"> </script>
|
|
||||||
<script>
|
|
||||||
window.onload = function() {
|
|
||||||
// Begin Swagger UI call region
|
|
||||||
const ui = SwaggerUIBundle({
|
|
||||||
url: "https://raw.githubusercontent.com/nextcloud/ocsms/master/doc/swagger.yml",
|
|
||||||
dom_id: '#swagger-ui',
|
|
||||||
deepLinking: true,
|
|
||||||
presets: [
|
|
||||||
SwaggerUIBundle.presets.apis,
|
|
||||||
SwaggerUIStandalonePreset
|
|
||||||
],
|
|
||||||
plugins: [
|
|
||||||
SwaggerUIBundle.plugins.DownloadUrl
|
|
||||||
],
|
|
||||||
layout: "StandaloneLayout"
|
|
||||||
})
|
|
||||||
// End Swagger UI call region
|
|
||||||
|
|
||||||
window.ui = ui
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@ -1,67 +0,0 @@
|
|||||||
<!doctype html>
|
|
||||||
<html lang="en-US">
|
|
||||||
<body onload="run()">
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
<script>
|
|
||||||
'use strict';
|
|
||||||
function run () {
|
|
||||||
var oauth2 = window.opener.swaggerUIRedirectOauth2;
|
|
||||||
var sentState = oauth2.state;
|
|
||||||
var redirectUrl = oauth2.redirectUrl;
|
|
||||||
var isValid, qp, arr;
|
|
||||||
|
|
||||||
if (/code|token|error/.test(window.location.hash)) {
|
|
||||||
qp = window.location.hash.substring(1);
|
|
||||||
} else {
|
|
||||||
qp = location.search.substring(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
arr = qp.split("&")
|
|
||||||
arr.forEach(function (v,i,_arr) { _arr[i] = '"' + v.replace('=', '":"') + '"';})
|
|
||||||
qp = qp ? JSON.parse('{' + arr.join() + '}',
|
|
||||||
function (key, value) {
|
|
||||||
return key === "" ? value : decodeURIComponent(value)
|
|
||||||
}
|
|
||||||
) : {}
|
|
||||||
|
|
||||||
isValid = qp.state === sentState
|
|
||||||
|
|
||||||
if ((
|
|
||||||
oauth2.auth.schema.get("flow") === "accessCode"||
|
|
||||||
oauth2.auth.schema.get("flow") === "authorizationCode"
|
|
||||||
) && !oauth2.auth.code) {
|
|
||||||
if (!isValid) {
|
|
||||||
oauth2.errCb({
|
|
||||||
authId: oauth2.auth.name,
|
|
||||||
source: "auth",
|
|
||||||
level: "warning",
|
|
||||||
message: "Authorization may be unsafe, passed state was changed in server Passed state wasn't returned from auth server"
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (qp.code) {
|
|
||||||
delete oauth2.state;
|
|
||||||
oauth2.auth.code = qp.code;
|
|
||||||
oauth2.callback({auth: oauth2.auth, redirectUrl: redirectUrl});
|
|
||||||
} else {
|
|
||||||
let oauthErrorMsg
|
|
||||||
if (qp.error) {
|
|
||||||
oauthErrorMsg = "["+qp.error+"]: " +
|
|
||||||
(qp.error_description ? qp.error_description+ ". " : "no accessCode received from the server. ") +
|
|
||||||
(qp.error_uri ? "More info: "+qp.error_uri : "");
|
|
||||||
}
|
|
||||||
|
|
||||||
oauth2.errCb({
|
|
||||||
authId: oauth2.auth.name,
|
|
||||||
source: "auth",
|
|
||||||
level: "error",
|
|
||||||
message: oauthErrorMsg || "[Authorization failed]: no accessCode received from the server"
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
oauth2.callback({auth: oauth2.auth, token: qp, isValid: isValid, redirectUrl: redirectUrl});
|
|
||||||
}
|
|
||||||
window.close();
|
|
||||||
}
|
|
||||||
</script>
|
|
@ -1 +0,0 @@
|
|||||||
{"version":3,"sources":[],"names":[],"mappings":"","file":"swagger-ui.css","sourceRoot":""}
|
|
@ -1,58 +0,0 @@
|
|||||||
swagger: "2.0"
|
|
||||||
|
|
||||||
info:
|
|
||||||
version: 2.0.0
|
|
||||||
title: OcSMS API
|
|
||||||
description: OcSMS API specification
|
|
||||||
|
|
||||||
schemes:
|
|
||||||
- https
|
|
||||||
host: nextcloud.example.org
|
|
||||||
basePath: /apps/ocsms
|
|
||||||
|
|
||||||
paths:
|
|
||||||
/get/apiversion:
|
|
||||||
get:
|
|
||||||
summary: Retrieve API version
|
|
||||||
description: Returns the current API version.
|
|
||||||
responses:
|
|
||||||
200:
|
|
||||||
description: OcSMS API version
|
|
||||||
schema:
|
|
||||||
required:
|
|
||||||
- version
|
|
||||||
properties:
|
|
||||||
version:
|
|
||||||
type: integer
|
|
||||||
# TODO: complete this
|
|
||||||
/push:
|
|
||||||
post:
|
|
||||||
summary: Push messages to server
|
|
||||||
description: Push a list of messages to the server
|
|
||||||
responses:
|
|
||||||
200:
|
|
||||||
# TODO: complete this
|
|
||||||
/replace:
|
|
||||||
post:
|
|
||||||
summary: Replace messages to server
|
|
||||||
description: Push a list of messages to replace on the server
|
|
||||||
responses:
|
|
||||||
200:
|
|
||||||
# TODO: complete this
|
|
||||||
/get/smsidlist:
|
|
||||||
get:
|
|
||||||
# TODO: complete this
|
|
||||||
/get/lastmsgtime:
|
|
||||||
get:
|
|
||||||
# TODO: complete this
|
|
||||||
/api/v2/phones/list:
|
|
||||||
get:
|
|
||||||
# TODO: complete this
|
|
||||||
/api/v2/messages/{start}/{limit}:
|
|
||||||
get:
|
|
||||||
# TODO: complete this
|
|
||||||
/api/v2/messages/count:
|
|
||||||
get:
|
|
||||||
# Not implemented
|
|
||||||
/api/v4/messages/sendqueue:
|
|
||||||
get:
|
|
1
js/anchorme.min.js
vendored
2
js/app.min.js
vendored
@ -97,12 +97,11 @@ var Conversation = new Vue({
|
|||||||
// Return (int) msgCount, (str) htmlConversation
|
// Return (int) msgCount, (str) htmlConversation
|
||||||
formatConversation: function (jsondata) {
|
formatConversation: function (jsondata) {
|
||||||
// Improve jQuery performance
|
// Improve jQuery performance
|
||||||
let buf = false;
|
let buf = false;
|
||||||
// Improve JS performance
|
// Improve JS performance
|
||||||
let msgClass = '';
|
let msgClass = '';
|
||||||
let msgCount = 0;
|
let msgCount = 0;
|
||||||
let self = this;
|
let self = this;
|
||||||
let twemojiOptions = { base: OC.generateUrl('/apps/ocsms/js/twemoji/')};
|
|
||||||
|
|
||||||
$.each(jsondata["conversation"], function (id, vals) {
|
$.each(jsondata["conversation"], function (id, vals) {
|
||||||
if (vals["type"] == 1) {
|
if (vals["type"] == 1) {
|
||||||
@ -125,7 +124,7 @@ var Conversation = new Vue({
|
|||||||
'id': id,
|
'id': id,
|
||||||
'type': msgClass,
|
'type': msgClass,
|
||||||
'date': new Date(id * 1),
|
'date': new Date(id * 1),
|
||||||
'content': twemoji.parse(anchorme(escapeHTML(vals['msg'])), twemojiOptions)
|
'content': vals['msg']
|
||||||
});
|
});
|
||||||
buf = true;
|
buf = true;
|
||||||
msgCount++;
|
msgCount++;
|
||||||
|
@ -26,52 +26,4 @@ function toBool(str) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function escapeHTML(string) {
|
|
||||||
var str = '' + string
|
|
||||||
var matchHtmlRegExp = /["'&<>]/
|
|
||||||
var match = matchHtmlRegExp.exec(str)
|
|
||||||
|
|
||||||
if (!match) {
|
|
||||||
return str
|
|
||||||
}
|
|
||||||
|
|
||||||
var escape
|
|
||||||
var html = ''
|
|
||||||
var index = 0
|
|
||||||
var lastIndex = 0
|
|
||||||
|
|
||||||
for (index = match.index; index < str.length; index++) {
|
|
||||||
switch (str.charCodeAt(index)) {
|
|
||||||
case 34: // "
|
|
||||||
escape = '"'
|
|
||||||
break
|
|
||||||
case 38: // &
|
|
||||||
escape = '&'
|
|
||||||
break
|
|
||||||
case 39: // '
|
|
||||||
escape = '''
|
|
||||||
break
|
|
||||||
case 60: // <
|
|
||||||
escape = '<'
|
|
||||||
break
|
|
||||||
case 62: // >
|
|
||||||
escape = '>'
|
|
||||||
break
|
|
||||||
default:
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lastIndex !== index) {
|
|
||||||
html += str.substring(lastIndex, index)
|
|
||||||
}
|
|
||||||
|
|
||||||
lastIndex = index + 1
|
|
||||||
html += escape
|
|
||||||
}
|
|
||||||
|
|
||||||
return lastIndex !== index
|
|
||||||
? html + str.substring(lastIndex, index)
|
|
||||||
: html
|
|
||||||
}
|
|
Before Width: | Height: | Size: 551 B |
Before Width: | Height: | Size: 923 B |
Before Width: | Height: | Size: 557 B |
Before Width: | Height: | Size: 458 B |
Before Width: | Height: | Size: 562 B |
Before Width: | Height: | Size: 403 B |
Before Width: | Height: | Size: 682 B |
Before Width: | Height: | Size: 561 B |
Before Width: | Height: | Size: 603 B |
Before Width: | Height: | Size: 517 B |
Before Width: | Height: | Size: 495 B |
Before Width: | Height: | Size: 668 B |
Before Width: | Height: | Size: 670 B |
Before Width: | Height: | Size: 640 B |
Before Width: | Height: | Size: 722 B |
Before Width: | Height: | Size: 553 B |
Before Width: | Height: | Size: 747 B |
Before Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 697 B |
Before Width: | Height: | Size: 287 B |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 849 B |
Before Width: | Height: | Size: 989 B |
Before Width: | Height: | Size: 662 B |
Before Width: | Height: | Size: 245 B |
Before Width: | Height: | Size: 723 B |
Before Width: | Height: | Size: 481 B |
Before Width: | Height: | Size: 453 B |
Before Width: | Height: | Size: 847 B |
Before Width: | Height: | Size: 205 B |
Before Width: | Height: | Size: 835 B |
Before Width: | Height: | Size: 387 B |
Before Width: | Height: | Size: 230 B |
Before Width: | Height: | Size: 402 B |
Before Width: | Height: | Size: 559 B |
Before Width: | Height: | Size: 652 B |
Before Width: | Height: | Size: 406 B |
Before Width: | Height: | Size: 336 B |
Before Width: | Height: | Size: 233 B |
Before Width: | Height: | Size: 390 B |
Before Width: | Height: | Size: 244 B |
Before Width: | Height: | Size: 411 B |
Before Width: | Height: | Size: 940 B |
Before Width: | Height: | Size: 279 B |
Before Width: | Height: | Size: 978 B |
Before Width: | Height: | Size: 919 B |
Before Width: | Height: | Size: 884 B |
Before Width: | Height: | Size: 666 B |
Before Width: | Height: | Size: 871 B |
Before Width: | Height: | Size: 805 B |
Before Width: | Height: | Size: 419 B |
Before Width: | Height: | Size: 1000 B |
Before Width: | Height: | Size: 270 B |
Before Width: | Height: | Size: 214 B |
Before Width: | Height: | Size: 669 B |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 459 B |
Before Width: | Height: | Size: 445 B |
Before Width: | Height: | Size: 706 B |
Before Width: | Height: | Size: 602 B |
Before Width: | Height: | Size: 389 B |
Before Width: | Height: | Size: 356 B |
Before Width: | Height: | Size: 220 B |
Before Width: | Height: | Size: 233 B |
Before Width: | Height: | Size: 961 B |
Before Width: | Height: | Size: 394 B |
Before Width: | Height: | Size: 341 B |