Coverage for app/venv/lib/python3.14/site-packages/weblate/urls.py: 80%

79 statements  

« prev     ^ index     » next       coverage.py v7.15.2, created at 2026-10-07 07:15 +0000

1# Copyright © Michal Čihař <michal@weblate.org> 

2# 

3# SPDX-License-Identifier: GPL-3.0-or-later 

4 

5from __future__ import annotations 

6 

7import django.contrib.sitemaps.views 

8import django.views.i18n 

9import django.views.static 

10from django.conf import settings 

11from django.contrib import admin 

12from django.urls import include, path, re_path 

13from django.views.decorators.cache import cache_control, cache_page 

14from django.views.decorators.vary import vary_on_cookie 

15from django.views.generic import RedirectView, TemplateView 

16from drf_spectacular.views import ( 

17 SpectacularAPIView, 

18 SpectacularRedocView, 

19) 

20 

21import weblate.accounts.urls 

22import weblate.accounts.views 

23import weblate.addons.views 

24import weblate.api.urls 

25import weblate.auth.views 

26import weblate.checks.views 

27import weblate.fonts.views 

28import weblate.glossary.views 

29import weblate.lang.views 

30import weblate.machinery.views 

31import weblate.memory.views 

32import weblate.screenshots.views 

33import weblate.trans.views.about 

34import weblate.trans.views.acl 

35import weblate.trans.views.agreement 

36import weblate.trans.views.basic 

37import weblate.trans.views.charts 

38import weblate.trans.views.create 

39import weblate.trans.views.dashboard 

40import weblate.trans.views.edit 

41import weblate.trans.views.error 

42import weblate.trans.views.files 

43import weblate.trans.views.git 

44import weblate.trans.views.js 

45import weblate.trans.views.labels 

46import weblate.trans.views.lock 

47import weblate.trans.views.reports 

48import weblate.trans.views.search 

49import weblate.trans.views.settings 

50import weblate.trans.views.source 

51import weblate.trans.views.widgets 

52import weblate.wladmin.views 

53from weblate.auth.decorators import management_access 

54from weblate.configuration.views import CustomCSSView 

55from weblate.sitemaps import SITEMAPS 

56from weblate.trans.feeds import ChangesFeed, LanguageChangesFeed, TranslationChangesFeed 

57from weblate.trans.views.changes import ChangesCSVView, ChangesView, show_change 

58from weblate.trans.views.hooks import ServiceHookView 

59from weblate.utils.version import VERSION 

60 

61handler400 = weblate.trans.views.error.bad_request 

62handler403 = weblate.trans.views.error.denied 

63handler404 = weblate.trans.views.error.not_found 

64handler500 = weblate.trans.views.error.server_error 

65 

66widget_pattern = "<word:widget>-<word:color>.<extension:extension>" 

67 

68URL_PREFIX = settings.URL_PREFIX 

69if URL_PREFIX: 69 ↛ 70line 69 didn't jump to line 70 because the condition on line 69 was never true

70 URL_PREFIX = URL_PREFIX.strip("/") + "/" 

71 

72real_patterns = [ 

73 path("", weblate.trans.views.dashboard.home, name="home"), 

74 path("projects/", weblate.trans.views.basic.list_projects, name="projects"), 

75 # Object display 

76 path( 

77 "projects/<object_path:path>/", 

78 weblate.trans.views.basic.show, 

79 name="show", 

80 ), 

81 # Engagement pages 

82 path( 

83 "engage/<object_path:path>/", 

84 weblate.trans.views.basic.show_engage, 

85 name="engage", 

86 ), 

87 # Component pages 

88 path( 

89 "guide/<object_path:path>/", 

90 weblate.trans.views.basic.guide, 

91 name="guide", 

92 ), 

93 path( 

94 "matrix/<object_path:path>/", 

95 weblate.trans.views.source.matrix, 

96 name="matrix", 

97 ), 

98 path( 

99 "js/matrix/<object_path:path>/", 

100 weblate.trans.views.source.matrix_load, 

101 name="matrix-load", 

102 ), 

103 path( 

104 "source/<int:pk>/context/", 

105 weblate.trans.views.source.edit_context, 

106 name="edit_context", 

107 ), 

108 # Translation pages 

109 path( 

110 "component-list/<name:name>/", 

111 weblate.trans.views.basic.show_component_list, 

112 name="component-list", 

113 ), 

114 path( 

115 "component-list/<name:name>/dashboard/", 

116 weblate.trans.views.dashboard.component_list_user, 

117 name="component-list-dashboard", 

118 ), 

119 path( 

120 "browse/<object_path:path>/", 

121 weblate.trans.views.edit.browse, 

122 name="browse", 

123 ), 

124 path( 

125 "translate/<object_path:path>/", 

126 weblate.trans.views.edit.translate, 

127 name="translate", 

128 ), 

129 path( 

130 "zen/<object_path:path>/", 

131 weblate.trans.views.edit.zen, 

132 name="zen", 

133 ), 

134 path( 

135 "download/<object_path:path>/", 

136 weblate.trans.views.files.download, 

137 name="download", 

138 ), 

139 path( 

140 "download-list/<name:name>/", 

141 weblate.trans.views.files.download_component_list, 

142 name="download_component_list", 

143 ), 

144 path( 

145 "upload/<object_path:path>/", 

146 weblate.trans.views.files.upload, 

147 name="upload", 

148 ), 

149 path( 

150 "unit/<int:unit_id>/delete/", 

151 weblate.trans.views.edit.delete_unit, 

152 name="delete-unit", 

153 ), 

154 path( 

155 "new-unit/<object_path:path>/", 

156 weblate.trans.views.edit.new_unit, 

157 name="new-unit", 

158 ), 

159 path( 

160 "auto-translate/<object_path:path>/", 

161 weblate.trans.views.edit.auto_translation, 

162 name="auto_translation", 

163 ), 

164 path( 

165 "replace/<object_path:path>/", 

166 weblate.trans.views.search.search_replace, 

167 name="replace", 

168 ), 

169 path( 

170 "bulk-edit/<object_path:path>/", 

171 weblate.trans.views.search.bulk_edit, 

172 name="bulk-edit", 

173 ), 

174 path("credits/", weblate.trans.views.reports.get_credits, name="credits"), 

175 path("counts/", weblate.trans.views.reports.get_counts, name="counts"), 

176 path( 

177 "credits/<object_path:path>/", 

178 weblate.trans.views.reports.get_credits, 

179 name="credits", 

180 ), 

181 path( 

182 "counts/<object_path:path>/", 

183 weblate.trans.views.reports.get_counts, 

184 name="counts", 

185 ), 

186 path( 

187 "new-lang/<object_path:path>/", 

188 weblate.trans.views.basic.new_language, 

189 name="new-language", 

190 ), 

191 path( 

192 "new-lang/", 

193 weblate.lang.views.CreateLanguageView.as_view(), 

194 name="create-language", 

195 ), 

196 path( 

197 "addons/<object_path:path>/", 

198 weblate.addons.views.AddonList.as_view(), 

199 name="addons", 

200 ), 

201 path( 

202 "addon/<int:pk>/", 

203 weblate.addons.views.AddonDetail.as_view(), 

204 name="addon-detail", 

205 ), 

206 path( 

207 "addon/<int:pk>/logs/", 

208 weblate.addons.views.AddonLogs.as_view(), 

209 name="addon-logs", 

210 ), 

211 path( 

212 "access/<name:project>/", 

213 weblate.trans.views.acl.manage_access, 

214 name="manage-access", 

215 ), 

216 path( 

217 "settings/<object_path:path>/", 

218 weblate.trans.views.settings.change, 

219 name="settings", 

220 ), 

221 path( 

222 "backups/<name:project>/", 

223 weblate.trans.views.settings.BackupsView.as_view(), 

224 name="backups", 

225 ), 

226 path( 

227 "backups/<name:project>/<name:backup>", 

228 weblate.trans.views.settings.BackupsDownloadView.as_view(), 

229 name="backups-download", 

230 ), 

231 path( 

232 "labels/<name:project>/", 

233 weblate.trans.views.labels.project_labels, 

234 name="labels", 

235 ), 

236 path( 

237 "labels/<name:project>/edit/<int:pk>/", 

238 weblate.trans.views.labels.label_edit, 

239 name="label_edit", 

240 ), 

241 path( 

242 "labels/<name:project>/delete/<int:pk>/", 

243 weblate.trans.views.labels.label_delete, 

244 name="label_delete", 

245 ), 

246 path( 

247 "fonts/<name:project>/", 

248 weblate.fonts.views.FontListView.as_view(), 

249 name="fonts", 

250 ), 

251 path( 

252 "fonts/<name:project>/font/<int:pk>/", 

253 weblate.fonts.views.FontDetailView.as_view(), 

254 name="font", 

255 ), 

256 path( 

257 "fonts/<name:project>/group/<int:pk>/", 

258 weblate.fonts.views.FontGroupDetailView.as_view(), 

259 name="font_group", 

260 ), 

261 path( 

262 "create/project/", 

263 weblate.trans.views.create.CreateProject.as_view(), 

264 name="create-project", 

265 ), 

266 path( 

267 "create/project/import/", 

268 weblate.trans.views.create.ImportProject.as_view(), 

269 name="create-project-import", 

270 ), 

271 path( 

272 "create/component/", 

273 weblate.trans.views.create.CreateComponentSelection.as_view(), 

274 name="create-component", 

275 ), 

276 path( 

277 "create/component/vcs/", 

278 weblate.trans.views.create.CreateComponent.as_view(), 

279 name="create-component-vcs", 

280 ), 

281 path( 

282 "create/component/zip/", 

283 weblate.trans.views.create.CreateFromZip.as_view(), 

284 name="create-component-zip", 

285 ), 

286 path( 

287 "create/component/doc/", 

288 weblate.trans.views.create.CreateFromDoc.as_view(), 

289 name="create-component-doc", 

290 ), 

291 path( 

292 "contributor-agreement/<object_path:path>", 

293 weblate.trans.views.agreement.agreement_confirm, 

294 name="contributor-agreement", 

295 ), 

296 path( 

297 "access/<name:project>/add/", 

298 weblate.trans.views.acl.add_user, 

299 name="add-user", 

300 ), 

301 path( 

302 "access/<name:project>/block/", 

303 weblate.trans.views.acl.block_user, 

304 name="block-user", 

305 ), 

306 path( 

307 "access/<name:project>/unblock/", 

308 weblate.trans.views.acl.unblock_user, 

309 name="unblock-user", 

310 ), 

311 path( 

312 "access/<name:project>/invite/", 

313 weblate.trans.views.acl.invite_user, 

314 name="invite-user", 

315 ), 

316 path( 

317 "access/<name:project>/remove/", 

318 weblate.trans.views.acl.delete_user, 

319 name="delete-user", 

320 ), 

321 path( 

322 "access/<name:project>/set/", 

323 weblate.trans.views.acl.set_groups, 

324 name="set-groups", 

325 ), 

326 path( 

327 "access/<name:project>/team/create/", 

328 weblate.trans.views.acl.create_group, 

329 name="create-project-group", 

330 ), 

331 path( 

332 "token/<name:project>/create/", 

333 weblate.trans.views.acl.create_token, 

334 name="create-project-token", 

335 ), 

336 # Used by weblate.org to render own activity chart on homepage 

337 path( 

338 "activity/month.json", 

339 weblate.trans.views.charts.monthly_activity_json, 

340 name="monthly_activity_json", 

341 ), 

342 # Comments 

343 path("comment/<int:pk>/", weblate.trans.views.edit.comment, name="comment"), 

344 path( 

345 "comment/<int:pk>/delete/", 

346 weblate.trans.views.edit.delete_comment, 

347 name="delete-comment", 

348 ), 

349 path( 

350 "comment/<int:pk>/resolve/", 

351 weblate.trans.views.edit.resolve_comment, 

352 name="resolve-comment", 

353 ), 

354 # VCS manipulation - commit 

355 path( 

356 "commit/<object_path:path>/", 

357 weblate.trans.views.git.commit, 

358 name="commit", 

359 ), 

360 # VCS manipulation - update 

361 path( 

362 "update/<object_path:path>/", 

363 weblate.trans.views.git.update, 

364 name="update", 

365 ), 

366 # VCS manipulation - push 

367 path( 

368 "push/<object_path:path>/", 

369 weblate.trans.views.git.push, 

370 name="push", 

371 ), 

372 # VCS manipulation - reset 

373 path( 

374 "reset/<object_path:path>/", 

375 weblate.trans.views.git.reset, 

376 name="reset", 

377 ), 

378 # VCS manipulation - cleanup 

379 path( 

380 "cleanup/<object_path:path>/", 

381 weblate.trans.views.git.cleanup, 

382 name="cleanup", 

383 ), 

384 # VCS manipulation - force sync 

385 path( 

386 "file-sync/<object_path:path>/", 

387 weblate.trans.views.git.file_sync, 

388 name="file_sync", 

389 ), 

390 # VCS manipulation - force scan 

391 path( 

392 "file-scan/<object_path:path>/", 

393 weblate.trans.views.git.file_scan, 

394 name="file_scan", 

395 ), 

396 path( 

397 "progress/<object_path:path>/", 

398 weblate.trans.views.settings.show_progress, 

399 name="show_progress", 

400 ), 

401 # Announcements 

402 path( 

403 "announcement/<object_path:path>/", 

404 weblate.trans.views.settings.announcement, 

405 name="announcement", 

406 ), 

407 path( 

408 "js/announcement/<int:pk>/delete/", 

409 weblate.trans.views.settings.announcement_delete, 

410 name="announcement-delete", 

411 ), 

412 # VCS manipulation - remove 

413 path( 

414 "remove/<object_path:path>/", 

415 weblate.trans.views.settings.remove, 

416 name="remove", 

417 ), 

418 # Project renaming and moving 

419 path( 

420 "rename/<object_path:path>/", weblate.trans.views.settings.rename, name="rename" 

421 ), 

422 path( 

423 "category/add/<object_path:path>/", 

424 weblate.trans.views.settings.add_category, 

425 name="add-category", 

426 ), 

427 # Alerts dismiss 

428 path( 

429 "alerts/<object_path:path>/dismiss/", 

430 weblate.trans.views.settings.dismiss_alert, 

431 name="dismiss-alert", 

432 ), 

433 # Locking 

434 path( 

435 "lock/<object_path:path>/", 

436 weblate.trans.views.lock.lock, 

437 name="lock", 

438 ), 

439 path( 

440 "unlock/<object_path:path>/", 

441 weblate.trans.views.lock.unlock, 

442 name="unlock", 

443 ), 

444 # Screenshots 

445 path( 

446 "screenshots/<object_path:path>/", 

447 weblate.screenshots.views.ScreenshotList.as_view(), 

448 name="screenshots", 

449 ), 

450 path( 

451 "screenshot/<int:pk>/", 

452 weblate.screenshots.views.ScreenshotDetail.as_view(), 

453 name="screenshot", 

454 ), 

455 path( 

456 "screenshot/<int:pk>/delete/", 

457 weblate.screenshots.views.delete_screenshot, 

458 name="screenshot-delete", 

459 ), 

460 path( 

461 "screenshot/<int:pk>/remove/", 

462 weblate.screenshots.views.remove_source, 

463 name="screenshot-remove-source", 

464 ), 

465 path( 

466 "js/screenshot/<int:pk>/get/", 

467 weblate.screenshots.views.get_sources, 

468 name="screenshot-js-get", 

469 ), 

470 path( 

471 "js/screenshot/<int:pk>/search/", 

472 weblate.screenshots.views.search_source, 

473 name="screenshot-js-search", 

474 ), 

475 path( 

476 "js/screenshot/<int:pk>/ocr/", 

477 weblate.screenshots.views.ocr_search, 

478 name="screenshot-js-ocr", 

479 ), 

480 path( 

481 "js/screenshot/<int:pk>/add/", 

482 weblate.screenshots.views.add_source, 

483 name="screenshot-js-add", 

484 ), 

485 # Translation memory 

486 path("memory/", weblate.memory.views.MemoryView.as_view(), name="memory"), 

487 path( 

488 "memory/delete/", 

489 weblate.memory.views.DeleteView.as_view(), 

490 name="memory-delete", 

491 ), 

492 path( 

493 "memory/rebuild/", 

494 weblate.memory.views.RebuildView.as_view(), 

495 name="memory-rebuild", 

496 ), 

497 path( 

498 "memory/upload/", 

499 weblate.memory.views.UploadView.as_view(), 

500 name="memory-upload", 

501 ), 

502 path( 

503 "memory/download/", 

504 weblate.memory.views.DownloadView.as_view(), 

505 name="memory-download", 

506 ), 

507 path( 

508 "manage/memory/", 

509 management_access(weblate.memory.views.MemoryView.as_view()), 

510 kwargs={"manage": 1}, 

511 name="manage-memory", 

512 ), 

513 path( 

514 "manage/memory/upload/", 

515 management_access(weblate.memory.views.UploadView.as_view()), 

516 kwargs={"manage": 1}, 

517 name="manage-memory-upload", 

518 ), 

519 path( 

520 "manage/memory/delete/", 

521 management_access(weblate.memory.views.DeleteView.as_view()), 

522 kwargs={"manage": 1}, 

523 name="manage-memory-delete", 

524 ), 

525 path( 

526 "manage/memory/rebuild/", 

527 management_access(weblate.memory.views.RebuildView.as_view()), 

528 kwargs={"manage": 1}, 

529 name="manage-memory-rebuild", 

530 ), 

531 path( 

532 "manage/memory/download/", 

533 management_access(weblate.memory.views.DownloadView.as_view()), 

534 kwargs={"manage": 1}, 

535 name="manage-memory-download", 

536 ), 

537 path( 

538 "memory/project/<name:project>/", 

539 weblate.memory.views.MemoryView.as_view(), 

540 name="memory", 

541 ), 

542 path( 

543 "memory/project/<name:project>/delete/", 

544 weblate.memory.views.DeleteView.as_view(), 

545 name="memory-delete", 

546 ), 

547 path( 

548 "memory/project/<name:project>/rebuild/", 

549 weblate.memory.views.RebuildView.as_view(), 

550 name="memory-rebuild", 

551 ), 

552 path( 

553 "memory/project/<name:project>/upload/", 

554 weblate.memory.views.UploadView.as_view(), 

555 name="memory-upload", 

556 ), 

557 path( 

558 "memory/project/<name:project>/download/", 

559 weblate.memory.views.DownloadView.as_view(), 

560 name="memory-download", 

561 ), 

562 # Machinery 

563 path( 

564 "manage/machinery/", 

565 management_access(weblate.machinery.views.ListMachineryGlobalView.as_view()), 

566 name="manage-machinery", 

567 ), 

568 path( 

569 "manage/machinery/<name:machinery>/", 

570 management_access(weblate.machinery.views.EditMachineryGlobalView.as_view()), 

571 name="machinery-edit", 

572 ), 

573 path( 

574 "machinery/<name:project>/", 

575 weblate.machinery.views.ListMachineryProjectView.as_view(), 

576 name="machinery-list", 

577 ), 

578 path( 

579 "machinery/<name:project>/<name:machinery>/", 

580 weblate.machinery.views.EditMachineryProjectView.as_view(), 

581 name="machinery-edit", 

582 ), 

583 # Languages browsing 

584 path("languages/", weblate.lang.views.show_languages, name="languages"), 

585 path( 

586 "languages/<name:lang>/", 

587 weblate.lang.views.show_language, 

588 name="show_language", 

589 ), 

590 path( 

591 "edit-language/<int:pk>/", 

592 weblate.lang.views.EditLanguageView.as_view(), 

593 name="edit-language", 

594 ), 

595 path( 

596 "edit-plural/<int:pk>/", 

597 weblate.lang.views.EditPluralView.as_view(), 

598 name="edit-plural", 

599 ), 

600 path( 

601 "languages/<name:lang>/<name:project>/", 

602 weblate.trans.views.basic.ProjectLanguageRedirectView.as_view(), 

603 name="project-language-redirect", 

604 ), 

605 path( 

606 "languages/<name:lang>/<name:project>/search/", 

607 weblate.trans.views.basic.ProjectLanguageRedirectView.as_view( 

608 pattern_name="search", 

609 ), 

610 name="project-language-search-redirect", 

611 ), 

612 # Checks browsing 

613 path("checks/", weblate.checks.views.CheckList.as_view(), name="checks"), 

614 path( 

615 "checks/<name:name>/", weblate.checks.views.CheckList.as_view(), name="checks" 

616 ), 

617 path( 

618 "checks/-/<object_path:path>/", 

619 weblate.checks.views.CheckList.as_view(), 

620 name="checks", 

621 ), 

622 path( 

623 "checks/<name:name>/<object_path:path>/", 

624 weblate.checks.views.CheckList.as_view(), 

625 name="checks", 

626 ), 

627 # Changes browsing 

628 path("changes/", ChangesView.as_view(), name="changes"), 

629 path("changes/browse/<object_path:path>/", ChangesView.as_view(), name="changes"), 

630 path("changes/csv/", ChangesCSVView.as_view(), name="changes-csv"), 

631 path( 

632 "changes/csv/<object_path:path>/", ChangesCSVView.as_view(), name="changes-csv" 

633 ), 

634 path("changes/render/<int:pk>/", show_change, name="show_change"), 

635 # Notification hooks 

636 path( 

637 "hooks/<slug:service>/", 

638 ServiceHookView.as_view(), 

639 name="webhook", 

640 ), 

641 # Compatibility URL with no trailing slash 

642 path( 

643 "hooks/<slug:service>", 

644 ServiceHookView.as_view(), 

645 ), 

646 # RSS exports 

647 path("exports/rss/", ChangesFeed(), name="rss"), 

648 path( 

649 "exports/rss/language/<name:lang>/", 

650 LanguageChangesFeed(), 

651 name="rss-language", 

652 ), 

653 path("exports/rss/<object_path:path>/", TranslationChangesFeed(), name="rss"), 

654 # Engagement widgets 

655 path("exports/og.png", weblate.trans.views.widgets.render_og, name="og-image"), 

656 path( 

657 f"widgets/<name:project>/-/{widget_pattern}", 

658 weblate.trans.views.widgets.WidgetRedirectView.as_view(), 

659 ), 

660 path( 

661 f"widgets/<name:project>/<name:lang>/{widget_pattern}", 

662 weblate.trans.views.widgets.WidgetRedirectView.as_view(), 

663 ), 

664 path( 

665 f"widgets/<name:project>/-/<name:component>/{widget_pattern}", 

666 weblate.trans.views.widgets.WidgetRedirectView.as_view(), 

667 ), 

668 path( 

669 f"widgets/<name:project>/<name:lang>/<name:component>/{widget_pattern}", 

670 weblate.trans.views.widgets.WidgetRedirectView.as_view(), 

671 ), 

672 path( 

673 f"widget/<object_path:path>/{widget_pattern}", 

674 weblate.trans.views.widgets.render_widget, 

675 name="widget-image", 

676 ), 

677 path( 

678 "widgets/<object_path:path>/", 

679 weblate.trans.views.widgets.widgets, 

680 name="widgets", 

681 ), 

682 path( 

683 "widgets/", 

684 RedirectView.as_view( 

685 pattern_name="projects", permanent=True, query_string=True 

686 ), 

687 ), 

688 # Data exports pages 

689 path( 

690 "data/", 

691 RedirectView.as_view( 

692 pattern_name="projects", permanent=True, query_string=True 

693 ), 

694 ), 

695 path( 

696 "data/<name:project>/", 

697 weblate.trans.views.basic.data_project, 

698 name="data_project", 

699 ), 

700 # AJAX/JS backends 

701 path( 

702 "js/render-check/<int:unit_id>/<name:check_id>/", 

703 weblate.checks.views.render_check, 

704 name="render-check", 

705 ), 

706 path( 

707 "js/ignore-check/<int:check_id>/", 

708 weblate.trans.views.js.ignore_check, 

709 name="js-ignore-check", 

710 ), 

711 path( 

712 "js/ignore-check/<int:check_id>/source/", 

713 weblate.trans.views.js.ignore_check_source, 

714 name="js-ignore-check-source", 

715 ), 

716 path( 

717 "js/i18n/", 

718 cache_page(3600, key_prefix=VERSION)( 

719 vary_on_cookie( 

720 django.views.i18n.JavaScriptCatalog.as_view(packages=["weblate"]) 

721 ) 

722 ), 

723 name="js-catalog", 

724 ), 

725 path("js/matomo/", weblate.trans.views.js.matomo, name="js-matomo"), 

726 path( 

727 "js/translate/<name:service>/<int:unit_id>/", 

728 weblate.machinery.views.translate, 

729 name="js-translate", 

730 ), 

731 path( 

732 "js/memory/<int:unit_id>/", 

733 weblate.machinery.views.memory, 

734 name="js-memory", 

735 ), 

736 path( 

737 "js/translations/<int:unit_id>/", 

738 weblate.trans.views.js.get_unit_translations, 

739 name="js-unit-translations", 

740 ), 

741 path( 

742 "js/git/<object_path:path>/", 

743 weblate.trans.views.js.git_status, 

744 name="git_status", 

745 ), 

746 path( 

747 "js/zen/<object_path:path>/", 

748 weblate.trans.views.edit.load_zen, 

749 name="load_zen", 

750 ), 

751 path( 

752 "js/save-zen/<object_path:path>/", 

753 weblate.trans.views.edit.save_zen, 

754 name="save_zen", 

755 ), 

756 # Glossary add 

757 path( 

758 "js/glossary/<int:unit_id>/", 

759 weblate.glossary.views.add_glossary_term, 

760 name="js-add-glossary", 

761 ), 

762 path( 

763 "css/custom.css", 

764 CustomCSSView.as_view(), 

765 name="css-custom", 

766 ), 

767 # Admin interface 

768 path("admin/", admin.site.urls), 

769 # Weblate management interface 

770 path("manage/", weblate.wladmin.views.manage, name="manage"), 

771 path("manage/support/", weblate.wladmin.views.support_form, name="manage-support"), 

772 path( 

773 "manage/addons/", weblate.addons.views.AddonList.as_view(), name="manage-addons" 

774 ), 

775 path("manage/tools/", weblate.wladmin.views.tools, name="manage-tools"), 

776 path( 

777 "manage/users/", 

778 weblate.wladmin.views.AdminUserList.as_view(), 

779 name="manage-users", 

780 ), 

781 path( 

782 "manage/teams/", 

783 weblate.wladmin.views.TeamListView.as_view(), 

784 name="manage-teams", 

785 ), 

786 path( 

787 "teams/<int:pk>/", 

788 weblate.auth.views.TeamUpdateView.as_view(), 

789 name="team", 

790 ), 

791 path( 

792 "manage/users/check/", 

793 weblate.wladmin.views.users_check, 

794 name="manage-users-check", 

795 ), 

796 path("manage/activate/", weblate.wladmin.views.activate, name="manage-activate"), 

797 path("manage/discovery/", weblate.wladmin.views.discovery, name="manage-discovery"), 

798 path("manage/alerts/", weblate.wladmin.views.alerts, name="manage-alerts"), 

799 path("manage/repos/", weblate.wladmin.views.repos, name="manage-repos"), 

800 path("manage/ssh/", weblate.wladmin.views.ssh, name="manage-ssh"), 

801 path("manage/ssh/key/", weblate.wladmin.views.ssh_key, name="manage-ssh-key"), 

802 path("manage/backup/", weblate.wladmin.views.backups, name="manage-backups"), 

803 path( 

804 "manage/appearance/", weblate.wladmin.views.appearance, name="manage-appearance" 

805 ), 

806 path( 

807 "manage/performance/", 

808 weblate.wladmin.views.performance, 

809 name="manage-performance", 

810 ), 

811 # Accounts 

812 path("accounts/", include(weblate.accounts.urls)), 

813 # Auth 

814 path("api/", include((weblate.api.urls, "weblate.api"), namespace="api")), 

815 # OpenAPI schema 

816 path("api/schema/", SpectacularAPIView.as_view(), name="api-schema"), 

817 # API documentation 

818 path( 

819 "api/docs/", SpectacularRedocView.as_view(url_name="api-schema"), name="redoc" 

820 ), 

821 # Static pages 

822 path("contact/", weblate.accounts.views.contact, name="contact"), 

823 path("hosting/", weblate.accounts.views.hosting, name="hosting"), 

824 path("trial/", weblate.accounts.views.trial, name="trial"), 

825 path("about/", weblate.trans.views.about.AboutView.as_view(), name="about"), 

826 path("donate/", weblate.trans.views.about.DonateView.as_view(), name="donate"), 

827 path("keys/", weblate.trans.views.about.KeysView.as_view(), name="keys"), 

828 path("stats/", weblate.trans.views.about.StatsView.as_view(), name="stats"), 

829 # User pages 

830 path("user/", weblate.accounts.views.UserList.as_view(), name="user_list"), 

831 path( 

832 "user/<name:user>/", weblate.accounts.views.UserPage.as_view(), name="user_page" 

833 ), 

834 path( 

835 "user/<name:user>/contributions/", 

836 weblate.accounts.views.user_contributions, 

837 name="user_contributions", 

838 ), 

839 path( 

840 "user/<name:user>/suggestions/", 

841 weblate.accounts.views.SuggestionView.as_view(), 

842 name="user_suggestions", 

843 ), 

844 # Avatars 

845 path( 

846 "avatar/<int:size>/<name:user>.png", 

847 weblate.accounts.views.user_avatar, 

848 name="user_avatar", 

849 ), 

850 # Sitemap 

851 path( 

852 "sitemap.xml", 

853 cache_page(3600, key_prefix=VERSION)(django.contrib.sitemaps.views.index), 

854 {"sitemaps": SITEMAPS, "sitemap_url_name": "sitemap"}, 

855 name="sitemap-index", 

856 ), 

857 path( 

858 "sitemap-<slug:section>.xml", 

859 cache_page(3600, key_prefix=VERSION)(django.contrib.sitemaps.views.sitemap), 

860 {"sitemaps": SITEMAPS}, 

861 name="sitemap", 

862 ), 

863 # Site wide search 

864 path("search/", weblate.trans.views.search.search, name="search"), 

865 path( 

866 "search/<object_path:path>/", weblate.trans.views.search.search, name="search" 

867 ), 

868 # Health check 

869 path("healthz/", weblate.trans.views.basic.healthz, name="healthz"), 

870 # Aliases for static files 

871 re_path( 

872 r"^(android-chrome|favicon)-(?P<size>192|512)x(?P=size)\.png$", 

873 RedirectView.as_view( 

874 url=settings.STATIC_URL + "weblate-%(size)s.png", 

875 permanent=True, 

876 ), 

877 ), 

878 path( 

879 "apple-touch-icon.png", 

880 RedirectView.as_view( 

881 url=settings.STATIC_URL + "weblate-180.png", 

882 permanent=True, 

883 ), 

884 ), 

885 path( 

886 "favicon.ico", 

887 RedirectView.as_view( 

888 url=settings.STATIC_URL + "favicon.ico", 

889 permanent=True, 

890 ), 

891 ), 

892 path( 

893 "robots.txt", 

894 cache_control(max_age=86400)( 

895 TemplateView.as_view(template_name="robots.txt", content_type="text/plain") 

896 ), 

897 ), 

898 path( 

899 "browserconfig.xml", 

900 cache_control(max_age=86400)( 

901 TemplateView.as_view( 

902 template_name="browserconfig.xml", content_type="application/xml" 

903 ) 

904 ), 

905 ), 

906 path( 

907 "site.webmanifest", 

908 cache_control(max_age=86400)( 

909 TemplateView.as_view( 

910 template_name="site.webmanifest", content_type="application/json" 

911 ) 

912 ), 

913 ), 

914 # Redirects for .well-known 

915 path( 

916 ".well-known/change-password", 

917 RedirectView.as_view(pattern_name="password", permanent=True), 

918 ), 

919] 

920 

921# Billing integration 

922if "weblate.billing" in settings.INSTALLED_APPS: 922 ↛ 923line 922 didn't jump to line 923 because the condition on line 922 was never true

923 import weblate.billing.views 

924 

925 real_patterns += [ 

926 path( 

927 "invoice/<int:pk>/download/", 

928 weblate.billing.views.download_invoice, 

929 name="invoice-download", 

930 ), 

931 path("billing/", weblate.billing.views.overview, name="billing"), 

932 path("billing/<int:pk>/", weblate.billing.views.detail, name="billing-detail"), 

933 path("manage/billing/", weblate.wladmin.views.billing, name="manage-billing"), 

934 ] 

935 

936# Git exporter integration 

937if "weblate.gitexport" in settings.INSTALLED_APPS: 937 ↛ 993line 937 didn't jump to line 993 because the condition on line 937 was always true

938 import weblate.gitexport.views 

939 

940 real_patterns += [ 

941 # Redirect clone from the Weblate project URL 

942 path( 

943 "projects/<object_path:path>.git/<git_path:git_request>", 

944 RedirectView.as_view( 

945 pattern_name="git-export", 

946 permanent=True, 

947 query_string=True, 

948 ), 

949 ), 

950 path( 

951 "projects/<object_path:path>/<git_path:git_request>", 

952 RedirectView.as_view( 

953 pattern_name="git-export", 

954 permanent=True, 

955 query_string=True, 

956 ), 

957 ), 

958 # Redirect clone in case user adds .git to the path 

959 path( 

960 "git/<object_path:path>.git/<git_path:git_request>", 

961 RedirectView.as_view( 

962 pattern_name="git-export", 

963 permanent=True, 

964 query_string=True, 

965 ), 

966 ), 

967 # Redirect accessing Git URL with a browser 

968 path( 

969 "git/<object_path:path>.git/", 

970 RedirectView.as_view( 

971 pattern_name="show", 

972 permanent=True, 

973 query_string=True, 

974 ), 

975 ), 

976 path( 

977 "git/<object_path:path>/", 

978 RedirectView.as_view( 

979 pattern_name="show", 

980 permanent=True, 

981 query_string=True, 

982 ), 

983 ), 

984 # Actual git server 

985 path( 

986 "git/<object_path:path>/<git_path:git_request>", 

987 weblate.gitexport.views.git_export, 

988 name="git-export", 

989 ), 

990 ] 

991 

992# Legal integartion 

993if "weblate.legal" in settings.INSTALLED_APPS: 993 ↛ 994line 993 didn't jump to line 994 because the condition on line 993 was never true

994 real_patterns.extend( 

995 ( 

996 path( 

997 "legal/", 

998 include(("weblate.legal.urls", "weblate.legal"), namespace="legal"), 

999 ), 

1000 path( 

1001 "security.txt", 

1002 RedirectView.as_view(url="/.well-known/security.txt", permanent=True), 

1003 ), 

1004 path( 

1005 ".well-known/security.txt", 

1006 TemplateView.as_view( 

1007 template_name="security.txt", content_type="text/plain" 

1008 ), 

1009 ), 

1010 ) 

1011 ) 

1012 

1013# Serving media files in DEBUG mode 

1014if settings.DEBUG: 1014 ↛ 1015line 1014 didn't jump to line 1015 because the condition on line 1014 was never true

1015 real_patterns.append( 

1016 path( 

1017 "media/<path:path>", 

1018 django.views.static.serve, 

1019 {"document_root": settings.MEDIA_ROOT}, 

1020 ) 

1021 ) 

1022 

1023# Django debug toolbar integration 

1024if settings.DEBUG and "debug_toolbar" in settings.INSTALLED_APPS: 1024 ↛ 1025line 1024 didn't jump to line 1025 because the condition on line 1024 was never true

1025 real_patterns.append( 

1026 path("__debug__/", include("debug_toolbar.urls")), 

1027 ) 

1028 

1029# Hosted Weblate integration 

1030if "wlhosted.integrations" in settings.INSTALLED_APPS: 1030 ↛ 1031line 1030 didn't jump to line 1031 because the condition on line 1030 was never true

1031 from wlhosted.integrations.views import CreateBillingView 

1032 

1033 real_patterns.append( 

1034 path("create/billing/", CreateBillingView.as_view(), name="create-billing"), 

1035 ) 

1036 

1037# Django SAML2 Identity Provider 

1038if "djangosaml2idp" in settings.INSTALLED_APPS: 1038 ↛ 1039line 1038 didn't jump to line 1039 because the condition on line 1038 was never true

1039 real_patterns.append( 

1040 path("idp/", include("djangosaml2idp.urls")), 

1041 ) 

1042 

1043# Handle URL prefix configuration 

1044if not URL_PREFIX: 1044 ↛ 1047line 1044 didn't jump to line 1047 because the condition on line 1044 was always true

1045 urlpatterns = real_patterns 

1046else: 

1047 urlpatterns = [path(URL_PREFIX, include(real_patterns))]