arastta/arastta

View on GitHub
admin/model/common/update.php

Summary

Maintainability
C
1 day
Test Coverage
<?php
/**
 * @package     Arastta eCommerce
 * @copyright   2015-2017 Arastta Association. All rights reserved.
 * @copyright   See CREDITS.txt for credits and other copyright notices.
 * @license     GNU GPL version 3; see LICENSE.txt
 * @link        https://arastta.org
 */

class ModelCommonUpdate extends Model
{

    public function check()
    {
        // Fire event
        $this->trigger->fire('pre.admin.update.check');

        $this->cache->remove('addon');
        $this->cache->remove('update');
        $this->cache->remove('version');

        return true;
    }

    public function changelog()
    {
        $output = '';

        $url = 'https://api.github.com/repos/arastta/arastta/releases';

        $json = \Httpful\Request::get($url)
            ->send()
            ->raw_body;

        if (empty($json)) {
            return $output;
        }

        $parsedown = new ParsedownExtra();

        $releases = json_decode($json);

        foreach ($releases as $release) {
            if ($release->tag_name <= VERSION) {
                continue;
            }
            
            if ($release->prerelease == true) {
                continue;
            }

            if (empty($release->body)) {
                continue;
            }

            $output .= '<h2><span class="label label-primary">'.$release->tag_name.'</span></h2>';

            // Parse markdown output
            $markdown = str_replace('## Changelog', '', $release->body);

            $output .= $parsedown->text($markdown);

            $output .= '<hr>';
        }

        return $output;
    }

    // Upgrade
    public function update()
    {
        $version = $this->request->get['version'];
        $product_id = $this->request->get['product_id'];

        if (!$data = $this->downloadUpdate($product_id, $version)) {
            return false;
        }

        $path = 'temp-' . md5(mt_rand());
        $file = DIR_UPLOAD . $path . '/upload.zip';

        if (!is_dir(DIR_UPLOAD . $path)) {
            $this->filesystem->mkdir(DIR_UPLOAD . $path);
        }

        $uploaded = is_int(file_put_contents($file, $data)) ? true : false;

        if (!$uploaded) {
            return false;
        }

        // Fire event
        $this->trigger->fire('pre.admin.update.update', array(&$product_id));

        // Force enable maintenance mode
        $maintenance_mode = $this->config->get('maintenance_mode');
        $this->config->set('maintenance_mode', 1);

        $installer = new Installer($this->registry);

        if (!$installer->unzip($file)) {
            return false;
        }

        // Remove Zip
        $this->filesystem->remove($file);

        if ($product_id == 'core') {
            $temp_path = DIR_UPLOAD . $path;
            $install_path = $temp_path . '/install';

            // Load the update script, if available
            if (is_file($install_path.'/update.php')) {
                require_once($install_path.'/update.php');
            }

            // Don't copy the install folder
            $this->filesystem->remove($install_path);

            // Move all files/folders from temp path
            try {
                $this->filesystem->mirror($temp_path, DIR_ROOT, null, array('override' => true));
            } catch (Exception $e) {
                return false;
            }

            // Delete the temp path
            $this->filesystem->remove($temp_path);
        } else {
            // Required for ftp & remove extension functions
            $this->request->post['path'] = $path;

            if ($this->filesystem->exists(DIR_UPLOAD . $path . '/install.json')) {
                $install_data = json_decode(file_get_contents(DIR_UPLOAD . $path . '/install.json'), true);

                // Set it to use in the next step, addExtensionTheme
                $this->session->data['product_id'] = $product_id;
                $this->session->data['installer_info'] = $install_data;
            }

            $ftp = $this->load->controller('extension/installer/parseFiles');
            $remove = $this->load->controller('extension/installer/remove');

            $this->db->query("UPDATE `" . DB_PREFIX . "addon` SET `product_version` = '" . $this->db->escape($version) . "' WHERE `product_id` = '" . (int)$product_id . "'");
        }

        // Restore maintenance mode
        $this->config->set('maintenance_mode', $maintenance_mode);

        // Fire event
        $this->trigger->fire('post.admin.update.update', array(&$product_id));

        return true;
    }

    public function countUpdates()
    {
        return array_sum(array_map("count", $this->getUpdates()));
    }

    public function getUpdates()
    {
        $data = $this->cache->get('update');

        if (empty($data)) {
            $data = array();

            $this->load->model('extension/marketplace');

            $addons = $this->model_extension_marketplace->getAddons(true);

            $versions = $this->getVersions($addons);

            foreach ($versions as $key => $version) {
                // Addons (extensions, themes, translations) comes as array
                if (is_array($version)) {
                    foreach ($version as $id => $addon_version) {
                        $addon = $addons[$id];
                        $type = $addon['product_type'];

                        // English (en-GB) language, always up-to-date
                        if ($addon['product_id'] == 225) {
                            continue;
                        }

                        // Up-to-date
                        if (version_compare($addon['product_version'], $addon_version) == 0) {
                            continue;
                        }

                        $data[$type][$addon['product_id']] = $addon_version;
                    }
                } elseif ($key == 'core') {
                    if (version_compare(VERSION, $version) != 0) {
                        $data['core'] = $version;
                    }
                }
            }

            $this->cache->set('update', $data);
        }

        return $data;
    }

    public function getVersions($addons = array())
    {
        $data = $this->cache->get('version');

        if (empty($data)) {
            $data = array();

            // Check core first
            $info = $this->utility->getInfo();
            $base_url = 'http://arastta.io';

            $url = $base_url.'/core/1.0/version/'.$info['arastta'].'/'.$info['php'].'/'.$info['mysql'].'/'.$info['langs'].'/'.$info['stores'];

            $data['core'] = $this->getRemoteVersion($url);

            // Then addons
            if (!empty($addons)) {
                foreach ($addons as $addon) {
                    $type = $addon['product_type'];

                    $url = $base_url.'/'.$type.'/1.0/version/'.$addon['product_id'].'/'.$addon['product_version'].'/'.$info['arastta'];

                    $data[$type][$addon['product_id']] = $this->getRemoteVersion($url);
                }
            }

            $this->cache->set('version', $data);
        }

        return $data;
    }

    public function getRemoteVersion($url)
    {
        $remote_data = \Httpful\Request::get($url)
            ->addOnCurlOption(CURLOPT_REFERER, $this->url->getDomain())
            ->send()
            ->raw_body;

        if (is_string($remote_data)) {
            $version = json_decode($remote_data);

            if (is_object($version)) {
                $latest = $version->latest;
            } else {
                $latest = '0.0.0';
            }
        } else {
            $latest = '0.0.0';
        }

        return $latest;
    }

    public function downloadUpdate($product_id, $version)
    {
        // Check core first
        $info = $this->utility->getInfo();
        $base_url = 'http://arastta.io';

        if ($product_id == 'core') {
            $url = $base_url.'/core/1.0/update/'.$version.'/'.$info['php'].'/'.$info['mysql'];
        } else {
            $this->load->model('extension/marketplace');

            $addons = $this->model_extension_marketplace->getAddons(true);
            
            $type = $addons[$product_id]['product_type'];

            $url = $base_url.'/'.$type.'/1.0/update/'.$product_id.'/'.$version.'/'.$info['arastta'].'/'.$info['api'];
        }

        $file = \Httpful\Request::get($url)
            ->timeout(30)
            ->addOnCurlOption(CURLOPT_REFERER, $this->url->getDomain())
            ->send()
            ->raw_body;

        return $file;
    }

    public function showColums($table)
    {
        $result = array();

        $query = $this->db->query("SHOW COLUMNS FROM `" . DB_PREFIX . $table . "`");

        if ($query->num_rows) {
            foreach ($query->rows as $row) {
                $result[] = $row['Field'];
            }
        }

        return $result;
    }
}