Replace password reset with email OTP verification flow. Add auth_otp module, OTP templates, and email delivery. Expand styleguide CSS with full component library. Rework login, register, and admin views for cookie sessions. Remove legacy 2FA templates and password reset flow. Update SSH wrappers, forms, validators, and middleware.
306 lines
12 KiB
Mako
306 lines
12 KiB
Mako
|
||
${h.secure_form(h.route_path('repo_create'), request=request)}
|
||
<div class="form">
|
||
<!-- fields -->
|
||
<div class="fields">
|
||
<div class="field">
|
||
<div class="label">
|
||
<label for="repo_name">${_('Repository')}:</label>
|
||
</div>
|
||
|
||
<div class="input">
|
||
<div class="full-repo-name-container">
|
||
% if c.personal_repo_group:
|
||
<a class="btn" href="#" id="select_my_group" data-personal-group-id="${c.personal_repo_group.group_id}">
|
||
<i class="icon-repo-group tooltip"
|
||
title="${_('Select my personal group ({})').format(c.personal_repo_group.group_name)}"></i>
|
||
</a>
|
||
% endif
|
||
${h.select('repo_group', request.GET.get('parent_group'), c.repo_groups, class_="medium")}
|
||
<div class="repo-create-spacer"> / </div>
|
||
<div class="repo-name-input-container">
|
||
${h.text('repo_name', class_="medium", id="repo_name_input")}
|
||
<div id="repo_name_error" class="error" aria-live="polite" style="display:none; color: #c00; margin-top: 6px; font-size: 0.9rem;"></div>
|
||
<div class="repo-check-container check-progress" id="repo_check" style="display: none"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="repo-header-row">
|
||
<span class="help-block-repo-create">
|
||
${_('Group / Repository Name')}
|
||
</span>
|
||
<div class="import-repo">
|
||
<a id="remote_clone_toggle" href="#">${_('Import existing')}</a>
|
||
</div>
|
||
</div>
|
||
|
||
## COPY PERMS
|
||
<div id="copy_perms">
|
||
<div id="checkbox-span">
|
||
${h.checkbox('repo_copy_permissions', value="True", checked="checked")}
|
||
</div>
|
||
|
||
<div class="help-block-inline">
|
||
${_('Copy permissions from parent repository group.')}
|
||
</div>
|
||
</div>
|
||
|
||
%if not c.rhodecode_user.is_admin:
|
||
${h.hidden('user_created',True)}
|
||
%endif
|
||
|
||
</div>
|
||
</div>
|
||
<div id="remote_clone" class="field" style="display: none;">
|
||
<div class="label">
|
||
<label for="clone_uri">${_('Clone from')}:</label>
|
||
</div>
|
||
<div class="input">
|
||
${h.text('clone_uri', class_="medium")}
|
||
<span class="help-block">
|
||
<pre>
|
||
- The repository must be accessible over http:// or https://
|
||
- For Git projects it's recommended appending .git to the end of clone url.
|
||
- Make sure to select proper repository type from the below selector before importing it.
|
||
- If your HTTP[S] repository is not publicly accessible,
|
||
add authentication information to the URL: https://username:password@server.company.com/repo-name.
|
||
- The Git LFS/Mercurial Largefiles objects will not be imported.
|
||
- For very large repositories, it's recommended to manually copy them into the
|
||
RhodeCode <a href="${h.route_path('admin_settings_vcs', _anchor='vcs-storage-options')}">storage location</a> and run <a href="${h.route_path('admin_settings_mapping')}">Remap and Rescan</a>.
|
||
</pre>
|
||
</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="field">
|
||
<div class="label">
|
||
<label for="repo_type">${_('Type')}:</label>
|
||
</div>
|
||
<div class="fields repo-type-radio">
|
||
% for backend in c.backends:
|
||
|
||
% if backend == c.default_backend:
|
||
<input id="repo_type_${backend}" name="repo_type" type="radio" value="${backend}" checked="checked"/>
|
||
% else:
|
||
<input id="repo_type_${backend}" name="repo_type" type="radio" value="${backend}" />
|
||
% endif
|
||
|
||
<label for="repo_type_${backend}">
|
||
<i class="icon-${backend}" style="font-size: 16px"></i>
|
||
${backend.upper()}
|
||
</label>
|
||
|
||
% endfor
|
||
|
||
<span class="help-block">${_('Set the type of repository to create.')}</span>
|
||
</div>
|
||
</div>
|
||
<div class="field">
|
||
<div class="label">
|
||
<label for="repo_description">${_('Description')}:</label>
|
||
</div>
|
||
<div class="textarea editor">
|
||
${h.textarea('repo_description',cols=23,rows=5,class_="medium")}
|
||
<% metatags_url = h.literal('''<a href="#metatagsShow" onclick="$('#meta-tags-desc').toggle();return false">meta-tags</a>''') %>
|
||
<span class="help-block">
|
||
% if c.visual.stylify_metatags:
|
||
${_('Plain text format with {metatags} support.').format(metatags=metatags_url)|n}
|
||
% else:
|
||
${_('Plain text format.')}
|
||
% endif
|
||
${_('Add a README file for longer descriptions')}
|
||
</span>
|
||
<span id="meta-tags-desc" style="display: none">
|
||
<%namespace name="dt" file="/data_table/_dt_elements.mako"/>
|
||
${dt.metatags_help()}
|
||
</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="field">
|
||
<div class="label label-checkbox">
|
||
<label for="repo_private">${_('Private Repository')}:</label>
|
||
</div>
|
||
<div class="checkboxes">
|
||
${h.checkbox('repo_private',value="True")}
|
||
<span class="help-block">${_('Private repositories are only visible to people explicitly added as collaborators.')}</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="field repo-bootstrap-items repo-bootstrap-readme">
|
||
<div class="label label-checkbox">
|
||
<label for="repo_bootstrap_readme">${_('Add Readme')}:</label>
|
||
</div>
|
||
<div class="checkboxes">
|
||
${h.checkbox('repo_bootstrap_readme',value="True")}
|
||
<span class="help-block">${_('Initialize repository with a README. Allows you to immediately clone this project’s repository.')}</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="field repo-bootstrap-items repo-bootstrap-svn" style="display: none">
|
||
<div class="label label-checkbox">
|
||
<label for="repo_bootstrap_svn_branch_struct">${_('Add SVN structure')}:</label>
|
||
</div>
|
||
<div class="checkboxes">
|
||
${h.checkbox('repo_bootstrap_svn_branch_struct',value="True")}
|
||
<span class="help-block">${_('Initialize repository with a branches/tags DIRS')}</span>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
<div class="buttons">
|
||
${h.submit('save',_('Create Repository'),class_="btn")}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<script>
|
||
$(document).ready(function () {
|
||
let setCopyPermsOption = function (group_val) {
|
||
if (group_val !== "-1") {
|
||
$('#copy_perms').show()
|
||
} else {
|
||
$('#copy_perms').hide();
|
||
}
|
||
};
|
||
|
||
$('#remote_clone_toggle').on('click', function (e) {
|
||
$('#remote_clone').show();
|
||
e.preventDefault();
|
||
$('#remote_clone_toggle').hide();
|
||
$('.repo-bootstrap-items').remove();
|
||
});
|
||
|
||
if ($('#remote_clone input').hasClass('error')) {
|
||
$('#remote_clone').show();
|
||
}
|
||
if ($('#remote_clone input').val()) {
|
||
$('#remote_clone').show();
|
||
}
|
||
|
||
$("#repo_group").select2({
|
||
'containerCssClass': "drop-menu",
|
||
'dropdownCssClass': "drop-menu-dropdown",
|
||
'dropdownAutoWidth': true,
|
||
'width': "resolve"
|
||
});
|
||
|
||
setCopyPermsOption($('#repo_group').val());
|
||
|
||
$("#repo_group").on("change", function (e) {
|
||
setCopyPermsOption(e.val);
|
||
$('#repo_name_input').trigger('input');
|
||
});
|
||
|
||
$('#repo_name_input').focus();
|
||
|
||
let debounceTimer;
|
||
|
||
$('#repo_name_input').on('input paste', function () {
|
||
const LIMIT = 192;
|
||
const $input = $("#repo_name_input");
|
||
const $error = $("#repo_name_error");
|
||
const $saveBtn = $("#save");
|
||
|
||
const len = $input.val().length;
|
||
|
||
if (len >= LIMIT) {
|
||
$error.text("You've reached the " + LIMIT + " character limit. Please select shorter name.").show();
|
||
$saveBtn.prop("disabled", true);
|
||
return;
|
||
} else {
|
||
$error.text("").hide();
|
||
$saveBtn.prop("disabled", false);
|
||
}
|
||
|
||
let repoName = $(this).val();
|
||
|
||
if (repoName.length > 0) {
|
||
$('#repo_check').text(_gettext('checking availability...'))
|
||
.show()
|
||
.removeClass('check-error check-success')
|
||
.addClass('check-progress');
|
||
} else {
|
||
$('#repo_check').hide();
|
||
clearTimeout(debounceTimer);
|
||
return;
|
||
}
|
||
|
||
clearTimeout(debounceTimer); // Cancel the previous timer
|
||
debounceTimer = setTimeout(function () {
|
||
performRepoLookup(repoName);
|
||
}, 200);
|
||
|
||
function performRepoLookup(repoName) {
|
||
self = this;
|
||
let repoGroup = $('#repo_group').val();
|
||
let repoType = $('input[name="repo_type"]').val();
|
||
$.ajax({
|
||
url: pyroutes.url('repo_name_check'),
|
||
data: {"repo_name": repoName, "repo_group": repoGroup, "repo_type": repoType},
|
||
dataType: 'json',
|
||
type: 'POST',
|
||
success: function (data) {
|
||
let result = data.result;
|
||
if (result.check_error === true) {
|
||
$('#repo_check')
|
||
.text(result.errors)
|
||
.removeClass('check-progress check-success')
|
||
.addClass('check-error');
|
||
} else {
|
||
let text = _gettext("Repository `{0}` is available").format(result.repo_name);
|
||
$('#repo_check')
|
||
.text(text)
|
||
.removeClass('check-progress check-error')
|
||
.addClass('check-success');
|
||
}
|
||
|
||
},
|
||
error: function (jqXHR, textStatus, errorThrown) {
|
||
var prefix = "Error while checking name.\n"
|
||
var message = formatErrorMessage(jqXHR, textStatus, errorThrown, prefix);
|
||
alert(message)
|
||
}
|
||
})
|
||
}
|
||
|
||
});
|
||
|
||
|
||
$('#select_my_group').on('click', function (e) {
|
||
e.preventDefault();
|
||
$("#repo_group").val($(this).data('personalGroupId')).trigger("change");
|
||
});
|
||
|
||
$('#clone_uri').on('input paste', function (e) {
|
||
let url = $(this).val().trim();
|
||
if (url) {
|
||
let parts = url.split('/').filter(Boolean);
|
||
let lastPart = parts[parts.length - 1];
|
||
let repoName = lastPart.replace(/\.git$/, "");
|
||
|
||
$('#repo_name_input').val(repoName).trigger('input');
|
||
} else {
|
||
$('#repo_name_input').val("").trigger('input');
|
||
}
|
||
});
|
||
|
||
let defaultVcsBackend = "${c.default_backend}";
|
||
|
||
if (defaultVcsBackend === "svn") {
|
||
$('.repo-bootstrap-svn').show();
|
||
}
|
||
$('input[name="repo_type"]').on('change', function (e) {
|
||
let selectedVcs = $(this).val();
|
||
|
||
if (selectedVcs === "svn") {
|
||
$('.repo-bootstrap-svn').show();
|
||
} else {
|
||
$('.repo-bootstrap-svn').hide();
|
||
}
|
||
})
|
||
|
||
trimRepoTitleName();
|
||
|
||
});
|
||
</script>
|
||
${h.end_form()}
|
||
|