Bug #49877 ยป svn-groups.php

Sync script - Steffen Gebert, 2013-07-12 22:51

 
1
#!/usr/bin/php
2
<?php
3
/*
4
 synchronize group membership from forge (redmine) to SVN authz
5
*/
6

    
7
// makes the following roles a project member:
8
$allowedMemberTypes = array(
9
	'Leader',
10
	'Co-Leader',
11
	'Member',
12
	'Active Contributor',
13
);
14

    
15
$token = "c66be699fbf763d050115fb729acdeaa5d122527";
16

    
17
$hostname = "redmine.typo3.vagrant";
18

    
19
$path = "/Users/st/authz";
20

    
21

    
22
/********************************************/
23

    
24

    
25
class GroupSync {
26
	protected $pdo;
27
	protected $requiredRoles = array();
28
	protected $accountIds = array();
29
	protected $usedGerritGroupTypes = array();
30
	protected $targetFile;
31
	protected $ssl = false;
32

    
33
	/** var string the URL without trailing / */
34
	protected $hostname = '';
35

    
36
	protected $apiToken = '';
37

    
38
	public function __construct() {
39
		ini_set('user_agent', 'SVN Group Sync Script');
40
	}
41

    
42
	public function setHostname($hostname) {
43
		$this->hostname = rtrim($hostname, '/');
44
		return $this;
45
	}
46

    
47
	public function setApiToken($token) {
48
		$this->apiToken = $token;
49
		return $this;
50
	}
51

    
52
	public function setRequiredRoles(array $allowedMemberTypes) {
53
		$this->requiredRoles = $allowedMemberTypes;
54
		return $this;
55
	}
56

    
57
	public function writeTo($path) {
58
		$this->targetFile = $path;
59
		return $this;
60
	}
61

    
62
	public function enableSsl() {
63
		$this->ssl = true;
64
	}
65

    
66
	public function sync() {
67
		$projects = $this->getAllProjects();
68

    
69
		echo "Received list of " . count($projects) . " projects\n";
70

    
71
		$projectsAndTheirMembers = array();
72

    
73
		foreach ($projects as $projectIdentifier) {
74
			echo "Processing project: " . $projectIdentifier . "\n";
75

    
76
			$members = $this->getMembersForProject($projectIdentifier);
77
			echo "Members: " . implode(",", $members) . "\n";
78

    
79
			$projectsAndTheirMembers[$projectIdentifier] = $members;
80
		}
81

    
82
		$file = $this->createAuthzFile($projectsAndTheirMembers);
83

    
84
		file_put_contents($this->targetFile, $file);
85

    
86
		return $this;
87
	}
88

    
89
	/**
90
	 * Reads all projects from redmine and returns a list of their identifiers
91
	 *
92
	 * @return array list of project identifiers
93
	 * @throws Exception
94
	 */
95
	protected function getAllProjects() {
96
		$url = "/projects.json?limit=100000";
97
		$projectData = json_decode(@file_get_contents($this->getUrl() . $url));
98
		$projects = array();
99

    
100
		// read the project identifiers
101
		foreach ($projectData->projects as $project) {
102
			$projects[] = $project->identifier;
103
		}
104

    
105
		if ($projectData->total_count != count($projects)) {
106
			throw new Exception("Something is weird, redmine said we have " . $projectData->total_count . " projects, but we got " . count($projects));
107
		}
108

    
109
		// a list of project identifiers
110
		return $projects;
111
	}
112

    
113

    
114
	/**
115
	 * Returns all the members of the project which should have write access
116
	 *
117
	 * @param $identifier string project identifier
118
	 * @return array list of members
119
	 * @throws Exception
120
	 */
121
	protected function getMembersForProject($identifier) {
122
		$url = '/projects/' . $identifier . '/memberships.json';
123

    
124
		$membershipData = json_decode(@file_get_contents($this->getUrl(true) . $url));
125

    
126
		$members = array();
127

    
128
		foreach ($membershipData->memberships as $membership) {
129

    
130
			echo "Processing user '" . $membership->user->name . "'\n";
131

    
132
			// read the role objects
133
			$roles = array();
134
			foreach ($membership->roles as $role) {
135
				$roles[] = $role->name;
136
			}
137

    
138
			if ($this->rolesPermitAccess($roles)) {
139

    
140
				if (!isset($membership->user->login)) {
141
					throw new Exception("The membership.json did not return a 'login' entry for the user " . $membership->user->name . ". Have you installed our typo3_api plugin, which adds this information?");
142
				}
143

    
144
				$members[] = $membership->user->login;
145
			}
146
		}
147

    
148
		return $members;
149
	}
150

    
151
	protected function getUrl($authenticated = false) {
152
		$protocol = $this->ssl ? "https" : "http";
153
		$credentials = $authenticated ? ($this->apiToken . ":passwordDoesNotMatter@") : "";
154

    
155
		return $protocol . "://" . $credentials . $this->hostname;
156
	}
157

    
158
	/**
159
	 * Checks if $rolesOfTheUser include at least one of the $requiredRoles to be listed as a team member
160
	 *
161
	 * @var array $rolesOfTheUser array of roles of a user to check
162
	 * @return bool true $rolesOfTheUser contains at least one of the $required roles
163
	 */
164
	protected function rolesPermitAccess(array $rolesOfTheUser) {
165
		echo "User has roles:" . implode(",", $rolesOfTheUser) ."\n";
166

    
167
		foreach ($this->requiredRoles as $requiredRole) {
168

    
169
			// we search for any of the required roles to be listed as a member
170
			if (in_array($requiredRole, $rolesOfTheUser)) {
171
				echo "User is ALLOWED\n";
172
				return true;
173
			}
174
		}
175

    
176
		echo "Could not find any of " . implode(",", $this->requiredRoles). "\n";
177
		return false;
178
	}
179

    
180
	/**
181
	 * @param $projectsAndMembers array with keys the project identifiers and values an array of login names of members
182
	 * @return string file contens for the authz file, like this:
183
	 * [groups]
184
	 * admins = john, inge, dieter
185
	 * extension-gimmefive-developers = jocrau, ohader
186
	 * extension-contentparser-developers = jocrau
187
	 *
188
	 * [/gimmefive]
189
	 * @extension-gimmefive-developers = rw
190
	 *
191
	 * [/contentparser]
192
	 * @extension-contentparser-developers = rw
193
	 *
194
	 * [/]
195
	 * @admins = rw
196
	 * * = r
197
	 *
198
	 * */
199
	protected function createAuthzFile($projectsAndMembers) {
200

    
201
		$lines = array();
202
		$lines[] = "[groups]";
203
		$lines[] = "admins = mstucki, stephenking, jugglepro, ohader";
204

    
205
		foreach ($projectsAndMembers as $projectIdentifier => $members) {
206
			$lines[] = $projectIdentifier . " = " . implode(", ", $members);
207
		}
208

    
209
		// add some space
210
		$lines[] = "";
211
		$lines[] = "";
212

    
213
		foreach ($projectsAndMembers as $projectIdentifier => $members) {
214
			$extensionKey = str_replace("extension-", "", $projectIdentifier);
215

    
216
			$lines[] = "[/$extensionKey]";
217
			$lines[] = "@$projectIdentifier = rw";
218
			$lines[] = "";
219
		}
220

    
221
		$lines[] = "[/]";
222
		$lines[] = "@admins = rw";
223
		$lines[] = "* = r";
224

    
225
		return implode("\n", $lines);
226
	}
227

    
228
}
229

    
230
$sync = new GroupSync();
231
$sync->setRequiredRoles($allowedMemberTypes)
232
	->setHostname($hostname)
233
	->setApiToken($token)
234
	->enableSsl()
235
	->writeTo($path)
236
	->sync();
237

    
238

    
239

    
240

    
241

    
242

    
243

    
244

    
245

    
246

    
247
?>
    (1-1/1)