mirror of https://github.com/go-gitea/gitea.git
fix org repo creation being limited by user limits (#34030)
fixes an issue where user is unable to create new repository in organization via UI if repository limits are in place and user has exhausted them for their own namespace. closes: https://github.com/go-gitea/gitea/issues/15504 --------- Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>pull/34001/head^2
parent
a7594969b6
commit
053592d847
routers/web/repo
templates/repo
tests/integration
web_src/js/features
|
@ -154,8 +154,8 @@ func createCommon(ctx *context.Context) {
|
||||||
ctx.Data["Licenses"] = repo_module.Licenses
|
ctx.Data["Licenses"] = repo_module.Licenses
|
||||||
ctx.Data["Readmes"] = repo_module.Readmes
|
ctx.Data["Readmes"] = repo_module.Readmes
|
||||||
ctx.Data["IsForcedPrivate"] = setting.Repository.ForcePrivate
|
ctx.Data["IsForcedPrivate"] = setting.Repository.ForcePrivate
|
||||||
ctx.Data["CanCreateRepo"] = ctx.Doer.CanCreateRepo()
|
ctx.Data["CanCreateRepoInDoer"] = ctx.Doer.CanCreateRepo()
|
||||||
ctx.Data["MaxCreationLimit"] = ctx.Doer.MaxCreationLimit()
|
ctx.Data["MaxCreationLimitOfDoer"] = ctx.Doer.MaxCreationLimit()
|
||||||
ctx.Data["SupportedObjectFormats"] = git.DefaultFeatures().SupportedObjectFormats
|
ctx.Data["SupportedObjectFormats"] = git.DefaultFeatures().SupportedObjectFormats
|
||||||
ctx.Data["DefaultObjectFormat"] = git.Sha1ObjectFormat
|
ctx.Data["DefaultObjectFormat"] = git.Sha1ObjectFormat
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,25 +7,21 @@
|
||||||
<div class="ui attached segment">
|
<div class="ui attached segment">
|
||||||
{{template "base/alert" .}}
|
{{template "base/alert" .}}
|
||||||
{{template "repo/create_helper" .}}
|
{{template "repo/create_helper" .}}
|
||||||
|
|
||||||
{{if not .CanCreateRepo}}
|
|
||||||
<div class="ui negative message">
|
|
||||||
<p>{{ctx.Locale.TrN .MaxCreationLimit "repo.form.reach_limit_of_creation_1" "repo.form.reach_limit_of_creation_n" .MaxCreationLimit}}</p>
|
|
||||||
</div>
|
|
||||||
{{end}}
|
|
||||||
<form class="ui form left-right-form new-repo-form" action="{{.Link}}" method="post">
|
<form class="ui form left-right-form new-repo-form" action="{{.Link}}" method="post">
|
||||||
{{.CsrfTokenHtml}}
|
{{.CsrfTokenHtml}}
|
||||||
|
<div id="create-repo-error-message" class="ui negative message tw-text-center tw-hidden"></div>
|
||||||
<div class="inline required field {{if .Err_Owner}}error{{end}}">
|
<div class="inline required field {{if .Err_Owner}}error{{end}}">
|
||||||
<label>{{ctx.Locale.Tr "repo.owner"}}</label>
|
<label>{{ctx.Locale.Tr "repo.owner"}}</label>
|
||||||
<div class="ui selection owner dropdown">
|
<div class="ui selection dropdown" id="repo_owner_dropdown">
|
||||||
<input type="hidden" id="uid" name="uid" value="{{.ContextUser.ID}}" required>
|
<input type="hidden" name="uid" value="{{.ContextUser.ID}}">
|
||||||
<span class="text truncated-item-container" title="{{.ContextUser.Name}}">
|
<span class="text truncated-item-name"></span>
|
||||||
{{ctx.AvatarUtils.Avatar .ContextUser 28 "mini"}}
|
|
||||||
<span class="truncated-item-name">{{.ContextUser.ShortName 40}}</span>
|
|
||||||
</span>
|
|
||||||
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
|
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
|
||||||
<div class="menu">
|
<div class="menu">
|
||||||
<div class="item truncated-item-container" data-value="{{.SignedUser.ID}}" title="{{.SignedUser.Name}}">
|
<div class="item truncated-item-container" data-value="{{.SignedUser.ID}}" title="{{.SignedUser.Name}}"
|
||||||
|
{{if not .CanCreateRepoInDoer}}
|
||||||
|
data-create-repo-disallowed-prompt="{{ctx.Locale.TrN .MaxCreationLimit "repo.form.reach_limit_of_creation_1" "repo.form.reach_limit_of_creation_n" .MaxCreationLimitOfDoer}}"
|
||||||
|
{{end}}
|
||||||
|
>
|
||||||
{{ctx.AvatarUtils.Avatar .SignedUser 28 "mini"}}
|
{{ctx.AvatarUtils.Avatar .SignedUser 28 "mini"}}
|
||||||
<span class="truncated-item-name">{{.SignedUser.ShortName 40}}</span>
|
<span class="truncated-item-name">{{.SignedUser.ShortName 40}}</span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -212,7 +208,7 @@
|
||||||
<br>
|
<br>
|
||||||
<div class="inline field">
|
<div class="inline field">
|
||||||
<label></label>
|
<label></label>
|
||||||
<button class="ui primary button{{if not .CanCreateRepo}} disabled{{end}}">
|
<button class="ui primary button">
|
||||||
{{ctx.Locale.Tr "repo.create_repo"}}
|
{{ctx.Locale.Tr "repo.create_repo"}}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -31,16 +31,16 @@ func testRepoGenerate(t *testing.T, session *TestSession, templateID, templateOw
|
||||||
|
|
||||||
// Step2: click the "Use this template" button
|
// Step2: click the "Use this template" button
|
||||||
htmlDoc := NewHTMLParser(t, resp.Body)
|
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||||
link, exists := htmlDoc.doc.Find("a.ui.button[href^=\"/repo/create\"]").Attr("href")
|
link, exists := htmlDoc.doc.Find(`a.ui.button[href^="/repo/create"]`).Attr("href")
|
||||||
assert.True(t, exists, "The template has changed")
|
assert.True(t, exists, "The template has changed")
|
||||||
req = NewRequest(t, "GET", link)
|
req = NewRequest(t, "GET", link)
|
||||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||||
|
|
||||||
// Step3: fill the form of the create
|
// Step3: fill the form on the "create" page
|
||||||
htmlDoc = NewHTMLParser(t, resp.Body)
|
htmlDoc = NewHTMLParser(t, resp.Body)
|
||||||
link, exists = htmlDoc.doc.Find("form.ui.form[action^=\"/repo/create\"]").Attr("action")
|
link, exists = htmlDoc.doc.Find(`form.ui.form[action^="/repo/create"]`).Attr("action")
|
||||||
assert.True(t, exists, "The template has changed")
|
assert.True(t, exists, "The template has changed")
|
||||||
_, exists = htmlDoc.doc.Find(fmt.Sprintf(".owner.dropdown .item[data-value=\"%d\"]", generateOwner.ID)).Attr("data-value")
|
_, exists = htmlDoc.doc.Find(fmt.Sprintf(`#repo_owner_dropdown .item[data-value="%d"]`, generateOwner.ID)).Attr("data-value")
|
||||||
assert.True(t, exists, "Generate owner '%s' is not present in select box", generateOwnerName)
|
assert.True(t, exists, "Generate owner '%s' is not present in select box", generateOwnerName)
|
||||||
req = NewRequestWithValues(t, "POST", link, map[string]string{
|
req = NewRequestWithValues(t, "POST", link, map[string]string{
|
||||||
"_csrf": htmlDoc.GetCSRF(),
|
"_csrf": htmlDoc.GetCSRF(),
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import {hideElem, showElem, toggleElem} from '../utils/dom.ts';
|
import {hideElem, querySingleVisibleElem, showElem, toggleElem} from '../utils/dom.ts';
|
||||||
import {htmlEscape} from 'escape-goat';
|
import {htmlEscape} from 'escape-goat';
|
||||||
import {fomanticQuery} from '../modules/fomantic/base.ts';
|
import {fomanticQuery} from '../modules/fomantic/base.ts';
|
||||||
import {sanitizeRepoName} from './repo-common.ts';
|
import {sanitizeRepoName} from './repo-common.ts';
|
||||||
|
@ -6,7 +6,9 @@ import {sanitizeRepoName} from './repo-common.ts';
|
||||||
const {appSubUrl} = window.config;
|
const {appSubUrl} = window.config;
|
||||||
|
|
||||||
function initRepoNewTemplateSearch(form: HTMLFormElement) {
|
function initRepoNewTemplateSearch(form: HTMLFormElement) {
|
||||||
const inputRepoOwnerUid = form.querySelector<HTMLInputElement>('#uid');
|
const elSubmitButton = querySingleVisibleElem<HTMLInputElement>(form, '.ui.primary.button');
|
||||||
|
const elCreateRepoErrorMessage = form.querySelector('#create-repo-error-message');
|
||||||
|
const elRepoOwnerDropdown = form.querySelector('#repo_owner_dropdown');
|
||||||
const elRepoTemplateDropdown = form.querySelector<HTMLInputElement>('#repo_template_search');
|
const elRepoTemplateDropdown = form.querySelector<HTMLInputElement>('#repo_template_search');
|
||||||
const inputRepoTemplate = form.querySelector<HTMLInputElement>('#repo_template');
|
const inputRepoTemplate = form.querySelector<HTMLInputElement>('#repo_template');
|
||||||
const elTemplateUnits = form.querySelector('#template_units');
|
const elTemplateUnits = form.querySelector('#template_units');
|
||||||
|
@ -19,11 +21,23 @@ function initRepoNewTemplateSearch(form: HTMLFormElement) {
|
||||||
inputRepoTemplate.addEventListener('change', checkTemplate);
|
inputRepoTemplate.addEventListener('change', checkTemplate);
|
||||||
checkTemplate();
|
checkTemplate();
|
||||||
|
|
||||||
const $dropdown = fomanticQuery(elRepoTemplateDropdown);
|
const $repoOwnerDropdown = fomanticQuery(elRepoOwnerDropdown);
|
||||||
|
const $repoTemplateDropdown = fomanticQuery(elRepoTemplateDropdown);
|
||||||
const onChangeOwner = function () {
|
const onChangeOwner = function () {
|
||||||
$dropdown.dropdown('setting', {
|
const ownerId = $repoOwnerDropdown.dropdown('get value');
|
||||||
|
const $ownerItem = $repoOwnerDropdown.dropdown('get item', ownerId);
|
||||||
|
hideElem(elCreateRepoErrorMessage);
|
||||||
|
elSubmitButton.disabled = false;
|
||||||
|
if ($ownerItem?.length) {
|
||||||
|
const elOwnerItem = $ownerItem[0];
|
||||||
|
elCreateRepoErrorMessage.textContent = elOwnerItem.getAttribute('data-create-repo-disallowed-prompt') ?? '';
|
||||||
|
const hasError = Boolean(elCreateRepoErrorMessage.textContent);
|
||||||
|
toggleElem(elCreateRepoErrorMessage, hasError);
|
||||||
|
elSubmitButton.disabled = hasError;
|
||||||
|
}
|
||||||
|
$repoTemplateDropdown.dropdown('setting', {
|
||||||
apiSettings: {
|
apiSettings: {
|
||||||
url: `${appSubUrl}/repo/search?q={query}&template=true&priority_owner_id=${inputRepoOwnerUid.value}`,
|
url: `${appSubUrl}/repo/search?q={query}&template=true&priority_owner_id=${ownerId}`,
|
||||||
onResponse(response: any) {
|
onResponse(response: any) {
|
||||||
const results = [];
|
const results = [];
|
||||||
results.push({name: '', value: ''}); // empty item means not using template
|
results.push({name: '', value: ''}); // empty item means not using template
|
||||||
|
@ -33,14 +47,14 @@ function initRepoNewTemplateSearch(form: HTMLFormElement) {
|
||||||
value: String(tmplRepo.repository.id),
|
value: String(tmplRepo.repository.id),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
$dropdown.fomanticExt.onResponseKeepSelectedItem($dropdown, inputRepoTemplate.value);
|
$repoTemplateDropdown.fomanticExt.onResponseKeepSelectedItem($repoTemplateDropdown, inputRepoTemplate.value);
|
||||||
return {results};
|
return {results};
|
||||||
},
|
},
|
||||||
cache: false,
|
cache: false,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
inputRepoOwnerUid.addEventListener('change', onChangeOwner);
|
$repoOwnerDropdown.dropdown('setting', 'onChange', onChangeOwner);
|
||||||
onChangeOwner();
|
onChangeOwner();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue