Skip to content

Commit c652d60

Browse files
committed
cocalc-api: testing organization management
1 parent 0772810 commit c652d60

File tree

8 files changed

+966
-227
lines changed

8 files changed

+966
-227
lines changed

src/python/cocalc-api/src/cocalc_api/hub.py

Lines changed: 18 additions & 217 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,18 @@
11
import httpx
22
from typing import Any, Literal, Optional
33
from .util import api_method, handle_error
4-
from .api_types import PingResponse, UserSearchResult, MessageType, TokenType, OrganizationUser
4+
from .api_types import PingResponse, UserSearchResult, MessageType
5+
from .org import Organizations
56

67

78
class Hub:
89

910
def __init__(self, api_key: str, host: str = "https://cocalc.com"):
1011
self.api_key = api_key
1112
self.host = host
12-
self.client = httpx.Client(
13-
auth=(api_key, ""), headers={"Content-Type": "application/json"})
13+
self.client = httpx.Client(auth=(api_key, ""), headers={"Content-Type": "application/json"})
1414

15-
def call(self,
16-
name: str,
17-
arguments: list[Any],
18-
timeout: Optional[int] = None) -> Any:
15+
def call(self, name: str, arguments: list[Any], timeout: Optional[int] = None) -> Any:
1916
"""
2017
Perform an API call to the CoCalc backend.
2118
@@ -136,18 +133,15 @@ def user_search(self, query: str) -> UserSearchResult:
136133
'created': 1756056224470,
137134
'email_address_verified': None}]
138135
"""
139-
raise NotImplementedError
136+
...
140137

141138

142139
class Projects:
143140

144141
def __init__(self, parent: "Hub"):
145142
self._parent = parent
146143

147-
def get(self,
148-
fields: Optional[list[str]] = None,
149-
all: Optional[bool] = False,
150-
project_id: Optional[str] = None) -> list[dict[str, Any]]:
144+
def get(self, fields: Optional[list[str]] = None, all: Optional[bool] = False, project_id: Optional[str] = None) -> list[dict[str, Any]]:
151145
"""
152146
Get data about projects that you are a collaborator on. Only gets
153147
recent projects by default; set all=True to get all projects.
@@ -219,12 +213,10 @@ def create_project(
219213
Returns:
220214
str: The ID of the newly created project.
221215
"""
222-
# actually implemented via the decorator
223-
raise NotImplementedError
216+
...
224217

225218
@api_method("projects.addCollaborator", opts=True)
226-
def add_collaborator(self, project_id: str | list[str],
227-
account_id: str | list[str]) -> dict[str, Any]:
219+
def add_collaborator(self, project_id: str | list[str], account_id: str | list[str]) -> dict[str, Any]:
228220
"""
229221
Add a collaborator to a project.
230222
@@ -243,8 +235,7 @@ def add_collaborator(self, project_id: str | list[str],
243235
...
244236

245237
@api_method("projects.removeCollaborator", opts=True)
246-
def remove_collaborator(self, project_id: str,
247-
account_id: str) -> dict[str, Any]:
238+
def remove_collaborator(self, project_id: str, account_id: str) -> dict[str, Any]:
248239
"""
249240
Remove a collaborator from a project.
250241
@@ -356,8 +347,7 @@ def __init__(self, parent: "Hub"):
356347
self._parent = parent
357348

358349
@api_method("sync.history")
359-
def history(self, project_id: str,
360-
path: str) -> list[dict[str, Any]]: # type: ignore[empty-body]
350+
def history(self, project_id: str, path: str) -> list[dict[str, Any]]: # type: ignore[empty-body]
361351
"""
362352
Get complete edit history of a file.
363353
@@ -412,11 +402,7 @@ def __init__(self, parent: "Hub"):
412402
self._parent = parent
413403

414404
@api_method("messages.send")
415-
def send(self,
416-
subject: str,
417-
body: str,
418-
to_ids: list[str],
419-
reply_id: Optional[int] = None) -> int:
405+
def send(self, subject: str, body: str, to_ids: list[str], reply_id: Optional[int] = None) -> int:
420406
"""
421407
Send a message to one or more users.
422408
@@ -429,15 +415,14 @@ def send(self,
429415
Returns:
430416
int: ID of the message.
431417
"""
432-
raise NotImplementedError
418+
...
433419

434420
@api_method("messages.get")
435421
def get(
436422
self,
437423
limit: Optional[int] = None,
438424
offset: Optional[int] = None,
439-
type: Optional[Literal["received", "sent", "new", "starred",
440-
"liked"]] = None,
425+
type: Optional[Literal["received", "sent", "new", "starred", "liked"]] = None,
441426
) -> list[MessageType]: # type: ignore[empty-body]
442427
"""
443428
Get your messages.
@@ -450,195 +435,11 @@ def get(
450435
Returns:
451436
list[MessageType]: List of messages.
452437
"""
453-
raise NotImplementedError
438+
...
454439

455440

456441
"""
457-
message: authFirst,
458-
removeUser: authFirst,
459-
removeAdmin: authFirst,
460-
"""
461-
462-
463-
class Organizations:
464-
465-
def __init__(self, parent: "Hub"):
466-
self._parent = parent
467-
468-
@api_method("org.getAll")
469-
def get_all(self) -> dict[str, Any]:
470-
"""
471-
Get all organizations (site admins only).
472-
473-
Returns:
474-
dict[str, Any]: Organization data.
475-
"""
476-
raise NotImplementedError
477-
478-
@api_method("org.create")
479-
def create(self, name: str) -> dict[str, Any]:
480-
"""
481-
Create an organization (site admins only).
482-
483-
Args:
484-
name (str): Name of the organization; must be globally unique,
485-
at most 39 characters, and CANNOT BE CHANGED.
486-
487-
Returns:
488-
dict[str, Any]: Organization data.
489-
"""
490-
raise NotImplementedError
491-
492-
@api_method("org.get")
493-
def get(self, name: str) -> dict[str, Any]:
494-
"""
495-
Get an organization.
496-
497-
Args:
498-
name (str): Name of the organization.
499-
500-
Returns:
501-
dict[str, Any]: Organization data.
502-
"""
503-
raise NotImplementedError
504-
505-
@api_method("org.set")
506-
def set(self,
507-
name: str,
508-
title: Optional[str] = None,
509-
description: Optional[str] = None,
510-
email_address: Optional[str] = None,
511-
link: Optional[str] = None) -> dict[str, Any]:
512-
"""
513-
Set properties of an organization.
514-
515-
Args:
516-
name (str): Name of the organization.
517-
title (Optional[str]): The title of the organization.
518-
description (Optional[str]): Description of the organization.
519-
email_address (Optional[str]): Email address to reach the organization
520-
(nothing to do with a cocalc account).
521-
link (Optional[str]): A website of the organization.
522-
"""
523-
raise NotImplementedError
524-
525-
@api_method("org.addAdmin")
526-
def add_admin(self, name: str, user: str) -> dict[str, Any]:
527-
"""
528-
Make the user with given account_id or email an admin
529-
of the named organization.
530-
531-
Args:
532-
name (str): name of the organization
533-
user (str): email or account_id
534-
"""
535-
raise NotImplementedError
536-
537-
@api_method("org.addUser")
538-
def add_user(self, name: str, user: str) -> dict[str, Any]:
539-
"""
540-
Make the user with given account_id or email a member
541-
of the named organization. Only site admins can do this.
542-
If you are an org admin, instead use create_user to create
543-
new users in your organization, or contact support.
544-
545-
Args:
546-
name (str): name of the organization
547-
user (str): email or account_id
548-
"""
549-
raise NotImplementedError
550-
551-
@api_method("org.createUser")
552-
def create_user(self,
553-
name: str,
554-
email: str,
555-
firstName: Optional[str] = None,
556-
lastName: Optional[str] = None,
557-
password: Optional[str] = None) -> str:
558-
"""
559-
Create a new cocalc account that is a member of the
560-
named organization.
561-
562-
Args:
563-
name (str): name of the organization
564-
email (str): email address
565-
firstName (Optional[str]): optional first name of the user
566-
lastName (Optional[str]): optional last name of the user
567-
password (Optional[str]): optional password (will be randomized if
568-
not given; you can instead use create_token to grant temporary
569-
account access).
570-
571-
Returns:
572-
str: account_id of the new user
573-
"""
574-
raise NotImplementedError
575-
576-
@api_method("org.createToken")
577-
def create_token(self, user: str) -> TokenType:
578-
"""
579-
Create a token that provides temporary access to the given
580-
account. You must be an admin for the org that the user
581-
belongs to or a site admin.
582-
583-
Args:
584-
user (str): email address or account_id
585-
586-
Returns:
587-
TokenType: token that grants temporary access
588-
589-
Notes:
590-
The returned `TokenType` has the following fields:
591-
592-
- `token` (str): The random token itself, which you may retain
593-
in case you want to explicitly expire it early.
594-
- `url` (str): The url that the user should visit to sign in as
595-
them. You can also test out this url, since the token works
596-
multiple times.
597-
"""
598-
raise NotImplementedError
599-
600-
@api_method("org.expireToken")
601-
def expire_token(self, token: str) -> dict[str, Any]:
602-
"""
603-
Immediately expire a token created using create_token.
604-
605-
Args:
606-
token (str): a token
607-
"""
608-
raise NotImplementedError
609-
610-
@api_method("org.getUsers")
611-
def get_users(
612-
self,
613-
name: str) -> list[OrganizationUser]: # type: ignore[empty-body]
614-
"""
615-
Return list of all accounts that are members of the named organization.
616-
617-
Args:
618-
name (str): name of the organization
619-
620-
Returns:
621-
list[OrganizationUser]
622-
623-
Notes:
624-
The returned `OrganizationUser` has the following fields:
625-
626-
- `first_name` (str)
627-
- `last_name` (str)
628-
- `account_id` (str): a uuid
629-
- `email_address` (str)
630-
"""
631-
raise NotImplementedError
632-
633-
@api_method("org.message")
634-
def message(self, name: str, subject: str, body: str) -> dict[str, Any]:
635-
"""
636-
Send a message from you to every account that is a member of
637-
the named organization.
638-
639-
Args:
640-
name (str): name of the organization
641-
subject (str): plain text subject of the message
642-
body (str): markdown body of the message (math typesetting works)
643-
"""
644-
raise NotImplementedError
442+
message: authFirst,
443+
removeUser: authFirst,
444+
removeAdmin: authFirst,
445+
"""

0 commit comments

Comments
 (0)