## Overview
Hi all, I'm a first-time contributor to Forgejo. I was looking for something interesting to contribute and the first thing that caught my attention was https://codeberg.org/forgejo/forgejo/issues/6043, a request for an enhancement to include "issue previews" when publishing links to social media platforms. As a bit of background, the way these platforms work is that they search for meta tags in the posted link's content, and if they find a meta `og:image` (along with other meta tags) they'll pull the image to include in the social media post. Forgejo currently provides an `og:image` tag but it just renders the repository or repository-owner's avatar.
This PR will render `og:image` for an issue or PR into a link to `{...}/summary-card`, which is a dynamically generated image that contains a summary of the issue.
## Design Notes
### Rendering / Rasterization
The tricky part of solving this problem is rendering an image that combines some text, some images, and some layout elements. To address this, I've created a `card` module which allows for a handful of operations:
- Create a new rendered image (a "Card")
- Add a margin to a card
- Split the card, horizontally or vertically, into two pieces with a proportional layout (eg. 70%/30%, as desired), each of which are "Cards" that render into the same root image
- Render text into a card, with line-wrapping and text-alignment capabilities
- Render an image onto a card
- Fetches an external image as safely as possible (for server-side fetch of Gravatar, etc.)
The card module can be reused to create `og:image` summary cards for any object in the future, although obviously it's capabilities are limited. The current implementation is on issues/PRs.
I considered a few alternative approaches before taking this approach, and here's why I rejected those options:
- Provide the summary card as an SVG object which could be rendered much more easily with a template file -- however, support for SVG isn't defined as positive for OpenGraph, and a quick look through some existing implementations suggest that it is not widely supported, if at all
- Rendering as HTML/CSS, or SVG, and then using an external tool to convert into a PNG (or other static) image -- this would be much nicer and easier to implement, but would require tying in some very heavy-weight dependencies
- Rendering using a more sophisticated graphics library, eg. cairo -- also would be nicer and easier to implement, but again a heavy dependency for a small functionality
As a result of the limited capabilities of the new card module, summary cards don't have icons on them (which would require SVG rasterization) or pretty status badges with colors and rounded rects. In the future if better drawing capabilities were added, the graphics could be improved, but it doesn't seem too important.
### External Avatars
In order to rasterize a user's avatar onto the summary card, it might have to be retrieved by the server from the external source (eg. Gravatar). A `fetchExternalImage` routine attempts to do this in the safest way possible to protect the server from any possible security exposure from this; (a) verifying that the content-types are acceptable, (b) ensuring that the file-size and image-size are within the safe bounds that are used for custom avatars, (c) using a very-short timeout to avoid stalling the server if an external dependency is offline.
### Caching
Summary cards are cached after rendered. This has the downside of causing updates to statuses, avatars, titles, etc. being stale on the summary card for the cache TTL. However, during testing I found that some social media engines like Mastodon will cause the summary card to be accessed a significant number of times after being referenced by a post, causing a mini-tornado of requests. The cache compensates for this to avoid server load in this situation.
### Scope
I'm considering out-of-scope:
- Summary cards on other objects (eg. repos, users) can be left for future implementation
## Checklist
The [contributor guide](https://forgejo.org/docs/next/contributor/) contains information that will be helpful to first time contributors. There also are a few [conditions for merging Pull Requests in Forgejo repositories](https://codeberg.org/forgejo/governance/src/branch/main/PullRequestsAgreement.md). You are also welcome to join the [Forgejo development chatroom](https://matrix.to/#/#forgejo-development:matrix.org).
### Tests
- I added test coverage for Go changes...
- [x] in their respective `*_test.go` for unit tests.
- [x] in the `tests/integration` directory if it involves interactions with a live Forgejo server.
- ~~I added test coverage for JavaScript changes...~~ n/a, no JS changes
- [x] ~~in `web_src/js/*.test.js` if it can be unit tested.~~
- [x] ~~in `tests/e2e/*.test.e2e.js` if it requires interactions with a live Forgejo server (see also the [developer guide for JavaScript testing](https://codeberg.org/forgejo/forgejo/src/branch/forgejo/tests/e2e/README.md#end-to-end-tests)).~~
- Manual testing
- [x] Access & attach screenshots of both an issue and a pull-request's summary card; see below
- [x] Ensure reasonable (non-crash) behavior of rendering text with glyphs outside the font -- correctly rendered as replacement unicode chars
- [x] Using a public test instance, verify that og:image behavior looks good on platforms like Mastodon and BlueSky
- [x] Bluesky: ✅
- [x] Mastodon: ✅ (Note that the summary card will be requested many times as the post is federated; either each server, or each client, will fetch it itself)
- [x] OpenGraph test site (https://www.opengraph.xyz/): ✅
- [x] Discord: Looks OK ✅; needs "twitter:card" to be set to "summary_large_image" to display the large-scale image, but (a) that's probably annoying to use, (b) probably wrong because it doesn't match Twitter Card's spec for a "photographic image", and (c) don't want to encourage/continue use of vendor-specific tag
- [x] Verify cases with user avatar missing (or autogen), and repo avatar missing (falls back to repo owner avatar)
Pull request summary card:
![image](/attachments/b64283e3-9a3c-4f19-9d00-961662ffe86b)
Issue summary card:
![image](/attachments/318ce589-02e0-493e-b10c-5b2cb2627db2)
(images to the right are the custom repo avatar, w/ fallback to the repo owner avatar)
### Documentation
- [ ] I created a pull request [to the documentation](https://codeberg.org/forgejo/docs) to explain to Forgejo users how to use this change.
- [x] I did not document these changes and I do not expect someone else to do it.
- OpenGraph capabilities are expected to work in the background without user awareness, and so there is no need for documentation to explain the capabilities for users.
### Release notes
- [ ] I do not want this change to show in the release notes.
- [x] I want the title to show in the release notes with a link to this pull request.
- [ ] I want the content of the `release-notes/<pull request number>.md` to be be used for the release notes instead of the title.
Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/6053
Reviewed-by: Gusted <gusted@noreply.codeberg.org>
Co-authored-by: Mathieu Fenniak <mathieu@fenniak.net>
Co-committed-by: Mathieu Fenniak <mathieu@fenniak.net>
- Instead of having code that relied on the result being sorted (which
wasn't specified in the query and therefore not safe to assume so). Use
a map where it doesn't care if the result that we get from the database
is sorted or not.
- Added unit test.
Functions modifying the labels in the database (DeleteIssueLabel,
NewIssueLabels, NewIssueLabel, ReplaceIssueLabels) need to force
reload them. Instead of:
issue.isLabelsLoaded = false
issue.Labels = nil
if err = issue.LoadLabels(ctx); err != nil {
return err
}
They can now use:
if err = issue.ReloadLabels(ctx); err != nil {
return err
}
When ReplaceIssueLabels calls issue.LoadLabels it was a noop because
issue.isLabelsLoaded is still set to true because of the call to
issue.LoadLabels that was done at the beginning of the function.
(cherry picked from commit f4d3aaeeb9e1b11c5495e4608a3f52f316c35758)
Conflicts:
- modules/charset/charset_test.go
Resolved by manually changing a `=` to `:=`, as per the
original patch. Conflict was due to `require.NoError`.
- Combine review requests comments similairy how labels comments are
combined. If review requests comments were made within 60 seconds of
each other they will be grouped.
- Integration and unit test added.
- Resolves#2774
The Issue and PullRequest list has 3 states:
- open: This lists all open Issues/PullRequests
- closed: This lists all closed Issues/PullRequests
- all: This lists all open and closed Issues/PullRequests
If you want to get to the all state, you need to click Open while in open state or Closed while in closed state, which is very unintuitive. This PR adss a third button to get to this state.
![grafik](/attachments/4ff59e4c-e318-40f0-80ba-f921ce098919)
I'm not sure if the eye icon fits well, but I couldn't find a better one.
Tests will be added once #4124 is merged.
Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/4125
Reviewed-by: Earl Warren <earl-warren@noreply.codeberg.org>
Co-authored-by: JakobDev <jakobdev@gmx.de>
Co-committed-by: JakobDev <jakobdev@gmx.de>
Fix#31423
(cherry picked from commit f4b8f6fc40ce2869135372a5c6ec6418d27ebfba)
Conflicts:
models/fixtures/comment.yml
comment fixtures have to be shifted because there is one more in Forgejo
If the assign the pull request review to a team, it did not show the
members of the team in the "requested_reviewers" field, so the field was
null. As a solution, I added the team members to the array.
fix#31764
(cherry picked from commit 94cca8846e7d62c8a295d70c8199d706dfa60e5c)
Resolves https://github.com/go-gitea/gitea/issues/26996
Added default sorting for milestones by name.
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
---
Conflict resolution: trivial, was due to the improvement made to 'the due
date sorting' strings.
(cherry picked from commit e8d4b7a8b198eca3b0bd117efb422d7d7cac93fe)
fix a bug from #30490
`prs.GetIssueIDs()` will also be used in other places, e.g.
`InvalidateCodeComments`
so we should not add `if pr.Issue == nil` in it, or if `pr.Issue` is
already loaded, you will not get the issueID in the results list and
this is not an expected result.
So this will caused a bug:
before calling `InvalidateCodeComments`, all `pr.Issues` in `prs` are
loaded, so `issueIDs` in this function will always be `[]`.
![image](https://github.com/go-gitea/gitea/assets/18380374/ef94d9d2-0bf9-455a-abd6-4d5e6497db7c)
(cherry picked from commit e61e9a36b7117bab2cb122a95d606a86527ed45d)
Enable [unparam](https://github.com/mvdan/unparam) linter.
Often I could not tell the intention why param is unused, so I put
`//nolint` for those cases like webhook request creation functions never
using `ctx`.
---------
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: delvh <dev.lh@web.de>
(cherry picked from commit fc2d75f86d77b022ece848acf2581c14ef21d43b)
Conflicts:
modules/setting/config_env.go
modules/storage/azureblob.go
services/webhook/dingtalk.go
services/webhook/discord.go
services/webhook/feishu.go
services/webhook/matrix.go
services/webhook/msteams.go
services/webhook/packagist.go
services/webhook/slack.go
services/webhook/telegram.go
services/webhook/wechatwork.go
run make lint-go and fix Forgejo specific warnings
This PR adds some fields to the gitea webhook payload that
[openproject](https://www.openproject.org/) expects to exists in order
to process the webhooks.
These fields do exists in Github's webhook payload so adding them makes
Gitea's native webhook more compatible towards Github's.
Previously, all posters were updated, even if they were not part of
posterMaps. In that case, a ghost user was erroneously inserted.
Fixes#31213.
(cherry picked from commit 3cc7f763c3c22ae4c3b5331f8b72b7009c5b11ea)
fixes#22907
Tested:
- [x] issue content edit
- [x] issue content change tasklist
- [x] pull request content edit
- [x] pull request change tasklist
![issue-content-edit](https://github.com/go-gitea/gitea/assets/29250154/a0828889-fb96-4bc4-8600-da92e3205812)
(cherry picked from commit aa92b13164e84c26be91153b6022220ce0a27720)
Conflicts:
models/issues/comment.go
c7a389f2b2 [FEAT] allow setting the update date on issues and comments
options/locale/locale_en-US.ini
trivial context conflicts
routers/api/v1/repo/issue_comment.go
routers/api/v1/repo/issue_comment_attachment.go
services/issue/comments.go
services/issue/content.go
user blocking is implemented differently in Forgejo
routers/web/repo/issue.go
trivial difference from 6a0750177f Allow to save empty comment
user blocking is implemented differently in Forgejo
templates/repo/issue/view_content/conversation.tmpl
templates changed a lot in Forgejo but the change is
trivially ported
tests/integration/issue_test.go
other tests were added in the same region
web_src/js/features/repo-issue-edit.js
the code is still web_src/js/features/repo-legacy.js
trivially ported
This PR split the `Board` into two parts. One is the struct has been
renamed to `Column` and the second we have a `Template Type`.
But to make it easier to review, this PR will not change the database
schemas, they are just renames. The database schema changes could be in
future PRs.
---------
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: yp05327 <576951401@qq.com>
(cherry picked from commit 98751108b11dc748cc99230ca0fc1acfdf2c8929)
Conflicts:
docs/content/administration/config-cheat-sheet.en-us.md
docs/content/index.en-us.md
docs/content/installation/comparison.en-us.md
docs/content/usage/permissions.en-us.md
non existent files
options/locale/locale_en-US.ini
routers/web/web.go
templates/repo/header.tmpl
templates/repo/settings/options.tmpl
trivial context conflicts
Replace #25741Close#24445Close#30658Close#20646
~Depends on #30805~
Since #25741 has been rewritten totally, to make the contribution
easier, I will continue the work in this PR. Thanks @6543
---------
Co-authored-by: 6543 <6543@obermui.de>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
(cherry picked from commit c6cf96d31d80ab79d370a6192fd761b4443daec2)
Conflicts:
tests/integration/editor_test.go
trivial context conflict because of 75ce1e2ac1 [GITEA] Allow user to select email for file operations in Web UI
tests/integration/pull_merge_test.go
trivial context conflicts in imports because more tests were added in Forgejo
The previous implementation will start multiple POST requests from the
frontend when moving a column and another bug is moving the default
column will never be remembered in fact.
- [x] This PR will allow the default column to move to a non-first
position
- [x] And it also uses one request instead of multiple requests when
moving the columns
- [x] Use a star instead of a pin as the icon for setting the default
column action
- [x] Inserted new column will be append to the end
- [x] Fix#30701 the newly added issue will be append to the end of the
default column
- [x] Fix when deleting a column, all issues in it will be displayed
from UI but database records exist.
- [x] Add a limitation for columns in a project to 20. So the sorting
will not be overflow because it's int8.
---------
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
(cherry picked from commit a303c973e0264dab45a787c4afa200e183e0d953)
Conflicts:
routers/web/web.go
e91733468ef726fc9365aa4820cdd5f2ddfdaa23 Add missing database transaction for new issue (#29490) was not cherry-picked
services/issue/issue.go
fe6792dff3 Enable/disable owner and repo projects independently (#28805) was not cherry-picked
More about codespell: https://github.com/codespell-project/codespell .
I personally introduced it to dozens if not hundreds of projects already and so far only positive feedback.
```
❯ grep lint-spell Makefile
@echo " - lint-spell lint spelling"
@echo " - lint-spell-fix lint spelling and fix issues"
lint: lint-frontend lint-backend lint-spell
lint-fix: lint-frontend-fix lint-backend-fix lint-spell-fix
.PHONY: lint-spell
lint-spell: lint-codespell
.PHONY: lint-spell-fix
lint-spell-fix: lint-codespell-fix
❯ git grep lint- -- .forgejo/
.forgejo/workflows/testing.yml: - run: make --always-make -j$(nproc) lint-backend checks-backend # ensure the "go-licenses" make target runs
.forgejo/workflows/testing.yml: - run: make lint-frontend
```
so how would you like me to invoke `lint-codespell` on CI? (without that would be IMHO very suboptimal and let typos sneak in)
Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/3270
Reviewed-by: Earl Warren <earl-warren@noreply.codeberg.org>
Co-authored-by: Yaroslav Halchenko <debian@onerussian.com>
Co-committed-by: Yaroslav Halchenko <debian@onerussian.com>
Fix#30807
reuse functions in services
(cherry picked from commit a50026e2f30897904704895362da0fb12c7e5b26)
Conflicts:
models/issues/issue_update.go
routers/api/v1/repo/issue.go
trivial context conflict because of 'allow setting the update date on issues and comments'
Resolve all cases for `unused parameter` and `unnecessary type
arguments`
Related: #30729
---------
Co-authored-by: Giteabot <teabot@gitea.io>
(cherry picked from commit e80466f7349164ce4cf3c07bdac30d736d20f035)
Conflicts:
modules/markup/markdown/transform_codespan.go
modules/setting/incoming_email.go
routers/api/v1/admin/user_badge.go
routers/private/hook_pre_receive.go
tests/integration/repo_search_test.go
resolved by discarding the change, this is linting only and
for the sake of avoiding future conflicts
Noteable additions:
- `redefines-builtin-id` forbid variable names that shadow go builtins
- `empty-lines` remove unnecessary empty lines that `gofumpt` does not
remove for some reason
- `superfluous-else` eliminate more superfluous `else` branches
Rules are also sorted alphabetically and I cleaned up various parts of
`.golangci.yml`.
(cherry picked from commit 74f0c84fa4245a20ce6fb87dac1faf2aeeded2a2)
Conflicts:
.golangci.yml
apply the linter recommendations to Forgejo code as well
Many places have the following logic:
```go
func (jobs ActionJobList) GetRunIDs() []int64 {
ids := make(container.Set[int64], len(jobs))
for _, j := range jobs {
if j.RunID == 0 {
continue
}
ids.Add(j.RunID)
}
return ids.Values()
}
```
this introduces a `container.FilterMapUnique` function, which reduces
the code above to:
```go
func (jobs ActionJobList) GetRunIDs() []int64 {
return container.FilterMapUnique(jobs, func(j *ActionRunJob) (int64, bool) {
return j.RunID, j.RunID != 0
})
}
```
Conflicts:
models/issues/comment_list.go due to premature refactor in #3116
* Split TestPullRequest out of AddTestPullRequestTask
* A Created field is added to the Issue table
* The Created field is set to the time (with nano resolution) on creation
* Record the nano time repo_module.PushUpdateOptions is created by the hook
* The decision to update a pull request created before a commit was
pushed is based on the time (with nano resolution) the git hook
was run and the Created field
It ensures the following happens:
* commit C is pushed
* the git hook queues AddTestPullRequestTask for processing and returns with success
* TestPullRequest is not called yet
* a pull request P with commit C as the head is created
* TestPullRequest runs and ignores P because it was created after the commit was received
When the "created" column is NULL, no verification is done, pull
requests that were created before the column was created in the
database cannot be newer than the latest call to a git hook.
Fixes: https://codeberg.org/forgejo/forgejo/issues/2009
This PR do some performance optimzations.
- [x] Add `index` for the column `comment_id` of `Attachment` table to
accelerate query from the database.
- [x] Remove unnecessary database queries when viewing issues. Before
some conditions which id = 0 will be sent to the database
- [x] Remove duplicated load posters
- [x] Batch loading attachements, isread of comments on viewing issue
---------
Co-authored-by: Zettat123 <zettat123@gmail.com>
Conflicts:
models/issues/comment_code.go: function was renamed in Forgejo
models/migrations/migrations.go: migration already ported
This is a squashed result of conflict resolution for the following commits from Gitea:
- 36de5b299b
- 9a93b1816e
- 712e19fa6f
- 83850cc479
It is lacking CSS rule for archived labels, though.
Changes in this commit are authored by:
- 6543
- delvh
- silverwind
Resolves#29965.
---
Manually tested this by:
- Following the
[installation](https://docs.gitea.com/next/installation/install-with-docker#basics)
guide (but built a local Docker image instead)
- Creating 2 users, one who is the `Owner` of a newly-created repository
and the other a `Collaborator`
- Had the `Collaborator` create a PR that the `Owner` reviews
- `Collaborator` resolves conversation and `Owner` merges PR
And with this change we see that we can no longer see re-request review
button for the `Owner`:
<img width="1351" alt="Screenshot 2024-03-25 at 12 39 18 AM"
src="https://github.com/go-gitea/gitea/assets/60799661/bcd9c579-3cf7-474f-a51e-b436fe1a39a4">
(cherry picked from commit 242b331260925e604150346e61329097d5731e77)
On creation of an empty project (no template) a default board will be
created instead of falling back to the uneditable pseudo-board.
Every project now has to have exactly one default boards. As a
consequence, you cannot unset a board as default, instead you have to
set another board as default. Existing projects will be modified using a
cron job, additionally this check will run every midnight by default.
Deleting the default board is not allowed, you have to set another board
as default to do it.
Fixes#29873Fixes#14679 along the way
Fixes#29853
Co-authored-by: delvh <dev.lh@web.de>
(cherry picked from commit e5160185ed65fd1c2bcb2fc7dc7e0b5514ddb299)
Conflicts:
options/locale/locale_en-US.ini
trivial conflict because Forgejo strings do not have
surrounding double quotes