Skip to content

Commit

Permalink
Merge branch 'dev' into fix-url
Browse files Browse the repository at this point in the history
  • Loading branch information
Arnaud-D authored Aug 31, 2022
2 parents ca34338 + bf30207 commit 69aa791
Show file tree
Hide file tree
Showing 27 changed files with 263 additions and 90 deletions.
24 changes: 17 additions & 7 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ env:
MARIADB_VERSION: "10.4.10"
COVERALLS_VERSION: "3.3.1" # check if Coverage needs to be also updated in requirements-ci.txt
BLACK_VERSION: "22.6.0" # needs to be also updated in requirements-dev.txt and .pre-commit-config.yaml
GECKODRIVER_VERSION: "0.31.0"

# As GitHub Action does not allow environment variables
# to be used in services definitions, these are only for
Expand All @@ -21,7 +22,7 @@ jobs:
# Lint the Python back-end with flake8.
lint-back:
name: Lint back-end
runs-on: ubuntu-18.04
runs-on: ubuntu-22.04

steps:
- name: Checkout
Expand All @@ -41,7 +42,7 @@ jobs:
# Build the documentation and upload it as an artifact.
build-doc:
name: Build Sphinx documentation
runs-on: ubuntu-18.04
runs-on: ubuntu-22.04

steps:
- name: Checkout
Expand Down Expand Up @@ -83,7 +84,7 @@ jobs:
# Build the website front-end and upload built assets as an artifact.
build-front:
name: Lint and build front-end
runs-on: ubuntu-18.04
runs-on: ubuntu-22.04

steps:
- name: Checkout
Expand Down Expand Up @@ -130,7 +131,7 @@ jobs:
test:
name: Install and test zds-site
needs: build-front
runs-on: ubuntu-18.04
runs-on: ubuntu-22.04

strategy:
matrix:
Expand Down Expand Up @@ -176,6 +177,15 @@ jobs:
mysql database: "ci_db_name"
mysql root password: "ci_root_password"

- name: Install Firefox
run: sudo apt-get update && sudo apt-get install firefox

- name: Install Geckodriver
run: |
wget https://github.com/mozilla/geckodriver/releases/download/v${{ env.GECKODRIVER_VERSION }}/geckodriver-v${{ env.GECKODRIVER_VERSION }}-linux64.tar.gz
mkdir geckodriver
tar -xzf geckodriver-v${{ env.GECKODRIVER_VERSION }}-linux64.tar.gz -C geckodriver
- name: Checkout
uses: actions/checkout@v2

Expand Down Expand Up @@ -233,7 +243,7 @@ jobs:
- name: Run tests for ${{ matrix.module }}
run: |
export PATH="$PATH:$GECKOWEBDRIVER"
export PATH="$PATH:$PWD/geckodriver"
coverage run --source='.' manage.py test -v=2 --keepdb --settings zds.settings.ci_test ${{ matrix.module }}
- name: Analyze coverage
Expand All @@ -251,7 +261,7 @@ jobs:
coverage:
name: Push coverage to Coveralls
needs: test
runs-on: ubuntu-18.04
runs-on: ubuntu-22.04

steps:
- name: Set up Python ${{ env.PYTHON_VERSION }}
Expand All @@ -271,7 +281,7 @@ jobs:
push_doc:
name: Push documentation to GitHub Pages
needs: ["build-doc", "test"]
runs-on: ubuntu-18.04
runs-on: ubuntu-22.04
if: "github.ref == 'refs/heads/dev'"

steps:
Expand Down
30 changes: 30 additions & 0 deletions fixtures/bots.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
- model: auth.user
pk: 5
fields:
first_name: anonymous
last_name: User
username: anonymous
password: pbkdf2_sha256$12000$DWHNLpO3jXIv$MrnMZblGu1Q+xemP4XK2keLtbyfkRXxczPTLhSJ0AAM=
is_superuser: False
groups:
- 2
- model: auth.user
pk: 6
fields:
first_name: external
last_name: User
username: external
password: pbkdf2_sha256$12000$DWHNLpO3jXIv$MrnMZblGu1Q+xemP4XK2keLtbyfkRXxczPTLhSJ0AAM=
is_superuser: False
groups:
- 2
- model: auth.user
pk: 9
fields:
first_name: Clem
last_name: Sanspépins
username: bot
password: pbkdf2_sha256$150000$bzWpLKZ2InfO$pmA3IQng4g+79tJ4p99GHKfEkGoztRnzDqa7Ny6jNu8=
is_superuser: False
groups:
- 2
30 changes: 0 additions & 30 deletions fixtures/users.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -206,26 +206,6 @@
username: ïtrema
password: pbkdf2_sha256$12000$FssznaRHkjFK$8GvNM2oqOIHRNNr4G+8s+cbk6LIYXaxGOsI1Hh6cswI=
is_superuser: False
- model: auth.user
pk: 5
fields:
first_name: Anonymous
last_name: User
username: anonymous
password: pbkdf2_sha256$12000$DWHNLpO3jXIv$MrnMZblGu1Q+xemP4XK2keLtbyfkRXxczPTLhSJ0AAM=
is_superuser: False
groups:
- - bot
- model: auth.user
pk: 6
fields:
first_name: External
last_name: User
username: external
password: pbkdf2_sha256$12000$DWHNLpO3jXIv$MrnMZblGu1Q+xemP4XK2keLtbyfkRXxczPTLhSJ0AAM=
is_superuser: False
groups:
- - bot
- model: auth.user
pk: 7
fields:
Expand All @@ -244,16 +224,6 @@
is_superuser: False
groups:
- - devs
- model: auth.user
pk: 9
fields:
first_name: Clem
last_name: Sanspépins
username: bot
password: pbkdf2_sha256$150000$bzWpLKZ2InfO$pmA3IQng4g+79tJ4p99GHKfEkGoztRnzDqa7Ny6jNu8=
is_superuser: False
groups:
- - bot

- model: member.Profile
pk: 1
Expand Down
2 changes: 1 addition & 1 deletion templates/tutorialv2/view/base_categories.html
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
{% endif %}

{% blocktrans %}
Découvrez tous nos publications dans {{ name }}. Vous pourrez également découvrir divers sujets tous plus intéressants les uns que les autres !
Découvrez toutes nos publications dans {{ name }}. Vous pourrez également découvrir divers sujets tous plus intéressants les uns que les autres !
{% endblocktrans %}
{% else %}
{% blocktrans %}
Expand Down
16 changes: 11 additions & 5 deletions zds/forum/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,7 @@ def get_last_answer(self):
Note the first post is not considered as an answer, therefore a topic with a single post (the 1st one) will
return `None`.
:return: the last answer in the thread, if any.
:rtype: Post
"""
last_post = self.get_last_post()

Expand Down Expand Up @@ -361,13 +362,16 @@ def resolve_last_post_pk_and_pos_read_by_user(self, user):
Post.objects.filter(topic__pk=self.pk).order_by("position").values("pk", "position").first().values()
)

def first_unread_post(self, user=None):
def first_unread_post(self, user: User = None):
"""
Returns the first post of this topics the current user has never read, or the first post if it has never read \
this topic.\
Used in notification menu.
:return: The first unread post for this topic and this user.
:param user: The user who potentially has read a post. If ``None`` will get request user
:return: The first unread post for this topic and this user. If the topic was read, gets ``last_post`` or None \
if no posts was found after OP.
"""
try:
if user is None:
Expand All @@ -376,10 +380,12 @@ def first_unread_post(self, user=None):
last_post = TopicRead.objects.filter(topic__pk=self.pk, user__pk=user.pk).latest("post__position").post

next_post = (
Post.objects.filter(topic__pk=self.pk, position__gt=last_post.position).select_related("author").first()
)
Post.objects.filter(topic__pk=self.pk, position__gt=last_post.position).order_by("position").first()
) or self.get_last_answer()
# if read was the last message, there is no next so default to last message
return next_post
except (TopicRead.DoesNotExist, Post.DoesNotExist):
except TopicRead.DoesNotExist:
# if no read : the whole topic is not read so get first message
return self.first_post()

def antispam(self, user=None):
Expand Down
41 changes: 41 additions & 0 deletions zds/forum/tests/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -1211,6 +1211,47 @@ def test_is_read(self):
self.assertFalse(topic.is_read_by_user(reader.user, check_auth=False))


class TopicReadAndUnreadTests(TestCase):
def setUp(self):
self.author = ProfileFactory().user
self.reader = ProfileFactory().user
self.topic = TopicFactory(
author=self.author, forum=ForumFactory(category=ForumCategoryFactory(), position_in_category=1)
)

def test_first_unread_on_non_read_op(self):
post = PostFactory(topic=self.topic, author=self.author, position=1)
topic = Topic.objects.get(pk=self.topic.pk)
self.assertEqual(post, topic.first_unread_post(self.reader))

def test_first_unread_on_read_op(self):
post = PostFactory(topic=self.topic, author=self.author, position=1)
TopicRead(topic=self.topic, post=post, user=self.reader).save()
topic = Topic.objects.get(pk=self.topic.pk)
self.assertEqual(None, topic.first_unread_post(self.reader))

def test_first_unread_on_read_other_message(self):
op = PostFactory(topic=self.topic, author=self.author, position=1)
TopicRead(topic=self.topic, post=op, user=self.reader).save()
post = PostFactory(topic=self.topic, author=ProfileFactory().user, position=2)
topic = Topic.objects.get(pk=self.topic.pk)
self.assertEqual(post, topic.first_unread_post(self.reader))

def test_first_unread_on_not_read_other_message(self):
op = PostFactory(topic=self.topic, author=self.author, position=1)
PostFactory(topic=self.topic, author=ProfileFactory().user, position=2)
topic = Topic.objects.get(pk=self.topic.pk)
self.assertEqual(op, topic.first_unread_post(self.reader))

def test_two_messages_read(self):
op = PostFactory(topic=self.topic, author=self.author, position=1)
TopicRead(topic=self.topic, post=op, user=self.reader).save()
post = PostFactory(topic=self.topic, author=ProfileFactory().user, position=2)
PostFactory(topic=self.topic, author=ProfileFactory().user, position=3)
topic = Topic.objects.get(pk=self.topic.pk)
self.assertEqual(post, topic.first_unread_post(self.reader))


class TestMixins(TestCase):
def test_double_unread_is_handled(self):
author = ProfileFactory().user
Expand Down
3 changes: 2 additions & 1 deletion zds/member/commons.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from django.utils.translation import gettext_lazy as _

from zds.member.models import Profile, TokenRegister, Ban
from zds.member.utils import get_bot_account
from zds.utils.models import get_hat_from_settings
from zds.mp.utils import send_mp

Expand Down Expand Up @@ -205,7 +206,7 @@ def notify_member(self, ban, msg):
:return: nothing
:rtype: None
"""
bot = get_object_or_404(User, username=settings.ZDS_APP["member"]["bot_account"])
bot = get_bot_account()
send_mp(
bot,
[ban.user],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from django.contrib.auth.models import User

from zds.member.models import BannedEmailProvider
from zds.member.utils import get_bot_account


def forwards_func(apps, schema_editor):
Expand Down Expand Up @@ -818,7 +819,7 @@ def forwards_func(apps, schema_editor):
]

try:
bot = User.objects.get(username=settings.ZDS_APP["member"]["bot_account"])
bot = get_bot_account()
bans = [BannedEmailProvider(provider=p, moderator=bot) for p in providers]
BannedEmailProvider.objects.bulk_create(bans)
except User.DoesNotExist:
Expand Down
26 changes: 26 additions & 0 deletions zds/member/utils.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from django.conf import settings
from django.contrib.auth.models import User
from social_django.middleware import SocialAuthExceptionMiddleware
from django.contrib import messages
from django.utils.translation import gettext_lazy as _
Expand All @@ -23,3 +25,27 @@ def get_message(self, request, exception):

def get_redirect_uri(self, *_, **__):
return reverse("member-login")


def get_bot_account() -> User:
"""
Get the bot account.
Used for example to send automated private messages.
"""
return User.objects.get(username=settings.ZDS_APP["member"]["bot_account"])


def get_external_account() -> User:
"""
Get the external account.
Used for example to mark publications by authors not registered on the site.
"""
return User.objects.get(username=settings.ZDS_APP["member"]["external_account"])


def get_anonymous_account() -> User:
"""
Get the anonymous account.
Used for example as a replacement for unregistered users.
"""
return User.objects.get(username=settings.ZDS_APP["member"]["anonymous_account"])
3 changes: 2 additions & 1 deletion zds/member/views/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

from zds.member.forms import PromoteMemberForm
from zds.member.models import Profile
from zds.member.utils import get_bot_account
from zds.utils.models import get_hat_from_settings
from zds.mp.utils import send_mp

Expand Down Expand Up @@ -62,7 +63,7 @@ def settings_promote(request, user_pk):
user.save()

usergroups = user.groups.all()
bot = get_object_or_404(User, username=settings.ZDS_APP["member"]["bot_account"])
bot = get_bot_account()
msg = _(
"Bonjour {0},\n\n" "Un administrateur vient de modifier les groupes " "auxquels vous appartenez. \n"
).format(user.username)
Expand Down
3 changes: 2 additions & 1 deletion zds/member/views/profile.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
Ban,
NewEmailProvider,
)
from zds.member.utils import get_bot_account
from zds.notification.models import TopicAnswerSubscription, NewPublicationSubscription
from zds.tutorialv2.models import CONTENT_TYPES
from zds.tutorialv2.models.database import PublishedContent, ContentContribution, ContentReaction
Expand Down Expand Up @@ -417,7 +418,7 @@ def update_profile(self, profile, form):
previous_email = form.cleaned_data.get("previous_email")
if new_username and new_username != previous_username:
# Add a karma message for the staff
bot = get_object_or_404(User, username=settings.ZDS_APP["member"]["bot_account"])
bot = get_bot_account()
KarmaNote(
user=profile.user,
moderator=bot,
Expand Down
7 changes: 4 additions & 3 deletions zds/member/views/register.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
BannedEmailProvider,
NewEmailProvider,
)
from zds.member.utils import get_bot_account, get_anonymous_account, get_external_account
from zds.member.views import get_client_ip
from zds.mp.models import PrivatePost, PrivateTopic
from zds.tutorialv2.models.database import PickListOperation
Expand Down Expand Up @@ -180,8 +181,8 @@ def unregister(request):
request, "member/settings/unregister.html", {"user": request.user, "unregister_form": unregister_form}
)

anonymous = get_object_or_404(User, username=settings.ZDS_APP["member"]["anonymous_account"])
external = get_object_or_404(User, username=settings.ZDS_APP["member"]["external_account"])
anonymous = get_anonymous_account()
external = get_external_account()
current = request.user
# Nota : as of v21 all about content paternity is held by a proper receiver in zds.tutorialv2.models.database
PickListOperation.objects.filter(staff_user=current).update(staff_user=anonymous)
Expand Down Expand Up @@ -276,7 +277,7 @@ def activate_account(request):
usr.save()

# Send welcome message
bot = get_object_or_404(User, username=settings.ZDS_APP["member"]["bot_account"])
bot = get_bot_account()
msg = render_to_string(
"member/messages/account_activated.md",
{
Expand Down
Loading

0 comments on commit 69aa791

Please sign in to comment.