Compare commits

..

No commits in common. "b301cb17a355e6f44e480f04f8ce89a7e43c58eb" and "e9991b1f060a08e5fbfbf56a3ef92cde74488143" have entirely different histories.

25 changed files with 87 additions and 291 deletions

View File

@ -1,18 +1,12 @@
plugins: plugins:
- stylelint-declaration-strict-value - stylelint-declaration-strict-value
ignoreFiles:
- "**/*.go"
overrides: overrides:
- files: ["**/*.less"] - files: ["**/*.less"]
customSyntax: postcss-less customSyntax: postcss-less
- files: ["**/chroma/*", "**/codemirror/*", "**/standalone/*", "**/console/*"] - files: ["**/chroma/*", "**/codemirror/*", "**/standalone/*", "**/console/*"]
rules: rules:
scale-unlimited/declaration-strict-value: null scale-unlimited/declaration-strict-value: null
- files: ["**/chroma/*", "**/codemirror/*"]
rules:
block-no-empty: null
rules: rules:
alpha-value-notation: null alpha-value-notation: null

View File

@ -7,7 +7,6 @@ package cmd
import ( import (
"errors" "errors"
"fmt" "fmt"
"net/url"
"os" "os"
"strings" "strings"
"text/tabwriter" "text/tabwriter"
@ -470,19 +469,11 @@ func runAddOauth(c *cli.Context) error {
return err return err
} }
config := parseOAuth2Config(c)
if config.Provider == "openidConnect" {
discoveryURL, err := url.Parse(config.OpenIDConnectAutoDiscoveryURL)
if err != nil || (discoveryURL.Scheme != "http" && discoveryURL.Scheme != "https") {
return fmt.Errorf("invalid Auto Discovery URL: %s (this must be a valid URL starting with http:// or https://)", config.OpenIDConnectAutoDiscoveryURL)
}
}
return auth_model.CreateSource(&auth_model.Source{ return auth_model.CreateSource(&auth_model.Source{
Type: auth_model.OAuth2, Type: auth_model.OAuth2,
Name: c.String("name"), Name: c.String("name"),
IsActive: true, IsActive: true,
Cfg: config, Cfg: parseOAuth2Config(c),
}) })
} }

View File

@ -239,32 +239,6 @@ func (org *Organization) CustomAvatarRelativePath() string {
return org.Avatar return org.Avatar
} }
// UnitPermission returns unit permission
func (org *Organization) UnitPermission(ctx context.Context, doer *user_model.User, unitType unit.Type) perm.AccessMode {
if doer != nil {
teams, err := GetUserOrgTeams(ctx, org.ID, doer.ID)
if err != nil {
log.Error("GetUserOrgTeams: %v", err)
return perm.AccessModeNone
}
if err := teams.LoadUnits(ctx); err != nil {
log.Error("LoadUnits: %v", err)
return perm.AccessModeNone
}
if len(teams) > 0 {
return teams.UnitMaxAccess(unitType)
}
}
if org.Visibility.IsPublic() {
return perm.AccessModeRead
}
return perm.AccessModeNone
}
// CreateOrganization creates record of a new organization. // CreateOrganization creates record of a new organization.
func CreateOrganization(org *Organization, owner *user_model.User) (err error) { func CreateOrganization(org *Organization, owner *user_model.User) (err error) {
if !owner.CanCreateOrganization() { if !owner.CanCreateOrganization() {

View File

@ -393,11 +393,6 @@ func (u *User) IsOrganization() bool {
return u.Type == UserTypeOrganization return u.Type == UserTypeOrganization
} }
// IsIndividual returns true if user is actually a individual user.
func (u *User) IsIndividual() bool {
return u.Type == UserTypeIndividual
}
// DisplayName returns full name if it's not empty, // DisplayName returns full name if it's not empty,
// returns username otherwise. // returns username otherwise.
func (u *User) DisplayName() string { func (u *User) DisplayName() string {

View File

@ -11,6 +11,7 @@ import (
"code.gitea.io/gitea/models/perm" "code.gitea.io/gitea/models/perm"
"code.gitea.io/gitea/models/unit" "code.gitea.io/gitea/models/unit"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/structs"
) )
@ -30,34 +31,29 @@ type Organization struct {
} }
func (org *Organization) CanWriteUnit(ctx *Context, unitType unit.Type) bool { func (org *Organization) CanWriteUnit(ctx *Context, unitType unit.Type) bool {
return org.Organization.UnitPermission(ctx, ctx.Doer, unitType) >= perm.AccessModeWrite if ctx.Doer == nil {
} return false
func (org *Organization) CanReadUnit(ctx *Context, unitType unit.Type) bool {
return org.Organization.UnitPermission(ctx, ctx.Doer, unitType) >= perm.AccessModeRead
}
func GetOrganizationByParams(ctx *Context) {
orgName := ctx.Params(":org")
var err error
ctx.Org.Organization, err = organization.GetOrgByName(ctx, orgName)
if err != nil {
if organization.IsErrOrgNotExist(err) {
redirectUserID, err := user_model.LookupUserRedirect(orgName)
if err == nil {
RedirectToUser(ctx, orgName, redirectUserID)
} else if user_model.IsErrUserRedirectNotExist(err) {
ctx.NotFound("GetUserByName", err)
} else {
ctx.ServerError("LookupUserRedirect", err)
}
} else {
ctx.ServerError("GetUserByName", err)
}
return
} }
return org.UnitPermission(ctx, ctx.Doer.ID, unitType) >= perm.AccessModeWrite
}
func (org *Organization) UnitPermission(ctx *Context, doerID int64, unitType unit.Type) perm.AccessMode {
if doerID > 0 {
teams, err := organization.GetUserOrgTeams(ctx, org.Organization.ID, doerID)
if err != nil {
log.Error("GetUserOrgTeams: %v", err)
return perm.AccessModeNone
}
if len(teams) > 0 {
return teams.UnitMaxAccess(unitType)
}
}
if org.Organization.Visibility == structs.VisibleTypePublic {
return perm.AccessModeRead
}
return perm.AccessModeNone
} }
// HandleOrgAssignment handles organization assignment // HandleOrgAssignment handles organization assignment
@ -81,26 +77,25 @@ func HandleOrgAssignment(ctx *Context, args ...bool) {
requireTeamAdmin = args[3] requireTeamAdmin = args[3]
} }
var err error orgName := ctx.Params(":org")
if ctx.ContextUser == nil { var err error
// if Organization is not defined, get it from params ctx.Org.Organization, err = organization.GetOrgByName(ctx, orgName)
if ctx.Org.Organization == nil { if err != nil {
GetOrganizationByParams(ctx) if organization.IsErrOrgNotExist(err) {
if ctx.Written() { redirectUserID, err := user_model.LookupUserRedirect(orgName)
return if err == nil {
RedirectToUser(ctx, orgName, redirectUserID)
} else if user_model.IsErrUserRedirectNotExist(err) {
ctx.NotFound("GetUserByName", err)
} else {
ctx.ServerError("LookupUserRedirect", err)
} }
} else {
ctx.ServerError("GetUserByName", err)
} }
} else if ctx.ContextUser.IsOrganization() {
if ctx.Org == nil {
ctx.Org = &Organization{}
}
ctx.Org.Organization = (*organization.Organization)(ctx.ContextUser)
} else {
// ContextUser is an individual User
return return
} }
org := ctx.Org.Organization org := ctx.Org.Organization
// Handle Visibility // Handle Visibility
@ -161,7 +156,6 @@ func HandleOrgAssignment(ctx *Context, args ...bool) {
} }
ctx.Data["IsOrganizationOwner"] = ctx.Org.IsOwner ctx.Data["IsOrganizationOwner"] = ctx.Org.IsOwner
ctx.Data["IsOrganizationMember"] = ctx.Org.IsMember ctx.Data["IsOrganizationMember"] = ctx.Org.IsMember
ctx.Data["IsProjectEnabled"] = true
ctx.Data["IsPackageEnabled"] = setting.Packages.Enabled ctx.Data["IsPackageEnabled"] = setting.Packages.Enabled
ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
ctx.Data["IsPublicMember"] = func(uid int64) bool { ctx.Data["IsPublicMember"] = func(uid int64) bool {
@ -237,10 +231,6 @@ func HandleOrgAssignment(ctx *Context, args ...bool) {
return return
} }
} }
ctx.Data["CanReadProjects"] = ctx.Org.CanReadUnit(ctx, unit.TypeProjects)
ctx.Data["CanReadPackages"] = ctx.Org.CanReadUnit(ctx, unit.TypePackages)
ctx.Data["CanReadCode"] = ctx.Org.CanReadUnit(ctx, unit.TypeCode)
} }
// OrgAssignment returns a middleware to handle organization assignment // OrgAssignment returns a middleware to handle organization assignment

View File

@ -2806,8 +2806,6 @@ auths.still_in_used = The authentication source is still in use. Convert or dele
auths.deletion_success = The authentication source has been deleted. auths.deletion_success = The authentication source has been deleted.
auths.login_source_exist = The authentication source '%s' already exists. auths.login_source_exist = The authentication source '%s' already exists.
auths.login_source_of_type_exist = An authentication source of this type already exists. auths.login_source_of_type_exist = An authentication source of this type already exists.
auths.unable_to_initialize_openid = Unable to initialize OpenID Connect Provider: %s
auths.invalid_openIdConnectAutoDiscoveryURL = Invalid Auto Discovery URL (this must be a valid URL starting with http:// or https://)
config.server_config = Server Configuration config.server_config = Server Configuration
config.app_name = Site Title config.app_name = Site Title

View File

@ -271,15 +271,6 @@ func NewAuthSourcePost(ctx *context.Context) {
} }
case auth.OAuth2: case auth.OAuth2:
config = parseOAuth2Config(form) config = parseOAuth2Config(form)
oauth2Config := config.(*oauth2.Source)
if oauth2Config.Provider == "openidConnect" {
discoveryURL, err := url.Parse(oauth2Config.OpenIDConnectAutoDiscoveryURL)
if err != nil || (discoveryURL.Scheme != "http" && discoveryURL.Scheme != "https") {
ctx.Data["Err_DiscoveryURL"] = true
ctx.RenderWithErr(ctx.Tr("admin.auths.invalid_openIdConnectAutoDiscoveryURL"), tplAuthNew, form)
return
}
}
case auth.SSPI: case auth.SSPI:
var err error var err error
config, err = parseSSPIConfig(ctx, form) config, err = parseSSPIConfig(ctx, form)
@ -314,10 +305,6 @@ func NewAuthSourcePost(ctx *context.Context) {
if auth.IsErrSourceAlreadyExist(err) { if auth.IsErrSourceAlreadyExist(err) {
ctx.Data["Err_Name"] = true ctx.Data["Err_Name"] = true
ctx.RenderWithErr(ctx.Tr("admin.auths.login_source_exist", err.(auth.ErrSourceAlreadyExist).Name), tplAuthNew, form) ctx.RenderWithErr(ctx.Tr("admin.auths.login_source_exist", err.(auth.ErrSourceAlreadyExist).Name), tplAuthNew, form)
} else if oauth2.IsErrOpenIDConnectInitialize(err) {
ctx.Data["Err_DiscoveryURL"] = true
unwrapped := err.(oauth2.ErrOpenIDConnectInitialize).Unwrap()
ctx.RenderWithErr(ctx.Tr("admin.auths.unable_to_initialize_openid", unwrapped), tplAuthNew, form)
} else { } else {
ctx.ServerError("auth.CreateSource", err) ctx.ServerError("auth.CreateSource", err)
} }
@ -402,15 +389,6 @@ func EditAuthSourcePost(ctx *context.Context) {
} }
case auth.OAuth2: case auth.OAuth2:
config = parseOAuth2Config(form) config = parseOAuth2Config(form)
oauth2Config := config.(*oauth2.Source)
if oauth2Config.Provider == "openidConnect" {
discoveryURL, err := url.Parse(oauth2Config.OpenIDConnectAutoDiscoveryURL)
if err != nil || (discoveryURL.Scheme != "http" && discoveryURL.Scheme != "https") {
ctx.Data["Err_DiscoveryURL"] = true
ctx.RenderWithErr(ctx.Tr("admin.auths.invalid_openIdConnectAutoDiscoveryURL"), tplAuthEdit, form)
return
}
}
case auth.SSPI: case auth.SSPI:
config, err = parseSSPIConfig(ctx, form) config, err = parseSSPIConfig(ctx, form)
if err != nil { if err != nil {
@ -430,7 +408,6 @@ func EditAuthSourcePost(ctx *context.Context) {
if err := auth.UpdateSource(source); err != nil { if err := auth.UpdateSource(source); err != nil {
if oauth2.IsErrOpenIDConnectInitialize(err) { if oauth2.IsErrOpenIDConnectInitialize(err) {
ctx.Flash.Error(err.Error(), true) ctx.Flash.Error(err.Error(), true)
ctx.Data["Err_DiscoveryURL"] = true
ctx.HTML(http.StatusOK, tplAuthEdit) ctx.HTML(http.StatusOK, tplAuthEdit)
} else { } else {
ctx.ServerError("UpdateSource", err) ctx.ServerError("UpdateSource", err)

View File

@ -156,7 +156,6 @@ func Home(ctx *context.Context) {
pager.SetDefaultParams(ctx) pager.SetDefaultParams(ctx)
pager.AddParam(ctx, "language", "Language") pager.AddParam(ctx, "language", "Language")
ctx.Data["Page"] = pager ctx.Data["Page"] = pager
ctx.Data["ContextUser"] = ctx.ContextUser
ctx.HTML(http.StatusOK, tplOrgHome) ctx.HTML(http.StatusOK, tplOrgHome)
} }

View File

@ -123,7 +123,6 @@ func NewProject(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("repo.projects.new") ctx.Data["Title"] = ctx.Tr("repo.projects.new")
ctx.Data["BoardTypes"] = project_model.GetBoardConfig() ctx.Data["BoardTypes"] = project_model.GetBoardConfig()
ctx.Data["CanWriteProjects"] = canWriteProjects(ctx) ctx.Data["CanWriteProjects"] = canWriteProjects(ctx)
ctx.Data["PageIsViewProjects"] = true
ctx.Data["HomeLink"] = ctx.ContextUser.HomeLink() ctx.Data["HomeLink"] = ctx.ContextUser.HomeLink()
shared_user.RenderUserHeader(ctx) shared_user.RenderUserHeader(ctx)
ctx.HTML(http.StatusOK, tplProjectsNew) ctx.HTML(http.StatusOK, tplProjectsNew)

View File

@ -9,8 +9,6 @@ import (
) )
func RenderUserHeader(ctx *context.Context) { func RenderUserHeader(ctx *context.Context) {
ctx.Data["IsProjectEnabled"] = true
ctx.Data["IsPackageEnabled"] = setting.Packages.Enabled
ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
ctx.Data["ContextUser"] = ctx.ContextUser ctx.Data["ContextUser"] = ctx.ContextUser
} }

View File

@ -24,7 +24,6 @@ func CodeSearch(ctx *context.Context) {
return return
} }
ctx.Data["IsProjectEnabled"] = true
ctx.Data["IsPackageEnabled"] = setting.Packages.Enabled ctx.Data["IsPackageEnabled"] = setting.Packages.Enabled
ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
ctx.Data["Title"] = ctx.Tr("explore.code") ctx.Data["Title"] = ctx.Tr("explore.code")

View File

@ -288,7 +288,6 @@ func Profile(ctx *context.Context) {
pager.AddParam(ctx, "language", "Language") pager.AddParam(ctx, "language", "Language")
} }
ctx.Data["Page"] = pager ctx.Data["Page"] = pager
ctx.Data["IsProjectEnabled"] = true
ctx.Data["IsPackageEnabled"] = setting.Packages.Enabled ctx.Data["IsPackageEnabled"] = setting.Packages.Enabled
ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled

View File

@ -690,21 +690,6 @@ func RegisterRoutes(m *web.Route) {
} }
} }
reqUnitAccess := func(unitType unit.Type, accessMode perm.AccessMode) func(ctx *context.Context) {
return func(ctx *context.Context) {
if ctx.ContextUser == nil {
ctx.NotFound(unitType.String(), nil)
return
}
if ctx.ContextUser.IsOrganization() {
if ctx.Org.Organization.UnitPermission(ctx, ctx.Doer, unitType) < accessMode {
ctx.NotFound(unitType.String(), nil)
return
}
}
}
}
// ***** START: Organization ***** // ***** START: Organization *****
m.Group("/org", func() { m.Group("/org", func() {
m.Group("/{org}", func() { m.Group("/{org}", func() {
@ -884,10 +869,8 @@ func RegisterRoutes(m *web.Route) {
} }
m.Group("/projects", func() { m.Group("/projects", func() {
m.Group("", func() { m.Get("", org.Projects)
m.Get("", org.Projects) m.Get("/{id}", org.ViewProject)
m.Get("/{id}", org.ViewProject)
}, reqUnitAccess(unit.TypeProjects, perm.AccessModeRead))
m.Group("", func() { //nolint:dupl m.Group("", func() { //nolint:dupl
m.Get("/new", org.NewProject) m.Get("/new", org.NewProject)
m.Post("/new", web.Bind(forms.CreateProjectForm{}), org.NewProjectPost) m.Post("/new", web.Bind(forms.CreateProjectForm{}), org.NewProjectPost)
@ -907,18 +890,25 @@ func RegisterRoutes(m *web.Route) {
m.Post("/move", org.MoveIssues) m.Post("/move", org.MoveIssues)
}) })
}) })
}, reqSignIn, reqUnitAccess(unit.TypeProjects, perm.AccessModeWrite), func(ctx *context.Context) { }, reqSignIn, func(ctx *context.Context) {
if ctx.ContextUser.IsIndividual() && ctx.ContextUser.ID != ctx.Doer.ID { if ctx.ContextUser == nil {
ctx.NotFound("NewProject", nil)
return
}
if ctx.ContextUser.IsOrganization() {
if !ctx.Org.CanWriteUnit(ctx, unit.TypeProjects) {
ctx.NotFound("NewProject", nil)
return
}
} else if ctx.ContextUser.ID != ctx.Doer.ID {
ctx.NotFound("NewProject", nil) ctx.NotFound("NewProject", nil)
return return
} }
}) })
}, repo.MustEnableProjects) }, repo.MustEnableProjects)
m.Group("", func() { m.Get("/code", user.CodeSearch)
m.Get("/code", user.CodeSearch) }, context_service.UserAssignmentWeb())
}, reqUnitAccess(unit.TypeCode, perm.AccessModeRead))
}, context_service.UserAssignmentWeb(), context.OrgAssignment())
// ***** Release Attachment Download without Signin // ***** Release Attachment Download without Signin
m.Get("/{username}/{reponame}/releases/download/{vTag}/{fileName}", ignSignIn, context.RepoAssignment, repo.MustBeNotEmpty, repo.RedirectDownload) m.Get("/{username}/{reponame}/releases/download/{vTag}/{fileName}", ignSignIn, context.RepoAssignment, repo.MustBeNotEmpty, repo.RedirectDownload)

View File

@ -36,10 +36,6 @@ func (err ErrOpenIDConnectInitialize) Error() string {
return fmt.Sprintf("Failed to initialize OpenID Connect Provider with name '%s' with url '%s': %v", err.ProviderName, err.OpenIDConnectAutoDiscoveryURL, err.Cause) return fmt.Sprintf("Failed to initialize OpenID Connect Provider with name '%s' with url '%s': %v", err.ProviderName, err.OpenIDConnectAutoDiscoveryURL, err.Cause)
} }
func (err ErrOpenIDConnectInitialize) Unwrap() error {
return err.Cause
}
// wrapOpenIDConnectInitializeError is used to wrap the error but this cannot be done in modules/auth/oauth2 // wrapOpenIDConnectInitializeError is used to wrap the error but this cannot be done in modules/auth/oauth2
// inside oauth2: import cycle not allowed models -> modules/auth/oauth2 -> models // inside oauth2: import cycle not allowed models -> modules/auth/oauth2 -> models
func wrapOpenIDConnectInitializeError(err error, providerName string, source *Source) error { func wrapOpenIDConnectInitializeError(err error, providerName string, source *Source) error {

View File

@ -8,6 +8,7 @@ import (
"net/http" "net/http"
"strings" "strings"
org_model "code.gitea.io/gitea/models/organization"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/context"
) )
@ -56,6 +57,14 @@ func userAssignment(ctx *context.Context, errCb func(int, string, interface{}))
} else { } else {
errCb(http.StatusInternalServerError, "GetUserByName", err) errCb(http.StatusInternalServerError, "GetUserByName", err)
} }
} else {
if ctx.ContextUser.IsOrganization() {
if ctx.Org == nil {
ctx.Org = &context.Organization{}
}
ctx.Org.Organization = (*org_model.Organization)(ctx.ContextUser)
ctx.Data["Org"] = ctx.Org.Organization
}
} }
} }
} }

View File

@ -24,7 +24,7 @@
<label for="oauth2_icon_url">{{.locale.Tr "admin.auths.oauth2_icon_url"}}</label> <label for="oauth2_icon_url">{{.locale.Tr "admin.auths.oauth2_icon_url"}}</label>
<input id="oauth2_icon_url" name="oauth2_icon_url" value="{{.oauth2_icon_url}}"> <input id="oauth2_icon_url" name="oauth2_icon_url" value="{{.oauth2_icon_url}}">
</div> </div>
<div class="open_id_connect_auto_discovery_url required field{{if .Err_DiscoveryURL}} error{{end}}"> <div class="open_id_connect_auto_discovery_url required field">
<label for="open_id_connect_auto_discovery_url">{{.locale.Tr "admin.auths.openIdConnectAutoDiscoveryURL"}}</label> <label for="open_id_connect_auto_discovery_url">{{.locale.Tr "admin.auths.openIdConnectAutoDiscoveryURL"}}</label>
<input id="open_id_connect_auto_discovery_url" name="open_id_connect_auto_discovery_url" value="{{.open_id_connect_auto_discovery_url}}"> <input id="open_id_connect_auto_discovery_url" name="open_id_connect_auto_discovery_url" value="{{.open_id_connect_auto_discovery_url}}">
</div> </div>

View File

@ -3,18 +3,16 @@
<a class="{{if .PageIsViewRepositories}}active {{end}}item" href="{{$.Org.HomeLink}}"> <a class="{{if .PageIsViewRepositories}}active {{end}}item" href="{{$.Org.HomeLink}}">
{{svg "octicon-repo"}} {{.locale.Tr "user.repositories"}} {{svg "octicon-repo"}} {{.locale.Tr "user.repositories"}}
</a> </a>
{{if and .IsProjectEnabled .CanReadProjects}}
<a class="{{if .PageIsViewProjects}}active {{end}}item" href="{{$.Org.HomeLink}}/-/projects"> <a class="{{if .PageIsViewProjects}}active {{end}}item" href="{{$.Org.HomeLink}}/-/projects">
{{svg "octicon-project-symlink"}} {{.locale.Tr "user.projects"}} {{svg "octicon-project-symlink"}} {{.locale.Tr "user.projects"}}
</a> </a>
{{end}} {{if .IsPackageEnabled}}
{{if and .IsPackageEnabled .CanReadPackages}}
<a class="item" href="{{$.Org.HomeLink}}/-/packages"> <a class="item" href="{{$.Org.HomeLink}}/-/packages">
{{svg "octicon-package"}} {{.locale.Tr "packages.title"}} {{svg "octicon-package"}} {{.locale.Tr "packages.title"}}
</a> </a>
{{end}} {{end}}
{{if and .IsRepoIndexerEnabled .CanReadCode}} {{if .IsRepoIndexerEnabled}}
<a class="item" href="{{$.Org.HomeLink}}/-/code"> <a class="{{if $.PageIsOrgCode}}active {{end}}item" href="{{$.Org.HomeLink}}/-/code">
{{svg "octicon-code"}}&nbsp;{{$.locale.Tr "org.code"}} {{svg "octicon-code"}}&nbsp;{{$.locale.Tr "org.code"}}
</a> </a>
{{end}} {{end}}

View File

@ -63,7 +63,7 @@
{{end}} {{end}}
{{template "repo/sub_menu" .}} {{template "repo/sub_menu" .}}
<div class="repo-button-row gt-df gt-ac gt-sb gt-fw"> <div class="repo-button-row gt-df gt-ac gt-sb gt-fw">
<div class="gt-df gt-ac gt-fw gt-gap-y-3"> <div class="gt-df gt-ac">
{{template "repo/branch_dropdown" dict "root" .}} {{template "repo/branch_dropdown" dict "root" .}}
{{$n := len .TreeNames}} {{$n := len .TreeNames}}
{{$l := Subtract $n 1}} {{$l := Subtract $n 1}}
@ -99,16 +99,20 @@
{{svg "octicon-triangle-down" 14 "dropdown icon"}} {{svg "octicon-triangle-down" 14 "dropdown icon"}}
</button> </button>
{{end}} {{end}}
{{if and (eq $n 0) (.Repository.IsTemplate)}}
<a role="button" class="ui primary compact button" href="{{AppSubUrl}}/repo/create?template_id={{.Repository.ID}}">
{{.locale.Tr "repo.use_template"}}
</a>
{{end}}
{{if ne $n 0}} {{if ne $n 0}}
<span class="ui breadcrumb repo-path gt-ml-2"><a class="section" href="{{.RepoLink}}/src/{{.BranchNameSubURL}}" title="{{.Repository.Name}}">{{EllipsisString .Repository.Name 30}}</a>{{range $i, $v := .TreeNames}}<span class="divider">/</span>{{if eq $i $l}}<span class="active section" title="{{$v}}">{{EllipsisString $v 30}}</span>{{else}}{{$p := index $.Paths $i}}<span class="section"><a href="{{$.BranchLink}}/{{PathEscapeSegments $p}}" title="{{$v}}">{{EllipsisString $v 30}}</a></span>{{end}}{{end}}</span> <span class="ui breadcrumb repo-path gt-ml-2"><a class="section" href="{{.RepoLink}}/src/{{.BranchNameSubURL}}" title="{{.Repository.Name}}">{{EllipsisString .Repository.Name 30}}</a>{{range $i, $v := .TreeNames}}<span class="divider">/</span>{{if eq $i $l}}<span class="active section" title="{{$v}}">{{EllipsisString $v 30}}</span>{{else}}{{$p := index $.Paths $i}}<span class="section"><a href="{{$.BranchLink}}/{{PathEscapeSegments $p}}" title="{{$v}}">{{EllipsisString $v 30}}</a></span>{{end}}{{end}}</span>
{{end}} {{end}}
</div> </div>
<div class="gt-df gt-ac"> <div class="gt-df gt-ac">
{{if eq $n 0}}
{{if .Repository.IsTemplate}}
<div class="ui tiny primary buttons">
<a href="{{AppSubUrl}}/repo/create?template_id={{.Repository.ID}}" class="ui button">
{{.locale.Tr "repo.use_template"}}
</a>
</div>
{{end}}
{{end}}
<!-- Only show clone panel in repository home page --> <!-- Only show clone panel in repository home page -->
{{if eq $n 0}} {{if eq $n 0}}
<div class="ui action tiny input" id="clone-panel"> <div class="ui action tiny input" id="clone-panel">

View File

@ -22,17 +22,15 @@
<a class="item" href="{{.ContextUser.HomeLink}}"> <a class="item" href="{{.ContextUser.HomeLink}}">
{{svg "octicon-repo"}} {{.locale.Tr "user.repositories"}} {{svg "octicon-repo"}} {{.locale.Tr "user.repositories"}}
</a> </a>
{{if and .IsProjectEnabled (or .ContextUser.IsIndividual (and .ContextUser.IsOrganization .CanReadProjects))}}
<a href="{{.ContextUser.HomeLink}}/-/projects" class="{{if .PageIsViewProjects}}active {{end}}item"> <a href="{{.ContextUser.HomeLink}}/-/projects" class="{{if .PageIsViewProjects}}active {{end}}item">
{{svg "octicon-project-symlink"}} {{.locale.Tr "user.projects"}} {{svg "octicon-project-symlink"}} {{.locale.Tr "user.projects"}}
</a> </a>
{{end}} {{if (not .UnitPackagesGlobalDisabled)}}
{{if and .IsPackageEnabled (or .ContextUser.IsIndividual (and .ContextUser.IsOrganization .CanReadPackages))}}
<a href="{{.ContextUser.HomeLink}}/-/packages" class="{{if .IsPackagesPage}}active {{end}}item"> <a href="{{.ContextUser.HomeLink}}/-/packages" class="{{if .IsPackagesPage}}active {{end}}item">
{{svg "octicon-package"}} {{.locale.Tr "packages.title"}} {{svg "octicon-package"}} {{.locale.Tr "packages.title"}}
</a> </a>
{{end}} {{end}}
{{if and .IsRepoIndexerEnabled (or .ContextUser.IsIndividual (and .ContextUser.IsOrganization .CanReadCode))}} {{if .IsRepoIndexerEnabled}}
<a href="{{.ContextUser.HomeLink}}/-/code" class="{{if .IsCodePage}}active {{end}}item"> <a href="{{.ContextUser.HomeLink}}/-/code" class="{{if .IsCodePage}}active {{end}}item">
{{svg "octicon-code"}} {{.locale.Tr "user.code"}} {{svg "octicon-code"}} {{.locale.Tr "user.code"}}
</a> </a>

View File

@ -2869,7 +2869,7 @@
} }
.repo-button-row > * { .repo-button-row > * {
margin-top: 8px; margin-top: 10px;
} }
.wiki .repo-button-row { .wiki .repo-button-row {

View File

@ -1,79 +0,0 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
//go:build ignore
/*
This tool is used to compare the CSS names in a chroma builtin styles with the Gitea theme CSS names.
It outputs the difference between the two sets of CSS names, eg:
```
CSS names not in builtin:
.chroma .ln
----
Builtin CSS names not in file:
.chroma .vm
```
Developers could use this tool to re-sync the CSS names in the Gitea theme.
*/
package main
import (
"os"
"regexp"
"strings"
"github.com/alecthomas/chroma/v2"
)
func main() {
if len(os.Args) != 2 {
println("Usage: chroma-style-diff css-or-less-file")
os.Exit(1)
}
data, err := os.ReadFile(os.Args[1])
if err != nil {
println(err.Error())
os.Exit(1)
}
content := string(data)
// a simple CSS parser to collect CSS names
content = regexp.MustCompile("//.*\r?\n").ReplaceAllString(content, "\n")
content = regexp.MustCompile("/\\*.*?\\*/").ReplaceAllString(content, "")
matches := regexp.MustCompile("\\s*([-.#:\\w\\s]+)\\s*\\{[^}]*}").FindAllStringSubmatch(content, -1)
cssNames := map[string]bool{}
for _, matchGroup := range matches {
cssName := strings.TrimSpace(matchGroup[1])
cssNames[cssName] = true
}
// collect Chroma builtin CSS names
builtin := map[string]bool{}
for tokenType, cssName := range chroma.StandardTypes {
if tokenType > 0 && cssName != "" {
builtin[".chroma ."+cssName] = true
}
}
// show the diff
println("CSS names not in builtin:")
for cssName := range cssNames {
if !builtin[cssName] {
println(cssName)
}
}
println("----")
println("Builtin CSS names not in file:")
for cssName := range builtin {
if !cssNames[cssName] {
println(cssName)
}
}
}

View File

@ -7,19 +7,17 @@
.chroma .cpf { color: #649bc4; } /* CommentPreprocFile */ .chroma .cpf { color: #649bc4; } /* CommentPreprocFile */
.chroma .cs { color: #9075cd; } /* CommentSpecial */ .chroma .cs { color: #9075cd; } /* CommentSpecial */
.chroma .dl { color: #649bc4; } /* LiteralStringDelimiter */ .chroma .dl { color: #649bc4; } /* LiteralStringDelimiter */
.chroma .fm {} /* NameFunctionMagic */
.chroma .g {} /* Generic */
.chroma .gd { color: #ffffff; background-color: #5f3737; } /* GenericDeleted */ .chroma .gd { color: #ffffff; background-color: #5f3737; } /* GenericDeleted */
.chroma .ge { color: #ddee30; } /* GenericEmph */ .chroma .ge { color: #ddee30; } /* GenericEmph */
.chroma .gh { color: #ffaa10; } /* GenericHeading */ .chroma .gh { color: #ffaa10; } /* GenericHeading */
.chroma .gi { color: #ffffff; background-color: #3a523a; } /* GenericInserted */ .chroma .gi { color: #ffffff; background-color: #3a523a; } /* GenericInserted */
.chroma .gl {} /* GenericUnderline */
.chroma .go { color: #777e94; } /* GenericOutput */ .chroma .go { color: #777e94; } /* GenericOutput */
.chroma .gp { color: #ebdbb2; } /* GenericPrompt */ .chroma .gp { color: #ebdbb2; } /* GenericPrompt */
.chroma .gr { color: #ff4433; } /* GenericError */ .chroma .gr { color: #ff4433; } /* GenericError */
.chroma .gs { color: #ebdbb2; } /* GenericStrong */ .chroma .gs { color: #ebdbb2; } /* GenericStrong */
.chroma .gt { color: #ff7540; } /* GenericTraceback */ .chroma .gt { color: #ff7540; } /* GenericTraceback */
.chroma .gu { color: #b8bb26; } /* GenericSubheading */ .chroma .gu { color: #b8bb26; } /* GenericSubheading */
.chroma .hl { background-color: #3f424d; } /* LineHighlight */
.chroma .il { color: #649bc4; } /* LiteralNumberIntegerLong */ .chroma .il { color: #649bc4; } /* LiteralNumberIntegerLong */
.chroma .k { color: #ff7540; } /* Keyword */ .chroma .k { color: #ff7540; } /* Keyword */
.chroma .kc { color: #649bc4; } /* KeywordConstant */ .chroma .kc { color: #649bc4; } /* KeywordConstant */
@ -27,16 +25,16 @@
.chroma .kn { color: #ffaa10; } /* KeywordNamespace */ .chroma .kn { color: #ffaa10; } /* KeywordNamespace */
.chroma .kp { color: #5f8700; } /* KeywordPseudo */ .chroma .kp { color: #5f8700; } /* KeywordPseudo */
.chroma .kr { color: #ff7540; } /* KeywordReserved */ .chroma .kr { color: #ff7540; } /* KeywordReserved */
.chroma .kt { color: #ff7b72; } /* KeywordType */ .chroma .kt { color: #fabd2f; } /* KeywordType */
.chroma .l {} /* Literal */ .chroma .ln { color: #7f8699; } /* LineNumbers */
.chroma .ld {} /* LiteralDate */ .chroma .lnt { color: #7f8699; } /* LineNumbersTable */
.chroma .m { color: #649bc4; } /* LiteralNumber */ .chroma .m { color: #649bc4; } /* LiteralNumber */
.chroma .mb { color: #649bc4; } /* LiteralNumberBin */ .chroma .mb { color: #649bc4; } /* LiteralNumberBin */
.chroma .mf { color: #649bc4; } /* LiteralNumberFloat */ .chroma .mf { color: #649bc4; } /* LiteralNumberFloat */
.chroma .mh { color: #649bc4; } /* LiteralNumberHex */ .chroma .mh { color: #649bc4; } /* LiteralNumberHex */
.chroma .mi { color: #649bc4; } /* LiteralNumberInteger */ .chroma .mi { color: #649bc4; } /* LiteralNumberInteger */
.chroma .mo { color: #649bc4; } /* LiteralNumberOct */ .chroma .mo { color: #649bc4; } /* LiteralNumberOct */
.chroma .n { color: #c9d1d9; } /* Name */ .chroma .n { color: #fabd2f; } /* Name */
.chroma .na { color: #b8bb26; } /* NameAttribute */ .chroma .na { color: #b8bb26; } /* NameAttribute */
.chroma .nb { color: #fabd2f; } /* NameBuiltin */ .chroma .nb { color: #fabd2f; } /* NameBuiltin */
.chroma .nc { color: #ffaa10; } /* NameClass */ .chroma .nc { color: #ffaa10; } /* NameClass */
@ -53,7 +51,6 @@
.chroma .o { color: #ff7540; } /* Operator */ .chroma .o { color: #ff7540; } /* Operator */
.chroma .ow { color: #5f8700; } /* OperatorWord */ .chroma .ow { color: #5f8700; } /* OperatorWord */
.chroma .p { color: #d2d4db; } /* Punctuation */ .chroma .p { color: #d2d4db; } /* Punctuation */
.chroma .py {} /* NameProperty */
.chroma .s { color: #b8bb26; } /* LiteralString */ .chroma .s { color: #b8bb26; } /* LiteralString */
.chroma .s1 { color: #b8bb26; } /* LiteralStringSingle */ .chroma .s1 { color: #b8bb26; } /* LiteralStringSingle */
.chroma .s2 { color: #b8bb26; } /* LiteralStringDouble */ .chroma .s2 { color: #b8bb26; } /* LiteralStringDouble */
@ -70,5 +67,4 @@
.chroma .vc { color: #ff7540; } /* NameVariableClass */ .chroma .vc { color: #ff7540; } /* NameVariableClass */
.chroma .vg { color: #ffaa10; } /* NameVariableGlobal */ .chroma .vg { color: #ffaa10; } /* NameVariableGlobal */
.chroma .vi { color: #ffaa10; } /* NameVariableInstance */ .chroma .vi { color: #ffaa10; } /* NameVariableInstance */
.chroma .vm {} /* NameVariableMagic */
.chroma .w { color: #7f8699; } /* TextWhitespace */ .chroma .w { color: #7f8699; } /* TextWhitespace */

View File

@ -7,19 +7,16 @@
.chroma .cpf { color: #4c4dbc; } /* CommentPreprocFile */ .chroma .cpf { color: #4c4dbc; } /* CommentPreprocFile */
.chroma .cs { color: #999999; } /* CommentSpecial */ .chroma .cs { color: #999999; } /* CommentSpecial */
.chroma .dl { color: #106303; } /* LiteralStringDelimiter */ .chroma .dl { color: #106303; } /* LiteralStringDelimiter */
.chroma .fm {} /* NameFunctionMagic */
.chroma .g {} /* Generic */
.chroma .gd { color: #000000; background-color: #ffdddd; } /* GenericDeleted */ .chroma .gd { color: #000000; background-color: #ffdddd; } /* GenericDeleted */
.chroma .ge { color: #000000; } /* GenericEmph */ .chroma .ge { color: #000000; } /* GenericEmph */
.chroma .gh { color: #999999; } /* GenericHeading */ .chroma .gh { color: #999999; } /* GenericHeading */
.chroma .gi { color: #000000; background-color: #ddffdd; } /* GenericInserted */ .chroma .gi { color: #000000; background-color: #ddffdd; } /* GenericInserted */
.chroma .gl {} /* GenericUnderline */
.chroma .go { color: #888888; } /* GenericOutput */ .chroma .go { color: #888888; } /* GenericOutput */
.chroma .gp { color: #555555; } /* GenericPrompt */ .chroma .gp { color: #555555; } /* GenericPrompt */
.chroma .gr { color: #aa0000; } /* GenericError */ .chroma .gr { color: #aa0000; } /* GenericError */
.chroma .gs {} /* GenericStrong */
.chroma .gt { color: #aa0000; } /* GenericTraceback */ .chroma .gt { color: #aa0000; } /* GenericTraceback */
.chroma .gu { color: #aaaaaa; } /* GenericSubheading */ .chroma .gu { color: #aaaaaa; } /* GenericSubheading */
.chroma .hl { background-color: #e5e5e5; } /* LineHighlight */
.chroma .il { color: #009999; } /* LiteralNumberIntegerLong */ .chroma .il { color: #009999; } /* LiteralNumberIntegerLong */
.chroma .k { color: #d73a49; } /* Keyword */ .chroma .k { color: #d73a49; } /* Keyword */
.chroma .kc { color: #d73a49; } /* KeywordConstant */ .chroma .kc { color: #d73a49; } /* KeywordConstant */
@ -28,15 +25,14 @@
.chroma .kp { color: #d73a49; } /* KeywordPseudo */ .chroma .kp { color: #d73a49; } /* KeywordPseudo */
.chroma .kr { color: #d73a49; } /* KeywordReserved */ .chroma .kr { color: #d73a49; } /* KeywordReserved */
.chroma .kt { color: #445588; } /* KeywordType */ .chroma .kt { color: #445588; } /* KeywordType */
.chroma .l {} /* Literal */ .chroma .ln { color: #7f7f7f; } /* LineNumbers */
.chroma .ld {} /* LiteralDate */ .chroma .lnt { color: #7f7f7f; } /* LineNumbersTable */
.chroma .m { color: #009999; } /* LiteralNumber */ .chroma .m { color: #009999; } /* LiteralNumber */
.chroma .mb { color: #009999; } /* LiteralNumberBin */ .chroma .mb { color: #009999; } /* LiteralNumberBin */
.chroma .mf { color: #009999; } /* LiteralNumberFloat */ .chroma .mf { color: #009999; } /* LiteralNumberFloat */
.chroma .mh { color: #009999; } /* LiteralNumberHex */ .chroma .mh { color: #009999; } /* LiteralNumberHex */
.chroma .mi { color: #009999; } /* LiteralNumberInteger */ .chroma .mi { color: #009999; } /* LiteralNumberInteger */
.chroma .mo { color: #009999; } /* LiteralNumberOct */ .chroma .mo { color: #009999; } /* LiteralNumberOct */
.chroma .n {} /* Name */
.chroma .na { color: #d73a49; } /* NameAttribute */ .chroma .na { color: #d73a49; } /* NameAttribute */
.chroma .nb { color: #005cc5; } /* NameBuiltin */ .chroma .nb { color: #005cc5; } /* NameBuiltin */
.chroma .nc { color: #445588; } /* NameClass */ .chroma .nc { color: #445588; } /* NameClass */
@ -52,8 +48,6 @@
.chroma .nx { color: #24292e; } /* NameOther */ .chroma .nx { color: #24292e; } /* NameOther */
.chroma .o { color: #d73a49; } /* Operator */ .chroma .o { color: #d73a49; } /* Operator */
.chroma .ow { color: #d73a49; } /* OperatorWord */ .chroma .ow { color: #d73a49; } /* OperatorWord */
.chroma .p {} /* Punctuation */
.chroma .py {} /* NameProperty */
.chroma .s { color: #106303; } /* LiteralString */ .chroma .s { color: #106303; } /* LiteralString */
.chroma .s1 { color: #cc7a00; } /* LiteralStringSingle */ .chroma .s1 { color: #cc7a00; } /* LiteralStringSingle */
.chroma .s2 { color: #106303; } /* LiteralStringDouble */ .chroma .s2 { color: #106303; } /* LiteralStringDouble */
@ -70,5 +64,4 @@
.chroma .vc { color: #008080; } /* NameVariableClass */ .chroma .vc { color: #008080; } /* NameVariableClass */
.chroma .vg { color: #008080; } /* NameVariableGlobal */ .chroma .vg { color: #008080; } /* NameVariableGlobal */
.chroma .vi { color: #008080; } /* NameVariableInstance */ .chroma .vi { color: #008080; } /* NameVariableInstance */
.chroma .vm {} /* NameVariableMagic */
.chroma .w { color: #bbbbbb; } /* TextWhitespace */ .chroma .w { color: #bbbbbb; } /* TextWhitespace */

View File

@ -172,27 +172,6 @@
.gt-py-4 { padding-top: 1rem !important; padding-bottom: 1rem !important; } .gt-py-4 { padding-top: 1rem !important; padding-bottom: 1rem !important; }
.gt-py-5 { padding-top: 2rem !important; padding-bottom: 2rem !important; } .gt-py-5 { padding-top: 2rem !important; padding-bottom: 2rem !important; }
.gt-gap-0 { gap: 0 !important; }
.gt-gap-1 { gap: .125rem !important; }
.gt-gap-2 { gap: .25rem !important; }
.gt-gap-3 { gap: .5rem !important; }
.gt-gap-4 { gap: 1rem !important; }
.gt-gap-5 { gap: 2rem !important; }
.gt-gap-x-0 { column-gap: 0 !important; }
.gt-gap-x-1 { column-gap: .125rem !important; }
.gt-gap-x-2 { column-gap: .25rem !important; }
.gt-gap-x-3 { column-gap: .5rem !important; }
.gt-gap-x-4 { column-gap: 1rem !important; }
.gt-gap-x-5 { column-gap: 2rem !important; }
.gt-gap-y-0 { row-gap: 0 !important; }
.gt-gap-y-1 { row-gap: .125rem !important; }
.gt-gap-y-2 { row-gap: .25rem !important; }
.gt-gap-y-3 { row-gap: .5rem !important; }
.gt-gap-y-4 { row-gap: 1rem !important; }
.gt-gap-y-5 { row-gap: 2rem !important; }
.gt-content-center { align-content: center !important; } .gt-content-center { align-content: center !important; }
@media @mediaSm { @media @mediaSm {

View File

@ -1,4 +1,3 @@
@import "../chroma/base.less";
@import "../chroma/dark.less"; @import "../chroma/dark.less";
@import "../codemirror/dark.less"; @import "../codemirror/dark.less";