djangoldp-ds4go 1.0.0__tar.gz → 1.0.2__tar.gz
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.
- {djangoldp_ds4go-1.0.0 → djangoldp_ds4go-1.0.2}/PKG-INFO +1 -1
- djangoldp_ds4go-1.0.2/README.md +59 -0
- djangoldp_ds4go-1.0.2/djangoldp_ds4go/__init__.py +1 -0
- djangoldp_ds4go-1.0.2/djangoldp_ds4go/management/commands/__init__.py +0 -0
- djangoldp_ds4go-1.0.2/djangoldp_ds4go/management/commands/import_rss.py +126 -0
- djangoldp_ds4go-1.0.2/djangoldp_ds4go/migrations/__init__.py +0 -0
- {djangoldp_ds4go-1.0.0 → djangoldp_ds4go-1.0.2}/djangoldp_ds4go/models/category.py +1 -0
- {djangoldp_ds4go-1.0.0 → djangoldp_ds4go-1.0.2}/djangoldp_ds4go/models/fact.py +2 -1
- {djangoldp_ds4go-1.0.0 → djangoldp_ds4go-1.0.2}/djangoldp_ds4go.egg-info/PKG-INFO +1 -1
- {djangoldp_ds4go-1.0.0 → djangoldp_ds4go-1.0.2}/djangoldp_ds4go.egg-info/SOURCES.txt +3 -0
- djangoldp_ds4go-1.0.0/README.md +0 -20
- djangoldp_ds4go-1.0.0/djangoldp_ds4go/__init__.py +0 -1
- {djangoldp_ds4go-1.0.0 → djangoldp_ds4go-1.0.2}/djangoldp_ds4go/admin.py +0 -0
- {djangoldp_ds4go-1.0.0 → djangoldp_ds4go-1.0.2}/djangoldp_ds4go/apps.py +0 -0
- {djangoldp_ds4go-1.0.0/djangoldp_ds4go/migrations → djangoldp_ds4go-1.0.2/djangoldp_ds4go/management}/__init__.py +0 -0
- {djangoldp_ds4go-1.0.0 → djangoldp_ds4go-1.0.2}/djangoldp_ds4go/migrations/0001_initial.py +0 -0
- {djangoldp_ds4go-1.0.0 → djangoldp_ds4go-1.0.2}/djangoldp_ds4go/migrations/0002_djangoldp_i18n.py +0 -0
- {djangoldp_ds4go-1.0.0 → djangoldp_ds4go-1.0.2}/djangoldp_ds4go/models/__base_model.py +0 -0
- {djangoldp_ds4go-1.0.0 → djangoldp_ds4go-1.0.2}/djangoldp_ds4go/models/__base_named_model.py +0 -0
- {djangoldp_ds4go-1.0.0 → djangoldp_ds4go-1.0.2}/djangoldp_ds4go/models/__init__.py +0 -0
- {djangoldp_ds4go-1.0.0 → djangoldp_ds4go-1.0.2}/djangoldp_ds4go/models/media.py +0 -0
- {djangoldp_ds4go-1.0.0 → djangoldp_ds4go-1.0.2}/djangoldp_ds4go/translation.py +0 -0
- {djangoldp_ds4go-1.0.0 → djangoldp_ds4go-1.0.2}/djangoldp_ds4go.egg-info/dependency_links.txt +0 -0
- {djangoldp_ds4go-1.0.0 → djangoldp_ds4go-1.0.2}/djangoldp_ds4go.egg-info/requires.txt +0 -0
- {djangoldp_ds4go-1.0.0 → djangoldp_ds4go-1.0.2}/djangoldp_ds4go.egg-info/top_level.txt +0 -0
- {djangoldp_ds4go-1.0.0 → djangoldp_ds4go-1.0.2}/setup.cfg +0 -0
- {djangoldp_ds4go-1.0.0 → djangoldp_ds4go-1.0.2}/setup.py +0 -0
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# DjangoLDP DS4GO
|
|
2
|
+
|
|
3
|
+
This is a Django package for the DS4GO ecosystem, providing models and tools for fact-checking applications.
|
|
4
|
+
|
|
5
|
+
See [DSIF](https://dsif.eu/).
|
|
6
|
+
|
|
7
|
+
## Configuration
|
|
8
|
+
|
|
9
|
+
Add `djangoldp_ds4go` to your `INSTALLED_APPS` and configure internationalization settings:
|
|
10
|
+
|
|
11
|
+
```yaml
|
|
12
|
+
dependencies:
|
|
13
|
+
- djangoldp-account
|
|
14
|
+
- django-webidoidc-provider
|
|
15
|
+
- djangoldp-i18n
|
|
16
|
+
- djangoldp-ds4go
|
|
17
|
+
# ...
|
|
18
|
+
|
|
19
|
+
ldppackages:
|
|
20
|
+
- rest_framework
|
|
21
|
+
- oidc_provider
|
|
22
|
+
- djangoldp_account
|
|
23
|
+
- djangoldp_i18n
|
|
24
|
+
- djangoldp_ds4go
|
|
25
|
+
# ...
|
|
26
|
+
|
|
27
|
+
# [...]
|
|
28
|
+
|
|
29
|
+
server:
|
|
30
|
+
# [...] # See djangoldp configuration for other settings
|
|
31
|
+
|
|
32
|
+
USE_I18N: True
|
|
33
|
+
# Your application default language, will be served if no header are provided
|
|
34
|
+
LANGUAGE_CODE: fr
|
|
35
|
+
# Your application fallback language, will be served when a requested language is not available
|
|
36
|
+
MODELTRANSLATION_DEFAULT_LANGUAGE: fr
|
|
37
|
+
# Priority order. Ensure that every language is listed here to avoid empty translations
|
|
38
|
+
MODELTRANSLATION_FALLBACK_LANGUAGES:
|
|
39
|
+
- fr
|
|
40
|
+
- en
|
|
41
|
+
- es
|
|
42
|
+
# A list of all supported languages, you **must** make a migration afterwise
|
|
43
|
+
LANGUAGES:
|
|
44
|
+
- ['fr', 'Français']
|
|
45
|
+
- ['en', 'English']
|
|
46
|
+
- ['es', 'Español']
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Run `python manage.py makemigrations` and `python manage.py migrate` after updating language settings.
|
|
50
|
+
|
|
51
|
+
## Importing RSS Data
|
|
52
|
+
|
|
53
|
+
Import fact-check data from RSS feeds using the management command:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
python manage.py import_rss --rss_file="path/to/rss.xml"
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
This command parses RSS XML to create or update facts, handling translations based on the feed language, creating category hierarchies, and importing media metadata.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = '1.0.2'
|
|
File without changes
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import json
|
|
2
|
+
|
|
3
|
+
from defusedxml.ElementTree import parse
|
|
4
|
+
from django.core.management.base import BaseCommand
|
|
5
|
+
|
|
6
|
+
from djangoldp_ds4go.models import Category, Fact, Media
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Command(BaseCommand):
|
|
10
|
+
help = "Import facts from RSS file"
|
|
11
|
+
|
|
12
|
+
def add_arguments(self, parser):
|
|
13
|
+
parser.add_argument("--rss_file", type=str, help="Path to the RSS file")
|
|
14
|
+
|
|
15
|
+
def handle(self, *args, **options):
|
|
16
|
+
rss_file = options["rss_file"]
|
|
17
|
+
tree = parse(rss_file)
|
|
18
|
+
root = tree.getroot()
|
|
19
|
+
ns = {
|
|
20
|
+
"schema": "https://schema.org/",
|
|
21
|
+
"media": "http://search.yahoo.com/mrss/",
|
|
22
|
+
"content": "http://purl.org/rss/1.0/modules/content/",
|
|
23
|
+
}
|
|
24
|
+
channel = root.find("channel")
|
|
25
|
+
language_elem = channel.find("language")
|
|
26
|
+
language = language_elem.text if language_elem is not None else "fr"
|
|
27
|
+
|
|
28
|
+
for item in channel.findall("item"):
|
|
29
|
+
guid = item.find("guid").text
|
|
30
|
+
existing_fact = Fact.objects.filter(rss_guid=guid).first()
|
|
31
|
+
title = item.find("title").text
|
|
32
|
+
link = item.find("link").text
|
|
33
|
+
review_elem = item.find("schema:review", ns)
|
|
34
|
+
|
|
35
|
+
try:
|
|
36
|
+
review = json.loads(review_elem.text) if review_elem is not None else {}
|
|
37
|
+
except json.JSONDecodeError:
|
|
38
|
+
review = {}
|
|
39
|
+
self.stderr.write(self.style.WARNING("Failed to parse review for item with guid %s. Ignoring." % (guid)))
|
|
40
|
+
|
|
41
|
+
description = item.find("description").text
|
|
42
|
+
content_elem = item.find("content:encoded", ns)
|
|
43
|
+
content = content_elem.text if content_elem is not None else ""
|
|
44
|
+
author = item.find("author").text if item.find("author") is not None else ""
|
|
45
|
+
enclosure_url = None
|
|
46
|
+
enclosure = item.find("enclosure")
|
|
47
|
+
|
|
48
|
+
if enclosure is not None:
|
|
49
|
+
enclosure_url = enclosure.get("url")
|
|
50
|
+
|
|
51
|
+
if existing_fact:
|
|
52
|
+
fact = existing_fact
|
|
53
|
+
self.stdout.write(f"Updating existing fact with guid {guid}")
|
|
54
|
+
else:
|
|
55
|
+
fact = Fact.objects.create(
|
|
56
|
+
rss_guid=guid,
|
|
57
|
+
link=link,
|
|
58
|
+
review=review,
|
|
59
|
+
)
|
|
60
|
+
self.stdout.write(f"Creating new fact: {title}")
|
|
61
|
+
|
|
62
|
+
# Set translated fields
|
|
63
|
+
setattr(fact, f"name_{language}", title)
|
|
64
|
+
setattr(fact, f"description_{language}", description)
|
|
65
|
+
setattr(fact, f"content_{language}", content)
|
|
66
|
+
setattr(fact, f"author_{language}", author)
|
|
67
|
+
|
|
68
|
+
if enclosure_url:
|
|
69
|
+
setattr(fact, f"enclosure_{language}", enclosure_url)
|
|
70
|
+
|
|
71
|
+
fact.save()
|
|
72
|
+
|
|
73
|
+
# Categories
|
|
74
|
+
categories = item.findall("category")
|
|
75
|
+
for cat_elem in categories:
|
|
76
|
+
cat_name = cat_elem.text
|
|
77
|
+
category = self.get_or_create_category(cat_name, language)
|
|
78
|
+
fact.categories.add(category)
|
|
79
|
+
|
|
80
|
+
# Medias
|
|
81
|
+
for media_elem in item.findall("media:content", ns):
|
|
82
|
+
url = media_elem.get("url")
|
|
83
|
+
file_size = int(media_elem.get("fileSize", 0))
|
|
84
|
+
width = int(media_elem.get("width", 0))
|
|
85
|
+
height = int(media_elem.get("height", 0))
|
|
86
|
+
file_type = media_elem.get("type")
|
|
87
|
+
desc = media_elem.find("media:description", ns)
|
|
88
|
+
description = desc.text if desc is not None else ""
|
|
89
|
+
existing_media = Media.objects.filter(
|
|
90
|
+
url=url, related_fact=fact
|
|
91
|
+
).first()
|
|
92
|
+
|
|
93
|
+
if existing_media:
|
|
94
|
+
setattr(existing_media, f"description_{language}", description)
|
|
95
|
+
existing_media.save()
|
|
96
|
+
else:
|
|
97
|
+
media = Media.objects.create(
|
|
98
|
+
url=url,
|
|
99
|
+
file_size=file_size,
|
|
100
|
+
width=width,
|
|
101
|
+
height=height,
|
|
102
|
+
file_type=file_type,
|
|
103
|
+
related_fact=fact,
|
|
104
|
+
)
|
|
105
|
+
setattr(media, f"description_{language}", description)
|
|
106
|
+
media.save()
|
|
107
|
+
|
|
108
|
+
self.stdout.write(f"Processed fact: {title}")
|
|
109
|
+
|
|
110
|
+
def get_or_create_category(self, cat_name, language):
|
|
111
|
+
parts = cat_name.split("/")
|
|
112
|
+
current_parent = None
|
|
113
|
+
|
|
114
|
+
for part in parts:
|
|
115
|
+
part = part.strip()
|
|
116
|
+
category, created = Category.objects.get_or_create(
|
|
117
|
+
name=part,
|
|
118
|
+
parent_category=current_parent,
|
|
119
|
+
)
|
|
120
|
+
# FIXME: I don't know how to handle i18n here as these are strings: "Media Topic" could be "Totoro" in another lang?
|
|
121
|
+
# if created or not getattr(category, f"name_{language}", None):
|
|
122
|
+
# setattr(category, f"name_{language}", part)
|
|
123
|
+
# category.save()
|
|
124
|
+
current_parent = category
|
|
125
|
+
|
|
126
|
+
return current_parent
|
|
File without changes
|
|
@@ -14,6 +14,7 @@ class Category(baseNamedModel):
|
|
|
14
14
|
class Meta(baseNamedModel.Meta):
|
|
15
15
|
verbose_name = _("Category")
|
|
16
16
|
verbose_name_plural = _("Categories")
|
|
17
|
+
container_path = "categories"
|
|
17
18
|
|
|
18
19
|
rdf_type = "ds4go:Category"
|
|
19
20
|
serializer_fields = baseNamedModel.Meta.serializer_fields + [
|
|
@@ -26,6 +26,7 @@ class Fact(baseNamedModel):
|
|
|
26
26
|
enclosure = fields.LDPUrlField(blank=True, null=True, verbose_name=_("Enclosure"))
|
|
27
27
|
|
|
28
28
|
class Meta(baseNamedModel.Meta):
|
|
29
|
+
depth = 1
|
|
29
30
|
verbose_name = _("Fact")
|
|
30
31
|
verbose_name_plural = _("Facts")
|
|
31
32
|
|
|
@@ -41,6 +42,6 @@ class Fact(baseNamedModel):
|
|
|
41
42
|
"review",
|
|
42
43
|
]
|
|
43
44
|
|
|
44
|
-
nested_fields = baseNamedModel.Meta.nested_fields + ["medias"]
|
|
45
|
+
nested_fields = baseNamedModel.Meta.nested_fields + ["categories", "medias"]
|
|
45
46
|
|
|
46
47
|
view_set = I18nLDPViewSet
|
|
@@ -10,6 +10,9 @@ djangoldp_ds4go.egg-info/SOURCES.txt
|
|
|
10
10
|
djangoldp_ds4go.egg-info/dependency_links.txt
|
|
11
11
|
djangoldp_ds4go.egg-info/requires.txt
|
|
12
12
|
djangoldp_ds4go.egg-info/top_level.txt
|
|
13
|
+
djangoldp_ds4go/management/__init__.py
|
|
14
|
+
djangoldp_ds4go/management/commands/__init__.py
|
|
15
|
+
djangoldp_ds4go/management/commands/import_rss.py
|
|
13
16
|
djangoldp_ds4go/migrations/0001_initial.py
|
|
14
17
|
djangoldp_ds4go/migrations/0002_djangoldp_i18n.py
|
|
15
18
|
djangoldp_ds4go/migrations/__init__.py
|
djangoldp_ds4go-1.0.0/README.md
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
# DjangoLDP DS4GO
|
|
2
|
-
|
|
3
|
-
This is a Django project for DS4GO ecosystem.
|
|
4
|
-
|
|
5
|
-
See [DS4GO](https://dsif.eu/).
|
|
6
|
-
|
|
7
|
-
## Server settings
|
|
8
|
-
|
|
9
|
-
```yaml
|
|
10
|
-
USE_I18N: True
|
|
11
|
-
# Your application default language, will be served if no header are provided
|
|
12
|
-
LANGUAGE_CODE: fr
|
|
13
|
-
# Your application fallback language, will be served when a translation is not available
|
|
14
|
-
MODELTRANSLATION_DEFAULT_LANGUAGE: fr
|
|
15
|
-
# A list of all supported languages, you **must** make a migration afterwise
|
|
16
|
-
LANGUAGES:
|
|
17
|
-
- ['fr', 'Français']
|
|
18
|
-
- ['en', 'English']
|
|
19
|
-
- ['es', 'Español']
|
|
20
|
-
```
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = '1.0.0'
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{djangoldp_ds4go-1.0.0 → djangoldp_ds4go-1.0.2}/djangoldp_ds4go/migrations/0002_djangoldp_i18n.py
RENAMED
|
File without changes
|
|
File without changes
|
{djangoldp_ds4go-1.0.0 → djangoldp_ds4go-1.0.2}/djangoldp_ds4go/models/__base_named_model.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{djangoldp_ds4go-1.0.0 → djangoldp_ds4go-1.0.2}/djangoldp_ds4go.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|