예제 #1
0
def emails(workspace_id):
    '''
    For GET requests, return all emails for the given workspace.
    For POST requests, add a new email to the given workspace.
    '''
    if not validate_workspace(workspace_id):
        return 'workspace does not exist', 404

    # request is a GET
    if request.method == 'GET':
        all_emails = Email.query.filter_by(workspace_id=workspace_id).order_by(Email.updated_at.desc()).all()
        schema = EmailSchema(many=True)
        email_data = schema.dump(all_emails)
        return jsonify(email_data)

    # request is a POST
    elif request.method == 'POST':
        name = request.form.get('Name')
        html = request.form.get('HTML').encode()
        subject = request.form.get('Subject')
        track = request.form.get('Track')

        track_bool = convert_to_bool(track)
        if type(track_bool) != bool:
            return 'Track must be either true or false', 400

        email = Email(name=name, html=html, subject=subject, workspace_id=workspace_id, track=track_bool)
        db.session.add(email)
        update_workspace_ts(Workspace.query.filter_by(id=workspace_id).first())
        db.session.commit()
        
        schema = EmailSchema()
        email_data = schema.dump(email)
        app.logger.info(f'Added email {name} - Added by {current_user.username} - Client IP address {request.remote_addr}')
        return jsonify(email_data), 200
예제 #2
0
def email(workspace_id, email_id):
    '''
    For GET requests, return the given email.
    For DELETE requests, delete the given email.
    For PUT requests, update the given email.
    '''
    if not validate_workspace(workspace_id):
        return 'workspace does not exist', 404

    email = Email.query.filter_by(id=email_id,
                                  workspace_id=workspace_id).first()
    if email is None:
        return 'email does not exist', 404

    #request is a GET
    if request.method == 'GET':
        schema = EmailSchema()
        email_data = schema.dump(email)
        return jsonify(email_data)

    # request is a DELETE
    elif request.method == 'DELETE':
        app.logger.info(
            f'Deleted email {email.name} - Deleted by {current_user.username} - Client IP address {request.remote_addr}'
        )
        db.session.delete(email)
        update_workspace_ts(Workspace.query.filter_by(id=workspace_id).first())
        db.session.commit()
        return 'deleted', 204

    # request is a PUT
    elif request.method == 'PUT':
        name = request.form.get('Name')
        subject = request.form.get('Subject')
        html = request.form.get('HTML').encode()
        track = request.form.get('Track')

        same_email = Email.query.filter_by(name=name).first()

        if same_email is not None and str(same_email.id) != email_id:
            return json.dumps({'success': False}), 200, {
                'ContentType': 'application/json'
            }

        track_bool = convert_to_bool(track)
        if type(track_bool) != bool:
            return 'Track must be either true or false', 400

        email.name = name
        email.subject = subject
        email.html = html
        email.track = track_bool
        update_workspace_ts(Workspace.query.filter_by(id=workspace_id).first())
        db.session.commit()
        app.logger.info(
            f'Updated email {name} - Updated by {current_user.username} - Client IP address {request.remote_addr}'
        )
        return json.dumps({'success': True}), 200, {
            'ContentType': 'application/json'
        }
예제 #3
0
def targets(workspace_id, list_id):
    '''
    For GET requets, return all targets of the given list.
    For POST requests, add a target to the given list.
    '''
    if not validate_workspace(workspace_id):
        return 'workspace does not exist', 404

    targetlist = List.query.filter_by(id=list_id,
                                      workspace_id=workspace_id).first()
    if targetlist is None:
        return 'list does not exist', 404

    # request is a GET
    if request.method == 'GET':
        targets = Person.query.filter_by(list_id=list_id)
        schema = PersonSchema(many=True)
        all_targets = schema.dump(targets)
        return jsonify(all_targets)

    # request is a POST
    if request.method == 'POST':
        first_name = request.form.get('first_name')
        last_name = request.form.get('last_name')
        email = request.form.get('email')
        person = Person(first_name=first_name,
                        last_name=last_name,
                        email=email)
        targetlist.targets.append(person)
        update_workspace_ts(Workspace.query.filter_by(id=workspace_id).first())
        db.session.commit()
    return 'added person', 201
예제 #4
0
def targetlist(workspace_id, list_id):
    '''
    For GET requests, return the given list.
    For PUT requests, udpate the given list.
    For DELETE requests, delete the given list.
    '''
    if not validate_workspace(workspace_id):
        return 'workspace does not exist', 404

    targetlist = List.query.filter_by(id=list_id,
                                      workspace_id=workspace_id).first()
    if targetlist is None:
        return 'list does not exist', 404

    # request is a GET
    if request.method == 'GET':
        schema = ListSchema()
        list_data = schema.dump(targetlist)
        return jsonify(list_data)
    # request is a DELETE
    elif request.method == 'DELETE':
        app.logger.info(
            f'Deleted list {targetlist.name} - Deleted by {current_user.username} - Client IP address {request.remote_addr}'
        )
        db.session.delete(targetlist)
        update_workspace_ts(Workspace.query.filter_by(id=workspace_id).first())
        db.session.commit()
        return '', 204

    # request is a PUT (update attributes of the List)
    elif request.method == 'PUT':
        req_json = request.get_json()
        name = req_json['name']
        targets = req_json['targets']

        same_list = List.query.filter_by(name=name).first()

        if same_list is not None and str(same_list.id) != list_id:
            return json.dumps({'success': False}), 200, {
                'ContentType': 'application/json'
            }

        targetlist.targets = []
        for target in targets:
            person = Person(first_name=target['first_name'],
                            last_name=target['last_name'],
                            email=target['email'])
            targetlist.targets.append(person)
        targetlist.name = name
        update_workspace_ts(Workspace.query.filter_by(id=workspace_id).first())
        db.session.commit()

        schema = ListSchema()
        list_data = schema.dump(targetlist)
        app.logger.info(
            f'Updated list {targetlist.name} - Updated by {current_user.username} - Client IP address {request.remote_addr}'
        )
        return jsonify(list_data), 201
예제 #5
0
def page(workspace_id, page_id):
    '''
    For GET requests, return the given page.
    For DELETE requests, delete the given page.
    For PUT requests, update the given page.
    '''
    if not validate_workspace(workspace_id):
        return 'workspace does not exist', 404

    page = Page.query.filter_by(id=page_id, workspace_id=workspace_id).first()
    if page is None:
        return 'page does not exist', 404

    #request is a GET
    if request.method == 'GET':
        page.find_form_fields()
        schema = PageSchema()
        page_data = schema.dump(page)
        return jsonify(page_data)

    # request is a DELETE
    elif request.method == 'DELETE':
        app.logger.info(
            f'Deleted page {page.name} - Deleted by {current_user.username} - Client IP address {request.remote_addr}'
        )
        db.session.delete(page)
        update_workspace_ts(Workspace.query.filter_by(id=workspace_id).first())
        db.session.commit()
        return 'deleted', 204

    # request is a PUT
    elif request.method == 'PUT':
        name = request.form.get('Name')
        html = request.form.get('HTML').encode()
        url = request.form.get('URL')

        same_page = Page.query.filter_by(name=name).first()

        if same_page is not None and str(same_page.id) != page_id:
            return json.dumps({'success': False}), 200, {
                'ContentType': 'application/json'
            }

        page.name = name
        page.html = html
        page.url = url
        update_workspace_ts(Workspace.query.filter_by(id=workspace_id).first())
        db.session.commit()
        app.logger.info(
            f'Updated page {page.name} - Updated by {current_user.username} - Client IP address {request.remote_addr}'
        )
        return json.dumps({'success': True}), 200, {
            'ContentType': 'application/json'
        }
예제 #6
0
def profiles(workspace_id):
    '''
    For GET requests, return all profiles.
    For POST requests, add a new profile.
    '''
    if not validate_workspace(workspace_id):
        return 'workspace does not exist', 404

    if request.method == 'GET':
        all_profiles = Profile.query.filter_by(
            workspace_id=workspace_id).order_by(
                Profile.updated_at.desc()).all()
        schema = ProfileSchema(many=True)
        profiles = schema.dump(all_profiles)
        return jsonify(profiles)
    # request is a POST
    else:
        name = request.form.get('Name')
        from_address = request.form.get('From_Address')
        host = request.form.get('SMTP_Host')
        port = request.form.get('SMTP_Port')
        username = request.form.get('Username')
        password = request.form.get('Password')
        tls = request.form.get('TLS')
        ssl = request.form.get('SSL')

        profile = Profile.query.filter_by(name=name).first()
        ssl_bool = convert_to_bool(ssl)
        tls_bool = convert_to_bool(tls)

        if profile is not None:
            return json.dumps({'success': False}), 200, {
                'ContentType': 'application/json'
            }

        elif type(ssl_bool) != bool or type(tls_bool) != bool:
            return 'ssl/tls must be either true or false', 400


        profile = Profile(name=name, from_address=from_address, smtp_host=host, smtp_port=port, \
            username=encrypt(username.encode()), password=encrypt(password.encode()), tls=tls_bool, ssl=ssl_bool, workspace_id=workspace_id)
        db.session.add(profile)
        update_workspace_ts(Workspace.query.filter_by(id=workspace_id).first())
        db.session.commit()

        schema = ProfileSchema()
        profile_data = schema.dump(profile)
        app.logger.info(
            f'Added profile {name} - Added by {current_user.username} - Client IP address {request.remote_addr}'
        )
        return jsonify(profile_data), 201
예제 #7
0
def campaign_results(workspace_id, campaign_id):
    '''
    For GET requests, return results for the given campaign.
    '''

    if not validate_workspace(workspace_id):
        return 'workspace does not exist', 404

    campaign = Campaign.query.filter_by(id=campaign_id,
                                        workspace_id=workspace_id).first()
    if campaign is None:
        return 'campaign does not exist', 404

    schema = ResultSchema(many=True)
    results = schema.dump(campaign.results)
    return jsonify(results)
예제 #8
0
def kill(workspace_id, campaign_id):
    '''
    For GET requests, kill the given campaign.
    '''

    if not validate_workspace(workspace_id):
        return 'workspace does not exist', 404

    campaign = Campaign.query.filter_by(id=campaign_id,
                                        workspace_id=workspace_id).first()
    if campaign is None:
        return 'campaign does not exist', 404

    if campaign.status != 'Active':
        return 'campaign is not active', 400

    if campaign.server.check_status() != 'Online':
        return json.dumps({'success': False}), 200, {
            'ContentType': 'application/json'
        }

    http_code = campaign.kill()

    if http_code != 200:
        app.logger.warning(
            f'Error stopping campaign {campaign.name} (ID: {campaign.id}) - Stop attempted by {current_user.username} - Client IP address {request.remote_addr}'
        )
        return json.dumps({'success': False}), 200, {
            'ContentType': 'application/json'
        }

    app.logger.info(
        f'Stopped campaign {campaign.name} (ID: {campaign.id}) - Stopped by {current_user.username} - Client IP address {request.remote_addr}'
    )
    sch = Result.query.filter_by(campaign_id=campaign.id,
                                 status='Scheduled').all()
    for x in sch:
        app.logger.warning(
            f'Campaign killed before email was scheduled to send to {x.person.email} - result (ID: {x.id}) deleted'
        )
        db.session.delete(x)
    db.session.commit()
    return json.dumps({'success': True}), 200, {
        'ContentType': 'application/json'
    }
예제 #9
0
def targetlists(workspace_id):
    '''
    For GET requests, return all target lists associated with the given workspace.
    For POST requests, add a new list to the given workspace.
    '''
    if not validate_workspace(workspace_id):
        return 'workspace does not exist', 404

    # request is a GET
    if request.method == 'GET':
        workspace_lists = List.query.filter_by(
            workspace_id=workspace_id).order_by(List.updated_at.desc()).all()
        schema = ListSchema(many=True)
        list_data = schema.dump(workspace_lists)
        return jsonify(list_data)

    # request is a POST
    elif request.method == 'POST':
        req_json = request.get_json()
        name = req_json['name']
        targets = req_json['targets']

        list_name = List.query.filter_by(workspace_id=workspace_id,
                                         name=name).first()
        if list_name is not None:
            return json.dumps({'success': False}), 200, {
                'ContentType': 'application/json'
            }

        new_list = List(name=name, workspace_id=workspace_id)
        for target in targets:
            person = Person(first_name=target['first_name'],
                            last_name=target['last_name'],
                            email=target['email'])
            new_list.targets.append(person)
        db.session.add(new_list)
        update_workspace_ts(Workspace.query.filter_by(id=workspace_id).first())
        db.session.commit()

        schema = ListSchema()
        list_data = schema.dump(new_list)
        app.logger.info(
            f'Added list {name} - Added by {current_user.username} - Client IP address {request.remote_addr}'
        )
        return jsonify(list_data), 201
예제 #10
0
def workspace_results(workspace_id):
    '''
    For GET requests, return results for all campaigns in the given workspace.
    '''

    if not validate_workspace(workspace_id):
        return 'workspace does not exist', 404

    workspace_results = Result.query.join(Campaign).join(Workspace).filter(
        Workspace.id == workspace_id).all()
    campaigns = Campaign.query.filter_by(workspace_id=workspace_id).all()

    schema = ResultCampaignSchema(many=True)
    c_results = schema.dump(campaigns)

    schema = ResultSchema(many=True)
    results = schema.dump(workspace_results)

    return jsonify(c_results, results)
예제 #11
0
def target(workspace_id, list_id, target_id):
    '''
    For DELETE requests, delete the given target from the given list.
    '''
    if not validate_workspace(workspace_id):
        return 'workspace does not exist', 404

    targetlist = List.query.filter_by(id=list_id,
                                      workspace_id=workspace_id).first()
    if targetlist is None:
        return 'list does not exist', 404

    target = Person.query.filter_by(id=target_id, list_id=list_id).first()
    if target is None:
        return 'target does not exist'

    db.session.delete(target)
    update_workspace_ts(Workspace.query.filter_by(id=workspace_id).first())
    db.session.commit()
    return 'deleted', 204
예제 #12
0
def pages(workspace_id):
    '''
    For GET requests, return all pages for the given workspace.
    For POST requests, add a new pages to the given workspace.
    '''
    if not validate_workspace(workspace_id):
        return 'workspace does not exist', 404

    # request is a GET
    if request.method == 'GET':
        all_pages = Page.query.filter_by(workspace_id=workspace_id).order_by(
            Page.updated_at.desc()).all()
        schema = PageSchema(many=True)
        page_data = schema.dump(all_pages)
        return jsonify(page_data)

    # request is a POST
    elif request.method == 'POST':
        name = request.form.get('Name')
        html = request.form.get('HTML').encode()
        url = request.form.get('URL')

        page = Page.query.filter_by(name=name).first()

        if page is not None:
            return json.dumps({'success': False}), 200, {
                'ContentType': 'application/json'
            }

        page = Page(name=name, html=html, workspace_id=workspace_id, url=url)
        db.session.add(page)
        update_workspace_ts(Workspace.query.filter_by(id=workspace_id).first())
        db.session.commit()

        schema = PageSchema()
        page_data = schema.dump(page)
        app.logger.info(
            f'Added page {name} - Added by {current_user.username} - Client IP address {request.remote_addr}'
        )
        return jsonify(page_data), 201
예제 #13
0
def campaign_modules(workspace_id):
    '''
    For GET requests, return possible campaign modules in the given workspace.
    '''

    if not validate_workspace(workspace_id):
        return 'workspace does not exist', 404

    page_names = Page.query.with_entities(
        Page.id, Page.name).filter((Page.workspace_id == workspace_id)
                                   | (Page.workspace_id == 1)).all()
    list_names = List.query.with_entities(
        List.id, List.name).filter((List.workspace_id == workspace_id)
                                   | (List.workspace_id == 1)).all()
    email_names = Email.query.with_entities(
        Email.id, Email.name).filter((Email.workspace_id == workspace_id)
                                     | (Email.workspace_id == 1)).all()
    profile_names = Profile.query.with_entities(
        Profile.id, Profile.name).filter((Profile.workspace_id == workspace_id)
                                         | (Profile.workspace_id == 1)).all()
    domain_names = Domain.query.with_entities(Domain.id, Domain.domain,
                                              Domain.ip).all()
    server_names = Server.query.with_entities(Server.id, Server.alias,
                                              Server.ip).all()

    all_info = {
        "pages": [dict(zip(['id', 'name'], p)) for p in page_names],
        "lists": [dict(zip(['id', 'name'], l)) for l in list_names],
        "emails": [dict(zip(['id', 'name'], e)) for e in email_names],
        "profiles": [dict(zip(['id', 'name'], p)) for p in profile_names],
        "domains":
        [dict(zip(['id', 'domain', 'ip'], d)) for d in domain_names],
        "servers": [dict(zip(['id', 'alias', 'ip'], s)) for s in server_names],
        "console_time": datetime.now()
    }

    return jsonify(all_info), 200
예제 #14
0
def campaigns(workspace_id):
    '''
    For GET requests, return all campaigns for the given workspace.
    For POST requests, all a campaign to the given workspace.
    '''

    if not validate_workspace(workspace_id):
        return 'workspace does not exist', 404

    # request is a GET
    if request.method == 'GET':
        all_campaigns = Campaign.query.filter_by(
            workspace_id=workspace_id).order_by(
                Campaign.updated_at.desc()).all()

        # sort the pages associated with the campaign by index
        # for campaign in all_campaigns:
        #     campaign.pages.sort(key=lambda camp: camp.index)

        schema = CampaignSchema(many=True)
        campaign_data = schema.dump(all_campaigns)
        return jsonify(campaign_data)

    # request is a POST
    elif request.method == 'POST':
        name = request.form.get('Name')
        email_id = request.form.get('Email')
        page_ids = request.form.getlist(
            'Pages[]'
        )  # page names is a list of page names # page names is a list of page names
        profile_id = request.form.get('Profile')
        list_id = request.form.get('List')
        domain_id = request.form.get('Domain')
        server_id = request.form.get('Server')
        port = request.form.get('Port')
        ssl = request.form.get('SSL')
        redirect_url = request.form.get('Redirect_URL')
        safety_url = request.form.get('Safety_URL')
        start_time = request.form.get('Start_Time')
        interval = request.form.get('Interval')
        batch_size = request.form.get('Batch_Size')
        payload_url = request.form.get('Payload_URL')
        payload_file = request.form.get('Payload_File')

        if len(request.files) > 0:
            attach = request.files['Attachment']
            attach_name = attach.filename
            attach_bytes = attach.read()
        else:
            attach_name = None
            attach_bytes = None

        if start_time:
            start_time = convert_to_datetime(start_time)
        else:
            start_time = datetime.now()

        ssl_bool = convert_to_bool(ssl)
        if type(ssl_bool) != bool:
            return 'ssl must be either true or false', 400

        pages = []

        for page_id in page_ids:
            page = Page.query.with_entities(Page).filter(
                (Page.id == page_id) & ((Page.workspace_id == workspace_id)
                                        | (Page.workspace_id == 1))).first()
            pages.append(page)

        email = Email.query.with_entities(Email).filter(
            (Email.id == email_id) & ((Email.workspace_id == workspace_id)
                                      | (Email.workspace_id == 1))).first()
        profile = Profile.query.with_entities(
            Profile).filter((Profile.id == profile_id)
                            & ((Profile.workspace_id == workspace_id)
                               | (Profile.workspace_id == 1))).first()
        targetlist = List.query.with_entities(List).filter(
            (List.id == list_id) & ((List.workspace_id == workspace_id)
                                    | (List.workspace_id == 1))).first()
        domain = Domain.query.filter_by(id=domain_id).first()
        server = Server.query.filter_by(id=server_id).first()

        # make sure all given modules exist before continuing
        makeup = validate_campaign_makeup(email, pages, profile, targetlist,
                                          domain, server)
        if makeup:
            return makeup

        campaign = Campaign(name=name, workspace_id=workspace_id, email_id=email.id, profile_id=profile.id, \
                start_time=start_time, send_interval=interval, batch_size=batch_size, \
                list_id=targetlist.id, domain_id=domain.id, server_id=server.id, port=port, ssl=ssl_bool, redirect_url=redirect_url, \
                safety_url=safety_url, payload_url=payload_url, payload_file=payload_file, attachment=attach_bytes, attachment_name=attach_name)

        db.session.add(campaign)
        update_workspace_ts(Workspace.query.filter_by(id=workspace_id).first())
        db.session.commit()

        for idx, page in enumerate(pages):
            #page_association = Campaignpages(index=idx)
            #campaign.pages.append(page_association)
            page_association = Campaignpages(campaign_id=campaign.id,
                                             page_id=page.id,
                                             index=idx)
            db.session.add(page_association)
            db.session.commit()

        #schema = WorkerCampaignSchema()
        #campaign_data = schema.dump(campaign)
        app.logger.info(
            f'Added campaign {name} (ID: {campaign.id}) (Start time: {start_time}) - Added by {current_user.username} - Client IP address {request.remote_addr}'
        )

        prep_tracking(campaign.list.targets, campaign.id)
        #campaign.cast(campaign_data)
        campaign.cast()

        schema = CampaignSchema()
        data = schema.dump(campaign)

        return json.dumps({
            'success': True,
            'campaign': data
        }), 200, {
            'ContentType': 'application/json'
        }
예제 #15
0
def profile(workspace_id, profile_id):
    '''
    For GET requests, return the profile with the given name.
    For POST requests, use the given profile to send a test email.
    For DELETE requests, delete the given profile.
    '''
    if not validate_workspace(workspace_id):
        return 'workspace does not exist', 404

    profile = Profile.query.filter_by(id=profile_id,
                                      workspace_id=workspace_id).first()
    if profile is None:
        return 'profile does not exist', 404

    # request is a GET
    if request.method == 'GET':
        schema = ProfileSchema()
        profile_data = schema.dump(profile)
        return jsonify(profile_data)

    # request is a DELETE
    elif request.method == 'DELETE':
        app.logger.info(
            f'Deleted profile {profile.name} - Deleted by {current_user.username} - Client IP address {request.remote_addr}'
        )
        db.session.delete(profile)
        update_workspace_ts(Workspace.query.filter_by(id=workspace_id).first())
        db.session.commit()
        return 'profile deleted', 204

    # request is a POST
    elif request.method == 'POST':
        address = request.form.get('Address')

        if not validate_email_format(address):
            return 'Enter a valid email address', 400

        success = profile.send_test_mail(address)
        if success:
            app.logger.info(
                f'Test email successfully email to {address} using profile {profile.name} - Sent by {current_user.username} - Client IP address {request.remote_addr}'
            )
        else:
            app.logger.warning(
                f'Test email failed to {address} using profile {profile.name} - Sent by {current_user.username} - Client IP address {request.remote_addr}'
            )
        return json.dumps({'success': success}), 200, {
            'ContentType': 'application/json'
        }

    # request is a PUT
    elif request.method == 'PUT':
        name = request.form.get('Name')
        from_address = request.form.get('From_Address')
        host = request.form.get('SMTP_Host')
        port = request.form.get('SMTP_Port')
        username = request.form.get('Username')
        password = request.form.get('Password')
        tls = request.form.get('TLS')
        ssl = request.form.get('SSL')

        same_profile = Profile.query.filter_by(name=name).first()

        if same_profile is not None and str(same_profile.id) != profile_id:
            return json.dumps({'success': False}), 200, {
                'ContentType': 'application/json'
            }

        ssl_bool = convert_to_bool(ssl)
        tls_bool = convert_to_bool(tls)

        if type(ssl_bool) != bool or type(tls_bool) != bool:
            return 'ssl/tls must be either true or false', 400

        profile.name = name
        profile.from_address = from_address
        profile.smtp_host = host
        profile.smtp_port = port
        profile.username = encrypt(username.encode())
        profile.password = encrypt(password.encode())
        profile.tls = tls_bool
        profile.ssl = ssl_bool
        profile.workspace_id = workspace_id
        update_workspace_ts(Workspace.query.filter_by(id=workspace_id).first())
        db.session.commit()

        schema = ProfileSchema()
        profile_data = schema.dump(profile)
        app.logger.info(
            f'Updated profile {name} - Updated by {current_user.username} - Client IP address {request.remote_addr}'
        )
        return jsonify(profile_data), 200
예제 #16
0
def campaign(workspace_id, campaign_id):
    '''
    For GET requests, return the given campaign.
    For DELETE requests, delete the given campaign.
    For PUT requests, update the given campaign.
    '''

    if not validate_workspace(workspace_id):
        return 'workspace does not exist', 404

    campaign = Campaign.query.filter_by(id=campaign_id,
                                        workspace_id=workspace_id).first()
    if campaign is None:
        return 'campaign does not exist', 404

    # request is a GET
    if request.method == 'GET':
        schema = CampaignSchema()
        campaign_data = schema.dump(campaign)
        return jsonify(campaign_data)

    # request is a DELETE
    elif request.method == 'DELETE':
        if campaign.status == 'Active':
            campaign.kill()
        if campaign.status == 'Scheduled':
            campaign.remove_job()
        app.logger.info(
            f'Deleted campaign {campaign.name} (ID: {campaign.id}) - Deleted by {current_user.username} - Client IP address {request.remote_addr}'
        )
        db.session.delete(campaign)
        update_workspace_ts(Workspace.query.filter_by(id=workspace_id).first())
        db.session.commit()
        return 'campaign deleted', 204

    # request is a PUT
    elif request.method == 'PUT':
        name = request.form.get('Name')
        email_name = request.form.get('Email_Name')
        profile_name = request.form.get('Profile_Name')
        list_name = request.form.get('List_Name')
        domain_name = request.form.get('Domain_Name')
        server_alias = request.form.get('Server_Alias')
        port = request.form.get('Port')
        ssl = request.form.get('SSL')
        redirect_url = request.form.get('Redirect_URL')

        same_campaign = Campaign.query.filter_by(name=name).first()

        if same_campaign is not None and str(same_campaign.id) != campaign_id:
            return json.dumps({'success': False}), 200, {
                'ContentType': 'application/json'
            }

        ssl_bool = convert_to_bool(ssl)
        if type(ssl_bool) != bool:
            return 'ssl must be either true or false', 400

        email = Email.query.filter_by(name=email_name,
                                      workspace_id=workspace_id).first()
        profile = Profile.query.filter_by(name=profile_name,
                                          workspace_id=workspace_id).first()
        targetlist = List.query.filter_by(name=list_name,
                                          workspace_id=workspace_id).first()
        domain = Domain.query.filter_by(domain=domain_name).first()
        server = Server.query.filter_by(alias=server_alias).first()

        # make sure all given modules exist before continuing
        makeup = validate_campaign_makeup(email, page, profile, targetlist,
                                          domain, server)
        if makeup:
            return makeup

        campaign.name = name
        campaign.email_id = email.id
        campaign.profile_id = profile.id
        campaign.list_id = targetlist.id
        campaign.domain_id = domain.id
        campaign.server_id = server.id
        campaign.port = port
        campaign.ssl = ssl_bool
        campaign.redirect_url = redirect_url
        update_workspace_ts(Workspace.query.filter_by(id=workspace_id).first())
        db.session.commit()
        return 'campaign updated'