/**
  * Adds given address to given mailing list.
  * @param string listname
  * @param string email
  * @return boolean status (true=success, false=failure)
  */
 public static function subscribe($listname, $email)
 {
     $conn = sfDoctrine::Connection();
     try {
         $conn->beginTransaction();
         $sympa = new Sympa();
         $sympa->list_subscriber = $listname;
         $sympa->user_subscriber = $email;
         $sympa->save();
         $conn->commit();
         return true;
     } catch (Exception $e) {
         // Subscription failed! For instance because email address was already registered.
         $conn->rollback();
         c2cTools::log("Failed adding address {$email} to list {$listname}: " . $e->getMessage());
         return false;
     }
 }
 /**
  * Changes the association order for associations of same type (eg summit-summit)
  * It should only be used for ss, pp and tt associations, but there is probably
  * no real problem if other associations are inverted
  */
 public function executeInvertAssociation()
 {
     $user = $this->getUser();
     $user_id = $user->getId();
     $is_moderator = $user->hasCredential('moderator');
     $type = $this->getRequestParameter('type');
     $main_id = $this->getRequestParameter('main_id');
     $linked_id = $this->getRequestParameter('linked_id');
     // check if session timed out
     if (!$user_id) {
         return $this->setErrorAndRedirect('Session is over. Please login again.', $this->getRequest()->getReferer());
     }
     // only moderators can perform such actions
     if (!$is_moderator) {
         return $this->setErrorAndRedirect('You do not have enough credentials to perform this operation', $this->getRequest()->getReferer());
     }
     // we check that the association type really exists and that the two
     // documents are from the same model
     if (substr($type, 0, 1) != substr($type, -1) || !in_array($type, sfConfig::get('app_associations_types'))) {
         return $this->ajax_feedback('Wrong association type');
     }
     // check that association exists in database
     $models = c2cTools::Type2Models($type);
     $model = $models['main'];
     $module = c2cTools::model2module($model);
     $a = Association::find($main_id, $linked_id, $type);
     // strict search
     if (!$a) {
         return $this->setErrorAndRedirect('Operation not allowed', $this->getRequest()->getReferer());
     }
     // invert association
     $conn = sfDoctrine::Connection();
     try {
         $conn->beginTransaction();
         $a->main_id = $linked_id;
         $a->linked_id = $main_id;
         $a->save();
         $al1 = new AssociationLog();
         $al1->main_id = $main_id;
         $al1->linked_id = $linked_id;
         $al1->type = $type;
         $al1->user_id = $user_id;
         $al1->is_creation = 'false';
         $al1->save();
         $al1 = new AssociationLog();
         $al1->main_id = $linked_id;
         $al1->linked_id = $main_id;
         $al1->type = $type;
         $al1->user_id = $user_id;
         $al1->is_creation = 'true';
         $al1->save();
         $conn->commit();
     } catch (exception $e) {
         $conn->rollback();
         c2cTools::log("executeInvertAssociation() : invertion failed ({$main_id}, {$linked_id}, {$type}, {$user_id}) - rollback");
         return $this->ajax_feedback('Association invertion failed');
     }
     // remove cache and force page reload
     $this->clearCache($module, $main_id, false, 'view');
     $this->clearCache($module, $linked_id, false, 'view');
     return $this->setNoticeAndRedirect('Association inverted', $this->getRequest()->getReferer());
 }
 public function doSaveWithValues($main_id, $linked_id, $type, $user_id)
 {
     $conn = sfDoctrine::Connection();
     try {
         $conn->beginTransaction();
         // we create the association:
         $this->main_id = $main_id;
         $this->linked_id = $linked_id;
         $this->type = $type;
         $this->save();
         // and we log this:
         $al = new AssociationLog();
         $al->main_id = $main_id;
         $al->linked_id = $linked_id;
         $al->type = $type;
         $al->user_id = $user_id;
         $al->is_creation = true;
         $al->save();
         $conn->commit();
         // send an email to moderators if a picture is associated to a book
         if ($type == 'bi') {
             try {
                 // retrieve moderators email
                 $moderator_id = sfConfig::get('app_moderator_user_id');
                 // currently send to topo-fr only
                 $conn->beginTransaction();
                 $rows = $conn->standaloneQuery('SELECT email FROM app_users_private_data d WHERE id = ' . $moderator_id)->fetchAll();
                 $conn->commit();
                 $email_recipient = $rows[0]['email'];
                 $mail = new sfMail();
                 $mail->setCharset('utf-8');
                 // definition of the required parameters
                 $mail->setSender(sfConfig::get('app_outgoing_emails_sender'));
                 $mail->setFrom(sfConfig::get('app_outgoing_emails_from'));
                 $mail->addReplyTo(sfConfig::get('app_outgoing_emails_reply_to'));
                 $mail->addAddress($email_recipient);
                 $mail->setSubject('New image associated to book');
                 $mail->setContentType('text/html');
                 $server = $_SERVER['SERVER_NAME'];
                 $body = "<p>A <a href=\"http://{$server}/images/{$linked_id}\">new image</a> has been associated to <a href=\"http://{$server}/books/{$main_id}\">book {$main_id}</a>.</p>" . "<p>The image may require a copyright license. If so, please ensure that:</p>" . "<ul>" . "<li>the owner is correctly acknowledged in the author field;</li>" . "<li>the image is not too big (max 800px width or height).</li>" . "</ul>";
                 $mail->setBody($body);
                 // send the email
                 $mail->send();
             } catch (exception $e) {
                 $conn->rollback();
                 c2cTools::log("Association::doSaveWithValues({$main_id}, {$linked_id}, {$type}, {$user_id}) failed sending email for image associated to book");
             }
         }
         return true;
     } catch (exception $e) {
         $conn->rollback();
         c2cTools::log("Association::doSaveWithValues({$main_id}, {$linked_id}, {$type}, {$user_id}) failed - rollback");
         return false;
     }
 }
 public static function getLinkedFiles($id)
 {
     $filename_rows = sfDoctrine::Connection()->standaloneQuery('SELECT DISTINCT filename FROM app_images_archives WHERE id = ?', array($id))->fetchAll();
     $filenames = array();
     foreach ($filename_rows as $row) {
         $filenames[] = $row['filename'];
     }
     return $filenames;
 }
 public function signIn($login_name, $password, $remember = false, $password_is_hashed = false)
 {
     c2cTools::log('in signin function from myUser class');
     $return = false;
     // we need to retrieve the stored hash for the correspondings user to:
     // - the salt is stored there, needed for verifiying the password
     // - allows us to check whether it is still an old hash, without salt
     $upd = UserPrivateData::retrieveByLoginName($login_name);
     if (!$upd) {
         return false;
     } else {
         $userid = $upd->id;
         $hash_tmp = $upd->password_tmp;
         $hash = $upd->password;
     }
     if ($password_is_hashed) {
         $user = $password === $hash ? sfDoctrine::getTable('User')->find($userid) : false;
     } else {
         $user = self::check_password($password, $hash) ? sfDoctrine::getTable('User')->find($userid) : false;
     }
     // maybe the user requested a new password, check if password_tmp is ok
     if (!$user && !$password_is_hashed) {
         // This block is not used when password is hashed. Indeed password is hashed only
         // when performing an automatic signIn ("remember me").
         // In that case, no temp password is used.
         c2cTools::log('base login failed, start trying with password_temp');
         // user not found, try with tmp password
         $user = self::check_password($password, $hash_tmp) ? sfDoctrine::getTable('User')->find($userid) : false;
         if ($user) {
             c2cTools::log('user found, make temp password the new password');
             // user used his tmp password
             $user_private_data = $user->get('private_data');
             // set password to tmp password
             $user_private_data->set('password', $password);
             // delete tmp password
             $user_private_data->set('password_tmp', null);
             $user->save();
         }
     }
     if ($user) {
         c2cTools::log('user found, continue to test if active');
         if ($user->isActive()) {
             c2cTools::log('user is active');
             $user_id = $user->get('id');
             // if we went there with the old hash algorithm (simple hash, no salt),
             // then update the db with so that we use the new algorithm next time
             if (!$password_is_hashed && password_needs_rehash($hash, PASSWORD_DEFAULT)) {
                 c2cTools::log('upgrading user to new hash algorithm');
                 $conn = sfDoctrine::Connection();
                 try {
                     $user_private_data = UserPrivateData::find($user_id);
                     $user_private_data->setPassword($password);
                     $user_private_data->save();
                     $conn->commit();
                 } catch (Exception $e) {
                     $conn->rollback();
                     c2cTools::log('could not upgrade user to new hash algorithm');
                 }
                 $hash = $user_private_data->getPassword();
             }
             $user_culture = $user->get('private_data')->getPreferedCulture();
             // when user signs-in it confirms his signup
             if ($user->isConfirmationPending()) {
                 c2cTools::log('remove user from pending group');
                 $user->removeFromGroup('pending');
             }
             // login punbb
             if ($password_is_hashed) {
                 Punbb::signIn($user_id, $password);
             } else {
                 Punbb::signIn($user_id, $hash);
             }
             c2cTools::log('logged in punbb');
             // remember?
             if ($remember) {
                 c2cTools::log('remember me requested / or renew');
                 $context = sfContext::getInstance();
                 $remember_cookie = sfConfig::get('app_remember_key_cookie_name', 'c2corg_remember');
                 $key = RememberKey::generateRandomKey();
                 // if remember_cookie was set in the request, it means that we are renewing it
                 $remember_key = $context->getRequest()->getCookie($remember_cookie);
                 if ($remember_key) {
                     RememberKey::renewKey($remember_key, $key);
                 } else {
                     $rk = new RememberKey();
                     $rk->set('remember_key', $key);
                     $rk->set('user', $user);
                     $rk->set('ip_address', isset($_SERVER['HTTP_X_ORIGIN_IP']) ? $_SERVER['HTTP_X_ORIGIN_IP'] : $_SERVER['REMOTE_ADDR']);
                     // TODO remove obsolete field
                     $rk->save();
                 }
                 // TODO : move remove old keys in a batch
                 // remove old keys
                 RememberKey::deleteOldKeys();
                 // make key as a cookie
                 $expiration_age = sfConfig::get('app_remember_key_expiration_age', 30 * 24 * 3600);
                 $context->getResponse()->setCookie($remember_cookie, $key, time() + $expiration_age, '/', '', false, true);
             } else {
                 // user is authenticated but has not checked "remember me" option
                 // let's add a cookie to indicate his/her session should not be reset while his/her browser is open
                 sfContext::getInstance()->getResponse()->setCookie('temp_remember', 1);
             }
             c2cTools::log('add some information in user session');
             // give credentials
             $this->addCredentials($user->getAllPermissionNames());
             // login session symfony
             $this->setAttribute('username', $user->get('private_data')->get('topo_name'));
             $this->setAttribute('id', $user_id);
             // set the prefered language for user session
             // and the list of languages ordered by preference
             $this->saveLanguageListInSession($user->get('private_data')->getDocumentCulture());
             // set logged
             $this->setAuthenticated(true);
             $return = true;
             // change language session if needed
             if ($this->getCulture() != $user_culture) {
                 $this->setCulture($user_culture);
             }
             // be sure to update punbb language cookie
             Punbb::setLanguage($user_culture);
             // Restore pref cookies
             c2cPersonalization::restorePrefCookies($user_id);
         }
     }
     return $return;
 }
                 echo '  Create association with image ' . $image_data['id'] . "\n";
             }
             if (!$DRY_RUN) {
                 $asso = new Association();
                 $asso->doSaveWithValues($doc['id'], $image_data['id'], $association_type, $TOPO_MODERATOR_USER_ID);
             }
             $stat_associations_required++;
         }
         $image_ids[$tag[1]] = $image_data['id'];
     } else {
         // no corresponding id, the tag is incorrect and must not be modified. but a warning should be notified
         $stat_docs_with_invalid_references[] = $doc['id'] . ' (' . $doc['culture'] . ' - ' . $doc['name'] . ') http://' . $SERVER_NAME . '/' . strtolower($table) . 's' . '/' . $doc['id'] . '/' . $doc['culture'] . "\n";
     }
 }
 // replace image tags
 $conn = sfDoctrine::Connection();
 $db_doc = Document::find($table, $doc['id']);
 if (!$DRY_RUN) {
     $conn->beginTransaction();
     $history_metadata = new HistoryMetadata();
     $history_metadata->setComment('Updated image tags');
     $history_metadata->set('is_minor', true);
     $history_metadata->set('user_id', $TOPO_MODERATOR_USER_ID);
     $history_metadata->save();
     $db_doc->setCulture($doc['culture']);
 }
 foreach ($fields as $field) {
     $tag_data = $tags_for_field[$field];
     $text = $doc[$field];
     foreach ($tag_data as $tag_idx) {
         $references_to_modify++;
 public function executeAddroute()
 {
     $id = $this->getRequestParameter('document_id');
     // check if a summit is already associated to hut. if not, create it
     $create_summit = Association::countMains($id, 'sh') == 0;
     if ($create_summit) {
         $document = Document::find('Hut', $id, array('elevation', 'geom_wkt'));
         $conn = sfDoctrine::Connection();
         try {
             $conn->beginTransaction();
             // create first version of document, with culture and geometry of hut document
             $hut_elevation = $document['elevation'];
             $hut_lat = $document['lat'];
             $hut_lon = $document['lon'];
             $hut_culture = $document->getCulture();
             $hut_name = $document['name'];
             $history_metadata = new HistoryMetadata();
             $history_metadata->setComment($this->__('Created summit synchronized with hut for access'));
             $history_metadata->set('is_minor', false);
             $history_metadata->set('user_id', 2);
             // C2C user
             $history_metadata->save();
             $summit = new Summit();
             $summit->setCulture($hut_culture);
             $summit->set('name', $hut_name);
             $summit->set('elevation', $hut_elevation);
             $summit->set('summit_type', 100);
             // set summit type to ' hut'
             $summit->set('lat', $hut_lat);
             $summit->set('lon', $hut_lon);
             $summit->save();
             $conn->commit();
             // add others culture versions
             foreach ($document->get('HutI18n') as $i18n) {
                 $culture = $i18n->getCulture();
                 if ($culture != $hut_culture) {
                     $conn->beginTransaction();
                     $hut_name = $i18n->getName();
                     $history_metadata = new HistoryMetadata();
                     $history_metadata->setComment($this->__('Created summit synchronized with hut for access'));
                     $history_metadata->set('is_minor', false);
                     $history_metadata->set('user_id', 2);
                     // C2C user
                     $history_metadata->save();
                     $summit->setCulture($culture);
                     $summit->set('name', $hut_name);
                     $summit->save();
                     $conn->commit();
                 }
             }
         } catch (Exception $e) {
             $conn->rollback();
             return $this->setErrorAndRedirect($this->__('Failed to create synchronized summit'), "routes/edit?link={$summit_id}");
         }
         $summit_id = $summit->get('id');
         // get all associated regions (3+maps) with this hut:
         $associations = GeoAssociation::findAllAssociations($id, array('dr', 'dc', 'dd', 'dv', 'dm'));
         // replicate them with summit_id instead of id:
         foreach ($associations as $ea) {
             $a = new GeoAssociation();
             $a->doSaveWithValues($summit_id, $ea->get('linked_id'), $ea->get('type'));
         }
         // associate hut to summit
         $asso = new Association();
         $asso->doSaveWithValues($summit_id, $id, 'sh', 2);
         // C2C user
     } else {
         $associations = Association::findAllAssociations($id, 'sh');
         $summit_id = $associations[0]->get('main_id');
     }
     $this->clearCache('huts', $id);
     return $this->redirect("routes/edit?link={$summit_id}");
 }
 public function executeManageimages()
 {
     if (!$this->getUser()->isConnected()) {
         $referer = $this->getRequest()->getReferer();
         $this->setErrorAndRedirect('You need to login to access this page', $referer);
     }
     $user_id = $this->getUser()->getId();
     // logged user id
     $this->pager = new c2cDoctrinePager('Image', c2cTools::mobileVersion() ? sfConfig::get('app_list_mobile_maxline_number') : sfConfig::get('app_list_maxline_number'));
     $q = $this->pager->getQuery();
     $q->select('i.id, i.filename, i.image_type, ii.name, ii.culture')->from('Image i')->leftJoin('i.associations a ON i.id = a.linked_id')->leftJoin('i.ImageI18n ii')->leftJoin('i.versions v')->leftJoin('v.history_metadata hm');
     $where = 'i.image_type = 2 AND v.version = 1 AND hm.user_id = ?';
     $document_type = $this->getRequestParameter('dtyp');
     if (!empty($document_type)) {
         if ($document_type <= 1) {
             $types = array('ai', 'mi', 'bi', 'hi', 'pi', 'ri', 'ti', 'si');
         } else {
             $types = array('oi', 'ui');
         }
         $where .= " AND a.type IN ( '" . implode("', '", $types) . "' )";
     } else {
         $document_type = $this->getRequestParameter('ctyp');
         if (!empty($document_type)) {
             $q->leftJoin('a.Article c');
             if ($document_type <= 1) {
                 $document_type = 1;
             } else {
                 $document_type = 2;
             }
             $where .= " AND a.type = 'ci' AND c.article_type = {$document_type}";
         }
     }
     $q->where($where, array($user_id));
     $q->orderBy('i.id DESC');
     $page = $this->getRequestParameter('page', 1);
     $this->pager->setPage($page);
     $this->pager->init();
     $this->page = $page;
     if ($this->getRequest()->getMethod() == sfRequest::POST) {
         // images management
         $switch = $this->getRequestParameter('switch');
         $lang = $this->getUser()->getCulture();
         if (empty($switch)) {
             return $this->setNoticeAndRedirect('No image has been edited', "/users/manageimages?module=users&page={$page}");
         }
         $conn = sfDoctrine::Connection();
         $conn->beginTransaction();
         $history_metadata = new HistoryMetadata();
         $history_metadata->setComment('Switch to collaborative license');
         $history_metadata->set('is_minor', true);
         $history_metadata->set('user_id', $user_id);
         $history_metadata->save();
         foreach ($switch as $image_id) {
             // verify id corresponds to an image created by the user
             $img = Doctrine_Query::create()->select('i.id')->from('Image i')->leftJoin('i.versions v')->leftJoin('v.history_metadata hm')->where('v.version = 1 AND hm.user_id = ? AND i.id = ?', array($user_id, $image_id))->execute();
             if (empty($img)) {
                 $conn->rollback();
                 return $this->setNoticeAndRedirect('You do not have the right to change the license of theses images', "/users/manageimages?module=users&page={$page}");
             }
             $db_doc = Document::find('Image', $image_id);
             $db_doc->set('image_type', 1);
             $db_doc->save();
             // clear cache
             $this->clearCache('images', $image_id, false, 'view');
             $associated_docs = Association::findAllAssociatedDocs($image_id, array('id', 'module'));
             foreach ($associated_docs as $doc) {
                 // clear their view cache
                 $this->clearCache($doc['module'], $doc['id'], false, 'view');
             }
         }
         // apply modifications if everything went fine
         $conn->commit();
         return $this->setNoticeAndRedirect('Your images have been successfully updated', "/users/manageimages?module=users&page={$page}");
     } else {
         // display form
         $this->setPageTitle($this->__('User image management'));
     }
 }
 protected function doMerge($from_id, $document_from, $to_id, $document_to)
 {
     // fetch associated documents before doing the merging as associations will be transferred
     $associations = Association::findAllAssociations($from_id);
     parent::doMerge($from_id, $document_from, $to_id, $document_to);
     // search documents in which from is inserted, and replace the insertion with to
     foreach ($associations as $a) {
         $check_id = $a['main_id'] == $from_id ? $a['linked_id'] : ($check_id = $a['main_id']);
         $check_model = c2cTools::Letter2Model(substr($a['type'], 0, 1));
         $check_module = c2cTools::Model2Module($check_model);
         $check_doc = Document::find($check_model, $check_id);
         $fields = sfConfig::get('mod_images_bbcode_fields_' . $check_module);
         // clear linked doc cache
         $this->clearCache($check_module, $check_id);
         $languages = $check_doc->getLanguages();
         foreach ($languages as $language) {
             $modified = false;
             $conn = sfDoctrine::Connection();
             $conn->beginTransaction();
             $check_doc->setCulture($language);
             foreach ($fields as $field) {
                 $text = $check_doc[$field];
                 $edited = preg_replace('#(\\[img=\\s*)' . $from_id . '([\\w\\s]*\\].*?\\[/img\\])\\n?#is', '${1}' . $to_id . '${2}', $text);
                 $edited = preg_replace('#(\\[img=\\s*)' . $from_id . '([\\w\\s]*\\/\\])\\n?#is', '${1}' . $to_id . '${2}', $edited);
                 if ($edited != $text) {
                     $modified = true;
                     $check_doc->set($field, $edited);
                 }
             }
             if ($modified) {
                 $history_metadata = new HistoryMetadata();
                 $history_metadata->setComment('Updated image tags');
                 $history_metadata->set('is_minor', true);
                 $history_metadata->set('user_id', sfConfig::get('app_moderator_user_id'));
                 $history_metadata->save();
                 c2cTools::log('After merge of image ' . $from_id . ' into ' . $to_id . ': update image tag for ' . strtolower($check_model) . ' ' . $check_id . ' (' . $language . ')');
                 $check_doc->save();
                 $conn->commit();
             } else {
                 $conn->rollback();
             }
         }
     }
     // clear images lists and whatsnew cache
     $this->clearCache('images', 0, true);
 }
 /**
  * restore cookie values from profile. Managed cookies not in the profile will be deleted
  */
 public static function restorePrefCookies($user_id)
 {
     if (!($user_private_data = UserPrivateData::find($user_id))) {
         return;
         // silently stop
     }
     $response = sfContext::getInstance()->getResponse();
     $managed_cookies = sfConfig::get('app_profile_cookies_list');
     $fold_prefs = sfConfig::get('app_personalization_cookie_fold_positions');
     $cookie_prefs = $user_private_data->getPref_cookies();
     if (empty($cookie_prefs)) {
         // no saved value in profile, copy the current cookie values into profile
         // 'regular' cookies
         $cookie_values = array();
         foreach ($managed_cookies as $cookie) {
             if (sfContext::getInstance()->getRequest()->getCookie($cookie)) {
                 $cookie_values[$cookie] = urlencode(sfContext::getInstance()->getRequest()->getCookie($cookie));
             }
         }
         // fold prefs
         if (sfContext::getInstance()->getRequest()->getCookie('fold')) {
             $fold_cookie_value = sfContext::getInstance()->getRequest()->getCookie('fold');
             foreach ($fold_prefs as $pos => $pref) {
                 if ($fold_cookie_value[$pos] == 't') {
                     $cookie_values[$pref + '_home_status'] = 'true';
                 } else {
                     if ($fold_cookie_value[$pos] == 'f') {
                         $cookie_values[$pref + '_home_status'] = 'false';
                     }
                 }
             }
         }
         if (!empty($cookie_values)) {
             $conn = sfDoctrine::Connection();
             try {
                 $user_private_data->setPref_cookies($cookie_values);
                 $user_private_data->save();
                 $conn->commit();
             } catch (Exception $e) {
                 $conn->rollback();
             }
         }
     } else {
         // set fold cookie
         $fold_cookie_value = $default = str_repeat('x', sfConfig::get('app_personalization_cookie_fold_size'));
         foreach ($fold_prefs as $pos => $pref) {
             if (isset($cookie_prefs[$pref . '_home_status'])) {
                 $fold_cookie_value[$pos] = $cookie_prefs[$pref . '_home_status'] == 'true' ? 't' : 'f';
             }
         }
         if ($fold_cookie_value != $default) {
             $response->setCookie('fold', $fold_cookie_value, time() + sfConfig::get('app_personalization_filter_timeout'));
         } else {
             $response->setCookie('fold', '');
         }
         // erase all managed cookies or replace values with the one in profile
         foreach ($managed_cookies as $cookie_name) {
             if (array_key_exists($cookie_name, $cookie_prefs)) {
                 $response->setCookie($cookie_name, $cookie_prefs[$cookie_name], time() + sfConfig::get('app_personalization_filter_timeout'));
             } else {
                 $response->setCookie($cookie_name, '');
             }
         }
     }
 }
 /**
  * Saves new data for the document with its metadata.
  *
  */
 public function doSaveWithMetadata($user_id, $is_minor = false, $comment = null)
 {
     $conn = sfDoctrine::Connection();
     try {
         $conn->beginTransaction();
         // history metadata saving here
         $history_metadata = new HistoryMetadata();
         $history_metadata->setComment($comment);
         $history_metadata->set('is_minor', $is_minor);
         $history_metadata->set('user_id', $user_id);
         // data saving must be done in this order :
         $history_metadata->save();
         $this->save();
         $conn->commit();
         return true;
     } catch (exception $e) {
         $conn->rollback();
         throw $e;
     }
 }