Completed
Pull Request — master (#489)
by Helpful
03:34
created
code/model/DNData.php 3 patches
Indentation   +220 added lines, -220 removed lines patch added patch discarded remove patch
@@ -6,224 +6,224 @@
 block discarded – undo
6 6
 class DNData extends ViewableData
7 7
 {
8 8
 
9
-    /**
10
-     * Path where the environment configurations can be found.
11
-     *
12
-     * @var string
13
-     */
14
-    protected $environmentDir = '';
15
-
16
-    /**
17
-     * Path where the keys are stored.
18
-     *
19
-     * @var string
20
-     */
21
-    protected $keyDir = '';
22
-
23
-    /**
24
-     * Path where data transfers are stored.
25
-     * Needs to be relative to webroot, and start with assets/
26
-     * since all files are also referenced in the SilverStripe database
27
-     * through {@link File}.
28
-     *
29
-     * @var string
30
-     */
31
-    protected $dataTransferDir = '';
32
-
33
-    /**
34
-     * If set, this provides an alternate user to the current one
35
-     * executing the Git shell commands. e.g. if this is set to
36
-     * a user called "composer", any Git commands that Deploynaut
37
-     * will perform will be run as "sudo -u composer git ..."
38
-     *
39
-     * @var string|null
40
-     */
41
-    protected $gitUser = null;
42
-
43
-    /**
44
-     * Gets the DNData singleton
45
-     *
46
-     * @return DNData
47
-     */
48
-    public static function inst()
49
-    {
50
-        return Injector::inst()->get('DNData');
51
-    }
52
-
53
-    public function __construct($environmentDir = null, $keyDir = null, $dataTransferDir = null, $gitUser = null)
54
-    {
55
-        parent::__construct();
56
-
57
-        // Better to use injector to set these
58
-        if (func_num_args() == 0) {
59
-            return;
60
-        }
61
-        Deprecation::notice(
62
-            '1.2.0',
63
-            "Don't construct DNData with parameters. Assign settings via properties instead"
64
-        );
65
-        $this->setEnvironmentDir($environmentDir);
66
-        $this->setKeyDir($keyDir);
67
-        $this->setDataTransferDir($dataTransferDir);
68
-        $this->setGitUser($gitUser);
69
-    }
70
-
71
-    /**
72
-     * Get the directory environment code is saved
73
-     *
74
-     * @return string
75
-     */
76
-    public function getEnvironmentDir()
77
-    {
78
-        return $this->environmentDir;
79
-    }
80
-
81
-    /**
82
-     * Set the directory environment code is saved
83
-     *
84
-     * @param string $environmentDir
85
-     */
86
-    public function setEnvironmentDir($environmentDir)
87
-    {
88
-        if ($environmentDir[0] != "/") {
89
-            $environmentDir = BASE_PATH . '/' . $environmentDir;
90
-        }
91
-        $this->environmentDir = realpath($environmentDir) ?: $environmentDir;
92
-    }
93
-
94
-    /**
95
-     * Get the directory where ssh are stored
96
-     *
97
-     * @return string
98
-     */
99
-    public function getKeyDir()
100
-    {
101
-        return $this->keyDir;
102
-    }
103
-
104
-    /**
105
-     * Set the directory where ssh are stored
106
-     *
107
-     * @param string $keyDir
108
-     */
109
-    public function setKeyDir($keyDir)
110
-    {
111
-        if ($keyDir[0] != "/") {
112
-            $keyDir = BASE_PATH . '/' . $keyDir;
113
-        }
114
-        $this->keyDir = realpath($keyDir) ?: $keyDir;
115
-    }
116
-
117
-    /**
118
-     * Get the username that git commands should be run as
119
-     *
120
-     * @return string
121
-     */
122
-    public function getGitUser()
123
-    {
124
-        return $this->gitUser;
125
-    }
126
-
127
-    /**
128
-     * Get the username that git commands should be run as
129
-     *
130
-     * @param string $user
131
-     */
132
-    public function setGitUser($user)
133
-    {
134
-        $this->gitUser = $user;
135
-    }
136
-
137
-    /**
138
-     * Get the directory where data transfers should be saved
139
-     *
140
-     * @return string
141
-     */
142
-    public function getDataTransferDir()
143
-    {
144
-        return $this->dataTransferDir;
145
-    }
146
-
147
-    /**
148
-     * Set the directory where data transfers should be saved
149
-     *
150
-     * This should either be an absolute path (beginning with /) or a path that can
151
-     * be appended to the web root safely
152
-     *
153
-     * @param string $transferDir
154
-     */
155
-    public function setDataTransferDir($transferDir)
156
-    {
157
-        if ($transferDir[0] != "/") {
158
-            $transferDir = BASE_PATH . '/' . $transferDir;
159
-        }
160
-        if (strpos($transferDir, ASSETS_PATH) === false) {
161
-            throw new LogicException(sprintf(
162
-                'DNData::dataTransferDir needs to be located within <webroot>assets/ (location: %s)',
163
-                $transferDir
164
-            ));
165
-        }
166
-        $this->dataTransferDir = realpath($transferDir) ?: $transferDir;
167
-    }
168
-
169
-    /**
170
-     * Provide a list of all projects.
171
-     * @return DataList
172
-     */
173
-    public function DNProjectList()
174
-    {
175
-        return DNProject::get();
176
-    }
177
-
178
-    /**
179
-     * Grabs a list of projects from the env directory. The projects
180
-     * in the builds directory alone will not be picked up.
181
-     * Returns an array of paths
182
-     *
183
-     * @return array
184
-     * @throws Exception
185
-     */
186
-    public function getProjectPaths()
187
-    {
188
-        $paths = array();
189
-        if (!file_exists($this->getEnvironmentDir())) {
190
-            $eMessage = 'The environment directory ' . $this->getEnvironmentDir() . ' doesn\'t exist. Create it '
191
-            . 'first and add some projects to it.';
192
-            throw new Exception($eMessage);
193
-        }
194
-        foreach (scandir($this->getEnvironmentDir()) as $project) {
195
-            // Exlcude dot-prefixed directories (.git was getting in the way)
196
-            if (preg_match('/^[^\.]/', $project)) {
197
-                $path = $this->getEnvironmentDir() . '/' . $project;
198
-                if (is_dir($path) && $project != '.' && $project != '..') {
199
-                    $paths[] = $project;
200
-                }
201
-            }
202
-        }
203
-        sort($paths);
204
-        return array_values($paths);
205
-    }
206
-
207
-    /**
208
-     * Scan the directory and enumerate all envs founds within.
209
-     * Returns an array of paths
210
-     */
211
-    public function getEnvironmentPaths($project)
212
-    {
213
-        $baseDir = $this->getEnvironmentDir() . '/' . $project;
214
-
215
-        $paths = array();
216
-        if (!file_exists($baseDir)) {
217
-            throw new Exception('Environment directory ' . $baseDir . ' doesn\'t exist. Create it first.');
218
-        }
219
-        // Search the directory for config files.
220
-        foreach (scandir($baseDir) as $environmentFile) {
221
-            if (preg_match('/\.rb$/', $environmentFile)) {
222
-                // Config found, wrap it into an object.
223
-                $paths[] = "$baseDir/$environmentFile";
224
-            }
225
-        }
226
-        sort($paths);
227
-        return array_values($paths);
228
-    }
9
+	/**
10
+	 * Path where the environment configurations can be found.
11
+	 *
12
+	 * @var string
13
+	 */
14
+	protected $environmentDir = '';
15
+
16
+	/**
17
+	 * Path where the keys are stored.
18
+	 *
19
+	 * @var string
20
+	 */
21
+	protected $keyDir = '';
22
+
23
+	/**
24
+	 * Path where data transfers are stored.
25
+	 * Needs to be relative to webroot, and start with assets/
26
+	 * since all files are also referenced in the SilverStripe database
27
+	 * through {@link File}.
28
+	 *
29
+	 * @var string
30
+	 */
31
+	protected $dataTransferDir = '';
32
+
33
+	/**
34
+	 * If set, this provides an alternate user to the current one
35
+	 * executing the Git shell commands. e.g. if this is set to
36
+	 * a user called "composer", any Git commands that Deploynaut
37
+	 * will perform will be run as "sudo -u composer git ..."
38
+	 *
39
+	 * @var string|null
40
+	 */
41
+	protected $gitUser = null;
42
+
43
+	/**
44
+	 * Gets the DNData singleton
45
+	 *
46
+	 * @return DNData
47
+	 */
48
+	public static function inst()
49
+	{
50
+		return Injector::inst()->get('DNData');
51
+	}
52
+
53
+	public function __construct($environmentDir = null, $keyDir = null, $dataTransferDir = null, $gitUser = null)
54
+	{
55
+		parent::__construct();
56
+
57
+		// Better to use injector to set these
58
+		if (func_num_args() == 0) {
59
+			return;
60
+		}
61
+		Deprecation::notice(
62
+			'1.2.0',
63
+			"Don't construct DNData with parameters. Assign settings via properties instead"
64
+		);
65
+		$this->setEnvironmentDir($environmentDir);
66
+		$this->setKeyDir($keyDir);
67
+		$this->setDataTransferDir($dataTransferDir);
68
+		$this->setGitUser($gitUser);
69
+	}
70
+
71
+	/**
72
+	 * Get the directory environment code is saved
73
+	 *
74
+	 * @return string
75
+	 */
76
+	public function getEnvironmentDir()
77
+	{
78
+		return $this->environmentDir;
79
+	}
80
+
81
+	/**
82
+	 * Set the directory environment code is saved
83
+	 *
84
+	 * @param string $environmentDir
85
+	 */
86
+	public function setEnvironmentDir($environmentDir)
87
+	{
88
+		if ($environmentDir[0] != "/") {
89
+			$environmentDir = BASE_PATH . '/' . $environmentDir;
90
+		}
91
+		$this->environmentDir = realpath($environmentDir) ?: $environmentDir;
92
+	}
93
+
94
+	/**
95
+	 * Get the directory where ssh are stored
96
+	 *
97
+	 * @return string
98
+	 */
99
+	public function getKeyDir()
100
+	{
101
+		return $this->keyDir;
102
+	}
103
+
104
+	/**
105
+	 * Set the directory where ssh are stored
106
+	 *
107
+	 * @param string $keyDir
108
+	 */
109
+	public function setKeyDir($keyDir)
110
+	{
111
+		if ($keyDir[0] != "/") {
112
+			$keyDir = BASE_PATH . '/' . $keyDir;
113
+		}
114
+		$this->keyDir = realpath($keyDir) ?: $keyDir;
115
+	}
116
+
117
+	/**
118
+	 * Get the username that git commands should be run as
119
+	 *
120
+	 * @return string
121
+	 */
122
+	public function getGitUser()
123
+	{
124
+		return $this->gitUser;
125
+	}
126
+
127
+	/**
128
+	 * Get the username that git commands should be run as
129
+	 *
130
+	 * @param string $user
131
+	 */
132
+	public function setGitUser($user)
133
+	{
134
+		$this->gitUser = $user;
135
+	}
136
+
137
+	/**
138
+	 * Get the directory where data transfers should be saved
139
+	 *
140
+	 * @return string
141
+	 */
142
+	public function getDataTransferDir()
143
+	{
144
+		return $this->dataTransferDir;
145
+	}
146
+
147
+	/**
148
+	 * Set the directory where data transfers should be saved
149
+	 *
150
+	 * This should either be an absolute path (beginning with /) or a path that can
151
+	 * be appended to the web root safely
152
+	 *
153
+	 * @param string $transferDir
154
+	 */
155
+	public function setDataTransferDir($transferDir)
156
+	{
157
+		if ($transferDir[0] != "/") {
158
+			$transferDir = BASE_PATH . '/' . $transferDir;
159
+		}
160
+		if (strpos($transferDir, ASSETS_PATH) === false) {
161
+			throw new LogicException(sprintf(
162
+				'DNData::dataTransferDir needs to be located within <webroot>assets/ (location: %s)',
163
+				$transferDir
164
+			));
165
+		}
166
+		$this->dataTransferDir = realpath($transferDir) ?: $transferDir;
167
+	}
168
+
169
+	/**
170
+	 * Provide a list of all projects.
171
+	 * @return DataList
172
+	 */
173
+	public function DNProjectList()
174
+	{
175
+		return DNProject::get();
176
+	}
177
+
178
+	/**
179
+	 * Grabs a list of projects from the env directory. The projects
180
+	 * in the builds directory alone will not be picked up.
181
+	 * Returns an array of paths
182
+	 *
183
+	 * @return array
184
+	 * @throws Exception
185
+	 */
186
+	public function getProjectPaths()
187
+	{
188
+		$paths = array();
189
+		if (!file_exists($this->getEnvironmentDir())) {
190
+			$eMessage = 'The environment directory ' . $this->getEnvironmentDir() . ' doesn\'t exist. Create it '
191
+			. 'first and add some projects to it.';
192
+			throw new Exception($eMessage);
193
+		}
194
+		foreach (scandir($this->getEnvironmentDir()) as $project) {
195
+			// Exlcude dot-prefixed directories (.git was getting in the way)
196
+			if (preg_match('/^[^\.]/', $project)) {
197
+				$path = $this->getEnvironmentDir() . '/' . $project;
198
+				if (is_dir($path) && $project != '.' && $project != '..') {
199
+					$paths[] = $project;
200
+				}
201
+			}
202
+		}
203
+		sort($paths);
204
+		return array_values($paths);
205
+	}
206
+
207
+	/**
208
+	 * Scan the directory and enumerate all envs founds within.
209
+	 * Returns an array of paths
210
+	 */
211
+	public function getEnvironmentPaths($project)
212
+	{
213
+		$baseDir = $this->getEnvironmentDir() . '/' . $project;
214
+
215
+		$paths = array();
216
+		if (!file_exists($baseDir)) {
217
+			throw new Exception('Environment directory ' . $baseDir . ' doesn\'t exist. Create it first.');
218
+		}
219
+		// Search the directory for config files.
220
+		foreach (scandir($baseDir) as $environmentFile) {
221
+			if (preg_match('/\.rb$/', $environmentFile)) {
222
+				// Config found, wrap it into an object.
223
+				$paths[] = "$baseDir/$environmentFile";
224
+			}
225
+		}
226
+		sort($paths);
227
+		return array_values($paths);
228
+	}
229 229
 }
Please login to merge, or discard this patch.
Spacing   +12 added lines, -12 removed lines patch added patch discarded remove patch
@@ -55,7 +55,7 @@  discard block
 block discarded – undo
55 55
         parent::__construct();
56 56
 
57 57
         // Better to use injector to set these
58
-        if (func_num_args() == 0) {
58
+        if(func_num_args() == 0) {
59 59
             return;
60 60
         }
61 61
         Deprecation::notice(
@@ -85,7 +85,7 @@  discard block
 block discarded – undo
85 85
      */
86 86
     public function setEnvironmentDir($environmentDir)
87 87
     {
88
-        if ($environmentDir[0] != "/") {
88
+        if($environmentDir[0] != "/") {
89 89
             $environmentDir = BASE_PATH . '/' . $environmentDir;
90 90
         }
91 91
         $this->environmentDir = realpath($environmentDir) ?: $environmentDir;
@@ -108,7 +108,7 @@  discard block
 block discarded – undo
108 108
      */
109 109
     public function setKeyDir($keyDir)
110 110
     {
111
-        if ($keyDir[0] != "/") {
111
+        if($keyDir[0] != "/") {
112 112
             $keyDir = BASE_PATH . '/' . $keyDir;
113 113
         }
114 114
         $this->keyDir = realpath($keyDir) ?: $keyDir;
@@ -154,10 +154,10 @@  discard block
 block discarded – undo
154 154
      */
155 155
     public function setDataTransferDir($transferDir)
156 156
     {
157
-        if ($transferDir[0] != "/") {
157
+        if($transferDir[0] != "/") {
158 158
             $transferDir = BASE_PATH . '/' . $transferDir;
159 159
         }
160
-        if (strpos($transferDir, ASSETS_PATH) === false) {
160
+        if(strpos($transferDir, ASSETS_PATH) === false) {
161 161
             throw new LogicException(sprintf(
162 162
                 'DNData::dataTransferDir needs to be located within <webroot>assets/ (location: %s)',
163 163
                 $transferDir
@@ -186,16 +186,16 @@  discard block
 block discarded – undo
186 186
     public function getProjectPaths()
187 187
     {
188 188
         $paths = array();
189
-        if (!file_exists($this->getEnvironmentDir())) {
189
+        if(!file_exists($this->getEnvironmentDir())) {
190 190
             $eMessage = 'The environment directory ' . $this->getEnvironmentDir() . ' doesn\'t exist. Create it '
191 191
             . 'first and add some projects to it.';
192 192
             throw new Exception($eMessage);
193 193
         }
194
-        foreach (scandir($this->getEnvironmentDir()) as $project) {
194
+        foreach(scandir($this->getEnvironmentDir()) as $project) {
195 195
             // Exlcude dot-prefixed directories (.git was getting in the way)
196
-            if (preg_match('/^[^\.]/', $project)) {
196
+            if(preg_match('/^[^\.]/', $project)) {
197 197
                 $path = $this->getEnvironmentDir() . '/' . $project;
198
-                if (is_dir($path) && $project != '.' && $project != '..') {
198
+                if(is_dir($path) && $project != '.' && $project != '..') {
199 199
                     $paths[] = $project;
200 200
                 }
201 201
             }
@@ -213,12 +213,12 @@  discard block
 block discarded – undo
213 213
         $baseDir = $this->getEnvironmentDir() . '/' . $project;
214 214
 
215 215
         $paths = array();
216
-        if (!file_exists($baseDir)) {
216
+        if(!file_exists($baseDir)) {
217 217
             throw new Exception('Environment directory ' . $baseDir . ' doesn\'t exist. Create it first.');
218 218
         }
219 219
         // Search the directory for config files.
220
-        foreach (scandir($baseDir) as $environmentFile) {
221
-            if (preg_match('/\.rb$/', $environmentFile)) {
220
+        foreach(scandir($baseDir) as $environmentFile) {
221
+            if(preg_match('/\.rb$/', $environmentFile)) {
222 222
                 // Config found, wrap it into an object.
223 223
                 $paths[] = "$baseDir/$environmentFile";
224 224
             }
Please login to merge, or discard this patch.
Braces   +14 added lines, -28 removed lines patch added patch discarded remove patch
@@ -3,8 +3,7 @@  discard block
 block discarded – undo
3 3
 /**
4 4
  * Parent class for managing a set of Deploynaut data
5 5
  */
6
-class DNData extends ViewableData
7
-{
6
+class DNData extends ViewableData {
8 7
 
9 8
     /**
10 9
      * Path where the environment configurations can be found.
@@ -45,13 +44,11 @@  discard block
 block discarded – undo
45 44
      *
46 45
      * @return DNData
47 46
      */
48
-    public static function inst()
49
-    {
47
+    public static function inst() {
50 48
         return Injector::inst()->get('DNData');
51 49
     }
52 50
 
53
-    public function __construct($environmentDir = null, $keyDir = null, $dataTransferDir = null, $gitUser = null)
54
-    {
51
+    public function __construct($environmentDir = null, $keyDir = null, $dataTransferDir = null, $gitUser = null) {
55 52
         parent::__construct();
56 53
 
57 54
         // Better to use injector to set these
@@ -73,8 +70,7 @@  discard block
 block discarded – undo
73 70
      *
74 71
      * @return string
75 72
      */
76
-    public function getEnvironmentDir()
77
-    {
73
+    public function getEnvironmentDir() {
78 74
         return $this->environmentDir;
79 75
     }
80 76
 
@@ -83,8 +79,7 @@  discard block
 block discarded – undo
83 79
      *
84 80
      * @param string $environmentDir
85 81
      */
86
-    public function setEnvironmentDir($environmentDir)
87
-    {
82
+    public function setEnvironmentDir($environmentDir) {
88 83
         if ($environmentDir[0] != "/") {
89 84
             $environmentDir = BASE_PATH . '/' . $environmentDir;
90 85
         }
@@ -96,8 +91,7 @@  discard block
 block discarded – undo
96 91
      *
97 92
      * @return string
98 93
      */
99
-    public function getKeyDir()
100
-    {
94
+    public function getKeyDir() {
101 95
         return $this->keyDir;
102 96
     }
103 97
 
@@ -106,8 +100,7 @@  discard block
 block discarded – undo
106 100
      *
107 101
      * @param string $keyDir
108 102
      */
109
-    public function setKeyDir($keyDir)
110
-    {
103
+    public function setKeyDir($keyDir) {
111 104
         if ($keyDir[0] != "/") {
112 105
             $keyDir = BASE_PATH . '/' . $keyDir;
113 106
         }
@@ -119,8 +112,7 @@  discard block
 block discarded – undo
119 112
      *
120 113
      * @return string
121 114
      */
122
-    public function getGitUser()
123
-    {
115
+    public function getGitUser() {
124 116
         return $this->gitUser;
125 117
     }
126 118
 
@@ -129,8 +121,7 @@  discard block
 block discarded – undo
129 121
      *
130 122
      * @param string $user
131 123
      */
132
-    public function setGitUser($user)
133
-    {
124
+    public function setGitUser($user) {
134 125
         $this->gitUser = $user;
135 126
     }
136 127
 
@@ -139,8 +130,7 @@  discard block
 block discarded – undo
139 130
      *
140 131
      * @return string
141 132
      */
142
-    public function getDataTransferDir()
143
-    {
133
+    public function getDataTransferDir() {
144 134
         return $this->dataTransferDir;
145 135
     }
146 136
 
@@ -152,8 +142,7 @@  discard block
 block discarded – undo
152 142
      *
153 143
      * @param string $transferDir
154 144
      */
155
-    public function setDataTransferDir($transferDir)
156
-    {
145
+    public function setDataTransferDir($transferDir) {
157 146
         if ($transferDir[0] != "/") {
158 147
             $transferDir = BASE_PATH . '/' . $transferDir;
159 148
         }
@@ -170,8 +159,7 @@  discard block
 block discarded – undo
170 159
      * Provide a list of all projects.
171 160
      * @return DataList
172 161
      */
173
-    public function DNProjectList()
174
-    {
162
+    public function DNProjectList() {
175 163
         return DNProject::get();
176 164
     }
177 165
 
@@ -183,8 +171,7 @@  discard block
 block discarded – undo
183 171
      * @return array
184 172
      * @throws Exception
185 173
      */
186
-    public function getProjectPaths()
187
-    {
174
+    public function getProjectPaths() {
188 175
         $paths = array();
189 176
         if (!file_exists($this->getEnvironmentDir())) {
190 177
             $eMessage = 'The environment directory ' . $this->getEnvironmentDir() . ' doesn\'t exist. Create it '
@@ -208,8 +195,7 @@  discard block
 block discarded – undo
208 195
      * Scan the directory and enumerate all envs founds within.
209 196
      * Returns an array of paths
210 197
      */
211
-    public function getEnvironmentPaths($project)
212
-    {
198
+    public function getEnvironmentPaths($project) {
213 199
         $baseDir = $this->getEnvironmentDir() . '/' . $project;
214 200
 
215 201
         $paths = array();
Please login to merge, or discard this patch.
code/model/DNDataArchive.php 3 patches
Indentation   +540 added lines, -540 removed lines patch added patch discarded remove patch
@@ -50,544 +50,544 @@
 block discarded – undo
50 50
 class DNDataArchive extends DataObject
51 51
 {
52 52
 
53
-    private static $db = array(
54
-        'UploadToken' => 'Varchar(8)',
55
-        'ArchiveFileHash' => 'Varchar(32)',
56
-        "Mode" => "Enum('all, assets, db', '')",
57
-        "IsBackup" => "Boolean",
58
-        "IsManualUpload" => "Boolean",
59
-    );
60
-
61
-    private static $has_one = array(
62
-        'Author' => 'Member',
63
-        'OriginalEnvironment' => 'DNEnvironment',
64
-        'Environment' => 'DNEnvironment',
65
-        'ArchiveFile' => 'File'
66
-    );
67
-
68
-    private static $has_many = array(
69
-        'DataTransfers' => 'DNDataTransfer',
70
-    );
71
-
72
-    private static $singular_name = 'Data Archive';
73
-
74
-    private static $plural_name = 'Data Archives';
75
-
76
-    private static $summary_fields = array(
77
-        'Created' => 'Created',
78
-        'Author.Title' => 'Author',
79
-        'Environment.Project.Name' => 'Project',
80
-        'OriginalEnvironment.Name' => 'Origin',
81
-        'Environment.Name' => 'Environment',
82
-        'ArchiveFile.Name' => 'File',
83
-    );
84
-
85
-    private static $searchable_fields = array(
86
-        'Environment.Project.Name' => array(
87
-            'title' => 'Project',
88
-        ),
89
-        'OriginalEnvironment.Name' => array(
90
-            'title' => 'Origin',
91
-        ),
92
-        'Environment.Name' => array(
93
-            'title' => 'Environment',
94
-        ),
95
-        'UploadToken' => array(
96
-            'title' => 'Upload Token',
97
-        ),
98
-        'Mode' => array(
99
-            'title' => 'Mode',
100
-        ),
101
-    );
102
-
103
-    private static $_cache_can_restore = array();
104
-
105
-    private static $_cache_can_download = array();
106
-
107
-    public static function get_mode_map()
108
-    {
109
-        return array(
110
-            'all' => 'Database and Assets',
111
-            'db' => 'Database only',
112
-            'assets' => 'Assets only',
113
-        );
114
-    }
115
-
116
-    /**
117
-     * Returns a unique token to correlate an offline item (posted DVD)
118
-     * with a specific archive placeholder.
119
-     *
120
-     * @return string
121
-     */
122
-    public static function generate_upload_token($chars = 8)
123
-    {
124
-        $generator = new RandomGenerator();
125
-        return strtoupper(substr($generator->randomToken(), 0, $chars));
126
-    }
127
-
128
-    public function onBeforeWrite()
129
-    {
130
-        if (!$this->AuthorID) {
131
-            $this->AuthorID = Member::currentUserID();
132
-        }
133
-
134
-        parent::onBeforeWrite();
135
-    }
136
-
137
-    public function onAfterDelete()
138
-    {
139
-        $this->ArchiveFile()->delete();
140
-    }
141
-
142
-    public function getCMSFields()
143
-    {
144
-        $fields = parent::getCMSFields();
145
-        $fields->removeByName('OriginalEnvironmentID');
146
-        $fields->removeByName('EnvironmentID');
147
-        $fields->removeByName('ArchiveFile');
148
-        $fields->addFieldsToTab(
149
-            'Root.Main',
150
-            array(
151
-                new ReadonlyField('ProjectName', 'Project', $this->Environment()->Project()->Name),
152
-                new ReadonlyField('OriginalEnvironmentName', 'OriginalEnvironment', $this->OriginalEnvironment()->Name),
153
-                new ReadonlyField('EnvironmentName', 'Environment', $this->Environment()->Name),
154
-                $linkField = new ReadonlyField(
155
-                    'DataArchive',
156
-                    'Archive File',
157
-                    sprintf(
158
-                        '<a href="%s">%s</a>',
159
-                        $this->ArchiveFile()->AbsoluteURL,
160
-                        $this->ArchiveFile()->Filename
161
-                    )
162
-                ),
163
-                new GridField(
164
-                    'DataTransfers',
165
-                    'Transfers',
166
-                    $this->DataTransfers()
167
-                ),
168
-            )
169
-        );
170
-        $linkField->dontEscape = true;
171
-        $fields = $fields->makeReadonly();
172
-
173
-        return $fields;
174
-    }
175
-
176
-    public function getDefaultSearchContext()
177
-    {
178
-        $context = parent::getDefaultSearchContext();
179
-        $context->getFields()->dataFieldByName('Mode')->setHasEmptyDefault(true);
180
-
181
-        return $context;
182
-    }
183
-
184
-    /**
185
-     * Calculates and returns a human-readable size of this archive file. If the file exists, it will determine
186
-     * whether to display the output in bytes, kilobytes, megabytes, or gigabytes.
187
-     *
188
-     * @return string The human-readable size of this archive file
189
-     */
190
-    public function FileSize()
191
-    {
192
-        if ($this->ArchiveFile()->exists()) {
193
-            return $this->ArchiveFile()->getSize();
194
-        } else {
195
-            return "N/A";
196
-        }
197
-    }
198
-
199
-    public function getModeNice()
200
-    {
201
-        if ($this->Mode == 'all') {
202
-            return 'database and assets';
203
-        } else {
204
-            return $this->Mode;
205
-        }
206
-    }
207
-
208
-    /**
209
-     * Some archives don't have files attached to them yet,
210
-     * because a file has been posted offline and is waiting to be uploaded
211
-     * against this "archive placeholder".
212
-     *
213
-     * @return boolean
214
-     */
215
-    public function isPending()
216
-    {
217
-        return !($this->ArchiveFileID);
218
-    }
219
-
220
-    /**
221
-     * Inferred from both restore and backup permissions.
222
-     *
223
-     * @param Member|null $member The {@link Member} object to test against.
224
-     */
225
-    public function canView($member = null)
226
-    {
227
-        return ($this->canRestore($member) || $this->canDownload($member));
228
-    }
229
-
230
-    /**
231
-     * Whether a {@link Member} can restore this archive to an environment.
232
-     * This only needs to be checked *once* per member and environment.
233
-     *
234
-     * @param Member|null $member The {@link Member} object to test against.
235
-     * @return true if $member (or the currently logged in member if null) can upload this archive
236
-     */
237
-    public function canRestore($member = null)
238
-    {
239
-        $memberID = $member ? $member->ID : Member::currentUserID();
240
-        if (!$memberID) {
241
-            return false;
242
-        }
243
-
244
-        $key = $memberID . '-' . $this->EnvironmentID;
245
-        if (!isset(self::$_cache_can_restore[$key])) {
246
-            self::$_cache_can_restore[$key] = $this->Environment()->canUploadArchive($member);
247
-        }
248
-
249
-        return self::$_cache_can_restore[$key];
250
-    }
251
-
252
-    /**
253
-     * Whether a {@link Member} can download this archive to their PC.
254
-     * This only needs to be checked *once* per member and environment.
255
-     *
256
-     * @param Member|null $member The {@link Member} object to test against.
257
-     * @return true if $member (or the currently logged in member if null) can download this archive
258
-     */
259
-    public function canDownload($member = null)
260
-    {
261
-        $memberID = $member ? $member->ID : Member::currentUserID();
262
-        if (!$memberID) {
263
-            return false;
264
-        }
265
-
266
-        $key = $memberID . '-' . $this->EnvironmentID;
267
-        if (!isset(self::$_cache_can_download[$key])) {
268
-            self::$_cache_can_download[$key] = $this->Environment()->canDownloadArchive($member);
269
-        }
270
-        return self::$_cache_can_download[$key];
271
-    }
272
-
273
-    /**
274
-     * Whether a {@link Member} can delete this archive from staging area.
275
-     *
276
-     * @param Member|null $member The {@link Member} object to test against.
277
-     * @return boolean if $member (or the currently logged in member if null) can delete this archive
278
-     */
279
-    public function canDelete($member = null)
280
-    {
281
-        return $this->Environment()->canDeleteArchive($member);
282
-    }
283
-
284
-    /**
285
-     * Check if this member can move archive into the environment.
286
-     *
287
-     * @param DNEnvironment $targetEnv Environment to check.
288
-     * @param Member|null $member The {@link Member} object to test against. If null, uses Member::currentMember();
289
-     *
290
-     * @return boolean true if $member can upload archives linked to this environment, false if they can't.
291
-     */
292
-    public function canMoveTo($targetEnv, $member = null)
293
-    {
294
-        if ($this->Environment()->Project()->ID != $targetEnv->Project()->ID) {
295
-            // We don't permit moving snapshots between projects at this stage.
296
-            return false;
297
-        }
298
-
299
-        if (!$member) {
300
-            $member = Member::currentUser();
301
-        }
302
-
303
-        // Must be logged in to check permissions
304
-        if (!$member) {
305
-            return false;
306
-        }
307
-
308
-        // Admin can always move.
309
-        if (Permission::checkMember($member, 'ADMIN')) {
310
-            return true;
311
-        }
312
-
313
-        // Checks if the user can actually access the archive.
314
-        if (!$this->canDownload($member)) {
315
-            return false;
316
-        }
317
-
318
-        // Hooks into ArchiveUploaders permission to prevent proliferation of permission checkboxes.
319
-        // Bypasses the quota check - we don't need to check for it as long as we move the snapshot within the project.
320
-        return $targetEnv->ArchiveUploaders()->byID($member->ID)
321
-            || $member->inGroups($targetEnv->ArchiveUploaderGroups());
322
-    }
323
-
324
-    /**
325
-     * Finds all environments within this project where the archive can be moved to.
326
-     * Excludes current environment automatically.
327
-     *
328
-     * @return ArrayList List of valid environments.
329
-     */
330
-    public function validTargetEnvironments()
331
-    {
332
-        $archive = $this;
333
-        $envs = $this->Environment()->Project()->DNEnvironmentList()
334
-            ->filterByCallback(function ($item) use ($archive) {
335
-                return $archive->EnvironmentID != $item->ID && $archive->canMoveTo($item);
336
-            });
337
-
338
-        return $envs;
339
-    }
340
-
341
-    /**
342
-     * Returns a unique filename, including project/environment/timestamp details.
343
-     * @return string
344
-     */
345
-    public function generateFilename(DNDataTransfer $dataTransfer)
346
-    {
347
-        $generator = new RandomGenerator();
348
-        $filter = FileNameFilter::create();
349
-
350
-        return sprintf(
351
-            '%s-%s-%s-%s-%s',
352
-            $filter->filter(strtolower($this->OriginalEnvironment()->Project()->Name)),
353
-            $filter->filter(strtolower($this->OriginalEnvironment()->Name)),
354
-            $dataTransfer->Mode,
355
-            date('Ymd'),
356
-            sha1($generator->generateEntropy())
357
-        );
358
-    }
359
-
360
-    /**
361
-     * Returns a path unique to a specific transfer, including project/environment details.
362
-     * Does not create the path on the filesystem. Can be used to store files related to this transfer.
363
-     *
364
-     * @param DNDataTransfer
365
-     * @return string Absolute file path
366
-     */
367
-    public function generateFilepath(DNDataTransfer $dataTransfer)
368
-    {
369
-        $data = DNData::inst();
370
-        $transferDir = $data->getDataTransferDir();
371
-        $filter = FileNameFilter::create();
372
-
373
-        return sprintf('%s/%s/%s/transfer-%s/',
374
-            $transferDir,
375
-            $filter->filter(strtolower($this->OriginalEnvironment()->Project()->Name)),
376
-            $filter->filter(strtolower($this->OriginalEnvironment()->Name)),
377
-            $dataTransfer->ID
378
-        );
379
-    }
380
-
381
-    /**
382
-     * Attach an sspak file path to this archive and associate the transfer.
383
-     * Does the job of creating a {@link File} record, and setting correct paths into the assets directory.
384
-     *
385
-     * @param string $sspakFilepath
386
-     * @param DNDataTransfer $dataTransfer
387
-     * @return bool
388
-     */
389
-    public function attachFile($sspakFilepath, DNDataTransfer $dataTransfer)
390
-    {
391
-        $sspakFilepath = ltrim(
392
-            str_replace(
393
-                array(ASSETS_PATH, realpath(ASSETS_PATH)),
394
-                '',
395
-                $sspakFilepath
396
-            ),
397
-            DIRECTORY_SEPARATOR
398
-        );
399
-
400
-        $folder = Folder::find_or_make(dirname($sspakFilepath));
401
-        $file = new File();
402
-        $file->Name = basename($sspakFilepath);
403
-        $file->Filename = $sspakFilepath;
404
-        $file->ParentID = $folder->ID;
405
-        $file->write();
406
-
407
-        // "Status" will be updated by the job execution
408
-        $dataTransfer->write();
409
-
410
-        // Get file hash to ensure consistency.
411
-        // Only do this when first associating the file since hashing large files is expensive.
412
-        // Note that with CapistranoDeploymentBackend the file won't be available yet, as it
413
-        // gets put in place immediately after this method gets called. In which case, it will
414
-        // be hashed in setArchiveFromFiles()
415
-        if (file_exists($file->FullPath)) {
416
-            $this->ArchiveFileHash = md5_file($file->FullPath);
417
-        }
418
-        $this->ArchiveFileID = $file->ID;
419
-        $this->DataTransfers()->add($dataTransfer);
420
-        $this->write();
421
-
422
-        return true;
423
-    }
424
-
425
-    /**
426
-     * Extract the current sspak contents into the given working directory.
427
-     * This also extracts the assets and database and puts them into
428
-     * <workingdir>/database.sql and <workingdir>/assets, respectively.
429
-     *
430
-     * @param string|null $workingDir The path to extract to
431
-     * @throws RuntimeException
432
-     * @return bool
433
-     */
434
-    public function extractArchive($workingDir = null)
435
-    {
436
-        if (!is_dir($workingDir)) {
437
-            mkdir($workingDir, 0700, true);
438
-        }
439
-
440
-        $cleanupFn = function () use ($workingDir) {
441
-            $process = new Process(sprintf('rm -rf %s', escapeshellarg($workingDir)));
442
-            $process->run();
443
-        };
444
-
445
-        // Extract *.sspak to a temporary location
446
-        $sspakFilename = $this->ArchiveFile()->FullPath;
447
-        $process = new Process(sprintf(
448
-            'sspak extract %s %s',
449
-            escapeshellarg($sspakFilename),
450
-            escapeshellarg($workingDir)
451
-        ));
452
-        $process->setTimeout(3600);
453
-        $process->run();
454
-        if (!$process->isSuccessful()) {
455
-            $cleanupFn();
456
-            throw new RuntimeException(sprintf('Could not extract the sspak file: %s', $process->getErrorOutput()));
457
-        }
458
-
459
-        // Extract database.sql.gz to <workingdir>/database.sql
460
-        if (file_exists($workingDir . DIRECTORY_SEPARATOR . 'database.sql.gz')) {
461
-            $process = new Process('gunzip database.sql.gz', $workingDir);
462
-            $process->setTimeout(3600);
463
-            $process->run();
464
-            if (!$process->isSuccessful()) {
465
-                $cleanupFn();
466
-                throw new RuntimeException(sprintf('Could not extract the db archive: %s', $process->getErrorOutput()));
467
-            }
468
-        }
469
-
470
-        // Extract assets.tar.gz to <workingdir>/assets/
471
-        if (file_exists($workingDir . DIRECTORY_SEPARATOR . 'assets.tar.gz')) {
472
-            $process = new Process('tar xzf assets.tar.gz', $workingDir);
473
-            $process->setTimeout(3600);
474
-            $process->run();
475
-            if (!$process->isSuccessful()) {
476
-                $cleanupFn();
477
-                throw new RuntimeException(sprintf('Could not extract the assets archive: %s', $process->getErrorOutput()));
478
-            }
479
-        }
480
-
481
-        return true;
482
-    }
483
-
484
-    /**
485
-     * Validate that an sspak contains the correct content.
486
-     *
487
-     * For example, if the user uploaded an sspak containing just the db, but declared in the form
488
-     * that it contained db+assets, then the archive is not valid.
489
-     *
490
-     * @param string|null $mode "db", "assets", or "all". This is the content we're checking for. Default to the archive setting
491
-     * @return ValidationResult
492
-     */
493
-    public function validateArchiveContents($mode = null)
494
-    {
495
-        $mode = $mode ?: $this->Mode;
496
-        $result = new ValidationResult();
497
-
498
-        $file = $this->ArchiveFile()->FullPath;
499
-
500
-        if (!is_readable($file)) {
501
-            $result->error(sprintf('SSPak file "%s" cannot be read.', $file));
502
-            return $result;
503
-        }
504
-
505
-        $process = new Process(sprintf('tar -tf %s', escapeshellarg($file)));
506
-        $process->setTimeout(120);
507
-        $process->run();
508
-        if (!$process->isSuccessful()) {
509
-            throw new RuntimeException(sprintf('Could not list files in archive: %s', $process->getErrorOutput()));
510
-        }
511
-
512
-        $output = explode(PHP_EOL, $process->getOutput());
513
-        $files = array_filter($output);
514
-
515
-        if (in_array($mode, array('all', 'db')) && !in_array('database.sql.gz', $files)) {
516
-            $result->error('The snapshot is missing the database.');
517
-            return $result;
518
-        }
519
-
520
-        if (in_array($mode, array('all', 'assets')) && !in_array('assets.tar.gz', $files)) {
521
-            $result->error('The snapshot is missing assets.');
522
-            return $result;
523
-        }
524
-
525
-        return $result;
526
-    }
527
-
528
-    /**
529
-     * Given a path that already exists and contains an extracted sspak, including
530
-     * the assets, fix all of the file permissions so they're in a state ready to
531
-     * be pushed to remote servers.
532
-     *
533
-     * Normally, command line tar will use permissions found in the archive, but will
534
-     * substract the user's umask from them. This has a potential to create unreadable
535
-     * files, e.g. cygwin on Windows will pack files with mode 000, hence why this fix
536
-     * is necessary.
537
-     *
538
-     * @param string|null $workingDir The path of where the sspak has been extracted to
539
-     * @throws RuntimeException
540
-     * @return bool
541
-     */
542
-    public function fixArchivePermissions($workingDir)
543
-    {
544
-        $fixCmds = array(
545
-            // The directories need to have permissions changed one by one (hence the ; instead of +),
546
-            // otherwise we might end up having no +x access to a directory deeper down.
547
-            sprintf('find %s -type d -exec chmod 755 {} \;', escapeshellarg($workingDir)),
548
-            sprintf('find %s -type f -exec chmod 644 {} +', escapeshellarg($workingDir))
549
-        );
550
-
551
-        foreach ($fixCmds as $cmd) {
552
-            $process = new Process($cmd);
553
-            $process->setTimeout(3600);
554
-            $process->run();
555
-            if (!$process->isSuccessful()) {
556
-                throw new RuntimeException($process->getErrorOutput());
557
-            }
558
-        }
559
-
560
-        return true;
561
-    }
562
-
563
-    /**
564
-     * Given extracted sspak contents, create an sspak from it
565
-     * and overwrite the current ArchiveFile with it's contents.
566
-     *
567
-     * @param string|null $workingDir The path of where the sspak has been extracted to
568
-     * @return bool
569
-     */
570
-    public function setArchiveFromFiles($workingDir)
571
-    {
572
-        $command = sprintf('sspak saveexisting %s 2>&1', $this->ArchiveFile()->FullPath);
573
-        if ($this->Mode == 'db') {
574
-            $command .= sprintf(' --db=%s/database.sql', $workingDir);
575
-        } elseif ($this->Mode == 'assets') {
576
-            $command .= sprintf(' --assets=%s/assets', $workingDir);
577
-        } else {
578
-            $command .= sprintf(' --db=%s/database.sql --assets=%s/assets', $workingDir, $workingDir);
579
-        }
580
-
581
-        $process = new Process($command, $workingDir);
582
-        $process->setTimeout(3600);
583
-        $process->run();
584
-        if (!$process->isSuccessful()) {
585
-            throw new RuntimeException($process->getErrorOutput());
586
-        }
587
-
588
-        $this->ArchiveFileHash = md5_file($this->ArchiveFile()->FullPath);
589
-        $this->write();
590
-
591
-        return true;
592
-    }
53
+	private static $db = array(
54
+		'UploadToken' => 'Varchar(8)',
55
+		'ArchiveFileHash' => 'Varchar(32)',
56
+		"Mode" => "Enum('all, assets, db', '')",
57
+		"IsBackup" => "Boolean",
58
+		"IsManualUpload" => "Boolean",
59
+	);
60
+
61
+	private static $has_one = array(
62
+		'Author' => 'Member',
63
+		'OriginalEnvironment' => 'DNEnvironment',
64
+		'Environment' => 'DNEnvironment',
65
+		'ArchiveFile' => 'File'
66
+	);
67
+
68
+	private static $has_many = array(
69
+		'DataTransfers' => 'DNDataTransfer',
70
+	);
71
+
72
+	private static $singular_name = 'Data Archive';
73
+
74
+	private static $plural_name = 'Data Archives';
75
+
76
+	private static $summary_fields = array(
77
+		'Created' => 'Created',
78
+		'Author.Title' => 'Author',
79
+		'Environment.Project.Name' => 'Project',
80
+		'OriginalEnvironment.Name' => 'Origin',
81
+		'Environment.Name' => 'Environment',
82
+		'ArchiveFile.Name' => 'File',
83
+	);
84
+
85
+	private static $searchable_fields = array(
86
+		'Environment.Project.Name' => array(
87
+			'title' => 'Project',
88
+		),
89
+		'OriginalEnvironment.Name' => array(
90
+			'title' => 'Origin',
91
+		),
92
+		'Environment.Name' => array(
93
+			'title' => 'Environment',
94
+		),
95
+		'UploadToken' => array(
96
+			'title' => 'Upload Token',
97
+		),
98
+		'Mode' => array(
99
+			'title' => 'Mode',
100
+		),
101
+	);
102
+
103
+	private static $_cache_can_restore = array();
104
+
105
+	private static $_cache_can_download = array();
106
+
107
+	public static function get_mode_map()
108
+	{
109
+		return array(
110
+			'all' => 'Database and Assets',
111
+			'db' => 'Database only',
112
+			'assets' => 'Assets only',
113
+		);
114
+	}
115
+
116
+	/**
117
+	 * Returns a unique token to correlate an offline item (posted DVD)
118
+	 * with a specific archive placeholder.
119
+	 *
120
+	 * @return string
121
+	 */
122
+	public static function generate_upload_token($chars = 8)
123
+	{
124
+		$generator = new RandomGenerator();
125
+		return strtoupper(substr($generator->randomToken(), 0, $chars));
126
+	}
127
+
128
+	public function onBeforeWrite()
129
+	{
130
+		if (!$this->AuthorID) {
131
+			$this->AuthorID = Member::currentUserID();
132
+		}
133
+
134
+		parent::onBeforeWrite();
135
+	}
136
+
137
+	public function onAfterDelete()
138
+	{
139
+		$this->ArchiveFile()->delete();
140
+	}
141
+
142
+	public function getCMSFields()
143
+	{
144
+		$fields = parent::getCMSFields();
145
+		$fields->removeByName('OriginalEnvironmentID');
146
+		$fields->removeByName('EnvironmentID');
147
+		$fields->removeByName('ArchiveFile');
148
+		$fields->addFieldsToTab(
149
+			'Root.Main',
150
+			array(
151
+				new ReadonlyField('ProjectName', 'Project', $this->Environment()->Project()->Name),
152
+				new ReadonlyField('OriginalEnvironmentName', 'OriginalEnvironment', $this->OriginalEnvironment()->Name),
153
+				new ReadonlyField('EnvironmentName', 'Environment', $this->Environment()->Name),
154
+				$linkField = new ReadonlyField(
155
+					'DataArchive',
156
+					'Archive File',
157
+					sprintf(
158
+						'<a href="%s">%s</a>',
159
+						$this->ArchiveFile()->AbsoluteURL,
160
+						$this->ArchiveFile()->Filename
161
+					)
162
+				),
163
+				new GridField(
164
+					'DataTransfers',
165
+					'Transfers',
166
+					$this->DataTransfers()
167
+				),
168
+			)
169
+		);
170
+		$linkField->dontEscape = true;
171
+		$fields = $fields->makeReadonly();
172
+
173
+		return $fields;
174
+	}
175
+
176
+	public function getDefaultSearchContext()
177
+	{
178
+		$context = parent::getDefaultSearchContext();
179
+		$context->getFields()->dataFieldByName('Mode')->setHasEmptyDefault(true);
180
+
181
+		return $context;
182
+	}
183
+
184
+	/**
185
+	 * Calculates and returns a human-readable size of this archive file. If the file exists, it will determine
186
+	 * whether to display the output in bytes, kilobytes, megabytes, or gigabytes.
187
+	 *
188
+	 * @return string The human-readable size of this archive file
189
+	 */
190
+	public function FileSize()
191
+	{
192
+		if ($this->ArchiveFile()->exists()) {
193
+			return $this->ArchiveFile()->getSize();
194
+		} else {
195
+			return "N/A";
196
+		}
197
+	}
198
+
199
+	public function getModeNice()
200
+	{
201
+		if ($this->Mode == 'all') {
202
+			return 'database and assets';
203
+		} else {
204
+			return $this->Mode;
205
+		}
206
+	}
207
+
208
+	/**
209
+	 * Some archives don't have files attached to them yet,
210
+	 * because a file has been posted offline and is waiting to be uploaded
211
+	 * against this "archive placeholder".
212
+	 *
213
+	 * @return boolean
214
+	 */
215
+	public function isPending()
216
+	{
217
+		return !($this->ArchiveFileID);
218
+	}
219
+
220
+	/**
221
+	 * Inferred from both restore and backup permissions.
222
+	 *
223
+	 * @param Member|null $member The {@link Member} object to test against.
224
+	 */
225
+	public function canView($member = null)
226
+	{
227
+		return ($this->canRestore($member) || $this->canDownload($member));
228
+	}
229
+
230
+	/**
231
+	 * Whether a {@link Member} can restore this archive to an environment.
232
+	 * This only needs to be checked *once* per member and environment.
233
+	 *
234
+	 * @param Member|null $member The {@link Member} object to test against.
235
+	 * @return true if $member (or the currently logged in member if null) can upload this archive
236
+	 */
237
+	public function canRestore($member = null)
238
+	{
239
+		$memberID = $member ? $member->ID : Member::currentUserID();
240
+		if (!$memberID) {
241
+			return false;
242
+		}
243
+
244
+		$key = $memberID . '-' . $this->EnvironmentID;
245
+		if (!isset(self::$_cache_can_restore[$key])) {
246
+			self::$_cache_can_restore[$key] = $this->Environment()->canUploadArchive($member);
247
+		}
248
+
249
+		return self::$_cache_can_restore[$key];
250
+	}
251
+
252
+	/**
253
+	 * Whether a {@link Member} can download this archive to their PC.
254
+	 * This only needs to be checked *once* per member and environment.
255
+	 *
256
+	 * @param Member|null $member The {@link Member} object to test against.
257
+	 * @return true if $member (or the currently logged in member if null) can download this archive
258
+	 */
259
+	public function canDownload($member = null)
260
+	{
261
+		$memberID = $member ? $member->ID : Member::currentUserID();
262
+		if (!$memberID) {
263
+			return false;
264
+		}
265
+
266
+		$key = $memberID . '-' . $this->EnvironmentID;
267
+		if (!isset(self::$_cache_can_download[$key])) {
268
+			self::$_cache_can_download[$key] = $this->Environment()->canDownloadArchive($member);
269
+		}
270
+		return self::$_cache_can_download[$key];
271
+	}
272
+
273
+	/**
274
+	 * Whether a {@link Member} can delete this archive from staging area.
275
+	 *
276
+	 * @param Member|null $member The {@link Member} object to test against.
277
+	 * @return boolean if $member (or the currently logged in member if null) can delete this archive
278
+	 */
279
+	public function canDelete($member = null)
280
+	{
281
+		return $this->Environment()->canDeleteArchive($member);
282
+	}
283
+
284
+	/**
285
+	 * Check if this member can move archive into the environment.
286
+	 *
287
+	 * @param DNEnvironment $targetEnv Environment to check.
288
+	 * @param Member|null $member The {@link Member} object to test against. If null, uses Member::currentMember();
289
+	 *
290
+	 * @return boolean true if $member can upload archives linked to this environment, false if they can't.
291
+	 */
292
+	public function canMoveTo($targetEnv, $member = null)
293
+	{
294
+		if ($this->Environment()->Project()->ID != $targetEnv->Project()->ID) {
295
+			// We don't permit moving snapshots between projects at this stage.
296
+			return false;
297
+		}
298
+
299
+		if (!$member) {
300
+			$member = Member::currentUser();
301
+		}
302
+
303
+		// Must be logged in to check permissions
304
+		if (!$member) {
305
+			return false;
306
+		}
307
+
308
+		// Admin can always move.
309
+		if (Permission::checkMember($member, 'ADMIN')) {
310
+			return true;
311
+		}
312
+
313
+		// Checks if the user can actually access the archive.
314
+		if (!$this->canDownload($member)) {
315
+			return false;
316
+		}
317
+
318
+		// Hooks into ArchiveUploaders permission to prevent proliferation of permission checkboxes.
319
+		// Bypasses the quota check - we don't need to check for it as long as we move the snapshot within the project.
320
+		return $targetEnv->ArchiveUploaders()->byID($member->ID)
321
+			|| $member->inGroups($targetEnv->ArchiveUploaderGroups());
322
+	}
323
+
324
+	/**
325
+	 * Finds all environments within this project where the archive can be moved to.
326
+	 * Excludes current environment automatically.
327
+	 *
328
+	 * @return ArrayList List of valid environments.
329
+	 */
330
+	public function validTargetEnvironments()
331
+	{
332
+		$archive = $this;
333
+		$envs = $this->Environment()->Project()->DNEnvironmentList()
334
+			->filterByCallback(function ($item) use ($archive) {
335
+				return $archive->EnvironmentID != $item->ID && $archive->canMoveTo($item);
336
+			});
337
+
338
+		return $envs;
339
+	}
340
+
341
+	/**
342
+	 * Returns a unique filename, including project/environment/timestamp details.
343
+	 * @return string
344
+	 */
345
+	public function generateFilename(DNDataTransfer $dataTransfer)
346
+	{
347
+		$generator = new RandomGenerator();
348
+		$filter = FileNameFilter::create();
349
+
350
+		return sprintf(
351
+			'%s-%s-%s-%s-%s',
352
+			$filter->filter(strtolower($this->OriginalEnvironment()->Project()->Name)),
353
+			$filter->filter(strtolower($this->OriginalEnvironment()->Name)),
354
+			$dataTransfer->Mode,
355
+			date('Ymd'),
356
+			sha1($generator->generateEntropy())
357
+		);
358
+	}
359
+
360
+	/**
361
+	 * Returns a path unique to a specific transfer, including project/environment details.
362
+	 * Does not create the path on the filesystem. Can be used to store files related to this transfer.
363
+	 *
364
+	 * @param DNDataTransfer
365
+	 * @return string Absolute file path
366
+	 */
367
+	public function generateFilepath(DNDataTransfer $dataTransfer)
368
+	{
369
+		$data = DNData::inst();
370
+		$transferDir = $data->getDataTransferDir();
371
+		$filter = FileNameFilter::create();
372
+
373
+		return sprintf('%s/%s/%s/transfer-%s/',
374
+			$transferDir,
375
+			$filter->filter(strtolower($this->OriginalEnvironment()->Project()->Name)),
376
+			$filter->filter(strtolower($this->OriginalEnvironment()->Name)),
377
+			$dataTransfer->ID
378
+		);
379
+	}
380
+
381
+	/**
382
+	 * Attach an sspak file path to this archive and associate the transfer.
383
+	 * Does the job of creating a {@link File} record, and setting correct paths into the assets directory.
384
+	 *
385
+	 * @param string $sspakFilepath
386
+	 * @param DNDataTransfer $dataTransfer
387
+	 * @return bool
388
+	 */
389
+	public function attachFile($sspakFilepath, DNDataTransfer $dataTransfer)
390
+	{
391
+		$sspakFilepath = ltrim(
392
+			str_replace(
393
+				array(ASSETS_PATH, realpath(ASSETS_PATH)),
394
+				'',
395
+				$sspakFilepath
396
+			),
397
+			DIRECTORY_SEPARATOR
398
+		);
399
+
400
+		$folder = Folder::find_or_make(dirname($sspakFilepath));
401
+		$file = new File();
402
+		$file->Name = basename($sspakFilepath);
403
+		$file->Filename = $sspakFilepath;
404
+		$file->ParentID = $folder->ID;
405
+		$file->write();
406
+
407
+		// "Status" will be updated by the job execution
408
+		$dataTransfer->write();
409
+
410
+		// Get file hash to ensure consistency.
411
+		// Only do this when first associating the file since hashing large files is expensive.
412
+		// Note that with CapistranoDeploymentBackend the file won't be available yet, as it
413
+		// gets put in place immediately after this method gets called. In which case, it will
414
+		// be hashed in setArchiveFromFiles()
415
+		if (file_exists($file->FullPath)) {
416
+			$this->ArchiveFileHash = md5_file($file->FullPath);
417
+		}
418
+		$this->ArchiveFileID = $file->ID;
419
+		$this->DataTransfers()->add($dataTransfer);
420
+		$this->write();
421
+
422
+		return true;
423
+	}
424
+
425
+	/**
426
+	 * Extract the current sspak contents into the given working directory.
427
+	 * This also extracts the assets and database and puts them into
428
+	 * <workingdir>/database.sql and <workingdir>/assets, respectively.
429
+	 *
430
+	 * @param string|null $workingDir The path to extract to
431
+	 * @throws RuntimeException
432
+	 * @return bool
433
+	 */
434
+	public function extractArchive($workingDir = null)
435
+	{
436
+		if (!is_dir($workingDir)) {
437
+			mkdir($workingDir, 0700, true);
438
+		}
439
+
440
+		$cleanupFn = function () use ($workingDir) {
441
+			$process = new Process(sprintf('rm -rf %s', escapeshellarg($workingDir)));
442
+			$process->run();
443
+		};
444
+
445
+		// Extract *.sspak to a temporary location
446
+		$sspakFilename = $this->ArchiveFile()->FullPath;
447
+		$process = new Process(sprintf(
448
+			'sspak extract %s %s',
449
+			escapeshellarg($sspakFilename),
450
+			escapeshellarg($workingDir)
451
+		));
452
+		$process->setTimeout(3600);
453
+		$process->run();
454
+		if (!$process->isSuccessful()) {
455
+			$cleanupFn();
456
+			throw new RuntimeException(sprintf('Could not extract the sspak file: %s', $process->getErrorOutput()));
457
+		}
458
+
459
+		// Extract database.sql.gz to <workingdir>/database.sql
460
+		if (file_exists($workingDir . DIRECTORY_SEPARATOR . 'database.sql.gz')) {
461
+			$process = new Process('gunzip database.sql.gz', $workingDir);
462
+			$process->setTimeout(3600);
463
+			$process->run();
464
+			if (!$process->isSuccessful()) {
465
+				$cleanupFn();
466
+				throw new RuntimeException(sprintf('Could not extract the db archive: %s', $process->getErrorOutput()));
467
+			}
468
+		}
469
+
470
+		// Extract assets.tar.gz to <workingdir>/assets/
471
+		if (file_exists($workingDir . DIRECTORY_SEPARATOR . 'assets.tar.gz')) {
472
+			$process = new Process('tar xzf assets.tar.gz', $workingDir);
473
+			$process->setTimeout(3600);
474
+			$process->run();
475
+			if (!$process->isSuccessful()) {
476
+				$cleanupFn();
477
+				throw new RuntimeException(sprintf('Could not extract the assets archive: %s', $process->getErrorOutput()));
478
+			}
479
+		}
480
+
481
+		return true;
482
+	}
483
+
484
+	/**
485
+	 * Validate that an sspak contains the correct content.
486
+	 *
487
+	 * For example, if the user uploaded an sspak containing just the db, but declared in the form
488
+	 * that it contained db+assets, then the archive is not valid.
489
+	 *
490
+	 * @param string|null $mode "db", "assets", or "all". This is the content we're checking for. Default to the archive setting
491
+	 * @return ValidationResult
492
+	 */
493
+	public function validateArchiveContents($mode = null)
494
+	{
495
+		$mode = $mode ?: $this->Mode;
496
+		$result = new ValidationResult();
497
+
498
+		$file = $this->ArchiveFile()->FullPath;
499
+
500
+		if (!is_readable($file)) {
501
+			$result->error(sprintf('SSPak file "%s" cannot be read.', $file));
502
+			return $result;
503
+		}
504
+
505
+		$process = new Process(sprintf('tar -tf %s', escapeshellarg($file)));
506
+		$process->setTimeout(120);
507
+		$process->run();
508
+		if (!$process->isSuccessful()) {
509
+			throw new RuntimeException(sprintf('Could not list files in archive: %s', $process->getErrorOutput()));
510
+		}
511
+
512
+		$output = explode(PHP_EOL, $process->getOutput());
513
+		$files = array_filter($output);
514
+
515
+		if (in_array($mode, array('all', 'db')) && !in_array('database.sql.gz', $files)) {
516
+			$result->error('The snapshot is missing the database.');
517
+			return $result;
518
+		}
519
+
520
+		if (in_array($mode, array('all', 'assets')) && !in_array('assets.tar.gz', $files)) {
521
+			$result->error('The snapshot is missing assets.');
522
+			return $result;
523
+		}
524
+
525
+		return $result;
526
+	}
527
+
528
+	/**
529
+	 * Given a path that already exists and contains an extracted sspak, including
530
+	 * the assets, fix all of the file permissions so they're in a state ready to
531
+	 * be pushed to remote servers.
532
+	 *
533
+	 * Normally, command line tar will use permissions found in the archive, but will
534
+	 * substract the user's umask from them. This has a potential to create unreadable
535
+	 * files, e.g. cygwin on Windows will pack files with mode 000, hence why this fix
536
+	 * is necessary.
537
+	 *
538
+	 * @param string|null $workingDir The path of where the sspak has been extracted to
539
+	 * @throws RuntimeException
540
+	 * @return bool
541
+	 */
542
+	public function fixArchivePermissions($workingDir)
543
+	{
544
+		$fixCmds = array(
545
+			// The directories need to have permissions changed one by one (hence the ; instead of +),
546
+			// otherwise we might end up having no +x access to a directory deeper down.
547
+			sprintf('find %s -type d -exec chmod 755 {} \;', escapeshellarg($workingDir)),
548
+			sprintf('find %s -type f -exec chmod 644 {} +', escapeshellarg($workingDir))
549
+		);
550
+
551
+		foreach ($fixCmds as $cmd) {
552
+			$process = new Process($cmd);
553
+			$process->setTimeout(3600);
554
+			$process->run();
555
+			if (!$process->isSuccessful()) {
556
+				throw new RuntimeException($process->getErrorOutput());
557
+			}
558
+		}
559
+
560
+		return true;
561
+	}
562
+
563
+	/**
564
+	 * Given extracted sspak contents, create an sspak from it
565
+	 * and overwrite the current ArchiveFile with it's contents.
566
+	 *
567
+	 * @param string|null $workingDir The path of where the sspak has been extracted to
568
+	 * @return bool
569
+	 */
570
+	public function setArchiveFromFiles($workingDir)
571
+	{
572
+		$command = sprintf('sspak saveexisting %s 2>&1', $this->ArchiveFile()->FullPath);
573
+		if ($this->Mode == 'db') {
574
+			$command .= sprintf(' --db=%s/database.sql', $workingDir);
575
+		} elseif ($this->Mode == 'assets') {
576
+			$command .= sprintf(' --assets=%s/assets', $workingDir);
577
+		} else {
578
+			$command .= sprintf(' --db=%s/database.sql --assets=%s/assets', $workingDir, $workingDir);
579
+		}
580
+
581
+		$process = new Process($command, $workingDir);
582
+		$process->setTimeout(3600);
583
+		$process->run();
584
+		if (!$process->isSuccessful()) {
585
+			throw new RuntimeException($process->getErrorOutput());
586
+		}
587
+
588
+		$this->ArchiveFileHash = md5_file($this->ArchiveFile()->FullPath);
589
+		$this->write();
590
+
591
+		return true;
592
+	}
593 593
 }
Please login to merge, or discard this patch.
Spacing   +30 added lines, -30 removed lines patch added patch discarded remove patch
@@ -127,7 +127,7 @@  discard block
 block discarded – undo
127 127
 
128 128
     public function onBeforeWrite()
129 129
     {
130
-        if (!$this->AuthorID) {
130
+        if(!$this->AuthorID) {
131 131
             $this->AuthorID = Member::currentUserID();
132 132
         }
133 133
 
@@ -189,7 +189,7 @@  discard block
 block discarded – undo
189 189
      */
190 190
     public function FileSize()
191 191
     {
192
-        if ($this->ArchiveFile()->exists()) {
192
+        if($this->ArchiveFile()->exists()) {
193 193
             return $this->ArchiveFile()->getSize();
194 194
         } else {
195 195
             return "N/A";
@@ -198,7 +198,7 @@  discard block
 block discarded – undo
198 198
 
199 199
     public function getModeNice()
200 200
     {
201
-        if ($this->Mode == 'all') {
201
+        if($this->Mode == 'all') {
202 202
             return 'database and assets';
203 203
         } else {
204 204
             return $this->Mode;
@@ -237,12 +237,12 @@  discard block
 block discarded – undo
237 237
     public function canRestore($member = null)
238 238
     {
239 239
         $memberID = $member ? $member->ID : Member::currentUserID();
240
-        if (!$memberID) {
240
+        if(!$memberID) {
241 241
             return false;
242 242
         }
243 243
 
244 244
         $key = $memberID . '-' . $this->EnvironmentID;
245
-        if (!isset(self::$_cache_can_restore[$key])) {
245
+        if(!isset(self::$_cache_can_restore[$key])) {
246 246
             self::$_cache_can_restore[$key] = $this->Environment()->canUploadArchive($member);
247 247
         }
248 248
 
@@ -259,12 +259,12 @@  discard block
 block discarded – undo
259 259
     public function canDownload($member = null)
260 260
     {
261 261
         $memberID = $member ? $member->ID : Member::currentUserID();
262
-        if (!$memberID) {
262
+        if(!$memberID) {
263 263
             return false;
264 264
         }
265 265
 
266 266
         $key = $memberID . '-' . $this->EnvironmentID;
267
-        if (!isset(self::$_cache_can_download[$key])) {
267
+        if(!isset(self::$_cache_can_download[$key])) {
268 268
             self::$_cache_can_download[$key] = $this->Environment()->canDownloadArchive($member);
269 269
         }
270 270
         return self::$_cache_can_download[$key];
@@ -291,27 +291,27 @@  discard block
 block discarded – undo
291 291
      */
292 292
     public function canMoveTo($targetEnv, $member = null)
293 293
     {
294
-        if ($this->Environment()->Project()->ID != $targetEnv->Project()->ID) {
294
+        if($this->Environment()->Project()->ID != $targetEnv->Project()->ID) {
295 295
             // We don't permit moving snapshots between projects at this stage.
296 296
             return false;
297 297
         }
298 298
 
299
-        if (!$member) {
299
+        if(!$member) {
300 300
             $member = Member::currentUser();
301 301
         }
302 302
 
303 303
         // Must be logged in to check permissions
304
-        if (!$member) {
304
+        if(!$member) {
305 305
             return false;
306 306
         }
307 307
 
308 308
         // Admin can always move.
309
-        if (Permission::checkMember($member, 'ADMIN')) {
309
+        if(Permission::checkMember($member, 'ADMIN')) {
310 310
             return true;
311 311
         }
312 312
 
313 313
         // Checks if the user can actually access the archive.
314
-        if (!$this->canDownload($member)) {
314
+        if(!$this->canDownload($member)) {
315 315
             return false;
316 316
         }
317 317
 
@@ -331,7 +331,7 @@  discard block
 block discarded – undo
331 331
     {
332 332
         $archive = $this;
333 333
         $envs = $this->Environment()->Project()->DNEnvironmentList()
334
-            ->filterByCallback(function ($item) use ($archive) {
334
+            ->filterByCallback(function($item) use ($archive) {
335 335
                 return $archive->EnvironmentID != $item->ID && $archive->canMoveTo($item);
336 336
             });
337 337
 
@@ -412,7 +412,7 @@  discard block
 block discarded – undo
412 412
         // Note that with CapistranoDeploymentBackend the file won't be available yet, as it
413 413
         // gets put in place immediately after this method gets called. In which case, it will
414 414
         // be hashed in setArchiveFromFiles()
415
-        if (file_exists($file->FullPath)) {
415
+        if(file_exists($file->FullPath)) {
416 416
             $this->ArchiveFileHash = md5_file($file->FullPath);
417 417
         }
418 418
         $this->ArchiveFileID = $file->ID;
@@ -433,11 +433,11 @@  discard block
 block discarded – undo
433 433
      */
434 434
     public function extractArchive($workingDir = null)
435 435
     {
436
-        if (!is_dir($workingDir)) {
436
+        if(!is_dir($workingDir)) {
437 437
             mkdir($workingDir, 0700, true);
438 438
         }
439 439
 
440
-        $cleanupFn = function () use ($workingDir) {
440
+        $cleanupFn = function() use ($workingDir) {
441 441
             $process = new Process(sprintf('rm -rf %s', escapeshellarg($workingDir)));
442 442
             $process->run();
443 443
         };
@@ -451,28 +451,28 @@  discard block
 block discarded – undo
451 451
         ));
452 452
         $process->setTimeout(3600);
453 453
         $process->run();
454
-        if (!$process->isSuccessful()) {
454
+        if(!$process->isSuccessful()) {
455 455
             $cleanupFn();
456 456
             throw new RuntimeException(sprintf('Could not extract the sspak file: %s', $process->getErrorOutput()));
457 457
         }
458 458
 
459 459
         // Extract database.sql.gz to <workingdir>/database.sql
460
-        if (file_exists($workingDir . DIRECTORY_SEPARATOR . 'database.sql.gz')) {
460
+        if(file_exists($workingDir . DIRECTORY_SEPARATOR . 'database.sql.gz')) {
461 461
             $process = new Process('gunzip database.sql.gz', $workingDir);
462 462
             $process->setTimeout(3600);
463 463
             $process->run();
464
-            if (!$process->isSuccessful()) {
464
+            if(!$process->isSuccessful()) {
465 465
                 $cleanupFn();
466 466
                 throw new RuntimeException(sprintf('Could not extract the db archive: %s', $process->getErrorOutput()));
467 467
             }
468 468
         }
469 469
 
470 470
         // Extract assets.tar.gz to <workingdir>/assets/
471
-        if (file_exists($workingDir . DIRECTORY_SEPARATOR . 'assets.tar.gz')) {
471
+        if(file_exists($workingDir . DIRECTORY_SEPARATOR . 'assets.tar.gz')) {
472 472
             $process = new Process('tar xzf assets.tar.gz', $workingDir);
473 473
             $process->setTimeout(3600);
474 474
             $process->run();
475
-            if (!$process->isSuccessful()) {
475
+            if(!$process->isSuccessful()) {
476 476
                 $cleanupFn();
477 477
                 throw new RuntimeException(sprintf('Could not extract the assets archive: %s', $process->getErrorOutput()));
478 478
             }
@@ -497,7 +497,7 @@  discard block
 block discarded – undo
497 497
 
498 498
         $file = $this->ArchiveFile()->FullPath;
499 499
 
500
-        if (!is_readable($file)) {
500
+        if(!is_readable($file)) {
501 501
             $result->error(sprintf('SSPak file "%s" cannot be read.', $file));
502 502
             return $result;
503 503
         }
@@ -505,19 +505,19 @@  discard block
 block discarded – undo
505 505
         $process = new Process(sprintf('tar -tf %s', escapeshellarg($file)));
506 506
         $process->setTimeout(120);
507 507
         $process->run();
508
-        if (!$process->isSuccessful()) {
508
+        if(!$process->isSuccessful()) {
509 509
             throw new RuntimeException(sprintf('Could not list files in archive: %s', $process->getErrorOutput()));
510 510
         }
511 511
 
512 512
         $output = explode(PHP_EOL, $process->getOutput());
513 513
         $files = array_filter($output);
514 514
 
515
-        if (in_array($mode, array('all', 'db')) && !in_array('database.sql.gz', $files)) {
515
+        if(in_array($mode, array('all', 'db')) && !in_array('database.sql.gz', $files)) {
516 516
             $result->error('The snapshot is missing the database.');
517 517
             return $result;
518 518
         }
519 519
 
520
-        if (in_array($mode, array('all', 'assets')) && !in_array('assets.tar.gz', $files)) {
520
+        if(in_array($mode, array('all', 'assets')) && !in_array('assets.tar.gz', $files)) {
521 521
             $result->error('The snapshot is missing assets.');
522 522
             return $result;
523 523
         }
@@ -548,11 +548,11 @@  discard block
 block discarded – undo
548 548
             sprintf('find %s -type f -exec chmod 644 {} +', escapeshellarg($workingDir))
549 549
         );
550 550
 
551
-        foreach ($fixCmds as $cmd) {
551
+        foreach($fixCmds as $cmd) {
552 552
             $process = new Process($cmd);
553 553
             $process->setTimeout(3600);
554 554
             $process->run();
555
-            if (!$process->isSuccessful()) {
555
+            if(!$process->isSuccessful()) {
556 556
                 throw new RuntimeException($process->getErrorOutput());
557 557
             }
558 558
         }
@@ -570,9 +570,9 @@  discard block
 block discarded – undo
570 570
     public function setArchiveFromFiles($workingDir)
571 571
     {
572 572
         $command = sprintf('sspak saveexisting %s 2>&1', $this->ArchiveFile()->FullPath);
573
-        if ($this->Mode == 'db') {
573
+        if($this->Mode == 'db') {
574 574
             $command .= sprintf(' --db=%s/database.sql', $workingDir);
575
-        } elseif ($this->Mode == 'assets') {
575
+        } elseif($this->Mode == 'assets') {
576 576
             $command .= sprintf(' --assets=%s/assets', $workingDir);
577 577
         } else {
578 578
             $command .= sprintf(' --db=%s/database.sql --assets=%s/assets', $workingDir, $workingDir);
@@ -581,7 +581,7 @@  discard block
 block discarded – undo
581 581
         $process = new Process($command, $workingDir);
582 582
         $process->setTimeout(3600);
583 583
         $process->run();
584
-        if (!$process->isSuccessful()) {
584
+        if(!$process->isSuccessful()) {
585 585
             throw new RuntimeException($process->getErrorOutput());
586 586
         }
587 587
 
Please login to merge, or discard this patch.
Braces   +23 added lines, -46 removed lines patch added patch discarded remove patch
@@ -47,8 +47,7 @@  discard block
 block discarded – undo
47 47
  * @method ManyManyList DataTransfers()
48 48
  *
49 49
  */
50
-class DNDataArchive extends DataObject
51
-{
50
+class DNDataArchive extends DataObject {
52 51
 
53 52
     private static $db = array(
54 53
         'UploadToken' => 'Varchar(8)',
@@ -104,8 +103,7 @@  discard block
 block discarded – undo
104 103
 
105 104
     private static $_cache_can_download = array();
106 105
 
107
-    public static function get_mode_map()
108
-    {
106
+    public static function get_mode_map() {
109 107
         return array(
110 108
             'all' => 'Database and Assets',
111 109
             'db' => 'Database only',
@@ -119,14 +117,12 @@  discard block
 block discarded – undo
119 117
      *
120 118
      * @return string
121 119
      */
122
-    public static function generate_upload_token($chars = 8)
123
-    {
120
+    public static function generate_upload_token($chars = 8) {
124 121
         $generator = new RandomGenerator();
125 122
         return strtoupper(substr($generator->randomToken(), 0, $chars));
126 123
     }
127 124
 
128
-    public function onBeforeWrite()
129
-    {
125
+    public function onBeforeWrite() {
130 126
         if (!$this->AuthorID) {
131 127
             $this->AuthorID = Member::currentUserID();
132 128
         }
@@ -134,13 +130,11 @@  discard block
 block discarded – undo
134 130
         parent::onBeforeWrite();
135 131
     }
136 132
 
137
-    public function onAfterDelete()
138
-    {
133
+    public function onAfterDelete() {
139 134
         $this->ArchiveFile()->delete();
140 135
     }
141 136
 
142
-    public function getCMSFields()
143
-    {
137
+    public function getCMSFields() {
144 138
         $fields = parent::getCMSFields();
145 139
         $fields->removeByName('OriginalEnvironmentID');
146 140
         $fields->removeByName('EnvironmentID');
@@ -173,8 +167,7 @@  discard block
 block discarded – undo
173 167
         return $fields;
174 168
     }
175 169
 
176
-    public function getDefaultSearchContext()
177
-    {
170
+    public function getDefaultSearchContext() {
178 171
         $context = parent::getDefaultSearchContext();
179 172
         $context->getFields()->dataFieldByName('Mode')->setHasEmptyDefault(true);
180 173
 
@@ -187,8 +180,7 @@  discard block
 block discarded – undo
187 180
      *
188 181
      * @return string The human-readable size of this archive file
189 182
      */
190
-    public function FileSize()
191
-    {
183
+    public function FileSize() {
192 184
         if ($this->ArchiveFile()->exists()) {
193 185
             return $this->ArchiveFile()->getSize();
194 186
         } else {
@@ -196,8 +188,7 @@  discard block
 block discarded – undo
196 188
         }
197 189
     }
198 190
 
199
-    public function getModeNice()
200
-    {
191
+    public function getModeNice() {
201 192
         if ($this->Mode == 'all') {
202 193
             return 'database and assets';
203 194
         } else {
@@ -212,8 +203,7 @@  discard block
 block discarded – undo
212 203
      *
213 204
      * @return boolean
214 205
      */
215
-    public function isPending()
216
-    {
206
+    public function isPending() {
217 207
         return !($this->ArchiveFileID);
218 208
     }
219 209
 
@@ -222,8 +212,7 @@  discard block
 block discarded – undo
222 212
      *
223 213
      * @param Member|null $member The {@link Member} object to test against.
224 214
      */
225
-    public function canView($member = null)
226
-    {
215
+    public function canView($member = null) {
227 216
         return ($this->canRestore($member) || $this->canDownload($member));
228 217
     }
229 218
 
@@ -234,8 +223,7 @@  discard block
 block discarded – undo
234 223
      * @param Member|null $member The {@link Member} object to test against.
235 224
      * @return true if $member (or the currently logged in member if null) can upload this archive
236 225
      */
237
-    public function canRestore($member = null)
238
-    {
226
+    public function canRestore($member = null) {
239 227
         $memberID = $member ? $member->ID : Member::currentUserID();
240 228
         if (!$memberID) {
241 229
             return false;
@@ -256,8 +244,7 @@  discard block
 block discarded – undo
256 244
      * @param Member|null $member The {@link Member} object to test against.
257 245
      * @return true if $member (or the currently logged in member if null) can download this archive
258 246
      */
259
-    public function canDownload($member = null)
260
-    {
247
+    public function canDownload($member = null) {
261 248
         $memberID = $member ? $member->ID : Member::currentUserID();
262 249
         if (!$memberID) {
263 250
             return false;
@@ -276,8 +263,7 @@  discard block
 block discarded – undo
276 263
      * @param Member|null $member The {@link Member} object to test against.
277 264
      * @return boolean if $member (or the currently logged in member if null) can delete this archive
278 265
      */
279
-    public function canDelete($member = null)
280
-    {
266
+    public function canDelete($member = null) {
281 267
         return $this->Environment()->canDeleteArchive($member);
282 268
     }
283 269
 
@@ -289,8 +275,7 @@  discard block
 block discarded – undo
289 275
      *
290 276
      * @return boolean true if $member can upload archives linked to this environment, false if they can't.
291 277
      */
292
-    public function canMoveTo($targetEnv, $member = null)
293
-    {
278
+    public function canMoveTo($targetEnv, $member = null) {
294 279
         if ($this->Environment()->Project()->ID != $targetEnv->Project()->ID) {
295 280
             // We don't permit moving snapshots between projects at this stage.
296 281
             return false;
@@ -327,8 +312,7 @@  discard block
 block discarded – undo
327 312
      *
328 313
      * @return ArrayList List of valid environments.
329 314
      */
330
-    public function validTargetEnvironments()
331
-    {
315
+    public function validTargetEnvironments() {
332 316
         $archive = $this;
333 317
         $envs = $this->Environment()->Project()->DNEnvironmentList()
334 318
             ->filterByCallback(function ($item) use ($archive) {
@@ -342,8 +326,7 @@  discard block
 block discarded – undo
342 326
      * Returns a unique filename, including project/environment/timestamp details.
343 327
      * @return string
344 328
      */
345
-    public function generateFilename(DNDataTransfer $dataTransfer)
346
-    {
329
+    public function generateFilename(DNDataTransfer $dataTransfer) {
347 330
         $generator = new RandomGenerator();
348 331
         $filter = FileNameFilter::create();
349 332
 
@@ -364,8 +347,7 @@  discard block
 block discarded – undo
364 347
      * @param DNDataTransfer
365 348
      * @return string Absolute file path
366 349
      */
367
-    public function generateFilepath(DNDataTransfer $dataTransfer)
368
-    {
350
+    public function generateFilepath(DNDataTransfer $dataTransfer) {
369 351
         $data = DNData::inst();
370 352
         $transferDir = $data->getDataTransferDir();
371 353
         $filter = FileNameFilter::create();
@@ -386,8 +368,7 @@  discard block
 block discarded – undo
386 368
      * @param DNDataTransfer $dataTransfer
387 369
      * @return bool
388 370
      */
389
-    public function attachFile($sspakFilepath, DNDataTransfer $dataTransfer)
390
-    {
371
+    public function attachFile($sspakFilepath, DNDataTransfer $dataTransfer) {
391 372
         $sspakFilepath = ltrim(
392 373
             str_replace(
393 374
                 array(ASSETS_PATH, realpath(ASSETS_PATH)),
@@ -431,8 +412,7 @@  discard block
 block discarded – undo
431 412
      * @throws RuntimeException
432 413
      * @return bool
433 414
      */
434
-    public function extractArchive($workingDir = null)
435
-    {
415
+    public function extractArchive($workingDir = null) {
436 416
         if (!is_dir($workingDir)) {
437 417
             mkdir($workingDir, 0700, true);
438 418
         }
@@ -490,8 +470,7 @@  discard block
 block discarded – undo
490 470
      * @param string|null $mode "db", "assets", or "all". This is the content we're checking for. Default to the archive setting
491 471
      * @return ValidationResult
492 472
      */
493
-    public function validateArchiveContents($mode = null)
494
-    {
473
+    public function validateArchiveContents($mode = null) {
495 474
         $mode = $mode ?: $this->Mode;
496 475
         $result = new ValidationResult();
497 476
 
@@ -539,8 +518,7 @@  discard block
 block discarded – undo
539 518
      * @throws RuntimeException
540 519
      * @return bool
541 520
      */
542
-    public function fixArchivePermissions($workingDir)
543
-    {
521
+    public function fixArchivePermissions($workingDir) {
544 522
         $fixCmds = array(
545 523
             // The directories need to have permissions changed one by one (hence the ; instead of +),
546 524
             // otherwise we might end up having no +x access to a directory deeper down.
@@ -567,8 +545,7 @@  discard block
 block discarded – undo
567 545
      * @param string|null $workingDir The path of where the sspak has been extracted to
568 546
      * @return bool
569 547
      */
570
-    public function setArchiveFromFiles($workingDir)
571
-    {
548
+    public function setArchiveFromFiles($workingDir) {
572 549
         $command = sprintf('sspak saveexisting %s 2>&1', $this->ArchiveFile()->FullPath);
573 550
         if ($this->Mode == 'db') {
574 551
             $command .= sprintf(' --db=%s/database.sql', $workingDir);
Please login to merge, or discard this patch.
code/model/DNFailedCommits.php 2 patches
Indentation   +6 added lines, -6 removed lines patch added patch discarded remove patch
@@ -9,11 +9,11 @@
 block discarded – undo
9 9
 class DNFailedCommits extends DNFilteredCommits
10 10
 {
11 11
 
12
-    private $description = 'Commits that have failed in the past';
12
+	private $description = 'Commits that have failed in the past';
13 13
 
14
-    public function __construct()
15
-    {
16
-        parent::__construct();
17
-        $this->setFilter('Failed');
18
-    }
14
+	public function __construct()
15
+	{
16
+		parent::__construct();
17
+		$this->setFilter('Failed');
18
+	}
19 19
 }
Please login to merge, or discard this patch.
Braces   +2 added lines, -4 removed lines patch added patch discarded remove patch
@@ -6,13 +6,11 @@
 block discarded – undo
6 6
  *  Class to represent failed commits
7 7
  *
8 8
  */
9
-class DNFailedCommits extends DNFilteredCommits
10
-{
9
+class DNFailedCommits extends DNFilteredCommits {
11 10
 
12 11
     private $description = 'Commits that have failed in the past';
13 12
 
14
-    public function __construct()
15
-    {
13
+    public function __construct() {
16 14
         parent::__construct();
17 15
         $this->setFilter('Failed');
18 16
     }
Please login to merge, or discard this patch.
code/model/DNFilteredCommits.php 3 patches
Indentation   +32 added lines, -32 removed lines patch added patch discarded remove patch
@@ -30,43 +30,43 @@
 block discarded – undo
30 30
 class DNFilteredCommits extends Object
31 31
 {
32 32
 
33
-    public $env;
33
+	public $env;
34 34
 
35
-    private $filter;
35
+	private $filter;
36 36
 
37
-    private $environmentExceptionError = 'Environment has not been set';
37
+	private $environmentExceptionError = 'Environment has not been set';
38 38
 
39
-    // default sort to be by the latest commit
40
-    protected $sort = 'DESC';
39
+	// default sort to be by the latest commit
40
+	protected $sort = 'DESC';
41 41
 
42
-    public function setFilter($filter = 'Finished')
43
-    {
44
-        $this->filter = $filter;
45
-    }
42
+	public function setFilter($filter = 'Finished')
43
+	{
44
+		$this->filter = $filter;
45
+	}
46 46
 
47
-    public function getCommits()
48
-    {
49
-        if (!isset($this->env)) {
50
-            $this->environmentNotSetException();
51
-        }
52
-        $successfulCommits =
53
-            $this->env->DeployHistory()->filter(
54
-                array('Status' => $this->filter, 'EnvironmentID' => $this->env->ID)
55
-            )->sort('Created', $this->sort);
56
-        return $successfulCommits;
57
-    }
47
+	public function getCommits()
48
+	{
49
+		if (!isset($this->env)) {
50
+			$this->environmentNotSetException();
51
+		}
52
+		$successfulCommits =
53
+			$this->env->DeployHistory()->filter(
54
+				array('Status' => $this->filter, 'EnvironmentID' => $this->env->ID)
55
+			)->sort('Created', $this->sort);
56
+		return $successfulCommits;
57
+	}
58 58
 
59
-    public function getLatestCommit()
60
-    {
61
-        if (!isset($this->env)) {
62
-            $this->environmentNotSetException();
63
-        }
64
-        $commits = $this->getCommits();
65
-        return $commits->first();
66
-    }
59
+	public function getLatestCommit()
60
+	{
61
+		if (!isset($this->env)) {
62
+			$this->environmentNotSetException();
63
+		}
64
+		$commits = $this->getCommits();
65
+		return $commits->first();
66
+	}
67 67
 
68
-    private function environmentNotSetException()
69
-    {
70
-        throw new Exception($this->environmentExceptionError);
71
-    }
68
+	private function environmentNotSetException()
69
+	{
70
+		throw new Exception($this->environmentExceptionError);
71
+	}
72 72
 }
Please login to merge, or discard this patch.
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -46,7 +46,7 @@  discard block
 block discarded – undo
46 46
 
47 47
     public function getCommits()
48 48
     {
49
-        if (!isset($this->env)) {
49
+        if(!isset($this->env)) {
50 50
             $this->environmentNotSetException();
51 51
         }
52 52
         $successfulCommits =
@@ -58,7 +58,7 @@  discard block
 block discarded – undo
58 58
 
59 59
     public function getLatestCommit()
60 60
     {
61
-        if (!isset($this->env)) {
61
+        if(!isset($this->env)) {
62 62
             $this->environmentNotSetException();
63 63
         }
64 64
         $commits = $this->getCommits();
Please login to merge, or discard this patch.
Braces   +5 added lines, -10 removed lines patch added patch discarded remove patch
@@ -27,8 +27,7 @@  discard block
 block discarded – undo
27 27
  *    PerformTestOn: 'ThisEnvironment'
28 28
  *
29 29
  */
30
-class DNFilteredCommits extends Object
31
-{
30
+class DNFilteredCommits extends Object {
32 31
 
33 32
     public $env;
34 33
 
@@ -39,13 +38,11 @@  discard block
 block discarded – undo
39 38
     // default sort to be by the latest commit
40 39
     protected $sort = 'DESC';
41 40
 
42
-    public function setFilter($filter = 'Finished')
43
-    {
41
+    public function setFilter($filter = 'Finished') {
44 42
         $this->filter = $filter;
45 43
     }
46 44
 
47
-    public function getCommits()
48
-    {
45
+    public function getCommits() {
49 46
         if (!isset($this->env)) {
50 47
             $this->environmentNotSetException();
51 48
         }
@@ -56,8 +53,7 @@  discard block
 block discarded – undo
56 53
         return $successfulCommits;
57 54
     }
58 55
 
59
-    public function getLatestCommit()
60
-    {
56
+    public function getLatestCommit() {
61 57
         if (!isset($this->env)) {
62 58
             $this->environmentNotSetException();
63 59
         }
@@ -65,8 +61,7 @@  discard block
 block discarded – undo
65 61
         return $commits->first();
66 62
     }
67 63
 
68
-    private function environmentNotSetException()
69
-    {
64
+    private function environmentNotSetException() {
70 65
         throw new Exception($this->environmentExceptionError);
71 66
     }
72 67
 }
Please login to merge, or discard this patch.
code/model/DNFinishedCommits.php 2 patches
Indentation   +9 added lines, -9 removed lines patch added patch discarded remove patch
@@ -8,14 +8,14 @@
 block discarded – undo
8 8
  */
9 9
 class DNFinishedCommits extends DNFilteredCommits
10 10
 {
11
-    /**
12
-     * @var string
13
-     */
14
-    private $description = 'Commits successfully deployed in the past';
11
+	/**
12
+	 * @var string
13
+	 */
14
+	private $description = 'Commits successfully deployed in the past';
15 15
 
16
-    public function __construct()
17
-    {
18
-        parent::__construct();
19
-        $this->setFilter('Finished');
20
-    }
16
+	public function __construct()
17
+	{
18
+		parent::__construct();
19
+		$this->setFilter('Finished');
20
+	}
21 21
 }
Please login to merge, or discard this patch.
Braces   +2 added lines, -4 removed lines patch added patch discarded remove patch
@@ -6,15 +6,13 @@
 block discarded – undo
6 6
  *  Class to represent finished commits
7 7
  *
8 8
  */
9
-class DNFinishedCommits extends DNFilteredCommits
10
-{
9
+class DNFinishedCommits extends DNFilteredCommits {
11 10
     /**
12 11
      * @var string
13 12
      */
14 13
     private $description = 'Commits successfully deployed in the past';
15 14
 
16
-    public function __construct()
17
-    {
15
+    public function __construct() {
18 16
         parent::__construct();
19 17
         $this->setFilter('Finished');
20 18
     }
Please login to merge, or discard this patch.
code/model/DNProject.php 3 patches
Indentation   +1157 added lines, -1157 removed lines patch added patch discarded remove patch
@@ -15,887 +15,887 @@  discard block
 block discarded – undo
15 15
 class DNProject extends DataObject
16 16
 {
17 17
 
18
-    /**
19
-     * @var array
20
-     */
21
-    public static $db = array(
22
-        "Name" => "Varchar",
23
-        "CVSPath" => "Varchar(255)",
24
-        "DiskQuotaMB" => "Int",
25
-        "AllowedEnvironmentType" => "Varchar(255)",
26
-    );
27
-
28
-    /**
29
-     * @var array
30
-     */
31
-    public static $has_many = array(
32
-        "Environments" => "DNEnvironment",
33
-        "CreateEnvironments" => "DNCreateEnvironment"
34
-    );
35
-
36
-    /**
37
-     * @var array
38
-     */
39
-    public static $many_many = array(
40
-        "Viewers" => "Group",
41
-        'StarredBy' => "Member"
42
-    );
43
-
44
-    /**
45
-     * @var array
46
-     */
47
-    public static $summary_fields = array(
48
-        "Name",
49
-        "ViewersList",
50
-    );
51
-
52
-    /**
53
-     * @var array
54
-     */
55
-    public static $searchable_fields = array(
56
-        "Name",
57
-    );
58
-
59
-    /**
60
-     * @var string
61
-     */
62
-    private static $singular_name = 'Project';
63
-
64
-    /**
65
-     * @var string
66
-     */
67
-    private static $plural_name = 'Projects';
68
-
69
-    /**
70
-     * @var string
71
-     */
72
-    private static $default_sort = 'Name';
73
-
74
-    /**
75
-     * Display the repository URL on the project page.
76
-     *
77
-     * @var bool
78
-     */
79
-    private static $show_repository_url = false;
80
-
81
-    /**
82
-     * In-memory cache for currentBuilds per environment since fetching them from
83
-     * disk is pretty resource hungry.
84
-     *
85
-     * @var array
86
-     */
87
-    protected static $relation_cache = array();
88
-
89
-    /**
90
-     * In-memory cache to determine whether clone repo was called.
91
-     * @var array
92
-     */
93
-    private static $has_cloned_cache = array();
94
-
95
-    /**
96
-     * @var bool|Member
97
-     */
98
-    protected static $_current_member_cache = null;
99
-
100
-    /**
101
-     * Used by the sync task
102
-     *
103
-     * @param string $path
104
-     * @return \DNProject
105
-     */
106
-    public static function create_from_path($path)
107
-    {
108
-        $project = DNProject::create();
109
-        $project->Name = $path;
110
-        $project->write();
111
-
112
-        // add the administrators group as the viewers of the new project
113
-        $adminGroup = Group::get()->filter('Code', 'administrators')->first();
114
-        if ($adminGroup && $adminGroup->exists()) {
115
-            $project->Viewers()->add($adminGroup);
116
-        }
117
-        return $project;
118
-    }
119
-
120
-    /**
121
-     * Return the used quota in MB.
122
-     *
123
-     * @param int $round Number of decimal places to round to
124
-     * @return double The used quota size in MB
125
-     */
126
-    public function getUsedQuotaMB($round = 2)
127
-    {
128
-        $size = 0;
129
-
130
-        foreach ($this->Environments() as $environment) {
131
-            foreach ($environment->DataArchives()->filter('IsBackup', 0) as $archive) {
132
-                $size += $archive->ArchiveFile()->getAbsoluteSize();
133
-            }
134
-        }
135
-
136
-        // convert bytes to megabytes and round
137
-        return round(($size / 1024) / 1024, $round);
138
-    }
139
-
140
-    /**
141
-     * Getter for DiskQuotaMB field to provide a default for existing
142
-     * records that have no quota field set, as it will need to default
143
-     * to a globally set size.
144
-     *
145
-     * @return string|int The quota size in MB
146
-     */
147
-    public function getDiskQuotaMB()
148
-    {
149
-        $size = $this->getField('DiskQuotaMB');
150
-
151
-        if (empty($size)) {
152
-            $defaults = $this->config()->get('defaults');
153
-            $size = (isset($defaults['DiskQuotaMB'])) ? $defaults['DiskQuotaMB'] : 0;
154
-        }
155
-
156
-        return $size;
157
-    }
158
-
159
-    /**
160
-     * Has the disk quota been exceeded?
161
-     *
162
-     * @return boolean
163
-     */
164
-    public function HasExceededDiskQuota()
165
-    {
166
-        return $this->getUsedQuotaMB(0) >= $this->getDiskQuotaMB();
167
-    }
168
-
169
-    /**
170
-     * Is there a disk quota set for this project?
171
-     *
172
-     * @return boolean
173
-     */
174
-    public function HasDiskQuota()
175
-    {
176
-        return $this->getDiskQuotaMB() > 0;
177
-    }
178
-
179
-    /**
180
-     * Returns the current disk quota usage as a percentage
181
-     *
182
-     * @return int
183
-     */
184
-    public function DiskQuotaUsagePercent()
185
-    {
186
-        $quota = $this->getDiskQuotaMB();
187
-        if ($quota > 0) {
188
-            return $this->getUsedQuotaMB() * 100 / $quota;
189
-        }
190
-        return 100;
191
-    }
192
-
193
-    /**
194
-     * Get the menu to be shown on projects
195
-     *
196
-     * @return ArrayList
197
-     */
198
-    public function Menu()
199
-    {
200
-        $list = new ArrayList();
201
-
202
-        $controller = Controller::curr();
203
-        $actionType = $controller->getField('CurrentActionType');
204
-
205
-        if (DNRoot::FlagSnapshotsEnabled() && $this->isProjectReady()) {
206
-            $list->push(new ArrayData(array(
207
-                'Link' => sprintf('naut/project/%s/snapshots', $this->Name),
208
-                'Title' => 'Snapshots',
209
-                'IsCurrent' => $this->isSection() && $controller->getAction() == 'snapshots',
210
-                'IsSection' => $this->isSection() && $actionType == DNRoot::ACTION_SNAPSHOT
211
-            )));
212
-        }
213
-
214
-        $this->extend('updateMenu', $list);
215
-
216
-        return $list;
217
-    }
218
-
219
-    /**
220
-     * Is this project currently at the root level of the controller that handles it?
221
-     *
222
-     * @return bool
223
-     */
224
-    public function isCurrent()
225
-    {
226
-        return $this->isSection() && Controller::curr()->getAction() == 'project';
227
-    }
228
-
229
-    /**
230
-     * Return the current object from $this->Menu()
231
-     * Good for making titles and things
232
-     *
233
-     * @return DataObject
234
-     */
235
-    public function CurrentMenu()
236
-    {
237
-        return $this->Menu()->filter('IsSection', true)->First();
238
-    }
239
-
240
-    /**
241
-     * Is this project currently in a controller that is handling it or performing a sub-task?
242
-     *
243
-     * @return bool
244
-     */
245
-    public function isSection()
246
-    {
247
-        $controller = Controller::curr();
248
-        $project = $controller->getField('CurrentProject');
249
-        return $project && $this->ID == $project->ID;
250
-    }
251
-
252
-    /**
253
-     * Restrict access to viewing this project
254
-     *
255
-     * @param Member|null $member
256
-     * @return boolean
257
-     */
258
-    public function canView($member = null)
259
-    {
260
-        if (!$member) {
261
-            $member = Member::currentUser();
262
-        }
263
-
264
-        if (Permission::checkMember($member, 'ADMIN')) {
265
-            return true;
266
-        }
267
-
268
-        return $member->inGroups($this->Viewers());
269
-    }
270
-
271
-    /**
272
-     * @param Member|null $member
273
-     *
274
-     * @return bool
275
-     */
276
-    public function canRestore($member = null)
277
-    {
278
-        if ($this->allowedAny(
279
-            array(
280
-                DNRoot::ALLOW_PROD_SNAPSHOT,
281
-                DNRoot::ALLOW_NON_PROD_SNAPSHOT
282
-            ),
283
-            $member
284
-        )) {
285
-            return true;
286
-        }
287
-
288
-        return (bool)$this->Environments()->filterByCallback(function ($env) use ($member) {
289
-            return $env->canRestore($member);
290
-        })->Count();
291
-    }
292
-
293
-    /**
294
-     * @param Member|null $member
295
-     * @return bool
296
-     */
297
-    public function canBackup($member = null)
298
-    {
299
-        if ($this->allowedAny(
300
-            array(
301
-                DNRoot::ALLOW_PROD_SNAPSHOT,
302
-                DNRoot::ALLOW_NON_PROD_SNAPSHOT
303
-            ),
304
-            $member
305
-        )) {
306
-            return true;
307
-        }
308
-
309
-        return (bool)$this->Environments()->filterByCallback(function ($env) use ($member) {
310
-            return $env->canBackup($member);
311
-        })->Count();
312
-    }
313
-
314
-    /**
315
-     * @param Member|null $member
316
-     * @return bool
317
-     */
318
-    public function canUploadArchive($member = null)
319
-    {
320
-        if ($this->allowedAny(
321
-            array(
322
-                DNRoot::ALLOW_PROD_SNAPSHOT,
323
-                DNRoot::ALLOW_NON_PROD_SNAPSHOT
324
-            ),
325
-            $member
326
-        )) {
327
-            return true;
328
-        }
329
-
330
-        return (bool)$this->Environments()->filterByCallback(function ($env) use ($member) {
331
-            return $env->canUploadArchive($member);
332
-        })->Count();
333
-    }
334
-
335
-    /**
336
-     * @param Member|null $member
337
-     * @return bool
338
-     */
339
-    public function canDownloadArchive($member = null)
340
-    {
341
-        if ($this->allowedAny(
342
-            array(
343
-                DNRoot::ALLOW_PROD_SNAPSHOT,
344
-                DNRoot::ALLOW_NON_PROD_SNAPSHOT
345
-            ),
346
-            $member
347
-        )) {
348
-            return true;
349
-        }
350
-
351
-        return (bool)$this->Environments()->filterByCallback(function ($env) use ($member) {
352
-            return $env->canDownloadArchive($member);
353
-        })->Count();
354
-    }
355
-
356
-    /**
357
-     * This is a permission check for the front-end only.
358
-     *
359
-     * Only admins can create environments for now. Also, we need to check the value
360
-     * of AllowedEnvironmentType which dictates which backend to use to render the form.
361
-     *
362
-     * @param Member|null $member
363
-     *
364
-     * @return bool
365
-     */
366
-    public function canCreateEnvironments($member = null)
367
-    {
368
-        $envType = $this->AllowedEnvironmentType;
369
-        if ($envType) {
370
-            $env = Injector::inst()->get($envType);
371
-            if ($env instanceof EnvironmentCreateBackend) {
372
-                return $this->allowed(DNRoot::ALLOW_CREATE_ENVIRONMENT, $member);
373
-            }
374
-        }
375
-        return false;
376
-    }
377
-
378
-    /**
379
-     * @return DataList
380
-     */
381
-    public function DataArchives()
382
-    {
383
-        $envIds = $this->Environments()->column('ID');
384
-        return DNDataArchive::get()->filter('EnvironmentID', $envIds);
385
-    }
386
-
387
-    /**
388
-     * Return all archives which are "manual upload requests",
389
-     * meaning they don't have a file attached to them (yet).
390
-     *
391
-     * @return DataList
392
-     */
393
-    public function PendingManualUploadDataArchives()
394
-    {
395
-        return $this->DataArchives()->filter('ArchiveFileID', null);
396
-    }
397
-
398
-    /**
399
-     * Build an environment variable array to be used with this project.
400
-     *
401
-     * This is relevant if every project needs to use an individual SSH pubkey.
402
-     *
403
-     * Include this with all Gitonomy\Git\Repository, and
404
-     * \Symfony\Component\Process\Processes.
405
-     *
406
-     * @return array
407
-     */
408
-    public function getProcessEnv()
409
-    {
410
-        if (file_exists($this->getPrivateKeyPath())) {
411
-            // Key-pair is available, use it.
412
-            $processEnv = array(
413
-                'IDENT_KEY' => $this->getPrivateKeyPath(),
414
-                'GIT_SSH' => BASE_PATH . "/deploynaut/git-deploy.sh"
415
-            );
416
-        } else {
417
-            $processEnv = array();
418
-        }
419
-        $this->extend('updateProcessEnv', $processEnv);
420
-
421
-        return $processEnv;
422
-    }
423
-
424
-    /**
425
-     * Get a string of people allowed to view this project
426
-     *
427
-     * @return string
428
-     */
429
-    public function getViewersList()
430
-    {
431
-        return implode(", ", $this->Viewers()->column("Title"));
432
-    }
433
-
434
-    /**
435
-     * @return DNData
436
-     */
437
-    public function DNData()
438
-    {
439
-        return DNData::inst();
440
-    }
441
-
442
-    /**
443
-     * Provides a DNBuildList of builds found in this project.
444
-     *
445
-     * @return DNReferenceList
446
-     */
447
-    public function DNBuildList()
448
-    {
449
-        return DNReferenceList::create($this, $this->DNData());
450
-    }
451
-
452
-    /**
453
-     * Provides a list of the branches in this project.
454
-     *
455
-     * @return DNBranchList
456
-     */
457
-    public function DNBranchList()
458
-    {
459
-        if ($this->CVSPath && !$this->repoExists()) {
460
-            $this->cloneRepo();
461
-        }
462
-        return DNBranchList::create($this, $this->DNData());
463
-    }
464
-
465
-    /**
466
-     * Provides a list of the tags in this project.
467
-     *
468
-     * @return DNReferenceList
469
-     */
470
-    public function DNTagList()
471
-    {
472
-        if ($this->CVSPath && !$this->repoExists()) {
473
-            $this->cloneRepo();
474
-        }
475
-        return DNReferenceList::create($this, $this->DNData(), null, null, true);
476
-    }
477
-
478
-    /**
479
-     * @return false|Gitonomy\Git\Repository
480
-     */
481
-    public function getRepository()
482
-    {
483
-        if (!$this->repoExists()) {
484
-            return false;
485
-        }
486
-
487
-        return new Gitonomy\Git\Repository($this->getLocalCVSPath());
488
-    }
489
-
490
-    /**
491
-     * Provides a list of environments found in this project.
492
-     * CAUTION: filterByCallback will change this into an ArrayList!
493
-     *
494
-     * @return ArrayList
495
-     */
496
-    public function DNEnvironmentList()
497
-    {
498
-        if (!self::$_current_member_cache) {
499
-            self::$_current_member_cache = Member::currentUser();
500
-        }
501
-
502
-        if (self::$_current_member_cache === false) {
503
-            return new ArrayList();
504
-        }
505
-
506
-        $currentMember = self::$_current_member_cache;
507
-        return $this->Environments()
508
-            ->filterByCallBack(function ($item) use ($currentMember) {
509
-                return $item->canView($currentMember);
510
-            });
511
-    }
512
-
513
-    /**
514
-     * @param string $usage
515
-     * @return ArrayList
516
-     */
517
-    public function EnvironmentsByUsage($usage)
518
-    {
519
-        return $this->DNEnvironmentList()->filter('Usage', $usage);
520
-    }
521
-
522
-    /**
523
-     * Returns a map of envrionment name to build name
524
-     *
525
-     * @return false|DNDeployment
526
-     */
527
-    public function currentBuilds()
528
-    {
529
-        if (!isset(self::$relation_cache['currentBuilds.'.$this->ID])) {
530
-            $currentBuilds = array();
531
-            foreach ($this->Environments() as $env) {
532
-                $currentBuilds[$env->Name] = $env->CurrentBuild();
533
-            }
534
-            self::$relation_cache['currentBuilds.'.$this->ID] = $currentBuilds;
535
-        }
536
-        return self::$relation_cache['currentBuilds.'.$this->ID];
537
-    }
538
-
539
-    /**
540
-     * @param string
541
-     * @return string
542
-     */
543
-    public function Link($action = '')
544
-    {
545
-        return Controller::join_links("naut", "project", $this->Name, $action);
546
-    }
547
-
548
-    /**
549
-     * @return string|null
550
-     */
551
-    public function CreateEnvironmentLink()
552
-    {
553
-        if ($this->canCreateEnvironments()) {
554
-            return $this->Link('createenv');
555
-        }
556
-        return null;
557
-    }
558
-
559
-    /**
560
-     * @return string
561
-     */
562
-    public function ToggleStarLink()
563
-    {
564
-        return $this->Link('/star');
565
-    }
566
-
567
-    /**
568
-     * @return bool
569
-     */
570
-    public function IsStarred()
571
-    {
572
-        $member = Member::currentUser();
573
-        if ($member === null) {
574
-            return false;
575
-        }
576
-        $favourited = $this->StarredBy()->filter('MemberID', $member->ID);
577
-        if ($favourited->count() == 0) {
578
-            return false;
579
-        }
580
-        return true;
581
-    }
582
-
583
-    /**
584
-     * @param string $action
585
-     * @return string
586
-     */
587
-    public function APILink($action)
588
-    {
589
-        return Controller::join_links("naut", "api", $this->Name, $action);
590
-    }
591
-
592
-    /**
593
-     * @return FieldList
594
-     */
595
-    public function getCMSFields()
596
-    {
597
-        $fields = parent::getCMSFields();
598
-
599
-        /** @var GridField $environments */
600
-        $environments = $fields->dataFieldByName("Environments");
601
-
602
-        $fields->fieldByName("Root")->removeByName("Viewers");
603
-        $fields->fieldByName("Root")->removeByName("Environments");
604
-        $fields->fieldByName("Root")->removeByName("LocalCVSPath");
605
-
606
-        $diskQuotaDesc = 'This is the maximum amount of disk space (in megabytes) that all environments within this '
607
-            . 'project can use for stored snapshots';
608
-        $fields->dataFieldByName('DiskQuotaMB')->setDescription($diskQuotaDesc);
609
-
610
-        $projectNameDesc = 'Changing the name will <strong>reset</strong> the deploy configuration and avoid using non'
611
-            . 'alphanumeric characters';
612
-        $fields->fieldByName('Root.Main.Name')
613
-            ->setTitle('Project name')
614
-            ->setDescription($projectNameDesc);
615
-
616
-        $fields->fieldByName('Root.Main.CVSPath')
617
-            ->setTitle('Git repository')
618
-            ->setDescription('E.g. [email protected]:silverstripe/silverstripe-installer.git');
619
-
620
-        $workspaceField = new ReadonlyField('LocalWorkspace', 'Git workspace', $this->getLocalCVSPath());
621
-        $workspaceField->setDescription('This is where the GIT repository are located on this server');
622
-        $fields->insertAfter($workspaceField, 'CVSPath');
623
-
624
-        $readAccessGroups = ListboxField::create('Viewers', 'Project viewers', Group::get()->map()->toArray())
625
-            ->setMultiple(true)
626
-            ->setDescription('These groups can view the project in the front-end.');
627
-        $fields->addFieldToTab("Root.Main", $readAccessGroups);
628
-
629
-        $this->setCreateProjectFolderField($fields);
630
-        $this->setEnvironmentFields($fields, $environments);
631
-
632
-        $environmentTypes = ClassInfo::implementorsOf('EnvironmentCreateBackend');
633
-        $types = array();
634
-        foreach ($environmentTypes as $type) {
635
-            $types[$type] = $type;
636
-        }
637
-
638
-        $fields->addFieldsToTab('Root.Main', array(
639
-            DropdownField::create(
640
-                'AllowedEnvironmentType',
641
-                'Allowed Environment Type',
642
-                $types
643
-            )->setDescription('This defined which form to show on the front end for '
644
-                . 'environment creation. This will not affect backend functionality.')
645
-            ->setEmptyString(' - None - '),
646
-        ));
647
-
648
-        return $fields;
649
-    }
650
-
651
-    /**
652
-     * If there isn't a capistrano env project folder, show options to create one
653
-     *
654
-     * @param FieldList $fields
655
-     */
656
-    public function setCreateProjectFolderField(&$fields)
657
-    {
658
-        // Check if the capistrano project folder exists
659
-        if (!$this->Name) {
660
-            return;
661
-        }
662
-
663
-        if ($this->projectFolderExists()) {
664
-            return;
665
-        }
666
-
667
-        $createFolderNotice = new LabelField('CreateEnvFolderNotice', 'Warning: No Capistrano project folder exists');
668
-        $createFolderNotice->addExtraClass('message warning');
669
-        $fields->insertBefore($createFolderNotice, 'Name');
670
-        $createFolderField = new CheckboxField('CreateEnvFolder', 'Create folder');
671
-        $createFolderField->setDescription('Would you like to create the capistrano project folder?');
672
-        $fields->insertAfter($createFolderField, 'CreateEnvFolderNotice');
673
-    }
674
-
675
-    /**
676
-     * @return boolean
677
-     */
678
-    public function projectFolderExists()
679
-    {
680
-        return file_exists($this->getProjectFolderPath());
681
-    }
682
-
683
-    /**
684
-     * @return bool
685
-     */
686
-    public function repoExists()
687
-    {
688
-        return file_exists(sprintf('%s/HEAD', $this->getLocalCVSPath()));
689
-    }
690
-
691
-    /**
692
-     * Setup a job to clone a git repository.
693
-     * @return string resque token
694
-     */
695
-    public function cloneRepo()
696
-    {
697
-        // Avoid this being called multiple times in the same request
698
-        if (!isset(self::$has_cloned_cache[$this->ID])) {
699
-            $fetch = DNGitFetch::create();
700
-            $fetch->ProjectID = $this->ID;
701
-            $fetch->write();
702
-
703
-            // passing true here tells DNGitFetch to force a git clone, otherwise
704
-            // it will just update the repo if it already exists. We want to ensure
705
-            // we're always cloning a new repo in this case, as the git URL may have changed.
706
-            $fetch->start(true);
707
-
708
-            self::$has_cloned_cache[$this->ID] = true;
709
-        }
710
-    }
711
-
712
-    /**
713
-     * @return string
714
-     */
715
-    public function getLocalCVSPath()
716
-    {
717
-        return sprintf('%s/%s', DEPLOYNAUT_LOCAL_VCS_PATH, $this->Name);
718
-    }
719
-
720
-    public function onBeforeWrite()
721
-    {
722
-        parent::onBeforeWrite();
723
-
724
-        if ($this->CreateEnvFolder && !file_exists($this->getProjectFolderPath())) {
725
-            mkdir($this->getProjectFolderPath());
726
-        }
727
-    }
728
-
729
-    public function onAfterWrite()
730
-    {
731
-        parent::onAfterWrite();
732
-
733
-        if (!$this->CVSPath) {
734
-            return;
735
-        }
736
-
737
-        $changedFields = $this->getChangedFields(true, 2);
738
-        if (isset($changedFields['CVSPath']) || isset($changedFields['Name'])) {
739
-            $this->cloneRepo();
740
-        }
741
-    }
742
-
743
-    /**
744
-     * Delete related environments and folders
745
-     */
746
-    public function onAfterDelete()
747
-    {
748
-        parent::onAfterDelete();
749
-
750
-        // Delete related environments
751
-        foreach ($this->Environments() as $env) {
752
-            $env->delete();
753
-        }
754
-
755
-        // Delete local repository
756
-        if (file_exists($this->getLocalCVSPath())) {
757
-            Filesystem::removeFolder($this->getLocalCVSPath());
758
-        }
759
-
760
-        // Delete project template
761
-        if (file_exists($this->getProjectFolderPath()) && Config::inst()->get('DNEnvironment', 'allow_web_editing')) {
762
-            Filesystem::removeFolder($this->getProjectFolderPath());
763
-        }
764
-
765
-        // Delete the deploy key
766
-        if (file_exists($this->getKeyDir())) {
767
-            Filesystem::removeFolder($this->getKeyDir());
768
-        }
769
-    }
770
-
771
-    /**
772
-     * Fetch the public key for this project.
773
-     *
774
-     * @return string|void
775
-     */
776
-    public function getPublicKey()
777
-    {
778
-        $key = $this->getPublicKeyPath();
779
-
780
-        if (file_exists($key)) {
781
-            return trim(file_get_contents($key));
782
-        }
783
-    }
784
-
785
-    /**
786
-     * This returns that path of the public key if a key directory is set. It doesn't check whether the file exists.
787
-     *
788
-     * @return string|null
789
-     */
790
-    public function getPublicKeyPath()
791
-    {
792
-        if ($privateKey = $this->getPrivateKeyPath()) {
793
-            return $privateKey . '.pub';
794
-        }
795
-        return null;
796
-    }
797
-
798
-    /**
799
-     * This returns that path of the private key if a key directory is set. It doesn't check whether the file exists.
800
-     *
801
-     * @return string|null
802
-     */
803
-    public function getPrivateKeyPath()
804
-    {
805
-        $keyDir = $this->getKeyDir();
806
-        if (!empty($keyDir)) {
807
-            $filter = FileNameFilter::create();
808
-            $name = $filter->filter($this->Name);
809
-            return $keyDir . '/' . $name;
810
-        }
811
-        return null;
812
-    }
813
-
814
-    /**
815
-     * Returns the location of the projects key dir if one exists.
816
-     *
817
-     * @return string|null
818
-     */
819
-    public function getKeyDir()
820
-    {
821
-        $keyDir = $this->DNData()->getKeyDir();
822
-        if (!$keyDir) {
823
-            return null;
824
-        }
825
-
826
-        $filter = FileNameFilter::create();
827
-        $name = $filter->filter($this->Name);
828
-
829
-        return $this->DNData()->getKeyDir() . '/' . $name;
830
-    }
831
-
832
-    /**
833
-     * Setup a gridfield for the environment configs
834
-     *
835
-     * @param FieldList $fields
836
-     * @param GridField $environments
837
-     */
838
-    protected function setEnvironmentFields(&$fields, $environments)
839
-    {
840
-        if (!$environments) {
841
-            return;
842
-        }
843
-
844
-        $environments->getConfig()->addComponent(new GridFieldAddNewMultiClass());
845
-        $environments->getConfig()->removeComponentsByType('GridFieldAddNewButton');
846
-        $environments->getConfig()->removeComponentsByType('GridFieldAddExistingAutocompleter');
847
-        $environments->getConfig()->removeComponentsByType('GridFieldDeleteAction');
848
-        $environments->getConfig()->removeComponentsByType('GridFieldPageCount');
849
-        if (Config::inst()->get('DNEnvironment', 'allow_web_editing')) {
850
-            $addNewRelease = new GridFieldAddNewButton('toolbar-header-right');
851
-            $addNewRelease->setButtonName('Add');
852
-            $environments->getConfig()->addComponent($addNewRelease);
853
-        }
854
-
855
-        $fields->addFieldToTab("Root.Main", $environments);
856
-    }
857
-
858
-    /**
859
-     * Provide current repository URL to the users.
860
-     *
861
-     * @return void|string
862
-     */
863
-    public function getRepositoryURL()
864
-    {
865
-        $showUrl = Config::inst()->get($this->class, 'show_repository_url');
866
-        if ($showUrl) {
867
-            return $this->CVSPath;
868
-        }
869
-    }
870
-
871
-    /**
872
-     * Whitelist configuration that describes how to convert a repository URL into a link
873
-     * to a web user interface for that URL
874
-     *
875
-     * Consists of a hash of "full.lower.case.domain" => {configuration} key/value pairs
876
-     *
877
-     * {configuration} can either be boolean true to auto-detect both the host and the
878
-     * name of the UI provider, or a nested array that overrides either one or both
879
-     * of the auto-detected valyes
880
-     *
881
-     * @var array
882
-     */
883
-    private static $repository_interfaces = array(
884
-        'github.com' => array(
885
-            'icon' => 'deploynaut/img/github.png',
886
-            'name' => 'Github.com',
887
-        ),
888
-        'bitbucket.org' => array(
889
-            'commit' => 'commits',
890
-            'name' => 'Bitbucket.org',
891
-        ),
892
-        'repo.or.cz' => array(
893
-            'scheme' => 'http',
894
-            'name' => 'repo.or.cz',
895
-            'regex' => array('^(.*)$' => '/w$1'),
896
-        ),
897
-
898
-        /* Example for adding your own gitlab repository and override all auto-detected values (with their defaults)
18
+	/**
19
+	 * @var array
20
+	 */
21
+	public static $db = array(
22
+		"Name" => "Varchar",
23
+		"CVSPath" => "Varchar(255)",
24
+		"DiskQuotaMB" => "Int",
25
+		"AllowedEnvironmentType" => "Varchar(255)",
26
+	);
27
+
28
+	/**
29
+	 * @var array
30
+	 */
31
+	public static $has_many = array(
32
+		"Environments" => "DNEnvironment",
33
+		"CreateEnvironments" => "DNCreateEnvironment"
34
+	);
35
+
36
+	/**
37
+	 * @var array
38
+	 */
39
+	public static $many_many = array(
40
+		"Viewers" => "Group",
41
+		'StarredBy' => "Member"
42
+	);
43
+
44
+	/**
45
+	 * @var array
46
+	 */
47
+	public static $summary_fields = array(
48
+		"Name",
49
+		"ViewersList",
50
+	);
51
+
52
+	/**
53
+	 * @var array
54
+	 */
55
+	public static $searchable_fields = array(
56
+		"Name",
57
+	);
58
+
59
+	/**
60
+	 * @var string
61
+	 */
62
+	private static $singular_name = 'Project';
63
+
64
+	/**
65
+	 * @var string
66
+	 */
67
+	private static $plural_name = 'Projects';
68
+
69
+	/**
70
+	 * @var string
71
+	 */
72
+	private static $default_sort = 'Name';
73
+
74
+	/**
75
+	 * Display the repository URL on the project page.
76
+	 *
77
+	 * @var bool
78
+	 */
79
+	private static $show_repository_url = false;
80
+
81
+	/**
82
+	 * In-memory cache for currentBuilds per environment since fetching them from
83
+	 * disk is pretty resource hungry.
84
+	 *
85
+	 * @var array
86
+	 */
87
+	protected static $relation_cache = array();
88
+
89
+	/**
90
+	 * In-memory cache to determine whether clone repo was called.
91
+	 * @var array
92
+	 */
93
+	private static $has_cloned_cache = array();
94
+
95
+	/**
96
+	 * @var bool|Member
97
+	 */
98
+	protected static $_current_member_cache = null;
99
+
100
+	/**
101
+	 * Used by the sync task
102
+	 *
103
+	 * @param string $path
104
+	 * @return \DNProject
105
+	 */
106
+	public static function create_from_path($path)
107
+	{
108
+		$project = DNProject::create();
109
+		$project->Name = $path;
110
+		$project->write();
111
+
112
+		// add the administrators group as the viewers of the new project
113
+		$adminGroup = Group::get()->filter('Code', 'administrators')->first();
114
+		if ($adminGroup && $adminGroup->exists()) {
115
+			$project->Viewers()->add($adminGroup);
116
+		}
117
+		return $project;
118
+	}
119
+
120
+	/**
121
+	 * Return the used quota in MB.
122
+	 *
123
+	 * @param int $round Number of decimal places to round to
124
+	 * @return double The used quota size in MB
125
+	 */
126
+	public function getUsedQuotaMB($round = 2)
127
+	{
128
+		$size = 0;
129
+
130
+		foreach ($this->Environments() as $environment) {
131
+			foreach ($environment->DataArchives()->filter('IsBackup', 0) as $archive) {
132
+				$size += $archive->ArchiveFile()->getAbsoluteSize();
133
+			}
134
+		}
135
+
136
+		// convert bytes to megabytes and round
137
+		return round(($size / 1024) / 1024, $round);
138
+	}
139
+
140
+	/**
141
+	 * Getter for DiskQuotaMB field to provide a default for existing
142
+	 * records that have no quota field set, as it will need to default
143
+	 * to a globally set size.
144
+	 *
145
+	 * @return string|int The quota size in MB
146
+	 */
147
+	public function getDiskQuotaMB()
148
+	{
149
+		$size = $this->getField('DiskQuotaMB');
150
+
151
+		if (empty($size)) {
152
+			$defaults = $this->config()->get('defaults');
153
+			$size = (isset($defaults['DiskQuotaMB'])) ? $defaults['DiskQuotaMB'] : 0;
154
+		}
155
+
156
+		return $size;
157
+	}
158
+
159
+	/**
160
+	 * Has the disk quota been exceeded?
161
+	 *
162
+	 * @return boolean
163
+	 */
164
+	public function HasExceededDiskQuota()
165
+	{
166
+		return $this->getUsedQuotaMB(0) >= $this->getDiskQuotaMB();
167
+	}
168
+
169
+	/**
170
+	 * Is there a disk quota set for this project?
171
+	 *
172
+	 * @return boolean
173
+	 */
174
+	public function HasDiskQuota()
175
+	{
176
+		return $this->getDiskQuotaMB() > 0;
177
+	}
178
+
179
+	/**
180
+	 * Returns the current disk quota usage as a percentage
181
+	 *
182
+	 * @return int
183
+	 */
184
+	public function DiskQuotaUsagePercent()
185
+	{
186
+		$quota = $this->getDiskQuotaMB();
187
+		if ($quota > 0) {
188
+			return $this->getUsedQuotaMB() * 100 / $quota;
189
+		}
190
+		return 100;
191
+	}
192
+
193
+	/**
194
+	 * Get the menu to be shown on projects
195
+	 *
196
+	 * @return ArrayList
197
+	 */
198
+	public function Menu()
199
+	{
200
+		$list = new ArrayList();
201
+
202
+		$controller = Controller::curr();
203
+		$actionType = $controller->getField('CurrentActionType');
204
+
205
+		if (DNRoot::FlagSnapshotsEnabled() && $this->isProjectReady()) {
206
+			$list->push(new ArrayData(array(
207
+				'Link' => sprintf('naut/project/%s/snapshots', $this->Name),
208
+				'Title' => 'Snapshots',
209
+				'IsCurrent' => $this->isSection() && $controller->getAction() == 'snapshots',
210
+				'IsSection' => $this->isSection() && $actionType == DNRoot::ACTION_SNAPSHOT
211
+			)));
212
+		}
213
+
214
+		$this->extend('updateMenu', $list);
215
+
216
+		return $list;
217
+	}
218
+
219
+	/**
220
+	 * Is this project currently at the root level of the controller that handles it?
221
+	 *
222
+	 * @return bool
223
+	 */
224
+	public function isCurrent()
225
+	{
226
+		return $this->isSection() && Controller::curr()->getAction() == 'project';
227
+	}
228
+
229
+	/**
230
+	 * Return the current object from $this->Menu()
231
+	 * Good for making titles and things
232
+	 *
233
+	 * @return DataObject
234
+	 */
235
+	public function CurrentMenu()
236
+	{
237
+		return $this->Menu()->filter('IsSection', true)->First();
238
+	}
239
+
240
+	/**
241
+	 * Is this project currently in a controller that is handling it or performing a sub-task?
242
+	 *
243
+	 * @return bool
244
+	 */
245
+	public function isSection()
246
+	{
247
+		$controller = Controller::curr();
248
+		$project = $controller->getField('CurrentProject');
249
+		return $project && $this->ID == $project->ID;
250
+	}
251
+
252
+	/**
253
+	 * Restrict access to viewing this project
254
+	 *
255
+	 * @param Member|null $member
256
+	 * @return boolean
257
+	 */
258
+	public function canView($member = null)
259
+	{
260
+		if (!$member) {
261
+			$member = Member::currentUser();
262
+		}
263
+
264
+		if (Permission::checkMember($member, 'ADMIN')) {
265
+			return true;
266
+		}
267
+
268
+		return $member->inGroups($this->Viewers());
269
+	}
270
+
271
+	/**
272
+	 * @param Member|null $member
273
+	 *
274
+	 * @return bool
275
+	 */
276
+	public function canRestore($member = null)
277
+	{
278
+		if ($this->allowedAny(
279
+			array(
280
+				DNRoot::ALLOW_PROD_SNAPSHOT,
281
+				DNRoot::ALLOW_NON_PROD_SNAPSHOT
282
+			),
283
+			$member
284
+		)) {
285
+			return true;
286
+		}
287
+
288
+		return (bool)$this->Environments()->filterByCallback(function ($env) use ($member) {
289
+			return $env->canRestore($member);
290
+		})->Count();
291
+	}
292
+
293
+	/**
294
+	 * @param Member|null $member
295
+	 * @return bool
296
+	 */
297
+	public function canBackup($member = null)
298
+	{
299
+		if ($this->allowedAny(
300
+			array(
301
+				DNRoot::ALLOW_PROD_SNAPSHOT,
302
+				DNRoot::ALLOW_NON_PROD_SNAPSHOT
303
+			),
304
+			$member
305
+		)) {
306
+			return true;
307
+		}
308
+
309
+		return (bool)$this->Environments()->filterByCallback(function ($env) use ($member) {
310
+			return $env->canBackup($member);
311
+		})->Count();
312
+	}
313
+
314
+	/**
315
+	 * @param Member|null $member
316
+	 * @return bool
317
+	 */
318
+	public function canUploadArchive($member = null)
319
+	{
320
+		if ($this->allowedAny(
321
+			array(
322
+				DNRoot::ALLOW_PROD_SNAPSHOT,
323
+				DNRoot::ALLOW_NON_PROD_SNAPSHOT
324
+			),
325
+			$member
326
+		)) {
327
+			return true;
328
+		}
329
+
330
+		return (bool)$this->Environments()->filterByCallback(function ($env) use ($member) {
331
+			return $env->canUploadArchive($member);
332
+		})->Count();
333
+	}
334
+
335
+	/**
336
+	 * @param Member|null $member
337
+	 * @return bool
338
+	 */
339
+	public function canDownloadArchive($member = null)
340
+	{
341
+		if ($this->allowedAny(
342
+			array(
343
+				DNRoot::ALLOW_PROD_SNAPSHOT,
344
+				DNRoot::ALLOW_NON_PROD_SNAPSHOT
345
+			),
346
+			$member
347
+		)) {
348
+			return true;
349
+		}
350
+
351
+		return (bool)$this->Environments()->filterByCallback(function ($env) use ($member) {
352
+			return $env->canDownloadArchive($member);
353
+		})->Count();
354
+	}
355
+
356
+	/**
357
+	 * This is a permission check for the front-end only.
358
+	 *
359
+	 * Only admins can create environments for now. Also, we need to check the value
360
+	 * of AllowedEnvironmentType which dictates which backend to use to render the form.
361
+	 *
362
+	 * @param Member|null $member
363
+	 *
364
+	 * @return bool
365
+	 */
366
+	public function canCreateEnvironments($member = null)
367
+	{
368
+		$envType = $this->AllowedEnvironmentType;
369
+		if ($envType) {
370
+			$env = Injector::inst()->get($envType);
371
+			if ($env instanceof EnvironmentCreateBackend) {
372
+				return $this->allowed(DNRoot::ALLOW_CREATE_ENVIRONMENT, $member);
373
+			}
374
+		}
375
+		return false;
376
+	}
377
+
378
+	/**
379
+	 * @return DataList
380
+	 */
381
+	public function DataArchives()
382
+	{
383
+		$envIds = $this->Environments()->column('ID');
384
+		return DNDataArchive::get()->filter('EnvironmentID', $envIds);
385
+	}
386
+
387
+	/**
388
+	 * Return all archives which are "manual upload requests",
389
+	 * meaning they don't have a file attached to them (yet).
390
+	 *
391
+	 * @return DataList
392
+	 */
393
+	public function PendingManualUploadDataArchives()
394
+	{
395
+		return $this->DataArchives()->filter('ArchiveFileID', null);
396
+	}
397
+
398
+	/**
399
+	 * Build an environment variable array to be used with this project.
400
+	 *
401
+	 * This is relevant if every project needs to use an individual SSH pubkey.
402
+	 *
403
+	 * Include this with all Gitonomy\Git\Repository, and
404
+	 * \Symfony\Component\Process\Processes.
405
+	 *
406
+	 * @return array
407
+	 */
408
+	public function getProcessEnv()
409
+	{
410
+		if (file_exists($this->getPrivateKeyPath())) {
411
+			// Key-pair is available, use it.
412
+			$processEnv = array(
413
+				'IDENT_KEY' => $this->getPrivateKeyPath(),
414
+				'GIT_SSH' => BASE_PATH . "/deploynaut/git-deploy.sh"
415
+			);
416
+		} else {
417
+			$processEnv = array();
418
+		}
419
+		$this->extend('updateProcessEnv', $processEnv);
420
+
421
+		return $processEnv;
422
+	}
423
+
424
+	/**
425
+	 * Get a string of people allowed to view this project
426
+	 *
427
+	 * @return string
428
+	 */
429
+	public function getViewersList()
430
+	{
431
+		return implode(", ", $this->Viewers()->column("Title"));
432
+	}
433
+
434
+	/**
435
+	 * @return DNData
436
+	 */
437
+	public function DNData()
438
+	{
439
+		return DNData::inst();
440
+	}
441
+
442
+	/**
443
+	 * Provides a DNBuildList of builds found in this project.
444
+	 *
445
+	 * @return DNReferenceList
446
+	 */
447
+	public function DNBuildList()
448
+	{
449
+		return DNReferenceList::create($this, $this->DNData());
450
+	}
451
+
452
+	/**
453
+	 * Provides a list of the branches in this project.
454
+	 *
455
+	 * @return DNBranchList
456
+	 */
457
+	public function DNBranchList()
458
+	{
459
+		if ($this->CVSPath && !$this->repoExists()) {
460
+			$this->cloneRepo();
461
+		}
462
+		return DNBranchList::create($this, $this->DNData());
463
+	}
464
+
465
+	/**
466
+	 * Provides a list of the tags in this project.
467
+	 *
468
+	 * @return DNReferenceList
469
+	 */
470
+	public function DNTagList()
471
+	{
472
+		if ($this->CVSPath && !$this->repoExists()) {
473
+			$this->cloneRepo();
474
+		}
475
+		return DNReferenceList::create($this, $this->DNData(), null, null, true);
476
+	}
477
+
478
+	/**
479
+	 * @return false|Gitonomy\Git\Repository
480
+	 */
481
+	public function getRepository()
482
+	{
483
+		if (!$this->repoExists()) {
484
+			return false;
485
+		}
486
+
487
+		return new Gitonomy\Git\Repository($this->getLocalCVSPath());
488
+	}
489
+
490
+	/**
491
+	 * Provides a list of environments found in this project.
492
+	 * CAUTION: filterByCallback will change this into an ArrayList!
493
+	 *
494
+	 * @return ArrayList
495
+	 */
496
+	public function DNEnvironmentList()
497
+	{
498
+		if (!self::$_current_member_cache) {
499
+			self::$_current_member_cache = Member::currentUser();
500
+		}
501
+
502
+		if (self::$_current_member_cache === false) {
503
+			return new ArrayList();
504
+		}
505
+
506
+		$currentMember = self::$_current_member_cache;
507
+		return $this->Environments()
508
+			->filterByCallBack(function ($item) use ($currentMember) {
509
+				return $item->canView($currentMember);
510
+			});
511
+	}
512
+
513
+	/**
514
+	 * @param string $usage
515
+	 * @return ArrayList
516
+	 */
517
+	public function EnvironmentsByUsage($usage)
518
+	{
519
+		return $this->DNEnvironmentList()->filter('Usage', $usage);
520
+	}
521
+
522
+	/**
523
+	 * Returns a map of envrionment name to build name
524
+	 *
525
+	 * @return false|DNDeployment
526
+	 */
527
+	public function currentBuilds()
528
+	{
529
+		if (!isset(self::$relation_cache['currentBuilds.'.$this->ID])) {
530
+			$currentBuilds = array();
531
+			foreach ($this->Environments() as $env) {
532
+				$currentBuilds[$env->Name] = $env->CurrentBuild();
533
+			}
534
+			self::$relation_cache['currentBuilds.'.$this->ID] = $currentBuilds;
535
+		}
536
+		return self::$relation_cache['currentBuilds.'.$this->ID];
537
+	}
538
+
539
+	/**
540
+	 * @param string
541
+	 * @return string
542
+	 */
543
+	public function Link($action = '')
544
+	{
545
+		return Controller::join_links("naut", "project", $this->Name, $action);
546
+	}
547
+
548
+	/**
549
+	 * @return string|null
550
+	 */
551
+	public function CreateEnvironmentLink()
552
+	{
553
+		if ($this->canCreateEnvironments()) {
554
+			return $this->Link('createenv');
555
+		}
556
+		return null;
557
+	}
558
+
559
+	/**
560
+	 * @return string
561
+	 */
562
+	public function ToggleStarLink()
563
+	{
564
+		return $this->Link('/star');
565
+	}
566
+
567
+	/**
568
+	 * @return bool
569
+	 */
570
+	public function IsStarred()
571
+	{
572
+		$member = Member::currentUser();
573
+		if ($member === null) {
574
+			return false;
575
+		}
576
+		$favourited = $this->StarredBy()->filter('MemberID', $member->ID);
577
+		if ($favourited->count() == 0) {
578
+			return false;
579
+		}
580
+		return true;
581
+	}
582
+
583
+	/**
584
+	 * @param string $action
585
+	 * @return string
586
+	 */
587
+	public function APILink($action)
588
+	{
589
+		return Controller::join_links("naut", "api", $this->Name, $action);
590
+	}
591
+
592
+	/**
593
+	 * @return FieldList
594
+	 */
595
+	public function getCMSFields()
596
+	{
597
+		$fields = parent::getCMSFields();
598
+
599
+		/** @var GridField $environments */
600
+		$environments = $fields->dataFieldByName("Environments");
601
+
602
+		$fields->fieldByName("Root")->removeByName("Viewers");
603
+		$fields->fieldByName("Root")->removeByName("Environments");
604
+		$fields->fieldByName("Root")->removeByName("LocalCVSPath");
605
+
606
+		$diskQuotaDesc = 'This is the maximum amount of disk space (in megabytes) that all environments within this '
607
+			. 'project can use for stored snapshots';
608
+		$fields->dataFieldByName('DiskQuotaMB')->setDescription($diskQuotaDesc);
609
+
610
+		$projectNameDesc = 'Changing the name will <strong>reset</strong> the deploy configuration and avoid using non'
611
+			. 'alphanumeric characters';
612
+		$fields->fieldByName('Root.Main.Name')
613
+			->setTitle('Project name')
614
+			->setDescription($projectNameDesc);
615
+
616
+		$fields->fieldByName('Root.Main.CVSPath')
617
+			->setTitle('Git repository')
618
+			->setDescription('E.g. [email protected]:silverstripe/silverstripe-installer.git');
619
+
620
+		$workspaceField = new ReadonlyField('LocalWorkspace', 'Git workspace', $this->getLocalCVSPath());
621
+		$workspaceField->setDescription('This is where the GIT repository are located on this server');
622
+		$fields->insertAfter($workspaceField, 'CVSPath');
623
+
624
+		$readAccessGroups = ListboxField::create('Viewers', 'Project viewers', Group::get()->map()->toArray())
625
+			->setMultiple(true)
626
+			->setDescription('These groups can view the project in the front-end.');
627
+		$fields->addFieldToTab("Root.Main", $readAccessGroups);
628
+
629
+		$this->setCreateProjectFolderField($fields);
630
+		$this->setEnvironmentFields($fields, $environments);
631
+
632
+		$environmentTypes = ClassInfo::implementorsOf('EnvironmentCreateBackend');
633
+		$types = array();
634
+		foreach ($environmentTypes as $type) {
635
+			$types[$type] = $type;
636
+		}
637
+
638
+		$fields->addFieldsToTab('Root.Main', array(
639
+			DropdownField::create(
640
+				'AllowedEnvironmentType',
641
+				'Allowed Environment Type',
642
+				$types
643
+			)->setDescription('This defined which form to show on the front end for '
644
+				. 'environment creation. This will not affect backend functionality.')
645
+			->setEmptyString(' - None - '),
646
+		));
647
+
648
+		return $fields;
649
+	}
650
+
651
+	/**
652
+	 * If there isn't a capistrano env project folder, show options to create one
653
+	 *
654
+	 * @param FieldList $fields
655
+	 */
656
+	public function setCreateProjectFolderField(&$fields)
657
+	{
658
+		// Check if the capistrano project folder exists
659
+		if (!$this->Name) {
660
+			return;
661
+		}
662
+
663
+		if ($this->projectFolderExists()) {
664
+			return;
665
+		}
666
+
667
+		$createFolderNotice = new LabelField('CreateEnvFolderNotice', 'Warning: No Capistrano project folder exists');
668
+		$createFolderNotice->addExtraClass('message warning');
669
+		$fields->insertBefore($createFolderNotice, 'Name');
670
+		$createFolderField = new CheckboxField('CreateEnvFolder', 'Create folder');
671
+		$createFolderField->setDescription('Would you like to create the capistrano project folder?');
672
+		$fields->insertAfter($createFolderField, 'CreateEnvFolderNotice');
673
+	}
674
+
675
+	/**
676
+	 * @return boolean
677
+	 */
678
+	public function projectFolderExists()
679
+	{
680
+		return file_exists($this->getProjectFolderPath());
681
+	}
682
+
683
+	/**
684
+	 * @return bool
685
+	 */
686
+	public function repoExists()
687
+	{
688
+		return file_exists(sprintf('%s/HEAD', $this->getLocalCVSPath()));
689
+	}
690
+
691
+	/**
692
+	 * Setup a job to clone a git repository.
693
+	 * @return string resque token
694
+	 */
695
+	public function cloneRepo()
696
+	{
697
+		// Avoid this being called multiple times in the same request
698
+		if (!isset(self::$has_cloned_cache[$this->ID])) {
699
+			$fetch = DNGitFetch::create();
700
+			$fetch->ProjectID = $this->ID;
701
+			$fetch->write();
702
+
703
+			// passing true here tells DNGitFetch to force a git clone, otherwise
704
+			// it will just update the repo if it already exists. We want to ensure
705
+			// we're always cloning a new repo in this case, as the git URL may have changed.
706
+			$fetch->start(true);
707
+
708
+			self::$has_cloned_cache[$this->ID] = true;
709
+		}
710
+	}
711
+
712
+	/**
713
+	 * @return string
714
+	 */
715
+	public function getLocalCVSPath()
716
+	{
717
+		return sprintf('%s/%s', DEPLOYNAUT_LOCAL_VCS_PATH, $this->Name);
718
+	}
719
+
720
+	public function onBeforeWrite()
721
+	{
722
+		parent::onBeforeWrite();
723
+
724
+		if ($this->CreateEnvFolder && !file_exists($this->getProjectFolderPath())) {
725
+			mkdir($this->getProjectFolderPath());
726
+		}
727
+	}
728
+
729
+	public function onAfterWrite()
730
+	{
731
+		parent::onAfterWrite();
732
+
733
+		if (!$this->CVSPath) {
734
+			return;
735
+		}
736
+
737
+		$changedFields = $this->getChangedFields(true, 2);
738
+		if (isset($changedFields['CVSPath']) || isset($changedFields['Name'])) {
739
+			$this->cloneRepo();
740
+		}
741
+	}
742
+
743
+	/**
744
+	 * Delete related environments and folders
745
+	 */
746
+	public function onAfterDelete()
747
+	{
748
+		parent::onAfterDelete();
749
+
750
+		// Delete related environments
751
+		foreach ($this->Environments() as $env) {
752
+			$env->delete();
753
+		}
754
+
755
+		// Delete local repository
756
+		if (file_exists($this->getLocalCVSPath())) {
757
+			Filesystem::removeFolder($this->getLocalCVSPath());
758
+		}
759
+
760
+		// Delete project template
761
+		if (file_exists($this->getProjectFolderPath()) && Config::inst()->get('DNEnvironment', 'allow_web_editing')) {
762
+			Filesystem::removeFolder($this->getProjectFolderPath());
763
+		}
764
+
765
+		// Delete the deploy key
766
+		if (file_exists($this->getKeyDir())) {
767
+			Filesystem::removeFolder($this->getKeyDir());
768
+		}
769
+	}
770
+
771
+	/**
772
+	 * Fetch the public key for this project.
773
+	 *
774
+	 * @return string|void
775
+	 */
776
+	public function getPublicKey()
777
+	{
778
+		$key = $this->getPublicKeyPath();
779
+
780
+		if (file_exists($key)) {
781
+			return trim(file_get_contents($key));
782
+		}
783
+	}
784
+
785
+	/**
786
+	 * This returns that path of the public key if a key directory is set. It doesn't check whether the file exists.
787
+	 *
788
+	 * @return string|null
789
+	 */
790
+	public function getPublicKeyPath()
791
+	{
792
+		if ($privateKey = $this->getPrivateKeyPath()) {
793
+			return $privateKey . '.pub';
794
+		}
795
+		return null;
796
+	}
797
+
798
+	/**
799
+	 * This returns that path of the private key if a key directory is set. It doesn't check whether the file exists.
800
+	 *
801
+	 * @return string|null
802
+	 */
803
+	public function getPrivateKeyPath()
804
+	{
805
+		$keyDir = $this->getKeyDir();
806
+		if (!empty($keyDir)) {
807
+			$filter = FileNameFilter::create();
808
+			$name = $filter->filter($this->Name);
809
+			return $keyDir . '/' . $name;
810
+		}
811
+		return null;
812
+	}
813
+
814
+	/**
815
+	 * Returns the location of the projects key dir if one exists.
816
+	 *
817
+	 * @return string|null
818
+	 */
819
+	public function getKeyDir()
820
+	{
821
+		$keyDir = $this->DNData()->getKeyDir();
822
+		if (!$keyDir) {
823
+			return null;
824
+		}
825
+
826
+		$filter = FileNameFilter::create();
827
+		$name = $filter->filter($this->Name);
828
+
829
+		return $this->DNData()->getKeyDir() . '/' . $name;
830
+	}
831
+
832
+	/**
833
+	 * Setup a gridfield for the environment configs
834
+	 *
835
+	 * @param FieldList $fields
836
+	 * @param GridField $environments
837
+	 */
838
+	protected function setEnvironmentFields(&$fields, $environments)
839
+	{
840
+		if (!$environments) {
841
+			return;
842
+		}
843
+
844
+		$environments->getConfig()->addComponent(new GridFieldAddNewMultiClass());
845
+		$environments->getConfig()->removeComponentsByType('GridFieldAddNewButton');
846
+		$environments->getConfig()->removeComponentsByType('GridFieldAddExistingAutocompleter');
847
+		$environments->getConfig()->removeComponentsByType('GridFieldDeleteAction');
848
+		$environments->getConfig()->removeComponentsByType('GridFieldPageCount');
849
+		if (Config::inst()->get('DNEnvironment', 'allow_web_editing')) {
850
+			$addNewRelease = new GridFieldAddNewButton('toolbar-header-right');
851
+			$addNewRelease->setButtonName('Add');
852
+			$environments->getConfig()->addComponent($addNewRelease);
853
+		}
854
+
855
+		$fields->addFieldToTab("Root.Main", $environments);
856
+	}
857
+
858
+	/**
859
+	 * Provide current repository URL to the users.
860
+	 *
861
+	 * @return void|string
862
+	 */
863
+	public function getRepositoryURL()
864
+	{
865
+		$showUrl = Config::inst()->get($this->class, 'show_repository_url');
866
+		if ($showUrl) {
867
+			return $this->CVSPath;
868
+		}
869
+	}
870
+
871
+	/**
872
+	 * Whitelist configuration that describes how to convert a repository URL into a link
873
+	 * to a web user interface for that URL
874
+	 *
875
+	 * Consists of a hash of "full.lower.case.domain" => {configuration} key/value pairs
876
+	 *
877
+	 * {configuration} can either be boolean true to auto-detect both the host and the
878
+	 * name of the UI provider, or a nested array that overrides either one or both
879
+	 * of the auto-detected valyes
880
+	 *
881
+	 * @var array
882
+	 */
883
+	private static $repository_interfaces = array(
884
+		'github.com' => array(
885
+			'icon' => 'deploynaut/img/github.png',
886
+			'name' => 'Github.com',
887
+		),
888
+		'bitbucket.org' => array(
889
+			'commit' => 'commits',
890
+			'name' => 'Bitbucket.org',
891
+		),
892
+		'repo.or.cz' => array(
893
+			'scheme' => 'http',
894
+			'name' => 'repo.or.cz',
895
+			'regex' => array('^(.*)$' => '/w$1'),
896
+		),
897
+
898
+		/* Example for adding your own gitlab repository and override all auto-detected values (with their defaults)
899 899
         'gitlab.mysite.com' => array(
900 900
             'icon' => 'deploynaut/img/git.png',
901 901
             'host' => 'gitlab.mysite.com',
@@ -904,280 +904,280 @@  discard block
 block discarded – undo
904 904
             'commit' => "commit"
905 905
         ),
906 906
         */
907
-    );
908
-
909
-    /**
910
-     * Get a ViewableData structure describing the UI tool that lets the user view the repository code
911
-     *
912
-     * @return ArrayData
913
-     */
914
-    public function getRepositoryInterface()
915
-    {
916
-        $interfaces = $this->config()->repository_interfaces;
917
-
918
-        /* Look for each whitelisted hostname */
919
-        foreach ($interfaces as $host => $interface) {
920
-            /* See if the CVS Path is for this hostname, followed by some junk (maybe a port), then the path */
921
-            if (preg_match('{^[^.]*' . $host . '(.*?)([/a-zA-Z].+)}', $this->CVSPath, $match)) {
922
-                $path = $match[2];
923
-
924
-                $scheme = isset($interface['scheme']) ? $interface['scheme'] : 'https';
925
-                $host = isset($interface['host']) ? $interface['host'] : $host;
926
-                $regex = isset($interface['regex']) ? $interface['regex'] : array('\.git$' => '');
927
-
928
-                $components = explode('.', $host);
929
-
930
-                foreach ($regex as $pattern => $replacement) {
931
-                    $path = preg_replace('/' . $pattern . '/', $replacement, $path);
932
-                }
933
-
934
-                $uxurl = Controller::join_links($scheme . '://', $host, $path);
935
-
936
-                if (array_key_exists('commit', $interface) && $interface['commit'] == false) {
937
-                    $commiturl = false;
938
-                } else {
939
-                    $commiturl = Controller::join_links(
940
-                        $uxurl,
941
-                        isset($interface['commit']) ? $interface['commit'] : 'commit'
942
-                    );
943
-                }
944
-
945
-                return new ArrayData(array(
946
-                    'Name'      => isset($interface['name']) ? $interface['name'] : ucfirst($components[0]),
947
-                    'Icon'      => isset($interface['icon']) ? $interface['icon'] : 'deploynaut/img/git.png',
948
-                    'URL'       => $uxurl,
949
-                    'CommitURL' => $commiturl
950
-                ));
951
-            }
952
-        }
953
-    }
954
-
955
-    /**
956
-     * @return string
957
-     */
958
-    protected function getProjectFolderPath()
959
-    {
960
-        return sprintf('%s/%s', $this->DNData()->getEnvironmentDir(), $this->Name);
961
-    }
962
-
963
-    /**
964
-     * Convenience wrapper for a single permission code.
965
-     *
966
-     * @param string $code
967
-     * @return SS_List
968
-     */
969
-    public function whoIsAllowed($code)
970
-    {
971
-        return $this->whoIsAllowedAny(array($code));
972
-    }
973
-
974
-    /**
975
-     * List members who have $codes on this project.
976
-     * Does not support Permission::DENY_PERMISSION malarky, same as Permission::get_groups_by_permission anyway...
977
-     *
978
-     * @param array|string $codes
979
-     * @return SS_List
980
-     */
981
-    public function whoIsAllowedAny($codes)
982
-    {
983
-        if (!is_array($codes)) {
984
-            $codes = array($codes);
985
-        }
986
-
987
-        $SQLa_codes = Convert::raw2sql($codes);
988
-        $SQL_codes = join("','", $SQLa_codes);
989
-
990
-        return DataObject::get('Member')
991
-            ->where("\"PermissionRoleCode\".\"Code\" IN ('$SQL_codes') OR \"Permission\".\"Code\" IN ('$SQL_codes')")
992
-            ->filter("DNProject_Viewers.DNProjectID", $this->ID)
993
-            ->leftJoin('Group_Members', "\"Group_Members\".\"MemberID\" = \"Member\".\"ID\"")
994
-            ->leftJoin('Group', "\"Group_Members\".\"GroupID\" = \"Group\".\"ID\"")
995
-            ->leftJoin('DNProject_Viewers', "\"DNProject_Viewers\".\"GroupID\" = \"Group\".\"ID\"")
996
-            ->leftJoin('Permission', "\"Permission\".\"GroupID\" = \"Group\".\"ID\"")
997
-            ->leftJoin('Group_Roles', "\"Group_Roles\".\"GroupID\" = \"Group\".\"ID\"")
998
-            ->leftJoin('PermissionRole', "\"Group_Roles\".\"PermissionRoleID\" = \"PermissionRole\".\"ID\"")
999
-            ->leftJoin('PermissionRoleCode', "\"PermissionRoleCode\".\"RoleID\" = \"PermissionRole\".\"ID\"");
1000
-    }
1001
-
1002
-    /**
1003
-     * Convenience wrapper for a single permission code.
1004
-     *
1005
-     * @param string $code
1006
-     * @param Member|null $member
1007
-     *
1008
-     * @return bool
1009
-     */
1010
-    public function allowed($code, $member = null)
1011
-    {
1012
-        return $this->allowedAny(array($code), $member);
1013
-    }
1014
-
1015
-    /**
1016
-     * Checks if a group is allowed to the project and the permission code
1017
-     *
1018
-     * @param string $permissionCode
1019
-     * @param Group $group
1020
-     *
1021
-     * @return bool
1022
-     */
1023
-    public function groupAllowed($permissionCode, Group $group)
1024
-    {
1025
-        $viewers = $this->Viewers();
1026
-        if (!$viewers->find('ID', $group->ID)) {
1027
-            return false;
1028
-        }
1029
-        $groups = Permission::get_groups_by_permission($permissionCode);
1030
-        if (!$groups->find('ID', $group->ID)) {
1031
-            return false;
1032
-        }
1033
-        return true;
1034
-    }
1035
-
1036
-    /**
1037
-     * Check if member has a permission code in this project.
1038
-     *
1039
-     * @param array|string $codes
1040
-     * @param Member|null $member
1041
-     *
1042
-     * @return bool
1043
-     */
1044
-    public function allowedAny($codes, $member = null)
1045
-    {
1046
-        if (!$member) {
1047
-            $member = Member::currentUser();
1048
-        }
1049
-
1050
-        if (Permission::checkMember($member, 'ADMIN')) {
1051
-            return true;
1052
-        }
1053
-
1054
-        $hits = $this->whoIsAllowedAny($codes)->filter('Member.ID', $member->ID)->count();
1055
-        return ($hits>0 ? true : false);
1056
-    }
1057
-
1058
-    /**
1059
-     * Checks if the environment has been fully built.
1060
-     *
1061
-     * @return bool
1062
-     */
1063
-    public function isProjectReady()
1064
-    {
1065
-        if ($this->getRunningInitialEnvironmentCreations()->count() > 0) {
1066
-            // We're still creating the initial environments for this project so we're
1067
-            // not quite done
1068
-            return false;
1069
-        }
1070
-
1071
-        // Provide a hook for further checks. Logic stolen from
1072
-        // {@see DataObject::extendedCan()}
1073
-        $isDone = $this->extend('isProjectReady');
1074
-        if ($isDone && is_array($isDone)) {
1075
-            $isDone = array_filter($isDone, function ($val) {
1076
-                return !is_null($val);
1077
-            });
1078
-
1079
-            // If anything returns false then we're not ready.
1080
-            if ($isDone) {
1081
-                return min($isDone);
1082
-            }
1083
-        }
1084
-
1085
-        return true;
1086
-    }
1087
-
1088
-    /**
1089
-     * Returns a list of environments still being created.
1090
-     *
1091
-     * @return SS_List
1092
-     */
1093
-    public function getRunningEnvironmentCreations()
1094
-    {
1095
-        return $this->CreateEnvironments()
1096
-            ->filter('Status', ['Queued', 'Started']);
1097
-    }
1098
-
1099
-    /**
1100
-     * Returns a list of initial environments created for this project.
1101
-     *
1102
-     * @return DataList
1103
-     */
1104
-    public function getInitialEnvironmentCreations()
1105
-    {
1106
-        return $this->CreateEnvironments()->filter('IsInitialEnvironment', true);
1107
-    }
1108
-
1109
-    /**
1110
-     * Only returns initial environments that are being created.
1111
-     *
1112
-     * @return DataList
1113
-     */
1114
-    public function getRunningInitialEnvironmentCreations()
1115
-    {
1116
-        return $this->getInitialEnvironmentCreations()
1117
-            ->filter('Status', ['Queued', 'Started']);
1118
-    }
1119
-
1120
-    /**
1121
-     * Returns a list of completed initial environment creations. This includes failed tasks.
1122
-     *
1123
-     * @return DataList
1124
-     */
1125
-    public function getCompleteInitialEnvironmentCreations()
1126
-    {
1127
-        return $this->getInitialEnvironmentCreations()
1128
-            ->exclude('Status', ['Queued', 'Started']);
1129
-    }
1130
-
1131
-    /**
1132
-     * @return ValidationResult
1133
-     */
1134
-    protected function validate()
1135
-    {
1136
-        $validation = parent::validate();
1137
-        if ($validation->valid()) {
1138
-            if (empty($this->Name)) {
1139
-                return $validation->error('The stack must have a name.');
1140
-            }
1141
-
1142
-            // The name is used to build filepaths so should be restricted
1143
-            if (!preg_match('/^[a-zA-Z0-9][a-zA-Z0-9\-\_]+$/', $this->Name)) {
1144
-                return $validation->error('Project name can only contain alphanumeric, hyphens and underscores.');
1145
-            }
1146
-
1147
-            if (empty($this->CVSPath)) {
1148
-                return $validation->error('You must provide a repository URL.');
1149
-            }
1150
-
1151
-            $existing = DNProject::get()->filter('Name', $this->Name);
1152
-            if ($this->ID) {
1153
-                $existing = $existing->exclude('ID', $this->ID);
1154
-            }
1155
-            if ($existing->count() > 0) {
1156
-                return $validation->error('A stack already exists with that name.');
1157
-            }
1158
-        }
1159
-        return $validation;
1160
-    }
1161
-
1162
-    /**
1163
-     * @param Member $member
1164
-     *
1165
-     * @return bool
1166
-     */
1167
-    public function canCreate($member = null)
1168
-    {
1169
-        if (!$member) {
1170
-            $member = Member::currentUser();
1171
-        }
1172
-        if (!$member) {
1173
-            return false;
1174
-        }
1175
-
1176
-        if (Permission::checkMember($member, 'ADMIN')) {
1177
-            return true;
1178
-        }
1179
-
1180
-        // This calls canCreate on extensions.
1181
-        return parent::canCreate($member);
1182
-    }
907
+	);
908
+
909
+	/**
910
+	 * Get a ViewableData structure describing the UI tool that lets the user view the repository code
911
+	 *
912
+	 * @return ArrayData
913
+	 */
914
+	public function getRepositoryInterface()
915
+	{
916
+		$interfaces = $this->config()->repository_interfaces;
917
+
918
+		/* Look for each whitelisted hostname */
919
+		foreach ($interfaces as $host => $interface) {
920
+			/* See if the CVS Path is for this hostname, followed by some junk (maybe a port), then the path */
921
+			if (preg_match('{^[^.]*' . $host . '(.*?)([/a-zA-Z].+)}', $this->CVSPath, $match)) {
922
+				$path = $match[2];
923
+
924
+				$scheme = isset($interface['scheme']) ? $interface['scheme'] : 'https';
925
+				$host = isset($interface['host']) ? $interface['host'] : $host;
926
+				$regex = isset($interface['regex']) ? $interface['regex'] : array('\.git$' => '');
927
+
928
+				$components = explode('.', $host);
929
+
930
+				foreach ($regex as $pattern => $replacement) {
931
+					$path = preg_replace('/' . $pattern . '/', $replacement, $path);
932
+				}
933
+
934
+				$uxurl = Controller::join_links($scheme . '://', $host, $path);
935
+
936
+				if (array_key_exists('commit', $interface) && $interface['commit'] == false) {
937
+					$commiturl = false;
938
+				} else {
939
+					$commiturl = Controller::join_links(
940
+						$uxurl,
941
+						isset($interface['commit']) ? $interface['commit'] : 'commit'
942
+					);
943
+				}
944
+
945
+				return new ArrayData(array(
946
+					'Name'      => isset($interface['name']) ? $interface['name'] : ucfirst($components[0]),
947
+					'Icon'      => isset($interface['icon']) ? $interface['icon'] : 'deploynaut/img/git.png',
948
+					'URL'       => $uxurl,
949
+					'CommitURL' => $commiturl
950
+				));
951
+			}
952
+		}
953
+	}
954
+
955
+	/**
956
+	 * @return string
957
+	 */
958
+	protected function getProjectFolderPath()
959
+	{
960
+		return sprintf('%s/%s', $this->DNData()->getEnvironmentDir(), $this->Name);
961
+	}
962
+
963
+	/**
964
+	 * Convenience wrapper for a single permission code.
965
+	 *
966
+	 * @param string $code
967
+	 * @return SS_List
968
+	 */
969
+	public function whoIsAllowed($code)
970
+	{
971
+		return $this->whoIsAllowedAny(array($code));
972
+	}
973
+
974
+	/**
975
+	 * List members who have $codes on this project.
976
+	 * Does not support Permission::DENY_PERMISSION malarky, same as Permission::get_groups_by_permission anyway...
977
+	 *
978
+	 * @param array|string $codes
979
+	 * @return SS_List
980
+	 */
981
+	public function whoIsAllowedAny($codes)
982
+	{
983
+		if (!is_array($codes)) {
984
+			$codes = array($codes);
985
+		}
986
+
987
+		$SQLa_codes = Convert::raw2sql($codes);
988
+		$SQL_codes = join("','", $SQLa_codes);
989
+
990
+		return DataObject::get('Member')
991
+			->where("\"PermissionRoleCode\".\"Code\" IN ('$SQL_codes') OR \"Permission\".\"Code\" IN ('$SQL_codes')")
992
+			->filter("DNProject_Viewers.DNProjectID", $this->ID)
993
+			->leftJoin('Group_Members', "\"Group_Members\".\"MemberID\" = \"Member\".\"ID\"")
994
+			->leftJoin('Group', "\"Group_Members\".\"GroupID\" = \"Group\".\"ID\"")
995
+			->leftJoin('DNProject_Viewers', "\"DNProject_Viewers\".\"GroupID\" = \"Group\".\"ID\"")
996
+			->leftJoin('Permission', "\"Permission\".\"GroupID\" = \"Group\".\"ID\"")
997
+			->leftJoin('Group_Roles', "\"Group_Roles\".\"GroupID\" = \"Group\".\"ID\"")
998
+			->leftJoin('PermissionRole', "\"Group_Roles\".\"PermissionRoleID\" = \"PermissionRole\".\"ID\"")
999
+			->leftJoin('PermissionRoleCode', "\"PermissionRoleCode\".\"RoleID\" = \"PermissionRole\".\"ID\"");
1000
+	}
1001
+
1002
+	/**
1003
+	 * Convenience wrapper for a single permission code.
1004
+	 *
1005
+	 * @param string $code
1006
+	 * @param Member|null $member
1007
+	 *
1008
+	 * @return bool
1009
+	 */
1010
+	public function allowed($code, $member = null)
1011
+	{
1012
+		return $this->allowedAny(array($code), $member);
1013
+	}
1014
+
1015
+	/**
1016
+	 * Checks if a group is allowed to the project and the permission code
1017
+	 *
1018
+	 * @param string $permissionCode
1019
+	 * @param Group $group
1020
+	 *
1021
+	 * @return bool
1022
+	 */
1023
+	public function groupAllowed($permissionCode, Group $group)
1024
+	{
1025
+		$viewers = $this->Viewers();
1026
+		if (!$viewers->find('ID', $group->ID)) {
1027
+			return false;
1028
+		}
1029
+		$groups = Permission::get_groups_by_permission($permissionCode);
1030
+		if (!$groups->find('ID', $group->ID)) {
1031
+			return false;
1032
+		}
1033
+		return true;
1034
+	}
1035
+
1036
+	/**
1037
+	 * Check if member has a permission code in this project.
1038
+	 *
1039
+	 * @param array|string $codes
1040
+	 * @param Member|null $member
1041
+	 *
1042
+	 * @return bool
1043
+	 */
1044
+	public function allowedAny($codes, $member = null)
1045
+	{
1046
+		if (!$member) {
1047
+			$member = Member::currentUser();
1048
+		}
1049
+
1050
+		if (Permission::checkMember($member, 'ADMIN')) {
1051
+			return true;
1052
+		}
1053
+
1054
+		$hits = $this->whoIsAllowedAny($codes)->filter('Member.ID', $member->ID)->count();
1055
+		return ($hits>0 ? true : false);
1056
+	}
1057
+
1058
+	/**
1059
+	 * Checks if the environment has been fully built.
1060
+	 *
1061
+	 * @return bool
1062
+	 */
1063
+	public function isProjectReady()
1064
+	{
1065
+		if ($this->getRunningInitialEnvironmentCreations()->count() > 0) {
1066
+			// We're still creating the initial environments for this project so we're
1067
+			// not quite done
1068
+			return false;
1069
+		}
1070
+
1071
+		// Provide a hook for further checks. Logic stolen from
1072
+		// {@see DataObject::extendedCan()}
1073
+		$isDone = $this->extend('isProjectReady');
1074
+		if ($isDone && is_array($isDone)) {
1075
+			$isDone = array_filter($isDone, function ($val) {
1076
+				return !is_null($val);
1077
+			});
1078
+
1079
+			// If anything returns false then we're not ready.
1080
+			if ($isDone) {
1081
+				return min($isDone);
1082
+			}
1083
+		}
1084
+
1085
+		return true;
1086
+	}
1087
+
1088
+	/**
1089
+	 * Returns a list of environments still being created.
1090
+	 *
1091
+	 * @return SS_List
1092
+	 */
1093
+	public function getRunningEnvironmentCreations()
1094
+	{
1095
+		return $this->CreateEnvironments()
1096
+			->filter('Status', ['Queued', 'Started']);
1097
+	}
1098
+
1099
+	/**
1100
+	 * Returns a list of initial environments created for this project.
1101
+	 *
1102
+	 * @return DataList
1103
+	 */
1104
+	public function getInitialEnvironmentCreations()
1105
+	{
1106
+		return $this->CreateEnvironments()->filter('IsInitialEnvironment', true);
1107
+	}
1108
+
1109
+	/**
1110
+	 * Only returns initial environments that are being created.
1111
+	 *
1112
+	 * @return DataList
1113
+	 */
1114
+	public function getRunningInitialEnvironmentCreations()
1115
+	{
1116
+		return $this->getInitialEnvironmentCreations()
1117
+			->filter('Status', ['Queued', 'Started']);
1118
+	}
1119
+
1120
+	/**
1121
+	 * Returns a list of completed initial environment creations. This includes failed tasks.
1122
+	 *
1123
+	 * @return DataList
1124
+	 */
1125
+	public function getCompleteInitialEnvironmentCreations()
1126
+	{
1127
+		return $this->getInitialEnvironmentCreations()
1128
+			->exclude('Status', ['Queued', 'Started']);
1129
+	}
1130
+
1131
+	/**
1132
+	 * @return ValidationResult
1133
+	 */
1134
+	protected function validate()
1135
+	{
1136
+		$validation = parent::validate();
1137
+		if ($validation->valid()) {
1138
+			if (empty($this->Name)) {
1139
+				return $validation->error('The stack must have a name.');
1140
+			}
1141
+
1142
+			// The name is used to build filepaths so should be restricted
1143
+			if (!preg_match('/^[a-zA-Z0-9][a-zA-Z0-9\-\_]+$/', $this->Name)) {
1144
+				return $validation->error('Project name can only contain alphanumeric, hyphens and underscores.');
1145
+			}
1146
+
1147
+			if (empty($this->CVSPath)) {
1148
+				return $validation->error('You must provide a repository URL.');
1149
+			}
1150
+
1151
+			$existing = DNProject::get()->filter('Name', $this->Name);
1152
+			if ($this->ID) {
1153
+				$existing = $existing->exclude('ID', $this->ID);
1154
+			}
1155
+			if ($existing->count() > 0) {
1156
+				return $validation->error('A stack already exists with that name.');
1157
+			}
1158
+		}
1159
+		return $validation;
1160
+	}
1161
+
1162
+	/**
1163
+	 * @param Member $member
1164
+	 *
1165
+	 * @return bool
1166
+	 */
1167
+	public function canCreate($member = null)
1168
+	{
1169
+		if (!$member) {
1170
+			$member = Member::currentUser();
1171
+		}
1172
+		if (!$member) {
1173
+			return false;
1174
+		}
1175
+
1176
+		if (Permission::checkMember($member, 'ADMIN')) {
1177
+			return true;
1178
+		}
1179
+
1180
+		// This calls canCreate on extensions.
1181
+		return parent::canCreate($member);
1182
+	}
1183 1183
 }
Please login to merge, or discard this patch.
Spacing   +73 added lines, -73 removed lines patch added patch discarded remove patch
@@ -111,7 +111,7 @@  discard block
 block discarded – undo
111 111
 
112 112
         // add the administrators group as the viewers of the new project
113 113
         $adminGroup = Group::get()->filter('Code', 'administrators')->first();
114
-        if ($adminGroup && $adminGroup->exists()) {
114
+        if($adminGroup && $adminGroup->exists()) {
115 115
             $project->Viewers()->add($adminGroup);
116 116
         }
117 117
         return $project;
@@ -127,8 +127,8 @@  discard block
 block discarded – undo
127 127
     {
128 128
         $size = 0;
129 129
 
130
-        foreach ($this->Environments() as $environment) {
131
-            foreach ($environment->DataArchives()->filter('IsBackup', 0) as $archive) {
130
+        foreach($this->Environments() as $environment) {
131
+            foreach($environment->DataArchives()->filter('IsBackup', 0) as $archive) {
132 132
                 $size += $archive->ArchiveFile()->getAbsoluteSize();
133 133
             }
134 134
         }
@@ -148,7 +148,7 @@  discard block
 block discarded – undo
148 148
     {
149 149
         $size = $this->getField('DiskQuotaMB');
150 150
 
151
-        if (empty($size)) {
151
+        if(empty($size)) {
152 152
             $defaults = $this->config()->get('defaults');
153 153
             $size = (isset($defaults['DiskQuotaMB'])) ? $defaults['DiskQuotaMB'] : 0;
154 154
         }
@@ -184,7 +184,7 @@  discard block
 block discarded – undo
184 184
     public function DiskQuotaUsagePercent()
185 185
     {
186 186
         $quota = $this->getDiskQuotaMB();
187
-        if ($quota > 0) {
187
+        if($quota > 0) {
188 188
             return $this->getUsedQuotaMB() * 100 / $quota;
189 189
         }
190 190
         return 100;
@@ -202,7 +202,7 @@  discard block
 block discarded – undo
202 202
         $controller = Controller::curr();
203 203
         $actionType = $controller->getField('CurrentActionType');
204 204
 
205
-        if (DNRoot::FlagSnapshotsEnabled() && $this->isProjectReady()) {
205
+        if(DNRoot::FlagSnapshotsEnabled() && $this->isProjectReady()) {
206 206
             $list->push(new ArrayData(array(
207 207
                 'Link' => sprintf('naut/project/%s/snapshots', $this->Name),
208 208
                 'Title' => 'Snapshots',
@@ -257,11 +257,11 @@  discard block
 block discarded – undo
257 257
      */
258 258
     public function canView($member = null)
259 259
     {
260
-        if (!$member) {
260
+        if(!$member) {
261 261
             $member = Member::currentUser();
262 262
         }
263 263
 
264
-        if (Permission::checkMember($member, 'ADMIN')) {
264
+        if(Permission::checkMember($member, 'ADMIN')) {
265 265
             return true;
266 266
         }
267 267
 
@@ -275,7 +275,7 @@  discard block
 block discarded – undo
275 275
      */
276 276
     public function canRestore($member = null)
277 277
     {
278
-        if ($this->allowedAny(
278
+        if($this->allowedAny(
279 279
             array(
280 280
                 DNRoot::ALLOW_PROD_SNAPSHOT,
281 281
                 DNRoot::ALLOW_NON_PROD_SNAPSHOT
@@ -285,7 +285,7 @@  discard block
 block discarded – undo
285 285
             return true;
286 286
         }
287 287
 
288
-        return (bool)$this->Environments()->filterByCallback(function ($env) use ($member) {
288
+        return (bool)$this->Environments()->filterByCallback(function($env) use ($member) {
289 289
             return $env->canRestore($member);
290 290
         })->Count();
291 291
     }
@@ -296,7 +296,7 @@  discard block
 block discarded – undo
296 296
      */
297 297
     public function canBackup($member = null)
298 298
     {
299
-        if ($this->allowedAny(
299
+        if($this->allowedAny(
300 300
             array(
301 301
                 DNRoot::ALLOW_PROD_SNAPSHOT,
302 302
                 DNRoot::ALLOW_NON_PROD_SNAPSHOT
@@ -306,7 +306,7 @@  discard block
 block discarded – undo
306 306
             return true;
307 307
         }
308 308
 
309
-        return (bool)$this->Environments()->filterByCallback(function ($env) use ($member) {
309
+        return (bool)$this->Environments()->filterByCallback(function($env) use ($member) {
310 310
             return $env->canBackup($member);
311 311
         })->Count();
312 312
     }
@@ -317,7 +317,7 @@  discard block
 block discarded – undo
317 317
      */
318 318
     public function canUploadArchive($member = null)
319 319
     {
320
-        if ($this->allowedAny(
320
+        if($this->allowedAny(
321 321
             array(
322 322
                 DNRoot::ALLOW_PROD_SNAPSHOT,
323 323
                 DNRoot::ALLOW_NON_PROD_SNAPSHOT
@@ -327,7 +327,7 @@  discard block
 block discarded – undo
327 327
             return true;
328 328
         }
329 329
 
330
-        return (bool)$this->Environments()->filterByCallback(function ($env) use ($member) {
330
+        return (bool)$this->Environments()->filterByCallback(function($env) use ($member) {
331 331
             return $env->canUploadArchive($member);
332 332
         })->Count();
333 333
     }
@@ -338,7 +338,7 @@  discard block
 block discarded – undo
338 338
      */
339 339
     public function canDownloadArchive($member = null)
340 340
     {
341
-        if ($this->allowedAny(
341
+        if($this->allowedAny(
342 342
             array(
343 343
                 DNRoot::ALLOW_PROD_SNAPSHOT,
344 344
                 DNRoot::ALLOW_NON_PROD_SNAPSHOT
@@ -348,7 +348,7 @@  discard block
 block discarded – undo
348 348
             return true;
349 349
         }
350 350
 
351
-        return (bool)$this->Environments()->filterByCallback(function ($env) use ($member) {
351
+        return (bool)$this->Environments()->filterByCallback(function($env) use ($member) {
352 352
             return $env->canDownloadArchive($member);
353 353
         })->Count();
354 354
     }
@@ -366,9 +366,9 @@  discard block
 block discarded – undo
366 366
     public function canCreateEnvironments($member = null)
367 367
     {
368 368
         $envType = $this->AllowedEnvironmentType;
369
-        if ($envType) {
369
+        if($envType) {
370 370
             $env = Injector::inst()->get($envType);
371
-            if ($env instanceof EnvironmentCreateBackend) {
371
+            if($env instanceof EnvironmentCreateBackend) {
372 372
                 return $this->allowed(DNRoot::ALLOW_CREATE_ENVIRONMENT, $member);
373 373
             }
374 374
         }
@@ -407,7 +407,7 @@  discard block
 block discarded – undo
407 407
      */
408 408
     public function getProcessEnv()
409 409
     {
410
-        if (file_exists($this->getPrivateKeyPath())) {
410
+        if(file_exists($this->getPrivateKeyPath())) {
411 411
             // Key-pair is available, use it.
412 412
             $processEnv = array(
413 413
                 'IDENT_KEY' => $this->getPrivateKeyPath(),
@@ -456,7 +456,7 @@  discard block
 block discarded – undo
456 456
      */
457 457
     public function DNBranchList()
458 458
     {
459
-        if ($this->CVSPath && !$this->repoExists()) {
459
+        if($this->CVSPath && !$this->repoExists()) {
460 460
             $this->cloneRepo();
461 461
         }
462 462
         return DNBranchList::create($this, $this->DNData());
@@ -469,7 +469,7 @@  discard block
 block discarded – undo
469 469
      */
470 470
     public function DNTagList()
471 471
     {
472
-        if ($this->CVSPath && !$this->repoExists()) {
472
+        if($this->CVSPath && !$this->repoExists()) {
473 473
             $this->cloneRepo();
474 474
         }
475 475
         return DNReferenceList::create($this, $this->DNData(), null, null, true);
@@ -480,7 +480,7 @@  discard block
 block discarded – undo
480 480
      */
481 481
     public function getRepository()
482 482
     {
483
-        if (!$this->repoExists()) {
483
+        if(!$this->repoExists()) {
484 484
             return false;
485 485
         }
486 486
 
@@ -495,17 +495,17 @@  discard block
 block discarded – undo
495 495
      */
496 496
     public function DNEnvironmentList()
497 497
     {
498
-        if (!self::$_current_member_cache) {
498
+        if(!self::$_current_member_cache) {
499 499
             self::$_current_member_cache = Member::currentUser();
500 500
         }
501 501
 
502
-        if (self::$_current_member_cache === false) {
502
+        if(self::$_current_member_cache === false) {
503 503
             return new ArrayList();
504 504
         }
505 505
 
506 506
         $currentMember = self::$_current_member_cache;
507 507
         return $this->Environments()
508
-            ->filterByCallBack(function ($item) use ($currentMember) {
508
+            ->filterByCallBack(function($item) use ($currentMember) {
509 509
                 return $item->canView($currentMember);
510 510
             });
511 511
     }
@@ -526,14 +526,14 @@  discard block
 block discarded – undo
526 526
      */
527 527
     public function currentBuilds()
528 528
     {
529
-        if (!isset(self::$relation_cache['currentBuilds.'.$this->ID])) {
529
+        if(!isset(self::$relation_cache['currentBuilds.' . $this->ID])) {
530 530
             $currentBuilds = array();
531
-            foreach ($this->Environments() as $env) {
531
+            foreach($this->Environments() as $env) {
532 532
                 $currentBuilds[$env->Name] = $env->CurrentBuild();
533 533
             }
534
-            self::$relation_cache['currentBuilds.'.$this->ID] = $currentBuilds;
534
+            self::$relation_cache['currentBuilds.' . $this->ID] = $currentBuilds;
535 535
         }
536
-        return self::$relation_cache['currentBuilds.'.$this->ID];
536
+        return self::$relation_cache['currentBuilds.' . $this->ID];
537 537
     }
538 538
 
539 539
     /**
@@ -550,7 +550,7 @@  discard block
 block discarded – undo
550 550
      */
551 551
     public function CreateEnvironmentLink()
552 552
     {
553
-        if ($this->canCreateEnvironments()) {
553
+        if($this->canCreateEnvironments()) {
554 554
             return $this->Link('createenv');
555 555
         }
556 556
         return null;
@@ -570,11 +570,11 @@  discard block
 block discarded – undo
570 570
     public function IsStarred()
571 571
     {
572 572
         $member = Member::currentUser();
573
-        if ($member === null) {
573
+        if($member === null) {
574 574
             return false;
575 575
         }
576 576
         $favourited = $this->StarredBy()->filter('MemberID', $member->ID);
577
-        if ($favourited->count() == 0) {
577
+        if($favourited->count() == 0) {
578 578
             return false;
579 579
         }
580 580
         return true;
@@ -631,7 +631,7 @@  discard block
 block discarded – undo
631 631
 
632 632
         $environmentTypes = ClassInfo::implementorsOf('EnvironmentCreateBackend');
633 633
         $types = array();
634
-        foreach ($environmentTypes as $type) {
634
+        foreach($environmentTypes as $type) {
635 635
             $types[$type] = $type;
636 636
         }
637 637
 
@@ -656,11 +656,11 @@  discard block
 block discarded – undo
656 656
     public function setCreateProjectFolderField(&$fields)
657 657
     {
658 658
         // Check if the capistrano project folder exists
659
-        if (!$this->Name) {
659
+        if(!$this->Name) {
660 660
             return;
661 661
         }
662 662
 
663
-        if ($this->projectFolderExists()) {
663
+        if($this->projectFolderExists()) {
664 664
             return;
665 665
         }
666 666
 
@@ -695,7 +695,7 @@  discard block
 block discarded – undo
695 695
     public function cloneRepo()
696 696
     {
697 697
         // Avoid this being called multiple times in the same request
698
-        if (!isset(self::$has_cloned_cache[$this->ID])) {
698
+        if(!isset(self::$has_cloned_cache[$this->ID])) {
699 699
             $fetch = DNGitFetch::create();
700 700
             $fetch->ProjectID = $this->ID;
701 701
             $fetch->write();
@@ -721,7 +721,7 @@  discard block
 block discarded – undo
721 721
     {
722 722
         parent::onBeforeWrite();
723 723
 
724
-        if ($this->CreateEnvFolder && !file_exists($this->getProjectFolderPath())) {
724
+        if($this->CreateEnvFolder && !file_exists($this->getProjectFolderPath())) {
725 725
             mkdir($this->getProjectFolderPath());
726 726
         }
727 727
     }
@@ -730,12 +730,12 @@  discard block
 block discarded – undo
730 730
     {
731 731
         parent::onAfterWrite();
732 732
 
733
-        if (!$this->CVSPath) {
733
+        if(!$this->CVSPath) {
734 734
             return;
735 735
         }
736 736
 
737 737
         $changedFields = $this->getChangedFields(true, 2);
738
-        if (isset($changedFields['CVSPath']) || isset($changedFields['Name'])) {
738
+        if(isset($changedFields['CVSPath']) || isset($changedFields['Name'])) {
739 739
             $this->cloneRepo();
740 740
         }
741 741
     }
@@ -748,22 +748,22 @@  discard block
 block discarded – undo
748 748
         parent::onAfterDelete();
749 749
 
750 750
         // Delete related environments
751
-        foreach ($this->Environments() as $env) {
751
+        foreach($this->Environments() as $env) {
752 752
             $env->delete();
753 753
         }
754 754
 
755 755
         // Delete local repository
756
-        if (file_exists($this->getLocalCVSPath())) {
756
+        if(file_exists($this->getLocalCVSPath())) {
757 757
             Filesystem::removeFolder($this->getLocalCVSPath());
758 758
         }
759 759
 
760 760
         // Delete project template
761
-        if (file_exists($this->getProjectFolderPath()) && Config::inst()->get('DNEnvironment', 'allow_web_editing')) {
761
+        if(file_exists($this->getProjectFolderPath()) && Config::inst()->get('DNEnvironment', 'allow_web_editing')) {
762 762
             Filesystem::removeFolder($this->getProjectFolderPath());
763 763
         }
764 764
 
765 765
         // Delete the deploy key
766
-        if (file_exists($this->getKeyDir())) {
766
+        if(file_exists($this->getKeyDir())) {
767 767
             Filesystem::removeFolder($this->getKeyDir());
768 768
         }
769 769
     }
@@ -777,7 +777,7 @@  discard block
 block discarded – undo
777 777
     {
778 778
         $key = $this->getPublicKeyPath();
779 779
 
780
-        if (file_exists($key)) {
780
+        if(file_exists($key)) {
781 781
             return trim(file_get_contents($key));
782 782
         }
783 783
     }
@@ -789,7 +789,7 @@  discard block
 block discarded – undo
789 789
      */
790 790
     public function getPublicKeyPath()
791 791
     {
792
-        if ($privateKey = $this->getPrivateKeyPath()) {
792
+        if($privateKey = $this->getPrivateKeyPath()) {
793 793
             return $privateKey . '.pub';
794 794
         }
795 795
         return null;
@@ -803,7 +803,7 @@  discard block
 block discarded – undo
803 803
     public function getPrivateKeyPath()
804 804
     {
805 805
         $keyDir = $this->getKeyDir();
806
-        if (!empty($keyDir)) {
806
+        if(!empty($keyDir)) {
807 807
             $filter = FileNameFilter::create();
808 808
             $name = $filter->filter($this->Name);
809 809
             return $keyDir . '/' . $name;
@@ -819,7 +819,7 @@  discard block
 block discarded – undo
819 819
     public function getKeyDir()
820 820
     {
821 821
         $keyDir = $this->DNData()->getKeyDir();
822
-        if (!$keyDir) {
822
+        if(!$keyDir) {
823 823
             return null;
824 824
         }
825 825
 
@@ -837,7 +837,7 @@  discard block
 block discarded – undo
837 837
      */
838 838
     protected function setEnvironmentFields(&$fields, $environments)
839 839
     {
840
-        if (!$environments) {
840
+        if(!$environments) {
841 841
             return;
842 842
         }
843 843
 
@@ -846,7 +846,7 @@  discard block
 block discarded – undo
846 846
         $environments->getConfig()->removeComponentsByType('GridFieldAddExistingAutocompleter');
847 847
         $environments->getConfig()->removeComponentsByType('GridFieldDeleteAction');
848 848
         $environments->getConfig()->removeComponentsByType('GridFieldPageCount');
849
-        if (Config::inst()->get('DNEnvironment', 'allow_web_editing')) {
849
+        if(Config::inst()->get('DNEnvironment', 'allow_web_editing')) {
850 850
             $addNewRelease = new GridFieldAddNewButton('toolbar-header-right');
851 851
             $addNewRelease->setButtonName('Add');
852 852
             $environments->getConfig()->addComponent($addNewRelease);
@@ -863,7 +863,7 @@  discard block
 block discarded – undo
863 863
     public function getRepositoryURL()
864 864
     {
865 865
         $showUrl = Config::inst()->get($this->class, 'show_repository_url');
866
-        if ($showUrl) {
866
+        if($showUrl) {
867 867
             return $this->CVSPath;
868 868
         }
869 869
     }
@@ -916,9 +916,9 @@  discard block
 block discarded – undo
916 916
         $interfaces = $this->config()->repository_interfaces;
917 917
 
918 918
         /* Look for each whitelisted hostname */
919
-        foreach ($interfaces as $host => $interface) {
919
+        foreach($interfaces as $host => $interface) {
920 920
             /* See if the CVS Path is for this hostname, followed by some junk (maybe a port), then the path */
921
-            if (preg_match('{^[^.]*' . $host . '(.*?)([/a-zA-Z].+)}', $this->CVSPath, $match)) {
921
+            if(preg_match('{^[^.]*' . $host . '(.*?)([/a-zA-Z].+)}', $this->CVSPath, $match)) {
922 922
                 $path = $match[2];
923 923
 
924 924
                 $scheme = isset($interface['scheme']) ? $interface['scheme'] : 'https';
@@ -927,13 +927,13 @@  discard block
 block discarded – undo
927 927
 
928 928
                 $components = explode('.', $host);
929 929
 
930
-                foreach ($regex as $pattern => $replacement) {
930
+                foreach($regex as $pattern => $replacement) {
931 931
                     $path = preg_replace('/' . $pattern . '/', $replacement, $path);
932 932
                 }
933 933
 
934 934
                 $uxurl = Controller::join_links($scheme . '://', $host, $path);
935 935
 
936
-                if (array_key_exists('commit', $interface) && $interface['commit'] == false) {
936
+                if(array_key_exists('commit', $interface) && $interface['commit'] == false) {
937 937
                     $commiturl = false;
938 938
                 } else {
939 939
                     $commiturl = Controller::join_links(
@@ -980,7 +980,7 @@  discard block
 block discarded – undo
980 980
      */
981 981
     public function whoIsAllowedAny($codes)
982 982
     {
983
-        if (!is_array($codes)) {
983
+        if(!is_array($codes)) {
984 984
             $codes = array($codes);
985 985
         }
986 986
 
@@ -1023,11 +1023,11 @@  discard block
 block discarded – undo
1023 1023
     public function groupAllowed($permissionCode, Group $group)
1024 1024
     {
1025 1025
         $viewers = $this->Viewers();
1026
-        if (!$viewers->find('ID', $group->ID)) {
1026
+        if(!$viewers->find('ID', $group->ID)) {
1027 1027
             return false;
1028 1028
         }
1029 1029
         $groups = Permission::get_groups_by_permission($permissionCode);
1030
-        if (!$groups->find('ID', $group->ID)) {
1030
+        if(!$groups->find('ID', $group->ID)) {
1031 1031
             return false;
1032 1032
         }
1033 1033
         return true;
@@ -1043,16 +1043,16 @@  discard block
 block discarded – undo
1043 1043
      */
1044 1044
     public function allowedAny($codes, $member = null)
1045 1045
     {
1046
-        if (!$member) {
1046
+        if(!$member) {
1047 1047
             $member = Member::currentUser();
1048 1048
         }
1049 1049
 
1050
-        if (Permission::checkMember($member, 'ADMIN')) {
1050
+        if(Permission::checkMember($member, 'ADMIN')) {
1051 1051
             return true;
1052 1052
         }
1053 1053
 
1054 1054
         $hits = $this->whoIsAllowedAny($codes)->filter('Member.ID', $member->ID)->count();
1055
-        return ($hits>0 ? true : false);
1055
+        return ($hits > 0 ? true : false);
1056 1056
     }
1057 1057
 
1058 1058
     /**
@@ -1062,7 +1062,7 @@  discard block
 block discarded – undo
1062 1062
      */
1063 1063
     public function isProjectReady()
1064 1064
     {
1065
-        if ($this->getRunningInitialEnvironmentCreations()->count() > 0) {
1065
+        if($this->getRunningInitialEnvironmentCreations()->count() > 0) {
1066 1066
             // We're still creating the initial environments for this project so we're
1067 1067
             // not quite done
1068 1068
             return false;
@@ -1071,13 +1071,13 @@  discard block
 block discarded – undo
1071 1071
         // Provide a hook for further checks. Logic stolen from
1072 1072
         // {@see DataObject::extendedCan()}
1073 1073
         $isDone = $this->extend('isProjectReady');
1074
-        if ($isDone && is_array($isDone)) {
1075
-            $isDone = array_filter($isDone, function ($val) {
1074
+        if($isDone && is_array($isDone)) {
1075
+            $isDone = array_filter($isDone, function($val) {
1076 1076
                 return !is_null($val);
1077 1077
             });
1078 1078
 
1079 1079
             // If anything returns false then we're not ready.
1080
-            if ($isDone) {
1080
+            if($isDone) {
1081 1081
                 return min($isDone);
1082 1082
             }
1083 1083
         }
@@ -1134,25 +1134,25 @@  discard block
 block discarded – undo
1134 1134
     protected function validate()
1135 1135
     {
1136 1136
         $validation = parent::validate();
1137
-        if ($validation->valid()) {
1138
-            if (empty($this->Name)) {
1137
+        if($validation->valid()) {
1138
+            if(empty($this->Name)) {
1139 1139
                 return $validation->error('The stack must have a name.');
1140 1140
             }
1141 1141
 
1142 1142
             // The name is used to build filepaths so should be restricted
1143
-            if (!preg_match('/^[a-zA-Z0-9][a-zA-Z0-9\-\_]+$/', $this->Name)) {
1143
+            if(!preg_match('/^[a-zA-Z0-9][a-zA-Z0-9\-\_]+$/', $this->Name)) {
1144 1144
                 return $validation->error('Project name can only contain alphanumeric, hyphens and underscores.');
1145 1145
             }
1146 1146
 
1147
-            if (empty($this->CVSPath)) {
1147
+            if(empty($this->CVSPath)) {
1148 1148
                 return $validation->error('You must provide a repository URL.');
1149 1149
             }
1150 1150
 
1151 1151
             $existing = DNProject::get()->filter('Name', $this->Name);
1152
-            if ($this->ID) {
1152
+            if($this->ID) {
1153 1153
                 $existing = $existing->exclude('ID', $this->ID);
1154 1154
             }
1155
-            if ($existing->count() > 0) {
1155
+            if($existing->count() > 0) {
1156 1156
                 return $validation->error('A stack already exists with that name.');
1157 1157
             }
1158 1158
         }
@@ -1166,14 +1166,14 @@  discard block
 block discarded – undo
1166 1166
      */
1167 1167
     public function canCreate($member = null)
1168 1168
     {
1169
-        if (!$member) {
1169
+        if(!$member) {
1170 1170
             $member = Member::currentUser();
1171 1171
         }
1172
-        if (!$member) {
1172
+        if(!$member) {
1173 1173
             return false;
1174 1174
         }
1175 1175
 
1176
-        if (Permission::checkMember($member, 'ADMIN')) {
1176
+        if(Permission::checkMember($member, 'ADMIN')) {
1177 1177
             return true;
1178 1178
         }
1179 1179
 
Please login to merge, or discard this patch.
Braces   +63 added lines, -126 removed lines patch added patch discarded remove patch
@@ -12,8 +12,7 @@  discard block
 block discarded – undo
12 12
  * @method ManyManyList Viewers()
13 13
  * @method ManyManyList StarredBy()
14 14
  */
15
-class DNProject extends DataObject
16
-{
15
+class DNProject extends DataObject {
17 16
 
18 17
     /**
19 18
      * @var array
@@ -103,8 +102,7 @@  discard block
 block discarded – undo
103 102
      * @param string $path
104 103
      * @return \DNProject
105 104
      */
106
-    public static function create_from_path($path)
107
-    {
105
+    public static function create_from_path($path) {
108 106
         $project = DNProject::create();
109 107
         $project->Name = $path;
110 108
         $project->write();
@@ -123,8 +121,7 @@  discard block
 block discarded – undo
123 121
      * @param int $round Number of decimal places to round to
124 122
      * @return double The used quota size in MB
125 123
      */
126
-    public function getUsedQuotaMB($round = 2)
127
-    {
124
+    public function getUsedQuotaMB($round = 2) {
128 125
         $size = 0;
129 126
 
130 127
         foreach ($this->Environments() as $environment) {
@@ -144,8 +141,7 @@  discard block
 block discarded – undo
144 141
      *
145 142
      * @return string|int The quota size in MB
146 143
      */
147
-    public function getDiskQuotaMB()
148
-    {
144
+    public function getDiskQuotaMB() {
149 145
         $size = $this->getField('DiskQuotaMB');
150 146
 
151 147
         if (empty($size)) {
@@ -161,8 +157,7 @@  discard block
 block discarded – undo
161 157
      *
162 158
      * @return boolean
163 159
      */
164
-    public function HasExceededDiskQuota()
165
-    {
160
+    public function HasExceededDiskQuota() {
166 161
         return $this->getUsedQuotaMB(0) >= $this->getDiskQuotaMB();
167 162
     }
168 163
 
@@ -171,8 +166,7 @@  discard block
 block discarded – undo
171 166
      *
172 167
      * @return boolean
173 168
      */
174
-    public function HasDiskQuota()
175
-    {
169
+    public function HasDiskQuota() {
176 170
         return $this->getDiskQuotaMB() > 0;
177 171
     }
178 172
 
@@ -181,8 +175,7 @@  discard block
 block discarded – undo
181 175
      *
182 176
      * @return int
183 177
      */
184
-    public function DiskQuotaUsagePercent()
185
-    {
178
+    public function DiskQuotaUsagePercent() {
186 179
         $quota = $this->getDiskQuotaMB();
187 180
         if ($quota > 0) {
188 181
             return $this->getUsedQuotaMB() * 100 / $quota;
@@ -195,8 +188,7 @@  discard block
 block discarded – undo
195 188
      *
196 189
      * @return ArrayList
197 190
      */
198
-    public function Menu()
199
-    {
191
+    public function Menu() {
200 192
         $list = new ArrayList();
201 193
 
202 194
         $controller = Controller::curr();
@@ -221,8 +213,7 @@  discard block
 block discarded – undo
221 213
      *
222 214
      * @return bool
223 215
      */
224
-    public function isCurrent()
225
-    {
216
+    public function isCurrent() {
226 217
         return $this->isSection() && Controller::curr()->getAction() == 'project';
227 218
     }
228 219
 
@@ -232,8 +223,7 @@  discard block
 block discarded – undo
232 223
      *
233 224
      * @return DataObject
234 225
      */
235
-    public function CurrentMenu()
236
-    {
226
+    public function CurrentMenu() {
237 227
         return $this->Menu()->filter('IsSection', true)->First();
238 228
     }
239 229
 
@@ -242,8 +232,7 @@  discard block
 block discarded – undo
242 232
      *
243 233
      * @return bool
244 234
      */
245
-    public function isSection()
246
-    {
235
+    public function isSection() {
247 236
         $controller = Controller::curr();
248 237
         $project = $controller->getField('CurrentProject');
249 238
         return $project && $this->ID == $project->ID;
@@ -255,8 +244,7 @@  discard block
 block discarded – undo
255 244
      * @param Member|null $member
256 245
      * @return boolean
257 246
      */
258
-    public function canView($member = null)
259
-    {
247
+    public function canView($member = null) {
260 248
         if (!$member) {
261 249
             $member = Member::currentUser();
262 250
         }
@@ -273,8 +261,7 @@  discard block
 block discarded – undo
273 261
      *
274 262
      * @return bool
275 263
      */
276
-    public function canRestore($member = null)
277
-    {
264
+    public function canRestore($member = null) {
278 265
         if ($this->allowedAny(
279 266
             array(
280 267
                 DNRoot::ALLOW_PROD_SNAPSHOT,
@@ -294,8 +281,7 @@  discard block
 block discarded – undo
294 281
      * @param Member|null $member
295 282
      * @return bool
296 283
      */
297
-    public function canBackup($member = null)
298
-    {
284
+    public function canBackup($member = null) {
299 285
         if ($this->allowedAny(
300 286
             array(
301 287
                 DNRoot::ALLOW_PROD_SNAPSHOT,
@@ -315,8 +301,7 @@  discard block
 block discarded – undo
315 301
      * @param Member|null $member
316 302
      * @return bool
317 303
      */
318
-    public function canUploadArchive($member = null)
319
-    {
304
+    public function canUploadArchive($member = null) {
320 305
         if ($this->allowedAny(
321 306
             array(
322 307
                 DNRoot::ALLOW_PROD_SNAPSHOT,
@@ -336,8 +321,7 @@  discard block
 block discarded – undo
336 321
      * @param Member|null $member
337 322
      * @return bool
338 323
      */
339
-    public function canDownloadArchive($member = null)
340
-    {
324
+    public function canDownloadArchive($member = null) {
341 325
         if ($this->allowedAny(
342 326
             array(
343 327
                 DNRoot::ALLOW_PROD_SNAPSHOT,
@@ -363,8 +347,7 @@  discard block
 block discarded – undo
363 347
      *
364 348
      * @return bool
365 349
      */
366
-    public function canCreateEnvironments($member = null)
367
-    {
350
+    public function canCreateEnvironments($member = null) {
368 351
         $envType = $this->AllowedEnvironmentType;
369 352
         if ($envType) {
370 353
             $env = Injector::inst()->get($envType);
@@ -378,8 +361,7 @@  discard block
 block discarded – undo
378 361
     /**
379 362
      * @return DataList
380 363
      */
381
-    public function DataArchives()
382
-    {
364
+    public function DataArchives() {
383 365
         $envIds = $this->Environments()->column('ID');
384 366
         return DNDataArchive::get()->filter('EnvironmentID', $envIds);
385 367
     }
@@ -390,8 +372,7 @@  discard block
 block discarded – undo
390 372
      *
391 373
      * @return DataList
392 374
      */
393
-    public function PendingManualUploadDataArchives()
394
-    {
375
+    public function PendingManualUploadDataArchives() {
395 376
         return $this->DataArchives()->filter('ArchiveFileID', null);
396 377
     }
397 378
 
@@ -405,8 +386,7 @@  discard block
 block discarded – undo
405 386
      *
406 387
      * @return array
407 388
      */
408
-    public function getProcessEnv()
409
-    {
389
+    public function getProcessEnv() {
410 390
         if (file_exists($this->getPrivateKeyPath())) {
411 391
             // Key-pair is available, use it.
412 392
             $processEnv = array(
@@ -426,16 +406,14 @@  discard block
 block discarded – undo
426 406
      *
427 407
      * @return string
428 408
      */
429
-    public function getViewersList()
430
-    {
409
+    public function getViewersList() {
431 410
         return implode(", ", $this->Viewers()->column("Title"));
432 411
     }
433 412
 
434 413
     /**
435 414
      * @return DNData
436 415
      */
437
-    public function DNData()
438
-    {
416
+    public function DNData() {
439 417
         return DNData::inst();
440 418
     }
441 419
 
@@ -444,8 +422,7 @@  discard block
 block discarded – undo
444 422
      *
445 423
      * @return DNReferenceList
446 424
      */
447
-    public function DNBuildList()
448
-    {
425
+    public function DNBuildList() {
449 426
         return DNReferenceList::create($this, $this->DNData());
450 427
     }
451 428
 
@@ -454,8 +431,7 @@  discard block
 block discarded – undo
454 431
      *
455 432
      * @return DNBranchList
456 433
      */
457
-    public function DNBranchList()
458
-    {
434
+    public function DNBranchList() {
459 435
         if ($this->CVSPath && !$this->repoExists()) {
460 436
             $this->cloneRepo();
461 437
         }
@@ -467,8 +443,7 @@  discard block
 block discarded – undo
467 443
      *
468 444
      * @return DNReferenceList
469 445
      */
470
-    public function DNTagList()
471
-    {
446
+    public function DNTagList() {
472 447
         if ($this->CVSPath && !$this->repoExists()) {
473 448
             $this->cloneRepo();
474 449
         }
@@ -478,8 +453,7 @@  discard block
 block discarded – undo
478 453
     /**
479 454
      * @return false|Gitonomy\Git\Repository
480 455
      */
481
-    public function getRepository()
482
-    {
456
+    public function getRepository() {
483 457
         if (!$this->repoExists()) {
484 458
             return false;
485 459
         }
@@ -493,8 +467,7 @@  discard block
 block discarded – undo
493 467
      *
494 468
      * @return ArrayList
495 469
      */
496
-    public function DNEnvironmentList()
497
-    {
470
+    public function DNEnvironmentList() {
498 471
         if (!self::$_current_member_cache) {
499 472
             self::$_current_member_cache = Member::currentUser();
500 473
         }
@@ -514,8 +487,7 @@  discard block
 block discarded – undo
514 487
      * @param string $usage
515 488
      * @return ArrayList
516 489
      */
517
-    public function EnvironmentsByUsage($usage)
518
-    {
490
+    public function EnvironmentsByUsage($usage) {
519 491
         return $this->DNEnvironmentList()->filter('Usage', $usage);
520 492
     }
521 493
 
@@ -524,8 +496,7 @@  discard block
 block discarded – undo
524 496
      *
525 497
      * @return false|DNDeployment
526 498
      */
527
-    public function currentBuilds()
528
-    {
499
+    public function currentBuilds() {
529 500
         if (!isset(self::$relation_cache['currentBuilds.'.$this->ID])) {
530 501
             $currentBuilds = array();
531 502
             foreach ($this->Environments() as $env) {
@@ -540,16 +511,14 @@  discard block
 block discarded – undo
540 511
      * @param string
541 512
      * @return string
542 513
      */
543
-    public function Link($action = '')
544
-    {
514
+    public function Link($action = '') {
545 515
         return Controller::join_links("naut", "project", $this->Name, $action);
546 516
     }
547 517
 
548 518
     /**
549 519
      * @return string|null
550 520
      */
551
-    public function CreateEnvironmentLink()
552
-    {
521
+    public function CreateEnvironmentLink() {
553 522
         if ($this->canCreateEnvironments()) {
554 523
             return $this->Link('createenv');
555 524
         }
@@ -559,16 +528,14 @@  discard block
 block discarded – undo
559 528
     /**
560 529
      * @return string
561 530
      */
562
-    public function ToggleStarLink()
563
-    {
531
+    public function ToggleStarLink() {
564 532
         return $this->Link('/star');
565 533
     }
566 534
 
567 535
     /**
568 536
      * @return bool
569 537
      */
570
-    public function IsStarred()
571
-    {
538
+    public function IsStarred() {
572 539
         $member = Member::currentUser();
573 540
         if ($member === null) {
574 541
             return false;
@@ -584,16 +551,14 @@  discard block
 block discarded – undo
584 551
      * @param string $action
585 552
      * @return string
586 553
      */
587
-    public function APILink($action)
588
-    {
554
+    public function APILink($action) {
589 555
         return Controller::join_links("naut", "api", $this->Name, $action);
590 556
     }
591 557
 
592 558
     /**
593 559
      * @return FieldList
594 560
      */
595
-    public function getCMSFields()
596
-    {
561
+    public function getCMSFields() {
597 562
         $fields = parent::getCMSFields();
598 563
 
599 564
         /** @var GridField $environments */
@@ -653,8 +618,7 @@  discard block
 block discarded – undo
653 618
      *
654 619
      * @param FieldList $fields
655 620
      */
656
-    public function setCreateProjectFolderField(&$fields)
657
-    {
621
+    public function setCreateProjectFolderField(&$fields) {
658 622
         // Check if the capistrano project folder exists
659 623
         if (!$this->Name) {
660 624
             return;
@@ -675,16 +639,14 @@  discard block
 block discarded – undo
675 639
     /**
676 640
      * @return boolean
677 641
      */
678
-    public function projectFolderExists()
679
-    {
642
+    public function projectFolderExists() {
680 643
         return file_exists($this->getProjectFolderPath());
681 644
     }
682 645
 
683 646
     /**
684 647
      * @return bool
685 648
      */
686
-    public function repoExists()
687
-    {
649
+    public function repoExists() {
688 650
         return file_exists(sprintf('%s/HEAD', $this->getLocalCVSPath()));
689 651
     }
690 652
 
@@ -692,8 +654,7 @@  discard block
 block discarded – undo
692 654
      * Setup a job to clone a git repository.
693 655
      * @return string resque token
694 656
      */
695
-    public function cloneRepo()
696
-    {
657
+    public function cloneRepo() {
697 658
         // Avoid this being called multiple times in the same request
698 659
         if (!isset(self::$has_cloned_cache[$this->ID])) {
699 660
             $fetch = DNGitFetch::create();
@@ -712,13 +673,11 @@  discard block
 block discarded – undo
712 673
     /**
713 674
      * @return string
714 675
      */
715
-    public function getLocalCVSPath()
716
-    {
676
+    public function getLocalCVSPath() {
717 677
         return sprintf('%s/%s', DEPLOYNAUT_LOCAL_VCS_PATH, $this->Name);
718 678
     }
719 679
 
720
-    public function onBeforeWrite()
721
-    {
680
+    public function onBeforeWrite() {
722 681
         parent::onBeforeWrite();
723 682
 
724 683
         if ($this->CreateEnvFolder && !file_exists($this->getProjectFolderPath())) {
@@ -726,8 +685,7 @@  discard block
 block discarded – undo
726 685
         }
727 686
     }
728 687
 
729
-    public function onAfterWrite()
730
-    {
688
+    public function onAfterWrite() {
731 689
         parent::onAfterWrite();
732 690
 
733 691
         if (!$this->CVSPath) {
@@ -743,8 +701,7 @@  discard block
 block discarded – undo
743 701
     /**
744 702
      * Delete related environments and folders
745 703
      */
746
-    public function onAfterDelete()
747
-    {
704
+    public function onAfterDelete() {
748 705
         parent::onAfterDelete();
749 706
 
750 707
         // Delete related environments
@@ -773,8 +730,7 @@  discard block
 block discarded – undo
773 730
      *
774 731
      * @return string|void
775 732
      */
776
-    public function getPublicKey()
777
-    {
733
+    public function getPublicKey() {
778 734
         $key = $this->getPublicKeyPath();
779 735
 
780 736
         if (file_exists($key)) {
@@ -787,8 +743,7 @@  discard block
 block discarded – undo
787 743
      *
788 744
      * @return string|null
789 745
      */
790
-    public function getPublicKeyPath()
791
-    {
746
+    public function getPublicKeyPath() {
792 747
         if ($privateKey = $this->getPrivateKeyPath()) {
793 748
             return $privateKey . '.pub';
794 749
         }
@@ -800,8 +755,7 @@  discard block
 block discarded – undo
800 755
      *
801 756
      * @return string|null
802 757
      */
803
-    public function getPrivateKeyPath()
804
-    {
758
+    public function getPrivateKeyPath() {
805 759
         $keyDir = $this->getKeyDir();
806 760
         if (!empty($keyDir)) {
807 761
             $filter = FileNameFilter::create();
@@ -816,8 +770,7 @@  discard block
 block discarded – undo
816 770
      *
817 771
      * @return string|null
818 772
      */
819
-    public function getKeyDir()
820
-    {
773
+    public function getKeyDir() {
821 774
         $keyDir = $this->DNData()->getKeyDir();
822 775
         if (!$keyDir) {
823 776
             return null;
@@ -835,8 +788,7 @@  discard block
 block discarded – undo
835 788
      * @param FieldList $fields
836 789
      * @param GridField $environments
837 790
      */
838
-    protected function setEnvironmentFields(&$fields, $environments)
839
-    {
791
+    protected function setEnvironmentFields(&$fields, $environments) {
840 792
         if (!$environments) {
841 793
             return;
842 794
         }
@@ -860,8 +812,7 @@  discard block
 block discarded – undo
860 812
      *
861 813
      * @return void|string
862 814
      */
863
-    public function getRepositoryURL()
864
-    {
815
+    public function getRepositoryURL() {
865 816
         $showUrl = Config::inst()->get($this->class, 'show_repository_url');
866 817
         if ($showUrl) {
867 818
             return $this->CVSPath;
@@ -911,8 +862,7 @@  discard block
 block discarded – undo
911 862
      *
912 863
      * @return ArrayData
913 864
      */
914
-    public function getRepositoryInterface()
915
-    {
865
+    public function getRepositoryInterface() {
916 866
         $interfaces = $this->config()->repository_interfaces;
917 867
 
918 868
         /* Look for each whitelisted hostname */
@@ -955,8 +905,7 @@  discard block
 block discarded – undo
955 905
     /**
956 906
      * @return string
957 907
      */
958
-    protected function getProjectFolderPath()
959
-    {
908
+    protected function getProjectFolderPath() {
960 909
         return sprintf('%s/%s', $this->DNData()->getEnvironmentDir(), $this->Name);
961 910
     }
962 911
 
@@ -966,8 +915,7 @@  discard block
 block discarded – undo
966 915
      * @param string $code
967 916
      * @return SS_List
968 917
      */
969
-    public function whoIsAllowed($code)
970
-    {
918
+    public function whoIsAllowed($code) {
971 919
         return $this->whoIsAllowedAny(array($code));
972 920
     }
973 921
 
@@ -978,8 +926,7 @@  discard block
 block discarded – undo
978 926
      * @param array|string $codes
979 927
      * @return SS_List
980 928
      */
981
-    public function whoIsAllowedAny($codes)
982
-    {
929
+    public function whoIsAllowedAny($codes) {
983 930
         if (!is_array($codes)) {
984 931
             $codes = array($codes);
985 932
         }
@@ -1007,8 +954,7 @@  discard block
 block discarded – undo
1007 954
      *
1008 955
      * @return bool
1009 956
      */
1010
-    public function allowed($code, $member = null)
1011
-    {
957
+    public function allowed($code, $member = null) {
1012 958
         return $this->allowedAny(array($code), $member);
1013 959
     }
1014 960
 
@@ -1020,8 +966,7 @@  discard block
 block discarded – undo
1020 966
      *
1021 967
      * @return bool
1022 968
      */
1023
-    public function groupAllowed($permissionCode, Group $group)
1024
-    {
969
+    public function groupAllowed($permissionCode, Group $group) {
1025 970
         $viewers = $this->Viewers();
1026 971
         if (!$viewers->find('ID', $group->ID)) {
1027 972
             return false;
@@ -1041,8 +986,7 @@  discard block
 block discarded – undo
1041 986
      *
1042 987
      * @return bool
1043 988
      */
1044
-    public function allowedAny($codes, $member = null)
1045
-    {
989
+    public function allowedAny($codes, $member = null) {
1046 990
         if (!$member) {
1047 991
             $member = Member::currentUser();
1048 992
         }
@@ -1060,8 +1004,7 @@  discard block
 block discarded – undo
1060 1004
      *
1061 1005
      * @return bool
1062 1006
      */
1063
-    public function isProjectReady()
1064
-    {
1007
+    public function isProjectReady() {
1065 1008
         if ($this->getRunningInitialEnvironmentCreations()->count() > 0) {
1066 1009
             // We're still creating the initial environments for this project so we're
1067 1010
             // not quite done
@@ -1090,8 +1033,7 @@  discard block
 block discarded – undo
1090 1033
      *
1091 1034
      * @return SS_List
1092 1035
      */
1093
-    public function getRunningEnvironmentCreations()
1094
-    {
1036
+    public function getRunningEnvironmentCreations() {
1095 1037
         return $this->CreateEnvironments()
1096 1038
             ->filter('Status', ['Queued', 'Started']);
1097 1039
     }
@@ -1101,8 +1043,7 @@  discard block
 block discarded – undo
1101 1043
      *
1102 1044
      * @return DataList
1103 1045
      */
1104
-    public function getInitialEnvironmentCreations()
1105
-    {
1046
+    public function getInitialEnvironmentCreations() {
1106 1047
         return $this->CreateEnvironments()->filter('IsInitialEnvironment', true);
1107 1048
     }
1108 1049
 
@@ -1111,8 +1052,7 @@  discard block
 block discarded – undo
1111 1052
      *
1112 1053
      * @return DataList
1113 1054
      */
1114
-    public function getRunningInitialEnvironmentCreations()
1115
-    {
1055
+    public function getRunningInitialEnvironmentCreations() {
1116 1056
         return $this->getInitialEnvironmentCreations()
1117 1057
             ->filter('Status', ['Queued', 'Started']);
1118 1058
     }
@@ -1122,8 +1062,7 @@  discard block
 block discarded – undo
1122 1062
      *
1123 1063
      * @return DataList
1124 1064
      */
1125
-    public function getCompleteInitialEnvironmentCreations()
1126
-    {
1065
+    public function getCompleteInitialEnvironmentCreations() {
1127 1066
         return $this->getInitialEnvironmentCreations()
1128 1067
             ->exclude('Status', ['Queued', 'Started']);
1129 1068
     }
@@ -1131,8 +1070,7 @@  discard block
 block discarded – undo
1131 1070
     /**
1132 1071
      * @return ValidationResult
1133 1072
      */
1134
-    protected function validate()
1135
-    {
1073
+    protected function validate() {
1136 1074
         $validation = parent::validate();
1137 1075
         if ($validation->valid()) {
1138 1076
             if (empty($this->Name)) {
@@ -1164,8 +1102,7 @@  discard block
 block discarded – undo
1164 1102
      *
1165 1103
      * @return bool
1166 1104
      */
1167
-    public function canCreate($member = null)
1168
-    {
1105
+    public function canCreate($member = null) {
1169 1106
         if (!$member) {
1170 1107
             $member = Member::currentUser();
1171 1108
         }
Please login to merge, or discard this patch.
code/model/DNQueuedCommits.php 2 patches
Indentation   +6 added lines, -6 removed lines patch added patch discarded remove patch
@@ -9,11 +9,11 @@
 block discarded – undo
9 9
 class DNQueuedCommits extends DNFilteredCommits
10 10
 {
11 11
 
12
-    private $description = 'Commits that are currently queued';
12
+	private $description = 'Commits that are currently queued';
13 13
 
14
-    public function __construct()
15
-    {
16
-        parent::__construct();
17
-        $this->setFilter('Queued');
18
-    }
14
+	public function __construct()
15
+	{
16
+		parent::__construct();
17
+		$this->setFilter('Queued');
18
+	}
19 19
 }
Please login to merge, or discard this patch.
Braces   +2 added lines, -4 removed lines patch added patch discarded remove patch
@@ -6,13 +6,11 @@
 block discarded – undo
6 6
  *  Class to represent queued commits
7 7
  *
8 8
  */
9
-class DNQueuedCommits extends DNFilteredCommits
10
-{
9
+class DNQueuedCommits extends DNFilteredCommits {
11 10
 
12 11
     private $description = 'Commits that are currently queued';
13 12
 
14
-    public function __construct()
15
-    {
13
+    public function __construct() {
16 14
         parent::__construct();
17 15
         $this->setFilter('Queued');
18 16
     }
Please login to merge, or discard this patch.
code/model/DNReference.php 2 patches
Indentation   +25 added lines, -25 removed lines patch added patch discarded remove patch
@@ -3,34 +3,34 @@
 block discarded – undo
3 3
 class DNReference extends ViewableData
4 4
 {
5 5
 
6
-    /**
7
-     * @var Gitonomy\Git\Reference
8
-     */
9
-    protected $reference;
6
+	/**
7
+	 * @var Gitonomy\Git\Reference
8
+	 */
9
+	protected $reference;
10 10
 
11
-    private static $casting = array(
12
-        'Name' => 'Text',
13
-        'FullName' => 'Text',
14
-        'Filename' => 'Text'
15
-    );
11
+	private static $casting = array(
12
+		'Name' => 'Text',
13
+		'FullName' => 'Text',
14
+		'Filename' => 'Text'
15
+	);
16 16
 
17
-    public function __construct(Gitonomy\Git\Reference $reference)
18
-    {
19
-        $this->reference = $reference;
20
-    }
17
+	public function __construct(Gitonomy\Git\Reference $reference)
18
+	{
19
+		$this->reference = $reference;
20
+	}
21 21
 
22
-    public function Name()
23
-    {
24
-        return $this->reference->getName();
25
-    }
22
+	public function Name()
23
+	{
24
+		return $this->reference->getName();
25
+	}
26 26
 
27
-    public function FullName()
28
-    {
29
-        return $this->reference->getCommitHash();
30
-    }
27
+	public function FullName()
28
+	{
29
+		return $this->reference->getCommitHash();
30
+	}
31 31
 
32
-    public function Filename()
33
-    {
34
-        return $this->reference->getFullname();
35
-    }
32
+	public function Filename()
33
+	{
34
+		return $this->reference->getFullname();
35
+	}
36 36
 }
Please login to merge, or discard this patch.
Braces   +5 added lines, -10 removed lines patch added patch discarded remove patch
@@ -1,7 +1,6 @@  discard block
 block discarded – undo
1 1
 <?php
2 2
 
3
-class DNReference extends ViewableData
4
-{
3
+class DNReference extends ViewableData {
5 4
 
6 5
     /**
7 6
      * @var Gitonomy\Git\Reference
@@ -14,23 +13,19 @@  discard block
 block discarded – undo
14 13
         'Filename' => 'Text'
15 14
     );
16 15
 
17
-    public function __construct(Gitonomy\Git\Reference $reference)
18
-    {
16
+    public function __construct(Gitonomy\Git\Reference $reference) {
19 17
         $this->reference = $reference;
20 18
     }
21 19
 
22
-    public function Name()
23
-    {
20
+    public function Name() {
24 21
         return $this->reference->getName();
25 22
     }
26 23
 
27
-    public function FullName()
28
-    {
24
+    public function FullName() {
29 25
         return $this->reference->getCommitHash();
30 26
     }
31 27
 
32
-    public function Filename()
33
-    {
28
+    public function Filename() {
34 29
         return $this->reference->getFullname();
35 30
     }
36 31
 }
Please login to merge, or discard this patch.
code/model/DNReferenceList.php 3 patches
Indentation   +206 added lines, -206 removed lines patch added patch discarded remove patch
@@ -5,210 +5,210 @@
 block discarded – undo
5 5
 class DNReferenceList extends ArrayList
6 6
 {
7 7
 
8
-    /**
9
-     * @var string
10
-     */
11
-    protected static $refs_dir = '';
12
-
13
-    /**
14
-     * @var bool
15
-     */
16
-    protected $loaded = false;
17
-
18
-    /**
19
-     * @var Reference|null
20
-     */
21
-    protected $reference = null;
22
-
23
-    /**
24
-     * @var null|string
25
-     */
26
-    protected $blockBranch;
27
-
28
-    /**
29
-     * @var array
30
-     */
31
-    protected $builds = array();
32
-
33
-    /**
34
-     * @var int
35
-     */
36
-    protected $limit = 10;
37
-
38
-    /**
39
-     * @var bool
40
-     */
41
-    protected $getTags = false;
42
-
43
-    /**
44
-     * @var DNProject
45
-     */
46
-    protected $project;
47
-
48
-    /**
49
-     * @var DNData
50
-     */
51
-    protected $data;
52
-
53
-    /**
54
-     * @param $refsDir
55
-     */
56
-    public static function set_refs_dir($refsDir)
57
-    {
58
-        self::$refs_dir = $refsDir;
59
-    }
60
-
61
-    /**
62
-     * @return string
63
-     */
64
-    public static function get_refs_dir()
65
-    {
66
-        return self::$refs_dir;
67
-    }
68
-
69
-    /**
70
-     * @param DNProject $project
71
-     * @param DNData $data
72
-     * @param Reference|null $reference
73
-     * @param string|null $blockBranch
74
-     * @param bool $getTags
75
-     */
76
-    public function __construct(
77
-        DNProject $project,
78
-        DNData $data,
79
-        Reference $reference = null,
80
-        $blockBranch = null,
81
-        $getTags = false
82
-    ) {
83
-        $this->project = $project;
84
-        $this->data = $data;
85
-        $this->reference = $reference;
86
-        $this->blockBranch = $blockBranch;
87
-        $this->getTags = $getTags;
88
-        parent::__construct(array());
89
-    }
90
-
91
-    /**
92
-     * @param int $limit
93
-     * @return DNReferenceList
94
-     */
95
-    public function setLimit($limit)
96
-    {
97
-        $this->limit = $limit;
98
-        return $this;
99
-    }
100
-
101
-    /**
102
-     * @return array
103
-     */
104
-    protected function getReferences()
105
-    {
106
-        try {
107
-            $repository = new Gitonomy\Git\Repository($this->project->getLocalCVSPath());
108
-        } catch (Exception $e) {
109
-            return array();
110
-        }
111
-
112
-        if ($this->getTags) {
113
-            if ($this->reference) {
114
-                throw new LogicException("Can't have \$reference and \$getTags both set");
115
-            }
116
-            $log = $repository->getReferences()->getTags();
117
-        } elseif ($this->reference) {
118
-            $log = $this->reference->getLog();
119
-        } else {
120
-            $log = $repository->getLog();
121
-        }
122
-
123
-        if ($this->limit) {
124
-            if (is_array($log)) {
125
-                $limitedLog = array_slice($log, 0, $this->limit);
126
-            } else {
127
-                $limitedLog = $log->setLimit($this->limit);
128
-            }
129
-        } else {
130
-            $limitedLog = $log;
131
-        }
132
-
133
-        // cache them for look up in byName
134
-        $builds = array();
135
-        foreach ($limitedLog as $reference) {
136
-            if (!empty($this->blockBranch)) {
137
-                $branchesIncluding = GitonomyCache::getIncludingBranches($reference);
138
-                foreach ($branchesIncluding as $candidate) {
139
-                    if ($candidate->getName() == $this->blockBranch) {
140
-                        // Break out of the function
141
-                        return $builds;
142
-                    }
143
-                }
144
-            }
145
-
146
-            if ($this->getTags) {
147
-                $builds[] = DNTag::create($reference, $this->project, $this->data);
148
-            } else {
149
-                $name = $this->reference ? $this->reference->getName() : '';
150
-                $builds[] = DNCommit::create($reference, $this->project, $this->data, $name);
151
-            }
152
-        }
153
-
154
-        return $builds;
155
-    }
156
-
157
-    /**
158
-     * Find a build in this set by hash.
159
-     *
160
-     * @param string $hash
161
-     * @return DNCommit
162
-     */
163
-    public function byName($hash)
164
-    {
165
-        if ($this->loaded === false) {
166
-            $this->items = $this->getReferences();
167
-            $this->loaded = true;
168
-        }
169
-
170
-        // The item might not be in the list because of the limit, try to find
171
-        // in an older version and add it to the list.
172
-        $found = null;
173
-        foreach ($this->items as $item) {
174
-            if ($item->SHA() == $hash) {
175
-                $found = $item;
176
-                break;
177
-            }
178
-        }
179
-
180
-        if ($found === null) {
181
-            $repository = new Gitonomy\Git\Repository($this->project->getLocalCVSPath());
182
-            $commit = new Gitonomy\Git\Commit($repository, $hash);
183
-            $found = DNCommit::create($commit, $this->project, $this->data);
184
-        }
185
-
186
-        return $found;
187
-    }
188
-
189
-    public function Count()
190
-    {
191
-        $this->getIterator();
192
-        return parent::Count();
193
-    }
194
-
195
-    /**
196
-     * Returns an Iterator for this ArrayList.
197
-     * This function allows you to use ArrayList in foreach loops
198
-     *
199
-     * @return ArrayIterator
200
-     */
201
-    public function getIterator()
202
-    {
203
-        if ($this->loaded === false) {
204
-            $this->items = $this->getReferences();
205
-            $this->loaded = true;
206
-        }
207
-        foreach ($this->items as $item) {
208
-            if (is_array($item)) {
209
-                $this->items[] = new ArrayData($item);
210
-            }
211
-        }
212
-        return new ArrayIterator($this->items);
213
-    }
8
+	/**
9
+	 * @var string
10
+	 */
11
+	protected static $refs_dir = '';
12
+
13
+	/**
14
+	 * @var bool
15
+	 */
16
+	protected $loaded = false;
17
+
18
+	/**
19
+	 * @var Reference|null
20
+	 */
21
+	protected $reference = null;
22
+
23
+	/**
24
+	 * @var null|string
25
+	 */
26
+	protected $blockBranch;
27
+
28
+	/**
29
+	 * @var array
30
+	 */
31
+	protected $builds = array();
32
+
33
+	/**
34
+	 * @var int
35
+	 */
36
+	protected $limit = 10;
37
+
38
+	/**
39
+	 * @var bool
40
+	 */
41
+	protected $getTags = false;
42
+
43
+	/**
44
+	 * @var DNProject
45
+	 */
46
+	protected $project;
47
+
48
+	/**
49
+	 * @var DNData
50
+	 */
51
+	protected $data;
52
+
53
+	/**
54
+	 * @param $refsDir
55
+	 */
56
+	public static function set_refs_dir($refsDir)
57
+	{
58
+		self::$refs_dir = $refsDir;
59
+	}
60
+
61
+	/**
62
+	 * @return string
63
+	 */
64
+	public static function get_refs_dir()
65
+	{
66
+		return self::$refs_dir;
67
+	}
68
+
69
+	/**
70
+	 * @param DNProject $project
71
+	 * @param DNData $data
72
+	 * @param Reference|null $reference
73
+	 * @param string|null $blockBranch
74
+	 * @param bool $getTags
75
+	 */
76
+	public function __construct(
77
+		DNProject $project,
78
+		DNData $data,
79
+		Reference $reference = null,
80
+		$blockBranch = null,
81
+		$getTags = false
82
+	) {
83
+		$this->project = $project;
84
+		$this->data = $data;
85
+		$this->reference = $reference;
86
+		$this->blockBranch = $blockBranch;
87
+		$this->getTags = $getTags;
88
+		parent::__construct(array());
89
+	}
90
+
91
+	/**
92
+	 * @param int $limit
93
+	 * @return DNReferenceList
94
+	 */
95
+	public function setLimit($limit)
96
+	{
97
+		$this->limit = $limit;
98
+		return $this;
99
+	}
100
+
101
+	/**
102
+	 * @return array
103
+	 */
104
+	protected function getReferences()
105
+	{
106
+		try {
107
+			$repository = new Gitonomy\Git\Repository($this->project->getLocalCVSPath());
108
+		} catch (Exception $e) {
109
+			return array();
110
+		}
111
+
112
+		if ($this->getTags) {
113
+			if ($this->reference) {
114
+				throw new LogicException("Can't have \$reference and \$getTags both set");
115
+			}
116
+			$log = $repository->getReferences()->getTags();
117
+		} elseif ($this->reference) {
118
+			$log = $this->reference->getLog();
119
+		} else {
120
+			$log = $repository->getLog();
121
+		}
122
+
123
+		if ($this->limit) {
124
+			if (is_array($log)) {
125
+				$limitedLog = array_slice($log, 0, $this->limit);
126
+			} else {
127
+				$limitedLog = $log->setLimit($this->limit);
128
+			}
129
+		} else {
130
+			$limitedLog = $log;
131
+		}
132
+
133
+		// cache them for look up in byName
134
+		$builds = array();
135
+		foreach ($limitedLog as $reference) {
136
+			if (!empty($this->blockBranch)) {
137
+				$branchesIncluding = GitonomyCache::getIncludingBranches($reference);
138
+				foreach ($branchesIncluding as $candidate) {
139
+					if ($candidate->getName() == $this->blockBranch) {
140
+						// Break out of the function
141
+						return $builds;
142
+					}
143
+				}
144
+			}
145
+
146
+			if ($this->getTags) {
147
+				$builds[] = DNTag::create($reference, $this->project, $this->data);
148
+			} else {
149
+				$name = $this->reference ? $this->reference->getName() : '';
150
+				$builds[] = DNCommit::create($reference, $this->project, $this->data, $name);
151
+			}
152
+		}
153
+
154
+		return $builds;
155
+	}
156
+
157
+	/**
158
+	 * Find a build in this set by hash.
159
+	 *
160
+	 * @param string $hash
161
+	 * @return DNCommit
162
+	 */
163
+	public function byName($hash)
164
+	{
165
+		if ($this->loaded === false) {
166
+			$this->items = $this->getReferences();
167
+			$this->loaded = true;
168
+		}
169
+
170
+		// The item might not be in the list because of the limit, try to find
171
+		// in an older version and add it to the list.
172
+		$found = null;
173
+		foreach ($this->items as $item) {
174
+			if ($item->SHA() == $hash) {
175
+				$found = $item;
176
+				break;
177
+			}
178
+		}
179
+
180
+		if ($found === null) {
181
+			$repository = new Gitonomy\Git\Repository($this->project->getLocalCVSPath());
182
+			$commit = new Gitonomy\Git\Commit($repository, $hash);
183
+			$found = DNCommit::create($commit, $this->project, $this->data);
184
+		}
185
+
186
+		return $found;
187
+	}
188
+
189
+	public function Count()
190
+	{
191
+		$this->getIterator();
192
+		return parent::Count();
193
+	}
194
+
195
+	/**
196
+	 * Returns an Iterator for this ArrayList.
197
+	 * This function allows you to use ArrayList in foreach loops
198
+	 *
199
+	 * @return ArrayIterator
200
+	 */
201
+	public function getIterator()
202
+	{
203
+		if ($this->loaded === false) {
204
+			$this->items = $this->getReferences();
205
+			$this->loaded = true;
206
+		}
207
+		foreach ($this->items as $item) {
208
+			if (is_array($item)) {
209
+				$this->items[] = new ArrayData($item);
210
+			}
211
+		}
212
+		return new ArrayIterator($this->items);
213
+	}
214 214
 }
Please login to merge, or discard this patch.
Spacing   +18 added lines, -18 removed lines patch added patch discarded remove patch
@@ -105,23 +105,23 @@  discard block
 block discarded – undo
105 105
     {
106 106
         try {
107 107
             $repository = new Gitonomy\Git\Repository($this->project->getLocalCVSPath());
108
-        } catch (Exception $e) {
108
+        } catch(Exception $e) {
109 109
             return array();
110 110
         }
111 111
 
112
-        if ($this->getTags) {
113
-            if ($this->reference) {
112
+        if($this->getTags) {
113
+            if($this->reference) {
114 114
                 throw new LogicException("Can't have \$reference and \$getTags both set");
115 115
             }
116 116
             $log = $repository->getReferences()->getTags();
117
-        } elseif ($this->reference) {
117
+        } elseif($this->reference) {
118 118
             $log = $this->reference->getLog();
119 119
         } else {
120 120
             $log = $repository->getLog();
121 121
         }
122 122
 
123
-        if ($this->limit) {
124
-            if (is_array($log)) {
123
+        if($this->limit) {
124
+            if(is_array($log)) {
125 125
                 $limitedLog = array_slice($log, 0, $this->limit);
126 126
             } else {
127 127
                 $limitedLog = $log->setLimit($this->limit);
@@ -132,18 +132,18 @@  discard block
 block discarded – undo
132 132
 
133 133
         // cache them for look up in byName
134 134
         $builds = array();
135
-        foreach ($limitedLog as $reference) {
136
-            if (!empty($this->blockBranch)) {
135
+        foreach($limitedLog as $reference) {
136
+            if(!empty($this->blockBranch)) {
137 137
                 $branchesIncluding = GitonomyCache::getIncludingBranches($reference);
138
-                foreach ($branchesIncluding as $candidate) {
139
-                    if ($candidate->getName() == $this->blockBranch) {
138
+                foreach($branchesIncluding as $candidate) {
139
+                    if($candidate->getName() == $this->blockBranch) {
140 140
                         // Break out of the function
141 141
                         return $builds;
142 142
                     }
143 143
                 }
144 144
             }
145 145
 
146
-            if ($this->getTags) {
146
+            if($this->getTags) {
147 147
                 $builds[] = DNTag::create($reference, $this->project, $this->data);
148 148
             } else {
149 149
                 $name = $this->reference ? $this->reference->getName() : '';
@@ -162,7 +162,7 @@  discard block
 block discarded – undo
162 162
      */
163 163
     public function byName($hash)
164 164
     {
165
-        if ($this->loaded === false) {
165
+        if($this->loaded === false) {
166 166
             $this->items = $this->getReferences();
167 167
             $this->loaded = true;
168 168
         }
@@ -170,14 +170,14 @@  discard block
 block discarded – undo
170 170
         // The item might not be in the list because of the limit, try to find
171 171
         // in an older version and add it to the list.
172 172
         $found = null;
173
-        foreach ($this->items as $item) {
174
-            if ($item->SHA() == $hash) {
173
+        foreach($this->items as $item) {
174
+            if($item->SHA() == $hash) {
175 175
                 $found = $item;
176 176
                 break;
177 177
             }
178 178
         }
179 179
 
180
-        if ($found === null) {
180
+        if($found === null) {
181 181
             $repository = new Gitonomy\Git\Repository($this->project->getLocalCVSPath());
182 182
             $commit = new Gitonomy\Git\Commit($repository, $hash);
183 183
             $found = DNCommit::create($commit, $this->project, $this->data);
@@ -200,12 +200,12 @@  discard block
 block discarded – undo
200 200
      */
201 201
     public function getIterator()
202 202
     {
203
-        if ($this->loaded === false) {
203
+        if($this->loaded === false) {
204 204
             $this->items = $this->getReferences();
205 205
             $this->loaded = true;
206 206
         }
207
-        foreach ($this->items as $item) {
208
-            if (is_array($item)) {
207
+        foreach($this->items as $item) {
208
+            if(is_array($item)) {
209 209
                 $this->items[] = new ArrayData($item);
210 210
             }
211 211
         }
Please login to merge, or discard this patch.
Braces   +8 added lines, -16 removed lines patch added patch discarded remove patch
@@ -2,8 +2,7 @@  discard block
 block discarded – undo
2 2
 
3 3
 use Gitonomy\Git\Reference;
4 4
 
5
-class DNReferenceList extends ArrayList
6
-{
5
+class DNReferenceList extends ArrayList {
7 6
 
8 7
     /**
9 8
      * @var string
@@ -53,16 +52,14 @@  discard block
 block discarded – undo
53 52
     /**
54 53
      * @param $refsDir
55 54
      */
56
-    public static function set_refs_dir($refsDir)
57
-    {
55
+    public static function set_refs_dir($refsDir) {
58 56
         self::$refs_dir = $refsDir;
59 57
     }
60 58
 
61 59
     /**
62 60
      * @return string
63 61
      */
64
-    public static function get_refs_dir()
65
-    {
62
+    public static function get_refs_dir() {
66 63
         return self::$refs_dir;
67 64
     }
68 65
 
@@ -92,8 +89,7 @@  discard block
 block discarded – undo
92 89
      * @param int $limit
93 90
      * @return DNReferenceList
94 91
      */
95
-    public function setLimit($limit)
96
-    {
92
+    public function setLimit($limit) {
97 93
         $this->limit = $limit;
98 94
         return $this;
99 95
     }
@@ -101,8 +97,7 @@  discard block
 block discarded – undo
101 97
     /**
102 98
      * @return array
103 99
      */
104
-    protected function getReferences()
105
-    {
100
+    protected function getReferences() {
106 101
         try {
107 102
             $repository = new Gitonomy\Git\Repository($this->project->getLocalCVSPath());
108 103
         } catch (Exception $e) {
@@ -160,8 +155,7 @@  discard block
 block discarded – undo
160 155
      * @param string $hash
161 156
      * @return DNCommit
162 157
      */
163
-    public function byName($hash)
164
-    {
158
+    public function byName($hash) {
165 159
         if ($this->loaded === false) {
166 160
             $this->items = $this->getReferences();
167 161
             $this->loaded = true;
@@ -186,8 +180,7 @@  discard block
 block discarded – undo
186 180
         return $found;
187 181
     }
188 182
 
189
-    public function Count()
190
-    {
183
+    public function Count() {
191 184
         $this->getIterator();
192 185
         return parent::Count();
193 186
     }
@@ -198,8 +191,7 @@  discard block
 block discarded – undo
198 191
      *
199 192
      * @return ArrayIterator
200 193
      */
201
-    public function getIterator()
202
-    {
194
+    public function getIterator() {
203 195
         if ($this->loaded === false) {
204 196
             $this->items = $this->getReferences();
205 197
             $this->loaded = true;
Please login to merge, or discard this patch.