static function save_username(Contact $user, $username) { global $Me; // does it contain odd characters? $username = trim((string) $username); if ($username == "") { if ($Me->privChair) { return $user->change_username("github", null); } return Conf::msg_error("Empty username."); } if (preg_match('_[@,;:~/\\[\\](){}\\<>&#=\\000-\\027]_', $username)) { return Conf::msg_error("The username “" . htmlspecialchars($username) . "” contains funny characters. Remove them."); } // is it in use? $x = $user->conf->fetch_value("select contactId from ContactInfo where github_username=?", $username); if ($x && $x != $user->contactId) { return Conf::msg_error("That username is already in use."); } // is it valid? XXX GitHub API $response = null; if ($org = $user->conf->opt("githubOrganization")) { $url = "https://api.github.com/orgs/" . urlencode($org) . "/members/" . urlencode($username); $response = self::api($user->conf, $url); if ($response->status == 404 && $user->conf->opt("githubRequireOrganizationMembership")) { return Conf::msg_error("That user isn’t a member of the " . Ht::link(htmlspecialchars($org) . " organization", self::MAINURL . urlencode($org)) . " that manages the class. Follow the link for registering with the class, or contact course staff."); } } if (!$response || $response->status == 404) { $url = "https://api.github.com/users/" . urlencode($username); $response = self::api($user->conf, $url); } if ($response->status == 404) { return Conf::msg_error("That username doesn’t appear to exist. Check your spelling."); } else { if ($response->status != 200 && $response->status != 204) { return Conf::msg_error("Error contacting " . htmlspecialchars($userurl) . " (response code {$response_code}). Maybe try again?"); } } if ($org && ($staff_team = $user->conf->opt("githubStaffTeam")) && $user->is_student()) { if (!is_int($staff_team)) { $staff_team = self::api_find_first($user->conf, "https://api.github.com/orgs/" . urlencode($org) . "/teams?per_page=100", function ($team) use($staff_team) { if (isset($team->name) && $team->name === $staff_team) { return $team->id; } }); } if (is_int($staff_team)) { $tresp = self::api($user->conf, "https://api.github.com/teams/{$staff_team}/members/" . urlencode($username)); if ($tresp->status == 200 || $tresp->status == 204) { return Conf::msg_error("That username belongs to a member of the course staff."); } } } return $user->change_username("github", $username); }
static function home_link($html) { return Ht::link($html, self::MAINURL); }
static function echo_repo_group($info, $include_tarball = false) { global $Conf, $Me, $Now; if ($info->pset->gitless) { return; } list($user, $pset, $partner, $repo) = array($info->user, $info->pset, $info->partner, $info->repo); $editable = $info->can_set_repo && !$user->is_anonymous; $repo_url = $repo ? $repo->friendly_url() : ""; $title = "repository"; if (!RepositorySite::is_primary($repo)) { $title = $repo->reposite->friendly_siteclass() . " " . $title; } if ($repo && $repo->url) { $title = $user->link_repo($title, $repo->web_url()); } if ($editable) { $value = Ht::entry("repo", $repo_url, array("style" => "width:32em")) . " " . Ht::submit("Save"); } else { if ($user->is_anonymous) { $value = $repo_url ? "[anonymous]" : "(none)"; } else { $value = htmlspecialchars($repo_url ? $repo_url : "(none)"); } } if ($repo_url) { $value .= ' <button class="b repoclip hottooltip" data-pa-repo="' . htmlspecialchars($repo->ssh_url()) . '"'; if ($user->is_anonymous) { $value .= ' data-tooltip="[anonymous]"'; } else { $value .= ' data-tooltip="' . htmlspecialchars($repo->ssh_url()) . '"'; } $value .= ' type="button" onclick="false">Copy URL to clipboard</button>'; Ht::stash_script('$(".repoclip").each(pa_init_repoclip)', "repoclip"); if ($include_tarball && $info->commit_hash() && ($tarball_url = $info->tarball_url())) { $value .= ' <a class="bsm q" href="' . htmlspecialchars($tarball_url) . '">Download tarball for ' . substr($info->commit_hash(), 0, 7) . '</a>'; } } // check repo $ms = new MessageSet($user); if ($repo) { $repo->check_working($ms); $repo->check_open($ms); } if ($partner && $info->partner_same()) { $prepo = $partner->repo($pset->id); if (!$repo && $prepo || $repo && !$prepo || $repo && $prepo && $repo->repoid != $prepo->repoid) { if ($prepo && $repo) { $prepo_url = ", " . htmlspecialchars($prepo->friendly_url_like($repo)); } else { if ($prepo) { $prepo_url = ", " . htmlspecialchars($prepo->friendly_url()); } else { $prepo_url = ""; } } $your_partner = "your partner’s"; if ($Me->isPC) { $your_partner = '<a href="' . hoturl("pset", array("pset" => $pset->urlkey, "u" => $Me->user_linkpart($partner))) . '">' . $your_partner . '</a>'; } $ms->set_error_html("partner", "This repository differs from {$your_partner}{$prepo_url}."); } } if ($repo) { $repo->check_ownership($user, $partner, $ms); } $prefixes = ["", "WARNING: ", "ERROR: "]; $notes = array_map(function ($m) use($prefixes) { return [$m[2] > 0, $prefixes[$m[2]] . $m[1]]; }, $ms->messages(true)); if ($repo && $repo->truncated_psetdir($pset)) { $notes[] = array(true, "Please create your repository by cloning our repository. Creating your repository from scratch makes it harder for us to grade and harder for you to get pset updates."); } if (!$repo) { $repoclasses = RepositorySite::site_classes($Conf); $x = commajoin(array_map(function ($k) { return Ht::link($k::global_friendly_siteclass(), $k::global_friendly_siteurl()); }, $repoclasses), "or"); if ($editable) { $notes[] = array(false, "Enter your {$x} repository URL here."); } } // edit if ($editable) { echo Ht::form(self_href(array("post" => post_value(), "set_repo" => 1, "pset" => $pset->urlkey))), '<div class="f-contain">'; } self::echo_group($title, $value, $notes); if ($editable) { echo "</div></form>\n"; } return $repo; }