Package coprs :: Module forms
[hide private]
[frames] | no frames]

Source Code for Module coprs.forms

  1  import re 
  2  from six.moves.urllib.parse import urlparse 
  3   
  4  import flask 
  5  import wtforms 
  6  import json 
  7   
  8  from flask_wtf.file import FileAllowed, FileRequired, FileField 
  9   
 10  from flask_wtf import Form as FlaskForm 
 11  from jinja2 import Markup 
 12   
 13  from coprs import constants 
 14  from coprs import helpers 
 15  from coprs import models 
 16  from coprs.logic.coprs_logic import CoprsLogic 
 17  from coprs.logic.users_logic import UsersLogic 
 18  from coprs.logic.modules_logic import ModulesLogic 
 19  from coprs.models import Package 
 20  from coprs import exceptions 
21 22 -def get_package_form_cls_by_source_type_text(source_type_text):
23 """ 24 Params 25 ------ 26 source_type_text : str 27 name of the source type (scm/pypi/rubygems/git_and_tito/mock_scm) 28 29 Returns 30 ------- 31 BasePackageForm child 32 based on source_type_text input 33 """ 34 if source_type_text == 'scm': 35 return PackageFormScm 36 elif source_type_text == 'pypi': 37 return PackageFormPyPI 38 elif source_type_text == 'rubygems': 39 return PackageFormRubyGems 40 elif source_type_text == 'git_and_tito': 41 return PackageFormTito # deprecated 42 elif source_type_text == 'mock_scm': 43 return PackageFormMock # deprecated 44 else: 45 raise exceptions.UnknownSourceTypeException("Invalid source type")
46
47 48 -class MultiCheckboxField(wtforms.SelectMultipleField):
49 widget = wtforms.widgets.ListWidget(prefix_label=False) 50 option_widget = wtforms.widgets.CheckboxInput()
51
52 53 -class UrlListValidator(object):
54
55 - def __init__(self, message=None):
56 if not message: 57 message = ("A list of http[s] URLs separated by whitespace characters" 58 " is needed ('{0}' doesn't seem to be a valid URL).") 59 self.message = message
60
61 - def __call__(self, form, field):
62 urls = field.data.split() 63 for u in urls: 64 if not self.is_url(u): 65 raise wtforms.ValidationError(self.message.format(u))
66
67 - def is_url(self, url):
68 parsed = urlparse(url) 69 if not parsed.scheme.startswith("http"): 70 return False 71 if not parsed.netloc: 72 return False 73 return True
74
75 76 -class UrlRepoListValidator(UrlListValidator):
77 """ Allows also `repo://` schema"""
78 - def is_url(self, url):
79 parsed = urlparse(url) 80 if parsed.scheme not in ["http", "https", "copr"]: 81 return False 82 if not parsed.netloc: 83 return False 84 # copr://username/projectname 85 # ^^ schema ^^ netlock ^^ path 86 if parsed.scheme == "copr": 87 # check if projectname missed 88 path_split = parsed.path.split("/") 89 if len(path_split) < 2 or path_split[1] == "": 90 return False 91 92 return True
93
94 95 -class UrlSrpmListValidator(UrlListValidator):
96 - def __init__(self, message=None):
97 if not message: 98 message = ("URLs must end with .src.rpm, .nosrc.rpm, or .spec" 99 " ('{0}' doesn't seem to be a valid URL).") 100 super(UrlSrpmListValidator, self).__init__(message)
101
102 - def is_url(self, url):
103 parsed = urlparse(url) 104 if not parsed.path.endswith((".src.rpm", ".nosrc.rpm", ".spec")): 105 return False 106 return True
107
108 109 -class SrpmValidator(object):
110 - def __init__(self, message=None):
111 if not message: 112 message = "You can upload only .src.rpm, .nosrc.rpm, and .spec files" 113 self.message = message
114
115 - def __call__(self, form, field):
116 filename = field.data.filename.lower() 117 if not filename.endswith((".src.rpm", ".nosrc.rpm", ".spec")): 118 raise wtforms.ValidationError(self.message)
119
120 121 -class CoprUniqueNameValidator(object):
122
123 - def __init__(self, message=None, user=None, group=None):
124 if not message: 125 if group is None: 126 message = "You already have project named '{}'." 127 else: 128 message = "Group {} ".format(group) + "already have project named '{}'." 129 self.message = message 130 if not user: 131 user = flask.g.user 132 self.user = user 133 self.group = group
134
135 - def __call__(self, form, field):
136 if self.group: 137 existing = CoprsLogic.exists_for_group( 138 self.group, field.data).first() 139 else: 140 existing = CoprsLogic.exists_for_user( 141 self.user, field.data).first() 142 143 if existing and str(existing.id) != form.id.data: 144 raise wtforms.ValidationError(self.message.format(field.data))
145
146 147 -class NameCharactersValidator(object):
148 - def __init__(self, message=None):
149 if not message: 150 message = "Name must contain only letters, digits, underscores, dashes and dots." 151 self.message = message
152
153 - def __call__(self, form, field):
154 validator = wtforms.validators.Regexp( 155 re.compile(r"^[\w.-]+$"), 156 message=self.message) 157 validator(form, field)
158
159 160 -class ChrootsValidator(object):
161 - def __call__(self, form, field):
162 selected = set(field.data.split()) 163 enabled = set(self.chroots_list()) 164 165 if not (selected <= enabled): 166 raise wtforms.ValidationError("Such chroot is not enabled: {}".format(", ".join(selected - enabled)))
167
168 - def chroots_list(self):
169 return [c.name for c in models.MockChroot.query.filter(models.MockChroot.is_active).all()]
170
171 172 -class NameNotNumberValidator(object):
173
174 - def __init__(self, message=None):
175 if not message: 176 message = "Project's name can not be just number." 177 self.message = message
178
179 - def __call__(self, form, field):
180 if field.data.isdigit(): 181 raise wtforms.ValidationError(self.message.format(field.data))
182
183 184 -class EmailOrURL(object):
185
186 - def __init__(self, message=None):
187 if not message: 188 message = "{} must be email address or URL" 189 self.message = message
190
191 - def __call__(self, form, field):
192 for validator in [wtforms.validators.Email(), wtforms.validators.URL()]: 193 try: 194 validator(form, field) 195 return True 196 except wtforms.ValidationError: 197 pass 198 raise wtforms.ValidationError(self.message.format(field.name.capitalize()))
199
200 201 -class StringListFilter(object):
202
203 - def __call__(self, value):
204 if not value: 205 return '' 206 # Replace every whitespace string with one newline 207 # Formats ideally for html form filling, use replace('\n', ' ') 208 # to get space-separated values or split() to get list 209 result = value.strip() 210 regex = re.compile(r"\s+") 211 return regex.sub(lambda x: '\n', result)
212
213 214 -class ValueToPermissionNumberFilter(object):
215
216 - def __call__(self, value):
217 if value: 218 return helpers.PermissionEnum("request") 219 return helpers.PermissionEnum("nothing")
220
221 222 -class CoprFormFactory(object):
223 224 @staticmethod
225 - def create_form_cls(mock_chroots=None, user=None, group=None):
226 class F(FlaskForm): 227 # also use id here, to be able to find out whether user 228 # is updating a copr if so, we don't want to shout 229 # that name already exists 230 id = wtforms.HiddenField() 231 group_id = wtforms.HiddenField() 232 233 name = wtforms.StringField( 234 "Name", 235 validators=[ 236 wtforms.validators.DataRequired(), 237 NameCharactersValidator(), 238 CoprUniqueNameValidator(user=user, group=group), 239 NameNotNumberValidator() 240 ]) 241 242 homepage = wtforms.StringField( 243 "Homepage", 244 validators=[ 245 wtforms.validators.Optional(), 246 wtforms.validators.URL()]) 247 248 contact = wtforms.StringField( 249 "Contact", 250 validators=[ 251 wtforms.validators.Optional(), 252 EmailOrURL()]) 253 254 description = wtforms.TextAreaField("Description") 255 256 instructions = wtforms.TextAreaField("Instructions") 257 258 repos = wtforms.TextAreaField( 259 "External Repositories", 260 validators=[UrlRepoListValidator()], 261 filters=[StringListFilter()]) 262 263 initial_pkgs = wtforms.TextAreaField( 264 "Initial packages to build", 265 validators=[ 266 UrlListValidator(), 267 UrlSrpmListValidator()], 268 filters=[StringListFilter()]) 269 270 disable_createrepo = wtforms.BooleanField(default=False) 271 build_enable_net = wtforms.BooleanField(default=False) 272 unlisted_on_hp = wtforms.BooleanField("Do not display this project on home page", default=False) 273 persistent = wtforms.BooleanField(default=False) 274 auto_prune = wtforms.BooleanField("If backend auto-prunning script should be run for this project", default=True) 275 use_bootstrap_container = wtforms.BooleanField("Enable use_bootstrap_container mock's feature (experimental)", default=False) 276 follow_fedora_branching = wtforms.BooleanField("If newly branched chroots should be automatically enabled and populated.", default=False) 277 278 @property 279 def selected_chroots(self): 280 selected = [] 281 for ch in self.chroots_list: 282 if getattr(self, ch).data: 283 selected.append(ch) 284 return selected
285 286 def validate(self): 287 if not super(F, self).validate(): 288 return False 289 290 if not self.validate_mock_chroots_not_empty(): 291 self.errors["chroots"] = ["At least one chroot must be selected"] 292 return False 293 return True
294 295 def validate_mock_chroots_not_empty(self): 296 have_any = False 297 for c in self.chroots_list: 298 if getattr(self, c).data: 299 have_any = True 300 return have_any 301 302 F.chroots_list = list(map(lambda x: x.name, 303 models.MockChroot.query.filter( 304 models.MockChroot.is_active == True 305 ).all())) 306 F.chroots_list.sort() 307 # sets of chroots according to how we should print them in columns 308 F.chroots_sets = {} 309 for ch in F.chroots_list: 310 checkbox_default = False 311 if mock_chroots and ch in map(lambda x: x.name, 312 mock_chroots): 313 checkbox_default = True 314 315 setattr(F, ch, wtforms.BooleanField(ch, default=checkbox_default)) 316 if ch[0] in F.chroots_sets: 317 F.chroots_sets[ch[0]].append(ch) 318 else: 319 F.chroots_sets[ch[0]] = [ch] 320 321 return F 322
323 324 -class CoprDeleteForm(FlaskForm):
325 verify = wtforms.TextField( 326 "Confirm deleting by typing 'yes'", 327 validators=[ 328 wtforms.validators.Required(), 329 wtforms.validators.Regexp( 330 r"^yes$", 331 message="Type 'yes' - without the quotes, lowercase.") 332 ])
333
334 335 # @TODO jkadlcik - rewrite via BaseBuildFormFactory after fe-dev-cloud is back online 336 -class BuildFormRebuildFactory(object):
337 @staticmethod
338 - def create_form_cls(active_chroots):
339 class F(FlaskForm): 340 @property 341 def selected_chroots(self): 342 selected = [] 343 for ch in self.chroots_list: 344 if getattr(self, ch).data: 345 selected.append(ch) 346 return selected
347 348 memory_reqs = wtforms.IntegerField( 349 "Memory requirements", 350 validators=[ 351 wtforms.validators.NumberRange( 352 min=constants.MIN_BUILD_MEMORY, 353 max=constants.MAX_BUILD_MEMORY)], 354 default=constants.DEFAULT_BUILD_MEMORY) 355 356 timeout = wtforms.IntegerField( 357 "Timeout", 358 validators=[ 359 wtforms.validators.NumberRange( 360 min=constants.MIN_BUILD_TIMEOUT, 361 max=constants.MAX_BUILD_TIMEOUT)], 362 default=constants.DEFAULT_BUILD_TIMEOUT) 363 364 enable_net = wtforms.BooleanField()
365 366 F.chroots_list = list(map(lambda x: x.name, active_chroots)) 367 F.chroots_list.sort() 368 F.chroots_sets = {} 369 for ch in F.chroots_list: 370 setattr(F, ch, wtforms.BooleanField(ch, default=True)) 371 if ch[0] in F.chroots_sets: 372 F.chroots_sets[ch[0]].append(ch) 373 else: 374 F.chroots_sets[ch[0]] = [ch] 375 376 return F 377
378 379 -class BasePackageForm(FlaskForm):
380 package_name = wtforms.StringField( 381 "Package name", 382 validators=[wtforms.validators.DataRequired()]) 383 webhook_rebuild = wtforms.BooleanField(default=False)
384
385 386 -class PackageFormScm(BasePackageForm):
387 scm_type = wtforms.SelectField( 388 "Type", 389 choices=[("git", "Git"), ("svn", "SVN")]) 390 391 clone_url = wtforms.StringField( 392 "Clone url", 393 validators=[ 394 wtforms.validators.DataRequired(), 395 wtforms.validators.URL()]) 396 397 committish = wtforms.StringField( 398 "Committish", 399 validators=[ 400 wtforms.validators.Optional()]) 401 402 subdirectory = wtforms.StringField( 403 "Subdirectory", 404 validators=[ 405 wtforms.validators.Optional()]) 406 407 spec = wtforms.StringField( 408 "Spec File", 409 validators=[ 410 wtforms.validators.Optional(), 411 wtforms.validators.Regexp( 412 r"^.+\.spec$", 413 message="RPM spec file must end with .spec")]) 414 415 srpm_build_method = wtforms.StringField( 416 "SRPM build method", 417 validators=[ 418 wtforms.validators.DataRequired(), 419 wtforms.validators.AnyOf(["rpkg", "tito", "tito_test", "make_srpm"]) 420 ], 421 default='rpkg') 422 423 @property
424 - def source_json(self):
425 return json.dumps({ 426 "type": self.scm_type.data, 427 "clone_url": self.clone_url.data, 428 "subdirectory": self.subdirectory.data, 429 "committish": self.committish.data, 430 "spec": self.spec.data, 431 "srpm_build_method": self.srpm_build_method.data, 432 })
433
434 435 -class PackageFormPyPI(BasePackageForm):
436 pypi_package_name = wtforms.StringField( 437 "PyPI package name", 438 validators=[wtforms.validators.DataRequired()]) 439 440 pypi_package_version = wtforms.StringField( 441 "PyPI package version", 442 validators=[ 443 wtforms.validators.Optional(), 444 ]) 445 446 python_versions = MultiCheckboxField( 447 'Build for Python', 448 choices=[ 449 ('3', 'python3'), 450 ('2', 'python2') 451 ], 452 default=['3', '2']) 453 454 @property
455 - def source_json(self):
456 return json.dumps({ 457 "pypi_package_name": self.pypi_package_name.data, 458 "pypi_package_version": self.pypi_package_version.data, 459 "python_versions": self.python_versions.data 460 })
461
462 463 -class PackageFormRubyGems(BasePackageForm):
464 gem_name = wtforms.StringField( 465 "Gem Name", 466 validators=[wtforms.validators.DataRequired()]) 467 468 @property
469 - def source_json(self):
470 return json.dumps({ 471 "gem_name": self.gem_name.data 472 })
473
474 475 -class PackageFormTito(BasePackageForm):
476 """ 477 @deprecated 478 """ 479 git_url = wtforms.StringField( 480 "Git URL", 481 validators=[ 482 wtforms.validators.DataRequired(), 483 wtforms.validators.URL()]) 484 485 git_directory = wtforms.StringField( 486 "Git Directory", 487 validators=[ 488 wtforms.validators.Optional()]) 489 490 git_branch = wtforms.StringField( 491 "Git Branch", 492 validators=[ 493 wtforms.validators.Optional()]) 494 495 tito_test = wtforms.BooleanField(default=False) 496 497 @property
498 - def source_json(self):
499 return json.dumps({ 500 "type": 'git', 501 "clone_url": self.git_url.data, 502 "committish": self.git_branch.data, 503 "subdirectory": self.git_directory.data, 504 "spec": '', 505 "srpm_build_method": 'tito_test' if self.tito_test.data else 'tito', 506 })
507
508 509 -class PackageFormMock(BasePackageForm):
510 """ 511 @deprecated 512 """ 513 scm_type = wtforms.SelectField( 514 "SCM Type", 515 choices=[("git", "Git"), ("svn", "SVN")]) 516 517 scm_url = wtforms.StringField( 518 "SCM URL", 519 validators=[ 520 wtforms.validators.DataRequired(), 521 wtforms.validators.URL()]) 522 523 scm_branch = wtforms.StringField( 524 "Git Branch", 525 validators=[ 526 wtforms.validators.Optional()]) 527 528 scm_subdir = wtforms.StringField( 529 "Subdirectory", 530 validators=[ 531 wtforms.validators.Optional()]) 532 533 spec = wtforms.StringField( 534 "Spec File", 535 validators=[ 536 wtforms.validators.Optional(), 537 wtforms.validators.Regexp( 538 r"^.+\.spec$", 539 message="RPM spec file must end with .spec")]) 540 541 @property
542 - def source_json(self):
543 return json.dumps({ 544 "type": self.scm_type.data, 545 "clone_url": self.scm_url.data, 546 "committish": self.scm_branch.data, 547 "subdirectory": self.scm_subdir.data, 548 "spec": self.spec.data, 549 "srpm_build_method": 'rpkg', 550 })
551
552 553 -class PackageFormDistGit(BasePackageForm):
554 """ 555 @deprecated 556 """ 557 clone_url = wtforms.StringField( 558 "Clone Url", 559 validators=[wtforms.validators.DataRequired()]) 560 561 branch = wtforms.StringField( 562 "Branch", 563 validators=[wtforms.validators.Optional()]) 564 565 @property
566 - def source_json(self):
567 return json.dumps({ 568 "type": 'git', 569 "clone_url": self.clone_url.data, 570 "committish": self.branch.data, 571 "subdirectory": '', 572 "spec": '', 573 "srpm_build_method": 'rpkg', 574 })
575
576 577 -class RebuildAllPackagesFormFactory(object):
578 - def __new__(cls, active_chroots, package_names):
579 form_cls = BaseBuildFormFactory(active_chroots, FlaskForm) 580 form_cls.packages = MultiCheckboxField( 581 "Packages", 582 choices=[(name, name) for name in package_names], 583 default=package_names, 584 validators=[wtforms.validators.DataRequired()]) 585 return form_cls
586
587 588 -class BaseBuildFormFactory(object):
589 - def __new__(cls, active_chroots, form):
590 class F(form): 591 @property 592 def selected_chroots(self): 593 selected = [] 594 for ch in self.chroots_list: 595 if getattr(self, ch).data: 596 selected.append(ch) 597 return selected
598 599 F.memory_reqs = wtforms.IntegerField( 600 "Memory requirements", 601 validators=[ 602 wtforms.validators.Optional(), 603 wtforms.validators.NumberRange( 604 min=constants.MIN_BUILD_MEMORY, 605 max=constants.MAX_BUILD_MEMORY)], 606 default=constants.DEFAULT_BUILD_MEMORY) 607 608 F.timeout = wtforms.IntegerField( 609 "Timeout", 610 validators=[ 611 wtforms.validators.Optional(), 612 wtforms.validators.NumberRange( 613 min=constants.MIN_BUILD_TIMEOUT, 614 max=constants.MAX_BUILD_TIMEOUT)], 615 default=constants.DEFAULT_BUILD_TIMEOUT) 616 617 F.enable_net = wtforms.BooleanField() 618 F.background = wtforms.BooleanField(default=False) 619 620 # overrides BasePackageForm.package_name and is unused for building 621 F.package_name = wtforms.StringField() 622 623 F.chroots_list = list(map(lambda x: x.name, active_chroots)) 624 F.chroots_list.sort() 625 F.chroots_sets = {} 626 for ch in F.chroots_list: 627 setattr(F, ch, wtforms.BooleanField(ch, default=True)) 628 if ch[0] in F.chroots_sets: 629 F.chroots_sets[ch[0]].append(ch) 630 else: 631 F.chroots_sets[ch[0]] = [ch] 632 return F 633
634 635 -class BuildFormScmFactory(object):
636 - def __new__(cls, active_chroots):
638
639 640 -class BuildFormTitoFactory(object):
641 """ 642 @deprecated 643 """
644 - def __new__(cls, active_chroots):
646
647 648 -class BuildFormMockFactory(object):
649 """ 650 @deprecated 651 """
652 - def __new__(cls, active_chroots):
654
655 656 -class BuildFormPyPIFactory(object):
657 - def __new__(cls, active_chroots):
659
660 661 -class BuildFormRubyGemsFactory(object):
662 - def __new__(cls, active_chroots):
664
665 666 -class BuildFormDistGitFactory(object):
667 - def __new__(cls, active_chroots):
669
670 671 -class BuildFormUploadFactory(object):
672 - def __new__(cls, active_chroots):
673 form = BaseBuildFormFactory(active_chroots, FlaskForm) 674 form.pkgs = FileField('srpm', validators=[ 675 FileRequired(), 676 SrpmValidator()]) 677 return form
678
679 680 -class BuildFormUrlFactory(object):
681 - def __new__(cls, active_chroots):
682 form = BaseBuildFormFactory(active_chroots, FlaskForm) 683 form.pkgs = wtforms.TextAreaField( 684 "Pkgs", 685 validators=[ 686 wtforms.validators.DataRequired(message="URLs to packages are required"), 687 UrlListValidator(), 688 UrlSrpmListValidator()], 689 filters=[StringListFilter()]) 690 return form
691
692 693 -class ModuleFormUploadFactory(FlaskForm):
694 modulemd = FileField("modulemd", validators=[ 695 FileRequired(), 696 # @TODO Validate modulemd.yaml file 697 ]) 698 699 create = wtforms.BooleanField("create", default=True) 700 build = wtforms.BooleanField("build", default=True)
701
702 703 -class ModuleBuildForm(FlaskForm):
704 modulemd = FileField("modulemd") 705 scmurl = wtforms.StringField() 706 branch = wtforms.StringField() 707 copr_owner = wtforms.StringField() 708 copr_project = wtforms.StringField()
709
710 711 -class ChrootForm(FlaskForm):
712 713 """ 714 Validator for editing chroots in project 715 (adding packages to minimal chroot) 716 """ 717 718 buildroot_pkgs = wtforms.TextField( 719 "Packages") 720 721 repos = wtforms.TextAreaField('Repos', 722 validators=[UrlRepoListValidator(), 723 wtforms.validators.Optional()], 724 filters=[StringListFilter()]) 725 726 module_md = FileField("module_md") 727 728 comps = FileField("comps_xml")
729
730 731 -class CoprLegalFlagForm(FlaskForm):
732 comment = wtforms.TextAreaField("Comment")
733
734 735 -class PermissionsApplierFormFactory(object):
736 737 @staticmethod
738 - def create_form_cls(permission=None):
739 class F(FlaskForm): 740 pass
741 742 builder_default = False 743 admin_default = False 744 745 if permission: 746 if permission.copr_builder != helpers.PermissionEnum("nothing"): 747 builder_default = True 748 if permission.copr_admin != helpers.PermissionEnum("nothing"): 749 admin_default = True 750 751 setattr(F, "copr_builder", 752 wtforms.BooleanField( 753 default=builder_default, 754 filters=[ValueToPermissionNumberFilter()])) 755 756 setattr(F, "copr_admin", 757 wtforms.BooleanField( 758 default=admin_default, 759 filters=[ValueToPermissionNumberFilter()])) 760 761 return F
762
763 764 -class PermissionsFormFactory(object):
765 766 """Creates a dynamic form for given set of copr permissions""" 767 @staticmethod
768 - def create_form_cls(permissions):
769 class F(FlaskForm): 770 pass
771 772 for perm in permissions: 773 builder_choices = helpers.PermissionEnum.choices_list() 774 admin_choices = helpers.PermissionEnum.choices_list() 775 776 builder_default = perm.copr_builder 777 admin_default = perm.copr_admin 778 779 setattr(F, "copr_builder_{0}".format(perm.user.id), 780 wtforms.SelectField( 781 choices=builder_choices, 782 default=builder_default, 783 coerce=int)) 784 785 setattr(F, "copr_admin_{0}".format(perm.user.id), 786 wtforms.SelectField( 787 choices=admin_choices, 788 default=admin_default, 789 coerce=int)) 790 791 return F
792
793 794 -class CoprModifyForm(FlaskForm):
795 description = wtforms.TextAreaField('Description', 796 validators=[wtforms.validators.Optional()]) 797 798 instructions = wtforms.TextAreaField('Instructions', 799 validators=[wtforms.validators.Optional()]) 800 801 chroots = wtforms.TextAreaField('Chroots', 802 validators=[wtforms.validators.Optional(), ChrootsValidator()]) 803 804 repos = wtforms.TextAreaField('Repos', 805 validators=[UrlRepoListValidator(), 806 wtforms.validators.Optional()], 807 filters=[StringListFilter()]) 808 809 disable_createrepo = wtforms.BooleanField(validators=[wtforms.validators.Optional()]) 810 unlisted_on_hp = wtforms.BooleanField(validators=[wtforms.validators.Optional()]) 811 build_enable_net = wtforms.BooleanField(validators=[wtforms.validators.Optional()]) 812 auto_prune = wtforms.BooleanField(validators=[wtforms.validators.Optional()]) 813 use_bootstrap_container = wtforms.BooleanField(validators=[wtforms.validators.Optional()]) 814 follow_fedora_branching = wtforms.BooleanField(validators=[wtforms.validators.Optional()])
815
816 817 -class CoprForkFormFactory(object):
818 @staticmethod
819 - def create_form_cls(copr, user, groups):
820 class F(FlaskForm): 821 source = wtforms.StringField( 822 "Source", 823 default=copr.full_name) 824 825 owner = wtforms.SelectField( 826 "Fork owner", 827 choices=[(user.name, user.name)] + [(g.at_name, g.at_name) for g in groups], 828 default=user.name, 829 validators=[wtforms.validators.DataRequired()]) 830 831 name = wtforms.StringField( 832 "Fork name", 833 default=copr.name, 834 validators=[wtforms.validators.DataRequired(), NameCharactersValidator()]) 835 836 confirm = wtforms.BooleanField( 837 "Confirm", 838 default=False)
839 return F
840
841 842 -class ModifyChrootForm(FlaskForm):
843 buildroot_pkgs = wtforms.TextField('Additional packages to be always present in minimal buildroot') 844 repos = wtforms.TextAreaField('Additional repos to be used for builds in chroot', 845 validators=[UrlRepoListValidator(), 846 wtforms.validators.Optional()], 847 filters=[StringListFilter()]) 848 upload_comps = FileField("Upload comps.xml") 849 delete_comps = wtforms.BooleanField("Delete comps.xml")
850
851 852 -class AdminPlaygroundForm(FlaskForm):
853 playground = wtforms.BooleanField("Playground")
854
855 856 -class AdminPlaygroundSearchForm(FlaskForm):
857 project = wtforms.TextField("Project")
858
859 860 -class GroupUniqueNameValidator(object):
861
862 - def __init__(self, message=None):
863 if not message: 864 message = "Group with the alias '{}' already exists." 865 self.message = message
866
867 - def __call__(self, form, field):
868 if UsersLogic.group_alias_exists(field.data): 869 raise wtforms.ValidationError(self.message.format(field.data))
870
871 872 -class ActivateFasGroupForm(FlaskForm):
873 874 name = wtforms.StringField( 875 validators=[ 876 wtforms.validators.Regexp( 877 re.compile(r"^[\w.-]+$"), 878 message="Name must contain only letters," 879 "digits, underscores, dashes and dots."), 880 GroupUniqueNameValidator() 881 ] 882 )
883
884 885 -class CreateModuleForm(FlaskForm):
886 name = wtforms.StringField("Name") 887 stream = wtforms.StringField("Stream") 888 version = wtforms.IntegerField("Version") 889 builds = wtforms.FieldList(wtforms.StringField("Builds ID list")) 890 packages = wtforms.FieldList(wtforms.StringField("Packages list")) 891 filter = wtforms.FieldList(wtforms.StringField("Package Filter")) 892 api = wtforms.FieldList(wtforms.StringField("Module API")) 893 profile_names = wtforms.FieldList(wtforms.StringField("Install Profiles"), min_entries=2) 894 profile_pkgs = wtforms.FieldList(wtforms.FieldList(wtforms.StringField("Install Profiles")), min_entries=2) 895
896 - def __init__(self, copr=None, *args, **kwargs):
897 self.copr = copr 898 super(CreateModuleForm, self).__init__(*args, **kwargs)
899
900 - def validate(self):
901 if not FlaskForm.validate(self): 902 return False 903 904 module = ModulesLogic.get_by_nsv(self.copr, self.name.data, self.stream.data, self.version.data).first() 905 if module: 906 self.errors["nsv"] = [Markup("Module <a href='{}'>{}</a> already exists".format( 907 helpers.copr_url("coprs_ns.copr_module", module.copr, id=module.id), module.full_name))] 908 return False 909 910 # Profile names should be unique 911 names = filter(None, self.profile_names.data) 912 if len(set(names)) < len(names): 913 self.errors["profiles"] = ["Profile names must be unique"] 914 return False 915 916 # WORKAROUND 917 # profile_pkgs are somehow sorted so if I fill profile_name in the first box and 918 # profile_pkgs in seconds box, it is sorted and validated correctly 919 for i in range(0, len(self.profile_names.data)): 920 # If profile name is not set, then there should not be any packages in this profile 921 if not flask.request.form["profile_names-{}".format(i)]: 922 if [j for j in range(0, len(self.profile_names)) if "profile_pkgs-{}-{}".format(i, j) in flask.request.form]: 923 self.errors["profiles"] = ["Missing profile name"] 924 return False 925 return True
926
927 928 -class ModuleRepo(FlaskForm):
929 owner = wtforms.StringField("Owner Name", validators=[wtforms.validators.DataRequired()]) 930 copr = wtforms.StringField("Copr Name", validators=[wtforms.validators.DataRequired()]) 931 name = wtforms.StringField("Name", validators=[wtforms.validators.DataRequired()]) 932 stream = wtforms.StringField("Stream", validators=[wtforms.validators.DataRequired()]) 933 version = wtforms.IntegerField("Version", validators=[wtforms.validators.DataRequired()]) 934 arch = wtforms.StringField("Arch", validators=[wtforms.validators.DataRequired()])
935