Conditions | 9 |
Total Lines | 169 |
Code Lines | 54 |
Lines | 0 |
Ratio | 0 % |
Changes | 0 |
Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.
For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.
Commonly applied refactorings include:
If many parameters/temporary variables are present:
1 | # -*- coding: utf-8 -*- |
||
38 | def create(self, context, request): |
||
39 | """/@@API/create: Create new object. |
||
40 | |||
41 | Required parameters: |
||
42 | |||
43 | - obj_type = portal_type of new object. |
||
44 | - obj_path = path of new object, from plone site root. - Not required for |
||
45 | obj_type=AnalysisRequest |
||
46 | |||
47 | Optionally: |
||
48 | |||
49 | - obj_id = ID of new object. |
||
50 | |||
51 | All other parameters in the request are matched against the object's |
||
52 | Schema. If a matching field is found in the schema, then the value is |
||
53 | taken from the request and sent to the field's mutator. |
||
54 | |||
55 | Reference fields may have their target value(s) specified with a |
||
56 | delimited string query syntax, containing the portal_catalog search: |
||
57 | |||
58 | <FieldName>=index1:value1|index2:value2 |
||
59 | |||
60 | eg to set the Client of a batch: |
||
61 | |||
62 | ...@@API/update?obj_path=<path>... |
||
63 | ...&Client=title:<client_title>&... |
||
64 | |||
65 | And, to set a multi-valued reference, these both work: |
||
66 | |||
67 | ...@@API/update?obj_path=<path>... |
||
68 | ...&InheritedObjects:list=title:AR1... |
||
69 | ...&InheritedObjects:list=title:AR2... |
||
70 | |||
71 | ...@@API/update?obj_path=<path>... |
||
72 | ...&InheritedObjects[]=title:AR1... |
||
73 | ...&InheritedObjects[]=title:AR2... |
||
74 | |||
75 | The Analysis_Specification parameter is special, it mimics |
||
76 | the format of the python dictionaries, and only service Keyword |
||
77 | can be used to reference services. Even if the keyword is not |
||
78 | actively required, it must be supplied: |
||
79 | |||
80 | <service_keyword>:min:max:error tolerance |
||
81 | |||
82 | The function returns a dictionary as a json string: |
||
83 | |||
84 | { |
||
85 | runtime: Function running time. |
||
86 | error: true or string(message) if error. false if no error. |
||
87 | success: true or string(message) if success. false if no success. |
||
88 | } |
||
89 | |||
90 | >>> portal = layer['portal'] |
||
91 | >>> portal_url = portal.absolute_url() |
||
92 | >>> from plone.app.testing import SITE_OWNER_NAME |
||
93 | >>> from plone.app.testing import SITE_OWNER_PASSWORD |
||
94 | |||
95 | Simple AR creation, no obj_path parameter is required: |
||
96 | |||
97 | >>> browser = layer['getBrowser'](portal, loggedIn=True, username=SITE_OWNER_NAME, password=SITE_OWNER_PASSWORD) |
||
98 | >>> browser.open(portal_url+"/@@API/create", "&".join([ |
||
99 | ... "obj_type=AnalysisRequest", |
||
100 | ... "Client=portal_type:Client|id:client-1", |
||
101 | ... "SampleType=portal_type:SampleType|title:Apple Pulp", |
||
102 | ... "Contact=portal_type:Contact|getFullname:Rita Mohale", |
||
103 | ... "Services:list=portal_type:AnalysisService|title:Calcium", |
||
104 | ... "Services:list=portal_type:AnalysisService|title:Copper", |
||
105 | ... "Services:list=portal_type:AnalysisService|title:Magnesium", |
||
106 | ... "SamplingDate=2013-09-29", |
||
107 | ... "Specification=portal_type:AnalysisSpec|title:Apple Pulp", |
||
108 | ... ])) |
||
109 | >>> browser.contents |
||
110 | '{..."success": true...}' |
||
111 | |||
112 | If some parameters are specified and are not located as existing fields or properties |
||
113 | of the created instance, the create should fail: |
||
114 | |||
115 | >>> browser = layer['getBrowser'](portal, loggedIn=True, username=SITE_OWNER_NAME, password=SITE_OWNER_PASSWORD) |
||
116 | >>> browser.open(portal_url+"/@@API/create?", "&".join([ |
||
117 | ... "obj_type=Batch", |
||
118 | ... "obj_path=/batches", |
||
119 | ... "title=Test", |
||
120 | ... "Thing=Fish" |
||
121 | ... ])) |
||
122 | >>> browser.contents |
||
123 | '{...The following request fields were not used: ...Thing...}' |
||
124 | |||
125 | Now we test that the AR create also fails if some fields are spelled wrong |
||
126 | |||
127 | >>> browser = layer['getBrowser'](portal, loggedIn=True, username=SITE_OWNER_NAME, password=SITE_OWNER_PASSWORD) |
||
128 | >>> browser.open(portal_url+"/@@API/create", "&".join([ |
||
129 | ... "obj_type=AnalysisRequest", |
||
130 | ... "thing=Fish", |
||
131 | ... "Client=portal_type:Client|id:client-1", |
||
132 | ... "SampleType=portal_type:SampleType|title:Apple Pulp", |
||
133 | ... "Contact=portal_type:Contact|getFullname:Rita Mohale", |
||
134 | ... "Services:list=portal_type:AnalysisService|title:Calcium", |
||
135 | ... "Services:list=portal_type:AnalysisService|title:Copper", |
||
136 | ... "Services:list=portal_type:AnalysisService|title:Magnesium", |
||
137 | ... "SamplingDate=2013-09-29" |
||
138 | ... ])) |
||
139 | >>> browser.contents |
||
140 | '{...The following request fields were not used: ...thing...}' |
||
141 | |||
142 | """ |
||
143 | savepoint = transaction.savepoint() |
||
144 | self.context = context |
||
145 | self.request = request |
||
146 | self.unused = [x for x in self.request.form.keys()] |
||
147 | self.used("form.submitted") |
||
148 | self.used("__ac_name") |
||
149 | self.used("__ac_password") |
||
150 | # always require obj_type |
||
151 | self.require("obj_type") |
||
152 | obj_type = self.request['obj_type'] |
||
153 | self.used("obj_type") |
||
154 | # AnalysisRequest shortcut: creates Sample, Partition, AR, Analyses. |
||
155 | if obj_type == "AnalysisRequest": |
||
156 | raise BadRequest("Creation of Analysis Request through JSON API is " |
||
157 | "not supported. Request aborted.") |
||
158 | # Other object types require explicit path as their parent |
||
159 | self.require("obj_path") |
||
160 | obj_path = self.request['obj_path'] |
||
161 | if not obj_path.startswith("/"): |
||
162 | obj_path = "/" + obj_path |
||
163 | self.used("obj_path") |
||
164 | site_path = request['PATH_INFO'].replace("/@@API/create", "") |
||
165 | parent = context.restrictedTraverse(str(site_path + obj_path)) |
||
166 | # normal permissions still apply for this user |
||
167 | if not getSecurityManager().checkPermission(AccessJSONAPI, parent): |
||
168 | msg = "You don't have the '{0}' permission on {1}".format( |
||
169 | AccessJSONAPI, parent.absolute_url()) |
||
170 | raise Unauthorized(msg) |
||
171 | |||
172 | obj_id = request.get("obj_id", "") |
||
173 | _renameAfterCreation = False |
||
174 | if not obj_id: |
||
175 | _renameAfterCreation = True |
||
176 | obj_id = tmpID() |
||
177 | self.used(obj_id) |
||
178 | |||
179 | ret = { |
||
180 | "url": router.url_for("create", force_external=True), |
||
181 | "success": True, |
||
182 | "error": False, |
||
183 | } |
||
184 | |||
185 | try: |
||
186 | obj = _createObjectByType(obj_type, parent, obj_id) |
||
187 | obj.unmarkCreationFlag() |
||
188 | if _renameAfterCreation: |
||
189 | renameAfterCreation(obj) |
||
190 | ret['obj_id'] = obj.getId() |
||
191 | ret['obj_uid'] = obj.UID() |
||
192 | used_fields = set_fields_from_request(obj, request) |
||
193 | for field in used_fields: |
||
194 | self.used(field) |
||
195 | obj.reindexObject() |
||
196 | obj.aq_parent.reindexObject() |
||
197 | event.notify(ObjectInitializedEvent(obj)) |
||
198 | obj.at_post_create_script() |
||
199 | except: |
||
200 | savepoint.rollback() |
||
201 | raise |
||
202 | |||
203 | if self.unused: |
||
204 | raise BadRequest("The following request fields were not used: %s. Request aborted." % self.unused) |
||
205 | |||
206 | return ret |
||
207 | |||
219 |