├── system
└── expressionengine
│ └── third_party
│ └── github_addon_installer
│ ├── src
│ ├── Installer
│ │ ├── SystemUnzipInstaller.php
│ │ ├── ZipArchiveInstaller.php
│ │ ├── FileInstaller.php
│ │ ├── AbstractZipInstaller.php
│ │ └── Installer.php
│ ├── Application.php
│ ├── Repo.php
│ └── Api.php
│ ├── language
│ └── english
│ │ └── github_addon_installer_lang.php
│ ├── views
│ └── index.php
│ ├── upd.github_addon_installer.php
│ ├── mcp.github_addon_installer.php
│ ├── libraries
│ └── Github_addon_installer.php
│ └── config
│ └── manifest.js
├── composer.json
└── README.markdown
/system/expressionengine/third_party/github_addon_installer/src/Installer/SystemUnzipInstaller.php:
--------------------------------------------------------------------------------
1 | tempPath, $filePath));
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "eecli/github-addon-installer",
3 | "description": "Install Github-hosted Addons with eecli.",
4 | "authors": [
5 | {
6 | "name": "Rob Sanchez",
7 | "email": "info@robsanchez.com"
8 | }
9 | ],
10 | "autoload": {
11 | "psr-4": { "eecli\\GithubAddonInstaller\\": "system/expressionengine/third_party/github_addon_installer/src/" }
12 | },
13 | "require": {}
14 | }
15 |
--------------------------------------------------------------------------------
/system/expressionengine/third_party/github_addon_installer/src/Installer/ZipArchiveInstaller.php:
--------------------------------------------------------------------------------
1 | open($filePath);
14 |
15 | $zip->extractTo($this->tempPath);
16 |
17 | $zip->close();
18 |
19 | unset($zip);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/system/expressionengine/third_party/github_addon_installer/src/Installer/FileInstaller.php:
--------------------------------------------------------------------------------
1 | getBlob($file->sha);
12 |
13 | if (isset($data->content)) {
14 | $handle = fopen($destination, 'w');
15 |
16 | fwrite($handle, base64_decode($data->content));
17 |
18 | fclose($handle);
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/system/expressionengine/third_party/github_addon_installer/language/english/github_addon_installer_lang.php:
--------------------------------------------------------------------------------
1 |
5 | 'GitHub Addon Installer',
6 |
7 | 'github_addon_installer_module_description' =>
8 | 'Install and update addons with public git repositories.',
9 |
10 | // Start inserting custom language keys/values here
11 |
12 | 'incomplete_repo_definition' => 'The definition for this repo is incomplete.',
13 | 'branch_not_found' => 'Branch %s not found',
14 | 'repo_not_found' => 'Repo %s not found',
15 | 'fetch_dir_doesnt_exist' => 'The directory %s does not exist.',
16 | 'path_third_not_writable' => 'The third_party/ cannot be written to.',
17 | 'temp_dir_not_writable' => 'The temp directory cannot be written to.',
18 | 'cant_write_file' => 'The installer could not write the file %s.',
19 | 'successfully_installed' => 'Successfully installed %s.',
20 | 'invalid_addon' => 'No definition found for %s.',
21 | 'addon_name' => 'Addon',
22 | 'addon_status' => 'Status',
23 | 'addon_install' => 'Install',
24 | 'addon_not_installed' => 'Not Installed',
25 | 'addon_installed' => 'Installed',
26 | 'addon_installing' => 'Installing...',
27 | 'addon_reinstall' => 'Re-install/Update',
28 | 'addon_update' => 'Update Available',// %s',
29 | 'addon_author' => 'Author',
30 | 'addon_branch' => 'Branch',
31 | 'addon_stars' => 'Stars',
32 | 'addon_github_url' => 'GitHub URL',
33 | 'filter_by_status' => 'Filter By Status',
34 | 'filter_by_author' => 'Filter By Author',
35 | 'keyword' => 'Keyword',
36 | 'filter_by_keyword' => 'Filter By Keyword',
37 | 'filter' => 'Filter',
38 | 'no_filter' => 'No Filter',
39 | );
40 |
41 | /* End of file lang.github_addon_installer.php */
42 | /* Location: /system/expressionengine/third_party/github_addon_installer/language/english/lang.github_addon_installer.php */
43 |
--------------------------------------------------------------------------------
/system/expressionengine/third_party/github_addon_installer/views/index.php:
--------------------------------------------------------------------------------
1 |
24 |
25 |
26 |
27 |
28 | | =lang('addon_name')?> |
29 | =lang('addon_github_url')?> |
30 | =lang('addon_branch')?> |
31 | =lang('addon_author')?> |
32 | =lang('addon_stars')?> |
33 | =lang('addon_status')?> |
34 | |
35 |
36 |
37 |
38 |
39 |
40 | | =element('name', $addon)?> |
41 | =element('github_url', $addon)?> |
42 | =element('branch', $addon)?> |
43 | =element('author', $addon)?> |
44 | =element('stars', $addon)?> |
45 | =element('status', $addon)?> |
46 | =element('install', $addon)?> |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/system/expressionengine/third_party/github_addon_installer/src/Installer/AbstractZipInstaller.php:
--------------------------------------------------------------------------------
1 | tempPath.$repo->getSha().'.zip';
16 |
17 | if ( ! file_exists($filePath)) {
18 | $handle = fopen($filePath, 'w');
19 |
20 | fwrite($handle, $repo->getZipball());
21 |
22 | fclose($handle);
23 |
24 | $this->unzip($filePath);
25 | }
26 |
27 | //this is how github names the zipball, usually
28 | $shortSha = substr($repo->getSha(), 0, 7);
29 |
30 | $tempDir = $repo->getUser().'-'.$repo->getRepo().'-'.$shortSha;
31 |
32 | $files = array();
33 |
34 | //the sha numbering is off, else is a somewhat messy fallback
35 | if (! is_dir($this->tempPath.$tempDir)) {
36 | $tempDir = null;
37 |
38 | $iterator = new \DirectoryIterator($this->tempPath);
39 |
40 | foreach ($iterator as $file) {
41 | // does it start with this user/repo combo?
42 | if (! $file->isDot() && $file->isDir() && preg_match('/^'.preg_quote($repo->getUser()).'-'.preg_quote($repo->getRepo()).'-/', $file->getBasename())) {
43 | $tempDir = $file->getBasename();
44 | break;
45 | }
46 | }
47 | }
48 |
49 | if (is_null($tempDir)) {
50 | throw new \Exception(sprintf('Could not find unzipped contents for %s/%s in %s', $repo->getUser(), $repo->getRepo(), $this->tempPath));
51 | }
52 |
53 | $this->tempDir = $tempDir;
54 |
55 | parent::install($repo, $addonName, $addonPath, $themePath, $addFolder);
56 |
57 | unlink($this->tempPath.$repo->getSha().'.zip');
58 | }
59 |
60 | protected function copyFile(Repo $repo, $file, $destination)
61 | {
62 | rename($this->tempPath.$this->tempDir.'/'.$file->path, $destination);
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/system/expressionengine/third_party/github_addon_installer/upd.github_addon_installer.php:
--------------------------------------------------------------------------------
1 | 'Github_addon_installer',
40 | 'module_version' => $this->version,
41 | 'has_cp_backend' => "y",
42 | 'has_publish_fields' => 'n'
43 | );
44 |
45 | ee()->db->insert('modules', $mod_data);
46 |
47 | // ee()->load->dbforge();
48 | /**
49 | * In order to setup your custom tables, uncomment the line above, and
50 | * start adding them below!
51 | */
52 |
53 | return TRUE;
54 | }
55 |
56 | // ----------------------------------------------------------------
57 |
58 | /**
59 | * Uninstall
60 | *
61 | * @return boolean TRUE
62 | */
63 | public function uninstall()
64 | {
65 | $mod_id = ee()->db->select('module_id')
66 | ->get_where('modules', array(
67 | 'module_name' => 'Github_addon_installer'
68 | ))->row('module_id');
69 |
70 | ee()->db->where('module_id', $mod_id)
71 | ->delete('module_member_groups');
72 |
73 | ee()->db->where('module_name', 'Github_addon_installer')
74 | ->delete('modules');
75 |
76 | // ee()->load->dbforge();
77 | // Delete your custom tables & any ACT rows
78 | // you have in the actions table
79 |
80 | return TRUE;
81 | }
82 |
83 | // ----------------------------------------------------------------
84 |
85 | /**
86 | * Module Updater
87 | *
88 | * @return boolean TRUE
89 | */
90 | public function update($current = '')
91 | {
92 | // If you have updates, drop 'em in here.
93 | return TRUE;
94 | }
95 |
96 | }
97 | /* End of file upd.github_addon_installer.php */
98 | /* Location: /system/expressionengine/third_party/github_addon_installer/upd.github_addon_installer.php */
--------------------------------------------------------------------------------
/system/expressionengine/third_party/github_addon_installer/src/Application.php:
--------------------------------------------------------------------------------
1 | manifest = json_decode($manifestContents, true);
36 |
37 | if (! $this->manifest) {
38 | throw new \Exception('Could not load the Github Addon Installer manifest.');
39 | }
40 |
41 | ksort($this->manifest);
42 |
43 | $this->api = new Api();
44 |
45 | $this->installer = Installer::create($thirdPartyPath, $themePath, $tempPath);
46 | }
47 |
48 | public function getApi()
49 | {
50 | return $this->api;
51 | }
52 |
53 | public function getInstaller()
54 | {
55 | return $this->installer;
56 | }
57 |
58 | public function getManifest()
59 | {
60 | return $this->manifest;
61 | }
62 |
63 | public function getRepo($addon, $branch = null)
64 | {
65 | if (! isset($this->manifest[$addon])) {
66 | throw new \Exception('Addon not found in manifest.');
67 | }
68 |
69 | if (! $branch) {
70 | $branch = isset($this->manifest[$addon]['branch']) ? isset($this->manifest[$addon]['branch']) : 'master';
71 | }
72 |
73 | return new Repo(
74 | $this->api,
75 | $this->manifest[$addon]['user'],
76 | $this->manifest[$addon]['repo'],
77 | $branch
78 | );
79 | }
80 |
81 | public function installAddon($addon, $branch = null)
82 | {
83 | return $this->installer->install(
84 | $this->getRepo($addon, $branch),
85 | $addon,
86 | isset($this->manifest[$addon]['addon_path']) ? $this->manifest[$addon]['addon_path'] : null,
87 | isset($this->manifest[$addon]['theme_path']) ? $this->manifest[$addon]['theme_path'] : null,
88 | isset($this->manifest[$addon]['add_folder']) ? $this->manifest[$addon]['add_folder'] : false
89 | );
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/system/expressionengine/third_party/github_addon_installer/src/Installer/Installer.php:
--------------------------------------------------------------------------------
1 | thirdPartyPath = $thirdPartyPath;
18 |
19 | $this->themePath = $themePath;
20 |
21 | $this->tempPath = $tempPath;
22 | }
23 |
24 | public static function create($thirdPartyPath, $themePath, $tempPath)
25 | {
26 | if (extension_loaded('zip')) {
27 | return new ZipArchiveInstaller($thirdPartyPath, $themePath, $tempPath);
28 | } elseif (shell_exec('which unzip')) {
29 | return new SystemUnzipInstaller($thirdPartyPath, $themePath, $tempPath);
30 | }
31 |
32 | return new FileInstaller($thirdPartyPath, $themePath, $tempPath);
33 | }
34 |
35 | abstract protected function copyFile(Repo $repo, $file, $destination);
36 |
37 | public function install(Repo $repo, $addonName, $addonPath = null, $themePath = null, $addFolder = false)
38 | {
39 | foreach ($repo->getFiles() as $file) {
40 | $path = $this->thirdPartyPath;
41 |
42 | $destination = $file->path;
43 |
44 | $proceed = false;
45 |
46 | if ($addonPath) {
47 | if (strncmp($destination, $addonPath, strlen($addonPath)) === 0) {
48 | $proceed = true;
49 |
50 | $destination = str_replace($addonPath, '', $destination);
51 |
52 | if ($addFolder) {
53 | $destination = is_bool($addFolder) ? $addonName.'/'.$destination : $addFolder.'/'.$destination;
54 | }
55 | }
56 | }
57 |
58 | if ($proceed === false && $themePath) {
59 | if (strncmp($destination, $themePath, strlen($themePath)) === 0) {
60 | $proceed = true;
61 |
62 | $destination = str_replace($themePath, '', $destination);
63 |
64 | $path = $this->themePath;
65 | }
66 | }
67 |
68 | if (! $addonPath && $proceed === false && ! $repo->isFileIgnored($destination)) {
69 | $proceed = true;
70 |
71 | if ($addFolder) {
72 | $destination = is_bool($addFolder) ? $addonName.'/'.$destination : $addFolder.'/'.$destination;
73 | }
74 | }
75 |
76 | if ($proceed === false) {
77 | continue;
78 | }
79 |
80 | if (strpos($destination, '/') !== false) {
81 | $path = realpath($path);
82 |
83 | $dirs = explode('/', $destination);
84 |
85 | $path .= '/';
86 |
87 | $destination = array_pop($dirs);
88 |
89 | foreach ($dirs as $dir) {
90 | if (! is_dir($path.$dir)) {
91 | @mkdir($path.$dir, 0777);
92 | }
93 |
94 | $path .= $dir.'/';
95 | }
96 | }
97 |
98 | $destination = $path.$destination;
99 |
100 | if (! is_writable($path) || (file_exists($destination) && ! is_writable($destination))) {
101 | throw new \Exception(sprintf('Cannot write file %s', $destination));
102 | }
103 |
104 | $this->copyFile($repo, $file, $destination);
105 | }
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/README.markdown:
--------------------------------------------------------------------------------
1 | # GitHub Addon Installer for ExpressionEngine
2 |
3 | Install and update free EE addons found on Github.
4 |
5 | 
6 |
7 | ## About
8 |
9 | How it works: it downloads a zip file from Github to your temp dir and then it unzips it to your third_party/ folder. If the addon already exists (aka you are updating it), it will be overwritten. If the addon has an installer you will be redirected to the installer page. That's it, no other magic involved.
10 |
11 | This addon is not meant to be run on a production environment. You are encouraged to use this addon on local and/or staging environments only. Your third_party folder on your production environment should not be writable.
12 |
13 | I always use this locally on a version controlled repository, where I can easily roll back any changes.
14 |
15 | ## Installation
16 |
17 | * Copy the system/expressionengine/third_party/github_addon_installer/ folder to system/expressionengine/third_party/
18 | * Install the module
19 | * Make sure your system/expressionengine/cache/ and system/expressionengine/third_party/ (or your user-defined third_party) directories are writable
20 |
21 | ## Updating
22 |
23 | This addon does not use traditional version releases, but rather rolling releases, as new addons are added to and removed from the manifest. You are encouraged to use Github Addon Installer to update itself.
24 |
25 | ## Requirements
26 |
27 | * ExpressionEngine 2.6+
28 | * PHP 5.2+
29 | * *nix server (no Windows/IIS)
30 |
31 | ## Usage
32 |
33 | Go to Add-Ons > Modules > Github Addon Installer. You are shown an alphabetical list of all the eligible addons. You can filter this list by status (Installed or Not Installed) or by author. You can also type in keywords to quickly find an addon by name using a fuzzy search.
34 |
35 | Click the "Install" button to install an addon.
36 |
37 | ## Config
38 |
39 | If you wish to change your temp dir location, you can add this to your EE config file:
40 |
41 | $config['github_addon_installer_temp_path'] = '/path/to/dir/'; # default is system/expressionengine/cache/github_addon_installer/
42 |
43 | You can disable Github Addon Installer with a config item. This is useful for disabling in production environments.
44 |
45 | $config['github_addon_installer_disabled'] = $_SERVER['HTTP_HOST'] === 'my-production-site.com';
46 |
47 | ## Adding an Addon to the Manifest
48 |
49 | The list of eligible addons is stored in github_addon_installer/config/manifest.js. This file contains a JSON object. To add something to this list, fork this project, add repos to the list, and submit a pull request. The key of your manifest entry should be the short name of your add-on. The manifest is indented with two spaces, please adhere to that. Please remember that unlike PHP, you cannot leave a trailing comma in a JSON array/object.
50 |
51 | Manifest entry examples:
52 |
53 | If your repo directory structure is like:
54 |
55 |
56 | └── my_addon
57 | └── pi.my_addon.php
58 |
59 | Manifest Entry:
60 |
61 | "my_addon":{
62 | "user": "username",
63 | "repo": "reponame"
64 | }
65 |
66 | If your repo directory structure is like this (just the bare addon file in the root of the repo):
67 |
68 |
69 | └── pi.my_addon.php
70 |
71 | Manifest Entry:
72 |
73 | "my_addon": {
74 | "user": "username",
75 | "repo": "reponame",
76 | "add_folder": true,
77 | "stars": 10
78 | }
79 |
80 | If your repo directory structure is like:
81 |
82 |
83 | └── system
84 | └── expressionengine
85 | └── third_party
86 | └── my_addon
87 | └── pi.my_addon.php
88 |
89 | Manifest Entry:
90 |
91 | "my_addon": {
92 | "user": "username",
93 | "repo": "reponame",
94 | "addon_path": "system/expressionengine/third_party/",
95 | "stars": 10
96 | }
97 |
98 | If your repo directory structure is like:
99 |
100 |
101 | ├── ee2
102 | │ └── third_party
103 | │ └── my_addon
104 | │ └── pi.my_addon.php
105 | └── themes
106 | └── third_party
107 | └── my_addon
108 | └── my_addon.css
109 |
110 | Manifest Entry:
111 |
112 | "my_addon": {
113 | "user": "username",
114 | "repo": "reponame",
115 | "addon_path": "ee2/third_party/",
116 | "theme_path": "themes/third_party/"
117 | }
118 |
--------------------------------------------------------------------------------
/system/expressionengine/third_party/github_addon_installer/src/Repo.php:
--------------------------------------------------------------------------------
1 | api = $api;
74 |
75 | $this->user = $user;
76 | $this->repo = $repo;
77 | $this->branch = $branch;
78 |
79 | $data = $this->api->fetchJson('repos', $this->user, $this->repo, 'branches');
80 |
81 | if (empty($data)) {
82 | throw new \Exception(sprintf('Repo %s not found', 'https://github.com/'.$this->user.'/'.$this->repo, $this->repo));
83 | }
84 |
85 | $branch = null;
86 |
87 | foreach ($data as $row) {
88 | if ($row->name === $this->branch) {
89 | $branch = $row;
90 | break;
91 | }
92 | }
93 |
94 | if (! $branch) {
95 | throw new \Exception(sprintf('Branch %s not found', 'https://github.com/'.$this->user.'/'.$this->repo.'/tree/'.$this->branch, $this->branch));
96 | }
97 |
98 | $this->sha = $branch->commit->sha;
99 |
100 | /* @TODO use this later */
101 | /*
102 | $data = $this->api->fetchJson('repos', 'show', $this->user, $this->repo, 'tags');
103 |
104 | $this->tags = (isset($data->tags)) ? (array) $data->tags : FALSE;
105 | */
106 |
107 | $data = $this->api->fetchJson('repos', $this->user, $this->repo);
108 |
109 | if (is_object($data)) {
110 | foreach ((array) $data as $property => $value) {
111 | $this->$property = $value;
112 | }
113 | }
114 | }
115 |
116 | public function getFiles()
117 | {
118 | $files = array();
119 |
120 | $data = $this->api->fetchJson('repos', $this->user, $this->repo, 'git', 'trees', $this->sha, array('recursive' => true));
121 |
122 | if (isset($data->tree)) {
123 | foreach ($data->tree as $file) {
124 | if ($file->type !== 'tree') {
125 | $files[] = $file;
126 | }
127 | }
128 | }
129 |
130 | return $files;
131 | }
132 |
133 | public function getZipball()
134 | {
135 | return $this->api->fetchProgress('repos', $this->user, $this->repo, 'zipball', $this->branch);
136 | }
137 |
138 | public function getBlob($sha)
139 | {
140 | return $this->api->fetchJson('repos', $this->user, $this->repo, 'git', 'blobs', $sha);
141 | }
142 |
143 | public function getTrees($recursive = false)
144 | {
145 | return $this->api->fetchJson('repos', $this->user, $this->repo, 'git', 'trees', $this->sha, array('recursive' => $recursive));
146 | }
147 |
148 | public function getUser()
149 | {
150 | return $this->user;
151 | }
152 |
153 | public function getRepo()
154 | {
155 | return $this->repo;
156 | }
157 |
158 | public function getBranch()
159 | {
160 | return $this->branch;
161 | }
162 |
163 | public function getSha()
164 | {
165 | return $this->sha;
166 | }
167 |
168 | public function isFileIgnored($filename)
169 | {
170 | foreach ($this->ignore as $ignore) {
171 | if (strncasecmp($filename, $ignore, strlen($ignore)) === 0) {
172 | return true;
173 | }
174 | }
175 |
176 | return false;
177 | }
178 | }
179 |
--------------------------------------------------------------------------------
/system/expressionengine/third_party/github_addon_installer/src/Api.php:
--------------------------------------------------------------------------------
1 | 'EE Github Addon Installer',
13 | CURLOPT_RETURNTRANSFER => true,
14 | CURLOPT_FOLLOWLOCATION => true,
15 | CURLOPT_SSL_VERIFYPEER => false,//@TODO remove this
16 | );
17 |
18 | protected $basicAuthUsername;
19 |
20 | protected $basicAuthPassword;
21 |
22 | protected $output;
23 |
24 | protected $progress;
25 |
26 | protected $progressBar;
27 |
28 | public function setBasicAuth($username, $password)
29 | {
30 | $this->basicAuthUsername = $username;
31 | $this->basicAuthPassword = $password;
32 |
33 | return $this;
34 | }
35 |
36 | public function setOutput(OutputInterface $output)
37 | {
38 | $this->output = $output;
39 | }
40 |
41 | public function setProgressHelper(ProgressHelper $progress)
42 | {
43 | $this->progress = $progress;
44 | }
45 |
46 | public function setProgressBar(ProgressBar $progressBar)
47 | {
48 | $this->progressBar = $progressBar;
49 | }
50 |
51 | protected function buildUrl(array $segments, array $queryString = null)
52 | {
53 | $url = 'https://api.github.com/'.implode('/', $segments);
54 |
55 | if ($queryString) {
56 | $url .= '?'.http_build_query($queryString);
57 | }
58 |
59 | return $url;
60 | }
61 |
62 | /**
63 | * Fetch raw data from a github url
64 | *
65 | * @param string $segment,... unlimited number of segments
66 | * @param array $params an optional array of query string params
67 | * @return mixed
68 | */
69 | public function fetch()
70 | {
71 | $segments = func_get_args();
72 |
73 | $queryString = is_array(end($segments)) ? array_pop($segments) : null;
74 |
75 | $url = $this->buildUrl($segments, $queryString);
76 |
77 | return $this->curl($url);
78 | }
79 |
80 | public function fetchProgress()
81 | {
82 | $segments = func_get_args();
83 |
84 | $queryString = is_array(end($segments)) ? array_pop($segments) : null;
85 |
86 | $url = $this->buildUrl($segments, $queryString);
87 |
88 | $progress = $this->progress ? $this->progress : $this->progressBar;
89 |
90 | if ($progress && $this->output) {
91 | $output = $this->output;
92 | $current = 0;
93 |
94 | if ($progress instanceof ProgressBar) {
95 | $progress->start(100);
96 | } else {
97 | $progress->start($output, 100);
98 | }
99 |
100 | $return = $this->curl($url, function($downloadSize, $downloadedSize) use ($progress, $output) {
101 | $current = $downloadSize !== 0 ? round($downloadedSize / $downloadSize * 100) : 0;
102 |
103 | if ($progress instanceof ProgressBar) {
104 | $progress->setProgress($current);
105 | } else {
106 | $progress->setCurrent($current);
107 | }
108 | });
109 |
110 | $progress->finish();
111 |
112 | return $return;
113 | }
114 |
115 | return $this->curl($url);
116 | }
117 |
118 | /**
119 | * Fetch json data from the github v3 api
120 | *
121 | * @param string $segment,... unlimited number of segments
122 | * @param array $params an optional array of query string params
123 | * @return mixed|null
124 | */
125 | public function fetchJson()
126 | {
127 | $segments = func_get_args();
128 |
129 | $queryString = is_array(end($segments)) ? array_pop($segments) : null;
130 |
131 | $url = $this->buildUrl($segments, $queryString);
132 |
133 | $data = $this->curl($url);
134 |
135 | return ($data) ? @json_decode($data) : null;
136 | }
137 |
138 | protected function curl($url, \Closure $progressCallback = null)
139 | {
140 | $ch = curl_init($url);
141 |
142 | curl_setopt_array($ch, $this->curlOptions);
143 |
144 | if ($this->basicAuthUsername && $this->basicAuthPassword) {
145 | curl_setopt($ch, CURLOPT_USERPWD, $this->basicAuthUsername.':'.$this->basicAuthPassword);
146 | }
147 |
148 | if (is_callable($progressCallback)) {
149 | curl_setopt($ch, CURLOPT_NOPROGRESS, false);
150 | curl_setopt($ch, CURLOPT_PROGRESSFUNCTION, $progressCallback);
151 | }
152 |
153 | $data = curl_exec($ch);
154 |
155 | $status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
156 |
157 | if ($status === 403) {
158 | $json = json_decode($data);
159 |
160 | throw new \Exception($json->message);
161 | } elseif ($status !== 200) {
162 | $data = false;
163 | }
164 |
165 | curl_close($ch);
166 |
167 | return $data;
168 | }
169 | }
170 |
--------------------------------------------------------------------------------
/system/expressionengine/third_party/github_addon_installer/mcp.github_addon_installer.php:
--------------------------------------------------------------------------------
1 | config->item('github_addon_installer_disabled'))
49 | {
50 | show_error(lang('unauthorized_access'));
51 | }
52 |
53 | $this->base = BASE.AMP.'C=addons_modules'.AMP.'M=show_module_cp'.AMP.'module=github_addon_installer';
54 |
55 | // no autoloader
56 | if (version_compare(APP_VER, '2.9', '<'))
57 | {
58 | require_once PATH_THIRD.'github_addon_installer/src/Application.php';
59 | require_once PATH_THIRD.'github_addon_installer/src/Api.php';
60 | require_once PATH_THIRD.'github_addon_installer/src/Repo.php';
61 | require_once PATH_THIRD.'github_addon_installer/src/Installer/Installer.php';
62 | require_once PATH_THIRD.'github_addon_installer/src/Installer/AbstractZipInstaller.php';
63 | require_once PATH_THIRD.'github_addon_installer/src/Installer/FileInstaller.php';
64 | require_once PATH_THIRD.'github_addon_installer/src/Installer/SystemUnzipInstaller.php';
65 | require_once PATH_THIRD.'github_addon_installer/src/Installer/ZipArchiveInstaller.php';
66 | }
67 | else
68 | {
69 | if ( ! class_exists('Autoloader')) {
70 | require_once APPPATH.'../EllisLab/ExpressionEngine/Core/Autoloader.php';
71 | }
72 |
73 | Autoloader::getInstance()->addPrefix('eecli\\GithubAddonInstaller', PATH_THIRD.'github_addon_installer/src/');
74 | }
75 |
76 | $temp_path = APPPATH.'cache/github_addon_installer/';
77 |
78 | if (! is_dir($temp_path)) {
79 | mkdir($temp_path);
80 | }
81 |
82 | $this->application = new Application(PATH_THIRD, PATH_THIRD_THEMES, $temp_path);
83 |
84 | $this->manifest = $this->application->getManifest();
85 | }
86 |
87 | public function index()
88 | {
89 | ee()->view->cp_page_title = ee()->lang->line('github_addon_installer_module_name');
90 |
91 | ee()->load->library('addons');
92 |
93 | $vars = array();
94 | $vars['addons'] = array();
95 |
96 | foreach ($this->manifest as $addon => $params)
97 | {
98 | $name = (isset($params['name'])) ? $params['name'] : $addon;
99 | $description = (isset($params['description'])) ? br().$params['description'] : '';
100 | //$status = (in_array($addon, $current_addons)) ? lang('addon_installed') : lang('addon_not_installed');
101 | $status = (ee()->addons->is_package($addon)) ? lang('addon_installed') : lang('addon_not_installed');
102 |
103 | //$install = (in_array($addon, $current_addons)) ? lang('addon_install') : lang('addon_reinstall');
104 |
105 | $url = 'https://github.com/'.$params['user'].'/'.$params['repo'];
106 |
107 | if (isset($params['branch']))
108 | {
109 | $url .= '/tree/'.$params['branch'];
110 | }
111 |
112 | $branch = isset($params['branch']) ? $params['branch'] : 'master';
113 |
114 | $vars['addons'][] = array(
115 | 'name' => $name,//.$description,
116 | 'github_url' => anchor($url, $url, 'rel="external"'),
117 | 'branch' => form_input("", $branch, 'class="branch '.$addon.'-branch"'),
118 | 'author' => $params['user'],
119 | 'stars' => empty($params['stars']) ? '0' : (string) $params['stars'],
120 | 'status' => $status,
121 | 'install' => anchor($this->base.AMP.'method=install'.AMP.'addon='.$addon, lang('addon_install'), 'data-addon="'.$addon.'"')
122 | );
123 | }
124 |
125 | ee()->load->library('javascript');
126 |
127 | ee()->javascript->output('
128 | $("table#addons").tablesorter({
129 | headers: {1: {sorter: false}, 6: {sorter: false}},
130 | widgets: ["zebra"]
131 | });
132 | $("table#addons tr td.addon_install a").click(function(){
133 | var a = $(this);
134 | var tds = a.parents("tr").children("td");
135 | var statusTd = a.parents("td").siblings("td.addon_status");
136 | var originalColor = tds.css("backgroundColor");
137 | var originalText = a.text();
138 | tds.animate({backgroundColor:"#d0d0d0"});
139 | a.html("'.lang('addon_installing').'");
140 | $.get(
141 | $(this).attr("href"),
142 | {branch: $("."+$(this).data("addon")+"-branch").val()},
143 | function(data){
144 | tds.animate({backgroundColor:originalColor});
145 | a.html(originalText);
146 | if (data.message_success) {
147 | if (data.redirect) {
148 | window.location.href = data.redirect;
149 | return;
150 | }
151 | statusTd.html("'.lang('addon_installed').'");
152 | $.ee_notice(data.message_success, {"type":"success"});
153 | } else {
154 | $.ee_notice(data.message_failure, {"type":"error"});
155 | //td.animate({backgroundColor:"red"});
156 | }
157 | },
158 | "json"
159 | );
160 | return false;
161 | });
162 | $("select#addonFilter").change(function(){
163 | var filter = $(this).val();
164 | $("#addonKeyword").hide();
165 | $("table#addons tbody tr").show();
166 | if (filter == "") {
167 | $("table#addons tbody tr").show();
168 | } else if (filter == "keyword") {
169 | $("#addonKeyword").val("").show().focus();
170 | } else {
171 | $("td."+$(this.options[this.selectedIndex]).parents("optgroup").data("filter")).filter(function(){
172 | return $(this).text() != filter;
173 | }).parents("tr").hide();
174 | }
175 | });
176 | //add all values from the table to filter
177 | $("select#addonFilter optgroup").each(function(index, element){
178 | var values = [];
179 | $("td."+$(this).data("filter")).each(function(){
180 | if ($.inArray($(this).text(), values) === -1) {
181 | values.push($(this).text());
182 | }
183 | });
184 | //case insensitive sort
185 | values.sort(function(a, b){
186 | a = a.toLowerCase();
187 | b = b.toLowerCase();
188 | if (a > b) {
189 | return 1;
190 | }
191 | if (a < b) {
192 | return -1;
193 | }
194 | return 0;
195 | });
196 | for (i in values) {
197 | $(element).append($("