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 python_versions = MultiCheckboxField( 477 'Build for Python', 478 choices=[ 479 ('3', 'python3'), 480 ('2', 'python2') 481 ], 482 default=['3', '2']) 483 484 @property
485 - def source_json(self):
486 return json.dumps({ 487 "pypi_package_name": self.pypi_package_name.data, 488 "pypi_package_version": self.pypi_package_version.data, 489 "python_versions": self.python_versions.data 490 })
491
492 493 -class PackageFormRubyGems(BasePackageForm):
494 gem_name = wtforms.StringField( 495 "Gem Name", 496 validators=[wtforms.validators.DataRequired()]) 497 498 @property
499 - def source_json(self):
500 return json.dumps({ 501 "gem_name": self.gem_name.data 502 })
503
504 505 -class PackageFormTito(BasePackageForm):
506 """ 507 @deprecated 508 """ 509 git_url = wtforms.StringField( 510 "Git URL", 511 validators=[ 512 wtforms.validators.DataRequired(), 513 wtforms.validators.URL()]) 514 515 git_directory = wtforms.StringField( 516 "Git Directory", 517 validators=[ 518 wtforms.validators.Optional()]) 519 520 git_branch = wtforms.StringField( 521 "Git Branch", 522 validators=[ 523 wtforms.validators.Optional()]) 524 525 tito_test = wtforms.BooleanField(default=False, false_values=FALSE_VALUES) 526 527 @property
528 - def source_json(self):
529 return json.dumps({ 530 "type": 'git', 531 "clone_url": self.git_url.data, 532 "committish": self.git_branch.data, 533 "subdirectory": self.git_directory.data, 534 "spec": '', 535 "srpm_build_method": 'tito_test' if self.tito_test.data else 'tito', 536 })
537
538 539 -class PackageFormMock(BasePackageForm):
540 """ 541 @deprecated 542 """ 543 scm_type = wtforms.SelectField( 544 "SCM Type", 545 choices=[("git", "Git"), ("svn", "SVN")]) 546 547 scm_url = wtforms.StringField( 548 "SCM URL", 549 validators=[ 550 wtforms.validators.DataRequired(), 551 wtforms.validators.URL()]) 552 553 scm_branch = wtforms.StringField( 554 "Git Branch", 555 validators=[ 556 wtforms.validators.Optional()]) 557 558 scm_subdir = wtforms.StringField( 559 "Subdirectory", 560 validators=[ 561 wtforms.validators.Optional()]) 562 563 spec = wtforms.StringField( 564 "Spec File", 565 validators=[ 566 wtforms.validators.Optional(), 567 wtforms.validators.Regexp( 568 r"^.+\.spec$", 569 message="RPM spec file must end with .spec")]) 570 571 @property
572 - def source_json(self):
573 return json.dumps({ 574 "type": self.scm_type.data, 575 "clone_url": self.scm_url.data, 576 "committish": self.scm_branch.data, 577 "subdirectory": self.scm_subdir.data, 578 "spec": self.spec.data, 579 "srpm_build_method": 'rpkg', 580 })
581
582 583 -class PackageFormDistGit(BasePackageForm):
584 """ 585 @deprecated 586 """ 587 clone_url = wtforms.StringField( 588 "Clone Url", 589 validators=[wtforms.validators.DataRequired()]) 590 591 branch = wtforms.StringField( 592 "Branch", 593 validators=[wtforms.validators.Optional()]) 594 595 @property
596 - def source_json(self):
597 return json.dumps({ 598 "type": 'git', 599 "clone_url": self.clone_url.data, 600 "committish": self.branch.data, 601 "subdirectory": '', 602 "spec": '', 603 "srpm_build_method": 'rpkg', 604 })
605
606 607 -def cleanup_script(string):
608 if not string: 609 return string 610 611 if string.split('\n')[0].endswith('\r'): 612 # This script is most probably coming from the web-UI, where 613 # web-browsers mistakenly put '\r\n' as EOL; and that would just 614 # mean that the script is not executable (any line can mean 615 # syntax error, but namely shebang would cause 100% fail) 616 string = string.replace('\r\n', '\n') 617 618 # And append newline to have a valid unix file. 619 if not string.endswith('\n'): 620 string += '\n' 621 622 return string
623
624 625 -class PackageFormCustom(BasePackageForm):
626 script = wtforms.TextAreaField( 627 "Script", 628 validators=[ 629 wtforms.validators.DataRequired(), 630 wtforms.validators.Length( 631 max=4096, 632 message="Maximum script size is 4kB"), 633 ], 634 filters=[cleanup_script], 635 ) 636 637 builddeps = wtforms.StringField( 638 "Build dependencies", 639 validators=[wtforms.validators.Optional()]) 640 641 chroot = wtforms.SelectField( 642 'Mock chroot', 643 choices=[], 644 default='fedora-latest-x86_64', 645 ) 646 647 resultdir = wtforms.StringField( 648 "Result directory", 649 validators=[wtforms.validators.Optional()]) 650
651 - def __init__(self, *args, **kwargs):
652 super(PackageFormCustom, self).__init__(*args, **kwargs) 653 chroot_objects = models.MockChroot.query.filter(models.MockChroot.is_active).all() 654 655 chroots = [c.name for c in chroot_objects] 656 chroots.sort() 657 chroots = [(name, name) for name in chroots] 658 659 arches = set() 660 for ch in chroot_objects: 661 if ch.os_release == 'fedora': 662 arches.add(ch.arch) 663 664 self.chroot.choices = [] 665 if arches: 666 self.chroot.choices += [('fedora-latest-' + l, 'fedora-latest-' + l) for l in arches] 667 668 self.chroot.choices += chroots
669 670 @property
671 - def source_json(self):
672 return json.dumps({ 673 "script": self.script.data, 674 "chroot": self.chroot.data, 675 "builddeps": self.builddeps.data, 676 "resultdir": self.resultdir.data, 677 })
678
679 680 -class RebuildAllPackagesFormFactory(object):
681 - def __new__(cls, active_chroots, package_names):
682 form_cls = BaseBuildFormFactory(active_chroots, FlaskForm) 683 form_cls.packages = MultiCheckboxField( 684 "Packages", 685 choices=[(name, name) for name in package_names], 686 default=package_names, 687 validators=[wtforms.validators.DataRequired()]) 688 return form_cls
689
690 691 -class BaseBuildFormFactory(object):
692 - def __new__(cls, active_chroots, form):
693 class F(form): 694 @property 695 def selected_chroots(self): 696 selected = [] 697 for ch in self.chroots_list: 698 if getattr(self, ch).data: 699 selected.append(ch) 700 return selected
701 702 F.memory_reqs = wtforms.IntegerField( 703 "Memory requirements", 704 validators=[ 705 wtforms.validators.Optional(), 706 wtforms.validators.NumberRange( 707 min=constants.MIN_BUILD_MEMORY, 708 max=constants.MAX_BUILD_MEMORY)], 709 default=constants.DEFAULT_BUILD_MEMORY) 710 711 F.timeout = wtforms.IntegerField( 712 "Timeout", 713 validators=[ 714 wtforms.validators.Optional(), 715 wtforms.validators.NumberRange( 716 min=constants.MIN_BUILD_TIMEOUT, 717 max=constants.MAX_BUILD_TIMEOUT)], 718 default=constants.DEFAULT_BUILD_TIMEOUT) 719 720 F.enable_net = wtforms.BooleanField(false_values=FALSE_VALUES) 721 F.background = wtforms.BooleanField(default=False, false_values=FALSE_VALUES) 722 723 # overrides BasePackageForm.package_name and is unused for building 724 F.package_name = wtforms.StringField() 725 726 F.chroots_list = list(map(lambda x: x.name, active_chroots)) 727 F.chroots_list.sort() 728 F.chroots_sets = {} 729 for ch in F.chroots_list: 730 setattr(F, ch, wtforms.BooleanField(ch, default=True, false_values=FALSE_VALUES)) 731 if ch[0] in F.chroots_sets: 732 F.chroots_sets[ch[0]].append(ch) 733 else: 734 F.chroots_sets[ch[0]] = [ch] 735 return F 736
737 738 -class BuildFormScmFactory(object):
739 - def __new__(cls, active_chroots):
741
742 743 -class BuildFormTitoFactory(object):
744 """ 745 @deprecated 746 """
747 - def __new__(cls, active_chroots):
749
750 751 -class BuildFormMockFactory(object):
752 """ 753 @deprecated 754 """
755 - def __new__(cls, active_chroots):
757
758 759 -class BuildFormPyPIFactory(object):
760 - def __new__(cls, active_chroots):
762
763 764 -class BuildFormRubyGemsFactory(object):
765 - def __new__(cls, active_chroots):
767
768 769 -class BuildFormDistGitFactory(object):
770 - def __new__(cls, active_chroots):
772
773 774 -class BuildFormUploadFactory(object):
775 - def __new__(cls, active_chroots):
776 form = BaseBuildFormFactory(active_chroots, FlaskForm) 777 form.pkgs = FileField('srpm', validators=[ 778 FileRequired(), 779 SrpmValidator()]) 780 return form
781
782 783 -class BuildFormCustomFactory(object):
784 - def __new__(cls, active_chroots):
786
787 788 -class BuildFormUrlFactory(object):
789 - def __new__(cls, active_chroots):
790 form = BaseBuildFormFactory(active_chroots, FlaskForm) 791 form.pkgs = wtforms.TextAreaField( 792 "Pkgs", 793 validators=[ 794 wtforms.validators.DataRequired(message="URLs to packages are required"), 795 UrlListValidator(), 796 UrlSrpmListValidator()], 797 filters=[StringListFilter()]) 798 return form
799
800 801 -class ModuleFormUploadFactory(FlaskForm):
802 modulemd = FileField("modulemd", validators=[ 803 FileRequired(), 804 # @TODO Validate modulemd.yaml file 805 ]) 806 807 create = wtforms.BooleanField("create", default=True, false_values=FALSE_VALUES) 808 build = wtforms.BooleanField("build", default=True, false_values=FALSE_VALUES)
809
810 811 -class ModuleBuildForm(FlaskForm):
812 modulemd = FileField("modulemd") 813 scmurl = wtforms.StringField() 814 branch = wtforms.StringField()
815
816 817 -class PagureIntegrationForm(FlaskForm):
818 repo_url = wtforms.StringField("repo_url", default='') 819 api_key = wtforms.StringField("api_key", default='') 820
821 - def __init__(self, api_key=None, repo_url=None, *args, **kwargs):
822 super(PagureIntegrationForm, self).__init__(*args, **kwargs) 823 if api_key != None: 824 self.api_key.data = api_key 825 if repo_url != None: 826 self.repo_url.data = repo_url
827
828 829 -class ChrootForm(FlaskForm):
830 831 """ 832 Validator for editing chroots in project 833 (adding packages to minimal chroot) 834 """ 835 836 buildroot_pkgs = wtforms.TextField("Packages") 837 838 repos = wtforms.TextAreaField('Repos', 839 validators=[UrlRepoListValidator(), 840 wtforms.validators.Optional()], 841 filters=[StringListFilter()]) 842 843 module_md = FileField("module_md") 844 845 comps = FileField("comps_xml") 846 847 with_opts = wtforms.TextField("With options") 848 without_opts = wtforms.TextField("Without options")
849
850 -class CoprLegalFlagForm(FlaskForm):
851 comment = wtforms.TextAreaField("Comment")
852
853 854 -class PermissionsApplierFormFactory(object):
855 856 @staticmethod
857 - def create_form_cls(permission=None):
858 class F(FlaskForm): 859 pass
860 861 builder_default = False 862 admin_default = False 863 864 if permission: 865 if permission.copr_builder != helpers.PermissionEnum("nothing"): 866 builder_default = True 867 if permission.copr_admin != helpers.PermissionEnum("nothing"): 868 admin_default = True 869 870 setattr(F, "copr_builder", 871 wtforms.BooleanField( 872 default=builder_default, 873 false_values=FALSE_VALUES, 874 filters=[ValueToPermissionNumberFilter()])) 875 876 setattr(F, "copr_admin", 877 wtforms.BooleanField( 878 default=admin_default, 879 false_values=FALSE_VALUES, 880 filters=[ValueToPermissionNumberFilter()])) 881 882 return F
883
884 885 -class PermissionsFormFactory(object):
886 887 """Creates a dynamic form for given set of copr permissions""" 888 @staticmethod
889 - def create_form_cls(permissions):
890 class F(FlaskForm): 891 pass
892 893 for perm in permissions: 894 builder_choices = helpers.PermissionEnum.choices_list() 895 admin_choices = helpers.PermissionEnum.choices_list() 896 897 builder_default = perm.copr_builder 898 admin_default = perm.copr_admin 899 900 setattr(F, "copr_builder_{0}".format(perm.user.id), 901 wtforms.SelectField( 902 choices=builder_choices, 903 default=builder_default, 904 coerce=int)) 905 906 setattr(F, "copr_admin_{0}".format(perm.user.id), 907 wtforms.SelectField( 908 choices=admin_choices, 909 default=admin_default, 910 coerce=int)) 911 912 return F
913
914 915 -class CoprModifyForm(FlaskForm):
916 description = wtforms.TextAreaField('Description', 917 validators=[wtforms.validators.Optional()]) 918 919 instructions = wtforms.TextAreaField('Instructions', 920 validators=[wtforms.validators.Optional()]) 921 922 chroots = wtforms.TextAreaField('Chroots', 923 validators=[wtforms.validators.Optional(), ChrootsValidator()]) 924 925 repos = wtforms.TextAreaField('Repos', 926 validators=[UrlRepoListValidator(), 927 wtforms.validators.Optional()], 928 filters=[StringListFilter()]) 929 930 disable_createrepo = wtforms.BooleanField(validators=[wtforms.validators.Optional()], false_values=FALSE_VALUES) 931 unlisted_on_hp = wtforms.BooleanField(validators=[wtforms.validators.Optional()], false_values=FALSE_VALUES) 932 auto_prune = wtforms.BooleanField(validators=[wtforms.validators.Optional()], false_values=FALSE_VALUES) 933 use_bootstrap_container = wtforms.BooleanField(validators=[wtforms.validators.Optional()], false_values=FALSE_VALUES) 934 follow_fedora_branching = wtforms.BooleanField(validators=[wtforms.validators.Optional()], false_values=FALSE_VALUES) 935 936 # Deprecated, use `enable_net` instead 937 build_enable_net = wtforms.BooleanField(validators=[wtforms.validators.Optional()], false_values=FALSE_VALUES) 938 enable_net = wtforms.BooleanField(validators=[wtforms.validators.Optional()], false_values=FALSE_VALUES)
939
940 941 -class CoprForkFormFactory(object):
942 @staticmethod
943 - def create_form_cls(copr, user, groups):
944 class F(FlaskForm): 945 source = wtforms.StringField( 946 "Source", 947 default=copr.full_name) 948 949 owner = wtforms.SelectField( 950 "Fork owner", 951 choices=[(user.name, user.name)] + [(g.at_name, g.at_name) for g in groups], 952 default=user.name, 953 validators=[wtforms.validators.DataRequired()]) 954 955 name = wtforms.StringField( 956 "Fork name", 957 default=copr.name, 958 validators=[wtforms.validators.DataRequired(), NameCharactersValidator()]) 959 960 confirm = wtforms.BooleanField( 961 "Confirm", 962 false_values=FALSE_VALUES, 963 default=False)
964 return F
965
966 967 -class ModifyChrootForm(ChrootForm):
968 buildroot_pkgs = wtforms.TextField('Additional packages to be always present in minimal buildroot') 969 repos = wtforms.TextAreaField('Additional repos to be used for builds in chroot', 970 validators=[UrlRepoListValidator(), 971 wtforms.validators.Optional()], 972 filters=[StringListFilter()]) 973 comps = None 974 upload_comps = FileField("Upload comps.xml") 975 delete_comps = wtforms.BooleanField("Delete comps.xml", false_values=FALSE_VALUES)
976
977 -class AdminPlaygroundForm(FlaskForm):
978 playground = wtforms.BooleanField("Playground", false_values=FALSE_VALUES)
979
980 981 -class AdminPlaygroundSearchForm(FlaskForm):
982 project = wtforms.TextField("Project")
983
984 985 -class GroupUniqueNameValidator(object):
986
987 - def __init__(self, message=None):
988 if not message: 989 message = "Group with the alias '{}' already exists." 990 self.message = message
991
992 - def __call__(self, form, field):
993 if UsersLogic.group_alias_exists(field.data): 994 raise wtforms.ValidationError(self.message.format(field.data))
995
996 997 -class ActivateFasGroupForm(FlaskForm):
998 999 name = wtforms.StringField( 1000 validators=[ 1001 wtforms.validators.Regexp( 1002 re.compile(r"^[\w.-]+$"), 1003 message="Name must contain only letters," 1004 "digits, underscores, dashes and dots."), 1005 GroupUniqueNameValidator() 1006 ] 1007 )
1008
1009 1010 -class CreateModuleForm(FlaskForm):
1011 builds = wtforms.FieldList(wtforms.StringField("Builds ID list")) 1012 packages = wtforms.FieldList(wtforms.StringField("Packages list")) 1013 filter = wtforms.FieldList(wtforms.StringField("Package Filter")) 1014 api = wtforms.FieldList(wtforms.StringField("Module API")) 1015 profile_names = wtforms.FieldList(wtforms.StringField("Install Profiles"), min_entries=2) 1016 profile_pkgs = wtforms.FieldList(wtforms.FieldList(wtforms.StringField("Install Profiles")), min_entries=2) 1017
1018 - def __init__(self, copr=None, *args, **kwargs):
1019 self.copr = copr 1020 super(CreateModuleForm, self).__init__(*args, **kwargs)
1021
1022 - def validate(self):
1023 if not FlaskForm.validate(self): 1024 return False 1025 1026 # Profile names should be unique 1027 names = [x for x in self.profile_names.data if x] 1028 if len(set(names)) < len(names): 1029 self.errors["profiles"] = ["Profile names must be unique"] 1030 return False 1031 1032 # WORKAROUND 1033 # profile_pkgs are somehow sorted so if I fill profile_name in the first box and 1034 # profile_pkgs in seconds box, it is sorted and validated correctly 1035 for i in range(0, len(self.profile_names.data)): 1036 # If profile name is not set, then there should not be any packages in this profile 1037 if not flask.request.form["profile_names-{}".format(i)]: 1038 if [j for j in range(0, len(self.profile_names)) if "profile_pkgs-{}-{}".format(i, j) in flask.request.form]: 1039 self.errors["profiles"] = ["Missing profile name"] 1040 return False 1041 return True
1042
1043 1044 -class ModuleRepo(FlaskForm):
1045 owner = wtforms.StringField("Owner Name", validators=[wtforms.validators.DataRequired()]) 1046 copr = wtforms.StringField("Copr Name", validators=[wtforms.validators.DataRequired()]) 1047 name = wtforms.StringField("Name", validators=[wtforms.validators.DataRequired()]) 1048 stream = wtforms.StringField("Stream", validators=[wtforms.validators.DataRequired()]) 1049 version = wtforms.IntegerField("Version", validators=[wtforms.validators.DataRequired()]) 1050 arch = wtforms.StringField("Arch", validators=[wtforms.validators.DataRequired()])
1051