Beispiel #1
0
        /// <summary>
        /// Método que encontra uma conta, refrescando o token, e cria uma sessão de upload.
        /// </summary>
        /// <param name="size">tamanho do ficheiro.</param>
        /// <param name="name">nome do ficheiro.</param>
        /// <returns>Retorna Json consoante o sucesso ou insucesso da criação da sessão de upload.</returns>
        public async Task <IActionResult> UploadSession(long size, string name)
        {
            #region Encontrar conta e refrescar token
            ContaOnedrive conta = await _onedrive.GetAccountToUploadAsync(size);

            if (conta == null)
            {
                return(Json(new { success = false, details = "Já não existe contas com espaço sufeciente." }));
            }
            #endregion

            #region Criar sessão de upload
            string uploadUrl = await _onedrive.GetUploadSessionAsync(conta, name);

            switch (uploadUrl)
            {
            case "Error":
                return(Json(new { success = false, details = "Não foi possível criar sessão de upload." }));

            case "API":
                return(Json(new { success = false, details = "A API da OneDrive não conseguiu criar sessão de Upload." }));

            default:
                return(Json(new { success = true, url = uploadUrl, contaId = conta.ID }));
            }
            #endregion
        }
Beispiel #2
0
        public async Task <IActionResult> RegisterFile(string galeriaId, string fileOnedriveId, string fileOnedriveName, int contaId)
        {
            #region Adicionar foto à Bd
            try
            {
                // Certificar que a conta existe
                ContaOnedrive conta = await _context.ContasOnedrive.FindAsync(contaId);

                if (conta == null)
                {
                    return(Json(new { success = false }));
                }

                // Criar e guardar a fotografia
                Fotografia foto = new Fotografia
                {
                    Nome            = fileOnedriveName,
                    ItemId          = fileOnedriveId,
                    ContaOnedriveFK = contaId,
                    GaleriaFK       = galeriaId,
                    Formato         = GetFileFormat(fileOnedriveName)
                };

                await _context.AddAsync(foto);

                await _context.SaveChangesAsync();

                // Atualizar a informação do espaço da conta
                await _onedrive.UpdateDriveQuotaAsync(conta);

                List <Fotografia> fotos = new List <Fotografia>();
                fotos.Add(await _context.Fotografias.Include(f => f.ContaOnedrive).FirstOrDefaultAsync(f => f.ID == foto.ID));

                await _onedrive.RefreshPhotoUrlsAsync(fotos);

                // Encontrar index da fotografia para fornecer ao photoSwipe
                Galeria galeria = await _context.Galerias.Include(g => g.Fotografias).FirstOrDefaultAsync(g => g.ID.Equals(galeriaId));

                int index = galeria.Fotografias.Count() - 1;

                var response = new ThumbnailsViewModel
                {
                    Fotos = fotos,
                    Index = index
                };

                return(PartialView("PartialViews/_ListPhotos", response));
            }
            catch (Exception)
            {
                return(Json(new { success = false }));
            }
            #endregion
        }
Beispiel #3
0
        public async Task <IActionResult> Edit(int id, [Bind("ID,Username,Password")] ContaOnedrive contaOnedrive)
        {
            if (id != contaOnedrive.ID)
            {
                return(NotFound());
            }

            ContaOnedrive conta = null;

            try
            {
                conta = await _context.ContasOnedrive.FindAsync(id);
            }
            catch (Exception)
            {
                // Feeback ao utilizador - Vai ser redirecionado para o Index
                TempData["Feedback"] = "Não foi possível editar a conta.";
                TempData["Type"]     = "error";
                return(RedirectToAction("Index"));
            }

            if (ModelState.IsValid)
            {
                try
                {
                    // Garantir que apenas estes dados são alterados
                    conta.Username = contaOnedrive.Username;
                    conta.Password = contaOnedrive.Password;
                    _context.Update(conta);
                    await _context.SaveChangesAsync();
                }
                catch (DbUpdateConcurrencyException e)
                {
                    if (!ContaOnedriveExists(conta.ID))
                    {
                        return(NotFound());
                    }
                    else
                    {
                        await _logger.LogError(
                            descricao : "Erro ao guardar na BD.",
                            classe : "ContasOnedriveController",
                            metodo : "Edit",
                            erro : e.Message
                            );
                    }
                }
                // Feeback ao utilizador - Vai ser redirecionado para o Index
                TempData["Feedback"] = "Conta editada com sucesso.";
                TempData["Type"]     = "success";
                return(RedirectToAction("Index"));
            }
            return(View(contaOnedrive));
        }
Beispiel #4
0
        public async Task <IActionResult> Delete(int id)
        {
            ContaOnedrive contaOnedrive = null;

            try
            {
                contaOnedrive = await _context.ContasOnedrive.Include(c => c.Fotografias).Where(c => c.ID == id).FirstOrDefaultAsync();
            }
            catch (Exception e)
            {
                await _logger.LogError(
                    descricao : "Erro ao encontrar a conta Onedrive.",
                    classe : "ContasOnedriveController",
                    metodo : "Delete",
                    erro : e.Message
                    );

                return(Json(new { success = false }));
            }

            // Apenas deixar apagar a conta caso não existam fotografias na conta
            if (contaOnedrive != null && contaOnedrive.Fotografias.Count() == 0)
            {
                try
                {
                    _context.Remove(contaOnedrive);
                    await _context.SaveChangesAsync();
                }
                catch (Exception e)
                {
                    await _logger.LogError(
                        descricao : "Erro ao eliminar conta Onedrive.",
                        classe : "ContasOnedriveController",
                        metodo : "Delete",
                        erro : e.Message
                        );

                    return(Json(new { success = false }));
                }

                // Feeback ao utilizador - Vai ser redirecionado para o Index
                TempData["Feedback"] = "Conta Onedrive eliminada com sucesso.";
                TempData["Type"]     = "success";

                return(Json(new { success = true }));
            }

            return(Json(new { success = false, hasPhotos = true }));
        }
Beispiel #5
0
        public async Task <IActionResult> Create([Bind("ID,Username,Password")] ContaOnedrive ContaOnedrive, string Code)
        {
            if (ModelState.IsValid)
            {
                _context.Add(ContaOnedrive);
                await _context.SaveChangesAsync();

                return(RedirectToAction("InitAccount", new { Code, id = ContaOnedrive.ID }));
            }
            return(View(new ContaOnedriveCreateViewModel
            {
                ContaOnedrive = ContaOnedrive,
                Code = Code
            }));
        }
Beispiel #6
0
        /// <summary>
        /// Procura uma conta onedrive com espaço suficiente para alojar o tamanho do ficheiro que chega por parametro.
        /// </summary>
        /// <param name="fileSize">Tamanho do ficheiro utilizado para upload</param>
        /// <returns>Conta Onedrive</returns>
        public async Task <ContaOnedrive> GetAccountToUploadAsync(long fileSize)
        {
            ContaOnedrive conta = null;

            // Tenta encontrar conta com espaço
            try
            {
                while (true)
                {
                    conta = _context.ContasOnedrive.Where(c => Int64.Parse(c.Quota_Remaining) * 3 > fileSize).FirstOrDefault();

                    // Caso não encontre conta, é porque já não existem contas com espaço
                    if (conta == null)
                    {
                        _emailAPI.Send(_appSettings.AdminEmails, "Já não existem contas Onedrive com espaço", $"Todas as contas Onedrive estão cheias.");
                        return(null);
                    }

                    // Confirmar que a conta tem mesmo o espaço suficiente
                    if (await UpdateDriveQuotaAsync(conta))
                    {
                        if (conta.Quota_Remaining != null && Int64.Parse(conta.Quota_Remaining) > fileSize)
                        {
                            return(conta);
                        }
                        else
                        {
                            _emailAPI.Send(_appSettings.AdminEmails, "Conta Onedrive com pouco espaço", $"A conta onedrive {conta.Username} já só tem menos de 50 Gb.");
                        }
                    }
                    else
                    {
                        return(null);
                    }
                }
            }
            catch (Exception e)
            {
                await _logger.LogError(
                    descricao : "Erro ao encontrar conta com espaço para upload.",
                    classe : "OneDriveAPI",
                    metodo : "GetAccountToUploadAsync",
                    erro : e.Message
                    );

                return(null);
            }
        }
Beispiel #7
0
        /// <summary>
        /// Upload do ficheiro para a Onedrive.
        /// </summary>
        /// <param name="filePath">Caminho do ficheiro no disco.</param>
        /// <param name="fileName">Nome do ficheiro.</param>
        /// <returns>Booleano que indica o sucesso do método.</returns>
        private async Task <UploadedPhotoModel> UploadFileAsync(string filePath, string fileName)
        {
            WebResponse   result = null;
            ContaOnedrive conta  = null;

            using (FileStream stream = File.OpenRead(filePath))
            {
                long position               = 0;
                long totalLength            = stream.Length;
                int  uploadFragmentSizeInMB = _appSettings.UploadFragmentSizeInMB;
                int  length = uploadFragmentSizeInMB * 1024 * 1024;

                #region Encontrar conta e refrescar token
                // Encontrar a conta onedrive a ser utilizada para o upload
                conta = await GetAccountToUploadAsync(totalLength);

                // Se a conta retornar null, poderá ser porque já não existem contas com espaço
                if (conta == null)
                {
                    return(new UploadedPhotoModel
                    {
                        Success = false,
                        ErrorDescription = "Não foi possível adquirir uma conta com espaço suficiente."
                    });
                }
                await RefreshTokenAsync(conta, 2000);

                #endregion

                #region Criar sessão de upload
                string uploadUrl = await GetUploadSessionAsync(conta, fileName);

                if (uploadUrl == "Error")
                {
                    // Não foi possível fazer a sessão de upload
                    return(new UploadedPhotoModel
                    {
                        Success = false,
                        ErrorDescription = "Não foi possível criar sessão de upload."
                    });
                }
                #endregion

                #region Upload do fragmento do ficheiro
                while (true)
                {
                    byte[] bytes = await ReadFileFragmentAsync(stream, position, length);

                    if (position >= totalLength)
                    {
                        break;
                    }

                    result = await UploadFileFragmentAsync(bytes, uploadUrl, position, totalLength, conta.AccessToken);

                    position += bytes.Length;
                }
                #endregion

                #region Identificar as informações do ficheiro na onedrive
                if (result != null && conta != null)
                {
                    string itemId = "", itemName = "";
                    using (Stream dataStream = result.GetResponseStream()) // Recolher a stream que contem o conteudo
                    {
                        try
                        {
                            StreamReader reader             = new StreamReader(dataStream);      // Abrir a stream
                            string       responseFromServer = reader.ReadToEnd();                // Ler o conteudo
                            JObject      content            = JObject.Parse(responseFromServer); // Converter a resposta para um objeto json
                            itemId   = (string)content["id"];                                    // Recolher o id da imagem na onedrive
                            itemName = (string)content["name"];                                  // Recolher o nome da imagem na onedrive
                        }
                        catch (Exception e)
                        {
                            _emailAPI.NotifyError("Erro ao recolher as informações do ficheiro que foi feito o upload.", "OnedriveAPI", "UploadFileAsync", e.Message);
                            return(new UploadedPhotoModel
                            {
                                Success = false,
                                ErrorDescription = "Não foi possível fazer upload do ficheiro."
                            });
                        }

                        if (!String.IsNullOrEmpty(itemId) && !String.IsNullOrEmpty(itemName))
                        {
                            #region Atualizar o espaço da conta
                            await UpdateDriveQuotaAsync(conta);

                            #endregion

                            return(new UploadedPhotoModel
                            {
                                ItemId = itemId,
                                ItemName = itemName,
                                Conta = conta,
                                Success = true
                            });
                        }
                    }
                    result.Close();
                }
                #endregion
            }

            return(new UploadedPhotoModel
            {
                Success = false,
                ErrorDescription = "Não foi possível fazer upload do ficheiro."
            });
        }
Beispiel #8
0
        /// <summary>
        /// Cria uma sessão de upload
        /// </summary>
        /// <param name="conta">Conta Onedrive</param>
        /// <param name="fileName">Nome do ficheiro. Este irá ser utilizado na OneDrive.</param>
        /// <returns>Url da sessão</returns>
        public async Task <string> GetUploadSessionAsync(ContaOnedrive conta, string fileName)
        {
            if (await RefreshTokenAsync(conta, 1800)) // Refrescar token
            {
                #region Preparar pedido HTTP
                string url     = "https://graph.microsoft.com/v1.0/me/drives/" + conta.DriveId + "/root:/" + fileName + ":/createUploadSession";
                var    request = new HttpRequestMessage(HttpMethod.Post, url);
                request.Headers.Add("Authorization", "Bearer " + conta.AccessToken);
                // Especificar que em caso de nomes iguais, a onedrive altera o nome e carrega a imagem na mesma
                request.Content = new StringContent("{\"item\":{\"@microsoft.graph.conflictBehavior\": \"rename\"}}", Encoding.UTF8, "application/json");
                #endregion

                #region Fazer pedido HTTP
                HttpResponseMessage response = null;
                try
                {
                    // Fazer o pedido e obter resposta
                    response = await _client.SendAsync(request);
                }
                catch (Exception e)
                {
                    await _logger.LogError(
                        descricao : "Erro ao enviar pedido HTTP.",
                        classe : "OneDriveAPI",
                        metodo : "GetUploadSessionAsync",
                        erro : e.Message
                        );
                }
                #endregion

                #region Tratar resposta ao pedido
                // Caso retorne OK 2xx
                if (response != null)
                {
                    if (response.IsSuccessStatusCode)
                    {
                        try
                        {
                            // Converter a resposta para um objeto json
                            JObject content = JObject.Parse(await response.Content.ReadAsStringAsync());

                            return((string)content["uploadUrl"]);
                        }
                        catch (Exception e)
                        {
                            await _logger.LogError(
                                descricao : "Erro ao tratar o JSON da resposta.",
                                classe : "OneDriveAPI",
                                metodo : "GetUploadSessionAsync",
                                erro : e.Message
                                );
                        }
                    }
                    else
                    {
                        return("API");
                    }
                }
            }

            return("Error");

            #endregion
        }
Beispiel #9
0
        /// <summary>
        /// Atualiza as informações sobre o espaço ocupado na conta Onedrive.
        /// </summary>
        /// <param name="conta">Conta Onedrive.</param>
        /// <returns></returns>
        public async Task <bool> UpdateDriveQuotaAsync(ContaOnedrive conta)
        {
            if (await RefreshTokenAsync(conta, 3400)) // Refrescar token
            {
                try
                {
                    // Faz o pedido HTTP.GET para pedir as informações da Onedrive
                    // Para que estas possam ser associadas ao objeto 'conta'
                    JObject driveInfo = await GetDriveInfoAsync(conta.AccessToken);

                    // Transformar o array num array de objetos
                    JObject[] values = driveInfo["value"].Select(s => (JObject)s).ToArray();

                    JObject quota           = (JObject)values[0]["quota"];
                    string  quota_Total     = (string)quota["total"];
                    string  quota_Used      = (string)quota["used"];
                    string  quota_Remaining = (string)quota["remaining"];

                    // Atualizar a conta com as informações recolhidas da API da Onedrive
                    conta.Quota_Remaining = quota_Remaining;
                    conta.Quota_Total     = quota_Total;
                    conta.Quota_Used      = quota_Used;

                    // Quando a conta só tiver 50 gb, envia email ao admins para notificar
                    if (Int64.Parse(quota_Remaining) < 53687091200)
                    {
                        _emailAPI.Send(_appSettings.AdminEmails, "Conta Onedrive com pouco espaço", $"A conta onedrive {conta.Username} já só tem menos de 50 Gb.");
                    }
                }
                catch (Exception e)
                {
                    await _logger.LogError(
                        descricao : "Erro ao interpretar o JSON da resposta.",
                        classe : "OneDriveAPI",
                        metodo : "UpdateDriveQuotaAsync",
                        erro : e.Message
                        );

                    return(false);
                }

                try
                {
                    _context.Update(conta);
                    await _context.SaveChangesAsync();

                    return(true);
                }
                catch (Exception e)
                {
                    await _logger.LogError(
                        descricao : "Erro ao dar update à conta Onedrive localmente.",
                        classe : "OneDriveAPI",
                        metodo : "UpdateDriveQuotaAsync",
                        erro : e.Message
                        );
                }
            }

            return(false);
        }
Beispiel #10
0
        /// <summary>
        /// Refresca o token de uma conta caso este esteja expirado.
        /// </summary>
        /// <param name="conta">Conta Onedrive.</param>
        /// <returns></returns>
        private async Task <bool> RefreshTokenAsync(ContaOnedrive conta, int seconds = 3400)
        {
            if (!IsTokenValid(conta, seconds))
            {
                #region Preparar pedido HTTP
                string url     = "https://login.microsoftonline.com/21e90dfc-54f1-4b21-8f3b-7fb9798ed2e0/oauth2/v2.0/token";
                var    request = new HttpRequestMessage(HttpMethod.Get, url);
                request.Content = new StringContent(
                    "client_id=" + _applicationClientId +
                    "&scope=offline_access+files.read+files.read.all" +
                    "&refresh_token=" + conta.RefreshToken +
                    "&redirect_uri=" + _appSettings.SiteUrl +
                    "&grant_type=refresh_token" +
                    "&client_secret=" + _applicationClientSecret,
                    Encoding.UTF8, "application/x-www-form-urlencoded"
                    );
                #endregion

                #region Fazer o pedido HTTP
                HttpResponseMessage response = null;
                try
                {
                    // Fazer o pedido e obter resposta
                    response = await _client.SendAsync(request);
                }
                catch (Exception e)
                {
                    await _logger.LogError(
                        descricao : "Erro no pedido HTTP de um token.",
                        classe : "OneDriveAPI",
                        metodo : "RefreshTokenAsync",
                        erro : e.Message
                        );

                    return(false);
                }
                #endregion

                #region Tratar resposta
                if (response != null)
                {
                    if (response != null && response.IsSuccessStatusCode)
                    {
                        try
                        {
                            JObject content = JObject.Parse(await response.Content.ReadAsStringAsync());

                            // Atualizar a data do token
                            conta.TokenDate    = DateTime.Now;
                            conta.AccessToken  = (string)content["access_token"];
                            conta.RefreshToken = (string)content["refresh_token"];
                        }
                        catch (Exception e)
                        {
                            await _logger.LogError(
                                descricao : "Erro ao interpretar o JSON da resposta.",
                                classe : "OneDriveAPI",
                                metodo : "RefreshTokenAsync",
                                erro : e.Message
                                );

                            return(false);
                        }

                        try
                        {
                            _context.Update(conta);
                            await _context.SaveChangesAsync();
                        }
                        catch (Exception e)
                        {
                            await _logger.LogError(
                                descricao : "Erro ao dar update à conta Onedrive localmente.",
                                classe : "OneDriveAPI",
                                metodo : "RefreshTokenAsync",
                                erro : e.Message
                                );

                            return(false);
                        }

                        return(true);
                    }
                    else
                    {
                        return(false);
                    }
                }
                else
                {
                    return(false);
                }
                #endregion
            }

            return(true);
        }
Beispiel #11
0
 /// <summary>
 /// Verifica se o token de uma conta já expirou
 /// </summary>
 /// <param name="conta"></param>
 /// <returns></returns>
 private bool IsTokenValid(ContaOnedrive conta, int seconds)
 {
     return((DateTime.Now - conta.TokenDate).TotalSeconds < seconds);
 }
Beispiel #12
0
        public async Task <IActionResult> InitAccount(string Code, int id)
        {
            // Define se a operação foi executada com sucesso
            bool success = true;

            ContaOnedrive conta = await _context.ContasOnedrive.FindAsync(id);

            string access_token = "";

            #region Atualizar token
            try
            {
                // Faz o pedido HTTP.GET para pedir o token utilizando o codigo das permissões
                JObject tokenResponse = await _onedrive.GetInitialTokenAsync(Code);

                // Recolher os tokens
                access_token = (string)tokenResponse["access_token"];
                string refresh_token = (string)tokenResponse["refresh_token"];

                // Atualizar informações da conta
                conta.AccessToken  = access_token;
                conta.RefreshToken = refresh_token;
                conta.TokenDate    = DateTime.Now;
            }
            catch (Exception e)
            {
                success = false;
                await _logger.LogError(
                    descricao : "Erro ao obter token da conta.",
                    classe : "ContasOnedriveController",
                    metodo : "InitAccount",
                    erro : e.Message
                    );

                // Feeback ao utilizador - Vai ser redirecionado para o Index
                TempData["Feedback"] = "Ocorreu obter o token da conta.";
                TempData["Type"]     = "error";
            }
            #endregion

            #region Recolher ID e informação do espaço na drive
            // Caso exista acesso token e a operação acima tenha sido executada com sucesso
            if (!String.IsNullOrEmpty(access_token) && success)
            {
                try
                {
                    // Faz o pedido HTTP.GET para pedir as informações da Onedrive
                    // Para que estas possam ser associadas ao objeto 'conta'
                    JObject driveInfo = await _onedrive.GetDriveInfoAsync(access_token);

                    // Transformar o array num array de objetos
                    JObject[] values = driveInfo["value"].Select(s => (JObject)s).ToArray();

                    string driveId = (string)values[0]["id"];

                    JObject quota           = (JObject)values[0]["quota"];
                    string  quota_Total     = (string)quota["total"];
                    string  quota_Used      = (string)quota["used"];
                    string  quota_Remaining = (string)quota["remaining"];

                    // Atualizar a conta com as informações recolhidas da API da Onedrive
                    conta.DriveId         = driveId;
                    conta.Quota_Remaining = quota_Remaining;
                    conta.Quota_Total     = quota_Total;
                    conta.Quota_Used      = quota_Used;
                }
                catch (Exception e)
                {
                    success = false;
                    await _logger.LogError(
                        descricao : "Erro ao obter informações da conta.",
                        classe : "ContasOnedriveController",
                        metodo : "InitAccount",
                        erro : e.Message
                        );

                    // Feeback ao utilizador - Vai ser redirecionado para o Index
                    TempData["Feedback"] = "Ocorreu um erro ao obter informações da conta.";
                    TempData["Type"]     = "error";
                }
            }
            #endregion

            #region Atualizar a conta
            // Caso as operações acima tenham sido executadas com sucesso
            if (success)
            {
                try
                {
                    // Atualizar conta
                    _context.ContasOnedrive.Update(conta);
                    await _context.SaveChangesAsync();
                }
                catch (Exception e)
                {
                    success = false;
                    await _logger.LogError(
                        descricao : "Erro ao criar a conta.",
                        classe : "ContasOnedriveController",
                        metodo : "InitAccount",
                        erro : e.Message
                        );

                    // Feeback ao utilizador - Vai ser redirecionado para o Index
                    TempData["Feedback"] = "Ocorreu um erro ao criar a conta.";
                    TempData["Type"]     = "error";
                }
            }
            #endregion

            if (success)
            {
                // Feeback ao utilizador - Vai ser redirecionado para o Index
                TempData["Feedback"] = "Conta Onedrive adiconada com sucesso.";
                TempData["Type"]     = "success";
            }
            else
            {
                // Caso tenha acontecido algum erro, certificar que a conta não é criada
                _context.ContasOnedrive.Remove(conta);
                await _context.SaveChangesAsync();
            }

            return(RedirectToAction("Index"));
        }