I was tasked with fiding way how to add approved vacations to calendar from database. So I made this simple code:
import win32com.client
outlook = win32com.client.Dispatch("Outlook.Application")
def sendMeeting():
appt = outlook.CreateItem(1) # AppointmentItem
appt.Start = "2021-12-09 10:10" # yyyy-MM-dd hh:mm
appt.Subject = "Test test"
appt.Duration = 60
appt.Location = "Out of office"
appt.MeetingStatus = 1 # 1 - olMeeting; Changing the appointment to meeting. Only after changing the meeting status recipients can be added
appt.Organizer = "michal.liska#havelpartners.cz"
appt.Recipients.Add("michal.liska#havelpartners.cz") # Don't end ; as delimiter
appt.Save()
appt.Send()
print("sent")
sendMeeting()
This is all well, but problem is that if I sent the meeting It also appear in my calendar. So If I was to create it for 100 users my callendar would be spammed.
Also I can't connect directly to server and creating something more complex like this: Sending Meeting Invitations With Python. This is not desirable, because I presume, that I would need get login and password for all the users.
So is there some simple way to do it? Meaby just delete it afterwards or outlook parameter, that I can disable it with?
There is no way to get this working by automating Outlook locally.
Everything you do with the Outlook object model is related to the local accounts only. If you need to modify the remote calendar by adding appointments or meeting without customizing yours, consider using the EWS, Outlook REST API or Graph API if you use Exchange accounts or O365. See Explore the EWS Managed API, EWS, and web services in Exchange and One Outlook REST API - your favorite platform - 400+ million users for more information. Graph API is most reliable way because other technologies are going to die in near future.
Also you may consider delegating access to other accounts and use the NameSpace.GetSharedDefaultFolder method which returns a Folder object that represents the specified default folder for the specified user. This method is used in a delegation scenario, where one user has delegated access to another user for one or more of their default folders (for example, their shared Calendar folder). In that case you will be able to access calendar folders of users and add appointments directly there without sending anything. Here is the sample VBA code which illustrates the sequence of OOM calls:
Sub ResolveName()
Dim myNamespace As Outlook.NameSpace
Dim myRecipient As Outlook.Recipient
Dim CalendarFolder As Outlook.Folder
Set myNamespace = Application.GetNamespace("MAPI")
Set myRecipient = myNamespace.CreateRecipient("Eugene Astafiev")
myRecipient.Resolve
If myRecipient.Resolved Then
Call ShowCalendar(myNamespace, myRecipient)
End If
End Sub
Sub ShowCalendar(myNamespace, myRecipient)
Dim CalendarFolder As Outlook.Folder
Set CalendarFolder = myNamespace.GetSharedDefaultFolder(myRecipient, olFolderCalendar)
CalendarFolder.Display
End Sub
I know the question is in Python, but the Outlook object model is common for all kind of programming languages, so hopefully it will not a problem to understand the OOM calls.
Related
I'm attempting to use Autodesk Inventor's COM API to create a python script that will generate PDFs of a selection on Inventor Drawings, these PDFs will then be processed in particular ways that aren't important to my question. I'm using pywin32 to access the COM API, but I'm not particularly familiar with how COM APIs are used, and the pywin32 module.
This is the extent of the documentation for Inventor's API that I have been able to find (diagram of API Object Model Reference Document), and I have not been able to find documentation for the individual objects listed. As such, I'm basing my understanding of the use of these objects on what I can find from examples online (all in VB or iLogic - Inventor's own simple built-in language).
A big issue I'm coming up against is in creating the objects I'd like to use. Simplified example below:
from win32com.client import *
# user chooses file paths for open and save here...
drawing_filepath = ""
# Open Inventor application, and set visible (so I can tell it's opened for now)
app = Dispatch('Inventor.Application')
app.Visible = True
# Open the file to be saved as a pdf (returns a Document object)
app.Documents.Open(drawing_filepath)
# Cast the opened Document object to a DrawingDocument object (it is guaranteed to be a drawing)
drawing = CastTo(app.ActiveDocument, "DrawingDocument")
# Create and setup a print manager (so can use "Adobe PDF" printer to convert the drawings to PDF)
print_manager = ??? # How can I create this object
# I've tried:
# print_manager = Dispatch("Inventor.Application.Documents.DrawingDocument.DrawingPrintManager") #"Invalid class string"
# print_manager = drawing.DrawingPrintManager() #"object has no attribute 'DrawingPrintManger'
# print_manager = drawing.DrawingPrintManager # same as above
# print_manager = drawing.PrintManger # worked in the end
print_manager.Printer = "Adobe PDF"
print_manager.NumberOfCopies = 1
print_manager.ScaleMode = print_manager.PrintScaleModeEnum.kPrintFullScale
print_manager.PaperSize = print_manager.PrintSizeEnum.kPaperSizeA3
# Print PDF
print_manager.SubmitPrint()
So I can't figure out how to create a DrawingPrintManager to use! You can see I've avoided this issue when creating my DrawingDocument object, as I just happened to know that there is an ActiveDocument attribute that I can get from the application itself.
I also:
don't know what the full list of attributes and methods for DrawingPrintManager are, so I don't know how to set a save location
don't know for sure that the two Enums I'm trying to use are actually defined within DrawingPrintManager, but I can figure that out once I actually have a DrawingPrintManager to work with
If anyone with more experience in using COM APIs or pywin32 can help me out, I'd be really appreciative. And the same if anyone can point me towards any actual documentation of Inventor's API Objects, which would make things a lot easier.
Thanks
Edit: After posting I've almost immediately found that I can get a PrintManager (can't tell if a PrintManager or DrawingPrintManager) by accessing drawing.PrintManager rather than drawing.DrawingPrintManager.
This is a workaround however as it doesn't answer my question of how to create objects within pywin32.
My problem moving forward is finding where I can access the PrintScaleModeEnum and PrintSizeEnum objects, and finding how to set the save location of the printed PDF (which I think will be a a separate question, as it's probably unrelated to the COM API).
I'm not familiar with python and pywin32, but I try to answer your questions.
Documentation of Inventor API is available in local installation "C:\Users\Public\Documents\Autodesk\Inventor 2020\Local Help" or online https://help.autodesk.com/view/INVNTOR/2020/ENU/
Generaly you are not able to create new instances of Inventor API objects. You must obtain them as a result of appropriate method or property value.
For example:
You CAN'T do this
doc = new Inventor.Document()
You MUST do this
doc = app.Documents.Add(...)
With print manager is this
print_manager = drawing.PrintManger
# this returns object of type Inventor.DrawingPrintManager
# when drawing is of type Inventor.DrawingDocument
See this for more details
telethon vaersion: 0.19.1.4
Python version : 3.6.
When using CreateChatRequest to create a group, it occurs error like this:
CreateChatRequest occurs Not enough users (to create a chat, for example).
And my code like this:
user = InputUser(user_id=12345, access_hash=12345678901234)
client(CreateChatRequest([user], title=title))
user_id and access_hash is correct, but I'm confused about the error message.
I ran into this problem, as well, even when I tried to supply 2 or 3 users in the initial user list. In the end I figured out the problem: the users weren't letting me add them to the group since I wasn't in their contacts, and their privacy settings did not allow such things. I was able to create the group using just one user whose permissions allowed me to add them.
if you want to create a new group, you can use CreateChannelRequest method and set megagroup=True
also, if you want to add a user to the group you can use InviteToChannelRequest method
from telethon.tl.functions.channels import InviteToChannelRequest,
CreateChannelRequest
group=client(CreateChannelRequest(title='test group',about='this is test group',megagroup=True))
print('group created')
# add a user to the group
custom_user='Shahabi77' # username
user_entity=client.get_entity(custom_user)
client(InviteToChannelRequest(
group.chats[0],
[user_entity]
))
print('user added & finish')
I've been trying to fetch list of autoscaling groups with a specific tag. The below script does this.
#!/usr/bin/python
import boto3
import base64
import time
client = boto3.client('autoscaling', region_name='us-west-2')
paginator = client.get_paginator('describe_auto_scaling_groups')
page_iterator = paginator.paginate(
PaginationConfig={'PageSize': 100}
)
filtered_asgs = page_iterator.search(
'AutoScalingGroups[] | [?contains(Tags[?Key==`{}`].Value, `{}`)]'.format(
'Application', 'CCP')
)
for asg in filtered_asgs:
# print asg['AutoScalingGroupName']
Now, I am trying to double the number of instances in each ASG from the output list. I have a new Launch configuration with a new AMI and that I have already pushed in to this ASG. Now doubling the instance count will be creating new instances within this ASG using new with new AMI. Please suggest on how to double the instance count..
For doing this first you have to create a new launch configuration for updated image-id because you cannot modify launch configurations:
aws autoscaling create-launch-configuration \
--launch-configuration-name my-launch-config \
--image-id ami-c6169af6 --instance-type m1.medium
Then attached created launch configuration to auto-scaling
update-auto-scaling-group \
--auto-scaling-group-name <value> \
--launch-configuration-name <value> \
--min-size <value> --max-size <value>
After doing this it will double the no. of instances and all new instances will be with new image.
But all old instances are still with old image-id so you have to delete those instances once launch-configuration is updated.
As soon as you delete the instance auto-scaling will spin up new instances with new image id.
This methodology of doing updates is called rolling updates.
Other Method is blue-green approach in which
create one new launch configuration
create new auto-scaling group
As soon as your new stack is ready attach it to your ELB or what ever approach you are using and delete old one.
Both approaches will have their own use cases depends upon your use requirements:
If you want your all instances to be sync all the time go for second approach
import win32com.client
outlook=win32com.clent.Dispatch("Outlook.Application").GetNamespace("MAPI")
inbox=outlook.GetDefaultFolder(6)
messages=inbox.Items
message.messages.GetLast()
body_content=message.Body
print(body_content)
This will print the body of an email in my inbox. What I want to do is to reveal what is happening at each stage of this code so that I may better understand it, however when I try to print inbox, messages I get:
<COMObject <unknown>>
How do I reveal this so that I can begin to see what I'm working with.
I'm also looking for a place which has clear documentation surrounding using python to interact with MS Outlook, if anyone can share.
Try here:
http://msdn.microsoft.com/en-us/library/office/aa221870(v=office.11).aspx
In the outlook object model, most objects have a Class property, which returns an enumeration of type OlObjectType, saying what type of object it is. Other properties common to outlook (and indeed MS Office) object are Parent and Application.
If you really want to, it should be easy enough to make a function describe_outlook_object which returns a string with useful information. You will have to write it yourself of course.
Alternatively if you just want to explore the object model, you could do worse than hit Alt+F11 in Outlook and have a play with Visual Basic. (You will have to enable macros.)
I cannot comment yet, but wanted to add to Ben's answer (which helped me immensely in a similar situation)
I wanted a way to scrape emails from multiple PST files/accounts in Outlook
import win32com.client
outlook_object = win32com.client.Dispatch("Outlook.Application")
namespace = outlook_object.GetNamespace("MAPI")
# collection of accounts
accounts = namespace.Folders
# number of outlook accounts
accounts_count = accounts.Count
# .Item(1) not .Item(0) because counting starts at 1
account1 = accounts.Item(1)
# collection of folders for account1
account_folders = account1.Folders
# number of folders under outlook account
account_folders_count = account_folders.Count
# print account1 folder names
for folder in range(account_folders_count):
# must be +1 because .Folder(0) and .Item(0) do not work
print str(folder+1)+":", account_folders.Item(folder+1)
There is a pattern to using Folders.Count and Folders.Item(1) to get down to the messages. Hopefully this helps someone, because it took me hours of googling to get to this point.
After a user has filled out a (ploneformgen) form , I would like to use a custom script adapter to call a python script to change the user’s local role so that they can’t see the form anymore. In other words, I want to prevent the user from filling out (or viewing) the form twice.
I figured that one way to do this is to call the script permission_changer.py which is located in the form folder. The code I have in that script is this:
container.manage_delLocalRoles((‘bob',))
container.reindexObjectSecurity()
Where ‘bob’ is just an example user, who has only the global role FormFiller (which I created under the Security tab of the ZMI) and the local role “Reader” for the form folder.
When I fill out the form (which has a "private" state) as a system admin, the script is called successfully and bob loses his “Reader” local role (which is all he had to begin with), and he can’t see the form anymore. However, when bob fills out the form, a “You do not have sufficient privileges to view this page.” error is displayed, and bob’s local role is not removed. I can’t work out why –– and I’ve tried many different things:
I’ve changed the proxy for the permission_changer.py by clicking on “Proxy” tab for the script in ZMI. I changed it to “Manager”, "System Administrator”, and “Owner”, but that didn’t solve the problem (nor did any combination of those).
I tried changing the proxy by creating a file permission_changer.py.metdadata in the form folder and including this:
[default]
proxy = Manager
but that didn’t work either.
Strangely, when I change bob’s global role to Manager, or System Administrator, or even Viewer, or Editor, the problem goes away and the script runs just fine (I can also change the script so that it adds and removes arbitrary other local roles). (These options are not solutions for me because bob will still be able to see the form because of his global role.)
Also, I tried giving the role FormFiller role every possible permission under the Security tab, but didn’t work.
So, I’m guessing that the problem has to do with the proxy settings, but I can’t work out what I’m doing wrong. I've searched around a lot, and I can't find anyone discussing a similar problem.
Any help would be much appreciated!
Ugly ugly way to handle this may be to access to the data saver field's download method and parse its output to find data to check.
For example, if username is the second pfg field added into form, a custom script adapter that prevents furthers fillings by a user may be
alreadyInDB = False
savedData = ploneformgen.savefield.getSavedFormInputForEdit()
username = request.AUTHENTICATED_USER.getId()
usersInDB = [x.split(',')[1] for x in savedData.split('\r\n') if len(x)>0]
if username in usersInDB:
alreadyInDB = True
if alreadyInDB:
return {'username': 'No way man!'}
I worked out what was going on, but I'm not sure how to describe it precisely. Basically, I found that by calling the script as a Custom Success Action (form > edit > overrides), I don't get the problem. So I think that by calling the script as custom script adapter I was trying to change the user's permission while they were still engaged with the form and that is impossible, even with the Manager proxy role.
I hope that helps. And if anyone has a more precise description of the problem, that would be appreciated.
For granting and revoking the permissions to submit a form, you could:
Create a group (e.g. with the ID "Submitters") and assign the chosen users to it
Make sure the form-folder has the state 'private' and grant View-permissions via the sharing-tab of the form-folder to the group
Add a content-item of type 'Page' in the form-folder's parent (e.g. with the ID 'submitted') and set its state to 'public'
Add a content-item of type 'Custom Script Adapter', select 'Manager' in the field 'Proxy role', and insert the lines below into the field 'Script body':
# Remove current user of group and redirect to [FORM_PARENT_URL]/landing_page_id'.
# If user is not in group, fail silently and continue.
# Fail if landing_page_id does not exist in form-folder, or one of its parents.
#
# Assumes a page with the ID as declared in `landing_page_id` lives in the
# form-folder's parent (or one of its grand-parents, first found wins),
# and holds the state 'public', so users can view it regardless of their
# group-memberships.
#
# Ment to be used after submission of a PloneFormGen-form with private-state and
# a locally assigned Reader-role for the group, so only group-members can view and
# submit the form.
from Products.CMFCore.utils import getToolByName
group_id = 'Submitters' # change as needed
landing_page_id = 'submitted' # change as needed
portal_groups = getToolByName(ploneformgen, 'portal_groups')
user_id = ploneformgen.memberId()
parent_url = '/'.join(ploneformgen.absolute_url().split('/')[:-1])
redirect_to_url = parent_url + '/' + landing_page_id
# Revoke current user's group-membership:
portal_groups.removePrincipalFromGroup(user_id, group_id)
# Let user land in userland:
request.response.redirect(redirect_to_url)
Tested with Plone-4.3.11 and Products.PloneFormGen-1.7.25