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