Coverage for an_website/js_licenses/js_licenses.py: 90.909%

33 statements  

« prev     ^ index     » next       coverage.py v7.6.4, created at 2024-11-16 19:56 +0000

1# This program is free software: you can redistribute it and/or modify 

2# it under the terms of the GNU Affero General Public License as 

3# published by the Free Software Foundation, either version 3 of the 

4# License, or (at your option) any later version. 

5# 

6# This program is distributed in the hope that it will be useful, 

7# but WITHOUT ANY WARRANTY; without even the implied warranty of 

8# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

9# GNU Affero General Public License for more details. 

10# 

11# You should have received a copy of the GNU Affero General Public License 

12# along with this program. If not, see <https://www.gnu.org/licenses/>. 

13 

14""" 

15A page with all the JavaScript files and their licenses. 

16 

17This is used for LibreJS to make sure the extension knows the licenses. 

18This isn't important, as the JS files should contain the licenses themselves. 

19 

20See: https://www.gnu.org/software/librejs/free-your-javascript.html#step3 

21and https://www.gnu.org/licenses/javascript-labels.html 

22""" 

23 

24from __future__ import annotations 

25 

26import logging 

27from collections.abc import Mapping 

28from functools import cache 

29from typing import Final 

30 

31from .. import STATIC_DIR 

32from ..utils.request_handler import HTMLRequestHandler 

33from ..utils.utils import ModuleInfo, recurse_directory 

34 

35LOGGER: Final = logging.getLogger(__name__) 

36 

37 

38def get_module_info() -> ModuleInfo: 

39 """Create and return the ModuleInfo for this module.""" 

40 return ModuleInfo( 

41 handlers=((r"/js-lizenzen", JSLicenses),), 

42 name="JavaScript-Lizenzen", 

43 description=( 

44 "Informationen über die Lizenzen der JavaScript-Dateien " 

45 "auf dieser Seite" 

46 ), 

47 path="/js-lizenzen", 

48 aliases=("/js-licenses",), 

49 keywords=("JavaScript", "License", "Lizenz"), 

50 ) 

51 

52 

53LICENSES: Final[Mapping[str, str]] = { 

54 "magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt": ( 

55 "https://www.gnu.org/licenses/agpl-3.0.html" 

56 ), 

57 "magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt": ( 

58 "https://www.jclark.com/xml/copying.txt" 

59 ), 

60} 

61 

62 

63@cache 

64def get_js_filenames_and_licenses() -> list[tuple[str, str, str]]: 

65 """ 

66 Get the names of the JS files in this project. 

67 

68 Returns a list of tuples with filename, license and license URL. 

69 """ 

70 js_files_dir = STATIC_DIR / "js" 

71 licenses_list: list[tuple[str, str, str]] = [] 

72 for filename in recurse_directory( 

73 js_files_dir, lambda path: path.name.endswith(".js") 

74 ): 

75 path = js_files_dir / filename 

76 if not path.is_file(): 

77 continue 

78 with path.open(encoding="UTF-8") as file: 

79 license_line = file.readline().strip().removeprefix('"use strict";') 

80 if not license_line.startswith("// @license "): 

81 LOGGER.critical("%s has no license comment", filename) 

82 continue 

83 magnet, name = ( 

84 license_line.removeprefix("// @license").strip().split(" ") 

85 ) 

86 licenses_list.append((filename, name.strip(), LICENSES[magnet.strip()])) 

87 return licenses_list 

88 

89 

90class JSLicenses(HTMLRequestHandler): 

91 """The request handler for the JS licenses page.""" 

92 

93 async def get(self, *, head: bool = False) -> None: 

94 """Handle GET requests to the JS licenses page.""" 

95 if head: 

96 return 

97 await self.render( 

98 "pages/js_licenses.html", js_files=get_js_filenames_and_licenses() 

99 )