Merge pull request '[gitea] week 2024-48 cherry pick (gitea/main -> forgejo)' (#6062) from earl-warren/wcp/2024-48 into forgejo
Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/6062 Reviewed-by: Gusted <gusted@noreply.codeberg.org>
This commit is contained in:
		
				commit
				
					
						e5417fdede
					
				
			
		
					 18 changed files with 287 additions and 146 deletions
				
			
		| 
						 | 
				
			
			@ -29,7 +29,6 @@
 | 
			
		|||
            poetry
 | 
			
		||||
 | 
			
		||||
            # backend
 | 
			
		||||
            go_1_22
 | 
			
		||||
            gofumpt
 | 
			
		||||
            sqlite
 | 
			
		||||
          ];
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,3 +1,22 @@
 | 
			
		|||
-
 | 
			
		||||
  id: 46
 | 
			
		||||
  attempt: 3
 | 
			
		||||
  runner_id: 1
 | 
			
		||||
  status: 3 # 3 is the status code for "cancelled"
 | 
			
		||||
  started: 1683636528
 | 
			
		||||
  stopped: 1683636626
 | 
			
		||||
  repo_id: 4
 | 
			
		||||
  owner_id: 1
 | 
			
		||||
  commit_sha: c2d72f548424103f01ee1dc02889c1e2bff816b0
 | 
			
		||||
  is_fork_pull_request: 0
 | 
			
		||||
  token_hash: 6d8ef48297195edcc8e22c70b3020eaa06c52976db67d39b4260c64a69a2cc1508825121b7b8394e48e00b1bf8718b2aaaaa
 | 
			
		||||
  token_salt: eeeeeeee
 | 
			
		||||
  token_last_eight: eeeeeeee
 | 
			
		||||
  log_filename: artifact-test2/2f/47.log
 | 
			
		||||
  log_in_storage: 1
 | 
			
		||||
  log_length: 707
 | 
			
		||||
  log_size: 90179
 | 
			
		||||
  log_expired: 0
 | 
			
		||||
-
 | 
			
		||||
  id: 47
 | 
			
		||||
  job_id: 192
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,7 +1,7 @@
 | 
			
		|||
-
 | 
			
		||||
  id: 1
 | 
			
		||||
  setting_key: 'picture.disable_gravatar'
 | 
			
		||||
  setting_value: 'false'
 | 
			
		||||
  setting_value: 'true'
 | 
			
		||||
  version: 1
 | 
			
		||||
  created: 1653533198
 | 
			
		||||
  updated: 1653533198
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,9 +23,9 @@
 | 
			
		|||
  allow_import_local: false
 | 
			
		||||
  allow_create_organization: true
 | 
			
		||||
  prohibit_login: false
 | 
			
		||||
  avatar: avatar1
 | 
			
		||||
  avatar: ""
 | 
			
		||||
  avatar_email: user1@example.com
 | 
			
		||||
  use_custom_avatar: false
 | 
			
		||||
  use_custom_avatar: true
 | 
			
		||||
  num_followers: 0
 | 
			
		||||
  num_following: 0
 | 
			
		||||
  num_stars: 0
 | 
			
		||||
| 
						 | 
				
			
			@ -60,8 +60,9 @@
 | 
			
		|||
  allow_import_local: false
 | 
			
		||||
  allow_create_organization: true
 | 
			
		||||
  prohibit_login: false
 | 
			
		||||
  avatar: avatar2
 | 
			
		||||
  avatar: ""
 | 
			
		||||
  avatar_email: user2@example.com
 | 
			
		||||
  # cause a random avatar to be generated when referenced for test purposes
 | 
			
		||||
  use_custom_avatar: false
 | 
			
		||||
  num_followers: 2
 | 
			
		||||
  num_following: 1
 | 
			
		||||
| 
						 | 
				
			
			@ -97,9 +98,9 @@
 | 
			
		|||
  allow_import_local: false
 | 
			
		||||
  allow_create_organization: true
 | 
			
		||||
  prohibit_login: false
 | 
			
		||||
  avatar: avatar3
 | 
			
		||||
  avatar: ""
 | 
			
		||||
  avatar_email: org3@example.com
 | 
			
		||||
  use_custom_avatar: false
 | 
			
		||||
  use_custom_avatar: true
 | 
			
		||||
  num_followers: 0
 | 
			
		||||
  num_following: 0
 | 
			
		||||
  num_stars: 0
 | 
			
		||||
| 
						 | 
				
			
			@ -134,9 +135,9 @@
 | 
			
		|||
  allow_import_local: false
 | 
			
		||||
  allow_create_organization: true
 | 
			
		||||
  prohibit_login: false
 | 
			
		||||
  avatar: avatar4
 | 
			
		||||
  avatar: ""
 | 
			
		||||
  avatar_email: user4@example.com
 | 
			
		||||
  use_custom_avatar: false
 | 
			
		||||
  use_custom_avatar: true
 | 
			
		||||
  num_followers: 0
 | 
			
		||||
  num_following: 1
 | 
			
		||||
  num_stars: 0
 | 
			
		||||
| 
						 | 
				
			
			@ -171,9 +172,9 @@
 | 
			
		|||
  allow_import_local: false
 | 
			
		||||
  allow_create_organization: false
 | 
			
		||||
  prohibit_login: false
 | 
			
		||||
  avatar: avatar5
 | 
			
		||||
  avatar: ""
 | 
			
		||||
  avatar_email: user5@example.com
 | 
			
		||||
  use_custom_avatar: false
 | 
			
		||||
  use_custom_avatar: true
 | 
			
		||||
  num_followers: 0
 | 
			
		||||
  num_following: 0
 | 
			
		||||
  num_stars: 0
 | 
			
		||||
| 
						 | 
				
			
			@ -208,9 +209,9 @@
 | 
			
		|||
  allow_import_local: false
 | 
			
		||||
  allow_create_organization: true
 | 
			
		||||
  prohibit_login: false
 | 
			
		||||
  avatar: avatar6
 | 
			
		||||
  avatar: ""
 | 
			
		||||
  avatar_email: org6@example.com
 | 
			
		||||
  use_custom_avatar: false
 | 
			
		||||
  use_custom_avatar: true
 | 
			
		||||
  num_followers: 0
 | 
			
		||||
  num_following: 0
 | 
			
		||||
  num_stars: 0
 | 
			
		||||
| 
						 | 
				
			
			@ -245,9 +246,9 @@
 | 
			
		|||
  allow_import_local: false
 | 
			
		||||
  allow_create_organization: true
 | 
			
		||||
  prohibit_login: false
 | 
			
		||||
  avatar: avatar7
 | 
			
		||||
  avatar: ""
 | 
			
		||||
  avatar_email: org7@example.com
 | 
			
		||||
  use_custom_avatar: false
 | 
			
		||||
  use_custom_avatar: true
 | 
			
		||||
  num_followers: 0
 | 
			
		||||
  num_following: 0
 | 
			
		||||
  num_stars: 0
 | 
			
		||||
| 
						 | 
				
			
			@ -282,9 +283,9 @@
 | 
			
		|||
  allow_import_local: false
 | 
			
		||||
  allow_create_organization: true
 | 
			
		||||
  prohibit_login: false
 | 
			
		||||
  avatar: avatar8
 | 
			
		||||
  avatar: ""
 | 
			
		||||
  avatar_email: user8@example.com
 | 
			
		||||
  use_custom_avatar: false
 | 
			
		||||
  use_custom_avatar: true
 | 
			
		||||
  num_followers: 1
 | 
			
		||||
  num_following: 1
 | 
			
		||||
  num_stars: 0
 | 
			
		||||
| 
						 | 
				
			
			@ -319,9 +320,9 @@
 | 
			
		|||
  allow_import_local: false
 | 
			
		||||
  allow_create_organization: true
 | 
			
		||||
  prohibit_login: false
 | 
			
		||||
  avatar: avatar9
 | 
			
		||||
  avatar: ""
 | 
			
		||||
  avatar_email: user9@example.com
 | 
			
		||||
  use_custom_avatar: false
 | 
			
		||||
  use_custom_avatar: true
 | 
			
		||||
  num_followers: 0
 | 
			
		||||
  num_following: 0
 | 
			
		||||
  num_stars: 0
 | 
			
		||||
| 
						 | 
				
			
			@ -332,6 +333,7 @@
 | 
			
		|||
  repo_admin_change_team_access: false
 | 
			
		||||
  theme: ""
 | 
			
		||||
  keep_activity_private: false
 | 
			
		||||
  created_unix: 1730468968
 | 
			
		||||
 | 
			
		||||
-
 | 
			
		||||
  id: 10
 | 
			
		||||
| 
						 | 
				
			
			@ -356,9 +358,9 @@
 | 
			
		|||
  allow_import_local: false
 | 
			
		||||
  allow_create_organization: true
 | 
			
		||||
  prohibit_login: false
 | 
			
		||||
  avatar: avatar10
 | 
			
		||||
  avatar: ""
 | 
			
		||||
  avatar_email: user10@example.com
 | 
			
		||||
  use_custom_avatar: false
 | 
			
		||||
  use_custom_avatar: true
 | 
			
		||||
  num_followers: 0
 | 
			
		||||
  num_following: 0
 | 
			
		||||
  num_stars: 0
 | 
			
		||||
| 
						 | 
				
			
			@ -393,9 +395,9 @@
 | 
			
		|||
  allow_import_local: false
 | 
			
		||||
  allow_create_organization: true
 | 
			
		||||
  prohibit_login: false
 | 
			
		||||
  avatar: avatar11
 | 
			
		||||
  avatar: ""
 | 
			
		||||
  avatar_email: user11@example.com
 | 
			
		||||
  use_custom_avatar: false
 | 
			
		||||
  use_custom_avatar: true
 | 
			
		||||
  num_followers: 0
 | 
			
		||||
  num_following: 0
 | 
			
		||||
  num_stars: 0
 | 
			
		||||
| 
						 | 
				
			
			@ -430,9 +432,9 @@
 | 
			
		|||
  allow_import_local: false
 | 
			
		||||
  allow_create_organization: true
 | 
			
		||||
  prohibit_login: false
 | 
			
		||||
  avatar: avatar12
 | 
			
		||||
  avatar: ""
 | 
			
		||||
  avatar_email: user12@example.com
 | 
			
		||||
  use_custom_avatar: false
 | 
			
		||||
  use_custom_avatar: true
 | 
			
		||||
  num_followers: 0
 | 
			
		||||
  num_following: 0
 | 
			
		||||
  num_stars: 0
 | 
			
		||||
| 
						 | 
				
			
			@ -467,9 +469,9 @@
 | 
			
		|||
  allow_import_local: false
 | 
			
		||||
  allow_create_organization: true
 | 
			
		||||
  prohibit_login: false
 | 
			
		||||
  avatar: avatar13
 | 
			
		||||
  avatar: ""
 | 
			
		||||
  avatar_email: user13@example.com
 | 
			
		||||
  use_custom_avatar: false
 | 
			
		||||
  use_custom_avatar: true
 | 
			
		||||
  num_followers: 0
 | 
			
		||||
  num_following: 0
 | 
			
		||||
  num_stars: 0
 | 
			
		||||
| 
						 | 
				
			
			@ -504,9 +506,9 @@
 | 
			
		|||
  allow_import_local: false
 | 
			
		||||
  allow_create_organization: true
 | 
			
		||||
  prohibit_login: false
 | 
			
		||||
  avatar: avatar14
 | 
			
		||||
  avatar: ""
 | 
			
		||||
  avatar_email: user13@example.com
 | 
			
		||||
  use_custom_avatar: false
 | 
			
		||||
  use_custom_avatar: true
 | 
			
		||||
  num_followers: 0
 | 
			
		||||
  num_following: 0
 | 
			
		||||
  num_stars: 0
 | 
			
		||||
| 
						 | 
				
			
			@ -541,9 +543,9 @@
 | 
			
		|||
  allow_import_local: false
 | 
			
		||||
  allow_create_organization: true
 | 
			
		||||
  prohibit_login: false
 | 
			
		||||
  avatar: avatar15
 | 
			
		||||
  avatar: ""
 | 
			
		||||
  avatar_email: user15@example.com
 | 
			
		||||
  use_custom_avatar: false
 | 
			
		||||
  use_custom_avatar: true
 | 
			
		||||
  num_followers: 0
 | 
			
		||||
  num_following: 0
 | 
			
		||||
  num_stars: 0
 | 
			
		||||
| 
						 | 
				
			
			@ -578,9 +580,9 @@
 | 
			
		|||
  allow_import_local: false
 | 
			
		||||
  allow_create_organization: true
 | 
			
		||||
  prohibit_login: false
 | 
			
		||||
  avatar: avatar16
 | 
			
		||||
  avatar: ""
 | 
			
		||||
  avatar_email: user16@example.com
 | 
			
		||||
  use_custom_avatar: false
 | 
			
		||||
  use_custom_avatar: true
 | 
			
		||||
  num_followers: 0
 | 
			
		||||
  num_following: 0
 | 
			
		||||
  num_stars: 0
 | 
			
		||||
| 
						 | 
				
			
			@ -615,9 +617,9 @@
 | 
			
		|||
  allow_import_local: false
 | 
			
		||||
  allow_create_organization: true
 | 
			
		||||
  prohibit_login: false
 | 
			
		||||
  avatar: avatar17
 | 
			
		||||
  avatar: ""
 | 
			
		||||
  avatar_email: org17@example.com
 | 
			
		||||
  use_custom_avatar: false
 | 
			
		||||
  use_custom_avatar: true
 | 
			
		||||
  num_followers: 0
 | 
			
		||||
  num_following: 0
 | 
			
		||||
  num_stars: 0
 | 
			
		||||
| 
						 | 
				
			
			@ -652,9 +654,9 @@
 | 
			
		|||
  allow_import_local: false
 | 
			
		||||
  allow_create_organization: true
 | 
			
		||||
  prohibit_login: false
 | 
			
		||||
  avatar: avatar18
 | 
			
		||||
  avatar: ""
 | 
			
		||||
  avatar_email: user18@example.com
 | 
			
		||||
  use_custom_avatar: false
 | 
			
		||||
  use_custom_avatar: true
 | 
			
		||||
  num_followers: 0
 | 
			
		||||
  num_following: 0
 | 
			
		||||
  num_stars: 0
 | 
			
		||||
| 
						 | 
				
			
			@ -689,9 +691,9 @@
 | 
			
		|||
  allow_import_local: false
 | 
			
		||||
  allow_create_organization: true
 | 
			
		||||
  prohibit_login: false
 | 
			
		||||
  avatar: avatar19
 | 
			
		||||
  avatar: ""
 | 
			
		||||
  avatar_email: org19@example.com
 | 
			
		||||
  use_custom_avatar: false
 | 
			
		||||
  use_custom_avatar: true
 | 
			
		||||
  num_followers: 0
 | 
			
		||||
  num_following: 0
 | 
			
		||||
  num_stars: 0
 | 
			
		||||
| 
						 | 
				
			
			@ -726,9 +728,9 @@
 | 
			
		|||
  allow_import_local: false
 | 
			
		||||
  allow_create_organization: true
 | 
			
		||||
  prohibit_login: false
 | 
			
		||||
  avatar: avatar20
 | 
			
		||||
  avatar: ""
 | 
			
		||||
  avatar_email: user20@example.com
 | 
			
		||||
  use_custom_avatar: false
 | 
			
		||||
  use_custom_avatar: true
 | 
			
		||||
  num_followers: 0
 | 
			
		||||
  num_following: 0
 | 
			
		||||
  num_stars: 0
 | 
			
		||||
| 
						 | 
				
			
			@ -763,9 +765,9 @@
 | 
			
		|||
  allow_import_local: false
 | 
			
		||||
  allow_create_organization: true
 | 
			
		||||
  prohibit_login: false
 | 
			
		||||
  avatar: avatar21
 | 
			
		||||
  avatar: ""
 | 
			
		||||
  avatar_email: user21@example.com
 | 
			
		||||
  use_custom_avatar: false
 | 
			
		||||
  use_custom_avatar: true
 | 
			
		||||
  num_followers: 0
 | 
			
		||||
  num_following: 0
 | 
			
		||||
  num_stars: 0
 | 
			
		||||
| 
						 | 
				
			
			@ -800,9 +802,9 @@
 | 
			
		|||
  allow_import_local: false
 | 
			
		||||
  allow_create_organization: true
 | 
			
		||||
  prohibit_login: false
 | 
			
		||||
  avatar: avatar22
 | 
			
		||||
  avatar: ""
 | 
			
		||||
  avatar_email: limited_org@example.com
 | 
			
		||||
  use_custom_avatar: false
 | 
			
		||||
  use_custom_avatar: true
 | 
			
		||||
  num_followers: 0
 | 
			
		||||
  num_following: 0
 | 
			
		||||
  num_stars: 0
 | 
			
		||||
| 
						 | 
				
			
			@ -837,9 +839,9 @@
 | 
			
		|||
  allow_import_local: false
 | 
			
		||||
  allow_create_organization: true
 | 
			
		||||
  prohibit_login: false
 | 
			
		||||
  avatar: avatar23
 | 
			
		||||
  avatar: ""
 | 
			
		||||
  avatar_email: privated_org@example.com
 | 
			
		||||
  use_custom_avatar: false
 | 
			
		||||
  use_custom_avatar: true
 | 
			
		||||
  num_followers: 0
 | 
			
		||||
  num_following: 0
 | 
			
		||||
  num_stars: 0
 | 
			
		||||
| 
						 | 
				
			
			@ -874,9 +876,9 @@
 | 
			
		|||
  allow_import_local: false
 | 
			
		||||
  allow_create_organization: true
 | 
			
		||||
  prohibit_login: false
 | 
			
		||||
  avatar: avatar24
 | 
			
		||||
  avatar: ""
 | 
			
		||||
  avatar_email: user24@example.com
 | 
			
		||||
  use_custom_avatar: false
 | 
			
		||||
  use_custom_avatar: true
 | 
			
		||||
  num_followers: 0
 | 
			
		||||
  num_following: 0
 | 
			
		||||
  num_stars: 0
 | 
			
		||||
| 
						 | 
				
			
			@ -911,9 +913,9 @@
 | 
			
		|||
  allow_import_local: false
 | 
			
		||||
  allow_create_organization: true
 | 
			
		||||
  prohibit_login: false
 | 
			
		||||
  avatar: avatar25
 | 
			
		||||
  avatar: ""
 | 
			
		||||
  avatar_email: org25@example.com
 | 
			
		||||
  use_custom_avatar: false
 | 
			
		||||
  use_custom_avatar: true
 | 
			
		||||
  num_followers: 0
 | 
			
		||||
  num_following: 0
 | 
			
		||||
  num_stars: 0
 | 
			
		||||
| 
						 | 
				
			
			@ -948,9 +950,9 @@
 | 
			
		|||
  allow_import_local: false
 | 
			
		||||
  allow_create_organization: true
 | 
			
		||||
  prohibit_login: false
 | 
			
		||||
  avatar: avatar26
 | 
			
		||||
  avatar: ""
 | 
			
		||||
  avatar_email: org26@example.com
 | 
			
		||||
  use_custom_avatar: false
 | 
			
		||||
  use_custom_avatar: true
 | 
			
		||||
  num_followers: 0
 | 
			
		||||
  num_following: 0
 | 
			
		||||
  num_stars: 0
 | 
			
		||||
| 
						 | 
				
			
			@ -985,9 +987,9 @@
 | 
			
		|||
  allow_import_local: false
 | 
			
		||||
  allow_create_organization: true
 | 
			
		||||
  prohibit_login: false
 | 
			
		||||
  avatar: avatar27
 | 
			
		||||
  avatar: ""
 | 
			
		||||
  avatar_email: user27@example.com
 | 
			
		||||
  use_custom_avatar: false
 | 
			
		||||
  use_custom_avatar: true
 | 
			
		||||
  num_followers: 0
 | 
			
		||||
  num_following: 0
 | 
			
		||||
  num_stars: 0
 | 
			
		||||
| 
						 | 
				
			
			@ -1022,9 +1024,9 @@
 | 
			
		|||
  allow_import_local: false
 | 
			
		||||
  allow_create_organization: true
 | 
			
		||||
  prohibit_login: false
 | 
			
		||||
  avatar: avatar28
 | 
			
		||||
  avatar: ""
 | 
			
		||||
  avatar_email: user28@example.com
 | 
			
		||||
  use_custom_avatar: false
 | 
			
		||||
  use_custom_avatar: true
 | 
			
		||||
  num_followers: 0
 | 
			
		||||
  num_following: 0
 | 
			
		||||
  num_stars: 0
 | 
			
		||||
| 
						 | 
				
			
			@ -1059,9 +1061,9 @@
 | 
			
		|||
  allow_import_local: false
 | 
			
		||||
  allow_create_organization: true
 | 
			
		||||
  prohibit_login: false
 | 
			
		||||
  avatar: avatar29
 | 
			
		||||
  avatar: ""
 | 
			
		||||
  avatar_email: user29@example.com
 | 
			
		||||
  use_custom_avatar: false
 | 
			
		||||
  use_custom_avatar: true
 | 
			
		||||
  num_followers: 0
 | 
			
		||||
  num_following: 0
 | 
			
		||||
  num_stars: 0
 | 
			
		||||
| 
						 | 
				
			
			@ -1096,9 +1098,9 @@
 | 
			
		|||
  allow_import_local: false
 | 
			
		||||
  allow_create_organization: true
 | 
			
		||||
  prohibit_login: false
 | 
			
		||||
  avatar: avatar29
 | 
			
		||||
  avatar: ""
 | 
			
		||||
  avatar_email: user30@example.com
 | 
			
		||||
  use_custom_avatar: false
 | 
			
		||||
  use_custom_avatar: true
 | 
			
		||||
  num_followers: 0
 | 
			
		||||
  num_following: 0
 | 
			
		||||
  num_stars: 0
 | 
			
		||||
| 
						 | 
				
			
			@ -1133,9 +1135,9 @@
 | 
			
		|||
  allow_import_local: false
 | 
			
		||||
  allow_create_organization: true
 | 
			
		||||
  prohibit_login: false
 | 
			
		||||
  avatar: avatar31
 | 
			
		||||
  avatar: ""
 | 
			
		||||
  avatar_email: user31@example.com
 | 
			
		||||
  use_custom_avatar: false
 | 
			
		||||
  use_custom_avatar: true
 | 
			
		||||
  num_followers: 0
 | 
			
		||||
  num_following: 1
 | 
			
		||||
  num_stars: 0
 | 
			
		||||
| 
						 | 
				
			
			@ -1170,9 +1172,9 @@
 | 
			
		|||
  allow_import_local: false
 | 
			
		||||
  allow_create_organization: true
 | 
			
		||||
  prohibit_login: false
 | 
			
		||||
  avatar: avatar32
 | 
			
		||||
  avatar: ""
 | 
			
		||||
  avatar_email: user30@example.com
 | 
			
		||||
  use_custom_avatar: false
 | 
			
		||||
  use_custom_avatar: true
 | 
			
		||||
  num_followers: 0
 | 
			
		||||
  num_following: 0
 | 
			
		||||
  num_stars: 0
 | 
			
		||||
| 
						 | 
				
			
			@ -1207,9 +1209,9 @@
 | 
			
		|||
  allow_import_local: false
 | 
			
		||||
  allow_create_organization: true
 | 
			
		||||
  prohibit_login: false
 | 
			
		||||
  avatar: avatar33
 | 
			
		||||
  avatar: ""
 | 
			
		||||
  avatar_email: user33@example.com
 | 
			
		||||
  use_custom_avatar: false
 | 
			
		||||
  use_custom_avatar: true
 | 
			
		||||
  num_followers: 1
 | 
			
		||||
  num_following: 0
 | 
			
		||||
  num_stars: 0
 | 
			
		||||
| 
						 | 
				
			
			@ -1245,7 +1247,7 @@
 | 
			
		|||
  allow_import_local: false
 | 
			
		||||
  allow_create_organization: false
 | 
			
		||||
  prohibit_login: false
 | 
			
		||||
  avatar: avatar34
 | 
			
		||||
  avatar: ""
 | 
			
		||||
  avatar_email: user34@example.com
 | 
			
		||||
  use_custom_avatar: true
 | 
			
		||||
  num_followers: 0
 | 
			
		||||
| 
						 | 
				
			
			@ -1282,9 +1284,9 @@
 | 
			
		|||
  allow_import_local: false
 | 
			
		||||
  allow_create_organization: true
 | 
			
		||||
  prohibit_login: false
 | 
			
		||||
  avatar: avatar35
 | 
			
		||||
  avatar: ""
 | 
			
		||||
  avatar_email: private_org35@example.com
 | 
			
		||||
  use_custom_avatar: false
 | 
			
		||||
  use_custom_avatar: true
 | 
			
		||||
  num_followers: 0
 | 
			
		||||
  num_following: 0
 | 
			
		||||
  num_stars: 0
 | 
			
		||||
| 
						 | 
				
			
			@ -1319,9 +1321,9 @@
 | 
			
		|||
  allow_import_local: false
 | 
			
		||||
  allow_create_organization: true
 | 
			
		||||
  prohibit_login: false
 | 
			
		||||
  avatar: avatar22
 | 
			
		||||
  avatar: ""
 | 
			
		||||
  avatar_email: abcde@gitea.com
 | 
			
		||||
  use_custom_avatar: false
 | 
			
		||||
  use_custom_avatar: true
 | 
			
		||||
  num_followers: 0
 | 
			
		||||
  num_following: 0
 | 
			
		||||
  num_stars: 0
 | 
			
		||||
| 
						 | 
				
			
			@ -1356,9 +1358,9 @@
 | 
			
		|||
  allow_import_local: false
 | 
			
		||||
  allow_create_organization: true
 | 
			
		||||
  prohibit_login: true
 | 
			
		||||
  avatar: avatar29
 | 
			
		||||
  avatar: ""
 | 
			
		||||
  avatar_email: user37@example.com
 | 
			
		||||
  use_custom_avatar: false
 | 
			
		||||
  use_custom_avatar: true
 | 
			
		||||
  num_followers: 0
 | 
			
		||||
  num_following: 0
 | 
			
		||||
  num_stars: 0
 | 
			
		||||
| 
						 | 
				
			
			@ -1393,9 +1395,9 @@
 | 
			
		|||
  allow_import_local: false
 | 
			
		||||
  allow_create_organization: true
 | 
			
		||||
  prohibit_login: false
 | 
			
		||||
  avatar: avatar38
 | 
			
		||||
  avatar: ""
 | 
			
		||||
  avatar_email: user38@example.com
 | 
			
		||||
  use_custom_avatar: false
 | 
			
		||||
  use_custom_avatar: true
 | 
			
		||||
  num_followers: 0
 | 
			
		||||
  num_following: 0
 | 
			
		||||
  num_stars: 0
 | 
			
		||||
| 
						 | 
				
			
			@ -1430,9 +1432,9 @@
 | 
			
		|||
  allow_import_local: false
 | 
			
		||||
  allow_create_organization: true
 | 
			
		||||
  prohibit_login: false
 | 
			
		||||
  avatar: avatar39
 | 
			
		||||
  avatar: ""
 | 
			
		||||
  avatar_email: user39@example.com
 | 
			
		||||
  use_custom_avatar: false
 | 
			
		||||
  use_custom_avatar: true
 | 
			
		||||
  num_followers: 0
 | 
			
		||||
  num_following: 0
 | 
			
		||||
  num_stars: 0
 | 
			
		||||
| 
						 | 
				
			
			@ -1467,9 +1469,9 @@
 | 
			
		|||
  allow_import_local: false
 | 
			
		||||
  allow_create_organization: true
 | 
			
		||||
  prohibit_login: false
 | 
			
		||||
  avatar: avatar40
 | 
			
		||||
  avatar: ""
 | 
			
		||||
  avatar_email: user40@example.com
 | 
			
		||||
  use_custom_avatar: false
 | 
			
		||||
  use_custom_avatar: true
 | 
			
		||||
  num_followers: 0
 | 
			
		||||
  num_following: 0
 | 
			
		||||
  num_stars: 0
 | 
			
		||||
| 
						 | 
				
			
			@ -1504,9 +1506,9 @@
 | 
			
		|||
  allow_import_local: false
 | 
			
		||||
  allow_create_organization: true
 | 
			
		||||
  prohibit_login: false
 | 
			
		||||
  avatar: avatar41
 | 
			
		||||
  avatar: ""
 | 
			
		||||
  avatar_email: org41@example.com
 | 
			
		||||
  use_custom_avatar: false
 | 
			
		||||
  use_custom_avatar: true
 | 
			
		||||
  num_followers: 0
 | 
			
		||||
  num_following: 0
 | 
			
		||||
  num_stars: 0
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -50,19 +50,19 @@ const (
 | 
			
		|||
	UserTypeIndividual UserType = iota // Historic reason to make it starts at 0.
 | 
			
		||||
 | 
			
		||||
	// UserTypeOrganization defines an organization
 | 
			
		||||
	UserTypeOrganization
 | 
			
		||||
	UserTypeOrganization // 1
 | 
			
		||||
 | 
			
		||||
	// UserTypeUserReserved reserves a (non-existing) user, i.e. to prevent a spam user from re-registering after being deleted, or to reserve the name until the user is actually created later on
 | 
			
		||||
	UserTypeUserReserved
 | 
			
		||||
	UserTypeUserReserved // 2
 | 
			
		||||
 | 
			
		||||
	// UserTypeOrganizationReserved reserves a (non-existing) organization, to be used in combination with UserTypeUserReserved
 | 
			
		||||
	UserTypeOrganizationReserved
 | 
			
		||||
	UserTypeOrganizationReserved // 3
 | 
			
		||||
 | 
			
		||||
	// UserTypeBot defines a bot user
 | 
			
		||||
	UserTypeBot
 | 
			
		||||
	UserTypeBot // 4
 | 
			
		||||
 | 
			
		||||
	// UserTypeRemoteUser defines a remote user for federated users
 | 
			
		||||
	UserTypeRemoteUser
 | 
			
		||||
	UserTypeRemoteUser // 5
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
| 
						 | 
				
			
			@ -919,7 +919,13 @@ func UpdateUserCols(ctx context.Context, u *User, cols ...string) error {
 | 
			
		|||
 | 
			
		||||
// GetInactiveUsers gets all inactive users
 | 
			
		||||
func GetInactiveUsers(ctx context.Context, olderThan time.Duration) ([]*User, error) {
 | 
			
		||||
	var cond builder.Cond = builder.Eq{"is_active": false}
 | 
			
		||||
	cond := builder.And(
 | 
			
		||||
		builder.Eq{"is_active": false},
 | 
			
		||||
		builder.Or( // only plain user
 | 
			
		||||
			builder.Eq{"`type`": UserTypeIndividual},
 | 
			
		||||
			builder.Eq{"`type`": UserTypeUserReserved},
 | 
			
		||||
		),
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	if olderThan > 0 {
 | 
			
		||||
		cond = cond.And(builder.Lt{"created_unix": time.Now().Add(-olderThan).Unix()})
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -766,3 +766,17 @@ func TestVerifyUserAuthorizationToken(t *testing.T) {
 | 
			
		|||
		assert.Nil(t, authToken)
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestGetInactiveUsers(t *testing.T) {
 | 
			
		||||
	require.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
	// all inactive users
 | 
			
		||||
	// user1's createdunix is 1730468968
 | 
			
		||||
	users, err := user_model.GetInactiveUsers(db.DefaultContext, 0)
 | 
			
		||||
	require.NoError(t, err)
 | 
			
		||||
	assert.Len(t, users, 1)
 | 
			
		||||
	interval := time.Now().Unix() - 1730468968 + 3600*24
 | 
			
		||||
	users, err = user_model.GetInactiveUsers(db.DefaultContext, time.Duration(interval*int64(time.Second)))
 | 
			
		||||
	require.NoError(t, err)
 | 
			
		||||
	require.Empty(t, users)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -17,6 +17,8 @@ import (
 | 
			
		|||
 | 
			
		||||
	"code.gitea.io/gitea/modules/log"
 | 
			
		||||
	"code.gitea.io/gitea/modules/util"
 | 
			
		||||
 | 
			
		||||
	"github.com/go-git/go-git/v5/config"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Commit represents a git commit.
 | 
			
		||||
| 
						 | 
				
			
			@ -365,37 +367,32 @@ func (c *Commit) GetSubModules() (*ObjectCache, error) {
 | 
			
		|||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	rd, err := entry.Blob().DataAsync()
 | 
			
		||||
	content, err := entry.Blob().GetBlobContent(10 * 1024)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	defer rd.Close()
 | 
			
		||||
	scanner := bufio.NewScanner(rd)
 | 
			
		||||
	c.submoduleCache = newObjectCache()
 | 
			
		||||
	var ismodule bool
 | 
			
		||||
	var path string
 | 
			
		||||
	for scanner.Scan() {
 | 
			
		||||
		if strings.HasPrefix(scanner.Text(), "[submodule") {
 | 
			
		||||
			ismodule = true
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		if ismodule {
 | 
			
		||||
			fields := strings.Split(scanner.Text(), "=")
 | 
			
		||||
			k := strings.TrimSpace(fields[0])
 | 
			
		||||
			if k == "path" {
 | 
			
		||||
				path = strings.TrimSpace(fields[1])
 | 
			
		||||
			} else if k == "url" {
 | 
			
		||||
				c.submoduleCache.Set(path, &SubModule{path, strings.TrimSpace(fields[1])})
 | 
			
		||||
				ismodule = false
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	c.submoduleCache, err = parseSubmoduleContent([]byte(content))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	if err = scanner.Err(); err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("GetSubModules scan: %w", err)
 | 
			
		||||
	return c.submoduleCache, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func parseSubmoduleContent(bs []byte) (*ObjectCache, error) {
 | 
			
		||||
	cfg := config.NewModules()
 | 
			
		||||
	if err := cfg.Unmarshal(bs); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	submoduleCache := newObjectCache()
 | 
			
		||||
	if len(cfg.Submodules) == 0 {
 | 
			
		||||
		return nil, fmt.Errorf("no submodules found")
 | 
			
		||||
	}
 | 
			
		||||
	for _, subModule := range cfg.Submodules {
 | 
			
		||||
		submoduleCache.Set(subModule.Path, subModule.URL)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return c.submoduleCache, nil
 | 
			
		||||
	return submoduleCache, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetSubModule get the sub module according entryname
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -369,3 +369,33 @@ func TestParseCommitRenames(t *testing.T) {
 | 
			
		|||
		assert.Equal(t, testcase.renames, renames)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func Test_parseSubmoduleContent(t *testing.T) {
 | 
			
		||||
	submoduleFiles := []struct {
 | 
			
		||||
		fileContent  string
 | 
			
		||||
		expectedPath string
 | 
			
		||||
		expectedURL  string
 | 
			
		||||
	}{
 | 
			
		||||
		{
 | 
			
		||||
			fileContent: `[submodule "jakarta-servlet"]
 | 
			
		||||
url = ../../ALP-pool/jakarta-servlet
 | 
			
		||||
path = jakarta-servlet`,
 | 
			
		||||
			expectedPath: "jakarta-servlet",
 | 
			
		||||
			expectedURL:  "../../ALP-pool/jakarta-servlet",
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			fileContent: `[submodule "jakarta-servlet"]
 | 
			
		||||
path = jakarta-servlet
 | 
			
		||||
url = ../../ALP-pool/jakarta-servlet`,
 | 
			
		||||
			expectedPath: "jakarta-servlet",
 | 
			
		||||
			expectedURL:  "../../ALP-pool/jakarta-servlet",
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	for _, kase := range submoduleFiles {
 | 
			
		||||
		submodule, err := parseSubmoduleContent([]byte(kase.fileContent))
 | 
			
		||||
		require.NoError(t, err)
 | 
			
		||||
		v, ok := submodule.Get(kase.expectedPath)
 | 
			
		||||
		assert.True(t, ok)
 | 
			
		||||
		assert.Equal(t, kase.expectedURL, v)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,8 +4,6 @@
 | 
			
		|||
package repository
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"crypto/md5"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"testing"
 | 
			
		||||
	"time"
 | 
			
		||||
| 
						 | 
				
			
			@ -126,15 +124,12 @@ func TestPushCommits_AvatarLink(t *testing.T) {
 | 
			
		|||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	setting.GravatarSource = "https://secure.gravatar.com/avatar"
 | 
			
		||||
	setting.OfflineMode = true
 | 
			
		||||
 | 
			
		||||
	assert.Equal(t,
 | 
			
		||||
		"/avatars/avatar2?size="+strconv.Itoa(28*setting.Avatar.RenderedSizeFactor),
 | 
			
		||||
		"/avatars/ab53a2911ddf9b4817ac01ddcd3d975f?size="+strconv.Itoa(28*setting.Avatar.RenderedSizeFactor),
 | 
			
		||||
		pushCommits.AvatarLink(db.DefaultContext, "user2@example.com"))
 | 
			
		||||
 | 
			
		||||
	assert.Equal(t,
 | 
			
		||||
		fmt.Sprintf("https://secure.gravatar.com/avatar/%x?d=identicon&s=%d", md5.Sum([]byte("nonexistent@example.com")), 28*setting.Avatar.RenderedSizeFactor),
 | 
			
		||||
		"/assets/img/avatar_default.png",
 | 
			
		||||
		pushCommits.AvatarLink(db.DefaultContext, "nonexistent@example.com"))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										4
									
								
								release-notes/6062.md
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								release-notes/6062.md
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,4 @@
 | 
			
		|||
fix: [commit](https://codeberg.org/forgejo/forgejo/commit/32a91add34519ef7768ec907888ed837ad0dde2f) Fix GetInactiveUsers
 | 
			
		||||
fix: [commit](https://codeberg.org/forgejo/forgejo/commit/64824290912b6300ede2b2f95ff77d55dde9859b) Fix submodule parsing
 | 
			
		||||
fix: [commit](https://codeberg.org/forgejo/forgejo/commit/ddabba5f89c4b196daeeb2af17de9ec2cec14b63) allow the actions user to login via the jwt token
 | 
			
		||||
feat: [commit](https://codeberg.org/forgejo/forgejo/commit/262c48409b1224e3f6dc63c8d1e04fef0e0cf2c0) Support HTTP POST requests to `/userinfo`, aligning to OpenID Core specification
 | 
			
		||||
| 
						 | 
				
			
			@ -133,11 +133,6 @@ func DeleteBranch(ctx *context.APIContext) {
 | 
			
		|||
 | 
			
		||||
	branchName := ctx.Params("*")
 | 
			
		||||
 | 
			
		||||
	if ctx.Repo.Repository.IsEmpty {
 | 
			
		||||
		ctx.Error(http.StatusForbidden, "", "Git Repository is empty.")
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// check whether branches of this repository has been synced
 | 
			
		||||
	totalNumOfBranches, err := db.Count[git_model.Branch](ctx, git_model.FindBranchOptions{
 | 
			
		||||
		RepoID:          ctx.Repo.Repository.ID,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -530,7 +530,7 @@ func registerRoutes(m *web.Route) {
 | 
			
		|||
			m.Post("/authorize", web.Bind(forms.AuthorizationForm{}), auth.AuthorizeOAuth)
 | 
			
		||||
		}, ignSignInAndCsrf, reqSignIn)
 | 
			
		||||
 | 
			
		||||
		m.Methods("GET, OPTIONS", "/userinfo", optionsCorsHandler(), ignSignInAndCsrf, auth.InfoOAuth)
 | 
			
		||||
		m.Methods("GET, POST, OPTIONS", "/userinfo", optionsCorsHandler(), ignSignInAndCsrf, auth.InfoOAuth)
 | 
			
		||||
		m.Methods("POST, OPTIONS", "/access_token", optionsCorsHandler(), web.Bind(forms.AccessTokenForm{}), ignSignInAndCsrf, auth.AccessTokenOAuth)
 | 
			
		||||
		m.Methods("GET, OPTIONS", "/keys", optionsCorsHandler(), ignSignInAndCsrf, auth.OIDCKeys)
 | 
			
		||||
		m.Methods("POST, OPTIONS", "/introspect", optionsCorsHandler(), web.Bind(forms.IntrospectTokenForm{}), ignSignInAndCsrf, auth.IntrospectOAuth)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -83,7 +83,12 @@ func ParseAuthorizationToken(req *http.Request) (int64, error) {
 | 
			
		|||
		return 0, fmt.Errorf("split token failed")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	token, err := jwt.ParseWithClaims(parts[1], &actionsClaims{}, func(t *jwt.Token) (any, error) {
 | 
			
		||||
	return TokenToTaskID(parts[1])
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TokenToTaskID returns the TaskID associated with the provided JWT token
 | 
			
		||||
func TokenToTaskID(token string) (int64, error) {
 | 
			
		||||
	parsedToken, err := jwt.ParseWithClaims(token, &actionsClaims{}, func(t *jwt.Token) (any, error) {
 | 
			
		||||
		if _, ok := t.Method.(*jwt.SigningMethodHMAC); !ok {
 | 
			
		||||
			return nil, fmt.Errorf("unexpected signing method: %v", t.Header["alg"])
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -93,8 +98,8 @@ func ParseAuthorizationToken(req *http.Request) (int64, error) {
 | 
			
		|||
		return 0, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	c, ok := token.Claims.(*actionsClaims)
 | 
			
		||||
	if !token.Valid || !ok {
 | 
			
		||||
	c, ok := parsedToken.Claims.(*actionsClaims)
 | 
			
		||||
	if !parsedToken.Valid || !ok {
 | 
			
		||||
		return 0, fmt.Errorf("invalid token claim")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -18,6 +18,7 @@ import (
 | 
			
		|||
	"code.gitea.io/gitea/modules/setting"
 | 
			
		||||
	"code.gitea.io/gitea/modules/timeutil"
 | 
			
		||||
	"code.gitea.io/gitea/modules/web/middleware"
 | 
			
		||||
	"code.gitea.io/gitea/services/actions"
 | 
			
		||||
	"code.gitea.io/gitea/services/auth/source/oauth2"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -94,6 +95,18 @@ func CheckOAuthAccessToken(ctx context.Context, accessToken string) (int64, stri
 | 
			
		|||
	return grant.UserID, grantScopes
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CheckTaskIsRunning verifies that the TaskID corresponds to a running task
 | 
			
		||||
func CheckTaskIsRunning(ctx context.Context, taskID int64) bool {
 | 
			
		||||
	// Verify the task exists
 | 
			
		||||
	task, err := actions_model.GetTaskByID(ctx, taskID)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Verify that it's running
 | 
			
		||||
	return task.Status == actions_model.StatusRunning
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// OAuth2 implements the Auth interface and authenticates requests
 | 
			
		||||
// (API requests only) by looking for an OAuth token in query parameters or the
 | 
			
		||||
// "Authorization" header.
 | 
			
		||||
| 
						 | 
				
			
			@ -137,8 +150,17 @@ func parseToken(req *http.Request) (string, bool) {
 | 
			
		|||
func (o *OAuth2) userIDFromToken(ctx context.Context, tokenSHA string, store DataStore) int64 {
 | 
			
		||||
	// Let's see if token is valid.
 | 
			
		||||
	if strings.Contains(tokenSHA, ".") {
 | 
			
		||||
		uid, grantScopes := CheckOAuthAccessToken(ctx, tokenSHA)
 | 
			
		||||
		// First attempt to decode an actions JWT, returning the actions user
 | 
			
		||||
		if taskID, err := actions.TokenToTaskID(tokenSHA); err == nil {
 | 
			
		||||
			if CheckTaskIsRunning(ctx, taskID) {
 | 
			
		||||
				store.GetData()["IsActionsToken"] = true
 | 
			
		||||
				store.GetData()["ActionsTaskID"] = taskID
 | 
			
		||||
				return user_model.ActionsUserID
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Otherwise, check if this is an OAuth access token
 | 
			
		||||
		uid, grantScopes := CheckOAuthAccessToken(ctx, tokenSHA)
 | 
			
		||||
		if uid != 0 {
 | 
			
		||||
			store.GetData()["IsApiToken"] = true
 | 
			
		||||
			if grantScopes != "" {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										55
									
								
								services/auth/oauth2_test.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								services/auth/oauth2_test.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,55 @@
 | 
			
		|||
// Copyright 2024 The Gitea Authors. All rights reserved.
 | 
			
		||||
// SPDX-License-Identifier: MIT
 | 
			
		||||
 | 
			
		||||
package auth
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/models/unittest"
 | 
			
		||||
	user_model "code.gitea.io/gitea/models/user"
 | 
			
		||||
	"code.gitea.io/gitea/modules/web/middleware"
 | 
			
		||||
	"code.gitea.io/gitea/services/actions"
 | 
			
		||||
 | 
			
		||||
	"github.com/stretchr/testify/assert"
 | 
			
		||||
	"github.com/stretchr/testify/require"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestUserIDFromToken(t *testing.T) {
 | 
			
		||||
	require.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
	t.Run("Actions JWT", func(t *testing.T) {
 | 
			
		||||
		const RunningTaskID = 47
 | 
			
		||||
		token, err := actions.CreateAuthorizationToken(RunningTaskID, 1, 2)
 | 
			
		||||
		require.NoError(t, err)
 | 
			
		||||
 | 
			
		||||
		ds := make(middleware.ContextData)
 | 
			
		||||
 | 
			
		||||
		o := OAuth2{}
 | 
			
		||||
		uid := o.userIDFromToken(context.Background(), token, ds)
 | 
			
		||||
		assert.Equal(t, int64(user_model.ActionsUserID), uid)
 | 
			
		||||
		assert.Equal(t, true, ds["IsActionsToken"])
 | 
			
		||||
		assert.Equal(t, ds["ActionsTaskID"], int64(RunningTaskID))
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestCheckTaskIsRunning(t *testing.T) {
 | 
			
		||||
	require.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	cases := map[string]struct {
 | 
			
		||||
		TaskID   int64
 | 
			
		||||
		Expected bool
 | 
			
		||||
	}{
 | 
			
		||||
		"Running":   {TaskID: 47, Expected: true},
 | 
			
		||||
		"Missing":   {TaskID: 1, Expected: false},
 | 
			
		||||
		"Cancelled": {TaskID: 46, Expected: false},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for name := range cases {
 | 
			
		||||
		c := cases[name]
 | 
			
		||||
		t.Run(name, func(t *testing.T) {
 | 
			
		||||
			actual := CheckTaskIsRunning(context.Background(), c.TaskID)
 | 
			
		||||
			assert.Equal(t, c.Expected, actual)
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -413,14 +413,7 @@ func repoAssignment(ctx *Context, repo *repo_model.Repository) {
 | 
			
		|||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pushMirrors, _, err := repo_model.GetPushMirrorsByRepoID(ctx, repo.ID, db.ListOptions{})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		ctx.ServerError("GetPushMirrorsByRepoID", err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ctx.Repo.Repository = repo
 | 
			
		||||
	ctx.Data["PushMirrors"] = pushMirrors
 | 
			
		||||
	ctx.Data["RepoName"] = ctx.Repo.Repository.Name
 | 
			
		||||
	ctx.Data["IsEmptyRepo"] = ctx.Repo.Repository.IsEmpty
 | 
			
		||||
	ctx.Data["DefaultWikiBranchName"] = setting.Repository.DefaultBranch
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -43,7 +43,7 @@ func TestRepository_ContributorsGraph(t *testing.T) {
 | 
			
		|||
	dataString, isData := mockCache.Get("key2").(string)
 | 
			
		||||
	assert.True(t, isData)
 | 
			
		||||
	// Verify that JSON is actually stored in the cache.
 | 
			
		||||
	assert.JSONEq(t, `{"ethantkoenig@gmail.com":{"name":"Ethan Koenig","login":"","avatar_link":"https://secure.gravatar.com/avatar/b42fb195faa8c61b8d88abfefe30e9e3?d=identicon","home_link":"","total_commits":1,"weeks":{"1511654400000":{"week":1511654400000,"additions":3,"deletions":0,"commits":1}}},"jimmy.praet@telenet.be":{"name":"Jimmy Praet","login":"","avatar_link":"https://secure.gravatar.com/avatar/93c49b7c89eb156971d11161c9b52795?d=identicon","home_link":"","total_commits":1,"weeks":{"1624752000000":{"week":1624752000000,"additions":2,"deletions":0,"commits":1}}},"jon@allspice.io":{"name":"Jon","login":"","avatar_link":"https://secure.gravatar.com/avatar/00388ce725e6886f3e07c3733007289b?d=identicon","home_link":"","total_commits":1,"weeks":{"1607817600000":{"week":1607817600000,"additions":10,"deletions":0,"commits":1}}},"total":{"name":"Total","login":"","avatar_link":"","home_link":"","total_commits":3,"weeks":{"1511654400000":{"week":1511654400000,"additions":3,"deletions":0,"commits":1},"1607817600000":{"week":1607817600000,"additions":10,"deletions":0,"commits":1},"1624752000000":{"week":1624752000000,"additions":2,"deletions":0,"commits":1}}}}`, dataString)
 | 
			
		||||
	assert.JSONEq(t, `{"ethantkoenig@gmail.com":{"name":"Ethan Koenig","login":"","avatar_link":"/assets/img/avatar_default.png","home_link":"","total_commits":1,"weeks":{"1511654400000":{"week":1511654400000,"additions":3,"deletions":0,"commits":1}}},"jimmy.praet@telenet.be":{"name":"Jimmy Praet","login":"","avatar_link":"/assets/img/avatar_default.png","home_link":"","total_commits":1,"weeks":{"1624752000000":{"week":1624752000000,"additions":2,"deletions":0,"commits":1}}},"jon@allspice.io":{"name":"Jon","login":"","avatar_link":"/assets/img/avatar_default.png","home_link":"","total_commits":1,"weeks":{"1607817600000":{"week":1607817600000,"additions":10,"deletions":0,"commits":1}}},"total":{"name":"Total","login":"","avatar_link":"","home_link":"","total_commits":3,"weeks":{"1511654400000":{"week":1511654400000,"additions":3,"deletions":0,"commits":1},"1607817600000":{"week":1607817600000,"additions":10,"deletions":0,"commits":1},"1624752000000":{"week":1624752000000,"additions":2,"deletions":0,"commits":1}}}}`, dataString)
 | 
			
		||||
 | 
			
		||||
	var data map[string]*ContributorData
 | 
			
		||||
	require.NoError(t, json.Unmarshal([]byte(dataString), &data))
 | 
			
		||||
| 
						 | 
				
			
			@ -62,7 +62,7 @@ func TestRepository_ContributorsGraph(t *testing.T) {
 | 
			
		|||
 | 
			
		||||
	assert.EqualValues(t, &ContributorData{
 | 
			
		||||
		Name:         "Ethan Koenig",
 | 
			
		||||
		AvatarLink:   "https://secure.gravatar.com/avatar/b42fb195faa8c61b8d88abfefe30e9e3?d=identicon",
 | 
			
		||||
		AvatarLink:   "/assets/img/avatar_default.png",
 | 
			
		||||
		TotalCommits: 1,
 | 
			
		||||
		Weeks: map[int64]*WeekData{
 | 
			
		||||
			1511654400000: {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,6 +5,7 @@ package integration
 | 
			
		|||
 | 
			
		||||
import (
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/modules/setting"
 | 
			
		||||
| 
						 | 
				
			
			@ -42,7 +43,7 @@ func TestOpenGraphProperties(t *testing.T) {
 | 
			
		|||
				"og:title":     "User Thirty",
 | 
			
		||||
				"og:url":       setting.AppURL + "user30",
 | 
			
		||||
				"og:type":      "profile",
 | 
			
		||||
				"og:image":     "https://secure.gravatar.com/avatar/eae1f44b34ff27284cb0792c7601c89c?d=identicon",
 | 
			
		||||
				"og:image":     "http://localhost:3003/assets/img/avatar_default.png",
 | 
			
		||||
				"og:site_name": siteName,
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
| 
						 | 
				
			
			@ -54,7 +55,7 @@ func TestOpenGraphProperties(t *testing.T) {
 | 
			
		|||
				"og:url":         setting.AppURL + "the_34-user.with.all.allowedChars",
 | 
			
		||||
				"og:description": "some [commonmark](https://commonmark.org/)!",
 | 
			
		||||
				"og:type":        "profile",
 | 
			
		||||
				"og:image":       setting.AppURL + "avatars/avatar34",
 | 
			
		||||
				"og:image":       "http://localhost:3003/assets/img/avatar_default.png",
 | 
			
		||||
				"og:site_name":   siteName,
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
| 
						 | 
				
			
			@ -66,7 +67,7 @@ func TestOpenGraphProperties(t *testing.T) {
 | 
			
		|||
				"og:url":         setting.AppURL + "user2/repo1/issues/1",
 | 
			
		||||
				"og:description": "content for the first issue",
 | 
			
		||||
				"og:type":        "object",
 | 
			
		||||
				"og:image":       "https://secure.gravatar.com/avatar/ab53a2911ddf9b4817ac01ddcd3d975f?d=identicon",
 | 
			
		||||
				"og:image":       "http://localhost:3003/avatars/ab53a2911ddf9b4817ac01ddcd3d975f",
 | 
			
		||||
				"og:site_name":   siteName,
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
| 
						 | 
				
			
			@ -78,7 +79,7 @@ func TestOpenGraphProperties(t *testing.T) {
 | 
			
		|||
				"og:url":         setting.AppURL + "user2/repo1/pulls/2",
 | 
			
		||||
				"og:description": "content for the second issue",
 | 
			
		||||
				"og:type":        "object",
 | 
			
		||||
				"og:image":       "https://secure.gravatar.com/avatar/ab53a2911ddf9b4817ac01ddcd3d975f?d=identicon",
 | 
			
		||||
				"og:image":       "http://localhost:3003/avatars/ab53a2911ddf9b4817ac01ddcd3d975f",
 | 
			
		||||
				"og:site_name":   siteName,
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
| 
						 | 
				
			
			@ -89,7 +90,7 @@ func TestOpenGraphProperties(t *testing.T) {
 | 
			
		|||
				"og:title":     "repo49/test/test.txt at master",
 | 
			
		||||
				"og:url":       setting.AppURL + "/user27/repo49/src/branch/master/test/test.txt",
 | 
			
		||||
				"og:type":      "object",
 | 
			
		||||
				"og:image":     "https://secure.gravatar.com/avatar/7095710e927665f1bdd1ced94152f232?d=identicon",
 | 
			
		||||
				"og:image":     "http://localhost:3003/assets/img/avatar_default.png",
 | 
			
		||||
				"og:site_name": siteName,
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
| 
						 | 
				
			
			@ -100,7 +101,7 @@ func TestOpenGraphProperties(t *testing.T) {
 | 
			
		|||
				"og:title":     "Page With Spaced Name",
 | 
			
		||||
				"og:url":       setting.AppURL + "/user2/repo1/wiki/Page-With-Spaced-Name",
 | 
			
		||||
				"og:type":      "object",
 | 
			
		||||
				"og:image":     "https://secure.gravatar.com/avatar/ab53a2911ddf9b4817ac01ddcd3d975f?d=identicon",
 | 
			
		||||
				"og:image":     "http://localhost:3003/avatars/ab53a2911ddf9b4817ac01ddcd3d975f",
 | 
			
		||||
				"og:site_name": siteName,
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
| 
						 | 
				
			
			@ -111,7 +112,7 @@ func TestOpenGraphProperties(t *testing.T) {
 | 
			
		|||
				"og:title":     "repo1",
 | 
			
		||||
				"og:url":       setting.AppURL + "user2/repo1",
 | 
			
		||||
				"og:type":      "object",
 | 
			
		||||
				"og:image":     "https://secure.gravatar.com/avatar/ab53a2911ddf9b4817ac01ddcd3d975f?d=identicon",
 | 
			
		||||
				"og:image":     "http://localhost:3003/avatars/ab53a2911ddf9b4817ac01ddcd3d975f",
 | 
			
		||||
				"og:site_name": siteName,
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
| 
						 | 
				
			
			@ -123,7 +124,7 @@ func TestOpenGraphProperties(t *testing.T) {
 | 
			
		|||
				"og:url":         setting.AppURL + "user27/repo49",
 | 
			
		||||
				"og:description": "A wonderful repository with more than just a README.md",
 | 
			
		||||
				"og:type":        "object",
 | 
			
		||||
				"og:image":       "https://secure.gravatar.com/avatar/7095710e927665f1bdd1ced94152f232?d=identicon",
 | 
			
		||||
				"og:image":       "http://localhost:3003/assets/img/avatar_default.png",
 | 
			
		||||
				"og:site_name":   siteName,
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
| 
						 | 
				
			
			@ -141,6 +142,10 @@ func TestOpenGraphProperties(t *testing.T) {
 | 
			
		|||
				assert.True(t, foundProp)
 | 
			
		||||
				content, foundContent := selection.Attr("content")
 | 
			
		||||
				assert.True(t, foundContent, "opengraph meta tag without a content property")
 | 
			
		||||
				if prop == "og:image" {
 | 
			
		||||
					content = strings.ReplaceAll(content, "http://localhost:3001", "http://localhost:3003")
 | 
			
		||||
					content = strings.ReplaceAll(content, "http://localhost:3002", "http://localhost:3003")
 | 
			
		||||
				}
 | 
			
		||||
				foundProps[prop] = content
 | 
			
		||||
			})
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue