예제 #1
0
class SiaNode(Schema):
    id = UUID(title="id",
              description="Sia unique identifier.",
              required=True,
              dump_only=True)
    accepting_contracts = Boolean(
        title="accepting_contracts",
        description="True if the host is accepting new contracts.")
    max_download_batch_size = Integer(
        title="max_download_batch_size",
        description=
        "Maximum number of bytes that the host will allow to be requested by a single download request",
    )
    max_duration = Integer(
        title="max_duration",
        description=
        "Maximum duration in blocks that a host will allow for a file contract. The host commits to "
        "keeping files for the full duration under the threat of facing a large penalty for losing or "
        "dropping data before the duration is complete. The storage proof window of an incoming file "
        "contract must end before the current height + maxduration.",
    )
    max_revise_batch_size = Integer(
        title="max_revise_batch_size",
        description=
        "Maximum size in bytes of a single batch of file contract revisions. Larger batch sizes allow for "
        "higher throughput as there is significant communication overhead associated with performing a "
        "batch upload.",
    )
    net_address = String(
        title="net_address",
        description=
        "Remote address of the host. It can be an IPv4, IPv6, or hostname, along with the port. IPv6 "
        "addresses are enclosed in square brackets.",
    )
    remaining_storage = Integer(
        title="remaining_storage",
        description="Unused storage capacity the host claims it has.")
    sector_size = Integer(
        title="sector_size",
        description=
        "Smallest amount of data in bytes that can be uploaded or downloaded to or from the host.",
    )
    total_storage = Integer(
        title="total_storage",
        description="Total amount of storage capacity the host claims it has.")
    unlock_hash = String(
        title="unlock_hash",
        description=
        "Address at which the host can be paid when forming file contracts.")
    window_size = Integer(
        title="window_size",
        description=
        "A storage proof window is the number of blocks that the host has to get a storage proof onto the "
        "blockchain. The window size is the minimum size of window that the host will accept in a file "
        "contract.",
    )
    collateral = String(
        title="collateral",
        description=
        "The maximum amount of money that the host will put up as collateral for storage that is contracted"
        " by the renter.",
    )
    max_collateral = String(
        title="max_collateral",
        description=
        "The maximum amount of collateral that the host will put into a single file contract.",
    )
    contract_price = String(
        title="contract_price",
        description=
        "The price that a renter has to pay to create a contract with the host. The payment is intended "
        "to cover transaction fees for the file contract revision and the storage proof that the host will "
        "be submitting to the blockchain.",
    )
    download_bandwidth_price = String(
        title="download_bandwidth_price",
        description=
        "The price that a renter has to pay when downloading data from the host.",
    )
    storage_price = String(
        title="storage_price",
        description=
        "The price that a renter has to pay to store files with the host.")
    upload_bandwidth_price = String(
        title="upload_bandwidth_price",
        description=
        "The price that a renter has to pay when uploading data to the host.",
    )
    revision_number = Integer(
        title="revision_number",
        description=
        "The revision number indicates to the renter what iteration of settings the host is currently at. "
        "Settings are generally signed. If the renter has multiple conflicting copies of settings from "
        "the host, the renter can expect the one with the higher revision number to be more recent.",
    )
    version = String(title="version", description="The version of the host.")
    first_seen = Integer(
        title="first_seen",
        description=
        "Firstseen is the last block height at which this host was announced.")
    historic_downtime = Integer(
        title="historic_downtime",
        description="Total amount of time the host has been offline.")
    historic_uptime = Integer(
        title="historic_uptime",
        description="Total amount of time the host has been online.")
    historic_failed_interactions = Integer(
        title="historic_failed_interactions",
        description="Number of historic failed interactions with the host.")
    historic_successful_interactions = Integer(
        title="historic_successful_interactions",
        description="Number of historic successful interactions with the host.",
    )
    recent_failed_interactions = Integer(
        title="recent_failed_interactions",
        description="Number of recent failed interactions with the host.")
    recent_successful_interactions = Integer(
        title="recent_successful_interactions",
        description="Number of recent successful interactions with the host.")
    last_historic_update = Integer(
        title="last_historic_update",
        description=
        "The last time that the interactions within scanhistory have been compressed into the historic "
        "ones.",
    )
    public_key_string = String(
        title="public_key_string",
        description=
        "The string representation of the full public key, used when calling /hostdb/hosts.",
    )
    ipnets = List(
        String(),
        title="ipnets",
        description=
        "List of IP subnet masks used by the host. For IPv4 the /24 and for IPv6 the /54 subnet mask is "
        "used. A host can have either one IPv4 or one IPv6 subnet or one of each. E.g. these lists are "
        'valid: [ "IPv4" ], [ "IPv6" ] or [ "IPv4", "IPv6" ]. The following lists are invalid: [ "IPv4", '
        '"IPv4" ], [ "IPv4", "IPv6", "IPv6" ]. Hosts with an invalid list are ignored.',
    )
    address = String(title="address",
                     description="The full address of the node.")
    country = String(title="country",
                     description="The country where the node can be found.")
    city = String(title="city",
                  description="The city where the node can be found.")
    latitude = Float(title="latitude",
                     description="Geolocation latitude coordinate")
    longitude = Float(title="longitude",
                      description="Geolocation longitude coordinate")
예제 #2
0
 class _Schema(Schema):
     registration_number = String(required=True)
     name = String(required=True, allow_none=False)
     age = Integer()
예제 #3
0
 class _Schema(Schema):
     code = String(required=True)
     name = String(required=True)
     credit_hours = Integer()
     has_labs = Boolean(missing=True)
예제 #4
0
class ReservationEventDataSchema(Schema):
    id = Number()
    title = String()
    url = String()
    can_access = Function(lambda event: event.can_access(session.user))
예제 #5
0
from pyramid.security import NO_PERMISSION_REQUIRED
from pyramid.view import view_config
from webargs.pyramidparser import use_kwargs

from tildes.views.decorators import rate_limit_view


@view_config(
    route_name="donate_stripe",
    request_method="POST",
    renderer="donate_stripe.jinja2",
    permission=NO_PERMISSION_REQUIRED,
    require_csrf=False,
)
@use_kwargs({
    "stripe_token": String(required=True),
    "donator_email": Email(required=True),
    "amount": Float(required=True, validate=Range(min=1.0)),
    "currency": String(required=True, validate=OneOf(("CAD", "USD"))),
})
@rate_limit_view("donate")
def post_donate_stripe(request: Request, stripe_token: str, donator_email: str,
                       amount: int, currency: str) -> dict:
    """Process a Stripe donation."""
    try:
        stripe.api_key = request.registry.settings["api_keys.stripe"]
    except KeyError:
        raise HTTPInternalServerError

    payment_successful = True
    try:
예제 #6
0
class ProfileForm(Schema):
    username = String(required=True, allow_none=False,
        validate=[
            Length(min=1, error=_('Username is required')),
            Regexp(r'^[a-zA-Z_\-0-9]+$', error=_('Username cannot contain space and can only contain a-z,_,0-9'))
        ],
        error_messages={
            'required': _('Username is required'),
            'null': _('Username is required')
        }
    )
    password = String(required=False, allow_none=True,
        validate=[
            Length(min=1, error=_('Password is required'))
        ],
        error_messages={
            'required': _('Password is required'),
            'null': _('Password is required')
        }
    )
    confirm_password = String(required=False, allow_none=True,
        validate=[
            Length(min=1, error=_('Confirm Password is required'))
        ],
        error_messages={
            'required': _('Confirm Password is required'),
            'null': _('Confirm Password is required')
        }
    )
    name = String(required=True, allow_none=False,
        validate=[
            Length(min=1, error=_('Name is required'))
        ],
        error_messages={
            'required': _('Name is required'),
            'null': _('Name is required')
        }
    )
    email = String(required=True, allow_none=False,
        validate=[
            Length(min=1, error=_('Email is required')),
            Email(error=_('Invalid email format'))
        ],
        error_messages={
            'required': _('Email is required'),
            'null': _('Email is required')
        }
    )

    class Meta:
        unknown = EXCLUDE

    @validates('username')
    def validate_username(self, username):
        user = self.context.get('user')
        connect_db()
        check = g.db.execute(
            sa.select([User.c.id]).where(
                sa.and_(
                    User.c.username == username,
                    User.c.id != user.id
                )
            )
        ).scalar()

        if check:
            raise ValidationError(_('Username %(username)s already exists. Please input another username.', username=username))

    @validates_schema(skip_on_field_errors=True)
    def validate_confirm_password(self, data, **kwargs):
        password = data.get('password')
        confirm_password = data.get('confirm_password')

        if password and not confirm_password:
            raise ValidationError(_('Confirm password is required'), 'confirm_password')

        if password and confirm_password and confirm_password != password:
            raise ValidationError(_('Confirm password does not match'), 'confirm_password')
    
    @validates('email')
    def validate_email(self, email):
        user = self.context.get('user')
        connect_db()
        check = g.db.execute(
            sa.select([User.c.id]).where(
                sa.and_(
                    User.c.email == email,
                    User.c.id != user.id
                )
            )
        ).scalar()

        if check:
            raise ValidationError(_('Email %(email)s already exists. Please input another email.', email=email))
예제 #7
0
class ChannelsEndpoint(MetadataEndpointBase):
    def __init__(self,
                 download_manager: DownloadManager,
                 gigachannel_manager: GigaChannelManager,
                 gigachannel_community: GigaChannelCommunity,
                 *args, **kwargs):
        MetadataEndpointBase.__init__(self, *args, **kwargs)
        self.download_manager = download_manager
        self.gigachannel_manager = gigachannel_manager
        self.gigachannel_community = gigachannel_community

    def setup_routes(self):
        self.app.add_routes(
            [
                web.get('', self.get_channels),
                web.get(r'/{channel_pk:\w*}/{channel_id:\w*}', self.get_channel_contents),
                web.get(r'/{channel_pk:\w*}/{channel_id:\w*}/description', self.get_channel_description),
                web.put(r'/{channel_pk:\w*}/{channel_id:\w*}/description', self.put_channel_description),
                web.get(r'/{channel_pk:\w*}/{channel_id:\w*}/thumbnail', self.get_channel_thumbnail),
                web.put(r'/{channel_pk:\w*}/{channel_id:\w*}/thumbnail', self.put_channel_thumbnail),
                web.post(r'/{channel_pk:\w*}/{channel_id:\w*}/copy', self.copy_channel),
                web.post(r'/{channel_pk:\w*}/{channel_id:\w*}/channels', self.create_channel),
                web.post(r'/{channel_pk:\w*}/{channel_id:\w*}/collections', self.create_collection),
                web.put(r'/{channel_pk:\w*}/{channel_id:\w*}/torrents', self.add_torrent_to_channel),
                web.post(r'/{channel_pk:\w*}/{channel_id:\w*}/commit', self.post_commit),
                web.get(r'/{channel_pk:\w*}/{channel_id:\w*}/commit', self.is_channel_dirty),
                web.get('/popular_torrents', self.get_popular_torrents_channel),
            ]
        )

    def add_download_progress_to_metadata_list(self, contents_list):
        for torrent in contents_list:
            if torrent['type'] == REGULAR_TORRENT:
                dl = self.download_manager.get_download(unhexlify(torrent['infohash']))
                if dl is not None and dl.tdef.infohash not in self.download_manager.metainfo_requests:
                    torrent['progress'] = dl.get_state().get_progress()

    def get_channel_from_request(self, request):
        channel_pk = (
            self.mds.my_key.pub().key_to_bin()[10:]
            if request.match_info['channel_pk'] == 'mychannel'
            else unhexlify(request.match_info['channel_pk'])
        )
        channel_id = int(request.match_info['channel_id'])
        return channel_pk, channel_id

    @docs(
        tags=['Metadata'],
        summary='Get a list of all channels known to the system.',
        responses={
            200: {
                'schema': schema(
                    GetChannelsResponse={
                        'results': [ChannelSchema],
                        'first': Integer(),
                        'last': Integer(),
                        'sort_by': String(),
                        'sort_desc': Integer(),
                        'total': Integer(),
                    }
                )
            }
        },
    )
    async def get_channels(self, request):
        sanitized = self.sanitize_parameters(request.query)
        sanitized['subscribed'] = None if 'subscribed' not in request.query else bool(int(request.query['subscribed']))
        include_total = request.query.get('include_total', '')
        sanitized.update({"origin_id": 0})
        sanitized['metadata_type'] = CHANNEL_TORRENT

        with db_session:
            channels = self.mds.get_entries(**sanitized)
            total = self.mds.get_total_count(**sanitized) if include_total else None
            channels_list = []
            for channel in channels:
                channel_dict = channel.to_simple_dict()
                # Add progress info for those channels that are still being processed
                if channel.subscribed:
                    if channel_dict["state"] == CHANNEL_STATE.UPDATING.value:
                        try:
                            progress = self.mds.compute_channel_update_progress(channel)
                            channel_dict["progress"] = progress
                        except (ZeroDivisionError, FileNotFoundError) as e:
                            self._logger.error(
                                "Error %s when calculating channel update progress. Channel data: %s-%i %i/%i",
                                e,
                                hexlify(channel.public_key),
                                channel.id_,
                                channel.start_timestamp,
                                channel.local_version,
                            )
                    elif channel_dict["state"] == CHANNEL_STATE.METAINFO_LOOKUP.value:
                        if not self.download_manager.metainfo_requests.get(
                            bytes(channel.infohash)
                        ) and self.download_manager.download_exists(bytes(channel.infohash)):
                            channel_dict["state"] = CHANNEL_STATE.DOWNLOADING.value

                channels_list.append(channel_dict)
        response_dict = {
            "results": channels_list,
            "first": sanitized["first"],
            "last": sanitized["last"],
            "sort_by": sanitized["sort_by"],
            "sort_desc": int(sanitized["sort_desc"]),
        }
        if total is not None:
            response_dict.update({"total": total})
        return RESTResponse(response_dict)

    @docs(
        tags=['Metadata'],
        summary='Get a list of the channel\'s contents (torrents/channels/etc.).',
        responses={
            200: {
                'schema': schema(
                    GetChannelContentsResponse={
                        'results': [MetadataSchema],
                        'first': Integer(),
                        'last': Integer(),
                        'sort_by': String(),
                        'sort_desc': Integer(),
                        'total': Integer(),
                    }
                )
            }
        },
    )
    async def get_channel_contents(self, request):
        sanitized = self.sanitize_parameters(request.query)
        include_total = request.query.get('include_total', '')
        channel_pk, channel_id = self.get_channel_from_request(request)
        sanitized.update({"channel_pk": channel_pk, "origin_id": channel_id})
        remote = sanitized.pop("remote", None)

        total = None

        remote_failed = False
        if remote:
            try:
                contents_list = await self.gigachannel_community.remote_select_channel_contents(**sanitized)
            except (RequestTimeoutException, NoChannelSourcesException, CancelledError):
                remote_failed = True

        if not remote or remote_failed:
            with db_session:
                contents = self.mds.get_entries(**sanitized)
                contents_list = [c.to_simple_dict() for c in contents]
                total = self.mds.get_total_count(**sanitized) if include_total else None
        self.add_download_progress_to_metadata_list(contents_list)
        self.add_tags_to_metadata_list(contents_list, hide_xxx=sanitized["hide_xxx"])
        response_dict = {
            "results": contents_list,
            "first": sanitized['first'],
            "last": sanitized['last'],
            "sort_by": sanitized['sort_by'],
            "sort_desc": int(sanitized['sort_desc']),
        }
        if total is not None:
            response_dict.update({"total": total})

        return RESTResponse(response_dict)

    async def get_channel_description(self, request):
        channel_pk, channel_id = self.get_channel_from_request(request)
        with db_session:
            channel_description = self.mds.ChannelDescription.select(
                lambda g: g.public_key == channel_pk and g.origin_id == channel_id
            ).first()

        response_dict = json.loads(channel_description.json_text) if (channel_description is not None) else {}
        return RESTResponse(response_dict)

    async def put_channel_description(self, request):
        channel_pk, channel_id = self.get_channel_from_request(request)
        request_parsed = await request.json()
        updated_json_text = json.dumps({"description_text": request_parsed["description_text"]})
        with db_session:
            channel_description = self.mds.ChannelDescription.select(
                lambda g: g.public_key == channel_pk and g.origin_id == channel_id
            ).first()
            if channel_description is not None:
                channel_description.update_properties({"json_text": updated_json_text})
            else:
                channel_description = self.mds.ChannelDescription(
                    public_key=channel_pk, origin_id=channel_id, json_text=updated_json_text, status=NEW
                )
        return RESTResponse(json.loads(channel_description.json_text))

    async def get_channel_thumbnail(self, request):
        channel_pk, channel_id = self.get_channel_from_request(request)
        with db_session:
            obj = self.mds.ChannelThumbnail.select(
                lambda g: g.public_key == channel_pk and g.origin_id == channel_id
            ).first()
        return web.Response(body=obj.binary_data, content_type=obj.data_type) if obj else web.Response(status=400)

    async def put_channel_thumbnail(self, request):
        content_type = request.headers["Content-Type"]
        post_body = await request.read()
        channel_pk, channel_id = self.get_channel_from_request(request)
        obj_properties = {"binary_data": post_body, "data_type": content_type}
        with db_session:
            obj = self.mds.ChannelThumbnail.select(
                lambda g: g.public_key == channel_pk and g.origin_id == channel_id,
            ).first()
            if obj is not None:
                obj.update_properties(obj_properties)
            else:
                self.mds.ChannelThumbnail(public_key=channel_pk, origin_id=channel_id, status=NEW, **obj_properties)
        return web.Response(status=201)

    @docs(
        tags=['Metadata'],
        summary='Create a copy of an entry/entries from another channel.',
        parameters=[
            {
                'in': 'body',
                'name': 'entries',
                'description': 'List of entries to copy',
                'example': [{'public_key': '1234567890', 'id': 123}],
                'required': True,
            }
        ],
        responses={
            200: {'description': 'Returns a list of copied content'},
            HTTP_NOT_FOUND: {'schema': HandledErrorSchema, 'example': {"error": "Target channel not found"}},
            HTTP_BAD_REQUEST: {'schema': HandledErrorSchema, 'example': {"error": "Source entry not found"}},
        },
    )
    async def copy_channel(self, request):
        with db_session:
            channel_pk, channel_id = self.get_channel_from_request(request)
            personal_root = channel_id == 0 and channel_pk == self.mds.my_key.pub().key_to_bin()[10:]
            # TODO: better error handling
            target_collection = self.mds.CollectionNode.get(public_key=channel_pk, id_=channel_id)
            try:
                request_parsed = await request.json()
            except (ContentTypeError, ValueError):
                return RESTResponse({"error": "Bad JSON"}, status=HTTP_BAD_REQUEST)

            if not target_collection and not personal_root:
                return RESTResponse({"error": "Target channel not found"}, status=HTTP_NOT_FOUND)
            results_list = []
            for entry in request_parsed:
                public_key, id_ = unhexlify(entry["public_key"]), entry["id"]
                source = self.mds.ChannelNode.get(public_key=public_key, id_=id_)
                if not source:
                    return RESTResponse({"error": "Source entry not found"}, status=HTTP_BAD_REQUEST)
                # We must upgrade Collections to Channels when moving them to root channel, and, vice-versa,
                # downgrade Channels to Collections when moving them into existing channels
                if isinstance(source, self.mds.CollectionNode):
                    src_dict = source.to_dict()
                    if channel_id == 0:
                        rslt = self.mds.ChannelMetadata.create_channel(title=source.title)
                    else:
                        dst_dict = {'origin_id': channel_id, "status": NEW}
                        for k in self.mds.CollectionNode.nonpersonal_attributes:
                            dst_dict[k] = src_dict[k]
                        dst_dict.pop("metadata_type")
                        rslt = self.mds.CollectionNode(**dst_dict)
                    for child in source.actual_contents:
                        child.make_copy(rslt.id_)
                else:
                    rslt = source.make_copy(channel_id)
                results_list.append(rslt.to_simple_dict())
            return RESTResponse(results_list)

    @docs(
        tags=['Metadata'],
        summary='Create a new channel entry in the given channel.',
        responses={
            200: {
                'description': 'Returns the newly created channel',
                'schema': schema(CreateChannelResponse={'results': [ChannelSchema]}),
            }
        },
    )
    async def create_channel(self, request):
        with db_session:
            _, channel_id = self.get_channel_from_request(request)
            request_parsed = await request.json()
            channel_name = request_parsed.get("name", "New channel")
            md = self.mds.ChannelMetadata.create_channel(channel_name, origin_id=channel_id)
            return RESTResponse({"results": [md.to_simple_dict()]})

    @docs(
        tags=['Metadata'],
        summary='Create a new collection entry in the given channel.',
        responses={
            200: {
                'description': 'Returns the newly created collection',
                'schema': schema(CreateCollectionResponse={'results': [ChannelSchema]}),
            }
        },
    )
    async def create_collection(self, request):
        with db_session:
            _, channel_id = self.get_channel_from_request(request)
            request_parsed = await request.json()
            collection_name = request_parsed.get("name", "New collection")
            md = self.mds.CollectionNode(origin_id=channel_id, title=collection_name, status=NEW)
            return RESTResponse({"results": [md.to_simple_dict()]})

    @docs(
        tags=['Metadata'],
        summary='Add a torrent file to your own channel.',
        responses={
            200: {
                'schema': schema(
                    AddTorrentToChannelResponse={'added': (Integer, 'Number of torrent that were added to the channel')}
                )
            },
            HTTP_NOT_FOUND: {'schema': HandledErrorSchema, 'example': {"error": "Unknown channel"}},
            HTTP_BAD_REQUEST: {'schema': HandledErrorSchema, 'example': {"error": "unknown uri type"}},
        },
    )
    @json_schema(
        schema(
            AddTorrentToChannelRequest={
                'torrent': (String, 'Base64-encoded torrent file'),
                'uri': (String, 'Add a torrent from a magnet link or URL'),
                'torrents_dir': (String, 'Add all .torrent files from a chosen directory'),
                'recursive': (Boolean, 'Toggle recursive scanning of the chosen directory for .torrent files'),
                'description': (String, 'Description for the torrent'),
            }
        )
    )
    async def add_torrent_to_channel(self, request):
        channel_pk, channel_id = self.get_channel_from_request(request)
        with db_session:
            channel = self.mds.CollectionNode.get(public_key=channel_pk, id_=channel_id)
        if not channel:
            return RESTResponse({"error": "Unknown channel"}, status=HTTP_NOT_FOUND)

        parameters = await request.json()

        extra_info = {}
        if parameters.get('description', None):
            extra_info = {'description': parameters['description']}

        # First, check whether we did upload a magnet link or URL
        if parameters.get('uri', None):
            uri = parameters['uri']
            if uri.startswith("http:") or uri.startswith("https:"):
                data = await _fetch_uri(uri)
                tdef = TorrentDef.load_from_memory(data)
            elif uri.startswith("magnet:"):
                _, xt, _ = parse_magnetlink(uri)
                if (
                    xt
                    and is_infohash(codecs.encode(xt, 'hex'))
                    and (self.mds.torrent_exists_in_personal_channel(xt) or channel.copy_torrent_from_infohash(xt))
                ):
                    return RESTResponse({"added": 1})

                meta_info = await self.download_manager.get_metainfo(xt, timeout=30, url=uri)
                if not meta_info:
                    raise RuntimeError("Metainfo timeout")
                tdef = TorrentDef.load_from_dict(meta_info)
            else:
                return RESTResponse({"error": "unknown uri type"}, status=HTTP_BAD_REQUEST)

            added = 0
            if tdef:
                channel.add_torrent_to_channel(tdef, extra_info)
                added = 1
            return RESTResponse({"added": added})

        torrents_dir = None
        if parameters.get('torrents_dir', None):
            torrents_dir = parameters['torrents_dir']
            if not Path(torrents_dir).is_absolute():
                return RESTResponse({"error": "the torrents_dir should point to a directory"}, status=HTTP_BAD_REQUEST)

        recursive = False
        if parameters.get('recursive'):
            recursive = parameters['recursive']
            if not torrents_dir:
                return RESTResponse(
                    {"error": "the torrents_dir parameter should be provided when the recursive parameter is set"},
                    status=HTTP_BAD_REQUEST,
                )

        if torrents_dir:
            torrents_list, errors_list = channel.add_torrents_from_dir(torrents_dir, recursive)
            return RESTResponse({"added": len(torrents_list), "errors": errors_list})

        if not parameters.get('torrent', None):
            return RESTResponse({"error": "torrent parameter missing"}, status=HTTP_BAD_REQUEST)

        # Try to parse the torrent data
        # Any errors will be handled by the error_middleware
        torrent = base64.b64decode(parameters['torrent'])
        torrent_def = TorrentDef.load_from_memory(torrent)
        channel.add_torrent_to_channel(torrent_def, extra_info)
        return RESTResponse({"added": 1})

    @docs(
        tags=['Metadata'],
        summary='Commit a channel.',
        responses={200: {'schema': schema(CommitResponse={'success': Boolean()})}},
    )
    async def post_commit(self, request):
        channel_pk, channel_id = self.get_channel_from_request(request)
        with db_session:
            if channel_id == 0:
                for t in self.mds.CollectionNode.commit_all_channels():
                    self.gigachannel_manager.updated_my_channel(TorrentDef.load_from_dict(t))
            else:
                coll = self.mds.CollectionNode.get(public_key=channel_pk, id_=channel_id)
                if not coll:
                    return RESTResponse({"success": False}, status=HTTP_NOT_FOUND)
                torrent_dict = coll.commit_channel_torrent()
                if torrent_dict:
                    self.gigachannel_manager.updated_my_channel(TorrentDef.load_from_dict(torrent_dict))

        return RESTResponse({"success": True})

    @docs(
        tags=['Metadata'],
        summary='Check if a channel has uncommitted changes.',
        responses={200: {'schema': schema(IsChannelDirtyResponse={'dirty': Boolean()})}},
    )
    async def is_channel_dirty(self, request):
        channel_pk, _ = self.get_channel_from_request(request)
        with db_session:
            dirty = self.mds.MetadataNode.exists(lambda g: g.public_key == channel_pk and g.status in DIRTY_STATUSES)
            return RESTResponse({"dirty": dirty})

    @docs(
        tags=['Metadata'],
        summary='Get the list of most popular torrents. Functions as a pseudo-channel.',
        responses={
            200: {
                'schema': schema(
                    GetPopularTorrentsResponse={
                        'results': [TorrentSchema],
                        'first': Integer(),
                        'last': Integer(),
                    }
                )
            }
        },
    )
    async def get_popular_torrents_channel(self, request):
        sanitized = self.sanitize_parameters(request.query)
        sanitized["metadata_type"] = REGULAR_TORRENT
        sanitized["popular"] = True

        with db_session:
            contents = self.mds.get_entries(**sanitized)
            contents_list = [c.to_simple_dict() for c in contents]
        self.add_download_progress_to_metadata_list(contents_list)
        self.add_tags_to_metadata_list(contents_list, hide_xxx=sanitized["hide_xxx"])
        response_dict = {
            "results": contents_list,
            "first": sanitized['first'],
            "last": sanitized['last'],
        }

        return RESTResponse(response_dict)
예제 #8
0
class TourBookingUpdateRequestSchema(BaseRequestSchema):
    status = String(required=False, allow_none=True)
    image_witness = String(data_key='imageWitness',
                           required=False,
                           allow_none=True)
예제 #9
0
파일: schemas.py 프로젝트: talee/ubuntu.com
class Status(Schema):
    release_codename = ReleaseCodename(required=True)
    status = String(required=True)
    description = String(allow_none=True)
    component = Component(required=False)
    pocket = Pocket(required=False)
예제 #10
0
 class Schema:
     silly = String(required=True)
예제 #11
0
    def post():
        arg_fields = {
            'scheduled_user_id': String(required=True),
            'localized_start_time': String(required=True),
            'localized_end_time': String(required=True),
            'local_tz': String(
                required=True,
                validate=validate.OneOf(pytz.all_timezones)
            ),
            'notes': String(
                required=False,
                validate=validate.Length(max=512),
                missing=None,
                default=None
            ),
            'is_paid': Boolean(default=True, missing=True),
            'nonce': String(
                required=False,
                default='',
                missing='',
            ),
            'address_id': String(
                required=False,
            )
        }
        args = parser.parse(arg_fields)
        args['scheduling_user_id'] = g.user_info['user_id']

        if args['is_paid']:
            if args.get('nonce') is None or args.get('nonce') == '':
                raise EndpointException(
                    'For paid scheduling, a payment nonce must be supplied.'
                )

            del args['is_paid']
            event_info = EventFacade().create_new_event(**args)
        else:
            if not current_app.config.get('TESTING'):
                logging.error(
                    'Attempted to create unpaid event in prod: {0}'.format(
                        args
                    )
                )
                raise EndpointException(
                    'Non-paid events are not allowed.'
                )

            del args['is_paid']
            del args['nonce']
            event_info = EventDAO().create_new_event(
                **args
            )

        logging.info(
            'Created event for user {0} with user {1} for time range: {2}->{3}'
            'at timezone {4}.',
            args['scheduling_user_id'],
            args['scheduling_user_id'],
            args['localized_start_time'],
            args['localized_end_time'],
            args['local_tz']
        )

        return jsonify(EventMarshal().dump(event_info).data)
예제 #12
0
파일: entities.py 프로젝트: roukdanus/aleph
class ShallowCombinedSchema(BaseSchema):
    collection_id = String()

    # Joint entity/document attributes
    collection = Nested(CollectionSchema())
    schema = SchemaName()
    schemata = List(SchemaName())
    names = List(String())
    addresses = List(String())
    phones = List(String())
    emails = List(String())
    identifiers = List(String())
    countries = List(Country())
    dates = List(PartialDate())
    bulk = Boolean()

    # Entity attributes
    foreign_id = String()
    name = String()
    entities = List(String())
    properties = Dict()

    # Document attributes
    status = String()
    content_hash = String()
    uploader_id = String()
    uploader = Nested(RoleReferenceSchema())
    error_message = String()
    title = String()
    summary = String()
    languages = List(Language())
    keywords = List(String())
    date = PartialDate()
    authored_at = PartialDate()
    modified_at = PartialDate()
    published_at = PartialDate()
    retrieved_at = PartialDate()
    file_name = String()
    file_size = Integer()
    author = String()
    generator = String()
    mime_type = String()
    extension = String()
    encoding = String()
    source_url = String()
    pdf_version = String()
    columns = List(String())
    headers = Dict()
    children = Integer()

    # TODO: is this a separate endpoint?
    text = String()
    html = String()

    def document_links(self, data, pk, schemata):
        links = {
            'self': url_for('documents_api.view', document_id=pk),
            'tags': url_for('entities_api.tags', id=pk),
            'ui': document_url(pk)
        }
        if data.get('content_hash'):
            links['file'] = url_for('documents_api.file',
                                    document_id=pk,
                                    _authorize=True)
        if schemata.intersection([Document.SCHEMA_PDF]):
            links['pdf'] = url_for('documents_api.pdf',
                                   document_id=pk,
                                   _authorize=True)
        if schemata.intersection([Document.SCHEMA_PDF, Document.SCHEMA_TABLE]):
            links['records'] = url_for('documents_api.records', document_id=pk)
        if schemata.intersection([Document.SCHEMA_FOLDER]):
            query = (('filter:parent.id', pk), )
            links['children'] = url_for('documents_api.index', _query=query)
        return links

    def entity_links(self, data, pk, schemata):
        return {
            'self': url_for('entities_api.view', id=pk),
            # 'similar': url_for('entities_api.similar', id=pk),
            # 'documents': url_for('entities_api.documents', id=pk),
            'references': url_for('entities_api.references', id=pk),
            'tags': url_for('entities_api.tags', id=pk),
            'ui': entity_url(pk)
        }

    @post_dump
    def hypermedia(self, data):
        pk = str(data.get('id'))
        collection = data.get('collection', {})
        collection_id = collection.get('id')
        collection_id = collection_id or data.get('collection_id')
        schemata = set(data.get('schemata', []))
        if Document.SCHEMA in schemata:
            data['links'] = self.document_links(data, pk, schemata)
        else:
            data['links'] = self.entity_links(data, pk, schemata)

        if data.get('bulk'):
            data['writeable'] = False
        else:
            data['writeable'] = request.authz.can_write(collection_id)
        return data
예제 #13
0
파일: entities.py 프로젝트: roukdanus/aleph
class DocumentParentSchema(Schema):
    id = String(allow_none=True)
    foreign_id = String(allow_none=True)
예제 #14
0
파일: entities.py 프로젝트: roukdanus/aleph
class EntityUpdateSchema(Schema):
    name = String(allow_none=True)
    schema = SchemaName(required=True)
    properties = Dict()
예제 #15
0
class PlanSchema(Schema):
    id = Integer(dump_only=True)
    name = String(validate=Length(1, 64), required=True)
    created_at = DateTime(dump_only=True)
    updated_at = DateTime(dump_only=True)
    deleted_at = DateTime(dump_only=True)
예제 #16
0
파일: schemas.py 프로젝트: talee/ubuntu.com
class CvePackage(Schema):
    name = String(required=True)
    source = String(required=True)
    ubuntu = String(required=True)
    debian = String(required=True)
    statuses = List(Nested(Status))
    def post(self, user_id):
        arg_fields = {
            'individual':
            Nested({
                'first_name':
                String(required=True),
                'last_name':
                String(required=False),
                'email':
                String(required=True),
                'phone':
                String(),
                # TODO(ian): Do we need to assert this is > 18 years old?
                'date_of_birth':
                DateTime(required=True),
                'address':
                Nested(
                    {
                        'street_address': String(required=True),
                        'locality': String(required=True),
                        'region': String(required=True),
                        'postal_code': String(required=True)
                    },
                    required=True)
            }),

            # NOTE: Business is only required if requesting user is
            # registering on behalf of a business.
            'business':
            Nested({
                'legal_name':
                String(required=True),
                'dba_name':
                String(required=True),
                # TODO(ian): Only required if `legal_name` is added above.
                'tax_id':
                String(required=True),
                'address':
                Nested({
                    'street_address': String(required=True),
                    'locality': String(required=True),
                    'region': String(required=True),
                    'postal_code': String(required=True)
                })
            }),
            'funding':
            Nested({
                # TODO(ian): Set something here. The name of my company?
                'descriptor': String(missing=''),
                'account_number': String(required=True),
                'routing_number': String(required=True),
            }),
            'tos_accepted':
            Boolean(required=True,
                    default=False,
                    missing=False,
                    validate=validate.OneOf([True])),
            'register_as_business':
            Boolean(
                required=True,
                default=False,
                missing=False,
            )
        }
        args = parser.parse(arg_fields)

        if args['register_as_business'] and args.get('business') is None:
            raise EndpointException(
                'Whenever registering as a business, business information '
                'must be supplied.')

        SubmerchantFacade().create_submerchant(args, user_id)

        logging.info('Successfully created submerchant for email {0} on User '
                     '{1}.'.format(args['individual']['email'], user_id))

        return jsonify({'success': True})
예제 #18
0
파일: schemas.py 프로젝트: talee/ubuntu.com
class Note(Schema):
    author = String(required=True)
    note = String(required=True)
 class SchemaWithDict(Schema):
     dict_field = Dict(values=String())
예제 #20
0
파일: schemas.py 프로젝트: talee/ubuntu.com
class CVESchema(Schema):
    id = String(required=True)
    published = ParsedDateTime(allow_none=True)
    description = String(allow_none=True)
    ubuntu_description = String(allow_none=True)
    notes = List(Nested(Note))
    priority = String(allow_none=True)
    status = String(allow_none=True)
    cvss3 = Float(allow_none=True)
    packages = List(Nested(CvePackage))
    references = List(String())
    bugs = List(String())
    patches = Dict(keys=String(),
                   values=List(String(), required=False),
                   allow_none=True)
    tags = Dict(keys=String(),
                values=List(String(), required=False),
                allow_none=True)
예제 #21
0
class RoomAttributesSchema(mm.ModelSchema):
    title = String(attribute='attribute.title')

    class Meta:
        model = RoomAttributeAssociation
        fields = ('value', 'title')
예제 #22
0
class LoggedInUserPasswordSchema(marshmallow.Schema):
    loggedin_user_password = String(required=True, validate=user_password_validator)
예제 #23
0
class QuestionLoaderSchema(Schema):
    id = Integer()
    order = Integer()
    question = String()
    options = Dict()
    type = String()
    subQuestions = Nested("self", many=True)

    @validates_schema
    def validate_schema(self, data):
        if data.get("id") is not None:

            if data.get("question") is None:
                raise ValidationError(
                    "you must provide the text for the question to create the question",
                    "question")

            if data.get("type") is None:
                raise ValidationError(
                    "you must provide the type of the question", "type")

            if (data.get("type") is not None
                    and (data["type"] == "matrix" or data["type"] == "ranking")
                    and data.get("subQuestions") is None):
                raise ValidationError(
                    "you must provide at least one sub question for matrix and ranking type questions",
                    "subQuestions")

    @post_load
    def load_question(self, data):
        session = get_db()
        if data.get("id") is not None:
            question = session.query(QuestionModel).filter_by(
                id=data["id"]).one_or_none()
            if question is None:
                raise ValidationError(
                    f"The id {data[id]} for the question you have provided does not exist",
                    "id")
        else:
            question = QuestionModel()

        if data.get("question") is not None:
            question.question = data["question"]
        if data.get("type") is not None:
            type = session.query(QuestionTypeModel).filter_by(
                type=data['type']).one_or_none()
            if type is None:
                raise ValidationError("The type " + data.get("type") +
                                      "is not supported")
            else:
                question.type = type

        if data.get("options") is not None:
            question.options = data["options"]

        if data.get("subQuestions") is not None:
            if question.type.type != "matrix" and question.type.type != "ranking":
                raise ValidationError(
                    "Only matrix and ranking type questions may have sub questions"
                )
            for sub in question.subQuestions:
                if sub not in data["subQuestions"]:
                    sub.status = "deactive"
            for sub in data['subQuestions']:
                if sub['object'] not in question.subQuestions:
                    question.subQuestions.append(sub['object'])
                elif sub.status == "deactive":
                    sub.status = "active"

            for sub in data['subQuestions']:
                if sub.get('order') is not None:
                    question.set_item_order(sub['order'], sub['object'])

        elif (question.type.type == "matrix"
              or question.type.type == "ranking"):
            for sub in question.subQuestions:
                if sub.status == "active":
                    sub.status == "deactive"
            question.status = "deactive"

        # handle the case of matrix and ranking questions
        # the sub questions of these types need the parent questionKey as a prefix
        if (question.questionKey is None and question.type.type == "matrix"
                and question.type.type == "ranking"):
            for sub in question.subQuestions:
                if sub.questionKey is None:
                    sub.set_prefix(question.questionKey)

        deserialized_return = {"object": question}

        if data.get("order") is not None:
            deserialized_return['order'] = data['order']

        return deserialized_return
예제 #24
0
 def __init__(self, *args, **kwargs):
     String.__init__(self, *args, **kwargs)
     # Insert validation into self.validators so that multiple errors can be
     # stored.
     self.validators.insert(0, RFCEmailValidator(error=self.error_messages["invalid"]))
예제 #25
0
class ReservationUserEventSchema(mm.Schema):
    id = Number()
    title = String()
    url = String()
    start_dt = DateTime()
    end_dt = DateTime()
예제 #26
0
class HandledErrorSchema(Schema):
    error = String(description='Optional field describing any failures that may have occurred', required=True)
예제 #27
0
 class _Schema(Schema):
     employee_id = String(required=True)
     name = String(required=True)
예제 #28
0
class EventSchema(BaseSchema):
    name = String()
    template = String()
    params = ParamTypes()
예제 #29
0
 class _Schema(Schema):
     expertise_level = String(options=["expert", "intermediate", "basic"])
예제 #30
0
    request.db_session.add(Log(LogEventType.USER_EMAIL_SET, request, log_info))

    user.email_address = email_address
    user.email_address_note = email_address_note

    return Response("Your email address has been updated")


@ic_view_config(
    route_name="user",
    request_method="POST",
    request_param="ic-trigger-name=enable-two-factor",
    renderer="two_factor_enabled.jinja2",
    permission="change_settings",
)
@use_kwargs({"code": String()}, location="form")
def post_enable_two_factor(request: Request, code: str) -> dict:
    """Enable two-factor authentication for the user."""
    user = request.context

    if not user.is_correct_two_factor_code(code):
        raise HTTPUnprocessableEntity("Invalid code, please try again.")

    request.user.two_factor_enabled = True

    # Generate 10 backup codes (16 lowercase letters each)
    request.user.two_factor_backup_codes = [
        "".join(random.choices(string.ascii_lowercase, k=16))
        for _ in range(10)
    ]