def send_email(to, subject, template, **kwargs): mail = Mail(app) msg = Message(app.config['FLASKY_MAIL_SUBJECT_PREFIX'] + ' ' + subject, sender=app.config['FLASKY_MAIL_SENDER'], recipients=[to]) msg.body = render_template(template + '.txt', **kwargs) msg.html = render_template(template + '.html', **kwargs) mail.send(msg)
def send_message(subject, body, html=False, caps_gs_sem=False): from sync import app mail = Mail(app) if caps_gs_sem: recipients = CAPS_GS_SEM_RECIPIENTS else: recipients = ADMIN_RECIPIENTS msg = Message(subject=subject, sender="*****@*****.**", recipients=recipients) if html: msg.html = body else: msg.body = body try: mail.send(msg) except socket.error: print "failed to send message %s" % body return False return True
def register(): owner = "*****@*****.**" sysadmin = "*****@*****.**" name = request.form.get('name', None) email = request.form.get('email', None) institute = request.form.get('institute', None) message = request.form.get('message', None) app =Flask(__name__) mail=Mail(app) _subject = "[Multinet] Request Access Form: %s, %s" % ( name, email ) #1.check if user exists, generate access url for user and save user to db _token = generate_id() udata = { "email" : email,"name" : name,"institute" : institute,"message" : message, "token": _token } ret = insert_user(udata) if not ret: return render_template('start.html',errors="This email address is already registered.") #2.send new user to admin try: msg = Message( subject=_subject , recipients=[ owner ], body=message, sender=sysadmin ) mail.send(msg) except Exception,e: exc_type, exc_value, exc_traceback = sys.exc_info() traceback.print_tb(exc_traceback, limit=5, file=sys.stdout)
def send_pdf_by_email(invoice_id): form = InvoiceEmail(request.form) if not form.validate(): return form.errors_as_json() invoice = Invoice.find_by_id(invoice_id) if not invoice: return abort(404) message = Message(form.subject.data.encode('utf-8'), sender=(g.member.display, g.member.get_email().encode('utf-8'))) message.add_recipient(sanitize_address((form.name.data, form.email.data))) message.body = form.message.data.encode('utf-8') invoice_key = amazons3.get_invoice(invoice) message.attach("Invoice_{0}.pdf".format(invoice.reference), "application/pdf", invoice_key.get_contents_as_string()) mail = Mail() mail.init_app(current_app) mail.send(message) history = InvoiceHistory() history.description = 'Sent email to {0}'.format(message.recipients[0]) history.pdf = invoice_key.key history.status = 'SENT' history.misc = "{0}\n\n{1}".format(message.subject, message.body) history.member_id = g.member.id history.invoice_id = invoice.id history.save() return 'sent', 200
def test_send_email(): mailForm= MailForm() if mailForm.validate_on_submit():#表单提交成功的判断 try: app = Flask(__name__) app.config['SECRET_KEY'] = 'qiyeboy' #下面是SMTP服务器配置 app.config['MAIL_SERVER'] = 'smtp.163.com' #电子邮件服务器的主机名或IP地址 app.config['MAIL_PORT'] = '25' #电子邮件服务器的端口 app.config['MAIL_USE_TLS'] = True #启用传输层安全 app.config['MAIL_USERNAME'] ='******' #os.environ.get('MAIL_USERNAME') #邮件账户用户名 app.config['MAIL_PASSWORD'] = '******'#os.environ.get('MAIL_PASSWORD') #邮件账户的密码 mail = Mail(app) receiverName = mailForm.receiver.data #收件人文本框的内容 styledata = mailForm.style.data#主题文本框的内容 bodydata = mailForm.body.data#正文文本框的内容 msg = Message(styledata,sender='*****@*****.**',recipients=[receiverName])#发件人,收件人 msg.body = bodydata # send_email('*****@*****.**','Test email-function',) mail.send(msg) flash('邮件发送成功!')#提示信息 return redirect(url_for('.index')) except: flash('邮件发送失败!') return redirect(url_for('.index')) return render_template('testemail.html',form=mailForm,name ='*****@*****.**' )#渲染网页 # @main.route('/secret') # @login_required # def secret(): # return 'Only authenticated users are allowed!'
def UserMail(user, passwd, smtp, smtp_port, smtp_tsl, smtp_auth, data): mail_user = user mail_passwd = passwd print "--- DEBUG ---" print "--- DEBUG ---" print data print "--- DEBUG ---" print "--- DEBUG ---" from_addr = user to_addr = ';'.join(data.get("from_mail")) print to_addr mail = Mail(current_app) current_app.config.update( MAIL_SERVER=smtp, MAIL_PORT=smtp_port, MAIL_USE_SSL=smtp_auth, MAIL_USE_TLS=smtp_tsl, MAIL_USERNAME=mail_user, MAIL_PASSWORD=mail_passwd ) mail.init_app(current_app) msg = Message('Reztoran', sender=from_addr, recipients=to_addr.split(";")) msg.html = data.get("text") msg.subject = data.get('title') mail.send(msg) return "ok"
def adoptPuppyPage(puppy_id): """ Provides a page where adopters can adopt a puppy. """ puppy = session.query(Puppy).filter_by(id=puppy_id).one() if request.method == 'POST': try: # Change the adopter_puppy field of adopter to reflect the puppy. adopter_id = int(request.form['adopterIDField']) adopter = session.query(Adopter).filter_by(id=adopter_id).one() adopter.adopted_puppy = puppy.id session.add(adopter) # Change the shelter id of the puppy to None since it has a home. puppy.shelter_id = None session.add(puppy) session.commit() # Create a mail instance for use with sending messages. mail = Mail(app) msg = Message("Hello Em, thanks for adopting %s" % puppy.name, sender="*****@*****.**", recipients=["*****@*****.**"]) mail.send(msg) return redirect(url_for('puppyList')) except: print "The adoption process was unsuccessful." return redirect(url_for('puppyList')) else: return render_template('adopt_puppy.html', puppy=puppy)
def send_email(title, content, to_list, cc_list=None, bcc_list=None, sender=None): """ 发送邮件 """ mail = Mail(current_app) extra = {"Accept-Charset": "ISO-8859-1,utf-8"} try: msg = Message(subject=title, html=content, recipients=to_list, sender=sender, cc=cc_list, bcc=bcc_list, extra_headers=extra) mail.send(msg) return True except SMTPRecipientsRefused as e: raise e except Exception as e: current_app.logger.exception(e) return False
def send_email(msg): from routes import app with app.app_context(): mail = Mail() mail.init_app(current_app) print("hallo world") mail.send(msg)
def adoptPuppyPage(puppy_id): """ Provides a page where adopters can adopt a puppy. """ puppy = session.query(Puppy).filter_by(id=puppy_id).one() if request.method == 'POST': try: # Change the adopter_puppy field of adopter to reflect the puppy. adopter_id = int(request.form['adopterIDField']) adopter = session.query(Adopter).filter_by(id=adopter_id).one() adopter.adopted_puppy = puppy.id session.add(adopter) # Change the shelter id of the puppy to None since it has a home. puppy.shelter_id = None session.add(puppy) session.commit() # Create a mail instance for use with sending messages. mail = Mail(app) msg = Message("Hello Em, thanks for adopting %s" % puppy.name, sender="*****@*****.**", recipients=["*****@*****.**"]) mail.send(msg) return redirect(url_for('puppyList')) except: print "The adoption process was unsuccessful." return redirect(url_for('puppyList')) else: return render_template('adopt_puppy.html', puppy=puppy)
def send_email(to,subject,template): mail = Mail(application) mail.init_app(application) msg = Message( subject,recipients = [to], html = template, sender = application.config['MAIL_USERNAME']) mail.send(msg)
def sendConfirmation(app, teamEmail, html = None): if not configSet : setConfigOptions(app) mail = Mail(app) msg = Message(subject=_subject, sender=_mailDefaultSender, recipients=[teamEmail], bcc=[_mailDefaultSender]) msg.body = getEmailTemplate() msg.html = html mail.send(msg)
def send_email(email, pdf): mail_ext = Mail(app) subject = "Phone Notes" receiver = "*****@*****.**" mail_to_be_sent = Message(subject=subject, recipients=[receiver]) mail_to_be_sent.body = "This email contains PDF." mail_to_be_sent.attach("file.pdf", "application/pdf", pdf) mail_ext.send(mail_to_be_sent)
def count_words_at_url(url, mailAddress): resp = requests.get(url) result = len(resp.text.split()) mail = Mail(current_app) msg = Message("test", recipients=["*****@*****.**"]) msg.body = str(result) msg.add_recipient(str(mailAddress)) mail.send(msg) return result
def send(MessageClass, **kwargs): with app.test_request_context(): mailer = Mail(app) mailer.send(MessageClass(**kwargs)) if 'to' in kwargs: return "Mail type: %s, recipient: %s" % (MessageClass.desc(), kwargs['to']) return True
def send_email(subject, text): """ Send email """ msg = Message(subject, sender='*****@*****.**', recipients=['*****@*****.**']) msg.body = text mail = Mail(current_app) mail.send(msg)
def send_async_email(app, msg, list_id, manager_id, uu): with app.app_context(): try: OA_Email_Url(list_id, manager_id, uu, 0).add() db.session.commit() mail = Mail(app) mail.send(msg) except: # 回滚 db.session.rollback() logger.exception("exception")
def sendEmail(From, To, Subject, Body, Html, Attachments): '''To:must be a list''' msg = Message(Subject, sender = From, recipients = To) msg.body = Body msg.html = Html for f in Attachments: with app.open_resource(f) as fp: msg.attach(filename=os.path.basename(f), data=fp.read(), content_type='application/octet-stream') mail = Mail(app) with app.app_context(): mail.send(msg)
def sender_email(traceback): from flask.ext.mail import Mail, Message mail = Mail(app) senders = app.config.get("SENDERS", []) if not senders: return msg = Message(subject=u"%s %s时遇到异常" % (request.method, request.url), html=traceback.render_summary(), sender="*****@*****.**", recipients=senders) mail.send(msg)
def send_mail(subject, html, recipients): sender = app.config.get('MAILS_SENDER_NAME', 'BDR Help Desk') message = Message(subject=subject, recipients=recipients, html=html, sender=sender) mail = Mail(app) try: mail.send(message) return True except smtplib.SMTPAuthenticationError: print('Wrong username/password. ' \ 'Please review their values in settings.py') return False
def sender_email(traceback): from flask.ext.mail import Mail, Message mail = Mail(app) senders = app.config.get("SENDERS", []) if not senders: return msg = Message(subject=u"%s %s时遇到异常" % (request.method, request.url), html=traceback.render_summary(), sender="*****@*****.**", recipients=senders) mail.send(msg)
def email_scheduler(email_html): app.config['MAIL_SERVER'] = 'smtp.googlemail.com' app.config['MAIL_PORT'] = 587 app.config['MAIL_USE_TLS'] = True app.config['MAIL_USERNAME'] = '******' app.config['MAIL_PASSWORD'] = '******' mail = Mail(app) msg = Message(subject='Test Email Job Task Breakdown', sender=app.config['FLASKY_MAIL_SENDER'], recipients=recipent_list) msg.body = email_html mail.send(msg)
def mail_test(): from flask.ext.mail import Mail, Message as Msg mail = Mail(app) msg = Msg('A test message', sender=app.config['MAIL_SENDER '], recipients=['*****@*****.**']) msg.body = 'Hello and welcome!' msg.html = 'No html available' print 'Sending an email from '+app.config['MAIL_USERNAME']+ \ ' on the server '+app.config['MAIL_SERVER']+':'+str(app.config['MAIL_PORT']) + \ ' using: SSL - '+str(app.config['MAIL_USE_SSL'])+', TLS - '+str(app.config['MAIL_USE_TLS']) with(app.app_context()): mail.send(msg)
def send_mail(subject, recipients, html, attachment=False, **kwargs): sender = 'Eau de Web <%s>' % app.config.get('MAIL_USERNAME') message = Message(subject=subject, recipients=recipients, html=html, sender=sender) if attachment: attach(message, **kwargs) mail = Mail(app) try: mail.send(message) return True except smtplib.SMTPAuthenticationError: print 'Wrong username/password. ' + \ 'Please review their values in settings.py' return False
def sendmessage(self): coll = get_coll() result = coll.find_one({"userID": self.userID}) code = result['confirmnumber'] address = result['email'] mail = Mail(app) msg = Message('What to Eat Tonight', sender='*****@*****.**', recipients=[address]) msg.body = "Hello, dear friend!\nYour verification code is : " + str( code) + "\nThanks for your support!" with app.app_context(): mail.send(msg) return "True"
def send_email(user): from flask.ext.mail import Mail, Message mail = Mail(app) msg = Message("Gamma Computations Complete", recipients=[user.email]) msg.body = """A simulation has been completed by the Flask Gamma app. Please log in at http://localhost:5000/login to see the results. --- This email has been automatically generated by the Gamma app created by Parampool. If you don't want email notifications when a result is found, please register a new user and leave the 'notify' field unchecked.""" mail.send(msg)
def email_appkey(prj_id, member_email): memkey = ProjectMemberKey.find_one(prj_id=prj_id, member_email=member_email) if settings.MAIL_SERVER: mail = Mail(current_app._get_current_object()) message = Message("Your new appkey for 4k mobile app", sender='*****@*****.**', recipients=[member_email]) message.body = ( 'Project ID: %s \nAppkey: %s' % (prj_id, memkey.appkey) ) mail.send(message) flash("New appkey has been send to your email.", category='info') else: flash("Can not email because email server is not availalbe. " + "Contact administrator", category='error') return redirect(url_for('.view_project', prj_id=prj_id))
def send_email(user): from flask.ext.mail import Mail, Message mail = Mail(app) msg = Message("Gamma Computations Complete", recipients=[user.email]) msg.body = """A simulation has been completed by the Flask Gamma app. Please log in at http://localhost:5000/login to see the results. --- This email has been automatically generated by the Gamma app created by Parampool. If you don't want email notifications when a result is found, please register a new user and leave the 'notify' field unchecked.""" mail.send(msg)
def contact_exchange(event): if request.method == 'GET': return render_template('contact_exchange.html', event=event, debug=str(app.config['DEBUG']).lower(), ui_test=str(request.args.get('ui_test', False)).lower()) if request.method == 'POST': ids = tuple(request.form.getlist('ids[]')) if len(ids) < 2: return jsonify(status=False, error=u'Insufficient users to connect') users = Participant.query.filter(Participant.event_id == event.id, Participant.nfc_id.in_(ids)).all() mail = Mail(app) message = Message("You connected with " + str(len(users) - 1) + " people using ContactExchange") message.cc = list() for user in users: email = '"' + user.name + '"<' + user.email + '>' if message.reply_to is None: message.reply_to = email message.add_recipient(email) else: message.cc.append(email) message.attach( make_name(user.name) + '.vcf', 'text/vcard', render_template('user_card.vcf', user=user, event=event)) message.sender = '"HasGeek"<*****@*****.**>' message.body = render_template('connectemail.md', users=users, event=event) message.html = markdown(message.body) log = CXLog() try: mail.send(message) log.sent = True log.log_message = u"Mail delivered to postfix server" except Exception as error: log.sent = True log.log_message = unicode(error) log.users = u','.join(ids) db.session.add(log) db.session.commit() return jsonify(success=True)
def sendEmails(): emails = request.values.get('emails') emails = emails.split(',') app = current_app._get_current_object() mail = Mail(app) emailer = Email() inviteURL = url_for('accountAPI.register', _external=True) invitePage = render_template('emailInviteTemplate.html', inviteURL=inviteURL) for email in emails: msg = emailer.get_email(email, 'invite', invitePage) try: mail.send(msg) logger.info('email for ' + email + ' has been sent') except SMTPException as error: logger.error('Invite email for ' + email + ' failed to send') return jsonify(message='error') return jsonify(message='success')
def send_email(title, content, to_list, cc_list=None, bcc_list=None, sender=None): """ 发送邮件 """ mail = Mail(current_app) extra = { "Accept-Charset": "ISO-8859-1,utf-8" } try: msg = Message(subject=title, html=content, recipients=to_list, sender=sender, cc=cc_list, bcc=bcc_list, extra_headers=extra) mail.send(msg) return True except SMTPRecipientsRefused as e: raise e except Exception as e: current_app.logger.exception(e) return False
def send_email_invites(event): if event.is_email_involved(): contacts_to_invite = list(event.contacts_email_to_invite) mail = Mail(app) if contacts_to_invite: with db.transaction: for contact in contacts_to_invite: hash = contact.invitation_hash(event) msg = Message('Inviation to %s' % event.name) msg.sender = '%s <%s>' % (current_user.name, current_user.email) msg.add_recipient('%s <%s>' % (contact.name, contact.email)) msg.html = render_template('_invitation.html', event=event, hash=hash) mail.send(msg) event.set_invitation_sent(contact)
def mandaemail2((email, assunto, content)): app.config.update(dict( DEBUG = True, MAIL_SERVER = 'smtp.gmail.com', MAIL_PORT = 587, MAIL_USE_TLS = True, MAIL_USE_SSL = False, MAIL_USERNAME = '******', MAIL_PASSWORD = '******', )) mail = Mail(app) msg = Message( assunto, sender = '*****@*****.**', recipients = [email]) msg.body = content mail.send(msg)
def email_appkey(prj_id, member_email): debug_set = current_app.config["DEBUG"] if debug_set == True: print "\n\n\n==========> account->views.py -> email_appkey() " memkey = ProjectMemberKey.find_one(prj_id=prj_id, member_email=member_email) if settings.MAIL_SERVER: mail = Mail(current_app._get_current_object()) message = Message( "Your new appkey for 4k mobile app", sender="*****@*****.**", recipients=[member_email] ) message.body = "Project ID: %s \nAppkey: %s" % (prj_id, memkey.appkey) mail.send(message) flash("New appkey has been send to your email.", category="info") else: flash("Can not email because email server is not availalbe. " + "Contact administrator", category="error") return redirect(url_for(".view_project", prj_id=prj_id))
def send_mail(subject, to, message_file, url=""): mail = Mail(app) body = read_file(message_file) or "" body = body % { 'url': url, 'ip': request.remote_addr, 'user_agent': request.user_agent, 'mail': to, } msg = Message( subject, recipients=[to], sender=(u"Petr Joachim", "*****@*****.**") ) msg.body = body msg.html = markdown.markdown(body) mail.send(msg)
def post_id_postcomment(id): comment = Comment( post=session.query(Post).get(id), content=mistune.markdown(request.form["content"]), author=current_user ) session.add(comment) session.commit() mail=Mail(app) message = Message(current_user.name + " posted a comment on AnthonyDevBlog", sender="*****@*****.**", recipients=["*****@*****.**"]) mail.send(message) flash("Your comment posted successfully", "info") return redirect(url_for("posts") + "post/" + str(id))
def send_mail(subject, to, message_file, url=""): mail = Mail(app) body = read_file(message_file) or "" body = body % { 'url': url, 'ip': request.remote_addr, 'user_agent': request.user_agent, 'mail': to, } msg = Message( subject, recipients=[to], sender=(u"Petr Joachim", "*****@*****.**") ) msg.body = body msg.html = markdown.markdown(body) mail.send(msg)
def send_feedback_mail(subject, template, data, user, url): mail = Mail(app) body = read_file(template) or "" data = copy(data) data['ip'] = request.remote_addr data['user_agent'] = request.user_agent data['url'] = url data.update(user) body = body % data msg = Message( subject, recipients=["*****@*****.**"], sender=(user['name'], user['email']) ) msg.body = body msg.html = markdown.markdown(body) mail.send(msg)
def send_feedback_mail(subject, template, data, user, url): mail = Mail(app) body = read_file(template) or "" data = copy(data) data['ip'] = request.remote_addr data['user_agent'] = request.user_agent data['url'] = url data.update(user) body = body % data msg = Message( subject, recipients=["*****@*****.**"], sender=(user['name'], user['email']) ) msg.body = body msg.html = markdown.markdown(body) mail.send(msg)
def signup_post(): name=request.form["name"] email=request.form["email"] password=request.form["password"] password_2=request.form["repassword"] if session.query(User).filter_by(email=email).first(): flash("User with that email address already exists", "danger") return redirect(url_for("signup_get")) if not (password and password_2) or password != password_2: flash("Passwords did not match", "danger") return redirect(url_for("signup_get")) user = User(name=name, email=email, password=generate_password_hash(password)) session.add(user) session.commit() login_user(user) mail=Mail(app) message = Message(subject="A new user named " + user.name + " signed up on AnthonyDevBlog", body="The new user's email address is " + current_user.email, sender="*****@*****.**", recipients=["*****@*****.**"]) mail.send(message) message = Message(subject="Thanks for signing up to comment on AnthonyDevBlog!", body="Thanks for signing up to comment on AnthonyDevBlog, " + current_user.name + "! I'm looking forward to your feedback.", sender="*****@*****.**", recipients=[current_user.email]) mail.send(message) flash("Success! You may now login and start commenting", "info") return redirect(url_for("posts"))
def mail(subject, sender, recipient, file, data, sender_name=None): body = read_file(file) or "" body = body % data if sender_name: sender = (sender_name, sender) msg = Message( subject, sender=sender, recipients=[recipient] ) msg.body = body msg.html = markdown.markdown(body) mail = Mail(app) return mail.send(msg)
def send(self, MessageClass, **kwargs): if app.config.get('USE_CELERY', False): task = send.delay(MessageClass, **kwargs) return True return Mail.send(self, MessageClass(**kwargs))
def convert_model(input_file, options=None): """ Task to run the model convestion. This task is written in a manner that is can run independently from the web application. You can call this task from the command line or other rich gui. The only requirement is a settings module in the current package as well as the requierd dependencies (celery, jinja, aopt, meshlab, etc.). This tasks is currently very monolithic and does too much. To make this more flexible, this task should really only convert and optimize one file. If multiple files are uploaded, tasks can be chained. This task is currently a spaghetti monster mess from hell. """ # used for configuration handling TASK_CONFIG_SECTION = 'task:modelconvert.tasks.convert_model' update_progress("Warming up...") # # need this so pubsub will work, it's probably due to too fast processing # # and the reconn timout of evensource # # FIXME find out why we need to wait a bit and fix it # import time # time.sleep(10) logger = current_app.logger # The current tasks id task_id = current_task.request.id # options: # meshlab # template # hash # meta # keep the generated hash for filenames # use the taskid for status only # delted uploaded file on successfull conversion, otherwise # log filename in error trace # the hash should always be provided, however if not # i.e. running outside a web application, we reuse the taskid hash = options.get('hash', task_id) # meshlab options meshlab = options.get('meshlab', None) # alternative template template = options.get('template', 'basic') email_to = options.get('email_to', None) # copy metadata to output dir if present meta_filename = options.get('meta_filename', None) # get the filename without extension # i.e. /path/tp/foo.obj -> foo # /path/tp/foo.bar.obj -> foo.bar # FIXME: get rid of this, in case of zip file this is hash.zip # and not usable the way we use it right now input_filename = os.path.splitext(os.path.basename(input_file))[0] update_progress("Starting to process uploaded file") logger.info("Uploaded file: {0}".format(input_file)) download_path = current_app.config['DOWNLOAD_PATH'] bundles_path = current_app.config['BUNDLES_PATH'] upload_path = current_app.config['UPLOAD_PATH'] # this should actuayll come in as parameter, as we assume too much here upload_directory = os.path.join(current_app.config['UPLOAD_PATH'], hash) # first create where everything is stored output_directory = os.path.join(download_path, hash) os.mkdir(output_directory) # {{{ Per bundle configuration update_progress("Reading output template configuration") # TODO FIXME # this whole config stuff is a very naive implementation anbelongs in a # task superclass / or coposite object which then scopes for configuration relevant for the # related task. i.g. self.config.get_boolean('aopt.option', default) should actually be # task_config_parser.get_boolean('aopt.option', default_value) # task_config_arser is a subclass of config farser and actually performs this: # config_parser.get+boolean('task:path.to.this_task', 'aopt.option', default_value) import ConfigParser bundle_config = ConfigParser.SafeConfigParser() # bundle_config = ConfigParser.SafeConfigParser(allow_no_value=True) 2.7 # read the defaults and template config bundle_config.read([ os.path.abspath( os.path.join(os.path.dirname(__file__), 'convert_model.defaults')), os.path.join(bundles_path, template, 'settings.ini') ]) # convert this to no_value with 2.7 requirement try: if bundle_config.getboolean(TASK_CONFIG_SECTION, 'meshlab.disabled'): meshlab = None except ConfigParser.NoOptionError: pass meshlab_log = bundle_config.getboolean(TASK_CONFIG_SECTION, 'meshlab.log') aopt_log = bundle_config.getboolean(TASK_CONFIG_SECTION, 'aopt.log') #nexus_log = bundle_config.getboolean(TASK_CONFIG_SECTION, 'nexus.log') # {{{ ZIPFILES # If the uploaded file is a archive, uncompress it. # Note that this step should be moved to the controller (or another task) # once we switch to a different workflow (upload file->select template->convert) # for each model. but for now, we are using the naive approach. # refactor this out # format ('infile.obj','outfile.x3d', ['outfile.xml'] or None) # it might make sense to create a class or at least a dict for this # in the future, models_to_convert = [] if compression.is_archive(input_file): update_progress("Uncompressing archive") uncompressed_path = upload_directory + '.tmp' os.mkdir(uncompressed_path) compression.unzip(input_file, uncompressed_path) update_progress("Archive uncompressed") resources_to_copy = [] # entry format path/to/resource found_models = [] found_metadata = [] update_progress("Detecting models and resources") # detect and collect models, metadata, and resources for root, dirs, files in os.walk(uncompressed_path, topdown=False): for name in files: if security.is_model_file(name): update_progress("Found model: {0}".format(name)) found_models.append(name) elif security.is_meta_file(name): update_progress("Found meta data: {0}".format(name)) found_metadata.append(name) resources_to_copy.append(name) else: update_progress("Found resource: {0}".format(name)) resources_to_copy.append(name) # just copy over for name in dirs: update_progress("Found directory: {0}".format(name)) resources_to_copy.append(name) if not found_models: raise ConversionError( "No models found in archive. Be sure to put all models at the root level of your archive." ) logger.info("****** FOUND_META: {0}".format(found_metadata)) update_progress("Associating meta data to models") # FIXME: this could be improved for model in found_models: m_root = os.path.splitext(os.path.basename(model))[0] m_output_inline = m_root + '.x3d' m_output_html = m_root + '.html' # now we have a list of metas belonging to the current model # store that in the master list model_base_split = os.path.splitext(os.path.basename(model)) model_info_dict = { 'name': model_base_split[0], 'input': model, 'input_format': model_base_split[1] [1:], # fixme, use magic|mime instead of extension 'input_path': os.path.abspath(uncompressed_path), 'output': model_base_split[0] + '.x3d', 'output_format': 'x3d', 'inline': model_base_split[0] + '.x3d', 'preview': model_base_split[0] + '.html', 'resources': resources_to_copy, } # then walk each metadata to find match for model m_metas = [] for r in found_metadata: # found matching metadata file, mark it r_root = os.path.splitext(os.path.basename(r))[0] r_ext = os.path.splitext(os.path.basename(r))[1][1:] if r_root == m_root: m_metas.append({ 'file': r, 'type': r_ext, }) if m_metas: model_info_dict.update(metadata=m_metas) models_to_convert.append(model_info_dict) # models_to_convert.append( (model, m_output_inline, m_output_html, m_metas,) ) # we now have list of models with associated metadata # and a list of plain resources that simply need to be copied # models_to_convert # resources_to_copy logger.info("****** MODELS: {0}".format(models_to_convert)) logger.info("****** RESOURCES: {0}".format(resources_to_copy)) ####### First copy the resources # simplified: we just copy everything that is dir blindly as well # as all files in the root level which are not models. for resource in resources_to_copy: src = os.path.join(uncompressed_path, resource) dest = os.path.join(output_directory, resource) if os.path.isdir(src): fs.copytree(src, dest) else: shutil.copy(src, dest) # }}} else: # no compression, no multimodel, no, textures.. current_input_filename = os.path.splitext( os.path.basename(input_file))[0] model_base_split = os.path.splitext(os.path.basename(input_file)) model_info_dict = { 'name': model_base_split[0], 'input': os.path.basename(input_file), 'input_format': model_base_split[1] [1:], # fixme, use magic|mime instead of extension 'input_path': os.path.abspath(os.path.dirname(input_file)), 'output': model_base_split[0] + '.x3d', 'output_format': 'x3d', 'inline': model_base_split[0] + '.x3d', 'preview': model_base_split[0] + '.html', 'resources': None, } # we have a meta file which could be named whatever, normalize # this is a mess - but for the review... # this should be handled by the zip code above, since its the same # but only one file. if meta_filename: meta_dest_filename = input_filename + os.path.splitext( meta_filename)[1] shutil.copy(meta_filename, os.path.join(output_directory, meta_dest_filename)) meta_data_list = [] meta_data_list.append({ 'file': meta_dest_filename, 'type': os.path.splitext(meta_filename)[1][1:] }) model_info_dict.update(metadata=meta_data_list) models_to_convert.append(model_info_dict) logger.info("***** MODELS TO CONVERT: {0} ".format(models_to_convert)) # models_to_convert = [ (input_file, current_input_filename+'.x3d', current_input_filename+'.html', meta_dest_filename) ] logger.info("***** MODELS TO CONVERT: {0} ".format(models_to_convert)) # ------------------------------------------------------------------ # The following steop only generates templates, for the uploaded # data. This can be refactored out. The reason this runs before aopt # is in order to allow live preview of partially optimized models later # on as well as reading configuration for aopt/meshlab # first copy static assets output_directory_static = os.path.join(output_directory, 'static') input_directory_static = os.path.join(bundles_path, template, 'static') input_directory_shared = os.path.join(bundles_path, '_shared') # copy shared resources fs.copytree(input_directory_shared, output_directory) # copy template resources fs.copytree(input_directory_static, output_directory_static) # init template engine jinja = Environment( loader=FileSystemLoader(os.path.join(bundles_path, template))) tpl_job_context = { # fixme assuming too much here 'archive_uri': hash + '.zip' } list_template = 'list.html' model_template = 'view.html' # first render index template if it's present in the template bundle. # we always do this, even if there's only one model to convert try: update_progress("Starting to render list template") tpl = jinja.get_template(list_template) context = {} context.update(models=models_to_convert, job=tpl_job_context) # we need info on the models, probably a object would be nice tpl_output = os.path.join(output_directory, 'list.html') # finally render template bundle with open(tpl_output, 'w+') as f: f.write(tpl.render(context)) except TemplateNotFound as tplnf: # not sure if we should stop here, for the moment we proceed # since the list.html list view is technically not necessary # to complete rendering update_progress("List template not found, proceeding without") logger.error("Template '{0}' not found - ignoring list view".format( list_template)) finally: update_progress("Done processing list template") model_template_context = dict() try: model_template_renderer = jinja.get_template(model_template) for model in models_to_convert: # now render templates for individual models update_progress("Rendering template for model: {0}".format( model['name'])) # write out template model_template_context.update( model=model, # the job this model belongs to (used for getting archive name) job=tpl_job_context) tpl_output = os.path.join(output_directory, model['preview']) with open(tpl_output, 'w+') as f: f.write(model_template_renderer.render(model_template_context)) except TemplateNotFound: logger.error("Template '{0}'' not found - ignoring list view".format( view_template)) ### temp output_filename = models_to_convert[0]['output'] output_template_filename = models_to_convert[0]['preview'] # end template generation # ------------------------------------------------------------------ # ------------------------------------------------------------------ # Meshlab doing it's thing, generating temproary outputs # this should live in its own task # ------------------------------------------------------------------ working_directory = os.getcwd() os.chdir(output_directory) logger.info("Output filename: {0}".format(output_filename)) logger.info("Output directory: {0}".format(output_directory)) logger.info("Working directory: {0}".format(working_directory)) logger.info("Aopt binary: {0}".format(current_app.config['AOPT_BINARY'])) logger.info("Meshlab binary: {0}".format( current_app.config['MESHLAB_BINARY'])) logger.info("Nexus binary: {0}".format(current_app.config['NEXUS_BINARY'])) if meshlab: #inputfile = outputfile could lead to problems later on update_progress("Meshlab optimization...") env = os.environ.copy() env['DISPLAY'] = current_app.config['MESHLAB_DISPLAY'] meshlab_filter = "" meshlab_filter += "<!DOCTYPE FilterScript><FilterScript>" for item in meshlab: # fixme, parameterization could be dynamic, not hardcoded if item == "Remove Isolated pieces (wrt Face Num.)": meshlab_filter += '<filter name="' + item + '">' meshlab_filter += '<Param type="RichInt" value="2500" name="MinComponentSize"/>' meshlab_filter += '</filter>' meshlab_filter += '<filter name="Remove Unreferenced Vertex"/>' else: meshlab_filter += '<filter name="' + item + '"/>' meshlab_filter += "</FilterScript>" # todo-> name this after model meshlab_filter_filename = os.path.join(output_directory, hash + '.mlx') with open(meshlab_filter_filename, 'w+') as f: f.write(meshlab_filter) # Subprocess in combination with PIPE/STDOUT could deadlock # be careful with this. Prefer the Python 2.7 version below or for model in models_to_convert: update_progress("Meshlab optimization: {0}".format(model['input'])) meshlab_input_file = os.path.join(model['input_path'], model['input']) # options to account for many different attributes: -om vc fc vn vt wt proc = subprocess.Popen([ current_app.config['MESHLAB_BINARY'], "-i", meshlab_input_file, "-o", meshlab_input_file, "-s", meshlab_filter_filename, "-om", "vc" if model['input_format'] != "obj" else "", "vt", "wt", "ff" ], env=env, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) output = proc.communicate()[0] returncode = proc.wait() # create a aopt log in debug mode if current_app.config['DEBUG'] or meshlab_log: with open(os.path.join(output_directory, 'meshlab.log'), 'a+') as f: f.write(output) logger.info("Meshlab optimization model: {0} return: {1}".format( meshlab_input_file, returncode)) logger.info(output) if returncode == 0: update_progress("Meshlab successfull") else: update_progress("Meshlab failed!") logger.error("Meshlab problem: {0} return: {1}".format( meshlab_input_file, returncode)) # Python 2.7 # try: # check_output([ # current_app.config['MESHLAB_BINARY'], # "-i", # input_file, # "-o", # input_file, # "-s", # meshlab_filter_filename, # "-om", # "ff" # ], env=env) # # except CalledProcessError as e: # logger.info("Meshlab problem exit code {0}".format(e.returncode)) # logger.error("Meshlab: " + e.output) # if status == 0: # logger.info("Meshlab optimization {0}".format(status)) # else: # logger.info("Meshlab problem exit code {0}".format(status)) else: update_progress("Skipping Meshlab optimization") # end Meshlab # ------------------------------------------------------------------ # NEXUS TEMPLATE CONVERSION (a template which needs processing..) # ------------------------------------------------------------------ if template == "nexus": update_progress("Starting NEXUS conversion") logger.info("Nexus processing is started!") env = os.environ.copy() for model in models_to_convert: nexus_input_file = os.path.join(model['input_path'], model['input']) name = model['name'] + ".nxs" output_file = os.path.join(output_directory, name) proc = subprocess.Popen([ current_app.config['NEXUS_BINARY'], nexus_input_file, "-o", output_file ], env=env, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) output = proc.communicate()[0] returncode = proc.wait() if returncode == 0: msg = "Model " + model['name'] + " successfully converted." update_progress(msg) logger.info(msg) else: update_progress("Nexus failed!") logger.error("Nexus problem: {0} return: {1}".format( nexus_input_file, returncode)) # END NEXUS PROCESSING # ------------------------------------------------------------------ # ------------------------------------------------------------------ # Aopt call # this should live in its own task (or maybe transcoder in the future) # ------------------------------------------------------------------ update_progress("Starting AOPT conversion") status = -100 if template != "nexus": for model in models_to_convert: update_progress("Converting: {0}".format(model['input'])) aopt_geo_prefix = "{0}_bin".format(model['name']) os.mkdir(os.path.join(output_directory, aopt_geo_prefix)) infile = os.path.join(model['input_path'], model['input']) outfile = os.path.join(output_directory, model['output']) ## Config aopt call {{{ ### FIXME: naive impl for the config stuff ### build a custom config parser, set defaults on init ### maybe useing argparse to reconstruct arguments ### http://stackoverflow.com/questions/14823363/is-it-possible-to-reconstruct-a-command-line-with-pythons-argparse ### however, probably would make it less straight forward aopt_geo_output = bundle_config.get(TASK_CONFIG_SECTION, 'aopt.geoOutput') aopt_geo_param = bundle_config.get(TASK_CONFIG_SECTION, 'aopt.geoParams') # validation check not really necessary, since all combinations are possible and invalid ones are just ignored... aopt_geo_valid = ['sa', 'sac', 'sacp', 'i'] if not aopt_geo_param in aopt_geo_valid: logger.warning( "AOPT binGeo param {0} invalid, useing default 'sa'". format(aopt_geo_param)) #aopt_geo_param = 'sa' # set output mode if aopt_geo_output == 'pop': aopt_geo_switch = '-K' # POP else: # assume binary aopt_geo_switch = '-G' # binary aopt_gencam = bundle_config.getboolean(TASK_CONFIG_SECTION, 'aopt.genCam') aopt_flatten_graph = bundle_config.getboolean( TASK_CONFIG_SECTION, 'aopt.flattenGraph') aopt_cmd = [current_app.config['AOPT_BINARY'], '-i', infile] if aopt_flatten_graph: aopt_cmd.append('-F') aopt_cmd.append('Scene:"cacheopt(true)"') aopt_cmd.append('-f') aopt_cmd.append('PrimitiveSet:creaseAngle:4') aopt_cmd.append('-f') aopt_cmd.append('PrimitiveSet:normalPerVertex:TRUE') if aopt_gencam: aopt_cmd.append('-V') aopt_cmd.append(aopt_geo_switch) aopt_cmd.append(aopt_geo_prefix + '/:' + aopt_geo_param) aopt_cmd.append('-x') aopt_cmd.append(outfile) # }}} end config aopt call # aopt_cmd = [ # current_app.config['AOPT_BINARY'], # '-i', # infile, # '-F', # 'Scene:"cacheopt(true)"', # '-f', # 'PrimitiveSet:creaseAngle:4', # '-f', # 'PrimitiveSet:normalPerVertex:TRUE', # '-V', # '-G', # aopt_bingeo + '/:sacp', # '-x', # outfile # ] try: update_progress("Running AOPT on: {0}".format(model['input'])) #status = subprocess.call(aopt_cmd) process = subprocess.Popen(aopt_cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) output = process.communicate()[0] status = process.wait() # create a aopt log in debug mode # this is a secuirty concern as long as aopt does include # full path names in the log output if current_app.config['DEBUG'] or aopt_log: with open(os.path.join(output_directory, 'aopt.log'), 'a+') as f: f.write(output) logger.info("Aopt return: {0}".format(status)) logger.info(output) except OSError: update_progress("Failure to execute AOPT") err_msg = "Error: AOPT not found or not executable {0}".format( repr(aopt_cmd)) logger.error(err_msg) raise ConversionError(err_msg) else: status = 0 if status < 0: # FIXME error handling and cleanup (breaking early is good but # cleanup calls for try/catch/finally or contextmanager) os.chdir(working_directory) # fixme: put this in exception code update_progress("Error on conversion process") logger.error("Error converting file!!!!!!!!!!") raise ConversionError('AOPT RETURNS: {0}'.format(status)) else: # ------------------------------------------------------------------ # Final creation of deliverable, could live in it's own task # ------------------------------------------------------------------ update_progress("Assembling deliverable...") zip_path = os.path.join(download_path, hash) compression.zipdir(zip_path, '%s.zip' % hash) os.chdir(working_directory) # ------------------------------------------------------------------ # cleaning up # ------------------------------------------------------------------ if not current_app.config['DEBUG']: # delete the uploaded file update_progress("Cleaning up...") # todo remove upload directory uncompressed_path = upload_directory + '.tmp' if os.path.exists(uncompressed_path): shutil.rmtree(uncompressed_path) if os.path.exists(upload_directory): shutil.rmtree(upload_directory) # import time # time.sleep(10) # hah: hackish as hell if len(models_to_convert) > 1: preview = 'list.html' else: preview = models_to_convert[0]['preview'] # send mail if any # email address nees to be trusted, no checks are made if email_to: update_progress("Sending email") mail = Mail(current_app) msg = Message(subject="Your models are ready", recipients=[email_to], sender=current_app.config['DEFAULT_MAIL_SENDER']) msg.body = "Preview: {0}\nDownload:{1}".format( flask.url_for('frontend.preview', _external=True, hash=hash, filename=preview), flask.url_for('frontend.download', _external=True, hash=hash, filename='%s.zip' % hash)) mail.send(msg) update_progress("Done") result_set = dict( hash=hash, filenames=[preview, '%s.zip' % hash], input_file=input_file, ) return result_set
app.secret_key = 'development key' app.config['MAIL_SERVER'] = 'smtp.gmail.com' app.config['MAIL_PORT'] = 465 app.config['MAIL_USE_SSL'] = True app.config['MAIL_USERNAME'] = '******' app.config['MAIL_PASSWORD'] = '******' mail.init_app(app) @app.route('/contact', methods=['GET', 'POST']) def contact(): form = ContactForm() if request.method == 'POST': if not form.validate(): class ContactForm(Form): name = TextField("Name", [wtforms.validators.Required('Please enter your name')]) email = TextField("Email", [wtforms.validators.Required('Please enter your email'), wtforms.validators.Email()]) subject = TextField("Subject", [wtforms.validators.Required('Please enter a subject')]) message = TextAreaField("Message", [wtforms.validators.Required('Please enter a message')]) submit = SubmitField("Send") flash('All fields are required.') return render_template('contact.html', form=form) else: msg = Message(form.subject.data, sender='*****@*****.**', recipients=['*****@*****.**'] msg.body = """From: %s <%s> %s""" % (form.name.data, form.email.data, form.message.data) mail.send(msg) return render_template('contact.html', success=True) elif request.method == 'GET': return render_template('contact.html', form=form)
def send(MessageClass, **kwargs): # The Flask-Mail extension requires the app context to exist to instantiate # the message. with app.test_request_context() as request: mailer = Mail(app) mailer.send(MessageClass(**kwargs))