wbnews 1.50.4__py2.py3-none-any.whl → 1.58.1__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
wbnews/filters/news.py CHANGED
@@ -4,7 +4,7 @@ from wbnews.models import News, NewsRelationship, NewsSource
4
4
 
5
5
 
6
6
  class NewsFilterSet(wb_filters.FilterSet):
7
- datetime = wb_filters.DateTimeRangeFilter(method=wb_filters.DateRangeFilter.base_date_range_filter_method)
7
+ datetime = wb_filters.DateTimeRangeFilter()
8
8
 
9
9
  class Meta:
10
10
  model = News
@@ -24,6 +24,8 @@ class NewsRelationshipFilterSet(wb_filters.FilterSet):
24
24
  label_key=NewsSource.get_representation_label_key(),
25
25
  method="filter_source",
26
26
  )
27
+ content_type = wb_filters.CharFilter(method="fake_filter", hidden=True)
28
+ object_id = wb_filters.CharFilter(method="fake_filter", hidden=True)
27
29
 
28
30
  def filter_datetime(self, queryset, name, value):
29
31
  if value:
@@ -31,6 +31,13 @@ class NewsImportHandler(ImportExportHandler):
31
31
  else:
32
32
  data["guid"] = data["default_guid"]
33
33
 
34
+ # constrained fields to the max allowed size
35
+ if "title" in data:
36
+ data["title"] = data["title"][:500]
37
+
38
+ if "link" in data:
39
+ data["link"] = data["link"][:1024]
40
+
34
41
  def _get_instance(self, data: Dict[str, Any], history: Optional[models.QuerySet] = None, **kwargs) -> models.Model:
35
42
  default_guid = data.pop("default_guid")
36
43
  instance = None
@@ -3,7 +3,6 @@ from contextlib import suppress
3
3
  from datetime import datetime
4
4
 
5
5
  from django.conf.global_settings import LANGUAGES
6
- from langdetect import detect, lang_detect_exception
7
6
  from wbcore.utils.importlib import import_from_dotted_path
8
7
 
9
8
  from .utils import EmlContentParser
@@ -37,12 +36,4 @@ def parse(import_source):
37
36
  "source": parser.source,
38
37
  }
39
38
 
40
- # Language
41
- try:
42
- language = detect(data["description"])
43
- if language in languages_dict:
44
- data["language"] = language
45
- except lang_detect_exception.LangDetectException:
46
- pass
47
-
48
39
  return {"data": [data]}
@@ -22,10 +22,10 @@ class EmlContentParser:
22
22
  html = self.get_html(self.message)
23
23
  return html.decode(self.encoding) if html else None
24
24
 
25
- def get_html(cls, parsed: message.Message) -> bytes | None:
25
+ def get_html(self, parsed: message.Message) -> bytes | None:
26
26
  if parsed.is_multipart():
27
27
  for item in parsed.get_payload(): # type:message.Message
28
- if html := cls.get_html(item):
28
+ if html := self.get_html(item):
29
29
  return html
30
30
  elif parsed.get_content_type() == "text/html":
31
31
  return parsed.get_payload(decode=True)
@@ -4,7 +4,6 @@ from time import mktime
4
4
 
5
5
  from django.conf.global_settings import LANGUAGES
6
6
  from django.utils.html import strip_tags
7
- from langdetect import detect, lang_detect_exception
8
7
 
9
8
  languages_dict = dict(LANGUAGES)
10
9
 
@@ -43,12 +42,6 @@ def parse(import_source):
43
42
  "link": entry.get("link", None),
44
43
  "guid": entry.get("id", None),
45
44
  }
46
- try:
47
- language = detect(entry["summary"])
48
- if language in languages_dict:
49
- res["language"] = language
50
- except lang_detect_exception.LangDetectException:
51
- pass
52
45
  if published_parsed := entry.get("published_parsed", None):
53
46
  updated = datetime.fromtimestamp(mktime(tuple(published_parsed)))
54
47
  res["datetime"] = updated.strftime("%Y-%m-%dT%H:%M:%S")
Binary file
@@ -3,110 +3,164 @@
3
3
  # This file is distributed under the same license as the PACKAGE package.
4
4
  # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
5
5
  #
6
+ # Translators:
7
+ # Kevin Decoster, 2025
8
+ #
9
+ #, fuzzy
6
10
  msgid ""
7
11
  msgstr ""
8
- "Project-Id-Version: \n"
12
+ "Project-Id-Version: PACKAGE VERSION\n"
9
13
  "Report-Msgid-Bugs-To: \n"
10
- "POT-Creation-Date: 2022-10-17 14:50+0200\n"
11
- "PO-Revision-Date: 2022-10-17 14:51+0200\n"
12
- "Last-Translator: \n"
13
- "Language-Team: \n"
14
- "Language: de\n"
14
+ "POT-Creation-Date: 2025-05-30 11:37+0200\n"
15
+ "PO-Revision-Date: 2025-05-30 09:40+0000\n"
16
+ "Last-Translator: Kevin Decoster, 2025\n"
17
+ "Language-Team: German (https://app.transifex.com/stainly/teams/171242/de/)\n"
15
18
  "MIME-Version: 1.0\n"
16
19
  "Content-Type: text/plain; charset=UTF-8\n"
17
20
  "Content-Transfer-Encoding: 8bit\n"
21
+ "Language: de\n"
18
22
  "Plural-Forms: nplurals=2; plural=(n != 1);\n"
19
- "X-Generator: Poedit 3.1.1\n"
20
23
 
21
- #: wbnews/models.py:45 wbnews/viewsets/display.py:59
22
- #: wbnews/viewsets/display.py:86
24
+ #: models/news.py:51 viewsets/display.py:54 viewsets/display.py:100
25
+ #: viewsets/display.py:141
23
26
  msgid "Datetime"
24
27
  msgstr "Zeitpunkt"
25
28
 
26
- #: wbnews/models.py:46 wbnews/serializers.py:17 wbnews/viewsets/display.py:12
27
- #: wbnews/viewsets/display.py:60 wbnews/viewsets/display.py:87
29
+ #: models/news.py:52 serializers.py:21 serializers.py:76
30
+ #: viewsets/display.py:20 viewsets/display.py:55 viewsets/display.py:102
31
+ #: viewsets/display.py:142
28
32
  msgid "Title"
29
33
  msgstr "Titel"
30
34
 
31
- #: wbnews/models.py:47 wbnews/serializers.py:20 wbnews/viewsets/display.py:15
32
- #: wbnews/viewsets/display.py:62 wbnews/viewsets/display.py:88
35
+ #: models/news.py:54 serializers.py:24 serializers.py:77
36
+ #: viewsets/display.py:23 viewsets/display.py:57 viewsets/display.py:104
37
+ #: viewsets/display.py:143
33
38
  msgid "Description"
34
39
  msgstr "Beschreibung"
35
40
 
36
- #: wbnews/models.py:48 wbnews/viewsets/display.py:61
41
+ #: models/news.py:55 serializers.py:78 viewsets/display.py:56
42
+ #: viewsets/display.py:103
37
43
  msgid "Summary"
38
44
  msgstr "Zusammenfassung"
39
45
 
40
- #: wbnews/models.py:49 wbnews/viewsets/display.py:65
41
- #: wbnews/viewsets/display.py:89
46
+ #: models/news.py:56 viewsets/display.py:60 viewsets/display.py:144
42
47
  msgid "Language"
43
48
  msgstr "Sprache"
44
49
 
45
- #: wbnews/models.py:50
50
+ #: models/news.py:57
46
51
  msgid "Link"
47
52
  msgstr "Link"
48
53
 
49
- #: wbnews/models.py:54 wbnews/viewsets/display.py:64
54
+ #: models/news.py:61 viewsets/display.py:59 viewsets/display.py:106
50
55
  msgid "Source"
51
56
  msgstr "Quelle"
52
57
 
53
- #: wbnews/serializers.py:18
58
+ #: models/news.py:64
59
+ msgid "Mark as duplicate"
60
+ msgstr ""
61
+
62
+ #: models/relationships.py:9
63
+ msgid "Positive"
64
+ msgstr ""
65
+
66
+ #: models/relationships.py:10
67
+ msgid "Slightly Positive"
68
+ msgstr ""
69
+
70
+ #: models/relationships.py:11
71
+ msgid "Slightly Negative"
72
+ msgstr ""
73
+
74
+ #: models/relationships.py:12
75
+ msgid "Negative"
76
+ msgstr ""
77
+
78
+ #: serializers.py:22
54
79
  msgid "Identifier"
55
80
  msgstr "Identifikator"
56
81
 
57
- #: wbnews/serializers.py:21 wbnews/viewsets/display.py:14
82
+ #: serializers.py:25 viewsets/display.py:22
58
83
  msgid "Author"
59
84
  msgstr "Autor*in"
60
85
 
61
- #: wbnews/serializers.py:22
86
+ #: serializers.py:26
62
87
  msgid "Updated"
63
88
  msgstr "Geändert"
64
89
 
65
- #: wbnews/viewsets/buttons.py:8
90
+ #: serializers.py:79
91
+ msgid "Date"
92
+ msgstr ""
93
+
94
+ #: serializers.py:92 viewsets/menu.py:6 viewsets/titles.py:24
95
+ msgid "News"
96
+ msgstr "Neuigkeiten"
97
+
98
+ #: viewsets/buttons.py:14
66
99
  msgid "Open News"
67
100
  msgstr "Neuigkeiten Öffnen"
68
101
 
69
- #: wbnews/viewsets/display.py:13
102
+ #: viewsets/buttons.py:21 viewsets/buttons.py:22 viewsets/buttons.py:24
103
+ msgid "Reset relationships"
104
+ msgstr ""
105
+
106
+ #: viewsets/display.py:21
70
107
  msgid "RSS feed"
71
108
  msgstr "RSS Feed"
72
109
 
73
- #: wbnews/viewsets/display.py:16
110
+ #: viewsets/display.py:24
74
111
  msgid "Last Update"
75
112
  msgstr "Letztes Aktualisierung"
76
113
 
77
- #: wbnews/viewsets/display.py:33 wbnews/viewsets/menu.py:6
78
- #: wbnews/viewsets/titles.py:23 wbnews_config/menu.py:6
79
- msgid "News"
80
- msgstr "Neuigkeiten"
81
-
82
- #: wbnews/viewsets/display.py:66
114
+ #: viewsets/display.py:61
83
115
  msgid "Image"
84
116
  msgstr "Bild"
85
117
 
86
- #: wbnews/viewsets/menu.py:11 wbnews/viewsets/titles.py:8
118
+ #: viewsets/display.py:93
119
+ msgid "Linked Object"
120
+ msgstr ""
121
+
122
+ #: viewsets/display.py:101
123
+ msgid "Analysis"
124
+ msgstr ""
125
+
126
+ #: viewsets/display.py:105
127
+ msgid "Important"
128
+ msgstr ""
129
+
130
+ #: viewsets/menu.py:11
131
+ msgid "News Relationships"
132
+ msgstr ""
133
+
134
+ #: viewsets/menu.py:17 viewsets/titles.py:9
87
135
  msgid "Sources"
88
136
  msgstr "Quellen"
89
137
 
90
- #: wbnews/viewsets/menu.py:15
138
+ #: viewsets/menu.py:23
91
139
  msgid "Create Source"
92
140
  msgstr "Quelle Erstellen"
93
141
 
94
- #: wbnews/viewsets/titles.py:12
142
+ #: viewsets/titles.py:13
95
143
  #, python-brace-format
96
144
  msgid "Source: {source}"
97
145
  msgstr "Quelle: {source}"
98
146
 
99
- #: wbnews/viewsets/titles.py:13
100
- #, fuzzy
101
- #| msgid "Source"
147
+ #: viewsets/titles.py:14
102
148
  msgid "News Source"
103
- msgstr "Quelle"
149
+ msgstr ""
104
150
 
105
- #: wbnews/viewsets/titles.py:18
151
+ #: viewsets/titles.py:19
106
152
  msgid "News Flow"
107
153
  msgstr "Nachrichtenfluss"
108
154
 
109
- #: wbnews/viewsets/titles.py:29
155
+ #: viewsets/titles.py:30
110
156
  #, python-brace-format
111
157
  msgid "News from {source}"
112
158
  msgstr "Neuigkeiten von {source}"
159
+
160
+ #: viewsets/titles.py:36
161
+ msgid "News Article for {}"
162
+ msgstr ""
163
+
164
+ #: viewsets/titles.py:37 viewsets/titles.py:44
165
+ msgid "News Article"
166
+ msgstr ""
@@ -0,0 +1,173 @@
1
+ # SOME DESCRIPTIVE TITLE.
2
+ # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
3
+ # This file is distributed under the same license as the PACKAGE package.
4
+ # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
5
+ #
6
+ msgid ""
7
+ msgstr ""
8
+ "Project-Id-Version: \n"
9
+ "Report-Msgid-Bugs-To: \n"
10
+ "POT-Creation-Date: 2025-05-29 13:33+0200\n"
11
+ "PO-Revision-Date: 2022-10-17 14:51+0200\n"
12
+ "Last-Translator: \n"
13
+ "Language-Team: \n"
14
+ "Language: de\n"
15
+ "MIME-Version: 1.0\n"
16
+ "Content-Type: text/plain; charset=UTF-8\n"
17
+ "Content-Transfer-Encoding: 8bit\n"
18
+ "Plural-Forms: nplurals=2; plural=(n != 1);\n"
19
+ "X-Generator: Poedit 3.1.1\n"
20
+
21
+ #: wbnews/models/news.py:51 wbnews/viewsets/display.py:54
22
+ #: wbnews/viewsets/display.py:100 wbnews/viewsets/display.py:141
23
+ msgid "Datetime"
24
+ msgstr "Zeitpunkt"
25
+
26
+ #: wbnews/models/news.py:52 wbnews/serializers.py:21 wbnews/serializers.py:76
27
+ #: wbnews/viewsets/display.py:20 wbnews/viewsets/display.py:55
28
+ #: wbnews/viewsets/display.py:102 wbnews/viewsets/display.py:142
29
+ msgid "Title"
30
+ msgstr "Titel"
31
+
32
+ #: wbnews/models/news.py:54 wbnews/serializers.py:24 wbnews/serializers.py:77
33
+ #: wbnews/viewsets/display.py:23 wbnews/viewsets/display.py:57
34
+ #: wbnews/viewsets/display.py:104 wbnews/viewsets/display.py:143
35
+ msgid "Description"
36
+ msgstr "Beschreibung"
37
+
38
+ #: wbnews/models/news.py:55 wbnews/serializers.py:78
39
+ #: wbnews/viewsets/display.py:56 wbnews/viewsets/display.py:103
40
+ msgid "Summary"
41
+ msgstr "Zusammenfassung"
42
+
43
+ #: wbnews/models/news.py:56 wbnews/viewsets/display.py:60
44
+ #: wbnews/viewsets/display.py:144
45
+ msgid "Language"
46
+ msgstr "Sprache"
47
+
48
+ #: wbnews/models/news.py:57
49
+ msgid "Link"
50
+ msgstr "Link"
51
+
52
+ #: wbnews/models/news.py:61 wbnews/viewsets/display.py:59
53
+ #: wbnews/viewsets/display.py:106
54
+ msgid "Source"
55
+ msgstr "Quelle"
56
+
57
+ #: wbnews/models/news.py:64
58
+ msgid "Mark as duplicate"
59
+ msgstr ""
60
+
61
+ #: wbnews/models/relationships.py:9
62
+ msgid "Positive"
63
+ msgstr ""
64
+
65
+ #: wbnews/models/relationships.py:10
66
+ msgid "Slightly Positive"
67
+ msgstr ""
68
+
69
+ #: wbnews/models/relationships.py:11
70
+ msgid "Slightly Negative"
71
+ msgstr ""
72
+
73
+ #: wbnews/models/relationships.py:12
74
+ msgid "Negative"
75
+ msgstr ""
76
+
77
+ #: wbnews/serializers.py:22
78
+ msgid "Identifier"
79
+ msgstr "Identifikator"
80
+
81
+ #: wbnews/serializers.py:25 wbnews/viewsets/display.py:22
82
+ msgid "Author"
83
+ msgstr "Autor*in"
84
+
85
+ #: wbnews/serializers.py:26
86
+ msgid "Updated"
87
+ msgstr "Geändert"
88
+
89
+ #: wbnews/serializers.py:79
90
+ #, fuzzy
91
+ #| msgid "Datetime"
92
+ msgid "Date"
93
+ msgstr "Zeitpunkt"
94
+
95
+ #: wbnews/serializers.py:92 wbnews/viewsets/menu.py:6
96
+ #: wbnews/viewsets/titles.py:24 wbnews_config/menu.py:5
97
+ msgid "News"
98
+ msgstr "Neuigkeiten"
99
+
100
+ #: wbnews/viewsets/buttons.py:14
101
+ msgid "Open News"
102
+ msgstr "Neuigkeiten Öffnen"
103
+
104
+ #: wbnews/viewsets/buttons.py:21 wbnews/viewsets/buttons.py:22
105
+ #: wbnews/viewsets/buttons.py:24
106
+ msgid "Reset relationships"
107
+ msgstr ""
108
+
109
+ #: wbnews/viewsets/display.py:21
110
+ msgid "RSS feed"
111
+ msgstr "RSS Feed"
112
+
113
+ #: wbnews/viewsets/display.py:24
114
+ msgid "Last Update"
115
+ msgstr "Letztes Aktualisierung"
116
+
117
+ #: wbnews/viewsets/display.py:61
118
+ msgid "Image"
119
+ msgstr "Bild"
120
+
121
+ #: wbnews/viewsets/display.py:93
122
+ msgid "Linked Object"
123
+ msgstr ""
124
+
125
+ #: wbnews/viewsets/display.py:101
126
+ msgid "Analysis"
127
+ msgstr ""
128
+
129
+ #: wbnews/viewsets/display.py:105
130
+ msgid "Important"
131
+ msgstr ""
132
+
133
+ #: wbnews/viewsets/menu.py:11
134
+ msgid "News Relationships"
135
+ msgstr ""
136
+
137
+ #: wbnews/viewsets/menu.py:17 wbnews/viewsets/titles.py:9
138
+ msgid "Sources"
139
+ msgstr "Quellen"
140
+
141
+ #: wbnews/viewsets/menu.py:23
142
+ msgid "Create Source"
143
+ msgstr "Quelle Erstellen"
144
+
145
+ #: wbnews/viewsets/titles.py:13
146
+ #, python-brace-format
147
+ msgid "Source: {source}"
148
+ msgstr "Quelle: {source}"
149
+
150
+ #: wbnews/viewsets/titles.py:14
151
+ #, fuzzy
152
+ #| msgid "Source"
153
+ msgid "News Source"
154
+ msgstr "Quelle"
155
+
156
+ #: wbnews/viewsets/titles.py:19
157
+ msgid "News Flow"
158
+ msgstr "Nachrichtenfluss"
159
+
160
+ #: wbnews/viewsets/titles.py:30
161
+ #, python-brace-format
162
+ msgid "News from {source}"
163
+ msgstr "Neuigkeiten von {source}"
164
+
165
+ #: wbnews/viewsets/titles.py:36
166
+ msgid "News Article for {}"
167
+ msgstr ""
168
+
169
+ #: wbnews/viewsets/titles.py:37 wbnews/viewsets/titles.py:44
170
+ #, fuzzy
171
+ #| msgid "Source"
172
+ msgid "News Article"
173
+ msgstr "Quelle"
Binary file
@@ -0,0 +1,159 @@
1
+ # SOME DESCRIPTIVE TITLE.
2
+ # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
3
+ # This file is distributed under the same license as the PACKAGE package.
4
+ # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
5
+ #
6
+ msgid ""
7
+ msgstr ""
8
+ "Project-Id-Version: PACKAGE VERSION\n"
9
+ "Report-Msgid-Bugs-To: \n"
10
+ "POT-Creation-Date: 2025-05-30 11:37+0200\n"
11
+ "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
12
+ "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
13
+ "Language-Team: LANGUAGE <LL@li.org>\n"
14
+ "Language: \n"
15
+ "MIME-Version: 1.0\n"
16
+ "Content-Type: text/plain; charset=UTF-8\n"
17
+ "Content-Transfer-Encoding: 8bit\n"
18
+
19
+ #: models/news.py:51 viewsets/display.py:54 viewsets/display.py:100
20
+ #: viewsets/display.py:141
21
+ msgid "Datetime"
22
+ msgstr ""
23
+
24
+ #: models/news.py:52 serializers.py:21 serializers.py:76 viewsets/display.py:20
25
+ #: viewsets/display.py:55 viewsets/display.py:102 viewsets/display.py:142
26
+ msgid "Title"
27
+ msgstr ""
28
+
29
+ #: models/news.py:54 serializers.py:24 serializers.py:77 viewsets/display.py:23
30
+ #: viewsets/display.py:57 viewsets/display.py:104 viewsets/display.py:143
31
+ msgid "Description"
32
+ msgstr ""
33
+
34
+ #: models/news.py:55 serializers.py:78 viewsets/display.py:56
35
+ #: viewsets/display.py:103
36
+ msgid "Summary"
37
+ msgstr ""
38
+
39
+ #: models/news.py:56 viewsets/display.py:60 viewsets/display.py:144
40
+ msgid "Language"
41
+ msgstr ""
42
+
43
+ #: models/news.py:57
44
+ msgid "Link"
45
+ msgstr ""
46
+
47
+ #: models/news.py:61 viewsets/display.py:59 viewsets/display.py:106
48
+ msgid "Source"
49
+ msgstr ""
50
+
51
+ #: models/news.py:64
52
+ msgid "Mark as duplicate"
53
+ msgstr ""
54
+
55
+ #: models/relationships.py:9
56
+ msgid "Positive"
57
+ msgstr ""
58
+
59
+ #: models/relationships.py:10
60
+ msgid "Slightly Positive"
61
+ msgstr ""
62
+
63
+ #: models/relationships.py:11
64
+ msgid "Slightly Negative"
65
+ msgstr ""
66
+
67
+ #: models/relationships.py:12
68
+ msgid "Negative"
69
+ msgstr ""
70
+
71
+ #: serializers.py:22
72
+ msgid "Identifier"
73
+ msgstr ""
74
+
75
+ #: serializers.py:25 viewsets/display.py:22
76
+ msgid "Author"
77
+ msgstr ""
78
+
79
+ #: serializers.py:26
80
+ msgid "Updated"
81
+ msgstr ""
82
+
83
+ #: serializers.py:79
84
+ msgid "Date"
85
+ msgstr ""
86
+
87
+ #: serializers.py:92 viewsets/menu.py:6 viewsets/titles.py:24
88
+ msgid "News"
89
+ msgstr ""
90
+
91
+ #: viewsets/buttons.py:14
92
+ msgid "Open News"
93
+ msgstr ""
94
+
95
+ #: viewsets/buttons.py:21 viewsets/buttons.py:22 viewsets/buttons.py:24
96
+ msgid "Reset relationships"
97
+ msgstr ""
98
+
99
+ #: viewsets/display.py:21
100
+ msgid "RSS feed"
101
+ msgstr ""
102
+
103
+ #: viewsets/display.py:24
104
+ msgid "Last Update"
105
+ msgstr ""
106
+
107
+ #: viewsets/display.py:61
108
+ msgid "Image"
109
+ msgstr ""
110
+
111
+ #: viewsets/display.py:93
112
+ msgid "Linked Object"
113
+ msgstr ""
114
+
115
+ #: viewsets/display.py:101
116
+ msgid "Analysis"
117
+ msgstr ""
118
+
119
+ #: viewsets/display.py:105
120
+ msgid "Important"
121
+ msgstr ""
122
+
123
+ #: viewsets/menu.py:11
124
+ msgid "News Relationships"
125
+ msgstr ""
126
+
127
+ #: viewsets/menu.py:17 viewsets/titles.py:9
128
+ msgid "Sources"
129
+ msgstr ""
130
+
131
+ #: viewsets/menu.py:23
132
+ msgid "Create Source"
133
+ msgstr ""
134
+
135
+ #: viewsets/titles.py:13
136
+ #, python-brace-format
137
+ msgid "Source: {source}"
138
+ msgstr ""
139
+
140
+ #: viewsets/titles.py:14
141
+ msgid "News Source"
142
+ msgstr ""
143
+
144
+ #: viewsets/titles.py:19
145
+ msgid "News Flow"
146
+ msgstr ""
147
+
148
+ #: viewsets/titles.py:30
149
+ #, python-brace-format
150
+ msgid "News from {source}"
151
+ msgstr ""
152
+
153
+ #: viewsets/titles.py:36
154
+ msgid "News Article for {}"
155
+ msgstr ""
156
+
157
+ #: viewsets/titles.py:37 viewsets/titles.py:44
158
+ msgid "News Article"
159
+ msgstr ""
Binary file
@@ -0,0 +1,162 @@
1
+ # SOME DESCRIPTIVE TITLE.
2
+ # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
3
+ # This file is distributed under the same license as the PACKAGE package.
4
+ # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
5
+ #
6
+ #, fuzzy
7
+ msgid ""
8
+ msgstr ""
9
+ "Project-Id-Version: PACKAGE VERSION\n"
10
+ "Report-Msgid-Bugs-To: \n"
11
+ "POT-Creation-Date: 2025-05-30 11:37+0200\n"
12
+ "PO-Revision-Date: 2025-05-30 09:40+0000\n"
13
+ "Language-Team: French (https://app.transifex.com/stainly/teams/171242/fr/)\n"
14
+ "MIME-Version: 1.0\n"
15
+ "Content-Type: text/plain; charset=UTF-8\n"
16
+ "Content-Transfer-Encoding: 8bit\n"
17
+ "Language: fr\n"
18
+ "Plural-Forms: nplurals=3; plural=(n == 0 || n == 1) ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;\n"
19
+
20
+ #: models/news.py:51 viewsets/display.py:54 viewsets/display.py:100
21
+ #: viewsets/display.py:141
22
+ msgid "Datetime"
23
+ msgstr ""
24
+
25
+ #: models/news.py:52 serializers.py:21 serializers.py:76
26
+ #: viewsets/display.py:20 viewsets/display.py:55 viewsets/display.py:102
27
+ #: viewsets/display.py:142
28
+ msgid "Title"
29
+ msgstr ""
30
+
31
+ #: models/news.py:54 serializers.py:24 serializers.py:77
32
+ #: viewsets/display.py:23 viewsets/display.py:57 viewsets/display.py:104
33
+ #: viewsets/display.py:143
34
+ msgid "Description"
35
+ msgstr ""
36
+
37
+ #: models/news.py:55 serializers.py:78 viewsets/display.py:56
38
+ #: viewsets/display.py:103
39
+ msgid "Summary"
40
+ msgstr ""
41
+
42
+ #: models/news.py:56 viewsets/display.py:60 viewsets/display.py:144
43
+ msgid "Language"
44
+ msgstr ""
45
+
46
+ #: models/news.py:57
47
+ msgid "Link"
48
+ msgstr ""
49
+
50
+ #: models/news.py:61 viewsets/display.py:59 viewsets/display.py:106
51
+ msgid "Source"
52
+ msgstr ""
53
+
54
+ #: models/news.py:64
55
+ msgid "Mark as duplicate"
56
+ msgstr ""
57
+
58
+ #: models/relationships.py:9
59
+ msgid "Positive"
60
+ msgstr ""
61
+
62
+ #: models/relationships.py:10
63
+ msgid "Slightly Positive"
64
+ msgstr ""
65
+
66
+ #: models/relationships.py:11
67
+ msgid "Slightly Negative"
68
+ msgstr ""
69
+
70
+ #: models/relationships.py:12
71
+ msgid "Negative"
72
+ msgstr ""
73
+
74
+ #: serializers.py:22
75
+ msgid "Identifier"
76
+ msgstr ""
77
+
78
+ #: serializers.py:25 viewsets/display.py:22
79
+ msgid "Author"
80
+ msgstr ""
81
+
82
+ #: serializers.py:26
83
+ msgid "Updated"
84
+ msgstr ""
85
+
86
+ #: serializers.py:79
87
+ msgid "Date"
88
+ msgstr ""
89
+
90
+ #: serializers.py:92 viewsets/menu.py:6 viewsets/titles.py:24
91
+ msgid "News"
92
+ msgstr ""
93
+
94
+ #: viewsets/buttons.py:14
95
+ msgid "Open News"
96
+ msgstr ""
97
+
98
+ #: viewsets/buttons.py:21 viewsets/buttons.py:22 viewsets/buttons.py:24
99
+ msgid "Reset relationships"
100
+ msgstr ""
101
+
102
+ #: viewsets/display.py:21
103
+ msgid "RSS feed"
104
+ msgstr ""
105
+
106
+ #: viewsets/display.py:24
107
+ msgid "Last Update"
108
+ msgstr ""
109
+
110
+ #: viewsets/display.py:61
111
+ msgid "Image"
112
+ msgstr ""
113
+
114
+ #: viewsets/display.py:93
115
+ msgid "Linked Object"
116
+ msgstr ""
117
+
118
+ #: viewsets/display.py:101
119
+ msgid "Analysis"
120
+ msgstr ""
121
+
122
+ #: viewsets/display.py:105
123
+ msgid "Important"
124
+ msgstr ""
125
+
126
+ #: viewsets/menu.py:11
127
+ msgid "News Relationships"
128
+ msgstr ""
129
+
130
+ #: viewsets/menu.py:17 viewsets/titles.py:9
131
+ msgid "Sources"
132
+ msgstr ""
133
+
134
+ #: viewsets/menu.py:23
135
+ msgid "Create Source"
136
+ msgstr ""
137
+
138
+ #: viewsets/titles.py:13
139
+ #, python-brace-format
140
+ msgid "Source: {source}"
141
+ msgstr ""
142
+
143
+ #: viewsets/titles.py:14
144
+ msgid "News Source"
145
+ msgstr ""
146
+
147
+ #: viewsets/titles.py:19
148
+ msgid "News Flow"
149
+ msgstr ""
150
+
151
+ #: viewsets/titles.py:30
152
+ #, python-brace-format
153
+ msgid "News from {source}"
154
+ msgstr ""
155
+
156
+ #: viewsets/titles.py:36
157
+ msgid "News Article for {}"
158
+ msgstr ""
159
+
160
+ #: viewsets/titles.py:37 viewsets/titles.py:44
161
+ msgid "News Article"
162
+ msgstr ""
@@ -0,0 +1,27 @@
1
+ # Generated by Django 5.0.14 on 2025-05-06 14:44
2
+
3
+ from django.db import migrations, models
4
+ from django.db.models import Count
5
+ from tqdm import tqdm
6
+
7
+ def handle_duplicated_relationship(apps, schema_editor):
8
+ NewsRelationship = apps.get_model("wbnews", "NewsRelationship")
9
+ qs = NewsRelationship.objects.values('content_type', 'object_id', 'news').annotate(c=Count('*')).filter(c__gt=1)
10
+ for row in tqdm(qs, total=qs.count()):
11
+ for rel in NewsRelationship.objects.filter(content_type=row['content_type'], news=row['news'], object_id=row["object_id"])[1:]:
12
+ rel.delete()
13
+
14
+ class Migration(migrations.Migration):
15
+
16
+ dependencies = [
17
+ ('contenttypes', '0002_remove_content_type_name'),
18
+ ('wbnews', '0013_alter_news_datetime'),
19
+ ]
20
+
21
+ operations = [
22
+ migrations.RunPython(handle_duplicated_relationship),
23
+ migrations.AddConstraint(
24
+ model_name='newsrelationship',
25
+ constraint=models.UniqueConstraint(fields=('content_type', 'object_id', 'news'), name='unique_news_relationship'),
26
+ ),
27
+ ]
@@ -5,27 +5,7 @@ from pydantic import BaseModel, Field
5
5
  from wbcore.contrib.ai.llm.config import LLMConfig
6
6
 
7
7
  if TYPE_CHECKING:
8
- from wbnews.models import News
9
-
10
-
11
- def clean_news_prompt(news: "News"):
12
- return [
13
- SystemMessage(
14
- content="I have an HTML email title and body, and I want to extract only the meaningful content in plain text format, removing all metadata, subscription links, and non-essential parts. The output should be HTML- and Markdown-free and should exclude any text related to links, subscription information, or common phrases like 'Unsubscribe' or 'View online'. Only retain the main email content but do not remove any information related to news."
15
- ),
16
- HumanMessage(
17
- content=f"Title: {news.title}\n\nDescription: {news.description}",
18
- ),
19
- ]
20
-
21
-
22
- def summarize_news_prompt(news: "News"):
23
- return [
24
- SystemMessage(content="Given this news description, please extract a short summary"),
25
- HumanMessage(
26
- content=f"Description: {news.description}",
27
- ),
28
- ]
8
+ from wbnews.models import News # noqa
29
9
 
30
10
 
31
11
  class CleanNewsModel(BaseModel):
@@ -46,18 +26,41 @@ class SummarizedNewsModel(BaseModel):
46
26
  )
47
27
 
48
28
 
29
+ def get_clean_news_config_query(instance):
30
+ return {"description": instance.description, "title": instance.title}
31
+
32
+
49
33
  clean_news_config = LLMConfig["News"](
50
34
  key="clean",
51
35
  output_model=CleanNewsModel,
52
- prompt=clean_news_prompt,
36
+ prompt=[
37
+ SystemMessage(
38
+ content="I have an HTML email title and body, and I want to extract only the meaningful content in plain text format, removing all metadata, subscription links, and non-essential parts. The output should be HTML- and Markdown-free and should exclude any text related to links, subscription information, or common phrases like 'Unsubscribe' or 'View online'. Only retain the main email content but do not remove any information related to news."
39
+ ),
40
+ HumanMessage(
41
+ content="Title: {title}\n\nDescription: {description}",
42
+ ),
43
+ ],
53
44
  on_save=True,
54
45
  on_condition=lambda n: n.source.clean_content,
46
+ query=get_clean_news_config_query,
55
47
  )
56
48
 
49
+
50
+ def get_summarized_news_config_query(instance):
51
+ return {"description": instance.description}
52
+
53
+
57
54
  summarized_news_config = LLMConfig["News"](
58
55
  key="summarize",
59
56
  output_model=SummarizedNewsModel,
60
- prompt=summarize_news_prompt,
57
+ prompt=[
58
+ SystemMessage(content="Given this news description, please extract a short summary"),
59
+ HumanMessage(
60
+ content="Description: {description}",
61
+ ),
62
+ ],
61
63
  on_save=True,
62
64
  on_condition=lambda n: not n.summary,
65
+ query=get_summarized_news_config_query,
63
66
  )
wbnews/models/news.py CHANGED
@@ -81,7 +81,8 @@ class News(ImportMixin, WBModel):
81
81
  """
82
82
  tasks = []
83
83
  for sender, task_signature in create_news_relationships.send(sender=News, instance=self):
84
- assert isinstance(task_signature, Signature), self.errors["relationship_signal"].format(sender)
84
+ if not isinstance(task_signature, Signature):
85
+ raise AssertionError(self.errors["relationship_signal"].format(sender))
85
86
  tasks.append(task_signature)
86
87
  if tasks:
87
88
  res = chord(tasks, create_relationship.s(self.id))
@@ -40,3 +40,6 @@ class NewsRelationship(models.Model):
40
40
  class Meta:
41
41
  verbose_name = "News Relationship"
42
42
  indexes = [models.Index(fields=["content_type", "object_id"])]
43
+ constraints = [
44
+ models.UniqueConstraint(name="unique_news_relationship", fields=["content_type", "object_id", "news"])
45
+ ]
@@ -1,5 +1,4 @@
1
- from unittest import mock
2
- from unittest.mock import patch, PropertyMock
1
+ from unittest.mock import PropertyMock, patch
3
2
 
4
3
  import pytest
5
4
 
@@ -7,19 +6,20 @@ from wbnews.import_export.parsers.emails.utils import EmlContentParser
7
6
 
8
7
 
9
8
  class TestEmlContentParser:
10
-
11
9
  @pytest.fixture
12
10
  def content_parser(self):
13
- parser = EmlContentParser(b'')
11
+ parser = EmlContentParser(b"")
14
12
  parser.message = {"From": "main@acme.com"}
15
13
  return parser
16
14
 
17
15
  @patch.object(EmlContentParser, "text", new_callable=PropertyMock)
18
16
  def test_source_from_in_text(self, mock_text, content_parser):
19
- mock_text.return_value = "some random email content with a From field From: source name <email@test.com> and the rest of the email"
17
+ mock_text.return_value = (
18
+ "some random email content with a From field From: source name <email@test.com> and the rest of the email"
19
+ )
20
20
  assert content_parser.source == {"title": "Source Name", "endpoint": "email@test.com", "type": "EMAIL"}
21
21
 
22
22
  @patch.object(EmlContentParser, "text", new_callable=PropertyMock)
23
- def test_source_from_in_text(self, mock_text, content_parser):
23
+ def test_source_from_in_text_alt(self, mock_text, content_parser):
24
24
  mock_text.return_value = "some random email content without a From field"
25
25
  assert content_parser.source == {"title": "Acme.Com", "endpoint": "main@acme.com", "type": "EMAIL"}
@@ -1,14 +1,15 @@
1
- from datetime import timedelta, datetime, timezone
2
- from django.utils import timezone as django_timezone
1
+ from datetime import timedelta, timezone
3
2
  from unittest.mock import patch
4
3
 
5
4
  import pytest
5
+ from django.utils import timezone as django_timezone
6
+ from faker import Faker
6
7
 
7
8
  from wbnews.models import News, NewsSource
8
- from faker import Faker
9
9
 
10
10
  fake = Faker()
11
11
 
12
+
12
13
  @pytest.mark.django_db
13
14
  class TestSource:
14
15
  @pytest.mark.parametrize("news_source__title", ["source1"])
@@ -19,17 +20,19 @@ class TestSource:
19
20
  ns1 = news_source_factory.create()
20
21
  ns2 = news_source_factory.create()
21
22
 
22
- assert NewsSource.source_dict_to_model({"id": ns1.id, "identifier": ns2.identifier}) == ns1 # priority to "id"
23
- assert NewsSource.source_dict_to_model({"endpoint": ns1.endpoint, "identifier": ns2.identifier}) == ns2 # priority to "identifier"
24
- assert NewsSource.source_dict_to_model({"endpoint": ns2.endpoint}) == ns2 # exact match on endpoint
23
+ assert NewsSource.source_dict_to_model({"id": ns1.id, "identifier": ns2.identifier}) == ns1 # priority to "id"
24
+ assert (
25
+ NewsSource.source_dict_to_model({"endpoint": ns1.endpoint, "identifier": ns2.identifier}) == ns2
26
+ ) # priority to "identifier"
27
+ assert NewsSource.source_dict_to_model({"endpoint": ns2.endpoint}) == ns2 # exact match on endpoint
25
28
 
26
29
  ns1.endpoint = ".*@test.com"
27
30
  ns1.save()
28
- assert NewsSource.source_dict_to_model({"endpoint": "abc@test.com"}) == ns1 # regex match on endpoint
31
+ assert NewsSource.source_dict_to_model({"endpoint": "abc@test.com"}) == ns1 # regex match on endpoint
29
32
 
30
33
  new_source = NewsSource.source_dict_to_model({"endpoint": "abc@main_source.com", "title": "New Source"})
31
34
  assert new_source not in [ns1, ns2]
32
- assert new_source.endpoint == ".*@main_source\.com"
35
+ assert new_source.endpoint == r".*@main_source\.com"
33
36
  assert new_source.title == "New Source"
34
37
  assert new_source.author == "Main Source"
35
38
 
@@ -45,24 +48,31 @@ class TestNews:
45
48
 
46
49
  def test_get_default_guid(self):
47
50
  assert News.get_default_guid("This is a title", None) == "this-is-a-title"
48
- assert News.get_default_guid("This is a title", "http://mylink.com") == "http://mylink.com" # link takes precendence
51
+ assert (
52
+ News.get_default_guid("This is a title", "http://mylink.com") == "http://mylink.com"
53
+ ) # link takes precendence
49
54
  assert News.get_default_guid("a" * 24, None, max_length=20) == "a" * 20
50
55
 
51
56
  def test_future_news(self, news_factory):
52
57
  # ensure a future datetime always default to now
53
58
  now = django_timezone.now()
54
59
  future_news = news_factory.create(datetime=now + timedelta(days=1))
55
- assert (future_news.datetime - now).seconds < 1 # we do that to account for clock difference
60
+ assert (future_news.datetime - now).seconds < 1 # we do that to account for clock difference
56
61
 
57
62
  @patch("wbnews.models.news.detect_near_duplicates")
58
63
  def test_handle_duplicates(self, mock_fct, news_factory):
59
64
  val_date = fake.date_time(tzinfo=timezone.utc)
60
- n0 = news_factory.create(datetime=val_date - timedelta(days=1)) # we exclude this news from the duplicate search
65
+ n0 = news_factory.create(
66
+ datetime=val_date - timedelta(days=1)
67
+ ) # we exclude this news from the duplicate search
61
68
  n1 = news_factory.create(datetime=val_date)
62
69
  n2 = news_factory.create(datetime=val_date)
63
70
  n3 = news_factory.create(datetime=val_date)
64
71
 
65
- mock_fct.return_value = [n0.id, n3.id] # n0 is considered as duplicate but does not fall within the specified daterange so it will not be marked
72
+ mock_fct.return_value = [
73
+ n0.id,
74
+ n3.id,
75
+ ] # n0 is considered as duplicate but does not fall within the specified daterange so it will not be marked
66
76
  News.handle_duplicates(val_date, val_date)
67
77
 
68
78
  n3.refresh_from_db()
wbnews/utils.py CHANGED
@@ -11,7 +11,7 @@ logger = logging.getLogger("news")
11
11
 
12
12
  def _get_similarity_matrix_df(data: dict[int, str]) -> pd.DataFrame:
13
13
  # Convert texts to TF-IDF vectors
14
- ids, texts = zip(*data.items())
14
+ ids, texts = zip(*data.items(), strict=False)
15
15
  vectorizer = TfidfVectorizer()
16
16
  tfidf_matrix = vectorizer.fit_transform(texts)
17
17
  # Compute pairwise cosine similarity...
@@ -83,6 +83,8 @@ class NewsRelationshipDisplayConfig(DisplayViewConfig):
83
83
  "sentiment",
84
84
  ],
85
85
  ["analysis", "analysis"],
86
+ ["summary", "summary"],
87
+ ["description", "description"],
86
88
  ]
87
89
  )
88
90
 
@@ -7,23 +7,19 @@ class NewsEndpointConfig(EndpointViewConfig):
7
7
  def get_endpoint(self, **kwargs):
8
8
  return None
9
9
 
10
- def get_list_endpoint(self, **kwargs):
11
- return reverse("wbnews:news-list", request=self.request)
12
-
13
10
  def get_instance_endpoint(self, **kwargs):
14
- return self.get_list_endpoint()
11
+ return reverse("wbnews:news-list", request=self.request)
15
12
 
16
13
 
17
14
  class NewsSourceEndpointConfig(NewsEndpointConfig):
18
- def get_list_endpoint(self, **kwargs):
19
- return reverse("wbnews:source-news-list", args=[self.view.kwargs["source_id"]], request=self.request)
15
+ pass
20
16
 
21
17
 
22
18
  class NewsRelationshipEndpointConfig(EndpointViewConfig):
23
19
  def get_endpoint(self, **kwargs):
24
20
  return reverse("wbnews:newsrelationship-list", args=[], request=self.request)
25
21
 
26
- def get_list_endpoint(self, **kwargs):
22
+ def get_create_endpoint(self, **kwargs):
27
23
  params = {}
28
24
  if ct := self.view.content_type:
29
25
  params["content_type"] = ct.id
@@ -31,9 +27,6 @@ class NewsRelationshipEndpointConfig(EndpointViewConfig):
31
27
  params["object_id"] = object_id
32
28
  return get_urlencode_endpoint(self.get_endpoint(**kwargs), params)
33
29
 
34
- def get_create_endpoint(self, **kwargs):
35
- return self.get_list_endpoint()
36
-
37
30
  # def get_instance_endpoint(self, **kwargs):
38
31
  # return reverse("wbnews:news-list", args=[], request=self.request)
39
32
  #
@@ -1,8 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wbnews
3
- Version: 1.50.4
3
+ Version: 1.58.1
4
4
  Summary: A workbench module for managing news.
5
5
  Author-email: Christopher Wittlinger <c.wittlinger@stainly.com>
6
6
  Requires-Dist: feedparser==6.*
7
- Requires-Dist: langdetect==1.*
8
7
  Requires-Dist: wbcore
@@ -7,22 +7,28 @@ wbnews/serializers.py,sha256=KihExQ_GS1fNZnojryEcfU32xlTiPn-K2WGO0Zc84Cw,4732
7
7
  wbnews/signals.py,sha256=eqipwffwJnDQWUZ9VTKr5Jp-OMXLmVSNwoIsawnCKvM,192
8
8
  wbnews/tasks.py,sha256=ce9JbXKnJnf7La74h0LPwm3yrygHNe1BKZju_4m1itw,384
9
9
  wbnews/urls.py,sha256=2Gs9RGU8x6tNOLJiuG17n_ik82QVb8jlw7bU07Lk_S4,1008
10
- wbnews/utils.py,sha256=LFB9vDP4j5DK040drwHeNHK5Dl8Mf4NvDOVrjPjTXhw,1941
10
+ wbnews/utils.py,sha256=h4TdMbUL0qQ2h3o3jEpGuGwT90TWiryVRtBXc7avLW0,1955
11
11
  wbnews/filters/__init__.py,sha256=FXJcPsLQePCU-fzjpIu44Dsdu9vCckLHr0Kr-8Z_-C4,59
12
- wbnews/filters/news.py,sha256=YM4wQUUVoPJl-ssXJ_t__-fmUAG7IkI71wjLGyxpXYU,1576
12
+ wbnews/filters/news.py,sha256=glG45wx_Jxee57H43oqCCJIjQumrNUh8pVXiD0hBM6E,1662
13
13
  wbnews/fixtures/wbnews.yaml,sha256=cDu1UWYwIFxz-hdivW7rxLYsNOweBm4GdN1GDsycN90,173164
14
14
  wbnews/import_export/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
15
  wbnews/import_export/backends/__init__.py,sha256=_2HnB9uCuGhQDNg-Z0V2uIvKn26LtRBXAxUBoNetBIo,30
16
16
  wbnews/import_export/backends/news.py,sha256=QqMeAWYh4U3W4Sng0HlHx11RoR1LV_WZmRUr58dYrVg,1461
17
17
  wbnews/import_export/handlers/__init__.py,sha256=zOeENt9cpEcSLG9ZaVb4otmbTnLAa0XdTPsUjD11dXs,36
18
- wbnews/import_export/handlers/news.py,sha256=vxnVk00yHwpp7ZaNpBF-6n7HIvVFUQe91FJTm8AK8mA,1976
18
+ wbnews/import_export/handlers/news.py,sha256=cdrtWIP3XOU8NMYZKF8VLYH5qHmPLboUm_GwNAvO2ew,2181
19
19
  wbnews/import_export/parsers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
20
20
  wbnews/import_export/parsers/emails/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
- wbnews/import_export/parsers/emails/news.py,sha256=YbInbXJ5pk1IS7fEOutuW9LIU4KzZXBx0HZHZrKmeIc,1507
22
- wbnews/import_export/parsers/emails/utils.py,sha256=cdlq1hMbVYDzhB7qyXOvZNBPBeKhKwmuSHvfW18bWxM,2205
21
+ wbnews/import_export/parsers/emails/news.py,sha256=8fSgjSPuSmdfGKV1IxLMWriqGhDAG-tiZUyAgWpjZ_M,1236
22
+ wbnews/import_export/parsers/emails/utils.py,sha256=k7R1HZx18FKXRq10COARFgHjjBadsWe1DY3AHCrwHRs,2207
23
23
  wbnews/import_export/parsers/rss/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
24
- wbnews/import_export/parsers/rss/news.py,sha256=DERNesKPLzEcPYPjGc6lp2qhGtKdmqvLgqsab32Q3hw,2375
25
- wbnews/locale/de/LC_MESSAGES/django.po,sha256=b5Mc0-cowNbFMo-5cbhGa2-B-KfRM6pw8EZxTg6uRx4,2662
24
+ wbnews/import_export/parsers/rss/news.py,sha256=H89avqOU_AUAyHiIXd_tfoMbcqy67GgDQ2-ucihDpks,2076
25
+ wbnews/locale/de/LC_MESSAGES/django.mo,sha256=M70N6el-I7EymxHLw9n773Bimbztf8s8equWa9SydBs,1283
26
+ wbnews/locale/de/LC_MESSAGES/django.po,sha256=furtxh-NgkodwE4dv0uXaRtWF2z3NxWtEw64tH9OMN4,3494
27
+ wbnews/locale/de/LC_MESSAGES/django.po.translated,sha256=ILRIDL_vON91Do5QhZr5N85Y4vsOAIHsaU8QX0FiEA4,3962
28
+ wbnews/locale/en/LC_MESSAGES/django.mo,sha256=UXCQbz2AxBvh-IQ7bGgjoBnijo8h9DfE9107A-2Mgkk,337
29
+ wbnews/locale/en/LC_MESSAGES/django.po,sha256=K7SPoXdLZHyOOAoIOEydgJwl1qdQMrK3uapd4EMrVIg,3125
30
+ wbnews/locale/fr/LC_MESSAGES/django.mo,sha256=t4lh3zX7kshbDAFzXa5HU_YGPXkPzKqODNXL2MeZ5KQ,429
31
+ wbnews/locale/fr/LC_MESSAGES/django.po,sha256=kRBjvETEy0GMPqX0H6EArGqrtzhYXwswjUW-JDajlbM,3232
26
32
  wbnews/migrations/0001_initial_squashed_0005_alter_news_import_source.py,sha256=4qxqfpAYVeU16GsWaj7kUbtOk0ZLzuECTfzhUfmni2A,14596
27
33
  wbnews/migrations/0006_alter_news_language.py,sha256=necqSWKi20sHLok-RO9He3vnmMlmmdx07AiN3lnZPBM,4638
28
34
  wbnews/migrations/0007_auto_20240103_0955.py,sha256=YzkH_LSWH_8qdw_BrKaTN5vqLNCPnjMlJZxs03Xbbvw,1478
@@ -32,27 +38,28 @@ wbnews/migrations/0010_newsrelationship_important.py,sha256=seK-bFIzXa6uzja0gPnR
32
38
  wbnews/migrations/0011_newsrelationship_content_object_repr.py,sha256=oJUhx__5WI6TjPGPqqEqBgb3yDluc02hhh05nXTjbHw,428
33
39
  wbnews/migrations/0012_alter_news_unique_together_news_identifier_and_more.py,sha256=SLtQiREJYMwOytGGLqaCYr_9pSeD_XD5ax7lXSETT3w,3111
34
40
  wbnews/migrations/0013_alter_news_datetime.py,sha256=q4Gbxo25jClsv9b1kfTqBLmpPNHAq7LxOgEZeLYYRk4,497
41
+ wbnews/migrations/0014_newsrelationship_unique_news_relationship.py,sha256=aZUHLMKRMaXHJrrbnV9O2ZJRDVjbpkb9NjVPB7VKVW0,1073
35
42
  wbnews/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
36
43
  wbnews/models/__init__.py,sha256=KKIcQbpCPCVNJUPJs2MtpN9Q2Wb34Qdk-C7w6AAOy7w,99
37
- wbnews/models/news.py,sha256=PJFcG5WFBkEkfnxkLLMqyCz9cLq0fkwuPlgYVyK2i44,5165
38
- wbnews/models/relationships.py,sha256=jwLedg3Fb_nxxofJGmAJRMEuq5QwT5LyBQDBjtyqxNw,1692
44
+ wbnews/models/news.py,sha256=yRbOpVG69yssvJPzv9bZJGMoFcb9n2uLaG2mz2j8oxM,5203
45
+ wbnews/models/relationships.py,sha256=bcQbRa-ObS9h67pIuIrodD63RnkzbaOaRT4L6ctBoI0,1841
39
46
  wbnews/models/sources.py,sha256=N3-rBg4myeGG_stHvKiNnSoH0yS-LS_Zr_UeKPMBr5s,2629
40
47
  wbnews/models/utils.py,sha256=1JQxV4WxmmFGl7MdVtJoEeao3vnqqVwCi7mhSToaUvM,600
41
- wbnews/models/llm/cleaned_news.py,sha256=87T-qZjnTTJdCbbUWFCBc4cJr8Km9SmDP39fixVdo5o,2077
48
+ wbnews/models/llm/cleaned_news.py,sha256=PA0McsgMmR0TOZUNWs55sBnsCXGbaC61VtVFbJ8vx28,2226
42
49
  wbnews/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
43
50
  wbnews/tests/conftest.py,sha256=UEZOYH5Av-Cqqq5t8WQCR7QJdNnajhthBPpF8AnwQjY,186
44
- wbnews/tests/test_models.py,sha256=99npnSWhqfspxizaWa5Ay4JY84ziGy64_BnKj8Tmol8,3173
51
+ wbnews/tests/test_models.py,sha256=op79cYyz9f5dX1uRBztw-E0J4HYAY8K-7cz4kBCN0qk,3278
45
52
  wbnews/tests/test_utils.py,sha256=PsyHH_F_y-Uy3mdVgDINH19bPEd1bmZT_UQ7yu87BNU,278
46
53
  wbnews/tests/tests.py,sha256=OADY-vbKZBe0bjjVEO1KNzRYAP2JA9mWkO9pZuh1TSs,280
47
54
  wbnews/tests/parsers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
48
- wbnews/tests/parsers/test_emails.py,sha256=uFg9eErF3gzyc6zULnUq-3p6O3rg1HBAlb59Lw4CWSk,1072
55
+ wbnews/tests/parsers/test_emails.py,sha256=dStdTPI7Ns1jSw5PDbDEc84FJaoNPnBHC4BskWDDMxY,1073
49
56
  wbnews/viewsets/__init__.py,sha256=2OhRiJy0MVK9TdMpFmS9x9jl_gM-CjBxUoUHlZB3_8U,531
50
57
  wbnews/viewsets/buttons.py,sha256=6m_IdRYCQgTH4mD51DUoOa8Vx1y1-2zPQydUdvL_nF4,1788
51
- wbnews/viewsets/display.py,sha256=RilRauryRZf3WakiRX9XxeFZ2E0B4nX6QR3iP2quZrY,5227
52
- wbnews/viewsets/endpoints.py,sha256=2YCwkvAFtSIuIevF-V61_fD9Mj29DRSime5AewFI1oU,1477
58
+ wbnews/viewsets/display.py,sha256=fwMZLlwxHcNHM4AppwYpYTOicLD_pXaQ4QeFeIl4whk,5315
59
+ wbnews/viewsets/endpoints.py,sha256=2slGDJin_SA2heWsIaMdNTUN46FqZJvusbY1jhAaeZM,1165
53
60
  wbnews/viewsets/menu.py,sha256=XTShfTIykN9t7oclosPfFVb1r6o46QyglEEe1C7QCMk,979
54
61
  wbnews/viewsets/titles.py,sha256=iMyiGBMBpzng8s2ySVLqEOwueHRnAoEuc75dt9nCPjc,1367
55
62
  wbnews/viewsets/views.py,sha256=SMCDT6bJMQblyqX5cQ7X3qDe0zxTVWh1q7Aqj0fBo2Q,6795
56
- wbnews-1.50.4.dist-info/METADATA,sha256=Zr0lz3sRtFBnHoTt0UTuFeUFj6ehBON6XiMa1JNr-2c,246
57
- wbnews-1.50.4.dist-info/WHEEL,sha256=tkmg4JIqwd9H8mL30xA7crRmoStyCtGp0VWshokd1Jc,105
58
- wbnews-1.50.4.dist-info/RECORD,,
63
+ wbnews-1.58.1.dist-info/METADATA,sha256=fcooyHVRuEH6JK057omSnAA1I-EzsLuJJuoX5Ruvovs,215
64
+ wbnews-1.58.1.dist-info/WHEEL,sha256=tkmg4JIqwd9H8mL30xA7crRmoStyCtGp0VWshokd1Jc,105
65
+ wbnews-1.58.1.dist-info/RECORD,,