Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create invitations for closed registrations #233

Merged
merged 4 commits into from
Apr 2, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Prev Previous commit
Next Next commit
Copy link, dark mode
  • Loading branch information
thomiceli committed Mar 29, 2024
commit dfb363f45b0c381eab63538e5a1c7d39c9b733c9
2 changes: 1 addition & 1 deletion internal/db/invitation.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ func (i *Invitation) Use() error {

func generateRandomCode() string {
const charset = "0123456789ABCDEF"
var seededRand *rand.Rand = rand.New(rand.NewSource(time.Now().UnixNano()))
var seededRand = rand.New(rand.NewSource(time.Now().UnixNano()))
result := make([]byte, 16)

for i := range result {
Expand Down
8 changes: 8 additions & 0 deletions internal/i18n/locales/en-US.yml
Original file line number Diff line number Diff line change
Expand Up @@ -198,3 +198,11 @@ admin.gists.private: Private ?
admin.gists.nb-files: Nb. files
admin.gists.nb-likes: Nb. likes
admin.gists.delete_confirm: Do you want to delete this gist ?

admin.invitations.help: Invitations can be used to create an account even if signing up is disabled.
admin.invitations.max_uses: Max uses
admin.invitations.expires_at: Expires at
admin.invitations.code: Code
admin.invitations.copy_link: Copy link
admin.invitations.uses: Uses
admin.invitations.expired: Expired
16 changes: 1 addition & 15 deletions internal/web/gist.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,21 +73,7 @@ func gistInit(next echo.HandlerFunc) echo.HandlerFunc {
}
}

httpProtocol := "http"
if ctx.Request().TLS != nil || ctx.Request().Header.Get("X-Forwarded-Proto") == "https" {
httpProtocol = "https"
}
setData(ctx, "httpProtocol", strings.ToUpper(httpProtocol))

var baseHttpUrl string
// if a custom external url is set, use it
if config.C.ExternalUrl != "" {
baseHttpUrl = config.C.ExternalUrl
} else {
baseHttpUrl = httpProtocol + ":https://" + ctx.Request().Host
}

setData(ctx, "baseHttpUrl", baseHttpUrl)
baseHttpUrl := getData(ctx, "baseHttpUrl").(string)

if config.C.HttpGit {
setData(ctx, "httpCloneUrl", baseHttpUrl+"/"+userName+"/"+gistName+".git")
Expand Down
16 changes: 16 additions & 0 deletions internal/web/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,22 @@ func dataInit(next echo.HandlerFunc) echo.HandlerFunc {
setData(ctx, "giteaOauth", config.C.GiteaClientKey != "" && config.C.GiteaSecret != "")
setData(ctx, "oidcOauth", config.C.OIDCClientKey != "" && config.C.OIDCSecret != "" && config.C.OIDCDiscoveryUrl != "")

httpProtocol := "http"
if ctx.Request().TLS != nil || ctx.Request().Header.Get("X-Forwarded-Proto") == "https" {
httpProtocol = "https"
}
setData(ctx, "httpProtocol", strings.ToUpper(httpProtocol))

var baseHttpUrl string
// if a custom external url is set, use it
if config.C.ExternalUrl != "" {
baseHttpUrl = config.C.ExternalUrl
} else {
baseHttpUrl = httpProtocol + ":https://" + ctx.Request().Host
}

setData(ctx, "baseHttpUrl", baseHttpUrl)

return next(ctx)
}
}
Expand Down
9 changes: 9 additions & 0 deletions public/admin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,15 @@ document.addEventListener('DOMContentLoaded', () => {
registerDomSetting(elem as HTMLElement)
})
}

let copyInviteButtons = Array.from(document.getElementsByClassName("copy-invitation-link"));
for (let button of copyInviteButtons) {
button.addEventListener('click', () => {
navigator.clipboard.writeText((button as HTMLElement).dataset.link).catch((err) => {
console.error('Could not copy text: ', err);
});
})
}
});

const setSetting = (key: string, value: string) => {
Expand Down
1 change: 1 addition & 0 deletions templates/base/admin_footer.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
{{ template "_pagination" . }}
</div>
{{ end }}
<script src="{{ asset "admin.ts" }}"></script>
</main>
</div>
{{ end }}
2 changes: 0 additions & 2 deletions templates/pages/admin_config.html
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,5 @@
</div>
</div>

<script type="module" src="{{ asset "admin.ts" }}"></script>

{{ template "admin_footer" .}}
{{ template "footer" .}}
32 changes: 22 additions & 10 deletions templates/pages/admin_invitations.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,17 @@
{{ template "admin_header" .}}

<h3 class="text-sm text-gray-600 dark:text-gray-400 italic mb-4">
Invitations can be used to create an account even if signing up is disabled.
{{ .locale.Tr "admin.invitations.help" }}
</h3>

<form method="POST">
<div class="flex space-x-4">
<div class="flex-1">
<label for="nbMax" class="block text-sm font-medium text-slate-700 dark:text-slate-300">Max uses</label>
<label for="nbMax" class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-1">{{ .locale.Tr "admin.invitations.max_uses" }}</label>
<input type="number" id="nbMax" name="nbMax" value="10" min="1" max="100" class="dark:bg-gray-800 appearance-none block w-full px-3 py-2 border border-gray-200 dark:border-gray-700 rounded-md shadow-sm placeholder-gray-600 dark:placeholder-gray-400 focus:outline-none focus:ring-primary-500 focus:border-primary-500 sm:text-sm">
</div>
<div class="flex-1">
<label for="expiresAt" class="block text-sm font-medium text-slate-700 dark:text-slate-300">Expires at</label>
<label for="expiresAt" class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-1">{{ .locale.Tr "admin.invitations.expires_at" }}</label>
<input type="datetime-local" id="expiresAt" name="expiresAt" class="dark:bg-gray-800 appearance-none block w-full px-3 py-2 border border-gray-200 dark:border-gray-700 rounded-md shadow-sm placeholder-gray-600 dark:placeholder-gray-400 focus:outline-none focus:ring-primary-500 focus:border-primary-500 sm:text-sm">
</div>
</div>
Expand All @@ -26,20 +26,32 @@ <h3 class="text-sm text-gray-600 dark:text-gray-400 italic mb-4">
<table class="min-w-full divide-y divide-slate-300 dark:divide-gray-500">
<thead>
<tr>
<th scope="col" class="whitespace-nowrap px-2 py-3.5 text-left text-sm font-semibold text-slate-700 dark:text-slate-300">Code</th>
<th scope="col" class="whitespace-nowrap px-2 py-3.5 text-left text-sm font-semibold text-slate-700 dark:text-slate-300">Uses</th>
<th scope="col" class="whitespace-nowrap px-2 py-3.5 text-left text-sm font-semibold text-slate-700 dark:text-slate-300">Expires at</th>
<th scope="col" class="whitespace-nowrap px-2 py-3.5 text-left text-sm font-semibold text-slate-700 dark:text-slate-300">{{ .locale.Tr "admin.invitations.code" }}</th>
<th scope="col" class="whitespace-nowrap px-2 py-3.5 text-left text-sm font-semibold text-slate-700 dark:text-slate-300">{{ .locale.Tr "admin.invitations.copy_link" }}</th>
<th scope="col" class="whitespace-nowrap px-2 py-3.5 text-left text-sm font-semibold text-slate-700 dark:text-slate-300">{{ .locale.Tr "admin.invitations.uses" }}</th>
<th scope="col" class="whitespace-nowrap px-2 py-3.5 text-left text-sm font-semibold text-slate-700 dark:text-slate-300">{{ .locale.Tr "admin.invitations.expires_at" }}</th>
<th scope="col" class="relative whitespace-nowrap py-3.5 pl-3 pr-4 sm:pr-0">
<span class="sr-only">{{ .locale.Tr "admin.delete" }}</span>
</th>
</tr>
</thead>
<tbody class="divide-y divide-slate-300 dark:divide-gray-500">
{{ range $invitation := .invitations }}
<tr class="{{ if $invitation.IsUsable }}text-slate-700{{ else }}text-gray-300 italic{{ end }}">
<td class="whitespace-nowrap py-2 px-2 text-sm dark:text-slate-300">{{ $invitation.Code }}</td>
<td class="whitespace-nowrap py-2 px-2 text-sm dark:text-slate-300">{{ $invitation.NbUsed }}/{{ $invitation.NbMax }}</td>
<td class="whitespace-nowrap px-2 py-2 text-sm dark:text-slate-300"><span class="moment-timestamp-date">{{ $invitation.ExpiresAt }}</span></td>
<tr class="{{ if $invitation.IsUsable }}text-slate-700 dark:text-slate-100{{ else }}text-gray-300 italic{{ end }}">
<td class="whitespace-nowrap py-2 px-2 text-sm">{{ $invitation.Code }}</td>
<td class="whitespace-nowrap py-2 px-2 text-sm items-center">
{{ if $invitation.IsUsable }}
<span class="copy-invitation-link" data-link="{{ $.baseHttpUrl }}/register?code={{ $invitation.Code }}">
<svg xmlns="http:https://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6 cursor-pointer">
<path stroke-linecap="round" stroke-linejoin="round" d="M8.25 7.5V6.108c0-1.135.845-2.098 1.976-2.192.373-.03.748-.057 1.123-.08M15.75 18H18a2.25 2.25 0 0 0 2.25-2.25V6.108c0-1.135-.845-2.098-1.976-2.192a48.424 48.424 0 0 0-1.123-.08M15.75 18.75v-1.875a3.375 3.375 0 0 0-3.375-3.375h-1.5a1.125 1.125 0 0 1-1.125-1.125v-1.5A3.375 3.375 0 0 0 6.375 7.5H5.25m11.9-3.664A2.251 2.251 0 0 0 15 2.25h-1.5a2.251 2.251 0 0 0-2.15 1.586m5.8 0c.065.21.1.433.1.664v.75h-6V4.5c0-.231.035-.454.1-.664M6.75 7.5H4.875c-.621 0-1.125.504-1.125 1.125v12c0 .621.504 1.125 1.125 1.125h9.75c.621 0 1.125-.504 1.125-1.125V16.5a9 9 0 0 0-9-9Z" />
</svg>
</span>
{{ else }}
<span class="italic">{{ .locale.Tr "admin.invitations.expired" }}</span>
{{ end }}
</td>
<td class="whitespace-nowrap py-2 px-2 text-sm">{{ $invitation.NbUsed }}/{{ $invitation.NbMax }}</td>
<td class="whitespace-nowrap px-2 py-2 text-sm"><span class="moment-timestamp-date">{{ $invitation.ExpiresAt }}</span></td>
<td class="relative whitespace-nowrap py-2 pl-3 pr-4 text-right text-sm font-medium sm:pr-0">
<form action="{{ $.c.ExternalUrl }}/admin-panel/invitations/{{ $invitation.ID }}/delete" method="POST" onsubmit="return confirm('{{ $.locale.Tr "admin.users.delete_confirm" }}')">
{{ $.csrfHtml }}
Expand Down