diff --git a/resources/sql/autopatches/20150602.mlist.2.php b/resources/sql/autopatches/20150602.mlist.2.php new file mode 100644 index 0000000000..a8f2a090ba --- /dev/null +++ b/resources/sql/autopatches/20150602.mlist.2.php @@ -0,0 +1,145 @@ +establishConnection('w'); +$lists = new LiskRawMigrationIterator($conn_w, 'metamta_mailinglist'); + +echo pht('Migrating mailing lists...')."\n"; + +foreach ($lists as $list) { + $name = $list['name']; + $email = $list['email']; + $uri = $list['uri']; + $old_phid = $list['phid']; + + $username = preg_replace('/[^a-zA-Z0-9_-]+/', '-', $name); + $username = preg_replace('/-{2,}/', '-', $username); + $username = trim($username, '-'); + if (!strlen($username)) { + $username = 'mailinglist'; + } + $username .= '-list'; + + $username_okay = false; + for ($suffix = 1; $suffix <= 9; $suffix++) { + if ($suffix == 1) { + $effective_username = $username; + } else { + $effective_username = $username.$suffix; + } + + $collision = id(new PhabricatorPeopleQuery()) + ->setViewer(PhabricatorUser::getOmnipotentUser()) + ->withUsernames(array($effective_username)) + ->executeOne(); + if (!$collision) { + $username_okay = true; + break; + } + } + + if (!$username_okay) { + echo pht( + 'Failed to migrate mailing list "%s": unable to generate a unique '. + 'username for it.')."\n"; + continue; + } + + $username = $effective_username; + if (!PhabricatorUser::validateUsername($username)) { + echo pht( + 'Failed to migrate mailing list "%s": unable to generate a valid '. + 'username for it.', + $name)."\n"; + continue; + } + + $address = id(new PhabricatorUserEmail())->loadOneWhere( + 'address = %s', + $email); + if ($address) { + echo pht( + 'Failed to migrate mailing list "%s": an existing user already '. + 'has the email address "%s".', + $name, + $email)."\n"; + continue; + } + + $user = id(new PhabricatorUser()) + ->setUsername($username) + ->setRealName(pht('Mailing List "%s"', $name)) + ->setIsApproved(1) + ->setIsMailingList(1); + + $email_object = id(new PhabricatorUserEmail()) + ->setAddress($email) + ->setIsVerified(1); + + try { + id(new PhabricatorUserEditor()) + ->setActor($user) + ->createNewUser($user, $email_object); + } catch (Exception $ex) { + echo pht( + 'Failed to migrate mailing list "%s": %s.', + $name, + $ex->getMessage())."\n"; + continue; + } + + $new_phid = $user->getPHID(); + + // NOTE: After the PHID type is removed we can't use any Edge code to + // modify edges. + + $edge_type = PhabricatorSubscribedToObjectEdgeType::EDGECONST; + $edge_inverse = PhabricatorObjectHasSubscriberEdgeType::EDGECONST; + + $map = PhabricatorPHIDType::getAllTypes(); + foreach ($map as $type => $spec) { + try { + $object = $spec->newObject(); + if (!$object) { + continue; + } + $object_conn_w = $object->establishConnection('w'); + queryfx( + $object_conn_w, + 'UPDATE %T SET dst = %s WHERE dst = %s AND type = %s', + PhabricatorEdgeConfig::TABLE_NAME_EDGE, + $new_phid, + $old_phid, + $edge_inverse); + } catch (Exception $ex) { + // Just ignore these; they're mostly tables not existing. + continue; + } + } + + try { + $dst_phids = queryfx_all( + $conn_w, + 'SELECT dst FROM %T WHERE src = %s AND type = %s', + PhabricatorEdgeConfig::TABLE_NAME_EDGE, + $old_phid, + $edge_type); + if ($dst_phids) { + $editor = new PhabricatorEdgeEditor(); + foreach ($dst_phids as $dst_phid) { + $editor->addEdge($new_phid, $edge_type, $dst_phid['dst']); + } + $editor->save(); + } + } catch (Exception $ex) { + echo pht( + 'Unable to migrate some inverse edges for mailing list "%s": %s.', + $name, + $ex->getMessage())."\n"; + continue; + } + + echo pht( + 'Migrated mailing list "%s" to mailing list user "%s".', + $name, + $user->getUsername())."\n"; +}