You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

10 jaren geleden
10 jaren geleden
9 jaren geleden
10 jaren geleden
[UI] IssuePage multi repo select (#8741) * Make repository list @ issues/PR page persist Will partially fix #6355 * Enable multiple selections in repo list @ issues/PR page Part of issue #6355 * Add RepoIDs to UserIssueStatsOptions to make "type" count correct when selecting one/multiple repos. * Replace variable "repo" with list "repos[]" and enable multiple selections of repositories from list by including/excluding RepoIDs in list. * * Remove redundant code * Add 'All' button Improves functionality of the page, so that backtracking is not necessary to reset the page * Remove redundant variable Completely replace 'RepoID' with 'RepoIDs' and remove redundant code * Add RepoIDs to label link * Revert part of code to previous version to troubleshoot build failure * Implement old and new pieces of code whilst adhering to multi select * Attempt to join the two versions Last commit passed tests but doesn't work in practice, this works in practice and hopefully passes the tests. * Update tests to desired state * Fix pagination implementation and tests * Pass repoIDs as `repos=[1,2,3...]` instead of several `repos[]=..` * Update tests file to reflect new functionality * Update template with new `repos` format * Implement new solution to show constant "total issues" count for "All" button * Correct behavior when passing zero to array * Comment out test url returning 404 This keeps returning 404 in the test despite working in practice, for the sake of running more tests I am commenting it out * Comment out another test url returning 404 Last attempt, if more tests crash I will uncomment the urls and request assistance. * Reenable tests and test fix * Re-enable tests * Make selecting "In your repositories" reset selection as passing IDs of repos belonging to other profiles causes breakage * Remove unnecessary (with multi-selection enable) code * Drop repo from repo map and total count if permission denied * Remove extra parenthesis * make template work again * find bug! * forgot the '#' at bugfixing * delete unused RepoID * compile regex only one time * make fmt * local variable = capital letter lower * check if repos query pattern is correct * pagination remove last , - make regex work again * use Replace instead of ReplaceAll; del delete * fix test * how did this test binary got in?!? dont forgot the "-p" at git add * ! * dont replace -> cut fisrt & last string Co-Authored-By: zeripath <art27@cantab.net> * jet another regex dont mind as long as it has the same result and is performatn ... Co-Authored-By: zeripath <art27@cantab.net> * dont use nonexisting repo for test * exclude /issues?type=created_by from test * add table to querys use same syntax in each query (table.colum) * add new issue for test * dont make a workaround or something else this need a refactor itself and is out of scope for this PR * fix misspell * CI.redo() * englisch txt update Co-Authored-By: zeripath <art27@cantab.net> * add sugestions * Tweak & Fix * CI.restart()
4 jaren geleden
[UI] IssuePage multi repo select (#8741) * Make repository list @ issues/PR page persist Will partially fix #6355 * Enable multiple selections in repo list @ issues/PR page Part of issue #6355 * Add RepoIDs to UserIssueStatsOptions to make "type" count correct when selecting one/multiple repos. * Replace variable "repo" with list "repos[]" and enable multiple selections of repositories from list by including/excluding RepoIDs in list. * * Remove redundant code * Add 'All' button Improves functionality of the page, so that backtracking is not necessary to reset the page * Remove redundant variable Completely replace 'RepoID' with 'RepoIDs' and remove redundant code * Add RepoIDs to label link * Revert part of code to previous version to troubleshoot build failure * Implement old and new pieces of code whilst adhering to multi select * Attempt to join the two versions Last commit passed tests but doesn't work in practice, this works in practice and hopefully passes the tests. * Update tests to desired state * Fix pagination implementation and tests * Pass repoIDs as `repos=[1,2,3...]` instead of several `repos[]=..` * Update tests file to reflect new functionality * Update template with new `repos` format * Implement new solution to show constant "total issues" count for "All" button * Correct behavior when passing zero to array * Comment out test url returning 404 This keeps returning 404 in the test despite working in practice, for the sake of running more tests I am commenting it out * Comment out another test url returning 404 Last attempt, if more tests crash I will uncomment the urls and request assistance. * Reenable tests and test fix * Re-enable tests * Make selecting "In your repositories" reset selection as passing IDs of repos belonging to other profiles causes breakage * Remove unnecessary (with multi-selection enable) code * Drop repo from repo map and total count if permission denied * Remove extra parenthesis * make template work again * find bug! * forgot the '#' at bugfixing * delete unused RepoID * compile regex only one time * make fmt * local variable = capital letter lower * check if repos query pattern is correct * pagination remove last , - make regex work again * use Replace instead of ReplaceAll; del delete * fix test * how did this test binary got in?!? dont forgot the "-p" at git add * ! * dont replace -> cut fisrt & last string Co-Authored-By: zeripath <art27@cantab.net> * jet another regex dont mind as long as it has the same result and is performatn ... Co-Authored-By: zeripath <art27@cantab.net> * dont use nonexisting repo for test * exclude /issues?type=created_by from test * add table to querys use same syntax in each query (table.colum) * add new issue for test * dont make a workaround or something else this need a refactor itself and is out of scope for this PR * fix misspell * CI.redo() * englisch txt update Co-Authored-By: zeripath <art27@cantab.net> * add sugestions * Tweak & Fix * CI.restart()
4 jaren geleden
10 jaren geleden
Refactor and enhance issue indexer to support both searching, filtering and paging (#26012) Fix #24662. Replace #24822 and #25708 (although it has been merged) ## Background In the past, Gitea supported issue searching with a keyword and conditions in a less efficient way. It worked by searching for issues with the keyword and obtaining limited IDs (as it is heavy to get all) on the indexer (bleve/elasticsearch/meilisearch), and then querying with conditions on the database to find a subset of the found IDs. This is why the results could be incomplete. To solve this issue, we need to store all fields that could be used as conditions in the indexer and support both keyword and additional conditions when searching with the indexer. ## Major changes - Redefine `IndexerData` to include all fields that could be used as filter conditions. - Refactor `Search(ctx context.Context, kw string, repoIDs []int64, limit, start int, state string)` to `Search(ctx context.Context, options *SearchOptions)`, so it supports more conditions now. - Change the data type stored in `issueIndexerQueue`. Use `IndexerMetadata` instead of `IndexerData` in case the data has been updated while it is in the queue. This also reduces the storage size of the queue. - Enhance searching with Bleve/Elasticsearch/Meilisearch, make them fully support `SearchOptions`. Also, update the data versions. - Keep most logic of database indexer, but remove `issues.SearchIssueIDsByKeyword` in `models` to avoid confusion where is the entry point to search issues. - Start a Meilisearch instance to test it in unit tests. - Add unit tests with almost full coverage to test Bleve/Elasticsearch/Meilisearch indexer. --------- Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
11 maanden geleden
issue search on my related repositories (#9758) * adding search capability to user's issues dashboard * global issue search * placement of search bar on issues dashboard * fixed some bugs in the issue dashboard search * added unit test because IssueIDs option was added to UserIssueStatsOptions * some renaming of fields in the issue dashboard code to be more clear; also trying to fix issue of searching the right repos based on the filter * added unit test fro GetRepoIDsForIssuesOptions; fixed search lost on pagination; using shown issue status for open/close count; removed some debugging * fix issue with all count showing incorrectly * removed todo comment left in by mistake * typo pulling wrong count * fxied all count being off when selecting repositories * setting the opts.IsClosed after pulling repos to search, this is done so that the list of repo ids to serach for the keyword is not limited, we need to get all the issue ids for the shown issue stats * added "accessibleRepositoryCondition" check on the query to pull the repo ids to search for issues, this is an added protection to ensure we don't search repos the user does not have access to * added code so that in the issues search, we won't use an in clause of issues ids that goes over 1000 * fixed unit test * using 950 as the limit for issue search, removed unneeded group by in GetRepoIDsForIssuesOptions, showing search on pulls dashboard page too (not just issues) Co-authored-by: guillep2k <18600385+guillep2k@users.noreply.github.com>
4 jaren geleden
10 jaren geleden
8 jaren geleden
10 jaren geleden
10 jaren geleden
[UI] IssuePage multi repo select (#8741) * Make repository list @ issues/PR page persist Will partially fix #6355 * Enable multiple selections in repo list @ issues/PR page Part of issue #6355 * Add RepoIDs to UserIssueStatsOptions to make "type" count correct when selecting one/multiple repos. * Replace variable "repo" with list "repos[]" and enable multiple selections of repositories from list by including/excluding RepoIDs in list. * * Remove redundant code * Add 'All' button Improves functionality of the page, so that backtracking is not necessary to reset the page * Remove redundant variable Completely replace 'RepoID' with 'RepoIDs' and remove redundant code * Add RepoIDs to label link * Revert part of code to previous version to troubleshoot build failure * Implement old and new pieces of code whilst adhering to multi select * Attempt to join the two versions Last commit passed tests but doesn't work in practice, this works in practice and hopefully passes the tests. * Update tests to desired state * Fix pagination implementation and tests * Pass repoIDs as `repos=[1,2,3...]` instead of several `repos[]=..` * Update tests file to reflect new functionality * Update template with new `repos` format * Implement new solution to show constant "total issues" count for "All" button * Correct behavior when passing zero to array * Comment out test url returning 404 This keeps returning 404 in the test despite working in practice, for the sake of running more tests I am commenting it out * Comment out another test url returning 404 Last attempt, if more tests crash I will uncomment the urls and request assistance. * Reenable tests and test fix * Re-enable tests * Make selecting "In your repositories" reset selection as passing IDs of repos belonging to other profiles causes breakage * Remove unnecessary (with multi-selection enable) code * Drop repo from repo map and total count if permission denied * Remove extra parenthesis * make template work again * find bug! * forgot the '#' at bugfixing * delete unused RepoID * compile regex only one time * make fmt * local variable = capital letter lower * check if repos query pattern is correct * pagination remove last , - make regex work again * use Replace instead of ReplaceAll; del delete * fix test * how did this test binary got in?!? dont forgot the "-p" at git add * ! * dont replace -> cut fisrt & last string Co-Authored-By: zeripath <art27@cantab.net> * jet another regex dont mind as long as it has the same result and is performatn ... Co-Authored-By: zeripath <art27@cantab.net> * dont use nonexisting repo for test * exclude /issues?type=created_by from test * add table to querys use same syntax in each query (table.colum) * add new issue for test * dont make a workaround or something else this need a refactor itself and is out of scope for this PR * fix misspell * CI.redo() * englisch txt update Co-Authored-By: zeripath <art27@cantab.net> * add sugestions * Tweak & Fix * CI.restart()
4 jaren geleden
issue search on my related repositories (#9758) * adding search capability to user's issues dashboard * global issue search * placement of search bar on issues dashboard * fixed some bugs in the issue dashboard search * added unit test because IssueIDs option was added to UserIssueStatsOptions * some renaming of fields in the issue dashboard code to be more clear; also trying to fix issue of searching the right repos based on the filter * added unit test fro GetRepoIDsForIssuesOptions; fixed search lost on pagination; using shown issue status for open/close count; removed some debugging * fix issue with all count showing incorrectly * removed todo comment left in by mistake * typo pulling wrong count * fxied all count being off when selecting repositories * setting the opts.IsClosed after pulling repos to search, this is done so that the list of repo ids to serach for the keyword is not limited, we need to get all the issue ids for the shown issue stats * added "accessibleRepositoryCondition" check on the query to pull the repo ids to search for issues, this is an added protection to ensure we don't search repos the user does not have access to * added code so that in the issues search, we won't use an in clause of issues ids that goes over 1000 * fixed unit test * using 950 as the limit for issue search, removed unneeded group by in GetRepoIDsForIssuesOptions, showing search on pulls dashboard page too (not just issues) Co-authored-by: guillep2k <18600385+guillep2k@users.noreply.github.com>
4 jaren geleden
issue search on my related repositories (#9758) * adding search capability to user's issues dashboard * global issue search * placement of search bar on issues dashboard * fixed some bugs in the issue dashboard search * added unit test because IssueIDs option was added to UserIssueStatsOptions * some renaming of fields in the issue dashboard code to be more clear; also trying to fix issue of searching the right repos based on the filter * added unit test fro GetRepoIDsForIssuesOptions; fixed search lost on pagination; using shown issue status for open/close count; removed some debugging * fix issue with all count showing incorrectly * removed todo comment left in by mistake * typo pulling wrong count * fxied all count being off when selecting repositories * setting the opts.IsClosed after pulling repos to search, this is done so that the list of repo ids to serach for the keyword is not limited, we need to get all the issue ids for the shown issue stats * added "accessibleRepositoryCondition" check on the query to pull the repo ids to search for issues, this is an added protection to ensure we don't search repos the user does not have access to * added code so that in the issues search, we won't use an in clause of issues ids that goes over 1000 * fixed unit test * using 950 as the limit for issue search, removed unneeded group by in GetRepoIDsForIssuesOptions, showing search on pulls dashboard page too (not just issues) Co-authored-by: guillep2k <18600385+guillep2k@users.noreply.github.com>
4 jaren geleden
Refactor and enhance issue indexer to support both searching, filtering and paging (#26012) Fix #24662. Replace #24822 and #25708 (although it has been merged) ## Background In the past, Gitea supported issue searching with a keyword and conditions in a less efficient way. It worked by searching for issues with the keyword and obtaining limited IDs (as it is heavy to get all) on the indexer (bleve/elasticsearch/meilisearch), and then querying with conditions on the database to find a subset of the found IDs. This is why the results could be incomplete. To solve this issue, we need to store all fields that could be used as conditions in the indexer and support both keyword and additional conditions when searching with the indexer. ## Major changes - Redefine `IndexerData` to include all fields that could be used as filter conditions. - Refactor `Search(ctx context.Context, kw string, repoIDs []int64, limit, start int, state string)` to `Search(ctx context.Context, options *SearchOptions)`, so it supports more conditions now. - Change the data type stored in `issueIndexerQueue`. Use `IndexerMetadata` instead of `IndexerData` in case the data has been updated while it is in the queue. This also reduces the storage size of the queue. - Enhance searching with Bleve/Elasticsearch/Meilisearch, make them fully support `SearchOptions`. Also, update the data versions. - Keep most logic of database indexer, but remove `issues.SearchIssueIDsByKeyword` in `models` to avoid confusion where is the entry point to search issues. - Start a Meilisearch instance to test it in unit tests. - Add unit tests with almost full coverage to test Bleve/Elasticsearch/Meilisearch indexer. --------- Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
11 maanden geleden
Refactor and enhance issue indexer to support both searching, filtering and paging (#26012) Fix #24662. Replace #24822 and #25708 (although it has been merged) ## Background In the past, Gitea supported issue searching with a keyword and conditions in a less efficient way. It worked by searching for issues with the keyword and obtaining limited IDs (as it is heavy to get all) on the indexer (bleve/elasticsearch/meilisearch), and then querying with conditions on the database to find a subset of the found IDs. This is why the results could be incomplete. To solve this issue, we need to store all fields that could be used as conditions in the indexer and support both keyword and additional conditions when searching with the indexer. ## Major changes - Redefine `IndexerData` to include all fields that could be used as filter conditions. - Refactor `Search(ctx context.Context, kw string, repoIDs []int64, limit, start int, state string)` to `Search(ctx context.Context, options *SearchOptions)`, so it supports more conditions now. - Change the data type stored in `issueIndexerQueue`. Use `IndexerMetadata` instead of `IndexerData` in case the data has been updated while it is in the queue. This also reduces the storage size of the queue. - Enhance searching with Bleve/Elasticsearch/Meilisearch, make them fully support `SearchOptions`. Also, update the data versions. - Keep most logic of database indexer, but remove `issues.SearchIssueIDsByKeyword` in `models` to avoid confusion where is the entry point to search issues. - Start a Meilisearch instance to test it in unit tests. - Add unit tests with almost full coverage to test Bleve/Elasticsearch/Meilisearch indexer. --------- Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
11 maanden geleden
Refactor and enhance issue indexer to support both searching, filtering and paging (#26012) Fix #24662. Replace #24822 and #25708 (although it has been merged) ## Background In the past, Gitea supported issue searching with a keyword and conditions in a less efficient way. It worked by searching for issues with the keyword and obtaining limited IDs (as it is heavy to get all) on the indexer (bleve/elasticsearch/meilisearch), and then querying with conditions on the database to find a subset of the found IDs. This is why the results could be incomplete. To solve this issue, we need to store all fields that could be used as conditions in the indexer and support both keyword and additional conditions when searching with the indexer. ## Major changes - Redefine `IndexerData` to include all fields that could be used as filter conditions. - Refactor `Search(ctx context.Context, kw string, repoIDs []int64, limit, start int, state string)` to `Search(ctx context.Context, options *SearchOptions)`, so it supports more conditions now. - Change the data type stored in `issueIndexerQueue`. Use `IndexerMetadata` instead of `IndexerData` in case the data has been updated while it is in the queue. This also reduces the storage size of the queue. - Enhance searching with Bleve/Elasticsearch/Meilisearch, make them fully support `SearchOptions`. Also, update the data versions. - Keep most logic of database indexer, but remove `issues.SearchIssueIDsByKeyword` in `models` to avoid confusion where is the entry point to search issues. - Start a Meilisearch instance to test it in unit tests. - Add unit tests with almost full coverage to test Bleve/Elasticsearch/Meilisearch indexer. --------- Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
11 maanden geleden
[UI] IssuePage multi repo select (#8741) * Make repository list @ issues/PR page persist Will partially fix #6355 * Enable multiple selections in repo list @ issues/PR page Part of issue #6355 * Add RepoIDs to UserIssueStatsOptions to make "type" count correct when selecting one/multiple repos. * Replace variable "repo" with list "repos[]" and enable multiple selections of repositories from list by including/excluding RepoIDs in list. * * Remove redundant code * Add 'All' button Improves functionality of the page, so that backtracking is not necessary to reset the page * Remove redundant variable Completely replace 'RepoID' with 'RepoIDs' and remove redundant code * Add RepoIDs to label link * Revert part of code to previous version to troubleshoot build failure * Implement old and new pieces of code whilst adhering to multi select * Attempt to join the two versions Last commit passed tests but doesn't work in practice, this works in practice and hopefully passes the tests. * Update tests to desired state * Fix pagination implementation and tests * Pass repoIDs as `repos=[1,2,3...]` instead of several `repos[]=..` * Update tests file to reflect new functionality * Update template with new `repos` format * Implement new solution to show constant "total issues" count for "All" button * Correct behavior when passing zero to array * Comment out test url returning 404 This keeps returning 404 in the test despite working in practice, for the sake of running more tests I am commenting it out * Comment out another test url returning 404 Last attempt, if more tests crash I will uncomment the urls and request assistance. * Reenable tests and test fix * Re-enable tests * Make selecting "In your repositories" reset selection as passing IDs of repos belonging to other profiles causes breakage * Remove unnecessary (with multi-selection enable) code * Drop repo from repo map and total count if permission denied * Remove extra parenthesis * make template work again * find bug! * forgot the '#' at bugfixing * delete unused RepoID * compile regex only one time * make fmt * local variable = capital letter lower * check if repos query pattern is correct * pagination remove last , - make regex work again * use Replace instead of ReplaceAll; del delete * fix test * how did this test binary got in?!? dont forgot the "-p" at git add * ! * dont replace -> cut fisrt & last string Co-Authored-By: zeripath <art27@cantab.net> * jet another regex dont mind as long as it has the same result and is performatn ... Co-Authored-By: zeripath <art27@cantab.net> * dont use nonexisting repo for test * exclude /issues?type=created_by from test * add table to querys use same syntax in each query (table.colum) * add new issue for test * dont make a workaround or something else this need a refactor itself and is out of scope for this PR * fix misspell * CI.redo() * englisch txt update Co-Authored-By: zeripath <art27@cantab.net> * add sugestions * Tweak & Fix * CI.restart()
4 jaren geleden
Refactor and enhance issue indexer to support both searching, filtering and paging (#26012) Fix #24662. Replace #24822 and #25708 (although it has been merged) ## Background In the past, Gitea supported issue searching with a keyword and conditions in a less efficient way. It worked by searching for issues with the keyword and obtaining limited IDs (as it is heavy to get all) on the indexer (bleve/elasticsearch/meilisearch), and then querying with conditions on the database to find a subset of the found IDs. This is why the results could be incomplete. To solve this issue, we need to store all fields that could be used as conditions in the indexer and support both keyword and additional conditions when searching with the indexer. ## Major changes - Redefine `IndexerData` to include all fields that could be used as filter conditions. - Refactor `Search(ctx context.Context, kw string, repoIDs []int64, limit, start int, state string)` to `Search(ctx context.Context, options *SearchOptions)`, so it supports more conditions now. - Change the data type stored in `issueIndexerQueue`. Use `IndexerMetadata` instead of `IndexerData` in case the data has been updated while it is in the queue. This also reduces the storage size of the queue. - Enhance searching with Bleve/Elasticsearch/Meilisearch, make them fully support `SearchOptions`. Also, update the data versions. - Keep most logic of database indexer, but remove `issues.SearchIssueIDsByKeyword` in `models` to avoid confusion where is the entry point to search issues. - Start a Meilisearch instance to test it in unit tests. - Add unit tests with almost full coverage to test Bleve/Elasticsearch/Meilisearch indexer. --------- Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
11 maanden geleden
issue search on my related repositories (#9758) * adding search capability to user's issues dashboard * global issue search * placement of search bar on issues dashboard * fixed some bugs in the issue dashboard search * added unit test because IssueIDs option was added to UserIssueStatsOptions * some renaming of fields in the issue dashboard code to be more clear; also trying to fix issue of searching the right repos based on the filter * added unit test fro GetRepoIDsForIssuesOptions; fixed search lost on pagination; using shown issue status for open/close count; removed some debugging * fix issue with all count showing incorrectly * removed todo comment left in by mistake * typo pulling wrong count * fxied all count being off when selecting repositories * setting the opts.IsClosed after pulling repos to search, this is done so that the list of repo ids to serach for the keyword is not limited, we need to get all the issue ids for the shown issue stats * added "accessibleRepositoryCondition" check on the query to pull the repo ids to search for issues, this is an added protection to ensure we don't search repos the user does not have access to * added code so that in the issues search, we won't use an in clause of issues ids that goes over 1000 * fixed unit test * using 950 as the limit for issue search, removed unneeded group by in GetRepoIDsForIssuesOptions, showing search on pulls dashboard page too (not just issues) Co-authored-by: guillep2k <18600385+guillep2k@users.noreply.github.com>
4 jaren geleden
Refactor and enhance issue indexer to support both searching, filtering and paging (#26012) Fix #24662. Replace #24822 and #25708 (although it has been merged) ## Background In the past, Gitea supported issue searching with a keyword and conditions in a less efficient way. It worked by searching for issues with the keyword and obtaining limited IDs (as it is heavy to get all) on the indexer (bleve/elasticsearch/meilisearch), and then querying with conditions on the database to find a subset of the found IDs. This is why the results could be incomplete. To solve this issue, we need to store all fields that could be used as conditions in the indexer and support both keyword and additional conditions when searching with the indexer. ## Major changes - Redefine `IndexerData` to include all fields that could be used as filter conditions. - Refactor `Search(ctx context.Context, kw string, repoIDs []int64, limit, start int, state string)` to `Search(ctx context.Context, options *SearchOptions)`, so it supports more conditions now. - Change the data type stored in `issueIndexerQueue`. Use `IndexerMetadata` instead of `IndexerData` in case the data has been updated while it is in the queue. This also reduces the storage size of the queue. - Enhance searching with Bleve/Elasticsearch/Meilisearch, make them fully support `SearchOptions`. Also, update the data versions. - Keep most logic of database indexer, but remove `issues.SearchIssueIDsByKeyword` in `models` to avoid confusion where is the entry point to search issues. - Start a Meilisearch instance to test it in unit tests. - Add unit tests with almost full coverage to test Bleve/Elasticsearch/Meilisearch indexer. --------- Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
11 maanden geleden
issue search on my related repositories (#9758) * adding search capability to user's issues dashboard * global issue search * placement of search bar on issues dashboard * fixed some bugs in the issue dashboard search * added unit test because IssueIDs option was added to UserIssueStatsOptions * some renaming of fields in the issue dashboard code to be more clear; also trying to fix issue of searching the right repos based on the filter * added unit test fro GetRepoIDsForIssuesOptions; fixed search lost on pagination; using shown issue status for open/close count; removed some debugging * fix issue with all count showing incorrectly * removed todo comment left in by mistake * typo pulling wrong count * fxied all count being off when selecting repositories * setting the opts.IsClosed after pulling repos to search, this is done so that the list of repo ids to serach for the keyword is not limited, we need to get all the issue ids for the shown issue stats * added "accessibleRepositoryCondition" check on the query to pull the repo ids to search for issues, this is an added protection to ensure we don't search repos the user does not have access to * added code so that in the issues search, we won't use an in clause of issues ids that goes over 1000 * fixed unit test * using 950 as the limit for issue search, removed unneeded group by in GetRepoIDsForIssuesOptions, showing search on pulls dashboard page too (not just issues) Co-authored-by: guillep2k <18600385+guillep2k@users.noreply.github.com>
4 jaren geleden
[UI] IssuePage multi repo select (#8741) * Make repository list @ issues/PR page persist Will partially fix #6355 * Enable multiple selections in repo list @ issues/PR page Part of issue #6355 * Add RepoIDs to UserIssueStatsOptions to make "type" count correct when selecting one/multiple repos. * Replace variable "repo" with list "repos[]" and enable multiple selections of repositories from list by including/excluding RepoIDs in list. * * Remove redundant code * Add 'All' button Improves functionality of the page, so that backtracking is not necessary to reset the page * Remove redundant variable Completely replace 'RepoID' with 'RepoIDs' and remove redundant code * Add RepoIDs to label link * Revert part of code to previous version to troubleshoot build failure * Implement old and new pieces of code whilst adhering to multi select * Attempt to join the two versions Last commit passed tests but doesn't work in practice, this works in practice and hopefully passes the tests. * Update tests to desired state * Fix pagination implementation and tests * Pass repoIDs as `repos=[1,2,3...]` instead of several `repos[]=..` * Update tests file to reflect new functionality * Update template with new `repos` format * Implement new solution to show constant "total issues" count for "All" button * Correct behavior when passing zero to array * Comment out test url returning 404 This keeps returning 404 in the test despite working in practice, for the sake of running more tests I am commenting it out * Comment out another test url returning 404 Last attempt, if more tests crash I will uncomment the urls and request assistance. * Reenable tests and test fix * Re-enable tests * Make selecting "In your repositories" reset selection as passing IDs of repos belonging to other profiles causes breakage * Remove unnecessary (with multi-selection enable) code * Drop repo from repo map and total count if permission denied * Remove extra parenthesis * make template work again * find bug! * forgot the '#' at bugfixing * delete unused RepoID * compile regex only one time * make fmt * local variable = capital letter lower * check if repos query pattern is correct * pagination remove last , - make regex work again * use Replace instead of ReplaceAll; del delete * fix test * how did this test binary got in?!? dont forgot the "-p" at git add * ! * dont replace -> cut fisrt & last string Co-Authored-By: zeripath <art27@cantab.net> * jet another regex dont mind as long as it has the same result and is performatn ... Co-Authored-By: zeripath <art27@cantab.net> * dont use nonexisting repo for test * exclude /issues?type=created_by from test * add table to querys use same syntax in each query (table.colum) * add new issue for test * dont make a workaround or something else this need a refactor itself and is out of scope for this PR * fix misspell * CI.redo() * englisch txt update Co-Authored-By: zeripath <art27@cantab.net> * add sugestions * Tweak & Fix * CI.restart()
4 jaren geleden
[UI] IssuePage multi repo select (#8741) * Make repository list @ issues/PR page persist Will partially fix #6355 * Enable multiple selections in repo list @ issues/PR page Part of issue #6355 * Add RepoIDs to UserIssueStatsOptions to make "type" count correct when selecting one/multiple repos. * Replace variable "repo" with list "repos[]" and enable multiple selections of repositories from list by including/excluding RepoIDs in list. * * Remove redundant code * Add 'All' button Improves functionality of the page, so that backtracking is not necessary to reset the page * Remove redundant variable Completely replace 'RepoID' with 'RepoIDs' and remove redundant code * Add RepoIDs to label link * Revert part of code to previous version to troubleshoot build failure * Implement old and new pieces of code whilst adhering to multi select * Attempt to join the two versions Last commit passed tests but doesn't work in practice, this works in practice and hopefully passes the tests. * Update tests to desired state * Fix pagination implementation and tests * Pass repoIDs as `repos=[1,2,3...]` instead of several `repos[]=..` * Update tests file to reflect new functionality * Update template with new `repos` format * Implement new solution to show constant "total issues" count for "All" button * Correct behavior when passing zero to array * Comment out test url returning 404 This keeps returning 404 in the test despite working in practice, for the sake of running more tests I am commenting it out * Comment out another test url returning 404 Last attempt, if more tests crash I will uncomment the urls and request assistance. * Reenable tests and test fix * Re-enable tests * Make selecting "In your repositories" reset selection as passing IDs of repos belonging to other profiles causes breakage * Remove unnecessary (with multi-selection enable) code * Drop repo from repo map and total count if permission denied * Remove extra parenthesis * make template work again * find bug! * forgot the '#' at bugfixing * delete unused RepoID * compile regex only one time * make fmt * local variable = capital letter lower * check if repos query pattern is correct * pagination remove last , - make regex work again * use Replace instead of ReplaceAll; del delete * fix test * how did this test binary got in?!? dont forgot the "-p" at git add * ! * dont replace -> cut fisrt & last string Co-Authored-By: zeripath <art27@cantab.net> * jet another regex dont mind as long as it has the same result and is performatn ... Co-Authored-By: zeripath <art27@cantab.net> * dont use nonexisting repo for test * exclude /issues?type=created_by from test * add table to querys use same syntax in each query (table.colum) * add new issue for test * dont make a workaround or something else this need a refactor itself and is out of scope for this PR * fix misspell * CI.redo() * englisch txt update Co-Authored-By: zeripath <art27@cantab.net> * add sugestions * Tweak & Fix * CI.restart()
4 jaren geleden
Refactor and enhance issue indexer to support both searching, filtering and paging (#26012) Fix #24662. Replace #24822 and #25708 (although it has been merged) ## Background In the past, Gitea supported issue searching with a keyword and conditions in a less efficient way. It worked by searching for issues with the keyword and obtaining limited IDs (as it is heavy to get all) on the indexer (bleve/elasticsearch/meilisearch), and then querying with conditions on the database to find a subset of the found IDs. This is why the results could be incomplete. To solve this issue, we need to store all fields that could be used as conditions in the indexer and support both keyword and additional conditions when searching with the indexer. ## Major changes - Redefine `IndexerData` to include all fields that could be used as filter conditions. - Refactor `Search(ctx context.Context, kw string, repoIDs []int64, limit, start int, state string)` to `Search(ctx context.Context, options *SearchOptions)`, so it supports more conditions now. - Change the data type stored in `issueIndexerQueue`. Use `IndexerMetadata` instead of `IndexerData` in case the data has been updated while it is in the queue. This also reduces the storage size of the queue. - Enhance searching with Bleve/Elasticsearch/Meilisearch, make them fully support `SearchOptions`. Also, update the data versions. - Keep most logic of database indexer, but remove `issues.SearchIssueIDsByKeyword` in `models` to avoid confusion where is the entry point to search issues. - Start a Meilisearch instance to test it in unit tests. - Add unit tests with almost full coverage to test Bleve/Elasticsearch/Meilisearch indexer. --------- Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
11 maanden geleden
Refactor and enhance issue indexer to support both searching, filtering and paging (#26012) Fix #24662. Replace #24822 and #25708 (although it has been merged) ## Background In the past, Gitea supported issue searching with a keyword and conditions in a less efficient way. It worked by searching for issues with the keyword and obtaining limited IDs (as it is heavy to get all) on the indexer (bleve/elasticsearch/meilisearch), and then querying with conditions on the database to find a subset of the found IDs. This is why the results could be incomplete. To solve this issue, we need to store all fields that could be used as conditions in the indexer and support both keyword and additional conditions when searching with the indexer. ## Major changes - Redefine `IndexerData` to include all fields that could be used as filter conditions. - Refactor `Search(ctx context.Context, kw string, repoIDs []int64, limit, start int, state string)` to `Search(ctx context.Context, options *SearchOptions)`, so it supports more conditions now. - Change the data type stored in `issueIndexerQueue`. Use `IndexerMetadata` instead of `IndexerData` in case the data has been updated while it is in the queue. This also reduces the storage size of the queue. - Enhance searching with Bleve/Elasticsearch/Meilisearch, make them fully support `SearchOptions`. Also, update the data versions. - Keep most logic of database indexer, but remove `issues.SearchIssueIDsByKeyword` in `models` to avoid confusion where is the entry point to search issues. - Start a Meilisearch instance to test it in unit tests. - Add unit tests with almost full coverage to test Bleve/Elasticsearch/Meilisearch indexer. --------- Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
11 maanden geleden
[UI] IssuePage multi repo select (#8741) * Make repository list @ issues/PR page persist Will partially fix #6355 * Enable multiple selections in repo list @ issues/PR page Part of issue #6355 * Add RepoIDs to UserIssueStatsOptions to make "type" count correct when selecting one/multiple repos. * Replace variable "repo" with list "repos[]" and enable multiple selections of repositories from list by including/excluding RepoIDs in list. * * Remove redundant code * Add 'All' button Improves functionality of the page, so that backtracking is not necessary to reset the page * Remove redundant variable Completely replace 'RepoID' with 'RepoIDs' and remove redundant code * Add RepoIDs to label link * Revert part of code to previous version to troubleshoot build failure * Implement old and new pieces of code whilst adhering to multi select * Attempt to join the two versions Last commit passed tests but doesn't work in practice, this works in practice and hopefully passes the tests. * Update tests to desired state * Fix pagination implementation and tests * Pass repoIDs as `repos=[1,2,3...]` instead of several `repos[]=..` * Update tests file to reflect new functionality * Update template with new `repos` format * Implement new solution to show constant "total issues" count for "All" button * Correct behavior when passing zero to array * Comment out test url returning 404 This keeps returning 404 in the test despite working in practice, for the sake of running more tests I am commenting it out * Comment out another test url returning 404 Last attempt, if more tests crash I will uncomment the urls and request assistance. * Reenable tests and test fix * Re-enable tests * Make selecting "In your repositories" reset selection as passing IDs of repos belonging to other profiles causes breakage * Remove unnecessary (with multi-selection enable) code * Drop repo from repo map and total count if permission denied * Remove extra parenthesis * make template work again * find bug! * forgot the '#' at bugfixing * delete unused RepoID * compile regex only one time * make fmt * local variable = capital letter lower * check if repos query pattern is correct * pagination remove last , - make regex work again * use Replace instead of ReplaceAll; del delete * fix test * how did this test binary got in?!? dont forgot the "-p" at git add * ! * dont replace -> cut fisrt & last string Co-Authored-By: zeripath <art27@cantab.net> * jet another regex dont mind as long as it has the same result and is performatn ... Co-Authored-By: zeripath <art27@cantab.net> * dont use nonexisting repo for test * exclude /issues?type=created_by from test * add table to querys use same syntax in each query (table.colum) * add new issue for test * dont make a workaround or something else this need a refactor itself and is out of scope for this PR * fix misspell * CI.redo() * englisch txt update Co-Authored-By: zeripath <art27@cantab.net> * add sugestions * Tweak & Fix * CI.restart()
4 jaren geleden
[UI] IssuePage multi repo select (#8741) * Make repository list @ issues/PR page persist Will partially fix #6355 * Enable multiple selections in repo list @ issues/PR page Part of issue #6355 * Add RepoIDs to UserIssueStatsOptions to make "type" count correct when selecting one/multiple repos. * Replace variable "repo" with list "repos[]" and enable multiple selections of repositories from list by including/excluding RepoIDs in list. * * Remove redundant code * Add 'All' button Improves functionality of the page, so that backtracking is not necessary to reset the page * Remove redundant variable Completely replace 'RepoID' with 'RepoIDs' and remove redundant code * Add RepoIDs to label link * Revert part of code to previous version to troubleshoot build failure * Implement old and new pieces of code whilst adhering to multi select * Attempt to join the two versions Last commit passed tests but doesn't work in practice, this works in practice and hopefully passes the tests. * Update tests to desired state * Fix pagination implementation and tests * Pass repoIDs as `repos=[1,2,3...]` instead of several `repos[]=..` * Update tests file to reflect new functionality * Update template with new `repos` format * Implement new solution to show constant "total issues" count for "All" button * Correct behavior when passing zero to array * Comment out test url returning 404 This keeps returning 404 in the test despite working in practice, for the sake of running more tests I am commenting it out * Comment out another test url returning 404 Last attempt, if more tests crash I will uncomment the urls and request assistance. * Reenable tests and test fix * Re-enable tests * Make selecting "In your repositories" reset selection as passing IDs of repos belonging to other profiles causes breakage * Remove unnecessary (with multi-selection enable) code * Drop repo from repo map and total count if permission denied * Remove extra parenthesis * make template work again * find bug! * forgot the '#' at bugfixing * delete unused RepoID * compile regex only one time * make fmt * local variable = capital letter lower * check if repos query pattern is correct * pagination remove last , - make regex work again * use Replace instead of ReplaceAll; del delete * fix test * how did this test binary got in?!? dont forgot the "-p" at git add * ! * dont replace -> cut fisrt & last string Co-Authored-By: zeripath <art27@cantab.net> * jet another regex dont mind as long as it has the same result and is performatn ... Co-Authored-By: zeripath <art27@cantab.net> * dont use nonexisting repo for test * exclude /issues?type=created_by from test * add table to querys use same syntax in each query (table.colum) * add new issue for test * dont make a workaround or something else this need a refactor itself and is out of scope for this PR * fix misspell * CI.redo() * englisch txt update Co-Authored-By: zeripath <art27@cantab.net> * add sugestions * Tweak & Fix * CI.restart()
4 jaren geleden
issue search on my related repositories (#9758) * adding search capability to user's issues dashboard * global issue search * placement of search bar on issues dashboard * fixed some bugs in the issue dashboard search * added unit test because IssueIDs option was added to UserIssueStatsOptions * some renaming of fields in the issue dashboard code to be more clear; also trying to fix issue of searching the right repos based on the filter * added unit test fro GetRepoIDsForIssuesOptions; fixed search lost on pagination; using shown issue status for open/close count; removed some debugging * fix issue with all count showing incorrectly * removed todo comment left in by mistake * typo pulling wrong count * fxied all count being off when selecting repositories * setting the opts.IsClosed after pulling repos to search, this is done so that the list of repo ids to serach for the keyword is not limited, we need to get all the issue ids for the shown issue stats * added "accessibleRepositoryCondition" check on the query to pull the repo ids to search for issues, this is an added protection to ensure we don't search repos the user does not have access to * added code so that in the issues search, we won't use an in clause of issues ids that goes over 1000 * fixed unit test * using 950 as the limit for issue search, removed unneeded group by in GetRepoIDsForIssuesOptions, showing search on pulls dashboard page too (not just issues) Co-authored-by: guillep2k <18600385+guillep2k@users.noreply.github.com>
4 jaren geleden
[UI] IssuePage multi repo select (#8741) * Make repository list @ issues/PR page persist Will partially fix #6355 * Enable multiple selections in repo list @ issues/PR page Part of issue #6355 * Add RepoIDs to UserIssueStatsOptions to make "type" count correct when selecting one/multiple repos. * Replace variable "repo" with list "repos[]" and enable multiple selections of repositories from list by including/excluding RepoIDs in list. * * Remove redundant code * Add 'All' button Improves functionality of the page, so that backtracking is not necessary to reset the page * Remove redundant variable Completely replace 'RepoID' with 'RepoIDs' and remove redundant code * Add RepoIDs to label link * Revert part of code to previous version to troubleshoot build failure * Implement old and new pieces of code whilst adhering to multi select * Attempt to join the two versions Last commit passed tests but doesn't work in practice, this works in practice and hopefully passes the tests. * Update tests to desired state * Fix pagination implementation and tests * Pass repoIDs as `repos=[1,2,3...]` instead of several `repos[]=..` * Update tests file to reflect new functionality * Update template with new `repos` format * Implement new solution to show constant "total issues" count for "All" button * Correct behavior when passing zero to array * Comment out test url returning 404 This keeps returning 404 in the test despite working in practice, for the sake of running more tests I am commenting it out * Comment out another test url returning 404 Last attempt, if more tests crash I will uncomment the urls and request assistance. * Reenable tests and test fix * Re-enable tests * Make selecting "In your repositories" reset selection as passing IDs of repos belonging to other profiles causes breakage * Remove unnecessary (with multi-selection enable) code * Drop repo from repo map and total count if permission denied * Remove extra parenthesis * make template work again * find bug! * forgot the '#' at bugfixing * delete unused RepoID * compile regex only one time * make fmt * local variable = capital letter lower * check if repos query pattern is correct * pagination remove last , - make regex work again * use Replace instead of ReplaceAll; del delete * fix test * how did this test binary got in?!? dont forgot the "-p" at git add * ! * dont replace -> cut fisrt & last string Co-Authored-By: zeripath <art27@cantab.net> * jet another regex dont mind as long as it has the same result and is performatn ... Co-Authored-By: zeripath <art27@cantab.net> * dont use nonexisting repo for test * exclude /issues?type=created_by from test * add table to querys use same syntax in each query (table.colum) * add new issue for test * dont make a workaround or something else this need a refactor itself and is out of scope for this PR * fix misspell * CI.redo() * englisch txt update Co-Authored-By: zeripath <art27@cantab.net> * add sugestions * Tweak & Fix * CI.restart()
4 jaren geleden
7 jaren geleden
9 jaren geleden
9 jaren geleden
9 jaren geleden
9 jaren geleden
Fix inconsistent user profile layout across tabs (#25625) Fix ::User Profile Page Project Tab Have Inconsistent Layout and Style Added the big_avator for consistency in the all header_items tabs. Fixes: #24871 > ### Description > in the user profile page the `Packages` and `Projects` tab have small icons for user but other tabs have bigger profile picture with user info: > > ### Screenshots > ### **For Packages And Projects:** > ![image](https://user-images.githubusercontent.com/25511175/240148601-2420d77b-ba25-4718-9ccb-c5d0d95e3079.png) > > ### **For Other Tabs:** > ![image](https://user-images.githubusercontent.com/25511175/240148461-ce9636b3-fe11-4c46-a230-30d83eee5947.png) > ## Before ![image](https://github.com/go-gitea/gitea/assets/80308335/975ad038-07ca-4b10-b75d-ccf259be7b9d) ## After changes Project View <img width="1394" alt="image" src="https://github.com/go-gitea/gitea/assets/80308335/95d181d7-8e61-496d-9899-7b825c91ad56"> Packages View <img width="1378" alt="image" src="https://github.com/go-gitea/gitea/assets/80308335/7f5fd60f-6b18-4fa8-8c56-7b0d45d1a610"> ## Org view for projects page <img width="1385" alt="image" src="https://github.com/go-gitea/gitea/assets/80308335/6400dc89-a5ae-4f0a-831b-5b6efa020d89"> ## Org view for packages page <img width="1387" alt="image" src="https://github.com/go-gitea/gitea/assets/80308335/4e1e9ffe-1e4b-4334-8657-de11b5fd31d0"> --------- Co-authored-by: wxiaoguang <wxiaoguang@gmail.com> Co-authored-by: Giteabot <teabot@gitea.io> Co-authored-by: silverwind <me@silverwind.io>
1 jaar geleden
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937
  1. // Copyright 2014 The Gogs Authors. All rights reserved.
  2. // Copyright 2019 The Gitea Authors. All rights reserved.
  3. // SPDX-License-Identifier: MIT
  4. package user
  5. import (
  6. "bytes"
  7. "fmt"
  8. "net/http"
  9. "regexp"
  10. "slices"
  11. "sort"
  12. "strconv"
  13. "strings"
  14. activities_model "code.gitea.io/gitea/models/activities"
  15. asymkey_model "code.gitea.io/gitea/models/asymkey"
  16. "code.gitea.io/gitea/models/db"
  17. issues_model "code.gitea.io/gitea/models/issues"
  18. "code.gitea.io/gitea/models/organization"
  19. repo_model "code.gitea.io/gitea/models/repo"
  20. "code.gitea.io/gitea/models/unit"
  21. user_model "code.gitea.io/gitea/models/user"
  22. "code.gitea.io/gitea/modules/base"
  23. "code.gitea.io/gitea/modules/container"
  24. "code.gitea.io/gitea/modules/context"
  25. issue_indexer "code.gitea.io/gitea/modules/indexer/issues"
  26. "code.gitea.io/gitea/modules/json"
  27. "code.gitea.io/gitea/modules/log"
  28. "code.gitea.io/gitea/modules/markup"
  29. "code.gitea.io/gitea/modules/markup/markdown"
  30. "code.gitea.io/gitea/modules/setting"
  31. "code.gitea.io/gitea/modules/util"
  32. "code.gitea.io/gitea/routers/web/feed"
  33. context_service "code.gitea.io/gitea/services/context"
  34. issue_service "code.gitea.io/gitea/services/issue"
  35. pull_service "code.gitea.io/gitea/services/pull"
  36. "github.com/keybase/go-crypto/openpgp"
  37. "github.com/keybase/go-crypto/openpgp/armor"
  38. "xorm.io/builder"
  39. )
  40. const (
  41. tplDashboard base.TplName = "user/dashboard/dashboard"
  42. tplIssues base.TplName = "user/dashboard/issues"
  43. tplMilestones base.TplName = "user/dashboard/milestones"
  44. tplProfile base.TplName = "user/profile"
  45. )
  46. // getDashboardContextUser finds out which context user dashboard is being viewed as .
  47. func getDashboardContextUser(ctx *context.Context) *user_model.User {
  48. ctxUser := ctx.Doer
  49. orgName := ctx.Params(":org")
  50. if len(orgName) > 0 {
  51. ctxUser = ctx.Org.Organization.AsUser()
  52. ctx.Data["Teams"] = ctx.Org.Teams
  53. }
  54. ctx.Data["ContextUser"] = ctxUser
  55. orgs, err := organization.GetUserOrgsList(ctx, ctx.Doer)
  56. if err != nil {
  57. ctx.ServerError("GetUserOrgsList", err)
  58. return nil
  59. }
  60. ctx.Data["Orgs"] = orgs
  61. return ctxUser
  62. }
  63. // Dashboard render the dashboard page
  64. func Dashboard(ctx *context.Context) {
  65. ctxUser := getDashboardContextUser(ctx)
  66. if ctx.Written() {
  67. return
  68. }
  69. var (
  70. date = ctx.FormString("date")
  71. page = ctx.FormInt("page")
  72. )
  73. // Make sure page number is at least 1. Will be posted to ctx.Data.
  74. if page <= 1 {
  75. page = 1
  76. }
  77. ctx.Data["Title"] = ctxUser.DisplayName() + " - " + ctx.Tr("dashboard")
  78. ctx.Data["PageIsDashboard"] = true
  79. ctx.Data["PageIsNews"] = true
  80. cnt, _ := organization.GetOrganizationCount(ctx, ctxUser)
  81. ctx.Data["UserOrgsCount"] = cnt
  82. ctx.Data["MirrorsEnabled"] = setting.Mirror.Enabled
  83. ctx.Data["Date"] = date
  84. var uid int64
  85. if ctxUser != nil {
  86. uid = ctxUser.ID
  87. }
  88. ctx.PageData["dashboardRepoList"] = map[string]any{
  89. "searchLimit": setting.UI.User.RepoPagingNum,
  90. "uid": uid,
  91. }
  92. if setting.Service.EnableUserHeatmap {
  93. data, err := activities_model.GetUserHeatmapDataByUserTeam(ctx, ctxUser, ctx.Org.Team, ctx.Doer)
  94. if err != nil {
  95. ctx.ServerError("GetUserHeatmapDataByUserTeam", err)
  96. return
  97. }
  98. ctx.Data["HeatmapData"] = data
  99. ctx.Data["HeatmapTotalContributions"] = activities_model.GetTotalContributionsInHeatmap(data)
  100. }
  101. feeds, count, err := activities_model.GetFeeds(ctx, activities_model.GetFeedsOptions{
  102. RequestedUser: ctxUser,
  103. RequestedTeam: ctx.Org.Team,
  104. Actor: ctx.Doer,
  105. IncludePrivate: true,
  106. OnlyPerformedBy: false,
  107. IncludeDeleted: false,
  108. Date: ctx.FormString("date"),
  109. ListOptions: db.ListOptions{
  110. Page: page,
  111. PageSize: setting.UI.FeedPagingNum,
  112. },
  113. })
  114. if err != nil {
  115. ctx.ServerError("GetFeeds", err)
  116. return
  117. }
  118. ctx.Data["Feeds"] = feeds
  119. pager := context.NewPagination(int(count), setting.UI.FeedPagingNum, page, 5)
  120. pager.AddParam(ctx, "date", "Date")
  121. ctx.Data["Page"] = pager
  122. ctx.HTML(http.StatusOK, tplDashboard)
  123. }
  124. // Milestones render the user milestones page
  125. func Milestones(ctx *context.Context) {
  126. if unit.TypeIssues.UnitGlobalDisabled() && unit.TypePullRequests.UnitGlobalDisabled() {
  127. log.Debug("Milestones overview page not available as both issues and pull requests are globally disabled")
  128. ctx.Status(http.StatusNotFound)
  129. return
  130. }
  131. ctx.Data["Title"] = ctx.Tr("milestones")
  132. ctx.Data["PageIsMilestonesDashboard"] = true
  133. ctxUser := getDashboardContextUser(ctx)
  134. if ctx.Written() {
  135. return
  136. }
  137. repoOpts := repo_model.SearchRepoOptions{
  138. Actor: ctx.Doer,
  139. OwnerID: ctxUser.ID,
  140. Private: true,
  141. AllPublic: false, // Include also all public repositories of users and public organisations
  142. AllLimited: false, // Include also all public repositories of limited organisations
  143. Archived: util.OptionalBoolFalse,
  144. HasMilestones: util.OptionalBoolTrue, // Just needs display repos has milestones
  145. }
  146. if ctxUser.IsOrganization() && ctx.Org.Team != nil {
  147. repoOpts.TeamID = ctx.Org.Team.ID
  148. }
  149. var (
  150. userRepoCond = repo_model.SearchRepositoryCondition(&repoOpts) // all repo condition user could visit
  151. repoCond = userRepoCond
  152. repoIDs []int64
  153. reposQuery = ctx.FormString("repos")
  154. isShowClosed = ctx.FormString("state") == "closed"
  155. sortType = ctx.FormString("sort")
  156. page = ctx.FormInt("page")
  157. keyword = ctx.FormTrim("q")
  158. )
  159. if page <= 1 {
  160. page = 1
  161. }
  162. if len(reposQuery) != 0 {
  163. if issueReposQueryPattern.MatchString(reposQuery) {
  164. // remove "[" and "]" from string
  165. reposQuery = reposQuery[1 : len(reposQuery)-1]
  166. // for each ID (delimiter ",") add to int to repoIDs
  167. for _, rID := range strings.Split(reposQuery, ",") {
  168. // Ensure nonempty string entries
  169. if rID != "" && rID != "0" {
  170. rIDint64, err := strconv.ParseInt(rID, 10, 64)
  171. // If the repo id specified by query is not parseable or not accessible by user, just ignore it.
  172. if err == nil {
  173. repoIDs = append(repoIDs, rIDint64)
  174. }
  175. }
  176. }
  177. if len(repoIDs) > 0 {
  178. // Don't just let repoCond = builder.In("id", repoIDs) because user may has no permission on repoIDs
  179. // But the original repoCond has a limitation
  180. repoCond = repoCond.And(builder.In("id", repoIDs))
  181. }
  182. } else {
  183. log.Warn("issueReposQueryPattern not match with query")
  184. }
  185. }
  186. counts, err := issues_model.CountMilestonesByRepoCondAndKw(ctx, userRepoCond, keyword, isShowClosed)
  187. if err != nil {
  188. ctx.ServerError("CountMilestonesByRepoIDs", err)
  189. return
  190. }
  191. milestones, err := issues_model.SearchMilestones(ctx, repoCond, page, isShowClosed, sortType, keyword)
  192. if err != nil {
  193. ctx.ServerError("SearchMilestones", err)
  194. return
  195. }
  196. showRepos, _, err := repo_model.SearchRepositoryByCondition(ctx, &repoOpts, userRepoCond, false)
  197. if err != nil {
  198. ctx.ServerError("SearchRepositoryByCondition", err)
  199. return
  200. }
  201. sort.Sort(showRepos)
  202. for i := 0; i < len(milestones); {
  203. for _, repo := range showRepos {
  204. if milestones[i].RepoID == repo.ID {
  205. milestones[i].Repo = repo
  206. break
  207. }
  208. }
  209. if milestones[i].Repo == nil {
  210. log.Warn("Cannot find milestone %d 's repository %d", milestones[i].ID, milestones[i].RepoID)
  211. milestones = append(milestones[:i], milestones[i+1:]...)
  212. continue
  213. }
  214. milestones[i].RenderedContent, err = markdown.RenderString(&markup.RenderContext{
  215. URLPrefix: milestones[i].Repo.Link(),
  216. Metas: milestones[i].Repo.ComposeMetas(),
  217. Ctx: ctx,
  218. }, milestones[i].Content)
  219. if err != nil {
  220. ctx.ServerError("RenderString", err)
  221. return
  222. }
  223. if milestones[i].Repo.IsTimetrackerEnabled(ctx) {
  224. err := milestones[i].LoadTotalTrackedTime(ctx)
  225. if err != nil {
  226. ctx.ServerError("LoadTotalTrackedTime", err)
  227. return
  228. }
  229. }
  230. i++
  231. }
  232. milestoneStats, err := issues_model.GetMilestonesStatsByRepoCondAndKw(ctx, repoCond, keyword)
  233. if err != nil {
  234. ctx.ServerError("GetMilestoneStats", err)
  235. return
  236. }
  237. var totalMilestoneStats *issues_model.MilestonesStats
  238. if len(repoIDs) == 0 {
  239. totalMilestoneStats = milestoneStats
  240. } else {
  241. totalMilestoneStats, err = issues_model.GetMilestonesStatsByRepoCondAndKw(ctx, userRepoCond, keyword)
  242. if err != nil {
  243. ctx.ServerError("GetMilestoneStats", err)
  244. return
  245. }
  246. }
  247. showRepoIds := make(container.Set[int64], len(showRepos))
  248. for _, repo := range showRepos {
  249. if repo.ID > 0 {
  250. showRepoIds.Add(repo.ID)
  251. }
  252. }
  253. if len(repoIDs) == 0 {
  254. repoIDs = showRepoIds.Values()
  255. }
  256. repoIDs = slices.DeleteFunc(repoIDs, func(v int64) bool {
  257. return !showRepoIds.Contains(v)
  258. })
  259. var pagerCount int
  260. if isShowClosed {
  261. ctx.Data["State"] = "closed"
  262. ctx.Data["Total"] = totalMilestoneStats.ClosedCount
  263. pagerCount = int(milestoneStats.ClosedCount)
  264. } else {
  265. ctx.Data["State"] = "open"
  266. ctx.Data["Total"] = totalMilestoneStats.OpenCount
  267. pagerCount = int(milestoneStats.OpenCount)
  268. }
  269. ctx.Data["Milestones"] = milestones
  270. ctx.Data["Repos"] = showRepos
  271. ctx.Data["Counts"] = counts
  272. ctx.Data["MilestoneStats"] = milestoneStats
  273. ctx.Data["SortType"] = sortType
  274. ctx.Data["Keyword"] = keyword
  275. ctx.Data["RepoIDs"] = repoIDs
  276. ctx.Data["IsShowClosed"] = isShowClosed
  277. pager := context.NewPagination(pagerCount, setting.UI.IssuePagingNum, page, 5)
  278. pager.AddParam(ctx, "q", "Keyword")
  279. pager.AddParam(ctx, "repos", "RepoIDs")
  280. pager.AddParam(ctx, "sort", "SortType")
  281. pager.AddParam(ctx, "state", "State")
  282. ctx.Data["Page"] = pager
  283. ctx.HTML(http.StatusOK, tplMilestones)
  284. }
  285. // Pulls renders the user's pull request overview page
  286. func Pulls(ctx *context.Context) {
  287. if unit.TypePullRequests.UnitGlobalDisabled() {
  288. log.Debug("Pull request overview page not available as it is globally disabled.")
  289. ctx.Status(http.StatusNotFound)
  290. return
  291. }
  292. ctx.Data["Title"] = ctx.Tr("pull_requests")
  293. ctx.Data["PageIsPulls"] = true
  294. ctx.Data["SingleRepoAction"] = "pull"
  295. buildIssueOverview(ctx, unit.TypePullRequests)
  296. }
  297. // Issues renders the user's issues overview page
  298. func Issues(ctx *context.Context) {
  299. if unit.TypeIssues.UnitGlobalDisabled() {
  300. log.Debug("Issues overview page not available as it is globally disabled.")
  301. ctx.Status(http.StatusNotFound)
  302. return
  303. }
  304. ctx.Data["Title"] = ctx.Tr("issues")
  305. ctx.Data["PageIsIssues"] = true
  306. ctx.Data["SingleRepoAction"] = "issue"
  307. buildIssueOverview(ctx, unit.TypeIssues)
  308. }
  309. // Regexp for repos query
  310. var issueReposQueryPattern = regexp.MustCompile(`^\[\d+(,\d+)*,?\]$`)
  311. func buildIssueOverview(ctx *context.Context, unitType unit.Type) {
  312. // ----------------------------------------------------
  313. // Determine user; can be either user or organization.
  314. // Return with NotFound or ServerError if unsuccessful.
  315. // ----------------------------------------------------
  316. ctxUser := getDashboardContextUser(ctx)
  317. if ctx.Written() {
  318. return
  319. }
  320. var (
  321. viewType string
  322. sortType = ctx.FormString("sort")
  323. filterMode int
  324. )
  325. // Default to recently updated, unlike repository issues list
  326. if sortType == "" {
  327. sortType = "recentupdate"
  328. }
  329. // --------------------------------------------------------------------------------
  330. // Distinguish User from Organization.
  331. // Org:
  332. // - Remember pre-determined viewType string for later. Will be posted to ctx.Data.
  333. // Organization does not have view type and filter mode.
  334. // User:
  335. // - Use ctx.FormString("type") to determine filterMode.
  336. // The type is set when clicking for example "assigned to me" on the overview page.
  337. // - Remember either this or a fallback. Will be posted to ctx.Data.
  338. // --------------------------------------------------------------------------------
  339. // TODO: distinguish during routing
  340. viewType = ctx.FormString("type")
  341. switch viewType {
  342. case "assigned":
  343. filterMode = issues_model.FilterModeAssign
  344. case "created_by":
  345. filterMode = issues_model.FilterModeCreate
  346. case "mentioned":
  347. filterMode = issues_model.FilterModeMention
  348. case "review_requested":
  349. filterMode = issues_model.FilterModeReviewRequested
  350. case "reviewed_by":
  351. filterMode = issues_model.FilterModeReviewed
  352. case "your_repositories":
  353. fallthrough
  354. default:
  355. filterMode = issues_model.FilterModeYourRepositories
  356. viewType = "your_repositories"
  357. }
  358. // --------------------------------------------------------------------------
  359. // Build opts (IssuesOptions), which contains filter information.
  360. // Will eventually be used to retrieve issues relevant for the overview page.
  361. // Note: Non-final states of opts are used in-between, namely for:
  362. // - Keyword search
  363. // - Count Issues by repo
  364. // --------------------------------------------------------------------------
  365. // Get repository IDs where User/Org/Team has access.
  366. var team *organization.Team
  367. var org *organization.Organization
  368. if ctx.Org != nil {
  369. org = ctx.Org.Organization
  370. team = ctx.Org.Team
  371. }
  372. isPullList := unitType == unit.TypePullRequests
  373. opts := &issues_model.IssuesOptions{
  374. IsPull: util.OptionalBoolOf(isPullList),
  375. SortType: sortType,
  376. IsArchived: util.OptionalBoolFalse,
  377. Org: org,
  378. Team: team,
  379. User: ctx.Doer,
  380. }
  381. // Search all repositories which
  382. //
  383. // As user:
  384. // - Owns the repository.
  385. // - Have collaborator permissions in repository.
  386. //
  387. // As org:
  388. // - Owns the repository.
  389. //
  390. // As team:
  391. // - Team org's owns the repository.
  392. // - Team has read permission to repository.
  393. repoOpts := &repo_model.SearchRepoOptions{
  394. Actor: ctx.Doer,
  395. OwnerID: ctxUser.ID,
  396. Private: true,
  397. AllPublic: false,
  398. AllLimited: false,
  399. Collaborate: util.OptionalBoolNone,
  400. UnitType: unitType,
  401. Archived: util.OptionalBoolFalse,
  402. }
  403. if team != nil {
  404. repoOpts.TeamID = team.ID
  405. }
  406. accessibleRepos := container.Set[int64]{}
  407. {
  408. ids, _, err := repo_model.SearchRepositoryIDs(repoOpts)
  409. if err != nil {
  410. ctx.ServerError("SearchRepositoryIDs", err)
  411. return
  412. }
  413. accessibleRepos.AddMultiple(ids...)
  414. opts.RepoIDs = ids
  415. if len(opts.RepoIDs) == 0 {
  416. // no repos found, don't let the indexer return all repos
  417. opts.RepoIDs = []int64{0}
  418. }
  419. }
  420. switch filterMode {
  421. case issues_model.FilterModeAll:
  422. case issues_model.FilterModeYourRepositories:
  423. case issues_model.FilterModeAssign:
  424. opts.AssigneeID = ctx.Doer.ID
  425. case issues_model.FilterModeCreate:
  426. opts.PosterID = ctx.Doer.ID
  427. case issues_model.FilterModeMention:
  428. opts.MentionedID = ctx.Doer.ID
  429. case issues_model.FilterModeReviewRequested:
  430. opts.ReviewRequestedID = ctx.Doer.ID
  431. case issues_model.FilterModeReviewed:
  432. opts.ReviewedID = ctx.Doer.ID
  433. }
  434. // keyword holds the search term entered into the search field.
  435. keyword := strings.Trim(ctx.FormString("q"), " ")
  436. ctx.Data["Keyword"] = keyword
  437. // Educated guess: Do or don't show closed issues.
  438. isShowClosed := ctx.FormString("state") == "closed"
  439. opts.IsClosed = util.OptionalBoolOf(isShowClosed)
  440. // Filter repos and count issues in them. Count will be used later.
  441. // USING NON-FINAL STATE OF opts FOR A QUERY.
  442. issueCountByRepo, err := issue_indexer.CountIssuesByRepo(ctx, issue_indexer.ToSearchOptions(keyword, opts))
  443. if err != nil {
  444. ctx.ServerError("CountIssuesByRepo", err)
  445. return
  446. }
  447. // Make sure page number is at least 1. Will be posted to ctx.Data.
  448. page := ctx.FormInt("page")
  449. if page <= 1 {
  450. page = 1
  451. }
  452. opts.Paginator = &db.ListOptions{
  453. Page: page,
  454. PageSize: setting.UI.IssuePagingNum,
  455. }
  456. // Get IDs for labels (a filter option for issues/pulls).
  457. // Required for IssuesOptions.
  458. var labelIDs []int64
  459. selectedLabels := ctx.FormString("labels")
  460. if len(selectedLabels) > 0 && selectedLabels != "0" {
  461. var err error
  462. labelIDs, err = base.StringsToInt64s(strings.Split(selectedLabels, ","))
  463. if err != nil {
  464. ctx.ServerError("StringsToInt64s", err)
  465. return
  466. }
  467. }
  468. opts.LabelIDs = labelIDs
  469. // Parse ctx.FormString("repos") and remember matched repo IDs for later.
  470. // Gets set when clicking filters on the issues overview page.
  471. selectedRepoIDs := getRepoIDs(ctx.FormString("repos"))
  472. // Remove repo IDs that are not accessible to the user.
  473. selectedRepoIDs = slices.DeleteFunc(selectedRepoIDs, func(v int64) bool {
  474. return !accessibleRepos.Contains(v)
  475. })
  476. if len(selectedRepoIDs) > 0 {
  477. opts.RepoIDs = selectedRepoIDs
  478. }
  479. // ------------------------------
  480. // Get issues as defined by opts.
  481. // ------------------------------
  482. // Slice of Issues that will be displayed on the overview page
  483. // USING FINAL STATE OF opts FOR A QUERY.
  484. var issues issues_model.IssueList
  485. {
  486. issueIDs, _, err := issue_indexer.SearchIssues(ctx, issue_indexer.ToSearchOptions(keyword, opts))
  487. if err != nil {
  488. ctx.ServerError("issueIDsFromSearch", err)
  489. return
  490. }
  491. issues, err = issues_model.GetIssuesByIDs(ctx, issueIDs, true)
  492. if err != nil {
  493. ctx.ServerError("GetIssuesByIDs", err)
  494. return
  495. }
  496. }
  497. // ----------------------------------
  498. // Add repository pointers to Issues.
  499. // ----------------------------------
  500. // Remove repositories that should not be shown,
  501. // which are repositories that have no issues and are not selected by the user.
  502. selectedRepos := container.SetOf(selectedRepoIDs...)
  503. for k, v := range issueCountByRepo {
  504. if v == 0 && !selectedRepos.Contains(k) {
  505. delete(issueCountByRepo, k)
  506. }
  507. }
  508. // showReposMap maps repository IDs to their Repository pointers.
  509. showReposMap, err := loadRepoByIDs(ctxUser, issueCountByRepo, unitType)
  510. if err != nil {
  511. if repo_model.IsErrRepoNotExist(err) {
  512. ctx.NotFound("GetRepositoryByID", err)
  513. return
  514. }
  515. ctx.ServerError("loadRepoByIDs", err)
  516. return
  517. }
  518. // a RepositoryList
  519. showRepos := repo_model.RepositoryListOfMap(showReposMap)
  520. sort.Sort(showRepos)
  521. // maps pull request IDs to their CommitStatus. Will be posted to ctx.Data.
  522. for _, issue := range issues {
  523. if issue.Repo == nil {
  524. issue.Repo = showReposMap[issue.RepoID]
  525. }
  526. }
  527. commitStatuses, lastStatus, err := pull_service.GetIssuesAllCommitStatus(ctx, issues)
  528. if err != nil {
  529. ctx.ServerError("GetIssuesLastCommitStatus", err)
  530. return
  531. }
  532. // -------------------------------
  533. // Fill stats to post to ctx.Data.
  534. // -------------------------------
  535. issueStats, err := getUserIssueStats(ctx, filterMode, issue_indexer.ToSearchOptions(keyword, opts), ctx.Doer.ID)
  536. if err != nil {
  537. ctx.ServerError("getUserIssueStats", err)
  538. return
  539. }
  540. // Will be posted to ctx.Data.
  541. var shownIssues int
  542. if !isShowClosed {
  543. shownIssues = int(issueStats.OpenCount)
  544. } else {
  545. shownIssues = int(issueStats.ClosedCount)
  546. }
  547. if len(opts.RepoIDs) != 0 {
  548. shownIssues = 0
  549. for _, repoID := range opts.RepoIDs {
  550. shownIssues += int(issueCountByRepo[repoID])
  551. }
  552. }
  553. var allIssueCount int64
  554. for _, issueCount := range issueCountByRepo {
  555. allIssueCount += issueCount
  556. }
  557. ctx.Data["TotalIssueCount"] = allIssueCount
  558. if len(opts.RepoIDs) == 1 {
  559. repo := showReposMap[opts.RepoIDs[0]]
  560. if repo != nil {
  561. ctx.Data["SingleRepoLink"] = repo.Link()
  562. }
  563. }
  564. ctx.Data["IsShowClosed"] = isShowClosed
  565. ctx.Data["IssueRefEndNames"], ctx.Data["IssueRefURLs"] = issue_service.GetRefEndNamesAndURLs(issues, ctx.FormString("RepoLink"))
  566. if err := issues.LoadAttributes(ctx); err != nil {
  567. ctx.ServerError("issues.LoadAttributes", err)
  568. return
  569. }
  570. ctx.Data["Issues"] = issues
  571. approvalCounts, err := issues.GetApprovalCounts(ctx)
  572. if err != nil {
  573. ctx.ServerError("ApprovalCounts", err)
  574. return
  575. }
  576. ctx.Data["ApprovalCounts"] = func(issueID int64, typ string) int64 {
  577. counts, ok := approvalCounts[issueID]
  578. if !ok || len(counts) == 0 {
  579. return 0
  580. }
  581. reviewTyp := issues_model.ReviewTypeApprove
  582. if typ == "reject" {
  583. reviewTyp = issues_model.ReviewTypeReject
  584. } else if typ == "waiting" {
  585. reviewTyp = issues_model.ReviewTypeRequest
  586. }
  587. for _, count := range counts {
  588. if count.Type == reviewTyp {
  589. return count.Count
  590. }
  591. }
  592. return 0
  593. }
  594. ctx.Data["CommitLastStatus"] = lastStatus
  595. ctx.Data["CommitStatuses"] = commitStatuses
  596. ctx.Data["Repos"] = showRepos
  597. ctx.Data["Counts"] = issueCountByRepo
  598. ctx.Data["IssueStats"] = issueStats
  599. ctx.Data["ViewType"] = viewType
  600. ctx.Data["SortType"] = sortType
  601. ctx.Data["RepoIDs"] = selectedRepoIDs
  602. ctx.Data["IsShowClosed"] = isShowClosed
  603. ctx.Data["SelectLabels"] = selectedLabels
  604. if isShowClosed {
  605. ctx.Data["State"] = "closed"
  606. } else {
  607. ctx.Data["State"] = "open"
  608. }
  609. // Convert []int64 to string
  610. reposParam, _ := json.Marshal(opts.RepoIDs)
  611. ctx.Data["ReposParam"] = string(reposParam)
  612. pager := context.NewPagination(shownIssues, setting.UI.IssuePagingNum, page, 5)
  613. pager.AddParam(ctx, "q", "Keyword")
  614. pager.AddParam(ctx, "type", "ViewType")
  615. pager.AddParam(ctx, "repos", "ReposParam")
  616. pager.AddParam(ctx, "sort", "SortType")
  617. pager.AddParam(ctx, "state", "State")
  618. pager.AddParam(ctx, "labels", "SelectLabels")
  619. pager.AddParam(ctx, "milestone", "MilestoneID")
  620. pager.AddParam(ctx, "assignee", "AssigneeID")
  621. ctx.Data["Page"] = pager
  622. ctx.HTML(http.StatusOK, tplIssues)
  623. }
  624. func getRepoIDs(reposQuery string) []int64 {
  625. if len(reposQuery) == 0 || reposQuery == "[]" {
  626. return []int64{}
  627. }
  628. if !issueReposQueryPattern.MatchString(reposQuery) {
  629. log.Warn("issueReposQueryPattern does not match query: %q", reposQuery)
  630. return []int64{}
  631. }
  632. var repoIDs []int64
  633. // remove "[" and "]" from string
  634. reposQuery = reposQuery[1 : len(reposQuery)-1]
  635. // for each ID (delimiter ",") add to int to repoIDs
  636. for _, rID := range strings.Split(reposQuery, ",") {
  637. // Ensure nonempty string entries
  638. if rID != "" && rID != "0" {
  639. rIDint64, err := strconv.ParseInt(rID, 10, 64)
  640. if err == nil {
  641. repoIDs = append(repoIDs, rIDint64)
  642. }
  643. }
  644. }
  645. return repoIDs
  646. }
  647. func loadRepoByIDs(ctxUser *user_model.User, issueCountByRepo map[int64]int64, unitType unit.Type) (map[int64]*repo_model.Repository, error) {
  648. totalRes := make(map[int64]*repo_model.Repository, len(issueCountByRepo))
  649. repoIDs := make([]int64, 0, 500)
  650. for id := range issueCountByRepo {
  651. if id <= 0 {
  652. continue
  653. }
  654. repoIDs = append(repoIDs, id)
  655. if len(repoIDs) == 500 {
  656. if err := repo_model.FindReposMapByIDs(repoIDs, totalRes); err != nil {
  657. return nil, err
  658. }
  659. repoIDs = repoIDs[:0]
  660. }
  661. }
  662. if len(repoIDs) > 0 {
  663. if err := repo_model.FindReposMapByIDs(repoIDs, totalRes); err != nil {
  664. return nil, err
  665. }
  666. }
  667. return totalRes, nil
  668. }
  669. // ShowSSHKeys output all the ssh keys of user by uid
  670. func ShowSSHKeys(ctx *context.Context) {
  671. keys, err := asymkey_model.ListPublicKeys(ctx.ContextUser.ID, db.ListOptions{})
  672. if err != nil {
  673. ctx.ServerError("ListPublicKeys", err)
  674. return
  675. }
  676. var buf bytes.Buffer
  677. for i := range keys {
  678. buf.WriteString(keys[i].OmitEmail())
  679. buf.WriteString("\n")
  680. }
  681. ctx.PlainTextBytes(http.StatusOK, buf.Bytes())
  682. }
  683. // ShowGPGKeys output all the public GPG keys of user by uid
  684. func ShowGPGKeys(ctx *context.Context) {
  685. keys, err := asymkey_model.ListGPGKeys(ctx, ctx.ContextUser.ID, db.ListOptions{})
  686. if err != nil {
  687. ctx.ServerError("ListGPGKeys", err)
  688. return
  689. }
  690. entities := make([]*openpgp.Entity, 0)
  691. failedEntitiesID := make([]string, 0)
  692. for _, k := range keys {
  693. e, err := asymkey_model.GPGKeyToEntity(k)
  694. if err != nil {
  695. if asymkey_model.IsErrGPGKeyImportNotExist(err) {
  696. failedEntitiesID = append(failedEntitiesID, k.KeyID)
  697. continue // Skip previous import without backup of imported armored key
  698. }
  699. ctx.ServerError("ShowGPGKeys", err)
  700. return
  701. }
  702. entities = append(entities, e)
  703. }
  704. var buf bytes.Buffer
  705. headers := make(map[string]string)
  706. if len(failedEntitiesID) > 0 { // If some key need re-import to be exported
  707. headers["Note"] = fmt.Sprintf("The keys with the following IDs couldn't be exported and need to be reuploaded %s", strings.Join(failedEntitiesID, ", "))
  708. } else if len(entities) == 0 {
  709. headers["Note"] = "This user hasn't uploaded any GPG keys."
  710. }
  711. writer, _ := armor.Encode(&buf, "PGP PUBLIC KEY BLOCK", headers)
  712. for _, e := range entities {
  713. err = e.Serialize(writer) // TODO find why key are exported with a different cipherTypeByte as original (should not be blocking but strange)
  714. if err != nil {
  715. ctx.ServerError("ShowGPGKeys", err)
  716. return
  717. }
  718. }
  719. writer.Close()
  720. ctx.PlainTextBytes(http.StatusOK, buf.Bytes())
  721. }
  722. func UsernameSubRoute(ctx *context.Context) {
  723. // WORKAROUND to support usernames with "." in it
  724. // https://github.com/go-chi/chi/issues/781
  725. username := ctx.Params("username")
  726. reloadParam := func(suffix string) (success bool) {
  727. ctx.SetParams("username", strings.TrimSuffix(username, suffix))
  728. context_service.UserAssignmentWeb()(ctx)
  729. // check view permissions
  730. if !user_model.IsUserVisibleToViewer(ctx, ctx.ContextUser, ctx.Doer) {
  731. ctx.NotFound("user", fmt.Errorf(ctx.ContextUser.Name))
  732. return false
  733. }
  734. return !ctx.Written()
  735. }
  736. switch {
  737. case strings.HasSuffix(username, ".png"):
  738. if reloadParam(".png") {
  739. AvatarByUserName(ctx)
  740. }
  741. case strings.HasSuffix(username, ".keys"):
  742. if reloadParam(".keys") {
  743. ShowSSHKeys(ctx)
  744. }
  745. case strings.HasSuffix(username, ".gpg"):
  746. if reloadParam(".gpg") {
  747. ShowGPGKeys(ctx)
  748. }
  749. case strings.HasSuffix(username, ".rss"):
  750. if !setting.Other.EnableFeed {
  751. ctx.Error(http.StatusNotFound)
  752. return
  753. }
  754. if reloadParam(".rss") {
  755. context_service.UserAssignmentWeb()(ctx)
  756. feed.ShowUserFeedRSS(ctx)
  757. }
  758. case strings.HasSuffix(username, ".atom"):
  759. if !setting.Other.EnableFeed {
  760. ctx.Error(http.StatusNotFound)
  761. return
  762. }
  763. if reloadParam(".atom") {
  764. feed.ShowUserFeedAtom(ctx)
  765. }
  766. default:
  767. context_service.UserAssignmentWeb()(ctx)
  768. if !ctx.Written() {
  769. ctx.Data["EnableFeed"] = setting.Other.EnableFeed
  770. OwnerProfile(ctx)
  771. }
  772. }
  773. }
  774. func getUserIssueStats(ctx *context.Context, filterMode int, opts *issue_indexer.SearchOptions, doerID int64) (*issues_model.IssueStats, error) {
  775. opts = opts.Copy(func(o *issue_indexer.SearchOptions) {
  776. o.AssigneeID = nil
  777. o.PosterID = nil
  778. o.MentionID = nil
  779. o.ReviewRequestedID = nil
  780. o.ReviewedID = nil
  781. })
  782. var (
  783. err error
  784. ret = &issues_model.IssueStats{}
  785. )
  786. {
  787. openClosedOpts := opts.Copy()
  788. switch filterMode {
  789. case issues_model.FilterModeAll, issues_model.FilterModeYourRepositories:
  790. case issues_model.FilterModeAssign:
  791. openClosedOpts.AssigneeID = &doerID
  792. case issues_model.FilterModeCreate:
  793. openClosedOpts.PosterID = &doerID
  794. case issues_model.FilterModeMention:
  795. openClosedOpts.MentionID = &doerID
  796. case issues_model.FilterModeReviewRequested:
  797. openClosedOpts.ReviewRequestedID = &doerID
  798. case issues_model.FilterModeReviewed:
  799. openClosedOpts.ReviewedID = &doerID
  800. }
  801. openClosedOpts.IsClosed = util.OptionalBoolFalse
  802. ret.OpenCount, err = issue_indexer.CountIssues(ctx, openClosedOpts)
  803. if err != nil {
  804. return nil, err
  805. }
  806. openClosedOpts.IsClosed = util.OptionalBoolTrue
  807. ret.ClosedCount, err = issue_indexer.CountIssues(ctx, openClosedOpts)
  808. if err != nil {
  809. return nil, err
  810. }
  811. }
  812. ret.YourRepositoriesCount, err = issue_indexer.CountIssues(ctx, opts)
  813. if err != nil {
  814. return nil, err
  815. }
  816. ret.AssignCount, err = issue_indexer.CountIssues(ctx, opts.Copy(func(o *issue_indexer.SearchOptions) { o.AssigneeID = &doerID }))
  817. if err != nil {
  818. return nil, err
  819. }
  820. ret.CreateCount, err = issue_indexer.CountIssues(ctx, opts.Copy(func(o *issue_indexer.SearchOptions) { o.PosterID = &doerID }))
  821. if err != nil {
  822. return nil, err
  823. }
  824. ret.MentionCount, err = issue_indexer.CountIssues(ctx, opts.Copy(func(o *issue_indexer.SearchOptions) { o.MentionID = &doerID }))
  825. if err != nil {
  826. return nil, err
  827. }
  828. ret.ReviewRequestedCount, err = issue_indexer.CountIssues(ctx, opts.Copy(func(o *issue_indexer.SearchOptions) { o.ReviewRequestedID = &doerID }))
  829. if err != nil {
  830. return nil, err
  831. }
  832. ret.ReviewedCount, err = issue_indexer.CountIssues(ctx, opts.Copy(func(o *issue_indexer.SearchOptions) { o.ReviewedID = &doerID }))
  833. if err != nil {
  834. return nil, err
  835. }
  836. return ret, nil
  837. }