Ignore:
Timestamp:
23 Jan 2020, 12:25:29 (5 years ago)
Author:
Henrik Bettermann
Message:

Provide components for file uploads in the applicants section.

Location:
main/waeup.kofa/trunk
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • main/waeup.kofa/trunk/CHANGES.txt

    r15941 r15943  
    441.6.1.dev0 (unreleased)
    55=======================
     6
     7* Provide components for file uploads in the applicants section.
    68
    79* Copy also files from applicants to students section.
  • main/waeup.kofa/trunk/src/waeup/kofa/applicants/applicant.py

    r15941 r15943  
    253253        """
    254254        file_store = getUtility(IExtFileStore)
    255         filenames = getUtility(IApplicantsUtils).FILENAMES
     255        filenames = getUtility(IApplicantsUtils).ADDITIONAL_FILES
    256256        for filename in filenames:
    257             appl_file = file_store.getFileByContext(self, attr=filename)
     257            appl_file = file_store.getFileByContext(self, attr=filename[1])
    258258            if appl_file is None:
    259259                return
    260260            stud_file_id = IFileStoreNameChooser(student).chooseName(
    261                 attr=filename)
     261                attr=filename[1])
    262262            file_store.createFile(stud_file_id, appl_file)
    263263        return
     
    456456    file_store.deleteFileByContext(applicant)
    457457    # Remove all other files too
    458 
    459 
     458    filenames = getUtility(IApplicantsUtils).ADDITIONAL_FILES
     459    for filename in filenames:
     460        file_store.deleteFileByContext(applicant, attr=filename[1])
    460461    # Remove global role
    461462    role_manager = IPrincipalRoleManager(grok.getSite())
  • main/waeup.kofa/trunk/src/waeup/kofa/applicants/browser.py

    r15932 r15943  
    588588
    589589    @property
     590    def file_links(self):
     591        html = ''
     592        file_store = getUtility(IExtFileStore)
     593        additional_files = getUtility(IApplicantsUtils).ADDITIONAL_FILES
     594        for filename in additional_files:
     595            pdf = getUtility(IExtFileStore).getFileByContext(
     596                self.context, attr=filename[1])
     597            if pdf:
     598                html += '<a href="%s">%s</a>, ' % (self.url(
     599                    self.context, filename[1]), filename[0])
     600        html = html.strip(', ')
     601        return html
     602
     603    @property
    590604    def display_payments(self):
    591605        if self.context.payments:
     
    939953    return True
    940954
     955def handle_file_upload(upload, context, view, attr=None):
     956    """Handle upload of applicant files.
     957
     958    Returns `True` in case of success or `False`.
     959
     960    Please note that file pointer passed in (`upload`) most probably
     961    points to end of file when leaving this function.
     962    """
     963    size = file_size(upload)
     964    max_upload_size = 1024 * getUtility(IStudentsUtils).MAX_KB
     965    if size > max_upload_size:
     966        view.flash(_('Uploaded file is too big!'))
     967        return False
     968    dummy, ext = os.path.splitext(upload.filename)
     969    ext.lower()
     970    if ext != '.pdf':
     971        view.flash(_('pdf file extension expected.'))
     972        return False
     973    upload.seek(0) # file pointer moved when determining size
     974    store = getUtility(IExtFileStore)
     975    file_id = IFileStoreNameChooser(context).chooseName(attr=attr)
     976    store.createFile(file_id, upload)
     977    return True
     978
    941979class ApplicantManageFormPage(KofaEditFormPage):
    942980    """A full edit view for applicant data.
     
    10081046            if self.upload_success:
    10091047                self.context.writeLogMessage(self, 'saved: passport')
     1048        file_store = getUtility(IExtFileStore)
     1049        self.additional_files = getUtility(IApplicantsUtils).ADDITIONAL_FILES
     1050        for filename in self.additional_files:
     1051            upload = self.request.form.get(filename[1], None)
     1052            if upload:
     1053                # We got a fresh file upload
     1054                success = handle_file_upload(
     1055                    upload, self.context, self, attr=filename[1])
     1056                if success:
     1057                    self.context.writeLogMessage(
     1058                        self, 'saved: %s' % filename[1])
     1059                else:
     1060                    self.upload_success = False
     1061        self.max_file_upload_size = 1024 * getUtility(IStudentsUtils).MAX_KB
    10101062        return
    10111063
     
    16741726        self.redirect(self.application_url())
    16751727        return
     1728
     1729class AdditionalFile(grok.View):
     1730    """Renders additional pdf files for applicants.
     1731    This is a baseclass.
     1732    """
     1733    grok.baseclass()
     1734    grok.context(IApplicant)
     1735    grok.require('waeup.viewApplication')
     1736
     1737    def render(self):
     1738        pdf = getUtility(IExtFileStore).getFileByContext(
     1739            self.context, attr=self.__name__)
     1740        self.response.setHeader('Content-Type', 'application/pdf')
     1741        return pdf
     1742
     1743class TestFile(AdditionalFile):
     1744    """Renders testfile.pdf.
     1745    """
     1746    grok.name('testfile.pdf')
  • main/waeup.kofa/trunk/src/waeup/kofa/applicants/browser_templates/applicantdisplaypage.pt

    r15502 r15943  
    3636          <tal:password replace="view/hasPassword" />
    3737      </td>
    38     <tr>
     38    </tr>
     39    <tal:files>
     40      <tr>
     41        <td class="separator" colspan=2>
     42          Files
     43        </td>
     44      </tr>
     45      <tr>
     46        <td colspan=2>
     47          <span tal:replace="structure view/file_links" />
     48        </td>
     49      </tr>
     50    </tal:files>
    3951  </tbody>
    4052</table>
  • main/waeup.kofa/trunk/src/waeup/kofa/applicants/browser_templates/applicanteditpage.pt

    r15502 r15943  
    4343          <span tal:replace="view/max_upload_size">10 KB</span>
    4444      </tr>
     45
     46      <tal:files>
     47        <tr tal:repeat="filename view/additional_files">
     48          <td class="fieldname">
     49            <span tal:replace="python:filename[0]">FILENAME</span>
     50          </td>
     51          <td>
     52            <p tal:condition="python:view.file_exists(filename[1])">
     53              <a tal:attributes="href python:filename[1]"i18n:translate="">
     54                Download pdf file
     55              </a>
     56            </p>
     57            <div class="input-group half">
     58              <div class="input-group-btn">
     59                <div class="btn btn-default btn-file">
     60                  Select&hellip;
     61                <input type="file" tal:attributes="name python:filename[1]" />
     62                </div>
     63              </div>
     64              <input type="text" class="form-control" readonly>
     65            </div>
     66            <span i18n:translate="">
     67              PDF files only. Max. file size:
     68            </span>
     69            <span tal:replace="view/max_file_upload_size">10 KB</span>
     70          </td>
     71        </tr>
     72      </tal:files>
     73
    4574      <tr tal:condition="view/manage_applications">
    4675        <td class="fieldname" i18n:translate="">Password:</td>
  • main/waeup.kofa/trunk/src/waeup/kofa/applicants/tests/test_browser.py

    r15578 r15943  
    12781278            '<option selected="selected" value="CERT1">'
    12791279            in self.browser.contents)
     1280
     1281    def test_upload_testfile(self):
     1282        self.login()
     1283        self.browser.open(self.edit_path)
     1284        self.fill_correct_values() # fill other fields with correct values       
     1285        # Create a pseudo file with acceptable size
     1286        pdf_content = 'A' * 1024 * 300  # A string of 300 KB size
     1287        pseudo_pdf = StringIO(pdf_content)
     1288        ctrl = self.browser.getControl(name='testfile.pdf')
     1289        file_ctrl = ctrl.mech_control
     1290        file_ctrl.add_file(pseudo_pdf, filename='testfile.pdf')
     1291        self.browser.getControl("Save").click() # submit form
     1292        self.assertTrue('Uploaded file is too big!'
     1293            in self.browser.contents)
     1294        pdf_content = 'A' * 1024 * 200  # A string of 300 KB size
     1295        pseudo_pdf = StringIO(pdf_content)
     1296        ctrl = self.browser.getControl(name='testfile.pdf')
     1297        file_ctrl = ctrl.mech_control
     1298        file_ctrl.add_file(pseudo_pdf, filename='testfile.pdf')
     1299        self.browser.getControl("Save").click() # submit form
     1300        # The file has been successfully uploaded
     1301        self.assertTrue('Form has been saved.' in self.browser.contents)
     1302        # There is really a file stored for the applicant
     1303        storage = getUtility(IExtFileStore)
     1304        file_id = IFileStoreNameChooser(self.applicant).chooseName(
     1305            attr='testfile.pdf')
     1306        # The stored file can be fetched
     1307        fd = storage.getFile(file_id)
     1308        file_len = len(fd.read())
     1309        self.assertEqual(file_len, 204800)
     1310        # A file link is displayed on the edit view ...
     1311        self.browser.open(self.edit_path)
     1312        self.assertTrue('<a href="testfile.pdf">' in self.browser.contents)
     1313        # ... and on the dislay view
     1314        self.browser.open(self.view_path)
     1315        self.assertTrue('testfile.pdf">Test File</a>'
     1316            in self.browser.contents)
     1317        # Adding file is properly logged
     1318        logfile = os.path.join(
     1319            self.app['datacenter'].storage, 'logs', 'applicants.log')
     1320        logcontent = open(logfile).read()
     1321        self.assertTrue(
     1322            '%s - applicants.browser.ApplicantEditFormPage'
     1323            ' - %s - saved: testfile.pdf'
     1324            % (self.applicant.applicant_id, self.applicant.applicant_id)
     1325            in logcontent)
     1326        # When an applicant is removed, also the pdf files are gone.
     1327        del self.applicantscontainer[self.applicant.application_number]
     1328        fd = storage.getFile(file_id)
     1329        self.assertTrue(fd is None)
     1330        return
     1331
    12801332
    12811333class ApplicantRegisterTests(ApplicantsFullSetup):
  • main/waeup.kofa/trunk/src/waeup/kofa/applicants/utils.py

    r15941 r15943  
    4848      }
    4949
    50     #: A tuple of names of files to be copied over
    51     #: to students section.
    52     FILENAMES = ('testfile.pdf',)
     50    #: A tuple of tuple of file names to be uploaded by applicants and copied
     51    #: over to the students section.
     52    ADDITIONAL_FILES = (('Test File','testfile.pdf'),)
    5353
    5454    def setPaymentDetails(self, container, payment, applicant):
Note: See TracChangeset for help on using the changeset viewer.