Coverage for website/utils/management/commands/createfixtures.py: 0.00%

504 statements  

« prev     ^ index     » next       coverage.py v7.6.7, created at 2025-08-14 10:31 +0000

1"""Provides the command to generate fixtures.""" 

2 

3import math 

4import random 

5import string 

6from datetime import date, datetime, timedelta 

7from decimal import Decimal 

8from secrets import token_hex 

9 

10from django.contrib.auth import get_user_model 

11from django.core.files.uploadedfile import SimpleUploadedFile 

12from django.core.management.base import BaseCommand, CommandError 

13from django.db.utils import IntegrityError 

14from django.utils import timezone 

15from django.utils.text import slugify 

16 

17import factory 

18from faker import Faker 

19from pydenticon import Generator as IconGenerator 

20 

21from activemembers.models import ( 

22 Board, 

23 Committee, 

24 MemberGroup, 

25 MemberGroupMembership, 

26 Society, 

27) 

28from documents.models import Document 

29from education.models import Category, Course, Exam, Summary 

30from events.models import ( 

31 EVENT_CATEGORIES, 

32 Event, 

33 EventRegistration, 

34 registration_member_choices_limit, 

35) 

36from members.models import Member, Membership, Profile 

37from newsletters.models import Newsletter, NewsletterEvent, NewsletterItem 

38from partners.models import Partner, Vacancy, VacancyCategory 

39from payments.models import Payment 

40from payments.services import create_payment 

41from photos.models import Album, Photo 

42from pizzas.models import Product 

43from utils.snippets import datetime_to_lectureyear 

44 

45_faker = Faker(["en_US"]) 

46_local_faker = Faker(["nl_NL"]) 

47_pizza_name_faker = Faker("it_IT") 

48_current_tz = timezone.get_current_timezone() 

49 

50 

51def _generate_title(): 

52 words = _faker.words(random.randint(2, 4)) 

53 return " ".join([word.capitalize() for word in words]) 

54 

55 

56def maintain_integrity(func): 

57 def wrapper(*args, **kwargs): 

58 try_amnt = 0 

59 while True: 

60 try: 

61 return func(*args, **kwargs) 

62 except IntegrityError as e: 

63 try_amnt += 1 

64 if try_amnt > 10: 

65 raise CommandError("Unable to create an object") from e 

66 

67 return wrapper 

68 

69 

70class _ProfileFactory(factory.Factory): 

71 class Meta: 

72 model = Profile 

73 

74 programme = random.choice(["computingscience", "informationscience"]) 

75 student_number = factory.LazyAttribute(lambda x: _faker.numerify(text="s#######")) 

76 starting_year = factory.LazyAttribute( 

77 lambda x: random.randint(1990, date.today().year) 

78 ) 

79 

80 address_street = factory.LazyAttribute(lambda x: _local_faker.street_address()) 

81 address_postal_code = factory.LazyAttribute(lambda x: _faker.postcode()) 

82 address_city = factory.LazyAttribute(lambda x: _faker.city()) 

83 address_country = random.choice(["NL", "DE", "BE"]) 

84 

85 phone_number = f"+31{_faker.numerify(text='##########')}" 

86 

87 

88def get_event_to_register_for(member): 

89 for event in Event.objects.filter(published=True).order_by("?"): 

90 if event.registration_required and not event.reached_participants_limit(): 

91 if member.id not in event.registrations.values_list("member", flat=True): 

92 return event 

93 return None 

94 

95 

96class Command(BaseCommand): 

97 """Command to create fake data to populate the site.""" 

98 

99 help = "Creates fake data to test the site with" 

100 

101 def add_arguments(self, parser): 

102 """Add arguments to the argument parser. 

103 

104 :param parser: the argument parser 

105 """ 

106 parser.add_argument( 

107 "-a", 

108 "--all", 

109 action="store_true", 

110 help="Fully populate a database with fixtures", 

111 ) 

112 parser.add_argument( 

113 "-b", "--board", type=int, help="The amount of fake boards to add" 

114 ) 

115 parser.add_argument( 

116 "-c", "--committee", type=int, help="The amount of fake committees to add" 

117 ) 

118 parser.add_argument( 

119 "-d", 

120 "--document", 

121 type=int, 

122 help="The amount of fake miscellaneous documents to add", 

123 ) 

124 parser.add_argument( 

125 "-e", "--event", type=int, help="The amount of fake events to add" 

126 ) 

127 parser.add_argument( 

128 "-n", "--newsletter", type=int, help="The amount of fake newsletters to add" 

129 ) 

130 parser.add_argument( 

131 "-p", "--partner", type=int, help="The amount of fake partners to add" 

132 ) 

133 parser.add_argument( 

134 "-i", "--pizza", type=int, help="The amount of fake pizzas to add" 

135 ) 

136 parser.add_argument( 

137 "-s", "--society", type=int, help="The amount of fake societies to add" 

138 ) 

139 parser.add_argument( 

140 "-u", "--user", type=int, help="The amount of fake users to add" 

141 ) 

142 parser.add_argument( 

143 "-w", "--vacancy", type=int, help="The amount of fake vacancies to add" 

144 ) 

145 parser.add_argument("--course", type=int, help="The amount of courses to add") 

146 parser.add_argument( 

147 "-r", 

148 "--registration", 

149 type=int, 

150 help="The amount of event registrations to add", 

151 ) 

152 parser.add_argument("--payment", type=int, help="The amount of payments to add") 

153 parser.add_argument( 

154 "--photoalbum", type=int, help="The amount of photo albums to add" 

155 ) 

156 

157 def create_board(self, lecture_year): 

158 """Create a new board. 

159 

160 :param int lecture_year: the lecture year this board was active 

161 """ 

162 self.stdout.write("Creating a board") 

163 members = Member.objects.all() 

164 if len(members) < 6: 

165 self.stdout.write("Your database does not contain 6 users.") 

166 self.stdout.write(f"Creating {6 - len(members)} more users.") 

167 for __ in range(6 - len(members)): 

168 self.create_user() 

169 

170 board = Board() 

171 

172 board.name = f"Board {lecture_year}-{lecture_year+1}" 

173 while Board.objects.filter(name=board.name).exists(): 

174 lecture_year = lecture_year - 1 

175 board.name = f"Board {lecture_year}-{lecture_year+1}" 

176 

177 board.description = _faker.paragraph() 

178 

179 igen = IconGenerator(5, 5) # 5x5 blocks 

180 icon = igen.generate( 

181 board.name, 480, 480, padding=(10, 10, 10, 10), output_format="jpeg" 

182 ) # 620x620 pixels, with 10 pixels padding on each side 

183 board.photo = SimpleUploadedFile(f"{board.name}.jpg", icon, "image/jpeg") 

184 

185 board.since = date(year=lecture_year, month=9, day=1) 

186 board.until = date(year=lecture_year + 1, month=8, day=31) 

187 board.active = True 

188 board.contact_email = _faker.safe_email() 

189 

190 board.full_clean() 

191 board.save() 

192 

193 # Add members 

194 board_members = random.sample(list(members), random.randint(5, 6)) 

195 for member in board_members: 

196 self.create_member_group_membership(member, board) 

197 

198 # Make one member the chair 

199 chair = random.choice(board.membergroupmembership_set.all()) 

200 chair.until = None 

201 chair.chair = True 

202 

203 chair.full_clean() 

204 chair.save() 

205 

206 @maintain_integrity 

207 def create_member_group(self, group_model): 

208 """Create a MemberGroup.""" 

209 self.stdout.write("Creating a membergroup") 

210 members = Member.objects.all() 

211 if len(members) < 6: 

212 self.stdout.write("Your database does not contain 6 users.") 

213 self.stdout.write(f"Creating {6 - len(members)} more users.") 

214 for __ in range(6 - len(members)): 

215 self.create_user() 

216 members = Member.objects.all() 

217 

218 member_group = group_model() 

219 

220 member_group.name = _generate_title() 

221 member_group.description = _faker.paragraph() 

222 

223 igen = IconGenerator(5, 5) # 5x5 blocks 

224 icon = igen.generate( 

225 member_group.name, 

226 480, 

227 480, 

228 padding=(10, 10, 10, 10), 

229 output_format="jpeg", 

230 ) # 620x620 pixels, with 10 pixels padding on each side 

231 member_group.photo = SimpleUploadedFile( 

232 member_group.name + ".jpg", icon, "image/jpeg" 

233 ) 

234 

235 member_group.since = _faker.date_time_between("-10y", "+30d").date() 

236 

237 if random.random() < 0.1: 

238 month = timedelta(days=30) 

239 member_group.until = _faker.date_time_between_dates( 

240 member_group.since + 12 * month, member_group.since + 60 * month 

241 ).date() 

242 

243 member_group.active = random.random() < 0.9 

244 member_group.contact_email = _faker.safe_email() 

245 

246 member_group.full_clean() 

247 member_group.save() 

248 

249 # Add members 

250 committee_members = random.sample(list(members), random.randint(2, 6)) 

251 for member in committee_members: 

252 self.create_member_group_membership(member, member_group) 

253 

254 # Make one member the chair 

255 chair = random.choice(member_group.membergroupmembership_set.all()) 

256 chair.until = None 

257 chair.chair = True 

258 

259 chair.full_clean() 

260 chair.save() 

261 

262 def create_member_group_membership(self, member, group): 

263 """Create member group membership. 

264 

265 :param member: the member to add to the committee 

266 :param group: the group to add the member to 

267 """ 

268 self.stdout.write("Creating a group membership") 

269 membership = MemberGroupMembership() 

270 

271 membership.member = member 

272 membership.group = group 

273 

274 today = date.today() 

275 membership.since = _faker.date_time_between_dates( 

276 group.since, 

277 group.until - timedelta(days=3) 

278 if group.until 

279 else group.since + timedelta(days=365), 

280 ).date() 

281 

282 if random.random() < 0.2 and membership.since < today: 

283 membership.until = _faker.date_time_between_dates( 

284 membership.since, 

285 group.until if group.until else group.since + timedelta(days=2 * 365), 

286 ).date() 

287 

288 membership.full_clean() 

289 membership.save() 

290 

291 @maintain_integrity 

292 def create_event(self): 

293 """Create an event.""" 

294 self.stdout.write("Creating an event") 

295 groups = MemberGroup.objects.all() 

296 if len(groups) == 0: 

297 self.stdout.write("Your database does not contain any member groups.") 

298 self.stdout.write("Creating a committee.") 

299 self.create_member_group(Committee) 

300 groups = MemberGroup.objects.all() 

301 event = Event() 

302 

303 event.description = _faker.paragraph() 

304 event.caption = _faker.sentence() 

305 event.title = _generate_title() 

306 event.start = _faker.date_time_between("-30d", "+120d", _current_tz) 

307 duration = math.ceil(random.expovariate(0.2)) 

308 event.end = event.start + timedelta(hours=duration) 

309 event.save() 

310 event.organisers.add(*random.sample(list(groups), random.randint(1, 3))) 

311 event.category = random.choice(EVENT_CATEGORIES)[0] 

312 event.fine = 5 

313 event.slug = slugify(event.title) + "-" + str(event.start.year) 

314 

315 if random.random() < 0.5: 

316 week = timedelta(days=7) 

317 event.registration_start = _faker.date_time_between_dates( 

318 datetime_start=event.start - 4 * week, 

319 datetime_end=event.start - week, 

320 tzinfo=_current_tz, 

321 ) 

322 event.registration_end = _faker.date_time_between_dates( 

323 datetime_start=event.registration_start, 

324 datetime_end=event.start, 

325 tzinfo=_current_tz, 

326 ) 

327 event.cancel_deadline = _faker.date_time_between_dates( 

328 datetime_start=event.registration_end, 

329 datetime_end=event.start, 

330 tzinfo=_current_tz, 

331 ) 

332 event.optional_registrations = False 

333 

334 event.location = _local_faker.street_address() 

335 event.map_location = event.location 

336 event.send_cancel_email = False 

337 

338 if random.random() < 0.5: 

339 event.price = Decimal(random.randint(100, 2500)) / Decimal(100) 

340 event.fine = max( 

341 5.0, 

342 Decimal( 

343 random.randint(round(100 * event.price), round(500 * event.price)) 

344 ) 

345 / Decimal(100), 

346 ) 

347 

348 if random.random() < 0.5: 

349 event.max_participants = random.randint(20, 200) 

350 

351 event.published = random.random() < 0.9 

352 

353 event.full_clean() 

354 event.save() 

355 

356 @maintain_integrity 

357 def create_partner(self, type="normal"): 

358 """Create a new random partner.""" 

359 self.stdout.write("Creating a partner") 

360 partner = Partner() 

361 

362 partner.name = f"{_faker.company()} {_faker.company_suffix()}" 

363 partner.slug = _faker.slug() 

364 partner.link = _faker.uri() 

365 partner.company_profile = _faker.paragraph(nb_sentences=10) 

366 igen = IconGenerator(5, 5) # 5x5 blocks 

367 icon = igen.generate( 

368 partner.name, 

369 480, 

370 480, 

371 padding=(10, 10, 10, 10), 

372 output_format="jpeg", 

373 ) # 620x620 pixels, with 10 pixels padding on each side 

374 partner.logo = SimpleUploadedFile(partner.name + ".jpg", icon, "image/jpeg") 

375 

376 partner.address = _local_faker.street_name() + " " + str(random.randint(1, 300)) 

377 partner.zip_code = _local_faker.postcode() 

378 partner.city = _local_faker.city() 

379 partner.country = random.choice(["NL", "DE", "BE", "GB"]) 

380 

381 match type: 

382 case "normal": 

383 pass 

384 case "main": 

385 partner.is_main_partner = True 

386 case "local": 

387 partner.is_local_partner = True 

388 case "inactive": 

389 partner.is_active = False 

390 

391 partner.full_clean() 

392 partner.save() 

393 

394 def create_pizza(self): 

395 """Create a new random pizza product.""" 

396 self.stdout.write("Creating a pizza product") 

397 

398 product = Product() 

399 

400 product.name = f"Pizza {_pizza_name_faker.last_name()}" 

401 product.description = _faker.sentence() 

402 product.price = Decimal(random.randint(250, 1000)) / Decimal(100) 

403 product.available = random.random() < 0.9 

404 

405 product.full_clean() 

406 product.save() 

407 

408 @maintain_integrity 

409 def create_user(self): 

410 """Create a new random user.""" 

411 self.stdout.write("Creating a user") 

412 

413 fakeprofile = _faker.profile() 

414 fakeprofile["password"] = "".join( 

415 random.choice(string.ascii_uppercase + string.digits) for _ in range(16) 

416 ) 

417 user = get_user_model().objects.create_user( 

418 fakeprofile["username"], 

419 fakeprofile["mail"], 

420 fakeprofile["password"], 

421 ) 

422 

423 user.first_name = fakeprofile["name"].split()[0] 

424 user.last_name = " ".join(fakeprofile["name"].split()[1:]) 

425 

426 profile = _ProfileFactory() 

427 profile.user_id = user.id 

428 profile.birthday = fakeprofile["birthdate"] 

429 profile.website = fakeprofile["website"][0] 

430 

431 igen = IconGenerator(5, 5) # 5x5 blocks 

432 icon = igen.generate( 

433 user.username, 

434 480, 

435 480, 

436 padding=(10, 10, 10, 10), 

437 output_format="jpeg", 

438 ) # 620x620 pixels, with 10 pixels padding on each side 

439 profile.photo = SimpleUploadedFile( 

440 fakeprofile["username"] + ".jpg", icon, "image/jpeg" 

441 ) 

442 

443 membership = Membership() 

444 membership.user_id = user.id 

445 membership.since = _faker.date_time_between( 

446 start_date="-4y", end_date="now", tzinfo=None 

447 ) 

448 

449 membership.until = _faker.date_time_between( 

450 start_date=membership.since, end_date="+2y", tzinfo=None 

451 ) 

452 

453 membership.type = random.choice([t[0] for t in Membership.MEMBERSHIP_TYPES]) 

454 

455 if membership.type == Membership.HONORARY: 

456 membership.until = None 

457 

458 user.full_clean() 

459 user.save() 

460 profile.full_clean() 

461 profile.save() 

462 membership.full_clean() 

463 membership.save() 

464 

465 def create_vacancy(self, partners, categories): 

466 """Create a new random vacancy. 

467 

468 :param partners: the partners to choose a partner from 

469 :param categories: the categories to choose this vacancy from 

470 """ 

471 self.stdout.write("Creating a vacancy") 

472 vacancy = Vacancy() 

473 

474 vacancy.title = _faker.job() 

475 vacancy.description = _faker.paragraph(nb_sentences=10) 

476 vacancy.link = _faker.uri() 

477 

478 if random.random() < 0.75: 

479 vacancy.partner = random.choice(partners) 

480 else: 

481 vacancy.company_name = f"{_faker.company()} {_faker.company_suffix()}" 

482 igen = IconGenerator(5, 5) # 5x5 blocks 

483 icon = igen.generate( 

484 vacancy.company_name, 

485 480, 

486 480, 

487 padding=(10, 10, 10, 10), 

488 output_format="jpeg", 

489 ) # 620x620 pixels, with 10 pixels padding on each side 

490 vacancy.company_logo = SimpleUploadedFile( 

491 vacancy.company_name + ".jpg", icon, "image/jpeg" 

492 ) 

493 

494 vacancy.full_clean() 

495 vacancy.save() 

496 

497 vacancy.categories.set(random.sample(list(categories), random.randint(0, 3))) 

498 

499 def create_vacancy_category(self): 

500 """Create new random vacancy categories.""" 

501 self.stdout.write("Creating a new vacancy category") 

502 category = VacancyCategory() 

503 

504 category.name = _faker.text(max_nb_chars=30) 

505 category.slug = _faker.slug() 

506 

507 category.full_clean() 

508 category.save() 

509 

510 def create_document(self): 

511 """Create new random documents.""" 

512 self.stdout.write("Creating a document") 

513 doc = Document() 

514 

515 doc.name = _faker.text(max_nb_chars=30) 

516 doc.category = random.choice([c[0] for c in Document.DOCUMENT_CATEGORIES]) 

517 doc.members_only = random.random() < 0.75 

518 doc.file = SimpleUploadedFile( 

519 f"{doc.name}.txt", _faker.text(max_nb_chars=120).encode() 

520 ) 

521 doc.full_clean() 

522 doc.save() 

523 

524 def create_newsletter(self): 

525 self.stdout.write("Creating a new newsletter") 

526 newsletter = Newsletter() 

527 

528 newsletter.title = _generate_title() 

529 newsletter.description = _faker.paragraph() 

530 newsletter.date = _faker.date_time_between("-3m", "+3m", _current_tz) 

531 

532 newsletter.clean() # full_clean does not work because of rendered_file 

533 newsletter.save() 

534 

535 for _ in range(random.randint(1, 5)): 

536 item = NewsletterItem() 

537 item.title = _generate_title() 

538 item.description = _faker.paragraph() 

539 item.newsletter = newsletter 

540 item.full_clean() 

541 item.save() 

542 

543 for _ in range(random.randint(1, 5)): 

544 item = NewsletterEvent() 

545 item.title = _generate_title() 

546 item.description = _faker.paragraph() 

547 item.newsletter = newsletter 

548 

549 item.what = item.title 

550 item.where = _faker.city() 

551 item.start_datetime = _faker.date_time_between("-1y", "+3m", _current_tz) 

552 duration = math.ceil(random.expovariate(0.2)) 

553 item.end_datetime = item.start_datetime + timedelta(hours=duration) 

554 

555 if random.random() < 0.5: 

556 item.show_costs_warning = True 

557 item.price = Decimal(random.randint(100, 2500)) / Decimal(100) 

558 item.penalty_costs = max( 

559 5.0, 

560 Decimal( 

561 random.randint(round(100 * item.price), round(500 * item.price)) 

562 ) 

563 / Decimal(100), 

564 ) 

565 item.full_clean() 

566 item.save() 

567 

568 def create_course(self): 

569 self.stdout.write("Creating a new course") 

570 course = Course() 

571 

572 course.name = _generate_title() 

573 course.ec = 3 if random.random() < 0.5 else 6 

574 

575 course.course_code = "NWI-" + "".join(random.choices(string.digits, k=5)) 

576 

577 course.since = random.randint(2016, 2020) 

578 if random.random() < 0.5: 

579 course.until = max(course.since + random.randint(1, 5), datetime.now().year) 

580 

581 # Save so we can add categories 

582 course.save() 

583 

584 for category in Category.objects.order_by("?")[: random.randint(1, 3)]: 

585 course.categories.add(category) 

586 

587 course.full_clean() 

588 course.save() 

589 

590 for _ in range(random.randint(0, 5)): 

591 self.create_summary(course) 

592 for _ in range(random.randint(0, 5)): 

593 self.create_exam(course) 

594 

595 def create_exam(self, course): 

596 self.stdout.write("Creating an exam") 

597 exam = Exam() 

598 

599 exam.name = _generate_title() 

600 exam.type = random.choice(Exam.EXAM_TYPES)[0] 

601 exam.course = course 

602 exam.uploader = Member.objects.order_by("?")[0] 

603 exam.accepted = random.random() < 0.5 

604 exam.exam_date = _faker.date_between("-1y", "today") 

605 exam.file = SimpleUploadedFile( 

606 f"{exam.name}.txt", _faker.text(max_nb_chars=120).encode() 

607 ) 

608 exam.language = random.choice(Exam.language.field.choices)[0] 

609 exam.download_count = random.randint(0, 100) 

610 

611 exam.name = _generate_title() 

612 

613 exam.full_clean() 

614 exam.save() 

615 

616 def create_summary(self, course): 

617 self.stdout.write("Creating a summary") 

618 summary = Summary() 

619 

620 summary.name = _generate_title() 

621 summary.course = course 

622 summary.uploader = Member.objects.order_by("?")[0] 

623 summary.year = random.randint(2016, 2020) 

624 summary.author = _faker.name() 

625 summary.accepted = random.random() < 0.5 

626 summary.file = SimpleUploadedFile( 

627 f"{summary.name}.txt", _faker.text(max_nb_chars=120).encode() 

628 ) 

629 summary.language = random.choice(Summary.language.field.choices)[0] 

630 summary.download_count = random.randint(0, 100) 

631 

632 summary.full_clean() 

633 summary.save() 

634 

635 def create_event_registration(self, event_to_register_for=None): 

636 self.stdout.write("Creating an event registration") 

637 registration = EventRegistration() 

638 

639 eligible = Member.objects.filter(registration_member_choices_limit()) 

640 registration.member = eligible.order_by("?")[0] 

641 

642 possible_event = ( 

643 event_to_register_for 

644 if event_to_register_for 

645 else get_event_to_register_for(registration.member) 

646 ) 

647 

648 if not possible_event: 

649 self.stdout.write("No possible events to register for") 

650 self.stdout.write("Creating a new event") 

651 self.create_event() 

652 possible_event = get_event_to_register_for(registration.member) 

653 

654 if not possible_event: 

655 self.stdout.write("Could not create event") 

656 return None 

657 

658 registration.event = possible_event 

659 

660 registration.date = registration.event.registration_start 

661 

662 registration.full_clean() 

663 registration.save() 

664 

665 return registration 

666 

667 def create_payment(self): 

668 self.stdout.write("Creating a payment") 

669 

670 possible_events = list( 

671 filter( 

672 lambda e: e.registrations.exists(), 

673 Event.objects.filter(price__gt=0).order_by("?"), 

674 ) 

675 ) 

676 if len(possible_events) == 0: 

677 print("No event where can be payed could be found, creating a new event") 

678 self.create_event() 

679 possible_events = list( 

680 filter( 

681 lambda e: e.registrations.exists(), 

682 Event.objects.filter(price__gt=0).order_by("?"), 

683 ) 

684 ) 

685 

686 if len(possible_events) == 0: 

687 print("Could not create the event for an unexpected reason.") 

688 return 

689 

690 event = possible_events[0] 

691 if len(event.registrations) == 0: 

692 print("No registrations found. Create some more registrations first") 

693 return 

694 

695 registration = event.registrations.order_by("?")[0] 

696 

697 superusers = Member.objects.filter(is_superuser=True) 

698 if not superusers: 

699 print( 

700 "There is no member which is also a superuser. Creating payments without this isn't possible!" 

701 ) 

702 print("Please add an membership to the superuser.") 

703 return 

704 

705 payment = create_payment( 

706 registration, 

707 superusers[0], 

708 random.choice([Payment.CASH, Payment.CARD, Payment.WIRE]), 

709 ) 

710 

711 payment.full_clean() 

712 

713 @maintain_integrity 

714 def create_photo_album(self): 

715 self.stdout.write("Creating a photo album") 

716 album = Album() 

717 

718 album.title = _generate_title() 

719 

720 album.date = _faker.date_between("-1y", "today") 

721 

722 album.slug = slugify("-".join([str(album.date), album.title])) 

723 

724 # normally this is set in save(), but required for validation 

725 album.dirname = album.slug 

726 

727 if random.random() < 0.25: 

728 album.hidden = True 

729 if random.random() < 0.5: 

730 album.shareable = True 

731 

732 album.full_clean() 

733 album.save() 

734 

735 for _ in range(random.randint(20, 30)): 

736 self.create_photo(album) 

737 

738 def create_photo(self, album): 

739 self.stdout.write("Creating a photo") 

740 photo = Photo() 

741 

742 photo.album = album 

743 

744 name = _generate_title() 

745 

746 igen = IconGenerator(12, 12) 

747 icon = igen.generate( 

748 token_hex(16), 

749 480, 

750 480, 

751 padding=(10, 10, 10, 10), 

752 output_format="jpeg", 

753 ) # 620x620 pixels, with 10 pixels padding on each side 

754 photo.file = SimpleUploadedFile(f"{name}.jpg", icon, "image/jpeg") 

755 

756 photo.full_clean() 

757 photo.save() 

758 

759 def handle(self, *args, **options): 

760 """Handle the command being executed. 

761 

762 :param options: the passed-in options 

763 """ 

764 opts = [ 

765 "all", 

766 "board", 

767 "committee", 

768 "event", 

769 "partner", 

770 "pizza", 

771 "user", 

772 "vacancy", 

773 "document", 

774 "newsletter", 

775 "course", 

776 "registration", 

777 "payment", 

778 "photoalbum", 

779 ] 

780 

781 if all(not options[opt] for opt in opts): 

782 self.stdout.write( 

783 "Use ./manage.py help createfixtures to find out" 

784 " how to call this command" 

785 ) 

786 

787 if options["all"]: 

788 self.stdout.write("all argument given, overwriting all other inputs") 

789 options = { 

790 "user": 20, 

791 "board": 3, 

792 "committee": 3, 

793 "society": 3, 

794 "event": 20, 

795 "partner": 6, 

796 "vacancy": 4, 

797 "pizza": 5, 

798 "newsletter": 2, 

799 "document": 8, 

800 "course": 10, 

801 "registration": 20, 

802 "payment": 5, 

803 "photoalbum": 5, 

804 } 

805 

806 # Users need to be generated before boards and committees 

807 if options["user"]: 

808 for __ in range(options["user"]): 

809 self.create_user() 

810 

811 if options["board"]: 

812 lecture_year = datetime_to_lectureyear(date.today()) 

813 for i in range(options["board"]): 

814 self.create_board(lecture_year - i) 

815 

816 # Member groups need to be generated before events 

817 if options["committee"]: 

818 for __ in range(options["committee"]): 

819 self.create_member_group(Committee) 

820 

821 if options["society"]: 

822 for __ in range(options["society"]): 

823 self.create_member_group(Society) 

824 

825 if options["event"]: 

826 for __ in range(options["event"]): 

827 self.create_event() 

828 

829 # Partners need to be generated before vacancies 

830 if options["partner"]: 

831 local_partners = options["partner"] // 3 

832 for __ in range(local_partners): 

833 self.create_partner("local") 

834 other_partners = options["partner"] - local_partners 

835 for __ in range(other_partners): 

836 self.create_partner() 

837 inactive_partners = options["partner"] // 5 

838 for __ in range(inactive_partners): 

839 self.create_partner("inactive") 

840 

841 # Make one of the partners the main partner 

842 try: 

843 Partner.objects.get(is_main_partner=True) 

844 except Partner.DoesNotExist: 

845 self.create_partner("main") 

846 

847 if options["vacancy"]: 

848 categories = VacancyCategory.objects.all() 

849 if not categories: 

850 self.stdout.write("No vacancy categories found. Creating 5 categories.") 

851 for __ in range(5): 

852 self.create_vacancy_category() 

853 categories = VacancyCategory.objects.all() 

854 

855 partners = Partner.objects.all() 

856 for __ in range(options["vacancy"]): 

857 self.create_vacancy(partners, categories) 

858 

859 if options["pizza"]: 

860 for __ in range(options["pizza"]): 

861 self.create_pizza() 

862 

863 if options["newsletter"]: 

864 for __ in range(options["newsletter"]): 

865 self.create_newsletter() 

866 

867 if options["document"]: 

868 for __ in range(options["document"]): 

869 self.create_document() 

870 

871 # Courses need to be created before exams and summaries 

872 if options["course"]: 

873 # Create course categories if needed 

874 if len(Category.objects.all()) < 5: 

875 for _ in range(5): 

876 category = Category() 

877 category.name = _generate_title() 

878 

879 category.save() 

880 

881 for _ in range(options["course"]): 

882 self.create_course() 

883 

884 # Registrations need to be created before payments 

885 if options["registration"]: 

886 for _ in range(options["registration"]): 

887 self.create_event_registration() 

888 

889 if options["payment"]: 

890 for _ in range(options["payment"]): 

891 self.create_payment() 

892 

893 if options["photoalbum"]: 

894 for _ in range(options["photoalbum"]): 

895 self.create_photo_album()