diff options
| -rw-r--r-- | TODO | 19 | ||||
| -rw-r--r-- | fatcat-openapi2.yml | 54 | ||||
| -rw-r--r-- | notes/autoaccept_api.txt | 31 | ||||
| -rw-r--r-- | notes/cloud_instances.txt | 2 | ||||
| -rw-r--r-- | python/fatcat/crossref_importer.py | 2 | ||||
| -rw-r--r-- | python/fatcat/importer_common.py | 3 | ||||
| -rw-r--r-- | python/fatcat/issn_importer.py | 2 | ||||
| -rw-r--r-- | python/fatcat/orcid_importer.py | 2 | ||||
| -rw-r--r-- | python/fatcat_client/api/default_api.py | 50 | ||||
| -rw-r--r-- | rust/fatcat-api/README.md | 10 | ||||
| -rw-r--r-- | rust/fatcat-api/api.yaml | 54 | ||||
| -rw-r--r-- | rust/fatcat-api/api/swagger.yaml | 80 | ||||
| -rw-r--r-- | rust/fatcat-api/examples/client.rs | 10 | ||||
| -rw-r--r-- | rust/fatcat-api/examples/server_lib/server.rs | 76 | ||||
| -rw-r--r-- | rust/fatcat-api/src/client.rs | 95 | ||||
| -rw-r--r-- | rust/fatcat-api/src/lib.rs | 100 | ||||
| -rw-r--r-- | rust/fatcat-api/src/server.rs | 35 | ||||
| -rw-r--r-- | rust/src/api_server.rs | 31 | ||||
| -rw-r--r-- | rust/src/api_wrappers.rs | 6 | ||||
| -rw-r--r-- | rust/tests/test_api_server.rs | 41 | 
20 files changed, 628 insertions, 75 deletions
| @@ -2,14 +2,23 @@  ## Next Up  - some significant slow-down has happened? transactions, or regexes? +summer roadmap: +- PUT/UPDATE, DELETE, and merge code paths +- faster UPDATE-free bulk import code path +- container import (extra?): lang, region, subject +- basic API+webface creation, editing, merging, editgroup approval +- elastic schema/transform for releases; bulk and continuous scripts  features:  - fast database dump command: both changelog-based and entity-based (rust)      => lighter, more complete dumps for each entity type? +- guide skeleton (mdbook; guide.fatcat.wiki)  importers: +- CORE +- wikidata cross-ref (if they have a dump)  - manifest: multiple URLs per SHA1 -- pubmed (medline) +- pubmed (medline), if not in CORE      => and/or, use pubmed ID lookups on crossref import  - core  - semantic scholar (up to 39 million; author de-dupe) @@ -36,10 +45,16 @@ july roadmap:  ## Schema / Alignment / Scope  - "container" -> "venue"? -- release_type, release_status, url.rel enums (and others?) +- release_type, release_status, url.rel write-time schema(and others?)  name ref: https://www.w3.org/International/questions/qa-personal-names +## API + +- how to send edit "extra" metadata? +- hydrate entities in API +    ? "expand" query param +  ## High-Level Priorities  - full database dump (export) diff --git a/fatcat-openapi2.yml b/fatcat-openapi2.yml index d9cf8813..a8919216 100644 --- a/fatcat-openapi2.yml +++ b/fatcat-openapi2.yml @@ -57,6 +57,10 @@ x-entity-props: &ENTITYPROPS    extra:      type: object      additionalProperties: {} +# TODO: +#  edit_extra: +#    type: object +#    additionalProperties: {}  definitions:    error_response: @@ -438,6 +442,16 @@ paths:      post:        operationId: "create_container_batch"        parameters: +        - name: autoaccept +          in: query +          type: boolean +          required: false +          description: "If true, and editor is authorized, batch is accepted all at once" +        - name: editgroup +          in: query +          type: string +          required: false +          description: "Editgroup to auto-accept and apply to all entities (required if 'autoaccept' is True)"          - name: entity_list            in: body            required: true @@ -554,6 +568,16 @@ paths:      post:        operationId: "create_creator_batch"        parameters: +        - name: autoaccept +          in: query +          type: boolean +          required: false +          description: "If true, and editor is authorized, batch is accepted all at once" +        - name: editgroup +          in: query +          type: string +          required: false +          description: "Editgroup to auto-accept and apply to all entities (required if 'autoaccept' is True)"          - name: entity_list            in: body            required: true @@ -686,6 +710,16 @@ paths:      post:        operationId: "create_file_batch"        parameters: +        - name: autoaccept +          in: query +          type: boolean +          required: false +          description: "If true, and editor is authorized, batch is accepted all at once" +        - name: editgroup +          in: query +          type: string +          required: false +          description: "Editgroup to auto-accept and apply to all entities (required if 'autoaccept' is True)"          - name: entity_list            in: body            required: true @@ -802,6 +836,16 @@ paths:      post:        operationId: "create_release_batch"        parameters: +        - name: autoaccept +          in: query +          type: boolean +          required: false +          description: "If true, and editor is authorized, batch is accepted all at once" +        - name: editgroup +          in: query +          type: string +          required: false +          description: "Editgroup to auto-accept and apply to all entities (required if 'autoaccept' is True)"          - name: entity_list            in: body            required: true @@ -934,6 +978,16 @@ paths:      post:        operationId: "create_work_batch"        parameters: +        - name: autoaccept +          in: query +          type: boolean +          required: false +          description: "If true, and editor is authorized, batch is accepted all at once" +        - name: editgroup +          in: query +          type: string +          required: false +          description: "Editgroup to auto-accept and apply to all entities (required if 'autoaccept' is True)"          - name: entity_list            in: body            required: true diff --git a/notes/autoaccept_api.txt b/notes/autoaccept_api.txt new file mode 100644 index 00000000..b7e0a824 --- /dev/null +++ b/notes/autoaccept_api.txt @@ -0,0 +1,31 @@ + +Currently only on batch creation (POST) for entities. + +For all bulk operations, optional 'editgroup' query parameter overrides +individual editgroup parameters. + +If autoaccept flag is set and editgroup is not, a new editgroup is +automatically created and overrides for all entities inserted. Note +that this is different behavior from the "use current or create new" +default behavior for regular creation. + +Unfortunately, "true" and "false" are the only values acceptable for boolean +rust/openapi2 query parameters + +THOUGHT: doing an UPDATE in a transaction is probably not expensive + +Intent: +- check can_autoaccept flag on editor table + +--------- + +Crude benchmarking... + +cat /data/crossref/crossref-works.2018-01-21.badsample_5k.json | time ./fatcat_import.py import-crossref - /data/issn/20180216.ISSN-to-ISSN-L.txt + +autoaccept: 7.47user 0.48system 0:30.64elapsed 25%CPU +master: 5.70user 0.34system 0:25.61elapsed 23%CPU +    batch creation: ~153ms+ +    accept: ~5ms + +uh... diff --git a/notes/cloud_instances.txt b/notes/cloud_instances.txt index 4582c431..b7071758 100644 --- a/notes/cloud_instances.txt +++ b/notes/cloud_instances.txt @@ -6,3 +6,5 @@ digital ocean  aws      i3.2xlarge 61 GB RAM, 8 cores, 1900 GB NVMe, $455/month +OVH +    MG-128 128 GB RAM, 16 cores, 2880 GB SSD (RAID), 500mbps unlimited b/w, $315/month diff --git a/python/fatcat/crossref_importer.py b/python/fatcat/crossref_importer.py index d3e525a4..54a3e84f 100644 --- a/python/fatcat/crossref_importer.py +++ b/python/fatcat/crossref_importer.py @@ -152,4 +152,4 @@ class FatcatCrossrefImporter(FatcatImporter):                      re.container_id = container.ident                      self._issnl_id_map[ce.issnl] = container.ident                  release_batch.append(re) -        self.api.create_release_batch(release_batch) +        self.api.create_release_batch(release_batch, autoaccept="true", editgroup=editgroup_id) diff --git a/python/fatcat/importer_common.py b/python/fatcat/importer_common.py index e084d8c4..0b02d175 100644 --- a/python/fatcat/importer_common.py +++ b/python/fatcat/importer_common.py @@ -45,8 +45,7 @@ class FatcatImporter:          for rows in grouper(source, size):              eg = self.api.create_editgroup(                  fatcat_client.Editgroup(editor_id='aaaaaaaaaaaabkvkaaaaaaaaae')) -            self.create_batch(rows, eg.id) -            self.api.accept_editgroup(eg.id) +            self.create_batch(rows, editgroup_id=eg.id)      def process_csv_source(self, source, group_size=100, delimiter=','):          reader = csv.DictReader(source, delimiter=delimiter) diff --git a/python/fatcat/issn_importer.py b/python/fatcat/issn_importer.py index 181137ac..eb8a50ba 100644 --- a/python/fatcat/issn_importer.py +++ b/python/fatcat/issn_importer.py @@ -70,4 +70,4 @@ class FatcatIssnImporter(FatcatImporter):          objects = [o for o in objects if o != None]          for o in objects:              o.editgroup_id = editgroup_id -        self.api.create_container_batch(objects) +        self.api.create_container_batch(objects, autoaccept="true", editgroup=editgroup_id) diff --git a/python/fatcat/orcid_importer.py b/python/fatcat/orcid_importer.py index e57703d5..fe76b02c 100644 --- a/python/fatcat/orcid_importer.py +++ b/python/fatcat/orcid_importer.py @@ -71,4 +71,4 @@ class FatcatOrcidImporter(FatcatImporter):          objects = [o for o in objects if o != None]          for o in objects:              o.editgroup_id = editgroup_id -        self.api.create_creator_batch(objects) +        self.api.create_creator_batch(objects, autoaccept="true", editgroup=editgroup_id) diff --git a/python/fatcat_client/api/default_api.py b/python/fatcat_client/api/default_api.py index acd33c88..a0298750 100644 --- a/python/fatcat_client/api/default_api.py +++ b/python/fatcat_client/api/default_api.py @@ -245,6 +245,8 @@ class DefaultApi(object):          :param async bool          :param list[ContainerEntity] entity_list: (required) +        :param bool autoaccept: If true, and editor is authorized, batch is accepted all at once +        :param str editgroup: Editgroup to auto-accept and apply to all entities (required if 'autoaccept' is True)          :return: list[EntityEdit]                   If the method is called asynchronously,                   returns the request thread. @@ -266,12 +268,14 @@ class DefaultApi(object):          :param async bool          :param list[ContainerEntity] entity_list: (required) +        :param bool autoaccept: If true, and editor is authorized, batch is accepted all at once +        :param str editgroup: Editgroup to auto-accept and apply to all entities (required if 'autoaccept' is True)          :return: list[EntityEdit]                   If the method is called asynchronously,                   returns the request thread.          """ -        all_params = ['entity_list']  # noqa: E501 +        all_params = ['entity_list', 'autoaccept', 'editgroup']  # noqa: E501          all_params.append('async')          all_params.append('_return_http_data_only')          all_params.append('_preload_content') @@ -296,6 +300,10 @@ class DefaultApi(object):          path_params = {}          query_params = [] +        if 'autoaccept' in params: +            query_params.append(('autoaccept', params['autoaccept']))  # noqa: E501 +        if 'editgroup' in params: +            query_params.append(('editgroup', params['editgroup']))  # noqa: E501          header_params = {} @@ -439,6 +447,8 @@ class DefaultApi(object):          :param async bool          :param list[CreatorEntity] entity_list: (required) +        :param bool autoaccept: If true, and editor is authorized, batch is accepted all at once +        :param str editgroup: Editgroup to auto-accept and apply to all entities (required if 'autoaccept' is True)          :return: list[EntityEdit]                   If the method is called asynchronously,                   returns the request thread. @@ -460,12 +470,14 @@ class DefaultApi(object):          :param async bool          :param list[CreatorEntity] entity_list: (required) +        :param bool autoaccept: If true, and editor is authorized, batch is accepted all at once +        :param str editgroup: Editgroup to auto-accept and apply to all entities (required if 'autoaccept' is True)          :return: list[EntityEdit]                   If the method is called asynchronously,                   returns the request thread.          """ -        all_params = ['entity_list']  # noqa: E501 +        all_params = ['entity_list', 'autoaccept', 'editgroup']  # noqa: E501          all_params.append('async')          all_params.append('_return_http_data_only')          all_params.append('_preload_content') @@ -490,6 +502,10 @@ class DefaultApi(object):          path_params = {}          query_params = [] +        if 'autoaccept' in params: +            query_params.append(('autoaccept', params['autoaccept']))  # noqa: E501 +        if 'editgroup' in params: +            query_params.append(('editgroup', params['editgroup']))  # noqa: E501          header_params = {} @@ -730,6 +746,8 @@ class DefaultApi(object):          :param async bool          :param list[FileEntity] entity_list: (required) +        :param bool autoaccept: If true, and editor is authorized, batch is accepted all at once +        :param str editgroup: Editgroup to auto-accept and apply to all entities (required if 'autoaccept' is True)          :return: list[EntityEdit]                   If the method is called asynchronously,                   returns the request thread. @@ -751,12 +769,14 @@ class DefaultApi(object):          :param async bool          :param list[FileEntity] entity_list: (required) +        :param bool autoaccept: If true, and editor is authorized, batch is accepted all at once +        :param str editgroup: Editgroup to auto-accept and apply to all entities (required if 'autoaccept' is True)          :return: list[EntityEdit]                   If the method is called asynchronously,                   returns the request thread.          """ -        all_params = ['entity_list']  # noqa: E501 +        all_params = ['entity_list', 'autoaccept', 'editgroup']  # noqa: E501          all_params.append('async')          all_params.append('_return_http_data_only')          all_params.append('_preload_content') @@ -781,6 +801,10 @@ class DefaultApi(object):          path_params = {}          query_params = [] +        if 'autoaccept' in params: +            query_params.append(('autoaccept', params['autoaccept']))  # noqa: E501 +        if 'editgroup' in params: +            query_params.append(('editgroup', params['editgroup']))  # noqa: E501          header_params = {} @@ -924,6 +948,8 @@ class DefaultApi(object):          :param async bool          :param list[ReleaseEntity] entity_list: (required) +        :param bool autoaccept: If true, and editor is authorized, batch is accepted all at once +        :param str editgroup: Editgroup to auto-accept and apply to all entities (required if 'autoaccept' is True)          :return: list[EntityEdit]                   If the method is called asynchronously,                   returns the request thread. @@ -945,12 +971,14 @@ class DefaultApi(object):          :param async bool          :param list[ReleaseEntity] entity_list: (required) +        :param bool autoaccept: If true, and editor is authorized, batch is accepted all at once +        :param str editgroup: Editgroup to auto-accept and apply to all entities (required if 'autoaccept' is True)          :return: list[EntityEdit]                   If the method is called asynchronously,                   returns the request thread.          """ -        all_params = ['entity_list']  # noqa: E501 +        all_params = ['entity_list', 'autoaccept', 'editgroup']  # noqa: E501          all_params.append('async')          all_params.append('_return_http_data_only')          all_params.append('_preload_content') @@ -975,6 +1003,10 @@ class DefaultApi(object):          path_params = {}          query_params = [] +        if 'autoaccept' in params: +            query_params.append(('autoaccept', params['autoaccept']))  # noqa: E501 +        if 'editgroup' in params: +            query_params.append(('editgroup', params['editgroup']))  # noqa: E501          header_params = {} @@ -1118,6 +1150,8 @@ class DefaultApi(object):          :param async bool          :param list[WorkEntity] entity_list: (required) +        :param bool autoaccept: If true, and editor is authorized, batch is accepted all at once +        :param str editgroup: Editgroup to auto-accept and apply to all entities (required if 'autoaccept' is True)          :return: list[EntityEdit]                   If the method is called asynchronously,                   returns the request thread. @@ -1139,12 +1173,14 @@ class DefaultApi(object):          :param async bool          :param list[WorkEntity] entity_list: (required) +        :param bool autoaccept: If true, and editor is authorized, batch is accepted all at once +        :param str editgroup: Editgroup to auto-accept and apply to all entities (required if 'autoaccept' is True)          :return: list[EntityEdit]                   If the method is called asynchronously,                   returns the request thread.          """ -        all_params = ['entity_list']  # noqa: E501 +        all_params = ['entity_list', 'autoaccept', 'editgroup']  # noqa: E501          all_params.append('async')          all_params.append('_return_http_data_only')          all_params.append('_preload_content') @@ -1169,6 +1205,10 @@ class DefaultApi(object):          path_params = {}          query_params = [] +        if 'autoaccept' in params: +            query_params.append(('autoaccept', params['autoaccept']))  # noqa: E501 +        if 'editgroup' in params: +            query_params.append(('editgroup', params['editgroup']))  # noqa: E501          header_params = {} diff --git a/rust/fatcat-api/README.md b/rust/fatcat-api/README.md index 8381b9f7..4be4939f 100644 --- a/rust/fatcat-api/README.md +++ b/rust/fatcat-api/README.md @@ -68,11 +68,6 @@ cargo run --example client CreateRelease  cargo run --example client CreateReleaseBatch  cargo run --example client CreateWork  cargo run --example client CreateWorkBatch -cargo run --example client DeleteContainer -cargo run --example client DeleteCreator -cargo run --example client DeleteFile -cargo run --example client DeleteRelease -cargo run --example client DeleteWork  cargo run --example client GetChangelog  cargo run --example client GetChangelogEntry  cargo run --example client GetContainer @@ -96,11 +91,6 @@ cargo run --example client LookupContainer  cargo run --example client LookupCreator  cargo run --example client LookupFile  cargo run --example client LookupRelease -cargo run --example client UpdateContainer -cargo run --example client UpdateCreator -cargo run --example client UpdateFile -cargo run --example client UpdateRelease -cargo run --example client UpdateWork  ```  ### HTTPS diff --git a/rust/fatcat-api/api.yaml b/rust/fatcat-api/api.yaml index d9cf8813..a8919216 100644 --- a/rust/fatcat-api/api.yaml +++ b/rust/fatcat-api/api.yaml @@ -57,6 +57,10 @@ x-entity-props: &ENTITYPROPS    extra:      type: object      additionalProperties: {} +# TODO: +#  edit_extra: +#    type: object +#    additionalProperties: {}  definitions:    error_response: @@ -438,6 +442,16 @@ paths:      post:        operationId: "create_container_batch"        parameters: +        - name: autoaccept +          in: query +          type: boolean +          required: false +          description: "If true, and editor is authorized, batch is accepted all at once" +        - name: editgroup +          in: query +          type: string +          required: false +          description: "Editgroup to auto-accept and apply to all entities (required if 'autoaccept' is True)"          - name: entity_list            in: body            required: true @@ -554,6 +568,16 @@ paths:      post:        operationId: "create_creator_batch"        parameters: +        - name: autoaccept +          in: query +          type: boolean +          required: false +          description: "If true, and editor is authorized, batch is accepted all at once" +        - name: editgroup +          in: query +          type: string +          required: false +          description: "Editgroup to auto-accept and apply to all entities (required if 'autoaccept' is True)"          - name: entity_list            in: body            required: true @@ -686,6 +710,16 @@ paths:      post:        operationId: "create_file_batch"        parameters: +        - name: autoaccept +          in: query +          type: boolean +          required: false +          description: "If true, and editor is authorized, batch is accepted all at once" +        - name: editgroup +          in: query +          type: string +          required: false +          description: "Editgroup to auto-accept and apply to all entities (required if 'autoaccept' is True)"          - name: entity_list            in: body            required: true @@ -802,6 +836,16 @@ paths:      post:        operationId: "create_release_batch"        parameters: +        - name: autoaccept +          in: query +          type: boolean +          required: false +          description: "If true, and editor is authorized, batch is accepted all at once" +        - name: editgroup +          in: query +          type: string +          required: false +          description: "Editgroup to auto-accept and apply to all entities (required if 'autoaccept' is True)"          - name: entity_list            in: body            required: true @@ -934,6 +978,16 @@ paths:      post:        operationId: "create_work_batch"        parameters: +        - name: autoaccept +          in: query +          type: boolean +          required: false +          description: "If true, and editor is authorized, batch is accepted all at once" +        - name: editgroup +          in: query +          type: string +          required: false +          description: "Editgroup to auto-accept and apply to all entities (required if 'autoaccept' is True)"          - name: entity_list            in: body            required: true diff --git a/rust/fatcat-api/api/swagger.yaml b/rust/fatcat-api/api/swagger.yaml index e8026c8d..0b1ca88a 100644 --- a/rust/fatcat-api/api/swagger.yaml +++ b/rust/fatcat-api/api/swagger.yaml @@ -76,6 +76,22 @@ paths:      post:        operationId: "create_container_batch"        parameters: +      - name: "autoaccept" +        in: "query" +        description: "If true, and editor is authorized, batch is accepted all at\ +          \ once" +        required: false +        type: "boolean" +        formatString: "{:?}" +        example: "Some(true)" +      - name: "editgroup" +        in: "query" +        description: "Editgroup to auto-accept and apply to all entities (required\ +          \ if 'autoaccept' is True)" +        required: false +        type: "string" +        formatString: "{:?}" +        example: "Some(\"editgroup_example\".to_string())"        - in: "body"          name: "entity_list"          required: true @@ -492,6 +508,22 @@ paths:      post:        operationId: "create_creator_batch"        parameters: +      - name: "autoaccept" +        in: "query" +        description: "If true, and editor is authorized, batch is accepted all at\ +          \ once" +        required: false +        type: "boolean" +        formatString: "{:?}" +        example: "Some(true)" +      - name: "editgroup" +        in: "query" +        description: "Editgroup to auto-accept and apply to all entities (required\ +          \ if 'autoaccept' is True)" +        required: false +        type: "string" +        formatString: "{:?}" +        example: "Some(\"editgroup_example\".to_string())"        - in: "body"          name: "entity_list"          required: true @@ -962,6 +994,22 @@ paths:      post:        operationId: "create_file_batch"        parameters: +      - name: "autoaccept" +        in: "query" +        description: "If true, and editor is authorized, batch is accepted all at\ +          \ once" +        required: false +        type: "boolean" +        formatString: "{:?}" +        example: "Some(true)" +      - name: "editgroup" +        in: "query" +        description: "Editgroup to auto-accept and apply to all entities (required\ +          \ if 'autoaccept' is True)" +        required: false +        type: "string" +        formatString: "{:?}" +        example: "Some(\"editgroup_example\".to_string())"        - in: "body"          name: "entity_list"          required: true @@ -1375,6 +1423,22 @@ paths:      post:        operationId: "create_release_batch"        parameters: +      - name: "autoaccept" +        in: "query" +        description: "If true, and editor is authorized, batch is accepted all at\ +          \ once" +        required: false +        type: "boolean" +        formatString: "{:?}" +        example: "Some(true)" +      - name: "editgroup" +        in: "query" +        description: "Editgroup to auto-accept and apply to all entities (required\ +          \ if 'autoaccept' is True)" +        required: false +        type: "string" +        formatString: "{:?}" +        example: "Some(\"editgroup_example\".to_string())"        - in: "body"          name: "entity_list"          required: true @@ -1842,6 +1906,22 @@ paths:      post:        operationId: "create_work_batch"        parameters: +      - name: "autoaccept" +        in: "query" +        description: "If true, and editor is authorized, batch is accepted all at\ +          \ once" +        required: false +        type: "boolean" +        formatString: "{:?}" +        example: "Some(true)" +      - name: "editgroup" +        in: "query" +        description: "Editgroup to auto-accept and apply to all entities (required\ +          \ if 'autoaccept' is True)" +        required: false +        type: "string" +        formatString: "{:?}" +        example: "Some(\"editgroup_example\".to_string())"        - in: "body"          name: "entity_list"          required: true diff --git a/rust/fatcat-api/examples/client.rs b/rust/fatcat-api/examples/client.rs index 2ee65d7e..cc94af11 100644 --- a/rust/fatcat-api/examples/client.rs +++ b/rust/fatcat-api/examples/client.rs @@ -101,7 +101,7 @@ fn main() {          //     println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from("<none>")));          //  },          Some("CreateContainerBatch") => { -            let result = client.create_container_batch(&Vec::new()).wait(); +            let result = client.create_container_batch(&Vec::new(), Some(true), Some("editgroup_example".to_string())).wait();              println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from("<none>")));          } @@ -111,7 +111,7 @@ fn main() {          //     println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from("<none>")));          //  },          Some("CreateCreatorBatch") => { -            let result = client.create_creator_batch(&Vec::new()).wait(); +            let result = client.create_creator_batch(&Vec::new(), Some(true), Some("editgroup_example".to_string())).wait();              println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from("<none>")));          } @@ -127,7 +127,7 @@ fn main() {          //     println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from("<none>")));          //  },          Some("CreateFileBatch") => { -            let result = client.create_file_batch(&Vec::new()).wait(); +            let result = client.create_file_batch(&Vec::new(), Some(true), Some("editgroup_example".to_string())).wait();              println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from("<none>")));          } @@ -137,7 +137,7 @@ fn main() {          //     println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from("<none>")));          //  },          Some("CreateReleaseBatch") => { -            let result = client.create_release_batch(&Vec::new()).wait(); +            let result = client.create_release_batch(&Vec::new(), Some(true), Some("editgroup_example".to_string())).wait();              println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from("<none>")));          } @@ -147,7 +147,7 @@ fn main() {          //     println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from("<none>")));          //  },          Some("CreateWorkBatch") => { -            let result = client.create_work_batch(&Vec::new()).wait(); +            let result = client.create_work_batch(&Vec::new(), Some(true), Some("editgroup_example".to_string())).wait();              println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from("<none>")));          } diff --git a/rust/fatcat-api/examples/server_lib/server.rs b/rust/fatcat-api/examples/server_lib/server.rs index af3ece12..ab08f594 100644 --- a/rust/fatcat-api/examples/server_lib/server.rs +++ b/rust/fatcat-api/examples/server_lib/server.rs @@ -35,11 +35,19 @@ impl Api for Server {          Box::new(futures::failed("Generic failure".into()))      } -    fn create_container_batch(&self, entity_list: &Vec<models::ContainerEntity>, context: &Context) -> Box<Future<Item = CreateContainerBatchResponse, Error = ApiError> + Send> { +    fn create_container_batch( +        &self, +        entity_list: &Vec<models::ContainerEntity>, +        autoaccept: Option<bool>, +        editgroup: Option<String>, +        context: &Context, +    ) -> Box<Future<Item = CreateContainerBatchResponse, Error = ApiError> + Send> {          let context = context.clone();          println!( -            "create_container_batch({:?}) - X-Span-ID: {:?}", +            "create_container_batch({:?}, {:?}, {:?}) - X-Span-ID: {:?}",              entity_list, +            autoaccept, +            editgroup,              context.x_span_id.unwrap_or(String::from("<none>")).clone()          );          Box::new(futures::failed("Generic failure".into())) @@ -51,9 +59,21 @@ impl Api for Server {          Box::new(futures::failed("Generic failure".into()))      } -    fn create_creator_batch(&self, entity_list: &Vec<models::CreatorEntity>, context: &Context) -> Box<Future<Item = CreateCreatorBatchResponse, Error = ApiError> + Send> { +    fn create_creator_batch( +        &self, +        entity_list: &Vec<models::CreatorEntity>, +        autoaccept: Option<bool>, +        editgroup: Option<String>, +        context: &Context, +    ) -> Box<Future<Item = CreateCreatorBatchResponse, Error = ApiError> + Send> {          let context = context.clone(); -        println!("create_creator_batch({:?}) - X-Span-ID: {:?}", entity_list, context.x_span_id.unwrap_or(String::from("<none>")).clone()); +        println!( +            "create_creator_batch({:?}, {:?}, {:?}) - X-Span-ID: {:?}", +            entity_list, +            autoaccept, +            editgroup, +            context.x_span_id.unwrap_or(String::from("<none>")).clone() +        );          Box::new(futures::failed("Generic failure".into()))      } @@ -69,9 +89,21 @@ impl Api for Server {          Box::new(futures::failed("Generic failure".into()))      } -    fn create_file_batch(&self, entity_list: &Vec<models::FileEntity>, context: &Context) -> Box<Future<Item = CreateFileBatchResponse, Error = ApiError> + Send> { +    fn create_file_batch( +        &self, +        entity_list: &Vec<models::FileEntity>, +        autoaccept: Option<bool>, +        editgroup: Option<String>, +        context: &Context, +    ) -> Box<Future<Item = CreateFileBatchResponse, Error = ApiError> + Send> {          let context = context.clone(); -        println!("create_file_batch({:?}) - X-Span-ID: {:?}", entity_list, context.x_span_id.unwrap_or(String::from("<none>")).clone()); +        println!( +            "create_file_batch({:?}, {:?}, {:?}) - X-Span-ID: {:?}", +            entity_list, +            autoaccept, +            editgroup, +            context.x_span_id.unwrap_or(String::from("<none>")).clone() +        );          Box::new(futures::failed("Generic failure".into()))      } @@ -81,9 +113,21 @@ impl Api for Server {          Box::new(futures::failed("Generic failure".into()))      } -    fn create_release_batch(&self, entity_list: &Vec<models::ReleaseEntity>, context: &Context) -> Box<Future<Item = CreateReleaseBatchResponse, Error = ApiError> + Send> { +    fn create_release_batch( +        &self, +        entity_list: &Vec<models::ReleaseEntity>, +        autoaccept: Option<bool>, +        editgroup: Option<String>, +        context: &Context, +    ) -> Box<Future<Item = CreateReleaseBatchResponse, Error = ApiError> + Send> {          let context = context.clone(); -        println!("create_release_batch({:?}) - X-Span-ID: {:?}", entity_list, context.x_span_id.unwrap_or(String::from("<none>")).clone()); +        println!( +            "create_release_batch({:?}, {:?}, {:?}) - X-Span-ID: {:?}", +            entity_list, +            autoaccept, +            editgroup, +            context.x_span_id.unwrap_or(String::from("<none>")).clone() +        );          Box::new(futures::failed("Generic failure".into()))      } @@ -93,9 +137,21 @@ impl Api for Server {          Box::new(futures::failed("Generic failure".into()))      } -    fn create_work_batch(&self, entity_list: &Vec<models::WorkEntity>, context: &Context) -> Box<Future<Item = CreateWorkBatchResponse, Error = ApiError> + Send> { +    fn create_work_batch( +        &self, +        entity_list: &Vec<models::WorkEntity>, +        autoaccept: Option<bool>, +        editgroup: Option<String>, +        context: &Context, +    ) -> Box<Future<Item = CreateWorkBatchResponse, Error = ApiError> + Send> {          let context = context.clone(); -        println!("create_work_batch({:?}) - X-Span-ID: {:?}", entity_list, context.x_span_id.unwrap_or(String::from("<none>")).clone()); +        println!( +            "create_work_batch({:?}, {:?}, {:?}) - X-Span-ID: {:?}", +            entity_list, +            autoaccept, +            editgroup, +            context.x_span_id.unwrap_or(String::from("<none>")).clone() +        );          Box::new(futures::failed("Generic failure".into()))      } diff --git a/rust/fatcat-api/src/client.rs b/rust/fatcat-api/src/client.rs index 9b2caa32..6f61f773 100644 --- a/rust/fatcat-api/src/client.rs +++ b/rust/fatcat-api/src/client.rs @@ -298,8 +298,23 @@ impl Api for Client {          Box::new(futures::done(result))      } -    fn create_container_batch(&self, param_entity_list: &Vec<models::ContainerEntity>, context: &Context) -> Box<Future<Item = CreateContainerBatchResponse, Error = ApiError> + Send> { -        let url = format!("{}/v0/container/batch", self.base_path); +    fn create_container_batch( +        &self, +        param_entity_list: &Vec<models::ContainerEntity>, +        param_autoaccept: Option<bool>, +        param_editgroup: Option<String>, +        context: &Context, +    ) -> Box<Future<Item = CreateContainerBatchResponse, Error = ApiError> + Send> { +        // Query parameters +        let query_autoaccept = param_autoaccept.map_or_else(String::new, |query| format!("autoaccept={autoaccept}&", autoaccept = query.to_string())); +        let query_editgroup = param_editgroup.map_or_else(String::new, |query| format!("editgroup={editgroup}&", editgroup = query.to_string())); + +        let url = format!( +            "{}/v0/container/batch?{autoaccept}{editgroup}", +            self.base_path, +            autoaccept = utf8_percent_encode(&query_autoaccept, QUERY_ENCODE_SET), +            editgroup = utf8_percent_encode(&query_editgroup, QUERY_ENCODE_SET) +        );          let body = serde_json::to_string(¶m_entity_list).expect("impossible to fail to serialize"); @@ -428,8 +443,23 @@ impl Api for Client {          Box::new(futures::done(result))      } -    fn create_creator_batch(&self, param_entity_list: &Vec<models::CreatorEntity>, context: &Context) -> Box<Future<Item = CreateCreatorBatchResponse, Error = ApiError> + Send> { -        let url = format!("{}/v0/creator/batch", self.base_path); +    fn create_creator_batch( +        &self, +        param_entity_list: &Vec<models::CreatorEntity>, +        param_autoaccept: Option<bool>, +        param_editgroup: Option<String>, +        context: &Context, +    ) -> Box<Future<Item = CreateCreatorBatchResponse, Error = ApiError> + Send> { +        // Query parameters +        let query_autoaccept = param_autoaccept.map_or_else(String::new, |query| format!("autoaccept={autoaccept}&", autoaccept = query.to_string())); +        let query_editgroup = param_editgroup.map_or_else(String::new, |query| format!("editgroup={editgroup}&", editgroup = query.to_string())); + +        let url = format!( +            "{}/v0/creator/batch?{autoaccept}{editgroup}", +            self.base_path, +            autoaccept = utf8_percent_encode(&query_autoaccept, QUERY_ENCODE_SET), +            editgroup = utf8_percent_encode(&query_editgroup, QUERY_ENCODE_SET) +        );          let body = serde_json::to_string(¶m_entity_list).expect("impossible to fail to serialize"); @@ -616,8 +646,23 @@ impl Api for Client {          Box::new(futures::done(result))      } -    fn create_file_batch(&self, param_entity_list: &Vec<models::FileEntity>, context: &Context) -> Box<Future<Item = CreateFileBatchResponse, Error = ApiError> + Send> { -        let url = format!("{}/v0/file/batch", self.base_path); +    fn create_file_batch( +        &self, +        param_entity_list: &Vec<models::FileEntity>, +        param_autoaccept: Option<bool>, +        param_editgroup: Option<String>, +        context: &Context, +    ) -> Box<Future<Item = CreateFileBatchResponse, Error = ApiError> + Send> { +        // Query parameters +        let query_autoaccept = param_autoaccept.map_or_else(String::new, |query| format!("autoaccept={autoaccept}&", autoaccept = query.to_string())); +        let query_editgroup = param_editgroup.map_or_else(String::new, |query| format!("editgroup={editgroup}&", editgroup = query.to_string())); + +        let url = format!( +            "{}/v0/file/batch?{autoaccept}{editgroup}", +            self.base_path, +            autoaccept = utf8_percent_encode(&query_autoaccept, QUERY_ENCODE_SET), +            editgroup = utf8_percent_encode(&query_editgroup, QUERY_ENCODE_SET) +        );          let body = serde_json::to_string(¶m_entity_list).expect("impossible to fail to serialize"); @@ -746,8 +791,23 @@ impl Api for Client {          Box::new(futures::done(result))      } -    fn create_release_batch(&self, param_entity_list: &Vec<models::ReleaseEntity>, context: &Context) -> Box<Future<Item = CreateReleaseBatchResponse, Error = ApiError> + Send> { -        let url = format!("{}/v0/release/batch", self.base_path); +    fn create_release_batch( +        &self, +        param_entity_list: &Vec<models::ReleaseEntity>, +        param_autoaccept: Option<bool>, +        param_editgroup: Option<String>, +        context: &Context, +    ) -> Box<Future<Item = CreateReleaseBatchResponse, Error = ApiError> + Send> { +        // Query parameters +        let query_autoaccept = param_autoaccept.map_or_else(String::new, |query| format!("autoaccept={autoaccept}&", autoaccept = query.to_string())); +        let query_editgroup = param_editgroup.map_or_else(String::new, |query| format!("editgroup={editgroup}&", editgroup = query.to_string())); + +        let url = format!( +            "{}/v0/release/batch?{autoaccept}{editgroup}", +            self.base_path, +            autoaccept = utf8_percent_encode(&query_autoaccept, QUERY_ENCODE_SET), +            editgroup = utf8_percent_encode(&query_editgroup, QUERY_ENCODE_SET) +        );          let body = serde_json::to_string(¶m_entity_list).expect("impossible to fail to serialize"); @@ -876,8 +936,23 @@ impl Api for Client {          Box::new(futures::done(result))      } -    fn create_work_batch(&self, param_entity_list: &Vec<models::WorkEntity>, context: &Context) -> Box<Future<Item = CreateWorkBatchResponse, Error = ApiError> + Send> { -        let url = format!("{}/v0/work/batch", self.base_path); +    fn create_work_batch( +        &self, +        param_entity_list: &Vec<models::WorkEntity>, +        param_autoaccept: Option<bool>, +        param_editgroup: Option<String>, +        context: &Context, +    ) -> Box<Future<Item = CreateWorkBatchResponse, Error = ApiError> + Send> { +        // Query parameters +        let query_autoaccept = param_autoaccept.map_or_else(String::new, |query| format!("autoaccept={autoaccept}&", autoaccept = query.to_string())); +        let query_editgroup = param_editgroup.map_or_else(String::new, |query| format!("editgroup={editgroup}&", editgroup = query.to_string())); + +        let url = format!( +            "{}/v0/work/batch?{autoaccept}{editgroup}", +            self.base_path, +            autoaccept = utf8_percent_encode(&query_autoaccept, QUERY_ENCODE_SET), +            editgroup = utf8_percent_encode(&query_editgroup, QUERY_ENCODE_SET) +        );          let body = serde_json::to_string(¶m_entity_list).expect("impossible to fail to serialize"); diff --git a/rust/fatcat-api/src/lib.rs b/rust/fatcat-api/src/lib.rs index 8ff89b9f..fc1ae2a1 100644 --- a/rust/fatcat-api/src/lib.rs +++ b/rust/fatcat-api/src/lib.rs @@ -564,25 +564,55 @@ pub trait Api {      fn create_container(&self, entity: models::ContainerEntity, context: &Context) -> Box<Future<Item = CreateContainerResponse, Error = ApiError> + Send>; -    fn create_container_batch(&self, entity_list: &Vec<models::ContainerEntity>, context: &Context) -> Box<Future<Item = CreateContainerBatchResponse, Error = ApiError> + Send>; +    fn create_container_batch( +        &self, +        entity_list: &Vec<models::ContainerEntity>, +        autoaccept: Option<bool>, +        editgroup: Option<String>, +        context: &Context, +    ) -> Box<Future<Item = CreateContainerBatchResponse, Error = ApiError> + Send>;      fn create_creator(&self, entity: models::CreatorEntity, context: &Context) -> Box<Future<Item = CreateCreatorResponse, Error = ApiError> + Send>; -    fn create_creator_batch(&self, entity_list: &Vec<models::CreatorEntity>, context: &Context) -> Box<Future<Item = CreateCreatorBatchResponse, Error = ApiError> + Send>; +    fn create_creator_batch( +        &self, +        entity_list: &Vec<models::CreatorEntity>, +        autoaccept: Option<bool>, +        editgroup: Option<String>, +        context: &Context, +    ) -> Box<Future<Item = CreateCreatorBatchResponse, Error = ApiError> + Send>;      fn create_editgroup(&self, entity: models::Editgroup, context: &Context) -> Box<Future<Item = CreateEditgroupResponse, Error = ApiError> + Send>;      fn create_file(&self, entity: models::FileEntity, context: &Context) -> Box<Future<Item = CreateFileResponse, Error = ApiError> + Send>; -    fn create_file_batch(&self, entity_list: &Vec<models::FileEntity>, context: &Context) -> Box<Future<Item = CreateFileBatchResponse, Error = ApiError> + Send>; +    fn create_file_batch( +        &self, +        entity_list: &Vec<models::FileEntity>, +        autoaccept: Option<bool>, +        editgroup: Option<String>, +        context: &Context, +    ) -> Box<Future<Item = CreateFileBatchResponse, Error = ApiError> + Send>;      fn create_release(&self, entity: models::ReleaseEntity, context: &Context) -> Box<Future<Item = CreateReleaseResponse, Error = ApiError> + Send>; -    fn create_release_batch(&self, entity_list: &Vec<models::ReleaseEntity>, context: &Context) -> Box<Future<Item = CreateReleaseBatchResponse, Error = ApiError> + Send>; +    fn create_release_batch( +        &self, +        entity_list: &Vec<models::ReleaseEntity>, +        autoaccept: Option<bool>, +        editgroup: Option<String>, +        context: &Context, +    ) -> Box<Future<Item = CreateReleaseBatchResponse, Error = ApiError> + Send>;      fn create_work(&self, entity: models::WorkEntity, context: &Context) -> Box<Future<Item = CreateWorkResponse, Error = ApiError> + Send>; -    fn create_work_batch(&self, entity_list: &Vec<models::WorkEntity>, context: &Context) -> Box<Future<Item = CreateWorkBatchResponse, Error = ApiError> + Send>; +    fn create_work_batch( +        &self, +        entity_list: &Vec<models::WorkEntity>, +        autoaccept: Option<bool>, +        editgroup: Option<String>, +        context: &Context, +    ) -> Box<Future<Item = CreateWorkBatchResponse, Error = ApiError> + Send>;      fn delete_container(&self, id: String, editgroup: Option<String>, context: &Context) -> Box<Future<Item = DeleteContainerResponse, Error = ApiError> + Send>; @@ -657,25 +687,40 @@ pub trait ApiNoContext {      fn create_container(&self, entity: models::ContainerEntity) -> Box<Future<Item = CreateContainerResponse, Error = ApiError> + Send>; -    fn create_container_batch(&self, entity_list: &Vec<models::ContainerEntity>) -> Box<Future<Item = CreateContainerBatchResponse, Error = ApiError> + Send>; +    fn create_container_batch( +        &self, +        entity_list: &Vec<models::ContainerEntity>, +        autoaccept: Option<bool>, +        editgroup: Option<String>, +    ) -> Box<Future<Item = CreateContainerBatchResponse, Error = ApiError> + Send>;      fn create_creator(&self, entity: models::CreatorEntity) -> Box<Future<Item = CreateCreatorResponse, Error = ApiError> + Send>; -    fn create_creator_batch(&self, entity_list: &Vec<models::CreatorEntity>) -> Box<Future<Item = CreateCreatorBatchResponse, Error = ApiError> + Send>; +    fn create_creator_batch( +        &self, +        entity_list: &Vec<models::CreatorEntity>, +        autoaccept: Option<bool>, +        editgroup: Option<String>, +    ) -> Box<Future<Item = CreateCreatorBatchResponse, Error = ApiError> + Send>;      fn create_editgroup(&self, entity: models::Editgroup) -> Box<Future<Item = CreateEditgroupResponse, Error = ApiError> + Send>;      fn create_file(&self, entity: models::FileEntity) -> Box<Future<Item = CreateFileResponse, Error = ApiError> + Send>; -    fn create_file_batch(&self, entity_list: &Vec<models::FileEntity>) -> Box<Future<Item = CreateFileBatchResponse, Error = ApiError> + Send>; +    fn create_file_batch(&self, entity_list: &Vec<models::FileEntity>, autoaccept: Option<bool>, editgroup: Option<String>) -> Box<Future<Item = CreateFileBatchResponse, Error = ApiError> + Send>;      fn create_release(&self, entity: models::ReleaseEntity) -> Box<Future<Item = CreateReleaseResponse, Error = ApiError> + Send>; -    fn create_release_batch(&self, entity_list: &Vec<models::ReleaseEntity>) -> Box<Future<Item = CreateReleaseBatchResponse, Error = ApiError> + Send>; +    fn create_release_batch( +        &self, +        entity_list: &Vec<models::ReleaseEntity>, +        autoaccept: Option<bool>, +        editgroup: Option<String>, +    ) -> Box<Future<Item = CreateReleaseBatchResponse, Error = ApiError> + Send>;      fn create_work(&self, entity: models::WorkEntity) -> Box<Future<Item = CreateWorkResponse, Error = ApiError> + Send>; -    fn create_work_batch(&self, entity_list: &Vec<models::WorkEntity>) -> Box<Future<Item = CreateWorkBatchResponse, Error = ApiError> + Send>; +    fn create_work_batch(&self, entity_list: &Vec<models::WorkEntity>, autoaccept: Option<bool>, editgroup: Option<String>) -> Box<Future<Item = CreateWorkBatchResponse, Error = ApiError> + Send>;      fn delete_container(&self, id: String, editgroup: Option<String>) -> Box<Future<Item = DeleteContainerResponse, Error = ApiError> + Send>; @@ -768,16 +813,26 @@ impl<'a, T: Api> ApiNoContext for ContextWrapper<'a, T> {          self.api().create_container(entity, &self.context())      } -    fn create_container_batch(&self, entity_list: &Vec<models::ContainerEntity>) -> Box<Future<Item = CreateContainerBatchResponse, Error = ApiError> + Send> { -        self.api().create_container_batch(entity_list, &self.context()) +    fn create_container_batch( +        &self, +        entity_list: &Vec<models::ContainerEntity>, +        autoaccept: Option<bool>, +        editgroup: Option<String>, +    ) -> Box<Future<Item = CreateContainerBatchResponse, Error = ApiError> + Send> { +        self.api().create_container_batch(entity_list, autoaccept, editgroup, &self.context())      }      fn create_creator(&self, entity: models::CreatorEntity) -> Box<Future<Item = CreateCreatorResponse, Error = ApiError> + Send> {          self.api().create_creator(entity, &self.context())      } -    fn create_creator_batch(&self, entity_list: &Vec<models::CreatorEntity>) -> Box<Future<Item = CreateCreatorBatchResponse, Error = ApiError> + Send> { -        self.api().create_creator_batch(entity_list, &self.context()) +    fn create_creator_batch( +        &self, +        entity_list: &Vec<models::CreatorEntity>, +        autoaccept: Option<bool>, +        editgroup: Option<String>, +    ) -> Box<Future<Item = CreateCreatorBatchResponse, Error = ApiError> + Send> { +        self.api().create_creator_batch(entity_list, autoaccept, editgroup, &self.context())      }      fn create_editgroup(&self, entity: models::Editgroup) -> Box<Future<Item = CreateEditgroupResponse, Error = ApiError> + Send> { @@ -788,24 +843,29 @@ impl<'a, T: Api> ApiNoContext for ContextWrapper<'a, T> {          self.api().create_file(entity, &self.context())      } -    fn create_file_batch(&self, entity_list: &Vec<models::FileEntity>) -> Box<Future<Item = CreateFileBatchResponse, Error = ApiError> + Send> { -        self.api().create_file_batch(entity_list, &self.context()) +    fn create_file_batch(&self, entity_list: &Vec<models::FileEntity>, autoaccept: Option<bool>, editgroup: Option<String>) -> Box<Future<Item = CreateFileBatchResponse, Error = ApiError> + Send> { +        self.api().create_file_batch(entity_list, autoaccept, editgroup, &self.context())      }      fn create_release(&self, entity: models::ReleaseEntity) -> Box<Future<Item = CreateReleaseResponse, Error = ApiError> + Send> {          self.api().create_release(entity, &self.context())      } -    fn create_release_batch(&self, entity_list: &Vec<models::ReleaseEntity>) -> Box<Future<Item = CreateReleaseBatchResponse, Error = ApiError> + Send> { -        self.api().create_release_batch(entity_list, &self.context()) +    fn create_release_batch( +        &self, +        entity_list: &Vec<models::ReleaseEntity>, +        autoaccept: Option<bool>, +        editgroup: Option<String>, +    ) -> Box<Future<Item = CreateReleaseBatchResponse, Error = ApiError> + Send> { +        self.api().create_release_batch(entity_list, autoaccept, editgroup, &self.context())      }      fn create_work(&self, entity: models::WorkEntity) -> Box<Future<Item = CreateWorkResponse, Error = ApiError> + Send> {          self.api().create_work(entity, &self.context())      } -    fn create_work_batch(&self, entity_list: &Vec<models::WorkEntity>) -> Box<Future<Item = CreateWorkBatchResponse, Error = ApiError> + Send> { -        self.api().create_work_batch(entity_list, &self.context()) +    fn create_work_batch(&self, entity_list: &Vec<models::WorkEntity>, autoaccept: Option<bool>, editgroup: Option<String>) -> Box<Future<Item = CreateWorkBatchResponse, Error = ApiError> + Send> { +        self.api().create_work_batch(entity_list, autoaccept, editgroup, &self.context())      }      fn delete_container(&self, id: String, editgroup: Option<String>) -> Box<Future<Item = DeleteContainerResponse, Error = ApiError> + Send> { diff --git a/rust/fatcat-api/src/server.rs b/rust/fatcat-api/src/server.rs index 8db27496..04d10e14 100644 --- a/rust/fatcat-api/src/server.rs +++ b/rust/fatcat-api/src/server.rs @@ -309,6 +309,11 @@ where                  context.auth_data = req.extensions.remove::<AuthData>();                  context.authorization = req.extensions.remove::<Authorization>(); +                // Query parameters (note that non-required or collection query parameters will ignore garbage values, rather than causing a 400 response) +                let query_params = req.get::<UrlEncodedQuery>().unwrap_or_default(); +                let param_autoaccept = query_params.get("autoaccept").and_then(|list| list.first()).and_then(|x| x.parse::<bool>().ok()); +                let param_editgroup = query_params.get("editgroup").and_then(|list| list.first()).and_then(|x| x.parse::<String>().ok()); +                  // Body parameters (note that non-required body parameters will ignore garbage                  // values, rather than causing a 400 response). Produce warning header and logs for                  // any unused fields. @@ -333,7 +338,7 @@ where                  };                  let param_entity_list = param_entity_list.ok_or_else(|| Response::with((status::BadRequest, "Missing required body parameter entity_list".to_string())))?; -                match api.create_container_batch(param_entity_list.as_ref(), context).wait() { +                match api.create_container_batch(param_entity_list.as_ref(), param_autoaccept, param_editgroup, context).wait() {                      Ok(rsp) => match rsp {                          CreateContainerBatchResponse::CreatedEntities(body) => {                              let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -521,6 +526,11 @@ where                  context.auth_data = req.extensions.remove::<AuthData>();                  context.authorization = req.extensions.remove::<Authorization>(); +                // Query parameters (note that non-required or collection query parameters will ignore garbage values, rather than causing a 400 response) +                let query_params = req.get::<UrlEncodedQuery>().unwrap_or_default(); +                let param_autoaccept = query_params.get("autoaccept").and_then(|list| list.first()).and_then(|x| x.parse::<bool>().ok()); +                let param_editgroup = query_params.get("editgroup").and_then(|list| list.first()).and_then(|x| x.parse::<String>().ok()); +                  // Body parameters (note that non-required body parameters will ignore garbage                  // values, rather than causing a 400 response). Produce warning header and logs for                  // any unused fields. @@ -545,7 +555,7 @@ where                  };                  let param_entity_list = param_entity_list.ok_or_else(|| Response::with((status::BadRequest, "Missing required body parameter entity_list".to_string())))?; -                match api.create_creator_batch(param_entity_list.as_ref(), context).wait() { +                match api.create_creator_batch(param_entity_list.as_ref(), param_autoaccept, param_editgroup, context).wait() {                      Ok(rsp) => match rsp {                          CreateCreatorBatchResponse::CreatedEntities(body) => {                              let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -826,6 +836,11 @@ where                  context.auth_data = req.extensions.remove::<AuthData>();                  context.authorization = req.extensions.remove::<Authorization>(); +                // Query parameters (note that non-required or collection query parameters will ignore garbage values, rather than causing a 400 response) +                let query_params = req.get::<UrlEncodedQuery>().unwrap_or_default(); +                let param_autoaccept = query_params.get("autoaccept").and_then(|list| list.first()).and_then(|x| x.parse::<bool>().ok()); +                let param_editgroup = query_params.get("editgroup").and_then(|list| list.first()).and_then(|x| x.parse::<String>().ok()); +                  // Body parameters (note that non-required body parameters will ignore garbage                  // values, rather than causing a 400 response). Produce warning header and logs for                  // any unused fields. @@ -850,7 +865,7 @@ where                  };                  let param_entity_list = param_entity_list.ok_or_else(|| Response::with((status::BadRequest, "Missing required body parameter entity_list".to_string())))?; -                match api.create_file_batch(param_entity_list.as_ref(), context).wait() { +                match api.create_file_batch(param_entity_list.as_ref(), param_autoaccept, param_editgroup, context).wait() {                      Ok(rsp) => match rsp {                          CreateFileBatchResponse::CreatedEntities(body) => {                              let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -1038,6 +1053,11 @@ where                  context.auth_data = req.extensions.remove::<AuthData>();                  context.authorization = req.extensions.remove::<Authorization>(); +                // Query parameters (note that non-required or collection query parameters will ignore garbage values, rather than causing a 400 response) +                let query_params = req.get::<UrlEncodedQuery>().unwrap_or_default(); +                let param_autoaccept = query_params.get("autoaccept").and_then(|list| list.first()).and_then(|x| x.parse::<bool>().ok()); +                let param_editgroup = query_params.get("editgroup").and_then(|list| list.first()).and_then(|x| x.parse::<String>().ok()); +                  // Body parameters (note that non-required body parameters will ignore garbage                  // values, rather than causing a 400 response). Produce warning header and logs for                  // any unused fields. @@ -1062,7 +1082,7 @@ where                  };                  let param_entity_list = param_entity_list.ok_or_else(|| Response::with((status::BadRequest, "Missing required body parameter entity_list".to_string())))?; -                match api.create_release_batch(param_entity_list.as_ref(), context).wait() { +                match api.create_release_batch(param_entity_list.as_ref(), param_autoaccept, param_editgroup, context).wait() {                      Ok(rsp) => match rsp {                          CreateReleaseBatchResponse::CreatedEntities(body) => {                              let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -1250,6 +1270,11 @@ where                  context.auth_data = req.extensions.remove::<AuthData>();                  context.authorization = req.extensions.remove::<Authorization>(); +                // Query parameters (note that non-required or collection query parameters will ignore garbage values, rather than causing a 400 response) +                let query_params = req.get::<UrlEncodedQuery>().unwrap_or_default(); +                let param_autoaccept = query_params.get("autoaccept").and_then(|list| list.first()).and_then(|x| x.parse::<bool>().ok()); +                let param_editgroup = query_params.get("editgroup").and_then(|list| list.first()).and_then(|x| x.parse::<String>().ok()); +                  // Body parameters (note that non-required body parameters will ignore garbage                  // values, rather than causing a 400 response). Produce warning header and logs for                  // any unused fields. @@ -1274,7 +1299,7 @@ where                  };                  let param_entity_list = param_entity_list.ok_or_else(|| Response::with((status::BadRequest, "Missing required body parameter entity_list".to_string())))?; -                match api.create_work_batch(param_entity_list.as_ref(), context).wait() { +                match api.create_work_batch(param_entity_list.as_ref(), param_autoaccept, param_editgroup, context).wait() {                      Ok(rsp) => match rsp {                          CreateWorkBatchResponse::CreatedEntities(body) => {                              let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); diff --git a/rust/src/api_server.rs b/rust/src/api_server.rs index 57aeebea..602fbfb7 100644 --- a/rust/src/api_server.rs +++ b/rust/src/api_server.rs @@ -25,11 +25,40 @@ macro_rules! entity_batch_handler {          pub fn $post_batch_handler(              &self,              entity_list: &[models::$model], +            autoaccept: bool, +            editgroup: Option<String>,              conn: &DbConn,          ) -> Result<Vec<EntityEdit>> { -            let edit_context = make_edit_context(conn, None)?; +            // editgroup override logic based on parameters +            let eg_id: Option<Uuid> = match (editgroup, autoaccept) { +                (Some(eg_string), _) => Some(fcid2uuid(&eg_string)?), +                (None, true) => { +                    let eg_row: EditgroupRow = diesel::insert_into(editgroup::table) +                        .values((editgroup::editor_id.eq(editor_id),)) +                        .get_result(conn)?; +                    Some(eg_row.id) +                }, +                (None, false) => None +            }; +            for entity in entity_list { +                let mut e = entity.clone(); +                // override individual editgroup IDs (if set earlier) +                if let Some(inner_id) = eg_id { +                    e.editgroup_id = Some(uuid2fcid(&inner_id)); +                } +                // actual wrapped function call here +                ret.push(self.$post_handler(e, autoaccept, conn)?); +            } +            let mut edit_context = make_edit_context(conn, eg_id)?; +            edit_context.autoaccept = autoaccept;              let model_list: Vec<&models::$model> = entity_list.iter().map(|e| e).collect();              let edits = $model::db_create_batch(conn, &edit_context, model_list.as_slice())?; +            if autoaccept { +                // if autoaccept, eg_id is always Some +                let _clr: ChangelogRow = diesel::insert_into(changelog::table) +                    .values((changelog::editgroup_id.eq(eg_id.unwrap()),)) +                    .get_result(conn)?; +            }              edits.into_iter().map(|e| e.into_model()).collect()          }      } diff --git a/rust/src/api_wrappers.rs b/rust/src/api_wrappers.rs index de1fc9da..6272814e 100644 --- a/rust/src/api_wrappers.rs +++ b/rust/src/api_wrappers.rs @@ -61,7 +61,7 @@ macro_rules! wrap_entity_handlers {              _context: &Context,          ) -> Box<Future<Item = $post_resp, Error = ApiError> + Send> {              let conn = self.db_pool.get().expect("db_pool error"); -            let ret = match conn.transaction(|| self.$post_handler(entity, &conn)) { +            let ret = match conn.transaction(|| self.$post_handler(entity, false, &conn)) {                  Ok(edit) =>                      $post_resp::CreatedEntity(edit),                  Err(Error(ErrorKind::Diesel(e), _)) => @@ -84,10 +84,12 @@ macro_rules! wrap_entity_handlers {          fn $post_batch_fn(              &self,              entity_list: &Vec<models::$model>, +            autoaccept: Option<bool>, +            editgroup: Option<String>,              _context: &Context,          ) -> Box<Future<Item = $post_batch_resp, Error = ApiError> + Send> {              let conn = self.db_pool.get().expect("db_pool error"); -            let ret = match conn.transaction(|| self.$post_batch_handler(entity_list, &conn)) { +            let ret = match conn.transaction(|| self.$post_batch_handler(entity_list, autoaccept.unwrap_or(false), editgroup, &conn)) {                  Ok(edit) =>                      $post_batch_resp::CreatedEntities(edit),                  Err(Error(ErrorKind::Diesel(e), _)) => diff --git a/rust/tests/test_api_server.rs b/rust/tests/test_api_server.rs index 4b181188..54639228 100644 --- a/rust/tests/test_api_server.rs +++ b/rust/tests/test_api_server.rs @@ -983,3 +983,44 @@ fn test_contribs() {          None,      );  } + +#[test] +fn test_post_batch_autoaccept() { +    let (headers, router, _conn) = setup(); + +    // "true" +    check_response( +        request::post( +            "http://localhost:9411/v0/container/batch?autoaccept=true", +            headers.clone(), +            r#"[{"name": "test journal"}, {"name": "another test journal"}]"#, +            &router, +        ), +        status::Created, +        None, +    ); + +    // "n" +    check_response( +        request::post( +            "http://localhost:9411/v0/container/batch?autoaccept=n", +            headers.clone(), +            r#"[{"name": "test journal"}, {"name": "another test journal"}]"#, +            &router, +        ), +        status::Created, +        None, +    ); + +    // editgroup +    check_response( +        request::post( +            "http://localhost:9411/v0/container/batch?autoaccept=yes&editgroup=asdf", +            headers.clone(), +            r#"[{"name": "test journal"}, {"name": "another test journal"}]"#, +            &router, +        ), +        status::BadRequest, +        None, +    ); +} | 
