forked from 42CTF/website
Compare commits
213 Commits
dynamic-sc
...
main
Author | SHA1 | Date |
---|---|---|
Danhia | f1b1214291 | |
Danhia | 8b28f73bdb | |
Danhia | c8adc6caf9 | |
Danhia | 6ecb94eab5 | |
Danhia | 44897411f5 | |
Danhia | 5a10e033a2 | |
Danhia | 3d86f21ba2 | |
Starthur | 691c53e110 | |
Starthur | 2d4816e78f | |
Danhia | 5d84174db2 | |
Danhia | 9ad64e72bc | |
Danhia | 9d0a420cac | |
Starthur | 7120a80c1d | |
Starthur | fe71460537 | |
Danhia | 32bbc392d6 | |
UncleReaton | acf306097a | |
UncleReaton | dc955fc189 | |
UncleReaton | e304f7cd15 | |
Danhia | 73cf94515d | |
Danhia | 94237bd9b6 | |
Starthur | a983aafba2 | |
Starthur | cce09ed254 | |
Danhia | c2e58c4f92 | |
Danhia | eba672d067 | |
Danhia | 1a6c31f5e8 | |
Danhia | bd17ad5f8f | |
Danhia | 40984a2a0c | |
Danhia | 9ac003ea3c | |
Danhia | 5cf86b9c36 | |
zero | 7c06c24d9f | |
zero | 9b2da1e2cc | |
zero | 891c2530e6 | |
Danhia | 13895d7712 | |
Danhia | 0f64c7579c | |
zero | 02331beff4 | |
zero | 5b2abeac20 | |
Danhia | 1771f3c2bb | |
Danhia | 09118cac7a | |
Danhia | 7cd43ca35f | |
Danhia | d21915405e | |
zero | dd7a69aa50 | |
Danhia | 8a2cc6f3ae | |
Danhia | e36ca2b146 | |
Danhia | 63876e91ef | |
Danhia | eadede339b | |
zero | d1992e1476 | |
Danhia | 00acec6fdb | |
Danhia | 1ee02fc964 | |
Starthur | ff23250275 | |
Starthur | c449f26ad7 | |
Danhia | 42858e4342 | |
Danhia | ec61f06be0 | |
Danhia | 2233474c89 | |
Danhia | 7b9dfad15d | |
Starthur | 46ea80161d | |
Starthur | d222784bb0 | |
Starthur | 86fbf93dbf | |
Arthur-TRT | ff657c070a | |
Starthur | a1ec3e5f20 | |
Starthur | 0d7f39d335 | |
Danhia | f56322bd6e | |
Danhia | 506eb54d49 | |
Starthur | 87efa03ed0 | |
Starthur | 5435ea3316 | |
Starthur | 4245cfd19f | |
Starthur | f391a5a5cb | |
Starthur | ebdc3b9c9e | |
Starthur | 9d3b9ebf5f | |
Starthur | 04318e3b0a | |
Starthur | eeb752d605 | |
Starthur | 2d466454f5 | |
Starthur | 7ff972e623 | |
Starthur | d8791353fb | |
Starthur | dc3e7f4b27 | |
Starthur | 763853b3c6 | |
Starthur | c1c82ff9e0 | |
Starthur | fdc3796667 | |
Starthur | b25bf03485 | |
Starthur | 5a08764df7 | |
UncleReaton | 084fb1a62d | |
Starthur | d8c35db454 | |
UncleReaton | 6e860b2997 | |
Starthur | 4ee613d9af | |
Starthur | 9c75b317eb | |
Starthur | 2d2e97e794 | |
Arthur-TRT | 66ab43bf2b | |
Starthur | 4213883774 | |
Arthur-TRT | 9cb4b2b3a8 | |
Starthur | b90cc55b8d | |
UncleReaton | d19514f629 | |
Aslan | 6b2b0cef7d | |
Aslan | d7bf9ae74e | |
Danhia | dfa36b58a6 | |
Starthur | bf5678d371 | |
Danhia | 3c013794d7 | |
Danhia | 6110408cd0 | |
Starthur | bb2617a3e4 | |
Starthur | e23d6d7f49 | |
Starthur | 978dd24a00 | |
Danhia | 15f3a21c60 | |
Starthur | e480aec493 | |
Starthur | 3991dda7d3 | |
Starthur | e8575d559e | |
Starthur | ea691204c4 | |
Arthur TROUILLET | 21f38906df | |
Arthur TROUILLET | 39e3859836 | |
Arthur-TRT | a26784cd98 | |
Yir | ba7992e7be | |
Danhia | 7dad96d79f | |
Danhia | d554961dd1 | |
Danhia | 280ba0d1fc | |
Bertrand C | bdd51b6cf9 | |
Bertrand C | c004c18e75 | |
Danhia | e8d43586a6 | |
Danhia | 2da57b7b9b | |
Danhia | a828ce2ece | |
UncleReaton | 16030c14a4 | |
Aslan | ca86079148 | |
Aslan | 93c9844efa | |
Aslan | 4c06ed41bf | |
Aslan | fca3609c1b | |
Aslan | b0380d4fc3 | |
Aslan | 3ea2a41d2b | |
Aslan | de87c70ae0 | |
Aslan | 22fe0d601a | |
Danhia | 5191e300df | |
Danhia | 09377c509f | |
Danhia | 6a76f4b99f | |
ysaito | 5908ce4778 | |
Danhia | 4e5fe52984 | |
Danhia | 2f24fae611 | |
Danhia | 02385dcd08 | |
ysaito | 7b2de06225 | |
ysaito | ba1cb03dbf | |
Danhia | 11164bb84a | |
Danhia | 67a4d180e0 | |
Danhia | 3b86441259 | |
Danhia | 7b2552f0b5 | |
Danhia | eac835bef5 | |
Danhia | 06593b26f9 | |
Danhia | e8f5f33269 | |
Danhia | f0479f6577 | |
Danhia | 60a59b23e6 | |
Danhia | 8f32ef9a6e | |
Danhia | a0b76903a7 | |
Danhia | a7de7b8054 | |
Danhia | 0d734e98b1 | |
Danhia | 3d24fe9b3b | |
Danhia | ba0d75c250 | |
Danhia | 3ae80ca17f | |
Danhia | a7e75b2a43 | |
Danhia | 9ea67ae2a0 | |
Danhia | 899a01e472 | |
Danhia | c40d49c326 | |
Starthur | d6b1380552 | |
Arthur-TRT | d0c93f98a1 | |
Arthur-TRT | 97e120e5fc | |
Danhia | 494377399c | |
Starthur | 28d8874272 | |
Starthur | b9704d3cb3 | |
Danhia | 0ac395def8 | |
Danhia | 7ff556a986 | |
Danhia | 5e02041f0c | |
Danhia | f75a034094 | |
Danhia | 5f28bc5d2c | |
ysaito | 904ce1b748 | |
ysaito | 5b15b9cd6f | |
ysaito | 5d46bd6df0 | |
ysaito | 67de669459 | |
ysaito | 26aeb6d7bd | |
Danhia | 1b89fa88d8 | |
Danhia | 0bb3a8b805 | |
Danhia | 5eec76dd00 | |
Clément Hamada | 6b6f264fe0 | |
Clément Hamada | c4fd6d05c3 | |
Danhia | 901c73a4f2 | |
Danhia | 01c0f28b16 | |
Danhia | 7174cf9edb | |
Danhia | ef0fcc5fea | |
Danhia | aabba3ea53 | |
Miliviu | 1abeabebfe | |
Danhia | 9f2d78ac33 | |
Danhia | 27ed107501 | |
Miliviu | 0dea7fb619 | |
Danhia | 23529b3b07 | |
Danhia | cb9bc7cc56 | |
Danhia | af4912837f | |
Miliviu | 187579e61c | |
Miliviu | fabe417fe2 | |
Miliviu | a6a5e424df | |
Danhia | bcf0c51ba5 | |
Danhia | 241a3f2bc1 | |
Danhia | cb46708e5c | |
Danhia | 3c166f3834 | |
Danhia | 92a1dca27c | |
Danhia | 96121e401e | |
ix | 97f6b99133 | |
Danhia | c45cfed8d4 | |
ix | 5dc04f888b | |
Danhia | 993e1fa998 | |
Danhia | 9d33985fa4 | |
Clément Hamada | 0cd862734e | |
Clément Hamada | aed129b4b9 | |
Clément Hamada | d1ab64885e | |
Clément Hamada | b2cf802ab5 | |
Clément Hamada | 266e018d83 | |
Danhia | 8fd25d8fa6 | |
ix | 53fe69aa09 | |
Danhia | aadb2ac858 | |
ix | 34b8829797 | |
ix | 619ddf3d07 | |
ix | 5d00c5733f | |
ix | 248cdc54d5 |
|
@ -0,0 +1,3 @@
|
||||||
|
[submodule "src/ctfs/templates/challenges"]
|
||||||
|
path = src/ctfs/templates/challenges
|
||||||
|
url = https://gitea.42ctf.org/42CTF/challenges-descriptions.git
|
74
README.md
74
README.md
|
@ -1,50 +1,34 @@
|
||||||
# 42ctf
|
# 42CTF
|
||||||
CTF by 42 students
|
|
||||||
|
[42CTF](https://www.42ctf.org) is a CTF platform created by School 42 students and open to anyone.
|
||||||
|
|
||||||
|
|
||||||
### Todo
|
### Todo
|
||||||
|
|
||||||
- [x] Serveur SMTP & reset password
|
TODO has been migrated to [issues](https://gitea.42ctf.org/42CTF/website/issues) !
|
||||||
- [x] Clean le repo
|
And hopefully, it is not redirected anymore to `/dev/null`.
|
||||||
- [x] Accès au chall après validation
|
|
||||||
- [x] Section "Intro"
|
|
||||||
- [x] Section Treasure Hunt
|
|
||||||
- [x] Edition de profil
|
|
||||||
- [x] Ajouter de la Doc
|
|
||||||
- [x] Infrastructure de pwn
|
|
||||||
- [x] Organiser une session découverte
|
|
||||||
- [x] Compteur de flags
|
|
||||||
- [x] Graphiques statistiques
|
|
||||||
- [x] Création d'un discord linkable
|
|
||||||
- [ ] Refonte du linkage discord -> 42ctf
|
|
||||||
- [x] Traduction du site
|
|
||||||
- [x] Anglais
|
|
||||||
- [x] Français
|
|
||||||
- [ ] Russe
|
|
||||||
- [ ] Espagnol
|
|
||||||
- [ ] Italien
|
|
||||||
- [ ] OAuth 42
|
|
||||||
- [ ] Feature proposer une solution à un challenge
|
|
||||||
- [ ] Système de badge/succès
|
|
||||||
- [ ] Génération d'une page résumant le profil d'un utilisateur (ex: show resume sur intra.42.fr)
|
|
||||||
|
|
||||||
#### Event feature
|
### How to contribute ?
|
||||||
|
|
||||||
- [X] make relation between user and events
|
First, you need to contact a 42CTF admin to get an account on the 42CTF gitea.
|
||||||
- [X] make scoreboard for events
|
You can contact us on [discord](https://discord.gg/3KDvt6hbWW) or by [email](mailto:42ctf@protonmail.com).
|
||||||
- [X] make access mod for events :
|
You can also fill this [form](https://forms.42l.fr/apps/forms/bpmyGR37AR4yHGnC) and we'll contact you.
|
||||||
- [X] Sub button for public events
|
Then, once you have a gitea account, you can fork this repository, do some stuff, and open a pull request.
|
||||||
- [X] Access by password
|
|
||||||
- [X] Begin date for display challenges
|
If you want to translate the platform, then have a look at the [wiki](https://gitea.42ctf.org/42CTF/website/wiki).
|
||||||
- [X] Ending date for stop flag submission
|
|
||||||
- [ ] Access by invite link
|
If you want to help with bot development, it has now its own [repository](https://gitea.42ctf.org/42CTF/bot)
|
||||||
- [X] Admin rights
|
|
||||||
- [X] Admin can access to events pages without password
|
### How to set up my dev environment ?
|
||||||
- [X] Admin can subscribe to event without password
|
|
||||||
- [X] process flag submission
|
There is only one file missing on this repository for you to run the server: `local_settings.py`.
|
||||||
- [X] increment user score in Scores model
|
You should create one in the `src` directory, with the following content:
|
||||||
- [X] add filters for admin dashboard
|
```
|
||||||
- [X] add search in fields in admin dashboard
|
DEBUG = True
|
||||||
- [X] display more information in admin dashboard
|
SECRET_KEY = 'what you want'
|
||||||
- [X] Smooth display of events listing
|
```
|
||||||
- [X] Event info page with background and noice display
|
|
||||||
- [ ] Create teams for events
|
When you'll run `python manage.py migrate` then `python manage.py runserver`, an empty database will be automatically created.
|
||||||
|
The `local_settings.py` is in the `.gitignore` and should stay that way, so we don't accidentally overwrite the production file when we deploy.
|
||||||
|
|
||||||
|
To obtain administrator rights you can run `python manage.py createsuperuser`.
|
104
bot.py
104
bot.py
|
@ -1,104 +0,0 @@
|
||||||
import os
|
|
||||||
import discord
|
|
||||||
import discord.utils
|
|
||||||
import urllib.request, json
|
|
||||||
import asyncio
|
|
||||||
import json
|
|
||||||
import logging
|
|
||||||
|
|
||||||
TOKEN = os.getenv('DISCORD_TOKEN')
|
|
||||||
GUILD = '42ctf'
|
|
||||||
|
|
||||||
intents = discord.Intents.all()
|
|
||||||
client = discord.Client(intents=intents)
|
|
||||||
|
|
||||||
db_file = open('members.json', 'r')
|
|
||||||
users = json.load(db_file)
|
|
||||||
db_file.close()
|
|
||||||
|
|
||||||
logging.basicConfig(filename='bot.log', format='%(asctime)s %(message)s', level=logging.INFO)
|
|
||||||
|
|
||||||
guild = ''
|
|
||||||
roles = {}
|
|
||||||
|
|
||||||
def get_rank(token):
|
|
||||||
url = urllib.request.urlopen("https://www.42ctf.org/accounts/rank/" + token)
|
|
||||||
data = json.loads(url.read().decode())
|
|
||||||
rank = data['rank']
|
|
||||||
return rank
|
|
||||||
|
|
||||||
async def watch_roles():
|
|
||||||
global users
|
|
||||||
await client.wait_until_ready() # ensures cache is loaded
|
|
||||||
while not client.is_closed():
|
|
||||||
for member_id, token in users.items():
|
|
||||||
if (token == "0000"):
|
|
||||||
continue
|
|
||||||
member = discord.utils.get(guild.members, id=int(member_id))
|
|
||||||
rank = get_rank(token)
|
|
||||||
if rank == 1 and roles['top1'] not in member.roles:
|
|
||||||
await member.add_roles(roles['top1'])
|
|
||||||
await member.remove_roles(roles['top10'])
|
|
||||||
await member.remove_roles(roles['top50'])
|
|
||||||
elif rank > 1 and rank <= 10 and roles['top10'] not in member.roles:
|
|
||||||
await member.add_roles(roles['top10'])
|
|
||||||
await member.remove_roles(roles['top1'])
|
|
||||||
await member.remove_roles(roles['top50'])
|
|
||||||
elif rank > 10 and rank <= 50 and roles['top50'] not in member.roles:
|
|
||||||
await member.add_roles(roles['top50'])
|
|
||||||
await member.remove_roles(roles['top10'])
|
|
||||||
await member.remove_roles(roles['top1'])
|
|
||||||
elif rank > 50:
|
|
||||||
await member.remove_roles(roles['top1'])
|
|
||||||
await member.remove_roles(roles['top10'])
|
|
||||||
await member.remove_roles(roles['top50'])
|
|
||||||
await asyncio.sleep(60)
|
|
||||||
|
|
||||||
@client.event
|
|
||||||
async def on_ready():
|
|
||||||
global guild, roles
|
|
||||||
guild = discord.utils.get(client.guilds, name=GUILD)
|
|
||||||
roles['top10'] = discord.utils.get(guild.roles, id=801787467064672286)
|
|
||||||
roles['top1'] = discord.utils.get(guild.roles, id=798638767359524875)
|
|
||||||
roles['top50'] = discord.utils.get(guild.roles, id=803729539145924649)
|
|
||||||
|
|
||||||
logging.info('%s is connected to the following guild: %s(id: %d)', client.user, guild.name, guild.id)
|
|
||||||
client.loop.create_task(watch_roles())
|
|
||||||
|
|
||||||
@client.event
|
|
||||||
async def on_message(message):
|
|
||||||
global guild, roles
|
|
||||||
|
|
||||||
if message.author == client.user:
|
|
||||||
return
|
|
||||||
|
|
||||||
if '!connect' in message.content:
|
|
||||||
try:
|
|
||||||
user_token = message.content.split(' ')[1]
|
|
||||||
member = discord.utils.get(guild.members, name=message.author.name)
|
|
||||||
rank = get_rank(user_token)
|
|
||||||
users[str(member.id)] = user_token
|
|
||||||
logging.info("MESSAGE: from %s with token %s", message.author.name, user_token)
|
|
||||||
with open('members.json', 'w') as json_file:
|
|
||||||
json.dump(users, json_file)
|
|
||||||
if rank == 1:
|
|
||||||
await member.add_roles(roles['top1'])
|
|
||||||
response = "Congratulations, you're now Top 1. But for how long ?"
|
|
||||||
|
|
||||||
elif (rank <= 10):
|
|
||||||
await member.add_roles(roles['top10'])
|
|
||||||
response = "You've been granted the Top 10 role. Now, go away and flag !"
|
|
||||||
|
|
||||||
elif rank <= 50:
|
|
||||||
await member.add_roles(roles['top50'])
|
|
||||||
response = "You've been granted the Top 50 role. Now, go away and flag !"
|
|
||||||
|
|
||||||
else:
|
|
||||||
response = "No role for you now, but I'll keep watching you."
|
|
||||||
except IndexError:
|
|
||||||
response = 'usage: !connect 42ctf_token'
|
|
||||||
await message.author.create_dm()
|
|
||||||
await message.author.dm_channel.send(response)
|
|
||||||
|
|
||||||
|
|
||||||
client.run(TOKEN)
|
|
|
@ -1,3 +1,3 @@
|
||||||
Django
|
Django==3.2.11
|
||||||
requests
|
requests==2.27.1
|
||||||
authlib
|
authlib==0.15.5
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
from .models import UserProfileInfo
|
from .models import UserProfileInfo
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
|
from .models import Campus
|
||||||
|
|
||||||
#admin.site.register(UserProfileInfo)
|
#admin.site.register(UserProfileInfo)
|
||||||
# Register your models here.
|
# Register your models here.
|
||||||
|
@ -7,6 +8,10 @@ from django.contrib import admin
|
||||||
@admin.register(UserProfileInfo)
|
@admin.register(UserProfileInfo)
|
||||||
class userprofile(admin.ModelAdmin):
|
class userprofile(admin.ModelAdmin):
|
||||||
#list display
|
#list display
|
||||||
list_display = ['user', 'score', 'last_submission_date']
|
list_display = ['user', 'score', 'last_submission_date', 'campus']
|
||||||
# search list
|
# search list
|
||||||
search_fields = ['score', 'user__username']
|
search_fields = ['score', 'user__username', 'campus__name']
|
||||||
|
|
||||||
|
@admin.register(Campus)
|
||||||
|
class campus(admin.ModelAdmin):
|
||||||
|
list_display = ['name']
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
from collections import defaultdict
|
||||||
|
from django.core.management.base import BaseCommand, CommandError
|
||||||
|
from accounts import models as acc_models
|
||||||
|
from django.contrib.auth import models as auth_models
|
||||||
|
from django.contrib.auth.models import timezone
|
||||||
|
from datetime import timedelta
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
help = 'Remove all users who never logged in'
|
||||||
|
|
||||||
|
def handle(self, *args, **options):
|
||||||
|
all_users = acc_models.UserProfileInfo.objects.filter(score=0).select_related()
|
||||||
|
to_remove = []
|
||||||
|
for elem in all_users:
|
||||||
|
user = elem.user
|
||||||
|
if user.last_login is None and user.date_joined < timezone.now() - timedelta(hours=72):
|
||||||
|
to_remove.append(user)
|
||||||
|
print("You are going to remove {} users.".format(len(to_remove)))
|
||||||
|
answer = input("Continue ? [y/N] ")
|
||||||
|
|
||||||
|
if answer.lower() in ["y","yes"]:
|
||||||
|
for elem in to_remove:
|
||||||
|
elem.delete()
|
||||||
|
print("Users have been successfully pruned.")
|
|
@ -0,0 +1,23 @@
|
||||||
|
# Generated by Django 3.2.11 on 2022-03-29 08:34
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('accounts', '0007_auto_20220123_1704'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='userprofileinfo',
|
||||||
|
name='intra42_campus',
|
||||||
|
field=models.CharField(blank=True, max_length=50, null=True),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='userprofileinfo',
|
||||||
|
name='intra42_id',
|
||||||
|
field=models.CharField(blank=True, max_length=20, null=True, unique=True),
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,22 @@
|
||||||
|
# Generated by Django 3.2.11 on 2022-03-29 11:39
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('accounts', '0008_auto_20220329_1034'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterModelOptions(
|
||||||
|
name='userprofileinfo',
|
||||||
|
options={'ordering': ['-score', 'last_submission_date', 'user__username', 'intra42_campus'], 'permissions': (('view_info', 'View user info'),), 'verbose_name': 'profile', 'verbose_name_plural': 'profiles'},
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='userprofileinfo',
|
||||||
|
name='intra42_campus_id',
|
||||||
|
field=models.CharField(blank=True, max_length=10, null=True),
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,31 @@
|
||||||
|
# Generated by Django 3.2.11 on 2022-05-17 12:52
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('accounts', '0009_auto_20220329_1339'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Campus',
|
||||||
|
fields=[
|
||||||
|
('id', models.IntegerField(primary_key=True, serialize=False, unique=True)),
|
||||||
|
('name', models.CharField(max_length=50)),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'campus',
|
||||||
|
'verbose_name_plural': 'campuses',
|
||||||
|
'permissions': (('view_info', 'View user info'),),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='userprofileinfo',
|
||||||
|
name='campus',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='accounts.campus'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,23 @@
|
||||||
|
# Generated by Django 3.2.11 on 2022-05-17 12:54
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
from accounts.models import UserProfileInfo
|
||||||
|
from accounts.models import Campus
|
||||||
|
|
||||||
|
def migrate_campus(apps, schema_editor):
|
||||||
|
UserProfileInfo = apps.get_model('accounts', 'UserProfileInfo')
|
||||||
|
Campus = apps.get_model('accounts', 'Campus')
|
||||||
|
for user in UserProfileInfo.objects.all():
|
||||||
|
if user.intra42_campus_id:
|
||||||
|
user.campus, created = Campus.objects.get_or_create(id=user.intra42_campus_id, name=user.intra42_campus)
|
||||||
|
user.save()
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('accounts', '0010_auto_20220517_1452'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RunPython(migrate_campus),
|
||||||
|
]
|
|
@ -0,0 +1,25 @@
|
||||||
|
# Generated by Django 3.2.11 on 2022-08-01 20:12
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('accounts', '0011_migration_campus'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterModelOptions(
|
||||||
|
name='userprofileinfo',
|
||||||
|
options={'ordering': ['-score', 'last_submission_date', 'user__username', 'campus'], 'permissions': (('view_info', 'View user info'),), 'verbose_name': 'profile', 'verbose_name_plural': 'profiles'},
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='userprofileinfo',
|
||||||
|
name='intra42_campus',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='userprofileinfo',
|
||||||
|
name='intra42_campus_id',
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,25 @@
|
||||||
|
# Generated by Django 3.2.11 on 2022-08-18 15:41
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('accounts', '0012_auto_20220801_2212'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='campus',
|
||||||
|
name='logo',
|
||||||
|
field=models.URLField(default='https://42.fr'),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='campus',
|
||||||
|
name='url',
|
||||||
|
field=models.URLField(default='https://42.fr', max_length=100),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,23 @@
|
||||||
|
# Generated by Django 3.2.11 on 2022-08-18 15:44
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('accounts', '0013_auto_20220818_1741'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='campus',
|
||||||
|
name='logo',
|
||||||
|
field=models.URLField(blank=True),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='campus',
|
||||||
|
name='url',
|
||||||
|
field=models.URLField(blank=True, max_length=100),
|
||||||
|
),
|
||||||
|
]
|
|
@ -12,15 +12,29 @@ class UserProfileInfo(models.Model):
|
||||||
last_submission_date = models.DateTimeField('Last Submission Date', default=timezone.now)
|
last_submission_date = models.DateTimeField('Last Submission Date', default=timezone.now)
|
||||||
token = models.CharField(max_length=200, blank=True)
|
token = models.CharField(max_length=200, blank=True)
|
||||||
discord_id = models.CharField(max_length=20, null=True, blank=True, unique=True)
|
discord_id = models.CharField(max_length=20, null=True, blank=True, unique=True)
|
||||||
|
intra42_id = models.CharField(max_length=20, null=True, blank=True, unique=True)
|
||||||
|
campus = models.ForeignKey('Campus', on_delete=models.DO_NOTHING, null=True, blank=True)
|
||||||
member = models.BooleanField(default=False)
|
member = models.BooleanField(default=False)
|
||||||
member_since = models.DateTimeField('Member since', default=timezone.now)
|
member_since = models.DateTimeField('Member since', default=timezone.now)
|
||||||
member_until = models.DateTimeField('Member until', default=timezone.now)
|
member_until = models.DateTimeField('Member until', default=timezone.now)
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.user.username
|
return self.user.username
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ['-score', 'last_submission_date', 'user__username']
|
ordering = ['-score', 'last_submission_date', 'user__username', 'campus']
|
||||||
verbose_name = 'profile'
|
verbose_name = 'profile'
|
||||||
verbose_name_plural = 'profiles'
|
verbose_name_plural = 'profiles'
|
||||||
permissions = (("view_info", "View user info"),)
|
permissions = (("view_info", "View user info"),)
|
||||||
|
|
||||||
|
class Campus(models.Model):
|
||||||
|
id = models.IntegerField(primary_key=True, unique=True)
|
||||||
|
name = models.CharField(max_length=50)
|
||||||
|
url = models.URLField(max_length=100,blank=True)
|
||||||
|
logo = models.URLField(max_length=200,blank=True)
|
||||||
|
def __str__(self):
|
||||||
|
return self.name
|
||||||
|
class Meta:
|
||||||
|
verbose_name = 'campus'
|
||||||
|
verbose_name_plural = 'campuses'
|
||||||
|
permissions = (("view_info", "View user info"),)
|
||||||
|
|
||||||
# Create your models here.
|
# Create your models here.
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
{% trans "Deleted accounts cannot be recovered." %}<br><br>
|
{% trans "Deleted accounts cannot be recovered." %}<br><br>
|
||||||
<div class="col-sm-8 col-md-6 mx-auto">
|
<div class="col-sm-8 col-md-6 mx-auto">
|
||||||
{% if bad_password %}
|
{% if bad_password %}
|
||||||
<span class="message error-msg">{% trans "Password inccorect." %}</span>
|
<span class="message error-msg">{% trans "Password incorrect." %}</span>
|
||||||
{% elif deleted %}
|
{% elif deleted %}
|
||||||
<span class="message success-msg">{% trans "Your account has been deleted." %}</span>
|
<span class="message success-msg">{% trans "Your account has been deleted." %}</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
@ -2,67 +2,111 @@
|
||||||
{% block content %}
|
{% block content %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-12 col-md-9">
|
<div class="col-sm-12 col-md-9">
|
||||||
<div class="ctf-block">
|
<div class="ctf-block">
|
||||||
<div class="ctf-head">
|
<div class="ctf-head">
|
||||||
<h3>Edit info</h3>
|
<h3>Edit info</h3>
|
||||||
</div>
|
</div>
|
||||||
<div class="bloc-body">
|
<div class="bloc-body">
|
||||||
<div class="col-sm-12 col-md-12 mx-auto">
|
<div class="col-sm-12 col-md-12 mx-auto">
|
||||||
{{ u_form.non_field_errors }}
|
{{ u_form.non_field_errors }}
|
||||||
{% if error is not None %}
|
{% if error is not None %}
|
||||||
<span class="message error-msg">{{ error }}</span>
|
<span class="message error-msg">{{ error }}</span>
|
||||||
{% elif success is not None %}
|
{% elif success is not None %}
|
||||||
<span class="message success-msg">{{ success }}</span>
|
<span class="message success-msg">{{ success }}</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<form method='POST'>
|
<form method='POST'>
|
||||||
<div class="edit-infos-grp">
|
<div class="edit-infos-grp">
|
||||||
|
{%csrf_token%}
|
||||||
|
<label for="{{ u_form.username.id_for_label }}">{% trans "Username" %} *</label>
|
||||||
|
{{ u_form.username.errors}}
|
||||||
|
{{u_form.username}}
|
||||||
|
</br>
|
||||||
|
<label for="{{ u_form.email.id_for_label }}">{% trans "Email" %} *</label>
|
||||||
|
{{ u_form.email.errors}}
|
||||||
|
{{u_form.email}}
|
||||||
|
</br>
|
||||||
|
</br>
|
||||||
|
<label for="{{ p_form.portfolio_site.id_for_label }}">{% trans "Website" %}</label>
|
||||||
|
{{p_form.portfolio_site}}
|
||||||
|
</br>
|
||||||
|
</br>Token
|
||||||
|
<input type='text' readonly value='{{token}}'>
|
||||||
|
</br>
|
||||||
|
<input class="form-control" type="submit" value="{% trans " Apply" %}">
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="ctf-block">
|
||||||
|
<div class="ctf-head">
|
||||||
|
<h3>{% trans "Connected accounts" %}</h3>
|
||||||
|
</div>
|
||||||
|
<div class="bloc-body">
|
||||||
|
<div class="d-flex">
|
||||||
|
{% if user.userprofileinfo.discord_id|length > 0 %}
|
||||||
|
<form action="{% url 'accounts:connections-disconnect-discord' %}" method='POST'
|
||||||
|
class="form-inline p-2">
|
||||||
{%csrf_token%}
|
{%csrf_token%}
|
||||||
<label for="{{ u_form.username.id_for_label }}">{% trans "Username" %} *</label>
|
<button class="btn btn-dark" type="submit">{% trans "Disconnect Discord" %}</button>
|
||||||
{{ u_form.username.errors}}
|
</form>
|
||||||
{{u_form.username}}
|
{% else %}
|
||||||
</br>
|
<form action="{% url 'accounts:connections-connect-discord' %}" method='POST'
|
||||||
<label for="{{ u_form.email.id_for_label }}">{% trans "Email" %} *</label>
|
class="form-inline p-2">
|
||||||
{{ u_form.email.errors}}
|
{%csrf_token%}
|
||||||
{{u_form.email}}
|
<button class="btn btn-dark" type="submit">{% trans "Connect Discord" %}</button>
|
||||||
</br>
|
</form>
|
||||||
</br>
|
{% endif %}
|
||||||
<label for="{{ p_form.portfolio_site.id_for_label }}">{% trans "Website" %}</label>
|
</div>
|
||||||
{{p_form.portfolio_site}}
|
<div class="d-flex">
|
||||||
</br>
|
{% if user.userprofileinfo.intra42_id|length > 0 %}
|
||||||
</br>Token
|
<form action="{% url 'accounts:connections-disconnect-intra42' %}" method='POST'
|
||||||
<input type='text' readonly value='{{token}}'>
|
class="form-inline p-2">
|
||||||
</br>
|
{%csrf_token%}
|
||||||
<input class="form-control" type="submit" value="{% trans "Apply" %}">
|
<button class="btn btn-dark" type="submit">{% trans "Disconnect 42" %}</button>
|
||||||
</div>
|
</form>
|
||||||
</form>
|
{% else %}
|
||||||
|
<form action="{% url 'accounts:connections-connect-intra42' %}" method='POST'
|
||||||
|
class="form-inline p-2">
|
||||||
|
{%csrf_token%}
|
||||||
|
<button class="btn btn-dark" type="submit">{% trans "Connect 42" %}</button>
|
||||||
|
</form>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
<div class="d-none d-md-block col-10 col-md-3 right-sidebar">
|
||||||
<div class="d-none d-md-block col-10 col-md-3 right-sidebar">
|
<ul class="list-group">
|
||||||
<ul class="list-group">
|
|
||||||
<li class="list-group-item">{{ user.username }}</li>
|
<li class="list-group-item">{{ user.username }}</li>
|
||||||
<li class="list-group-item">{% trans "Score" %} : {{ user.userprofileinfo.score }}</li>
|
<li class="list-group-item">{% trans "Score" %} : {{ user.userprofileinfo.score }}</li>
|
||||||
{% if user.userprofileinfo.portfolio_site %}
|
{% if user.userprofileinfo.portfolio_site %}
|
||||||
<li class="list-group-item">
|
<li class="list-group-item">
|
||||||
<a href="{{ user.userprofileinfo.portfolio_site }}" target="_blank">
|
<a href="{{ user.userprofileinfo.portfolio_site }}" target="_blank">
|
||||||
{{ user.userprofileinfo.portfolio_site }}
|
{{ user.userprofileinfo.portfolio_site }}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<li class="list-group-item">{% trans "Registered since" %} {{ user.date_joined|date:"Y-m-d" }}</li>
|
<li class="list-group-item">{% trans "Registered since" %} {{ user.date_joined|date:"Y-m-d" }}</li>
|
||||||
</ul>
|
</ul>
|
||||||
<ul class="list-group">
|
<ul class="list-group">
|
||||||
<form method='GET' action="{% url 'accounts:delete_account' %}">
|
<form method='GET' action="{% url 'accounts:profile' user %}">
|
||||||
{%csrf_token%}
|
<li class="list-group-item">
|
||||||
<li class="list-group-item">
|
<input class="form-control" type="submit" value="{% trans " View my profile" %}">
|
||||||
<input class="form-control" type="submit" value="{% trans "Delete my account" %}">
|
</li>
|
||||||
</li>
|
|
||||||
</form>
|
</form>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
<ul class="list-group">
|
||||||
|
<form method='GET' action="{% url 'accounts:delete_account' %}">
|
||||||
|
{%csrf_token%}
|
||||||
|
<li class="list-group-item">
|
||||||
|
<input class="form-control" type="submit" value="{% trans " Delete my account" %}">
|
||||||
|
</li>
|
||||||
|
</form>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|
|
@ -53,9 +53,9 @@
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if member %}
|
{% if member %}
|
||||||
<li class="list-group-item is-member">{% trans "Status: Member" %}</li>
|
<li class="list-group-item">Status: <a class="{{ is_member }}" href="{% url 'resources:becomeMember' %}">{% trans "Member" %}</a></li>
|
||||||
{% else %}
|
{% else %}
|
||||||
<li class="list-group-item">{% trans "Status: Visitor" %}</li>
|
<li class="list-group-item">Status: {% trans " Visitor" %}</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<li class="list-group-item">{% trans "Registered since" %} {{ user.date_joined|date:"d-m-Y" }}</li>
|
<li class="list-group-item">{% trans "Registered since" %} {{ user.date_joined|date:"d-m-Y" }}</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -75,6 +75,19 @@
|
||||||
</li>
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
<ul class="list-group">
|
||||||
|
<ul class="list-group">
|
||||||
|
<li class="list-group-item">{% trans "Challenges created" %}</li>
|
||||||
|
{% if created %}
|
||||||
|
{% for creat in created %}
|
||||||
|
<li class="list-group-item"><a href="{% url 'ctf' cat_slug=creat.category.slug ctf_slug=creat.slug %}">{{ creat.name }}</a></li>
|
||||||
|
{% endfor %}
|
||||||
|
{% else %}
|
||||||
|
<li class="list-group-item">{% trans "It seems that this user has not created any challenge yet..." %}</li>
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -2,42 +2,40 @@
|
||||||
{% block content %}
|
{% block content %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-12 col-md-9">
|
<div class="col-sm-12 col-md-9">
|
||||||
<div class="ctf-block">
|
<div class="ctf-block">
|
||||||
<div class="ctf-head">
|
<div class="ctf-head">
|
||||||
<h3>Register</h3>
|
<h3>Register</h3>
|
||||||
</div>
|
</div>
|
||||||
<div class="ctf-body sign-body">
|
<div class="ctf-body sign-body">
|
||||||
<div class="col-sm-8 col-md-6 mx-auto">
|
<div class="col-sm-8 col-md-6 mx-auto">
|
||||||
{% if registered %}
|
{% if registered %}
|
||||||
<h1>{% trans "Welcome !" %}</h1>
|
<h1>{% trans "Welcome !" %}</h1>
|
||||||
<span class="message success-msg">{% trans "Your account has been created." %}</span>
|
<span class="message success-msg">{% trans "Your account has been created." %}</span>
|
||||||
{% else %}
|
{% else %}
|
||||||
{% if registered_failed %}
|
{% if registered_failed %}
|
||||||
<span class="message error-msg">{{ registered_failed }}</span>
|
<span class="message error-msg">{{ registered_failed }}</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<form enctype="multipart/form-data" method="POST">
|
<form enctype="multipart/form-data" method="POST">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<input class="form-control" type="text" name="username" placeholder="{% trans "Username" %} *" maxlength="150" required="" id="id_username"></br>
|
<input class="form-control" type="text" name="username" placeholder="{% trans "Username" %} *" maxlength="150" required="" id="id_username" value="{{ old_username }}"></br>
|
||||||
<input class="form-control" type="password" name="password" placeholder="{% trans "Password" %} *" required="" id="id_password"></br>
|
<input class="form-control" type="password" name="password" placeholder="{% trans "Password" %} *" required="" id="id_password"></br>
|
||||||
<input class="form-control" type="email" name="email" placeholder="pleasedontgivemy@private.infos*" required="" maxlength="254" id="id_email"></br>
|
<input class="form-control" type="email" name="email" placeholder="pleasedontgivemy@private.infos*" required="" maxlength="254" id="id_email" value="{{ old_email }}"></br>
|
||||||
<input class="form-control" type="url" name="portfolio_site" placeholder="{% trans "Personal website" %}"maxlength="200" id="id_portfolio_site"></br>
|
<input class="form-control" type="url" name="portfolio_site" placeholder="{% trans "Personal website" %}"maxlength="200" id="id_portfolio_site" value="{{ old_website }}"></br>
|
||||||
<input type="submit" name="" class="form-control" value="{% trans "Register" %}">
|
<input type="submit" name="" class="form-control" value="{% trans "Register" %}">
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
<div class="col-sm-12 col-md-3 right-sidebar">
|
||||||
<div class="col-sm-12 col-md-3 right-sidebar">
|
<ul class="list-group">
|
||||||
<ul class="list-group">
|
<a href="/accounts/signup" class="list-group-item">{% trans "Sign up" %}</a>
|
||||||
<a href="/accounts/signup" class="list-group-item">{% trans "Sign up" %}</a>
|
<a href="/accounts/signin" class="list-group-item">{% trans "Login" %}</a>
|
||||||
<a href="/accounts/signin" class="list-group-item">{% trans "Login" %}</a>
|
</ul>
|
||||||
</ul>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|
|
@ -10,8 +10,11 @@ urlpatterns = [
|
||||||
path('edit/', views.edit, name='edit'),
|
path('edit/', views.edit, name='edit'),
|
||||||
path('logout/', views.out, name='out'),
|
path('logout/', views.out, name='out'),
|
||||||
path('rank/<str:token>', views.rank, name='rank'),
|
path('rank/<str:token>', views.rank, name='rank'),
|
||||||
path('connections/connect/discord', views.connection.connect, name='connections-connect-discord'),
|
path('connections/connect/discord', views.connection.connect_discord, name='connections-connect-discord'),
|
||||||
path('connections/connect/discord/authorize', views.connection.authorize, name='connections-connect-discord-authorize'),
|
path('connections/connect/discord/authorize', views.connection.authorize_discord, name='connections-connect-discord-authorize'),
|
||||||
path('connections/disconnect/discord', views.connection.disconnect, name='connections-disconnect-discord'),
|
path('connections/disconnect/discord', views.connection.disconnect_discord, name='connections-disconnect-discord'),
|
||||||
|
path('connections/connect/intra42', views.connection.connect_intra42, name='connections-connect-intra42'),
|
||||||
|
path('connections/connect/intra42/authorize', views.connection.authorize_intra42, name='connections-connect-intra42-authorize'),
|
||||||
|
path('connections/disconnect/intra42', views.connection.disconnect_intra42, name='connections-disconnect-intra42'),
|
||||||
path('delete_account/', views.delete_account, name='delete_account'),
|
path('delete_account/', views.delete_account, name='delete_account'),
|
||||||
]
|
]
|
||||||
|
|
|
@ -4,47 +4,106 @@ from django.views.decorators.http import require_POST
|
||||||
from django.views.defaults import bad_request
|
from django.views.defaults import bad_request
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.shortcuts import redirect
|
from django.shortcuts import redirect
|
||||||
|
from django.contrib.sites.models import Site
|
||||||
|
from accounts.models import Campus
|
||||||
|
from django.db import IntegrityError
|
||||||
import os
|
import os
|
||||||
|
|
||||||
oauth = OAuth()
|
oauth = OAuth()
|
||||||
|
|
||||||
oauth.register(
|
oauth.register(
|
||||||
name='discord',
|
name='discord',
|
||||||
client_id=os.getenv('OAUTH2_DISCORD_CLIENT_ID'),
|
client_id=os.getenv('OAUTH2_DISCORD_CLIENT_ID'),
|
||||||
client_secret=os.getenv('OAUTH2_DISCORD_CLIENT_SECRET'),
|
client_secret=os.getenv('OAUTH2_DISCORD_CLIENT_SECRET'),
|
||||||
access_token_url='https://discord.com/api/oauth2/token',
|
access_token_url='https://discord.com/api/oauth2/token',
|
||||||
authorize_url='https://discord.com/api/oauth2/authorize',
|
authorize_url='https://discord.com/api/oauth2/authorize',
|
||||||
client_kwargs={'scope': 'identify'},
|
client_kwargs={'scope': 'identify'},
|
||||||
api_base_url='https://discord.com/api/'
|
api_base_url='https://discord.com/api/'
|
||||||
|
)
|
||||||
|
|
||||||
|
oauth.register(
|
||||||
|
name='intra42',
|
||||||
|
client_id=os.getenv('OAUTH2_INTRA42_CLIENT_ID'),
|
||||||
|
client_secret=os.getenv('OAUTH2_INTRA42_CLIENT_SECRET'),
|
||||||
|
access_token_url='https://api.intra.42.fr/oauth/token',
|
||||||
|
authorize_url='https://api.intra.42.fr/oauth/authorize',
|
||||||
|
api_base_url='https://api.intra.42.fr/'
|
||||||
)
|
)
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@require_POST
|
@require_POST
|
||||||
def connect(request):
|
def connect_intra42(request):
|
||||||
if request.user.userprofileinfo.discord_id:
|
if request.user.userprofileinfo.intra42_id:
|
||||||
return bad_request(request, "Already connected")
|
return bad_request(request, "Already connected")
|
||||||
redirect_uri = reverse('accounts:connections-connect-discord-authorize')
|
site = Site.objects.get_current()
|
||||||
redirect_uri = request.build_absolute_uri(redirect_uri)
|
redirect_uri = reverse('accounts:connections-connect-intra42-authorize')
|
||||||
print(redirect_uri)
|
redirect_uri = "https://" + site.domain + redirect_uri[3:] # remove language code
|
||||||
return oauth.discord.authorize_redirect(request, redirect_uri)
|
return oauth.intra42.authorize_redirect(request, redirect_uri)
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def authorize(request):
|
def authorize_intra42(request):
|
||||||
if request.user.userprofileinfo.discord_id:
|
if request.user.userprofileinfo.intra42_id:
|
||||||
return bad_request(request, "Already connected")
|
return bad_request(request, "Already connected")
|
||||||
token = oauth.discord.authorize_access_token(request)
|
try:
|
||||||
response = oauth.discord.get('users/@me', token=token)
|
token = oauth.intra42.authorize_access_token(request)
|
||||||
response = response.json()
|
except:
|
||||||
discord_id = response['id']
|
return redirect('accounts:edit')
|
||||||
request.user.userprofileinfo.discord_id = discord_id
|
response = oauth.intra42.get('v2/me', token=token)
|
||||||
request.user.userprofileinfo.save()
|
response = response.json()
|
||||||
return redirect('accounts:edit')
|
intra42_id = response['id']
|
||||||
|
intra42_campus = response['campus'][0]['name']
|
||||||
|
intra42_campus_id = response['campus'][0]['id']
|
||||||
|
request.user.userprofileinfo.intra42_id = intra42_id
|
||||||
|
request.user.userprofileinfo.campus, created = Campus.objects.get_or_create(id=intra42_campus_id, name=intra42_campus)
|
||||||
|
try:
|
||||||
|
request.user.userprofileinfo.save()
|
||||||
|
return redirect('accounts:edit')
|
||||||
|
except IntegrityError:
|
||||||
|
return redirect('accounts:edit')
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@require_POST
|
@require_POST
|
||||||
def disconnect(request):
|
def disconnect_intra42(request):
|
||||||
if not request.user.userprofileinfo.discord_id:
|
if not request.user.userprofileinfo.intra42_id:
|
||||||
return bad_request(request, "Already disconnected")
|
return bad_request(request, "Already disconnected")
|
||||||
request.user.userprofileinfo.discord_id = None
|
request.user.userprofileinfo.intra42_id = None
|
||||||
request.user.userprofileinfo.save()
|
request.user.userprofileinfo.intra42_campus = None
|
||||||
return redirect('accounts:edit')
|
request.user.userprofileinfo.intra42_campus_id = None
|
||||||
|
request.user.userprofileinfo.campus = None
|
||||||
|
request.user.userprofileinfo.save()
|
||||||
|
return redirect('accounts:edit')
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
@require_POST
|
||||||
|
def connect_discord(request):
|
||||||
|
if request.user.userprofileinfo.discord_id:
|
||||||
|
return bad_request(request, "Already connected")
|
||||||
|
site = Site.objects.get_current()
|
||||||
|
redirect_uri = reverse('accounts:connections-connect-discord-authorize')
|
||||||
|
redirect_uri = "https://" + site.domain + redirect_uri[3:] # remove language code
|
||||||
|
return oauth.discord.authorize_redirect(request, redirect_uri)
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def authorize_discord(request):
|
||||||
|
if request.user.userprofileinfo.discord_id:
|
||||||
|
return bad_request(request, "Already connected")
|
||||||
|
try:
|
||||||
|
token = oauth.discord.authorize_access_token(request)
|
||||||
|
except:
|
||||||
|
return redirect('accounts:edit')
|
||||||
|
response = oauth.discord.get('users/@me', token=token)
|
||||||
|
response = response.json()
|
||||||
|
discord_id = response['id']
|
||||||
|
request.user.userprofileinfo.discord_id = discord_id
|
||||||
|
request.user.userprofileinfo.save()
|
||||||
|
return redirect('accounts:edit')
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
@require_POST
|
||||||
|
def disconnect_discord(request):
|
||||||
|
if not request.user.userprofileinfo.discord_id:
|
||||||
|
return bad_request(request, "Already disconnected")
|
||||||
|
request.user.userprofileinfo.discord_id = None
|
||||||
|
request.user.userprofileinfo.save()
|
||||||
|
return redirect('accounts:edit')
|
||||||
|
|
|
@ -43,32 +43,69 @@ def signup(request):
|
||||||
user_form = UserForm()
|
user_form = UserForm()
|
||||||
profile_form = UserProfileInfoForm()
|
profile_form = UserProfileInfoForm()
|
||||||
registered = False
|
registered = False
|
||||||
|
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
pass1 = request.POST.get('password')
|
username = request.POST.get('username')
|
||||||
if len(pass1) < 8:
|
passwd = request.POST.get('password')
|
||||||
return render(request,'accounts/register.html', {'user_form':user_form, 'profile_form':profile_form, 'registered_failed':"The new password must be at least %d characters long." % 8})
|
email = request.POST.get('email')
|
||||||
first_isalpha = pass1[0].isalpha()
|
website = request.POST.get('portfolio_site')
|
||||||
if not any(c.isdigit() for c in pass1) or not any(c.isalpha() for c in pass1):
|
|
||||||
return render(request,'accounts/register.html', {'user_form':user_form, 'profile_form':profile_form, 'registered_failed':_("The password must contain at least one letter and at least one digit or punctuation character.")})
|
if len(passwd) < 8:
|
||||||
|
return render(request, 'accounts/register.html', {
|
||||||
|
'user_form': user_form,
|
||||||
|
'profile_form': profile_form,
|
||||||
|
'registered_failed': _("The password must be at least 8 characters long."),
|
||||||
|
'old_username': username,
|
||||||
|
'old_email': email,
|
||||||
|
'old_website': website
|
||||||
|
})
|
||||||
|
|
||||||
|
if not any(c.isdigit() for c in passwd) or not any(c.isalpha() for c in passwd):
|
||||||
|
return render(request, 'accounts/register.html', {
|
||||||
|
'user_form': user_form,
|
||||||
|
'profile_form': profile_form,
|
||||||
|
'registered_failed': _("The password must contain at least one letter and at least one digit or punctuation character."),
|
||||||
|
'old_username': username,
|
||||||
|
'old_email': email,
|
||||||
|
'old_website': website
|
||||||
|
})
|
||||||
|
|
||||||
if User.objects.filter(email=request.POST.get('email')).exists():
|
if User.objects.filter(email=request.POST.get('email')).exists():
|
||||||
return render(request,'accounts/register.html', {'user_form':user_form, 'profile_form':profile_form, 'registered_failed':_("A user with that email already exists.")})
|
return render(request, 'accounts/register.html', {
|
||||||
|
'user_form': user_form,
|
||||||
|
'profile_form': profile_form,
|
||||||
|
'registered_failed': _("A user with that email already exists."),
|
||||||
|
'old_username': username,
|
||||||
|
'old_website': website
|
||||||
|
})
|
||||||
|
|
||||||
user_form = UserForm(data=request.POST)
|
user_form = UserForm(data=request.POST)
|
||||||
profile_form = UserProfileInfoForm(data=request.POST)
|
profile_form = UserProfileInfoForm(data=request.POST)
|
||||||
if user_form.is_valid() and profile_form.is_valid():
|
if user_form.is_valid() and profile_form.is_valid():
|
||||||
user = user_form.save()
|
user = user_form.save()
|
||||||
user.set_password(user.password)
|
user.set_password(user.password)
|
||||||
user.save()
|
user.save()
|
||||||
|
|
||||||
profile = profile_form.save(commit=False)
|
profile = profile_form.save(commit=False)
|
||||||
profile.user = user
|
profile.user = user
|
||||||
profile.token = token_hex(16)
|
profile.token = token_hex(16)
|
||||||
profile.save()
|
profile.save()
|
||||||
|
|
||||||
registered = True
|
registered = True
|
||||||
else:
|
else:
|
||||||
return render(request,'accounts/register.html', {'user_form':user_form, 'profile_form':profile_form, 'registered_failed':_("A user with that username already exists.")})
|
return render(request, 'accounts/register.html', {
|
||||||
return render(request,'accounts/register.html',
|
'user_form': user_form,
|
||||||
{'user_form':user_form,
|
'profile_form': profile_form,
|
||||||
'profile_form':profile_form,
|
'registered_failed': _("A user with that username already exists."),
|
||||||
'registered':registered})
|
'old_email': email,
|
||||||
|
'old_website': website
|
||||||
|
})
|
||||||
|
|
||||||
|
return render(request, 'accounts/register.html', {
|
||||||
|
'user_form': user_form,
|
||||||
|
'profile_form': profile_form,
|
||||||
|
'registered': registered
|
||||||
|
})
|
||||||
else:
|
else:
|
||||||
return HttpResponseRedirect(reverse('home'))
|
return HttpResponseRedirect(reverse('home'))
|
||||||
|
|
||||||
|
@ -151,20 +188,9 @@ def profile(request, user_name):
|
||||||
for s in solves.reverse():
|
for s in solves.reverse():
|
||||||
somme += s.ctf.points
|
somme += s.ctf.points
|
||||||
solved.append([s.flag_date.timestamp() * 1000,somme])
|
solved.append([s.flag_date.timestamp() * 1000,somme])
|
||||||
|
created = CTF.objects.filter(author=user_obj, event=None)
|
||||||
return render(request,'accounts/profile.html', {'user':user_obj, 'solves':solves,'solved':solved,'catsDatas': catsDatas, 'pointDatas': pointDatas,
|
return render(request,'accounts/profile.html', {'user':user_obj, 'solves':solves,'solved':solved,'catsDatas': catsDatas, 'pointDatas': pointDatas,
|
||||||
'rank': rank, 'score' : somme, 'member' : member, 'cats':cats})
|
'rank': rank, 'score' : somme, 'member' : member, 'cats':cats, 'created':created})
|
||||||
|
|
||||||
def rank(request, token):
|
|
||||||
all_users = UserProfileInfo.objects.filter(score__gt=0).select_related().order_by('-score', 'last_submission_date', 'user__username')
|
|
||||||
|
|
||||||
rank = 1
|
|
||||||
for elem in all_users:
|
|
||||||
if elem.token == token:
|
|
||||||
break
|
|
||||||
rank += 1
|
|
||||||
data = {"rank": rank}
|
|
||||||
return JsonResponse(data)
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def delete_account(request):
|
def delete_account(request):
|
||||||
|
@ -182,3 +208,14 @@ def delete_account(request):
|
||||||
|
|
||||||
else:
|
else:
|
||||||
return render(request, 'accounts/delete.html', {'deleted': False, 'bad_password': False} )
|
return render(request, 'accounts/delete.html', {'deleted': False, 'bad_password': False} )
|
||||||
|
|
||||||
|
def rank(request, token):
|
||||||
|
all_users = UserProfileInfo.objects.filter(score__gt=0).select_related().order_by('-score', 'last_submission_date', 'user__username')
|
||||||
|
|
||||||
|
rank = 1
|
||||||
|
for elem in all_users:
|
||||||
|
if elem.token == token:
|
||||||
|
break
|
||||||
|
rank += 1
|
||||||
|
data = {"rank": rank}
|
||||||
|
return JsonResponse(data)
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
from django.contrib import admin
|
||||||
|
|
||||||
|
# Register your models here.
|
|
@ -0,0 +1,6 @@
|
||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class ApiConfig(AppConfig):
|
||||||
|
default_auto_field = 'django.db.models.BigAutoField'
|
||||||
|
name = 'api'
|
|
@ -0,0 +1,3 @@
|
||||||
|
from django.db import models
|
||||||
|
|
||||||
|
# Create your models here.
|
|
@ -0,0 +1,3 @@
|
||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
# Create your tests here.
|
|
@ -0,0 +1,9 @@
|
||||||
|
from django.urls import path
|
||||||
|
from . import views
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
path('bot/discord', views.bot_discord_rank, name='bot_discord_rank'), # legacy, to remove when new bot is deployed
|
||||||
|
path('bot/discord/rank', views.bot_discord_rank, name='bot_discord_rank'), # use this
|
||||||
|
path('bot/discord/campus', views.bot_discord_campus, name='bot_discord_campus'),
|
||||||
|
path('events/<str:event_slug>', views.events_data, name='events_data'),
|
||||||
|
]
|
|
@ -0,0 +1,72 @@
|
||||||
|
from django.shortcuts import render
|
||||||
|
from accounts.models import UserProfileInfo
|
||||||
|
from django.http import JsonResponse
|
||||||
|
import os
|
||||||
|
from events.models import Event, Team, EventPlayer
|
||||||
|
from django.shortcuts import get_object_or_404
|
||||||
|
|
||||||
|
# Create your views here.
|
||||||
|
|
||||||
|
def bot_discord_rank(request):
|
||||||
|
if request.method != 'GET':
|
||||||
|
return JsonResponse({'error':'bad request'})
|
||||||
|
|
||||||
|
token = request.GET.get('token')
|
||||||
|
auth_token = os.getenv('BOT_TOKEN')
|
||||||
|
|
||||||
|
if (token != auth_token or not auth_token):
|
||||||
|
return JsonResponse({'error':'not authorized'})
|
||||||
|
|
||||||
|
all_users = UserProfileInfo.objects.select_related().order_by('-score', 'last_submission_date', 'user__username')
|
||||||
|
data = {}
|
||||||
|
rank = 1
|
||||||
|
for user in all_users:
|
||||||
|
if user.discord_id:
|
||||||
|
data[user.discord_id] = rank
|
||||||
|
rank += 1
|
||||||
|
|
||||||
|
return JsonResponse(data)
|
||||||
|
|
||||||
|
def bot_discord_campus(request):
|
||||||
|
if request.method != 'GET':
|
||||||
|
return JsonResponse({'error':'bad request'})
|
||||||
|
|
||||||
|
token = request.GET.get('token')
|
||||||
|
auth_token = os.getenv('BOT_TOKEN')
|
||||||
|
|
||||||
|
if (token != auth_token or not auth_token):
|
||||||
|
return JsonResponse({'error':'not authorized'})
|
||||||
|
|
||||||
|
all_users = UserProfileInfo.objects.select_related().order_by('-score', 'last_submission_date', 'user__username')
|
||||||
|
data = {}
|
||||||
|
for user in all_users:
|
||||||
|
if user.campus and user.discord_id:
|
||||||
|
data[user.discord_id] = user.campus.name
|
||||||
|
|
||||||
|
return JsonResponse(data)
|
||||||
|
|
||||||
|
def events_data(request, event_slug):
|
||||||
|
if request.method != 'GET':
|
||||||
|
return JsonResponse({'error':'bad request'})
|
||||||
|
|
||||||
|
event_info = get_object_or_404(Event, slug=event_slug)
|
||||||
|
|
||||||
|
if event_info.password and request.GET.get('password') != event_info.password:
|
||||||
|
return JsonResponse({'error':'not authorized'})
|
||||||
|
|
||||||
|
players = EventPlayer.objects.filter(event=event_info)
|
||||||
|
|
||||||
|
data = {}
|
||||||
|
if event_info.team_size > 1:
|
||||||
|
for player in players:
|
||||||
|
if not player.team:
|
||||||
|
continue
|
||||||
|
if not player.team.name in data:
|
||||||
|
data[player.team.name] = []
|
||||||
|
data[player.team.name].append({"name": player.user.username, "score": player.score})
|
||||||
|
else:
|
||||||
|
for player in players:
|
||||||
|
data[player.user.username] = player.score
|
||||||
|
|
||||||
|
return JsonResponse(data)
|
||||||
|
|
|
@ -2,8 +2,6 @@ from django.contrib import admin
|
||||||
from .models import Category, CTF, CTF_flags
|
from .models import Category, CTF, CTF_flags
|
||||||
|
|
||||||
admin.site.register(Category)
|
admin.site.register(Category)
|
||||||
#admin.site.register(CTF)
|
|
||||||
#admin.site.register(CTF_flags)
|
|
||||||
|
|
||||||
@admin.register(CTF_flags)
|
@admin.register(CTF_flags)
|
||||||
class ctf_flags(admin.ModelAdmin):
|
class ctf_flags(admin.ModelAdmin):
|
||||||
|
@ -14,12 +12,61 @@ class ctf_flags(admin.ModelAdmin):
|
||||||
# search list
|
# search list
|
||||||
search_fields = ['ctf__category__name', 'ctf__name', 'user__username']
|
search_fields = ['ctf__category__name', 'ctf__name', 'user__username']
|
||||||
|
|
||||||
|
def get_queryset(self, request):
|
||||||
|
qs = super().get_queryset(request)
|
||||||
|
if request.user.is_superuser:
|
||||||
|
return qs
|
||||||
|
groups = list(request.user.groups.values_list('name', flat=True))
|
||||||
|
return qs.filter(event__name__in=groups)
|
||||||
|
|
||||||
|
def has_view_permission(self, request, obj=None):
|
||||||
|
if request.user.is_superuser:
|
||||||
|
return True
|
||||||
|
if obj is not None:
|
||||||
|
return request.user.groups.filter(name=obj.event.name).exists()
|
||||||
|
return super().has_view_permission(request, obj)
|
||||||
|
|
||||||
|
def has_change_permission(self, request, obj=None):
|
||||||
|
if request.user.is_superuser:
|
||||||
|
return True
|
||||||
|
if obj is not None:
|
||||||
|
return request.user.groups.filter(name=obj.event.name).exists()
|
||||||
|
return super().has_change_permission(request, obj)
|
||||||
|
|
||||||
|
def has_delete_permission(self, request, obj=None):
|
||||||
|
if request.user.is_superuser:
|
||||||
|
return True
|
||||||
|
if obj is not None:
|
||||||
|
return request.user.groups.filter(name=obj.event.name).exists()
|
||||||
|
return super().has_delete_permission(request, obj)
|
||||||
|
|
||||||
@admin.register(CTF)
|
@admin.register(CTF)
|
||||||
class ctf(admin.ModelAdmin):
|
class ctf(admin.ModelAdmin):
|
||||||
#list display
|
#list display
|
||||||
list_display = ['name', 'event', 'category']
|
list_display = ['name', 'event', 'category', 'points']
|
||||||
#list Filter
|
#list Filter
|
||||||
list_filter = ('category', 'event')
|
list_filter = ('category', 'event')
|
||||||
# search list
|
# search list
|
||||||
search_fields = ['category__name', 'name', 'author__username']
|
search_fields = ['category__name', 'name', 'author__username']
|
||||||
# Register your models here.
|
|
||||||
|
def get_queryset(self, request):
|
||||||
|
qs = super().get_queryset(request)
|
||||||
|
if request.user.is_superuser:
|
||||||
|
return qs
|
||||||
|
groups = list(request.user.groups.values_list('name', flat=True))
|
||||||
|
return qs.filter(event__name__in=groups)
|
||||||
|
|
||||||
|
def has_view_permission(self, request, obj=None):
|
||||||
|
if request.user.is_superuser:
|
||||||
|
return True
|
||||||
|
if obj is not None:
|
||||||
|
return request.user.groups.filter(name=obj.event.name).exists()
|
||||||
|
return super().has_view_permission(request, obj)
|
||||||
|
|
||||||
|
def has_change_permission(self, request, obj=None):
|
||||||
|
if request.user.is_superuser:
|
||||||
|
return True
|
||||||
|
if obj is not None:
|
||||||
|
return request.user.groups.filter(name=obj.event.name).exists()
|
||||||
|
return super().has_change_permission(request, obj)
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ class Command(BaseCommand):
|
||||||
nb_solves = len(solves)
|
nb_solves = len(solves)
|
||||||
|
|
||||||
if nb_solves > 0:
|
if nb_solves > 0:
|
||||||
new_points = 200 - int(log(nb_solves)*8.5)*5
|
new_points = max(200 - int(log(nb_solves)*8.5)*5, 5)
|
||||||
else:
|
else:
|
||||||
new_points = 200
|
new_points = 200
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
# Generated by Django 3.2.11 on 2022-02-15 16:13
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('ctfs', '0007_ctf_disabled'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='ctf',
|
||||||
|
name='description_de',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='ctf',
|
||||||
|
name='description_ru',
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='ctf',
|
||||||
|
name='port',
|
||||||
|
field=models.PositiveSmallIntegerField(blank=True, null=True),
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 3.2.11 on 2023-09-17 17:57
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('ctfs', '0008_auto_20220215_1713'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='ctf_flags',
|
||||||
|
name='bonus',
|
||||||
|
field=models.PositiveSmallIntegerField(default=0),
|
||||||
|
),
|
||||||
|
]
|
|
@ -15,10 +15,9 @@ class CTF(models.Model):
|
||||||
disabled = models.BooleanField(default=False)
|
disabled = models.BooleanField(default=False)
|
||||||
description = models.TextField(blank=True)
|
description = models.TextField(blank=True)
|
||||||
description_en = models.TextField(blank=True)
|
description_en = models.TextField(blank=True)
|
||||||
description_ru = models.TextField(blank=True)
|
|
||||||
description_de = models.TextField(blank=True)
|
|
||||||
file = models.FileField(blank=True, upload_to='challenges')
|
file = models.FileField(blank=True, upload_to='challenges')
|
||||||
ctf_url = models.URLField(blank=True)
|
ctf_url = models.URLField(blank=True)
|
||||||
|
port = models.PositiveSmallIntegerField(null=True, blank=True)
|
||||||
event = models.ForeignKey(Event, null=True, blank=True, on_delete=models.CASCADE)
|
event = models.ForeignKey(Event, null=True, blank=True, on_delete=models.CASCADE)
|
||||||
points = models.PositiveSmallIntegerField()
|
points = models.PositiveSmallIntegerField()
|
||||||
slug = models.SlugField(max_length=55)
|
slug = models.SlugField(max_length=55)
|
||||||
|
@ -46,6 +45,7 @@ class CTF_flags(models.Model):
|
||||||
user = models.ForeignKey(User, unique=False, on_delete=models.CASCADE)
|
user = models.ForeignKey(User, unique=False, on_delete=models.CASCADE)
|
||||||
ctf = models.ForeignKey(CTF, unique=False, on_delete=models.CASCADE)
|
ctf = models.ForeignKey(CTF, unique=False, on_delete=models.CASCADE)
|
||||||
flag_date = models.DateTimeField('Flag date')
|
flag_date = models.DateTimeField('Flag date')
|
||||||
|
bonus = models.PositiveSmallIntegerField(default=0)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ['-flag_date']
|
ordering = ['-flag_date']
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
from django.contrib import sitemaps
|
||||||
|
from django.urls import reverse
|
||||||
|
from .models import Category, CTF
|
||||||
|
from .views import category, ctf
|
||||||
|
|
||||||
|
class CategorySitemap(sitemaps.Sitemap):
|
||||||
|
changefreq = "weekly"
|
||||||
|
priority = 0.7
|
||||||
|
i18n = True
|
||||||
|
|
||||||
|
def items(self):
|
||||||
|
return Category.objects.all()
|
||||||
|
|
||||||
|
def location(self, obj):
|
||||||
|
return reverse(category, kwargs={'cat_slug': obj.slug})
|
||||||
|
|
||||||
|
class CTFSitemap(sitemaps.Sitemap):
|
||||||
|
changefreq = "weekly"
|
||||||
|
priority = 0.7
|
||||||
|
i18n = True
|
||||||
|
|
||||||
|
def items(self):
|
||||||
|
return CTF.objects.all()
|
||||||
|
|
||||||
|
def location(self, obj):
|
||||||
|
return reverse(ctf, kwargs={'cat_slug': obj.category.slug, 'ctf_slug': obj.slug})
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 5c7b5995fe12c0ed1bb10f97e56ec89377c98b54
|
|
@ -2,11 +2,13 @@
|
||||||
{% block content %}
|
{% block content %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load is_member %}
|
{% load is_member %}
|
||||||
|
{% load get_chall %}
|
||||||
|
{% get_current_language as lang %}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-12 col-md-9">
|
<div class="col-sm-12 col-md-9">
|
||||||
<div class="ctf-block">
|
<div class="ctf-block">
|
||||||
<div class="ctf-head">
|
<div class="ctf-head">
|
||||||
<h3>{{ ctf.name }}</h3>
|
<h1>{{ ctf.name }}</h1>
|
||||||
<small>{% trans "Published date" %} : {{ ctf.pub_date }}</small>
|
<small>{% trans "Published date" %} : {{ ctf.pub_date }}</small>
|
||||||
</div>
|
</div>
|
||||||
{% if date < ctf.pub_date %}
|
{% if date < ctf.pub_date %}
|
||||||
|
@ -15,11 +17,11 @@
|
||||||
</div>
|
</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="ctf-body">
|
<div class="ctf-body">
|
||||||
{% if description %}
|
{% get_chall_by_lang ctf lang as content %}
|
||||||
{{ description|safe }}
|
{{ content | safe }}
|
||||||
{% else %}
|
<!-- {% if ctf.port %}
|
||||||
{% trans "No translation available. Please try another language (English or French)." %}
|
<b>nc challenges.42ctf.org {{ ctf.port }}</b>
|
||||||
{% endif %}
|
{% endif %} -->
|
||||||
</div>
|
</div>
|
||||||
<div class="ctf-footer">
|
<div class="ctf-footer">
|
||||||
{% if request.user.is_authenticated %}
|
{% if request.user.is_authenticated %}
|
||||||
|
|
|
@ -2,8 +2,10 @@
|
||||||
{% block content %}
|
{% block content %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
<div class="col-12 ctf-head">
|
||||||
|
<h1>{{ cat.name }}</h1>
|
||||||
|
</div>
|
||||||
<div class="col-sm-12 col-md-9 news-card">
|
<div class="col-sm-12 col-md-9 news-card">
|
||||||
<h3>{{ cat.name }}</h3>
|
|
||||||
{% if ctfs %}
|
{% if ctfs %}
|
||||||
<table class="table table-striped table-dark">
|
<table class="table table-striped table-dark">
|
||||||
<thead>
|
<thead>
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
from django import template
|
||||||
|
|
||||||
|
register = template.Library()
|
||||||
|
|
||||||
|
@register.simple_tag
|
||||||
|
def get_chall_by_lang(chall, lang):
|
||||||
|
filepath = "ctfs/templates/challenges/"+ lang + "/" + chall.slug + ".html"
|
||||||
|
try:
|
||||||
|
with open(filepath) as fp:
|
||||||
|
return fp.read()
|
||||||
|
except:
|
||||||
|
return chall.description_en
|
|
@ -1,7 +1,15 @@
|
||||||
|
from django.contrib.sitemaps.views import sitemap
|
||||||
from django.urls import path
|
from django.urls import path
|
||||||
|
from .sitemaps import CategorySitemap, CTFSitemap
|
||||||
from . import views
|
from . import views
|
||||||
|
|
||||||
|
sitemaps = {
|
||||||
|
'categories': CategorySitemap(),
|
||||||
|
'challenges': CTFSitemap(),
|
||||||
|
}
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('<str:cat_slug>/', views.category, name='category'),
|
path('<str:cat_slug>/', views.category, name='category'),
|
||||||
path('<str:cat_slug>/<str:ctf_slug>', views.ctf, name='ctf')
|
path('<str:cat_slug>/<str:ctf_slug>', views.ctf, name='ctf'),
|
||||||
|
path('sitemap.xml', sitemap, {'sitemaps': sitemaps}, name='django.contrib.sitemaps.views.sitemap'),
|
||||||
]
|
]
|
||||||
|
|
|
@ -8,26 +8,13 @@ from django.utils.translation import get_language
|
||||||
from math import log
|
from math import log
|
||||||
from accounts.models import UserProfileInfo
|
from accounts.models import UserProfileInfo
|
||||||
|
|
||||||
def get_description_by_lang(ctf):
|
|
||||||
lang = get_language()
|
|
||||||
ret = None
|
|
||||||
if lang == "fr":
|
|
||||||
ret = ctf.description
|
|
||||||
elif lang == "en":
|
|
||||||
ret = ctf.description_en
|
|
||||||
elif lang == "de":
|
|
||||||
ret = ctf.description_de
|
|
||||||
elif lang == "ru":
|
|
||||||
ret = ctf.description_ru
|
|
||||||
return ret
|
|
||||||
|
|
||||||
def actualize_points(ctf):
|
def actualize_points(ctf):
|
||||||
if ctf.category.name == "-Intro-":
|
if ctf.category.name == "-Intro-":
|
||||||
return
|
return
|
||||||
solves = CTF_flags.objects.filter(ctf=ctf)
|
solves = CTF_flags.objects.filter(ctf=ctf)
|
||||||
nb_solves = len(solves)
|
nb_solves = len(solves)
|
||||||
|
|
||||||
new_points = 200 - int(log(nb_solves)*8.5)*5
|
new_points = max(200 - int(log(nb_solves)*8.5)*5, 5)
|
||||||
|
|
||||||
if new_points != ctf.points:
|
if new_points != ctf.points:
|
||||||
diff = ctf.points - new_points
|
diff = ctf.points - new_points
|
||||||
|
@ -50,7 +37,6 @@ def ctf(request, cat_slug, ctf_slug):
|
||||||
ctf_info = get_object_or_404(CTF, slug=ctf_slug, event=None)
|
ctf_info = get_object_or_404(CTF, slug=ctf_slug, event=None)
|
||||||
flagged = False
|
flagged = False
|
||||||
solved_list = CTF_flags.objects.filter(ctf=ctf_info).order_by('flag_date')
|
solved_list = CTF_flags.objects.filter(ctf=ctf_info).order_by('flag_date')
|
||||||
description = get_description_by_lang(ctf_info)
|
|
||||||
if request.user.is_authenticated:
|
if request.user.is_authenticated:
|
||||||
if CTF_flags.objects.filter(user=request.user, ctf=ctf_info):
|
if CTF_flags.objects.filter(user=request.user, ctf=ctf_info):
|
||||||
flagged = True
|
flagged = True
|
||||||
|
@ -66,12 +52,12 @@ def ctf(request, cat_slug, ctf_slug):
|
||||||
profil.score += ctf_info.points
|
profil.score += ctf_info.points
|
||||||
profil.save()
|
profil.save()
|
||||||
actualize_points(ctf_info)
|
actualize_points(ctf_info)
|
||||||
return render(request, 'ctfs/ctf_info.html', { 'ctf' : ctf_info, 'solved_list': solved_list, 'valitated': True, 'description': description, 'date': timezone.now()})
|
return render(request, 'ctfs/ctf_info.html', { 'ctf' : ctf_info, 'solved_list': solved_list, 'valitated': True, 'date': timezone.now()})
|
||||||
else:
|
else:
|
||||||
return render(request, 'ctfs/ctf_info.html', { 'ctf' : ctf_info, 'solved_list': solved_list, 'failed': True, 'description': description, 'date': timezone.now()})
|
return render(request, 'ctfs/ctf_info.html', { 'ctf' : ctf_info, 'solved_list': solved_list, 'failed': True, 'date': timezone.now()})
|
||||||
else:
|
else:
|
||||||
return render(request, 'ctfs/ctf_info.html', { 'ctf' : ctf_info, 'solved_list': solved_list, 'alvalitated': True, 'description': description, 'date': timezone.now()})
|
return render(request, 'ctfs/ctf_info.html', { 'ctf' : ctf_info, 'solved_list': solved_list, 'alvalitated': True, 'date': timezone.now()})
|
||||||
else:
|
else:
|
||||||
return render(request, 'ctfs/ctf_info.html', { 'ctf' : ctf_info, 'solved_list': solved_list, 'description': description, 'date': timezone.now()})
|
return render(request, 'ctfs/ctf_info.html', { 'ctf' : ctf_info, 'solved_list': solved_list, 'date': timezone.now()})
|
||||||
else:
|
else:
|
||||||
return render(request, 'ctfs/ctf_info.html', { 'ctf' : ctf_info, 'solved_list': solved_list, 'alvalitated': flagged, 'description': description, 'date': timezone.now()})
|
return render(request, 'ctfs/ctf_info.html', { 'ctf' : ctf_info, 'solved_list': solved_list, 'alvalitated': flagged, 'date': timezone.now()})
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from .models import Event, EventPlayer, Team
|
from .models import Event, EventPlayer, Team, Bonus
|
||||||
|
|
||||||
@admin.register(Event)
|
@admin.register(Event)
|
||||||
class event(admin.ModelAdmin):
|
class event(admin.ModelAdmin):
|
||||||
|
@ -8,6 +8,27 @@ class event(admin.ModelAdmin):
|
||||||
# search list
|
# search list
|
||||||
search_fields = ['name', 'slug', 'description', 'password']
|
search_fields = ['name', 'slug', 'description', 'password']
|
||||||
|
|
||||||
|
def get_queryset(self, request):
|
||||||
|
qs = super().get_queryset(request)
|
||||||
|
if request.user.is_superuser:
|
||||||
|
return qs
|
||||||
|
groups = list(request.user.groups.values_list('name', flat=True))
|
||||||
|
return qs.filter(name__in=groups)
|
||||||
|
|
||||||
|
def has_view_permission(self, request, obj=None):
|
||||||
|
if request.user.is_superuser:
|
||||||
|
return True
|
||||||
|
if obj is not None:
|
||||||
|
return request.user.groups.filter(name=obj.name).exists()
|
||||||
|
return super().has_view_permission(request, obj)
|
||||||
|
|
||||||
|
def has_change_permission(self, request, obj=None):
|
||||||
|
if request.user.is_superuser:
|
||||||
|
return True
|
||||||
|
if obj is not None:
|
||||||
|
return request.user.groups.filter(name=obj.name).exists()
|
||||||
|
return super().has_change_permission(request, obj)
|
||||||
|
|
||||||
@admin.register(EventPlayer)
|
@admin.register(EventPlayer)
|
||||||
class score(admin.ModelAdmin):
|
class score(admin.ModelAdmin):
|
||||||
#list display
|
#list display
|
||||||
|
@ -17,7 +38,33 @@ class score(admin.ModelAdmin):
|
||||||
# search list
|
# search list
|
||||||
search_fields = ['user__username', 'score', 'event__name']
|
search_fields = ['user__username', 'score', 'event__name']
|
||||||
|
|
||||||
# Register your models here.
|
def get_queryset(self, request):
|
||||||
|
qs = super().get_queryset(request)
|
||||||
|
if request.user.is_superuser:
|
||||||
|
return qs
|
||||||
|
groups = list(request.user.groups.values_list('name', flat=True))
|
||||||
|
return qs.filter(event__name__in=groups)
|
||||||
|
|
||||||
|
def has_view_permission(self, request, obj=None):
|
||||||
|
if request.user.is_superuser:
|
||||||
|
return True
|
||||||
|
if obj is not None:
|
||||||
|
return request.user.groups.filter(name=obj.event.name).exists()
|
||||||
|
return super().has_view_permission(request, obj)
|
||||||
|
|
||||||
|
def has_change_permission(self, request, obj=None):
|
||||||
|
if request.user.is_superuser:
|
||||||
|
return True
|
||||||
|
if obj is not None:
|
||||||
|
return request.user.groups.filter(name=obj.event.name).exists()
|
||||||
|
return super().has_change_permission(request, obj)
|
||||||
|
|
||||||
|
def has_delete_permission(self, request, obj=None):
|
||||||
|
if request.user.is_superuser:
|
||||||
|
return True
|
||||||
|
if obj is not None:
|
||||||
|
return request.user.groups.filter(name=obj.event.name).exists()
|
||||||
|
return super().has_delete_permission(request, obj)
|
||||||
|
|
||||||
@admin.register(Team)
|
@admin.register(Team)
|
||||||
class team(admin.ModelAdmin):
|
class team(admin.ModelAdmin):
|
||||||
|
@ -27,3 +74,36 @@ class team(admin.ModelAdmin):
|
||||||
list_filter = ('event',)
|
list_filter = ('event',)
|
||||||
# search list
|
# search list
|
||||||
search_fields = ['name']
|
search_fields = ['name']
|
||||||
|
|
||||||
|
def get_queryset(self, request):
|
||||||
|
qs = super().get_queryset(request)
|
||||||
|
if request.user.is_superuser:
|
||||||
|
return qs
|
||||||
|
groups = list(request.user.groups.values_list('name', flat=True))
|
||||||
|
return qs.filter(event__name__in=groups)
|
||||||
|
|
||||||
|
def has_view_permission(self, request, obj=None):
|
||||||
|
if request.user.is_superuser:
|
||||||
|
return True
|
||||||
|
if obj is not None:
|
||||||
|
return request.user.groups.filter(name=obj.event.name).exists()
|
||||||
|
return super().has_view_permission(request, obj)
|
||||||
|
|
||||||
|
def has_change_permission(self, request, obj=None):
|
||||||
|
if request.user.is_superuser:
|
||||||
|
return True
|
||||||
|
if obj is not None:
|
||||||
|
return request.user.groups.filter(name=obj.event.name).exists()
|
||||||
|
return super().has_change_permission(request, obj)
|
||||||
|
|
||||||
|
def has_delete_permission(self, request, obj=None):
|
||||||
|
if request.user.is_superuser:
|
||||||
|
return True
|
||||||
|
if obj is not None:
|
||||||
|
return request.user.groups.filter(name=obj.event.name).exists()
|
||||||
|
return super().has_delete_permission(request, obj)
|
||||||
|
|
||||||
|
@admin.register(Bonus)
|
||||||
|
class bonus(admin.ModelAdmin):
|
||||||
|
#list display
|
||||||
|
list_display = ['points', 'absolute']
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 3.1.5 on 2022-02-12 18:27
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('events', '0007_event_auto_match'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='event',
|
||||||
|
name='dynamic',
|
||||||
|
field=models.BooleanField(default=False),
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,23 @@
|
||||||
|
# Generated by Django 3.2.11 on 2022-02-15 16:06
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('events', '0008_event_dynamic'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='eventplayer',
|
||||||
|
name='id',
|
||||||
|
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='team',
|
||||||
|
name='id',
|
||||||
|
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,19 @@
|
||||||
|
# Generated by Django 3.2.11 on 2022-05-30 07:30
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('accounts', '0011_migration_campus'),
|
||||||
|
('events', '0009_auto_20220215_1706'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='event',
|
||||||
|
name='campus',
|
||||||
|
field=models.ManyToManyField(blank=True, to='accounts.Campus'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,28 @@
|
||||||
|
# Generated by Django 3.2.11 on 2023-09-17 17:00
|
||||||
|
|
||||||
|
import django.core.validators
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('events', '0010_event_campus'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Bonus',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('absolute', models.BooleanField(default=True)),
|
||||||
|
('points', models.CharField(max_length=100, validators=[django.core.validators.int_list_validator])),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='event',
|
||||||
|
name='bonus',
|
||||||
|
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='events.bonus'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,24 @@
|
||||||
|
# Generated by Django 3.2.11 on 2023-09-17 18:38
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('events', '0011_bonus_points'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='event',
|
||||||
|
name='bonus',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='events.bonus'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='eventplayer',
|
||||||
|
name='team',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='events.team'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -1,9 +1,17 @@
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.contrib.auth.models import timezone
|
from django.contrib.auth.models import timezone
|
||||||
|
from django.core.validators import int_list_validator
|
||||||
import uuid
|
import uuid
|
||||||
|
from accounts.models import Campus
|
||||||
|
|
||||||
# Create your models here.
|
# Create your models here.
|
||||||
|
class Bonus(models.Model):
|
||||||
|
absolute = models.BooleanField(default=True)
|
||||||
|
points = models.CharField(validators=[int_list_validator], max_length=100)
|
||||||
|
def __str__(self):
|
||||||
|
return self.points
|
||||||
|
|
||||||
class Event(models.Model):
|
class Event(models.Model):
|
||||||
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
|
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
|
||||||
name = models.CharField(max_length=200)
|
name = models.CharField(max_length=200)
|
||||||
|
@ -16,6 +24,9 @@ class Event(models.Model):
|
||||||
slug = models.SlugField(max_length=55)
|
slug = models.SlugField(max_length=55)
|
||||||
team_size = models.PositiveIntegerField(default=1)
|
team_size = models.PositiveIntegerField(default=1)
|
||||||
auto_match = models.BooleanField(default=False)
|
auto_match = models.BooleanField(default=False)
|
||||||
|
dynamic = models.BooleanField(default=False)
|
||||||
|
campus = models.ManyToManyField(Campus, blank=True)
|
||||||
|
bonus = models.ForeignKey(Bonus, null=True, on_delete=models.SET_NULL, blank=True)
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
@ -34,8 +45,6 @@ class EventPlayer(models.Model):
|
||||||
event = models.ForeignKey(Event, on_delete=models.CASCADE)
|
event = models.ForeignKey(Event, on_delete=models.CASCADE)
|
||||||
score = models.PositiveIntegerField(default=0, db_index=True)
|
score = models.PositiveIntegerField(default=0, db_index=True)
|
||||||
last_submission_date = models.DateTimeField('Last Submission Date', default=timezone.now)
|
last_submission_date = models.DateTimeField('Last Submission Date', default=timezone.now)
|
||||||
team = models.ForeignKey(Team, on_delete=models.CASCADE, null=True)
|
team = models.ForeignKey(Team, on_delete=models.CASCADE, null=True, blank=True)
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ['-score', 'last_submission_date', 'user__username']
|
ordering = ['-score', 'last_submission_date', 'user__username']
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
from django.contrib import sitemaps
|
||||||
|
from django.urls import reverse
|
||||||
|
from .models import Event
|
||||||
|
|
||||||
|
class EventsSitemap(sitemaps.Sitemap):
|
||||||
|
changefreq = "daily"
|
||||||
|
priority = 0.7
|
||||||
|
i18n = True
|
||||||
|
|
||||||
|
def items(self):
|
||||||
|
return Event.objects.all()
|
||||||
|
|
||||||
|
def location(self, obj):
|
||||||
|
return reverse('events:event_info', kwargs={'event_slug': obj.slug})
|
||||||
|
|
||||||
|
class StaticViewSitemap(sitemaps.Sitemap):
|
||||||
|
priority = 0.7
|
||||||
|
changefreq = 'daily'
|
||||||
|
i18n = True
|
||||||
|
def items(self):
|
||||||
|
return ['events:events']
|
||||||
|
|
||||||
|
def location(self, item):
|
||||||
|
return reverse(item)
|
|
@ -4,6 +4,7 @@
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-12 col-md-9">
|
<div class="col-sm-12 col-md-9">
|
||||||
<div class="ctf-block">
|
<div class="ctf-block">
|
||||||
|
<a href="{% url 'events:event_info' event_slug=event.slug %}">< Back to event</a>
|
||||||
<div class="ctf-head">
|
<div class="ctf-head">
|
||||||
<h3>{{ event.name }}</h3>
|
<h3>{{ event.name }}</h3>
|
||||||
<small>{% trans "This event starts at" %} : {{ event.start_date }}</small>
|
<small>{% trans "This event starts at" %} : {{ event.start_date }}</small>
|
||||||
|
@ -11,26 +12,29 @@
|
||||||
|
|
||||||
<div class="ctf-footer">
|
<div class="ctf-footer">
|
||||||
<div class="col-sm-8 col-md-6 mx-auto">
|
<div class="col-sm-8 col-md-6 mx-auto">
|
||||||
{% if logged == True%}
|
{% if logged == True%}
|
||||||
{% if registered == False %}
|
{% if registered == False %}
|
||||||
<span class="message error-msg">{% trans "You need to be registered to the event." %}</span>
|
<span class="message error-msg">{% trans "You need to be registered to the event." %}</span>
|
||||||
{% else %}
|
{% else %}
|
||||||
{% if exist == True %}
|
{% if invalid == True %}
|
||||||
<span class="message error-msg">{% trans "Name already taken." %}</span>
|
<span class="message error-msg">{% trans "Invalid characters in name" %}</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% if exist == True %}
|
||||||
|
<span class="message error-msg">{% trans "Name already taken." %}</span>
|
||||||
|
{% endif %}
|
||||||
<h2>Create Team</h2>
|
<h2>Create Team</h2>
|
||||||
<form method="post" action="{% url 'events:create_team' event_slug=event.slug %}" class="create-team-form">
|
<form method="post" action="{% url 'events:create_team' event_slug=event.slug %}" class="create-team-form">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<input class="form-control" type="text" name="teamname" placeholder="{% trans "Team name" %} *" maxlength="150" required="" id="id_teamname"></br>
|
<input class="form-control" type="text" name="teamname" placeholder="{% trans "Team name" %} *" maxlength="150" required="" id="id_teamname"></br>
|
||||||
<input class="form-control" type="password" name="password" placeholder="{% trans "Password" %} *" required="" id="id_password"></br>
|
<input class="form-control" type="password" name="password" placeholder="{% trans "Password" %} *" required="" id="id_password"></br>
|
||||||
<input type="submit" name="" class="form-control" value="{% trans "Create Team" %}">
|
<input type="submit" name="" class="form-control" value="{% trans "Create Team" %}">
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% else %}
|
{% else %}
|
||||||
<h4>{% trans "You need to be logged to access this event." %}</h4>
|
<h4>{% trans "You need to be logged to access this event." %}</h4>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -38,24 +42,26 @@
|
||||||
<div class="d-none d-md-block col-10 col-md-3 right-sidebar">
|
<div class="d-none d-md-block col-10 col-md-3 right-sidebar">
|
||||||
<ul class="list-group">
|
<ul class="list-group">
|
||||||
<li class="list-group-item">{{ event.name }}</li>
|
<li class="list-group-item">{{ event.name }}</li>
|
||||||
<li class="list-group-item">{% trans "Starts at" %} : {{ event.start_date | date:'H:i d-m-y'}}</li>
|
<li class="list-group-item">{% trans "Starts at" %} : <span style="position:absolute;right: 15px;">{{ event.start_date | date:'H:i d-m-y'}}</span></li>
|
||||||
<li class="list-group-item">{% trans "Ends at" %} : {{ event.end_date | date:'H:i d-m-y'}}</li>
|
<li class="list-group-item">{% trans "Ends at" %} : <span style="position:absolute;right: 15px;">{{ event.end_date | date:'H:i d-m-y'}}</span></li>
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
<ul class="list-group">
|
<ul class="list-group">
|
||||||
|
<li class="list-group-item">{% trans "Manage my team" %}</li>
|
||||||
|
<a href="{% url 'events:join_team' event_slug=event.slug %}" class="list-group-item">→{% trans "Join Team" %}</a>
|
||||||
<a href="{% url 'events:create_team' event_slug=event.slug %}" class="list-group-item">{% trans "Create Team" %}</a>
|
<a href="{% url 'events:create_team' event_slug=event.slug %}" class="list-group-item">{% trans "Create Team" %}</a>
|
||||||
<a href="{% url 'events:join_team' event_slug=event.slug %}" class="list-group-item">{% trans "Join Team" %}</a>
|
</ul>
|
||||||
</ul>
|
{% if event.auto_match %}
|
||||||
{% if event.auto_match %}
|
<ul class="list-group">
|
||||||
<ul class="list-group">
|
<li class="list-group-item">{% trans "Auto-matching" %}</li>
|
||||||
<form method='GET' action="{% url 'events:find_team' event_slug=event.slug %}">
|
<form method='GET' action="{% url 'events:find_team' event_slug=event.slug %}">
|
||||||
{%csrf_token%}
|
{%csrf_token%}
|
||||||
<li class="list-group-item">
|
<li class="list-group-item">
|
||||||
<input class="form-control" type="submit" value="{% trans "Find me a team !" %}">
|
<input class="form-control" type="submit" value="{% trans "Find me a team !" %}">
|
||||||
</li>
|
</li>
|
||||||
</form>
|
</form>
|
||||||
</ul>
|
</ul>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
|
@ -7,7 +7,7 @@
|
||||||
<div class="ctf-block">
|
<div class="ctf-block">
|
||||||
<a href="{% url 'events:event_info' event_slug=event.slug %}">< Back to event</a>
|
<a href="{% url 'events:event_info' event_slug=event.slug %}">< Back to event</a>
|
||||||
<div class="ctf-head">
|
<div class="ctf-head">
|
||||||
<h2>{% trans "Event" %} - {{ event.name }}</h2>
|
<h1>{% trans "Event" %} - {{ event.name }}</h1>
|
||||||
<h4>{{ ctf.name }}</h4>
|
<h4>{{ ctf.name }}</h4>
|
||||||
<small>{% trans "Published date" %} : {{ ctf.pub_date }}</small>
|
<small>{% trans "Published date" %} : {{ ctf.pub_date }}</small>
|
||||||
</div>
|
</div>
|
||||||
|
@ -20,16 +20,11 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="ctf-footer">
|
<div class="ctf-footer">
|
||||||
{% if request.user.is_authenticated %}
|
{% if request.user.is_authenticated %}
|
||||||
|
|
||||||
{% if subisover == True %}
|
|
||||||
<span class="message error-msg">{% trans "Subscriptions is over." %}</span>
|
|
||||||
{% endif %}
|
|
||||||
{% if alreadyregistered == True %}
|
|
||||||
<span class="message error-msg">{% trans "You're already registered to this event." %}</span>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if congrat == True %}
|
{% if congrat == True %}
|
||||||
<p>{% trans "Congratulation !" %}</p>
|
<p>{% trans "Congratulation !" %}</p>
|
||||||
|
{% if bonus|add:"0" > 0 %}
|
||||||
|
<p>{% trans "Bonus points awarded" %} : {{ bonus }}</p>
|
||||||
|
{% endif %}
|
||||||
{% elif alreadyflag == True %}
|
{% elif alreadyflag == True %}
|
||||||
<p>{% trans "Already flagged" %}</p>
|
<p>{% trans "Already flagged" %}</p>
|
||||||
{% elif eventisover == True %}
|
{% elif eventisover == True %}
|
||||||
|
@ -37,7 +32,9 @@
|
||||||
{% elif errorform == True %}
|
{% elif errorform == True %}
|
||||||
<p>{% trans "Error while processing your request. (Invalid Form)" %}</p>
|
<p>{% trans "Error while processing your request. (Invalid Form)" %}</p>
|
||||||
{% elif notsub == True %}
|
{% elif notsub == True %}
|
||||||
<span class="message error-msg">{% trans "Error: you're not registered to this event, so you can't register scores, fucking logic." %}</span>
|
<span class="message error-msg">{% trans "You must register to the event before submitting flags." %}</span>
|
||||||
|
{% elif noteam == True %}
|
||||||
|
<span class="message error-msg">{% trans "This is a team event, please create or join a team before submitting flags." %}</span>
|
||||||
{% if ctf.ctf_url %}
|
{% if ctf.ctf_url %}
|
||||||
<a class="begin-ctf-link" target="_blank" href="{{ ctf.ctf_url }}">{% trans "Start the challenge" %}</a></br>
|
<a class="begin-ctf-link" target="_blank" href="{{ ctf.ctf_url }}">{% trans "Start the challenge" %}</a></br>
|
||||||
{% elif ctf.file %}
|
{% elif ctf.file %}
|
||||||
|
@ -102,6 +99,9 @@
|
||||||
<ul class="list-group">
|
<ul class="list-group">
|
||||||
<li class="list-group-item">{% trans "Author" %} : <a style="position:absolute;right: 15px;" class="profile_link {{is_member}}" href="{% url 'accounts:profile' user_name=ctf.author.username %}">{{ ctf.author.username }}</a></li>
|
<li class="list-group-item">{% trans "Author" %} : <a style="position:absolute;right: 15px;" class="profile_link {{is_member}}" href="{% url 'accounts:profile' user_name=ctf.author.username %}">{{ ctf.author.username }}</a></li>
|
||||||
<li class="list-group-item">{% trans "Point reward" %} : <span style="position:absolute;right: 15px;">{{ ctf.points }}</span></li>
|
<li class="list-group-item">{% trans "Point reward" %} : <span style="position:absolute;right: 15px;">{{ ctf.points }}</span></li>
|
||||||
|
{% if ctf.event.bonus %}
|
||||||
|
<li class="list-group-item">{% trans "Speed Bonuses" %} : <span style="position:absolute;right: 15px;">{{ bonus_points }}</span></li>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<div class="event-block">
|
<div class="event-block">
|
||||||
<div class="event-head" style="background-image:linear-gradient(180deg, rgba(102,102,102,0.3) 100%, rgba(29,29,29,1) 100%),url('{{ event.img }}');">
|
<div class="event-head" style="background-image:linear-gradient(180deg, rgba(102,102,102,0.3) 100%, rgba(29,29,29,1) 100%),url('{{ event.img }}');">
|
||||||
<h3>{{ event.name }}</h3>
|
<h1>{{ event.name }}</h1>
|
||||||
{% if ended == True %}
|
{% if ended == True %}
|
||||||
<small>{% trans "This event is over." %}</small>
|
<small>{% trans "This event is over." %}</small>
|
||||||
{% else %}
|
{% else %}
|
||||||
|
@ -26,7 +26,7 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<div class="event-footer">
|
<div class="event-footer">
|
||||||
{% if begun == True %}
|
{% if begun == True or is_event_manager == True %}
|
||||||
<h4>{% trans "Challenges" %}</h4>
|
<h4>{% trans "Challenges" %}</h4>
|
||||||
|
|
||||||
{% if ctfs %}
|
{% if ctfs %}
|
||||||
|
|
|
@ -11,19 +11,35 @@
|
||||||
|
|
||||||
<div class="ctf-footer">
|
<div class="ctf-footer">
|
||||||
{% if logged == True %}
|
{% if logged == True %}
|
||||||
{% if wrongpwd == True %}
|
{% if userHasCampus == False %}
|
||||||
<span class="message error-msg">{% trans "Wrong password submited." %}</span>
|
<span class="message error-msg">
|
||||||
|
{% trans "This event is reserved for one or more 42 campuses. If you have not connected your intranet to 42CTF, you can do so with this button: " %}
|
||||||
|
<form action="{% url 'accounts:connections-connect-intra42' %}" method='POST' class="form-inline p-2">
|
||||||
|
{%csrf_token%}
|
||||||
|
<button class="btn btn-dark" type="submit">{% trans "Connect 42" %}</button>
|
||||||
|
</form>
|
||||||
|
</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if alreadyregistered == True %}
|
{% if campusCanJoin == False %}
|
||||||
<span class="message error-msg">{% trans "You're already registered to this event." %}</span>
|
<span class="message error-msg">
|
||||||
|
{% trans "This event is reserved for one or more 42 campuses. And unfortunately your campus can't participate. Do not hesitate to contact us to organize an event on your campus!" %}
|
||||||
|
</span>
|
||||||
|
{% endif %}
|
||||||
|
{% if userHasCampus == True and campusCanJoin == True %}
|
||||||
|
{% if wrongpwd == True %}
|
||||||
|
<span class="message error-msg">{% trans "Wrong password submited." %}</span>
|
||||||
|
{% endif %}
|
||||||
|
{% if alreadyregistered == True %}
|
||||||
|
<span class="message error-msg">{% trans "You're already registered to this event." %}</span>
|
||||||
|
{% endif %}
|
||||||
|
<h4>{% trans "This event is password protected" %}</h4>
|
||||||
|
<small>{% trans "You need to submit the event password to gain access to this event." %}</small>
|
||||||
|
<form method="post" action="{% url 'events:submit_pwd' event_slug=event.slug %}" class="submitflag-form">
|
||||||
|
{% csrf_token %}
|
||||||
|
<input type="text" name="password" maxlength="48" required="">
|
||||||
|
<input class="form-control" type="submit" value=">">
|
||||||
|
</form>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<h4>{% trans "This event is password protected" %}</h4>
|
|
||||||
<small>{% trans "You need to submit the event password to gain access to this event." %}</small>
|
|
||||||
<form method="post" action="{% url 'events:submit_pwd' event_slug=event.slug %}" class="submitflag-form">
|
|
||||||
{% csrf_token %}
|
|
||||||
<input type="text" name="password" maxlength="48" required="">
|
|
||||||
<input class="form-control" type="submit" value=">">
|
|
||||||
</form>
|
|
||||||
{% else %}
|
{% else %}
|
||||||
<h4>{% trans "You need to be logged to access this event." %}</h4>
|
<h4>{% trans "You need to be logged to access this event." %}</h4>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
{% block content %}
|
{% block content %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12">
|
<div class="col-12 ctf-head">
|
||||||
<h3>{% trans "Events" %}</h3>
|
<h1>{% trans "Events" %}</h1>
|
||||||
</div>
|
</div>
|
||||||
{% if events %}
|
{% if events %}
|
||||||
{% for ev in events %}
|
{% for ev in events %}
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-12 col-md-9">
|
<div class="col-sm-12 col-md-9">
|
||||||
<div class="ctf-block">
|
<div class="ctf-block">
|
||||||
|
<a href="{% url 'events:event_info' event_slug=event.slug %}">< Back to event</a>
|
||||||
<div class="ctf-head">
|
<div class="ctf-head">
|
||||||
<h3>{{ event.name }}</h3>
|
<h3>{{ event.name }}</h3>
|
||||||
<small>{% trans "This event starts at" %} : {{ event.start_date }}</small>
|
<small>{% trans "This event starts at" %} : {{ event.start_date }}</small>
|
||||||
|
@ -11,18 +12,18 @@
|
||||||
|
|
||||||
<div class="ctf-footer">
|
<div class="ctf-footer">
|
||||||
<div class="col-sm-8 col-md-6 mx-auto">
|
<div class="col-sm-8 col-md-6 mx-auto">
|
||||||
{% if logged == True%}
|
{% if logged == True%}
|
||||||
{% if registered == False %}
|
{% if registered == False %}
|
||||||
<span class="message error-msg">{% trans "You need to be registered to the event." %}</span>
|
<span class="message error-msg">{% trans "You need to be registered to the event." %}</span>
|
||||||
{% else %}
|
{% else %}
|
||||||
{% if notexist == True %}
|
{% if notexist == True %}
|
||||||
<span class="message error-msg">{% trans "Team does not exist." %}</span>
|
<span class="message error-msg">{% trans "Team does not exist." %}</span>
|
||||||
{% elif wrongpwd == True %}
|
{% elif wrongpwd == True %}
|
||||||
<span class="message error-msg">{% trans "Wrong password submited." %}</span>
|
<span class="message error-msg">{% trans "Wrong password submited." %}</span>
|
||||||
{% elif max == True %}
|
{% elif max == True %}
|
||||||
<span class="message error-msg">{% trans "Maximum size reached." %}</span>
|
<span class="message error-msg">{% trans "Maximum size reached." %}</span>
|
||||||
{% elif exist == True %}
|
{% elif exist == True %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<h2>Join Team</h2>
|
<h2>Join Team</h2>
|
||||||
<form method="post" action="{% url 'events:join_team' event_slug=event.slug %}" class="join-team-form">
|
<form method="post" action="{% url 'events:join_team' event_slug=event.slug %}" class="join-team-form">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
|
@ -31,11 +32,11 @@
|
||||||
<input class="form-control" type="password" name="password" placeholder="{% trans "Password" %} *" required="" id="id_password"></br>
|
<input class="form-control" type="password" name="password" placeholder="{% trans "Password" %} *" required="" id="id_password"></br>
|
||||||
<input type="submit" name="" class="form-control" value="{% trans "Join Team" %}">
|
<input type="submit" name="" class="form-control" value="{% trans "Join Team" %}">
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% else %}
|
{% else %}
|
||||||
<h4>{% trans "You need to be logged to access this event." %}</h4>
|
<h4>{% trans "You need to be logged to access this event." %}</h4>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -43,24 +44,26 @@
|
||||||
<div class="d-none d-md-block col-10 col-md-3 right-sidebar">
|
<div class="d-none d-md-block col-10 col-md-3 right-sidebar">
|
||||||
<ul class="list-group">
|
<ul class="list-group">
|
||||||
<li class="list-group-item">{{ event.name }}</li>
|
<li class="list-group-item">{{ event.name }}</li>
|
||||||
<li class="list-group-item">{% trans "Starts at" %} : {{ event.start_date | date:'H:i d-m-y' }}</li>
|
<li class="list-group-item">{% trans "Starts at" %} : <span style="position:absolute;right: 15px;">{{ event.start_date | date:'H:i d-m-y'}}</span></li>
|
||||||
<li class="list-group-item">{% trans "Ends at" %} : {{ event.end_date | date:'H:i d-m-y' }}</li>
|
<li class="list-group-item">{% trans "Ends at" %} : <span style="position:absolute;right: 15px;">{{ event.end_date | date:'H:i d-m-y'}}</span></li>
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
<ul class="list-group">
|
<ul class="list-group">
|
||||||
|
<li class="list-group-item">{% trans "Manage my team" %}</li>
|
||||||
<a href="{% url 'events:join_team' event_slug=event.slug %}" class="list-group-item">{% trans "Join Team" %}</a>
|
<a href="{% url 'events:join_team' event_slug=event.slug %}" class="list-group-item">{% trans "Join Team" %}</a>
|
||||||
<a href="{% url 'events:create_team' event_slug=event.slug %}" class="list-group-item">{% trans "Create Team" %}</a>
|
<a href="{% url 'events:create_team' event_slug=event.slug %}" class="list-group-item">{% trans "Create Team" %}</a>
|
||||||
</ul>
|
</ul>
|
||||||
{% if event.auto_match %}
|
{% if event.auto_match %}
|
||||||
<ul class="list-group">
|
<ul class="list-group">
|
||||||
<form method='GET' action="{% url 'events:find_team' event_slug=event.slug %}">
|
<li class="list-group-item">{% trans "Auto-matching" %}</li>
|
||||||
{%csrf_token%}
|
<form method='GET' action="{% url 'events:find_team' event_slug=event.slug %}">
|
||||||
<li class="list-group-item">
|
{%csrf_token%}
|
||||||
<input class="form-control" type="submit" value="{% trans "Find me a team !" %}">
|
<li class="list-group-item">
|
||||||
</li>
|
<input class="form-control" type="submit" value="{% trans "Find me a team !" %}">
|
||||||
</form>
|
</li>
|
||||||
</ul>
|
</form>
|
||||||
{% endif %}
|
</ul>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
|
@ -45,14 +45,28 @@
|
||||||
{% for p in members %}
|
{% for p in members %}
|
||||||
<li class="list-group-item"><a class="profile_link" href="{% url 'accounts:profile' user_name=p.user.username %}">{{ p.user.username }}</a></li>
|
<li class="list-group-item"><a class="profile_link" href="{% url 'accounts:profile' user_name=p.user.username %}">{{ p.user.username }}</a></li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
<form method='POST' action="{% url 'events:leave_team' event_slug=player.event.slug %}">
|
</ul>
|
||||||
|
<form method='POST' action="{% url 'events:leave_team' event_slug=player.event.slug %}">
|
||||||
|
{%csrf_token%}
|
||||||
|
<li class="list-group-item">
|
||||||
|
<input class="form-control" type="submit" value="{% trans "Leave Team" %}">
|
||||||
|
</li>
|
||||||
|
</form>
|
||||||
|
{% if player.team.auto == False and player.event.auto_match == True %}
|
||||||
|
<form method='POST' action="{% url 'events:open_team' event_slug=player.event.slug %}">
|
||||||
{%csrf_token%}
|
{%csrf_token%}
|
||||||
<li class="list-group-item">
|
<li class="list-group-item">
|
||||||
<input class="form-control" type="submit" value="{% trans "Leave Team" %}">
|
<input class="form-control" type="submit" value="{% trans "Open to automatching" %}">
|
||||||
</li>
|
</li>
|
||||||
</form>
|
</form>
|
||||||
|
{% elif player.event.auto_match == True %}
|
||||||
</ul>
|
<form method='POST' action="{% url 'events:close_team' event_slug=player.event.slug %}">
|
||||||
|
{%csrf_token%}
|
||||||
|
<li class="list-group-item">
|
||||||
|
<input class="form-control" type="submit" value="{% trans "Close to automatching" %}">
|
||||||
|
</li>
|
||||||
|
</form>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -0,0 +1,168 @@
|
||||||
|
{% extends 'base.html' %}
|
||||||
|
{% block content %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% load key_value %}
|
||||||
|
{% load is_member %}
|
||||||
|
{% ismember user.userprofileinfo as is_member %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-12 col-md-9">
|
||||||
|
<a href="{% url 'events:event_info' event_slug=event.slug %}">< Back to event</a>
|
||||||
|
<div>
|
||||||
|
<h4>{% trans "Challenges Solved by" %} <span class="{{ is_member }}">{{ user.username }} - {{ event.name }}</span></h4>
|
||||||
|
{% if solves%}
|
||||||
|
|
||||||
|
<div class="table table-dark">
|
||||||
|
<div class="card-body">
|
||||||
|
<div id="time-chart"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<table class="table table-dark">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th scope="col">{% trans "Challenge Name" %}</th>
|
||||||
|
<th scope="col">{% trans "Category" %}</th>
|
||||||
|
<th scope="col">{% trans "Points" %}</th>
|
||||||
|
<th scope="col">{% trans "Bonus" %}</th>
|
||||||
|
<th scope="col">{% trans "Date" %}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for s in solves %}
|
||||||
|
<tr>
|
||||||
|
<th scope="row"><a href="{% url 'events:event_chall_info' event_slug=event.slug chall_slug=s.ctf.slug %}">{{ s.ctf.name }}</a></th>
|
||||||
|
<td>{{ s.ctf.category.name}}</td>
|
||||||
|
<td>{{ s.ctf.points }}</td>
|
||||||
|
<td>{{ s.bonus }}</td>
|
||||||
|
<td>{{ s.flag_date|date:"Y-m-d H:i:s" }}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{% else %}
|
||||||
|
<p>{% trans "It seems that this user has not solved any challenge yet..." %}</p>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="d-none d-md-block col-10 col-md-3 right-sidebar">
|
||||||
|
<ul class="list-group">
|
||||||
|
<li class="list-group-item {{ is_member }}">{{ user.username }}</li>
|
||||||
|
<li class="list-group-item">{% trans "Score" %} : {{ score }}</li>
|
||||||
|
<li class="list-group-item">{% trans "Rank" %} : {{ rank }}</li>
|
||||||
|
{% if user.userprofileinfo.portfolio_site %}
|
||||||
|
<li class="list-group-item">
|
||||||
|
<a href="{{ user.userprofileinfo.portfolio_site }}" target="_blank">
|
||||||
|
{{ user.userprofileinfo.portfolio_site }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
{% if member %}
|
||||||
|
<li class="list-group-item is-member">{% trans "Status: Member" %}</li>
|
||||||
|
{% else %}
|
||||||
|
<li class="list-group-item">{% trans "Status: Visitor" %}</li>
|
||||||
|
{% endif %}
|
||||||
|
<li class="list-group-item">{% trans "Registered since" %} {{ user.date_joined|date:"d-m-Y" }}</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<ul class="list-group">
|
||||||
|
<li class="list-group-item">{% trans "Categories stats" %}</li>
|
||||||
|
{% for cat in catsDatas %}
|
||||||
|
<li class="list-group-item" style="padding-bottom: 3;padding-top: 0;">
|
||||||
|
<span>{{ cat.0 }}</span>
|
||||||
|
<div class="progress">
|
||||||
|
{% if cat.3 == '0' %}
|
||||||
|
<div class="progress-bar bg-success" role="progressbar" style="width: 0%;color:#d9d9d9;" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100">0 %</div>
|
||||||
|
{% else %}
|
||||||
|
<div class="progress-bar bg-success" role="progressbar" style="width: {{ cat.3 }}%" aria-valuenow="{{ cat.3 }}" aria-valuemin="0" aria-valuemax="100">{{ cat.3 }} %</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<ul class="list-group">
|
||||||
|
<ul class="list-group">
|
||||||
|
<li class="list-group-item">{% trans "Challenges created" %}</li>
|
||||||
|
{% if created %}
|
||||||
|
{% for creat in created %}
|
||||||
|
<li class="list-group-item"><a href="{% url 'ctf' cat_slug=creat.category.slug ctf_slug=creat.slug %}">{{ creat.name }}</a></li>
|
||||||
|
{% endfor %}
|
||||||
|
{% else %}
|
||||||
|
<li class="list-group-item">{% trans "It seems that this user has not created any challenge yet..." %}</li>
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="https://code.highcharts.com/highcharts.src.js"></script>
|
||||||
|
<script>
|
||||||
|
Highcharts.theme={colors:["#2b908f","#90ee7e","#f45b5b","#7798BF","#aaeeee","#ff0066","#eeaaee","#55BF3B","#DF5353","#7798BF","#aaeeee"],chart:{backgroundColor:{linearGradient:{x1:0,y1:0,x2:1,y2:1},stops:[[0,"#1D1D1D"],[1,"#1D1D1D"]]},style:{fontFamily:"'Unica One', sans-serif"},plotBorderColor:"#606063"},title:{style:{color:"#E0E0E3",textTransform:"uppercase",fontSize:"20px"}},subtitle:{style:{color:"#E0E0E3",textTransform:"uppercase"}},xAxis:{gridLineColor:"#707073",labels:{style:{color:"#E0E0E3"}},lineColor:"#707073",minorGridLineColor:"#505053",tickColor:"#707073",title:{style:{color:"#A0A0A3"}}},yAxis:{gridLineColor:"#707073",labels:{style:{color:"#E0E0E3"}},lineColor:"#707073",minorGridLineColor:"#505053",tickColor:"#707073",tickWidth:1,title:{style:{color:"#A0A0A3"}}},tooltip:{backgroundColor:"rgba(0, 0, 0, 0.85)",style:{color:"#F0F0F0"}},plotOptions:{series:{dataLabels:{color:"#F0F0F3",style:{fontSize:"13px"}},marker:{lineColor:"#333"}},boxplot:{fillColor:"#505053"},candlestick:{lineColor:"white"},errorbar:{color:"white"}},legend:{backgroundColor:"#1D1D1D",itemStyle:{color:"#E0E0E3"},itemHoverStyle:{color:"#FFF"},itemHiddenStyle:{color:"#606063"},title:{style:{color:"#C0C0C0"}}},credits:{style:{color:"#666"}},labels:{style:{color:"#707073"}},drilldown:{activeAxisLabelStyle:{color:"#F0F0F3"},activeDataLabelStyle:{color:"#F0F0F3"}},navigation:{buttonOptions:{symbolStroke:"#DDDDDD",theme:{fill:"#505053"}}},rangeSelector:{buttonTheme:{fill:"#505053",stroke:"#000000",style:{color:"#CCC"},states:{hover:{fill:"#707073",stroke:"#000000",style:{color:"white"}},select:{fill:"#000003",stroke:"#000000",style:{color:"white"}}}},inputBoxBorderColor:"#505053",inputStyle:{backgroundColor:"#333",color:"silver"},labelStyle:{color:"silver"}},navigator:{handles:{backgroundColor:"#666",borderColor:"#AAA"},outlineColor:"#CCC",maskFill:"rgba(255,255,255,0.1)",series:{color:"#7798BF",lineColor:"#A6C7ED"},xAxis:{gridLineColor:"#505053"}},scrollbar:{barBackgroundColor:"#808083",barBorderColor:"#808083",buttonArrowColor:"#CCC",buttonBackgroundColor:"#606063",buttonBorderColor:"#606063",rifleColor:"#FFF",trackBackgroundColor:"#404043",trackBorderColor:"#404043"}};
|
||||||
|
|
||||||
|
Highcharts.setOptions(Highcharts.theme);
|
||||||
|
|
||||||
|
Highcharts.chart('time-chart', {
|
||||||
|
title: {
|
||||||
|
text: 'Points earned for each category'
|
||||||
|
},
|
||||||
|
yAxis: {
|
||||||
|
title: {
|
||||||
|
text: 'Points earned'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
type: 'datetime',
|
||||||
|
labels: {
|
||||||
|
formatter: function() {
|
||||||
|
return Highcharts.dateFormat('%d.%b %Y',
|
||||||
|
this.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
layout: 'vertical',
|
||||||
|
align: 'right',
|
||||||
|
verticalAlign: 'middle'
|
||||||
|
},
|
||||||
|
plotOptions: {
|
||||||
|
pointStart: {{ user.date_joined|timestamp_fromdate }},
|
||||||
|
series: {
|
||||||
|
label: {
|
||||||
|
connectorAllowed: false
|
||||||
|
},
|
||||||
|
allowPointSelect: true,
|
||||||
|
marker: {
|
||||||
|
enabled: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: 'Total',
|
||||||
|
data: {{ solved|safe }}
|
||||||
|
},
|
||||||
|
{% for cat in cats %}
|
||||||
|
{
|
||||||
|
name: '{{ cat.name }}',
|
||||||
|
data: {{ pointDatas|keyvalue:cat.name|safe }},
|
||||||
|
visible: false,
|
||||||
|
},
|
||||||
|
{% endfor %}
|
||||||
|
],
|
||||||
|
responsive: {
|
||||||
|
rules: [{
|
||||||
|
condition: {
|
||||||
|
maxWidth: 500
|
||||||
|
},
|
||||||
|
chartOptions: {
|
||||||
|
legend: {
|
||||||
|
layout: 'horizontal',
|
||||||
|
align: 'center',
|
||||||
|
verticalAlign: 'bottom'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
||||||
|
|
|
@ -1,10 +1,18 @@
|
||||||
|
from django.contrib.sitemaps.views import sitemap
|
||||||
from django.urls import path
|
from django.urls import path
|
||||||
|
from .sitemaps import StaticViewSitemap, EventsSitemap
|
||||||
from . import views
|
from . import views
|
||||||
|
|
||||||
app_name = "events"
|
app_name = "events"
|
||||||
|
|
||||||
|
sitemaps = {
|
||||||
|
'events': EventsSitemap(),
|
||||||
|
'static': StaticViewSitemap(),
|
||||||
|
}
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('', views.events, name='events'),
|
path('', views.events, name='events'),
|
||||||
|
path('sitemap.xml', sitemap, {'sitemaps': sitemaps}, name='django.contrib.sitemaps.views.sitemap'),
|
||||||
path('<str:event_slug>', views.event, name='event_info'),
|
path('<str:event_slug>', views.event, name='event_info'),
|
||||||
path('<str:event_slug>/challenge/<str:chall_slug>', views.chall_event_info, name='event_chall_info'),
|
path('<str:event_slug>/challenge/<str:chall_slug>', views.chall_event_info, name='event_chall_info'),
|
||||||
path('pwd/<str:event_slug>', views.submit_pwd, name='submit_pwd'),
|
path('pwd/<str:event_slug>', views.submit_pwd, name='submit_pwd'),
|
||||||
|
@ -17,4 +25,6 @@ urlpatterns = [
|
||||||
path('<str:event_slug>/manage_team', views.manage_team, name='manage_team'),
|
path('<str:event_slug>/manage_team', views.manage_team, name='manage_team'),
|
||||||
path('<str:event_slug>/leave_team', views.leave_team, name='leave_team'),
|
path('<str:event_slug>/leave_team', views.leave_team, name='leave_team'),
|
||||||
path('find_team/<str:event_slug>', views.find_team, name='find_team'),
|
path('find_team/<str:event_slug>', views.find_team, name='find_team'),
|
||||||
|
path('<str:event_slug>/open_team', views.open_team, name='open_team'),
|
||||||
|
path('<str:event_slug>/close_team', views.close_team, name='close_team'),
|
||||||
]
|
]
|
||||||
|
|
|
@ -4,9 +4,11 @@ from django.contrib.auth.models import timezone
|
||||||
from ..forms import submit_flag
|
from ..forms import submit_flag
|
||||||
from ..models import Event, EventPlayer, Team
|
from ..models import Event, EventPlayer, Team
|
||||||
from ctfs.models import CTF, CTF_flags, Category
|
from ctfs.models import CTF, CTF_flags, Category
|
||||||
|
from accounts.models import UserProfileInfo
|
||||||
from django.utils.translation import get_language
|
from django.utils.translation import get_language
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
from math import log
|
||||||
|
|
||||||
def get_description_by_lang(ctf):
|
def get_description_by_lang(ctf):
|
||||||
lang = get_language()
|
lang = get_language()
|
||||||
|
@ -21,6 +23,49 @@ def get_description_by_lang(ctf):
|
||||||
ret = ctf.description_ru
|
ret = ctf.description_ru
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
def actualize_points(ctf):
|
||||||
|
solves = CTF_flags.objects.filter(ctf=ctf)
|
||||||
|
nb_solves = len(solves)
|
||||||
|
|
||||||
|
new_points = max(50 - int(log(nb_solves)*2.5)*5, 5)
|
||||||
|
|
||||||
|
if new_points != ctf.points:
|
||||||
|
diff = ctf.points - new_points
|
||||||
|
ctf.points = new_points
|
||||||
|
ctf.save()
|
||||||
|
for s in solves:
|
||||||
|
player = EventPlayer.objects.get(event=ctf.event, user=s.user)
|
||||||
|
player.score -= diff
|
||||||
|
player.save()
|
||||||
|
if player.team:
|
||||||
|
player.team.score -= diff
|
||||||
|
player.team.save()
|
||||||
|
|
||||||
|
def compute_bonus_points(ctf):
|
||||||
|
if not ctf.event.bonus:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
solves = CTF_flags.objects.filter(ctf=ctf)
|
||||||
|
bonuses = ctf.event.bonus.points.split(',')
|
||||||
|
|
||||||
|
if len(solves) >= len(bonuses):
|
||||||
|
return 0
|
||||||
|
else:
|
||||||
|
if ctf.event.bonus.absolute == True:
|
||||||
|
return int(bonuses[len(solves)])
|
||||||
|
else:
|
||||||
|
return int(bonuses[len(solves)]) * ctf.points // 100
|
||||||
|
|
||||||
|
def format_bonus_points(ctf):
|
||||||
|
if not ctf.event.bonus:
|
||||||
|
return None
|
||||||
|
|
||||||
|
bonuses = ctf.event.bonus.points.split(',')
|
||||||
|
if ctf.event.bonus.absolute == True:
|
||||||
|
return ''.join([b + ', ' for b in bonuses])[:-2]
|
||||||
|
return ''.join([str(ctf.points * int(b) // 100) + ', ' for b in bonuses])[:-2]
|
||||||
|
|
||||||
|
|
||||||
# Create your views here.
|
# Create your views here.
|
||||||
def events(request):
|
def events(request):
|
||||||
list_events = Event.objects.filter().order_by('-end_date', 'start_date')
|
list_events = Event.objects.filter().order_by('-end_date', 'start_date')
|
||||||
|
@ -29,7 +74,9 @@ def events(request):
|
||||||
def chall_event_info(request, event_slug, chall_slug):
|
def chall_event_info(request, event_slug, chall_slug):
|
||||||
event_info = get_object_or_404(Event, slug=event_slug)
|
event_info = get_object_or_404(Event, slug=event_slug)
|
||||||
ctf_info = get_object_or_404(CTF, event__slug=event_info.slug, slug=chall_slug)
|
ctf_info = get_object_or_404(CTF, event__slug=event_info.slug, slug=chall_slug)
|
||||||
if timezone.now() < ctf_info.pub_date:
|
|
||||||
|
is_event_manager = request.user.groups.filter(name=event_info.name).exists() or request.user.is_superuser
|
||||||
|
if timezone.now() < ctf_info.pub_date and not is_event_manager:
|
||||||
return redirect('events:event_info', event_slug=event_slug)
|
return redirect('events:event_info', event_slug=event_slug)
|
||||||
eventisover = False
|
eventisover = False
|
||||||
alreadyflag = False
|
alreadyflag = False
|
||||||
|
@ -37,14 +84,16 @@ def chall_event_info(request, event_slug, chall_slug):
|
||||||
wrongflag = False
|
wrongflag = False
|
||||||
errorform = False
|
errorform = False
|
||||||
notsub = False
|
notsub = False
|
||||||
|
noteam = False
|
||||||
player = None
|
player = None
|
||||||
|
bonus = 0
|
||||||
if request.user.is_authenticated and not request.user.is_staff:
|
if request.user.is_authenticated and not request.user.is_staff:
|
||||||
player = EventPlayer.objects.filter(event=event_info, user=request.user)
|
player = EventPlayer.objects.filter(event=event_info, user=request.user)
|
||||||
if not player:
|
if not player:
|
||||||
return redirect('events:event_info', event_slug=event_slug)
|
return redirect('events:event_info', event_slug=event_slug)
|
||||||
elif not request.user.is_authenticated:
|
elif not request.user.is_authenticated:
|
||||||
return redirect('accounts:signin')
|
return redirect('accounts:signin')
|
||||||
if request.GET.get('EventIsOver'):
|
if request.GET.get('EventIsOver') or timezone.now() > event_info.end_date:
|
||||||
eventisover = True
|
eventisover = True
|
||||||
if request.GET.get('AlreadyFlagged'):
|
if request.GET.get('AlreadyFlagged'):
|
||||||
alreadyflag = True
|
alreadyflag = True
|
||||||
|
@ -56,6 +105,10 @@ def chall_event_info(request, event_slug, chall_slug):
|
||||||
errorform = True
|
errorform = True
|
||||||
if request.GET.get('NotRegistered'):
|
if request.GET.get('NotRegistered'):
|
||||||
notsub = True
|
notsub = True
|
||||||
|
if request.GET.get('NoTeam'):
|
||||||
|
noteam = True
|
||||||
|
bonus = request.GET.get('Bonus')
|
||||||
|
bonus_points = format_bonus_points(ctf_info)
|
||||||
solved_challs = CTF_flags.objects.filter(ctf=ctf_info).order_by('flag_date')
|
solved_challs = CTF_flags.objects.filter(ctf=ctf_info).order_by('flag_date')
|
||||||
solved_list = []
|
solved_list = []
|
||||||
for s in solved_challs:
|
for s in solved_challs:
|
||||||
|
@ -65,56 +118,65 @@ def chall_event_info(request, event_slug, chall_slug):
|
||||||
solved_list.append([s.user, s.flag_date])
|
solved_list.append([s.user, s.flag_date])
|
||||||
description = get_description_by_lang(ctf_info)
|
description = get_description_by_lang(ctf_info)
|
||||||
return render(request, 'events/ctf_info.html', { 'ctf' : ctf_info, 'event':event_info, 'solved_list': solved_list, 'description': description, 'eventisover': eventisover, 'alreadyflag': alreadyflag,
|
return render(request, 'events/ctf_info.html', { 'ctf' : ctf_info, 'event':event_info, 'solved_list': solved_list, 'description': description, 'eventisover': eventisover, 'alreadyflag': alreadyflag,
|
||||||
'congrat': congrat, 'wrongflag': wrongflag, 'errorform': errorform, 'notsub': notsub})
|
'congrat': congrat, 'wrongflag': wrongflag, 'errorform': errorform, 'notsub': notsub, 'noteam':noteam, 'bonus':bonus, 'bonus_points':bonus_points})
|
||||||
|
|
||||||
def event(request, event_slug):
|
def event(request, event_slug):
|
||||||
event_info = get_object_or_404(Event, slug=event_slug)
|
event_info = get_object_or_404(Event, slug=event_slug)
|
||||||
IsRegistered = False
|
|
||||||
wrongpwd = False
|
wrongpwd = False
|
||||||
alreadyregistered = False
|
alreadyregistered = False
|
||||||
subisover = False
|
subisover = False
|
||||||
|
|
||||||
|
is_event_manager = request.user.groups.filter(name=event_info.name).exists() or request.user.is_superuser
|
||||||
|
|
||||||
|
ended = (timezone.now() >= event_info.end_date)
|
||||||
|
begun = (timezone.now() >= event_info.start_date)
|
||||||
|
|
||||||
|
if is_event_manager: # we want to see all the challenges
|
||||||
|
challenges = CTF.objects.filter(event=event_info).order_by('category', 'points')
|
||||||
|
else:
|
||||||
|
challenges = CTF.objects.filter(event=event_info, pub_date__lte=timezone.now()).order_by('category', 'points')
|
||||||
|
|
||||||
|
if event_info.team_size == 1:
|
||||||
|
solved_list = EventPlayer.objects.filter(event=event_info).order_by('-score', 'last_submission_date', 'user__username')
|
||||||
|
else:
|
||||||
|
solved_list = Team.objects.filter(event=event_info).order_by('-score', 'last_submission_date', 'name')
|
||||||
|
|
||||||
if request.GET.get('WrongPassword'):
|
if request.GET.get('WrongPassword'):
|
||||||
wrongpwd = True
|
wrongpwd = True
|
||||||
if request.GET.get('AlreadyRegistered'):
|
if request.GET.get('AlreadyRegistered'):
|
||||||
alreadyregistered = True
|
alreadyregistered = True
|
||||||
if request.GET.get('SubscriptionIsOver'):
|
if request.GET.get('SubscriptionIsOver'):
|
||||||
subisover = True
|
subisover = True
|
||||||
|
|
||||||
if request.user.is_authenticated:
|
if request.user.is_authenticated:
|
||||||
try:
|
try:
|
||||||
player = EventPlayer.objects.get(event=event_info, user=request.user)
|
EventPlayer.objects.get(event=event_info, user=request.user)
|
||||||
|
return render(request, 'events/event_info.html', {'event' : event_info, 'IsRegistered': True, 'ctfs': challenges, 'solved_list':solved_list,
|
||||||
|
'ended': ended, 'begun': begun, 'wrongpwd': wrongpwd, 'alreadyregistered': alreadyregistered, 'subisover': subisover, 'is_event_manager':is_event_manager})
|
||||||
except:
|
except:
|
||||||
player = None
|
pass
|
||||||
if player:
|
|
||||||
IsRegistered = True
|
if (event_info.campus.all() or event_info.password) and request.user.is_authenticated is False:
|
||||||
if not player.team and event_info.team_size > 1:
|
return render(request, 'events/event_pwd.html', {'event' : event_info, 'logged': False})
|
||||||
return render(request, 'events/create_team.html', {'event' : event_info, 'logged': True, 'wrongpwd': False, 'registered' : True, 'notexist' : False})
|
|
||||||
if event_info.password:
|
if event_info.campus.all() and is_event_manager is False:
|
||||||
if request.user.is_authenticated:
|
user = UserProfileInfo.objects.get(user=request.user)
|
||||||
if request.user.is_staff is False:
|
if user.campus is None:
|
||||||
if not player:
|
return render(request, 'events/event_pwd.html', {'event' : event_info, 'logged': True, 'wrongpwd': wrongpwd, 'alreadyregistered': alreadyregistered, 'userHasCampus': False, 'campusCanJoin': True})
|
||||||
return render(request, 'events/event_pwd.html', {'event' : event_info, 'logged': True, 'wrongpwd': wrongpwd, 'alreadyregistered': alreadyregistered})
|
elif user.campus not in event_info.campus.all():
|
||||||
elif not player.team and event_info.team_size > 1:
|
return render(request, 'events/event_pwd.html', {'event' : event_info, 'logged': True, 'wrongpwd': wrongpwd, 'alreadyregistered': alreadyregistered, 'userHasCampus': True, 'campusCanJoin': False})
|
||||||
return render(request, 'events/create_team.html', {'event' : event_info, 'logged': True, 'wrongpwd': False, 'registered' : True, 'notexist' : False})
|
|
||||||
else:
|
if event_info.password and is_event_manager is False:
|
||||||
return render(request, 'events/event_pwd.html', {'event' : event_info, 'logged': False, 'wrongpwd': wrongpwd, 'alreadyregistered': alreadyregistered})
|
return render(request, 'events/event_pwd.html', {'event' : event_info, 'logged': True, 'wrongpwd': wrongpwd, 'alreadyregistered': alreadyregistered, 'userHasCampus': True, 'campusCanJoin': True})
|
||||||
ended = False
|
|
||||||
if timezone.now() >= event_info.end_date:
|
return render(request, 'events/event_info.html', {'event' : event_info, 'ctfs': challenges, 'solved_list':solved_list, 'IsRegistered': False,
|
||||||
ended = True
|
'ended': ended, 'begun': begun, 'wrongpwd': wrongpwd, 'alreadyregistered': alreadyregistered, 'subisover': subisover, 'is_event_manager':is_event_manager})
|
||||||
begun = False
|
|
||||||
if timezone.now() >= event_info.start_date:
|
|
||||||
begun = True
|
|
||||||
challenges = CTF.objects.filter(event=event_info).order_by('category', 'points')
|
|
||||||
if event_info.team_size == 1:
|
|
||||||
solved_list = EventPlayer.objects.filter(event=event_info).order_by('-score', 'last_submission_date', 'user__username')
|
|
||||||
else:
|
|
||||||
solved_list = Team.objects.filter(event=event_info).order_by('-score', 'last_submission_date', 'name')
|
|
||||||
return render(request, 'events/event_info.html', {'event' : event_info, 'IsRegistered': IsRegistered, 'ctfs': challenges, 'solved_list':solved_list,
|
|
||||||
'ended': ended, 'begun': begun, 'wrongpwd': wrongpwd, 'alreadyregistered': alreadyregistered, 'subisover': subisover})
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def submit_event_flag(request, event_slug, chall_slug):
|
def submit_event_flag(request, event_slug, chall_slug):
|
||||||
ev = get_object_or_404(Event, slug=event_slug)
|
ev = get_object_or_404(Event, slug=event_slug)
|
||||||
response = redirect('events:event_chall_info', event_slug=event_slug, chall_slug=chall_slug)
|
response = redirect('events:event_chall_info', event_slug=event_slug, chall_slug=chall_slug)
|
||||||
|
flagged = False
|
||||||
|
|
||||||
if timezone.now() >= ev.end_date:
|
if timezone.now() >= ev.end_date:
|
||||||
response['Location'] += '?EventIsOver=1'
|
response['Location'] += '?EventIsOver=1'
|
||||||
|
@ -126,12 +188,18 @@ def submit_event_flag(request, event_slug, chall_slug):
|
||||||
response['Location'] += '?ChallengeNotFound=1'
|
response['Location'] += '?ChallengeNotFound=1'
|
||||||
return response
|
return response
|
||||||
|
|
||||||
flagged = False
|
try:
|
||||||
player = EventPlayer.objects.get(user=request.user, event=ev)
|
player = EventPlayer.objects.get(event=ev, user=request.user)
|
||||||
|
except:
|
||||||
|
player = None
|
||||||
|
|
||||||
if player:
|
if player:
|
||||||
if ev.team_size == 1 and CTF_flags.objects.filter(user=request.user, ctf=ctf_info):
|
if ev.team_size > 1 and player.team is None:
|
||||||
flagged = True
|
response['Location'] += '?NoTeam=1'
|
||||||
|
return response
|
||||||
|
if ev.team_size == 1:
|
||||||
|
if CTF_flags.objects.filter(user=request.user, ctf=ctf_info):
|
||||||
|
flagged = True
|
||||||
else:
|
else:
|
||||||
solved_list = CTF_flags.objects.filter(ctf=ctf_info)
|
solved_list = CTF_flags.objects.filter(ctf=ctf_info)
|
||||||
for s in solved_list:
|
for s in solved_list:
|
||||||
|
@ -146,18 +214,21 @@ def submit_event_flag(request, event_slug, chall_slug):
|
||||||
|
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
if ctf_info.flag == request.POST.get('flag'):
|
if ctf_info.flag == request.POST.get('flag'):
|
||||||
new = CTF_flags(user = request.user, ctf = ctf_info, flag_date = timezone.now())
|
bonus = compute_bonus_points(ctf_info)
|
||||||
|
new = CTF_flags(user = request.user, ctf = ctf_info, flag_date = timezone.now(), bonus = bonus)
|
||||||
new.save()
|
new.save()
|
||||||
if ctf_info.points > 0:
|
if ctf_info.points > 0:
|
||||||
player.last_submission_date = timezone.now()
|
player.last_submission_date = timezone.now()
|
||||||
player.score += ctf_info.points
|
player.score += (ctf_info.points + bonus)
|
||||||
player.save()
|
player.save()
|
||||||
if player.team:
|
if player.team:
|
||||||
if ctf_info.points > 0:
|
if ctf_info.points > 0:
|
||||||
player.team.last_submission_date = timezone.now()
|
player.team.last_submission_date = timezone.now()
|
||||||
player.team.score += ctf_info.points
|
player.team.score += (ctf_info.points + bonus)
|
||||||
player.team.save()
|
player.team.save()
|
||||||
response['Location'] += '?Congrat=1'
|
if ev.dynamic:
|
||||||
|
actualize_points(ctf_info)
|
||||||
|
response['Location'] += '?Congrat=1&Bonus=' + str(bonus)
|
||||||
return response
|
return response
|
||||||
else:
|
else:
|
||||||
response['Location'] += '?WrongFlag=1'
|
response['Location'] += '?WrongFlag=1'
|
||||||
|
@ -191,8 +262,6 @@ def submit_pwd(request, event_slug):
|
||||||
else:
|
else:
|
||||||
new = EventPlayer(user=request.user, event=ev)
|
new = EventPlayer(user=request.user, event=ev)
|
||||||
new.save()
|
new.save()
|
||||||
if event_info.team_size > 1:
|
|
||||||
return render(request, 'events/create_team.html', {'event' : event_info, 'logged': True, 'wrongpwd': False, 'registered' : True, 'notexist' : False})
|
|
||||||
return redirect('events:event_info', event_slug=event_slug)
|
return redirect('events:event_info', event_slug=event_slug)
|
||||||
|
|
||||||
|
|
||||||
|
@ -214,8 +283,6 @@ def register_to_event(request, event_slug):
|
||||||
else:
|
else:
|
||||||
new = EventPlayer(user=request.user, event=ev, score=0)
|
new = EventPlayer(user=request.user, event=ev, score=0)
|
||||||
new.save()
|
new.save()
|
||||||
if ev.team_size > 1:
|
|
||||||
return render(request, 'events/create_team.html', {'event' : ev, 'logged': True, 'wrongpwd': False, 'registered' : True, 'notexist' : False})
|
|
||||||
return redirect('events:event_info', event_slug=event_slug)
|
return redirect('events:event_info', event_slug=event_slug)
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
|
@ -243,7 +310,7 @@ def profile(request, user_name, event_slug):
|
||||||
percent = (solved_count / max_count) * 100
|
percent = (solved_count / max_count) * 100
|
||||||
catsDatas.append([cat.name, solved_count, max_count, '{:.0f}'.format(percent)])
|
catsDatas.append([cat.name, solved_count, max_count, '{:.0f}'.format(percent)])
|
||||||
for flag in solved:
|
for flag in solved:
|
||||||
somme += flag.ctf.points
|
somme += (flag.ctf.points + flag.bonus)
|
||||||
pointDatas[cat.name].append([flag.flag_date.timestamp() * 1000, somme])
|
pointDatas[cat.name].append([flag.flag_date.timestamp() * 1000, somme])
|
||||||
|
|
||||||
solves = CTF_flags.objects.filter(user=user_obj, ctf__event=event_info).order_by('-flag_date')
|
solves = CTF_flags.objects.filter(user=user_obj, ctf__event=event_info).order_by('-flag_date')
|
||||||
|
@ -251,10 +318,10 @@ def profile(request, user_name, event_slug):
|
||||||
somme = 0
|
somme = 0
|
||||||
solved.append([event_info.start_date.timestamp() * 1000, 0])
|
solved.append([event_info.start_date.timestamp() * 1000, 0])
|
||||||
for s in solves.reverse():
|
for s in solves.reverse():
|
||||||
somme += s.ctf.points
|
somme += (s.ctf.points + s.bonus)
|
||||||
solved.append([s.flag_date.timestamp() * 1000,somme])
|
solved.append([s.flag_date.timestamp() * 1000,somme])
|
||||||
|
|
||||||
return render(request,'accounts/profile.html', {'user':user_obj, 'solves':solves,'solved':solved,'catsDatas': catsDatas, 'pointDatas': pointDatas,
|
return render(request,'events/profile.html', {'user':user_obj, 'solves':solves,'solved':solved,'catsDatas': catsDatas, 'pointDatas': pointDatas,
|
||||||
'rank': rank, 'score' : somme, 'cats':cats})
|
'rank': rank, 'score' : player.score, 'cats':cats, 'event': event_info})
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -11,22 +11,25 @@ from random import randint
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def create_team(request, event_slug):
|
def create_team(request, event_slug):
|
||||||
response = redirect('events:create_team', event_slug=event_slug)
|
|
||||||
ev = get_object_or_404(Event, slug=event_slug)
|
ev = get_object_or_404(Event, slug=event_slug)
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
|
teamname = request.POST.get('teamname')
|
||||||
if request.user.is_authenticated and ev.team_size > 1:
|
if request.user.is_authenticated and ev.team_size > 1:
|
||||||
if Team.objects.filter(name=request.POST.get('teamname'), event=ev).exists():
|
if any(c in set('./') for c in teamname):
|
||||||
|
return render(request, 'events/create_team.html', {'event' : ev, 'logged': True, 'wrongpwd': False, 'registered' : True, 'exist' : False, 'invalid' : True})
|
||||||
|
if Team.objects.filter(name=teamname, event=ev).exists():
|
||||||
return render(request, 'events/create_team.html', {'event' : ev, 'logged': True, 'wrongpwd': False, 'registered' : True, 'exist' : True})
|
return render(request, 'events/create_team.html', {'event' : ev, 'logged': True, 'wrongpwd': False, 'registered' : True, 'exist' : True})
|
||||||
new = Team(name=request.POST.get('teamname'), password=request.POST.get('password'), event=ev)
|
new = Team(name=teamname, password=request.POST.get('password'), event=ev)
|
||||||
new.save()
|
new.save()
|
||||||
player = EventPlayer.objects.get(user=request.user, event=ev)
|
player = EventPlayer.objects.get(user=request.user, event=ev)
|
||||||
player.team = new
|
player.team = new
|
||||||
player.save()
|
player.save()
|
||||||
return redirect('events:event_info', event_slug=event_slug)
|
return redirect('events:event_info', event_slug=event_slug)
|
||||||
|
else:
|
||||||
|
return render(request, 'events/create_team.html', {'event' : ev, 'logged': True, 'wrongpwd': False, 'registered' : True, 'exist' : False})
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def join_team(request, event_slug):
|
def join_team(request, event_slug):
|
||||||
response = redirect('events:join_team', event_slug=event_slug)
|
|
||||||
ev = get_object_or_404(Event, slug=event_slug)
|
ev = get_object_or_404(Event, slug=event_slug)
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
if request.user.is_authenticated and ev.team_size > 1:
|
if request.user.is_authenticated and ev.team_size > 1:
|
||||||
|
@ -46,9 +49,9 @@ def join_team(request, event_slug):
|
||||||
player = EventPlayer.objects.get(user=request.user, event=ev)
|
player = EventPlayer.objects.get(user=request.user, event=ev)
|
||||||
player.team = team
|
player.team = team
|
||||||
player.save()
|
player.save()
|
||||||
|
return redirect('events:event_info', event_slug=event_slug)
|
||||||
else:
|
else:
|
||||||
return render(request, 'events/join_team.html', {'event' : ev, 'logged': True, 'wrongpwd': False, 'registered' : True, 'notexist' : False})
|
return render(request, 'events/join_team.html', {'event' : ev, 'logged': True, 'wrongpwd': False, 'registered' : True, 'notexist' : False})
|
||||||
return redirect('events:event_info', event_slug=event_slug)
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def team_info(request, name, event_slug):
|
def team_info(request, name, event_slug):
|
||||||
|
@ -102,6 +105,8 @@ def team_info(request, name, event_slug):
|
||||||
def manage_team(request, event_slug):
|
def manage_team(request, event_slug):
|
||||||
event_info = get_object_or_404(Event, slug=event_slug)
|
event_info = get_object_or_404(Event, slug=event_slug)
|
||||||
player = EventPlayer.objects.get(user=request.user, event=event_info)
|
player = EventPlayer.objects.get(user=request.user, event=event_info)
|
||||||
|
if not player.team:
|
||||||
|
return render(request, 'events/create_team.html', {'event' : event_info, 'logged': True, 'wrongpwd': False, 'registered' : True, 'notexist' : False})
|
||||||
members = EventPlayer.objects.filter(team=player.team, event=event_info)
|
members = EventPlayer.objects.filter(team=player.team, event=event_info)
|
||||||
|
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
|
@ -113,9 +118,10 @@ def manage_team(request, event_slug):
|
||||||
pname = p_form.cleaned_data['name']
|
pname = p_form.cleaned_data['name']
|
||||||
if pname == tname:
|
if pname == tname:
|
||||||
pass
|
pass
|
||||||
else:
|
elif any(c in set('./') for c in pname):
|
||||||
if Team.objects.filter(name=pname, event=event_info).exists():
|
error = _("Invalid characters in name")
|
||||||
error = _("Name already taken.")
|
elif Team.objects.filter(name=pname, event=event_info).exists():
|
||||||
|
error = _("Name already taken.")
|
||||||
ppassword = p_form.cleaned_data['password']
|
ppassword = p_form.cleaned_data['password']
|
||||||
if error is None:
|
if error is None:
|
||||||
p_form.save()
|
p_form.save()
|
||||||
|
@ -135,19 +141,21 @@ def leave_team(request, event_slug):
|
||||||
player = EventPlayer.objects.get(user=request.user, event=event_info)
|
player = EventPlayer.objects.get(user=request.user, event=event_info)
|
||||||
team = Team.objects.get(event=event_info, name=player.team.name)
|
team = Team.objects.get(event=event_info, name=player.team.name)
|
||||||
|
|
||||||
team.score -= player.score
|
|
||||||
team.save()
|
|
||||||
player.team = None
|
player.team = None
|
||||||
|
player.save()
|
||||||
|
members = EventPlayer.objects.filter(team=team, event=event_info)
|
||||||
|
if members.count() == 0:
|
||||||
|
team.delete()
|
||||||
|
else:
|
||||||
|
team.score -= player.score
|
||||||
|
team.save()
|
||||||
|
|
||||||
solved = CTF_flags.objects.filter(user=player.user, ctf__event=event_info)
|
solved = CTF_flags.objects.filter(user=player.user, ctf__event=event_info)
|
||||||
player.score = 0
|
player.score = 0
|
||||||
solved.delete()
|
solved.delete()
|
||||||
player.save()
|
player.save()
|
||||||
|
|
||||||
members = EventPlayer.objects.filter(team=team, event=event_info)
|
return redirect('events:event_info', event_slug=event_slug)
|
||||||
if members.count() == 0:
|
|
||||||
team.delete()
|
|
||||||
|
|
||||||
return render(request, 'events/create_team.html', {'event' : event_info, 'logged': True, 'wrongpwd': False, 'registered' : True, 'notexist' : False})
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def find_team(request, event_slug):
|
def find_team(request, event_slug):
|
||||||
|
@ -174,3 +182,27 @@ def find_team(request, event_slug):
|
||||||
player.save()
|
player.save()
|
||||||
|
|
||||||
return redirect('events:event_info', event_slug=event_slug)
|
return redirect('events:event_info', event_slug=event_slug)
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def open_team(request, event_slug):
|
||||||
|
event_info = get_object_or_404(Event, slug=event_slug)
|
||||||
|
player = EventPlayer.objects.get(user=request.user, event=event_info)
|
||||||
|
|
||||||
|
if not player.team:
|
||||||
|
return render(request, 'events/create_team.html', {'event' : event_info, 'logged': True, 'wrongpwd': False, 'registered' : True, 'notexist' : False})
|
||||||
|
|
||||||
|
player.team.auto = True
|
||||||
|
player.team.save()
|
||||||
|
return redirect('events:manage_team', event_slug=event_slug)
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def close_team(request, event_slug):
|
||||||
|
event_info = get_object_or_404(Event, slug=event_slug)
|
||||||
|
player = EventPlayer.objects.get(user=request.user, event=event_info)
|
||||||
|
|
||||||
|
if not player.team:
|
||||||
|
return render(request, 'events/create_team.html', {'event' : event_info, 'logged': True, 'wrongpwd': False, 'registered' : True, 'notexist' : False})
|
||||||
|
|
||||||
|
player.team.auto = False
|
||||||
|
player.team.save()
|
||||||
|
return redirect('events:manage_team', event_slug=event_slug)
|
|
@ -0,0 +1,12 @@
|
||||||
|
from django.contrib import sitemaps
|
||||||
|
from django.urls import reverse
|
||||||
|
|
||||||
|
class StaticViewSitemap(sitemaps.Sitemap):
|
||||||
|
priority = 0.5
|
||||||
|
changefreq = 'monthly'
|
||||||
|
i18n = True
|
||||||
|
def items(self):
|
||||||
|
return ['home', 'cgu']
|
||||||
|
|
||||||
|
def location(self, item):
|
||||||
|
return reverse(item)
|
|
@ -4,7 +4,7 @@
|
||||||
{% get_current_language as lang %}
|
{% get_current_language as lang %}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12 news-card">
|
<div class="col-12 news-card">
|
||||||
<h2>Conditions générales d'utilisation du site 42CTF</h2>
|
<h1>Conditions générales d'utilisation du site 42CTF</h1>
|
||||||
|
|
||||||
<h5>Article 1 : Objet</h5>
|
<h5>Article 1 : Objet</h5>
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% get_current_language as lang %}
|
{% get_current_language as lang %}
|
||||||
{% load is_member %}
|
{% load is_member %}
|
||||||
|
{% load get_news %}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-lg-3 col-sm-12 right-sidebar middle-sm">
|
<div class="col-lg-3 col-sm-12 right-sidebar middle-sm">
|
||||||
|
|
||||||
|
@ -34,17 +35,8 @@
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h5 class="card-title">{{ n.name|safe }}</h5>
|
<h5 class="card-title">{{ n.name|safe }}</h5>
|
||||||
<p class="card-text">
|
<p class="card-text">
|
||||||
{% if lang == "fr" and n.content %}
|
{% get_news_by_lang n lang as content %}
|
||||||
{{ n.content|safe }}
|
{{ content | safe }}
|
||||||
{% elif lang == "en" and n.content_en %}
|
|
||||||
{{ n.content_en|safe }}
|
|
||||||
{% elif lang == "de" and n.content_de %}
|
|
||||||
{{ n.content_de|safe }}
|
|
||||||
{% elif lang == "ru" and n.content_ru %}
|
|
||||||
{{ n.content_ru|safe }}
|
|
||||||
{% else %}
|
|
||||||
{% trans "No translation available. Please try another language (English or French)." %}
|
|
||||||
{% endif %}
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-footer text-muted">
|
<div class="card-footer text-muted">
|
||||||
|
@ -83,13 +75,13 @@
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
<div class="row flex-nowrap">
|
<div class="row flex-nowrap">
|
||||||
<div class="col-lg-6 col-sm-3">
|
<div class="col-lg-6 col-md-6">
|
||||||
<ul class="list-group">
|
<ul class="list-group">
|
||||||
<li class="list-group-item active">{% trans "Flags" %}</li>
|
<li class="list-group-item active">{% trans "Flags" %}</li>
|
||||||
<li class="list-group-item"><span>{{ flags }}</span></li>
|
<li class="list-group-item"><span>{{ flags }}</span></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-lg-6 col-sm-3">
|
<div class="col-lg-6 col-md-6">
|
||||||
<ul class="list-group">
|
<ul class="list-group">
|
||||||
<li class="list-group-item active">{% trans "Users" %}</li>
|
<li class="list-group-item active">{% trans "Users" %}</li>
|
||||||
<li class="list-group-item"><span>{{ nb_users }}</span></li>
|
<li class="list-group-item"><span>{{ nb_users }}</span></li>
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
Wie Sie es vielleicht schon wissen, braucht man um CTF Herausforderungen zu lösen viele Werkzeuge und es ist manchmal schwierig zu wissen welche benötigt werden.</br>
|
||||||
|
Wir haben eine VM erstellt, mit vorinstallierten Werkzeugen, damit Sie sich auf das wesentliche konzentrieren können: Flaggen!</br>
|
||||||
|
Alles was Sie tun müssen ist diese <b><a href="/media/xubuntu-42ctf.ova">OVA</a></b> herunterzuladen und auf <b><a href="https://www.virtualbox.org/wiki/Downloads">Virtual Box</a></b> zu importieren.<br>
|
||||||
|
Also, worauf warten Sie?
|
|
@ -0,0 +1,7 @@
|
||||||
|
Haben Sie eine Änderung am Punktestand bemerkt?<br><br>
|
||||||
|
|
||||||
|
Keine Panik, alle Ihre Flaggen sind in Sicherheit. Wir haben bloß zu dynamischen Belohnungen gewächselt. Das heißt, dass die Punktzahl der Herausforderungen nicht mehr festgelegt ist: sie sinken nun jedes Mal, dass die Herausforderung gelöst wird.
|
||||||
|
|
||||||
|
Belohnungspunkte beginnen bei 200 und können nicht unter 5 fallen.<br><br>
|
||||||
|
|
||||||
|
Wir erhoffen, dass dadurch die echte Schwierigkeit der Herausforderungen besser gespiegelt werden kann. Zeitgebundene Ereignisse sind von dieser Änderung nicht beinträchtigt.
|
|
@ -0,0 +1,9 @@
|
||||||
|
Suchen Sie Ihren Seelenverwandten, einen neuen Freund oder bloß einen dezenten CTF-Partner?<br><br>
|
||||||
|
|
||||||
|
Wir bei 42CTF haben was Sie brauchen: den <a href="/events/speed_dating_2022">Speed Dating CTF</a>!<br><br>
|
||||||
|
|
||||||
|
Kommen Sie alleine oder gut begleitet zu diesem sehr kurzen Wettbewerb, der nur 4 Studen dauern wird.<br>
|
||||||
|
Für dieses Team-CTF können Sie nur auf einen anderen Spieler zählen.<br>
|
||||||
|
Sie können entweder Ihren Partner aussuchen oder das Schicksal für sie entscheiden lassen.<br><br>
|
||||||
|
|
||||||
|
Viel Glück!
|
|
@ -0,0 +1,8 @@
|
||||||
|
Schon immer lust gehabt etwas über SQL-Einbrüche zu lernen?<br>
|
||||||
|
<br>
|
||||||
|
Wir bieten Ihnen drei brandneue Herausvorderungen erstellt von <b><a class=profile_link href=https://www.42ctf.org/accounts/profile/aldubar>aldubar</a></b>:<br>
|
||||||
|
- <b><a href='https://www.42ctf.org/ctfs/web/simple_question_1'>Simple Question of Logic 1</a></b> (10 Punkte)<br>
|
||||||
|
- <b><a href='https://www.42ctf.org/ctfs/web/simple_question_2'>Simple Question of Logic 2</a></b> (30 Punkte)<br>
|
||||||
|
- <b><a href='https://www.42ctf.org/ctfs/web/simple_question_3'>Simple Question of Logic 3</a></b> (40 Punkte)<br>
|
||||||
|
<br>
|
||||||
|
Vergessen Sie nicht, dass Sie uns jederzeit auf <a class="footer_imgs" href="https://discord.gg/DwZqPpA" target="_blank"><img src="/static/img/discord.png" width="30"></a> erreichen können, um uns neue Herausforderungen vorzuschalgen!
|
|
@ -0,0 +1,9 @@
|
||||||
|
Neues zeitgebundenes Ereignis: <b>Welcome CTF 2021</b>!<br><br>
|
||||||
|
|
||||||
|
Datum: vom 10.12.2021 20 Uhr biz zum 12.12.2021 20 Uhr (Pariser Zeit).<br>
|
||||||
|
Es ist ein CTF um die Studenten die neulich 42 beigetreten haben zu begrüßen.<br>
|
||||||
|
Es wird nur für die Personen die ihren Kursus <b>nach</b> dem 01.09.2021 begonnen haben zugänglich sein.<br><br>
|
||||||
|
|
||||||
|
Ansonsten können Sie trotzdem die auf der Webseite bereits verfügbaren Herausforderungen lösen und versuchen das Top 10 zu erreichen!<br><br>
|
||||||
|
|
||||||
|
Registrieren Sie sich <a href=https://forms.42l.fr/apps/forms/SooTbnT4PCs9na7C>hier</a>.
|
|
@ -0,0 +1,4 @@
|
||||||
|
As you may already be aware, solving CTF challenges require a lot of tools and it may be difficult to find out which ones you need to install. </br>
|
||||||
|
We've made a VM with everything you need for 42CTF challenges so that you can focus on what is really important: flag ! </br>
|
||||||
|
All you need to do is download this <b><a href="/media/xubuntu-42ctf.ova">OVA</a></b> and import it in <b><a href="https://www.virtualbox.org/wiki/Downloads">Virtual Box</a>.<br></b>
|
||||||
|
So, what are you waiting for ?
|
|
@ -0,0 +1,7 @@
|
||||||
|
You noticed a little change in the 42CTF scoreboard ?<br><br>
|
||||||
|
|
||||||
|
Don't panic, all your flags are safe and sound. We just switched to dynamic scoring. It means that challenges points are not fixed anymore: they will now decrease with each solve.<br>
|
||||||
|
|
||||||
|
Challenges points start at 200, and cannot go below than 5.<br><br>
|
||||||
|
|
||||||
|
We hope that this will allow better reflecting of the actual difficulty of the challenges. Limited-time events are not affected by this change.
|
|
@ -0,0 +1,3 @@
|
||||||
|
We're pleased to announce that 42CTF source code is now available on a self-hosted gitea <a class="footer_imgs" href="https://gitea.42ctf.org" target="_blank"><img src="/static/img/gitea_logo.png" width="30" alt="Gitea logo"></a><br><br>
|
||||||
|
|
||||||
|
If you want to contribute to the platform (development or translation), you can send us a message on <a class="footer_imgs" href="https://discord.gg/DwZqPpA" target="_blank"><img src="/static/img/discord.png" width="30" alt="Discord logo"></a> or simply fill this <a href="https://forms.42l.fr/apps/forms/bpmyGR37AR4yHGnC">form</a> and we'll contact you !
|
|
@ -0,0 +1,9 @@
|
||||||
|
Looking for your soul mate, a new friend, or just a decent CTF companion ?<br><br>
|
||||||
|
|
||||||
|
We at 42CTF have what you need: the <a href="/events/speed_dating_2022">Speed Dating CTF</a> !<br><br>
|
||||||
|
|
||||||
|
Come alone or in good company for this very short competition, which will last only 4 hours.<br>
|
||||||
|
You will be able to count on only one other player for this team CTF.<br>
|
||||||
|
You can either choose your partner or you can let the fate decide for you.<br><br>
|
||||||
|
|
||||||
|
Good luck !
|
|
@ -0,0 +1,8 @@
|
||||||
|
Always wanted to learn about SQL injections ? <br>
|
||||||
|
<br>
|
||||||
|
We offer you three brand new challenges created by <b><a class=profile_link href=https://www.42ctf.org/accounts/profile/aldubar>aldubar</a></b>:<br>
|
||||||
|
- <b><a href='https://www.42ctf.org/ctfs/web/simple_question_1'>Simple Question of Logic 1</a></b> (10 points)<br>
|
||||||
|
- <b><a href='https://www.42ctf.org/ctfs/web/simple_question_2'>Simple Question of Logic 2</a></b> (30 points)<br>
|
||||||
|
- <b><a href='https://www.42ctf.org/ctfs/web/simple_question_3'>Simple Question of Logic 3</a></b> (40 points)<br>
|
||||||
|
<br>
|
||||||
|
Don't forget that you can always reach out on <a class="footer_imgs" href="https://discord.gg/DwZqPpA" target="_blank"><img src="/static/img/discord.png" width="30" alt="Discord logo"></a> to propose new challenges !
|
|
@ -0,0 +1,9 @@
|
||||||
|
New limited-time event : <b>Welcome CTF 2021</b> !<br><br>
|
||||||
|
|
||||||
|
Dates: from 10/12/2021 8pm to 12/12/2021 8pm (Paris time).<br>
|
||||||
|
This is a CTF to welcome the new students who join us at 42.<br>
|
||||||
|
It will be accessible only for the persons who started their cursus <b>after</b> the 01/09/2021.<br><br>
|
||||||
|
|
||||||
|
For the others, you can still solve the challenges already available on the website and try to reach the top 10 ! <br><br>
|
||||||
|
|
||||||
|
Registration <a href=https://forms.42l.fr/apps/forms/SooTbnT4PCs9na7C>here</a>
|
|
@ -0,0 +1,4 @@
|
||||||
|
Como ya sabrás, resolver retos CTF requiere un montón de herramientas y puede ser dificil encontrar cuales tienes que instalar. </br>
|
||||||
|
Hemos hecho una máquina virtual con todo lo que necesitas para resolver para resolver retos de 42CTF, para que te puedas concentrar en lo importante: Flags! </br>
|
||||||
|
Todo lo que necesitas es descargar esto <b><a href="/media/xubuntu-42ctf.ova">OVA</a></b> e importarlo en <b><a href="https://www.virtualbox.org/wiki/Downloads">Virtual Box</a>.<br></b>
|
||||||
|
¿A qué estás esperando?
|
|
@ -0,0 +1,7 @@
|
||||||
|
¿ Has notado un pequeño cambio en la Tabla de Puntos de 42CTF ?<br><br>
|
||||||
|
|
||||||
|
No entres en pánico, todas tus flags estan a salvo. Solo hemos cambiado a puntuación dinámica. Esto significa que los puntos de retos no son fijos: irán disminuyendo cada vez que son resueltos.<br>
|
||||||
|
|
||||||
|
Los puntos de retos empiezan en 200, y no pueden valer menos de 5 puntos. <br><br>
|
||||||
|
|
||||||
|
Esperamos que esto ayude a reflejar la dificultad del reto. Eventos de tiempo limitado nos e ven afectados por este cambio.
|
|
@ -0,0 +1,9 @@
|
||||||
|
¿ Estás buscando tu alma gemela ? ¿ Un nuevo amigo ? ¿ O simplemente un buen compañero de CTF ?<br><br>
|
||||||
|
|
||||||
|
Aquí en 42CTF tenemos lo que necesitas: el <a href="/events/speed_dating_2022">Speed Dating CTF</a> !<br><br>
|
||||||
|
|
||||||
|
Ven solo o en compañía a esta competición cortita, que solo durará 4 horas.<br>
|
||||||
|
Podrás contar con un solo compañero para este CTF por equipos.<br>
|
||||||
|
Puedes o elegir un compañero o dejar a la fortuna que elija por ti.<br><br>
|
||||||
|
|
||||||
|
¡ Buena suerte !
|
|
@ -0,0 +1,8 @@
|
||||||
|
¿ Siempre has querido aprender sobre SQL injection ? <br>
|
||||||
|
<br>
|
||||||
|
Te ofrecemos tres nuevos retos creados por <b><a class=profile_link href=https://www.42ctf.org/accounts/profile/aldubar>aldubar</a></b>:<br>
|
||||||
|
- <b><a href='https://www.42ctf.org/ctfs/web/simple_question_1'>Cuestión de lógica simple 1</a></b> (10 puntos)<br>
|
||||||
|
- <b><a href='https://www.42ctf.org/ctfs/web/simple_question_2'>Cuestión de lógica simple 2</a></b> (30 puntos)<br>
|
||||||
|
- <b><a href='https://www.42ctf.org/ctfs/web/simple_question_3'>Cuestión de lógica simple 3</a></b> (40 puntos)<br>
|
||||||
|
<br>
|
||||||
|
No te olvides que siempre puedes contactarnos en <a class="footer_imgs" href="https://discord.gg/DwZqPpA" target="_blank"><img src="/static/img/discord.png" width="30"></a> para proponer nuevos retos !
|
|
@ -0,0 +1,9 @@
|
||||||
|
Nuevo evento de tiempo limitado: <b>Bienvenida a CTF 2021</b> !<br><br>
|
||||||
|
|
||||||
|
Fechas: desde 10/12/2021 8pm a 12/12/2021 8pm (Hora parís).<br>
|
||||||
|
Este CTF es una bienvenida para los nuevos estudiantes que se unan a 42.<br>
|
||||||
|
Solo estará disponible para las personas que empezaron su cursus <b>después</b> de 01/09/2021.<br><br>
|
||||||
|
|
||||||
|
Para otros, puedes resolver otros retos ya disponibles e intentar llegar al top 10! <br><br>
|
||||||
|
|
||||||
|
Registro: <a href=https://forms.42l.fr/apps/forms/SooTbnT4PCs9na7C>aquí</a>
|
|
@ -0,0 +1,7 @@
|
||||||
|
Comme vous le savez surement déjà, résoudre des challenges nécessite beaucoup d'outils et il peut être difficile de savoir lesquels sont vraiment nécessaires. <br>
|
||||||
|
|
||||||
|
Nous avons créé une VM avec tout ce dont vous avez besoin pour 42CTF afin que vous vous concentriez sur ce qui compte vraiment : flag ! <br>
|
||||||
|
|
||||||
|
Tout ce dont vous avez besoin est de télécharger cet <b><a href="/media/xubuntu-42ctf.ova">OVA</a></b> et de l'importer dans <b><a href="https://www.virtualbox.org/wiki/Downloads">Virtual Box</a></b>.<br>
|
||||||
|
|
||||||
|
Alors, qu'est ce que vous attendez ?
|
|
@ -0,0 +1,7 @@
|
||||||
|
Vous avez remarqué un petit changement sur le scoreboard de 42CTF ?<br><br>
|
||||||
|
|
||||||
|
Pas de panique, tous vos flags sont sains et saufs. Nous avons juste basculé sur du scoring dynamique. Cela signifie que les points des challenges ne sont plus fixes : ils diminueront désormais à chaque nouvelle résolution.<br>
|
||||||
|
|
||||||
|
Un challenge démarre à 200 points, et ne peut pas descendre en dessous de 5 points.<br><br>
|
||||||
|
|
||||||
|
Nous espérons que cela permettra de mieux refléter la véritable difficulté des challenges. Les événements à durée limitée ne sont pas concernés par ce changement.
|
|
@ -0,0 +1,3 @@
|
||||||
|
Nous sommes heureux de vous annoncer que le code source de 42CTF est désormais disponible sur un <a class="footer_imgs" href="https://gitea.42ctf.org" target="_blank"><img src="/static/img/gitea_logo.png" width="30" alt="Logo Gitea"></a> auto-hébergé.<br><br>
|
||||||
|
|
||||||
|
Si vous voulez contribuer a la plateforme (développement ou traduction), vous pouvez nous envoyer un message sur <a class="footer_imgs" href="https://discord.gg/DwZqPpA" target="_blank"><img src="/static/img/discord.png" width="30" alt="Logo Discord"></a> ou simplement remplir ce <a href="https://forms.42l.fr/apps/forms/bpmyGR37AR4yHGnC">formulaire</a> et nous vous contacterons !
|
|
@ -0,0 +1,9 @@
|
||||||
|
À la recherche de l'âme soeur, d'un nouvel ami, ou juste d'un compagnon de CTF ?<br><br>
|
||||||
|
|
||||||
|
Nous avons ce dont vous avez besoin : le <a href="/events/speed_dating_2022">Speed Dating CTF</a> !<br><br>
|
||||||
|
|
||||||
|
Venez seul ou bien accompagné pour cette très courte compétition, qui ne durera que 4 heures.<br>
|
||||||
|
Vous ne pourrez compter que sur une seule autre personne pour ce CTF en équipe.<br>
|
||||||
|
Vous pouvez soit choisir votre partenaire, soit laisser laisser le destin décider pour vous.<br><br>
|
||||||
|
|
||||||
|
Bonne chance !
|
|
@ -0,0 +1,8 @@
|
||||||
|
Vous avez toujours voulu en apprendre plus sur les injections SQL ? <br>
|
||||||
|
<br>
|
||||||
|
On vous propose trois nouveaux challenges créés par <b><a class=profile_link href=https://www.42ctf.org/accounts/profile/aldubar>aldubar</a></b>:<br>
|
||||||
|
- <b><a href='https://www.42ctf.org/ctfs/web/simple_question_1'>Simple Question of Logic 1</a></b> (10 points)<br>
|
||||||
|
- <b><a href='https://www.42ctf.org/ctfs/web/simple_question_2'>Simple Question of Logic 2</a></b> (30 points)<br>
|
||||||
|
- <b><a href='https://www.42ctf.org/ctfs/web/simple_question_3'>Simple Question of Logic 3</a></b> (40 points)<br>
|
||||||
|
<br>
|
||||||
|
N'oubliez pas que vous pouvez toujours nous contacter sur <a class="footer_imgs" href="https://discord.gg/DwZqPpA" target="_blank"><img src="/static/img/discord.png" width="30" alt="Logo Discord"></a> pour proposer des nouveaux challenges !
|
|
@ -0,0 +1,9 @@
|
||||||
|
Nouvel évènement en temps limité : <b>Welcome CTF 2021</b> !<br><br>
|
||||||
|
|
||||||
|
Dates : du 10/12/2021 20h au 12/12/2021 20h. <br>
|
||||||
|
Il s'agit d'un CTF pour souhaiter la bienvenue aux nouveaux étudiants qui nous rejoignent à 42.<br>
|
||||||
|
Il ne sera donc accessible qu'aux personnes ayant effectué leur rentrée <b>après</b> le 01/09/2021.<br><br>
|
||||||
|
|
||||||
|
Pour les autres, vous pouvez toujours résoudre les challenges déjà disponibles sur le site et tenter de vous hisser dans le top 10 ! <br><br>
|
||||||
|
|
||||||
|
Inscriptions <a href=https://forms.42l.fr/apps/forms/SooTbnT4PCs9na7C>ici</a>
|
|
@ -0,0 +1,4 @@
|
||||||
|
すでにお気づきかもしれませんが、CTFの課題を解くには多くのツールが必要で、どれをインストールすれば良いのかがわかりにくいかもしれません。</br>
|
||||||
|
私たちは、あなたが本当に重要なことに集中できるように、42CTFの課題に必要な全てのツールを備えたVMを作成しました。重要なのはフラグです!</br>
|
||||||
|
この<b><a href="/media/xubuntu-42ctf.ova">OVA</a></b>をダウンロードし、<b><a href="https://www.virtualbox.org/wiki/Downloads">Virtual Box</a></b>にインポートするだけです。<br>
|
||||||
|
さて、何をためらっているのですか?
|
|
@ -0,0 +1,7 @@
|
||||||
|
42CTFのスコアボードにちょっとした変化があったことにお気づきですか?<br><br>
|
||||||
|
|
||||||
|
慌てないでください、 あなたのフラグはすべて無事です。 動的スコアリングに切り替えただけです。 それはチャレンジポイントがもう固定ではないことを意味します。解決するたびに減少します。<br>
|
||||||
|
|
||||||
|
チャレンジポイントは200から始まり、5より低くなることはありません。<br><br>
|
||||||
|
|
||||||
|
これにより、課題の実際の難易度をより良く反映できるようになると期待しています。期間限定イベントは、この変更の影響は受けません。
|
|
@ -0,0 +1,3 @@
|
||||||
|
42CTFのソースコードがセルフホストのgitea <a class="footer_imgs" href="https://gitea.42ctf.org" target="_blank"><img src="/static/img/gitea_logo.png" width="30"></a> で公開されたことをお知らせします。<br><br>
|
||||||
|
|
||||||
|
プラットフォームへの貢献(開発や翻訳)をしていただける方は、 <a class="footer_imgs" href="https://discord.gg/DwZqPpA" target="_blank"><img src="/static/img/discord.png" width="30"></a> にメッセージをお送りいただくか、こちらの <a href="https://forms.42l.fr/apps/forms/bpmyGR37AR4yHGnC">フォーム</a> にご記入いただければご連絡いたします!
|
|
@ -0,0 +1,9 @@
|
||||||
|
ソウルメイト、新しい友達、またはちょうど良いCTFの仲間を探していますか?<br><br>
|
||||||
|
|
||||||
|
私たち42CTFは、あなたが求めているものを持っています。それは<a href="/events/speed_dating_2022">Speed Dating CTF</a>です!<br><br>
|
||||||
|
|
||||||
|
4時間という短い時間ですが、お一人でも、お仲間とご一緒でも、ぜひご参加ください。<br>
|
||||||
|
このチーム戦CTFでは、自分以外の一人のプレーヤーのみ頼ることができます。<br>
|
||||||
|
相手を選ぶもよし、運命に身を任せるもよし。<br><br>
|
||||||
|
|
||||||
|
幸運を祈ります!
|
|
@ -0,0 +1,8 @@
|
||||||
|
SQLインジェクションについて学びたいと思ったことはありませんか?<br>
|
||||||
|
<br>
|
||||||
|
<b><a class=profile_link href=https://www.42ctf.org/accounts/profile/aldubar>aldubar</a></b>が作成した全く新しい3つの課題を提供します。<br>
|
||||||
|
- <b><a href='https://www.42ctf.org/ctfs/web/simple_question_1'>Simple Question of Logic 1</a></b> (10 points)<br>
|
||||||
|
- <b><a href='https://www.42ctf.org/ctfs/web/simple_question_2'>Simple Question of Logic 2</a></b> (30 points)<br>
|
||||||
|
- <b><a href='https://www.42ctf.org/ctfs/web/simple_question_3'>Simple Question of Logic 3</a></b> (40 points)<br>
|
||||||
|
<br>
|
||||||
|
新しい課題を提案するために、<a class="footer_imgs" href="https://discord.gg/DwZqPpA" target="_blank"><img src="/static/img/discord.png" width="30"></a>へいつでも連絡できることを忘れないでください!
|
|
@ -0,0 +1,9 @@
|
||||||
|
期間限定の新イベント:<b>Welcome CTF 2021</b>!<br><br>
|
||||||
|
|
||||||
|
日程:2021年12月10日20時~2021年12月12日20時(パリ時間)<br>
|
||||||
|
42に入学する新入生を歓迎するためのCTFです。<br>
|
||||||
|
2021年9月1日<b>以降</b>にカーサスを開始した方のみアクセス可能です。<br><br>
|
||||||
|
|
||||||
|
それ以外の方は、ウェブサイト上で公開されている課題を解いて、トップ10入りを目指してください!<br><br>
|
||||||
|
|
||||||
|
登録は<a href=https://forms.42l.fr/apps/forms/SooTbnT4PCs9na7C>こちら</a>
|
|
@ -0,0 +1,13 @@
|
||||||
|
from django import template
|
||||||
|
from django.core.files.storage import default_storage
|
||||||
|
|
||||||
|
register = template.Library()
|
||||||
|
|
||||||
|
@register.simple_tag
|
||||||
|
def get_news_by_lang(news, lang):
|
||||||
|
filepath = "home/templates/news/"+ lang + "/" + news.slug + ".html"
|
||||||
|
try:
|
||||||
|
with open(filepath) as fp:
|
||||||
|
return fp.read()
|
||||||
|
except:
|
||||||
|
return news.content_en
|
|
@ -1,7 +1,14 @@
|
||||||
|
from django.contrib.sitemaps.views import sitemap
|
||||||
from django.urls import path
|
from django.urls import path
|
||||||
|
from .sitemaps import StaticViewSitemap
|
||||||
from . import views
|
from . import views
|
||||||
|
|
||||||
|
sitemaps = {
|
||||||
|
'static': StaticViewSitemap(),
|
||||||
|
}
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('', views.home, name='home'),
|
path('', views.home, name='home'),
|
||||||
path('CGU', views.cgu, name='cgu'),
|
path('CGU', views.cgu, name='cgu'),
|
||||||
|
path('sitemap.xml', sitemap, {'sitemaps': sitemaps}, name='django.contrib.sitemaps.views.sitemap'),
|
||||||
]
|
]
|
||||||
|
|
|
@ -8,25 +8,16 @@ from django.urls import translate_url
|
||||||
from django.utils.translation import (
|
from django.utils.translation import (
|
||||||
LANGUAGE_SESSION_KEY, check_for_language, get_language,
|
LANGUAGE_SESSION_KEY, check_for_language, get_language,
|
||||||
)
|
)
|
||||||
import datetime
|
from django.core.files.storage import default_storage
|
||||||
|
|
||||||
|
# import datetime
|
||||||
|
from django.utils import timezone
|
||||||
|
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
import operator
|
import operator
|
||||||
|
|
||||||
def get_content_by_lang(news):
|
|
||||||
lang = get_language()
|
|
||||||
ret = None
|
|
||||||
if lang == "fr":
|
|
||||||
ret = news.content
|
|
||||||
elif lang == "en":
|
|
||||||
ret = news.content_en
|
|
||||||
elif lang == "de":
|
|
||||||
ret = news.content_de
|
|
||||||
elif lang == "ru":
|
|
||||||
ret = news.content_ru
|
|
||||||
return ret
|
|
||||||
|
|
||||||
def get_weekly_top():
|
def get_weekly_top():
|
||||||
week_ago = datetime.datetime.now() - datetime.timedelta(days=7)
|
week_ago = timezone.now() - timezone.timedelta(days=7)
|
||||||
weekly_flags = CTF_flags.objects.filter(flag_date__gt=week_ago, ctf__disabled=False, ctf__event=None)
|
weekly_flags = CTF_flags.objects.filter(flag_date__gt=week_ago, ctf__disabled=False, ctf__event=None)
|
||||||
scores = defaultdict(int)
|
scores = defaultdict(int)
|
||||||
|
|
||||||
|
@ -44,7 +35,6 @@ def home(request):
|
||||||
lang_code = request.session[LANGUAGE_SESSION_KEY]
|
lang_code = request.session[LANGUAGE_SESSION_KEY]
|
||||||
url_translated = translate_url(request.path, lang_code)
|
url_translated = translate_url(request.path, lang_code)
|
||||||
if request.path != url_translated:
|
if request.path != url_translated:
|
||||||
print("%s\n%s" % (request.path, url_translated))
|
|
||||||
response = HttpResponseRedirect(url_translated)
|
response = HttpResponseRedirect(url_translated)
|
||||||
return response
|
return response
|
||||||
news = new.objects.order_by('-pub_date')[:5]
|
news = new.objects.order_by('-pub_date')[:5]
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -8,7 +8,7 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2022-02-02 19:22+0100\n"
|
"POT-Creation-Date: 2022-08-16 19:28+0200\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
|
@ -18,576 +18,653 @@ msgstr ""
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
|
|
||||||
#: accounts/templates/accounts/delete.html:8
|
#: src/accounts/templates/accounts/delete.html:8
|
||||||
msgid "Delete account"
|
msgid "Delete account"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: accounts/templates/accounts/delete.html:11
|
#: src/accounts/templates/accounts/delete.html:11
|
||||||
msgid "Please confirm your password to delete your account."
|
msgid "Please confirm your password to delete your account."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: accounts/templates/accounts/delete.html:12
|
#: src/accounts/templates/accounts/delete.html:12
|
||||||
msgid "Deleted accounts cannot be recovered."
|
msgid "Deleted accounts cannot be recovered."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: accounts/templates/accounts/delete.html:15
|
#: src/accounts/templates/accounts/delete.html:15
|
||||||
msgid "Password inccorect."
|
msgid "Password incorrect."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: accounts/templates/accounts/delete.html:17
|
#: src/accounts/templates/accounts/delete.html:17
|
||||||
msgid "Your account has been deleted."
|
msgid "Your account has been deleted."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: accounts/templates/accounts/delete.html:22
|
#: src/accounts/templates/accounts/delete.html:22
|
||||||
#: accounts/templates/accounts/login.html:19
|
#: src/accounts/templates/accounts/login.html:19
|
||||||
#: accounts/templates/accounts/register.html:23
|
#: src/accounts/templates/accounts/register.html:23
|
||||||
#: events/templates/events/create_team.html:26
|
#: src/events/templates/events/create_team.html:27
|
||||||
#: events/templates/events/join_team.html:31
|
#: src/events/templates/events/join_team.html:32
|
||||||
msgid "Password"
|
msgid "Password"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: accounts/templates/accounts/edit.html:21
|
#: src/accounts/templates/accounts/edit.html:21
|
||||||
#: accounts/templates/accounts/login.html:18
|
#: src/accounts/templates/accounts/login.html:18
|
||||||
#: accounts/templates/accounts/register.html:22
|
#: src/accounts/templates/accounts/register.html:22
|
||||||
#: ctfs/templates/ctfs/ctf_info.html:61 ctfs/templates/ctfs/ctfs_list.html:12
|
#: src/ctfs/templates/ctfs/ctf_info.html:63
|
||||||
#: events/templates/events/ctf_info.html:71
|
#: src/ctfs/templates/ctfs/ctfs_list.html:12
|
||||||
#: events/templates/events/event_info.html:64
|
#: src/events/templates/events/ctf_info.html:65
|
||||||
#: scoreboard/templates/scoreboard/scoreboard.html:13
|
#: src/events/templates/events/event_info.html:64
|
||||||
|
#: src/scoreboard/templates/scoreboard/scoreboard.html:13
|
||||||
msgid "Username"
|
msgid "Username"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: accounts/templates/accounts/edit.html:25
|
#: src/accounts/templates/accounts/edit.html:25
|
||||||
msgid "Email"
|
msgid "Email"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: accounts/templates/accounts/edit.html:30
|
#: src/accounts/templates/accounts/edit.html:30
|
||||||
#: ctfs/templates/ctfs/ctf_info.html:62
|
#: src/ctfs/templates/ctfs/ctf_info.html:64
|
||||||
#: events/templates/events/ctf_info.html:72
|
#: src/events/templates/events/ctf_info.html:66
|
||||||
#: events/templates/events/event_info.html:65
|
#: src/events/templates/events/event_info.html:65
|
||||||
#: scoreboard/templates/scoreboard/scoreboard.html:14
|
#: src/scoreboard/templates/scoreboard/scoreboard.html:14
|
||||||
msgid "Website"
|
msgid "Website"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: accounts/templates/accounts/edit.html:36
|
#: src/accounts/templates/accounts/edit.html:36
|
||||||
#: events/templates/events/manage_team.html:29
|
msgid " Apply"
|
||||||
msgid "Apply"
|
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: accounts/templates/accounts/edit.html:47
|
#: src/accounts/templates/accounts/edit.html:45
|
||||||
#: accounts/templates/accounts/profile.html:46
|
msgid "Connected accounts"
|
||||||
#: ctfs/templates/ctfs/ctf_info.html:63 ctfs/templates/ctfs/ctfs_list.html:13
|
msgstr ""
|
||||||
#: events/templates/events/event_info.html:66
|
|
||||||
#: events/templates/events/event_info.html:89
|
#: src/accounts/templates/accounts/edit.html:53
|
||||||
#: events/templates/events/manage_team.html:40
|
msgid "Disconnect Discord"
|
||||||
#: events/templates/events/team.html:45
|
msgstr ""
|
||||||
#: scoreboard/templates/scoreboard/scoreboard.html:15
|
|
||||||
|
#: src/accounts/templates/accounts/edit.html:59
|
||||||
|
msgid "Connect Discord"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/accounts/templates/accounts/edit.html:68
|
||||||
|
msgid "Disconnect 42"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/accounts/templates/accounts/edit.html:74
|
||||||
|
#: src/events/templates/events/event_pwd.html:19
|
||||||
|
msgid "Connect 42"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/accounts/templates/accounts/edit.html:85
|
||||||
|
#: src/accounts/templates/accounts/profile.html:46
|
||||||
|
#: src/ctfs/templates/ctfs/ctf_info.html:65
|
||||||
|
#: src/ctfs/templates/ctfs/ctfs_list.html:13
|
||||||
|
#: src/events/templates/events/event_info.html:66
|
||||||
|
#: src/events/templates/events/event_info.html:89
|
||||||
|
#: src/events/templates/events/manage_team.html:40
|
||||||
|
#: src/events/templates/events/team.html:45
|
||||||
|
#: src/scoreboard/templates/scoreboard/scoreboard.html:16
|
||||||
msgid "Score"
|
msgid "Score"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: accounts/templates/accounts/edit.html:55
|
#: src/accounts/templates/accounts/edit.html:93
|
||||||
#: accounts/templates/accounts/profile.html:60
|
#: src/accounts/templates/accounts/profile.html:60
|
||||||
msgid "Registered since"
|
msgid "Registered since"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: accounts/templates/accounts/edit.html:61
|
#: src/accounts/templates/accounts/edit.html:99
|
||||||
msgid "Delete my account"
|
msgid " Delete my account"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: accounts/templates/accounts/login.html:13
|
#: src/accounts/templates/accounts/login.html:13
|
||||||
msgid "Please, verify your infos."
|
msgid "Please, verify your infos."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: accounts/templates/accounts/login.html:22
|
#: src/accounts/templates/accounts/login.html:22
|
||||||
msgid "Reset password"
|
msgid "Reset password"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: accounts/templates/accounts/login.html:31
|
#: src/accounts/templates/accounts/login.html:31
|
||||||
#: accounts/templates/accounts/register.html:38 templates/base.html:103
|
#: src/accounts/templates/accounts/register.html:37 src/templates/base.html:97
|
||||||
#: templates/registration/password_reset_complete.html:18
|
#: src/templates/registration/password_reset_complete.html:18
|
||||||
#: templates/registration/password_reset_confirm.html:38
|
#: src/templates/registration/password_reset_confirm.html:38
|
||||||
#: templates/registration/password_reset_done.html:18
|
#: src/templates/registration/password_reset_done.html:18
|
||||||
#: templates/registration/password_reset_form.html:26
|
#: src/templates/registration/password_reset_form.html:26
|
||||||
msgid "Login"
|
msgid "Login"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: accounts/templates/accounts/login.html:32
|
#: src/accounts/templates/accounts/login.html:32
|
||||||
#: accounts/templates/accounts/register.html:37
|
#: src/accounts/templates/accounts/register.html:36
|
||||||
#: templates/registration/password_reset_complete.html:19
|
#: src/templates/registration/password_reset_complete.html:19
|
||||||
#: templates/registration/password_reset_confirm.html:39
|
#: src/templates/registration/password_reset_confirm.html:39
|
||||||
#: templates/registration/password_reset_done.html:19
|
#: src/templates/registration/password_reset_done.html:19
|
||||||
#: templates/registration/password_reset_form.html:27
|
#: src/templates/registration/password_reset_form.html:27
|
||||||
msgid "Sign up"
|
msgid "Sign up"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: accounts/templates/accounts/profile.html:10
|
#: src/accounts/templates/accounts/profile.html:10
|
||||||
msgid "Challenges Solved by"
|
msgid "Challenges Solved by"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: accounts/templates/accounts/profile.html:21
|
#: src/accounts/templates/accounts/profile.html:21
|
||||||
#: events/templates/events/team.html:20
|
#: src/events/templates/events/team.html:20
|
||||||
msgid "Challenge Name"
|
msgid "Challenge Name"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: accounts/templates/accounts/profile.html:22
|
#: src/accounts/templates/accounts/profile.html:22
|
||||||
#: events/templates/events/team.html:21
|
#: src/events/templates/events/team.html:21
|
||||||
msgid "Category"
|
msgid "Category"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: accounts/templates/accounts/profile.html:23
|
#: src/accounts/templates/accounts/profile.html:23
|
||||||
#: events/templates/events/team.html:22
|
#: src/events/templates/events/team.html:22
|
||||||
msgid "Points"
|
msgid "Points"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: accounts/templates/accounts/profile.html:24
|
#: src/accounts/templates/accounts/profile.html:24
|
||||||
#: ctfs/templates/ctfs/ctf_info.html:64
|
#: src/ctfs/templates/ctfs/ctf_info.html:66
|
||||||
#: events/templates/events/ctf_info.html:73
|
#: src/events/templates/events/ctf_info.html:67
|
||||||
#: events/templates/events/team.html:23
|
#: src/events/templates/events/team.html:23
|
||||||
msgid "Date"
|
msgid "Date"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: accounts/templates/accounts/profile.html:39
|
#: src/accounts/templates/accounts/profile.html:39
|
||||||
msgid "It seems that this user has not solved any challenge yet..."
|
msgid "It seems that this user has not solved any challenge yet..."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: accounts/templates/accounts/profile.html:47
|
#: src/accounts/templates/accounts/profile.html:47
|
||||||
#: events/templates/events/event_info.html:63
|
#: src/events/templates/events/event_info.html:63
|
||||||
#: events/templates/events/event_info.html:87
|
#: src/events/templates/events/event_info.html:87
|
||||||
#: events/templates/events/manage_team.html:41
|
#: src/events/templates/events/manage_team.html:41
|
||||||
#: events/templates/events/team.html:46
|
#: src/events/templates/events/team.html:46
|
||||||
#: scoreboard/templates/scoreboard/scoreboard.html:12
|
#: src/scoreboard/templates/scoreboard/scoreboard.html:12
|
||||||
msgid "Rank"
|
msgid "Rank"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: accounts/templates/accounts/profile.html:56
|
#: src/accounts/templates/accounts/profile.html:56
|
||||||
msgid "Status: Member"
|
msgid "Member"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: accounts/templates/accounts/profile.html:58
|
#: src/accounts/templates/accounts/profile.html:58
|
||||||
msgid "Status: Visitor"
|
msgid " Visitor"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: accounts/templates/accounts/profile.html:64
|
#: src/accounts/templates/accounts/profile.html:64
|
||||||
#: events/templates/events/team.html:57
|
#: src/events/templates/events/team.html:57
|
||||||
msgid "Categories stats"
|
msgid "Categories stats"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: accounts/templates/accounts/register.html:13
|
#: src/accounts/templates/accounts/profile.html:81
|
||||||
|
msgid "Challenges created"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/accounts/templates/accounts/profile.html:87
|
||||||
|
msgid "It seems that this user has not created any challenge yet..."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/accounts/templates/accounts/register.html:13
|
||||||
msgid "Welcome !"
|
msgid "Welcome !"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: accounts/templates/accounts/register.html:14
|
#: src/accounts/templates/accounts/register.html:14
|
||||||
msgid "Your account has been created."
|
msgid "Your account has been created."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: accounts/templates/accounts/register.html:25
|
#: src/accounts/templates/accounts/register.html:25
|
||||||
msgid "Personal website"
|
msgid "Personal website"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: accounts/templates/accounts/register.html:26
|
#: src/accounts/templates/accounts/register.html:26
|
||||||
#: events/templates/events/event_info.html:119
|
#: src/events/templates/events/event_info.html:119
|
||||||
msgid "Register"
|
msgid "Register"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: accounts/views/views.py:33
|
#: src/accounts/views/views.py:33
|
||||||
msgid "Your account was inactive."
|
msgid "Your account was inactive."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: accounts/views/views.py:52
|
#: src/accounts/views/views.py:57
|
||||||
|
msgid "The password must be at least 8 characters long."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/accounts/views/views.py:67
|
||||||
msgid ""
|
msgid ""
|
||||||
"The password must contain at least one letter and at least one digit or "
|
"The password must contain at least one letter and at least one digit or "
|
||||||
"punctuation character."
|
"punctuation character."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: accounts/views/views.py:54
|
#: src/accounts/views/views.py:77
|
||||||
msgid "A user with that email already exists."
|
msgid "A user with that email already exists."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: accounts/views/views.py:67
|
#: src/accounts/views/views.py:99
|
||||||
msgid "A user with that username already exists."
|
msgid "A user with that username already exists."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: accounts/views/views.py:95
|
#: src/accounts/views/views.py:132
|
||||||
msgid "Email already taken."
|
msgid "Email already taken."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: accounts/views/views.py:101
|
#: src/accounts/views/views.py:138
|
||||||
msgid "Username already taken."
|
msgid "Username already taken."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: accounts/views/views.py:105 events/views/teams.py:122
|
#: src/accounts/views/views.py:142 src/events/views/teams.py:124
|
||||||
msgid "Updated."
|
msgid "Updated."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ctfs/templates/ctfs/ctf_info.html:10
|
#: src/ctfs/templates/ctfs/ctf_info.html:12
|
||||||
#: events/templates/events/ctf_info.html:12
|
#: src/events/templates/events/ctf_info.html:12
|
||||||
msgid "Published date"
|
msgid "Published date"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ctfs/templates/ctfs/ctf_info.html:14
|
#: src/ctfs/templates/ctfs/ctf_info.html:16
|
||||||
msgid "Challenge is not yet available."
|
msgid "Challenge is not yet available."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ctfs/templates/ctfs/ctf_info.html:21
|
#: src/ctfs/templates/ctfs/ctf_info.html:29
|
||||||
#: events/templates/events/ctf_info.html:18 home/templates/home/home.html:46
|
#: src/events/templates/events/ctf_info.html:24
|
||||||
|
msgid "Congratulation !"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/ctfs/templates/ctfs/ctf_info.html:31
|
||||||
|
#: src/events/templates/events/ctf_info.html:26
|
||||||
|
msgid "Already flagged"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/ctfs/templates/ctfs/ctf_info.html:33
|
||||||
|
#: src/ctfs/templates/ctfs/ctf_info.html:42
|
||||||
|
#: src/events/templates/events/ctf_info.html:36
|
||||||
|
#: src/events/templates/events/ctf_info.html:45
|
||||||
|
msgid "Start the challenge"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/ctfs/templates/ctfs/ctf_info.html:35
|
||||||
|
#: src/ctfs/templates/ctfs/ctf_info.html:44
|
||||||
|
#: src/events/templates/events/ctf_info.html:38
|
||||||
|
#: src/events/templates/events/ctf_info.html:47
|
||||||
|
msgid "Download"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/ctfs/templates/ctfs/ctf_info.html:39
|
||||||
|
#: src/events/templates/events/ctf_info.html:42
|
||||||
|
msgid "Wrong flag ! You can do it !"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/ctfs/templates/ctfs/ctf_info.html:58
|
||||||
|
#: src/events/templates/events/ctf_info.html:60
|
||||||
|
msgid "Solved by"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/ctfs/templates/ctfs/ctf_info.html:82
|
||||||
|
#: src/events/templates/events/ctf_info.html:90
|
||||||
|
msgid "Nobody has solved this challenge yet."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/ctfs/templates/ctfs/ctf_info.html:89
|
||||||
|
#: src/events/templates/events/ctf_info.html:97
|
||||||
|
msgid "Author"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/ctfs/templates/ctfs/ctf_info.html:90
|
||||||
|
#: src/events/templates/events/ctf_info.html:98
|
||||||
|
msgid "Point reward"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/ctfs/templates/ctfs/ctfs_list.html:14
|
||||||
|
msgid "Solved"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/ctfs/templates/ctfs/ctfs_list.html:37
|
||||||
|
msgid "No ctf available for this category."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/ctfs/templates/ctfs/ctfs_list.html:42
|
||||||
|
msgid "Categories"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/ctfs/templates/ctfs/ctfs_list.html:48 src/templates/base.html:56
|
||||||
|
msgid "No category available."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/events/templates/events/create_team.html:10
|
||||||
|
#: src/events/templates/events/join_team.html:10
|
||||||
|
msgid "This event starts at"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/events/templates/events/create_team.html:17
|
||||||
|
#: src/events/templates/events/join_team.html:17
|
||||||
|
msgid "You need to be registered to the event."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/events/templates/events/create_team.html:20
|
||||||
|
#: src/events/views/teams.py:120
|
||||||
|
msgid "Name already taken."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/events/templates/events/create_team.html:26
|
||||||
|
#: src/events/templates/events/join_team.html:31
|
||||||
|
#: src/events/templates/events/manage_team.html:22
|
||||||
|
msgid "Team name"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/events/templates/events/create_team.html:28
|
||||||
|
#: src/events/templates/events/create_team.html:49
|
||||||
|
#: src/events/templates/events/join_team.html:54
|
||||||
|
msgid "Create Team"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/events/templates/events/create_team.html:33
|
||||||
|
#: src/events/templates/events/event_pwd.html:44
|
||||||
|
#: src/events/templates/events/join_team.html:38
|
||||||
|
msgid "You need to be logged to access this event."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/events/templates/events/create_team.html:42
|
||||||
|
#: src/events/templates/events/event_info.html:113
|
||||||
|
#: src/events/templates/events/event_pwd.html:52
|
||||||
|
#: src/events/templates/events/join_team.html:47
|
||||||
|
msgid "Starts at"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/events/templates/events/create_team.html:43
|
||||||
|
#: src/events/templates/events/event_info.html:114
|
||||||
|
#: src/events/templates/events/event_pwd.html:53
|
||||||
|
#: src/events/templates/events/join_team.html:48
|
||||||
|
msgid "Ends at"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/events/templates/events/create_team.html:47
|
||||||
|
#: src/events/templates/events/event_info.html:129
|
||||||
|
#: src/events/templates/events/join_team.html:52
|
||||||
|
msgid "Manage my team"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/events/templates/events/create_team.html:48
|
||||||
|
#: src/events/templates/events/join_team.html:33
|
||||||
|
#: src/events/templates/events/join_team.html:53
|
||||||
|
msgid "Join Team"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/events/templates/events/create_team.html:53
|
||||||
|
#: src/events/templates/events/join_team.html:58
|
||||||
|
msgid "Auto-matching"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/events/templates/events/create_team.html:57
|
||||||
|
#: src/events/templates/events/join_team.html:62
|
||||||
|
msgid "Find me a team !"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/events/templates/events/ctf_info.html:10
|
||||||
|
msgid "Event"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/events/templates/events/ctf_info.html:18
|
||||||
msgid ""
|
msgid ""
|
||||||
"No translation available. Please try another language (English or French)."
|
"No translation available. Please try another language (English or French)."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ctfs/templates/ctfs/ctf_info.html:27
|
#: src/events/templates/events/ctf_info.html:28
|
||||||
#: events/templates/events/ctf_info.html:32
|
#: src/events/templates/events/event_info.html:18
|
||||||
msgid "Congratulation !"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: ctfs/templates/ctfs/ctf_info.html:29
|
|
||||||
#: events/templates/events/ctf_info.html:34
|
|
||||||
msgid "Already flagged"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: ctfs/templates/ctfs/ctf_info.html:31 ctfs/templates/ctfs/ctf_info.html:40
|
|
||||||
#: events/templates/events/ctf_info.html:42
|
|
||||||
#: events/templates/events/ctf_info.html:51
|
|
||||||
msgid "Start the challenge"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: ctfs/templates/ctfs/ctf_info.html:33 ctfs/templates/ctfs/ctf_info.html:42
|
|
||||||
#: events/templates/events/ctf_info.html:44
|
|
||||||
#: events/templates/events/ctf_info.html:53
|
|
||||||
msgid "Download"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: ctfs/templates/ctfs/ctf_info.html:37
|
|
||||||
#: events/templates/events/ctf_info.html:48
|
|
||||||
msgid "Wrong flag ! You can do it !"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: ctfs/templates/ctfs/ctf_info.html:56
|
|
||||||
#: events/templates/events/ctf_info.html:66
|
|
||||||
msgid "Solved by"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: ctfs/templates/ctfs/ctf_info.html:80
|
|
||||||
#: events/templates/events/ctf_info.html:96
|
|
||||||
msgid "Nobody has solved this challenge yet."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: ctfs/templates/ctfs/ctf_info.html:87
|
|
||||||
#: events/templates/events/ctf_info.html:103
|
|
||||||
msgid "Author"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: ctfs/templates/ctfs/ctf_info.html:88
|
|
||||||
#: events/templates/events/ctf_info.html:104
|
|
||||||
msgid "Point reward"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: ctfs/templates/ctfs/ctfs_list.html:14
|
|
||||||
msgid "Solved"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: ctfs/templates/ctfs/ctfs_list.html:37
|
|
||||||
msgid "No ctf available for this category."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: ctfs/templates/ctfs/ctfs_list.html:42
|
|
||||||
msgid "Categories"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: ctfs/templates/ctfs/ctfs_list.html:48 templates/base.html:54
|
|
||||||
msgid "No category available."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: events/templates/events/create_team.html:9
|
|
||||||
#: events/templates/events/join_team.html:9
|
|
||||||
msgid "This event starts at"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: events/templates/events/create_team.html:16
|
|
||||||
#: events/templates/events/join_team.html:16
|
|
||||||
msgid "You need to be registered to the event."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: events/templates/events/create_team.html:19 events/views/teams.py:118
|
|
||||||
msgid "Name already taken."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: events/templates/events/create_team.html:25
|
|
||||||
#: events/templates/events/join_team.html:30
|
|
||||||
#: events/templates/events/manage_team.html:22
|
|
||||||
msgid "Team name"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: events/templates/events/create_team.html:27
|
|
||||||
#: events/templates/events/create_team.html:46
|
|
||||||
#: events/templates/events/join_team.html:52
|
|
||||||
msgid "Create Team"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: events/templates/events/create_team.html:32
|
|
||||||
#: events/templates/events/event_pwd.html:28
|
|
||||||
#: events/templates/events/join_team.html:37
|
|
||||||
msgid "You need to be logged to access this event."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: events/templates/events/create_team.html:41
|
|
||||||
#: events/templates/events/event_info.html:113
|
|
||||||
#: events/templates/events/event_pwd.html:36
|
|
||||||
#: events/templates/events/join_team.html:46
|
|
||||||
msgid "Starts at"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: events/templates/events/create_team.html:42
|
|
||||||
#: events/templates/events/event_info.html:114
|
|
||||||
#: events/templates/events/event_pwd.html:37
|
|
||||||
#: events/templates/events/join_team.html:47
|
|
||||||
msgid "Ends at"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: events/templates/events/create_team.html:47
|
|
||||||
#: events/templates/events/join_team.html:32
|
|
||||||
#: events/templates/events/join_team.html:51
|
|
||||||
msgid "Join Team"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: events/templates/events/create_team.html:54
|
|
||||||
#: events/templates/events/join_team.html:59
|
|
||||||
msgid "Find me a team !"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: events/templates/events/ctf_info.html:10
|
|
||||||
msgid "Event"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: events/templates/events/ctf_info.html:25
|
|
||||||
#: events/templates/events/event_info.html:9
|
|
||||||
msgid "Subscriptions is over."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: events/templates/events/ctf_info.html:28
|
|
||||||
#: events/templates/events/event_info.html:12
|
|
||||||
#: events/templates/events/event_pwd.html:18
|
|
||||||
msgid "You're already registered to this event."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: events/templates/events/ctf_info.html:36
|
|
||||||
#: events/templates/events/event_info.html:18
|
|
||||||
msgid "This event is over."
|
msgid "This event is over."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: events/templates/events/ctf_info.html:38
|
#: src/events/templates/events/ctf_info.html:30
|
||||||
msgid "Error while processing your request. (Invalid Form)"
|
msgid "Error while processing your request. (Invalid Form)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: events/templates/events/ctf_info.html:40
|
#: src/events/templates/events/ctf_info.html:32
|
||||||
msgid ""
|
msgid "You must register to the event before submitting flags."
|
||||||
"Error: you're not registered to this event, so you can't register scores, "
|
|
||||||
"fucking logic."
|
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: events/templates/events/event_info.html:20
|
#: src/events/templates/events/ctf_info.html:34
|
||||||
#: events/templates/events/event_pwd.html:9
|
msgid ""
|
||||||
|
"This is a team event, please create or join a team before submitting flags."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/events/templates/events/event_info.html:9
|
||||||
|
msgid "Subscriptions is over."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/events/templates/events/event_info.html:12
|
||||||
|
#: src/events/templates/events/event_pwd.html:33
|
||||||
|
msgid "You're already registered to this event."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/events/templates/events/event_info.html:20
|
||||||
|
#: src/events/templates/events/event_pwd.html:9
|
||||||
msgid "This event start at"
|
msgid "This event start at"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: events/templates/events/event_info.html:30
|
#: src/events/templates/events/event_info.html:30
|
||||||
msgid "Challenges"
|
msgid "Challenges"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: events/templates/events/event_info.html:47
|
#: src/events/templates/events/event_info.html:47
|
||||||
msgid "No challenges available."
|
msgid "No challenges available."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: events/templates/events/event_info.html:51
|
#: src/events/templates/events/event_info.html:51
|
||||||
msgid "The event has not started yet."
|
msgid "The event has not started yet."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: events/templates/events/event_info.html:57
|
#: src/events/templates/events/event_info.html:57
|
||||||
msgid "ScoreBoard"
|
msgid "ScoreBoard"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: events/templates/events/event_info.html:88
|
#: src/events/templates/events/event_info.html:88
|
||||||
msgid "Team"
|
msgid "Team"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: events/templates/events/event_info.html:106
|
#: src/events/templates/events/event_info.html:106
|
||||||
msgid "No one have earn point yet, you gonna be the first ?"
|
msgid "No one have earn point yet, you gonna be the first ?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: events/templates/events/event_info.html:129
|
#: src/events/templates/events/event_pwd.html:16
|
||||||
msgid "Manage my team"
|
msgid ""
|
||||||
|
"This event is reserved for one or more 42 campuses. If you have not "
|
||||||
|
"connected your intranet to 42CTF, you can do so with this button: "
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: events/templates/events/event_pwd.html:15
|
#: src/events/templates/events/event_pwd.html:25
|
||||||
#: events/templates/events/join_team.html:21
|
msgid ""
|
||||||
|
"This event is reserved for one or more 42 campuses. And unfortunately your "
|
||||||
|
"campus can't participate. Do not hesitate to contact us to organize an event "
|
||||||
|
"on your campus!"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/events/templates/events/event_pwd.html:30
|
||||||
|
#: src/events/templates/events/join_team.html:22
|
||||||
msgid "Wrong password submited."
|
msgid "Wrong password submited."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: events/templates/events/event_pwd.html:20
|
#: src/events/templates/events/event_pwd.html:35
|
||||||
msgid "This event is password protected"
|
msgid "This event is password protected"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: events/templates/events/event_pwd.html:21
|
#: src/events/templates/events/event_pwd.html:36
|
||||||
msgid "You need to submit the event password to gain access to this event."
|
msgid "You need to submit the event password to gain access to this event."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: events/templates/events/events_list.html:6 templates/base.html:63
|
#: src/events/templates/events/events_list.html:6 src/templates/base.html:65
|
||||||
msgid "Events"
|
msgid "Events"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: events/templates/events/events_list.html:38
|
#: src/events/templates/events/events_list.html:38
|
||||||
msgid "See more"
|
msgid "See more"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: events/templates/events/events_list.html:44
|
#: src/events/templates/events/events_list.html:44
|
||||||
msgid "No events available."
|
msgid "No events available."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: events/templates/events/join_team.html:19
|
#: src/events/templates/events/join_team.html:20
|
||||||
msgid "Team does not exist."
|
msgid "Team does not exist."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: events/templates/events/join_team.html:23
|
#: src/events/templates/events/join_team.html:24
|
||||||
msgid "Maximum size reached."
|
msgid "Maximum size reached."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: events/templates/events/manage_team.html:26
|
#: src/events/templates/events/manage_team.html:26
|
||||||
msgid "Team password"
|
msgid "Team password"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: events/templates/events/manage_team.html:44
|
#: src/events/templates/events/manage_team.html:29
|
||||||
#: events/templates/events/team.html:49
|
msgid "Apply"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/events/templates/events/manage_team.html:44
|
||||||
|
#: src/events/templates/events/team.html:49
|
||||||
msgid "Members"
|
msgid "Members"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: events/templates/events/manage_team.html:51
|
#: src/events/templates/events/manage_team.html:52
|
||||||
msgid "Leave Team"
|
msgid "Leave Team"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: events/templates/events/team.html:38
|
#: src/events/templates/events/manage_team.html:59
|
||||||
|
msgid "Open to automatching"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/events/templates/events/manage_team.html:66
|
||||||
|
msgid "Close to automatching"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/events/templates/events/team.html:38
|
||||||
msgid "It seems that this team has not solved any challenge yet..."
|
msgid "It seems that this team has not solved any challenge yet..."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: home/templates/home/home.html:20
|
#: src/home/templates/home/home.html:21
|
||||||
msgid "Weekly Top 5"
|
msgid "Weekly Top 5"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: home/templates/home/home.html:56
|
#: src/home/templates/home/home.html:48
|
||||||
msgid "No article available."
|
msgid "No article available."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: home/templates/home/home.html:61
|
#: src/home/templates/home/home.html:53
|
||||||
msgid "Latest challenges added"
|
msgid "Latest challenges added"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: home/templates/home/home.html:66
|
#: src/home/templates/home/home.html:58
|
||||||
msgid "points"
|
msgid "points"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: home/templates/home/home.html:70
|
#: src/home/templates/home/home.html:62
|
||||||
msgid "No ctf available."
|
msgid "No ctf available."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: home/templates/home/home.html:74
|
#: src/home/templates/home/home.html:66
|
||||||
msgid "Latest Flags"
|
msgid "Latest Flags"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: home/templates/home/home.html:88
|
#: src/home/templates/home/home.html:80
|
||||||
msgid "Flags"
|
msgid "Flags"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: home/templates/home/home.html:94
|
#: src/home/templates/home/home.html:86
|
||||||
msgid "Users"
|
msgid "Users"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: project/settings.py:115
|
#: src/project/settings.py:116
|
||||||
msgid "English"
|
msgid "English"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: project/settings.py:116
|
#: src/project/settings.py:117
|
||||||
msgid "German"
|
msgid "German"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: project/settings.py:117
|
#: src/project/settings.py:118
|
||||||
msgid "French"
|
msgid "French"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: project/settings.py:118
|
#: src/project/settings.py:119
|
||||||
msgid "Russian"
|
msgid "Russian"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: scoreboard/templates/scoreboard/scoreboard.html:38
|
#: src/project/settings.py:120
|
||||||
|
msgid "Japanese"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/project/settings.py:121
|
||||||
|
msgid "Spanish"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/scoreboard/templates/scoreboard/scoreboard.html:15
|
||||||
|
msgid "Campus"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/scoreboard/templates/scoreboard/scoreboard.html:46
|
||||||
msgid "First"
|
msgid "First"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: scoreboard/templates/scoreboard/scoreboard.html:39
|
#: src/scoreboard/templates/scoreboard/scoreboard.html:47
|
||||||
msgid "Previous"
|
msgid "Previous"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: scoreboard/templates/scoreboard/scoreboard.html:43
|
#: src/scoreboard/templates/scoreboard/scoreboard.html:51
|
||||||
msgid "Page "
|
msgid "Page "
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: scoreboard/templates/scoreboard/scoreboard.html:47
|
#: src/scoreboard/templates/scoreboard/scoreboard.html:55
|
||||||
msgid "Next"
|
msgid "Next"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: scoreboard/templates/scoreboard/scoreboard.html:48
|
#: src/scoreboard/templates/scoreboard/scoreboard.html:56
|
||||||
msgid "Last"
|
msgid "Last"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/base.html:59
|
#: src/templates/base.html:62
|
||||||
msgid "Scoreboard"
|
msgid "Scoreboard"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/base.html:66
|
#: src/templates/base.html:83
|
||||||
msgid "Resources"
|
msgid "Become a member"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/base.html:99
|
#: src/templates/base.html:93
|
||||||
msgid "Logout"
|
msgid "Logout"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/base.html:106
|
#: src/templates/base.html:100
|
||||||
msgid "Sign Up"
|
msgid "Sign Up"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/base.html:144
|
#: src/templates/registration/password_reset_complete.html:11
|
||||||
msgid "Become a Patron!"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: templates/registration/password_reset_complete.html:11
|
|
||||||
msgid "Your new password has been set."
|
msgid "Your new password has been set."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/registration/password_reset_confirm.html:20
|
#: src/templates/registration/password_reset_confirm.html:20
|
||||||
msgid "Your password can’t be too similar to your other personal information."
|
msgid "Your password can’t be too similar to your other personal information."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/registration/password_reset_confirm.html:21
|
#: src/templates/registration/password_reset_confirm.html:21
|
||||||
msgid "Your password must contain at least 8 characters."
|
msgid "Your password must contain at least 8 characters."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/registration/password_reset_confirm.html:22
|
#: src/templates/registration/password_reset_confirm.html:22
|
||||||
msgid "Your password can’t be a commonly used password."
|
msgid "Your password can’t be a commonly used password."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/registration/password_reset_confirm.html:23
|
#: src/templates/registration/password_reset_confirm.html:23
|
||||||
msgid "Your password can’t be entirely numeric."
|
msgid "Your password can’t be entirely numeric."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/registration/password_reset_confirm.html:26
|
#: src/templates/registration/password_reset_confirm.html:26
|
||||||
msgid "Confirm"
|
msgid "Confirm"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/registration/password_reset_confirm.html:28
|
#: src/templates/registration/password_reset_confirm.html:28
|
||||||
msgid "Submit"
|
msgid "Submit"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/registration/password_reset_done.html:11
|
#: src/templates/registration/password_reset_done.html:11
|
||||||
msgid ""
|
msgid ""
|
||||||
"We've emailed you instructions for setting your password. You should receive "
|
"We've emailed you instructions for setting your password. You should receive "
|
||||||
"the email shortly!"
|
"the email shortly!"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/registration/password_reset_form.html:16
|
#: src/templates/registration/password_reset_form.html:16
|
||||||
msgid "Reset"
|
msgid "Reset"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -8,7 +8,7 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2022-02-02 19:22+0100\n"
|
"POT-Creation-Date: 2022-08-16 19:28+0200\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
|
@ -18,189 +18,241 @@ msgstr ""
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||||
|
|
||||||
#: accounts/templates/accounts/delete.html:8
|
#: src/accounts/templates/accounts/delete.html:8
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
#| msgid "Connected accounts"
|
#| msgid "Connected accounts"
|
||||||
msgid "Delete account"
|
msgid "Delete account"
|
||||||
msgstr "Comptes connectés"
|
msgstr "Comptes connectés"
|
||||||
|
|
||||||
#: accounts/templates/accounts/delete.html:11
|
#: src/accounts/templates/accounts/delete.html:11
|
||||||
msgid "Please confirm your password to delete your account."
|
msgid "Please confirm your password to delete your account."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: accounts/templates/accounts/delete.html:12
|
#: src/accounts/templates/accounts/delete.html:12
|
||||||
msgid "Deleted accounts cannot be recovered."
|
msgid "Deleted accounts cannot be recovered."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: accounts/templates/accounts/delete.html:15
|
#: src/accounts/templates/accounts/delete.html:15
|
||||||
msgid "Password inccorect."
|
msgid "Password incorrect."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: accounts/templates/accounts/delete.html:17
|
#: src/accounts/templates/accounts/delete.html:17
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
#| msgid "Your account has been created."
|
#| msgid "Your account has been created."
|
||||||
msgid "Your account has been deleted."
|
msgid "Your account has been deleted."
|
||||||
msgstr "Votre compte a été créé."
|
msgstr "Votre compte a été créé."
|
||||||
|
|
||||||
#: accounts/templates/accounts/delete.html:22
|
#: src/accounts/templates/accounts/delete.html:22
|
||||||
#: accounts/templates/accounts/login.html:19
|
#: src/accounts/templates/accounts/login.html:19
|
||||||
#: accounts/templates/accounts/register.html:23
|
#: src/accounts/templates/accounts/register.html:23
|
||||||
#: events/templates/events/create_team.html:26
|
#: src/events/templates/events/create_team.html:27
|
||||||
#: events/templates/events/join_team.html:31
|
#: src/events/templates/events/join_team.html:32
|
||||||
msgid "Password"
|
msgid "Password"
|
||||||
msgstr "Mot de passe"
|
msgstr "Mot de passe"
|
||||||
|
|
||||||
#: accounts/templates/accounts/edit.html:21
|
#: src/accounts/templates/accounts/edit.html:21
|
||||||
#: accounts/templates/accounts/login.html:18
|
#: src/accounts/templates/accounts/login.html:18
|
||||||
#: accounts/templates/accounts/register.html:22
|
#: src/accounts/templates/accounts/register.html:22
|
||||||
#: ctfs/templates/ctfs/ctf_info.html:61 ctfs/templates/ctfs/ctfs_list.html:12
|
#: src/ctfs/templates/ctfs/ctf_info.html:63
|
||||||
#: events/templates/events/ctf_info.html:71
|
#: src/ctfs/templates/ctfs/ctfs_list.html:12
|
||||||
#: events/templates/events/event_info.html:64
|
#: src/events/templates/events/ctf_info.html:65
|
||||||
#: scoreboard/templates/scoreboard/scoreboard.html:13
|
#: src/events/templates/events/event_info.html:64
|
||||||
|
#: src/scoreboard/templates/scoreboard/scoreboard.html:13
|
||||||
msgid "Username"
|
msgid "Username"
|
||||||
msgstr "Pseudo"
|
msgstr "Pseudo"
|
||||||
|
|
||||||
#: accounts/templates/accounts/edit.html:25
|
#: src/accounts/templates/accounts/edit.html:25
|
||||||
msgid "Email"
|
msgid "Email"
|
||||||
msgstr "Email"
|
msgstr "Email"
|
||||||
|
|
||||||
#: accounts/templates/accounts/edit.html:30
|
#: src/accounts/templates/accounts/edit.html:30
|
||||||
#: ctfs/templates/ctfs/ctf_info.html:62
|
#: src/ctfs/templates/ctfs/ctf_info.html:64
|
||||||
#: events/templates/events/ctf_info.html:72
|
#: src/events/templates/events/ctf_info.html:66
|
||||||
#: events/templates/events/event_info.html:65
|
#: src/events/templates/events/event_info.html:65
|
||||||
#: scoreboard/templates/scoreboard/scoreboard.html:14
|
#: src/scoreboard/templates/scoreboard/scoreboard.html:14
|
||||||
msgid "Website"
|
msgid "Website"
|
||||||
msgstr "Site internet"
|
msgstr "Site internet"
|
||||||
|
|
||||||
#: accounts/templates/accounts/edit.html:36
|
#: src/accounts/templates/accounts/edit.html:36
|
||||||
#: events/templates/events/manage_team.html:29
|
#, fuzzy
|
||||||
msgid "Apply"
|
#| msgid "Apply"
|
||||||
|
msgid " Apply"
|
||||||
msgstr "Appliquer"
|
msgstr "Appliquer"
|
||||||
|
|
||||||
#: accounts/templates/accounts/edit.html:47
|
#: src/accounts/templates/accounts/edit.html:45
|
||||||
#: accounts/templates/accounts/profile.html:46
|
#, fuzzy
|
||||||
#: ctfs/templates/ctfs/ctf_info.html:63 ctfs/templates/ctfs/ctfs_list.html:13
|
#| msgid "Connected accounts"
|
||||||
#: events/templates/events/event_info.html:66
|
msgid "Connected accounts"
|
||||||
#: events/templates/events/event_info.html:89
|
msgstr "Comptes connectés"
|
||||||
#: events/templates/events/manage_team.html:40
|
|
||||||
#: events/templates/events/team.html:45
|
#: src/accounts/templates/accounts/edit.html:53
|
||||||
#: scoreboard/templates/scoreboard/scoreboard.html:15
|
msgid "Disconnect Discord"
|
||||||
|
msgstr "Déconnecter Discord"
|
||||||
|
|
||||||
|
#: src/accounts/templates/accounts/edit.html:59
|
||||||
|
msgid "Connect Discord"
|
||||||
|
msgstr "Connecter Discord"
|
||||||
|
|
||||||
|
#: src/accounts/templates/accounts/edit.html:68
|
||||||
|
#, fuzzy
|
||||||
|
#| msgid "Disconnect Discord"
|
||||||
|
msgid "Disconnect 42"
|
||||||
|
msgstr "Déconnecter Discord"
|
||||||
|
|
||||||
|
#: src/accounts/templates/accounts/edit.html:74
|
||||||
|
#: src/events/templates/events/event_pwd.html:19
|
||||||
|
#, fuzzy
|
||||||
|
#| msgid "Connect Discord"
|
||||||
|
msgid "Connect 42"
|
||||||
|
msgstr "Connecter Discord"
|
||||||
|
|
||||||
|
#: src/accounts/templates/accounts/edit.html:85
|
||||||
|
#: src/accounts/templates/accounts/profile.html:46
|
||||||
|
#: src/ctfs/templates/ctfs/ctf_info.html:65
|
||||||
|
#: src/ctfs/templates/ctfs/ctfs_list.html:13
|
||||||
|
#: src/events/templates/events/event_info.html:66
|
||||||
|
#: src/events/templates/events/event_info.html:89
|
||||||
|
#: src/events/templates/events/manage_team.html:40
|
||||||
|
#: src/events/templates/events/team.html:45
|
||||||
|
#: src/scoreboard/templates/scoreboard/scoreboard.html:16
|
||||||
msgid "Score"
|
msgid "Score"
|
||||||
msgstr "Score"
|
msgstr "Score"
|
||||||
|
|
||||||
#: accounts/templates/accounts/edit.html:55
|
#: src/accounts/templates/accounts/edit.html:93
|
||||||
#: accounts/templates/accounts/profile.html:60
|
#: src/accounts/templates/accounts/profile.html:60
|
||||||
msgid "Registered since"
|
msgid "Registered since"
|
||||||
msgstr "Inscrit depuis"
|
msgstr "Inscrit depuis"
|
||||||
|
|
||||||
#: accounts/templates/accounts/edit.html:61
|
#: src/accounts/templates/accounts/edit.html:99
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
#| msgid "Connected accounts"
|
#| msgid "Connected accounts"
|
||||||
msgid "Delete my account"
|
msgid " Delete my account"
|
||||||
msgstr "Comptes connectés"
|
msgstr "Comptes connectés"
|
||||||
|
|
||||||
#: accounts/templates/accounts/login.html:13
|
#: src/accounts/templates/accounts/login.html:13
|
||||||
msgid "Please, verify your infos."
|
msgid "Please, verify your infos."
|
||||||
msgstr "Merci de vérifier vos informations."
|
msgstr "Merci de vérifier vos informations."
|
||||||
|
|
||||||
#: accounts/templates/accounts/login.html:22
|
#: src/accounts/templates/accounts/login.html:22
|
||||||
msgid "Reset password"
|
msgid "Reset password"
|
||||||
msgstr "Réinitialiser le mot de passe"
|
msgstr "Réinitialiser le mot de passe"
|
||||||
|
|
||||||
#: accounts/templates/accounts/login.html:31
|
#: src/accounts/templates/accounts/login.html:31
|
||||||
#: accounts/templates/accounts/register.html:38 templates/base.html:103
|
#: src/accounts/templates/accounts/register.html:37 src/templates/base.html:97
|
||||||
#: templates/registration/password_reset_complete.html:18
|
#: src/templates/registration/password_reset_complete.html:18
|
||||||
#: templates/registration/password_reset_confirm.html:38
|
#: src/templates/registration/password_reset_confirm.html:38
|
||||||
#: templates/registration/password_reset_done.html:18
|
#: src/templates/registration/password_reset_done.html:18
|
||||||
#: templates/registration/password_reset_form.html:26
|
#: src/templates/registration/password_reset_form.html:26
|
||||||
msgid "Login"
|
msgid "Login"
|
||||||
msgstr "Connexion"
|
msgstr "Connexion"
|
||||||
|
|
||||||
#: accounts/templates/accounts/login.html:32
|
#: src/accounts/templates/accounts/login.html:32
|
||||||
#: accounts/templates/accounts/register.html:37
|
#: src/accounts/templates/accounts/register.html:36
|
||||||
#: templates/registration/password_reset_complete.html:19
|
#: src/templates/registration/password_reset_complete.html:19
|
||||||
#: templates/registration/password_reset_confirm.html:39
|
#: src/templates/registration/password_reset_confirm.html:39
|
||||||
#: templates/registration/password_reset_done.html:19
|
#: src/templates/registration/password_reset_done.html:19
|
||||||
#: templates/registration/password_reset_form.html:27
|
#: src/templates/registration/password_reset_form.html:27
|
||||||
msgid "Sign up"
|
msgid "Sign up"
|
||||||
msgstr "Inscription"
|
msgstr "Inscription"
|
||||||
|
|
||||||
#: accounts/templates/accounts/profile.html:10
|
#: src/accounts/templates/accounts/profile.html:10
|
||||||
msgid "Challenges Solved by"
|
msgid "Challenges Solved by"
|
||||||
msgstr "Challenges résolus par"
|
msgstr "Challenges résolus par"
|
||||||
|
|
||||||
#: accounts/templates/accounts/profile.html:21
|
#: src/accounts/templates/accounts/profile.html:21
|
||||||
#: events/templates/events/team.html:20
|
#: src/events/templates/events/team.html:20
|
||||||
msgid "Challenge Name"
|
msgid "Challenge Name"
|
||||||
msgstr "Nom du challenge"
|
msgstr "Nom du challenge"
|
||||||
|
|
||||||
#: accounts/templates/accounts/profile.html:22
|
#: src/accounts/templates/accounts/profile.html:22
|
||||||
#: events/templates/events/team.html:21
|
#: src/events/templates/events/team.html:21
|
||||||
msgid "Category"
|
msgid "Category"
|
||||||
msgstr "Catégorie"
|
msgstr "Catégorie"
|
||||||
|
|
||||||
#: accounts/templates/accounts/profile.html:23
|
#: src/accounts/templates/accounts/profile.html:23
|
||||||
#: events/templates/events/team.html:22
|
#: src/events/templates/events/team.html:22
|
||||||
msgid "Points"
|
msgid "Points"
|
||||||
msgstr "Points"
|
msgstr "Points"
|
||||||
|
|
||||||
#: accounts/templates/accounts/profile.html:24
|
#: src/accounts/templates/accounts/profile.html:24
|
||||||
#: ctfs/templates/ctfs/ctf_info.html:64
|
#: src/ctfs/templates/ctfs/ctf_info.html:66
|
||||||
#: events/templates/events/ctf_info.html:73
|
#: src/events/templates/events/ctf_info.html:67
|
||||||
#: events/templates/events/team.html:23
|
#: src/events/templates/events/team.html:23
|
||||||
msgid "Date"
|
msgid "Date"
|
||||||
msgstr "Date"
|
msgstr "Date"
|
||||||
|
|
||||||
#: accounts/templates/accounts/profile.html:39
|
#: src/accounts/templates/accounts/profile.html:39
|
||||||
msgid "It seems that this user has not solved any challenge yet..."
|
msgid "It seems that this user has not solved any challenge yet..."
|
||||||
msgstr "Il semble que cet utilisateur n'a pas encore résolu de CTF..."
|
msgstr "Il semble que cet utilisateur n'a pas encore résolu de CTF..."
|
||||||
|
|
||||||
#: accounts/templates/accounts/profile.html:47
|
#: src/accounts/templates/accounts/profile.html:47
|
||||||
#: events/templates/events/event_info.html:63
|
#: src/events/templates/events/event_info.html:63
|
||||||
#: events/templates/events/event_info.html:87
|
#: src/events/templates/events/event_info.html:87
|
||||||
#: events/templates/events/manage_team.html:41
|
#: src/events/templates/events/manage_team.html:41
|
||||||
#: events/templates/events/team.html:46
|
#: src/events/templates/events/team.html:46
|
||||||
#: scoreboard/templates/scoreboard/scoreboard.html:12
|
#: src/scoreboard/templates/scoreboard/scoreboard.html:12
|
||||||
msgid "Rank"
|
msgid "Rank"
|
||||||
msgstr "Rang"
|
msgstr "Rang"
|
||||||
|
|
||||||
#: accounts/templates/accounts/profile.html:56
|
#: src/accounts/templates/accounts/profile.html:56
|
||||||
msgid "Status: Member"
|
#, fuzzy
|
||||||
msgstr "Status : Membre"
|
#| msgid "Members"
|
||||||
|
msgid "Member"
|
||||||
|
msgstr "Membres"
|
||||||
|
|
||||||
#: accounts/templates/accounts/profile.html:58
|
#: src/accounts/templates/accounts/profile.html:58
|
||||||
msgid "Status: Visitor"
|
#, fuzzy
|
||||||
|
#| msgid "Status: Visitor"
|
||||||
|
msgid " Visitor"
|
||||||
msgstr "Status : Visiteur"
|
msgstr "Status : Visiteur"
|
||||||
|
|
||||||
#: accounts/templates/accounts/profile.html:64
|
#: src/accounts/templates/accounts/profile.html:64
|
||||||
#: events/templates/events/team.html:57
|
#: src/events/templates/events/team.html:57
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
#| msgid "Categories"
|
#| msgid "Categories"
|
||||||
msgid "Categories stats"
|
msgid "Categories stats"
|
||||||
msgstr "Catégories"
|
msgstr "Catégories"
|
||||||
|
|
||||||
#: accounts/templates/accounts/register.html:13
|
#: src/accounts/templates/accounts/profile.html:81
|
||||||
|
#, fuzzy
|
||||||
|
#| msgid "Challenge Name"
|
||||||
|
msgid "Challenges created"
|
||||||
|
msgstr "Nom du challenge"
|
||||||
|
|
||||||
|
#: src/accounts/templates/accounts/profile.html:87
|
||||||
|
#, fuzzy
|
||||||
|
#| msgid "It seems that this user has not solved any challenge yet..."
|
||||||
|
msgid "It seems that this user has not created any challenge yet..."
|
||||||
|
msgstr "Il semble que cet utilisateur n'a pas encore résolu de CTF..."
|
||||||
|
|
||||||
|
#: src/accounts/templates/accounts/register.html:13
|
||||||
msgid "Welcome !"
|
msgid "Welcome !"
|
||||||
msgstr "Bienvenue !"
|
msgstr "Bienvenue !"
|
||||||
|
|
||||||
#: accounts/templates/accounts/register.html:14
|
#: src/accounts/templates/accounts/register.html:14
|
||||||
msgid "Your account has been created."
|
msgid "Your account has been created."
|
||||||
msgstr "Votre compte a été créé."
|
msgstr "Votre compte a été créé."
|
||||||
|
|
||||||
#: accounts/templates/accounts/register.html:25
|
#: src/accounts/templates/accounts/register.html:25
|
||||||
msgid "Personal website"
|
msgid "Personal website"
|
||||||
msgstr "Site personnel"
|
msgstr "Site personnel"
|
||||||
|
|
||||||
#: accounts/templates/accounts/register.html:26
|
#: src/accounts/templates/accounts/register.html:26
|
||||||
#: events/templates/events/event_info.html:119
|
#: src/events/templates/events/event_info.html:119
|
||||||
msgid "Register"
|
msgid "Register"
|
||||||
msgstr "Inscription"
|
msgstr "Inscription"
|
||||||
|
|
||||||
#: accounts/views/views.py:33
|
#: src/accounts/views/views.py:33
|
||||||
msgid "Your account was inactive."
|
msgid "Your account was inactive."
|
||||||
msgstr "Votre compte était inactif."
|
msgstr "Votre compte était inactif."
|
||||||
|
|
||||||
#: accounts/views/views.py:52
|
#: src/accounts/views/views.py:57
|
||||||
|
#, fuzzy
|
||||||
|
#| msgid "Your password must contain at least 8 characters."
|
||||||
|
msgid "The password must be at least 8 characters long."
|
||||||
|
msgstr "Votre mot de passe doit contenir au moins 8 caractères."
|
||||||
|
|
||||||
|
#: src/accounts/views/views.py:67
|
||||||
msgid ""
|
msgid ""
|
||||||
"The password must contain at least one letter and at least one digit or "
|
"The password must contain at least one letter and at least one digit or "
|
||||||
"punctuation character."
|
"punctuation character."
|
||||||
|
@ -208,411 +260,454 @@ msgstr ""
|
||||||
"Le mot de passe doit contenir au moins une lettre, un chiffre et un signe de "
|
"Le mot de passe doit contenir au moins une lettre, un chiffre et un signe de "
|
||||||
"ponctuation."
|
"ponctuation."
|
||||||
|
|
||||||
#: accounts/views/views.py:54
|
#: src/accounts/views/views.py:77
|
||||||
msgid "A user with that email already exists."
|
msgid "A user with that email already exists."
|
||||||
msgstr "Un utilisateur avec cet email existe déjà."
|
msgstr "Un utilisateur avec cet email existe déjà."
|
||||||
|
|
||||||
#: accounts/views/views.py:67
|
#: src/accounts/views/views.py:99
|
||||||
msgid "A user with that username already exists."
|
msgid "A user with that username already exists."
|
||||||
msgstr "Un utilisateur avec ce pseudo existe déjà."
|
msgstr "Un utilisateur avec ce pseudo existe déjà."
|
||||||
|
|
||||||
#: accounts/views/views.py:95
|
#: src/accounts/views/views.py:132
|
||||||
msgid "Email already taken."
|
msgid "Email already taken."
|
||||||
msgstr "L'adresse mail est déjà utilisée."
|
msgstr "L'adresse mail est déjà utilisée."
|
||||||
|
|
||||||
#: accounts/views/views.py:101
|
#: src/accounts/views/views.py:138
|
||||||
msgid "Username already taken."
|
msgid "Username already taken."
|
||||||
msgstr "Le pseudo est déjà utilisé."
|
msgstr "Le pseudo est déjà utilisé."
|
||||||
|
|
||||||
#: accounts/views/views.py:105 events/views/teams.py:122
|
#: src/accounts/views/views.py:142 src/events/views/teams.py:124
|
||||||
msgid "Updated."
|
msgid "Updated."
|
||||||
msgstr "Mis à jour."
|
msgstr "Mis à jour."
|
||||||
|
|
||||||
#: ctfs/templates/ctfs/ctf_info.html:10
|
#: src/ctfs/templates/ctfs/ctf_info.html:12
|
||||||
#: events/templates/events/ctf_info.html:12
|
#: src/events/templates/events/ctf_info.html:12
|
||||||
msgid "Published date"
|
msgid "Published date"
|
||||||
msgstr "Date de publication"
|
msgstr "Date de publication"
|
||||||
|
|
||||||
#: ctfs/templates/ctfs/ctf_info.html:14
|
#: src/ctfs/templates/ctfs/ctf_info.html:16
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
#| msgid "No category available."
|
#| msgid "No category available."
|
||||||
msgid "Challenge is not yet available."
|
msgid "Challenge is not yet available."
|
||||||
msgstr "Il n'y a pas de catégorie disponible."
|
msgstr "Il n'y a pas de catégorie disponible."
|
||||||
|
|
||||||
#: ctfs/templates/ctfs/ctf_info.html:21
|
#: src/ctfs/templates/ctfs/ctf_info.html:29
|
||||||
#: events/templates/events/ctf_info.html:18 home/templates/home/home.html:46
|
#: src/events/templates/events/ctf_info.html:24
|
||||||
msgid ""
|
|
||||||
"No translation available. Please try another language (English or French)."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: ctfs/templates/ctfs/ctf_info.html:27
|
|
||||||
#: events/templates/events/ctf_info.html:32
|
|
||||||
msgid "Congratulation !"
|
msgid "Congratulation !"
|
||||||
msgstr "Félicitations !"
|
msgstr "Félicitations !"
|
||||||
|
|
||||||
#: ctfs/templates/ctfs/ctf_info.html:29
|
#: src/ctfs/templates/ctfs/ctf_info.html:31
|
||||||
#: events/templates/events/ctf_info.html:34
|
#: src/events/templates/events/ctf_info.html:26
|
||||||
msgid "Already flagged"
|
msgid "Already flagged"
|
||||||
msgstr "Déjà résolu"
|
msgstr "Déjà résolu"
|
||||||
|
|
||||||
#: ctfs/templates/ctfs/ctf_info.html:31 ctfs/templates/ctfs/ctf_info.html:40
|
#: src/ctfs/templates/ctfs/ctf_info.html:33
|
||||||
#: events/templates/events/ctf_info.html:42
|
#: src/ctfs/templates/ctfs/ctf_info.html:42
|
||||||
#: events/templates/events/ctf_info.html:51
|
#: src/events/templates/events/ctf_info.html:36
|
||||||
|
#: src/events/templates/events/ctf_info.html:45
|
||||||
msgid "Start the challenge"
|
msgid "Start the challenge"
|
||||||
msgstr "Démarrer le challenge"
|
msgstr "Démarrer le challenge"
|
||||||
|
|
||||||
#: ctfs/templates/ctfs/ctf_info.html:33 ctfs/templates/ctfs/ctf_info.html:42
|
#: src/ctfs/templates/ctfs/ctf_info.html:35
|
||||||
#: events/templates/events/ctf_info.html:44
|
#: src/ctfs/templates/ctfs/ctf_info.html:44
|
||||||
#: events/templates/events/ctf_info.html:53
|
#: src/events/templates/events/ctf_info.html:38
|
||||||
|
#: src/events/templates/events/ctf_info.html:47
|
||||||
msgid "Download"
|
msgid "Download"
|
||||||
msgstr "Télécharger"
|
msgstr "Télécharger"
|
||||||
|
|
||||||
#: ctfs/templates/ctfs/ctf_info.html:37
|
#: src/ctfs/templates/ctfs/ctf_info.html:39
|
||||||
#: events/templates/events/ctf_info.html:48
|
#: src/events/templates/events/ctf_info.html:42
|
||||||
msgid "Wrong flag ! You can do it !"
|
msgid "Wrong flag ! You can do it !"
|
||||||
msgstr "Mauvais flag ! Vous pouvez le faire !"
|
msgstr "Mauvais flag ! Vous pouvez le faire !"
|
||||||
|
|
||||||
#: ctfs/templates/ctfs/ctf_info.html:56
|
#: src/ctfs/templates/ctfs/ctf_info.html:58
|
||||||
#: events/templates/events/ctf_info.html:66
|
#: src/events/templates/events/ctf_info.html:60
|
||||||
msgid "Solved by"
|
msgid "Solved by"
|
||||||
msgstr "Résolu par"
|
msgstr "Résolu par"
|
||||||
|
|
||||||
#: ctfs/templates/ctfs/ctf_info.html:80
|
#: src/ctfs/templates/ctfs/ctf_info.html:82
|
||||||
#: events/templates/events/ctf_info.html:96
|
#: src/events/templates/events/ctf_info.html:90
|
||||||
msgid "Nobody has solved this challenge yet."
|
msgid "Nobody has solved this challenge yet."
|
||||||
msgstr "Personne n'a résolu ce CTF."
|
msgstr "Personne n'a résolu ce CTF."
|
||||||
|
|
||||||
#: ctfs/templates/ctfs/ctf_info.html:87
|
#: src/ctfs/templates/ctfs/ctf_info.html:89
|
||||||
#: events/templates/events/ctf_info.html:103
|
#: src/events/templates/events/ctf_info.html:97
|
||||||
msgid "Author"
|
msgid "Author"
|
||||||
msgstr "Auteur"
|
msgstr "Auteur"
|
||||||
|
|
||||||
#: ctfs/templates/ctfs/ctf_info.html:88
|
#: src/ctfs/templates/ctfs/ctf_info.html:90
|
||||||
#: events/templates/events/ctf_info.html:104
|
#: src/events/templates/events/ctf_info.html:98
|
||||||
msgid "Point reward"
|
msgid "Point reward"
|
||||||
msgstr "Points"
|
msgstr "Points"
|
||||||
|
|
||||||
#: ctfs/templates/ctfs/ctfs_list.html:14
|
#: src/ctfs/templates/ctfs/ctfs_list.html:14
|
||||||
msgid "Solved"
|
msgid "Solved"
|
||||||
msgstr "Résolu"
|
msgstr "Résolu"
|
||||||
|
|
||||||
#: ctfs/templates/ctfs/ctfs_list.html:37
|
#: src/ctfs/templates/ctfs/ctfs_list.html:37
|
||||||
msgid "No ctf available for this category."
|
msgid "No ctf available for this category."
|
||||||
msgstr "Il n'y a pas de challenges dans cette catégorie."
|
msgstr "Il n'y a pas de challenges dans cette catégorie."
|
||||||
|
|
||||||
#: ctfs/templates/ctfs/ctfs_list.html:42
|
#: src/ctfs/templates/ctfs/ctfs_list.html:42
|
||||||
msgid "Categories"
|
msgid "Categories"
|
||||||
msgstr "Catégories"
|
msgstr "Catégories"
|
||||||
|
|
||||||
#: ctfs/templates/ctfs/ctfs_list.html:48 templates/base.html:54
|
#: src/ctfs/templates/ctfs/ctfs_list.html:48 src/templates/base.html:56
|
||||||
msgid "No category available."
|
msgid "No category available."
|
||||||
msgstr "Il n'y a pas de catégorie disponible."
|
msgstr "Il n'y a pas de catégorie disponible."
|
||||||
|
|
||||||
#: events/templates/events/create_team.html:9
|
#: src/events/templates/events/create_team.html:10
|
||||||
#: events/templates/events/join_team.html:9
|
#: src/events/templates/events/join_team.html:10
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
#| msgid "This event start at"
|
#| msgid "This event start at"
|
||||||
msgid "This event starts at"
|
msgid "This event starts at"
|
||||||
msgstr "Cet événement débute à"
|
msgstr "Cet événement débute à"
|
||||||
|
|
||||||
#: events/templates/events/create_team.html:16
|
#: src/events/templates/events/create_team.html:17
|
||||||
#: events/templates/events/join_team.html:16
|
#: src/events/templates/events/join_team.html:17
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
#| msgid "You're already registered to this event."
|
#| msgid "You're already registered to this event."
|
||||||
msgid "You need to be registered to the event."
|
msgid "You need to be registered to the event."
|
||||||
msgstr "Vous êtes déjà inscrit à cet événement."
|
msgstr "Vous êtes déjà inscrit à cet événement."
|
||||||
|
|
||||||
#: events/templates/events/create_team.html:19 events/views/teams.py:118
|
#: src/events/templates/events/create_team.html:20
|
||||||
|
#: src/events/views/teams.py:120
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
#| msgid "Username already taken."
|
#| msgid "Username already taken."
|
||||||
msgid "Name already taken."
|
msgid "Name already taken."
|
||||||
msgstr "Ce nom est déjà utilisé."
|
msgstr "Ce nom est déjà utilisé."
|
||||||
|
|
||||||
#: events/templates/events/create_team.html:25
|
#: src/events/templates/events/create_team.html:26
|
||||||
#: events/templates/events/join_team.html:30
|
#: src/events/templates/events/join_team.html:31
|
||||||
#: events/templates/events/manage_team.html:22
|
#: src/events/templates/events/manage_team.html:22
|
||||||
msgid "Team name"
|
msgid "Team name"
|
||||||
msgstr "Nom de l'équipe"
|
msgstr "Nom de l'équipe"
|
||||||
|
|
||||||
#: events/templates/events/create_team.html:27
|
#: src/events/templates/events/create_team.html:28
|
||||||
#: events/templates/events/create_team.html:46
|
#: src/events/templates/events/create_team.html:49
|
||||||
#: events/templates/events/join_team.html:52
|
#: src/events/templates/events/join_team.html:54
|
||||||
msgid "Create Team"
|
msgid "Create Team"
|
||||||
msgstr "Créer une équipe"
|
msgstr "Créer une équipe"
|
||||||
|
|
||||||
#: events/templates/events/create_team.html:32
|
#: src/events/templates/events/create_team.html:33
|
||||||
#: events/templates/events/event_pwd.html:28
|
#: src/events/templates/events/event_pwd.html:44
|
||||||
#: events/templates/events/join_team.html:37
|
#: src/events/templates/events/join_team.html:38
|
||||||
msgid "You need to be logged to access this event."
|
msgid "You need to be logged to access this event."
|
||||||
msgstr "Vous devez être connecté pour accéder à cet événement."
|
msgstr "Vous devez être connecté pour accéder à cet événement."
|
||||||
|
|
||||||
#: events/templates/events/create_team.html:41
|
#: src/events/templates/events/create_team.html:42
|
||||||
#: events/templates/events/event_info.html:113
|
#: src/events/templates/events/event_info.html:113
|
||||||
#: events/templates/events/event_pwd.html:36
|
#: src/events/templates/events/event_pwd.html:52
|
||||||
#: events/templates/events/join_team.html:46
|
#: src/events/templates/events/join_team.html:47
|
||||||
msgid "Starts at"
|
msgid "Starts at"
|
||||||
msgstr "Début"
|
msgstr "Début"
|
||||||
|
|
||||||
#: events/templates/events/create_team.html:42
|
#: src/events/templates/events/create_team.html:43
|
||||||
#: events/templates/events/event_info.html:114
|
#: src/events/templates/events/event_info.html:114
|
||||||
#: events/templates/events/event_pwd.html:37
|
#: src/events/templates/events/event_pwd.html:53
|
||||||
#: events/templates/events/join_team.html:47
|
#: src/events/templates/events/join_team.html:48
|
||||||
msgid "Ends at"
|
msgid "Ends at"
|
||||||
msgstr "Fin"
|
msgstr "Fin"
|
||||||
|
|
||||||
#: events/templates/events/create_team.html:47
|
#: src/events/templates/events/create_team.html:47
|
||||||
#: events/templates/events/join_team.html:32
|
#: src/events/templates/events/event_info.html:129
|
||||||
#: events/templates/events/join_team.html:51
|
#: src/events/templates/events/join_team.html:52
|
||||||
|
msgid "Manage my team"
|
||||||
|
msgstr "Gérer mon équipe"
|
||||||
|
|
||||||
|
#: src/events/templates/events/create_team.html:48
|
||||||
|
#: src/events/templates/events/join_team.html:33
|
||||||
|
#: src/events/templates/events/join_team.html:53
|
||||||
msgid "Join Team"
|
msgid "Join Team"
|
||||||
msgstr "Rejoindre une équipe"
|
msgstr "Rejoindre une équipe"
|
||||||
|
|
||||||
#: events/templates/events/create_team.html:54
|
#: src/events/templates/events/create_team.html:53
|
||||||
#: events/templates/events/join_team.html:59
|
#: src/events/templates/events/join_team.html:58
|
||||||
|
msgid "Auto-matching"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/events/templates/events/create_team.html:57
|
||||||
|
#: src/events/templates/events/join_team.html:62
|
||||||
msgid "Find me a team !"
|
msgid "Find me a team !"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: events/templates/events/ctf_info.html:10
|
#: src/events/templates/events/ctf_info.html:10
|
||||||
msgid "Event"
|
msgid "Event"
|
||||||
msgstr "Événement"
|
msgstr "Événement"
|
||||||
|
|
||||||
#: events/templates/events/ctf_info.html:25
|
#: src/events/templates/events/ctf_info.html:18
|
||||||
#: events/templates/events/event_info.html:9
|
msgid ""
|
||||||
msgid "Subscriptions is over."
|
"No translation available. Please try another language (English or French)."
|
||||||
msgstr "Les inscriptions sont terminées."
|
msgstr ""
|
||||||
|
|
||||||
#: events/templates/events/ctf_info.html:28
|
#: src/events/templates/events/ctf_info.html:28
|
||||||
#: events/templates/events/event_info.html:12
|
#: src/events/templates/events/event_info.html:18
|
||||||
#: events/templates/events/event_pwd.html:18
|
|
||||||
msgid "You're already registered to this event."
|
|
||||||
msgstr "Vous êtes déjà inscrit à cet événement."
|
|
||||||
|
|
||||||
#: events/templates/events/ctf_info.html:36
|
|
||||||
#: events/templates/events/event_info.html:18
|
|
||||||
msgid "This event is over."
|
msgid "This event is over."
|
||||||
msgstr "Cet événement est terminé."
|
msgstr "Cet événement est terminé."
|
||||||
|
|
||||||
#: events/templates/events/ctf_info.html:38
|
#: src/events/templates/events/ctf_info.html:30
|
||||||
msgid "Error while processing your request. (Invalid Form)"
|
msgid "Error while processing your request. (Invalid Form)"
|
||||||
msgstr "Erreur lors du traitement de votre requête. (Formulaire non valide)"
|
msgstr "Erreur lors du traitement de votre requête. (Formulaire non valide)"
|
||||||
|
|
||||||
#: events/templates/events/ctf_info.html:40
|
#: src/events/templates/events/ctf_info.html:32
|
||||||
msgid ""
|
msgid "You must register to the event before submitting flags."
|
||||||
"Error: you're not registered to this event, so you can't register scores, "
|
|
||||||
"fucking logic."
|
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Erreur : vous n'êtes pas inscrit à cet événement, vous ne pouvez donc pas "
|
|
||||||
"enregistrer de scores,C'est putain de logique."
|
|
||||||
|
|
||||||
#: events/templates/events/event_info.html:20
|
#: src/events/templates/events/ctf_info.html:34
|
||||||
#: events/templates/events/event_pwd.html:9
|
msgid ""
|
||||||
|
"This is a team event, please create or join a team before submitting flags."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/events/templates/events/event_info.html:9
|
||||||
|
msgid "Subscriptions is over."
|
||||||
|
msgstr "Les inscriptions sont terminées."
|
||||||
|
|
||||||
|
#: src/events/templates/events/event_info.html:12
|
||||||
|
#: src/events/templates/events/event_pwd.html:33
|
||||||
|
msgid "You're already registered to this event."
|
||||||
|
msgstr "Vous êtes déjà inscrit à cet événement."
|
||||||
|
|
||||||
|
#: src/events/templates/events/event_info.html:20
|
||||||
|
#: src/events/templates/events/event_pwd.html:9
|
||||||
msgid "This event start at"
|
msgid "This event start at"
|
||||||
msgstr "Cet événement débute à"
|
msgstr "Cet événement débute à"
|
||||||
|
|
||||||
#: events/templates/events/event_info.html:30
|
#: src/events/templates/events/event_info.html:30
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
#| msgid "Challenge Name"
|
#| msgid "Challenge Name"
|
||||||
msgid "Challenges"
|
msgid "Challenges"
|
||||||
msgstr "Nom du challenge"
|
msgstr "Nom du challenge"
|
||||||
|
|
||||||
#: events/templates/events/event_info.html:47
|
#: src/events/templates/events/event_info.html:47
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
#| msgid "No category available."
|
#| msgid "No category available."
|
||||||
msgid "No challenges available."
|
msgid "No challenges available."
|
||||||
msgstr "Il n'y a pas de catégorie disponible."
|
msgstr "Il n'y a pas de catégorie disponible."
|
||||||
|
|
||||||
#: events/templates/events/event_info.html:51
|
#: src/events/templates/events/event_info.html:51
|
||||||
msgid "The event has not started yet."
|
msgid "The event has not started yet."
|
||||||
msgstr "L'événement n'a pas encore commencé."
|
msgstr "L'événement n'a pas encore commencé."
|
||||||
|
|
||||||
#: events/templates/events/event_info.html:57
|
#: src/events/templates/events/event_info.html:57
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
#| msgid "Scoreboard"
|
#| msgid "Scoreboard"
|
||||||
msgid "ScoreBoard"
|
msgid "ScoreBoard"
|
||||||
msgstr "Classement"
|
msgstr "Classement"
|
||||||
|
|
||||||
#: events/templates/events/event_info.html:88
|
#: src/events/templates/events/event_info.html:88
|
||||||
msgid "Team"
|
msgid "Team"
|
||||||
msgstr "Équipe"
|
msgstr "Équipe"
|
||||||
|
|
||||||
#: events/templates/events/event_info.html:106
|
#: src/events/templates/events/event_info.html:106
|
||||||
msgid "No one have earn point yet, you gonna be the first ?"
|
msgid "No one have earn point yet, you gonna be the first ?"
|
||||||
msgstr "Personne n'a encore gagné de point, allez-vous être le premier ?"
|
msgstr "Personne n'a encore gagné de point, allez-vous être le premier ?"
|
||||||
|
|
||||||
#: events/templates/events/event_info.html:129
|
#: src/events/templates/events/event_pwd.html:16
|
||||||
msgid "Manage my team"
|
msgid ""
|
||||||
msgstr "Gérer mon équipe"
|
"This event is reserved for one or more 42 campuses. If you have not "
|
||||||
|
"connected your intranet to 42CTF, you can do so with this button: "
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: events/templates/events/event_pwd.html:15
|
#: src/events/templates/events/event_pwd.html:25
|
||||||
#: events/templates/events/join_team.html:21
|
msgid ""
|
||||||
|
"This event is reserved for one or more 42 campuses. And unfortunately your "
|
||||||
|
"campus can't participate. Do not hesitate to contact us to organize an event "
|
||||||
|
"on your campus!"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/events/templates/events/event_pwd.html:30
|
||||||
|
#: src/events/templates/events/join_team.html:22
|
||||||
msgid "Wrong password submited."
|
msgid "Wrong password submited."
|
||||||
msgstr "Mauvais mot de passe saisi."
|
msgstr "Mauvais mot de passe saisi."
|
||||||
|
|
||||||
#: events/templates/events/event_pwd.html:20
|
#: src/events/templates/events/event_pwd.html:35
|
||||||
msgid "This event is password protected"
|
msgid "This event is password protected"
|
||||||
msgstr "Cet événement est protégé par un mot de passe"
|
msgstr "Cet événement est protégé par un mot de passe"
|
||||||
|
|
||||||
#: events/templates/events/event_pwd.html:21
|
#: src/events/templates/events/event_pwd.html:36
|
||||||
msgid "You need to submit the event password to gain access to this event."
|
msgid "You need to submit the event password to gain access to this event."
|
||||||
msgstr "Vous devez saisir le mot de passe de l'événement pour y avoir accès."
|
msgstr "Vous devez saisir le mot de passe de l'événement pour y avoir accès."
|
||||||
|
|
||||||
#: events/templates/events/events_list.html:6 templates/base.html:63
|
#: src/events/templates/events/events_list.html:6 src/templates/base.html:65
|
||||||
msgid "Events"
|
msgid "Events"
|
||||||
msgstr "Événements"
|
msgstr "Événements"
|
||||||
|
|
||||||
#: events/templates/events/events_list.html:38
|
#: src/events/templates/events/events_list.html:38
|
||||||
msgid "See more"
|
msgid "See more"
|
||||||
msgstr "Voir plus"
|
msgstr "Voir plus"
|
||||||
|
|
||||||
#: events/templates/events/events_list.html:44
|
#: src/events/templates/events/events_list.html:44
|
||||||
msgid "No events available."
|
msgid "No events available."
|
||||||
msgstr "Pas d'évènement disponible."
|
msgstr "Pas d'évènement disponible."
|
||||||
|
|
||||||
#: events/templates/events/join_team.html:19
|
#: src/events/templates/events/join_team.html:20
|
||||||
msgid "Team does not exist."
|
msgid "Team does not exist."
|
||||||
msgstr "Cette équipe n'existe pas."
|
msgstr "Cette équipe n'existe pas."
|
||||||
|
|
||||||
#: events/templates/events/join_team.html:23
|
#: src/events/templates/events/join_team.html:24
|
||||||
msgid "Maximum size reached."
|
msgid "Maximum size reached."
|
||||||
msgstr "Taille maximale atteinte."
|
msgstr "Taille maximale atteinte."
|
||||||
|
|
||||||
#: events/templates/events/manage_team.html:26
|
#: src/events/templates/events/manage_team.html:26
|
||||||
msgid "Team password"
|
msgid "Team password"
|
||||||
msgstr "Mot de passe de l'équipe"
|
msgstr "Mot de passe de l'équipe"
|
||||||
|
|
||||||
#: events/templates/events/manage_team.html:44
|
#: src/events/templates/events/manage_team.html:29
|
||||||
#: events/templates/events/team.html:49
|
msgid "Apply"
|
||||||
|
msgstr "Appliquer"
|
||||||
|
|
||||||
|
#: src/events/templates/events/manage_team.html:44
|
||||||
|
#: src/events/templates/events/team.html:49
|
||||||
msgid "Members"
|
msgid "Members"
|
||||||
msgstr "Membres"
|
msgstr "Membres"
|
||||||
|
|
||||||
#: events/templates/events/manage_team.html:51
|
#: src/events/templates/events/manage_team.html:52
|
||||||
msgid "Leave Team"
|
msgid "Leave Team"
|
||||||
msgstr "Quitte l'équipe"
|
msgstr "Quitte l'équipe"
|
||||||
|
|
||||||
#: events/templates/events/team.html:38
|
#: src/events/templates/events/manage_team.html:59
|
||||||
|
msgid "Open to automatching"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/events/templates/events/manage_team.html:66
|
||||||
|
msgid "Close to automatching"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/events/templates/events/team.html:38
|
||||||
msgid "It seems that this team has not solved any challenge yet..."
|
msgid "It seems that this team has not solved any challenge yet..."
|
||||||
msgstr "Il semble que cette équipe n'a pas encore résolu de challenge..."
|
msgstr "Il semble que cette équipe n'a pas encore résolu de challenge..."
|
||||||
|
|
||||||
#: home/templates/home/home.html:20
|
#: src/home/templates/home/home.html:21
|
||||||
msgid "Weekly Top 5"
|
msgid "Weekly Top 5"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: home/templates/home/home.html:56
|
#: src/home/templates/home/home.html:48
|
||||||
msgid "No article available."
|
msgid "No article available."
|
||||||
msgstr "Il n'y a pas d'article disponible."
|
msgstr "Il n'y a pas d'article disponible."
|
||||||
|
|
||||||
#: home/templates/home/home.html:61
|
#: src/home/templates/home/home.html:53
|
||||||
msgid "Latest challenges added"
|
msgid "Latest challenges added"
|
||||||
msgstr "Derniers challenges ajoutés"
|
msgstr "Derniers challenges ajoutés"
|
||||||
|
|
||||||
#: home/templates/home/home.html:66
|
#: src/home/templates/home/home.html:58
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
#| msgid "Points"
|
#| msgid "Points"
|
||||||
msgid "points"
|
msgid "points"
|
||||||
msgstr "Points"
|
msgstr "Points"
|
||||||
|
|
||||||
#: home/templates/home/home.html:70
|
#: src/home/templates/home/home.html:62
|
||||||
msgid "No ctf available."
|
msgid "No ctf available."
|
||||||
msgstr "Pas de challenge disponible"
|
msgstr "Pas de challenge disponible"
|
||||||
|
|
||||||
#: home/templates/home/home.html:74
|
#: src/home/templates/home/home.html:66
|
||||||
msgid "Latest Flags"
|
msgid "Latest Flags"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: home/templates/home/home.html:88
|
#: src/home/templates/home/home.html:80
|
||||||
msgid "Flags"
|
msgid "Flags"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: home/templates/home/home.html:94
|
#: src/home/templates/home/home.html:86
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
#| msgid "Username"
|
#| msgid "Username"
|
||||||
msgid "Users"
|
msgid "Users"
|
||||||
msgstr "Pseudo"
|
msgstr "Pseudo"
|
||||||
|
|
||||||
#: project/settings.py:115
|
#: src/project/settings.py:116
|
||||||
msgid "English"
|
msgid "English"
|
||||||
msgstr "Anglais"
|
msgstr "Anglais"
|
||||||
|
|
||||||
#: project/settings.py:116
|
#: src/project/settings.py:117
|
||||||
msgid "German"
|
msgid "German"
|
||||||
msgstr "Allemand"
|
msgstr "Allemand"
|
||||||
|
|
||||||
#: project/settings.py:117
|
#: src/project/settings.py:118
|
||||||
msgid "French"
|
msgid "French"
|
||||||
msgstr "Français"
|
msgstr "Français"
|
||||||
|
|
||||||
#: project/settings.py:118
|
#: src/project/settings.py:119
|
||||||
msgid "Russian"
|
msgid "Russian"
|
||||||
msgstr "Russe"
|
msgstr "Russe"
|
||||||
|
|
||||||
#: scoreboard/templates/scoreboard/scoreboard.html:38
|
#: src/project/settings.py:120
|
||||||
|
msgid "Japanese"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/project/settings.py:121
|
||||||
|
msgid "Spanish"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/scoreboard/templates/scoreboard/scoreboard.html:15
|
||||||
|
msgid "Campus"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/scoreboard/templates/scoreboard/scoreboard.html:46
|
||||||
msgid "First"
|
msgid "First"
|
||||||
msgstr "Début"
|
msgstr "Début"
|
||||||
|
|
||||||
#: scoreboard/templates/scoreboard/scoreboard.html:39
|
#: src/scoreboard/templates/scoreboard/scoreboard.html:47
|
||||||
msgid "Previous"
|
msgid "Previous"
|
||||||
msgstr "Précédente"
|
msgstr "Précédente"
|
||||||
|
|
||||||
#: scoreboard/templates/scoreboard/scoreboard.html:43
|
#: src/scoreboard/templates/scoreboard/scoreboard.html:51
|
||||||
msgid "Page "
|
msgid "Page "
|
||||||
msgstr "Page"
|
msgstr "Page"
|
||||||
|
|
||||||
#: scoreboard/templates/scoreboard/scoreboard.html:47
|
#: src/scoreboard/templates/scoreboard/scoreboard.html:55
|
||||||
msgid "Next"
|
msgid "Next"
|
||||||
msgstr "Suivante"
|
msgstr "Suivante"
|
||||||
|
|
||||||
#: scoreboard/templates/scoreboard/scoreboard.html:48
|
#: src/scoreboard/templates/scoreboard/scoreboard.html:56
|
||||||
msgid "Last"
|
msgid "Last"
|
||||||
msgstr "Fin"
|
msgstr "Fin"
|
||||||
|
|
||||||
#: templates/base.html:59
|
#: src/templates/base.html:62
|
||||||
msgid "Scoreboard"
|
msgid "Scoreboard"
|
||||||
msgstr "Classement"
|
msgstr "Classement"
|
||||||
|
|
||||||
#: templates/base.html:66
|
#: src/templates/base.html:83
|
||||||
msgid "Resources"
|
#, fuzzy
|
||||||
msgstr ""
|
#| msgid "Become a Patron!"
|
||||||
|
msgid "Become a member"
|
||||||
|
msgstr "Soutenez nous via Patreon !"
|
||||||
|
|
||||||
#: templates/base.html:99
|
#: src/templates/base.html:93
|
||||||
msgid "Logout"
|
msgid "Logout"
|
||||||
msgstr "Déconnexion"
|
msgstr "Déconnexion"
|
||||||
|
|
||||||
#: templates/base.html:106
|
#: src/templates/base.html:100
|
||||||
msgid "Sign Up"
|
msgid "Sign Up"
|
||||||
msgstr "Inscription"
|
msgstr "Inscription"
|
||||||
|
|
||||||
#: templates/base.html:144
|
#: src/templates/registration/password_reset_complete.html:11
|
||||||
msgid "Become a Patron!"
|
|
||||||
msgstr "Soutenez nous via Patreon !"
|
|
||||||
|
|
||||||
#: templates/registration/password_reset_complete.html:11
|
|
||||||
msgid "Your new password has been set."
|
msgid "Your new password has been set."
|
||||||
msgstr "Votre mot de passe a été mis à jour."
|
msgstr "Votre mot de passe a été mis à jour."
|
||||||
|
|
||||||
#: templates/registration/password_reset_confirm.html:20
|
#: src/templates/registration/password_reset_confirm.html:20
|
||||||
msgid "Your password can’t be too similar to your other personal information."
|
msgid "Your password can’t be too similar to your other personal information."
|
||||||
msgstr "Votre mot de passe ne peut pas être similaire à votre adresse mail."
|
msgstr "Votre mot de passe ne peut pas être similaire à votre adresse mail."
|
||||||
|
|
||||||
#: templates/registration/password_reset_confirm.html:21
|
#: src/templates/registration/password_reset_confirm.html:21
|
||||||
msgid "Your password must contain at least 8 characters."
|
msgid "Your password must contain at least 8 characters."
|
||||||
msgstr "Votre mot de passe doit contenir au moins 8 caractères."
|
msgstr "Votre mot de passe doit contenir au moins 8 caractères."
|
||||||
|
|
||||||
#: templates/registration/password_reset_confirm.html:22
|
#: src/templates/registration/password_reset_confirm.html:22
|
||||||
msgid "Your password can’t be a commonly used password."
|
msgid "Your password can’t be a commonly used password."
|
||||||
msgstr "Votre mot de passe ne peut pas être un mot de passe commun."
|
msgstr "Votre mot de passe ne peut pas être un mot de passe commun."
|
||||||
|
|
||||||
#: templates/registration/password_reset_confirm.html:23
|
#: src/templates/registration/password_reset_confirm.html:23
|
||||||
msgid "Your password can’t be entirely numeric."
|
msgid "Your password can’t be entirely numeric."
|
||||||
msgstr "Votre mot de passe ne peut pas être entièrement numérique."
|
msgstr "Votre mot de passe ne peut pas être entièrement numérique."
|
||||||
|
|
||||||
#: templates/registration/password_reset_confirm.html:26
|
#: src/templates/registration/password_reset_confirm.html:26
|
||||||
msgid "Confirm"
|
msgid "Confirm"
|
||||||
msgstr "Confirmer"
|
msgstr "Confirmer"
|
||||||
|
|
||||||
#: templates/registration/password_reset_confirm.html:28
|
#: src/templates/registration/password_reset_confirm.html:28
|
||||||
msgid "Submit"
|
msgid "Submit"
|
||||||
msgstr "Soumettre"
|
msgstr "Soumettre"
|
||||||
|
|
||||||
#: templates/registration/password_reset_done.html:11
|
#: src/templates/registration/password_reset_done.html:11
|
||||||
msgid ""
|
msgid ""
|
||||||
"We've emailed you instructions for setting your password. You should receive "
|
"We've emailed you instructions for setting your password. You should receive "
|
||||||
"the email shortly!"
|
"the email shortly!"
|
||||||
|
@ -620,18 +715,27 @@ msgstr ""
|
||||||
"Vous devrierz recevoir rapidement un email avec des instructions pour "
|
"Vous devrierz recevoir rapidement un email avec des instructions pour "
|
||||||
"réinitialiser votre mot de passe."
|
"réinitialiser votre mot de passe."
|
||||||
|
|
||||||
#: templates/registration/password_reset_form.html:16
|
#: src/templates/registration/password_reset_form.html:16
|
||||||
msgid "Reset"
|
msgid "Reset"
|
||||||
msgstr "Réinitialiser"
|
msgstr "Réinitialiser"
|
||||||
|
|
||||||
|
#~ msgid "Status: Member"
|
||||||
|
#~ msgstr "Status : Membre"
|
||||||
|
|
||||||
|
#~ msgid ""
|
||||||
|
#~ "Error: you're not registered to this event, so you can't register scores, "
|
||||||
|
#~ "fucking logic."
|
||||||
|
#~ msgstr ""
|
||||||
|
#~ "Erreur : vous n'êtes pas inscrit à cet événement, vous ne pouvez donc pas "
|
||||||
|
#~ "enregistrer de scores,C'est putain de logique."
|
||||||
|
|
||||||
|
#, fuzzy
|
||||||
|
#~| msgid "Manage my team"
|
||||||
|
#~ msgid "Manage team"
|
||||||
|
#~ msgstr "Gérer mon équipe"
|
||||||
|
|
||||||
#~ msgid "Start at"
|
#~ msgid "Start at"
|
||||||
#~ msgstr "Début"
|
#~ msgstr "Début"
|
||||||
|
|
||||||
#~ msgid "End at"
|
#~ msgid "End at"
|
||||||
#~ msgstr "Fin"
|
#~ msgstr "Fin"
|
||||||
|
|
||||||
#~ msgid "Disconnect Discord"
|
|
||||||
#~ msgstr "Déconnecter Discord"
|
|
||||||
|
|
||||||
#~ msgid "Connect Discord"
|
|
||||||
#~ msgstr "Connecter Discord"
|
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue