commit
5dfbd92b27
16
CONTRIBUTING.md → .github/CONTRIBUTING.md
vendored
16
CONTRIBUTING.md → .github/CONTRIBUTING.md
vendored
@ -2,8 +2,8 @@
|
||||
|
||||
Read the following before reporting a bug on GitHub:
|
||||
|
||||
1. Update to the newest version of Lychee
|
||||
2. Update your Browser to the newest version
|
||||
1. Update Lychee to the newest version
|
||||
2. Update your browser to the newest version
|
||||
2. Take a look in the [FAQ](https://github.com/electerious/Lychee/blob/master/docs/FAQ.md)
|
||||
3. Check if someone has [already reported](https://github.com/electerious/Lychee/issues) the same bug
|
||||
|
||||
@ -12,7 +12,7 @@ When reporting a bug on GitHub, make sure you include the following information:
|
||||
- Detailed description of the problem
|
||||
- How to reproduce the issue (step-by-step)
|
||||
- What you have already tried
|
||||
- Output of the diagnostics (`plugins/check/index.php`)
|
||||
- Output of the diagnostics (`plugins/Diagnostics/index.php`)
|
||||
- Browser and system version
|
||||
- Attach files when you have problems which specific photos
|
||||
|
||||
@ -23,15 +23,15 @@ Check if there are branches newer than `master`. Always fork the newest availabl
|
||||
Please follow the conventions already established in the code.
|
||||
|
||||
- **Spacing**:<br>
|
||||
Use tabs for indentation. No spaces.
|
||||
Use tabs for indentation. Spaces for alignment.
|
||||
|
||||
- **Naming**:<br>
|
||||
Keep variable and method names concise and descriptive.
|
||||
|
||||
- **Quotes**:<br>
|
||||
Single-quoted strings are preferred to double-quoted strings
|
||||
|
||||
|
||||
- **Comments**:<br>
|
||||
Please use single-line comments to annotate significant additions. Use `#` for comments in PHP; `//` for comments in JS and CSS.
|
||||
|
||||
Merge your changes when the forked branch has been updated in the meanwhile. Make sure your code is 100% working before creating a Pull-Request on GitHub.
|
||||
Please use single-line comments to annotate significant additions. Use `//` for comments in PHP, JS and CSS.
|
||||
|
||||
Merge your changes when the forked branch has been updated in the meanwhile. Make sure your code is 100% working before creating a Pull-Request on GitHub.
|
7
.github/ISSUE_TEMPLATE.md
vendored
Normal file
7
.github/ISSUE_TEMPLATE.md
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
### Detailed description of the problem
|
||||
|
||||
### Steps to reproduce the issue
|
||||
|
||||
### Output of the diagnostics (Settings => Diagnostics)
|
||||
|
||||
### Browser and system
|
7
.gitignore
vendored
7
.gitignore
vendored
@ -7,12 +7,13 @@ uploads/big/*
|
||||
uploads/import/*
|
||||
uploads/medium/*
|
||||
uploads/thumb/*
|
||||
plugins/*
|
||||
|
||||
!uploads/big/index.html
|
||||
!uploads/import/index.html
|
||||
!uploads/medium/index.html
|
||||
!uploads/thumb/index.html
|
||||
|
||||
!plugins/check/
|
||||
!plugins/displaylog/
|
||||
plugins/*
|
||||
|
||||
!plugins/Diagnostics/
|
||||
!plugins/Log/
|
@ -9,7 +9,7 @@ Lychee is a free photo-management tool, which runs on your server or web-space.
|
||||
|
||||
## Installation
|
||||
|
||||
To run Lychee, everything you need is a web-server with PHP 5.3 or later and a MySQL-Database. Follow the instructions to install Lychee on your server. [Installation »](docs/Installation.md)
|
||||
To run Lychee, everything you need is a web-server with PHP 5.5 or later and a MySQL-Database. Follow the instructions to install Lychee on your server. [Installation »](docs/Installation.md)
|
||||
|
||||
## How to use
|
||||
|
||||
@ -65,6 +65,7 @@ Here's a list of all available Plugins and Extensions:
|
||||
| lychee-rss | Creates a RSS-Feed out of your photos | [More »](https://github.com/cternes/Lychee-RSS) |
|
||||
| lychee-FlashAir | Import from a Toshiba FlashAir WiFi SD card | [More »](https://github.com/mhp/Lychee-FlashAir) |
|
||||
| lychee-webroot | Controls photos accessibility and keeps Lychee files hidden | [More »](https://github.com/Bramas/lychee-webroot) |
|
||||
| lychee-create-medium | Generate missing medium size photos | [More »](https://github.com/Bramas/lychee-create-medium) |
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
|
BIN
dist/main.css
vendored
BIN
dist/main.css
vendored
Binary file not shown.
BIN
dist/main.js
vendored
Normal file → Executable file
BIN
dist/main.js
vendored
Normal file → Executable file
Binary file not shown.
BIN
dist/view.js
vendored
BIN
dist/view.js
vendored
Binary file not shown.
@ -2,24 +2,20 @@
|
||||
|
||||
First you have to install the following dependencies:
|
||||
|
||||
- `node` [Node.js](http://nodejs.org) v0.10 or later
|
||||
- `node` [Node.js](http://nodejs.org) v5.7.0 or later
|
||||
- `npm` [Node Packaged Modules](https://www.npmjs.org)
|
||||
- `gulp` [Gulp.js](http://gulpjs.com)
|
||||
|
||||
After [installing Node.js](http://nodejs.org) you can use the included `npm` package manager to install the global requirements and Lychee-dependencies with the following command:
|
||||
After [installing Node.js](http://nodejs.org) you can use the included `npm` package manager to download all dependencies:
|
||||
|
||||
cd src/
|
||||
npm install -g gulp
|
||||
npm install
|
||||
|
||||
### Build
|
||||
|
||||
The Gulpfile is located in `src/` and can be easily executed using the `gulp` command.
|
||||
The Gulpfile is located in `src/` and can be executed using the `npm run compile` command.
|
||||
|
||||
### Watch for changes
|
||||
|
||||
While developing, you might want to use the following command to watch for changes:
|
||||
While developing, you might want to use the following command to automatically build Lychee everytime you save a file:
|
||||
|
||||
gulp watch
|
||||
|
||||
`gulp watch` will automatically build Lychee everytime you save a file.
|
||||
npm start
|
@ -1,3 +1,38 @@
|
||||
## v3.1.0
|
||||
|
||||
Released March ??, 2016
|
||||
|
||||
**Warning**: It's no longer possible to update from Lychee versions older than 2.7.
|
||||
|
||||
**Warning**: Plugins which use the plugin API of Lychee must be updated to work with the new back-end.
|
||||
|
||||
**Notice**: It's no longer possible to edit the thumb quality in the database.
|
||||
|
||||
**Notice**: It's no longer possible to disable the creation of medium-sized photos when Imagick is installed on the system.
|
||||
|
||||
This updates includes a huge rewrite of the back-end. We are now using namespaces and the singleton pattern for Settings::get(), Database::get() and Plugins::get(). Everything is way better documented thanks to PHPDoc comments. Ugly `#` comments have been replaced with the more known `//`. Unused functions are gone and returns are more strict. We also added a handy module to output messages. Failed database updates and invalid queries will be saved to the log.
|
||||
|
||||
- `New` Empty titles for albums
|
||||
- `New` Share albums as hidden so they are only viewable with a direct link (#27)
|
||||
- `New` Log failed and successful login attempts (Thanks @qligier, #382 #246)
|
||||
- `Improved` error messages and log output
|
||||
- `Improved` The search shows albums above photos (#434)
|
||||
- `Improved` Album id now based on the current microtime (#27)
|
||||
- `Improved` Back-end modules and plugins
|
||||
- `Improved` Database connect function and update mechanism
|
||||
- `Improved` Default photo title now "Untitled"
|
||||
- `Improved` Move to next photo after after moving a picture (#437)
|
||||
- `Improved` Return to album overview when canceling album password input
|
||||
- `Improved` URL import now accepts photo URLs containing "?" and ":" (Thanks @qligier, #482)
|
||||
- `Improved` Replaced date by strftime to simplify date translations (Thanks @qligier, #461)
|
||||
- `Fixed` Missing icons in Safari 9.1
|
||||
- `Fixed` duplicate uploads (Thanks @qligier, #433)
|
||||
- `Fixed` incorrect escaping when using backslashes
|
||||
- `Fixed` session_start() after sending headers (#433)
|
||||
- `Fixed` error when deleting last open photo in album
|
||||
- `Fixed` Photo sometimes not loading when visiting directly
|
||||
- `Fixed` Move album, merge album and switch album/photo menus no longer show empty titles for untitled albums/photos
|
||||
|
||||
## v3.0.9
|
||||
|
||||
Released January 10, 2016
|
||||
|
@ -1,5 +1,5 @@
|
||||
#### Lychee is not working
|
||||
If Lychee is not working properly, try to open `plugins/check/index.php`. This script will display all errors it can find.
|
||||
If Lychee is not working properly, try to open `plugins/Diagnostics/index.php`. This script will display all errors it can find.
|
||||
|
||||
#### What do I need to run Lychee on my server?
|
||||
To run Lychee, everything you need is a web-server with PHP 5.3 or later and a MySQL-Database.
|
||||
@ -38,7 +38,7 @@ To backup your Lychee installation you need to do the following steps:
|
||||
- INSERT INTO lychee_photos_backup SELECT * FROM lychee_photos;
|
||||
- CREATE TABLE lychee_settings_backup LIKE lychee_settings;
|
||||
- INSERT INTO lychee_settings_backup SELECT * FROM lychee_settings;
|
||||
|
||||
|
||||
#### Can I use my existing folder-structure?
|
||||
No. Lychee has it's own folder-structure and database. Please upload or import all your photos to use them.
|
||||
|
||||
@ -53,3 +53,6 @@ Yes. Lychee uses ImageMagick when available.
|
||||
|
||||
#### Blank screen when viewing a photo using iOS
|
||||
There's a problem with images compressed by ImageOptim. [Read more.](https://github.com/electerious/Lychee/issues/175#issuecomment-47403992)
|
||||
|
||||
#### How to change the title of the site?
|
||||
[#455](https://github.com/electerious/Lychee/issues/455)
|
@ -11,50 +11,47 @@ The plugin-system of Lychee allows you to execute scripts, when a certain action
|
||||
|
||||
### How to create a plugin
|
||||
|
||||
1. Create a folder in `plugins/`
|
||||
2. Create an `index.php` within the new folder and with the following content:
|
||||
1. Create a folder in `plugins/` (e.g. `plugins/ExamplePlugin/`)
|
||||
2. Create an `ExamplePlugin.php` file within the new folder and add the following content:
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
###
|
||||
# @name ExamplePlugin
|
||||
# @author Tobias Reich
|
||||
# @copyright 2015 by Tobias Reich
|
||||
###
|
||||
namespace ExamplePlugin;
|
||||
|
||||
if (!defined('LYCHEE')) exit('Error: Direct access is not allowed!');
|
||||
use SplObserver;
|
||||
use SplSubject;
|
||||
|
||||
class ExamplePlugin implements SplObserver {
|
||||
|
||||
private $database = null;
|
||||
private $settings = null;
|
||||
public function __construct() {
|
||||
|
||||
public function __construct($database, $settings) {
|
||||
|
||||
# These params are passed to your plugin from Lychee
|
||||
# Save them to access the database and settings of Lychee
|
||||
$this->database = $database;
|
||||
$this->settings = $settings;
|
||||
|
||||
# Add more code here if wanted
|
||||
# __construct() will be called every time Lychee gets called
|
||||
# Make sure this part is performant
|
||||
/**
|
||||
* Add code here if wanted
|
||||
* __construct() will be called every time Lychee gets called
|
||||
* Make sure this part is performant
|
||||
*/
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
public function update(\SplSubject $subject) {
|
||||
public function update(SplSubject $subject) {
|
||||
|
||||
/**
|
||||
* Check if the called hook is the hook you are waiting for
|
||||
* A list of all hooks is available online
|
||||
*/
|
||||
|
||||
# Check if the called hook is the hook you are waiting for
|
||||
# A list of all hooks is available online
|
||||
if ($subject->action!=='Photo::add:before') return false;
|
||||
|
||||
# Do something when Photo::add:before gets called
|
||||
# $this->database => The database of Lychee
|
||||
# $this->settings => The settings of Lychee
|
||||
# $subject->args => Params passed to the original function
|
||||
/**
|
||||
* Do something when Photo::add:before gets called
|
||||
* Database::get() => Database connection of Lychee
|
||||
* Settings::get() => Settings of Lychee
|
||||
* $subject->action => Called hook
|
||||
* $subject->args => Params passed to the original function
|
||||
*/
|
||||
|
||||
return true;
|
||||
|
||||
@ -62,15 +59,14 @@ class ExamplePlugin implements SplObserver {
|
||||
|
||||
}
|
||||
|
||||
# Register your plugin
|
||||
$plugins->attach(new ExamplePlugin($database, $settings));
|
||||
?>
|
||||
```
|
||||
|
||||
3. Add the plugin-path to the database of Lychee
|
||||
3. Add the class name to the database of Lychee
|
||||
|
||||
Select the table `lychee_settings` and edit the value of `plugins` to the path of your plugin. The path must be relative from the `plugins/`-folder: `ExamplePlugin/index.php`.
|
||||
Select the table `lychee_settings` and add the [external fully qualified name](http://php.net/manual/en/language.namespaces.importing.php) to the value of `plugins` (e.g. `ExamplePlugin\ExamplePlugin`). Please ensure that the folder has the same name as the namespace and the file the same name as the class.
|
||||
|
||||
Divide multiple plugins with semicolons: `Plugin01/index.php;Plugin02/index.php`.
|
||||
Divide multiple plugins with semicolons: `ExamplePlugin\ExamplePlugin;ExampleTwoPlugin\ExampleTwoPlugin`.
|
||||
|
||||
### Available hooks
|
||||
|
||||
|
@ -22,12 +22,6 @@ All settings are stored in the database. You can change the properties manually,
|
||||
|
||||
Your photos and albums are protected by a username and password. If both rows are empty, Lychee will prompt you to set them.
|
||||
|
||||
#### Thumb Quality
|
||||
|
||||
thumbQuality = [0-100]
|
||||
|
||||
Less means an inferiority quality of your thumbs, but faster loading. More means a better quality of your thumbs, but slower loading. The default value is 90. The allowed values are between 0 and 100.
|
||||
|
||||
#### Check For Updates
|
||||
|
||||
checkForUpdates = [0|1]
|
||||
@ -58,12 +52,6 @@ This key is required to use the Dropbox import feature from your server. Lychee
|
||||
|
||||
If `1`, Lychee will use Imagick when available. Disable [Imagick](http://www.imagemagick.org) if you have problems or if you are using an outdated version. Lychee will use [GD](http://php.net/manual/en/book.image.php) when Imagick is disabled or not available.
|
||||
|
||||
#### Medium
|
||||
|
||||
medium = [0|1]
|
||||
|
||||
If `1`, Lychee will create a second, smaller version of your photo. This feature requires [Imagick](http://www.imagemagick.org) on your server and an activated `imagick` option the the settings table.
|
||||
|
||||
#### Skip Duplicates on Upload
|
||||
|
||||
skipDuplicates = [0|1]
|
||||
|
@ -1,15 +1,20 @@
|
||||
### Update requirements
|
||||
|
||||
- Your system must comply with the latest [system requirements](https://github.com/electerious/Lychee/blob/master/docs/Installation.md) of Lychee.
|
||||
- Ensure that your current version is greater than 2.7.0. Updates from older Lychee versions aren't supported.
|
||||
|
||||
### Update with `git`
|
||||
|
||||
The easiest way to update Lychee is with `git`:
|
||||
Updating Lychee with `git` is the easiest way:
|
||||
|
||||
git pull
|
||||
|
||||
|
||||
### Update manually
|
||||
|
||||
1. Download the [newest Version](https://github.com/electerious/Lychee/archive/master.zip)
|
||||
1. Download the [newest Version](https://github.com/electerious/Lychee/release)
|
||||
2. Replace all existing files, excluding `uploads/` and `data/`
|
||||
3. Open Lychee (and enter your database details)
|
||||
|
||||
### Changelog
|
||||
|
||||
Take a look at the [Changelog](Changelog.md) to see what's new.
|
||||
Take a look at the [Changelog](Changelog.md) to see what's new.
|
17
php/Access/Access.php
Normal file
17
php/Access/Access.php
Normal file
@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace Lychee\Access;
|
||||
|
||||
use Lychee\Modules\Response;
|
||||
|
||||
abstract class Access {
|
||||
|
||||
final protected static function fnNotFound() {
|
||||
|
||||
Response::error('Function not found! Please check the spelling of the called function.');
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
344
php/Access/Admin.php
Normal file
344
php/Access/Admin.php
Normal file
@ -0,0 +1,344 @@
|
||||
<?php
|
||||
|
||||
namespace Lychee\Access;
|
||||
|
||||
use Lychee\Modules\Album;
|
||||
use Lychee\Modules\Albums;
|
||||
use Lychee\Modules\Import;
|
||||
use Lychee\Modules\Photo;
|
||||
use Lychee\Modules\Response;
|
||||
use Lychee\Modules\Session;
|
||||
use Lychee\Modules\Settings;
|
||||
use Lychee\Modules\Validator;
|
||||
|
||||
final class Admin extends Access {
|
||||
|
||||
public static function init($fn) {
|
||||
|
||||
switch ($fn) {
|
||||
|
||||
// Albums functions
|
||||
case 'Albums::get': self::getAlbumsAction(); break;
|
||||
|
||||
// Album functions
|
||||
case 'Album::get': self::getAlbumAction(); break;
|
||||
case 'Album::add': self::addAlbumAction(); break;
|
||||
case 'Album::setTitle': self::setAlbumTitleAction(); break;
|
||||
case 'Album::setDescription': self::setAlbumDescriptionAction(); break;
|
||||
case 'Album::setPublic': self::setAlbumPublicAction(); break;
|
||||
case 'Album::delete': self::deleteAlbumAction(); break;
|
||||
case 'Album::merge': self::mergeAlbumsAction(); break;
|
||||
|
||||
// Photo functions
|
||||
case 'Photo::get': self::getPhotoAction(); break;
|
||||
case 'Photo::setTitle': self::setPhotoTitleAction(); break;
|
||||
case 'Photo::setDescription': self::setPhotoDescriptionAction(); break;
|
||||
case 'Photo::setStar': self::setPhotoStarAction(); break;
|
||||
case 'Photo::setPublic': self::setPhotoPublicAction(); break;
|
||||
case 'Photo::setAlbum': self::setPhotoAlbumAction(); break;
|
||||
case 'Photo::setTags': self::setPhotoTagsAction(); break;
|
||||
case 'Photo::duplicate': self::duplicatePhotoAction(); break;
|
||||
case 'Photo::delete': self::deletePhotoAction(); break;
|
||||
|
||||
// Add functions
|
||||
case 'Photo::add': self::uploadAction(); break;
|
||||
case 'Import::url': self::importUrlAction(); break;
|
||||
case 'Import::server': self::importServerAction(); break;
|
||||
|
||||
// Search functions
|
||||
case 'search': self::searchAction(); break;
|
||||
|
||||
// Session functions
|
||||
case 'Session::init': self::initAction(); break;
|
||||
case 'Session::login': self::loginAction(); break;
|
||||
case 'Session::logout': self::logoutAction(); break;
|
||||
|
||||
// Settings functions
|
||||
case 'Settings::setLogin': self::setLoginAction(); break;
|
||||
case 'Settings::setSorting': self::setSortingAction(); break;
|
||||
case 'Settings::setDropboxKey': self::setDropboxKeyAction(); break;
|
||||
|
||||
// $_GET functions
|
||||
case 'Album::getArchive': self::getAlbumArchiveAction(); break;
|
||||
case 'Photo::getArchive': self::getPhotoArchiveAction(); break;
|
||||
|
||||
}
|
||||
|
||||
self::fnNotFound();
|
||||
|
||||
}
|
||||
|
||||
// Albums functions
|
||||
|
||||
private static function getAlbumsAction() {
|
||||
|
||||
$albums = new Albums();
|
||||
Response::json($albums->get(false));
|
||||
|
||||
}
|
||||
|
||||
// Album functions
|
||||
|
||||
private static function getAlbumAction() {
|
||||
|
||||
Validator::required(isset($_POST['albumID']), __METHOD__);
|
||||
|
||||
$album = new Album($_POST['albumID']);
|
||||
Response::json($album->get());
|
||||
|
||||
}
|
||||
|
||||
private static function addAlbumAction() {
|
||||
|
||||
Validator::required(isset($_POST['title']), __METHOD__);
|
||||
|
||||
$album = new Album(null);
|
||||
Response::json($album->add($_POST['title']), JSON_NUMERIC_CHECK);
|
||||
|
||||
}
|
||||
|
||||
private static function setAlbumTitleAction() {
|
||||
|
||||
Validator::required(isset($_POST['albumIDs'], $_POST['title']), __METHOD__);
|
||||
|
||||
$album = new Album($_POST['albumIDs']);
|
||||
Response::json($album->setTitle($_POST['title']));
|
||||
|
||||
}
|
||||
|
||||
private static function setAlbumDescriptionAction() {
|
||||
|
||||
Validator::required(isset($_POST['albumID'], $_POST['description']), __METHOD__);
|
||||
|
||||
$album = new Album($_POST['albumID']);
|
||||
Response::json($album->setDescription($_POST['description']));
|
||||
|
||||
}
|
||||
|
||||
private static function setAlbumPublicAction() {
|
||||
|
||||
Validator::required(isset($_POST['albumID'], $_POST['password'], $_POST['visible'], $_POST['downloadable']), __METHOD__);
|
||||
|
||||
$album = new Album($_POST['albumID']);
|
||||
Response::json($album->setPublic($_POST['public'], $_POST['password'], $_POST['visible'], $_POST['downloadable']));
|
||||
|
||||
}
|
||||
|
||||
private static function deleteAlbumAction() {
|
||||
|
||||
Validator::required(isset($_POST['albumIDs']), __METHOD__);
|
||||
|
||||
$album = new Album($_POST['albumIDs']);
|
||||
Response::json($album->delete());
|
||||
|
||||
}
|
||||
|
||||
private static function mergeAlbumsAction() {
|
||||
|
||||
Validator::required(isset($_POST['albumIDs']), __METHOD__);
|
||||
$album = new Album($_POST['albumIDs']);
|
||||
Response::json($album->merge());
|
||||
|
||||
}
|
||||
|
||||
// Photo functions
|
||||
|
||||
private static function getPhotoAction() {
|
||||
|
||||
Validator::required(isset($_POST['photoID'], $_POST['albumID']), __METHOD__);
|
||||
|
||||
$photo = new Photo($_POST['photoID']);
|
||||
Response::json($photo->get($_POST['albumID']));
|
||||
|
||||
}
|
||||
|
||||
private static function setPhotoTitleAction() {
|
||||
|
||||
Validator::required(isset($_POST['photoIDs'], $_POST['title']), __METHOD__);
|
||||
|
||||
$photo = new Photo($_POST['photoIDs']);
|
||||
Response::json($photo->setTitle($_POST['title']));
|
||||
|
||||
}
|
||||
|
||||
private static function setPhotoDescriptionAction() {
|
||||
|
||||
Validator::required(isset($_POST['photoID'], $_POST['description']), __METHOD__);
|
||||
|
||||
$photo = new Photo($_POST['photoID']);
|
||||
Response::json($photo->setDescription($_POST['description']));
|
||||
|
||||
}
|
||||
|
||||
private static function setPhotoStarAction() {
|
||||
|
||||
Validator::required(isset($_POST['photoIDs']), __METHOD__);
|
||||
|
||||
$photo = new Photo($_POST['photoIDs']);
|
||||
Response::json($photo->setStar());
|
||||
|
||||
}
|
||||
|
||||
private static function setPhotoPublicAction() {
|
||||
|
||||
Validator::required(isset($_POST['photoID']), __METHOD__);
|
||||
|
||||
$photo = new Photo($_POST['photoID']);
|
||||
Response::json($photo->setPublic());
|
||||
|
||||
}
|
||||
|
||||
private static function setPhotoAlbumAction() {
|
||||
|
||||
Validator::required(isset($_POST['photoIDs'], $_POST['albumID']), __METHOD__);
|
||||
|
||||
$photo = new Photo($_POST['photoIDs']);
|
||||
Response::json($photo->setAlbum($_POST['albumID']));
|
||||
|
||||
}
|
||||
|
||||
private static function setPhotoTagsAction() {
|
||||
|
||||
Validator::required(isset($_POST['photoIDs'], $_POST['tags']), __METHOD__);
|
||||
|
||||
$photo = new Photo($_POST['photoIDs']);
|
||||
Response::json($photo->setTags($_POST['tags']));
|
||||
|
||||
}
|
||||
|
||||
private static function duplicatePhotoAction() {
|
||||
|
||||
Validator::required(isset($_POST['photoIDs']), __METHOD__);
|
||||
|
||||
$photo = new Photo($_POST['photoIDs']);
|
||||
Response::json($photo->duplicate());
|
||||
|
||||
}
|
||||
|
||||
private static function deletePhotoAction() {
|
||||
|
||||
Validator::required(isset($_POST['photoIDs']), __METHOD__);
|
||||
|
||||
$photo = new Photo($_POST['photoIDs']);
|
||||
Response::json($photo->delete());
|
||||
|
||||
}
|
||||
|
||||
// Add functions
|
||||
|
||||
private static function uploadAction() {
|
||||
|
||||
Validator::required(isset($_FILES, $_POST['albumID']), __METHOD__);
|
||||
|
||||
$photo = new Photo(null);
|
||||
Response::json($photo->add($_FILES, $_POST['albumID']), JSON_NUMERIC_CHECK);
|
||||
|
||||
}
|
||||
|
||||
private static function importUrlAction() {
|
||||
|
||||
Validator::required(isset($_POST['url'], $_POST['albumID']), __METHOD__);
|
||||
|
||||
$import = new Import();
|
||||
Response::json($import->url($_POST['url'], $_POST['albumID']));
|
||||
|
||||
}
|
||||
|
||||
private static function importServerAction() {
|
||||
|
||||
Validator::required(isset($_POST['albumID'], $_POST['path']), __METHOD__);
|
||||
|
||||
$import = new Import();
|
||||
Response::json($import->server($_POST['path'], $_POST['albumID']));
|
||||
|
||||
}
|
||||
|
||||
// Search functions
|
||||
|
||||
private static function searchAction() {
|
||||
|
||||
Validator::required(isset($_POST['term']), __METHOD__);
|
||||
|
||||
Response::json(search($_POST['term']));
|
||||
|
||||
}
|
||||
|
||||
// Session functions
|
||||
|
||||
private static function initAction() {
|
||||
|
||||
$session = new Session();
|
||||
Response::json($session->init(false));
|
||||
|
||||
}
|
||||
|
||||
private static function loginAction() {
|
||||
|
||||
Validator::required(isset($_POST['user'], $_POST['password']), __METHOD__);
|
||||
|
||||
$session = new Session();
|
||||
Response::json($session->login($_POST['user'], $_POST['password']));
|
||||
|
||||
}
|
||||
|
||||
private static function logoutAction() {
|
||||
|
||||
$session = new Session();
|
||||
Response::json($session->logout());
|
||||
|
||||
}
|
||||
|
||||
// Settings functions
|
||||
|
||||
private static function setLoginAction() {
|
||||
|
||||
Validator::required(isset($_POST['username'], $_POST['password']), __METHOD__);
|
||||
|
||||
if (isset($_POST['oldPassword'])===false) $_POST['oldPassword'] = '';
|
||||
Response::json(Settings::setLogin($_POST['oldPassword'], $_POST['username'], $_POST['password']));
|
||||
|
||||
}
|
||||
|
||||
private static function setSortingAction() {
|
||||
|
||||
Validator::required(isset($_POST['typeAlbums'], $_POST['orderAlbums'], $_POST['typePhotos'], $_POST['orderPhotos']), __METHOD__);
|
||||
|
||||
$sA = Settings::setSortingAlbums($_POST['typeAlbums'], $_POST['orderAlbums']);
|
||||
$sP = Settings::setSortingPhotos($_POST['typePhotos'], $_POST['orderPhotos']);
|
||||
|
||||
if ($sA===true&&$sP===true) Response::json(true);
|
||||
else Response::json(false);
|
||||
|
||||
}
|
||||
|
||||
private static function setDropboxKeyAction() {
|
||||
|
||||
Validator::required(isset($_POST['key']), __METHOD__);
|
||||
|
||||
Response::json(Settings::setDropboxKey($_POST['key']));
|
||||
|
||||
}
|
||||
|
||||
// Get functions
|
||||
|
||||
private static function getAlbumArchiveAction() {
|
||||
|
||||
Validator::required(isset($_GET['albumID']), __METHOD__);
|
||||
|
||||
$album = new Album($_GET['albumID']);
|
||||
$album->getArchive();
|
||||
|
||||
}
|
||||
|
||||
private static function getPhotoArchiveAction() {
|
||||
|
||||
Validator::required(isset($_GET['photoID']), __METHOD__);
|
||||
|
||||
$photo = new Photo($_GET['photoID']);
|
||||
$photo->getArchive();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
185
php/Access/Guest.php
Normal file
185
php/Access/Guest.php
Normal file
@ -0,0 +1,185 @@
|
||||
<?php
|
||||
|
||||
namespace Lychee\Access;
|
||||
|
||||
use Lychee\Modules\Album;
|
||||
use Lychee\Modules\Albums;
|
||||
use Lychee\Modules\Photo;
|
||||
use Lychee\Modules\Response;
|
||||
use Lychee\Modules\Session;
|
||||
use Lychee\Modules\Validator;
|
||||
|
||||
final class Guest extends Access {
|
||||
|
||||
public static function init($fn) {
|
||||
|
||||
switch ($fn) {
|
||||
|
||||
// Albums functions
|
||||
case 'Albums::get': self::getAlbumsAction(); break;
|
||||
|
||||
// Album functions
|
||||
case 'Album::get': self::getAlbumAction(); break;
|
||||
case 'Album::getPublic': self::checkAlbumAccessAction(); break;
|
||||
|
||||
// Photo functions
|
||||
case 'Photo::get': self::getPhotoAction(); break;
|
||||
|
||||
// Session functions
|
||||
case 'Session::init': self::initAction(); break;
|
||||
case 'Session::login': self::loginAction(); break;
|
||||
case 'Session::logout': self::logoutAction(); break;
|
||||
|
||||
// $_GET functions
|
||||
case 'Album::getArchive': self::getAlbumArchiveAction(); break;
|
||||
case 'Photo::getArchive': self::getPhotoArchiveAction(); break;
|
||||
|
||||
}
|
||||
|
||||
self::fnNotFound();
|
||||
|
||||
}
|
||||
|
||||
// Albums functions
|
||||
|
||||
private static function getAlbumsAction() {
|
||||
|
||||
$albums = new Albums();
|
||||
Response::json($albums->get(true));
|
||||
|
||||
}
|
||||
|
||||
// Album functions
|
||||
|
||||
private static function getAlbumAction() {
|
||||
|
||||
Validator::required(isset($_POST['albumID'], $_POST['password']), __METHOD__);
|
||||
|
||||
$album = new Album($_POST['albumID']);
|
||||
|
||||
if ($album->getPublic()===true) {
|
||||
|
||||
// Album public
|
||||
if ($album->checkPassword($_POST['password'])===true) Response::json($album->get());
|
||||
else Response::warning('Wrong password!');
|
||||
|
||||
} else {
|
||||
|
||||
// Album private
|
||||
Response::warning('Album private!');
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static function checkAlbumAccessAction() {
|
||||
|
||||
Validator::required(isset($_POST['albumID'], $_POST['password']), __METHOD__);
|
||||
|
||||
$album = new Album($_POST['albumID']);
|
||||
|
||||
if ($album->getPublic()===true) {
|
||||
|
||||
// Album public
|
||||
if ($album->checkPassword($_POST['password'])===true) Response::json(true);
|
||||
else Response::json(false);
|
||||
|
||||
} else {
|
||||
|
||||
// Album private
|
||||
Response::json(false);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Photo functions
|
||||
|
||||
private static function getPhotoAction() {
|
||||
|
||||
Validator::required(isset($_POST['photoID'], $_POST['albumID'], $_POST['password']), __METHOD__);
|
||||
|
||||
$photo = new Photo($_POST['photoID']);
|
||||
|
||||
$pgP = $photo->getPublic($_POST['password']);
|
||||
|
||||
if ($pgP===2) Response::json($photo->get($_POST['albumID']));
|
||||
else if ($pgP===1) Response::warning('Wrong password!');
|
||||
else if ($pgP===0) Response::warning('Photo private!');
|
||||
|
||||
}
|
||||
|
||||
// Session functions
|
||||
|
||||
private static function initAction() {
|
||||
|
||||
$session = new Session();
|
||||
Response::json($session->init(true));
|
||||
|
||||
}
|
||||
|
||||
private static function loginAction() {
|
||||
|
||||
Validator::required(isset($_POST['user'], $_POST['password']), __METHOD__);
|
||||
|
||||
$session = new Session();
|
||||
Response::json($session->login($_POST['user'], $_POST['password']));
|
||||
|
||||
}
|
||||
|
||||
private static function logoutAction() {
|
||||
|
||||
$session = new Session();
|
||||
Response::json($session->logout());
|
||||
|
||||
}
|
||||
|
||||
// $_GET functions
|
||||
|
||||
private static function getAlbumArchiveAction() {
|
||||
|
||||
Validator::required(isset($_GET['albumID'], $_GET['password']), __METHOD__);
|
||||
|
||||
$album = new Album($_GET['albumID']);
|
||||
|
||||
if ($album->getPublic()&&$album->getDownloadable()) {
|
||||
|
||||
// Album Public
|
||||
if ($album->checkPassword($_GET['password'])) $album->getArchive();
|
||||
else Response::warning('Wrong password!');
|
||||
|
||||
} else {
|
||||
|
||||
// Album Private
|
||||
Response::warning('Album private or not downloadable!');
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static function getPhotoArchiveAction() {
|
||||
|
||||
Validator::required(isset($_GET['photoID'], $_GET['password']), __METHOD__);
|
||||
|
||||
$photo = new Photo($_GET['photoID']);
|
||||
|
||||
$pgP = $photo->getPublic($_GET['password']);
|
||||
|
||||
// Photo Download
|
||||
if ($pgP===2) {
|
||||
|
||||
// Photo Public
|
||||
$photo->getArchive();
|
||||
|
||||
} else {
|
||||
|
||||
// Photo Private
|
||||
Response::warning('Photo private or password incorrect!');
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
45
php/Access/Installation.php
Normal file
45
php/Access/Installation.php
Normal file
@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
namespace Lychee\Access;
|
||||
|
||||
use Lychee\Modules\Config;
|
||||
use Lychee\Modules\Response;
|
||||
use Lychee\Modules\Validator;
|
||||
|
||||
final class Installation extends Access {
|
||||
|
||||
public static function init($fn) {
|
||||
|
||||
switch ($fn) {
|
||||
|
||||
case 'Config::create': self::configCreateAction(); break;
|
||||
|
||||
default: self::initAction(); break;
|
||||
|
||||
}
|
||||
|
||||
self::fnNotFound();
|
||||
|
||||
}
|
||||
|
||||
private static function configCreateAction() {
|
||||
|
||||
Validator::required(isset($_POST['dbHost'], $_POST['dbUser'], $_POST['dbPassword'], $_POST['dbName'], $_POST['dbTablePrefix']), __METHOD__);
|
||||
|
||||
Response::json(Config::create($_POST['dbHost'], $_POST['dbUser'], $_POST['dbPassword'], $_POST['dbName'], $_POST['dbTablePrefix']));
|
||||
|
||||
}
|
||||
|
||||
private static function initAction() {
|
||||
|
||||
$return = array(
|
||||
'status' => LYCHEE_STATUS_NOCONFIG
|
||||
);
|
||||
|
||||
Response::json($return);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
647
php/Modules/Album.php
Normal file
647
php/Modules/Album.php
Normal file
@ -0,0 +1,647 @@
|
||||
<?php
|
||||
|
||||
namespace Lychee\Modules;
|
||||
|
||||
use ZipArchive;
|
||||
|
||||
final class Album {
|
||||
|
||||
private $albumIDs = null;
|
||||
|
||||
/**
|
||||
* @return boolean Returns true when successful.
|
||||
*/
|
||||
public function __construct($albumIDs) {
|
||||
|
||||
// Init vars
|
||||
$this->albumIDs = $albumIDs;
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|false ID of the created album.
|
||||
*/
|
||||
public function add($title = 'Untitled') {
|
||||
|
||||
// Call plugins
|
||||
Plugins::get()->activate(__METHOD__, 0, func_get_args());
|
||||
|
||||
// Properties
|
||||
$id = generateID();
|
||||
$sysstamp = time();
|
||||
$public = 0;
|
||||
$visible = 1;
|
||||
|
||||
// Database
|
||||
$query = Database::prepare(Database::get(), "INSERT INTO ? (id, title, sysstamp, public, visible) VALUES ('?', '?', '?', '?', '?')", array(LYCHEE_TABLE_ALBUMS, $id, $title, $sysstamp, $public, $visible));
|
||||
$result = Database::execute(Database::get(), $query, __METHOD__, __LINE__);
|
||||
|
||||
// Call plugins
|
||||
Plugins::get()->activate(__METHOD__, 1, func_get_args());
|
||||
|
||||
if ($result===false) return false;
|
||||
return $id;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Rurns album-attributes into a front-end friendly format. Note that some attributes remain unchanged.
|
||||
* @return array Returns album-attributes in a normalized structure.
|
||||
*/
|
||||
public static function prepareData(array $data) {
|
||||
|
||||
// This function requires the following album-attributes and turns them
|
||||
// into a front-end friendly format: id, title, public, sysstamp, password
|
||||
// Note that some attributes remain unchanged
|
||||
|
||||
// Init
|
||||
$album = null;
|
||||
|
||||
// Set unchanged attributes
|
||||
$album['id'] = $data['id'];
|
||||
$album['title'] = $data['title'];
|
||||
$album['public'] = $data['public'];
|
||||
|
||||
// Additional attributes
|
||||
// Only part of $album when available
|
||||
if (isset($data['description'])) $album['description'] = $data['description'];
|
||||
if (isset($data['visible'])) $album['visible'] = $data['visible'];
|
||||
if (isset($data['downloadable'])) $album['downloadable'] = $data['downloadable'];
|
||||
|
||||
// Parse date
|
||||
$album['sysdate'] = strftime('%B %Y', $data['sysstamp']);
|
||||
|
||||
// Parse password
|
||||
$album['password'] = ($data['password']=='' ? '0' : '1');
|
||||
|
||||
// Parse thumbs or set default value
|
||||
$album['thumbs'] = (isset($data['thumbs']) ? explode(',', $data['thumbs']) : array());
|
||||
|
||||
return $album;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array|false Returns an array of photos and album information or false on failure.
|
||||
*/
|
||||
public function get() {
|
||||
|
||||
// Check dependencies
|
||||
Validator::required(isset($this->albumIDs), __METHOD__);
|
||||
|
||||
// Call plugins
|
||||
Plugins::get()->activate(__METHOD__, 0, func_get_args());
|
||||
|
||||
// Get album information
|
||||
switch ($this->albumIDs) {
|
||||
|
||||
case 'f':
|
||||
$return['public'] = '0';
|
||||
$query = Database::prepare(Database::get(), "SELECT id, title, tags, public, star, album, thumbUrl, takestamp, url FROM ? WHERE star = 1 " . Settings::get()['sortingPhotos'], array(LYCHEE_TABLE_PHOTOS));
|
||||
break;
|
||||
|
||||
case 's':
|
||||
$return['public'] = '0';
|
||||
$query = Database::prepare(Database::get(), "SELECT id, title, tags, public, star, album, thumbUrl, takestamp, url FROM ? WHERE public = 1 " . Settings::get()['sortingPhotos'], array(LYCHEE_TABLE_PHOTOS));
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
$return['public'] = '0';
|
||||
$query = Database::prepare(Database::get(), "SELECT id, title, tags, public, star, album, thumbUrl, takestamp, url FROM ? WHERE LEFT(id, 10) >= unix_timestamp(DATE_SUB(NOW(), INTERVAL 1 DAY)) " . Settings::get()['sortingPhotos'], array(LYCHEE_TABLE_PHOTOS));
|
||||
break;
|
||||
|
||||
case '0':
|
||||
$return['public'] = '0';
|
||||
$query = Database::prepare(Database::get(), "SELECT id, title, tags, public, star, album, thumbUrl, takestamp, url FROM ? WHERE album = 0 " . Settings::get()['sortingPhotos'], array(LYCHEE_TABLE_PHOTOS));
|
||||
break;
|
||||
|
||||
default:
|
||||
$query = Database::prepare(Database::get(), "SELECT * FROM ? WHERE id = '?' LIMIT 1", array(LYCHEE_TABLE_ALBUMS, $this->albumIDs));
|
||||
$albums = Database::execute(Database::get(), $query, __METHOD__, __LINE__);
|
||||
$return = $albums->fetch_assoc();
|
||||
$return = Album::prepareData($return);
|
||||
$query = Database::prepare(Database::get(), "SELECT id, title, tags, public, star, album, thumbUrl, takestamp, url FROM ? WHERE album = '?' " . Settings::get()['sortingPhotos'], array(LYCHEE_TABLE_PHOTOS, $this->albumIDs));
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
// Get photos
|
||||
$photos = Database::execute(Database::get(), $query, __METHOD__, __LINE__);
|
||||
$previousPhotoID = '';
|
||||
|
||||
if ($photos===false) return false;
|
||||
|
||||
while ($photo = $photos->fetch_assoc()) {
|
||||
|
||||
// Turn data from the database into a front-end friendly format
|
||||
$photo = Photo::prepareData($photo);
|
||||
|
||||
// Set previous and next photoID for navigation purposes
|
||||
$photo['previousPhoto'] = $previousPhotoID;
|
||||
$photo['nextPhoto'] = '';
|
||||
|
||||
// Set current photoID as nextPhoto of previous photo
|
||||
if ($previousPhotoID!=='') $return['content'][$previousPhotoID]['nextPhoto'] = $photo['id'];
|
||||
$previousPhotoID = $photo['id'];
|
||||
|
||||
// Add to return
|
||||
$return['content'][$photo['id']] = $photo;
|
||||
|
||||
}
|
||||
|
||||
if ($photos->num_rows===0) {
|
||||
|
||||
// Album empty
|
||||
$return['content'] = false;
|
||||
|
||||
} else {
|
||||
|
||||
// Enable next and previous for the first and last photo
|
||||
$lastElement = end($return['content']);
|
||||
$lastElementId = $lastElement['id'];
|
||||
$firstElement = reset($return['content']);
|
||||
$firstElementId = $firstElement['id'];
|
||||
|
||||
if ($lastElementId!==$firstElementId) {
|
||||
$return['content'][$lastElementId]['nextPhoto'] = $firstElementId;
|
||||
$return['content'][$firstElementId]['previousPhoto'] = $lastElementId;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$return['id'] = $this->albumIDs;
|
||||
$return['num'] = $photos->num_rows;
|
||||
|
||||
// Call plugins
|
||||
Plugins::get()->activate(__METHOD__, 1, func_get_args());
|
||||
|
||||
return $return;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts a download of an album.
|
||||
* @return resource|boolean Sends a ZIP-file or returns false on failure.
|
||||
*/
|
||||
public function getArchive() {
|
||||
|
||||
// Check dependencies
|
||||
Validator::required(isset($this->albumIDs), __METHOD__);
|
||||
|
||||
// Call plugins
|
||||
Plugins::get()->activate(__METHOD__, 0, func_get_args());
|
||||
|
||||
// Illicit chars
|
||||
$badChars = array_merge(
|
||||
array_map('chr', range(0,31)),
|
||||
array("<", ">", ":", '"', "/", "\\", "|", "?", "*")
|
||||
);
|
||||
|
||||
// Photos query
|
||||
switch($this->albumIDs) {
|
||||
case 's':
|
||||
$photos = Database::prepare(Database::get(), 'SELECT title, url FROM ? WHERE public = 1', array(LYCHEE_TABLE_PHOTOS));
|
||||
$zipTitle = 'Public';
|
||||
break;
|
||||
case 'f':
|
||||
$photos = Database::prepare(Database::get(), 'SELECT title, url FROM ? WHERE star = 1', array(LYCHEE_TABLE_PHOTOS));
|
||||
$zipTitle = 'Starred';
|
||||
break;
|
||||
case 'r':
|
||||
$photos = Database::prepare(Database::get(), 'SELECT title, url FROM ? WHERE LEFT(id, 10) >= unix_timestamp(DATE_SUB(NOW(), INTERVAL 1 DAY)) GROUP BY checksum', array(LYCHEE_TABLE_PHOTOS));
|
||||
$zipTitle = 'Recent';
|
||||
break;
|
||||
default:
|
||||
$photos = Database::prepare(Database::get(), "SELECT title, url FROM ? WHERE album = '?'", array(LYCHEE_TABLE_PHOTOS, $this->albumIDs));
|
||||
$zipTitle = 'Unsorted';
|
||||
}
|
||||
|
||||
// Get title from database when album is not a SmartAlbum
|
||||
if ($this->albumIDs!=0&&is_numeric($this->albumIDs)) {
|
||||
|
||||
$query = Database::prepare(Database::get(), "SELECT title FROM ? WHERE id = '?' LIMIT 1", array(LYCHEE_TABLE_ALBUMS, $this->albumIDs));
|
||||
$album = Database::execute(Database::get(), $query, __METHOD__, __LINE__);
|
||||
|
||||
if ($album===false) return false;
|
||||
|
||||
// Get album object
|
||||
$album = $album->fetch_object();
|
||||
|
||||
// Album not found?
|
||||
if ($album===null) {
|
||||
Log::error(Database::get(), __METHOD__, __LINE__, 'Could not find specified album');
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set title
|
||||
$zipTitle = $album->title;
|
||||
|
||||
}
|
||||
|
||||
// Escape title
|
||||
$zipTitle = str_replace($badChars, '', $zipTitle);
|
||||
|
||||
$filename = LYCHEE_DATA . $zipTitle . '.zip';
|
||||
|
||||
// Create zip
|
||||
$zip = new ZipArchive();
|
||||
if ($zip->open($filename, ZIPARCHIVE::CREATE)!==TRUE) {
|
||||
Log::error(Database::get(), __METHOD__, __LINE__, 'Could not create ZipArchive');
|
||||
return false;
|
||||
}
|
||||
|
||||
// Execute query
|
||||
$photos = Database::execute(Database::get(), $photos, __METHOD__, __LINE__);
|
||||
|
||||
if ($album===null) return false;
|
||||
|
||||
// Check if album empty
|
||||
if ($photos->num_rows==0) {
|
||||
Log::error(Database::get(), __METHOD__, __LINE__, 'Could not create ZipArchive without images');
|
||||
return false;
|
||||
}
|
||||
|
||||
// Parse each path
|
||||
$files = array();
|
||||
while ($photo = $photos->fetch_object()) {
|
||||
|
||||
// Parse url
|
||||
$photo->url = LYCHEE_UPLOADS_BIG . $photo->url;
|
||||
|
||||
// Parse title
|
||||
$photo->title = str_replace($badChars, '', $photo->title);
|
||||
if (!isset($photo->title)||$photo->title==='') $photo->title = 'Untitled';
|
||||
|
||||
// Check if readable
|
||||
if (!@is_readable($photo->url)) continue;
|
||||
|
||||
// Get extension of image
|
||||
$extension = getExtension($photo->url, false);
|
||||
|
||||
// Set title for photo
|
||||
$zipFileName = $zipTitle . '/' . $photo->title . $extension;
|
||||
|
||||
// Check for duplicates
|
||||
if (!empty($files)) {
|
||||
$i = 1;
|
||||
while (in_array($zipFileName, $files)) {
|
||||
|
||||
// Set new title for photo
|
||||
$zipFileName = $zipTitle . '/' . $photo->title . '-' . $i . $extension;
|
||||
|
||||
$i++;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Add to array
|
||||
$files[] = $zipFileName;
|
||||
|
||||
// Add photo to zip
|
||||
$zip->addFile($photo->url, $zipFileName);
|
||||
|
||||
}
|
||||
|
||||
// Finish zip
|
||||
$zip->close();
|
||||
|
||||
// Send zip
|
||||
header("Content-Type: application/zip");
|
||||
header("Content-Disposition: attachment; filename=\"$zipTitle.zip\"");
|
||||
header("Content-Length: " . filesize($filename));
|
||||
readfile($filename);
|
||||
|
||||
// Delete zip
|
||||
unlink($filename);
|
||||
|
||||
// Call plugins
|
||||
Plugins::get()->activate(__METHOD__, 1, func_get_args());
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return boolean Returns true when successful.
|
||||
*/
|
||||
public function setTitle($title = 'Untitled') {
|
||||
|
||||
// Check dependencies
|
||||
Validator::required(isset($this->albumIDs), __METHOD__);
|
||||
|
||||
// Call plugins
|
||||
Plugins::get()->activate(__METHOD__, 0, func_get_args());
|
||||
|
||||
// Execute query
|
||||
$query = Database::prepare(Database::get(), "UPDATE ? SET title = '?' WHERE id IN (?)", array(LYCHEE_TABLE_ALBUMS, $title, $this->albumIDs));
|
||||
$result = Database::execute(Database::get(), $query, __METHOD__, __LINE__);
|
||||
|
||||
// Call plugins
|
||||
Plugins::get()->activate(__METHOD__, 1, func_get_args());
|
||||
|
||||
if ($result===false) return false;
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return boolean Returns true when successful.
|
||||
*/
|
||||
public function setDescription($description = '') {
|
||||
|
||||
// Check dependencies
|
||||
Validator::required(isset($this->albumIDs), __METHOD__);
|
||||
|
||||
// Call plugins
|
||||
Plugins::get()->activate(__METHOD__, 0, func_get_args());
|
||||
|
||||
// Execute query
|
||||
$query = Database::prepare(Database::get(), "UPDATE ? SET description = '?' WHERE id IN (?)", array(LYCHEE_TABLE_ALBUMS, $description, $this->albumIDs));
|
||||
$result = Database::execute(Database::get(), $query, __METHOD__, __LINE__);
|
||||
|
||||
// Call plugins
|
||||
Plugins::get()->activate(__METHOD__, 1, func_get_args());
|
||||
|
||||
if ($result===false) return false;
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return boolean Returns true when the album is public.
|
||||
*/
|
||||
public function getPublic() {
|
||||
|
||||
// Check dependencies
|
||||
Validator::required(isset($this->albumIDs), __METHOD__);
|
||||
|
||||
// Call plugins
|
||||
Plugins::get()->activate(__METHOD__, 0, func_get_args());
|
||||
|
||||
if ($this->albumIDs==='0'||$this->albumIDs==='s'||$this->albumIDs==='f') return false;
|
||||
|
||||
// Execute query
|
||||
$query = Database::prepare(Database::get(), "SELECT public FROM ? WHERE id = '?' LIMIT 1", array(LYCHEE_TABLE_ALBUMS, $this->albumIDs));
|
||||
$albums = Database::execute(Database::get(), $query, __METHOD__, __LINE__);
|
||||
|
||||
if ($albums===false) return false;
|
||||
|
||||
// Get album object
|
||||
$album = $albums->fetch_object();
|
||||
|
||||
// Album not found?
|
||||
if ($album===null) {
|
||||
Log::error(Database::get(), __METHOD__, __LINE__, 'Could not find specified album');
|
||||
return false;
|
||||
}
|
||||
|
||||
// Call plugins
|
||||
Plugins::get()->activate(__METHOD__, 1, func_get_args());
|
||||
|
||||
if ($album->public==1) return true;
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return boolean Returns true when the album is downloadable.
|
||||
*/
|
||||
public function getDownloadable() {
|
||||
|
||||
// Check dependencies
|
||||
Validator::required(isset($this->albumIDs), __METHOD__);
|
||||
|
||||
// Call plugins
|
||||
Plugins::get()->activate(__METHOD__, 0, func_get_args());
|
||||
|
||||
if ($this->albumIDs==='0'||$this->albumIDs==='s'||$this->albumIDs==='f'||$this->albumIDs==='r') return false;
|
||||
|
||||
// Execute query
|
||||
$query = Database::prepare(Database::get(), "SELECT downloadable FROM ? WHERE id = '?' LIMIT 1", array(LYCHEE_TABLE_ALBUMS, $this->albumIDs));
|
||||
$albums = Database::execute(Database::get(), $query, __METHOD__, __LINE__);
|
||||
|
||||
if ($albums===false) return false;
|
||||
|
||||
// Get album object
|
||||
$album = $albums->fetch_object();
|
||||
|
||||
// Album not found?
|
||||
if ($album===null) {
|
||||
Log::error(Database::get(), __METHOD__, __LINE__, 'Could not find specified album');
|
||||
return false;
|
||||
}
|
||||
|
||||
// Call plugins
|
||||
Plugins::get()->activate(__METHOD__, 1, func_get_args());
|
||||
|
||||
if ($album->downloadable==1) return true;
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return boolean Returns true when successful.
|
||||
*/
|
||||
public function setPublic($public, $password, $visible, $downloadable) {
|
||||
|
||||
// Check dependencies
|
||||
Validator::required(isset($this->albumIDs), __METHOD__);
|
||||
|
||||
// Call plugins
|
||||
Plugins::get()->activate(__METHOD__, 0, func_get_args());
|
||||
|
||||
// Convert values
|
||||
$public = ($public==='1' ? 1 : 0);
|
||||
$visible = ($visible==='1' ? 1 : 0);
|
||||
$downloadable = ($downloadable==='1' ? 1 : 0);
|
||||
|
||||
// Set public
|
||||
$query = Database::prepare(Database::get(), "UPDATE ? SET public = '?', visible = '?', downloadable = '?', password = NULL WHERE id IN (?)", array(LYCHEE_TABLE_ALBUMS, $public, $visible, $downloadable, $this->albumIDs));
|
||||
$result = Database::execute(Database::get(), $query, __METHOD__, __LINE__);
|
||||
|
||||
if ($result===false) return false;
|
||||
|
||||
// Reset permissions for photos
|
||||
if ($public===1) {
|
||||
|
||||
$query = Database::prepare(Database::get(), "UPDATE ? SET public = 0 WHERE album IN (?)", array(LYCHEE_TABLE_PHOTOS, $this->albumIDs));
|
||||
$result = Database::execute(Database::get(), $query, __METHOD__, __LINE__);
|
||||
|
||||
if ($result===false) return false;
|
||||
|
||||
}
|
||||
|
||||
// Call plugins
|
||||
Plugins::get()->activate(__METHOD__, 1, func_get_args());
|
||||
|
||||
// Set password
|
||||
if (isset($password)&&strlen($password)>0) return $this->setPassword($password);
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return boolean Returns true when successful.
|
||||
*/
|
||||
private function setPassword($password) {
|
||||
|
||||
// Check dependencies
|
||||
Validator::required(isset($this->albumIDs), __METHOD__);
|
||||
|
||||
// Call plugins
|
||||
Plugins::get()->activate(__METHOD__, 0, func_get_args());
|
||||
|
||||
if (strlen($password)>0) {
|
||||
|
||||
// Get hashed password
|
||||
$password = getHashedString($password);
|
||||
|
||||
// Set hashed password
|
||||
// Do not prepare $password because it is hashed and save
|
||||
// Preparing (escaping) the password would destroy the hash
|
||||
$query = Database::prepare(Database::get(), "UPDATE ? SET password = '$password' WHERE id IN (?)", array(LYCHEE_TABLE_ALBUMS, $this->albumIDs));
|
||||
|
||||
} else {
|
||||
|
||||
// Unset password
|
||||
$query = Database::prepare(Database::get(), "UPDATE ? SET password = NULL WHERE id IN (?)", array(LYCHEE_TABLE_ALBUMS, $this->albumIDs));
|
||||
|
||||
}
|
||||
|
||||
// Execute query
|
||||
$result = Database::execute(Database::get(), $query, __METHOD__, __LINE__);
|
||||
|
||||
// Call plugins
|
||||
Plugins::get()->activate(__METHOD__, 1, func_get_args());
|
||||
|
||||
if ($result===false) return false;
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return boolean Returns when album is public.
|
||||
*/
|
||||
public function checkPassword($password) {
|
||||
|
||||
// Check dependencies
|
||||
Validator::required(isset($this->albumIDs), __METHOD__);
|
||||
|
||||
// Call plugins
|
||||
Plugins::get()->activate(__METHOD__, 0, func_get_args());
|
||||
|
||||
// Execute query
|
||||
$query = Database::prepare(Database::get(), "SELECT password FROM ? WHERE id = '?' LIMIT 1", array(LYCHEE_TABLE_ALBUMS, $this->albumIDs));
|
||||
$albums = Database::execute(Database::get(), $query, __METHOD__, __LINE__);
|
||||
|
||||
if ($albums===false) return false;
|
||||
|
||||
// Get album object
|
||||
$album = $albums->fetch_object();
|
||||
|
||||
// Album not found?
|
||||
if ($album===null) {
|
||||
Log::error(Database::get(), __METHOD__, __LINE__, 'Could not find specified album');
|
||||
return false;
|
||||
}
|
||||
|
||||
// Call plugins
|
||||
Plugins::get()->activate(__METHOD__, 1, func_get_args());
|
||||
|
||||
// Check if password is correct
|
||||
if ($album->password=='') return true;
|
||||
if ($album->password===crypt($password, $album->password)) return true;
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return boolean Returns true when successful.
|
||||
*/
|
||||
public function merge() {
|
||||
|
||||
// Check dependencies
|
||||
Validator::required(isset($this->albumIDs), __METHOD__);
|
||||
|
||||
// Call plugins
|
||||
Plugins::get()->activate(__METHOD__, 0, func_get_args());
|
||||
|
||||
// Convert to array
|
||||
$albumIDs = explode(',', $this->albumIDs);
|
||||
|
||||
// Get first albumID
|
||||
$albumID = array_splice($albumIDs, 0, 1);
|
||||
$albumID = $albumID[0];
|
||||
|
||||
$query = Database::prepare(Database::get(), "UPDATE ? SET album = ? WHERE album IN (?)", array(LYCHEE_TABLE_PHOTOS, $albumID, $this->albumIDs));
|
||||
$result = Database::execute(Database::get(), $query, __METHOD__, __LINE__);
|
||||
|
||||
if ($result===false) return false;
|
||||
|
||||
// $albumIDs contains all IDs without the first albumID
|
||||
// Convert to string
|
||||
$filteredIDs = implode(',', $albumIDs);
|
||||
|
||||
$query = Database::prepare(Database::get(), "DELETE FROM ? WHERE id IN (?)", array(LYCHEE_TABLE_ALBUMS, $filteredIDs));
|
||||
$result = Database::execute(Database::get(), $query, __METHOD__, __LINE__);
|
||||
|
||||
// Call plugins
|
||||
Plugins::get()->activate(__METHOD__, 1, func_get_args());
|
||||
|
||||
if ($result===false) return false;
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return boolean Returns true when successful.
|
||||
*/
|
||||
public function delete() {
|
||||
|
||||
// Check dependencies
|
||||
Validator::required(isset($this->albumIDs), __METHOD__);
|
||||
|
||||
// Call plugins
|
||||
Plugins::get()->activate(__METHOD__, 0, func_get_args());
|
||||
|
||||
// Init vars
|
||||
$photoIDs = array();
|
||||
|
||||
// Execute query
|
||||
$query = Database::prepare(Database::get(), "SELECT id FROM ? WHERE album IN (?)", array(LYCHEE_TABLE_PHOTOS, $this->albumIDs));
|
||||
$photos = Database::execute(Database::get(), $query, __METHOD__, __LINE__);
|
||||
|
||||
if ($photos===false) return false;
|
||||
|
||||
// Only delete photos when albums contain photos
|
||||
if ($photos->num_rows>0) {
|
||||
|
||||
// Add each id to photoIDs
|
||||
while ($row = $photos->fetch_object()) $photoIDs[] = $row->id;
|
||||
|
||||
// Convert photoIDs to a string
|
||||
$photoIDs = implode(',', $photoIDs);
|
||||
|
||||
// Delete all photos
|
||||
$photo = new Photo($photoIDs);
|
||||
if ($photo->delete()!==true) return false;
|
||||
|
||||
}
|
||||
|
||||
// Delete albums
|
||||
$query = Database::prepare(Database::get(), "DELETE FROM ? WHERE id IN (?)", array(LYCHEE_TABLE_ALBUMS, $this->albumIDs));
|
||||
$result = Database::execute(Database::get(), $query, __METHOD__, __LINE__);
|
||||
|
||||
// Call plugins
|
||||
Plugins::get()->activate(__METHOD__, 1, func_get_args());
|
||||
|
||||
if ($result===false) return false;
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
191
php/Modules/Albums.php
Normal file
191
php/Modules/Albums.php
Normal file
@ -0,0 +1,191 @@
|
||||
<?php
|
||||
|
||||
namespace Lychee\Modules;
|
||||
|
||||
final class Albums {
|
||||
|
||||
/**
|
||||
* @return boolean Returns true when successful.
|
||||
*/
|
||||
public function __construct() {
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array|false Returns an array of albums or false on failure.
|
||||
*/
|
||||
public function get($public = true) {
|
||||
|
||||
// Call plugins
|
||||
Plugins::get()->activate(__METHOD__, 0, func_get_args());
|
||||
|
||||
// Initialize return var
|
||||
$return = array(
|
||||
'smartalbums' => null,
|
||||
'albums' => null,
|
||||
'num' => 0
|
||||
);
|
||||
|
||||
// Get SmartAlbums
|
||||
if ($public===false) $return['smartalbums'] = $this->getSmartAlbums();
|
||||
|
||||
// Albums query
|
||||
if ($public===false) $query = Database::prepare(Database::get(), 'SELECT id, title, public, sysstamp, password FROM ? ' . Settings::get()['sortingAlbums'], array(LYCHEE_TABLE_ALBUMS));
|
||||
else $query = Database::prepare(Database::get(), 'SELECT id, title, public, sysstamp, password FROM ? WHERE public = 1 AND visible <> 0 ' . Settings::get()['sortingAlbums'], array(LYCHEE_TABLE_ALBUMS));
|
||||
|
||||
// Execute query
|
||||
$albums = Database::execute(Database::get(), $query, __METHOD__, __LINE__);
|
||||
|
||||
if ($albums===false) return false;
|
||||
|
||||
// For each album
|
||||
while ($album = $albums->fetch_assoc()) {
|
||||
|
||||
// Turn data from the database into a front-end friendly format
|
||||
$album = Album::prepareData($album);
|
||||
|
||||
// Thumbs
|
||||
if (($public===true&&$album['password']==='0')||
|
||||
($public===false)) {
|
||||
|
||||
// Execute query
|
||||
$query = Database::prepare(Database::get(), "SELECT thumbUrl FROM ? WHERE album = '?' ORDER BY star DESC, " . substr(Settings::get()['sortingPhotos'], 9) . " LIMIT 3", array(LYCHEE_TABLE_PHOTOS, $album['id']));
|
||||
$thumbs = Database::execute(Database::get(), $query, __METHOD__, __LINE__);
|
||||
|
||||
if ($thumbs===false) return false;
|
||||
|
||||
// For each thumb
|
||||
$k = 0;
|
||||
while ($thumb = $thumbs->fetch_object()) {
|
||||
$album['thumbs'][$k] = LYCHEE_URL_UPLOADS_THUMB . $thumb->thumbUrl;
|
||||
$k++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Add to return
|
||||
$return['albums'][] = $album;
|
||||
|
||||
}
|
||||
|
||||
// Num of albums
|
||||
$return['num'] = $albums->num_rows;
|
||||
|
||||
// Call plugins
|
||||
Plugins::get()->activate(__METHOD__, 1, func_get_args());
|
||||
|
||||
return $return;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array|false Returns an array of smart albums or false on failure.
|
||||
*/
|
||||
private function getSmartAlbums() {
|
||||
|
||||
// Initialize return var
|
||||
$return = array(
|
||||
'unsorted' => null,
|
||||
'public' => null,
|
||||
'starred' => null,
|
||||
'recent' => null
|
||||
);
|
||||
|
||||
/**
|
||||
* Unsorted
|
||||
*/
|
||||
|
||||
$query = Database::prepare(Database::get(), 'SELECT thumbUrl FROM ? WHERE album = 0 ' . Settings::get()['sortingPhotos'], array(LYCHEE_TABLE_PHOTOS));
|
||||
$unsorted = Database::execute(Database::get(), $query, __METHOD__, __LINE__);
|
||||
$i = 0;
|
||||
|
||||
if ($unsorted===false) return false;
|
||||
|
||||
$return['unsorted'] = array(
|
||||
'thumbs' => array(),
|
||||
'num' => $unsorted->num_rows
|
||||
);
|
||||
|
||||
while($row = $unsorted->fetch_object()) {
|
||||
if ($i<3) {
|
||||
$return['unsorted']['thumbs'][$i] = LYCHEE_URL_UPLOADS_THUMB . $row->thumbUrl;
|
||||
$i++;
|
||||
} else break;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starred
|
||||
*/
|
||||
|
||||
$query = Database::prepare(Database::get(), 'SELECT thumbUrl FROM ? WHERE star = 1 ' . Settings::get()['sortingPhotos'], array(LYCHEE_TABLE_PHOTOS));
|
||||
$starred = Database::execute(Database::get(), $query, __METHOD__, __LINE__);
|
||||
$i = 0;
|
||||
|
||||
if ($starred===false) return false;
|
||||
|
||||
$return['starred'] = array(
|
||||
'thumbs' => array(),
|
||||
'num' => $starred->num_rows
|
||||
);
|
||||
|
||||
while($row3 = $starred->fetch_object()) {
|
||||
if ($i<3) {
|
||||
$return['starred']['thumbs'][$i] = LYCHEE_URL_UPLOADS_THUMB . $row3->thumbUrl;
|
||||
$i++;
|
||||
} else break;
|
||||
}
|
||||
|
||||
/**
|
||||
* Public
|
||||
*/
|
||||
|
||||
$query = Database::prepare(Database::get(), 'SELECT thumbUrl FROM ? WHERE public = 1 ' . Settings::get()['sortingPhotos'], array(LYCHEE_TABLE_PHOTOS));
|
||||
$public = Database::execute(Database::get(), $query, __METHOD__, __LINE__);
|
||||
$i = 0;
|
||||
|
||||
if ($public===false) return false;
|
||||
|
||||
$return['public'] = array(
|
||||
'thumbs' => array(),
|
||||
'num' => $public->num_rows
|
||||
);
|
||||
|
||||
while($row2 = $public->fetch_object()) {
|
||||
if ($i<3) {
|
||||
$return['public']['thumbs'][$i] = LYCHEE_URL_UPLOADS_THUMB . $row2->thumbUrl;
|
||||
$i++;
|
||||
} else break;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recent
|
||||
*/
|
||||
|
||||
$query = Database::prepare(Database::get(), 'SELECT thumbUrl FROM ? WHERE LEFT(id, 10) >= unix_timestamp(DATE_SUB(NOW(), INTERVAL 1 DAY)) ' . Settings::get()['sortingPhotos'], array(LYCHEE_TABLE_PHOTOS));
|
||||
$recent = Database::execute(Database::get(), $query, __METHOD__, __LINE__);
|
||||
$i = 0;
|
||||
|
||||
if ($recent===false) return false;
|
||||
|
||||
$return['recent'] = array(
|
||||
'thumbs' => array(),
|
||||
'num' => $recent->num_rows
|
||||
);
|
||||
|
||||
while($row3 = $recent->fetch_object()) {
|
||||
if ($i<3) {
|
||||
$return['recent']['thumbs'][$i] = LYCHEE_URL_UPLOADS_THUMB . $row3->thumbUrl;
|
||||
$i++;
|
||||
} else break;
|
||||
}
|
||||
|
||||
// Return SmartAlbums
|
||||
return $return;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
79
php/Modules/Config.php
Normal file
79
php/Modules/Config.php
Normal file
@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
namespace Lychee\Modules;
|
||||
|
||||
final class Config {
|
||||
|
||||
/**
|
||||
* Creates the configuration file.
|
||||
* @return true|string Returns true when successful.
|
||||
* Warning: Connection failed!
|
||||
* Warning: Creation failed!
|
||||
* Warning: Could not create file!
|
||||
*/
|
||||
public static function create($host, $user, $password, $name = 'lychee', $prefix = '') {
|
||||
|
||||
// Open a new connection to the MySQL server
|
||||
$connection = Database::connect($host, $user, $password);
|
||||
|
||||
// Check if the connection was successful
|
||||
if ($connection===false) return 'Warning: Connection failed!';
|
||||
|
||||
// Check if user can create the database before saving the configuration
|
||||
if (Database::createDatabase($connection, $name)===false) return 'Warning: Creation failed!';
|
||||
|
||||
// Escape data
|
||||
$host = mysqli_real_escape_string($connection, $host);
|
||||
$user = mysqli_real_escape_string($connection, $user);
|
||||
$password = mysqli_real_escape_string($connection, $password);
|
||||
$name = mysqli_real_escape_string($connection, $name);
|
||||
$prefix = mysqli_real_escape_string($connection, $prefix);
|
||||
|
||||
// Save config.php
|
||||
$config = "<?php
|
||||
|
||||
// Database configuration
|
||||
\$dbHost = '$host'; // Host of the database
|
||||
\$dbUser = '$user'; // Username of the database
|
||||
\$dbPassword = '$password'; // Password of the database
|
||||
\$dbName = '$name'; // Database name
|
||||
\$dbTablePrefix = '$prefix'; // Table prefix
|
||||
|
||||
?>";
|
||||
|
||||
// Save file
|
||||
if (@file_put_contents(LYCHEE_CONFIG_FILE, $config)===false) return 'Warning: Could not create file!';
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return boolean Returns true when the config exists.
|
||||
*/
|
||||
public static function exists() {
|
||||
|
||||
return file_exists(LYCHEE_CONFIG_FILE);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array Returns the config.
|
||||
*/
|
||||
public static function get() {
|
||||
|
||||
require(LYCHEE_CONFIG_FILE);
|
||||
|
||||
return(array(
|
||||
'host' => $dbHost,
|
||||
'user' => $dbUser,
|
||||
'password' => $dbPassword,
|
||||
'name' => $dbName,
|
||||
'prefix' => $dbTablePrefix
|
||||
));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
411
php/Modules/Database.php
Executable file
411
php/Modules/Database.php
Executable file
@ -0,0 +1,411 @@
|
||||
<?php
|
||||
|
||||
namespace Lychee\Modules;
|
||||
|
||||
use Mysqli;
|
||||
|
||||
final class Database {
|
||||
|
||||
private $connection = null;
|
||||
private static $instance = null;
|
||||
|
||||
private static $versions = array(
|
||||
'020700', // 2.7.0
|
||||
'030000', // 3.0.0
|
||||
'030001', // 3.0.1
|
||||
'030003', // 3.0.3
|
||||
'030100' // 3.1.0
|
||||
);
|
||||
|
||||
/**
|
||||
* @return object Returns a new or cached connection.
|
||||
*/
|
||||
public static function get() {
|
||||
|
||||
if (!self::$instance) {
|
||||
|
||||
$credentials = Config::get();
|
||||
|
||||
self::$instance = new self(
|
||||
$credentials['host'],
|
||||
$credentials['user'],
|
||||
$credentials['password'],
|
||||
$credentials['name'],
|
||||
$credentials['prefix']
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
return self::$instance->connection;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Exits on error.
|
||||
* @return boolean Returns true when successful.
|
||||
*/
|
||||
private function __construct($host, $user, $password, $name = 'lychee', $dbTablePrefix) {
|
||||
|
||||
// Check dependencies
|
||||
Validator::required(isset($host, $user, $password, $name), __METHOD__);
|
||||
|
||||
// Define the table prefix
|
||||
defineTablePrefix($dbTablePrefix);
|
||||
|
||||
// Open a new connection to the MySQL server
|
||||
$connection = self::connect($host, $user, $password);
|
||||
|
||||
// Check if the connection was successful
|
||||
if ($connection===false) Response::error($connection->connect_error);
|
||||
|
||||
if (self::setCharset($connection)===false) Response::error('Could not set database charset!');
|
||||
|
||||
// Create database
|
||||
if (self::createDatabase($connection, $name)===false) Response::error('Could not create database!');
|
||||
|
||||
// Create tables
|
||||
if (self::createTables($connection)===false) Response::error('Could not create tables!');
|
||||
|
||||
// Update database
|
||||
if (self::update($connection, $name)===false) Response::error('Could not update database and tables!');
|
||||
|
||||
$this->connection = $connection;
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return object|false Returns the connection when successful.
|
||||
*/
|
||||
public static function connect($host = 'localhost', $user, $password) {
|
||||
|
||||
// Open a new connection to the MySQL server
|
||||
$connection = @new Mysqli($host, $user, $password);
|
||||
|
||||
// Check if the connection was successful
|
||||
if ($connection->connect_errno) return false;
|
||||
|
||||
return $connection;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return boolean Returns true when successful.
|
||||
*/
|
||||
private static function setCharset($connection) {
|
||||
|
||||
// Check dependencies
|
||||
Validator::required(isset($connection), __METHOD__);
|
||||
|
||||
// Avoid sql injection on older MySQL versions by using GBK
|
||||
if ($connection->server_version<50500) @$connection->set_charset('GBK');
|
||||
else @$connection->set_charset('utf8');
|
||||
|
||||
// Set unicode
|
||||
$query = 'SET NAMES utf8';
|
||||
$result = self::execute($connection, $query, null, null);
|
||||
|
||||
if ($result===false) return false;
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return boolean Returns true when successful.
|
||||
*/
|
||||
public static function createDatabase($connection, $name = 'lychee') {
|
||||
|
||||
// Check dependencies
|
||||
Validator::required(isset($connection), __METHOD__);
|
||||
|
||||
// Check if database exists
|
||||
if ($connection->select_db($name)===true) return true;
|
||||
|
||||
// Create database
|
||||
$query = self::prepare($connection, 'CREATE DATABASE IF NOT EXISTS ?', array($name));
|
||||
$result = self::execute($connection, $query, null, null);
|
||||
|
||||
if ($result===false) return false;
|
||||
if ($connection->select_db($name)===false) return false;
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return boolean Returns true when successful.
|
||||
*/
|
||||
private static function createTables($connection) {
|
||||
|
||||
// Check dependencies
|
||||
Validator::required(isset($connection), __METHOD__);
|
||||
|
||||
// Check if tables exist
|
||||
$query = self::prepare($connection, 'SELECT * FROM ?, ?, ?, ? LIMIT 0', array(LYCHEE_TABLE_PHOTOS, LYCHEE_TABLE_ALBUMS, LYCHEE_TABLE_SETTINGS, LYCHEE_TABLE_LOG));
|
||||
$result = self::execute($connection, $query, null, null);
|
||||
if ($result!==false) return true;
|
||||
|
||||
// Check if log table exists
|
||||
$exist = self::prepare($connection, 'SELECT * FROM ? LIMIT 0', array(LYCHEE_TABLE_LOG));
|
||||
$result = self::execute($connection, $exist, null, null);
|
||||
|
||||
if ($result===false) {
|
||||
|
||||
// Read file
|
||||
$file = __DIR__ . '/../database/log_table.sql';
|
||||
$query = @file_get_contents($file);
|
||||
|
||||
if ($query===false) return false;
|
||||
|
||||
// Create table
|
||||
$query = self::prepare($connection, $query, array(LYCHEE_TABLE_LOG));
|
||||
$result = self::execute($connection, $query, null, null);
|
||||
|
||||
if ($result===false) return false;
|
||||
|
||||
}
|
||||
|
||||
// Check if settings table exists
|
||||
$exist = self::prepare($connection, 'SELECT * FROM ? LIMIT 0', array(LYCHEE_TABLE_SETTINGS));
|
||||
$result = self::execute($connection, $exist, __METHOD__, __LINE__);
|
||||
|
||||
if ($result===false) {
|
||||
|
||||
// Read file
|
||||
$file = __DIR__ . '/../database/settings_table.sql';
|
||||
$query = @file_get_contents($file);
|
||||
|
||||
if ($query===false) {
|
||||
Log::error($connection, __METHOD__, __LINE__, 'Could not load query for lychee_settings');
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create table
|
||||
$query = self::prepare($connection, $query, array(LYCHEE_TABLE_SETTINGS));
|
||||
$result = self::execute($connection, $query, __METHOD__, __LINE__);
|
||||
|
||||
if ($result===false) return false;
|
||||
|
||||
// Read file
|
||||
$file = __DIR__ . '/../database/settings_content.sql';
|
||||
$query = @file_get_contents($file);
|
||||
|
||||
if ($query===false) {
|
||||
Log::error($connection, __METHOD__, __LINE__, 'Could not load content-query for lychee_settings');
|
||||
return false;
|
||||
}
|
||||
|
||||
// Add content
|
||||
$query = self::prepare($connection, $query, array(LYCHEE_TABLE_SETTINGS));
|
||||
$result = self::execute($connection, $query, __METHOD__, __LINE__);
|
||||
|
||||
if ($result===false) return false;
|
||||
|
||||
// Generate identifier
|
||||
$identifier = md5(microtime(true));
|
||||
$query = self::prepare($connection, "UPDATE `?` SET `value` = '?' WHERE `key` = 'identifier' LIMIT 1", array(LYCHEE_TABLE_SETTINGS, $identifier));
|
||||
$result = self::execute($connection, $query, __METHOD__, __LINE__);
|
||||
|
||||
if ($result===false) return false;
|
||||
|
||||
}
|
||||
|
||||
// Check if albums table exists
|
||||
$exist = self::prepare($connection, 'SELECT * FROM ? LIMIT 0', array(LYCHEE_TABLE_ALBUMS));
|
||||
$result = self::execute($connection, $exist, __METHOD__, __LINE__);
|
||||
|
||||
if ($result===false) {
|
||||
|
||||
// Read file
|
||||
$file = __DIR__ . '/../database/albums_table.sql';
|
||||
$query = @file_get_contents($file);
|
||||
|
||||
if ($query===false) {
|
||||
Log::error($connection, __METHOD__, __LINE__, 'Could not load query for lychee_albums');
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create table
|
||||
$query = self::prepare($connection, $query, array(LYCHEE_TABLE_ALBUMS));
|
||||
$result = self::execute($connection, $query, __METHOD__, __LINE__);
|
||||
|
||||
if ($result===false) return false;
|
||||
|
||||
}
|
||||
|
||||
// Check if photos table exists
|
||||
$exist = self::prepare($connection, 'SELECT * FROM ? LIMIT 0', array(LYCHEE_TABLE_PHOTOS));
|
||||
$result = self::execute($connection, $exist, __METHOD__, __LINE__);
|
||||
|
||||
if ($result===false) {
|
||||
|
||||
// Read file
|
||||
$file = __DIR__ . '/../database/photos_table.sql';
|
||||
$query = @file_get_contents($file);
|
||||
|
||||
if ($query===false) {
|
||||
Log::error($connection, __METHOD__, __LINE__, 'Could not load query for lychee_photos');
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create table
|
||||
$query = self::prepare($connection, $query, array(LYCHEE_TABLE_PHOTOS));
|
||||
$result = self::execute($connection, $query, __METHOD__, __LINE__);
|
||||
|
||||
if ($result===false) return false;
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Exits when an update fails.
|
||||
* @return boolean Returns true when successful.
|
||||
*/
|
||||
private static function update($connection, $dbName) {
|
||||
|
||||
// Check dependencies
|
||||
Validator::required(isset($connection, $dbName), __METHOD__);
|
||||
|
||||
// Get current version
|
||||
$query = self::prepare($connection, "SELECT * FROM ? WHERE `key` = 'version'", array(LYCHEE_TABLE_SETTINGS));
|
||||
$result = self::execute($connection, $query, __METHOD__, __LINE__);
|
||||
|
||||
if ($result===false) return false;
|
||||
|
||||
// Extract current version
|
||||
$current = $result->fetch_object()->value;
|
||||
|
||||
// For each update
|
||||
foreach (self::$versions as $version) {
|
||||
|
||||
// Only update when newer version available
|
||||
if ($version<=$current) continue;
|
||||
|
||||
// Load update
|
||||
include(__DIR__ . '/../database/update_' . $version . '.php');
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return boolean Returns true when successful.
|
||||
*/
|
||||
public static function setVersion($connection, $version) {
|
||||
|
||||
// Check dependencies
|
||||
Validator::required(isset($connection), __METHOD__);
|
||||
|
||||
$query = self::prepare($connection, "UPDATE ? SET value = '?' WHERE `key` = 'version'", array(LYCHEE_TABLE_SETTINGS, $version));
|
||||
$result = self::execute($connection, $query, __METHOD__, __LINE__);
|
||||
|
||||
if ($result===false) return false;
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string Returns a escaped query.
|
||||
*/
|
||||
public static function prepare($connection, $query, array $data) {
|
||||
|
||||
// Check dependencies
|
||||
Validator::required(isset($connection, $query), __METHOD__);
|
||||
|
||||
// Count the number of placeholders and compare it with the number of arguments
|
||||
// If it doesn't match, calculate the difference and skip this number of placeholders before starting the replacement
|
||||
// This avoids problems with placeholders in user-input
|
||||
// $skip = Number of placeholders which need to be skipped
|
||||
$skip = 0;
|
||||
$temp = '';
|
||||
$num = array(
|
||||
'placeholder' => substr_count($query, '?'),
|
||||
'data' => count($data)
|
||||
);
|
||||
|
||||
if (($num['data']-$num['placeholder'])<0) Log::notice($connection, __METHOD__, __LINE__, 'Could not completely prepare query. Query has more placeholders than values.');
|
||||
|
||||
foreach ($data as $value) {
|
||||
|
||||
// Escape
|
||||
$value = mysqli_real_escape_string($connection, $value);
|
||||
|
||||
// Recalculate number of placeholders
|
||||
$num['placeholder'] = substr_count($query, '?');
|
||||
|
||||
// Calculate number of skips
|
||||
if ($num['placeholder']>$num['data']) $skip = $num['placeholder'] - $num['data'];
|
||||
|
||||
if ($skip>0) {
|
||||
|
||||
// Need to skip $skip placeholders, because the user input contained placeholders
|
||||
// Calculate a substring which does not contain the user placeholders
|
||||
// 1 or -1 is the length of the placeholder (placeholder = ?)
|
||||
|
||||
$pos = -1;
|
||||
for ($i=$skip; $i>0; $i--) $pos = strpos($query, '?', $pos + 1);
|
||||
$pos++;
|
||||
|
||||
$temp = substr($query, 0, $pos); // First part of $query
|
||||
$query = substr($query, $pos); // Last part of $query
|
||||
|
||||
}
|
||||
|
||||
// Put a backslash in front of every character that is part of the regular
|
||||
// expression syntax. Avoids a backreference when using preg_replace.
|
||||
$value = preg_quote($value);
|
||||
|
||||
// Replace
|
||||
$query = preg_replace('/\?/', $value, $query, 1);
|
||||
|
||||
if ($skip>0) {
|
||||
|
||||
// Reassemble the parts of $query
|
||||
$query = $temp . $query;
|
||||
|
||||
}
|
||||
|
||||
// Reset skip
|
||||
$skip = 0;
|
||||
|
||||
// Decrease number of data elements
|
||||
$num['data']--;
|
||||
|
||||
}
|
||||
|
||||
return $query;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return object|false Returns the results on success.
|
||||
*/
|
||||
public static function execute($connection, $query, $function, $line) {
|
||||
|
||||
// Check dependencies
|
||||
Validator::required(isset($connection, $query), __METHOD__);
|
||||
|
||||
// Only activate logging when $function and $line is set
|
||||
$logging = ($function===null||$line===null ? false : true);
|
||||
|
||||
// Execute query
|
||||
$result = $connection->query($query);
|
||||
|
||||
// Check if execution failed
|
||||
if ($result===false) {
|
||||
if ($logging===true) Log::error($connection, $function, $line, $connection->error);
|
||||
return false;
|
||||
}
|
||||
|
||||
return $result;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
194
php/Modules/Import.php
Normal file
194
php/Modules/Import.php
Normal file
@ -0,0 +1,194 @@
|
||||
<?php
|
||||
|
||||
namespace Lychee\Modules;
|
||||
|
||||
final class Import {
|
||||
|
||||
/**
|
||||
* Creates an array similar to a file upload array and adds the photo to Lychee.
|
||||
* @return boolean Returns true when photo import was successful.
|
||||
*/
|
||||
private function photo($path, $albumID = 0) {
|
||||
|
||||
// No need to validate photo type and extension in this function.
|
||||
// $photo->add will take care of it.
|
||||
|
||||
$info = getimagesize($path);
|
||||
$size = filesize($path);
|
||||
$photo = new Photo(null);
|
||||
|
||||
$nameFile = array(array());
|
||||
$nameFile[0]['name'] = $path;
|
||||
$nameFile[0]['type'] = $info['mime'];
|
||||
$nameFile[0]['tmp_name'] = $path;
|
||||
$nameFile[0]['error'] = 0;
|
||||
$nameFile[0]['size'] = $size;
|
||||
$nameFile[0]['error'] = UPLOAD_ERR_OK;
|
||||
|
||||
if ($photo->add($nameFile, $albumID, true)===false) return false;
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return boolean Returns true when successful.
|
||||
*/
|
||||
public function url($urls, $albumID = 0) {
|
||||
|
||||
// Call plugins
|
||||
Plugins::get()->activate(__METHOD__, 0, func_get_args());
|
||||
|
||||
$error = false;
|
||||
|
||||
// Parse URLs
|
||||
$urls = str_replace(' ', '%20', $urls);
|
||||
$urls = explode(',', $urls);
|
||||
|
||||
foreach ($urls as &$url) {
|
||||
|
||||
// Validate photo type and extension even when $this->photo (=> $photo->add) will do the same.
|
||||
// This prevents us from downloading invalid photos.
|
||||
|
||||
// Verify extension
|
||||
$extension = getExtension($url, true);
|
||||
if (!in_array(strtolower($extension), Photo::$validExtensions, true)) {
|
||||
$error = true;
|
||||
Log::error(Database::get(), __METHOD__, __LINE__, 'Photo format not supported (' . $url . ')');
|
||||
continue;
|
||||
}
|
||||
|
||||
// Verify image
|
||||
$type = @exif_imagetype($url);
|
||||
if (!in_array($type, Photo::$validTypes, true)) {
|
||||
$error = true;
|
||||
Log::error(Database::get(), __METHOD__, __LINE__, 'Photo type not supported (' . $url . ')');
|
||||
continue;
|
||||
}
|
||||
|
||||
$filename = pathinfo($url, PATHINFO_FILENAME) . $extension;
|
||||
$tmp_name = LYCHEE_DATA . $filename;
|
||||
|
||||
if (@copy($url, $tmp_name)===false) {
|
||||
$error = true;
|
||||
Log::error(Database::get(), __METHOD__, __LINE__, 'Could not copy file (' . $url . ') to temp-folder (' . $tmp_name . ')');
|
||||
continue;
|
||||
}
|
||||
|
||||
// Import photo
|
||||
if (!$this->photo($tmp_name, $albumID)) {
|
||||
$error = true;
|
||||
Log::error(Database::get(), __METHOD__, __LINE__, 'Could not import file (' . $tmp_name . ')');
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Call plugins
|
||||
Plugins::get()->activate(__METHOD__, 1, func_get_args());
|
||||
|
||||
if ($error===false) return true;
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return boolean|string Returns true when successful.
|
||||
* Warning: Folder empty or no readable files to process!
|
||||
* Notice: Import only contained albums!
|
||||
*/
|
||||
public function server($path, $albumID = 0) {
|
||||
|
||||
// Parse path
|
||||
if (!isset($path)) $path = LYCHEE_UPLOADS_IMPORT;
|
||||
if (substr($path, -1)==='/') $path = substr($path, 0, -1);
|
||||
|
||||
if (is_dir($path)===false) {
|
||||
Log::error(Database::get(), __METHOD__, __LINE__, 'Given path is not a directory (' . $path . ')');
|
||||
return false;
|
||||
}
|
||||
|
||||
// Skip folders of Lychee
|
||||
if ($path===LYCHEE_UPLOADS_BIG||($path . '/')===LYCHEE_UPLOADS_BIG||
|
||||
$path===LYCHEE_UPLOADS_MEDIUM||($path . '/')===LYCHEE_UPLOADS_MEDIUM||
|
||||
$path===LYCHEE_UPLOADS_THUMB||($path . '/')===LYCHEE_UPLOADS_THUMB) {
|
||||
Log::error(Database::get(), __METHOD__, __LINE__, 'The given path is a reserved path of Lychee (' . $path . ')');
|
||||
return false;
|
||||
}
|
||||
|
||||
$error = false;
|
||||
$contains['photos'] = false;
|
||||
$contains['albums'] = false;
|
||||
|
||||
// Call plugins
|
||||
// Note that updated albumId and path explicitly passed, rather
|
||||
// than using func_get_args() which will only return original ones
|
||||
Plugins::get()->activate(__METHOD__, 0, array($albumID, $path));
|
||||
|
||||
// Get all files
|
||||
$files = glob($path . '/*');
|
||||
|
||||
foreach ($files as $file) {
|
||||
|
||||
// It is possible to move a file because of directory permissions but
|
||||
// the file may still be unreadable by the user
|
||||
if (!is_readable($file)) {
|
||||
$error = true;
|
||||
Log::error(Database::get(), __METHOD__, __LINE__, 'Could not read file or directory (' . $file . ')');
|
||||
continue;
|
||||
}
|
||||
|
||||
if (@exif_imagetype($file)!==false) {
|
||||
|
||||
// Photo
|
||||
|
||||
$contains['photos'] = true;
|
||||
|
||||
if ($this->photo($file, $albumID)===false) {
|
||||
$error = true;
|
||||
Log::error(Database::get(), __METHOD__, __LINE__, 'Could not import file (' . $file . ')');
|
||||
continue;
|
||||
}
|
||||
|
||||
} else if (is_dir($file)) {
|
||||
|
||||
// Folder
|
||||
|
||||
$album = new Album(null);
|
||||
$newAlbumID = $album->add('[Import] ' . basename($file));
|
||||
$contains['albums'] = true;
|
||||
|
||||
if ($newAlbumID===false) {
|
||||
$error = true;
|
||||
Log::error(Database::get(), __METHOD__, __LINE__, 'Could not create album in Lychee (' . $newAlbumID . ')');
|
||||
continue;
|
||||
}
|
||||
|
||||
$import = $this->server($file . '/', $newAlbumID);
|
||||
|
||||
if ($import!==true&&$import!=='Notice: Import only contains albums!') {
|
||||
$error = true;
|
||||
Log::error(Database::get(), __METHOD__, __LINE__, 'Could not import folder. Function returned warning.');
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Call plugins
|
||||
// Note that updated albumId and path explicitly passed, rather
|
||||
// than using func_get_args() which will only return original ones
|
||||
Plugins::get()->activate(__METHOD__, 1, array($albumID, $path));
|
||||
|
||||
// The following returns will be caught in the front-end
|
||||
if ($contains['photos']===false&&$contains['albums']===false) return 'Warning: Folder empty or no readable files to process!';
|
||||
if ($contains['photos']===false&&$contains['albums']===true) return 'Notice: Import only contained albums!';
|
||||
|
||||
if ($error===true) return false;
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
47
php/Modules/Log.php
Normal file
47
php/Modules/Log.php
Normal file
@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace Lychee\Modules;
|
||||
|
||||
final class Log {
|
||||
|
||||
/**
|
||||
* @return boolean Returns true when successful.
|
||||
*/
|
||||
public static function notice($connection, $function, $line, $text = '') {
|
||||
|
||||
return Log::text($connection, 'notice', $function, $line, $text);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return boolean Returns true when successful.
|
||||
*/
|
||||
public static function error($connection, $function, $line, $text = '') {
|
||||
|
||||
return Log::text($connection, 'error', $function, $line, $text);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return boolean Returns true when successful.
|
||||
*/
|
||||
private static function text($connection, $type, $function, $line, $text = '') {
|
||||
|
||||
// Check dependencies
|
||||
Validator::required(isset($connection, $type, $function, $line, $text), __METHOD__);
|
||||
|
||||
// Get time
|
||||
$sysstamp = time();
|
||||
|
||||
// Save in database
|
||||
$query = Database::prepare($connection, "INSERT INTO ? (time, type, function, line, text) VALUES ('?', '?', '?', '?', '?')", array(LYCHEE_TABLE_LOG, $sysstamp, $type, $function, $line, $text));
|
||||
$result = Database::execute($connection, $query, null, null);
|
||||
|
||||
if ($result===false) return false;
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
1244
php/Modules/Photo.php
Executable file
1244
php/Modules/Photo.php
Executable file
File diff suppressed because it is too large
Load Diff
99
php/Modules/Plugins.php
Normal file
99
php/Modules/Plugins.php
Normal file
@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
namespace Lychee\Modules;
|
||||
|
||||
use SplSubject;
|
||||
use SplObserver;
|
||||
|
||||
final class Plugins implements SplSubject {
|
||||
|
||||
private static $instance = null;
|
||||
|
||||
private $observers = array();
|
||||
|
||||
public $action = null;
|
||||
public $args = null;
|
||||
|
||||
public static function get() {
|
||||
|
||||
if (!self::$instance) {
|
||||
|
||||
$files = Settings::get()['plugins'];
|
||||
|
||||
self::$instance = new self($files);
|
||||
|
||||
}
|
||||
|
||||
return self::$instance;
|
||||
|
||||
}
|
||||
|
||||
private function __construct(array $plugins) {
|
||||
|
||||
// Load plugins
|
||||
foreach ($plugins as $plugin) {
|
||||
|
||||
if ($plugin==='') continue;
|
||||
|
||||
$this->attach(new $plugin);
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
public function attach(SplObserver $observer) {
|
||||
|
||||
if (!isset($observer)) return false;
|
||||
|
||||
// Add observer
|
||||
$this->observers[] = $observer;
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
public function detach(SplObserver $observer) {
|
||||
|
||||
if (!isset($observer)) return false;
|
||||
|
||||
// Remove observer
|
||||
$key = array_search($observer, $this->observers, true);
|
||||
if ($key) unset($this->observers[$key]);
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
public function notify() {
|
||||
|
||||
// Notify each observer
|
||||
foreach ($this->observers as $value) $value->update($this);
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
public function activate($name, $location, array $args) {
|
||||
|
||||
if (!isset($name, $location, $args)) return false;
|
||||
|
||||
// Parse
|
||||
$location = ($location===0 ? 'before' : 'after');
|
||||
$action = $name . ":" . $location;
|
||||
|
||||
// Save vars
|
||||
$this->action = $action;
|
||||
$this->args = $args;
|
||||
|
||||
// Notify observers
|
||||
$this->notify();
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
25
php/Modules/Response.php
Normal file
25
php/Modules/Response.php
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace Lychee\Modules;
|
||||
|
||||
final class Response {
|
||||
|
||||
public static function warning($msg) {
|
||||
|
||||
exit(json_encode('Warning: ' . $msg));
|
||||
|
||||
}
|
||||
|
||||
public static function error($msg) {
|
||||
|
||||
exit(json_encode('Error: ' . $msg));
|
||||
|
||||
}
|
||||
|
||||
public static function json($str, $options = 0) {
|
||||
|
||||
exit(json_encode($str, $options));
|
||||
|
||||
}
|
||||
|
||||
}
|
137
php/Modules/Session.php
Executable file
137
php/Modules/Session.php
Executable file
@ -0,0 +1,137 @@
|
||||
<?php
|
||||
|
||||
namespace Lychee\Modules;
|
||||
|
||||
final class Session {
|
||||
|
||||
/**
|
||||
* Reads and returns information about the Lychee installation.
|
||||
* @return array Returns an array with the login status and configuration.
|
||||
*/
|
||||
public function init($public = true) {
|
||||
|
||||
// Call plugins
|
||||
Plugins::get()->activate(__METHOD__, 0, func_get_args());
|
||||
|
||||
// Return settings
|
||||
$return['config'] = Settings::get();
|
||||
|
||||
// Path to Lychee for the server-import dialog
|
||||
$return['config']['location'] = LYCHEE;
|
||||
|
||||
// Remove sensitive from response
|
||||
unset($return['config']['username']);
|
||||
unset($return['config']['password']);
|
||||
unset($return['config']['identifier']);
|
||||
|
||||
// Check if login credentials exist and login if they don't
|
||||
if ($this->noLogin()===true) {
|
||||
$public = false;
|
||||
$return['config']['login'] = false;
|
||||
} else {
|
||||
$return['config']['login'] = true;
|
||||
}
|
||||
|
||||
if ($public===false) {
|
||||
|
||||
// Logged in
|
||||
$return['status'] = LYCHEE_STATUS_LOGGEDIN;
|
||||
|
||||
} else {
|
||||
|
||||
// Logged out
|
||||
$return['status'] = LYCHEE_STATUS_LOGGEDOUT;
|
||||
|
||||
// Unset unused vars
|
||||
unset($return['config']['skipDuplicates']);
|
||||
unset($return['config']['sortingAlbums']);
|
||||
unset($return['config']['sortingPhotos']);
|
||||
unset($return['config']['dropboxKey']);
|
||||
unset($return['config']['login']);
|
||||
unset($return['config']['location']);
|
||||
unset($return['config']['imagick']);
|
||||
unset($return['config']['plugins']);
|
||||
|
||||
}
|
||||
|
||||
// Call plugins
|
||||
Plugins::get()->activate(__METHOD__, 1, func_get_args());
|
||||
|
||||
return $return;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the session values when username and password correct.
|
||||
* @return boolean Returns true when login was successful.
|
||||
*/
|
||||
public function login($username, $password) {
|
||||
|
||||
// Call plugins
|
||||
Plugins::get()->activate(__METHOD__, 0, func_get_args());
|
||||
|
||||
$username_crypt = crypt($username, Settings::get()['username']);
|
||||
$password_crypt = crypt($password, Settings::get()['password']);
|
||||
|
||||
// Check login with crypted hash
|
||||
if (Settings::get()['username']===$username_crypt&&
|
||||
Settings::get()['password']===$password_crypt) {
|
||||
$_SESSION['login'] = true;
|
||||
$_SESSION['identifier'] = Settings::get()['identifier'];
|
||||
Log::notice(Database::get(), __METHOD__, __LINE__, 'User (' . $username . ') has logged in from ' . $_SERVER['REMOTE_ADDR']);
|
||||
return true;
|
||||
}
|
||||
|
||||
// No login
|
||||
if ($this->noLogin()===true) return true;
|
||||
|
||||
// Call plugins
|
||||
Plugins::get()->activate(__METHOD__, 1, func_get_args());
|
||||
|
||||
// Log failed log in
|
||||
Log::error(Database::get(), __METHOD__, __LINE__, 'User (' . $username . ') has tried to log in from ' . $_SERVER['REMOTE_ADDR']);
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the session values when no there is no username and password in the database.
|
||||
* @return boolean Returns true when no login was found.
|
||||
*/
|
||||
private function noLogin() {
|
||||
|
||||
// Check if login credentials exist and login if they don't
|
||||
if (Settings::get()['username']===''&&
|
||||
Settings::get()['password']==='') {
|
||||
$_SESSION['login'] = true;
|
||||
$_SESSION['identifier'] = Settings::get()['identifier'];
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsets the session values.
|
||||
* @return boolean Returns true when logout was successful.
|
||||
*/
|
||||
public function logout() {
|
||||
|
||||
// Call plugins
|
||||
Plugins::get()->activate(__METHOD__, 0, func_get_args());
|
||||
|
||||
session_unset();
|
||||
session_destroy();
|
||||
|
||||
// Call plugins
|
||||
Plugins::get()->activate(__METHOD__, 1, func_get_args());
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
226
php/Modules/Settings.php
Executable file
226
php/Modules/Settings.php
Executable file
@ -0,0 +1,226 @@
|
||||
<?php
|
||||
|
||||
namespace Lychee\Modules;
|
||||
|
||||
final class Settings {
|
||||
|
||||
private static $cache = null;
|
||||
|
||||
/**
|
||||
* @return array Returns the settings of Lychee.
|
||||
*/
|
||||
public static function get() {
|
||||
|
||||
if (self::$cache) return self::$cache;
|
||||
|
||||
// Execute query
|
||||
$query = Database::prepare(Database::get(), "SELECT * FROM ?", array(LYCHEE_TABLE_SETTINGS));
|
||||
$settings = Database::execute(Database::get(), $query, __METHOD__, __LINE__);
|
||||
|
||||
// Add each to return
|
||||
while ($setting = $settings->fetch_object()) $return[$setting->key] = $setting->value;
|
||||
|
||||
// Convert plugins to array
|
||||
$return['plugins'] = explode(';', $return['plugins']);
|
||||
|
||||
self::$cache = $return;
|
||||
|
||||
return $return;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return boolean Returns true when successful.
|
||||
*/
|
||||
private static function set($key, $value, $row = false) {
|
||||
|
||||
if ($row===false) {
|
||||
|
||||
$query = Database::prepare(Database::get(), "UPDATE ? SET value = '?' WHERE `key` = '?'", array(LYCHEE_TABLE_SETTINGS, $value, $key));
|
||||
|
||||
} elseif ($row===true) {
|
||||
|
||||
// Do not prepare $value because it has already been escaped or is a true statement
|
||||
$query = Database::prepare(Database::get(), "UPDATE ? SET value = '$value' WHERE `key` = '?'", array(LYCHEE_TABLE_SETTINGS, $key));
|
||||
|
||||
} else {
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
$result = Database::execute(Database::get(), $query, __METHOD__, __LINE__);
|
||||
|
||||
if ($result===false) return false;
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the username and password when current password is correct.
|
||||
* Exits on error.
|
||||
* @return true Returns true when successful.
|
||||
*/
|
||||
public static function setLogin($oldPassword = '', $username, $password) {
|
||||
|
||||
if ($oldPassword===self::get()['password']||self::get()['password']===crypt($oldPassword, self::get()['password'])) {
|
||||
|
||||
// Save username
|
||||
if (self::setUsername($username)===false) Response::error('Updating username failed!');
|
||||
|
||||
// Save password
|
||||
if (self::setPassword($password)===false) Response::error('Updating password failed!');
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
Response::error('Current password entered incorrectly!');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a new username.
|
||||
* @return boolean Returns true when successful.
|
||||
*/
|
||||
private static function setUsername($username) {
|
||||
|
||||
// Check dependencies
|
||||
Validator::required(isset($username), __METHOD__);
|
||||
|
||||
// Hash username
|
||||
$username = getHashedString($username);
|
||||
|
||||
// Execute query
|
||||
// Do not prepare $username because it is hashed and save
|
||||
// Preparing (escaping) the username would destroy the hash
|
||||
if (self::set('username', $username, true)===false) return false;
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a new username.
|
||||
* @return boolean Returns true when successful.
|
||||
*/
|
||||
private static function setPassword($password) {
|
||||
|
||||
// Check dependencies
|
||||
Validator::required(isset($password), __METHOD__);
|
||||
|
||||
// Hash password
|
||||
$password = getHashedString($password);
|
||||
|
||||
// Do not prepare $password because it is hashed and save
|
||||
// Preparing (escaping) the password would destroy the hash
|
||||
if (self::set('password', $password, true)===false) return false;
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a new dropboxKey.
|
||||
* @return boolean Returns true when successful.
|
||||
*/
|
||||
public static function setDropboxKey($dropboxKey) {
|
||||
|
||||
if (strlen($dropboxKey)<1||strlen($dropboxKey)>50) {
|
||||
Log::notice(Database::get(), __METHOD__, __LINE__, 'Dropbox key is either too short or too long');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (self::set('dropboxKey', $dropboxKey)===false) return false;
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a new sorting for the photos.
|
||||
* @return boolean Returns true when successful.
|
||||
*/
|
||||
public static function setSortingPhotos($type, $order) {
|
||||
|
||||
$sorting = 'ORDER BY ';
|
||||
|
||||
// Set row
|
||||
switch ($type) {
|
||||
|
||||
case 'id': $sorting .= 'id'; break;
|
||||
case 'title': $sorting .= 'title'; break;
|
||||
case 'description': $sorting .= 'description'; break;
|
||||
case 'public': $sorting .= 'public'; break;
|
||||
case 'type': $sorting .= 'type'; break;
|
||||
case 'star': $sorting .= 'star'; break;
|
||||
case 'takestamp': $sorting .= 'takestamp'; break;
|
||||
default: Log::error(Database::get(), __METHOD__, __LINE__, 'Could not update settings. Unknown type for sorting.');
|
||||
return false;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
$sorting .= ' ';
|
||||
|
||||
// Set order
|
||||
switch ($order) {
|
||||
|
||||
case 'ASC': $sorting .= 'ASC'; break;
|
||||
case 'DESC': $sorting .= 'DESC'; break;
|
||||
default: Log::error(Database::get(), __METHOD__, __LINE__, 'Could not update settings. Unknown order for sorting.');
|
||||
return false;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
// Do not prepare $sorting because it is a true statement
|
||||
// Preparing (escaping) the sorting would destroy it
|
||||
// $sorting is save and can't contain user-input
|
||||
if (self::set('sortingPhotos', $sorting, true)===false) return false;
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a new sorting for the albums.
|
||||
* @return boolean Returns true when successful.
|
||||
*/
|
||||
public static function setSortingAlbums($type, $order) {
|
||||
|
||||
$sorting = 'ORDER BY ';
|
||||
|
||||
// Set row
|
||||
switch ($type) {
|
||||
|
||||
case 'id': $sorting .= 'id'; break;
|
||||
case 'title': $sorting .= 'title'; break;
|
||||
case 'description': $sorting .= 'description'; break;
|
||||
case 'public': $sorting .= 'public'; break;
|
||||
default: Log::error(Database::get(), __METHOD__, __LINE__, 'Could not update settings. Unknown type for sorting.');
|
||||
return false;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
$sorting .= ' ';
|
||||
|
||||
// Set order
|
||||
switch ($order) {
|
||||
|
||||
case 'ASC': $sorting .= 'ASC'; break;
|
||||
case 'DESC': $sorting .= 'DESC'; break;
|
||||
default: Log::error(Database::get(), __METHOD__, __LINE__, 'Could not update settings. Unknown order for sorting.');
|
||||
return false;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
// Do not prepare $sorting because it is a true statement
|
||||
// Preparing (escaping) the sorting would destroy it
|
||||
// $sorting is save and can't contain user-input
|
||||
if (self::set('sortingAlbums', $sorting, true)===false) return false;
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
41
php/Modules/Validator.php
Normal file
41
php/Modules/Validator.php
Normal file
@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace Lychee\Modules;
|
||||
|
||||
final class Validator {
|
||||
|
||||
public static function required($available = false, $function) {
|
||||
|
||||
if ($available===false) Response::error('Missing parameters. Can not execute function ' . $function);
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
public static function isAlbumIDs($albumIDs) {
|
||||
|
||||
return (preg_match('/^[0-9\,]{1,}$/', $albumIDs)===1 ? true : false);
|
||||
|
||||
}
|
||||
|
||||
public static function isAlbumID($albumID) {
|
||||
|
||||
return (preg_match('/^[0-9sfr]{1,}$/', $albumID)===1 ? true : false);
|
||||
|
||||
}
|
||||
|
||||
public static function isPhotoIDs($photoIDs) {
|
||||
|
||||
return (preg_match('/^[0-9\,]{1,}$/', $photoIDs)===1 ? true : false);
|
||||
|
||||
}
|
||||
|
||||
public static function isPhotoID($photoID) {
|
||||
|
||||
return (preg_match('/^[0-9]{14}$/', $photoID)===1 ? true : false);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
@ -1,29 +0,0 @@
|
||||
<?php
|
||||
|
||||
###
|
||||
# @name Access
|
||||
# @copyright 2015 by Tobias Reich
|
||||
###
|
||||
|
||||
if (!defined('LYCHEE')) exit('Error: Direct access is not allowed!');
|
||||
|
||||
class Access {
|
||||
|
||||
protected $database = null;
|
||||
protected $plugins = null;
|
||||
protected $settings = null;
|
||||
|
||||
public function __construct($database, $plugins, $settings) {
|
||||
|
||||
# Init vars
|
||||
$this->database = $database;
|
||||
$this->plugins = $plugins;
|
||||
$this->settings = $settings;
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
@ -1,321 +0,0 @@
|
||||
<?php
|
||||
|
||||
###
|
||||
# @name Admin Access
|
||||
# @copyright 2015 by Tobias Reich
|
||||
###
|
||||
|
||||
if (!defined('LYCHEE')) exit('Error: Direct access is not allowed!');
|
||||
if (!defined('LYCHEE_ACCESS_ADMIN')) exit('Error: You are not allowed to access this area!');
|
||||
|
||||
class Admin extends Access {
|
||||
|
||||
public function check($fn) {
|
||||
|
||||
switch ($fn) {
|
||||
|
||||
# Album functions
|
||||
case 'Album::getAll': $this->getAlbums(); break;
|
||||
case 'Album::get': $this->getAlbum(); break;
|
||||
case 'Album::add': $this->addAlbum(); break;
|
||||
case 'Album::setTitle': $this->setAlbumTitle(); break;
|
||||
case 'Album::setDescription': $this->setAlbumDescription(); break;
|
||||
case 'Album::setPublic': $this->setAlbumPublic(); break;
|
||||
case 'Album::delete': $this->deleteAlbum(); break;
|
||||
case 'Album::merge': $this->mergeAlbums(); break;
|
||||
|
||||
# Photo functions
|
||||
case 'Photo::get': $this->getPhoto(); break;
|
||||
case 'Photo::setTitle': $this->setPhotoTitle(); break;
|
||||
case 'Photo::setDescription': $this->setPhotoDescription(); break;
|
||||
case 'Photo::setStar': $this->setPhotoStar(); break;
|
||||
case 'Photo::setPublic': $this->setPhotoPublic(); break;
|
||||
case 'Photo::setAlbum': $this->setPhotoAlbum(); break;
|
||||
case 'Photo::setTags': $this->setPhotoTags(); break;
|
||||
case 'Photo::duplicate': $this->duplicatePhoto(); break;
|
||||
case 'Photo::delete': $this->deletePhoto(); break;
|
||||
|
||||
# Add functions
|
||||
case 'Photo::add': $this->upload(); break;
|
||||
case 'Import::url': $this->importUrl(); break;
|
||||
case 'Import::server': $this->importServer(); break;
|
||||
|
||||
# Search functions
|
||||
case 'search': $this->search(); break;
|
||||
|
||||
# Session functions
|
||||
case 'Session::init': $this->init(); break;
|
||||
case 'Session::login': $this->login(); break;
|
||||
case 'Session::logout': $this->logout(); break;
|
||||
|
||||
# Settings functions
|
||||
case 'Settings::setLogin': $this->setLogin(); break;
|
||||
case 'Settings::setSorting': $this->setSorting(); break;
|
||||
case 'Settings::setDropboxKey': $this->setDropboxKey(); break;
|
||||
|
||||
# $_GET functions
|
||||
case 'Album::getArchive': $this->getAlbumArchive(); break;
|
||||
case 'Photo::getArchive': $this->getPhotoArchive(); break;
|
||||
|
||||
# Error
|
||||
default: exit('Error: Function not found! Please check the spelling of the called function.');
|
||||
return false; break;
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
# Album functions
|
||||
|
||||
private function getAlbums() {
|
||||
|
||||
$album = new Album($this->database, $this->plugins, $this->settings, null);
|
||||
echo json_encode($album->getAll(false));
|
||||
|
||||
}
|
||||
|
||||
private function getAlbum() {
|
||||
|
||||
Module::dependencies(isset($_POST['albumID']));
|
||||
$album = new Album($this->database, $this->plugins, $this->settings, $_POST['albumID']);
|
||||
echo json_encode($album->get());
|
||||
|
||||
}
|
||||
|
||||
private function addAlbum() {
|
||||
|
||||
Module::dependencies(isset($_POST['title']));
|
||||
$album = new Album($this->database, $this->plugins, $this->settings, null);
|
||||
echo $album->add($_POST['title']);
|
||||
|
||||
}
|
||||
|
||||
private function setAlbumTitle() {
|
||||
|
||||
Module::dependencies(isset($_POST['albumIDs'], $_POST['title']));
|
||||
$album = new Album($this->database, $this->plugins, $this->settings, $_POST['albumIDs']);
|
||||
echo $album->setTitle($_POST['title']);
|
||||
|
||||
}
|
||||
|
||||
private function setAlbumDescription() {
|
||||
|
||||
Module::dependencies(isset($_POST['albumID'], $_POST['description']));
|
||||
$album = new Album($this->database, $this->plugins, $this->settings, $_POST['albumID']);
|
||||
echo $album->setDescription($_POST['description']);
|
||||
|
||||
}
|
||||
|
||||
private function setAlbumPublic() {
|
||||
|
||||
Module::dependencies(isset($_POST['albumID'], $_POST['password'], $_POST['visible'], $_POST['downloadable']));
|
||||
$album = new Album($this->database, $this->plugins, $this->settings, $_POST['albumID']);
|
||||
echo $album->setPublic($_POST['public'], $_POST['password'], $_POST['visible'], $_POST['downloadable']);
|
||||
|
||||
}
|
||||
|
||||
private function deleteAlbum() {
|
||||
|
||||
Module::dependencies(isset($_POST['albumIDs']));
|
||||
$album = new Album($this->database, $this->plugins, $this->settings, $_POST['albumIDs']);
|
||||
echo $album->delete();
|
||||
|
||||
}
|
||||
|
||||
private function mergeAlbums() {
|
||||
|
||||
Module::dependencies(isset($_POST['albumIDs']));
|
||||
$album = new Album($this->database, $this->plugins, $this->settings, $_POST['albumIDs']);
|
||||
echo $album->merge();
|
||||
|
||||
}
|
||||
|
||||
# Photo functions
|
||||
|
||||
private function getPhoto() {
|
||||
|
||||
Module::dependencies(isset($_POST['photoID'], $_POST['albumID']));
|
||||
$photo = new Photo($this->database, $this->plugins, null, $_POST['photoID']);
|
||||
echo json_encode($photo->get($_POST['albumID']));
|
||||
|
||||
}
|
||||
|
||||
private function setPhotoTitle() {
|
||||
|
||||
Module::dependencies(isset($_POST['photoIDs'], $_POST['title']));
|
||||
$photo = new Photo($this->database, $this->plugins, null, $_POST['photoIDs']);
|
||||
echo $photo->setTitle($_POST['title']);
|
||||
|
||||
}
|
||||
|
||||
private function setPhotoDescription() {
|
||||
|
||||
Module::dependencies(isset($_POST['photoID'], $_POST['description']));
|
||||
$photo = new Photo($this->database, $this->plugins, null, $_POST['photoID']);
|
||||
echo $photo->setDescription($_POST['description']);
|
||||
|
||||
}
|
||||
|
||||
private function setPhotoStar() {
|
||||
|
||||
Module::dependencies(isset($_POST['photoIDs']));
|
||||
$photo = new Photo($this->database, $this->plugins, null, $_POST['photoIDs']);
|
||||
echo $photo->setStar();
|
||||
|
||||
}
|
||||
|
||||
private function setPhotoPublic() {
|
||||
|
||||
Module::dependencies(isset($_POST['photoID']));
|
||||
$photo = new Photo($this->database, $this->plugins, null, $_POST['photoID']);
|
||||
echo $photo->setPublic();
|
||||
|
||||
}
|
||||
|
||||
private function setPhotoAlbum() {
|
||||
|
||||
Module::dependencies(isset($_POST['photoIDs'], $_POST['albumID']));
|
||||
$photo = new Photo($this->database, $this->plugins, null, $_POST['photoIDs']);
|
||||
echo $photo->setAlbum($_POST['albumID']);
|
||||
|
||||
}
|
||||
|
||||
private function setPhotoTags() {
|
||||
|
||||
Module::dependencies(isset($_POST['photoIDs'], $_POST['tags']));
|
||||
$photo = new Photo($this->database, $this->plugins, null, $_POST['photoIDs']);
|
||||
echo $photo->setTags($_POST['tags']);
|
||||
|
||||
}
|
||||
|
||||
private function duplicatePhoto() {
|
||||
|
||||
Module::dependencies(isset($_POST['photoIDs']));
|
||||
$photo = new Photo($this->database, $this->plugins, null, $_POST['photoIDs']);
|
||||
echo $photo->duplicate();
|
||||
|
||||
}
|
||||
|
||||
private function deletePhoto() {
|
||||
|
||||
Module::dependencies(isset($_POST['photoIDs']));
|
||||
$photo = new Photo($this->database, $this->plugins, null, $_POST['photoIDs']);
|
||||
echo $photo->delete();
|
||||
|
||||
}
|
||||
|
||||
# Add functions
|
||||
|
||||
private function upload() {
|
||||
|
||||
Module::dependencies(isset($_FILES, $_POST['albumID'], $_POST['tags']));
|
||||
$photo = new Photo($this->database, $this->plugins, $this->settings, null);
|
||||
echo $photo->add($_FILES, $_POST['albumID'], '', $_POST['tags']);
|
||||
|
||||
}
|
||||
|
||||
private function importUrl() {
|
||||
|
||||
Module::dependencies(isset($_POST['url'], $_POST['albumID']));
|
||||
$import = new Import($this->database, $this->plugins, $this->settings);
|
||||
echo $import->url($_POST['url'], $_POST['albumID']);
|
||||
|
||||
}
|
||||
|
||||
private function importServer() {
|
||||
|
||||
Module::dependencies(isset($_POST['albumID'], $_POST['path']));
|
||||
$import = new Import($this->database, $this->plugins, $this->settings);
|
||||
echo $import->server($_POST['path'], $_POST['albumID']);
|
||||
|
||||
}
|
||||
|
||||
# Search function
|
||||
|
||||
private function search() {
|
||||
|
||||
Module::dependencies(isset($_POST['term']));
|
||||
echo json_encode(search($this->database, $this->settings, $_POST['term']));
|
||||
|
||||
}
|
||||
|
||||
# Session functions
|
||||
|
||||
private function init() {
|
||||
|
||||
global $dbName;
|
||||
|
||||
Module::dependencies(isset($_POST['version']));
|
||||
$session = new Session($this->plugins, $this->settings);
|
||||
echo json_encode($session->init($this->database, $dbName, false, $_POST['version']));
|
||||
|
||||
}
|
||||
|
||||
private function login() {
|
||||
|
||||
Module::dependencies(isset($_POST['user'], $_POST['password']));
|
||||
$session = new Session($this->plugins, $this->settings);
|
||||
echo $session->login($_POST['user'], $_POST['password']);
|
||||
|
||||
}
|
||||
|
||||
private function logout() {
|
||||
|
||||
$session = new Session($this->plugins, $this->settings);
|
||||
echo $session->logout();
|
||||
|
||||
}
|
||||
|
||||
# Settings functions
|
||||
|
||||
private function setLogin() {
|
||||
|
||||
Module::dependencies(isset($_POST['username'], $_POST['password']));
|
||||
if (!isset($_POST['oldPassword'])) $_POST['oldPassword'] = '';
|
||||
$this->settings = new Settings($this->database);
|
||||
echo $this->settings->setLogin($_POST['oldPassword'], $_POST['username'], $_POST['password']);
|
||||
|
||||
}
|
||||
|
||||
private function setSorting() {
|
||||
|
||||
Module::dependencies(isset($_POST['typeAlbums'], $_POST['orderAlbums'], $_POST['typePhotos'], $_POST['orderPhotos']));
|
||||
$this->settings = new Settings($this->database);
|
||||
|
||||
$sA = $this->settings->setSortingAlbums($_POST['typeAlbums'], $_POST['orderAlbums']);
|
||||
$sP = $this->settings->setSortingPhotos($_POST['typePhotos'], $_POST['orderPhotos']);
|
||||
|
||||
if ($sA===true&&$sP===true) echo true;
|
||||
else echo false;
|
||||
|
||||
}
|
||||
|
||||
private function setDropboxKey() {
|
||||
|
||||
Module::dependencies(isset($_POST['key']));
|
||||
$this->settings = new Settings($this->database);
|
||||
echo $this->settings->setDropboxKey($_POST['key']);
|
||||
|
||||
}
|
||||
|
||||
# Get functions
|
||||
|
||||
private function getAlbumArchive() {
|
||||
|
||||
Module::dependencies(isset($_GET['albumID']));
|
||||
$album = new Album($this->database, $this->plugins, $this->settings, $_GET['albumID']);
|
||||
$album->getArchive();
|
||||
|
||||
}
|
||||
|
||||
private function getPhotoArchive() {
|
||||
|
||||
Module::dependencies(isset($_GET['photoID']));
|
||||
$photo = new Photo($this->database, $this->plugins, null, $_GET['photoID']);
|
||||
$photo->getArchive();
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,180 +0,0 @@
|
||||
<?php
|
||||
|
||||
###
|
||||
# @name Guest Access (Public Mode)
|
||||
# @copyright 2015 by Tobias Reich
|
||||
###
|
||||
|
||||
if (!defined('LYCHEE')) exit('Error: Direct access is not allowed!');
|
||||
if (!defined('LYCHEE_ACCESS_GUEST')) exit('Error: You are not allowed to access this area!');
|
||||
|
||||
class Guest extends Access {
|
||||
|
||||
public function check($fn) {
|
||||
|
||||
switch ($fn) {
|
||||
|
||||
# Album functions
|
||||
case 'Album::getAll': $this->getAlbums(); break;
|
||||
case 'Album::get': $this->getAlbum(); break;
|
||||
case 'Album::getPublic': $this->checkAlbumAccess(); break;
|
||||
|
||||
# Photo functions
|
||||
case 'Photo::get': $this->getPhoto(); break;
|
||||
|
||||
# Session functions
|
||||
case 'Session::init': $this->init(); break;
|
||||
case 'Session::login': $this->login(); break;
|
||||
case 'Session::logout': $this->logout(); break;
|
||||
|
||||
# $_GET functions
|
||||
case 'Album::getArchive': $this->getAlbumArchive(); break;
|
||||
case 'Photo::getArchive': $this->getPhotoArchive(); break;
|
||||
|
||||
# Error
|
||||
default: exit('Error: Function not found! Please check the spelling of the called function.');
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
# Album functions
|
||||
|
||||
private function getAlbums() {
|
||||
|
||||
$album = new Album($this->database, $this->plugins, $this->settings, null);
|
||||
echo json_encode($album->getAll(true));
|
||||
|
||||
}
|
||||
|
||||
private function getAlbum() {
|
||||
|
||||
Module::dependencies(isset($_POST['albumID'], $_POST['password']));
|
||||
$album = new Album($this->database, $this->plugins, $this->settings, $_POST['albumID']);
|
||||
|
||||
if ($album->getPublic()) {
|
||||
|
||||
# Album public
|
||||
if ($album->checkPassword($_POST['password'])) echo json_encode($album->get());
|
||||
else echo 'Warning: Wrong password!';
|
||||
|
||||
} else {
|
||||
|
||||
# Album private
|
||||
echo 'Warning: Album private!';
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private function checkAlbumAccess() {
|
||||
|
||||
Module::dependencies(isset($_POST['albumID'], $_POST['password']));
|
||||
$album = new Album($this->database, $this->plugins, $this->settings, $_POST['albumID']);
|
||||
|
||||
if ($album->getPublic()) {
|
||||
|
||||
# Album public
|
||||
if ($album->checkPassword($_POST['password'])) echo true;
|
||||
else echo false;
|
||||
|
||||
} else {
|
||||
|
||||
# Album private
|
||||
echo false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
# Photo functions
|
||||
|
||||
private function getPhoto() {
|
||||
|
||||
Module::dependencies(isset($_POST['photoID'], $_POST['albumID'], $_POST['password']));
|
||||
$photo = new Photo($this->database, $this->plugins, null, $_POST['photoID']);
|
||||
|
||||
$pgP = $photo->getPublic($_POST['password']);
|
||||
|
||||
if ($pgP===2) echo json_encode($photo->get($_POST['albumID']));
|
||||
else if ($pgP===1) echo 'Warning: Wrong password!';
|
||||
else if ($pgP===0) echo 'Warning: Photo private!';
|
||||
|
||||
}
|
||||
|
||||
# Session functions
|
||||
|
||||
private function init() {
|
||||
|
||||
global $dbName;
|
||||
|
||||
$session = new Session($this->plugins, $this->settings);
|
||||
echo json_encode($session->init($this->database, $dbName, true, $_POST['version']));
|
||||
|
||||
}
|
||||
|
||||
private function login() {
|
||||
|
||||
Module::dependencies(isset($_POST['user'], $_POST['password']));
|
||||
$session = new Session($this->plugins, $this->settings);
|
||||
echo $session->login($_POST['user'], $_POST['password']);
|
||||
|
||||
}
|
||||
|
||||
private function logout() {
|
||||
|
||||
$session = new Session($this->plugins, $this->settings);
|
||||
echo $session->logout();
|
||||
|
||||
}
|
||||
|
||||
# $_GET functions
|
||||
|
||||
private function getAlbumArchive() {
|
||||
|
||||
Module::dependencies(isset($_GET['albumID'], $_GET['password']));
|
||||
$album = new Album($this->database, $this->plugins, $this->settings, $_GET['albumID']);
|
||||
|
||||
if ($album->getPublic()&&$album->getDownloadable()) {
|
||||
|
||||
# Album Public
|
||||
if ($album->checkPassword($_GET['password'])) $album->getArchive();
|
||||
else exit('Warning: Wrong password!');
|
||||
|
||||
} else {
|
||||
|
||||
# Album Private
|
||||
exit('Warning: Album private or not downloadable!');
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private function getPhotoArchive() {
|
||||
|
||||
Module::dependencies(isset($_GET['photoID'], $_GET['password']));
|
||||
$photo = new Photo($this->database, $this->plugins, null, $_GET['photoID']);
|
||||
|
||||
$pgP = $photo->getPublic($_GET['password']);
|
||||
|
||||
# Photo Download
|
||||
if ($pgP===2) {
|
||||
|
||||
# Photo Public
|
||||
$photo->getArchive();
|
||||
|
||||
} else {
|
||||
|
||||
# Photo Private
|
||||
exit('Warning: Photo private or password incorrect!');
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
@ -1,47 +0,0 @@
|
||||
<?php
|
||||
|
||||
###
|
||||
# @name Installation Access
|
||||
# @copyright 2015 by Tobias Reich
|
||||
###
|
||||
|
||||
if (!defined('LYCHEE')) exit('Error: Direct access is not allowed!');
|
||||
if (!defined('LYCHEE_ACCESS_INSTALLATION')) exit('Error: You are not allowed to access this area!');
|
||||
|
||||
class Installation extends Access {
|
||||
|
||||
public function check($fn) {
|
||||
|
||||
switch ($fn) {
|
||||
|
||||
case 'Database::createConfig': $this->dbCreateConfig(); break;
|
||||
|
||||
# Error
|
||||
default: $this->init(); break;
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
private function dbCreateConfig() {
|
||||
|
||||
Module::dependencies(isset($_POST['dbHost'], $_POST['dbUser'], $_POST['dbPassword'], $_POST['dbName'], $_POST['dbTablePrefix']));
|
||||
echo Database::createConfig($_POST['dbHost'], $_POST['dbUser'], $_POST['dbPassword'], $_POST['dbName'], $_POST['dbTablePrefix']);
|
||||
|
||||
}
|
||||
|
||||
private function init() {
|
||||
|
||||
$return = array(
|
||||
'status' => LYCHEE_STATUS_NOCONFIG
|
||||
);
|
||||
|
||||
echo json_encode($return);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
93
php/api.php
93
php/api.php
@ -1,93 +0,0 @@
|
||||
<?php
|
||||
|
||||
###
|
||||
# @name API
|
||||
# @copyright 2015 by Tobias Reich
|
||||
###
|
||||
|
||||
if (!empty($_POST['function'])||!empty($_GET['function'])) {
|
||||
|
||||
session_start();
|
||||
date_default_timezone_set('UTC');
|
||||
|
||||
# Load required files
|
||||
require(__DIR__ . '/define.php');
|
||||
require(__DIR__ . '/autoload.php');
|
||||
require(__DIR__ . '/modules/misc.php');
|
||||
|
||||
if (file_exists(LYCHEE_CONFIG_FILE)) require(LYCHEE_CONFIG_FILE);
|
||||
else {
|
||||
|
||||
###
|
||||
# Installation Access
|
||||
# Limited access to configure Lychee. Only available when the config.php file is missing.
|
||||
###
|
||||
|
||||
define('LYCHEE_ACCESS_INSTALLATION', true);
|
||||
|
||||
$installation = new Installation(null, null, null);
|
||||
$installation->check($_POST['function']);
|
||||
|
||||
exit();
|
||||
|
||||
}
|
||||
|
||||
# Define the table prefix
|
||||
if (!isset($dbTablePrefix)) $dbTablePrefix = '';
|
||||
defineTablePrefix($dbTablePrefix);
|
||||
|
||||
# Connect to database
|
||||
$database = Database::connect($dbHost, $dbUser, $dbPassword, $dbName);
|
||||
|
||||
# Load settings
|
||||
$settings = new Settings($database);
|
||||
$settings = $settings->get();
|
||||
|
||||
# Init plugins
|
||||
$plugins = explode(';', $settings['plugins']);
|
||||
$plugins = new Plugins($plugins, $database, $settings);
|
||||
|
||||
# Validate parameters
|
||||
if (isset($_POST['albumIDs'])&&preg_match('/^[0-9\,]{1,}$/', $_POST['albumIDs'])!==1) exit('Error: Wrong parameter type for albumIDs!');
|
||||
if (isset($_POST['photoIDs'])&&preg_match('/^[0-9\,]{1,}$/', $_POST['photoIDs'])!==1) exit('Error: Wrong parameter type for photoIDs!');
|
||||
if (isset($_POST['albumID'])&&preg_match('/^[0-9sfr]{1,}$/', $_POST['albumID'])!==1) exit('Error: Wrong parameter type for albumID!');
|
||||
if (isset($_POST['photoID'])&&preg_match('/^[0-9]{14}$/', $_POST['photoID'])!==1) exit('Error: Wrong parameter type for photoID!');
|
||||
|
||||
# Function for switch statement
|
||||
if (isset($_POST['function'])) $fn = $_POST['function'];
|
||||
else $fn = $_GET['function'];
|
||||
|
||||
if ((isset($_SESSION['login'])&&$_SESSION['login']===true)&&
|
||||
(isset($_SESSION['identifier'])&&$_SESSION['identifier']===$settings['identifier'])) {
|
||||
|
||||
###
|
||||
# Admin Access
|
||||
# Full access to Lychee. Only with correct password/session.
|
||||
###
|
||||
|
||||
define('LYCHEE_ACCESS_ADMIN', true);
|
||||
|
||||
$admin = new Admin($database, $plugins, $settings);
|
||||
$admin->check($fn);
|
||||
|
||||
} else {
|
||||
|
||||
###
|
||||
# Guest Access
|
||||
# Access to view all public folders and photos in Lychee.
|
||||
###
|
||||
|
||||
define('LYCHEE_ACCESS_GUEST', true);
|
||||
|
||||
$guest = new Guest($database, $plugins, $settings);
|
||||
$guest->check($fn);
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
exit('Error: Called function not found!');
|
||||
|
||||
}
|
||||
|
||||
?>
|
@ -1,33 +1,24 @@
|
||||
<?php
|
||||
|
||||
###
|
||||
# @name Autoload
|
||||
# @copyright 2015 by Tobias Reich
|
||||
###
|
||||
spl_autoload_register(function($class) {
|
||||
|
||||
if (!defined('LYCHEE')) exit('Error: Direct access is not allowed!');
|
||||
$classPath = str_replace('Lychee\\', '', $class);
|
||||
$classPath = str_replace('\\', DIRECTORY_SEPARATOR, $classPath);
|
||||
|
||||
function lycheeAutoloaderModules($class_name) {
|
||||
$file = LYCHEE . 'php/' . $classPath . '.php';
|
||||
|
||||
$modules = array('Album', 'Database', 'Import', 'Log', 'Module', 'Photo', 'Plugins', 'Session', 'Settings');
|
||||
if (!in_array($class_name, $modules)) return false;
|
||||
if (file_exists($file)===true) require $file;
|
||||
|
||||
$file = LYCHEE . 'php/modules/' . $class_name . '.php';
|
||||
if (file_exists($file)!==false) require $file;
|
||||
});
|
||||
|
||||
}
|
||||
spl_autoload_register(function($class) {
|
||||
|
||||
function lycheeAutoloaderAccess($class_name) {
|
||||
$classPath = str_replace('\\', DIRECTORY_SEPARATOR, $class);
|
||||
|
||||
$access = array('Access', 'Admin', 'Guest', 'Installation');
|
||||
if (!in_array($class_name, $access)) return false;
|
||||
$file = LYCHEE . 'plugins/' . $classPath . '.php';
|
||||
|
||||
$file = LYCHEE . 'php/access/' . $class_name . '.php';
|
||||
if (file_exists($file)!==false) require $file;
|
||||
if (file_exists($file)===true) require $file;
|
||||
|
||||
}
|
||||
|
||||
spl_autoload_register('lycheeAutoloaderModules');
|
||||
spl_autoload_register('lycheeAutoloaderAccess');
|
||||
});
|
||||
|
||||
?>
|
@ -1,9 +1,8 @@
|
||||
# Dump of table lychee_albums
|
||||
# Version 2.5
|
||||
# ------------------------------------------------------------
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `?` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`id` bigint(14) NOT NULL,
|
||||
`title` varchar(100) NOT NULL DEFAULT '',
|
||||
`description` varchar(1000) DEFAULT '',
|
||||
`sysstamp` int(11) NOT NULL,
|
||||
|
@ -1,5 +1,4 @@
|
||||
# Dump of table lychee_log
|
||||
# Version 2.5
|
||||
# ------------------------------------------------------------
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `?` (
|
||||
|
@ -1,5 +1,4 @@
|
||||
# Dump of table lychee_photos
|
||||
# Version 2.5
|
||||
# ------------------------------------------------------------
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `?` (
|
||||
|
@ -1,5 +1,4 @@
|
||||
# Content of table lychee_settings
|
||||
# Version 2.5
|
||||
# ------------------------------------------------------------
|
||||
|
||||
INSERT INTO `?` (`key`, `value`)
|
||||
@ -7,11 +6,9 @@ VALUES
|
||||
('version',''),
|
||||
('username',''),
|
||||
('password',''),
|
||||
('thumbQuality','90'),
|
||||
('checkForUpdates','1'),
|
||||
('sortingPhotos','ORDER BY id DESC'),
|
||||
('sortingAlbums','ORDER BY id DESC'),
|
||||
('medium','1'),
|
||||
('imagick','1'),
|
||||
('dropboxKey',''),
|
||||
('identifier',''),
|
||||
|
@ -1,5 +1,4 @@
|
||||
# Dump of table lychee_settings
|
||||
# Version 2.5
|
||||
# ------------------------------------------------------------
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `?` (
|
||||
|
@ -1,44 +0,0 @@
|
||||
<?php
|
||||
|
||||
###
|
||||
# @name Update to version 2.1
|
||||
# @copyright 2015 by Tobias Reich
|
||||
###
|
||||
|
||||
if (!defined('LYCHEE')) exit('Error: Direct access is not allowed!');
|
||||
|
||||
$query = Database::prepare($database, "SELECT `tags` FROM `?` LIMIT 1", array(LYCHEE_TABLE_PHOTOS));
|
||||
if(!$database->query($query)) {
|
||||
$query = Database::prepare($database, "ALTER TABLE `?` ADD `tags` VARCHAR( 1000 ) NULL DEFAULT ''", array(LYCHEE_TABLE_PHOTOS));
|
||||
$result = $database->query($query);
|
||||
if (!$result) {
|
||||
Log::error($database, 'update_020100', __LINE__, 'Could not update database (' . $database->error . ')');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$query = Database::prepare($database, "SELECT `key` FROM `?` WHERE `key` = 'dropboxKey' LIMIT 1", array(LYCHEE_TABLE_SETTINGS));
|
||||
$result = $database->query($query);
|
||||
if ($result->num_rows===0) {
|
||||
$query = Database::prepare($database, "INSERT INTO `?` (`key`, `value`) VALUES ('dropboxKey', '')", array(LYCHEE_TABLE_SETTINGS));
|
||||
$result = $database->query($query);
|
||||
if (!$result) {
|
||||
Log::error($database, 'update_020100', __LINE__, 'Could not update database (' . $database->error . ')');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$query = Database::prepare($database, "SELECT `key` FROM `?` WHERE `key` = 'version' LIMIT 1", array(LYCHEE_TABLE_SETTINGS));
|
||||
$result = $database->query($query);
|
||||
if ($result->num_rows===0) {
|
||||
$query = Database::prepare($database, "INSERT INTO `?` (`key`, `value`) VALUES ('version', '020100')", array(LYCHEE_TABLE_SETTINGS));
|
||||
$result = $database->query($query);
|
||||
if (!$result) {
|
||||
Log::error($database, 'update_020100', __LINE__, 'Could not update database (' . $database->error . ')');
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (Database::setVersion($database, '020100')===false) return false;
|
||||
}
|
||||
|
||||
?>
|
@ -1,20 +0,0 @@
|
||||
<?php
|
||||
|
||||
###
|
||||
# @name Update to version 2.1.1
|
||||
# @copyright 2015 by Tobias Reich
|
||||
###
|
||||
|
||||
if (!defined('LYCHEE')) exit('Error: Direct access is not allowed!');
|
||||
|
||||
$query = Database::prepare($database, "ALTER TABLE `?` CHANGE `value` `value` VARCHAR( 200 ) NULL DEFAULT ''", array(LYCHEE_TABLE_SETTINGS));
|
||||
$result = $database->query($query);
|
||||
if (!$result) {
|
||||
Log::error($database, 'update_020101', __LINE__, 'Could not update database (' . $database->error . ')');
|
||||
return false;
|
||||
}
|
||||
|
||||
# Set version
|
||||
if (Database::setVersion($database, '020101')===false) return false;
|
||||
|
||||
?>
|
@ -1,23 +0,0 @@
|
||||
<?php
|
||||
|
||||
###
|
||||
# @name Update to version 2.2
|
||||
# @copyright 2015 by Tobias Reich
|
||||
###
|
||||
|
||||
if (!defined('LYCHEE')) exit('Error: Direct access is not allowed!');
|
||||
|
||||
$query = Database::prepare($database, "SELECT `visible` FROM `?` LIMIT 1", array(LYCHEE_TABLE_ALBUMS));
|
||||
if (!$database->query($query)) {
|
||||
$query = Database::prepare($database, "ALTER TABLE `?` ADD `visible` TINYINT(1) NOT NULL DEFAULT 1", array(LYCHEE_TABLE_ALBUMS));
|
||||
$result = $database->query($query);
|
||||
if (!$result) {
|
||||
Log::error($database, 'update_020200', __LINE__, 'Could not update database (' . $database->error . ')');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
# Set version
|
||||
if (Database::setVersion($database, '020200')===false) return false;
|
||||
|
||||
?>
|
@ -1,156 +0,0 @@
|
||||
<?php
|
||||
|
||||
###
|
||||
# @name Update to version 2.5
|
||||
# @copyright 2015 by Tobias Reich
|
||||
###
|
||||
|
||||
if (!defined('LYCHEE')) exit('Error: Direct access is not allowed!');
|
||||
|
||||
# Add `plugins`
|
||||
$query = Database::prepare($database, "SELECT `key` FROM `?` WHERE `key` = 'plugins' LIMIT 1", array(LYCHEE_TABLE_SETTINGS));
|
||||
$result = $database->query($query);
|
||||
if ($result->num_rows===0) {
|
||||
$query = Database::prepare($database, "INSERT INTO `?` (`key`, `value`) VALUES ('plugins', '')", array(LYCHEE_TABLE_SETTINGS));
|
||||
$result = $database->query($query);
|
||||
if (!$result) {
|
||||
Log::error($database, 'update_020500', __LINE__, 'Could not update database (' . $database->error . ')');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
# Add `takestamp`
|
||||
$query = Database::prepare($database, "SELECT `takestamp` FROM `?` LIMIT 1;", array(LYCHEE_TABLE_PHOTOS));
|
||||
if (!$database->query($query)) {
|
||||
$query = Database::prepare($database, "ALTER TABLE `?` ADD `takestamp` INT(11) DEFAULT NULL", array(LYCHEE_TABLE_PHOTOS));
|
||||
$result = $database->query($query);
|
||||
if (!$result) {
|
||||
Log::error($database, 'update_020500', __LINE__, 'Could not update database (' . $database->error . ')');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
# Convert to `takestamp`
|
||||
$query = Database::prepare($database, "SELECT `takedate`, `taketime` FROM `?` LIMIT 1;", array(LYCHEE_TABLE_PHOTOS));
|
||||
if ($database->query($query)) {
|
||||
$query = Database::prepare($database, "SELECT `id`, `takedate`, `taketime` FROM `?` WHERE `takedate` <> '' AND `taketime` <> ''", array(LYCHEE_TABLE_PHOTOS));
|
||||
$result = $database->query($query);
|
||||
if (!$result) {
|
||||
Log::error($database, 'update_020500', __LINE__, 'Could not update database (' . $database->error . ')');
|
||||
return false;
|
||||
}
|
||||
while ($photo = $result->fetch_object()) {
|
||||
$takestamp = strtotime($photo->takedate . $photo->taketime);
|
||||
$query = Database::prepare($database, "UPDATE `?` SET `takestamp` = '?' WHERE `id` = '?'", array(LYCHEE_TABLE_PHOTOS, $takestamp, $photo->id));
|
||||
$database->query($query);
|
||||
}
|
||||
$query = Database::prepare($database, "ALTER TABLE `?` DROP COLUMN `takedate`;", array(LYCHEE_TABLE_PHOTOS));
|
||||
$result = $database->query($query);
|
||||
$query = Database::prepare($database, "ALTER TABLE `?` DROP COLUMN `taketime`", array(LYCHEE_TABLE_PHOTOS));
|
||||
$result = $database->query($query);
|
||||
}
|
||||
|
||||
# Remove `import_name`
|
||||
$query = Database::prepare($database, "SELECT `import_name` FROM `?` LIMIT 1", array(LYCHEE_TABLE_PHOTOS));
|
||||
if ($database->query($query)) {
|
||||
$query = Database::prepare($database, "ALTER TABLE `?` DROP COLUMN `import_name`", array(LYCHEE_TABLE_PHOTOS));
|
||||
$result = $database->query($query);
|
||||
}
|
||||
|
||||
# Remove `sysdate` and `systime`
|
||||
$query = Database::prepare($database, "SELECT `sysdate`, `systime` FROM `?` LIMIT 1", array(LYCHEE_TABLE_PHOTOS));
|
||||
if ($database->query($query)) {
|
||||
$query = Database::prepare($database, "ALTER TABLE `?` DROP COLUMN `sysdate`", array(LYCHEE_TABLE_PHOTOS));
|
||||
$result = $database->query($query);
|
||||
$query = Database::prepare($database, "ALTER TABLE `?` DROP COLUMN `systime`", array(LYCHEE_TABLE_PHOTOS));
|
||||
$result = $database->query($query);
|
||||
}
|
||||
|
||||
# Add `sysstamp`
|
||||
$query = Database::prepare($database, "SELECT `sysstamp` FROM `?` LIMIT 1", array(LYCHEE_TABLE_ALBUMS));
|
||||
if (!$database->query($query)) {
|
||||
$query = Database::prepare($database, "ALTER TABLE `?` ADD `sysstamp` INT(11) DEFAULT NULL", array(LYCHEE_TABLE_ALBUMS));
|
||||
$result = $database->query($query);
|
||||
if (!$result) {
|
||||
Log::error($database, 'update_020500', __LINE__, 'Could not update database (' . $database->error . ')');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
# Convert to `sysstamp`
|
||||
$query = Database::prepare($database, "SELECT `sysdate` FROM `?` LIMIT 1", array(LYCHEE_TABLE_ALBUMS));
|
||||
if ($database->query($query)) {
|
||||
$query = Database::prepare($database, "SELECT `id`, `sysdate` FROM `?`", array(LYCHEE_TABLE_ALBUMS));
|
||||
$result = $database->query($query);
|
||||
if (!$result) {
|
||||
Log::error($database, 'update_020500', __LINE__, 'Could not update database (' . $database->error . ')');
|
||||
return false;
|
||||
}
|
||||
while ($album = $result->fetch_object()) {
|
||||
$sysstamp = strtotime($album->sysdate);
|
||||
$query = Database::prepare($database, "UPDATE `?` SET `sysstamp` = '?' WHERE `id` = '?'", array(LYCHEE_TABLE_ALBUMS, $sysstamp, $album->id));
|
||||
$database->query($query);
|
||||
}
|
||||
$query = Database::prepare($database, "ALTER TABLE `?` DROP COLUMN `sysdate`", array(LYCHEE_TABLE_ALBUMS));
|
||||
$result = $database->query($query);
|
||||
}
|
||||
|
||||
# Set character of database
|
||||
$result = $database->query("ALTER DATABASE $dbName CHARACTER SET utf8 COLLATE utf8_general_ci;");
|
||||
if (!$result) {
|
||||
Log::error($database, 'update_020500', __LINE__, 'Could not update database (' . $database->error . ')');
|
||||
return false;
|
||||
}
|
||||
|
||||
# Set character
|
||||
$query = Database::prepare($database, "ALTER TABLE `?` CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci", array(LYCHEE_TABLE_ALBUMS));
|
||||
$result = $database->query($query);
|
||||
if (!$result) {
|
||||
Log::error($database, 'update_020500', __LINE__, 'Could not update database (' . $database->error . ')');
|
||||
return false;
|
||||
}
|
||||
|
||||
# Set character
|
||||
$query = Database::prepare($database, "ALTER TABLE `?` CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci", array(LYCHEE_TABLE_PHOTOS));
|
||||
$result = $database->query($query);
|
||||
if (!$result) {
|
||||
Log::error($database, 'update_020500', __LINE__, 'Could not update database (' . $database->error . ')');
|
||||
return false;
|
||||
}
|
||||
|
||||
# Set character
|
||||
$query = Database::prepare($database, "ALTER TABLE `?` CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci", array(LYCHEE_TABLE_SETTINGS));
|
||||
$result = $database->query($query);
|
||||
if (!$result) {
|
||||
Log::error($database, 'update_020500', __LINE__, 'Could not update database (' . $database->error . ')');
|
||||
return false;
|
||||
}
|
||||
|
||||
# Set album password length to 100 (for longer hashes)
|
||||
$query = Database::prepare($database, "ALTER TABLE `?` CHANGE `password` `password` VARCHAR(100)", array(LYCHEE_TABLE_ALBUMS));
|
||||
$result = $database->query($query);
|
||||
if (!$result) {
|
||||
Log::error($database, 'update_020500', __LINE__, 'Could not update database (' . $database->error . ')');
|
||||
return false;
|
||||
}
|
||||
|
||||
# Set make length to 50
|
||||
$query = Database::prepare($database, "ALTER TABLE `?` CHANGE `make` `make` VARCHAR(50)", array(LYCHEE_TABLE_PHOTOS));
|
||||
$result = $database->query($query);
|
||||
if (!$result) {
|
||||
Log::error($database, 'update_020500', __LINE__, 'Could not update database (' . $database->error . ')');
|
||||
return false;
|
||||
}
|
||||
|
||||
# Reset sorting
|
||||
$query = Database::prepare($database, "UPDATE ? SET value = 'ORDER BY takestamp DESC' WHERE `key` = 'sorting' AND `value` LIKE '%UNIX_TIMESTAMP%'", array(LYCHEE_TABLE_SETTINGS));
|
||||
$result = $database->query($query);
|
||||
if (!$result) {
|
||||
Log::error($database, 'update_020500', __LINE__, 'Could not update database (' . $database->error . ')');
|
||||
return false;
|
||||
}
|
||||
|
||||
# Set version
|
||||
if (Database::setVersion($database, '020500')===false) return false;
|
||||
|
||||
?>
|
@ -1,24 +0,0 @@
|
||||
<?php
|
||||
|
||||
###
|
||||
# @name Update to version 2.5.5
|
||||
# @copyright 2015 by Tobias Reich
|
||||
###
|
||||
|
||||
if (!defined('LYCHEE')) exit('Error: Direct access is not allowed!');
|
||||
|
||||
# Add `checksum`
|
||||
$query = Database::prepare($database, "SELECT `checksum` FROM `?` LIMIT 1", array(LYCHEE_TABLE_PHOTOS));
|
||||
if (!$database->query($query)) {
|
||||
$query = Database::prepare($database, "ALTER TABLE `?` ADD `checksum` VARCHAR(100) DEFAULT NULL", array(LYCHEE_TABLE_PHOTOS));
|
||||
$result = $database->query($query);
|
||||
if (!$result) {
|
||||
Log::error($database, 'update_020505', __LINE__, 'Could not update database (' . $database->error . ')');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
# Set version
|
||||
if (Database::setVersion($database, '020505')===false) return false;
|
||||
|
||||
?>
|
@ -1,24 +0,0 @@
|
||||
<?php
|
||||
|
||||
###
|
||||
# @name Update to version 2.6.1
|
||||
# @copyright 2015 by Tobias Reich
|
||||
###
|
||||
|
||||
if (!defined('LYCHEE')) exit('Error: Direct access is not allowed!');
|
||||
|
||||
# Add `downloadable`
|
||||
$query = Database::prepare($database, "SELECT `downloadable` FROM `?` LIMIT 1", array(LYCHEE_TABLE_ALBUMS));
|
||||
if (!$database->query($query)) {
|
||||
$query = Database::prepare($database, "ALTER TABLE `?` ADD `downloadable` TINYINT(1) NOT NULL DEFAULT 1", array(LYCHEE_TABLE_ALBUMS));
|
||||
$result = $database->query($query);
|
||||
if (!$result) {
|
||||
Log::error($database, 'update_020601', __LINE__, 'Could not update database (' . $database->error . ')');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
# Set version
|
||||
if (Database::setVersion($database, '020601')===false) return false;
|
||||
|
||||
?>
|
@ -1,47 +0,0 @@
|
||||
<?php
|
||||
|
||||
###
|
||||
# @name Update to version 2.6.2
|
||||
# @copyright 2015 by Tobias Reich
|
||||
###
|
||||
|
||||
if (!defined('LYCHEE')) exit('Error: Direct access is not allowed!');
|
||||
|
||||
# Add a checksum
|
||||
$query = Database::prepare($database, "SELECT `id`, `url` FROM `?` WHERE `checksum` IS NULL", array(LYCHEE_TABLE_PHOTOS));
|
||||
$result = $database->query($query);
|
||||
if (!$result) {
|
||||
Log::error($database, 'update_020602', __LINE__, 'Could not find photos without checksum (' . $database->error . ')');
|
||||
return false;
|
||||
}
|
||||
while ($photo = $result->fetch_object()) {
|
||||
$checksum = sha1_file(LYCHEE_UPLOADS_BIG . $photo->url);
|
||||
if ($checksum!==false) {
|
||||
$query = Database::prepare($database, "UPDATE `?` SET `checksum` = '?' WHERE `id` = '?'", array(LYCHEE_TABLE_PHOTOS, $checksum, $photo->id));
|
||||
$setChecksum = $database->query($query);
|
||||
if (!$setChecksum) {
|
||||
Log::error($database, 'update_020602', __LINE__, 'Could not update checksum (' . $database->error . ')');
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
Log::error($database, 'update_020602', __LINE__, 'Could not calculate checksum for photo with id ' . $photo->id);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
# Add Imagick
|
||||
$query = Database::prepare($database, "SELECT `key` FROM `?` WHERE `key` = 'imagick' LIMIT 1", array(LYCHEE_TABLE_SETTINGS));
|
||||
$result = $database->query($query);
|
||||
if ($result->num_rows===0) {
|
||||
$query = Database::prepare($database, "INSERT INTO `?` (`key`, `value`) VALUES ('imagick', '1')", array(LYCHEE_TABLE_SETTINGS));
|
||||
$result = $database->query($query);
|
||||
if (!$result) {
|
||||
Log::error($database, 'update_020602', __LINE__, 'Could not update database (' . $database->error . ')');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
# Set version
|
||||
if (Database::setVersion($database, '020602')===false) return false;
|
||||
|
||||
?>
|
@ -1,43 +1,37 @@
|
||||
<?php
|
||||
|
||||
###
|
||||
# @name Update to version 2.7.0
|
||||
# @copyright 2015 by Tobias Reich
|
||||
###
|
||||
/**
|
||||
* Update to version 2.7.0
|
||||
*/
|
||||
|
||||
if (!defined('LYCHEE')) exit('Error: Direct access is not allowed!');
|
||||
use Lychee\Modules\Database;
|
||||
use Lychee\Modules\Response;
|
||||
|
||||
// Add medium to photos
|
||||
$query = Database::prepare($connection, "SELECT `medium` FROM `?` LIMIT 1", array(LYCHEE_TABLE_PHOTOS));
|
||||
$result = Database::execute($connection, $query, 'update_020700', __LINE__);
|
||||
|
||||
if ($result===false) {
|
||||
|
||||
$query = Database::prepare($connection, "ALTER TABLE `?` ADD `medium` TINYINT(1) NOT NULL DEFAULT 0", array(LYCHEE_TABLE_PHOTOS));
|
||||
$result = Database::execute($connection, $query, 'update_020700', __LINE__);
|
||||
|
||||
if ($result===false) Response::error('Could not add medium-field to database!');
|
||||
|
||||
# Add medium to photos
|
||||
$query = Database::prepare($database, "SELECT `medium` FROM `?` LIMIT 1", array(LYCHEE_TABLE_PHOTOS));
|
||||
if (!$database->query($query)) {
|
||||
$query = Database::prepare($database, "ALTER TABLE `?` ADD `medium` TINYINT(1) NOT NULL DEFAULT 0", array(LYCHEE_TABLE_PHOTOS));
|
||||
$result = $database->query($query);
|
||||
if (!$result) {
|
||||
Log::error($database, 'update_020700', __LINE__, 'Could not update database (' . $database->error . ')');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
# Create medium folder
|
||||
// Create medium folder
|
||||
if (is_dir(LYCHEE_UPLOADS_MEDIUM)===false) {
|
||||
# Only create the folder when it is missing
|
||||
if (@mkdir(LYCHEE_UPLOADS_MEDIUM)===false)
|
||||
Log::error($database, 'update_020700', __LINE__, 'Could not create medium-folder');
|
||||
}
|
||||
|
||||
# Add medium to settings
|
||||
$query = Database::prepare($database, "SELECT `key` FROM `?` WHERE `key` = 'medium' LIMIT 1", array(LYCHEE_TABLE_SETTINGS));
|
||||
$result = $database->query($query);
|
||||
if ($result->num_rows===0) {
|
||||
$query = Database::prepare($database, "INSERT INTO `?` (`key`, `value`) VALUES ('medium', '1')", array(LYCHEE_TABLE_SETTINGS));
|
||||
$result = $database->query($query);
|
||||
if (!$result) {
|
||||
Log::error($database, 'update_020700', __LINE__, 'Could not update database (' . $database->error . ')');
|
||||
return false;
|
||||
// Only create the folder when it is missing
|
||||
if (@mkdir(LYCHEE_UPLOADS_MEDIUM)===false) {
|
||||
Log::error($connection, 'update_020700', __LINE__, 'Could not create medium-folder');
|
||||
Response::error('Could not create medium-folder!');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
# Set version
|
||||
if (Database::setVersion($database, '020700')===false) return false;
|
||||
// Set version
|
||||
if (Database::setVersion($connection, '020700')===false) Response::error('Could not update version of database!');
|
||||
|
||||
?>
|
@ -1,37 +1,32 @@
|
||||
<?php
|
||||
|
||||
###
|
||||
# @name Update to version 3.0.0
|
||||
# @copyright 2015 by Tobias Reich
|
||||
###
|
||||
/**
|
||||
* Update to version 3.0.0
|
||||
*/
|
||||
|
||||
if (!defined('LYCHEE')) exit('Error: Direct access is not allowed!');
|
||||
use Lychee\Modules\Database;
|
||||
use Lychee\Modules\Response;
|
||||
|
||||
# Remove login
|
||||
# Login now saved as crypt without md5. Legacy code has been removed.
|
||||
$query = Database::prepare($database, "UPDATE `?` SET `value` = '' WHERE `key` = 'username' LIMIT 1", array(LYCHEE_TABLE_SETTINGS));
|
||||
$resetUsername = $database->query($query);
|
||||
if (!$resetUsername) {
|
||||
Log::error($database, 'update_030000', __LINE__, 'Could not reset username (' . $database->error . ')');
|
||||
return false;
|
||||
}
|
||||
$query = Database::prepare($database, "UPDATE `?` SET `value` = '' WHERE `key` = 'password' LIMIT 1", array(LYCHEE_TABLE_SETTINGS));
|
||||
$resetPassword = $database->query($query);
|
||||
if (!$resetPassword) {
|
||||
Log::error($database, 'update_030000', __LINE__, 'Could not reset password (' . $database->error . ')');
|
||||
return false;
|
||||
}
|
||||
// Remove login
|
||||
// Login now saved as crypt without md5. Legacy code has been removed.
|
||||
$query = Database::prepare($connection, "UPDATE `?` SET `value` = '' WHERE `key` = 'username' LIMIT 1", array(LYCHEE_TABLE_SETTINGS));
|
||||
$result = Database::execute($connection, $query, 'update_030000', __LINE__);
|
||||
|
||||
# Make public albums private and reset password
|
||||
# Password now saved as crypt without md5. Legacy code has been removed.
|
||||
$query = Database::prepare($database, "UPDATE `?` SET `public` = 0, `password` = NULL", array(LYCHEE_TABLE_ALBUMS));
|
||||
$resetPublic = $database->query($query);
|
||||
if (!$resetPublic) {
|
||||
Log::error($database, 'update_030000', __LINE__, 'Could not reset public albums (' . $database->error . ')');
|
||||
return false;
|
||||
}
|
||||
if ($result===false) Response::error('Could not reset username in database!');
|
||||
|
||||
# Set version
|
||||
if (Database::setVersion($database, '030000')===false) return false;
|
||||
$query = Database::prepare($connection, "UPDATE `?` SET `value` = '' WHERE `key` = 'password' LIMIT 1", array(LYCHEE_TABLE_SETTINGS));
|
||||
$result = Database::execute($connection, $query, 'update_030000', __LINE__);
|
||||
|
||||
if ($result===false) Response::error('Could not reset password in database!');
|
||||
|
||||
// Make public albums private and reset password
|
||||
// Password now saved as crypt without md5. Legacy code has been removed.
|
||||
$query = Database::prepare($connection, "UPDATE `?` SET `public` = 0, `password` = NULL", array(LYCHEE_TABLE_ALBUMS));
|
||||
$result = Database::execute($connection, $query, 'update_030000', __LINE__);
|
||||
|
||||
if ($result===false) Response::error('Could not reset publicity of photos in database!');
|
||||
|
||||
// Set version
|
||||
if (Database::setVersion($connection, '030000')===false) Response::error('Could not update version of database!');
|
||||
|
||||
?>
|
@ -1,62 +1,62 @@
|
||||
<?php
|
||||
|
||||
###
|
||||
# @name Update to version 3.0.1
|
||||
# @copyright 2015 by Tobias Reich
|
||||
###
|
||||
/**
|
||||
* Update to version 3.0.1
|
||||
*/
|
||||
|
||||
if (!defined('LYCHEE')) exit('Error: Direct access is not allowed!');
|
||||
use Lychee\Modules\Database;
|
||||
use Lychee\Modules\Response;
|
||||
|
||||
# Change length of photo title
|
||||
$query = Database::prepare($database, "ALTER TABLE `?` CHANGE `title` `title` VARCHAR( 100 ) NOT NULL DEFAULT ''", array(LYCHEE_TABLE_PHOTOS));
|
||||
$result = $database->query($query);
|
||||
if (!$result) {
|
||||
Log::error($database, 'update_030001', __LINE__, 'Could not update database (' . $database->error . ')');
|
||||
return false;
|
||||
}
|
||||
// Change length of photo title
|
||||
$query = Database::prepare($connection, "ALTER TABLE `?` CHANGE `title` `title` VARCHAR( 100 ) NOT NULL DEFAULT ''", array(LYCHEE_TABLE_PHOTOS));
|
||||
$result = Database::execute($connection, $query, 'update_030001', __LINE__);
|
||||
|
||||
# Change length of album title
|
||||
$query = Database::prepare($database, "ALTER TABLE `?` CHANGE `title` `title` VARCHAR( 100 ) NOT NULL DEFAULT ''", array(LYCHEE_TABLE_ALBUMS));
|
||||
$result = $database->query($query);
|
||||
if (!$result) {
|
||||
Log::error($database, 'update_030001', __LINE__, 'Could not update database (' . $database->error . ')');
|
||||
return false;
|
||||
}
|
||||
if ($result===false) Response::error('Could not change length of photo title in database!');
|
||||
|
||||
// Change length of album title
|
||||
$query = Database::prepare($connection, "ALTER TABLE `?` CHANGE `title` `title` VARCHAR( 100 ) NOT NULL DEFAULT ''", array(LYCHEE_TABLE_ALBUMS));
|
||||
$result = Database::execute($connection, $query, 'update_030001', __LINE__);
|
||||
|
||||
if ($result===false) Response::error('Could not change length of album title in database!');
|
||||
|
||||
// Add album sorting to settings
|
||||
$query = Database::prepare($connection, "SELECT `key` FROM `?` WHERE `key` = 'sortingAlbums' LIMIT 1", array(LYCHEE_TABLE_SETTINGS));
|
||||
$result = Database::execute($connection, $query, 'update_030001', __LINE__);
|
||||
|
||||
if ($result===false) Response::error('Could not get current album sorting from database!');
|
||||
|
||||
# Add album sorting to settings
|
||||
$query = Database::prepare($database, "SELECT `key` FROM `?` WHERE `key` = 'sortingAlbums' LIMIT 1", array(LYCHEE_TABLE_SETTINGS));
|
||||
$result = $database->query($query);
|
||||
if ($result->num_rows===0) {
|
||||
$query = Database::prepare($database, "INSERT INTO `?` (`key`, `value`) VALUES ('sortingAlbums', 'ORDER BY id DESC')", array(LYCHEE_TABLE_SETTINGS));
|
||||
$result = $database->query($query);
|
||||
if (!$result) {
|
||||
Log::error($database, 'update_030001', __LINE__, 'Could not update database (' . $database->error . ')');
|
||||
return false;
|
||||
}
|
||||
|
||||
$query = Database::prepare($connection, "INSERT INTO `?` (`key`, `value`) VALUES ('sortingAlbums', 'ORDER BY id DESC')", array(LYCHEE_TABLE_SETTINGS));
|
||||
$result = Database::execute($connection, $query, 'update_030001', __LINE__);
|
||||
|
||||
if ($result===false) Response::error('Could not add album sorting to database!');
|
||||
|
||||
}
|
||||
|
||||
# Rename sorting to sortingPhotos
|
||||
$query = Database::prepare($database, "UPDATE ? SET `key` = 'sortingPhotos' WHERE `key` = 'sorting' LIMIT 1", array(LYCHEE_TABLE_SETTINGS));
|
||||
$result = $database->query($query);
|
||||
if (!$result) {
|
||||
Log::error($database, 'update_030001', __LINE__, 'Could not update database (' . $database->error . ')');
|
||||
return false;
|
||||
}
|
||||
// Rename sorting to sortingPhotos
|
||||
$query = Database::prepare($connection, "UPDATE ? SET `key` = 'sortingPhotos' WHERE `key` = 'sorting' LIMIT 1", array(LYCHEE_TABLE_SETTINGS));
|
||||
$result = Database::execute($connection, $query, 'update_030001', __LINE__);
|
||||
|
||||
if ($result===false) Response::error('Could not rename photo sorting row in database!');
|
||||
|
||||
// Add identifier to settings
|
||||
$query = Database::prepare($connection, "SELECT `key` FROM `?` WHERE `key` = 'identifier' LIMIT 1", array(LYCHEE_TABLE_SETTINGS));
|
||||
$result = Database::execute($connection, $query, 'update_030001', __LINE__);
|
||||
|
||||
if ($result===false) Response::error('Could not get current identifier from database!');
|
||||
|
||||
# Add identifier to settings
|
||||
$query = Database::prepare($database, "SELECT `key` FROM `?` WHERE `key` = 'identifier' LIMIT 1", array(LYCHEE_TABLE_SETTINGS));
|
||||
$result = $database->query($query);
|
||||
if ($result->num_rows===0) {
|
||||
$identifier = md5(microtime(true));
|
||||
$query = Database::prepare($database, "INSERT INTO `?` (`key`, `value`) VALUES ('identifier', '?')", array(LYCHEE_TABLE_SETTINGS, $identifier));
|
||||
$result = $database->query($query);
|
||||
if (!$result) {
|
||||
Log::error($database, 'update_030001', __LINE__, 'Could not update database (' . $database->error . ')');
|
||||
return false;
|
||||
}
|
||||
|
||||
$identifier = md5(microtime(true));
|
||||
$query = Database::prepare($connection, "INSERT INTO `?` (`key`, `value`) VALUES ('identifier', '?')", array(LYCHEE_TABLE_SETTINGS, $identifier));
|
||||
$result = Database::execute($connection, $query, 'update_030001', __LINE__);
|
||||
|
||||
if ($result===false) Response::error('Could not add identifier to database!');
|
||||
|
||||
}
|
||||
|
||||
# Set version
|
||||
if (Database::setVersion($database, '030001')===false) return false;
|
||||
// Set version
|
||||
if (Database::setVersion($connection, '030001')===false) Response::error('Could not update version of database!');
|
||||
|
||||
?>
|
@ -1,25 +1,28 @@
|
||||
<?php
|
||||
|
||||
###
|
||||
# @name Update to version 3.0.3
|
||||
# @copyright 2015 by Tobias Reich
|
||||
###
|
||||
/**
|
||||
* Update to version 3.0.3
|
||||
*/
|
||||
|
||||
if (!defined('LYCHEE')) exit('Error: Direct access is not allowed!');
|
||||
use Lychee\Modules\Database;
|
||||
use Lychee\Modules\Response;
|
||||
|
||||
// Add skipDuplicates to settings
|
||||
$query = Database::prepare($connection, "SELECT `key` FROM `?` WHERE `key` = 'skipDuplicates' LIMIT 1", array(LYCHEE_TABLE_SETTINGS));
|
||||
$result = Database::execute($connection, $query, 'update_030003', __LINE__);
|
||||
|
||||
if ($result===false) Response::error('Could not get current skipDuplicates from database!');
|
||||
|
||||
# Add skipDuplicates to settings
|
||||
$query = Database::prepare($database, "SELECT `key` FROM `?` WHERE `key` = 'skipDuplicates' LIMIT 1", array(LYCHEE_TABLE_SETTINGS));
|
||||
$result = $database->query($query);
|
||||
if ($result->num_rows===0) {
|
||||
$query = Database::prepare($database, "INSERT INTO `?` (`key`, `value`) VALUES ('skipDuplicates', '0')", array(LYCHEE_TABLE_SETTINGS));
|
||||
$result = $database->query($query);
|
||||
if (!$result) {
|
||||
Log::error($database, 'update_030003', __LINE__, 'Could not update database (' . $database->error . ')');
|
||||
return false;
|
||||
}
|
||||
|
||||
$query = Database::prepare($connection, "INSERT INTO `?` (`key`, `value`) VALUES ('skipDuplicates', '0')", array(LYCHEE_TABLE_SETTINGS));
|
||||
$result = Database::execute($connection, $query, 'update_030003', __LINE__);
|
||||
|
||||
if ($result===false) Response::error('Could not add skipDuplicates to database!');
|
||||
|
||||
}
|
||||
|
||||
# Set version
|
||||
if (Database::setVersion($database, '030003')===false) return false;
|
||||
// Set version
|
||||
if (Database::setVersion($connection, '030003')===false) Response::error('Could not update version of database!');
|
||||
|
||||
?>
|
19
php/database/update_030100.php
Normal file
19
php/database/update_030100.php
Normal file
@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Update to version 3.1.0
|
||||
*/
|
||||
|
||||
use Lychee\Modules\Database;
|
||||
use Lychee\Modules\Response;
|
||||
|
||||
// Change length of album id field
|
||||
$query = Database::prepare($connection, "ALTER TABLE `?` CHANGE `id` `id` BIGINT(14) NOT NULL", array(LYCHEE_TABLE_ALBUMS));
|
||||
$result = Database::execute($connection, $query, 'update_030100', __LINE__);
|
||||
|
||||
if ($result===false) Response::error('Could not adjust the length of the album id field!');
|
||||
|
||||
// Set version
|
||||
if (Database::setVersion($connection, '030100')===false) Response::error('Could not update version of database!');
|
||||
|
||||
?>
|
@ -1,19 +1,14 @@
|
||||
<?php
|
||||
|
||||
###
|
||||
# @name Define
|
||||
# @copyright 2015 by Tobias Reich
|
||||
###
|
||||
|
||||
# Define root
|
||||
// Define root
|
||||
define('LYCHEE', substr(__DIR__, 0, -3));
|
||||
|
||||
# Define status
|
||||
// Define status
|
||||
define('LYCHEE_STATUS_NOCONFIG', 0);
|
||||
define('LYCHEE_STATUS_LOGGEDOUT', 1);
|
||||
define('LYCHEE_STATUS_LOGGEDIN', 2);
|
||||
|
||||
# Define dirs
|
||||
// Define dirs
|
||||
define('LYCHEE_DATA', LYCHEE . 'data/');
|
||||
define('LYCHEE_SRC', LYCHEE . 'src/');
|
||||
define('LYCHEE_UPLOADS', LYCHEE . 'uploads/');
|
||||
@ -23,26 +18,26 @@ define('LYCHEE_UPLOADS_THUMB', LYCHEE_UPLOADS . 'thumb/');
|
||||
define('LYCHEE_UPLOADS_IMPORT', LYCHEE_UPLOADS . 'import/');
|
||||
define('LYCHEE_PLUGINS', LYCHEE . 'plugins/');
|
||||
|
||||
# Define files
|
||||
// Define files
|
||||
define('LYCHEE_CONFIG_FILE', LYCHEE_DATA . 'config.php');
|
||||
|
||||
# Define urls
|
||||
// Define urls
|
||||
define('LYCHEE_URL_UPLOADS_BIG', 'uploads/big/');
|
||||
define('LYCHEE_URL_UPLOADS_MEDIUM', 'uploads/medium/');
|
||||
define('LYCHEE_URL_UPLOADS_THUMB', 'uploads/thumb/');
|
||||
|
||||
function defineTablePrefix($dbTablePrefix) {
|
||||
|
||||
# This part is wrapped into a function, because it needs to be called
|
||||
# after the config-file has been loaded. Other defines are also available
|
||||
# before the config-file has been loaded.
|
||||
// This part is wrapped into a function, because it needs to be called
|
||||
// after the config-file has been loaded. Other defines are available
|
||||
// before the config-file has been loaded.
|
||||
|
||||
# Parse table prefix
|
||||
# Old users do not have the table prefix stored in their config-file
|
||||
if (!isset($dbTablePrefix)||$dbTablePrefix==='') $dbTablePrefix = '';
|
||||
else $dbTablePrefix .= '_';
|
||||
// Parse table prefix
|
||||
// Old users do not have the table prefix stored in their config-file
|
||||
if (isset($dbTablePrefix)===false) $dbTablePrefix = '';
|
||||
if ($dbTablePrefix!=='') $dbTablePrefix .= '_';
|
||||
|
||||
# Define tables
|
||||
// Define tables
|
||||
define('LYCHEE_TABLE_ALBUMS', $dbTablePrefix . 'lychee_albums');
|
||||
define('LYCHEE_TABLE_LOG', $dbTablePrefix . 'lychee_log');
|
||||
define('LYCHEE_TABLE_PHOTOS', $dbTablePrefix . 'lychee_photos');
|
||||
|
35
php/helpers/fastImageCopyResampled.php
Normal file
35
php/helpers/fastImageCopyResampled.php
Normal file
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
function fastImageCopyResampled(&$dst_image, $src_image, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h, $quality = 4) {
|
||||
|
||||
/**
|
||||
* Plug-and-Play fastImageCopyResampled function replaces much slower imagecopyresampled.
|
||||
* Just include this function and change all "imagecopyresampled" references to "fastImageCopyResampled".
|
||||
* Typically from 30 to 60 times faster when reducing high resolution images down to thumbnail size using the default quality setting.
|
||||
* Author: Tim Eckel - Date: 09/07/07 - Version: 1.1 - Project: FreeRingers.net - Freely distributable - These comments must remain.
|
||||
*
|
||||
* Optional "quality" parameter (defaults is 3). Fractional values are allowed, for example 1.5. Must be greater than zero.
|
||||
* Between 0 and 1 = Fast, but mosaic results, closer to 0 increases the mosaic effect.
|
||||
* 1 = Up to 350 times faster. Poor results, looks very similar to imagecopyresized.
|
||||
* 2 = Up to 95 times faster. Images appear a little sharp, some prefer this over a quality of 3.
|
||||
* 3 = Up to 60 times faster. Will give high quality smooth results very close to imagecopyresampled, just faster.
|
||||
* 4 = Up to 25 times faster. Almost identical to imagecopyresampled for most images.
|
||||
* 5 = No speedup. Just uses imagecopyresampled, no advantage over imagecopyresampled.
|
||||
*/
|
||||
|
||||
if (empty($src_image) || empty($dst_image) || $quality <= 0) { return false; }
|
||||
|
||||
if ($quality < 5 && (($dst_w * $quality) < $src_w || ($dst_h * $quality) < $src_h)) {
|
||||
|
||||
$temp = imagecreatetruecolor($dst_w * $quality + 1, $dst_h * $quality + 1);
|
||||
imagecopyresized($temp, $src_image, 0, 0, $src_x, $src_y, $dst_w * $quality + 1, $dst_h * $quality + 1, $src_w, $src_h);
|
||||
imagecopyresampled($dst_image, $temp, $dst_x, $dst_y, 0, 0, $dst_w, $dst_h, $dst_w * $quality, $dst_h * $quality);
|
||||
imagedestroy($temp);
|
||||
|
||||
} else imagecopyresampled($dst_image, $src_image, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h);
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
?>
|
20
php/helpers/generateID.php
Normal file
20
php/helpers/generateID.php
Normal file
@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @return string Generated ID.
|
||||
*/
|
||||
function generateID() {
|
||||
|
||||
// Generate id based on the current microtime
|
||||
$id = str_replace('.', '', microtime(true));
|
||||
|
||||
// Ensure that the id has a length of 14 chars
|
||||
while(strlen($id)<14) $id .= 0;
|
||||
|
||||
// Return id as a string. Don't convert the id to an integer
|
||||
// as 14 digits are too big for 32bit PHP versions.
|
||||
return $id;
|
||||
|
||||
}
|
||||
|
||||
?>
|
24
php/helpers/getExtension.php
Normal file
24
php/helpers/getExtension.php
Normal file
@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Returns the extension of the filename (path or URI) or an empty string.
|
||||
* @return string Extension of the filename starting with a dot.
|
||||
*/
|
||||
function getExtension($filename, $isURI = false) {
|
||||
|
||||
// If $filename is an URI, get only the path component
|
||||
if ($isURI===true) $filename = parse_url($filename, PHP_URL_PATH);
|
||||
|
||||
$extension = pathinfo($filename, PATHINFO_EXTENSION);
|
||||
|
||||
// Special cases
|
||||
// https://github.com/electerious/Lychee/issues/482
|
||||
list($extension) = explode(':', $extension, 2);
|
||||
|
||||
if (empty($extension)===false) $extension = '.' . $extension;
|
||||
|
||||
return $extension;
|
||||
|
||||
}
|
||||
|
||||
?>
|
56
php/helpers/getGraphHeader.php
Normal file
56
php/helpers/getGraphHeader.php
Normal file
@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
use Lychee\Modules\Database;
|
||||
use Lychee\Modules\Photo;
|
||||
|
||||
function getGraphHeader($photoID) {
|
||||
|
||||
$photo = new Photo($photoID);
|
||||
if ($photo->getPublic('')===false) return false;
|
||||
|
||||
$query = Database::prepare(Database::get(), "SELECT title, description, url, medium FROM ? WHERE id = '?'", array(LYCHEE_TABLE_PHOTOS, $photoID));
|
||||
$result = Database::execute(Database::get(), $query, __METHOD__, __LINE__);
|
||||
|
||||
if ($result===false) return false;
|
||||
|
||||
$row = $result->fetch_object();
|
||||
|
||||
if ($row===null) {
|
||||
Log::error(Database::get(), __METHOD__, __LINE__, 'Could not find photo in database');
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($row->medium==='1') $dir = 'medium';
|
||||
else $dir = 'big';
|
||||
|
||||
$parseUrl = parse_url('http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']);
|
||||
$url = $parseUrl['scheme'] . '://' . $parseUrl['host'] . $parseUrl['path'] . '?' . $parseUrl['query'];
|
||||
$picture = $parseUrl['scheme'] . '://' . $parseUrl['host'] . $parseUrl['path'] . '/../uploads/' . $dir . '/' . $row->url;
|
||||
|
||||
$url = htmlentities($url);
|
||||
$picture = htmlentities($picture);
|
||||
|
||||
$row->title = htmlentities($row->title);
|
||||
$row->description = htmlentities($row->description);
|
||||
|
||||
$return = '<!-- General Meta Data -->';
|
||||
$return .= '<meta name="title" content="' . $row->title . '">';
|
||||
$return .= '<meta name="description" content="' . $row->description . ' - via Lychee">';
|
||||
$return .= '<link rel="image_src" type="image/jpeg" href="' . $picture . '">';
|
||||
|
||||
$return .= '<!-- Twitter Meta Data -->';
|
||||
$return .= '<meta name="twitter:card" content="photo">';
|
||||
$return .= '<meta name="twitter:title" content="' . $row->title . '">';
|
||||
$return .= '<meta name="twitter:image:src" content="' . $picture . '">';
|
||||
|
||||
$return .= '<!-- Facebook Meta Data -->';
|
||||
$return .= '<meta property="og:title" content="' . $row->title . '">';
|
||||
$return .= '<meta property="og:description" content="' . $row->description . ' - via Lychee">';
|
||||
$return .= '<meta property="og:image" content="' . $picture . '">';
|
||||
$return .= '<meta property="og:url" content="' . $url . '">';
|
||||
|
||||
return $return;
|
||||
|
||||
}
|
||||
|
||||
?>
|
38
php/helpers/getHashedString.php
Normal file
38
php/helpers/getHashedString.php
Normal file
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
function getHashedString($password) {
|
||||
|
||||
// Inspired by http://alias.io/2010/01/store-passwords-safely-with-php-and-mysql/
|
||||
|
||||
// A higher $cost is more secure but consumes more processing power
|
||||
$cost = 10;
|
||||
|
||||
// Create a random salt
|
||||
if (extension_loaded('openssl')) {
|
||||
|
||||
$salt = strtr(substr(base64_encode(openssl_random_pseudo_bytes(17)),0,22), '+', '.');
|
||||
|
||||
} elseif (extension_loaded('mcrypt')) {
|
||||
|
||||
$salt = strtr(substr(base64_encode(mcrypt_create_iv(17, MCRYPT_DEV_URANDOM)),0,22), '+', '.');
|
||||
|
||||
} else {
|
||||
|
||||
$salt = '';
|
||||
|
||||
for ($i = 0; $i < 22; $i++) {
|
||||
$salt .= substr("./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", mt_rand(0, 63), 1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Prefix information about the hash so PHP knows how to verify it later.
|
||||
// "$2a$" Means we're using the Blowfish algorithm. The following two digits are the cost parameter.
|
||||
$salt = sprintf("$2a$%02d$", $cost) . $salt;
|
||||
|
||||
// Hash the password with the salt
|
||||
return crypt($password, $salt);
|
||||
|
||||
}
|
||||
|
||||
?>
|
13
php/helpers/hasPermissions.php
Normal file
13
php/helpers/hasPermissions.php
Normal file
@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
function hasPermissions($path) {
|
||||
|
||||
// Check if the given path is readable and writable
|
||||
// Both functions are also verifying that the path exists
|
||||
if (is_readable($path)===true&&is_writeable($path)===true) return true;
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
?>
|
75
php/helpers/search.php
Executable file
75
php/helpers/search.php
Executable file
@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
use Lychee\Modules\Album;
|
||||
use Lychee\Modules\Database;
|
||||
use Lychee\Modules\Photo;
|
||||
use Lychee\Modules\Settings;
|
||||
|
||||
/**
|
||||
* @return array|false Returns an array with albums and photos.
|
||||
*/
|
||||
function search($term) {
|
||||
|
||||
// Initialize return var
|
||||
$return = array(
|
||||
'photos' => null,
|
||||
'albums' => null,
|
||||
'hash' => ''
|
||||
);
|
||||
|
||||
/**
|
||||
* Photos
|
||||
*/
|
||||
|
||||
$query = Database::prepare(Database::get(), "SELECT id, title, tags, public, star, album, thumbUrl, takestamp, url FROM ? WHERE title LIKE '%?%' OR description LIKE '%?%' OR tags LIKE '%?%'", array(LYCHEE_TABLE_PHOTOS, $term, $term, $term));
|
||||
$result = Database::execute(Database::get(), $query, __METHOD__, __LINE__);
|
||||
|
||||
if ($result===false) return false;
|
||||
|
||||
while($photo = $result->fetch_assoc()) {
|
||||
|
||||
$photo = Photo::prepareData($photo);
|
||||
$return['photos'][$photo['id']] = $photo;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Albums
|
||||
*/
|
||||
|
||||
$query = Database::prepare(Database::get(), "SELECT id, title, public, sysstamp, password FROM ? WHERE title LIKE '%?%' OR description LIKE '%?%'", array(LYCHEE_TABLE_ALBUMS, $term, $term));
|
||||
$result = Database::execute(Database::get(), $query, __METHOD__, __LINE__);
|
||||
|
||||
if ($result===false) return false;
|
||||
|
||||
while($album = $result->fetch_assoc()) {
|
||||
|
||||
// Turn data from the database into a front-end friendly format
|
||||
$album = Album::prepareData($album);
|
||||
|
||||
// Thumbs
|
||||
$query = Database::prepare(Database::get(), "SELECT thumbUrl FROM ? WHERE album = '?' " . Settings::get()['sortingPhotos'] . " LIMIT 0, 3", array(LYCHEE_TABLE_PHOTOS, $album['id']));
|
||||
$thumbs = Database::execute(Database::get(), $query, __METHOD__, __LINE__);
|
||||
|
||||
if ($thumbs===false) return false;
|
||||
|
||||
// For each thumb
|
||||
$k = 0;
|
||||
while ($thumb = $thumbs->fetch_object()) {
|
||||
$album['thumbs'][$k] = LYCHEE_URL_UPLOADS_THUMB . $thumb->thumbUrl;
|
||||
$k++;
|
||||
}
|
||||
|
||||
// Add to return
|
||||
$return['albums'][$album['id']] = $album;
|
||||
|
||||
}
|
||||
|
||||
// Hash
|
||||
$return['hash'] = md5(json_encode($return));
|
||||
|
||||
return $return;
|
||||
|
||||
}
|
||||
|
||||
?>
|
91
php/index.php
Executable file
91
php/index.php
Executable file
@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @author Tobias Reich
|
||||
* @copyright 2016 by Tobias Reich
|
||||
*/
|
||||
|
||||
namespace Lychee;
|
||||
|
||||
use Lychee\Modules\Config;
|
||||
use Lychee\Modules\Response;
|
||||
use Lychee\Modules\Settings;
|
||||
use Lychee\Modules\Validator;
|
||||
|
||||
use Lychee\Access\Installation;
|
||||
use Lychee\Access\Admin;
|
||||
use Lychee\Access\Guest;
|
||||
|
||||
require(__DIR__ . '/define.php');
|
||||
require(__DIR__ . '/autoload.php');
|
||||
|
||||
require(__DIR__ . '/helpers/fastImageCopyResampled.php');
|
||||
require(__DIR__ . '/helpers/generateID.php');
|
||||
require(__DIR__ . '/helpers/getExtension.php');
|
||||
require(__DIR__ . '/helpers/getGraphHeader.php');
|
||||
require(__DIR__ . '/helpers/getHashedString.php');
|
||||
require(__DIR__ . '/helpers/hasPermissions.php');
|
||||
require(__DIR__ . '/helpers/search.php');
|
||||
|
||||
// Define the called function
|
||||
if (isset($_POST['function'])) $fn = $_POST['function'];
|
||||
else if (isset($_GET['function'])) $fn = $_GET['function'];
|
||||
else $fn = null;
|
||||
|
||||
// Check if a function has been specified
|
||||
if (!empty($fn)) {
|
||||
|
||||
// Start the session and set the default timezone
|
||||
session_start();
|
||||
date_default_timezone_set('UTC');
|
||||
|
||||
// Validate parameters
|
||||
if (isset($_POST['albumIDs'])&&Validator::isAlbumIDs($_POST['albumIDs'])===false) Response::error('Wrong parameter type for albumIDs!');
|
||||
if (isset($_POST['photoIDs'])&&Validator::isPhotoIDs($_POST['photoIDs'])===false) Response::error('Wrong parameter type for photoIDs!');
|
||||
if (isset($_POST['albumID'])&&Validator::isAlbumID($_POST['albumID'])==false) Response::error('Wrong parameter type for albumID!');
|
||||
if (isset($_POST['photoID'])&&Validator::isPhotoID($_POST['photoID'])==false) Response::error('Wrong parameter type for photoID!');
|
||||
|
||||
// Check if a configuration exists
|
||||
if (Config::exists()===false) {
|
||||
|
||||
/**
|
||||
* Installation Access
|
||||
* Limited access to configure Lychee. Only available when the config.php file is missing.
|
||||
*/
|
||||
|
||||
Installation::init($fn);
|
||||
exit();
|
||||
|
||||
}
|
||||
|
||||
// Check if user is logged
|
||||
if ((isset($_SESSION['login'])&&$_SESSION['login']===true)&&
|
||||
(isset($_SESSION['identifier'])&&$_SESSION['identifier']===Settings::get()['identifier'])) {
|
||||
|
||||
/**
|
||||
* Admin Access
|
||||
* Full access to Lychee. Only with correct password/session.
|
||||
*/
|
||||
|
||||
Admin::init($fn);
|
||||
exit();
|
||||
|
||||
} else {
|
||||
|
||||
/**
|
||||
* Guest Access
|
||||
* Access to view all public folders and photos in Lychee.
|
||||
*/
|
||||
|
||||
Guest::init($fn);
|
||||
exit();
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
Response::error('No API function specified!');
|
||||
|
||||
}
|
||||
|
||||
?>
|
@ -1,759 +0,0 @@
|
||||
<?php
|
||||
|
||||
###
|
||||
# @name Album Module
|
||||
# @copyright 2015 by Tobias Reich
|
||||
###
|
||||
|
||||
if (!defined('LYCHEE')) exit('Error: Direct access is not allowed!');
|
||||
|
||||
class Album extends Module {
|
||||
|
||||
private $database = null;
|
||||
private $settings = null;
|
||||
private $albumIDs = null;
|
||||
|
||||
public function __construct($database, $plugins, $settings, $albumIDs) {
|
||||
|
||||
# Init vars
|
||||
$this->database = $database;
|
||||
$this->plugins = $plugins;
|
||||
$this->settings = $settings;
|
||||
$this->albumIDs = $albumIDs;
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
public function add($title = 'Untitled', $public = 0, $visible = 1) {
|
||||
|
||||
# Check dependencies
|
||||
self::dependencies(isset($this->database));
|
||||
|
||||
# Call plugins
|
||||
$this->plugins(__METHOD__, 0, func_get_args());
|
||||
|
||||
# Parse
|
||||
if (strlen($title)>50) $title = substr($title, 0, 50);
|
||||
|
||||
# Database
|
||||
$sysstamp = time();
|
||||
$query = Database::prepare($this->database, "INSERT INTO ? (title, sysstamp, public, visible) VALUES ('?', '?', '?', '?')", array(LYCHEE_TABLE_ALBUMS, $title, $sysstamp, $public, $visible));
|
||||
$result = $this->database->query($query);
|
||||
|
||||
# Call plugins
|
||||
$this->plugins(__METHOD__, 1, func_get_args());
|
||||
|
||||
if (!$result) {
|
||||
Log::error($this->database, __METHOD__, __LINE__, $this->database->error);
|
||||
return false;
|
||||
}
|
||||
return $this->database->insert_id;
|
||||
|
||||
}
|
||||
|
||||
public static function prepareData($data) {
|
||||
|
||||
# This function requires the following album-attributes and turns them
|
||||
# into a front-end friendly format: id, title, public, sysstamp, password
|
||||
# Note that some attributes remain unchanged
|
||||
|
||||
# Check dependencies
|
||||
self::dependencies(isset($data));
|
||||
|
||||
# Init
|
||||
$album = null;
|
||||
|
||||
# Set unchanged attributes
|
||||
$album['id'] = $data['id'];
|
||||
$album['title'] = $data['title'];
|
||||
$album['public'] = $data['public'];
|
||||
|
||||
# Additional attributes
|
||||
# Only part of $album when available
|
||||
if (isset($data['description'])) $album['description'] = $data['description'];
|
||||
if (isset($data['visible'])) $album['visible'] = $data['visible'];
|
||||
if (isset($data['downloadable'])) $album['downloadable'] = $data['downloadable'];
|
||||
|
||||
# Parse date
|
||||
$album['sysdate'] = date('F Y', $data['sysstamp']);
|
||||
|
||||
# Parse password
|
||||
$album['password'] = ($data['password']=='' ? '0' : '1');
|
||||
|
||||
# Parse thumbs or set default value
|
||||
$album['thumbs'] = (isset($data['thumbs']) ? explode(',', $data['thumbs']) : array());
|
||||
|
||||
return $album;
|
||||
|
||||
}
|
||||
|
||||
public function get() {
|
||||
|
||||
# Check dependencies
|
||||
self::dependencies(isset($this->database, $this->settings, $this->albumIDs));
|
||||
|
||||
# Call plugins
|
||||
$this->plugins(__METHOD__, 0, func_get_args());
|
||||
|
||||
# Get album information
|
||||
switch ($this->albumIDs) {
|
||||
|
||||
case 'f': $return['public'] = '0';
|
||||
$query = Database::prepare($this->database, "SELECT id, title, tags, public, star, album, thumbUrl, takestamp, url FROM ? WHERE star = 1 " . $this->settings['sortingPhotos'], array(LYCHEE_TABLE_PHOTOS));
|
||||
break;
|
||||
|
||||
case 's': $return['public'] = '0';
|
||||
$query = Database::prepare($this->database, "SELECT id, title, tags, public, star, album, thumbUrl, takestamp, url FROM ? WHERE public = 1 " . $this->settings['sortingPhotos'], array(LYCHEE_TABLE_PHOTOS));
|
||||
break;
|
||||
|
||||
case 'r': $return['public'] = '0';
|
||||
$query = Database::prepare($this->database, "SELECT id, title, tags, public, star, album, thumbUrl, takestamp, url FROM ? WHERE LEFT(id, 10) >= unix_timestamp(DATE_SUB(NOW(), INTERVAL 1 DAY)) " . $this->settings['sortingPhotos'], array(LYCHEE_TABLE_PHOTOS));
|
||||
break;
|
||||
|
||||
case '0': $return['public'] = '0';
|
||||
$query = Database::prepare($this->database, "SELECT id, title, tags, public, star, album, thumbUrl, takestamp, url FROM ? WHERE album = 0 " . $this->settings['sortingPhotos'], array(LYCHEE_TABLE_PHOTOS));
|
||||
break;
|
||||
|
||||
default: $query = Database::prepare($this->database, "SELECT * FROM ? WHERE id = '?' LIMIT 1", array(LYCHEE_TABLE_ALBUMS, $this->albumIDs));
|
||||
$albums = $this->database->query($query);
|
||||
$return = $albums->fetch_assoc();
|
||||
$return = Album::prepareData($return);
|
||||
$query = Database::prepare($this->database, "SELECT id, title, tags, public, star, album, thumbUrl, takestamp, url FROM ? WHERE album = '?' " . $this->settings['sortingPhotos'], array(LYCHEE_TABLE_PHOTOS, $this->albumIDs));
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
# Get photos
|
||||
$photos = $this->database->query($query);
|
||||
$previousPhotoID = '';
|
||||
while ($photo = $photos->fetch_assoc()) {
|
||||
|
||||
# Turn data from the database into a front-end friendly format
|
||||
$photo = Photo::prepareData($photo);
|
||||
|
||||
# Set previous and next photoID for navigation purposes
|
||||
$photo['previousPhoto'] = $previousPhotoID;
|
||||
$photo['nextPhoto'] = '';
|
||||
|
||||
# Set current photoID as nextPhoto of previous photo
|
||||
if ($previousPhotoID!=='') $return['content'][$previousPhotoID]['nextPhoto'] = $photo['id'];
|
||||
$previousPhotoID = $photo['id'];
|
||||
|
||||
# Add to return
|
||||
$return['content'][$photo['id']] = $photo;
|
||||
|
||||
}
|
||||
|
||||
if ($photos->num_rows===0) {
|
||||
|
||||
# Album empty
|
||||
$return['content'] = false;
|
||||
|
||||
} else {
|
||||
|
||||
# Enable next and previous for the first and last photo
|
||||
$lastElement = end($return['content']);
|
||||
$lastElementId = $lastElement['id'];
|
||||
$firstElement = reset($return['content']);
|
||||
$firstElementId = $firstElement['id'];
|
||||
|
||||
if ($lastElementId!==$firstElementId) {
|
||||
$return['content'][$lastElementId]['nextPhoto'] = $firstElementId;
|
||||
$return['content'][$firstElementId]['previousPhoto'] = $lastElementId;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$return['id'] = $this->albumIDs;
|
||||
$return['num'] = $photos->num_rows;
|
||||
|
||||
# Call plugins
|
||||
$this->plugins(__METHOD__, 1, func_get_args());
|
||||
|
||||
return $return;
|
||||
|
||||
}
|
||||
|
||||
public function getAll($public) {
|
||||
|
||||
# Check dependencies
|
||||
self::dependencies(isset($this->database, $this->settings, $public));
|
||||
|
||||
# Call plugins
|
||||
$this->plugins(__METHOD__, 0, func_get_args());
|
||||
|
||||
# Initialize return var
|
||||
$return = array(
|
||||
'smartalbums' => null,
|
||||
'albums' => null,
|
||||
'num' => 0
|
||||
);
|
||||
|
||||
# Get SmartAlbums
|
||||
if ($public===false) $return['smartalbums'] = $this->getSmartInfo();
|
||||
|
||||
# Albums query
|
||||
if ($public===false) $query = Database::prepare($this->database, 'SELECT id, title, public, sysstamp, password FROM ? ' . $this->settings['sortingAlbums'], array(LYCHEE_TABLE_ALBUMS));
|
||||
else $query = Database::prepare($this->database, 'SELECT id, title, public, sysstamp, password FROM ? WHERE public = 1 AND visible <> 0 ' . $this->settings['sortingAlbums'], array(LYCHEE_TABLE_ALBUMS));
|
||||
|
||||
# Execute query
|
||||
$albums = $this->database->query($query);
|
||||
if (!$albums) {
|
||||
Log::error($this->database, __METHOD__, __LINE__, 'Could not get all albums (' . $this->database->error . ')');
|
||||
exit('Error: ' . $this->database->error);
|
||||
}
|
||||
|
||||
# For each album
|
||||
while ($album = $albums->fetch_assoc()) {
|
||||
|
||||
# Turn data from the database into a front-end friendly format
|
||||
$album = Album::prepareData($album);
|
||||
|
||||
# Thumbs
|
||||
if (($public===true&&$album['password']==='0')||
|
||||
($public===false)) {
|
||||
|
||||
# Execute query
|
||||
$query = Database::prepare($this->database, "SELECT thumbUrl FROM ? WHERE album = '?' ORDER BY star DESC, " . substr($this->settings['sortingPhotos'], 9) . " LIMIT 3", array(LYCHEE_TABLE_PHOTOS, $album['id']));
|
||||
$thumbs = $this->database->query($query);
|
||||
|
||||
# For each thumb
|
||||
$k = 0;
|
||||
while ($thumb = $thumbs->fetch_object()) {
|
||||
$album['thumbs'][$k] = LYCHEE_URL_UPLOADS_THUMB . $thumb->thumbUrl;
|
||||
$k++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
# Add to return
|
||||
$return['albums'][] = $album;
|
||||
|
||||
}
|
||||
|
||||
# Num of albums
|
||||
$return['num'] = $albums->num_rows;
|
||||
|
||||
# Call plugins
|
||||
$this->plugins(__METHOD__, 1, func_get_args());
|
||||
|
||||
return $return;
|
||||
|
||||
}
|
||||
|
||||
private function getSmartInfo() {
|
||||
|
||||
# Check dependencies
|
||||
self::dependencies(isset($this->database, $this->settings));
|
||||
|
||||
# Initialize return var
|
||||
$return = array(
|
||||
'unsorted' => null,
|
||||
'public' => null,
|
||||
'starred' => null,
|
||||
'recent' => null
|
||||
);
|
||||
|
||||
###
|
||||
# Unsorted
|
||||
###
|
||||
|
||||
$query = Database::prepare($this->database, 'SELECT thumbUrl FROM ? WHERE album = 0 ' . $this->settings['sortingPhotos'], array(LYCHEE_TABLE_PHOTOS));
|
||||
$unsorted = $this->database->query($query);
|
||||
$i = 0;
|
||||
|
||||
$return['unsorted'] = array(
|
||||
'thumbs' => array(),
|
||||
'num' => $unsorted->num_rows
|
||||
);
|
||||
|
||||
while($row = $unsorted->fetch_object()) {
|
||||
if ($i<3) {
|
||||
$return['unsorted']['thumbs'][$i] = LYCHEE_URL_UPLOADS_THUMB . $row->thumbUrl;
|
||||
$i++;
|
||||
} else break;
|
||||
}
|
||||
|
||||
###
|
||||
# Starred
|
||||
###
|
||||
|
||||
$query = Database::prepare($this->database, 'SELECT thumbUrl FROM ? WHERE star = 1 ' . $this->settings['sortingPhotos'], array(LYCHEE_TABLE_PHOTOS));
|
||||
$starred = $this->database->query($query);
|
||||
$i = 0;
|
||||
|
||||
$return['starred'] = array(
|
||||
'thumbs' => array(),
|
||||
'num' => $starred->num_rows
|
||||
);
|
||||
|
||||
while($row3 = $starred->fetch_object()) {
|
||||
if ($i<3) {
|
||||
$return['starred']['thumbs'][$i] = LYCHEE_URL_UPLOADS_THUMB . $row3->thumbUrl;
|
||||
$i++;
|
||||
} else break;
|
||||
}
|
||||
|
||||
###
|
||||
# Public
|
||||
###
|
||||
|
||||
$query = Database::prepare($this->database, 'SELECT thumbUrl FROM ? WHERE public = 1 ' . $this->settings['sortingPhotos'], array(LYCHEE_TABLE_PHOTOS));
|
||||
$public = $this->database->query($query);
|
||||
$i = 0;
|
||||
|
||||
$return['public'] = array(
|
||||
'thumbs' => array(),
|
||||
'num' => $public->num_rows
|
||||
);
|
||||
|
||||
while($row2 = $public->fetch_object()) {
|
||||
if ($i<3) {
|
||||
$return['public']['thumbs'][$i] = LYCHEE_URL_UPLOADS_THUMB . $row2->thumbUrl;
|
||||
$i++;
|
||||
} else break;
|
||||
}
|
||||
|
||||
###
|
||||
# Recent
|
||||
###
|
||||
|
||||
$query = Database::prepare($this->database, 'SELECT thumbUrl FROM ? WHERE LEFT(id, 10) >= unix_timestamp(DATE_SUB(NOW(), INTERVAL 1 DAY)) ' . $this->settings['sortingPhotos'], array(LYCHEE_TABLE_PHOTOS));
|
||||
$recent = $this->database->query($query);
|
||||
$i = 0;
|
||||
|
||||
$return['recent'] = array(
|
||||
'thumbs' => array(),
|
||||
'num' => $recent->num_rows
|
||||
);
|
||||
|
||||
while($row3 = $recent->fetch_object()) {
|
||||
if ($i<3) {
|
||||
$return['recent']['thumbs'][$i] = LYCHEE_URL_UPLOADS_THUMB . $row3->thumbUrl;
|
||||
$i++;
|
||||
} else break;
|
||||
}
|
||||
|
||||
# Return SmartAlbums
|
||||
return $return;
|
||||
|
||||
}
|
||||
|
||||
public function getArchive() {
|
||||
|
||||
# Check dependencies
|
||||
self::dependencies(isset($this->database, $this->albumIDs));
|
||||
|
||||
# Call plugins
|
||||
$this->plugins(__METHOD__, 0, func_get_args());
|
||||
|
||||
# Illicit chars
|
||||
$badChars = array_merge(
|
||||
array_map('chr', range(0,31)),
|
||||
array("<", ">", ":", '"', "/", "\\", "|", "?", "*")
|
||||
);
|
||||
|
||||
# Photos query
|
||||
switch($this->albumIDs) {
|
||||
case 's':
|
||||
$photos = Database::prepare($this->database, 'SELECT title, url FROM ? WHERE public = 1', array(LYCHEE_TABLE_PHOTOS));
|
||||
$zipTitle = 'Public';
|
||||
break;
|
||||
case 'f':
|
||||
$photos = Database::prepare($this->database, 'SELECT title, url FROM ? WHERE star = 1', array(LYCHEE_TABLE_PHOTOS));
|
||||
$zipTitle = 'Starred';
|
||||
break;
|
||||
case 'r':
|
||||
$photos = Database::prepare($this->database, 'SELECT title, url FROM ? WHERE LEFT(id, 10) >= unix_timestamp(DATE_SUB(NOW(), INTERVAL 1 DAY)) GROUP BY checksum', array(LYCHEE_TABLE_PHOTOS));
|
||||
$zipTitle = 'Recent';
|
||||
break;
|
||||
default:
|
||||
$photos = Database::prepare($this->database, "SELECT title, url FROM ? WHERE album = '?'", array(LYCHEE_TABLE_PHOTOS, $this->albumIDs));
|
||||
$zipTitle = 'Unsorted';
|
||||
}
|
||||
|
||||
# Get title from database when album is not a SmartAlbum
|
||||
if ($this->albumIDs!=0&&is_numeric($this->albumIDs)) {
|
||||
|
||||
$query = Database::prepare($this->database, "SELECT title FROM ? WHERE id = '?' LIMIT 1", array(LYCHEE_TABLE_ALBUMS, $this->albumIDs));
|
||||
$album = $this->database->query($query);
|
||||
|
||||
# Error in database query
|
||||
if (!$album) {
|
||||
Log::error($this->database, __METHOD__, __LINE__, $this->database->error);
|
||||
return false;
|
||||
}
|
||||
|
||||
# Fetch object
|
||||
$album = $album->fetch_object();
|
||||
|
||||
# Photo not found
|
||||
if ($album===null) {
|
||||
Log::error($this->database, __METHOD__, __LINE__, 'Album not found. Cannot start download.');
|
||||
return false;
|
||||
}
|
||||
|
||||
# Set title
|
||||
$zipTitle = $album->title;
|
||||
|
||||
}
|
||||
|
||||
# Escape title
|
||||
$zipTitle = str_replace($badChars, '', $zipTitle);
|
||||
|
||||
$filename = LYCHEE_DATA . $zipTitle . '.zip';
|
||||
|
||||
# Create zip
|
||||
$zip = new ZipArchive();
|
||||
if ($zip->open($filename, ZIPARCHIVE::CREATE)!==TRUE) {
|
||||
Log::error($this->database, __METHOD__, __LINE__, 'Could not create ZipArchive');
|
||||
return false;
|
||||
}
|
||||
|
||||
# Execute query
|
||||
$photos = $this->database->query($photos);
|
||||
|
||||
# Check if album empty
|
||||
if ($photos->num_rows==0) {
|
||||
Log::error($this->database, __METHOD__, __LINE__, 'Could not create ZipArchive without images');
|
||||
return false;
|
||||
}
|
||||
|
||||
# Parse each path
|
||||
$files = array();
|
||||
while ($photo = $photos->fetch_object()) {
|
||||
|
||||
# Parse url
|
||||
$photo->url = LYCHEE_UPLOADS_BIG . $photo->url;
|
||||
|
||||
# Parse title
|
||||
$photo->title = str_replace($badChars, '', $photo->title);
|
||||
if (!isset($photo->title)||$photo->title==='') $photo->title = 'Untitled';
|
||||
|
||||
# Check if readable
|
||||
if (!@is_readable($photo->url)) continue;
|
||||
|
||||
# Get extension of image
|
||||
$extension = getExtension($photo->url);
|
||||
|
||||
# Set title for photo
|
||||
$zipFileName = $zipTitle . '/' . $photo->title . $extension;
|
||||
|
||||
# Check for duplicates
|
||||
if (!empty($files)) {
|
||||
$i = 1;
|
||||
while (in_array($zipFileName, $files)) {
|
||||
|
||||
# Set new title for photo
|
||||
$zipFileName = $zipTitle . '/' . $photo->title . '-' . $i . $extension;
|
||||
|
||||
$i++;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
# Add to array
|
||||
$files[] = $zipFileName;
|
||||
|
||||
# Add photo to zip
|
||||
$zip->addFile($photo->url, $zipFileName);
|
||||
|
||||
}
|
||||
|
||||
# Finish zip
|
||||
$zip->close();
|
||||
|
||||
# Send zip
|
||||
header("Content-Type: application/zip");
|
||||
header("Content-Disposition: attachment; filename=\"$zipTitle.zip\"");
|
||||
header("Content-Length: " . filesize($filename));
|
||||
readfile($filename);
|
||||
|
||||
# Delete zip
|
||||
unlink($filename);
|
||||
|
||||
# Call plugins
|
||||
$this->plugins(__METHOD__, 1, func_get_args());
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
public function setTitle($title = 'Untitled') {
|
||||
|
||||
# Check dependencies
|
||||
self::dependencies(isset($this->database, $this->albumIDs));
|
||||
|
||||
# Call plugins
|
||||
$this->plugins(__METHOD__, 0, func_get_args());
|
||||
|
||||
# Execute query
|
||||
$query = Database::prepare($this->database, "UPDATE ? SET title = '?' WHERE id IN (?)", array(LYCHEE_TABLE_ALBUMS, $title, $this->albumIDs));
|
||||
$result = $this->database->query($query);
|
||||
|
||||
# Call plugins
|
||||
$this->plugins(__METHOD__, 1, func_get_args());
|
||||
|
||||
if (!$result) {
|
||||
Log::error($this->database, __METHOD__, __LINE__, $this->database->error);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
public function setDescription($description = '') {
|
||||
|
||||
# Check dependencies
|
||||
self::dependencies(isset($this->database, $this->albumIDs));
|
||||
|
||||
# Call plugins
|
||||
$this->plugins(__METHOD__, 0, func_get_args());
|
||||
|
||||
# Execute query
|
||||
$query = Database::prepare($this->database, "UPDATE ? SET description = '?' WHERE id IN (?)", array(LYCHEE_TABLE_ALBUMS, $description, $this->albumIDs));
|
||||
$result = $this->database->query($query);
|
||||
|
||||
# Call plugins
|
||||
$this->plugins(__METHOD__, 1, func_get_args());
|
||||
|
||||
if (!$result) {
|
||||
Log::error($this->database, __METHOD__, __LINE__, $this->database->error);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
public function getPublic() {
|
||||
|
||||
# Check dependencies
|
||||
self::dependencies(isset($this->database, $this->albumIDs));
|
||||
|
||||
# Call plugins
|
||||
$this->plugins(__METHOD__, 0, func_get_args());
|
||||
|
||||
if ($this->albumIDs==='0'||$this->albumIDs==='s'||$this->albumIDs==='f') return false;
|
||||
|
||||
# Execute query
|
||||
$query = Database::prepare($this->database, "SELECT public FROM ? WHERE id = '?' LIMIT 1", array(LYCHEE_TABLE_ALBUMS, $this->albumIDs));
|
||||
$albums = $this->database->query($query);
|
||||
$album = $albums->fetch_object();
|
||||
|
||||
# Call plugins
|
||||
$this->plugins(__METHOD__, 1, func_get_args());
|
||||
|
||||
if ($album->public==1) return true;
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
public function getDownloadable() {
|
||||
|
||||
# Check dependencies
|
||||
self::dependencies(isset($this->database, $this->albumIDs));
|
||||
|
||||
# Call plugins
|
||||
$this->plugins(__METHOD__, 0, func_get_args());
|
||||
|
||||
if ($this->albumIDs==='0'||$this->albumIDs==='s'||$this->albumIDs==='f'||$this->albumIDs==='r') return false;
|
||||
|
||||
# Execute query
|
||||
$query = Database::prepare($this->database, "SELECT downloadable FROM ? WHERE id = '?' LIMIT 1", array(LYCHEE_TABLE_ALBUMS, $this->albumIDs));
|
||||
$albums = $this->database->query($query);
|
||||
$album = $albums->fetch_object();
|
||||
|
||||
# Call plugins
|
||||
$this->plugins(__METHOD__, 1, func_get_args());
|
||||
|
||||
if ($album->downloadable==1) return true;
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
public function setPublic($public, $password, $visible, $downloadable) {
|
||||
|
||||
# Check dependencies
|
||||
self::dependencies(isset($this->database, $this->albumIDs));
|
||||
|
||||
# Call plugins
|
||||
$this->plugins(__METHOD__, 0, func_get_args());
|
||||
|
||||
# Convert values
|
||||
$public = ($public==='1' ? 1 : 0);
|
||||
$visible = ($visible==='1' ? 1 : 0);
|
||||
$downloadable = ($downloadable==='1' ? 1 : 0);
|
||||
|
||||
# Set public
|
||||
$query = Database::prepare($this->database, "UPDATE ? SET public = '?', visible = '?', downloadable = '?', password = NULL WHERE id IN (?)", array(LYCHEE_TABLE_ALBUMS, $public, $visible, $downloadable, $this->albumIDs));
|
||||
$result = $this->database->query($query);
|
||||
if (!$result) {
|
||||
Log::error($this->database, __METHOD__, __LINE__, $this->database->error);
|
||||
return false;
|
||||
}
|
||||
|
||||
# Reset permissions for photos
|
||||
if ($public===1) {
|
||||
$query = Database::prepare($this->database, "UPDATE ? SET public = 0 WHERE album IN (?)", array(LYCHEE_TABLE_PHOTOS, $this->albumIDs));
|
||||
$result = $this->database->query($query);
|
||||
if (!$result) {
|
||||
Log::error($this->database, __METHOD__, __LINE__, $this->database->error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
# Call plugins
|
||||
$this->plugins(__METHOD__, 1, func_get_args());
|
||||
|
||||
# Set password
|
||||
if (isset($password)&&strlen($password)>0) return $this->setPassword($password);
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
private function setPassword($password) {
|
||||
|
||||
# Check dependencies
|
||||
self::dependencies(isset($this->database, $this->albumIDs));
|
||||
|
||||
# Call plugins
|
||||
$this->plugins(__METHOD__, 0, func_get_args());
|
||||
|
||||
if (strlen($password)>0) {
|
||||
|
||||
# Get hashed password
|
||||
$password = getHashedString($password);
|
||||
|
||||
# Set hashed password
|
||||
# Do not prepare $password because it is hashed and save
|
||||
# Preparing (escaping) the password would destroy the hash
|
||||
$query = Database::prepare($this->database, "UPDATE ? SET password = '$password' WHERE id IN (?)", array(LYCHEE_TABLE_ALBUMS, $this->albumIDs));
|
||||
|
||||
} else {
|
||||
|
||||
# Unset password
|
||||
$query = Database::prepare($this->database, "UPDATE ? SET password = NULL WHERE id IN (?)", array(LYCHEE_TABLE_ALBUMS, $this->albumIDs));
|
||||
|
||||
}
|
||||
|
||||
# Execute query
|
||||
$result = $this->database->query($query);
|
||||
|
||||
# Call plugins
|
||||
$this->plugins(__METHOD__, 1, func_get_args());
|
||||
|
||||
if (!$result) {
|
||||
Log::error($this->database, __METHOD__, __LINE__, $this->database->error);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
public function checkPassword($password) {
|
||||
|
||||
# Check dependencies
|
||||
self::dependencies(isset($this->database, $this->albumIDs));
|
||||
|
||||
# Call plugins
|
||||
$this->plugins(__METHOD__, 0, func_get_args());
|
||||
|
||||
# Execute query
|
||||
$query = Database::prepare($this->database, "SELECT password FROM ? WHERE id = '?' LIMIT 1", array(LYCHEE_TABLE_ALBUMS, $this->albumIDs));
|
||||
$albums = $this->database->query($query);
|
||||
$album = $albums->fetch_object();
|
||||
|
||||
# Call plugins
|
||||
$this->plugins(__METHOD__, 1, func_get_args());
|
||||
|
||||
if ($album->password=='') return true;
|
||||
else if ($album->password===crypt($password, $album->password)) return true;
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
public function merge() {
|
||||
|
||||
# Check dependencies
|
||||
self::dependencies(isset($this->database, $this->albumIDs));
|
||||
|
||||
# Call plugins
|
||||
$this->plugins(__METHOD__, 0, func_get_args());
|
||||
|
||||
# Convert to array
|
||||
$albumIDs = explode(',', $this->albumIDs);
|
||||
|
||||
# Get first albumID
|
||||
$albumID = array_splice($albumIDs, 0, 1);
|
||||
$albumID = $albumID[0];
|
||||
|
||||
$query = Database::prepare($this->database, "UPDATE ? SET album = ? WHERE album IN (?)", array(LYCHEE_TABLE_PHOTOS, $albumID, $this->albumIDs));
|
||||
$result = $this->database->query($query);
|
||||
|
||||
if (!$result) {
|
||||
Log::error($this->database, __METHOD__, __LINE__, $this->database->error);
|
||||
return false;
|
||||
}
|
||||
|
||||
# $albumIDs contains all IDs without the first albumID
|
||||
# Convert to string
|
||||
$filteredIDs = implode(',', $albumIDs);
|
||||
|
||||
$query = Database::prepare($this->database, "DELETE FROM ? WHERE id IN (?)", array(LYCHEE_TABLE_ALBUMS, $filteredIDs));
|
||||
$result = $this->database->query($query);
|
||||
|
||||
# Call plugins
|
||||
$this->plugins(__METHOD__, 1, func_get_args());
|
||||
|
||||
if (!$result) {
|
||||
Log::error($this->database, __METHOD__, __LINE__, $this->database->error);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
public function delete() {
|
||||
|
||||
# Check dependencies
|
||||
self::dependencies(isset($this->database, $this->albumIDs));
|
||||
|
||||
# Call plugins
|
||||
$this->plugins(__METHOD__, 0, func_get_args());
|
||||
|
||||
# Init vars
|
||||
$error = false;
|
||||
|
||||
# Execute query
|
||||
$query = Database::prepare($this->database, "SELECT id FROM ? WHERE album IN (?)", array(LYCHEE_TABLE_PHOTOS, $this->albumIDs));
|
||||
$photos = $this->database->query($query);
|
||||
|
||||
# For each album delete photo
|
||||
while ($row = $photos->fetch_object()) {
|
||||
|
||||
$photo = new Photo($this->database, $this->plugins, null, $row->id);
|
||||
if (!$photo->delete($row->id)) $error = true;
|
||||
|
||||
}
|
||||
|
||||
# Delete albums
|
||||
$query = Database::prepare($this->database, "DELETE FROM ? WHERE id IN (?)", array(LYCHEE_TABLE_ALBUMS, $this->albumIDs));
|
||||
$result = $this->database->query($query);
|
||||
|
||||
# Call plugins
|
||||
$this->plugins(__METHOD__, 1, func_get_args());
|
||||
|
||||
if ($error) return false;
|
||||
if (!$result) {
|
||||
Log::error($this->database, __METHOD__, __LINE__, $this->database->error);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
@ -1,338 +0,0 @@
|
||||
<?php
|
||||
|
||||
###
|
||||
# @name Database Module
|
||||
# @copyright 2015 by Tobias Reich
|
||||
###
|
||||
|
||||
if (!defined('LYCHEE')) exit('Error: Direct access is not allowed!');
|
||||
|
||||
class Database extends Module {
|
||||
|
||||
static function connect($host = 'localhost', $user, $password, $name = 'lychee') {
|
||||
|
||||
# Check dependencies
|
||||
Module::dependencies(isset($host, $user, $password, $name));
|
||||
|
||||
$database = new mysqli($host, $user, $password);
|
||||
|
||||
# Check connection
|
||||
if ($database->connect_errno) exit('Error: ' . $database->connect_error);
|
||||
|
||||
# Avoid sql injection on older MySQL versions by using GBK
|
||||
if ($database->server_version<50500) @$database->set_charset('GBK');
|
||||
else @$database->set_charset('utf8');
|
||||
|
||||
# Set unicode
|
||||
$database->query('SET NAMES utf8;');
|
||||
|
||||
# Check database
|
||||
if (!$database->select_db($name))
|
||||
if (!Database::createDatabase($database, $name)) exit('Error: Could not create database!');
|
||||
|
||||
# Check tables
|
||||
$query = Database::prepare($database, 'SELECT * FROM ?, ?, ?, ? LIMIT 0', array(LYCHEE_TABLE_PHOTOS, LYCHEE_TABLE_ALBUMS, LYCHEE_TABLE_SETTINGS, LYCHEE_TABLE_LOG));
|
||||
if (!$database->query($query))
|
||||
if (!Database::createTables($database)) exit('Error: Could not create tables!');
|
||||
|
||||
return $database;
|
||||
|
||||
}
|
||||
|
||||
static function update($database, $dbName, $version = 0) {
|
||||
|
||||
# Check dependencies
|
||||
Module::dependencies(isset($database, $dbName));
|
||||
if (!isset($version)) return true;
|
||||
|
||||
# List of updates
|
||||
$updates = array(
|
||||
'020100', #2.1
|
||||
'020101', #2.1.1
|
||||
'020200', #2.2
|
||||
'020500', #2.5
|
||||
'020505', #2.5.5
|
||||
'020601', #2.6.1
|
||||
'020602', #2.6.2
|
||||
'020700', #2.7.0
|
||||
'030000', #3.0.0
|
||||
'030001', #3.0.1
|
||||
'030003' #3.0.3
|
||||
);
|
||||
|
||||
# For each update
|
||||
foreach ($updates as $update) {
|
||||
|
||||
if ($update<=$version) continue;
|
||||
|
||||
# Load update
|
||||
include(__DIR__ . '/../database/update_' . $update . '.php');
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
static function createConfig($host = 'localhost', $user, $password, $name = 'lychee', $prefix = '') {
|
||||
|
||||
# Check dependencies
|
||||
Module::dependencies(isset($host, $user, $password, $name));
|
||||
|
||||
$database = new mysqli($host, $user, $password);
|
||||
|
||||
if ($database->connect_errno) return 'Warning: Connection failed!';
|
||||
|
||||
# Check if database exists
|
||||
if (!$database->select_db($name)) {
|
||||
|
||||
# Database doesn't exist
|
||||
# Check if user can create the database
|
||||
$result = Database::createDatabase($database, $name);
|
||||
if ($result===false) return 'Warning: Creation failed!';
|
||||
|
||||
}
|
||||
|
||||
# Escape data
|
||||
$host = mysqli_real_escape_string($database, $host);
|
||||
$user = mysqli_real_escape_string($database, $user);
|
||||
$password = mysqli_real_escape_string($database, $password);
|
||||
$name = mysqli_real_escape_string($database, $name);
|
||||
$prefix = mysqli_real_escape_string($database, $prefix);
|
||||
|
||||
# Save config.php
|
||||
$config = "<?php
|
||||
|
||||
###
|
||||
# @name Configuration
|
||||
# @author Tobias Reich
|
||||
# @copyright 2015 Tobias Reich
|
||||
###
|
||||
|
||||
if(!defined('LYCHEE')) exit('Error: Direct access is not allowed!');
|
||||
|
||||
# Database configuration
|
||||
\$dbHost = '$host'; # Host of the database
|
||||
\$dbUser = '$user'; # Username of the database
|
||||
\$dbPassword = '$password'; # Password of the database
|
||||
\$dbName = '$name'; # Database name
|
||||
\$dbTablePrefix = '$prefix'; # Table prefix
|
||||
|
||||
?>";
|
||||
|
||||
# Save file
|
||||
if (file_put_contents(LYCHEE_CONFIG_FILE, $config)===false) return 'Warning: Could not create file!';
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
static function createDatabase($database, $name = 'lychee') {
|
||||
|
||||
# Check dependencies
|
||||
Module::dependencies(isset($database, $name));
|
||||
|
||||
# Create database
|
||||
$query = Database::prepare($database, 'CREATE DATABASE IF NOT EXISTS ?', array($name));
|
||||
$result = $database->query($query);
|
||||
|
||||
if (!$database->select_db($name)||!$result) return false;
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
static function createTables($database) {
|
||||
|
||||
# Check dependencies
|
||||
Module::dependencies(isset($database));
|
||||
|
||||
# Create log
|
||||
$exist = Database::prepare($database, 'SELECT * FROM ? LIMIT 0', array(LYCHEE_TABLE_LOG));
|
||||
if (!$database->query($exist)) {
|
||||
|
||||
# Read file
|
||||
$file = __DIR__ . '/../database/log_table.sql';
|
||||
$query = @file_get_contents($file);
|
||||
|
||||
if (!isset($query)||$query===false) return false;
|
||||
|
||||
# Create table
|
||||
$query = Database::prepare($database, $query, array(LYCHEE_TABLE_LOG));
|
||||
if (!$database->query($query)) return false;
|
||||
|
||||
}
|
||||
|
||||
# Create settings
|
||||
$exist = Database::prepare($database, 'SELECT * FROM ? LIMIT 0', array(LYCHEE_TABLE_SETTINGS));
|
||||
if (!$database->query($exist)) {
|
||||
|
||||
# Read file
|
||||
$file = __DIR__ . '/../database/settings_table.sql';
|
||||
$query = @file_get_contents($file);
|
||||
|
||||
if (!isset($query)||$query===false) {
|
||||
Log::error($database, __METHOD__, __LINE__, 'Could not load query for lychee_settings');
|
||||
return false;
|
||||
}
|
||||
|
||||
# Create table
|
||||
$query = Database::prepare($database, $query, array(LYCHEE_TABLE_SETTINGS));
|
||||
if (!$database->query($query)) {
|
||||
Log::error($database, __METHOD__, __LINE__, $database->error);
|
||||
return false;
|
||||
}
|
||||
|
||||
# Read file
|
||||
$file = __DIR__ . '/../database/settings_content.sql';
|
||||
$query = @file_get_contents($file);
|
||||
|
||||
if (!isset($query)||$query===false) {
|
||||
Log::error($database, __METHOD__, __LINE__, 'Could not load content-query for lychee_settings');
|
||||
return false;
|
||||
}
|
||||
|
||||
# Add content
|
||||
$query = Database::prepare($database, $query, array(LYCHEE_TABLE_SETTINGS));
|
||||
if (!$database->query($query)) {
|
||||
Log::error($database, __METHOD__, __LINE__, $database->error);
|
||||
return false;
|
||||
}
|
||||
|
||||
# Generate identifier
|
||||
$identifier = md5(microtime(true));
|
||||
$query = Database::prepare($database, "UPDATE `?` SET `value` = '?' WHERE `key` = 'identifier' LIMIT 1", array(LYCHEE_TABLE_SETTINGS, $identifier));
|
||||
if (!$database->query($query)) {
|
||||
Log::error($database, __METHOD__, __LINE__, $database->error);
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
# Create albums
|
||||
$exist = Database::prepare($database, 'SELECT * FROM ? LIMIT 0', array(LYCHEE_TABLE_ALBUMS));
|
||||
if (!$database->query($exist)) {
|
||||
|
||||
# Read file
|
||||
$file = __DIR__ . '/../database/albums_table.sql';
|
||||
$query = @file_get_contents($file);
|
||||
|
||||
if (!isset($query)||$query===false) {
|
||||
Log::error($database, __METHOD__, __LINE__, 'Could not load query for lychee_albums');
|
||||
return false;
|
||||
}
|
||||
|
||||
# Create table
|
||||
$query = Database::prepare($database, $query, array(LYCHEE_TABLE_ALBUMS));
|
||||
if (!$database->query($query)) {
|
||||
Log::error($database, __METHOD__, __LINE__, $database->error);
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
# Create photos
|
||||
$exist = Database::prepare($database, 'SELECT * FROM ? LIMIT 0', array(LYCHEE_TABLE_PHOTOS));
|
||||
if (!$database->query($exist)) {
|
||||
|
||||
# Read file
|
||||
$file = __DIR__ . '/../database/photos_table.sql';
|
||||
$query = @file_get_contents($file);
|
||||
|
||||
if (!isset($query)||$query===false) {
|
||||
Log::error($database, __METHOD__, __LINE__, 'Could not load query for lychee_photos');
|
||||
return false;
|
||||
}
|
||||
|
||||
# Create table
|
||||
$query = Database::prepare($database, $query, array(LYCHEE_TABLE_PHOTOS));
|
||||
if (!$database->query($query)) {
|
||||
Log::error($database, __METHOD__, __LINE__, $database->error);
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
static function setVersion($database, $version) {
|
||||
|
||||
$query = Database::prepare($database, "UPDATE ? SET value = '?' WHERE `key` = 'version'", array(LYCHEE_TABLE_SETTINGS, $version));
|
||||
$result = $database->query($query);
|
||||
if (!$result) {
|
||||
Log::error($database, __METHOD__, __LINE__, 'Could not update database (' . $database->error . ')');
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static function prepare($database, $query, $data) {
|
||||
|
||||
# Check dependencies
|
||||
Module::dependencies(isset($database, $query, $data));
|
||||
|
||||
# Count the number of placeholders and compare it with the number of arguments
|
||||
# If it doesn't match, calculate the difference and skip this number of placeholders before starting the replacement
|
||||
# This avoids problems with placeholders in user-input
|
||||
# $skip = Number of placeholders which need to be skipped
|
||||
$skip = 0;
|
||||
$temp = '';
|
||||
$num = array(
|
||||
'placeholder' => substr_count($query, '?'),
|
||||
'data' => count($data)
|
||||
);
|
||||
|
||||
if (($num['data']-$num['placeholder'])<0) Log::notice($database, __METHOD__, __LINE__, 'Could not completely prepare query. Query has more placeholders than values.');
|
||||
|
||||
foreach ($data as $value) {
|
||||
|
||||
# Escape
|
||||
$value = mysqli_real_escape_string($database, $value);
|
||||
|
||||
# Recalculate number of placeholders
|
||||
$num['placeholder'] = substr_count($query, '?');
|
||||
|
||||
# Calculate number of skips
|
||||
if ($num['placeholder']>$num['data']) $skip = $num['placeholder'] - $num['data'];
|
||||
|
||||
if ($skip>0) {
|
||||
|
||||
# Need to skip $skip placeholders, because the user input contained placeholders
|
||||
# Calculate a substring which does not contain the user placeholders
|
||||
# 1 or -1 is the length of the placeholder (placeholder = ?)
|
||||
|
||||
$pos = -1;
|
||||
for ($i=$skip; $i>0; $i--) $pos = strpos($query, '?', $pos + 1);
|
||||
$pos++;
|
||||
|
||||
$temp = substr($query, 0, $pos); # First part of $query
|
||||
$query = substr($query, $pos); # Last part of $query
|
||||
|
||||
}
|
||||
|
||||
# Replace
|
||||
$query = preg_replace('/\?/', $value, $query, 1);
|
||||
|
||||
if ($skip>0) {
|
||||
|
||||
# Reassemble the parts of $query
|
||||
$query = $temp . $query;
|
||||
|
||||
}
|
||||
|
||||
# Reset skip
|
||||
$skip = 0;
|
||||
|
||||
# Decrease number of data elements
|
||||
$num['data']--;
|
||||
|
||||
}
|
||||
|
||||
return $query;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
@ -1,211 +0,0 @@
|
||||
<?php
|
||||
|
||||
###
|
||||
# @name Upload Module
|
||||
# @copyright 2015 by Tobias Reich
|
||||
###
|
||||
|
||||
if (!defined('LYCHEE')) exit('Error: Direct access is not allowed!');
|
||||
|
||||
class Import extends Module {
|
||||
|
||||
private $database = null;
|
||||
private $settings = null;
|
||||
|
||||
public function __construct($database, $plugins, $settings) {
|
||||
|
||||
# Init vars
|
||||
$this->database = $database;
|
||||
$this->plugins = $plugins;
|
||||
$this->settings = $settings;
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
private function photo($path, $albumID = 0, $description = '', $tags = '') {
|
||||
|
||||
# Check dependencies
|
||||
self::dependencies(isset($this->database, $this->plugins, $this->settings, $path));
|
||||
|
||||
# No need to validate photo type and extension in this function.
|
||||
# $photo->add will take care of it.
|
||||
|
||||
$info = getimagesize($path);
|
||||
$size = filesize($path);
|
||||
$photo = new Photo($this->database, $this->plugins, $this->settings, null);
|
||||
|
||||
$nameFile = array(array());
|
||||
$nameFile[0]['name'] = $path;
|
||||
$nameFile[0]['type'] = $info['mime'];
|
||||
$nameFile[0]['tmp_name'] = $path;
|
||||
$nameFile[0]['error'] = 0;
|
||||
$nameFile[0]['size'] = $size;
|
||||
$nameFile[0]['error'] = UPLOAD_ERR_OK;
|
||||
|
||||
if (!$photo->add($nameFile, $albumID, $description, $tags, true)) return false;
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
public function url($urls, $albumID = 0) {
|
||||
|
||||
# Check dependencies
|
||||
self::dependencies(isset($this->database, $urls));
|
||||
|
||||
# Call plugins
|
||||
$this->plugins(__METHOD__, 0, func_get_args());
|
||||
|
||||
$error = false;
|
||||
|
||||
# Parse URLs
|
||||
$urls = str_replace(' ', '%20', $urls);
|
||||
$urls = explode(',', $urls);
|
||||
|
||||
foreach ($urls as &$url) {
|
||||
|
||||
# Validate photo type and extension even when $this->photo (=> $photo->add) will do the same.
|
||||
# This prevents us from downloading invalid photos.
|
||||
|
||||
# Verify extension
|
||||
$extension = getExtension($url);
|
||||
if (!in_array(strtolower($extension), Photo::$validExtensions, true)) {
|
||||
$error = true;
|
||||
Log::error($this->database, __METHOD__, __LINE__, 'Photo format not supported (' . $url . ')');
|
||||
continue;
|
||||
}
|
||||
|
||||
# Verify image
|
||||
$type = @exif_imagetype($url);
|
||||
if (!in_array($type, Photo::$validTypes, true)) {
|
||||
$error = true;
|
||||
Log::error($this->database, __METHOD__, __LINE__, 'Photo type not supported (' . $url . ')');
|
||||
continue;
|
||||
}
|
||||
|
||||
$pathinfo = pathinfo($url);
|
||||
$filename = $pathinfo['filename'] . '.' . $pathinfo['extension'];
|
||||
$tmp_name = LYCHEE_DATA . $filename;
|
||||
|
||||
if (@copy($url, $tmp_name)===false) {
|
||||
$error = true;
|
||||
Log::error($this->database, __METHOD__, __LINE__, 'Could not copy file (' . $tmp_name . ') to temp-folder (' . $tmp_name . ')');
|
||||
continue;
|
||||
}
|
||||
|
||||
# Import photo
|
||||
if (!$this->photo($tmp_name, $albumID)) {
|
||||
$error = true;
|
||||
Log::error($this->database, __METHOD__, __LINE__, 'Could not import file: ' . $tmp_name);
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
# Call plugins
|
||||
$this->plugins(__METHOD__, 1, func_get_args());
|
||||
|
||||
if ($error===false) return true;
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
public function server($path, $albumID = 0) {
|
||||
|
||||
# Check dependencies
|
||||
self::dependencies(isset($this->database, $this->plugins, $this->settings));
|
||||
|
||||
# Parse path
|
||||
if (!isset($path)) $path = LYCHEE_UPLOADS_IMPORT;
|
||||
if (substr($path, -1)==='/') $path = substr($path, 0, -1);
|
||||
|
||||
if (is_dir($path)===false) {
|
||||
Log::error($this->database, __METHOD__, __LINE__, 'Given path is not a directory (' . $path . ')');
|
||||
return 'Error: Given path is not a directory!';
|
||||
}
|
||||
|
||||
# Skip folders of Lychee
|
||||
if ($path===LYCHEE_UPLOADS_BIG||($path . '/')===LYCHEE_UPLOADS_BIG||
|
||||
$path===LYCHEE_UPLOADS_MEDIUM||($path . '/')===LYCHEE_UPLOADS_MEDIUM||
|
||||
$path===LYCHEE_UPLOADS_THUMB||($path . '/')===LYCHEE_UPLOADS_THUMB) {
|
||||
Log::error($this->database, __METHOD__, __LINE__, 'The given path is a reserved path of Lychee (' . $path . ')');
|
||||
return 'Error: Given path is a reserved path of Lychee!';
|
||||
}
|
||||
|
||||
$error = false;
|
||||
$contains['photos'] = false;
|
||||
$contains['albums'] = false;
|
||||
|
||||
# Call plugins
|
||||
# Note that updated albumId and path explicitly passed, rather
|
||||
# than using func_get_args() which will only return original ones
|
||||
$this->plugins(__METHOD__, 0, array($albumID, $path));
|
||||
|
||||
# Get all files
|
||||
$files = glob($path . '/*');
|
||||
|
||||
foreach ($files as $file) {
|
||||
|
||||
# It is possible to move a file because of directory permissions but
|
||||
# the file may still be unreadable by the user
|
||||
if (!is_readable($file)) {
|
||||
$error = true;
|
||||
Log::error($this->database, __METHOD__, __LINE__, 'Could not read file or directory: ' . $file);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (@exif_imagetype($file)!==false) {
|
||||
|
||||
# Photo
|
||||
|
||||
$contains['photos'] = true;
|
||||
|
||||
if (!$this->photo($file, $albumID)) {
|
||||
$error = true;
|
||||
Log::error($this->database, __METHOD__, __LINE__, 'Could not import file: ' . $file);
|
||||
continue;
|
||||
}
|
||||
|
||||
} else if (is_dir($file)) {
|
||||
|
||||
# Folder
|
||||
|
||||
$album = new Album($this->database, $this->plugins, $this->settings, null);
|
||||
$newAlbumID = $album->add('[Import] ' . basename($file));
|
||||
$contains['albums'] = true;
|
||||
|
||||
if ($newAlbumID===false) {
|
||||
$error = true;
|
||||
Log::error($this->database, __METHOD__, __LINE__, 'Could not create album in Lychee (' . $newAlbumID . ')');
|
||||
continue;
|
||||
}
|
||||
|
||||
$import = $this->server($file . '/', $newAlbumID);
|
||||
|
||||
if ($import!==true&&$import!=='Notice: Import only contains albums!') {
|
||||
$error = true;
|
||||
Log::error($this->database, __METHOD__, __LINE__, 'Could not import folder. Function returned warning.');
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
# Call plugins
|
||||
# Note that updated albumId and path explicitly passed, rather
|
||||
# than using func_get_args() which will only return original ones
|
||||
$this->plugins(__METHOD__, 1, array($albumID, $path));
|
||||
|
||||
# The following returns will be caught in the front-end
|
||||
if ($contains['photos']===false&&$contains['albums']===false) return 'Warning: Folder empty or no readable files to process!';
|
||||
if ($contains['photos']===false&&$contains['albums']===true) return 'Notice: Import only contained albums!';
|
||||
|
||||
if ($error===true) return false;
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
@ -1,49 +0,0 @@
|
||||
<?php
|
||||
|
||||
###
|
||||
# @name Log Module
|
||||
# @copyright 2015 by Tobias Reich
|
||||
###
|
||||
|
||||
if (!defined('LYCHEE')) exit('Error: Direct access is not allowed!');
|
||||
|
||||
class Log extends Module {
|
||||
|
||||
public static function notice($database, $function, $line, $text = '') {
|
||||
|
||||
return Log::text($database, 'notice', $function, $line, $text);
|
||||
|
||||
}
|
||||
|
||||
public static function warning($database, $function, $line, $text = '') {
|
||||
|
||||
return Log::text($database, 'warning', $function, $line, $text);
|
||||
|
||||
}
|
||||
|
||||
public static function error($database, $function, $line, $text = '') {
|
||||
|
||||
return Log::text($database, 'error', $function, $line, $text);
|
||||
|
||||
}
|
||||
|
||||
public static function text($database, $type, $function, $line, $text = '') {
|
||||
|
||||
# Check dependencies
|
||||
Module::dependencies(isset($database, $type, $function, $line, $text));
|
||||
|
||||
# Get time
|
||||
$sysstamp = time();
|
||||
|
||||
# Save in database
|
||||
$query = Database::prepare($database, "INSERT INTO ? (time, type, function, line, text) VALUES ('?', '?', '?', '?', '?')", array(LYCHEE_TABLE_LOG, $sysstamp, $type, $function, $line, $text));
|
||||
$result = $database->query($query);
|
||||
|
||||
if (!$result) return false;
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
@ -1,36 +0,0 @@
|
||||
<?php
|
||||
|
||||
###
|
||||
# @name Module
|
||||
# @copyright 2015 by Tobias Reich
|
||||
###
|
||||
|
||||
if (!defined('LYCHEE')) exit('Error: Direct access is not allowed!');
|
||||
|
||||
class Module {
|
||||
|
||||
protected $plugins = null;
|
||||
|
||||
protected function plugins($name, $location, $args) {
|
||||
|
||||
if (!isset($this->plugins, $name, $location, $args)) return false;
|
||||
|
||||
# Parse
|
||||
$location = ($location===0 ? 'before' : 'after');
|
||||
|
||||
# Call plugins
|
||||
$this->plugins->activate($name . ":" . $location, $args);
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
public static function dependencies($available = false) {
|
||||
|
||||
if ($available===false) exit('Error: Can not execute function. Missing parameters or variables.');
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
File diff suppressed because it is too large
Load Diff
@ -1,94 +0,0 @@
|
||||
<?php
|
||||
|
||||
###
|
||||
# @name Plugins Module
|
||||
# @copyright 2015 by Tobias Reich
|
||||
###
|
||||
|
||||
if (!defined('LYCHEE')) exit('Error: Direct access is not allowed!');
|
||||
|
||||
class Plugins implements \SplSubject {
|
||||
|
||||
private $files = array();
|
||||
private $observers = array();
|
||||
|
||||
public $action = null;
|
||||
public $args = null;
|
||||
|
||||
public function __construct($files, $database, $settings) {
|
||||
|
||||
if (!isset($files)) return false;
|
||||
|
||||
# Init vars
|
||||
$this->files = $files;
|
||||
|
||||
# Load plugins
|
||||
foreach ($this->files as $file) {
|
||||
|
||||
if ($file==='') continue;
|
||||
|
||||
$file = LYCHEE_PLUGINS . $file;
|
||||
|
||||
if (file_exists($file)===false) {
|
||||
Log::warning($database, __METHOD__, __LINE__, 'Could not include plugin. File does not exist (' . $file . ').');
|
||||
continue;
|
||||
}
|
||||
|
||||
include($file);
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
public function attach(\SplObserver $observer) {
|
||||
|
||||
if (!isset($observer)) return false;
|
||||
|
||||
# Add observer
|
||||
$this->observers[] = $observer;
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
public function detach(\SplObserver $observer) {
|
||||
|
||||
if (!isset($observer)) return false;
|
||||
|
||||
# Remove observer
|
||||
$key = array_search($observer, $this->observers, true);
|
||||
if ($key) unset($this->observers[$key]);
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
public function notify() {
|
||||
|
||||
# Notify each observer
|
||||
foreach ($this->observers as $value) $value->update($this);
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
public function activate($action, $args) {
|
||||
|
||||
if (!isset($action, $args)) return false;
|
||||
|
||||
# Save vars
|
||||
$this->action = $action;
|
||||
$this->args = $args;
|
||||
|
||||
# Notify observers
|
||||
$this->notify();
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
@ -1,156 +0,0 @@
|
||||
<?php
|
||||
|
||||
###
|
||||
# @name Session Module
|
||||
# @copyright 2015 by Tobias Reich
|
||||
###
|
||||
|
||||
if (!defined('LYCHEE')) exit('Error: Direct access is not allowed!');
|
||||
|
||||
class Session extends Module {
|
||||
|
||||
private $settings = null;
|
||||
|
||||
public function __construct($plugins, $settings) {
|
||||
|
||||
# Init vars
|
||||
$this->plugins = $plugins;
|
||||
$this->settings = $settings;
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
public function init($database, $dbName, $public, $version) {
|
||||
|
||||
# Check dependencies
|
||||
self::dependencies(isset($this->settings, $public, $version));
|
||||
|
||||
# Call plugins
|
||||
$this->plugins(__METHOD__, 0, func_get_args());
|
||||
|
||||
# Update
|
||||
if (!isset($this->settings['version'])||$this->settings['version']!==$version) {
|
||||
if (!Database::update($database, $dbName, @$this->settings['version'])) {
|
||||
Log::error($database, __METHOD__, __LINE__, 'Updating the database failed');
|
||||
exit('Error: Updating the database failed!');
|
||||
}
|
||||
}
|
||||
|
||||
# Return settings
|
||||
$return['config'] = $this->settings;
|
||||
|
||||
# Remove username and password from response
|
||||
unset($return['config']['username']);
|
||||
unset($return['config']['password']);
|
||||
|
||||
# Remove identifier from response
|
||||
unset($return['config']['identifier']);
|
||||
|
||||
# Path to Lychee for the server-import dialog
|
||||
$return['config']['location'] = LYCHEE;
|
||||
|
||||
# Check if login credentials exist and login if they don't
|
||||
if ($this->noLogin()===true) {
|
||||
$public = false;
|
||||
$return['config']['login'] = false;
|
||||
} else {
|
||||
$return['config']['login'] = true;
|
||||
}
|
||||
|
||||
if ($public===false) {
|
||||
|
||||
# Logged in
|
||||
$return['status'] = LYCHEE_STATUS_LOGGEDIN;
|
||||
|
||||
} else {
|
||||
|
||||
# Logged out
|
||||
$return['status'] = LYCHEE_STATUS_LOGGEDOUT;
|
||||
|
||||
# Unset unused vars
|
||||
unset($return['config']['thumbQuality']);
|
||||
unset($return['config']['sortingAlbums']);
|
||||
unset($return['config']['sortingPhotos']);
|
||||
unset($return['config']['dropboxKey']);
|
||||
unset($return['config']['login']);
|
||||
unset($return['config']['location']);
|
||||
unset($return['config']['imagick']);
|
||||
unset($return['config']['medium']);
|
||||
unset($return['config']['plugins']);
|
||||
|
||||
}
|
||||
|
||||
# Call plugins
|
||||
$this->plugins(__METHOD__, 1, func_get_args());
|
||||
|
||||
return $return;
|
||||
|
||||
}
|
||||
|
||||
public function login($username, $password) {
|
||||
|
||||
# Check dependencies
|
||||
self::dependencies(isset($this->settings, $username, $password));
|
||||
|
||||
# Call plugins
|
||||
$this->plugins(__METHOD__, 0, func_get_args());
|
||||
|
||||
$username = crypt($username, $this->settings['username']);
|
||||
$password = crypt($password, $this->settings['password']);
|
||||
|
||||
# Check login with crypted hash
|
||||
if ($this->settings['username']===$username&&
|
||||
$this->settings['password']===$password) {
|
||||
$_SESSION['login'] = true;
|
||||
$_SESSION['identifier'] = $this->settings['identifier'];
|
||||
return true;
|
||||
}
|
||||
|
||||
# No login
|
||||
if ($this->noLogin()===true) return true;
|
||||
|
||||
# Call plugins
|
||||
$this->plugins(__METHOD__, 1, func_get_args());
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
private function noLogin() {
|
||||
|
||||
# Check dependencies
|
||||
self::dependencies(isset($this->settings));
|
||||
|
||||
# Check if login credentials exist and login if they don't
|
||||
if ($this->settings['username']===''&&
|
||||
$this->settings['password']==='') {
|
||||
$_SESSION['login'] = true;
|
||||
$_SESSION['identifier'] = $this->settings['identifier'];
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
public function logout() {
|
||||
|
||||
# Call plugins
|
||||
$this->plugins(__METHOD__, 0, func_get_args());
|
||||
|
||||
$_SESSION['login'] = null;
|
||||
$_SESSION['identifier'] = null;
|
||||
|
||||
session_destroy();
|
||||
|
||||
# Call plugins
|
||||
$this->plugins(__METHOD__, 1, func_get_args());
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
@ -1,255 +0,0 @@
|
||||
<?php
|
||||
|
||||
###
|
||||
# @name Settings Module
|
||||
# @copyright 2015 by Tobias Reich
|
||||
###
|
||||
|
||||
if (!defined('LYCHEE')) exit('Error: Direct access is not allowed!');
|
||||
|
||||
class Settings extends Module {
|
||||
|
||||
private $database = null;
|
||||
|
||||
public function __construct($database) {
|
||||
|
||||
# Init vars
|
||||
$this->database = $database;
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
public function get() {
|
||||
|
||||
# Check dependencies
|
||||
self::dependencies(isset($this->database));
|
||||
|
||||
# Execute query
|
||||
$query = Database::prepare($this->database, "SELECT * FROM ?", array(LYCHEE_TABLE_SETTINGS));
|
||||
$settings = $this->database->query($query);
|
||||
|
||||
# Add each to return
|
||||
while ($setting = $settings->fetch_object()) $return[$setting->key] = $setting->value;
|
||||
|
||||
# Fallback for versions below v2.5
|
||||
if (!isset($return['plugins'])) $return['plugins'] = '';
|
||||
|
||||
return $return;
|
||||
|
||||
}
|
||||
|
||||
public function setLogin($oldPassword = '', $username, $password) {
|
||||
|
||||
# Check dependencies
|
||||
self::dependencies(isset($this->database));
|
||||
|
||||
# Load settings
|
||||
$settings = $this->get();
|
||||
|
||||
if ($oldPassword===$settings['password']||$settings['password']===crypt($oldPassword, $settings['password'])) {
|
||||
|
||||
# Save username
|
||||
if ($this->setUsername($username)!==true) exit('Error: Updating username failed!');
|
||||
|
||||
# Save password
|
||||
if ($this->setPassword($password)!==true) exit('Error: Updating password failed!');
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
exit('Error: Current password entered incorrectly!');
|
||||
|
||||
}
|
||||
|
||||
private function setUsername($username) {
|
||||
|
||||
# Check dependencies
|
||||
self::dependencies(isset($this->database));
|
||||
|
||||
# Hash username
|
||||
$username = getHashedString($username);
|
||||
|
||||
# Execute query
|
||||
# Do not prepare $username because it is hashed and save
|
||||
# Preparing (escaping) the username would destroy the hash
|
||||
$query = Database::prepare($this->database, "UPDATE ? SET value = '$username' WHERE `key` = 'username'", array(LYCHEE_TABLE_SETTINGS));
|
||||
$result = $this->database->query($query);
|
||||
|
||||
if (!$result) {
|
||||
Log::error($this->database, __METHOD__, __LINE__, $this->database->error);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
private function setPassword($password) {
|
||||
|
||||
# Check dependencies
|
||||
self::dependencies(isset($this->database));
|
||||
|
||||
# Hash password
|
||||
$password = getHashedString($password);
|
||||
|
||||
# Execute query
|
||||
# Do not prepare $password because it is hashed and save
|
||||
# Preparing (escaping) the password would destroy the hash
|
||||
$query = Database::prepare($this->database, "UPDATE ? SET value = '$password' WHERE `key` = 'password'", array(LYCHEE_TABLE_SETTINGS));
|
||||
$result = $this->database->query($query);
|
||||
|
||||
if (!$result) {
|
||||
Log::error($this->database, __METHOD__, __LINE__, $this->database->error);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
public function setDropboxKey($key) {
|
||||
|
||||
# Check dependencies
|
||||
self::dependencies(isset($this->database, $key));
|
||||
|
||||
if (strlen($key)<1||strlen($key)>50) {
|
||||
Log::notice($this->database, __METHOD__, __LINE__, 'Dropbox key is either too short or too long');
|
||||
return false;
|
||||
}
|
||||
|
||||
# Execute query
|
||||
$query = Database::prepare($this->database, "UPDATE ? SET value = '?' WHERE `key` = 'dropboxKey'", array(LYCHEE_TABLE_SETTINGS, $key));
|
||||
$result = $this->database->query($query);
|
||||
|
||||
if (!$result) {
|
||||
Log::error($this->database, __METHOD__, __LINE__, $this->database->error);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
public function setSortingPhotos($type, $order) {
|
||||
|
||||
# Check dependencies
|
||||
self::dependencies(isset($this->database, $type, $order));
|
||||
|
||||
$sorting = 'ORDER BY ';
|
||||
|
||||
# Set row
|
||||
switch ($type) {
|
||||
|
||||
case 'id': $sorting .= 'id';
|
||||
break;
|
||||
|
||||
case 'title': $sorting .= 'title';
|
||||
break;
|
||||
|
||||
case 'description': $sorting .= 'description';
|
||||
break;
|
||||
|
||||
case 'public': $sorting .= 'public';
|
||||
break;
|
||||
|
||||
case 'type': $sorting .= 'type';
|
||||
break;
|
||||
|
||||
case 'star': $sorting .= 'star';
|
||||
break;
|
||||
|
||||
case 'takestamp': $sorting .= 'takestamp';
|
||||
break;
|
||||
|
||||
default: exit('Error: Unknown type for sorting!');
|
||||
|
||||
}
|
||||
|
||||
$sorting .= ' ';
|
||||
|
||||
# Set order
|
||||
switch ($order) {
|
||||
|
||||
case 'ASC': $sorting .= 'ASC';
|
||||
break;
|
||||
|
||||
case 'DESC': $sorting .= 'DESC';
|
||||
break;
|
||||
|
||||
default: exit('Error: Unknown order for sorting!');
|
||||
|
||||
}
|
||||
|
||||
# Execute query
|
||||
# Do not prepare $sorting because it is a true statement
|
||||
# Preparing (escaping) the sorting would destroy it
|
||||
# $sorting is save and can't contain user-input
|
||||
$query = Database::prepare($this->database, "UPDATE ? SET value = '$sorting' WHERE `key` = 'sortingPhotos'", array(LYCHEE_TABLE_SETTINGS));
|
||||
$result = $this->database->query($query);
|
||||
|
||||
if (!$result) {
|
||||
Log::error($this->database, __METHOD__, __LINE__, $this->database->error);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
public function setSortingAlbums($type, $order) {
|
||||
|
||||
# Check dependencies
|
||||
self::dependencies(isset($this->database, $type, $order));
|
||||
|
||||
$sorting = 'ORDER BY ';
|
||||
|
||||
# Set row
|
||||
switch ($type) {
|
||||
|
||||
case 'id': $sorting .= 'id';
|
||||
break;
|
||||
|
||||
case 'title': $sorting .= 'title';
|
||||
break;
|
||||
|
||||
case 'description': $sorting .= 'description';
|
||||
break;
|
||||
|
||||
case 'public': $sorting .= 'public';
|
||||
break;
|
||||
|
||||
default: exit('Error: Unknown type for sorting!');
|
||||
|
||||
}
|
||||
|
||||
$sorting .= ' ';
|
||||
|
||||
# Set order
|
||||
switch ($order) {
|
||||
|
||||
case 'ASC': $sorting .= 'ASC';
|
||||
break;
|
||||
|
||||
case 'DESC': $sorting .= 'DESC';
|
||||
break;
|
||||
|
||||
default: exit('Error: Unknown order for sorting!');
|
||||
|
||||
}
|
||||
|
||||
# Execute query
|
||||
# Do not prepare $sorting because it is a true statement
|
||||
# Preparing (escaping) the sorting would destroy it
|
||||
# $sorting is save and can't contain user-input
|
||||
$query = Database::prepare($this->database, "UPDATE ? SET value = '$sorting' WHERE `key` = 'sortingAlbums'", array(LYCHEE_TABLE_SETTINGS));
|
||||
$result = $this->database->query($query);
|
||||
|
||||
if (!$result) {
|
||||
Log::error($this->database, __METHOD__, __LINE__, $this->database->error);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
@ -1,199 +0,0 @@
|
||||
<?php
|
||||
|
||||
###
|
||||
# @name Misc Module
|
||||
# @copyright 2015 by Tobias Reich
|
||||
###
|
||||
|
||||
if (!defined('LYCHEE')) exit('Error: Direct access is not allowed!');
|
||||
|
||||
function search($database, $settings, $term) {
|
||||
|
||||
if (!isset($database, $settings, $term)) return false;
|
||||
|
||||
$return['albums'] = '';
|
||||
|
||||
# Initialize return var
|
||||
$return = array(
|
||||
'photos' => null,
|
||||
'albums' => null,
|
||||
'hash' => ''
|
||||
);
|
||||
|
||||
###
|
||||
# Photos
|
||||
###
|
||||
|
||||
$query = Database::prepare($database, "SELECT id, title, tags, public, star, album, thumbUrl, takestamp, url FROM ? WHERE title LIKE '%?%' OR description LIKE '%?%' OR tags LIKE '%?%'", array(LYCHEE_TABLE_PHOTOS, $term, $term, $term));
|
||||
$result = $database->query($query);
|
||||
|
||||
while($photo = $result->fetch_assoc()) {
|
||||
|
||||
$photo = Photo::prepareData($photo);
|
||||
$return['photos'][$photo['id']] = $photo;
|
||||
|
||||
}
|
||||
|
||||
###
|
||||
# Albums
|
||||
###
|
||||
|
||||
$query = Database::prepare($database, "SELECT id, title, public, sysstamp, password FROM ? WHERE title LIKE '%?%' OR description LIKE '%?%'", array(LYCHEE_TABLE_ALBUMS, $term, $term));
|
||||
$result = $database->query($query);
|
||||
|
||||
while($album = $result->fetch_assoc()) {
|
||||
|
||||
# Turn data from the database into a front-end friendly format
|
||||
$album = Album::prepareData($album);
|
||||
|
||||
# Thumbs
|
||||
$query = Database::prepare($database, "SELECT thumbUrl FROM ? WHERE album = '?' " . $settings['sortingPhotos'] . " LIMIT 0, 3", array(LYCHEE_TABLE_PHOTOS, $album['id']));
|
||||
$thumbs = $database->query($query);
|
||||
|
||||
# For each thumb
|
||||
$k = 0;
|
||||
while ($thumb = $thumbs->fetch_object()) {
|
||||
$album['thumbs'][$k] = LYCHEE_URL_UPLOADS_THUMB . $thumb->thumbUrl;
|
||||
$k++;
|
||||
}
|
||||
|
||||
# Add to return
|
||||
$return['albums'][$album['id']] = $album;
|
||||
|
||||
}
|
||||
|
||||
# Hash
|
||||
$return['hash'] = md5(json_encode($return));
|
||||
|
||||
return $return;
|
||||
|
||||
}
|
||||
|
||||
function getGraphHeader($database, $photoID) {
|
||||
|
||||
if (!isset($database, $photoID)) return false;
|
||||
|
||||
$photo = new Photo($database, null, null, $photoID);
|
||||
if ($photo->getPublic('')===false) return false;
|
||||
|
||||
$query = Database::prepare($database, "SELECT title, description, url, medium FROM ? WHERE id = '?'", array(LYCHEE_TABLE_PHOTOS, $photoID));
|
||||
$result = $database->query($query);
|
||||
$row = $result->fetch_object();
|
||||
|
||||
if (!$result||!$row) return false;
|
||||
|
||||
if ($row->medium==='1') $dir = 'medium';
|
||||
else $dir = 'big';
|
||||
|
||||
$parseUrl = parse_url('http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']);
|
||||
$url = $parseUrl['scheme'] . '://' . $parseUrl['host'] . $parseUrl['path'] . '?' . $parseUrl['query'];
|
||||
$picture = $parseUrl['scheme'] . '://' . $parseUrl['host'] . $parseUrl['path'] . '/../uploads/' . $dir . '/' . $row->url;
|
||||
|
||||
$url = htmlentities($url);
|
||||
$picture = htmlentities($picture);
|
||||
|
||||
$row->title = htmlentities($row->title);
|
||||
$row->description = htmlentities($row->description);
|
||||
|
||||
$return = '<!-- General Meta Data -->';
|
||||
$return .= '<meta name="title" content="' . $row->title . '">';
|
||||
$return .= '<meta name="description" content="' . $row->description . ' - via Lychee">';
|
||||
$return .= '<link rel="image_src" type="image/jpeg" href="' . $picture . '">';
|
||||
|
||||
$return .= '<!-- Twitter Meta Data -->';
|
||||
$return .= '<meta name="twitter:card" content="photo">';
|
||||
$return .= '<meta name="twitter:title" content="' . $row->title . '">';
|
||||
$return .= '<meta name="twitter:image:src" content="' . $picture . '">';
|
||||
|
||||
$return .= '<!-- Facebook Meta Data -->';
|
||||
$return .= '<meta property="og:title" content="' . $row->title . '">';
|
||||
$return .= '<meta property="og:description" content="' . $row->description . ' - via Lychee">';
|
||||
$return .= '<meta property="og:image" content="' . $picture . '">';
|
||||
$return .= '<meta property="og:url" content="' . $url . '">';
|
||||
|
||||
return $return;
|
||||
|
||||
}
|
||||
|
||||
function getExtension($filename) {
|
||||
|
||||
$extension = strpos($filename, '.') !== false
|
||||
? strrchr($filename, '.')
|
||||
: '';
|
||||
|
||||
return $extension;
|
||||
|
||||
}
|
||||
|
||||
function getHashedString($password) {
|
||||
|
||||
# Inspired by http://alias.io/2010/01/store-passwords-safely-with-php-and-mysql/
|
||||
|
||||
# A higher $cost is more secure but consumes more processing power
|
||||
$cost = 10;
|
||||
|
||||
# Create a random salt
|
||||
if (extension_loaded('openssl')) {
|
||||
$salt = strtr(substr(base64_encode(openssl_random_pseudo_bytes(17)),0,22), '+', '.');
|
||||
} elseif (extension_loaded('mcrypt')) {
|
||||
$salt = strtr(substr(base64_encode(mcrypt_create_iv(17, MCRYPT_DEV_URANDOM)),0,22), '+', '.');
|
||||
} else {
|
||||
$salt = "";
|
||||
for ($i = 0; $i < 22; $i++) {
|
||||
$salt .= substr("./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", mt_rand(0, 63), 1);
|
||||
}
|
||||
}
|
||||
|
||||
# Prefix information about the hash so PHP knows how to verify it later.
|
||||
# "$2a$" Means we're using the Blowfish algorithm. The following two digits are the cost parameter.
|
||||
$salt = sprintf("$2a$%02d$", $cost) . $salt;
|
||||
|
||||
# Hash the password with the salt
|
||||
return crypt($password, $salt);
|
||||
|
||||
}
|
||||
|
||||
function hasPermissions($path) {
|
||||
|
||||
// Check if the given path is readable and writable
|
||||
// Both functions are also verifying that the path exists
|
||||
if (is_readable($path)===true&&
|
||||
is_writeable($path)===true) return true;
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
function fastimagecopyresampled(&$dst_image, $src_image, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h, $quality = 4) {
|
||||
|
||||
###
|
||||
# Plug-and-Play fastimagecopyresampled function replaces much slower imagecopyresampled.
|
||||
# Just include this function and change all "imagecopyresampled" references to "fastimagecopyresampled".
|
||||
# Typically from 30 to 60 times faster when reducing high resolution images down to thumbnail size using the default quality setting.
|
||||
# Author: Tim Eckel - Date: 09/07/07 - Version: 1.1 - Project: FreeRingers.net - Freely distributable - These comments must remain.
|
||||
#
|
||||
# Optional "quality" parameter (defaults is 3). Fractional values are allowed, for example 1.5. Must be greater than zero.
|
||||
# Between 0 and 1 = Fast, but mosaic results, closer to 0 increases the mosaic effect.
|
||||
# 1 = Up to 350 times faster. Poor results, looks very similar to imagecopyresized.
|
||||
# 2 = Up to 95 times faster. Images appear a little sharp, some prefer this over a quality of 3.
|
||||
# 3 = Up to 60 times faster. Will give high quality smooth results very close to imagecopyresampled, just faster.
|
||||
# 4 = Up to 25 times faster. Almost identical to imagecopyresampled for most images.
|
||||
# 5 = No speedup. Just uses imagecopyresampled, no advantage over imagecopyresampled.
|
||||
###
|
||||
|
||||
if (empty($src_image) || empty($dst_image) || $quality <= 0) { return false; }
|
||||
|
||||
if ($quality < 5 && (($dst_w * $quality) < $src_w || ($dst_h * $quality) < $src_h)) {
|
||||
|
||||
$temp = imagecreatetruecolor($dst_w * $quality + 1, $dst_h * $quality + 1);
|
||||
imagecopyresized($temp, $src_image, 0, 0, $src_x, $src_y, $dst_w * $quality + 1, $dst_h * $quality + 1, $src_w, $src_h);
|
||||
imagecopyresampled($dst_image, $temp, $dst_x, $dst_y, 0, 0, $dst_w, $dst_h, $dst_w * $quality, $dst_h * $quality);
|
||||
imagedestroy($temp);
|
||||
|
||||
} else imagecopyresampled($dst_image, $src_image, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h);
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
?>
|
141
plugins/Diagnostics/index.php
Normal file
141
plugins/Diagnostics/index.php
Normal file
@ -0,0 +1,141 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @author Tobias Reich
|
||||
* @copyright 2015 by Tobias Reich
|
||||
* @description This file takes a look at your Lychee-configuration and displays all errors it can find.
|
||||
*/
|
||||
|
||||
namespace Diagnostics;
|
||||
|
||||
use Mysqli;
|
||||
use Imagick;
|
||||
use Lychee\Modules\Settings;
|
||||
|
||||
$lychee = __DIR__ . '/../../';
|
||||
|
||||
require($lychee . 'php/define.php');
|
||||
require($lychee . 'php/autoload.php');
|
||||
|
||||
require($lychee . 'php/helpers/hasPermissions.php');
|
||||
|
||||
// Start the session
|
||||
session_start();
|
||||
|
||||
// Set content
|
||||
header('content-type: text/plain');
|
||||
|
||||
// Declare
|
||||
$error = '';
|
||||
|
||||
// Show separator
|
||||
echo('Diagnostics' . PHP_EOL);
|
||||
echo('-----------' . PHP_EOL);
|
||||
|
||||
// PHP Version
|
||||
if (floatval(phpversion())<5.5) $error .= ('Error: Upgrade to PHP 5.5 or higher' . PHP_EOL);
|
||||
|
||||
// Extensions
|
||||
if (!extension_loaded('session')) $error .= ('Error: PHP session extension not activated' . PHP_EOL);
|
||||
if (!extension_loaded('exif')) $error .= ('Error: PHP exif extension not activated' . PHP_EOL);
|
||||
if (!extension_loaded('mbstring')) $error .= ('Error: PHP mbstring extension not activated' . PHP_EOL);
|
||||
if (!extension_loaded('gd')) $error .= ('Error: PHP gd extension not activated' . PHP_EOL);
|
||||
if (!extension_loaded('mysqli')) $error .= ('Error: PHP mysqli extension not activated' . PHP_EOL);
|
||||
if (!extension_loaded('json')) $error .= ('Error: PHP json extension not activated' . PHP_EOL);
|
||||
if (!extension_loaded('zip')) $error .= ('Error: PHP zip extension not activated' . PHP_EOL);
|
||||
|
||||
// Permissions
|
||||
if (hasPermissions(LYCHEE_UPLOADS_BIG)===false) $error .= ('Error: \'uploads/big\' is missing or has insufficient read/write privileges' . PHP_EOL);
|
||||
if (hasPermissions(LYCHEE_UPLOADS_MEDIUM)===false) $error .= ('Error: \'uploads/medium\' is missing or has insufficient read/write privileges' . PHP_EOL);
|
||||
if (hasPermissions(LYCHEE_UPLOADS_THUMB)===false) $error .= ('Error: \'uploads/thumb\' is missing or has insufficient read/write privileges' . PHP_EOL);
|
||||
if (hasPermissions(LYCHEE_UPLOADS_IMPORT)===false) $error .= ('Error: \'uploads/import\' is missing or has insufficient read/write privileges' . PHP_EOL);
|
||||
if (hasPermissions(LYCHEE_UPLOADS)===false) $error .= ('Error: \'uploads/\' is missing or has insufficient read/write privileges' . PHP_EOL);
|
||||
if (hasPermissions(LYCHEE_DATA)===false) $error .= ('Error: \'data/\' is missing or has insufficient read/write privileges' . PHP_EOL);
|
||||
|
||||
// About GD
|
||||
$gdVersion = gd_info();
|
||||
if (!$gdVersion['JPEG Support']) $error .= ('Error: PHP gd extension without jpeg support' . PHP_EOL);
|
||||
if (!$gdVersion['PNG Support']) $error .= ('Error: PHP gd extension without png support' . PHP_EOL);
|
||||
if (!$gdVersion['GIF Read Support'] || !$gdVersion['GIF Create Support']) $error .= ('Error: PHP gd extension without full gif support' . PHP_EOL);
|
||||
|
||||
// Load config
|
||||
if (!file_exists(LYCHEE_CONFIG_FILE)) exit('Error: Configuration not found. Please install Lychee for additional tests');
|
||||
require(LYCHEE_CONFIG_FILE);
|
||||
|
||||
// Database
|
||||
$database = new Mysqli($dbHost, $dbUser, $dbPassword, $dbName);
|
||||
if (mysqli_connect_errno()!=0) $error .= ('Error: ' . mysqli_connect_errno() . ': ' . mysqli_connect_error() . '' . PHP_EOL);
|
||||
|
||||
// Config
|
||||
if (!isset($dbName)||$dbName==='') $error .= ('Error: No property for $dbName in config.php' . PHP_EOL);
|
||||
if (!isset($dbUser)||$dbUser==='') $error .= ('Error: No property for $dbUser in config.php' . PHP_EOL);
|
||||
if (!isset($dbPassword)) $error .= ('Error: No property for $dbPassword in config.php' . PHP_EOL);
|
||||
if (!isset($dbHost)||$dbHost==='') $error .= ('Error: No property for $dbHost in config.php' . PHP_EOL);
|
||||
|
||||
// Load settings
|
||||
$settings = Settings::get();
|
||||
|
||||
// Settings
|
||||
if (!isset($settings['username'])||$settings['username']=='') $error .= ('Error: Username empty or not set in database' . PHP_EOL);
|
||||
if (!isset($settings['password'])||$settings['password']=='') $error .= ('Error: Password empty or not set in database' . PHP_EOL);
|
||||
if (!isset($settings['sortingPhotos'])||$settings['sortingPhotos']=='') $error .= ('Error: Wrong property for sortingPhotos in database' . PHP_EOL);
|
||||
if (!isset($settings['sortingAlbums'])||$settings['sortingAlbums']=='') $error .= ('Error: Wrong property for sortingAlbums in database' . PHP_EOL);
|
||||
if (!isset($settings['plugins'])) $error .= ('Error: No property for plugins in database' . PHP_EOL);
|
||||
if (!isset($settings['imagick'])||$settings['imagick']=='') $error .= ('Error: No or wrong property for imagick in database' . PHP_EOL);
|
||||
if (!isset($settings['identifier'])||$settings['identifier']=='') $error .= ('Error: No or wrong property for identifier in database' . PHP_EOL);
|
||||
if (!isset($settings['skipDuplicates'])||$settings['skipDuplicates']=='') $error .= ('Error: No or wrong property for skipDuplicates in database' . PHP_EOL);
|
||||
if (!isset($settings['checkForUpdates'])||($settings['checkForUpdates']!='0'&&$settings['checkForUpdates']!='1')) $error .= ('Error: No or wrong property for checkForUpdates in database' . PHP_EOL);
|
||||
|
||||
// Check dropboxKey
|
||||
if (!$settings['dropboxKey']) echo('Warning: Dropbox import not working. No property for dropboxKey.' . PHP_EOL);
|
||||
|
||||
// Check php.ini Settings
|
||||
if (ini_get('max_execution_time')<200&&ini_set('upload_max_filesize', '20M')===false) echo('Warning: You may experience problems when uploading a large amount of photos. Take a look in the FAQ for details.' . PHP_EOL);
|
||||
if (empty(ini_get('allow_url_fopen'))) echo('Warning: You may experience problems with the Dropbox- and URL-Import. Edit your php.ini and set allow_url_fopen to 1.' . PHP_EOL);
|
||||
|
||||
// Check mysql version
|
||||
if ($database->server_version<50500) echo('Warning: Lychee uses the GBK charset to avoid sql injections on your MySQL version. Please update to MySQL 5.5 or higher to enable UTF-8 support.' . PHP_EOL);
|
||||
|
||||
// Output
|
||||
if ($error==='') echo('No critical problems found. Lychee should work without problems!' . PHP_EOL);
|
||||
else echo $error;
|
||||
|
||||
// Show separator
|
||||
echo(PHP_EOL . PHP_EOL . 'System Information' . PHP_EOL);
|
||||
echo('------------------' . PHP_EOL);
|
||||
|
||||
// Ensure that user is logged in
|
||||
if ((isset($_SESSION['login'])&&$_SESSION['login']===true)&&
|
||||
(isset($_SESSION['identifier'])&&$_SESSION['identifier']===$settings['identifier'])) {
|
||||
|
||||
// Load json
|
||||
$json = file_get_contents(LYCHEE_SRC . 'package.json');
|
||||
$json = json_decode($json, true);
|
||||
|
||||
// About imagick
|
||||
$imagick = extension_loaded('imagick');
|
||||
if ($imagick===true) $imagickVersion = @Imagick::getVersion();
|
||||
else $imagick = '-';
|
||||
if (!isset($imagickVersion, $imagickVersion['versionNumber'])||$imagickVersion==='') $imagickVersion = '-';
|
||||
else $imagickVersion = $imagickVersion['versionNumber'];
|
||||
|
||||
// Output system information
|
||||
echo('Lychee Version: ' . $json['version'] . PHP_EOL);
|
||||
echo('DB Version: ' . $settings['version'] . PHP_EOL);
|
||||
echo('System: ' . PHP_OS . PHP_EOL);
|
||||
echo('PHP Version: ' . floatval(phpversion()) . PHP_EOL);
|
||||
echo('MySQL Version: ' . $database->server_version . PHP_EOL);
|
||||
echo('Imagick: ' . $imagick . PHP_EOL);
|
||||
echo('Imagick Active: ' . $settings['imagick'] . PHP_EOL);
|
||||
echo('Imagick Version: ' . $imagickVersion . PHP_EOL);
|
||||
echo('GD Version: ' . $gdVersion['GD Version'] . PHP_EOL);
|
||||
echo('Plugins: ' . implode($settings['plugins'], ', ') . PHP_EOL);
|
||||
|
||||
} else {
|
||||
|
||||
// Don't go further if the user is not logged in
|
||||
exit('You have to be logged in to see more information.');
|
||||
|
||||
}
|
||||
|
||||
?>
|
64
plugins/Log/index.php
Normal file
64
plugins/Log/index.php
Normal file
@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @author Tobias Reich
|
||||
* @copyright 2015 by Tobias Reich
|
||||
* @description This file queries the database for log messages and displays them if present.
|
||||
*/
|
||||
|
||||
namespace Log;
|
||||
|
||||
use Mysqli;
|
||||
use Lychee\Modules\Database;
|
||||
use Lychee\Modules\Settings;
|
||||
|
||||
$lychee = __DIR__ . '/../../';
|
||||
|
||||
require($lychee . 'php/define.php');
|
||||
require($lychee . 'php/autoload.php');
|
||||
|
||||
// Start the session
|
||||
session_start();
|
||||
|
||||
// Set content
|
||||
header('content-type: text/plain');
|
||||
|
||||
// Load config
|
||||
if (!file_exists(LYCHEE_CONFIG_FILE)) exit('Error 001: Configuration not found. Please install Lychee first.');
|
||||
require(LYCHEE_CONFIG_FILE);
|
||||
|
||||
// Ensure that user is logged in
|
||||
if ((isset($_SESSION['login'])&&$_SESSION['login']===true)&&
|
||||
(isset($_SESSION['identifier'])&&$_SESSION['identifier']===Settings::get()['identifier'])) {
|
||||
|
||||
// Result
|
||||
$query = Database::prepare(Database::get(), "SELECT FROM_UNIXTIME(time), type, function, line, text FROM ?", array(LYCHEE_TABLE_LOG));
|
||||
$result = Database::get()->query($query);
|
||||
|
||||
// Output
|
||||
if ($result->num_rows===0) {
|
||||
|
||||
echo('Everything looks fine, Lychee has not reported any problems!');
|
||||
|
||||
} else {
|
||||
|
||||
while($row = $result->fetch_row()) {
|
||||
|
||||
// Encode result before printing
|
||||
$row = array_map('htmlentities', $row);
|
||||
|
||||
// Format: time TZ - type - function(line) - text
|
||||
printf("%s - %s - %s (%s) \t- %s\n", $row[0], $row[1], $row[2], $row[3], $row[4]);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// Don't go further if the user is not logged in
|
||||
exit('You have to be logged in to see the log.');
|
||||
|
||||
}
|
||||
|
||||
?>
|
@ -1,143 +0,0 @@
|
||||
<?php
|
||||
|
||||
###
|
||||
# @name Check Plugin
|
||||
# @author Tobias Reich
|
||||
# @copyright 2015 by Tobias Reich
|
||||
# @description This file takes a look at your Lychee-configuration and displays all errors it can find.
|
||||
###
|
||||
|
||||
# Location
|
||||
$lychee = __DIR__ . '/../../';
|
||||
|
||||
# Load requirements
|
||||
require($lychee . 'php/define.php');
|
||||
require($lychee . 'php/autoload.php');
|
||||
require($lychee . 'php/modules/misc.php');
|
||||
|
||||
# Set content
|
||||
header('content-type: text/plain');
|
||||
|
||||
# Declare
|
||||
$error = '';
|
||||
|
||||
# Show separator
|
||||
echo('Diagnostics' . PHP_EOL);
|
||||
echo('-----------' . PHP_EOL);
|
||||
|
||||
# PHP Version
|
||||
if (floatval(phpversion())<5.5) $error .= ('Error: Upgrade to PHP 5.5 or higher' . PHP_EOL);
|
||||
|
||||
# Extensions
|
||||
if (!extension_loaded('session')) $error .= ('Error: PHP session extension not activated' . PHP_EOL);
|
||||
if (!extension_loaded('exif')) $error .= ('Error: PHP exif extension not activated' . PHP_EOL);
|
||||
if (!extension_loaded('mbstring')) $error .= ('Error: PHP mbstring extension not activated' . PHP_EOL);
|
||||
if (!extension_loaded('gd')) $error .= ('Error: PHP gd extension not activated' . PHP_EOL);
|
||||
if (!extension_loaded('mysqli')) $error .= ('Error: PHP mysqli extension not activated' . PHP_EOL);
|
||||
if (!extension_loaded('json')) $error .= ('Error: PHP json extension not activated' . PHP_EOL);
|
||||
if (!extension_loaded('zip')) $error .= ('Error: PHP zip extension not activated' . PHP_EOL);
|
||||
|
||||
# Permissions
|
||||
if (hasPermissions(LYCHEE_UPLOADS_BIG)===false) $error .= ('Error: \'uploads/big\' is missing or has insufficient read/write privileges' . PHP_EOL);
|
||||
if (hasPermissions(LYCHEE_UPLOADS_MEDIUM)===false) $error .= ('Error: \'uploads/medium\' is missing or has insufficient read/write privileges' . PHP_EOL);
|
||||
if (hasPermissions(LYCHEE_UPLOADS_THUMB)===false) $error .= ('Error: \'uploads/thumb\' is missing or has insufficient read/write privileges' . PHP_EOL);
|
||||
if (hasPermissions(LYCHEE_UPLOADS_IMPORT)===false) $error .= ('Error: \'uploads/import\' is missing or has insufficient read/write privileges' . PHP_EOL);
|
||||
if (hasPermissions(LYCHEE_UPLOADS)===false) $error .= ('Error: \'uploads/\' is missing or has insufficient read/write privileges' . PHP_EOL);
|
||||
if (hasPermissions(LYCHEE_DATA)===false) $error .= ('Error: \'data/\' is missing or has insufficient read/write privileges' . PHP_EOL);
|
||||
|
||||
# Load config
|
||||
if (!file_exists(LYCHEE_CONFIG_FILE)) exit('Error: Configuration not found. Please install Lychee for additional tests');
|
||||
else require(LYCHEE_CONFIG_FILE);
|
||||
|
||||
# Define the table prefix
|
||||
if (!isset($dbTablePrefix)) $dbTablePrefix = '';
|
||||
defineTablePrefix($dbTablePrefix);
|
||||
|
||||
# Database
|
||||
$database = new mysqli($dbHost, $dbUser, $dbPassword, $dbName);
|
||||
if (mysqli_connect_errno()!=0) $error .= ('Error: ' . mysqli_connect_errno() . ': ' . mysqli_connect_error() . '' . PHP_EOL);
|
||||
|
||||
# Load settings
|
||||
$settings = new Settings($database);
|
||||
$settings = $settings->get();
|
||||
|
||||
# Config
|
||||
if (!isset($dbName)||$dbName==='') $error .= ('Error: No property for $dbName in config.php' . PHP_EOL);
|
||||
if (!isset($dbUser)||$dbUser==='') $error .= ('Error: No property for $dbUser in config.php' . PHP_EOL);
|
||||
if (!isset($dbPassword)) $error .= ('Error: No property for $dbPassword in config.php' . PHP_EOL);
|
||||
if (!isset($dbHost)||$dbHost==='') $error .= ('Error: No property for $dbHost in config.php' . PHP_EOL);
|
||||
|
||||
# Settings
|
||||
if (!isset($settings['username'])||$settings['username']=='') $error .= ('Error: Username empty or not set in database' . PHP_EOL);
|
||||
if (!isset($settings['password'])||$settings['password']=='') $error .= ('Error: Password empty or not set in database' . PHP_EOL);
|
||||
if (!isset($settings['thumbQuality'])||$settings['thumbQuality']=='') $error .= ('Error: No or wrong property for thumbQuality in database' . PHP_EOL);
|
||||
if (!isset($settings['sortingPhotos'])||$settings['sortingPhotos']=='') $error .= ('Error: Wrong property for sortingPhotos in database' . PHP_EOL);
|
||||
if (!isset($settings['sortingAlbums'])||$settings['sortingAlbums']=='') $error .= ('Error: Wrong property for sortingAlbums in database' . PHP_EOL);
|
||||
if (!isset($settings['plugins'])) $error .= ('Error: No property for plugins in database' . PHP_EOL);
|
||||
if (!isset($settings['imagick'])||$settings['imagick']=='') $error .= ('Error: No or wrong property for imagick in database' . PHP_EOL);
|
||||
if (!isset($settings['identifier'])||$settings['identifier']=='') $error .= ('Error: No or wrong property for identifier in database' . PHP_EOL);
|
||||
if (!isset($settings['skipDuplicates'])||$settings['skipDuplicates']=='') $error .= ('Error: No or wrong property for skipDuplicates in database' . PHP_EOL);
|
||||
if (!isset($settings['checkForUpdates'])||($settings['checkForUpdates']!='0'&&$settings['checkForUpdates']!='1')) $error .= ('Error: No or wrong property for checkForUpdates in database' . PHP_EOL);
|
||||
|
||||
# Check dropboxKey
|
||||
if (!$settings['dropboxKey']) echo('Warning: Dropbox import not working. No property for dropboxKey' . PHP_EOL);
|
||||
|
||||
# Check php.ini Settings
|
||||
if (ini_get('max_execution_time')<200&&ini_set('upload_max_filesize', '20M')===false) echo('Warning: You may experience problems when uploading a large amount of photos. Take a look in the FAQ for details.' . PHP_EOL);
|
||||
if (!ini_get('allow_url_fopen')) echo('Warning: You may experience problems with the Dropbox- and URL-Import. Edit your php.ini and set allow_url_fopen to 1.' . PHP_EOL);
|
||||
|
||||
# Check mysql version
|
||||
if ($database->server_version<50500) echo('Warning: Lychee uses the GBK charset to avoid sql injections on your MySQL version. Please update to MySQL 5.5 or higher to enable UTF-8 support.' . PHP_EOL);
|
||||
|
||||
# About GD
|
||||
$gdVersion = gd_info();
|
||||
if (!$gdVersion['JPEG Support']) $error .= ('Error: PHP gd extension without jpeg support' . PHP_EOL);
|
||||
if (!$gdVersion['PNG Support']) $error .= ('Error: PHP gd extension without png support' . PHP_EOL);
|
||||
if (!$gdVersion['GIF Read Support'] || !$gdVersion['GIF Create Support']) $error .= ('Error: PHP gd extension without full gif support' . PHP_EOL);
|
||||
|
||||
# Output
|
||||
if ($error==='') echo('No critical problems found. Lychee should work without problems!' . PHP_EOL);
|
||||
else echo $error;
|
||||
|
||||
# Show separator
|
||||
echo(PHP_EOL . PHP_EOL . 'System Information' . PHP_EOL);
|
||||
echo('------------------' . PHP_EOL);
|
||||
|
||||
# Ensure that user is logged in
|
||||
session_start();
|
||||
|
||||
if ((isset($_SESSION['login'])&&$_SESSION['login']===true)&&
|
||||
(isset($_SESSION['identifier'])&&$_SESSION['identifier']===$settings['identifier'])) {
|
||||
|
||||
# Load json
|
||||
$json = file_get_contents(LYCHEE_SRC . 'package.json');
|
||||
$json = json_decode($json, true);
|
||||
|
||||
# About imagick
|
||||
$imagick = extension_loaded('imagick');
|
||||
if ($imagick===true) $imagickVersion = @Imagick::getVersion();
|
||||
else $imagick = '-';
|
||||
if (!isset($imagickVersion, $imagickVersion['versionNumber'])||$imagickVersion==='') $imagickVersion = '-';
|
||||
else $imagickVersion = $imagickVersion['versionNumber'];
|
||||
|
||||
# Output system information
|
||||
echo('Lychee Version: ' . $json['version'] . PHP_EOL);
|
||||
echo('DB Version: ' . $settings['version'] . PHP_EOL);
|
||||
echo('System: ' . PHP_OS . PHP_EOL);
|
||||
echo('PHP Version: ' . floatval(phpversion()) . PHP_EOL);
|
||||
echo('MySQL Version: ' . $database->server_version . PHP_EOL);
|
||||
echo('Imagick: ' . $imagick . PHP_EOL);
|
||||
echo('Imagick Active: ' . $settings['imagick'] . PHP_EOL);
|
||||
echo('Imagick Version: ' . $imagickVersion . PHP_EOL);
|
||||
echo('GD Version: ' . $gdVersion['GD Version'] . PHP_EOL);
|
||||
echo('Plugins: ' . $settings['plugins'] . PHP_EOL);
|
||||
|
||||
} else {
|
||||
|
||||
# Don't go further if the user is not logged in
|
||||
echo('You have to be logged in to see more information.');
|
||||
exit();
|
||||
|
||||
}
|
||||
|
||||
?>
|
@ -1,81 +0,0 @@
|
||||
<?php
|
||||
|
||||
###
|
||||
# @name Display Log Plugin
|
||||
# @author Tobias Reich
|
||||
# @copyright 2015 by Tobias Reich
|
||||
# @description This file queries the database for log messages and displays them if present.
|
||||
###
|
||||
|
||||
# Location
|
||||
$lychee = __DIR__ . '/../../';
|
||||
|
||||
# Load requirements
|
||||
require($lychee . 'php/define.php');
|
||||
require($lychee . 'php/autoload.php');
|
||||
require($lychee . 'php/modules/misc.php');
|
||||
|
||||
# Set content
|
||||
header('content-type: text/plain');
|
||||
|
||||
# Load config
|
||||
if (!file_exists(LYCHEE_CONFIG_FILE)) exit('Error 001: Configuration not found. Please install Lychee first.');
|
||||
require(LYCHEE_CONFIG_FILE);
|
||||
|
||||
# Define the table prefix
|
||||
if (!isset($dbTablePrefix)) $dbTablePrefix = '';
|
||||
defineTablePrefix($dbTablePrefix);
|
||||
|
||||
# Declare
|
||||
$result = '';
|
||||
|
||||
# Database
|
||||
$database = new mysqli($dbHost, $dbUser, $dbPassword, $dbName);
|
||||
|
||||
if (mysqli_connect_errno()!=0) {
|
||||
echo 'Error 100: ' . mysqli_connect_errno() . ': ' . mysqli_connect_error() . '' . PHP_EOL;
|
||||
exit();
|
||||
}
|
||||
|
||||
# Load settings
|
||||
$settings = new Settings($database);
|
||||
$settings = $settings->get();
|
||||
|
||||
# Ensure that user is logged in
|
||||
session_start();
|
||||
|
||||
if ((isset($_SESSION['login'])&&$_SESSION['login']===true)&&
|
||||
(isset($_SESSION['identifier'])&&$_SESSION['identifier']===$settings['identifier'])) {
|
||||
|
||||
# Result
|
||||
$query = Database::prepare($database, "SELECT FROM_UNIXTIME(time), type, function, line, text FROM ?", array(LYCHEE_TABLE_LOG));
|
||||
$result = $database->query($query);
|
||||
|
||||
# Output
|
||||
if ($result->num_rows===0) {
|
||||
|
||||
echo('Everything looks fine, Lychee has not reported any problems!');
|
||||
|
||||
} else {
|
||||
|
||||
while($row = $result->fetch_row()) {
|
||||
|
||||
# Encode result before printing
|
||||
$row = array_map('htmlentities', $row);
|
||||
|
||||
# Format: time TZ - type - function(line) - text
|
||||
printf ("%s - %s - %s (%s) \t- %s\n", $row[0], $row[1], $row[2], $row[3], $row[4]);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
# Don't go further if the user is not logged in
|
||||
echo('You have to be logged in to see the log.');
|
||||
exit();
|
||||
|
||||
}
|
||||
|
||||
?>
|
2141
src/npm-shrinkwrap.json
generated
Normal file
2141
src/npm-shrinkwrap.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Lychee",
|
||||
"version": "3.0.9",
|
||||
"version": "3.1.0",
|
||||
"description": "Self-hosted photo-management done right.",
|
||||
"authors": "Tobias Reich <tobias@electerious.com>",
|
||||
"license": "MIT",
|
||||
@ -9,21 +9,25 @@
|
||||
"type": "git",
|
||||
"url": "https://github.com/electerious/Lychee.git"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-preset-es2015": "^6.3.13",
|
||||
"scripts": {
|
||||
"start": "gulp watch",
|
||||
"compile": "gulp"
|
||||
},
|
||||
"dependencies": {
|
||||
"babel-preset-es2015": "^6.6.0",
|
||||
"basiccontext": "^3.5.1",
|
||||
"basicmodal": "^3.3.2",
|
||||
"gulp": "^3.9.0",
|
||||
"basicmodal": "^3.3.3",
|
||||
"gulp": "^3.9.1",
|
||||
"gulp-autoprefixer": "3.1.0",
|
||||
"gulp-babel": "^6.1.1",
|
||||
"gulp-babel": "^6.1.2",
|
||||
"gulp-concat": "^2.6.0",
|
||||
"gulp-inject": "^3.0.0",
|
||||
"gulp-load-plugins": "^1.2.0",
|
||||
"gulp-minify-css": "^1.2.3",
|
||||
"gulp-minify-css": "^1.2.4",
|
||||
"gulp-rimraf": "^0.2.0",
|
||||
"gulp-sass": "^2.1.1",
|
||||
"gulp-uglify": "^1.5.1",
|
||||
"jquery": "^2.1.4",
|
||||
"gulp-sass": "^2.2.0",
|
||||
"gulp-uglify": "^1.5.3",
|
||||
"jquery": "^2.2.1",
|
||||
"mousetrap": "^1.5.3"
|
||||
}
|
||||
}
|
||||
|
@ -2,9 +2,9 @@ function gup(b) {
|
||||
|
||||
b = b.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]")
|
||||
|
||||
let a = "[\\?&]" + b + "=([^&#]*)",
|
||||
d = new RegExp(a),
|
||||
c = d.exec(window.location.href)
|
||||
let a = "[\\?&]" + b + "=([^&#]*)"
|
||||
let d = new RegExp(a)
|
||||
let c = d.exec(window.location.href)
|
||||
|
||||
if (c === null) return ''
|
||||
else return c[1]
|
||||
|
@ -55,7 +55,7 @@ album.load = function(albumID, refresh = false) {
|
||||
} else {
|
||||
// Album not public
|
||||
lychee.content.show()
|
||||
lychee.goto('')
|
||||
lychee.goto()
|
||||
}
|
||||
return false
|
||||
}
|
||||
@ -110,12 +110,11 @@ album.add = function() {
|
||||
|
||||
basicModal.close()
|
||||
|
||||
if (title.length===0) title = 'Untitled'
|
||||
let params = {
|
||||
title
|
||||
}
|
||||
|
||||
api.post('Album::add', { title }, function(data) {
|
||||
|
||||
// Avoid first album to be true
|
||||
if (data===true) data = 1
|
||||
api.post('Album::add', params, function(data) {
|
||||
|
||||
if (data!==false && isNumber(data)) {
|
||||
albums.refresh()
|
||||
@ -146,20 +145,18 @@ album.add = function() {
|
||||
|
||||
album.delete = function(albumIDs) {
|
||||
|
||||
let action = {},
|
||||
cancel = {},
|
||||
msg = ''
|
||||
let action = {}
|
||||
let cancel = {}
|
||||
let msg = ''
|
||||
|
||||
if (!albumIDs) return false
|
||||
if (albumIDs instanceof Array===false) albumIDs = [albumIDs]
|
||||
if (albumIDs instanceof Array===false) albumIDs = [ albumIDs ]
|
||||
|
||||
action.fn = function() {
|
||||
|
||||
let params
|
||||
|
||||
basicModal.close()
|
||||
|
||||
params = {
|
||||
let params = {
|
||||
albumIDs: albumIDs.join()
|
||||
}
|
||||
|
||||
@ -176,7 +173,7 @@ album.delete = function(albumIDs) {
|
||||
} else {
|
||||
|
||||
albums.refresh()
|
||||
lychee.goto('')
|
||||
lychee.goto()
|
||||
|
||||
}
|
||||
|
||||
@ -204,6 +201,9 @@ album.delete = function(albumIDs) {
|
||||
if (album.json) albumTitle = album.json.title
|
||||
else if (albums.json) albumTitle = albums.getByID(albumIDs).title
|
||||
|
||||
// Fallback for album without a title
|
||||
if (albumTitle==='') albumTitle = 'Untitled'
|
||||
|
||||
msg = lychee.html`<p>Are you sure you want to delete the album '$${ albumTitle }' and all of the photos it contains? This action can't be undone!</p>`
|
||||
|
||||
} else {
|
||||
@ -234,11 +234,11 @@ album.delete = function(albumIDs) {
|
||||
|
||||
album.setTitle = function(albumIDs) {
|
||||
|
||||
let oldTitle = '',
|
||||
msg = ''
|
||||
let oldTitle = ''
|
||||
let msg = ''
|
||||
|
||||
if (!albumIDs) return false
|
||||
if (albumIDs instanceof Array===false) albumIDs = [albumIDs]
|
||||
if (albumIDs instanceof Array===false) albumIDs = [ albumIDs ]
|
||||
|
||||
if (albumIDs.length===1) {
|
||||
|
||||
@ -246,18 +246,13 @@ album.setTitle = function(albumIDs) {
|
||||
if (album.json) oldTitle = album.json.title
|
||||
else if (albums.json) oldTitle = albums.getByID(albumIDs).title
|
||||
|
||||
if (!oldTitle) oldTitle = ''
|
||||
|
||||
}
|
||||
|
||||
const action = function(data) {
|
||||
|
||||
let newTitle = data.title
|
||||
|
||||
basicModal.close()
|
||||
|
||||
// Set title to Untitled when empty
|
||||
newTitle = (newTitle==='') ? 'Untitled' : newTitle
|
||||
let newTitle = data.title
|
||||
|
||||
if (visible.album()) {
|
||||
|
||||
@ -315,7 +310,7 @@ album.setTitle = function(albumIDs) {
|
||||
|
||||
album.setDescription = function(albumID) {
|
||||
|
||||
let oldDescription = album.json.description.replace(/'/g, ''')
|
||||
let oldDescription = album.json.description
|
||||
|
||||
const action = function(data) {
|
||||
|
||||
@ -365,12 +360,12 @@ album.setPublic = function(albumID, modal, e) {
|
||||
|
||||
if (modal===true) {
|
||||
|
||||
let text = '',
|
||||
action = {}
|
||||
let text = ''
|
||||
let action = {}
|
||||
|
||||
action.fn = () => {
|
||||
|
||||
// setPublic function without showing the modal
|
||||
// Call setPublic function without showing the modal
|
||||
album.setPublic(album.getID(), false, e)
|
||||
|
||||
}
|
||||
@ -393,11 +388,11 @@ album.setPublic = function(albumID, modal, e) {
|
||||
<form>
|
||||
<div class='choice'>
|
||||
<label>
|
||||
<input type='checkbox' name='visible'>
|
||||
<input type='checkbox' name='hidden'>
|
||||
<span class='checkbox'>${ build.iconic('check') }</span>
|
||||
<span class='label'>Visible</span>
|
||||
<span class='label'>Hidden</span>
|
||||
</label>
|
||||
<p>Listed to visitors of your Lychee.</p>
|
||||
<p>Only people with the direct link can view this album.</p>
|
||||
</div>
|
||||
<div class='choice'>
|
||||
<label>
|
||||
@ -413,7 +408,7 @@ album.setPublic = function(albumID, modal, e) {
|
||||
<span class='checkbox'>${ build.iconic('check') }</span>
|
||||
<span class='label'>Password protected</span>
|
||||
</label>
|
||||
<p>Only accessible with a valid password.</p>
|
||||
<p>Album only accessible with a valid password.</p>
|
||||
<input class='text' name='passwordtext' type='password' placeholder='password' value=''>
|
||||
</div>
|
||||
</form>
|
||||
@ -433,9 +428,8 @@ album.setPublic = function(albumID, modal, e) {
|
||||
}
|
||||
})
|
||||
|
||||
// Active visible by default (public = 0)
|
||||
if ((album.json.public==='1' && album.json.visible==='1') || (album.json.public==='0')) $('.basicModal .choice input[name="visible"]').click()
|
||||
if (album.json.downloadable==='1') $('.basicModal .choice input[name="downloadable"]').click()
|
||||
if (album.json.public==='1' && album.json.visible==='0') $('.basicModal .choice input[name="hidden"]').click()
|
||||
if (album.json.downloadable==='1') $('.basicModal .choice input[name="downloadable"]').click()
|
||||
|
||||
$('.basicModal .choice input[name="password"]').on('change', function() {
|
||||
|
||||
@ -455,8 +449,8 @@ album.setPublic = function(albumID, modal, e) {
|
||||
album.json.public = '1'
|
||||
|
||||
// Set visible
|
||||
if ($('.basicModal .choice input[name="visible"]:checked').length===1) album.json.visible = '1'
|
||||
else album.json.visible = '0'
|
||||
if ($('.basicModal .choice input[name="hidden"]:checked').length===1) album.json.visible = '0'
|
||||
else album.json.visible = '1'
|
||||
|
||||
// Set downloadable
|
||||
if ($('.basicModal .choice input[name="downloadable"]:checked').length===1) album.json.downloadable = '1'
|
||||
@ -484,12 +478,12 @@ album.setPublic = function(albumID, modal, e) {
|
||||
// Set data and refresh view
|
||||
if (visible.album()) {
|
||||
|
||||
album.json.visible = (album.json.public==='0') ? '0' : album.json.visible
|
||||
album.json.visible = (album.json.public==='0') ? '1' : album.json.visible
|
||||
album.json.downloadable = (album.json.public==='0') ? '0' : album.json.downloadable
|
||||
album.json.password = (album.json.public==='0') ? '0' : album.json.password
|
||||
|
||||
view.album.public()
|
||||
view.album.visible()
|
||||
view.album.hidden()
|
||||
view.album.downloadable()
|
||||
view.album.password()
|
||||
|
||||
@ -515,8 +509,8 @@ album.setPublic = function(albumID, modal, e) {
|
||||
|
||||
album.share = function(service) {
|
||||
|
||||
let link = '',
|
||||
url = location.href
|
||||
let link = ''
|
||||
let url = location.href
|
||||
|
||||
switch (service) {
|
||||
case 'twitter':
|
||||
@ -539,8 +533,8 @@ album.share = function(service) {
|
||||
|
||||
album.getArchive = function(albumID) {
|
||||
|
||||
let link,
|
||||
url = `${ api.path }?function=Album::getArchive&albumID=${ albumID }`
|
||||
let link = ''
|
||||
let url = `${ api.path }?function=Album::getArchive&albumID=${ albumID }`
|
||||
|
||||
if (location.href.indexOf('index.html')>0) link = location.href.replace(location.hash, '').replace('index.html', url)
|
||||
else link = location.href.replace(location.hash, '') + url
|
||||
@ -553,26 +547,26 @@ album.getArchive = function(albumID) {
|
||||
|
||||
album.merge = function(albumIDs) {
|
||||
|
||||
let title = '',
|
||||
sTitle = '',
|
||||
msg = ''
|
||||
let title = ''
|
||||
let sTitle = ''
|
||||
let msg = ''
|
||||
|
||||
if (!albumIDs) return false
|
||||
if (albumIDs instanceof Array===false) albumIDs = [albumIDs]
|
||||
if (albumIDs instanceof Array===false) albumIDs = [ albumIDs ]
|
||||
|
||||
// Get title of first album
|
||||
if (albums.json) title = albums.getByID(albumIDs[0]).title
|
||||
if (!title) title = ''
|
||||
|
||||
title = title.replace(/'/g, ''')
|
||||
// Fallback for first album without a title
|
||||
if (title==='') title = 'Untitled'
|
||||
|
||||
if (albumIDs.length===2) {
|
||||
|
||||
// Get title of second album
|
||||
if (albums.json) sTitle = albums.getByID(albumIDs[1]).title
|
||||
|
||||
if (!sTitle) sTitle = ''
|
||||
sTitle = sTitle.replace(/'/g, ''')
|
||||
// Fallback for second album without a title
|
||||
if (sTitle==='') sTitle = 'Untitled'
|
||||
|
||||
msg = lychee.html`<p>Are you sure you want to merge the album '$${ sTitle }' into the album '$${ title }'?</p>`
|
||||
|
||||
@ -596,7 +590,7 @@ album.merge = function(albumIDs) {
|
||||
lychee.error(null, params, data)
|
||||
} else {
|
||||
albums.refresh()
|
||||
albums.load()
|
||||
lychee.goto()
|
||||
}
|
||||
|
||||
})
|
||||
|
@ -17,7 +17,7 @@ albums.load = function() {
|
||||
|
||||
if (albums.json===null) {
|
||||
|
||||
api.post('Album::getAll', {}, function(data) {
|
||||
api.post('Albums::get', {}, function(data) {
|
||||
|
||||
let waitTime = 0
|
||||
|
||||
@ -134,7 +134,7 @@ albums.deleteByID = function(albumID) {
|
||||
if (!albums.json) return false
|
||||
if (!albums.json.albums) return false
|
||||
|
||||
var deleted = false
|
||||
let deleted = false
|
||||
|
||||
$.each(albums.json.albums, function(i) {
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
api = {
|
||||
|
||||
path : 'php/api.php',
|
||||
path : 'php/index.php',
|
||||
onError : null
|
||||
|
||||
}
|
||||
@ -14,11 +14,11 @@ api.post = function(fn, params, callback) {
|
||||
|
||||
loadingBar.show()
|
||||
|
||||
params = $.extend({function: fn}, params)
|
||||
params = $.extend({ function: fn }, params)
|
||||
|
||||
const success = (data) => {
|
||||
|
||||
setTimeout(() => loadingBar.hide(), 100)
|
||||
setTimeout(loadingBar.hide, 100)
|
||||
|
||||
// Catch errors
|
||||
if (typeof data==='string' && data.substring(0, 7)==='Error: ') {
|
||||
@ -26,18 +26,6 @@ api.post = function(fn, params, callback) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Convert 1 to true and an empty string to false
|
||||
if (data==='1') data = true
|
||||
else if (data==='') data = false
|
||||
|
||||
// Convert to JSON if string start with '{' and ends with '}'
|
||||
if (typeof data==='string' &&
|
||||
data.substring(0, 1)==='{' &&
|
||||
data.substring(data.length-1, data.length)==='}') data = $.parseJSON(data)
|
||||
|
||||
// Output response when debug mode is enabled
|
||||
if (lychee.debugMode) console.log(data)
|
||||
|
||||
callback(data)
|
||||
|
||||
}
|
||||
@ -52,7 +40,7 @@ api.post = function(fn, params, callback) {
|
||||
type: 'POST',
|
||||
url: api.path,
|
||||
data: params,
|
||||
dataType: 'text',
|
||||
dataType: 'json',
|
||||
success,
|
||||
error
|
||||
})
|
||||
|
@ -115,16 +115,16 @@ build.photo = function(data) {
|
||||
|
||||
build.imageview = function(data, visibleControls) {
|
||||
|
||||
let html = '',
|
||||
hasMedium = data.medium!==''
|
||||
let html = ''
|
||||
let hasMedium = data.medium!==''
|
||||
|
||||
if (hasMedium===false) {
|
||||
|
||||
html += lychee.html`<div id='image' class='$${ visibleControls===true ? '' : 'full' }'><div><img src='$${ data.url }' draggable='false'></div></div>`
|
||||
html += lychee.html`<img id='image' class='$${ visibleControls===true ? '' : 'full' }' src='$${ data.url }' draggable='false'>`
|
||||
|
||||
} else {
|
||||
|
||||
html += lychee.html`<div id='image' class='$${ visibleControls===true ? '' : 'full' }'><div><img src='$${ data.url }' srcset='$${ data.medium } 1920w, $${ data.url } $${ data.width }w' draggable='false'></div></div>`
|
||||
html += lychee.html`<img id='image' class='$${ visibleControls===true ? '' : 'full' }' src='$${ data.url }' srcset='$${ data.medium } 1920w, $${ data.url } $${ data.width }w' draggable='false'>`
|
||||
|
||||
}
|
||||
|
||||
@ -182,17 +182,12 @@ build.uploadModal = function(title, files) {
|
||||
|
||||
let file = files[i]
|
||||
|
||||
if (file.name.length>40) file.name = file.name.substr(0, 17) + '...' + file.name.substr(file.name.length-20, 20)
|
||||
if (file.name.length>40) file.name = file.name.substr(0, 17) + '...' + file.name.substr(file.name.length - 20, 20)
|
||||
|
||||
html += lychee.html`
|
||||
<div class='row'>
|
||||
<a class='name'>$${ file.name }</a>
|
||||
`
|
||||
|
||||
if (file.supported===true) html += `<a class='status'></a>`
|
||||
else html += `<a class='status error'>Not supported</a>`
|
||||
|
||||
html += `
|
||||
<a class='status'></a>
|
||||
<p class='notice'></p>
|
||||
</div>
|
||||
`
|
||||
|
@ -31,8 +31,8 @@ contextMenu.settings = function(e) {
|
||||
{ title: build.iconic('dropbox', 'ionicons') + 'Set Dropbox', fn: settings.setDropboxKey },
|
||||
{ },
|
||||
{ title: build.iconic('info') + 'About Lychee', fn: () => window.open(lychee.website) },
|
||||
{ title: build.iconic('wrench') + 'Diagnostics', fn: () => window.open('plugins/check/') },
|
||||
{ title: build.iconic('align-left') + 'Show Log', fn: () => window.open('plugins/displaylog/') },
|
||||
{ title: build.iconic('wrench') + 'Diagnostics', fn: () => window.open('plugins/Diagnostics/') },
|
||||
{ title: build.iconic('align-left') + 'Show Log', fn: () => window.open('plugins/Log/') },
|
||||
{ },
|
||||
{ title: build.iconic('account-logout') + 'Sign Out', fn: lychee.logout }
|
||||
]
|
||||
@ -53,9 +53,9 @@ contextMenu.album = function(albumID, e) {
|
||||
let showMerge = (albums.json && albums.json.albums && Object.keys(albums.json.albums).length>1)
|
||||
|
||||
let items = [
|
||||
{ title: build.iconic('pencil') + 'Rename', fn: () => album.setTitle([albumID]) },
|
||||
{ title: build.iconic('pencil') + 'Rename', fn: () => album.setTitle([ albumID ]) },
|
||||
{ title: build.iconic('collapse-left') + 'Merge', visible: showMerge, fn: () => { basicContext.close(); contextMenu.mergeAlbum(albumID, e) } },
|
||||
{ title: build.iconic('trash') + 'Delete', fn: () => album.delete([albumID]) }
|
||||
{ title: build.iconic('trash') + 'Delete', fn: () => album.delete([ albumID ]) }
|
||||
]
|
||||
|
||||
$('.album[data-id="' + albumID + '"]').addClass('active')
|
||||
@ -90,7 +90,7 @@ contextMenu.albumMulti = function(albumIDs, e) {
|
||||
|
||||
contextMenu.albumTitle = function(albumID, e) {
|
||||
|
||||
api.post('Album::getAll', {}, function(data) {
|
||||
api.post('Albums::get', {}, function(data) {
|
||||
|
||||
let items = []
|
||||
|
||||
@ -100,10 +100,14 @@ contextMenu.albumTitle = function(albumID, e) {
|
||||
$.each(data.albums, function() {
|
||||
|
||||
if (!this.thumbs[0]) this.thumbs[0] = 'src/images/no_cover.svg'
|
||||
if (this.title==='') this.title = 'Untitled'
|
||||
|
||||
let title = lychee.html`<img class='cover' width='16' height='16' src='$${ this.thumbs[0] }'><div class='title'>$${ this.title }</div>`
|
||||
let html = lychee.html`<img class='cover' width='16' height='16' src='$${ this.thumbs[0] }'><div class='title'>$${ this.title }</div>`
|
||||
|
||||
if (this.id!=albumID) items.push({ title, fn: () => lychee.goto(this.id) })
|
||||
if (this.id!=albumID) items.push({
|
||||
title: html,
|
||||
fn: () => lychee.goto(this.id)
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
@ -111,7 +115,7 @@ contextMenu.albumTitle = function(albumID, e) {
|
||||
|
||||
}
|
||||
|
||||
items.unshift({ title: build.iconic('pencil') + 'Rename', fn: () => album.setTitle([albumID]) })
|
||||
items.unshift({ title: build.iconic('pencil') + 'Rename', fn: () => album.setTitle([ albumID ]) })
|
||||
|
||||
basicContext.show(items, e.originalEvent, contextMenu.close)
|
||||
|
||||
@ -121,7 +125,7 @@ contextMenu.albumTitle = function(albumID, e) {
|
||||
|
||||
contextMenu.mergeAlbum = function(albumID, e) {
|
||||
|
||||
api.post('Album::getAll', {}, function(data) {
|
||||
api.post('Albums::get', {}, function(data) {
|
||||
|
||||
let items = []
|
||||
|
||||
@ -130,10 +134,14 @@ contextMenu.mergeAlbum = function(albumID, e) {
|
||||
$.each(data.albums, function() {
|
||||
|
||||
if (!this.thumbs[0]) this.thumbs[0] = 'src/images/no_cover.svg'
|
||||
if (this.title==='') this.title = 'Untitled'
|
||||
|
||||
let title = lychee.html`<img class='cover' width='16' height='16' src='$${ this.thumbs[0] }'><div class='title'>$${ this.title }</div>`
|
||||
let html = lychee.html`<img class='cover' width='16' height='16' src='$${ this.thumbs[0] }'><div class='title'>$${ this.title }</div>`
|
||||
|
||||
if (this.id!=albumID) items.push({ title, fn: () => album.merge([albumID, this.id]) })
|
||||
if (this.id!=albumID) items.push({
|
||||
title: html,
|
||||
fn: () => album.merge([ albumID, this.id ])
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
@ -154,13 +162,13 @@ contextMenu.photo = function(photoID, e) {
|
||||
// in order to keep the selection
|
||||
|
||||
let items = [
|
||||
{ title: build.iconic('star') + 'Star', fn: () => photo.setStar([photoID]) },
|
||||
{ title: build.iconic('tag') + 'Tags', fn: () => photo.editTags([photoID]) },
|
||||
{ title: build.iconic('star') + 'Star', fn: () => photo.setStar([ photoID ]) },
|
||||
{ title: build.iconic('tag') + 'Tags', fn: () => photo.editTags([ photoID ]) },
|
||||
{ },
|
||||
{ title: build.iconic('pencil') + 'Rename', fn: () => photo.setTitle([photoID]) },
|
||||
{ title: build.iconic('layers') + 'Duplicate', fn: () => photo.duplicate([photoID]) },
|
||||
{ title: build.iconic('folder') + 'Move', fn: () => { basicContext.close(); contextMenu.move([photoID], e) } },
|
||||
{ title: build.iconic('trash') + 'Delete', fn: () => photo.delete([photoID]) }
|
||||
{ title: build.iconic('pencil') + 'Rename', fn: () => photo.setTitle([ photoID ]) },
|
||||
{ title: build.iconic('layers') + 'Duplicate', fn: () => photo.duplicate([ photoID ]) },
|
||||
{ title: build.iconic('folder') + 'Move', fn: () => { basicContext.close(); contextMenu.move([ photoID ], e) } },
|
||||
{ title: build.iconic('trash') + 'Delete', fn: () => photo.delete([ photoID ]) }
|
||||
]
|
||||
|
||||
$('.photo[data-id="' + photoID + '"]').addClass('active')
|
||||
@ -194,7 +202,7 @@ contextMenu.photoMulti = function(photoIDs, e) {
|
||||
contextMenu.photoTitle = function(albumID, photoID, e) {
|
||||
|
||||
let items = [
|
||||
{ title: build.iconic('pencil') + 'Rename', fn: () => photo.setTitle([photoID]) }
|
||||
{ title: build.iconic('pencil') + 'Rename', fn: () => photo.setTitle([ photoID ]) }
|
||||
]
|
||||
|
||||
let data = album.json
|
||||
@ -206,9 +214,14 @@ contextMenu.photoTitle = function(albumID, photoID, e) {
|
||||
// Generate list of albums
|
||||
$.each(data.content, function(index) {
|
||||
|
||||
let title = lychee.html`<img class='cover' width='16' height='16' src='$${ this.thumbUrl }'><div class='title'>$${ this.title }</div>`
|
||||
if (this.title==='') this.title = 'Untitled'
|
||||
|
||||
if (this.id!=photoID) items.push({ title, fn: () => lychee.goto(albumID + '/' + this.id) })
|
||||
let html = lychee.html`<img class='cover' width='16' height='16' src='$${ this.thumbUrl }'><div class='title'>$${ this.title }</div>`
|
||||
|
||||
if (this.id!=photoID) items.push({
|
||||
title: html,
|
||||
fn: () => lychee.goto(albumID + '/' + this.id)
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
@ -236,9 +249,9 @@ contextMenu.photoMore = function(photoID, e) {
|
||||
|
||||
contextMenu.move = function(photoIDs, e) {
|
||||
|
||||
var items = []
|
||||
let items = []
|
||||
|
||||
api.post('Album::getAll', {}, function(data) {
|
||||
api.post('Albums::get', {}, function(data) {
|
||||
|
||||
if (data.num===0) {
|
||||
|
||||
@ -253,10 +266,14 @@ contextMenu.move = function(photoIDs, e) {
|
||||
$.each(data.albums, function() {
|
||||
|
||||
if (!this.thumbs[0]) this.thumbs[0] = 'src/images/no_cover.svg'
|
||||
if (this.title==='') this.title = 'Untitled'
|
||||
|
||||
let title = lychee.html`<img class='cover' width='16' height='16' src='$${ this.thumbs[0] }'><div class='title'>$${ this.title }</div>`
|
||||
let html = lychee.html`<img class='cover' width='16' height='16' src='$${ this.thumbs[0] }'><div class='title'>$${ this.title }</div>`
|
||||
|
||||
if (this.id!=album.getID()) items.push({ title, fn: () => photo.setAlbum(photoIDs, this.id) })
|
||||
if (this.id!=album.getID()) items.push({
|
||||
title: html,
|
||||
fn: () => photo.setAlbum(photoIDs, this.id)
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
@ -278,8 +295,8 @@ contextMenu.move = function(photoIDs, e) {
|
||||
|
||||
contextMenu.sharePhoto = function(photoID, e) {
|
||||
|
||||
let link = photo.getViewLink(photoID),
|
||||
iconClass = 'ionicons'
|
||||
let link = photo.getViewLink(photoID)
|
||||
let iconClass = 'ionicons'
|
||||
|
||||
let items = [
|
||||
{ title: `<input readonly id="link" value="${ link }">`, fn: () => {}, class: 'basicContext__item--noHover' },
|
||||
|
@ -46,17 +46,17 @@ header.bind = function() {
|
||||
header.dom('#button_info') .on(eventName, sidebar.toggle)
|
||||
header.dom('.button_add') .on(eventName, contextMenu.add)
|
||||
header.dom('#button_more') .on(eventName, function(e) { contextMenu.photoMore(photo.getID(), e) })
|
||||
header.dom('#button_move') .on(eventName, function(e) { contextMenu.move([photo.getID()], e) })
|
||||
header.dom('#button_move') .on(eventName, function(e) { contextMenu.move([ photo.getID() ], e) })
|
||||
header.dom('.header__hostedwith') .on(eventName, function() { window.open(lychee.website) })
|
||||
header.dom('#button_trash_album') .on(eventName, function() { album.delete([album.getID()]) })
|
||||
header.dom('#button_trash') .on(eventName, function() { photo.delete([photo.getID()]) })
|
||||
header.dom('#button_trash_album') .on(eventName, function() { album.delete([ album.getID() ]) })
|
||||
header.dom('#button_trash') .on(eventName, function() { photo.delete([ photo.getID() ]) })
|
||||
header.dom('#button_archive') .on(eventName, function() { album.getArchive(album.getID()) })
|
||||
header.dom('#button_star') .on(eventName, function() { photo.setStar([photo.getID()]) })
|
||||
header.dom('#button_back_home') .on(eventName, function() { lychee.goto('') })
|
||||
header.dom('#button_star') .on(eventName, function() { photo.setStar([ photo.getID() ]) })
|
||||
header.dom('#button_back_home') .on(eventName, function() { lychee.goto() })
|
||||
header.dom('#button_back') .on(eventName, function() { lychee.goto(album.getID()) })
|
||||
|
||||
header.dom('.header__search').on('keyup click', function() { search.find($(this).val()) })
|
||||
header.dom('.header__clear').on(eventName, function () {
|
||||
header.dom('.header__clear').on(eventName, function() {
|
||||
header.dom('.header__search').focus()
|
||||
search.reset()
|
||||
})
|
||||
@ -99,8 +99,8 @@ header.hide = function(e, delay = 500) {
|
||||
|
||||
header.setTitle = function(title = 'Untitled') {
|
||||
|
||||
let $title = header.dom('.header__title'),
|
||||
html = lychee.html`$${ title }${ build.iconic('caret-bottom') }`
|
||||
let $title = header.dom('.header__title')
|
||||
let html = lychee.html`$${ title }${ build.iconic('caret-bottom') }`
|
||||
|
||||
$title.html(html)
|
||||
|
||||
|
@ -24,38 +24,38 @@ $(document).ready(function() {
|
||||
|
||||
// Keyboard
|
||||
Mousetrap
|
||||
.bind('left', function() {
|
||||
.bind([ 'left' ], function() {
|
||||
if (visible.photo()) { $('#imageview a#previous').click(); return false }
|
||||
})
|
||||
.bind('right', function() {
|
||||
.bind([ 'right' ], function() {
|
||||
if (visible.photo()) { $('#imageview a#next').click(); return false }
|
||||
})
|
||||
.bind('u', function() {
|
||||
.bind([ 'u' ], function() {
|
||||
if (!visible.photo()) { $('#upload_files').click(); return false }
|
||||
})
|
||||
.bind(['s', 'f'], function() {
|
||||
.bind([ 's', 'f' ], function() {
|
||||
if (visible.photo()) { header.dom('#button_star').click(); return false }
|
||||
else if (visible.albums()) { header.dom('.header__search').focus(); return false }
|
||||
})
|
||||
.bind('r', function() {
|
||||
.bind([ 'r' ], function() {
|
||||
if (visible.album()) { album.setTitle(album.getID()); return false }
|
||||
else if (visible.photo()) { photo.setTitle([photo.getID()]); return false }
|
||||
})
|
||||
.bind('d', function() {
|
||||
.bind([ 'd' ], function() {
|
||||
if (visible.photo()) { photo.setDescription(photo.getID()); return false }
|
||||
else if (visible.album()) { album.setDescription(album.getID()); return false }
|
||||
})
|
||||
.bind('t', function() {
|
||||
.bind([ 't' ], function() {
|
||||
if (visible.photo()) { photo.editTags([photo.getID()]); return false }
|
||||
})
|
||||
.bind('i', function() {
|
||||
.bind([ 'i' ], function() {
|
||||
if (!visible.multiselect()) { sidebar.toggle(); return false }
|
||||
})
|
||||
.bind(['command+backspace', 'ctrl+backspace'], function() {
|
||||
.bind([ 'command+backspace', 'ctrl+backspace' ], function() {
|
||||
if (visible.photo() && basicModal.visible()===false) { photo.delete([photo.getID()]); return false }
|
||||
else if (visible.album() && basicModal.visible()===false) { album.delete([album.getID()]); return false }
|
||||
})
|
||||
.bind(['command+a', 'ctrl+a'], function() {
|
||||
.bind([ 'command+a', 'ctrl+a' ], function() {
|
||||
if (visible.album() && basicModal.visible()===false) { multiselect.selectAll(); return false }
|
||||
else if (visible.albums() && basicModal.visible()===false) { multiselect.selectAll(); return false }
|
||||
})
|
||||
@ -64,11 +64,11 @@ $(document).ready(function() {
|
||||
if (basicModal.visible()===true) basicModal.action()
|
||||
})
|
||||
|
||||
Mousetrap.bindGlobal(['esc', 'command+up'], function() {
|
||||
Mousetrap.bindGlobal([ 'esc', 'command+up' ], function() {
|
||||
if (basicModal.visible()===true) basicModal.cancel()
|
||||
else if (visible.contextMenu()) contextMenu.close()
|
||||
else if (visible.photo()) lychee.goto(album.getID())
|
||||
else if (visible.album()) lychee.goto('')
|
||||
else if (visible.album()) lychee.goto()
|
||||
else if (visible.albums() && header.dom('.header__search').val().length!==0) search.reset()
|
||||
return false
|
||||
})
|
||||
|
@ -29,7 +29,7 @@ loadingBar.show = function(status, errorText) {
|
||||
if (!errorText) errorText = 'Whoops, it looks like something went wrong. Please reload the site and try again!'
|
||||
|
||||
// Move header down
|
||||
if (visible.header()) header.dom().addClass('header__error')
|
||||
if (visible.header()) header.dom().addClass('header--error')
|
||||
|
||||
// Modify loading
|
||||
loadingBar.dom()
|
||||
@ -56,7 +56,7 @@ loadingBar.show = function(status, errorText) {
|
||||
loadingBar._timeout = setTimeout(() => {
|
||||
|
||||
// Move header down
|
||||
if (visible.header()) header.dom().addClass('header__loading')
|
||||
if (visible.header()) header.dom().addClass('header--loading')
|
||||
|
||||
// Modify loading
|
||||
loadingBar.dom()
|
||||
@ -81,7 +81,7 @@ loadingBar.hide = function(force) {
|
||||
loadingBar.status = null
|
||||
|
||||
// Move header up
|
||||
header.dom().removeClass('header__error header__loading')
|
||||
header.dom().removeClass('header--error header--loading')
|
||||
|
||||
// Set timeout
|
||||
clearTimeout(loadingBar._timeout)
|
||||
|
@ -6,16 +6,15 @@
|
||||
lychee = {
|
||||
|
||||
title : document.title,
|
||||
version : '3.0.9',
|
||||
version_code : '030009',
|
||||
version : '3.1.0',
|
||||
versionCode : '030100',
|
||||
|
||||
update_path : '//update.electerious.com/index.json',
|
||||
updatePath : '//update.electerious.com/index.json',
|
||||
updateURL : 'https://github.com/electerious/Lychee',
|
||||
website : 'http://lychee.electerious.com',
|
||||
|
||||
publicMode : false,
|
||||
viewMode : false,
|
||||
debugMode : false,
|
||||
|
||||
checkForUpdates : '1',
|
||||
sortingPhotos : '',
|
||||
@ -32,11 +31,7 @@ lychee = {
|
||||
|
||||
lychee.init = function() {
|
||||
|
||||
let params = {
|
||||
version: lychee.version_code
|
||||
}
|
||||
|
||||
api.post('Session::init', params, function(data) {
|
||||
api.post('Session::init', {}, function(data) {
|
||||
|
||||
// Check status
|
||||
// 0 = No configuration
|
||||
@ -88,8 +83,8 @@ lychee.init = function() {
|
||||
|
||||
lychee.login = function(data) {
|
||||
|
||||
let user = data.username,
|
||||
password = data.password
|
||||
let user = data.username
|
||||
let password = data.password
|
||||
|
||||
let params = {
|
||||
user,
|
||||
@ -100,10 +95,6 @@ lychee.login = function(data) {
|
||||
|
||||
if (data===true) {
|
||||
|
||||
// Use 'try' to catch a thrown error when Safari is in private mode
|
||||
try { localStorage.setItem('lychee_username', user) }
|
||||
catch (err) {}
|
||||
|
||||
window.location.reload()
|
||||
|
||||
} else {
|
||||
@ -121,8 +112,8 @@ lychee.loginDialog = function() {
|
||||
|
||||
let msg = lychee.html`
|
||||
<p class='signIn'>
|
||||
<input class='text' name='username' autocomplete='username' type='text' value='' placeholder='username' autocapitalize='off' autocorrect='off'>
|
||||
<input class='text' name='password' autocomplete='current-password' type='password' value='' placeholder='password'>
|
||||
<input class='text' name='username' autocomplete='username' type='text' placeholder='username' autocapitalize='off' autocorrect='off'>
|
||||
<input class='text' name='password' autocomplete='current-password' type='password' placeholder='password'>
|
||||
</p>
|
||||
<p class='version'>Lychee $${ lychee.version }<span> – <a target='_blank' href='$${ lychee.updateURL }'>Update available!</a><span></p>
|
||||
`
|
||||
@ -141,14 +132,6 @@ lychee.loginDialog = function() {
|
||||
}
|
||||
})
|
||||
|
||||
if (localStorage) {
|
||||
let localUsername = localStorage.getItem('lychee_username')
|
||||
if (localUsername!=null && localUsername.length>0) {
|
||||
$('.basicModal input[name="username"]').val(localUsername)
|
||||
$('.basicModal input[name="password"]').focus()
|
||||
}
|
||||
}
|
||||
|
||||
if (lychee.checkForUpdates==='1') lychee.getUpdate()
|
||||
|
||||
}
|
||||
@ -161,10 +144,9 @@ lychee.logout = function() {
|
||||
|
||||
}
|
||||
|
||||
lychee.goto = function(url) {
|
||||
lychee.goto = function(url = '') {
|
||||
|
||||
if (url===undefined) url = '#'
|
||||
else url = '#' + url
|
||||
url = '#' + url
|
||||
|
||||
history.pushState(null, null, url)
|
||||
lychee.load()
|
||||
@ -173,9 +155,9 @@ lychee.goto = function(url) {
|
||||
|
||||
lychee.load = function() {
|
||||
|
||||
let albumID = '',
|
||||
photoID = '',
|
||||
hash = document.location.hash.replace('#', '').split('/')
|
||||
let albumID = ''
|
||||
let photoID = ''
|
||||
let hash = document.location.hash.replace('#', '').split('/')
|
||||
|
||||
$('.no_content').remove()
|
||||
contextMenu.close()
|
||||
@ -223,6 +205,7 @@ lychee.load = function() {
|
||||
|
||||
// Show Albums
|
||||
if (visible.photo()) view.photo.hide()
|
||||
lychee.content.show()
|
||||
albums.load()
|
||||
|
||||
}
|
||||
@ -231,9 +214,13 @@ lychee.load = function() {
|
||||
|
||||
lychee.getUpdate = function() {
|
||||
|
||||
const success = function(data) {
|
||||
if (data.lychee.version>parseInt(lychee.versionCode)) $('.version span').show()
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
url : lychee.update_path,
|
||||
success : function(data) { if (data.lychee.version>parseInt(lychee.version_code)) $('.version span').show() },
|
||||
url : lychee.updatePath,
|
||||
success : success
|
||||
})
|
||||
|
||||
}
|
||||
@ -260,14 +247,14 @@ lychee.setMode = function(mode) {
|
||||
.off('drop')
|
||||
|
||||
Mousetrap
|
||||
.unbind('u')
|
||||
.unbind('s')
|
||||
.unbind('f')
|
||||
.unbind('r')
|
||||
.unbind('d')
|
||||
.unbind('t')
|
||||
.unbind(['command+backspace', 'ctrl+backspace'])
|
||||
.unbind(['command+a', 'ctrl+a'])
|
||||
.unbind([ 'u' ])
|
||||
.unbind([ 's' ])
|
||||
.unbind([ 'f' ])
|
||||
.unbind([ 'r' ])
|
||||
.unbind([ 'd' ])
|
||||
.unbind([ 't' ])
|
||||
.unbind([ 'command+backspace', 'ctrl+backspace' ])
|
||||
.unbind([ 'command+a', 'ctrl+a' ])
|
||||
|
||||
if (mode==='public') {
|
||||
|
||||
@ -275,7 +262,8 @@ lychee.setMode = function(mode) {
|
||||
|
||||
} else if (mode==='view') {
|
||||
|
||||
Mousetrap.unbind(['esc', 'command+up'])
|
||||
Mousetrap.unbind([ 'esc', 'command+up' ])
|
||||
|
||||
$('#button_back, a#next, a#previous').remove()
|
||||
$('.no_content').remove()
|
||||
|
||||
@ -289,8 +277,8 @@ lychee.setMode = function(mode) {
|
||||
lychee.animate = function(obj, animation) {
|
||||
|
||||
let animations = [
|
||||
['fadeIn', 'fadeOut'],
|
||||
['contentZoomIn', 'contentZoomOut']
|
||||
[ 'fadeIn', 'fadeOut' ],
|
||||
[ 'contentZoomIn', 'contentZoomOut' ]
|
||||
]
|
||||
|
||||
if (!obj.jQuery) obj = $(obj)
|
||||
@ -310,8 +298,8 @@ lychee.animate = function(obj, animation) {
|
||||
|
||||
lychee.retinize = function(path = '') {
|
||||
|
||||
let extention = path.split('.').pop(),
|
||||
isPhoto = extention!=='svg'
|
||||
let extention = path.split('.').pop()
|
||||
let isPhoto = extention!=='svg'
|
||||
|
||||
if (isPhoto===true) {
|
||||
|
||||
@ -329,12 +317,12 @@ lychee.retinize = function(path = '') {
|
||||
|
||||
lychee.loadDropbox = function(callback) {
|
||||
|
||||
if (!lychee.dropbox && lychee.dropboxKey) {
|
||||
if (lychee.dropbox===false && lychee.dropboxKey!=null && lychee.dropboxKey!=='') {
|
||||
|
||||
loadingBar.show()
|
||||
|
||||
let g = document.createElement('script'),
|
||||
s = document.getElementsByTagName('script')[0]
|
||||
let g = document.createElement('script')
|
||||
let s = document.getElementsByTagName('script')[0]
|
||||
|
||||
g.src = 'https://www.dropbox.com/static/api/1/dropins.js'
|
||||
g.id = 'dropboxjs'
|
||||
@ -350,7 +338,7 @@ lychee.loadDropbox = function(callback) {
|
||||
}
|
||||
s.parentNode.insertBefore(g, s)
|
||||
|
||||
} else if (lychee.dropbox&&lychee.dropboxKey) {
|
||||
} else if (lychee.dropbox===true && lychee.dropboxKey!=null && lychee.dropboxKey!=='') {
|
||||
|
||||
callback()
|
||||
|
||||
@ -364,8 +352,8 @@ lychee.loadDropbox = function(callback) {
|
||||
|
||||
lychee.getEventName = function() {
|
||||
|
||||
let touchendSupport = (/Android|iPhone|iPad|iPod/i).test(navigator.userAgent || navigator.vendor || window.opera) && ('ontouchend' in document.documentElement),
|
||||
eventName = (touchendSupport===true ? 'touchend' : 'click')
|
||||
let touchendSupport = (/Android|iPhone|iPad|iPod/i).test(navigator.userAgent || navigator.vendor || window.opera) && ('ontouchend' in document.documentElement)
|
||||
let eventName = (touchendSupport===true ? 'touchend' : 'click')
|
||||
|
||||
return eventName
|
||||
|
||||
@ -392,8 +380,8 @@ lychee.html = function(literalSections, ...substs) {
|
||||
|
||||
// Use raw literal sections: we don’t want
|
||||
// backslashes (\n etc.) to be interpreted
|
||||
let raw = literalSections.raw,
|
||||
result = ''
|
||||
let raw = literalSections.raw
|
||||
let result = ''
|
||||
|
||||
substs.forEach((subst, i) => {
|
||||
|
||||
@ -416,7 +404,7 @@ lychee.html = function(literalSections, ...substs) {
|
||||
// Take care of last literal section
|
||||
// (Never fails, because an empty template string
|
||||
// produces one literal section, an empty string)
|
||||
result += raw[raw.length-1]
|
||||
result += raw[raw.length - 1]
|
||||
|
||||
return result
|
||||
|
||||
|
@ -89,8 +89,8 @@ multiselect.resize = function(e) {
|
||||
multiselect.position.bottom === null ||
|
||||
multiselect.position.left === null) return false
|
||||
|
||||
let newSize = {},
|
||||
documentSize = {}
|
||||
let newSize = {}
|
||||
let documentSize = {}
|
||||
|
||||
// Get the position of the mouse
|
||||
let mousePos = {
|
||||
@ -114,7 +114,7 @@ multiselect.resize = function(e) {
|
||||
|
||||
// Do not leave the screen
|
||||
newSize.height = mousePos.y - multiselect.position.top
|
||||
if ((multiselect.position.top+newSize.height)>=documentSize.height) {
|
||||
if ((multiselect.position.top + newSize.height)>=documentSize.height) {
|
||||
newSize.height -= (multiselect.position.top + newSize.height) - documentSize.height + 2
|
||||
}
|
||||
|
||||
@ -136,7 +136,7 @@ multiselect.resize = function(e) {
|
||||
|
||||
// Do not leave the screen
|
||||
newSize.width = mousePos.x - multiselect.position.left
|
||||
if ((multiselect.position.left+newSize.width)>=documentSize.width) {
|
||||
if ((multiselect.position.left + newSize.width)>=documentSize.width) {
|
||||
newSize.width -= (multiselect.position.left + newSize.width) - documentSize.width + 2
|
||||
}
|
||||
|
||||
@ -167,8 +167,8 @@ multiselect.getSize = function() {
|
||||
|
||||
if (!visible.multiselect()) return false
|
||||
|
||||
let $elem = $('#multiselect'),
|
||||
offset = $elem.offset()
|
||||
let $elem = $('#multiselect')
|
||||
let offset = $elem.offset()
|
||||
|
||||
return {
|
||||
top : offset.top,
|
||||
@ -181,9 +181,9 @@ multiselect.getSize = function() {
|
||||
|
||||
multiselect.getSelection = function(e) {
|
||||
|
||||
let tolerance = 150,
|
||||
ids = [],
|
||||
size = multiselect.getSize()
|
||||
let tolerance = 150
|
||||
let ids = []
|
||||
let size = multiselect.getSize()
|
||||
|
||||
if (visible.contextMenu()) return false
|
||||
if (!visible.multiselect()) return false
|
||||
@ -192,19 +192,19 @@ multiselect.getSelection = function(e) {
|
||||
|
||||
let offset = $(this).offset()
|
||||
|
||||
if (offset.top>=(size.top-tolerance) &&
|
||||
offset.left>=(size.left-tolerance) &&
|
||||
(offset.top+206)<=(size.top+size.height+tolerance) &&
|
||||
(offset.left+206)<=(size.left+size.width+tolerance)) {
|
||||
if (offset.top>=(size.top - tolerance) &&
|
||||
offset.left>=(size.left - tolerance) &&
|
||||
(offset.top + 206)<=(size.top + size.height + tolerance) &&
|
||||
(offset.left + 206)<=(size.left + size.width + tolerance)) {
|
||||
|
||||
let id = $(this).data('id')
|
||||
let id = $(this).data('id')
|
||||
|
||||
if (id!=='0' && id!==0 && id!=='f' && id!=='s' && id!=='r' && id!=null) {
|
||||
if (id!=='0' && id!==0 && id!=='f' && id!=='s' && id!=='r' && id!=null) {
|
||||
|
||||
ids.push(id)
|
||||
$(this).addClass('active')
|
||||
ids.push(id)
|
||||
$(this).addClass('active')
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,7 @@ password = {
|
||||
|
||||
}
|
||||
|
||||
password.get = function(albumID, callback, passwd) {
|
||||
password.get = function(albumID, callback) {
|
||||
|
||||
if (lychee.publicMode===false) callback()
|
||||
else if (album.json && album.json.password==='0') callback()
|
||||
@ -17,17 +17,25 @@ password.get = function(albumID, callback, passwd) {
|
||||
else if (!albums.json && !album.json) {
|
||||
|
||||
// Continue without password
|
||||
|
||||
album.json = { password: true }
|
||||
callback('')
|
||||
|
||||
} else if (passwd==null) {
|
||||
|
||||
// Request password
|
||||
password.getDialog(albumID, callback)
|
||||
|
||||
} else {
|
||||
|
||||
// Check password
|
||||
// Request password
|
||||
|
||||
password.getDialog(albumID, callback)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
password.getDialog = function(albumID, callback) {
|
||||
|
||||
const action = (data) => {
|
||||
|
||||
let passwd = data.password
|
||||
|
||||
let params = {
|
||||
albumID,
|
||||
@ -48,16 +56,10 @@ password.get = function(albumID, callback, passwd) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
password.getDialog = function(albumID, callback) {
|
||||
|
||||
const action = (data) => password.get(albumID, callback, data.password)
|
||||
|
||||
const cancel = () => {
|
||||
|
||||
basicModal.close()
|
||||
if (visible.albums()===false) lychee.goto()
|
||||
if (!visible.albums()) lychee.goto()
|
||||
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,21 @@ photo.getID = function() {
|
||||
|
||||
photo.load = function(photoID, albumID) {
|
||||
|
||||
const checkContent = function() {
|
||||
if (album.json!=null) photo.load(photoID, albumID)
|
||||
else setTimeout(checkContent, 100)
|
||||
}
|
||||
|
||||
const checkPasswd = function() {
|
||||
if (password.value!=='') photo.load(photoID, albumID)
|
||||
else setTimeout(checkPasswd, 200)
|
||||
}
|
||||
|
||||
if (album.json==null) {
|
||||
checkContent()
|
||||
return false
|
||||
}
|
||||
|
||||
let params = {
|
||||
photoID,
|
||||
albumID,
|
||||
@ -32,14 +47,9 @@ photo.load = function(photoID, albumID) {
|
||||
|
||||
api.post('Photo::get', params, function(data) {
|
||||
|
||||
const checkPasswd = function() {
|
||||
if (password.value!=='') photo.load(photoID, albumID)
|
||||
else setTimeout(checkPasswd, 250)
|
||||
}
|
||||
|
||||
if (data==='Warning: Photo private!') {
|
||||
lychee.content.show()
|
||||
lychee.goto('')
|
||||
lychee.goto()
|
||||
return false
|
||||
}
|
||||
|
||||
@ -71,8 +81,8 @@ photo.preloadNext = function(photoID) {
|
||||
album.json.content[photoID] &&
|
||||
album.json.content[photoID].nextPhoto!='') {
|
||||
|
||||
let nextPhoto = album.json.content[photoID].nextPhoto,
|
||||
url = album.json.content[nextPhoto].url
|
||||
let nextPhoto = album.json.content[photoID].nextPhoto
|
||||
let url = album.json.content[nextPhoto].url
|
||||
|
||||
$('head [data-prefetch]').remove()
|
||||
$('head').append(`<link data-prefetch rel="prefetch" href="${ url }">`)
|
||||
@ -152,7 +162,7 @@ photo.next = function(animate) {
|
||||
photo.duplicate = function(photoIDs) {
|
||||
|
||||
if (!photoIDs) return false
|
||||
if (photoIDs instanceof Array===false) photoIDs = [photoIDs]
|
||||
if (photoIDs instanceof Array===false) photoIDs = [ photoIDs ]
|
||||
|
||||
albums.refresh()
|
||||
|
||||
@ -171,13 +181,13 @@ photo.duplicate = function(photoIDs) {
|
||||
|
||||
photo.delete = function(photoIDs) {
|
||||
|
||||
let action = {},
|
||||
cancel = {},
|
||||
msg = '',
|
||||
photoTitle = ''
|
||||
let action = {}
|
||||
let cancel = {}
|
||||
let msg = ''
|
||||
let photoTitle = ''
|
||||
|
||||
if (!photoIDs) return false
|
||||
if (photoIDs instanceof Array===false) photoIDs = [photoIDs]
|
||||
if (photoIDs instanceof Array===false) photoIDs = [ photoIDs ]
|
||||
|
||||
if (photoIDs.length===1) {
|
||||
|
||||
@ -192,8 +202,8 @@ photo.delete = function(photoIDs) {
|
||||
|
||||
action.fn = function() {
|
||||
|
||||
let nextPhoto,
|
||||
previousPhoto
|
||||
let nextPhoto = null
|
||||
let previousPhoto = null
|
||||
|
||||
basicModal.close()
|
||||
|
||||
@ -219,8 +229,8 @@ photo.delete = function(photoIDs) {
|
||||
|
||||
// Go to next photo if there is a next photo and
|
||||
// next photo is not the current one. Show album otherwise.
|
||||
if (visible.photo() && nextPhoto!=='' && nextPhoto!==photo.getID()) lychee.goto(album.getID() + '/' + nextPhoto)
|
||||
else if (!visible.albums()) lychee.goto(album.getID())
|
||||
if (visible.photo() && nextPhoto!=null && nextPhoto!==photo.getID()) lychee.goto(album.getID() + '/' + nextPhoto)
|
||||
else if (!visible.albums()) lychee.goto(album.getID())
|
||||
|
||||
let params = {
|
||||
photoIDs: photoIDs.join()
|
||||
@ -269,11 +279,11 @@ photo.delete = function(photoIDs) {
|
||||
|
||||
photo.setTitle = function(photoIDs) {
|
||||
|
||||
let oldTitle = '',
|
||||
msg = ''
|
||||
let oldTitle = ''
|
||||
let msg = ''
|
||||
|
||||
if (!photoIDs) return false
|
||||
if (photoIDs instanceof Array===false) photoIDs = [photoIDs]
|
||||
if (photoIDs instanceof Array===false) photoIDs = [ photoIDs ]
|
||||
|
||||
if (photoIDs.length===1) {
|
||||
|
||||
@ -300,8 +310,8 @@ photo.setTitle = function(photoIDs) {
|
||||
})
|
||||
|
||||
let params = {
|
||||
photoIDs: photoIDs.join(),
|
||||
title: newTitle
|
||||
photoIDs : photoIDs.join(),
|
||||
title : newTitle
|
||||
}
|
||||
|
||||
api.post('Photo::setTitle', params, function(data) {
|
||||
@ -335,13 +345,11 @@ photo.setTitle = function(photoIDs) {
|
||||
|
||||
photo.setAlbum = function(photoIDs, albumID) {
|
||||
|
||||
let nextPhoto,
|
||||
previousPhoto
|
||||
let nextPhoto = null
|
||||
let previousPhoto = null
|
||||
|
||||
if (!photoIDs) return false
|
||||
if (photoIDs instanceof Array===false) photoIDs = [photoIDs]
|
||||
|
||||
if (visible.photo) lychee.goto(album.getID())
|
||||
if (photoIDs instanceof Array===false) photoIDs = [ photoIDs ]
|
||||
|
||||
photoIDs.forEach(function(id, index, array) {
|
||||
|
||||
@ -363,6 +371,11 @@ photo.setAlbum = function(photoIDs, albumID) {
|
||||
|
||||
albums.refresh()
|
||||
|
||||
// Go to next photo if there is a next photo and
|
||||
// next photo is not the current one. Show album otherwise.
|
||||
if (visible.photo() && nextPhoto!=null && nextPhoto!==photo.getID()) lychee.goto(album.getID() + '/' + nextPhoto)
|
||||
else if (!visible.albums()) lychee.goto(album.getID())
|
||||
|
||||
let params = {
|
||||
photoIDs: photoIDs.join(),
|
||||
albumID
|
||||
@ -416,7 +429,7 @@ photo.setPublic = function(photoID, e) {
|
||||
}
|
||||
|
||||
basicModal.show({
|
||||
body: "<p>This photo is located in a public album. To make this photo private or public, edit the visibility of the associated album.</p>",
|
||||
body: '<p>This photo is located in a public album. To make this photo private or public, edit the visibility of the associated album.</p>',
|
||||
buttons: {
|
||||
action: {
|
||||
title: 'Show Album',
|
||||
@ -500,11 +513,11 @@ photo.setDescription = function(photoID) {
|
||||
|
||||
photo.editTags = function(photoIDs) {
|
||||
|
||||
let oldTags = '',
|
||||
msg = ''
|
||||
let oldTags = ''
|
||||
let msg = ''
|
||||
|
||||
if (!photoIDs) return false
|
||||
if (photoIDs instanceof Array===false) photoIDs = [photoIDs]
|
||||
if (photoIDs instanceof Array===false) photoIDs = [ photoIDs ]
|
||||
|
||||
// Get tags
|
||||
if (visible.photo()) oldTags = photo.json.tags
|
||||
@ -553,7 +566,7 @@ photo.editTags = function(photoIDs) {
|
||||
photo.setTags = function(photoIDs, tags) {
|
||||
|
||||
if (!photoIDs) return false
|
||||
if (photoIDs instanceof Array===false) photoIDs = [photoIDs]
|
||||
if (photoIDs instanceof Array===false) photoIDs = [ photoIDs ]
|
||||
|
||||
// Parse tags
|
||||
tags = tags.replace(/(\ ,\ )|(\ ,)|(,\ )|(,{1,}\ {0,})|(,$|^,)/g, ',')
|
||||
@ -591,14 +604,14 @@ photo.deleteTag = function(photoID, index) {
|
||||
|
||||
// Save
|
||||
photo.json.tags = tags.toString()
|
||||
photo.setTags([photoID], photo.json.tags)
|
||||
photo.setTags([ photoID ], photo.json.tags)
|
||||
|
||||
}
|
||||
|
||||
photo.share = function(photoID, service) {
|
||||
|
||||
let link = '',
|
||||
url = photo.getViewLink(photoID)
|
||||
let link = ''
|
||||
let url = photo.getViewLink(photoID)
|
||||
|
||||
switch (service) {
|
||||
case 'twitter':
|
||||
@ -621,14 +634,14 @@ photo.share = function(photoID, service) {
|
||||
break
|
||||
}
|
||||
|
||||
if (link.length!=='') location.href = link
|
||||
if (link!=='') location.href = link
|
||||
|
||||
}
|
||||
|
||||
photo.getArchive = function(photoID) {
|
||||
|
||||
let link,
|
||||
url = `${ api.path }?function=Photo::getArchive&photoID=${ photoID }`
|
||||
let link
|
||||
let url = `${ api.path }?function=Photo::getArchive&photoID=${ photoID }`
|
||||
|
||||
if (location.href.indexOf('index.html')>0) link = location.href.replace(location.hash, '').replace('index.html', url)
|
||||
else link = location.href.replace(location.hash, '') + url
|
||||
|
@ -19,9 +19,9 @@ search.find = function(term) {
|
||||
|
||||
api.post('search', { term }, function(data) {
|
||||
|
||||
let html = '',
|
||||
albumsData = '',
|
||||
photosData = ''
|
||||
let html = ''
|
||||
let albumsData = ''
|
||||
let photosData = ''
|
||||
|
||||
// Build albums
|
||||
if (data && data.albums) {
|
||||
@ -47,7 +47,7 @@ search.find = function(term) {
|
||||
if (albumsData==='' && photosData==='') html = 'error'
|
||||
else if (albumsData==='') html = build.divider('Photos') + photosData
|
||||
else if (photosData==='') html = build.divider('Albums') + albumsData
|
||||
else html = build.divider('Photos') + photosData + build.divider('Albums') + albumsData
|
||||
else html = build.divider('Albums') + albumsData + build.divider('Photos') + photosData
|
||||
|
||||
// Only refresh view when search results are different
|
||||
if (search.hash!==data.hash) {
|
||||
@ -94,7 +94,7 @@ search.reset = function() {
|
||||
search.hash = null
|
||||
|
||||
lychee.animate('.divider', 'fadeOut')
|
||||
albums.load()
|
||||
lychee.goto()
|
||||
|
||||
}
|
||||
|
||||
|
@ -9,11 +9,11 @@ settings.createConfig = function() {
|
||||
|
||||
const action = function(data) {
|
||||
|
||||
let dbName = data.dbName || '',
|
||||
dbUser = data.dbUser || '',
|
||||
dbPassword = data.dbPassword || '',
|
||||
dbHost = data.dbHost || '',
|
||||
dbTablePrefix = data.dbTablePrefix || ''
|
||||
let dbName = data.dbName || ''
|
||||
let dbUser = data.dbUser || ''
|
||||
let dbPassword = data.dbPassword || ''
|
||||
let dbHost = data.dbHost || ''
|
||||
let dbTablePrefix = data.dbTablePrefix || ''
|
||||
|
||||
if (dbUser.length<1) {
|
||||
basicModal.error('dbUser')
|
||||
@ -31,12 +31,12 @@ settings.createConfig = function() {
|
||||
dbTablePrefix
|
||||
}
|
||||
|
||||
api.post('Database::createConfig', params, function(data) {
|
||||
api.post('Config::create', params, function(data) {
|
||||
|
||||
if (data!==true) {
|
||||
|
||||
// Connection failed
|
||||
if (data.indexOf('Warning: Connection failed!')!==-1) {
|
||||
if (data==='Warning: Connection failed!') {
|
||||
|
||||
basicModal.show({
|
||||
body: '<p>Unable to connect to host database because access was denied. Double-check your host, username and password and ensure that access from your current location is permitted.</p>',
|
||||
@ -53,7 +53,7 @@ settings.createConfig = function() {
|
||||
}
|
||||
|
||||
// Creation failed
|
||||
if (data.indexOf('Warning: Creation failed!')!==-1) {
|
||||
if (data==='Warning: Creation failed!') {
|
||||
|
||||
basicModal.show({
|
||||
body: '<p>Unable to create the database. Double-check your host, username and password and ensure that the specified user has the rights to modify and add content to the database.</p>',
|
||||
@ -70,7 +70,7 @@ settings.createConfig = function() {
|
||||
}
|
||||
|
||||
// Could not create file
|
||||
if (data.indexOf('Warning: Could not create file!')!==-1) {
|
||||
if (data==='Warning: Could not create file!') {
|
||||
|
||||
basicModal.show({
|
||||
body: "<p>Unable to save this configuration. Permission denied in <b>'data/'</b>. Please set the read, write and execute rights for others in <b>'data/'</b> and <b>'uploads/'</b>. Take a look at the readme for more information.</p>",
|
||||
@ -140,8 +140,8 @@ settings.createLogin = function() {
|
||||
|
||||
const action = function(data) {
|
||||
|
||||
let username = data.username,
|
||||
password = data.password
|
||||
let username = data.username
|
||||
let password = data.password
|
||||
|
||||
if (username.length<1) {
|
||||
basicModal.error('username')
|
||||
@ -204,9 +204,9 @@ settings.setLogin = function() {
|
||||
|
||||
const action = function(data) {
|
||||
|
||||
let oldPassword = data.oldPassword || '',
|
||||
username = data.username || '',
|
||||
password = data.password || ''
|
||||
let oldPassword = data.oldPassword || ''
|
||||
let username = data.username || ''
|
||||
let password = data.password || ''
|
||||
|
||||
if (oldPassword.length<1) {
|
||||
basicModal.error('oldPassword')
|
||||
@ -269,8 +269,8 @@ settings.setLogin = function() {
|
||||
|
||||
settings.setSorting = function() {
|
||||
|
||||
let sortingPhotos = [],
|
||||
sortingAlbums = []
|
||||
let sortingPhotos = []
|
||||
let sortingAlbums = []
|
||||
|
||||
const action = function() {
|
||||
|
||||
|
@ -30,14 +30,14 @@ sidebar.bind = function() {
|
||||
// event handlers should be removed before binding a new one.
|
||||
|
||||
// Event Name
|
||||
let eventName = lychee.getEventName();
|
||||
let eventName = lychee.getEventName()
|
||||
|
||||
sidebar
|
||||
.dom('#edit_title')
|
||||
.off(eventName)
|
||||
.on(eventName, function() {
|
||||
if (visible.photo()) photo.setTitle([photo.getID()])
|
||||
else if (visible.album()) album.setTitle([album.getID()])
|
||||
if (visible.photo()) photo.setTitle([ photo.getID() ])
|
||||
else if (visible.album()) album.setTitle([ album.getID() ])
|
||||
})
|
||||
|
||||
sidebar
|
||||
@ -52,7 +52,7 @@ sidebar.bind = function() {
|
||||
.dom('#edit_tags')
|
||||
.off(eventName)
|
||||
.on(eventName, function() {
|
||||
photo.editTags([photo.getID()])
|
||||
photo.editTags([ photo.getID() ])
|
||||
})
|
||||
|
||||
sidebar
|
||||
@ -114,10 +114,10 @@ sidebar.createStructure.photo = function(data) {
|
||||
|
||||
if (data==null || data==='') return false
|
||||
|
||||
let editable = false,
|
||||
exifHash = data.takestamp + data.make + data.model + data.shutter + data.aperture + data.focal + data.iso,
|
||||
structure = {},
|
||||
_public = ''
|
||||
let editable = false
|
||||
let exifHash = data.takestamp + data.make + data.model + data.shutter + data.aperture + data.focal + data.iso
|
||||
let structure = {}
|
||||
let _public = ''
|
||||
|
||||
// Enable editable when user logged in
|
||||
if (lychee.publicMode===false) editable = true
|
||||
@ -220,12 +220,12 @@ sidebar.createStructure.album = function(data) {
|
||||
|
||||
if (data==null || data==='') return false
|
||||
|
||||
let editable = false,
|
||||
structure = {},
|
||||
_public = '',
|
||||
visible = '',
|
||||
downloadable = '',
|
||||
password = ''
|
||||
let editable = false
|
||||
let structure = {}
|
||||
let _public = ''
|
||||
let hidden = ''
|
||||
let downloadable = ''
|
||||
let password = ''
|
||||
|
||||
// Enable editable when user logged in
|
||||
if (lychee.publicMode===false) editable = true
|
||||
@ -242,14 +242,14 @@ sidebar.createStructure.album = function(data) {
|
||||
|
||||
}
|
||||
|
||||
// Set value for visible
|
||||
// Set value for hidden
|
||||
switch (data.visible) {
|
||||
|
||||
case '0' : visible = 'No'
|
||||
case '0' : hidden = 'Yes'
|
||||
break
|
||||
case '1' : visible = 'Yes'
|
||||
case '1' : hidden = 'No'
|
||||
break
|
||||
default : visible = '-'
|
||||
default : hidden = '-'
|
||||
break
|
||||
|
||||
}
|
||||
@ -301,7 +301,7 @@ sidebar.createStructure.album = function(data) {
|
||||
type : sidebar.types.DEFAULT,
|
||||
rows : [
|
||||
{ title: 'Public', value: _public },
|
||||
{ title: 'Visible', value: visible },
|
||||
{ title: 'Hidden', value: hidden },
|
||||
{ title: 'Downloadable', value: downloadable },
|
||||
{ title: 'Password', value: password }
|
||||
]
|
||||
@ -367,8 +367,8 @@ sidebar.render = function(structure) {
|
||||
|
||||
let renderTags = function(section) {
|
||||
|
||||
let _html = '',
|
||||
editable = ''
|
||||
let _html = ''
|
||||
let editable = ''
|
||||
|
||||
// Add edit-icon to the value when editable
|
||||
if (section.editable===true) editable = build.editIcon('edit_tags')
|
||||
|
@ -40,16 +40,17 @@ upload.start = {
|
||||
|
||||
local: function(files) {
|
||||
|
||||
let albumID = album.getID(),
|
||||
error = false,
|
||||
warning = false
|
||||
let albumID = album.getID()
|
||||
let error = false
|
||||
let warning = false
|
||||
|
||||
const process = function(files, file) {
|
||||
|
||||
let formData = new FormData(),
|
||||
xhr = new XMLHttpRequest(),
|
||||
pre_progress = 0,
|
||||
progress = 0
|
||||
let formData = new FormData()
|
||||
let xhr = new XMLHttpRequest()
|
||||
let pre_progress = 0
|
||||
let progress = 0
|
||||
let next_file_started = false
|
||||
|
||||
const finish = function() {
|
||||
|
||||
@ -84,98 +85,83 @@ upload.start = {
|
||||
|
||||
}
|
||||
|
||||
// Check if file is supported
|
||||
if (file.supported===false) {
|
||||
|
||||
// Skip file
|
||||
if (file.next!=null) process(files, file.next)
|
||||
else {
|
||||
|
||||
// Look for supported files
|
||||
// If zero files are supported, hide the upload after a delay
|
||||
|
||||
let hasSupportedFiles = false
|
||||
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
|
||||
if (files[i].supported===true) {
|
||||
hasSupportedFiles = true
|
||||
break
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (hasSupportedFiles===false) setTimeout(finish, 2000)
|
||||
|
||||
}
|
||||
|
||||
return false
|
||||
|
||||
}
|
||||
|
||||
formData.append('function', 'Photo::add')
|
||||
formData.append('albumID', albumID)
|
||||
formData.append('tags', '')
|
||||
formData.append(0, file)
|
||||
|
||||
xhr.open('POST', api.path)
|
||||
|
||||
xhr.onload = function() {
|
||||
|
||||
let wait = false,
|
||||
errorText = ''
|
||||
let data = null
|
||||
let wait = false
|
||||
let errorText = ''
|
||||
|
||||
const isNumber = (n) => (!isNaN(parseFloat(n)) && isFinite(n))
|
||||
|
||||
try {
|
||||
data = JSON.parse(xhr.responseText)
|
||||
} catch(e) {
|
||||
data = ''
|
||||
}
|
||||
|
||||
file.ready = true
|
||||
|
||||
// Set status
|
||||
if (xhr.status===200 && xhr.responseText==='1') {
|
||||
if (xhr.status===200 && isNumber(data)) {
|
||||
|
||||
// Success
|
||||
$('.basicModal .rows .row:nth-child(' + (file.num+1) + ') .status')
|
||||
$('.basicModal .rows .row:nth-child(' + (file.num + 1) + ') .status')
|
||||
.html('Finished')
|
||||
.addClass('success')
|
||||
|
||||
} else {
|
||||
|
||||
if (xhr.responseText.substr(0, 6)==='Error:') {
|
||||
if (data.substr(0, 6)==='Error:') {
|
||||
|
||||
errorText = xhr.responseText.substr(6) + ' Please take a look at the console of your browser for further details.'
|
||||
errorText = data.substr(6) + ' Please take a look at the console of your browser for further details.'
|
||||
error = true
|
||||
|
||||
// Error Status
|
||||
$('.basicModal .rows .row:nth-child(' + (file.num+1) + ') .status')
|
||||
$('.basicModal .rows .row:nth-child(' + (file.num + 1) + ') .status')
|
||||
.html('Failed')
|
||||
.addClass('error')
|
||||
|
||||
} else if (xhr.responseText.substr(0, 8)==='Warning:') {
|
||||
// Throw error
|
||||
if (error===true) lychee.error('Upload failed. Server returned an error!', xhr, data)
|
||||
|
||||
errorText = xhr.responseText.substr(8)
|
||||
} else if (data.substr(0, 8)==='Warning:') {
|
||||
|
||||
errorText = data.substr(8)
|
||||
warning = true
|
||||
|
||||
// Warning Status
|
||||
$('.basicModal .rows .row:nth-child(' + (file.num+1) + ') .status')
|
||||
$('.basicModal .rows .row:nth-child(' + (file.num + 1) + ') .status')
|
||||
.html('Skipped')
|
||||
.addClass('warning')
|
||||
|
||||
// Throw error
|
||||
if (error===true) lychee.error('Upload failed. Server returned a warning!', xhr, data)
|
||||
|
||||
} else {
|
||||
|
||||
errorText = 'Server returned an unknown response. Please take a look at the console of your browser for further details.'
|
||||
error = true
|
||||
|
||||
// Error Status
|
||||
$('.basicModal .rows .row:nth-child(' + (file.num+1) + ') .status')
|
||||
$('.basicModal .rows .row:nth-child(' + (file.num + 1) + ') .status')
|
||||
.html('Failed')
|
||||
.addClass('error')
|
||||
|
||||
// Throw error
|
||||
if (error===true) lychee.error('Upload failed. Server returned an unkown error!', xhr, data)
|
||||
|
||||
}
|
||||
|
||||
$('.basicModal .rows .row:nth-child(' + (file.num+1) + ') p.notice')
|
||||
$('.basicModal .rows .row:nth-child(' + (file.num + 1) + ') p.notice')
|
||||
.html(errorText)
|
||||
.show()
|
||||
|
||||
// Throw error
|
||||
if (error===true) lychee.error('Upload failed. Server returned the status code ' + xhr.status + '!', xhr, xhr.responseText)
|
||||
|
||||
}
|
||||
|
||||
// Check if there are file which are not finished
|
||||
@ -206,18 +192,21 @@ upload.start = {
|
||||
pre_progress = progress
|
||||
}
|
||||
|
||||
if (progress>=100) {
|
||||
if (progress>=100 && next_file_started===false) {
|
||||
|
||||
// Scroll to the uploading file
|
||||
let scrollPos = 0
|
||||
if ((file.num+1)>4) scrollPos = (file.num + 1 - 4) * 40
|
||||
if ((file.num + 1)>4) scrollPos = (file.num + 1 - 4) * 40
|
||||
$('.basicModal .rows').scrollTop(scrollPos)
|
||||
|
||||
// Set status to processing
|
||||
$('.basicModal .rows .row:nth-child(' + (file.num+1) + ') .status').html('Processing')
|
||||
$('.basicModal .rows .row:nth-child(' + (file.num + 1) + ') .status').html('Processing')
|
||||
|
||||
// Upload next file
|
||||
if (file.next!=null) process(files, file.next)
|
||||
if (file.next!=null) {
|
||||
process(files, file.next)
|
||||
next_file_started = true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -232,21 +221,12 @@ upload.start = {
|
||||
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
|
||||
files[i].num = i
|
||||
files[i].ready = false
|
||||
files[i].supported = true
|
||||
files[i].num = i
|
||||
files[i].ready = false
|
||||
|
||||
if (i < files.length-1) files[i].next = files[i+1]
|
||||
if (i < files.length-1) files[i].next = files[i + 1]
|
||||
else files[i].next = null
|
||||
|
||||
// Check if file is supported
|
||||
if (files[i].type!=='image/jpeg' && files[i].type!=='image/jpg' && files[i].type!=='image/png' && files[i].type!=='image/gif') {
|
||||
|
||||
files[i].ready = true
|
||||
files[i].supported = false
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
window.onbeforeunload = function() { return 'Lychee is currently uploading!' }
|
||||
@ -276,15 +256,8 @@ upload.start = {
|
||||
|
||||
basicModal.close()
|
||||
|
||||
let extension = data.link.split('.').pop()
|
||||
if (extension!=='jpeg' && extension!=='jpg' && extension!=='png' && extension!=='gif' && extension!=='webp') {
|
||||
loadingBar.show('error', 'File format of link not supported.')
|
||||
return false
|
||||
}
|
||||
|
||||
files[0] = {
|
||||
name : data.link,
|
||||
supported : true
|
||||
name: data.link
|
||||
}
|
||||
|
||||
upload.show('Importing URL', files, function() {
|
||||
@ -363,8 +336,7 @@ upload.start = {
|
||||
let files = []
|
||||
|
||||
files[0] = {
|
||||
name : data.path,
|
||||
supported : true
|
||||
name: data.path
|
||||
}
|
||||
|
||||
upload.show('Importing from server', files, function() {
|
||||
@ -387,7 +359,7 @@ upload.start = {
|
||||
|
||||
// Go back to the album overview to show the imported albums
|
||||
if (visible.albums()) lychee.load()
|
||||
else lychee.goto('')
|
||||
else lychee.goto()
|
||||
|
||||
basicModal.close()
|
||||
|
||||
@ -473,14 +445,13 @@ upload.start = {
|
||||
links += files[i].link + ','
|
||||
|
||||
files[i] = {
|
||||
name : files[i].link,
|
||||
supported : true
|
||||
name : files[i].link
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Remove last comma
|
||||
links = links.substr(0, links.length-1)
|
||||
links = links.substr(0, links.length - 1)
|
||||
|
||||
upload.show('Importing from Dropbox', files, function() {
|
||||
|
||||
|
@ -26,8 +26,8 @@ view.albums = {
|
||||
|
||||
init: function() {
|
||||
|
||||
let smartData = '',
|
||||
albumsData = ''
|
||||
let smartData = ''
|
||||
let albumsData = ''
|
||||
|
||||
// Smart Albums
|
||||
if (lychee.publicMode===false) {
|
||||
@ -246,10 +246,10 @@ view.album = {
|
||||
|
||||
},
|
||||
|
||||
visible: function() {
|
||||
hidden: function() {
|
||||
|
||||
if (album.json.visible==='1') sidebar.changeAttr('visible', 'Yes')
|
||||
else sidebar.changeAttr('visible', 'No')
|
||||
if (album.json.visible==='1') sidebar.changeAttr('hidden', 'No')
|
||||
else sidebar.changeAttr('hidden', 'Yes')
|
||||
|
||||
},
|
||||
|
||||
@ -271,8 +271,8 @@ view.album = {
|
||||
|
||||
if ((visible.album() || !album.json.init) && !visible.photo()) {
|
||||
|
||||
let structure = sidebar.createStructure.album(album.json),
|
||||
html = sidebar.render(structure)
|
||||
let structure = sidebar.createStructure.album(album.json)
|
||||
let html = sidebar.render(structure)
|
||||
|
||||
sidebar.dom('.sidebar__wrapper').html(html)
|
||||
sidebar.bind()
|
||||
@ -408,27 +408,33 @@ view.photo = {
|
||||
|
||||
lychee.imageview.html(build.imageview(photo.json, visible.header()))
|
||||
|
||||
let $nextArrow = lychee.imageview.find('a#next'),
|
||||
$previousArrow = lychee.imageview.find('a#previous'),
|
||||
photoID = photo.getID(),
|
||||
hasNext = album.json && album.json.content && album.json.content[photoID] && album.json.content[photoID].nextPhoto!=='',
|
||||
hasPrevious = album.json && album.json.content && album.json.content[photoID] && album.json.content[photoID].previousPhoto!==''
|
||||
let $nextArrow = lychee.imageview.find('a#next')
|
||||
let $previousArrow = lychee.imageview.find('a#previous')
|
||||
let photoID = photo.getID()
|
||||
let hasNext = album.json && album.json.content && album.json.content[photoID] && album.json.content[photoID].nextPhoto!==''
|
||||
let hasPrevious = album.json && album.json.content && album.json.content[photoID] && album.json.content[photoID].previousPhoto!==''
|
||||
|
||||
if (hasNext===false || lychee.viewMode===true) { $nextArrow.hide() }
|
||||
else {
|
||||
if (hasNext===false || lychee.viewMode===true) {
|
||||
|
||||
let nextPhotoID = album.json.content[photoID].nextPhoto,
|
||||
nextPhoto = album.json.content[nextPhotoID]
|
||||
$nextArrow.hide()
|
||||
|
||||
} else {
|
||||
|
||||
let nextPhotoID = album.json.content[photoID].nextPhoto
|
||||
let nextPhoto = album.json.content[nextPhotoID]
|
||||
|
||||
$nextArrow.css('background-image', lychee.html`linear-gradient(to bottom, rgba(0, 0, 0, .4), rgba(0, 0, 0, .4)), url("$${ nextPhoto.thumbUrl }")`)
|
||||
|
||||
}
|
||||
|
||||
if (hasPrevious===false || lychee.viewMode===true) { $previousArrow.hide() }
|
||||
else {
|
||||
if (hasPrevious===false || lychee.viewMode===true) {
|
||||
|
||||
let previousPhotoID = album.json.content[photoID].previousPhoto,
|
||||
previousPhoto = album.json.content[previousPhotoID]
|
||||
$previousArrow.hide()
|
||||
|
||||
} else {
|
||||
|
||||
let previousPhotoID = album.json.content[photoID].previousPhoto
|
||||
let previousPhoto = album.json.content[previousPhotoID]
|
||||
|
||||
$previousArrow.css('background-image', lychee.html`linear-gradient(to bottom, rgba(0, 0, 0, .4), rgba(0, 0, 0, .4)), url("$${ previousPhoto.thumbUrl }")`)
|
||||
|
||||
@ -438,8 +444,8 @@ view.photo = {
|
||||
|
||||
sidebar: function() {
|
||||
|
||||
let structure = sidebar.createStructure.photo(photo.json),
|
||||
html = sidebar.render(structure)
|
||||
let structure = sidebar.createStructure.photo(photo.json)
|
||||
let html = sidebar.render(structure)
|
||||
|
||||
sidebar.dom('.sidebar__wrapper').html(html)
|
||||
sidebar.bind()
|
||||
|
@ -11,8 +11,8 @@ lychee.content = $('.content')
|
||||
|
||||
lychee.getEventName = function() {
|
||||
|
||||
let touchendSupport = (/Android|iPhone|iPad|iPod/i).test(navigator.userAgent || navigator.vendor || window.opera) && ('ontouchend' in document.documentElement),
|
||||
eventName = (touchendSupport===true ? 'touchend' : 'click')
|
||||
let touchendSupport = (/Android|iPhone|iPad|iPod/i).test(navigator.userAgent || navigator.vendor || window.opera) && ('ontouchend' in document.documentElement)
|
||||
let eventName = (touchendSupport===true ? 'touchend' : 'click')
|
||||
|
||||
return eventName
|
||||
|
||||
@ -39,8 +39,8 @@ lychee.html = function(literalSections, ...substs) {
|
||||
|
||||
// Use raw literal sections: we don’t want
|
||||
// backslashes (\n etc.) to be interpreted
|
||||
let raw = literalSections.raw,
|
||||
result = ''
|
||||
let raw = literalSections.raw
|
||||
let result = ''
|
||||
|
||||
substs.forEach((subst, i) => {
|
||||
|
||||
@ -63,7 +63,7 @@ lychee.html = function(literalSections, ...substs) {
|
||||
// Take care of last literal section
|
||||
// (Never fails, because an empty template string
|
||||
// produces one literal section, an empty string)
|
||||
result += raw[raw.length-1]
|
||||
result += raw[raw.length - 1]
|
||||
|
||||
return result
|
||||
|
||||
@ -88,7 +88,7 @@ $(document).ready(function() {
|
||||
// Direct Link
|
||||
header.dom('#button_direct').on(eventName, function() {
|
||||
|
||||
let link = $('#imageview #image').css('background-image').replace(/"/g,'').replace(/url\(|\)$/ig, '')
|
||||
let link = $('#imageview img').attr('src').replace(/"/g,'').replace(/url\(|\)$/ig, '')
|
||||
window.open(link, '_newtab')
|
||||
|
||||
})
|
||||
@ -127,8 +127,8 @@ const loadPhotoInfo = function(photoID) {
|
||||
imageview.addClass('fadeIn').show()
|
||||
|
||||
// Render Sidebar
|
||||
let structure = sidebar.createStructure.photo(data),
|
||||
html = sidebar.render(structure)
|
||||
let structure = sidebar.createStructure.photo(data)
|
||||
let html = sidebar.render(structure)
|
||||
|
||||
sidebar.dom('.sidebar__wrapper').html(html)
|
||||
sidebar.bind()
|
||||
|
@ -65,18 +65,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
// PopIn -------------------------------------------------------------- //
|
||||
@keyframes popIn {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: scale(0);
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Pulse -------------------------------------------------------------- //
|
||||
@keyframes pulse {
|
||||
0% {
|
||||
|
@ -12,7 +12,6 @@
|
||||
&__item {
|
||||
margin-bottom: 2px;
|
||||
font-size: 14px;
|
||||
text-shadow: $shadowLight;
|
||||
|
||||
&--separator {
|
||||
margin: 4px 0;
|
||||
|
@ -146,7 +146,6 @@
|
||||
margin: 0 5px 0 0;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
filter: drop-shadow(0 1px 3px black(.4));
|
||||
}
|
||||
|
||||
.album img[data-overlay='false'] + .overlay h1,
|
||||
@ -185,7 +184,6 @@
|
||||
fill: #fff;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
filter: drop-shadow($shadowLight);
|
||||
}
|
||||
}
|
||||
|
||||
@ -225,7 +223,6 @@
|
||||
left: 50%;
|
||||
padding-top: 20px;
|
||||
color: white(.35);
|
||||
text-shadow: 0 -1px 0 black(.4);
|
||||
text-align: center;
|
||||
transform: translateX(-50%) translateY(-50%);
|
||||
|
||||
@ -234,7 +231,6 @@
|
||||
margin: 0 0 10px;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
filter: drop-shadow(0 -1px 0 black(.4));
|
||||
}
|
||||
|
||||
p {
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user