<?php

# PLUGIN PREVIEW BY TEXTPATTERN.INFO



/*
 * rah_flat - Flat templates for Textpattern CMS
 * https://github.com/gocom/rah_flat
 *
 * Copyright (C) 2014 Jukka Svahn
 *
 * This file is part of rah_flat.
 *
 * rah_flat is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation, version 2.
 *
 * rah_flat is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with rah_flat. If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * Template iterator.
 *
 * This class iterates over template files.
 *
 * <code>
 * $template = new Rah_Flat_TemplateIterator();
 * while ($template->valid()) {
 *  $template->getTemplateName();
 *  $template->getTemplateContents();
 * }
 * </code>
 *
 * @see DirectoryIterator
 */

class Rah_Flat_TemplateIterator extends DirectoryIterator
{
    
/**
     * Template name pattern.
     *
     * This regular expression pattern is used to
     * validate template filenames.
     *
     * @var string
     */

    
protected $templateNamePattern '/[a-z][a-z0-9_\-\.]{1,63}\.[a-z0-9]+/i';

    
/**
     * Gets the template contents.
     *
     * @throws Exception
     */

    
public function getTemplateContents()
    {
        if ((
$contents file_get_contents($this->getPathname())) !== false) {
            return 
preg_replace('/[\r|\n]+$/'''$contents);
        }

        throw new 
Exception('Unable to read.');
    }

    
/**
     * Gets JSON file contents as an object.
     *
     * @return stdClass
     * @throws Exception
     */

    
public function getTemplateJSONContents()
    {
        if ((
$file $this->getTemplateContents()) && $file = @json_decode($file)) {
            return 
$file;
        }

        throw new 
Exception('Invalid JSON file.');
    }

    
/**
     * Gets the template name.
     *
     * @return string
     */

    
public function getTemplateName()
    {
        return 
pathinfo($this->getFilename(), PATHINFO_FILENAME);
    }

    
/**
     * Validates a template file name and stats.
     *
     * Template file must be a regular file or symbolic links,
     * readable and the name must be fewer than 64 characters long,
     * start with an ASCII character, followed by A-z, 0-9, -, _ and
     * and ends to a file extension.
     *
     * Valid template name would include:
     *
     * <code>
     * sitename.json
     * default.article.txp
     * form.name.misc.txp
     * default.txp
     * error_default.html
     * </code>
     *
     * But the following would be invalid:
     *
     * <code>
     * .sitename
     * _form.misc.txp
     * </code>
     *
     * @return bool TRUE if the name is valid
     */

    
public function isValidTemplate()
    {
        if (!
$this->isDot() && $this->isReadable() && ($this->isFile() || $this->isLink())) {
            return (bool) 
preg_match($this->templateNamePattern$this->getFilename());
        }

        return 
false;
    }

    
/**
     * {@inheritdoc}
     */

    
public function valid()
    {
        while (
parent::valid() && !$this->isValidTemplate()) {
            
$this->next();
        }

        if (
parent::valid()) {
            return 
true;
        }

        
$this->rewind();
        return 
false;
    }
}



/*
 * rah_flat - Flat templates for Textpattern CMS
 * https://github.com/gocom/rah_flat
 *
 * Copyright (C) 2014 Jukka Svahn
 *
 * This file is part of rah_flat.
 *
 * rah_flat is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation, version 2.
 *
 * rah_flat is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with rah_flat. If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * Form partial iterator.
 *
 * @see DirectoryIterator
 */

class Rah_Flat_FormIterator extends Rah_Flat_TemplateIterator
{
    
/**
     * {@inheritdoc}
     */

    
protected $templateNamePattern '/[a-z][a-z0-9_\-\.]{1,63}\.[a-z0-9]{1,28}\.[a-z0-9]+/i';

    
/**
     * {@inheritdoc}
     */

    
public function getTemplateName()
    {
        return 
pathinfo(pathinfo($this->getFilename(), PATHINFO_FILENAME), PATHINFO_FILENAME);
    }

    
/**
     * Gets the template type.
     *
     * If the template name doesn't specify a type, it
     * defaults to 'misc'. The second to last extension
     * is expected to be the type.
     *
     * If the file is named as:
     *
     * <code>
     * filename.red.ext
     * </code>
     *
     * The 'red' would be used as the type.
     *
     * @return string
     */

    
public function getTemplateType()
    {
        if (
$type pathinfo(pathinfo($this->getFilename(), PATHINFO_FILENAME), PATHINFO_EXTENSION)) {
            return 
$type;
        }

        return 
'misc';
    }
}



/*
 * rah_flat - Flat templates for Textpattern CMS
 * https://github.com/gocom/rah_flat
 *
 * Copyright (C) 2014 Jukka Svahn
 *
 * This file is part of rah_flat.
 *
 * rah_flat is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation, version 2.
 *
 * rah_flat is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with rah_flat. If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * Interface for import definitions.
 *
 * <code>
 * class Abc_Import_Definition implements Rah_Flat_Import_ImportInterface
 * {
 * }
 * </code>
 */

interface Rah_Flat_Import_ImportInterface
{
    
/**
     * Constructor.
     *
     * Registers the importer definition when the class is initialized.
     * The used event should be considered private and should not
     * be accessed manually.
     *
     * <code>
     * new Rah_Flat_Import_Forms('forms');
     * </code>
     *
     * @param string $directory The directory hosting the templates
     */

    
public function __construct($directory);

    
/**
     * Initializes the importer.
     *
     * This method is called when the import event is executed.
     *
     * @throws Exception
     */

    
public function init();

    
/**
     * Drops permissions to the panel.
     *
     * This makes sure the template items are not
     * modified through the GUI.
     *
     * This method only affects the admin-side interface and doesn't
     * truly reset permissions application wide. This is to
     * avoid unneccessary I/O activity that would otherwise have to
     * take place.
     */

    
public function dropPermissions();

    
/**
     * Drops removed template rows from the database.
     *
     * For most impletations this method removes all rows that aren't
     * present in the flat directory, but for some it might
     * not do anything.
     *
     * @throws Exception
     */

    
public function dropRemoved(Rah_Flat_TemplateIterator $template);

    
/**
     * Gets the panel name.
     *
     * The panel name is used to recognize the content-types
     * registered event and remove access to it.
     *
     * @return string
     */

    
public function getPanelName();

    
/**
     * Gets database table name.
     *
     * @return string
     */

    
public function getTableName();

    
/**
     * Imports the template file.
     *
     * This method executes the SQL statement to import
     * the template file.
     *
     * @param  Rah_Flat_TemplateIterator $file The template file
     * @throws Exception
     */

    
public function importTemplate(Rah_Flat_TemplateIterator $file);

    
/**
     * Gets an array of database columns in the table.
     *
     * @return array
     */

    
public function getTableColumns();

    
/**
     * Gets a path to the directory hosting the flat files.
     *
     * @return string|bool The path, or FALSE
     */

    
public function getDirectoryPath();

    
/**
     * Whether the content-type is enabled and has a directory.
     *
     * @return bool TRUE if its enabled, FALSE otherwise
     */

    
public function isEnabled();
}



/*
 * rah_flat - Flat templates for Textpattern CMS
 * https://github.com/gocom/rah_flat
 *
 * Copyright (C) 2014 Jukka Svahn
 *
 * This file is part of rah_flat.
 *
 * rah_flat is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation, version 2.
 *
 * rah_flat is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with rah_flat. If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * Base class for import definitions.
 *
 * To create a new importable template object, extend
 * this class or its theriatives.
 *
 * For instance the following would create a new import
 * definition using the Rah_Flat_Import_Pages as the
 * base:
 *
 * <code>
 * class Abc_My_Import_Definition extends Rah_Flat_Import_Pages
 * {
 *     public function getPanelName()
 *     {
 *         return 'abc_mypanel';
 *     }
 *     public function getTableName()
 *     {
 *         return 'abc_mytable';
 *     }
 * }
 * </code>
 *
 * It would automatically disable access to 'abc_mypanel' admin-side panel
 * and import items to 'abc_mytable' database table, consisting of 'name'
 * and 'user_html' columns, as with page templates and its txp_page table.
 *
 * To initialize the import, just create a new instance of the class. Pass
 * constructor the directory name the templates reside in the configured
 * templates directory.
 *
 * <code>
 * new Abc_My_Import_Definition('abc_mydirectory');
 * </code>
 */

abstract class Rah_Flat_Import_Base implements Rah_Flat_Import_ImportInterface
{
    
/**
     * The directory.
     *
     * @var string
     */

    
protected $directory;

    
/**
     * An array of database table columns.
     *
     * @var array
     */

    
private $columns = array();

    
/**
     * {@inheritdoc}
     */

    
public function __construct($directory)
    {
        
$this->directory $directory;
        
register_callback(array($this'init'), 'rah_flat.import_to_database');
        
$this->dropPermissions();
    }

    
/**
     * {@inheritdoc}
     */

    
public function getTemplateIterator($directory)
    {
        return new 
Rah_Flat_TemplateIterator($directory);
    }

    
/**
     * {@inheritdoc}
     */

    
public function getDirectoryPath()
    {
        if (
$this->directory && ($directory get_pref('rah_flat_path'))) {
            
$directory txpath '/' $directory '/' $this->directory;
            return 
$directory;
        }

        return 
false;
    }

    
/**
     * {@inheritdoc}
     */

    
public function isEnabled()
    {
        if (
$directory $this->getDirectoryPath()) {
            return 
file_exists($directory) && is_dir($directory) && is_readable($directory);
        }

        return 
false;
    }

    
/**
     * {@inheritdoc}
     */

    
public function init()
    {
        if (
$this->isEnabled()) {
            
$template $this->getTemplateIterator($this->getDirectoryPath());

            while (
$template->valid()) {
                if (
$this->importTemplate($template) === false) {
                    throw new 
Exception('Unable to import ' $template->getTemplateName());
                }

                
$template->next();
            }

            
$this->dropRemoved($template);
        }
    }

    
/**
     * {@inheritdoc}
     */

    
public function dropPermissions()
    {
        if (
txpinterface === 'admin' && $this->isEnabled()) {
            unset(
$GLOBALS['txp_permissions'][$this->getPanelName()]);
        }
    }

    
/**
     * {@inheritdoc}
     */

    
public function getTableColumns()
    {
        if (!
$this->columns) {
            
$this->columns doArray((array) @getThings('describe '.safe_pfx($this->getTableName())), 'strtolower');
        }

        return 
$this->columns;
    }
}



/*
 * rah_flat - Flat templates for Textpattern CMS
 * https://github.com/gocom/rah_flat
 *
 * Copyright (C) 2014 Jukka Svahn
 *
 * This file is part of rah_flat.
 *
 * rah_flat is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation, version 2.
 *
 * rah_flat is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with rah_flat. If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * Imports page templates.
 */

class Rah_Flat_Import_Pages extends Rah_Flat_Import_Base
{
    
/**
     * {@inheritdoc}
     */

    
public function getPanelName()
    {
        return 
'page';
    }

    
/**
     * {@inheritdoc}
     */

    
public function getTableName()
    {
        return 
'txp_page';
    }

    
/**
     * {@inheritdoc}
     */

    
public function importTemplate(Rah_Flat_TemplateIterator $file)
    {
        
safe_upsert(
            
$this->getTableName(),
            
"user_html = '".doSlash($file->getTemplateContents())."'",
            
"name = '".doSlash($file->getTemplateName())."'"
        
);
    }

    
/**
     * {@inheritdoc}
     */

    
public function dropRemoved(Rah_Flat_TemplateIterator $template)
    {
        
$name = array();

        while (
$template->valid()) {
            
$name[] = "'".doSlash($template->getTemplateName())."'";
            
$template->next();
        }

        if (
$name) {
            
safe_delete($this->getTableName(), 'name not in ('.implode(','$name).')');
        } else {
            
safe_delete($this->getTableName(), '1 = 1');
        }
    }
}



/*
 * rah_flat - Flat templates for Textpattern CMS
 * https://github.com/gocom/rah_flat
 *
 * Copyright (C) 2014 Jukka Svahn
 *
 * This file is part of rah_flat.
 *
 * rah_flat is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation, version 2.
 *
 * rah_flat is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with rah_flat. If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * Imports form partials.
 */

class Rah_Flat_Import_Forms extends Rah_Flat_Import_Pages
{
    
/**
     * {@inheritdoc}
     */

    
public function getPanelName()
    {
        return 
'form';
    }

    
/**
     * {@inheritdoc}
     */

    
public function getTableName()
    {
        return 
'txp_form';
    }

    
/**
     * {@inheritdoc}
     */

    
public function getTemplateIterator($directory)
    {
        return new 
Rah_Flat_FormIterator($directory);
    }

    
/**
     * {@inheritdoc}
     */

    
public function importTemplate(Rah_Flat_TemplateIterator $file)
    {
        
safe_upsert(
            
$this->getTableName(),
            
"Form = '".doSlash($file->getTemplateContents())."',
            type = '"
.doSlash($file->getTemplateType())."'",
            
"name = '".doSlash($file->getTemplateName())."'"
        
);
    }
}



/*
 * rah_flat - Flat templates for Textpattern CMS
 * https://github.com/gocom/rah_flat
 *
 * Copyright (C) 2014 Jukka Svahn
 *
 * This file is part of rah_flat.
 *
 * rah_flat is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation, version 2.
 *
 * rah_flat is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with rah_flat. If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * Imports sections.
 */

class Rah_Flat_Import_Sections extends Rah_Flat_Import_Pages
{
    
/**
     * {@inheritdoc}
     */

    
public function getPanelName()
    {
        return 
'section';
    }

    
/**
     * {@inheritdoc}
     */

    
public function getTableName()
    {
        return 
'txp_section';
    }

    
/**
     * {@inheritdoc}
     */

    
public function importTemplate(Rah_Flat_TemplateIterator $file)
    {
        
$sql = array();
        
$where "name = '".doSlash($file->getTemplateName())."'";

        foreach (
$file->getTemplateJSONContents() as $key => $value) {
            if (
$key !== 'name' && in_array(strtolower((string) $key), $this->getTableColumns(), true)) {
                
$sql[] = $this->formatStatement($key$value);
            }
        }

        return 
$sql && safe_upsert($this->getTableName(), implode(','$sql), $where);
    }

    
/**
     * Formats a SQL insert statement value.
     *
     * @param  string $field The field
     * @param  string $value The value
     * @return string
     */

    
protected function formatStatement($field$value)
    {
        if (
$value === null) {
            return 
"`{$field}` = NULL";
        }

        if (
is_bool($value) || is_int($value)) {
            return 
"`{$field}` = ".intval($value);
        }

        if (
is_array($value)) {
            
$value implode(', '$value);
        }

        return 
"`{$field}` = '".doSlash((string) $value)."'";
    }
}



/*
 * rah_flat - Flat templates for Textpattern CMS
 * https://github.com/gocom/rah_flat
 *
 * Copyright (C) 2014 Jukka Svahn
 *
 * This file is part of rah_flat.
 *
 * rah_flat is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation, version 2.
 *
 * rah_flat is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with rah_flat. If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * Imports preferences.
 */

class Rah_Flat_Import_Prefs extends Rah_Flat_Import_Sections
{
    
/**
     * {@inheritdoc}
     */

    
public function getPanelName()
    {
        return 
'prefs';
    }

    
/**
     * {@inheritdoc}
     */

    
public function getTableName()
    {
        return 
'txp_prefs';
    }

    
/**
     * {@inheritdoc}
     */

    
public function importTemplate(Rah_Flat_TemplateIterator $file)
    {
        
$sql = array();
        
$where "name = '".doSlash($file->getTemplateName())."' and user_name = ''";

        foreach (
$file->getTemplateJSONContents() as $key => $value) {
            if (
in_array(strtolower((string) $key), $this->getTableColumns(), true)) {
                
$sql[] = $this->formatStatement($key$value);
            }
        }

        return 
$sql && safe_update($this->getTableName(), implode(','$sql), $where);
    }

    
/**
     * {@inheritdoc}
     */

    
public function dropRemoved(Rah_Flat_TemplateIterator $template)
    {
    }

    
/**
     * {@inheritdoc}
     */

    
public function dropPermissions()
    {
    }
}



/*
 * rah_flat - Flat templates for Textpattern CMS
 * https://github.com/gocom/rah_flat
 *
 * Copyright (C) 2014 Jukka Svahn
 *
 * This file is part of rah_flat.
 *
 * rah_flat is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation, version 2.
 *
 * rah_flat is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with rah_flat. If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * Imports template styles.
 */

class Rah_Flat_Import_Styles extends Rah_Flat_Import_Pages
{
    
/**
     * {@inheritdoc}
     */

    
public function getPanelName()
    {
        return 
'css';
    }

    
/**
     * {@inheritdoc}
     */

    
public function getTableName()
    {
        return 
'txp_css';
    }

    
/**
     * {@inheritdoc}
     */

    
public function importTemplate(Rah_Flat_TemplateIterator $file)
    {
        
safe_upsert(
            
$this->getTableName(),
            
"css = '".doSlash($file->getTemplateContents())."'",
            
"name = '".doSlash($file->getTemplateName())."'"
        
);
    }
}



/*
 * rah_flat - Flat templates for Textpattern CMS
 * https://github.com/gocom/rah_flat
 *
 * Copyright (C) 2014 Jukka Svahn
 *
 * This file is part of rah_flat.
 *
 * rah_flat is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation, version 2.
 *
 * rah_flat is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with rah_flat. If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * Main plugin class.
 *
 * @internal
 */

class Rah_Flat
{
    
/**
     * Constructor.
     */

    
public function __construct()
    {
        
add_privs('prefs.rah_flat''1');
        
register_callback(array($this'install'), 'plugin_lifecycle.rah_flat''installed');
        
register_callback(array($this'uninstall'), 'plugin_lifecycle.rah_flat''deleted');

        if (
get_pref('rah_flat_path')) {

            new 
Rah_Flat_Import_Prefs('prefs');
            new 
Rah_Flat_Import_Sections('sections');
            new 
Rah_Flat_Import_Pages('pages');
            new 
Rah_Flat_Import_Forms('forms');
            new 
Rah_Flat_Import_Styles('styles');

            
register_callback(array($this'endpoint'), 'textpattern');
            
register_callback(array($this'initWrite'), 'rah_flat.import');

            if (
get_pref('production_status') !== 'live') {
                
register_callback(array($this'callbackHandler'), 'textpattern');
                
register_callback(array($this'callbackHandler'), 'admin_side''body_end');
            }
        }
    }

    
/**
     * Installer.
     */

    
public function install()
    {
        
$position 250;

        
$options = array(
            
'rah_flat_path' => array('text_input''../../src/templates'),
            
'rah_flat_key'  => array('text_input'md5(uniqid(mt_rand(), true))),
        );

        foreach (
$options as $name => $val) {
            if (
get_pref($namefalse) === false) {
                
set_pref($name$val[1], 'rah_flat'PREF_ADVANCED$val[0], $position);
            }

            
$position++;
        }
    }

    
/**
     * Uninstaller.
     */

    
public function uninstall()
    {
        
safe_delete('txp_prefs'"name like 'rah\_flat\_%'");
    }

    
/**
     * Initializes the importers.
     */

    
public function initWrite()
    {
        
safe_query('LOCK TABLES '.implode(' WRITE, 'getThings('show tables')).' WRITE');
        
callback_event('rah_flat.import_to_database');
        
safe_query('UNLOCK TABLES');
    }

    
/**
     * Registered callback handler.
     */

    
public function callbackHandler()
    {
        try {
            
callback_event('rah_flat.import');
        } catch (
Exception $e) {
            
trigger_error($e->getMessage());
        }
    }

    
/**
     * Import endpoint.
     */

    
public function endpoint()
    {
        if (!
get_pref('rah_flat_key') || get_pref('rah_flat_key') !== gps('rah_flat_key')) {
            return;
        }

        
header('Content-Type: application/json; charset=utf-8');

        try {
            
callback_event('rah_flat.import');
        } catch (
Exception $e) {
            
txp_status_header('500 Internal Server Error');

            die(
json_encode(array(
                
'success' => false,
                
'error'   => $e->getMessage(),
            )));
        }

        
update_lastmod();

        die(
json_encode(array(
            
'success' => true,
        )));
    }
}

new 
Rah_Flat();