InDefero

Sign in or create your account | Project List | Help

InDefero Git Source Tree

Root/src/IDF/Plugin/SyncSvn.php

1<?php
2/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3/*
4# ***** BEGIN LICENSE BLOCK *****
5# This file is part of InDefero, an open source project management application.
6# Copyright (C) 2008 Céondo Ltd and contributors.
7#
8# InDefero is free software; you can redistribute it and/or modify
9# it under the terms of the GNU General Public License as published by
10# the Free Software Foundation; either version 2 of the License, or
11# (at your option) any later version.
12#
13# InDefero is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the GNU General Public License
19# along with this program; if not, write to the Free Software
20# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21#
22# ***** END LICENSE BLOCK ***** */
23
24
25/**
26 * This classes is a plugin which allows to synchronise access rights
27 * between indefero and a DAV powered Subversion repository.
28 */
29class IDF_Plugin_SyncSvn
30{
31    
32    /**
33     * Entry point of the plugin.
34     */
35    static public function entry($signal, &$params)
36    {
37        // First check for the 3 mandatory config variables.
38        if (!Pluf::f('idf_plugin_syncsvn_authz_file', false) or
39            !Pluf::f('idf_plugin_syncsvn_passwd_file', false) or
40            !Pluf::f('idf_plugin_syncsvn_svn_path'. false)) {
41            return;
42        }
43        include_once 'File/Passwd/Authdigest.php'; // $ pear install File_Passwd
44        $plug = new IDF_Plugin_SyncSvn();
45        switch ($signal) {
46        case 'IDF_Project::created':
47            $plug->processSvnCreate($params['project']);
48            break;
49        case 'IDF_Project::membershipsUpdated':
50            $plug->processSyncAuthz($params['project']);
51            break;
52        case 'Pluf_User::passwordUpdated':
53            $plug->processSyncPasswd($params['user']);
54            break;
55        case 'IDF_Project::preDelete':
56            $plug->processSvnDelete($params['project']);
57            break;
58        }
59    }
60
61    /**
62     * Run svnadmin command to create the corresponding Subversion
63     * repository.
64     *
65     * @param IDF_Project
66     * @return bool Success
67     */
68    function processSvnCreate($project)
69    {
70        if ($project->getConf()->getVal('scm') != 'svn') {
71            return false;
72        }
73        $shortname = $project->shortname;
74        if (false===($svn_path=Pluf::f('idf_plugin_syncsvn_svn_path',false))) {
75            throw new Pluf_Exception_SettingError("'idf_plugin_syncsvn_svn_path' must be defined in your configuration file.");
76        }
77        if (file_exists($svn_path.'/'.$shortname)) {
78            throw new Exception(sprintf(__('The repository %s already exists.'),
79                                        $svn_path.'/'.$shortname));
80        }
81        $return = 0;
82        $output = array();
83        $cmd = sprintf(Pluf::f('svnadmin_path', 'svnadmin').' create %s',
84                       escapeshellarg($svn_path.'/'.$shortname));
85        $cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
86        $ll = exec($cmd, $output, $return);
87        return ($return == 0);
88    }
89
90    /**
91     * Remove the project from the drive and update the access rights.
92     *
93     * @param IDF_Project
94     * @return bool Success
95     */
96    function processSvnDelete($project)
97    {
98        if (!Pluf::f('idf_plugin_syncsvn_remove_orphans', false)) {
99            return;
100        }
101        if ($project->getConf()->getVal('scm') != 'svn') {
102            return false;
103        }
104        $this->SyncAccess($project); // exclude $project
105        $shortname = $project->shortname;
106        if (false===($svn_path=Pluf::f('idf_plugin_syncsvn_svn_path',false))) {
107            throw new Pluf_Exception_SettingError("'idf_plugin_syncsvn_svn_path' must be defined in your configuration file.");
108        }
109        if (file_exists($svn_path.'/'.$shortname)) {
110            $cmd = Pluf::f('idf_exec_cmd_prefix', '').'rm -rf '.$svn_path.'/'.$shortname;
111            exec($cmd);
112        }
113    }
114    
115    /**
116     * Synchronise an user's password.
117     *
118     * @param Pluf_User
119     */
120    function processSyncPasswd($user)
121    {
122        $passwd_file = Pluf::f('idf_plugin_syncsvn_passwd_file');
123        if (!file_exists($passwd_file) or !is_writable($passwd_file)) {
124            return false;
125        }
126        $ht = new File_Passwd_Authbasic($passwd_file);
127        $ht->load();
128        $ht->setMode(FILE_PASSWD_SHA);
129        if ($ht->userExists($user->login)) {
130            $ht->changePasswd($user->login, $this->getSvnPass($user));
131        } else {
132            $ht->addUser($user->login, $this->getSvnPass($user));
133        }
134        $ht->save();
135        return true;
136    }
137
138    /**
139     * Synchronize the authz file and the passwd file for the project.
140     *
141     * @param IDF_Project
142     */
143    function processSyncAuthz($project)
144    {
145        $this->SyncAccess();
146        $this->generateProjectPasswd($project);
147    }
148
149    /**
150     * Get the repository password for the user
151     */
152    function getSvnPass($user){
153        return substr(sha1($user->password.Pluf::f('secret_key')), 0, 8);
154    }
155
156    /**
157     * For a particular project: update all passwd information
158     */
159    function generateProjectPasswd($project)
160    {
161        $passwd_file = Pluf::f('idf_plugin_syncsvn_passwd_file');
162        if (!file_exists($passwd_file) or !is_writable($passwd_file)) {
163            return false;
164        }
165        $ht = new File_Passwd_Authbasic($passwd_file);
166        $ht->setMode(FILE_PASSWD_SHA);
167        $ht->load();
168        $mem = $project->getMembershipData();
169        $members = array_merge((array)$mem['members'], (array)$mem['owners'],
170                               (array)$mem['authorized']);
171        foreach($members as $user) {
172            if ($ht->userExists($user->login)) {
173                $ht->changePasswd($user->login, $this->getSvnPass($user));
174            } else {
175                $ht->addUser($user->login, $this->getSvnPass($user));
176            }
177        }
178        $ht->save();
179    }
180
181    /**
182     * Generate the dav_svn.authz file
183     *
184     * We rebuild the complete file each time. This is just to be sure
185     * not to bork the rights when trying to just edit part of the
186     * file.
187     *
188     * @param IDF_Project Possibly exclude a project (null)
189     */
190    function SyncAccess($exclude=null)
191    {
192        $authz_file = Pluf::f('idf_plugin_syncsvn_authz_file');
193        $access_owners = Pluf::f('idf_plugin_syncsvn_access_owners', 'rw');
194        $access_members = Pluf::f('idf_plugin_syncsvn_access_members', 'rw');
195        $access_extra = Pluf::f('idf_plugin_syncsvn_access_extra', 'r');
196        $access_public = Pluf::f('idf_plugin_syncsvn_access_public', 'r');
197        $access_public_priv = Pluf::f('idf_plugin_syncsvn_access_private', '');
198        if (!file_exists($authz_file) or !is_writable($authz_file)) {
199            return false;
200        }
201        $fcontent = '';
202        foreach (Pluf::factory('IDF_Project')->getList() as $project) {
203            if ($exclude and $exclude->id == $project->id) {
204                continue;
205            }
206            $conf = new IDF_Conf();
207            $conf->setProject($project);
208            if ($conf->getVal('scm') != 'svn' or
209                strlen($conf->getVal('svn_remote_url')) > 0) {
210                continue;
211            }
212            $mem = $project->getMembershipData();
213            // [shortname:/]
214            $fcontent .= '['.$project->shortname.':/]'."\n";
215            foreach ($mem['owners'] as $v) {
216                $fcontent .= $v->login.' = '.$access_owners."\n";
217            }
218            foreach ($mem['members'] as $v) {
219                $fcontent .= $v->login.' = '.$access_members."\n";
220            }
221            // access for all users
222            if ($project->private == true) {
223                foreach ($mem['authorized'] as $v) {
224                    $fcontent .= $v->login.' = '.$access_extra."\n";
225                }
226                $fcontent .= '* = '.$access_public_priv."\n";
227            } else {
228                $fcontent .= '* = '.$access_public."\n";
229            }
230            $fcontent .= "\n";
231        }
232        file_put_contents($authz_file, $fcontent, LOCK_EX);
233        return true;
234    }
235}
236

Archive Download this file

Branches:
dev
master
newdiff
svn