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.
Files changed (27) hide show
  1. {djangoldp_ds4go-1.0.0 → djangoldp_ds4go-1.0.2}/PKG-INFO +1 -1
  2. djangoldp_ds4go-1.0.2/README.md +59 -0
  3. djangoldp_ds4go-1.0.2/djangoldp_ds4go/__init__.py +1 -0
  4. djangoldp_ds4go-1.0.2/djangoldp_ds4go/management/commands/__init__.py +0 -0
  5. djangoldp_ds4go-1.0.2/djangoldp_ds4go/management/commands/import_rss.py +126 -0
  6. djangoldp_ds4go-1.0.2/djangoldp_ds4go/migrations/__init__.py +0 -0
  7. {djangoldp_ds4go-1.0.0 → djangoldp_ds4go-1.0.2}/djangoldp_ds4go/models/category.py +1 -0
  8. {djangoldp_ds4go-1.0.0 → djangoldp_ds4go-1.0.2}/djangoldp_ds4go/models/fact.py +2 -1
  9. {djangoldp_ds4go-1.0.0 → djangoldp_ds4go-1.0.2}/djangoldp_ds4go.egg-info/PKG-INFO +1 -1
  10. {djangoldp_ds4go-1.0.0 → djangoldp_ds4go-1.0.2}/djangoldp_ds4go.egg-info/SOURCES.txt +3 -0
  11. djangoldp_ds4go-1.0.0/README.md +0 -20
  12. djangoldp_ds4go-1.0.0/djangoldp_ds4go/__init__.py +0 -1
  13. {djangoldp_ds4go-1.0.0 → djangoldp_ds4go-1.0.2}/djangoldp_ds4go/admin.py +0 -0
  14. {djangoldp_ds4go-1.0.0 → djangoldp_ds4go-1.0.2}/djangoldp_ds4go/apps.py +0 -0
  15. {djangoldp_ds4go-1.0.0/djangoldp_ds4go/migrations → djangoldp_ds4go-1.0.2/djangoldp_ds4go/management}/__init__.py +0 -0
  16. {djangoldp_ds4go-1.0.0 → djangoldp_ds4go-1.0.2}/djangoldp_ds4go/migrations/0001_initial.py +0 -0
  17. {djangoldp_ds4go-1.0.0 → djangoldp_ds4go-1.0.2}/djangoldp_ds4go/migrations/0002_djangoldp_i18n.py +0 -0
  18. {djangoldp_ds4go-1.0.0 → djangoldp_ds4go-1.0.2}/djangoldp_ds4go/models/__base_model.py +0 -0
  19. {djangoldp_ds4go-1.0.0 → djangoldp_ds4go-1.0.2}/djangoldp_ds4go/models/__base_named_model.py +0 -0
  20. {djangoldp_ds4go-1.0.0 → djangoldp_ds4go-1.0.2}/djangoldp_ds4go/models/__init__.py +0 -0
  21. {djangoldp_ds4go-1.0.0 → djangoldp_ds4go-1.0.2}/djangoldp_ds4go/models/media.py +0 -0
  22. {djangoldp_ds4go-1.0.0 → djangoldp_ds4go-1.0.2}/djangoldp_ds4go/translation.py +0 -0
  23. {djangoldp_ds4go-1.0.0 → djangoldp_ds4go-1.0.2}/djangoldp_ds4go.egg-info/dependency_links.txt +0 -0
  24. {djangoldp_ds4go-1.0.0 → djangoldp_ds4go-1.0.2}/djangoldp_ds4go.egg-info/requires.txt +0 -0
  25. {djangoldp_ds4go-1.0.0 → djangoldp_ds4go-1.0.2}/djangoldp_ds4go.egg-info/top_level.txt +0 -0
  26. {djangoldp_ds4go-1.0.0 → djangoldp_ds4go-1.0.2}/setup.cfg +0 -0
  27. {djangoldp_ds4go-1.0.0 → djangoldp_ds4go-1.0.2}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: djangoldp_ds4go
3
- Version: 1.0.0
3
+ Version: 1.0.2
4
4
  Summary: djangoldp package for dataspace interoperability framework
5
5
  Home-page: https://git.startinblox.com/djangoldp-packages/djangoldp-ds4go
6
6
  Author: Startin'blox
@@ -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'
@@ -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
@@ -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
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: djangoldp_ds4go
3
- Version: 1.0.0
3
+ Version: 1.0.2
4
4
  Summary: djangoldp package for dataspace interoperability framework
5
5
  Home-page: https://git.startinblox.com/djangoldp-packages/djangoldp-ds4go
6
6
  Author: Startin'blox
@@ -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
@@ -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'