@@ -1214,6 +1214,72 @@ def get_namespace(self, namespace, exit_on_error=True):
12141214 return user_details
12151215 return None
12161216
1217+ def split_name (self , parameter_name , value , state , separator = "/" ):
1218+ """Split the namespace and the base name from a full name.
1219+
1220+ :param parameter_name: The name of the parameter being parsed. Used
1221+ only to display in the error message.
1222+ :type parameter_name: str
1223+ :param value: The value to split. Usually a namespace and a repository
1224+ (``production/smallimage`` for example), or a robot
1225+ account (``production+myrobot`` for example)
1226+ :type value: str
1227+ :param state: Whether it is a create/update (``present``) operation, or
1228+ a delete (``absent``) operation.
1229+ :type state: str
1230+ :param separator: The separator character between the namespace and the
1231+ object.
1232+ :type separator: str
1233+
1234+ :return: A list. The first item is the namespace, which can be a
1235+ personal namespace. The second item in the object name in the
1236+ namespace (usually a repository name or a robot account name).
1237+ The last item is a Boolean that indicates if the namespace is
1238+ an organization (``True``), or a personal namespace
1239+ (``False``).
1240+ :rtype: list
1241+ """
1242+ # Extract namespace and name from the parameter
1243+ my_name = self .who_am_i ()
1244+ try :
1245+ namespace , shortname = value .split (separator , 1 )
1246+ except ValueError :
1247+ # No namespace part in the name. Therefore, use the user's personal
1248+ # namespace
1249+ if my_name :
1250+ namespace = my_name
1251+ shortname = value
1252+ else :
1253+ self .fail_json (
1254+ msg = (
1255+ "The `{param}' parameter must include the"
1256+ " organization: <organization>{sep}{name}."
1257+ ).format (param = parameter_name , sep = separator , name = value )
1258+ )
1259+
1260+ # Check whether namespace exists (organization or user account)
1261+ namespace_details = self .get_namespace (namespace )
1262+ if not namespace_details :
1263+ if state == "absent" :
1264+ self .exit_json (changed = False )
1265+ self .fail_json (
1266+ msg = "The {namespace} namespace does not exist." .format (namespace = namespace )
1267+ )
1268+ # Make sure that the current user is the owner of that namespace
1269+ if (
1270+ not namespace_details .get ("is_organization" )
1271+ and namespace_details .get ("name" ) != my_name
1272+ ):
1273+ if my_name :
1274+ msg = "You ({user}) are not the owner of {namespace}'s namespace." .format (
1275+ user = my_name , namespace = namespace
1276+ )
1277+ else :
1278+ msg = "You cannot access {namespace}'s namespace." .format (namespace = namespace )
1279+ self .fail_json (msg = msg )
1280+
1281+ return (namespace , shortname , namespace_details .get ("is_organization" , False ))
1282+
12171283 def get_tags (self , namespace , repository , tag = None , digest = None , only_active_tags = True ):
12181284 """Return the list of tags for the given repository.
12191285
@@ -1419,6 +1485,51 @@ def process_prune_parameters(
14191485 )
14201486 return data
14211487
1488+ def str_period_to_second (self , parameter_name , value ):
1489+ """Convert a period string into seconds.
1490+
1491+ :param parameter_name: The name of the parameter being parsed. Used
1492+ only to display in the error message.
1493+ :type parameter_name: str
1494+ :param value: The value to convert into seconds. The value accepts
1495+ the ``s``, ``m``, ``h``, ``d``, and ``w`` suffixes, or no
1496+ suffix, and can contain spaces.
1497+ Parsing is case-insensitive.
1498+ :type value: str
1499+
1500+ :return: The session token.
1501+ :rtype: int
1502+ """
1503+ try :
1504+ return int (value )
1505+ except ValueError :
1506+ # Second
1507+ m = re .match (r"\s*(\d+)\s*s" , value , re .IGNORECASE )
1508+ if m :
1509+ return int (m .group (1 ))
1510+ # Minute
1511+ m = re .match (r"\s*(\d+)\s*m" , value , re .IGNORECASE )
1512+ if m :
1513+ return int (m .group (1 )) * 60
1514+ # Hour
1515+ m = re .match (r"\s*(\d+)\s*h" , value , re .IGNORECASE )
1516+ if m :
1517+ return int (m .group (1 )) * 60 * 60
1518+ # Day
1519+ m = re .match (r"\s*(\d+)\s*d" , value , re .IGNORECASE )
1520+ if m :
1521+ return int (m .group (1 )) * 60 * 60 * 24
1522+ # Week
1523+ m = re .match (r"\s*(\d+)\s*w" , value , re .IGNORECASE )
1524+ if m :
1525+ return int (m .group (1 )) * 60 * 60 * 24 * 7
1526+ self .fail_json (
1527+ msg = (
1528+ "Wrong format for the `{param}' parameter: {value} is not an"
1529+ " integer followed by the s, m, h, d, or w suffix."
1530+ ).format (param = parameter_name , value = value )
1531+ )
1532+
14221533
14231534class APIModuleNoAuth (APIModule ):
14241535 AUTH_ARGSPEC = dict (
0 commit comments